model.ts 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. /**
  2. * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
  3. *
  4. * @author David Sehnal <david.sehnal@gmail.com>
  5. */
  6. import { PluginStateTransform } from '../objects';
  7. import { PluginStateObject as SO } from '../objects';
  8. import { Task } from 'mol-task';
  9. import { Model, Format, Structure, ModelSymmetry, StructureSymmetry, QueryContext, StructureSelection } from 'mol-model/structure';
  10. import { ParamDefinition as PD } from 'mol-util/param-definition';
  11. import Expression from 'mol-script/language/expression';
  12. import { compile } from 'mol-script/runtime/query/compiler';
  13. import { Mat4 } from 'mol-math/linear-algebra';
  14. export { ParseTrajectoryFromMmCif }
  15. namespace ParseTrajectoryFromMmCif { export interface Params { blockHeader?: string } }
  16. const ParseTrajectoryFromMmCif = PluginStateTransform.Create<SO.Data.Cif, SO.Molecule.Trajectory, ParseTrajectoryFromMmCif.Params>({
  17. name: 'parse-trajectory-from-mmcif',
  18. display: {
  19. name: 'Models from mmCIF',
  20. description: 'Identify and create all separate models in the specified CIF data block'
  21. },
  22. from: [SO.Data.Cif],
  23. to: [SO.Molecule.Trajectory],
  24. params: {
  25. default: a => ({ blockHeader: a.data.blocks[0].header }),
  26. controls(a) {
  27. const { blocks } = a.data;
  28. if (blocks.length === 0) return {};
  29. return {
  30. blockHeader: PD.Select('Header', 'Header of the block to parse', blocks[0].header, blocks.map(b => [b.header, b.header] as [string, string]))
  31. };
  32. }
  33. },
  34. apply({ a, params }) {
  35. return Task.create('Parse mmCIF', async ctx => {
  36. const header = params.blockHeader || a.data.blocks[0].header;
  37. const block = a.data.blocks.find(b => b.header === header);
  38. if (!block) throw new Error(`Data block '${[header]}' not found.`);
  39. const models = await Model.create(Format.mmCIF(block)).runInContext(ctx);
  40. if (models.length === 0) throw new Error('No models found.');
  41. const label = { label: models[0].label, description: `${models.length} model${models.length === 1 ? '' : 's'}` };
  42. return new SO.Molecule.Trajectory(models, label);
  43. });
  44. }
  45. });
  46. export { CreateModelFromTrajectory }
  47. namespace CreateModelFromTrajectory { export interface Params { modelIndex: number } }
  48. const CreateModelFromTrajectory = PluginStateTransform.Create<SO.Molecule.Trajectory, SO.Molecule.Model, CreateModelFromTrajectory.Params>({
  49. name: 'create-model-from-trajectory',
  50. display: {
  51. name: 'Model from Trajectory',
  52. description: 'Create a molecular structure from the specified model.'
  53. },
  54. from: [SO.Molecule.Trajectory],
  55. to: [SO.Molecule.Model],
  56. params: {
  57. default: () => ({ modelIndex: 0 }),
  58. controls: a => ({ modelIndex: PD.Range('Model Index', 'Model Index', 0, 0, Math.max(0, a.data.length - 1), 1) })
  59. },
  60. isApplicable: a => a.data.length > 0,
  61. apply({ a, params }) {
  62. if (params.modelIndex < 0 || params.modelIndex >= a.data.length) throw new Error(`Invalid modelIndex ${params.modelIndex}`);
  63. const model = a.data[params.modelIndex];
  64. const label = { label: `Model ${model.modelNum}` };
  65. return new SO.Molecule.Model(model, label);
  66. }
  67. });
  68. export { CreateStructure }
  69. namespace CreateStructure { export interface Params { transform3d?: Mat4 } }
  70. const CreateStructure = PluginStateTransform.Create<SO.Molecule.Model, SO.Molecule.Structure, CreateStructure.Params>({
  71. name: 'create-structure-from-model',
  72. display: {
  73. name: 'Structure from Model',
  74. description: 'Create a molecular structure from the specified model.'
  75. },
  76. from: [SO.Molecule.Model],
  77. to: [SO.Molecule.Structure],
  78. apply({ a, params }) {
  79. let s = Structure.ofModel(a.data);
  80. if (params.transform3d) s = Structure.transform(s, params.transform3d);
  81. const label = { label: a.data.label, description: s.elementCount === 1 ? '1 element' : `${s.elementCount} elements` };
  82. return new SO.Molecule.Structure(s, label);
  83. }
  84. });
  85. function structureDesc(s: Structure) {
  86. return s.elementCount === 1 ? '1 element' : `${s.elementCount} elements`;
  87. }
  88. export { CreateStructureAssembly }
  89. namespace CreateStructureAssembly { export interface Params { /** if not specified, use the 1st */ id?: string } }
  90. const CreateStructureAssembly = PluginStateTransform.Create<SO.Molecule.Model, SO.Molecule.Structure, CreateStructureAssembly.Params>({
  91. name: 'create-structure-assembly',
  92. display: {
  93. name: 'Structure Assembly',
  94. description: 'Create a molecular structure assembly.'
  95. },
  96. from: [SO.Molecule.Model],
  97. to: [SO.Molecule.Structure],
  98. params: {
  99. default: () => ({ id: void 0 }),
  100. controls(a) {
  101. const model = a.data;
  102. const ids = model.symmetry.assemblies.map(a => [a.id, a.id] as [string, string]);
  103. return { id: PD.Select('Asm Id', 'Assembly Id', ids.length ? ids[0][0] : '', ids) };
  104. }
  105. },
  106. apply({ a, params }) {
  107. return Task.create('Build Assembly', async ctx => {
  108. let id = params.id;
  109. const model = a.data;
  110. if (!id && model.symmetry.assemblies.length) id = model.symmetry.assemblies[0].id;
  111. const asm = ModelSymmetry.findAssembly(model, id || '');
  112. if (!asm) throw new Error(`Assembly '${id}' not found`);
  113. const base = Structure.ofModel(model);
  114. const s = await StructureSymmetry.buildAssembly(base, id!).runInContext(ctx);
  115. const label = { label: `Assembly ${id}`, description: structureDesc(s) };
  116. return new SO.Molecule.Structure(s, label);
  117. })
  118. }
  119. });
  120. export { CreateStructureSelection }
  121. namespace CreateStructureSelection { export interface Params { query: Expression, label?: string } }
  122. const CreateStructureSelection = PluginStateTransform.Create<SO.Molecule.Structure, SO.Molecule.Structure, CreateStructureSelection.Params>({
  123. name: 'create-structure-selection',
  124. display: {
  125. name: 'Structure Selection',
  126. description: 'Create a molecular structure from the specified model.'
  127. },
  128. from: [SO.Molecule.Structure],
  129. to: [SO.Molecule.Structure],
  130. apply({ a, params }) {
  131. // TODO: use cache, add "update"
  132. const compiled = compile<StructureSelection>(params.query);
  133. const result = compiled(new QueryContext(a.data));
  134. const s = StructureSelection.unionStructure(result);
  135. const label = { label: `${params.label || 'Selection'}`, description: structureDesc(s) };
  136. return new SO.Molecule.Structure(s, label);
  137. }
  138. });