preset.ts 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. /**
  2. * Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
  3. *
  4. * @author Alexander Rose <alexander.rose@weirdbyte.de>
  5. */
  6. import { PluginContext } from 'molstar/lib/mol-plugin/context';
  7. import { MolScriptBuilder as MS } from 'molstar/lib/mol-script/language/builder';
  8. import Expression from 'molstar/lib/mol-script/language/expression';
  9. import { ParamDefinition as PD } from 'molstar/lib/mol-util/param-definition';
  10. import { TrajectoryHierarchyPresetProvider } from 'molstar/lib/mol-plugin-state/builder/structure/hierarchy-preset';
  11. import { ValidationReportGeometryQualityPreset } from 'molstar/lib/extensions/rcsb/validation-report/behavior';
  12. import { AssemblySymmetryPreset } from 'molstar/lib/extensions/rcsb/assembly-symmetry/behavior';
  13. import { PluginStateObject } from 'molstar/lib/mol-plugin-state/objects';
  14. import { RootStructureDefinition } from 'molstar/lib/mol-plugin-state/helpers/root-structure';
  15. import { StructureRepresentationPresetProvider } from 'molstar/lib/mol-plugin-state/builder/structure/representation-preset';
  16. import { Structure, StructureSelection, QueryContext, StructureElement } from 'molstar/lib/mol-model/structure';
  17. import { compile } from 'molstar/lib/mol-script/runtime/query/compiler';
  18. import { InitVolumeStreaming } from 'molstar/lib/mol-plugin/behavior/dynamic/volume-streaming/transformers';
  19. import { ViewerState } from '../types';
  20. import { StateSelection } from 'molstar/lib/mol-state';
  21. import { VolumeStreaming } from 'molstar/lib/mol-plugin/behavior/dynamic/volume-streaming/behavior';
  22. import { Mat4 } from 'molstar/lib/mol-math/linear-algebra';
  23. import { StructureSelectionFromExpression, TransformStructureConformation } from 'molstar/lib/mol-plugin-state/transforms/model';
  24. type Target = {
  25. readonly auth_seq_id?: number
  26. readonly label_seq_id?: number
  27. readonly label_comp_id?: string
  28. readonly label_asym_id?: string
  29. }
  30. function targetToExpression(target: Target): Expression {
  31. const residueTests: Expression[] = []
  32. const tests = Object.create(null)
  33. if (target.auth_seq_id) {
  34. residueTests.push(MS.core.rel.eq([target.auth_seq_id, MS.ammp('auth_seq_id')]))
  35. } else if (target.label_seq_id) {
  36. residueTests.push(MS.core.rel.eq([target.label_seq_id, MS.ammp('label_seq_id')]))
  37. }
  38. if (target.label_comp_id) {
  39. residueTests.push(MS.core.rel.eq([target.label_comp_id, MS.ammp('label_comp_id')]))
  40. }
  41. if (residueTests.length === 1) {
  42. tests['residue-test'] = residueTests[0]
  43. } else if (residueTests.length > 1) {
  44. tests['residue-test'] = MS.core.logic.and(residueTests)
  45. }
  46. if (target.label_asym_id) {
  47. tests['chain-test'] = MS.core.rel.eq([target.label_asym_id, MS.ammp('label_asym_id')])
  48. }
  49. if (Object.keys(tests).length > 0) {
  50. return MS.struct.modifier.union([
  51. MS.struct.generator.atomGroups(tests)
  52. ])
  53. } else {
  54. return MS.struct.generator.empty
  55. }
  56. }
  57. function targetToLoci(target: Target, structure: Structure): StructureElement.Loci {
  58. const expression = targetToExpression(target)
  59. const query = compile<StructureSelection>(expression)
  60. const selection = query(new QueryContext(structure));
  61. return StructureSelection.toLociWithSourceUnits(selection)
  62. }
  63. type BaseProps = {
  64. assemblyId?: string
  65. modelIndex?: number
  66. }
  67. type SubsetProps = {
  68. kind: 'subset'
  69. blocks: {
  70. asymId: string
  71. matrix: Mat4
  72. seqIdRange?: {
  73. beg: number
  74. end: number
  75. },
  76. color?: number
  77. }[]
  78. } & BaseProps
  79. type ValidationProps = {
  80. kind: 'validation'
  81. colorTheme?: string
  82. showClashes?: boolean
  83. } & BaseProps
  84. type StandardProps = {
  85. kind: 'standard'
  86. } & BaseProps
  87. type SymmetryProps = {
  88. kind: 'symmetry'
  89. symmetryIndex?: number
  90. } & BaseProps
  91. type FeatureProps = {
  92. kind: 'feature'
  93. target: Target
  94. } & BaseProps
  95. type DensityProps = {
  96. kind: 'density'
  97. } & BaseProps
  98. export type PresetProps = ValidationProps | StandardProps | SymmetryProps | FeatureProps | DensityProps | SubsetProps
  99. const RcsbParams = (a: PluginStateObject.Molecule.Trajectory | undefined, plugin: PluginContext) => ({
  100. preset: PD.Value<PresetProps>({ kind: 'standard', assemblyId: '' }, { isHidden: true })
  101. });
  102. export const RcsbPreset = TrajectoryHierarchyPresetProvider({
  103. id: 'preset-trajectory-rcsb',
  104. display: { name: 'RCSB' },
  105. isApplicable: o => {
  106. return true
  107. },
  108. params: RcsbParams,
  109. async apply(trajectory, params, plugin) {
  110. const builder = plugin.builders.structure;
  111. const p = params.preset
  112. const modelParams = { modelIndex: p.modelIndex || 0 }
  113. const structureParams: RootStructureDefinition.Params = { name: 'model', params: {} }
  114. if (p.assemblyId && p.assemblyId !== '' && p.assemblyId !== '0') {
  115. Object.assign(structureParams, {
  116. name: 'assembly',
  117. params: { id: p.assemblyId }
  118. } as RootStructureDefinition.Params)
  119. }
  120. const model = await builder.createModel(trajectory, modelParams);
  121. const modelProperties = await builder.insertModelProperties(model);
  122. const structure = await builder.createStructure(modelProperties || model, structureParams);
  123. const structureProperties = await builder.insertStructureProperties(structure);
  124. const unitcell = await builder.tryCreateUnitcell(modelProperties, undefined, { isHidden: true });
  125. let representation: StructureRepresentationPresetProvider.Result | undefined = undefined
  126. if (p.kind === 'subset') {
  127. const selections = new Array();
  128. const representations = new Array();
  129. p.blocks.forEach( async block => {
  130. structureProperties.data!.inheritedPropertyData.subset = {
  131. beg: block.seqIdRange!.beg,
  132. end: block.seqIdRange!.end,
  133. color: block!.color
  134. }
  135. const _sele = plugin.state.data.build().to(structureProperties).apply(StructureSelectionFromExpression, {
  136. expression: MS.struct.generator.atomGroups({
  137. 'chain-test': MS.core.rel.eq([MS.ammp('label_asym_id'), block.asymId]),
  138. }),
  139. label: `Chain ${block.asymId}`
  140. }).apply(TransformStructureConformation, {
  141. transform: { name: 'matrix', params: { data: block.matrix, transpose: false } }
  142. });
  143. const sele = await _sele.commit();
  144. selections.push(sele);
  145. const repr = await plugin.builders.structure.representation.applyPreset(sele, 'polymer-cartoon', {
  146. theme: { globalName: 'superpose' }
  147. });
  148. representations.push(repr);
  149. });
  150. } else if (p.kind === 'validation') {
  151. representation = await plugin.builders.structure.representation.applyPreset(structureProperties, ValidationReportGeometryQualityPreset);
  152. } else if (p.kind === 'symmetry') {
  153. representation = await plugin.builders.structure.representation.applyPreset<any>(structureProperties, AssemblySymmetryPreset, { symmetryIndex: p.symmetryIndex });
  154. ViewerState(plugin).collapsed.next({
  155. ...ViewerState(plugin).collapsed.value,
  156. custom: false
  157. })
  158. } else {
  159. representation = await plugin.builders.structure.representation.applyPreset(structureProperties, 'auto');
  160. }
  161. if (p.kind === 'feature' && structure.obj) {
  162. const loci = targetToLoci(p.target, structure.obj.data)
  163. const firstResidue = StructureElement.Loci.firstResidue(loci)
  164. plugin.managers.structure.focus.setFromLoci(firstResidue)
  165. plugin.managers.camera.focusLoci(firstResidue)
  166. }
  167. if (p.kind === 'density' && structure.cell?.parent) {
  168. const volumeRoot = StateSelection.findTagInSubtree(structure.cell.parent.tree, structure.cell.transform.ref, VolumeStreaming.RootTag);
  169. if (!volumeRoot) {
  170. const params = PD.getDefaultValues(InitVolumeStreaming.definition.params!(structure.obj!, plugin))
  171. await plugin.runTask(plugin.state.data.applyAction(InitVolumeStreaming, params, structure.ref))
  172. }
  173. ViewerState(plugin).collapsed.next({
  174. ...ViewerState(plugin).collapsed.value,
  175. volume: false
  176. })
  177. }
  178. return {
  179. model,
  180. modelProperties,
  181. unitcell,
  182. structure,
  183. structureProperties,
  184. representation
  185. };
  186. }
  187. });