superposition.ts 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. /**
  2. * Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
  3. *
  4. * @author David Sehnal <david.sehnal@gmail.com>
  5. */
  6. import { Mat4 } from '../../mol-math/linear-algebra';
  7. import { QueryContext, StructureSelection } from '../../mol-model/structure';
  8. import { superposeStructures } from '../../mol-model/structure/structure/util/superposition';
  9. import { PluginStateObject as PSO } from '../../mol-plugin-state/objects';
  10. import { PluginContext } from '../../mol-plugin/context';
  11. import { MolScriptBuilder as MS } from '../../mol-script/language/builder';
  12. import Expression from '../../mol-script/language/expression';
  13. import { compile } from '../../mol-script/runtime/query/compiler';
  14. import { StateObjectRef } from '../../mol-state';
  15. import { BuiltInTrajectoryFormat } from '../../mol-plugin-state/formats/trajectory';
  16. import { StateTransforms } from '../../mol-plugin-state/transforms';
  17. export type SuperpositionTestInput = {
  18. pdbId: string,
  19. auth_asym_id: string,
  20. matrix: Mat4
  21. }[];
  22. export function buildStaticSuperposition(plugin: PluginContext, src: SuperpositionTestInput) {
  23. return plugin.dataTransaction(async () => {
  24. for (const s of src) {
  25. const { structure } = await loadStructure(plugin, `https://www.ebi.ac.uk/pdbe/static/entry/${s.pdbId}_updated.cif`, 'mmcif');
  26. await transform(plugin, structure, s.matrix);
  27. const chain = await plugin.builders.structure.tryCreateComponentFromExpression(structure, chainSelection(s.auth_asym_id), `Chain ${s.auth_asym_id}`);
  28. if (chain) await plugin.builders.structure.representation.addRepresentation(chain, { type: 'cartoon' });
  29. }
  30. })
  31. }
  32. export const StaticSuperpositionTestData: SuperpositionTestInput = [
  33. {
  34. pdbId: '1aj5', auth_asym_id: 'A', matrix: Mat4.identity()
  35. },
  36. {
  37. pdbId: '1df0', auth_asym_id: 'B', matrix: Mat4.ofRows([
  38. [0.406, 0.879, 0.248, -200.633],
  39. [0.693, -0.473, 0.544, 73.403],
  40. [0.596, -0.049, -0.802, -14.209],
  41. [0, 0, 0, 1]])
  42. },
  43. {
  44. pdbId: '1dvi', auth_asym_id: 'A', matrix: Mat4.ofRows([
  45. [-0.053, -0.077, 0.996, -45.633],
  46. [-0.312, 0.949, 0.057, -12.255],
  47. [-0.949, -0.307, -0.074, 53.562],
  48. [0, 0, 0, 1]])
  49. }
  50. ];
  51. export function dynamicSuperpositionTest(plugin: PluginContext, src: string[], comp_id: string) {
  52. return plugin.dataTransaction(async () => {
  53. for (const s of src) {
  54. await loadStructure(plugin, `https://www.ebi.ac.uk/pdbe/static/entry/${s}_updated.cif`, 'mmcif');
  55. }
  56. const pivot = MS.struct.filter.first([
  57. MS.struct.generator.atomGroups({
  58. 'residue-test': MS.core.rel.eq([MS.struct.atomProperty.macromolecular.label_comp_id(), comp_id]),
  59. 'group-by': MS.struct.atomProperty.macromolecular.residueKey()
  60. })
  61. ]);
  62. const rest = MS.struct.modifier.exceptBy({
  63. 0: MS.struct.modifier.includeSurroundings({
  64. 0: pivot,
  65. radius: 5
  66. }),
  67. by: pivot
  68. });
  69. const query = compile<StructureSelection>(pivot);
  70. const xs = plugin.managers.structure.hierarchy.current.structures;
  71. const selections = xs.map(s => StructureSelection.toLociWithCurrentUnits(query(new QueryContext(s.cell.obj!.data))));
  72. const transforms = superposeStructures(selections);
  73. await siteVisual(plugin, xs[0].cell, pivot, rest);
  74. for (let i = 1; i < selections.length; i++) {
  75. await transform(plugin, xs[i].cell, transforms[i - 1].bTransform);
  76. await siteVisual(plugin, xs[i].cell, pivot, rest);
  77. }
  78. });
  79. }
  80. async function siteVisual(plugin: PluginContext, s: StateObjectRef<PSO.Molecule.Structure>, pivot: Expression, rest: Expression) {
  81. const center = await plugin.builders.structure.tryCreateComponentFromExpression(s, pivot, 'pivot');
  82. if (center) await plugin.builders.structure.representation.addRepresentation(center, { type: 'ball-and-stick', color: 'residue-name' });
  83. const surr = await plugin.builders.structure.tryCreateComponentFromExpression(s, rest, 'rest');
  84. if (surr) await plugin.builders.structure.representation.addRepresentation(surr, { type: 'ball-and-stick', color: 'uniform', size: 'uniform', sizeParams: { value: 0.33 } });
  85. }
  86. async function loadStructure(plugin: PluginContext, url: string, format: BuiltInTrajectoryFormat, assemblyId?: string) {
  87. const data = await plugin.builders.data.download({ url });
  88. const trajectory = await plugin.builders.structure.parseTrajectory(data, format);
  89. const model = await plugin.builders.structure.createModel(trajectory);
  90. const structure = await plugin.builders.structure.createStructure(model, assemblyId ? { name: 'assembly', params: { id: assemblyId } } : void 0);
  91. return { data, trajectory, model, structure };
  92. }
  93. function chainSelection(auth_asym_id: string) {
  94. return MS.struct.generator.atomGroups({
  95. 'chain-test': MS.core.rel.eq([MS.struct.atomProperty.macromolecular.auth_asym_id(), auth_asym_id])
  96. });
  97. }
  98. function transform(plugin: PluginContext, s: StateObjectRef<PSO.Molecule.Structure>, matrix: Mat4) {
  99. const b = plugin.state.data.build().to(s)
  100. .insert(StateTransforms.Model.TransformStructureConformation, { transform: { name: 'matrix', params: matrix } });
  101. return plugin.runTask(plugin.state.data.updateTree(b));
  102. }