Bläddra i källkod

trajectory and structure preset providers

bioinsilico 2 år sedan
förälder
incheckning
2673194822

+ 14 - 51
src/RcsbFvStructure/StructureUtils/MolstarAlignmentLoader.ts

@@ -18,19 +18,29 @@ import {StateTransforms} from "molstar/lib/mol-plugin-state/transforms";
 import {PluginCommands} from "molstar/lib/mol-plugin/commands";
 import {LoadMethod, LoadMolstarInterface} from "../StructureViewers/MolstarViewer/MolstarActionManager";
 import {TagDelimiter} from "@rcsb/rcsb-saguaro-app";
+import {TrajectoryHierarchyPresetProvider} from "molstar/lib/mol-plugin-state/builder/structure/hierarchy-preset";
+import {
+    AlignmentTrajectoryPresetProvider, TrajectoryParamsType
+} from "../StructureViewers/MolstarViewer/TrajectoryPresetProvider/AlignmentTrajectoryPresetProvider";
 
-const SuperpositionTag = 'SuperpositionTransform';
-export class MolstarAlignmentLoader implements StructureLoaderInterface<[ViewerCallbackManagerInterface & ViewerActionManagerInterface <LoadMolstarInterface>,{entryId:string;entityId:string;},{entryId:string;entityId:string;}]> {
+export class MolstarAlignmentLoader implements StructureLoaderInterface<[ViewerCallbackManagerInterface & ViewerActionManagerInterface <LoadMolstarInterface<TrajectoryParamsType>>,{entryId:string;entityId:string;},{entryId:string;entityId:string;}]> {
 
     private readonly structureMap: Map<string,string|undefined> = new Map<string,string|undefined>();
 
-    async load(structureViewer: ViewerCallbackManagerInterface & ViewerActionManagerInterface <LoadMolstarInterface>, ref: {entryId:string;entityId:string;}, pdb:{entryId:string;entityId:string;}): Promise<void> {
+    async load(structureViewer: ViewerCallbackManagerInterface & ViewerActionManagerInterface <LoadMolstarInterface<TrajectoryParamsType>>, ref: {entryId:string;entityId:string;}, pdb:{entryId:string;entityId:string;}): Promise<void> {
         const structureId: string = `${pdb.entryId}${TagDelimiter.entity}${pdb.entityId}`;
         if(!this.structureMap.has(structureId)){
             await structureViewer.load({
                 loadMethod: LoadMethod.loadPdbId,
                 loadParams:{
-                    entryId:pdb.entryId
+                    entryId:pdb.entryId,
+                    reprProvider: AlignmentTrajectoryPresetProvider,
+                    params:{
+                        assemblyId: "1",
+                        modelIndex: 0,
+                        ref:ref,
+                        pdb: pdb
+                    }
                 }
             });
             structureViewer.pluginCall(async (plugin)=>{
@@ -52,53 +62,6 @@ export class MolstarAlignmentLoader implements StructureLoaderInterface<[ViewerC
             });
             return;
         }
-        if(ref.entryId != pdb.entryId)
-            structureViewer.pluginCall(async (plugin)=>{
-                const pdbId: string = `${pdb.entryId}${TagDelimiter.entity}${pdb.entityId}`;
-                const refId: string = `${ref.entryId}${TagDelimiter.entity}${ref.entityId}`;
-                const refStr: StructureRef|undefined = plugin.managers.structure.hierarchy.current.structures.find(s=>s.properties?.cell?.obj?.data?.units[0]?.model?.id == this.structureMap.get(refId));
-                const pdbStr: StructureRef|undefined = plugin.managers.structure.hierarchy.current.structures.find(s=>s.properties?.cell?.obj?.data?.units[0]?.model?.id == this.structureMap.get(pdbId));
-                if(refStr && pdbStr){
-                    const refData: Structure|undefined = refStr.properties?.cell.obj?.data;
-                    const pdbData: Structure|undefined = pdbStr.properties?.cell.obj?.data;
-                    const pdbUnit:Unit|undefined = pdbData?.units.find((u,n)=>u.model.atomicHierarchy.chains.label_entity_id.value(n) === pdb.entityId);
-                    const refUnit:Unit|undefined = refData?.units.find((u,n)=>u.model.atomicHierarchy.chains.label_entity_id.value(n) === ref.entityId);
-                    if(pdbData && pdbUnit && refData && refUnit){
-                        const refLoci: Loci = Structure.toStructureElementLoci(Structure.create([refUnit]));
-                        const pdbLoci: Loci = Structure.toStructureElementLoci(Structure.create([pdbUnit]));
-                        if(StructureElement.Loci.is(refLoci) && StructureElement.Loci.is(pdbLoci)) {
-                            const pivot = plugin.managers.structure.hierarchy.findStructure(refLoci.structure);
-                            const coordinateSystem = pivot?.transform?.cell.obj?.data.coordinateSystem;
-                            const transforms = alignAndSuperpose([refLoci, pdbLoci]);
-                            const { bTransform } = transforms[0];
-                            await this.transform(plugin, plugin.helpers.substructureParent.get(pdbData)!, bTransform, coordinateSystem);
-                            await PluginCommands.Camera.Reset(plugin);
-                        }
-                    }
-                }
-            });
-    }
-
-    private async transform(plugin:PluginContext, s: StateObjectRef<PluginStateObject.Molecule.Structure>, matrix: Mat4, coordinateSystem?: SymmetryOperator) {
-        const r = StateObjectRef.resolveAndCheck(plugin.state.data, s);
-        if (!r) return;
-        const o = plugin.state.data.selectQ(q => q.byRef(r.transform.ref).subtree().withTransformer(StateTransforms.Model.TransformStructureConformation))[0];
-
-        const transform = coordinateSystem && !Mat4.isIdentity(coordinateSystem.matrix)
-            ? Mat4.mul(Mat4(), coordinateSystem.matrix, matrix)
-            : matrix;
-
-        const params = {
-            transform: {
-                name: 'matrix' as const,
-                params: { data: transform, transpose: false }
-            }
-        };
-        const b = o
-            ? plugin.state.data.build().to(o).update(params)
-            : plugin.state.data.build().to(s)
-                .insert(StateTransforms.Model.TransformStructureConformation, params, { tags: SuperpositionTag });
-        await plugin.runTask(plugin.state.data.updateTree(b));
     }
 
 }

+ 4 - 6
src/RcsbFvStructure/StructureViewers/MolstarViewer/MolstarActionManager.ts

@@ -2,13 +2,11 @@ import {
     SaguaroChain,
     SaguaroPosition,
     SaguaroRange,
-    ViewerActionManagerInterface, ViewerCallbackManagerInterface,
+    ViewerActionManagerInterface,
     ViewerModelMapManagerInterface
 } from "../../StructureViewerInterface";
 import {Viewer} from "@rcsb/rcsb-molstar/build/src/viewer";
-import {RcsbFvSelectorManager} from "../../../RcsbFvState/RcsbFvSelectorManager";
-import {DataContainer, DataContainerReader} from "../../../Utils/DataContainer";
-import {MolstarModelMapManager} from "./MolstarModelMapManager";
+import {DataContainer} from "../../../Utils/DataContainer";
 import {Structure, StructureElement, StructureSelection} from "molstar/lib/mol-model/structure";
 import {Expression} from "molstar/lib/commonjs/mol-script/language/expression";
 import {MolScriptBuilder as MS} from "molstar/lib/mol-script/language/builder";
@@ -32,9 +30,9 @@ export enum LoadMethod {
     loadStructureFromData = "loadStructureFromData"
 }
 
-export interface LoadMolstarInterface {
+export interface LoadMolstarInterface<P=any> {
     loadMethod: LoadMethod;
-    loadParams: LoadParams | Array<LoadParams>;
+    loadParams: LoadParams<P> | Array<LoadParams<P>>;
 }
 
 interface LoadParams<P=any,S={}> {

+ 146 - 0
src/RcsbFvStructure/StructureViewers/MolstarViewer/TrajectoryPresetProvider/AlignmentRepresentationPresetProvider.ts

@@ -0,0 +1,146 @@
+/*
+* Copyright (c) 2021 RCSB PDB and contributors, licensed under MIT, See LICENSE file for more info.
+* @author Joan Segura Mora <joan.segura@rcsb.org>
+*/
+
+import {
+    StructureRepresentationPresetProvider
+} from "molstar/lib/mol-plugin-state/builder/structure/representation-preset";
+import {PluginContext} from "molstar/lib/mol-plugin/context";
+import {PluginStateObject} from "molstar/lib/mol-plugin-state/objects";
+import {StateObjectRef} from "molstar/lib/mol-state";
+import {Structure, StructureElement, StructureProperties as SP, Unit} from "molstar/lib/mol-model/structure";
+import {MolScriptBuilder as MS} from "molstar/lib/mol-script/language/builder";
+import reprBuilder = StructureRepresentationPresetProvider.reprBuilder;
+import uniqid from "uniqid";
+import {PLDDTConfidenceColorThemeProvider} from "molstar/lib/extensions/model-archive/quality-assessment/color/plddt";
+import {ColorTheme} from "molstar/lib/mol-theme/color";
+import {createSelectionExpressions} from "@rcsb/rcsb-molstar/build/src/viewer/helpers/selection";
+import {ParamDefinition as PD} from "molstar/lib/mol-util/param-definition";
+import {Loci} from "molstar/lib/mol-model/loci";
+import {alignAndSuperpose} from "molstar/lib/mol-model/structure/structure/util/superposition";
+import {Mat4} from "molstar/lib/mol-math/linear-algebra";
+import {SymmetryOperator} from "molstar/lib/mol-math/geometry/symmetry-operator";
+import {StateTransforms} from "molstar/lib/mol-plugin-state/transforms";
+
+export const AlignmentRepresentationPresetProvider = StructureRepresentationPresetProvider<{ref?:{entryId:string;entityId:string;};pdb?:{entryId:string;entityId:string;};},any>({
+        id: 'alignment-to-reference',
+        display: {
+            name: 'Alignemnt to Reference'
+        },
+        isApplicable: (structureRef: PluginStateObject.Molecule.Structure, plugin: PluginContext): boolean => true,
+        params: (structureRef: PluginStateObject.Molecule.Structure | undefined, plugin: PluginContext) => ({
+            ref: PD.Value<{entryId:string;entityId:string;}|undefined>(undefined),
+            pdb: PD.Value<{entryId:string;entityId:string;}|undefined>(undefined)
+        }),
+        apply: async (structureRef: StateObjectRef<PluginStateObject.Molecule.Structure>, params: {ref?:{entryId:string;entityId:string;};pdb?:{entryId:string;entityId:string;};}, plugin: PluginContext) => {
+            const structureCell = StateObjectRef.resolveAndCheck(plugin.state.data, structureRef);
+            if (!structureCell) return;
+            const structure = structureCell.obj!.data;
+            if(params.ref && params.pdb){
+                await structuralAlignment(plugin, params.ref, params.pdb, structure);
+            }
+            const entryId = structure.model.entryId;
+            const l = StructureElement.Location.create(structure);
+            const asymObserved: {[key:string]:boolean} = {};
+            for(const unit of structure.units) {
+                StructureElement.Location.set(l, structure, unit, unit.elements[0]);
+                const asymId = SP.chain.label_asym_id(l);
+                if(asymObserved[asymId])
+                    continue;
+                asymObserved[asymId] = true;
+                const operators = SP.unit.pdbx_struct_oper_list_ids(l);
+                const type = SP.entity.type(l);
+                if (type == "polymer") {
+                    const comp = await plugin.builders.structure.tryCreateComponentFromExpression(
+                        structureCell,
+                        MS.struct.generator.atomGroups({
+                            'chain-test': MS.core.rel.eq([MS.ammp('label_asym_id'), asymId])
+                        }),
+                        uniqid(`${entryId}_${asymId}_${operators.join(",")}`),
+                        {
+                            label: `${entryId}.${asymId}-${operators.join(",")}`
+                        }
+                    );
+                    //TODO This needs to be called after tryCreateComponentFromExpression
+                    const { update, builder } = reprBuilder(plugin, {
+                        ignoreHydrogens: true,
+                        ignoreLight: false,
+                        quality: "auto"
+                    });
+                    builder.buildRepresentation(update, comp, {
+                        color: PLDDTConfidenceColorThemeProvider.isApplicable({ structure }) ? PLDDTConfidenceColorThemeProvider.name as ColorTheme.BuiltIn : "chain-id",
+                        type: "cartoon"
+                    })
+                    await update.commit({ revertOnError: false });
+                }
+            }
+            for(const expression of createSelectionExpressions(entryId)){
+                if(expression.tag == "polymer")
+                    continue;
+                const comp = await plugin.builders.structure.tryCreateComponentFromExpression(
+                    structureCell,
+                    expression.expression,
+                    uniqid(`${entryId}_${expression.tag}`),
+                    {
+                        label: expression.label
+                    });
+                //TODO This needs to be called after tryCreateComponentFromExpression
+                const { update, builder } = reprBuilder(plugin, {
+                    ignoreHydrogens: true,
+                    ignoreLight: false,
+                    quality: "auto"
+                });
+                builder.buildRepresentation(update, comp, {
+                    type: expression.type
+                });
+                await update.commit({ revertOnError: false });
+            }
+
+        }
+    });
+
+let refData: Structure|undefined = undefined;
+async function structuralAlignment(plugin: PluginContext, ref:{entryId:string;entityId:string;}, pdb:{entryId:string;entityId:string;}, structure: Structure): Promise<void> {
+    if(ref.entryId == pdb.entryId){
+        refData = structure;
+    }else{
+        const pdbData: Structure = structure;
+        const pdbUnit:Unit|undefined = pdbData?.units.find((u,n)=>u.model.atomicHierarchy.chains.label_entity_id.value(n) === pdb.entityId);
+        const refUnit:Unit|undefined = refData?.units.find((u,n)=>u.model.atomicHierarchy.chains.label_entity_id.value(n) === ref.entityId);
+        if(pdbData && pdbUnit && refData && refUnit){
+            const refLoci: Loci = Structure.toStructureElementLoci(Structure.create([refUnit]));
+            const pdbLoci: Loci = Structure.toStructureElementLoci(Structure.create([pdbUnit]));
+            if(StructureElement.Loci.is(refLoci) && StructureElement.Loci.is(pdbLoci)) {
+                const pivot = plugin.managers.structure.hierarchy.findStructure(refLoci.structure);
+                const coordinateSystem = pivot?.transform?.cell.obj?.data.coordinateSystem;
+                const transforms = alignAndSuperpose([refLoci, pdbLoci]);
+                const { bTransform } = transforms[0];
+                await transform(plugin, plugin.helpers.substructureParent.get(pdbData)!, bTransform, coordinateSystem);
+            }
+        }
+    }
+}
+
+const SuperpositionTag = 'SuperpositionTransform';
+async function transform(plugin:PluginContext, s: StateObjectRef<PluginStateObject.Molecule.Structure>, matrix: Mat4, coordinateSystem?: SymmetryOperator): Promise<void>{
+    const r = StateObjectRef.resolveAndCheck(plugin.state.data, s);
+    if (!r) return;
+    const o = plugin.state.data.selectQ(q => q.byRef(r.transform.ref).subtree().withTransformer(StateTransforms.Model.TransformStructureConformation))[0];
+
+    const transform = coordinateSystem && !Mat4.isIdentity(coordinateSystem.matrix)
+        ? Mat4.mul(Mat4(), coordinateSystem.matrix, matrix)
+        : matrix;
+
+    const params = {
+        transform: {
+            name: 'matrix' as const,
+            params: { data: transform, transpose: false }
+        }
+    };
+    const b = o
+        ? plugin.state.data.build().to(o).update(params)
+        : plugin.state.data.build().to(s)
+            .insert(StateTransforms.Model.TransformStructureConformation, params, { tags: SuperpositionTag });
+    await plugin.runTask(plugin.state.data.updateTree(b));
+}

+ 87 - 0
src/RcsbFvStructure/StructureViewers/MolstarViewer/TrajectoryPresetProvider/AlignmentTrajectoryPresetProvider.ts

@@ -0,0 +1,87 @@
+/*
+* Copyright (c) 2021 RCSB PDB and contributors, licensed under MIT, See LICENSE file for more info.
+* @author Joan Segura Mora <joan.segura@rcsb.org>
+*/
+
+import {TrajectoryHierarchyPresetProvider} from "molstar/lib/mol-plugin-state/builder/structure/hierarchy-preset";
+import {PluginContext} from "molstar/lib/mol-plugin/context";
+import {PluginStateObject} from "molstar/lib/mol-plugin-state/objects";
+import {ParamDefinition, ParamDefinition as PD} from "molstar/lib/mol-util/param-definition";
+import {StateObjectRef, StateObjectSelector} from "molstar/lib/mol-state";
+import {RootStructureDefinition} from "molstar/lib/mol-plugin-state/helpers/root-structure";
+import {StateTransformer} from "molstar/lib/mol-state/transformer";
+import {StateObject} from "molstar/lib/mol-state/object";
+import {
+    StructureRepresentationPresetProvider
+} from "molstar/lib/mol-plugin-state/builder/structure/representation-preset";
+import {PLDDTConfidenceColorThemeProvider} from "molstar/lib/extensions/model-archive/quality-assessment/color/plddt";
+import {AlignmentRepresentationPresetProvider} from "./AlignmentRepresentationPresetProvider";
+
+export type TrajectoryParamsType = {
+    ref?: {entryId:string;entityId:string;};
+    pdb?: {entryId:string;entityId:string;};
+    assemblyId?: string;
+    modelIndex?: number;
+    plddt?: 'off' | 'single-chain' | 'on';
+}
+
+type StructureObject = StateObjectSelector<PluginStateObject.Molecule.Structure, StateTransformer<StateObject<any, StateObject.Type<any>>, StateObject<any, StateObject.Type<any>>, any>>
+
+export const AlignmentTrajectoryPresetProvider = TrajectoryHierarchyPresetProvider<TrajectoryParamsType,any>({
+    id: 'alignment-to-reference',
+    display: {
+        name: 'Alignemnt to Reference'
+    },
+    isApplicable: (trajectory: PluginStateObject.Molecule.Trajectory, plugin: PluginContext): boolean => true,
+    params: (trajectory: PluginStateObject.Molecule.Trajectory | undefined, plugin: PluginContext):ParamDefinition.For<TrajectoryParamsType> => ({
+        ref:PD.Value<{entryId:string;entityId:string;}|undefined>(undefined),
+        pdb:PD.Value<{entryId:string;entityId:string;}|undefined>(undefined),
+        assemblyId:PD.Value<string|undefined>(undefined),
+        modelIndex:PD.Value<number|undefined>(undefined),
+        plddt:PD.Value<'off' | 'single-chain' | 'on' | undefined>(undefined)
+    }),
+    apply: async (trajectory: StateObjectRef<PluginStateObject.Molecule.Trajectory>, params: TrajectoryParamsType, plugin: PluginContext) => {
+        const builder = plugin.builders.structure;
+        const modelParams = { modelIndex: params.modelIndex || 0 };
+        const structureParams: RootStructureDefinition.Params = { name: 'model', params: {} };
+        if (params.assemblyId && params.assemblyId !== '' && params.assemblyId !== '0') {
+            Object.assign(structureParams, {
+                name: 'assembly',
+                params: { id: params.assemblyId }
+            } as RootStructureDefinition.Params);
+        }
+
+        const model = await builder.createModel(trajectory, modelParams);
+        const modelProperties = await builder.insertModelProperties(model);
+
+        const unitcell: StateObjectSelector | undefined = undefined;
+        const structure = await builder.createStructure(modelProperties || model, structureParams);
+        const structureProperties = await builder.insertStructureProperties(structure);
+
+        const representation: StructureRepresentationPresetProvider.Result | undefined = await plugin.builders.structure.representation.applyPreset(
+            structureProperties,
+            AlignmentRepresentationPresetProvider,
+            {
+                ref: params.ref,
+                pdb:params.pdb
+            }
+        );
+
+        //TODO what is the purpose of this return?
+        return {
+            model,
+            modelProperties,
+            unitcell,
+            structure,
+            structureProperties,
+            representation
+        };
+    }
+});
+
+function checkPlddtColorTheme(structure: StructureObject | undefined, plddt: 'on' | 'single-chain' | 'off') {
+    if (!structure?.data) return false;
+    if (plddt === 'off') return false;
+    if (plddt === 'single-chain' && structure.data?.polymerUnitCount !== 1) return false;
+    return PLDDTConfidenceColorThemeProvider.isApplicable({ structure: structure.data });
+}