structure.ts 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. /**
  2. * Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
  3. *
  4. * @author David Sehnal <david.sehnal@gmail.com>
  5. */
  6. import { PluginContext } from '../../mol-plugin/context';
  7. import { StateBuilder, StateObjectRef, StateObjectSelector, StateTransformer } from '../../mol-state';
  8. import { PluginStateObject as SO } from '../objects';
  9. import { StateTransforms } from '../transforms';
  10. import { RootStructureDefinition } from '../helpers/root-structure';
  11. import { StructureComponentParams } from '../helpers/structure-component';
  12. type TrajectoryFormat = 'pdb' | 'cif' | 'gro' | '3dg'
  13. export enum StructureBuilderTags {
  14. Trajectory = 'trajectory',
  15. Model = 'model',
  16. ModelProperties = 'model-properties',
  17. Structure = 'structure',
  18. Component = 'structure-component'
  19. }
  20. export class StructureBuilder {
  21. private get dataState() {
  22. return this.plugin.state.dataState;
  23. }
  24. private async parseTrajectoryData(data: StateObjectRef<SO.Data.Binary | SO.Data.String>, format: TrajectoryFormat) {
  25. const state = this.dataState;
  26. const root = state.build().to(data);
  27. let parsed: StateBuilder.To<SO.Molecule.Trajectory>;
  28. const tag = { tags: StructureBuilderTags.Trajectory };
  29. switch (format) {
  30. case 'cif':
  31. parsed = root.apply(StateTransforms.Data.ParseCif, void 0, { state: { isGhost: true } })
  32. .apply(StateTransforms.Model.TrajectoryFromMmCif, void 0, tag)
  33. break
  34. case 'pdb':
  35. parsed = root.apply(StateTransforms.Model.TrajectoryFromPDB, void 0, tag);
  36. break
  37. case 'gro':
  38. parsed = root.apply(StateTransforms.Model.TrajectoryFromGRO, void 0, tag);
  39. break
  40. case '3dg':
  41. parsed = root.apply(StateTransforms.Model.TrajectoryFrom3DG, void 0, tag);
  42. break
  43. default:
  44. throw new Error('unsupported format')
  45. }
  46. await this.plugin.runTask(this.dataState.updateTree(parsed, { revertOnError: true }));
  47. return parsed.selector;
  48. }
  49. private async parseTrajectoryBlob(data: StateObjectRef<SO.Data.Blob>, params: StateTransformer.Params<StateTransforms['Data']['ParseBlob']>) {
  50. const state = this.dataState;
  51. const trajectory = state.build().to(data)
  52. .apply(StateTransforms.Data.ParseBlob, params, { state: { isGhost: true } })
  53. .apply(StateTransforms.Model.TrajectoryFromBlob, void 0, { tags: StructureBuilderTags.Trajectory });
  54. await this.plugin.runTask(this.dataState.updateTree(trajectory, { revertOnError: true }));
  55. return trajectory.selector;
  56. }
  57. async parseTrajectory(data: StateObjectRef<SO.Data.Binary | SO.Data.String>, format: TrajectoryFormat): Promise<StateObjectSelector<SO.Molecule.Trajectory>>
  58. async parseTrajectory(blob: StateObjectRef<SO.Data.Blob>, params: StateTransformer.Params<StateTransforms['Data']['ParseBlob']>): Promise<StateObjectSelector<SO.Molecule.Trajectory>>
  59. async parseTrajectory(data: StateObjectRef, params: any) {
  60. // TODO: proper format support
  61. // needs to integrated to transforms directly because of blobs
  62. const cell = StateObjectRef.resolveAndCheck(this.dataState, data as StateObjectRef);
  63. if (!cell) throw new Error('Invalid data cell.');
  64. if (SO.Data.Blob.is(cell.obj)) {
  65. return this.parseTrajectoryBlob(data, params);
  66. } else {
  67. return this.parseTrajectoryData(data, params);
  68. }
  69. }
  70. async createModel(trajectory: StateObjectRef<SO.Molecule.Trajectory>, params?: StateTransformer.Params<StateTransforms['Model']['ModelFromTrajectory']>, supportProps?: boolean) {
  71. const state = this.dataState;
  72. if (supportProps) {
  73. const model = state.build().to(trajectory)
  74. .apply(StateTransforms.Model.ModelFromTrajectory, params || { modelIndex: 0 })
  75. .apply(StateTransforms.Model.CustomModelProperties, void 0, { tags: [StructureBuilderTags.Model, StructureBuilderTags.ModelProperties] });
  76. await this.plugin.runTask(this.dataState.updateTree(model, { revertOnError: true }));
  77. return model.selector;
  78. } else {
  79. const model = state.build().to(trajectory)
  80. .apply(StateTransforms.Model.ModelFromTrajectory, params || { modelIndex: 0 }, { tags: StructureBuilderTags.Model });
  81. await this.plugin.runTask(this.dataState.updateTree(model, { revertOnError: true }));
  82. return model.selector;
  83. }
  84. }
  85. async createStructure(model: StateObjectRef<SO.Molecule.Model>, params?: RootStructureDefinition.Params) {
  86. const state = this.dataState;
  87. const structure = state.build().to(model)
  88. .apply(StateTransforms.Model.StructureFromModel, { type: params || { name: 'assembly', params: { } } }, { tags: StructureBuilderTags.Structure });
  89. await this.plugin.runTask(this.dataState.updateTree(structure, { revertOnError: true }));
  90. return structure.selector;
  91. }
  92. /** returns undefined if the component is empty/null */
  93. async tryCreateComponent(structure: StateObjectRef<SO.Molecule.Structure>, params: StructureComponentParams, tag?: string): Promise<StateObjectRef<SO.Molecule.Structure> | undefined> {
  94. const state = this.dataState;
  95. const root = state.build().to(structure);
  96. let component: StateBuilder.To<SO.Molecule.Structure>;
  97. if (tag) {
  98. const typeTag = `structure-component-${tag}`;
  99. component = root.applyOrUpdateTagged(typeTag, StateTransforms.Model.StructureComponent, params, { tags: [StructureBuilderTags.Component, typeTag] });
  100. } else {
  101. component = root.apply(StateTransforms.Model.StructureComponent, params, { tags: StructureBuilderTags.Component });
  102. }
  103. await this.plugin.runTask(this.dataState.updateTree(component));
  104. const selector = component.selector;
  105. if (!selector.isOk || selector.cell?.obj?.data.elementCount === 0) {
  106. const del = state.build().delete(selector.ref);
  107. await this.plugin.runTask(this.dataState.updateTree(del));
  108. return;
  109. }
  110. return selector;
  111. }
  112. constructor(public plugin: PluginContext) {
  113. }
  114. }