basic.ts 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  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 { StateAction } from 'mol-state/action';
  7. import { PluginStateObject } from '../objects';
  8. import { StateTransforms } from '../transforms';
  9. import { ParamDefinition as PD } from 'mol-util/param-definition';
  10. import { StateSelection } from 'mol-state/state/selection';
  11. import { CartoonParams } from 'mol-repr/structure/representation/cartoon';
  12. import { BallAndStickParams } from 'mol-repr/structure/representation/ball-and-stick';
  13. import { Download } from '../transforms/data';
  14. import { StateTree, Transformer } from 'mol-state';
  15. import { StateTreeBuilder } from 'mol-state/tree/builder';
  16. import { PolymerIdColorThemeParams } from 'mol-theme/color/polymer-id';
  17. import { UniformSizeThemeParams } from 'mol-theme/size/uniform';
  18. import { ElementSymbolColorThemeParams } from 'mol-theme/color/element-symbol';
  19. // TODO: "structure parser provider"
  20. export { DownloadStructure }
  21. namespace DownloadStructure {
  22. export type Source = PD.NamedParamUnion<ObtainStructureHelpers.ControlMap>
  23. export interface Params {
  24. source: Source
  25. }
  26. }
  27. namespace ObtainStructureHelpers {
  28. export const ControlMap = {
  29. 'pdbe-updated': PD.Text('1cbs', { label: 'Id' }),
  30. 'rcsb': PD.Text('1tqn', { label: 'Id' }),
  31. 'bcif-static': PD.Text('1tqn', { label: 'Id' }),
  32. 'url': PD.Group({ url: PD.Text(''), isBinary: PD.Boolean(false) }, { isExpanded: true })
  33. }
  34. export type ControlMap = typeof ControlMap
  35. export const SourceOptions: [keyof ControlMap, string][] = [
  36. ['pdbe-updated', 'PDBe Updated'],
  37. ['rcsb', 'RCSB'],
  38. ['bcif-static', 'BinaryCIF (static PDBe Updated)'],
  39. ['url', 'URL']
  40. ];
  41. export function getControls(key: string) { return (ControlMap as any)[key]; }
  42. export function getUrl(src: DownloadStructure.Source): Transformer.Params<Download> {
  43. switch (src.name) {
  44. case 'url': return src.params;
  45. case 'pdbe-updated': return { url: `https://www.ebi.ac.uk/pdbe/static/entry/${src.params.toLowerCase()}_updated.cif`, isBinary: false, label: `PDBe: ${src.params}` };
  46. case 'rcsb': return { url: `https://files.rcsb.org/download/${src.params.toUpperCase()}.cif`, isBinary: false, label: `RCSB: ${src.params}` };
  47. case 'bcif-static': return { url: `https://webchem.ncbr.muni.cz/ModelServer/static/bcif/${src.params.toLowerCase()}`, isBinary: true, label: `BinaryCIF: ${src.params}` };
  48. default: throw new Error(`${(src as any).name} not supported.`);
  49. }
  50. }
  51. }
  52. const DownloadStructure = StateAction.create<PluginStateObject.Root, void, DownloadStructure.Params>({
  53. from: [PluginStateObject.Root],
  54. display: {
  55. name: 'Download Structure',
  56. description: 'Load a structure from PDBe and create its default Assembly and visual'
  57. },
  58. params: () => ({ source: PD.Mapped('bcif-static', ObtainStructureHelpers.SourceOptions, ObtainStructureHelpers.getControls) }),
  59. apply({ params, state }) {
  60. const b = state.build();
  61. // const query = MolScriptBuilder.struct.generator.atomGroups({
  62. // // 'atom-test': MolScriptBuilder.core.rel.eq([
  63. // // MolScriptBuilder.struct.atomProperty.macromolecular.label_comp_id(),
  64. // // MolScriptBuilder.es('C')
  65. // // ]),
  66. // 'residue-test': MolScriptBuilder.core.rel.eq([
  67. // MolScriptBuilder.struct.atomProperty.macromolecular.label_comp_id(),
  68. // 'ALA'
  69. // ])
  70. // });
  71. const url = ObtainStructureHelpers.getUrl(params.source);
  72. const data = b.toRoot().apply(StateTransforms.Data.Download, url);
  73. return state.update(createStructureTree(data));
  74. }
  75. });
  76. export const OpenStructure = StateAction.build({
  77. from: PluginStateObject.Root,
  78. params: { file: PD.File({ accept: '.cif,.bcif' }) }
  79. })({
  80. display: {
  81. name: 'Open Structure',
  82. description: 'Load a structure from file and create its default Assembly and visual'
  83. },
  84. apply({ params, state }) {
  85. const b = state.build();
  86. const data = b.toRoot().apply(StateTransforms.Data.ReadFile, { file: params.file, isBinary: /\.bcif$/i.test(params.file.name) });
  87. return state.update(createStructureTree(data));
  88. }
  89. });
  90. function createStructureTree(b: StateTreeBuilder.To<PluginStateObject.Data.Binary | PluginStateObject.Data.String>): StateTree {
  91. const root = b
  92. .apply(StateTransforms.Data.ParseCif)
  93. .apply(StateTransforms.Model.TrajectoryFromMmCif, {})
  94. .apply(StateTransforms.Model.ModelFromTrajectory, { modelIndex: 0 })
  95. .apply(StateTransforms.Model.StructureAssemblyFromModel);
  96. complexRepresentation(root);
  97. return root.getTree();
  98. }
  99. function complexRepresentation(root: StateTreeBuilder.To<PluginStateObject.Molecule.Structure>) {
  100. root.apply(StateTransforms.Model.StructureComplexElement, { type: 'atomic-sequence' })
  101. .apply(StateTransforms.Representation.StructureRepresentation3D, {
  102. type: { name: 'cartoon', params: PD.getDefaultValues(CartoonParams) },
  103. colorTheme: { name: 'polymer-id', params: PD.getDefaultValues(PolymerIdColorThemeParams) },
  104. sizeTheme: { name: 'uniform', params: PD.getDefaultValues(UniformSizeThemeParams) },
  105. });
  106. root.apply(StateTransforms.Model.StructureComplexElement, { type: 'atomic-het' })
  107. .apply(StateTransforms.Representation.StructureRepresentation3D, {
  108. type: { name: 'ball-and-stick', params: PD.getDefaultValues(BallAndStickParams) },
  109. colorTheme: { name: 'element-symbol', params: PD.getDefaultValues(ElementSymbolColorThemeParams) },
  110. sizeTheme: { name: 'uniform', params: PD.getDefaultValues(UniformSizeThemeParams) },
  111. });
  112. root.apply(StateTransforms.Model.StructureComplexElement, { type: 'water' })
  113. .apply(StateTransforms.Representation.StructureRepresentation3D, {
  114. type: { name: 'ball-and-stick', params: { ...PD.getDefaultValues(BallAndStickParams), alpha: 0.51 } },
  115. colorTheme: { name: 'element-symbol', params: PD.getDefaultValues(ElementSymbolColorThemeParams) },
  116. sizeTheme: { name: 'uniform', params: PD.getDefaultValues(UniformSizeThemeParams) },
  117. })
  118. root.apply(StateTransforms.Model.StructureComplexElement, { type: 'spheres' });
  119. // TODO: create spheres visual
  120. }
  121. export const CreateComplexRepresentation = StateAction.build({
  122. from: PluginStateObject.Molecule.Structure
  123. })({
  124. display: {
  125. name: 'Create Complex',
  126. description: 'Split the structure into Sequence/Water/Ligands/... '
  127. },
  128. apply({ ref, state }) {
  129. const root = state.build().to(ref);
  130. complexRepresentation(root);
  131. return state.update(root.getTree());
  132. }
  133. });
  134. export const UpdateTrajectory = StateAction.build({
  135. params: () => ({
  136. action: PD.Select<'advance' | 'reset'>('advance', [['advance', 'Advance'], ['reset', 'Reset']]),
  137. by: PD.makeOptional(PD.Numeric(1, { min: -1, max: 1, step: 1 }))
  138. })
  139. })({
  140. display: {
  141. name: 'Update Trajectory'
  142. },
  143. apply({ params, state }) {
  144. const models = state.select(q => q.rootsOfType(PluginStateObject.Molecule.Model)
  145. .filter(c => c.transform.transformer === StateTransforms.Model.ModelFromTrajectory));
  146. const update = state.build();
  147. if (params.action === 'reset') {
  148. for (const m of models) {
  149. update.to(m.transform.ref).update(StateTransforms.Model.ModelFromTrajectory,
  150. () => ({ modelIndex: 0 }));
  151. }
  152. } else {
  153. for (const m of models) {
  154. const parent = StateSelection.findAncestorOfType(state.tree, state.cells, m.transform.ref, [PluginStateObject.Molecule.Trajectory]);
  155. if (!parent || !parent.obj) continue;
  156. const traj = parent.obj as PluginStateObject.Molecule.Trajectory;
  157. update.to(m.transform.ref).update(StateTransforms.Model.ModelFromTrajectory,
  158. old => {
  159. let modelIndex = (old.modelIndex + params.by!) % traj.data.length;
  160. if (modelIndex < 0) modelIndex += traj.data.length;
  161. return { modelIndex };
  162. });
  163. }
  164. }
  165. return state.update(update);
  166. }
  167. });