diff --git a/src/apps/basic-wrapper/helpers.ts b/src/apps/basic-wrapper/helpers.ts index bbe9e92ab86c2a9f414a2a3f1f095c53a7a132cd..342325ee87e6abca504e1e7be3e018d1acc0f9a7 100644 --- a/src/apps/basic-wrapper/helpers.ts +++ b/src/apps/basic-wrapper/helpers.ts @@ -11,6 +11,8 @@ import { StateTransforms } from 'mol-plugin/state/transforms'; import { StructureRepresentation3DHelpers } from 'mol-plugin/state/transforms/representation'; import { MolScriptBuilder as MS } from 'mol-script/language/builder'; import { StateBuilder } from 'mol-state'; +import Expression from 'mol-script/language/expression'; +import { BuiltInColorThemeName } from 'mol-theme/color'; type SupportedFormats = 'cif' | 'pdb' export namespace StateHelper { @@ -27,7 +29,7 @@ export namespace StateHelper { } export function structure(b: StateBuilder.To<PSO.Molecule.Model>) { - return b.apply(StateTransforms.Model.StructureFromModel, { tags: 'struct' }) + return b.apply(StateTransforms.Model.StructureFromModel, { tags: 'structure' }) }; export function selectChain(b: StateBuilder.To<PSO.Molecule.Structure>, auth_asym_id: string) { @@ -37,6 +39,23 @@ export namespace StateHelper { return b.apply(StateTransforms.Model.StructureSelection, { query, label: `Chain ${auth_asym_id}` }); } + export function select(b: StateBuilder.To<PSO.Molecule.Structure>, query: Expression) { + return b.apply(StateTransforms.Model.StructureSelection, { query }); + } + + export function selectSurroundingsOfFirstResidue(b: StateBuilder.To<PSO.Molecule.Structure>, comp_id: string, radius: number) { + const query = MS.struct.modifier.includeSurroundings({ + 0: MS.struct.filter.first([ + MS.struct.generator.atomGroups({ + 'residue-test': MS.core.rel.eq([MS.struct.atomProperty.macromolecular.label_comp_id(), comp_id]), + 'group-by': MS.struct.atomProperty.macromolecular.residueKey() + }) + ]), + radius + }) + return b.apply(StateTransforms.Model.StructureSelection, { query, label: `Surr. ${comp_id} (${radius} ang)` }); + } + export function identityTransform(b: StateBuilder.To<PSO.Molecule.Structure>, m: Mat4) { return b.apply(StateTransforms.Model.TransformStructureConformation, { axis: Vec3.create(1, 0, 0), angle: 0, translation: Vec3.zero() }, @@ -64,4 +83,12 @@ export namespace StateHelper { return visualRoot; } + export function ballsAndSticks(ctx: PluginContext, visualRoot: StateBuilder.To<PSO.Molecule.Structure>, query: Expression, coloring?: BuiltInColorThemeName) { + visualRoot + .apply(StateTransforms.Model.StructureSelection, { query }) + .apply(StateTransforms.Representation.StructureRepresentation3D, + StructureRepresentation3DHelpers.getDefaultParamsStatic(ctx, 'ball-and-stick', void 0, coloring), { tags: 'het-visual' }); + return visualRoot; + } + } \ No newline at end of file diff --git a/src/apps/basic-wrapper/index.html b/src/apps/basic-wrapper/index.html index 1d68db266336484ba6557079d46d5da0066504c2..6c9f2d9d571045339824a9f9cd10a8d2a207ab39 100644 --- a/src/apps/basic-wrapper/index.html +++ b/src/apps/basic-wrapper/index.html @@ -107,7 +107,8 @@ addHeader('Tests'); - addControl('Static Super', () => BasicMolStarWrapper.tests.staticSuperposition()); + addControl('Static Superposition', () => BasicMolStarWrapper.tests.staticSuperposition()); + addControl('Dynamic Superposition', () => BasicMolStarWrapper.tests.dynamicSuperposition()); //////////////////////////////////////////////////////// diff --git a/src/apps/basic-wrapper/index.ts b/src/apps/basic-wrapper/index.ts index fb4392f3d17dd6c057fb1acaa5873a4cb8b20bf2..3520372ac8610ce0941c8138accb15731126e4c6 100644 --- a/src/apps/basic-wrapper/index.ts +++ b/src/apps/basic-wrapper/index.ts @@ -13,10 +13,10 @@ import { StructureRepresentation3DHelpers } from 'mol-plugin/state/transforms/re import { Color } from 'mol-util/color'; import { PluginStateObject as PSO } from 'mol-plugin/state/objects'; import { AnimateModelIndex } from 'mol-plugin/state/animation/built-in'; -import { StateBuilder } from 'mol-state'; +import { StateBuilder, StateTransform } from 'mol-state'; import { StripedResidues } from './coloring'; // import { BasicWrapperControls } from './controls'; -import { StaticSuperpositionTestData, buildStaticSuperposition } from './superposition'; +import { StaticSuperpositionTestData, buildStaticSuperposition, dynamicSuperpositionTest } from './superposition'; require('mol-plugin/skin/light.scss') type SupportedFormats = 'cif' | 'pdb' @@ -146,7 +146,12 @@ class BasicWrapper { staticSuperposition: async () => { const state = this.plugin.state.dataState; const tree = buildStaticSuperposition(this.plugin, StaticSuperpositionTestData); + await PluginCommands.State.RemoveObject.dispatch(this.plugin, { state, ref: StateTransform.RootRef }); await PluginCommands.State.Update.dispatch(this.plugin, { state, tree }); + }, + dynamicSuperposition: async () => { + await PluginCommands.State.RemoveObject.dispatch(this.plugin, { state: this.plugin.state.dataState, ref: StateTransform.RootRef }); + await dynamicSuperpositionTest(this.plugin, ['1tqn', '2hhb', '4hhb'], 'HEM'); } } } diff --git a/src/apps/basic-wrapper/superposition.ts b/src/apps/basic-wrapper/superposition.ts index 1961aab48cc207d7f12eb74ced534011e8037050..c2b190603746e2c6df06641baa2dfcceeee8f6d1 100644 --- a/src/apps/basic-wrapper/superposition.ts +++ b/src/apps/basic-wrapper/superposition.ts @@ -9,6 +9,14 @@ import { PluginContext } from 'mol-plugin/context'; import { Mat4 } from 'mol-math/linear-algebra'; import { StateHelper } from './helpers'; +import { PluginCommands } from 'mol-plugin/command'; +import { StateSelection, StateBuilder } from 'mol-state'; +import { PluginStateObject as PSO } from 'mol-plugin/state/objects'; +import { MolScriptBuilder as MS } from 'mol-script/language/builder'; +import { compile } from 'mol-script/runtime/query/compiler'; +import { StructureSelection, QueryContext } from 'mol-model/structure'; +import { superposeStructures } from 'mol-model/structure/structure/util/superposition'; +import Expression from 'mol-script/language/expression'; export type SuperpositionTestInput = { pdbId: string, @@ -52,4 +60,49 @@ export const StaticSuperpositionTestData: SuperpositionTestInput = [ [-0.312, 0.949, 0.057, -12.255], [-0.949, -0.307, -0.074, 53.562], [0, 0, 0, 1]] )} -]; \ No newline at end of file +]; + +export async function dynamicSuperpositionTest(ctx: PluginContext, src: string[], comp_id: string) { + const state = ctx.state.dataState; + + const structures = state.build().toRoot(); + for (const s of src) { + StateHelper.structure( + StateHelper.getModel(StateHelper.download(structures, `https://www.ebi.ac.uk/pdbe/static/entry/${s}_updated.cif`), 'cif')); + } + + await PluginCommands.State.Update.dispatch(ctx, { state, tree: structures }); + + const pivot = MS.struct.filter.first([ + MS.struct.generator.atomGroups({ + 'residue-test': MS.core.rel.eq([MS.struct.atomProperty.macromolecular.label_comp_id(), comp_id]), + 'group-by': MS.struct.atomProperty.macromolecular.residueKey() + }) + ]); + const rest = MS.struct.modifier.exceptBy({ + 0: MS.struct.generator.all(), + by: pivot + }); + + const query = compile<StructureSelection>(pivot); + const xs = state.select(StateSelection.Generators.rootsOfType(PSO.Molecule.Structure)); + const selections = xs.map(s => StructureSelection.toLoci(query(new QueryContext(s.obj!.data)))); + + const transforms = superposeStructures(selections); + const visuals = state.build(); + + siteVisual(ctx, StateHelper.selectSurroundingsOfFirstResidue(visuals.to(xs[0].transform.ref), 'HEM', 7), pivot, rest); + for (let i = 1; i < selections.length; i++) { + const root = visuals.to(xs[i].transform.ref); + siteVisual(ctx, + StateHelper.transform(StateHelper.selectSurroundingsOfFirstResidue(root, 'HEM', 7), transforms[i - 1].bTransform), + pivot, rest); + } + + await PluginCommands.State.Update.dispatch(ctx, { state, tree: visuals }); +} + +function siteVisual(ctx: PluginContext, b: StateBuilder.To<PSO.Molecule.Structure>, pivot: Expression, rest: Expression) { + StateHelper.ballsAndSticks(ctx, b, pivot, 'residue-name'); + StateHelper.ballsAndSticks(ctx, b, rest, 'uniform'); +} \ No newline at end of file diff --git a/src/mol-math/linear-algebra/3d.ts b/src/mol-math/linear-algebra/3d.ts index 88ba25f812d6d3576d81667afe0f706db77567c5..3a98d5ba703c65c011b471624d8669c8fb87c695 100644 --- a/src/mol-math/linear-algebra/3d.ts +++ b/src/mol-math/linear-algebra/3d.ts @@ -23,7 +23,6 @@ import Vec2 from './3d/vec2' import Vec3 from './3d/vec3' import Vec4 from './3d/vec4' import Quat from './3d/quat' -import MinimizeRmsd from './3d/minimize-rmsd' import { EPSILON } from './3d/common' -export { Mat4, Mat3, Vec2, Vec3, Vec4, Quat, EPSILON, MinimizeRmsd } \ No newline at end of file +export { Mat4, Mat3, Vec2, Vec3, Vec4, Quat, EPSILON } \ No newline at end of file diff --git a/src/mol-math/linear-algebra/3d/minimize-rmsd.ts b/src/mol-math/linear-algebra/3d/minimize-rmsd.ts index 1296e10f3aa316031ac5a048b26c702b9269ebe8..b757b2e7afa5394716cd76548d5490e2b9ee5d0b 100644 --- a/src/mol-math/linear-algebra/3d/minimize-rmsd.ts +++ b/src/mol-math/linear-algebra/3d/minimize-rmsd.ts @@ -10,8 +10,7 @@ import { EVD } from '../matrix/evd'; import { CentroidHelper } from 'mol-math/geometry/centroid-helper'; import Matrix from '../matrix/matrix'; -export default MinimizeRmsd; - +export { MinimizeRmsd }; namespace MinimizeRmsd { export interface Result { bTransform: Mat4, diff --git a/src/mol-model/structure/structure/util/superposition.ts b/src/mol-model/structure/structure/util/superposition.ts index 8c41ba996510e03eadbbf815c56715787fd41718..bcd72625890736cc51ee102d8759f0c84e7069d3 100644 --- a/src/mol-model/structure/structure/util/superposition.ts +++ b/src/mol-model/structure/structure/util/superposition.ts @@ -4,7 +4,7 @@ * @author David Sehnal <david.sehnal@gmail.com> */ -import { MinimizeRmsd } from 'mol-math/linear-algebra'; +import { MinimizeRmsd } from 'mol-math/linear-algebra/3d/minimize-rmsd'; import StructureElement from '../element'; import { OrderedSet } from 'mol-data/int'; diff --git a/src/mol-state/state/selection.ts b/src/mol-state/state/selection.ts index 2a47745f5c84e51b9ec4116a91a10b88e6033461..097d73b70a9af5b95f72137bd9be10356360044c 100644 --- a/src/mol-state/state/selection.ts +++ b/src/mol-state/state/selection.ts @@ -49,7 +49,7 @@ namespace StateSelection { parent(): Builder<C>; first(): Builder<C>; filter(p: (n: C) => boolean): Builder<C>; - withTag(tag: string): Builder<C>; + withTag<D extends StateObjectCell = C>(tag: string): Builder<D>; withTransformer<T extends StateTransformer<any, StateObjectCell.Obj<C>, any>>(t: T): Builder<StateObjectCell<StateObjectCell.Obj<C>, StateTransform<T>>>; withStatus(s: StateObjectCell.Status): Builder<C>; subtree(): Builder;