structure.ts 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  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 { StateObjectRef, StateObjectSelector, StateTransformer, StateTransform, StateObjectCell } 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, StaticStructureComponentType } from '../helpers/structure-component';
  12. import { BuiltInTrajectoryFormat, TrajectoryFormatProvider } from '../formats/trajectory';
  13. import { StructureRepresentationBuilder } from './structure/representation';
  14. import { StructureSelectionQuery } from '../helpers/structure-selection-query';
  15. import { Task } from '../../mol-task';
  16. import { StructureElement } from '../../mol-model/structure';
  17. import { ModelSymmetry } from '../../mol-model-formats/structure/property/symmetry';
  18. import { SpacegroupCell } from '../../mol-math/geometry';
  19. import Expression from '../../mol-script/language/expression';
  20. import { TrajectoryHierarchyBuilder } from './structure/hierarchy';
  21. export class StructureBuilder {
  22. private get dataState() {
  23. return this.plugin.state.data;
  24. }
  25. private async parseTrajectoryData(data: StateObjectRef<SO.Data.Binary | SO.Data.String>, format: BuiltInTrajectoryFormat | TrajectoryFormatProvider) {
  26. const provider = typeof format === 'string' ? this.plugin.dataFormat.trajectory.get(format) : format;
  27. if (!provider) throw new Error(`'${format}' is not a supported data format.`);
  28. const { trajectory } = await provider.parse(this.plugin, data);
  29. return trajectory;
  30. }
  31. private async parseTrajectoryBlob(data: StateObjectRef<SO.Data.Blob>, params: StateTransformer.Params<StateTransforms['Data']['ParseBlob']>) {
  32. const state = this.dataState;
  33. const trajectory = state.build().to(data)
  34. .apply(StateTransforms.Data.ParseBlob, params, { state: { isGhost: true } })
  35. .apply(StateTransforms.Model.TrajectoryFromBlob, void 0);
  36. await this.plugin.updateDataState(trajectory, { revertOnError: true });
  37. return trajectory.selector;
  38. }
  39. readonly hierarchy = new TrajectoryHierarchyBuilder(this.plugin);
  40. readonly representation = new StructureRepresentationBuilder(this.plugin);
  41. async parseTrajectory(data: StateObjectRef<SO.Data.Binary | SO.Data.String>, format: BuiltInTrajectoryFormat | TrajectoryFormatProvider): Promise<StateObjectSelector<SO.Molecule.Trajectory>>
  42. async parseTrajectory(blob: StateObjectRef<SO.Data.Blob>, params: StateTransformer.Params<StateTransforms['Data']['ParseBlob']>): Promise<StateObjectSelector<SO.Molecule.Trajectory>>
  43. async parseTrajectory(data: StateObjectRef, params: any) {
  44. const cell = StateObjectRef.resolveAndCheck(this.dataState, data as StateObjectRef);
  45. if (!cell) throw new Error('Invalid data cell.');
  46. if (SO.Data.Blob.is(cell.obj)) {
  47. return this.parseTrajectoryBlob(data, params);
  48. } else {
  49. return this.parseTrajectoryData(data, params);
  50. }
  51. }
  52. async createModel(trajectory: StateObjectRef<SO.Molecule.Trajectory>, params?: StateTransformer.Params<StateTransforms['Model']['ModelFromTrajectory']>, initialState?: Partial<StateTransform.State>) {
  53. const state = this.dataState;
  54. const model = state.build().to(trajectory)
  55. .apply(StateTransforms.Model.ModelFromTrajectory, params || { modelIndex: 0 }, { state: initialState });
  56. await this.plugin.updateDataState(model, { revertOnError: true });
  57. return model.selector;
  58. }
  59. async insertModelProperties(model: StateObjectRef<SO.Molecule.Model>, params?: StateTransformer.Params<StateTransforms['Model']['CustomModelProperties']>, initialState?: Partial<StateTransform.State>) {
  60. const state = this.dataState;
  61. const props = state.build().to(model)
  62. .apply(StateTransforms.Model.CustomModelProperties, params, { state: initialState });
  63. await this.plugin.updateDataState(props, { revertOnError: true });
  64. return props.selector;
  65. }
  66. async tryCreateUnitcell(model: StateObjectRef<SO.Molecule.Model>, params?: StateTransformer.Params<StateTransforms['Representation']['ModelUnitcell3D']>, initialState?: Partial<StateTransform.State>) {
  67. const state = this.dataState;
  68. const m = StateObjectRef.resolveAndCheck(state, model)?.obj?.data;
  69. if (!m) return;
  70. const cell = ModelSymmetry.Provider.get(m)?.spacegroup.cell;
  71. if (SpacegroupCell.isZero(cell)) return;
  72. const unitcell = state.build().to(model)
  73. .apply(StateTransforms.Representation.ModelUnitcell3D, params, { state: initialState });
  74. await this.plugin.updateDataState(unitcell, { revertOnError: true });
  75. return unitcell.selector;
  76. }
  77. async createStructure(modelRef: StateObjectRef<SO.Molecule.Model>, params?: RootStructureDefinition.Params, initialState?: Partial<StateTransform.State>) {
  78. const state = this.dataState;
  79. if (!params) {
  80. const model = StateObjectRef.resolveAndCheck(state, modelRef);
  81. if (model) {
  82. const symm = ModelSymmetry.Provider.get(model.obj?.data!);
  83. if (!symm || symm?.assemblies.length === 0) params = { name: 'deposited', params: { } };
  84. }
  85. }
  86. const structure = state.build().to(modelRef)
  87. .apply(StateTransforms.Model.StructureFromModel, { type: params || { name: 'assembly', params: { } } }, { state: initialState });
  88. await this.plugin.updateDataState(structure, { revertOnError: true });
  89. return structure.selector;
  90. }
  91. async insertStructureProperties(structure: StateObjectRef<SO.Molecule.Structure>, params?: StateTransformer.Params<StateTransforms['Model']['CustomStructureProperties']>) {
  92. const state = this.dataState;
  93. const props = state.build().to(structure)
  94. .apply(StateTransforms.Model.CustomStructureProperties, params);
  95. await this.plugin.updateDataState(props, { revertOnError: true });
  96. return props.selector;
  97. }
  98. isComponentTransform(cell: StateObjectCell) {
  99. return cell.transform.transformer === StateTransforms.Model.StructureComponent;
  100. }
  101. /** returns undefined if the component is empty/null */
  102. async tryCreateComponent(structure: StateObjectRef<SO.Molecule.Structure>, params: StructureComponentParams, key: string, tags?: string[]): Promise<StateObjectSelector<SO.Molecule.Structure> | undefined> {
  103. const state = this.dataState;
  104. const root = state.build().to(structure);
  105. const keyTag = `structure-component-${key}`;
  106. const component = root.applyOrUpdateTagged(keyTag, StateTransforms.Model.StructureComponent, params, {
  107. tags: tags ? [...tags, keyTag] : [keyTag]
  108. });
  109. await this.plugin.updateDataState(component);
  110. const selector = component.selector;
  111. if (!selector.isOk || selector.cell?.obj?.data.elementCount === 0) {
  112. const del = state.build().delete(selector.ref);
  113. await this.plugin.updateDataState(del);
  114. return;
  115. }
  116. return selector;
  117. }
  118. tryCreateComponentFromExpression(structure: StateObjectRef<SO.Molecule.Structure>, expression: Expression, key: string, params?: { label?: string, tags?: string[] }) {
  119. return this.tryCreateComponent(structure, {
  120. type: { name: 'expression', params: expression },
  121. nullIfEmpty: true,
  122. label: (params?.label || '').trim()
  123. }, key, params?.tags);
  124. }
  125. tryCreateComponentStatic(structure: StateObjectRef<SO.Molecule.Structure>, type: StaticStructureComponentType, params?: { label?: string, tags?: string[] }) {
  126. return this.tryCreateComponent(structure, {
  127. type: { name: 'static', params: type },
  128. nullIfEmpty: true,
  129. label: (params?.label || '').trim()
  130. }, `static-${type}`, params?.tags);
  131. }
  132. tryCreateComponentFromSelection(structure: StateObjectRef<SO.Molecule.Structure>, selection: StructureSelectionQuery, key: string, params?: { label?: string, tags?: string[] }): Promise<StateObjectSelector<SO.Molecule.Structure> | undefined> {
  133. return this.plugin.runTask(Task.create('Query Component', async taskCtx => {
  134. let { label, tags } = params || { };
  135. label = (label || '').trim();
  136. const structureData = StateObjectRef.resolveAndCheck(this.dataState, structure)?.obj?.data;
  137. if (!structureData) return;
  138. const transformParams: StructureComponentParams = selection.referencesCurrent
  139. ? {
  140. type: {
  141. name: 'bundle',
  142. params: StructureElement.Bundle.fromSelection(await selection.getSelection(this.plugin, taskCtx, structureData)) },
  143. nullIfEmpty: true,
  144. label: label || selection.label
  145. } : {
  146. type: { name: 'expression', params: selection.expression },
  147. nullIfEmpty: true,
  148. label: label || selection.label
  149. };
  150. if (selection.ensureCustomProperties) {
  151. await selection.ensureCustomProperties({ fetch: this.plugin.fetch, runtime: taskCtx }, structureData);
  152. }
  153. return this.tryCreateComponent(structure, transformParams, key, tags);
  154. }))
  155. }
  156. constructor(public plugin: PluginContext) {
  157. }
  158. }