mmcif.ts 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. /**
  2. * Copyright (c) 2017-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
  3. *
  4. * @author David Sehnal <david.sehnal@gmail.com>
  5. * @author Alexander Rose <alexander.rose@weirdbyte.de>
  6. */
  7. import { Model } from '../../mol-model/structure/model/model';
  8. import { RuntimeContext, Task } from '../../mol-task';
  9. import { ModelFormat } from '../format';
  10. import { CifFrame, CIF } from '../../mol-io/reader/cif';
  11. import { mmCIF_Database } from '../../mol-io/reader/cif/schema/mmcif';
  12. import { createModels } from './basic/parser';
  13. import { ModelSymmetry } from './property/symmetry';
  14. import { ModelSecondaryStructure } from './property/secondary-structure';
  15. import { Column, Table } from '../../mol-data/db';
  16. import { AtomSiteAnisotrop } from './property/anisotropic';
  17. import { ComponentBond } from './property/bonds/chem_comp';
  18. import { StructConn } from './property/bonds/struct_conn';
  19. import { ArrayTrajectory, Trajectory } from '../../mol-model/structure';
  20. import { GlobalModelTransformInfo } from '../../mol-model/structure/model/properties/global-transform';
  21. import { BasicSchema, createBasic } from './basic/schema';
  22. import { CCD_Database } from '../../mol-io/reader/cif/schema/ccd';
  23. import { EntityBuilder } from './common/entity';
  24. import { MoleculeType } from '../../mol-model/structure/model/types';
  25. import { ComponentBuilder } from './common/component';
  26. function modelSymmetryFromMmcif(model: Model) {
  27. if (!MmcifFormat.is(model.sourceData)) return;
  28. return ModelSymmetry.fromData(model.sourceData.data.db);
  29. }
  30. ModelSymmetry.Provider.formatRegistry.add('mmCIF', modelSymmetryFromMmcif);
  31. function secondaryStructureFromMmcif(model: Model) {
  32. if (!MmcifFormat.is(model.sourceData)) return;
  33. const { struct_conf, struct_sheet_range } = model.sourceData.data.db;
  34. return ModelSecondaryStructure.fromStruct(struct_conf, struct_sheet_range, model.atomicHierarchy);
  35. }
  36. ModelSecondaryStructure.Provider.formatRegistry.add('mmCIF', secondaryStructureFromMmcif);
  37. function atomSiteAnisotropFromMmcif(model: Model) {
  38. if (!MmcifFormat.is(model.sourceData)) return;
  39. const { atom_site_anisotrop } = model.sourceData.data.db;
  40. const data = Table.ofColumns(AtomSiteAnisotrop.Schema, atom_site_anisotrop);
  41. const elementToAnsiotrop = AtomSiteAnisotrop.getElementToAnsiotrop(model.atomicConformation.atomId, atom_site_anisotrop.id);
  42. return { data, elementToAnsiotrop };
  43. }
  44. function atomSiteAnisotropApplicableMmcif(model: Model) {
  45. if (!MmcifFormat.is(model.sourceData)) return false;
  46. return model.sourceData.data.db.atom_site_anisotrop.U.isDefined;
  47. }
  48. AtomSiteAnisotrop.Provider.formatRegistry.add('mmCIF', atomSiteAnisotropFromMmcif, atomSiteAnisotropApplicableMmcif);
  49. function componentBondFromMmcif(model: Model) {
  50. if (!MmcifFormat.is(model.sourceData)) return;
  51. const { chem_comp_bond } = model.sourceData.data.db;
  52. if (chem_comp_bond._rowCount === 0) return;
  53. return {
  54. data: chem_comp_bond,
  55. entries: ComponentBond.getEntriesFromChemCompBond(chem_comp_bond)
  56. };
  57. }
  58. ComponentBond.Provider.formatRegistry.add('mmCIF', componentBondFromMmcif);
  59. function structConnFromMmcif(model: Model) {
  60. if (!MmcifFormat.is(model.sourceData)) return;
  61. const { struct_conn } = model.sourceData.data.db;
  62. if (struct_conn._rowCount === 0) return;
  63. const entries = StructConn.getEntriesFromStructConn(struct_conn, model);
  64. return {
  65. data: struct_conn,
  66. byAtomIndex: StructConn.getAtomIndexFromEntries(entries),
  67. entries,
  68. };
  69. }
  70. StructConn.Provider.formatRegistry.add('mmCIF', structConnFromMmcif);
  71. GlobalModelTransformInfo.Provider.formatRegistry.add('mmCIF', GlobalModelTransformInfo.fromMmCif, GlobalModelTransformInfo.hasData);
  72. //
  73. export { MmcifFormat };
  74. type MmcifFormat = ModelFormat<MmcifFormat.Data>
  75. namespace MmcifFormat {
  76. export type Data = {
  77. db: mmCIF_Database,
  78. frame: CifFrame,
  79. /**
  80. * Original source format. Some formats, including PDB, are converted
  81. * to mmCIF before further processing.
  82. */
  83. source?: ModelFormat
  84. }
  85. export function is(x?: ModelFormat): x is MmcifFormat {
  86. return x?.kind === 'mmCIF';
  87. }
  88. export function fromFrame(frame: CifFrame, db?: mmCIF_Database, source?: ModelFormat): MmcifFormat {
  89. if (!db) db = CIF.schema.mmCIF(frame);
  90. return { kind: 'mmCIF', name: db._name, data: { db, frame, source } };
  91. }
  92. }
  93. export function trajectoryFromMmCIF(frame: CifFrame): Task<Trajectory> {
  94. const format = MmcifFormat.fromFrame(frame);
  95. const basic = createBasic(format.data.db, true);
  96. return Task.create('Create mmCIF Model', ctx => createModels(basic, format, ctx));
  97. }
  98. export { CCDFormat };
  99. type CCDFormat = ModelFormat<CCDFormat.Data>
  100. namespace CCDFormat {
  101. export type Data = {
  102. db: CCD_Database,
  103. frame: CifFrame
  104. }
  105. export function is(x?: ModelFormat): x is CCDFormat {
  106. return x?.kind === 'CCD';
  107. }
  108. export function fromFrame(frame: CifFrame, db?: CCD_Database): CCDFormat {
  109. if (!db) db = CIF.schema.CCD(frame);
  110. return { kind: 'CCD', name: db._name, data: { db, frame } };
  111. }
  112. }
  113. export function trajectoryFromCCD(frame: CifFrame): Task<Trajectory> {
  114. const format = CCDFormat.fromFrame(frame);
  115. return Task.create('Create CCD Models', ctx => createCcdModels(format.data.db, CCDFormat.fromFrame(frame), ctx));
  116. }
  117. async function createCcdModels(data: CCD_Database, format: CCDFormat, ctx: RuntimeContext) {
  118. const model = await createCcdModel(data, format, { suffix: '(model)', cartn_x: 'model_Cartn_x', cartn_y: 'model_Cartn_y', cartn_z: 'model_Cartn_z' }, ctx);
  119. const ideal = await createCcdModel(data, format, { suffix: '(ideal)', cartn_x: 'pdbx_model_Cartn_x_ideal', cartn_y: 'pdbx_model_Cartn_y_ideal', cartn_z: 'pdbx_model_Cartn_z_ideal' }, ctx);
  120. const models = [model.representative, ideal.representative];
  121. Model.TrajectoryInfo.set(models[0], { index: 0, size: models.length });
  122. Model.TrajectoryInfo.set(models[1], { index: 1, size: models.length });
  123. return new ArrayTrajectory(models);
  124. }
  125. type CCDProps = { suffix: string, cartn_x: 'model_Cartn_x' | 'pdbx_model_Cartn_x_ideal', cartn_y: 'model_Cartn_y' | 'pdbx_model_Cartn_y_ideal', cartn_z: 'model_Cartn_z' | 'pdbx_model_Cartn_z_ideal' };
  126. async function createCcdModel(data: CCD_Database, format: CCDFormat, props: CCDProps, ctx: RuntimeContext) {
  127. const { chem_comp, chem_comp_atom, chem_comp_bond } = data;
  128. const { suffix, cartn_x, cartn_y, cartn_z } = props;
  129. const name = chem_comp.name.value(0);
  130. const id = chem_comp.id.value(0);
  131. const { atom_id, charge, comp_id, pdbx_ordinal, type_symbol } = chem_comp_atom;
  132. const atomCount = chem_comp_atom._rowCount;
  133. const A = Column.ofConst('A', atomCount, Column.Schema.str);
  134. const seq_id = Column.ofConst(1, atomCount, Column.Schema.int);
  135. const entity_id = Column.ofConst('1', atomCount, Column.Schema.str);
  136. const occupancy = Column.ofConst(1, atomCount, Column.Schema.float);
  137. const model_num = Column.ofConst(1, atomCount, Column.Schema.int);
  138. const model_atom_site = Table.ofPartialColumns(BasicSchema.atom_site, {
  139. auth_asym_id: A,
  140. auth_atom_id: atom_id,
  141. auth_comp_id: comp_id,
  142. auth_seq_id: seq_id,
  143. Cartn_x: chem_comp_atom[cartn_x],
  144. Cartn_y: chem_comp_atom[cartn_y],
  145. Cartn_z: chem_comp_atom[cartn_z],
  146. id: pdbx_ordinal,
  147. label_asym_id: A,
  148. label_atom_id: atom_id,
  149. label_comp_id: comp_id,
  150. label_seq_id: seq_id,
  151. label_entity_id: entity_id,
  152. occupancy,
  153. type_symbol,
  154. pdbx_PDB_model_num: model_num,
  155. pdbx_formal_charge: charge
  156. }, atomCount);
  157. const entityBuilder = new EntityBuilder();
  158. entityBuilder.setNames([[id, `${name} ${suffix}`]]);
  159. entityBuilder.getEntityId(id, MoleculeType.Unknown, 'A');
  160. const componentBuilder = new ComponentBuilder(seq_id, type_symbol);
  161. componentBuilder.setNames([[id, `${name} ${suffix}`]]);
  162. componentBuilder.add(id, 0);
  163. const basicModel = createBasic({
  164. entity: entityBuilder.getEntityTable(),
  165. chem_comp: componentBuilder.getChemCompTable(),
  166. atom_site: model_atom_site
  167. });
  168. const models = await createModels(basicModel, format, ctx);
  169. const first = models.representative;
  170. const entries = ComponentBond.getEntriesFromChemCompBond(chem_comp_bond);
  171. ComponentBond.Provider.set(first, { data: chem_comp_bond, entries });
  172. return models;
  173. }