Quellcode durchsuchen

Issue #805: introduced TmDetRcsbPreset

cycle20 vor 1 Jahr
Ursprung
Commit
fabd7026c2

+ 3 - 10
src/examples/assembly-tm/FeatureViewConfig.ts

@@ -24,10 +24,9 @@ import {
 import {
 } from "../../RcsbFvStructure/StructureViewers/MolstarViewer/MolstarActionManager";
 import {ViewerProps} from "@rcsb/rcsb-molstar/build/src/viewer";
-import { RcsbPreset } from "@rcsb/rcsb-molstar/build/src/viewer/helpers/preset";
 import { updateSiteColors } from "./UniTmpColor";
 import { fetchHtpDescriptor, fetchPdbtmJsvLibDescriptor, htpDescriptorToTrackData, jsvLibDescriptorToTrackData } from "./UniTmpHelper";
-
+import { TmDetRcsbPreset } from "./preset";
 
 export async function createFeatureViewerConfing(params: { pdbEntry: string, pdbtmEntry: string, htpEntry: string, labelAsymId: string, side1: string }) {
     const modelId = `${params.pdbEntry}_model`;
@@ -84,12 +83,6 @@ export async function createFeatureViewerConfing(params: { pdbEntry: string, pdb
                 plugin.clearSelection("hover");
             else {
                 const e = elements[0];
-                console.log({
-                        modelId: modelId,
-                        labelAsymId: params.labelAsymId,
-                        begin: e.begin,
-                        end: e.end ?? e.begin
-                });
                 plugin.select(elements.map(e=>({
                     modelId: modelId,
                     labelAsymId: params.labelAsymId,
@@ -135,12 +128,12 @@ export async function createFeatureViewerConfing(params: { pdbEntry: string, pdb
         loadConfig: {
             loadMethod: LoadMethod.loadStructureFromUrl,
             loadParams: {
-                //url: `https://pdbtm.unitmp.org/api/v1/entry/${pdbEntry}.trpdb`,
+                //url: `https://pdbtm.unitmp.org/api/v1/entry/${params.pdbEntry}.trpdb`,
                 url: `https://www.ebi.ac.uk/pdbe/entry-files/download/${params.pdbEntry}_updated.cif`,
                 format: 'mmcif',
                 isBinary: false,
                 id: `${params.pdbEntry}_model`,
-                reprProvider: RcsbPreset
+                reprProvider: TmDetRcsbPreset
             }
         },
         structureViewerConfig: {

+ 14 - 2
src/examples/assembly-tm/UniTmpHelper.ts

@@ -1,6 +1,11 @@
 import { RcsbFvDisplayTypes } from "@rcsb/rcsb-saguaro";
 
 import { getColorByLocation, getLabelByLocation } from "./UniTmpColor";
+import { PDBTMDescriptor } from "@rcsb/rcsb-molstar/build/src/tmdet-extension/types";
+import { TmDetDescriptorCache } from "@rcsb/rcsb-molstar/build/src/tmdet-extension/prop";
+import { createMembraneOrientation } from "@rcsb/rcsb-molstar/build/src/tmdet-extension/transformation";
+import { setMembraneOrientation } from "@rcsb/rcsb-molstar/build/src/tmdet-extension/behavior";
+import { DebugUtil } from "@rcsb/rcsb-molstar/build/src/tmdet-extension/debug-utils";
 
 export async function fetchHtpDescriptor(entryId: string) {
     return fetchDescriptor(`https://htp.unitmp.org/api/v1/entry/${entryId}.json`);
@@ -29,7 +34,6 @@ export function htpDescriptorToTrackData(descriptor: any) {
         tracks.push(trackData);
     });
 
-    console.log(tracks);
     return tracks;
 }
 
@@ -40,10 +44,18 @@ export function jsvLibDescriptorToTrackData(descriptor: any) {
         const trackData = createNewTrack(descriptor.code, descriptor.regions, displayParamsFromJsvLibRegion);
         tracks.push(trackData);
     }
-    console.log(tracks);
+
     return tracks;
 }
 
+export async function registerRegionDescriptorData(url: string, side1: "Inside"|"Outside"|null) {
+    const pdbtmDescriptor: PDBTMDescriptor = await fetchDescriptor(url);
+    pdbtmDescriptor.side1 = side1;
+    TmDetDescriptorCache.add(pdbtmDescriptor);
+    const membraneOrientation = createMembraneOrientation(pdbtmDescriptor);
+    setMembraneOrientation(membraneOrientation);
+    DebugUtil.log('TMDET Membrane Orientation Params:', membraneOrientation);
+}
 
 function createNewTrack(rowTitle: string, regions: any[], paramsConverter: (region: any) => { begin: number, end: number, location: string }) {
     const trackData = {

+ 13 - 1
src/examples/assembly-tm/index.ts

@@ -1,6 +1,8 @@
 import {RcsbFv3DCustom, RcsbFv3DCustomInterface} from "../../RcsbFv3D/RcsbFv3DCustom";
 import { DebugUtil } from "@rcsb/rcsb-molstar/build/src/tmdet-extension/debug-utils";
 import { createFeatureViewerConfing } from "./FeatureViewConfig";
+import { TmDetDescriptorCache } from "@rcsb/rcsb-molstar/build/src/tmdet-extension/prop";
+import { registerRegionDescriptorData } from "./UniTmpHelper";
 
 document.addEventListener("DOMContentLoaded", (event) => {
     (async function(event) {
@@ -17,13 +19,23 @@ document.addEventListener("DOMContentLoaded", (event) => {
             pdbtmEntry: `${pdbEntry}_${labelAsymId}`
         };
 
+        const descriptorUrl = `/${pdbEntry}.json`;
+        registerRegionDescriptorData(descriptorUrl, params.side1 as any);
+
         const { sequenceConfig, molstarConfig } = await createFeatureViewerConfing(params);
         const panel3dConfig: RcsbFv3DCustomInterface = {
             elementId: "null",
             sequencePanelConfig: sequenceConfig,
             structurePanelConfig: molstarConfig
         };
-        DebugUtil.log(panel3dConfig);
+        DebugUtil.log('Panel config', panel3dConfig);
+        const pdbtmDescriptor = TmDetDescriptorCache.get(pdbEntry);
+        if (pdbtmDescriptor) {
+            const mx = DebugUtil.descriptorMxToMat4(pdbtmDescriptor!.additional_entry_annotations.membrane.transformation_matrix as any);
+            DebugUtil.log('Membrane transformation matrix:', mx);
+            (panel3dConfig.structurePanelConfig!.loadConfig as any).loadParams.matrix = mx;
+        }
+
 
         const panel3d = new RcsbFv3DCustom(panel3dConfig);
         panel3d.render();

+ 193 - 0
src/examples/assembly-tm/preset.ts

@@ -0,0 +1,193 @@
+/**
+ * Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ *
+ * @author Alexander Rose <alexander.rose@weirdbyte.de>
+ */
+
+import { ParamDefinition as PD } from 'molstar/lib/mol-util/param-definition';
+import { TrajectoryHierarchyPresetProvider } from 'molstar/lib/mol-plugin-state/builder/structure/hierarchy-preset';
+import { PluginStateObject } from 'molstar/lib/mol-plugin-state/objects';
+import { RootStructureDefinition } from 'molstar/lib/mol-plugin-state/helpers/root-structure';
+import { StructureRepresentationPresetProvider } from 'molstar/lib/mol-plugin-state/builder/structure/representation-preset';
+import {
+    StateObjectSelector,
+    StateObject,
+    StateTransformer
+} from 'molstar/lib/mol-state';
+import { Mat4 } from 'molstar/lib/mol-math/linear-algebra';
+import { MembraneOrientationPreset } from 'molstar/lib/extensions/anvil/behavior';
+import { Target } from '@rcsb/rcsb-molstar/build/src/viewer/helpers/selection';
+import { TMDET_STRUCTURE_PRESET_ID } from '@rcsb/rcsb-molstar/build/src/tmdet-extension/behavior';
+
+type BaseProps = {
+    assemblyId?: string
+    modelIndex?: number
+    plddt?: 'off' | 'single-chain' | 'on'
+}
+
+export { Mat4 } from 'molstar/lib/mol-math/linear-algebra';
+
+export type AlignmentProps = {
+    kind: 'alignment',
+    targets?: (Target & {
+        matrix?: Mat4
+    })[],
+    colors: {
+        value: number,
+        targets: Target[]
+    }[]
+} & BaseProps
+
+export type EmptyProps = {
+    kind: 'empty'
+} & BaseProps
+
+type ValidationProps = {
+    kind: 'validation'
+    colorTheme?: string
+    showClashes?: boolean
+} & BaseProps
+
+type StandardProps = {
+    kind: 'standard'
+} & BaseProps
+
+type SymmetryProps = {
+    kind: 'symmetry'
+    symmetryIndex?: number
+} & BaseProps
+
+type FeatureProps = {
+    kind: 'feature'
+    target: Target
+} & BaseProps
+
+type DensityProps = {
+    kind: 'density'
+} & BaseProps
+
+type MembraneProps = {
+    kind: 'membrane',
+} & BaseProps
+
+type FeatureDensityProps = {
+    kind: 'feature-density',
+    target: Target,
+    radius?: number,
+    hiddenChannels?: string[]
+} & BaseProps
+
+export type MotifProps = {
+    kind: 'motif',
+    label?: string,
+    targets: Target[],
+    color?: number
+} & BaseProps
+
+export type NakbProps = {
+    kind: 'nakb'
+} & BaseProps
+
+export type PresetProps = ValidationProps | StandardProps | SymmetryProps | FeatureProps | DensityProps | AlignmentProps |
+MembraneProps | FeatureDensityProps | MotifProps | NakbProps | EmptyProps;
+
+const RcsbParams = () => ({
+    preset: PD.Value<PresetProps>({ kind: 'standard', assemblyId: '' }, { isHidden: true })
+});
+
+type StructureObject = StateObjectSelector<PluginStateObject.Molecule.Structure, StateTransformer<StateObject<any, StateObject.Type<any>>, StateObject<any, StateObject.Type<any>>, any>>
+
+export const TmDetRcsbPreset = TrajectoryHierarchyPresetProvider({
+    id: 'tmdet-preset-trajectory-rcsb',
+    display: { name: 'TMDET RCSB Preset' },
+    isApplicable: () => true,
+    params: RcsbParams,
+    async apply(trajectory, params, plugin) {
+        console.log('TMDET RCSB PRESET: apply start');
+        const builder = plugin.builders.structure;
+        const p = params.preset;
+
+        const modelParams = { modelIndex: p.modelIndex || 0 };
+
+        const structureParams: RootStructureDefinition.Params = { name: 'model', params: {} };
+        if (p.assemblyId && p.assemblyId !== '' && p.assemblyId !== '0') {
+            Object.assign(structureParams, {
+                name: 'assembly',
+                params: { id: p.assemblyId }
+            } as RootStructureDefinition.Params);
+        }
+
+        const model = await builder.createModel(trajectory, modelParams);
+        const modelProperties = await builder.insertModelProperties(model);
+
+        let structure: StructureObject | undefined = undefined;
+        let structureProperties: StructureObject | undefined = undefined;
+        let unitcell: StateObjectSelector | undefined = undefined;
+        // If flexible transformation is allowed, we may need to create a single structure component
+        // from transformed substructures
+        structure = await builder.createStructure(modelProperties || model, structureParams);
+        structureProperties = await builder.insertStructureProperties(structure);
+
+        // default to pLDDT coloring when category present && single chain
+        const presetParams = Object.create(null);
+        let representation: StructureRepresentationPresetProvider.Result | undefined = undefined;
+        console.log('PRESET params:', params);
+        console.log('PRESET p:', p);
+
+        if (p.kind === 'alignment') {
+            console.warn('alignment case not implemented in TmDetRcsbPreset');
+        } else if (p.kind === 'motif' && structure?.obj) {
+            console.warn('motif case not implemented in TmDetRcsbPreset');
+        } else if (p.kind === 'validation') {
+            console.warn('validation case not implemented in TmDetRcsbPreset');
+        } else if (p.kind === 'symmetry' && structure?.obj) {
+            console.warn('symmetry case not implemented in TmDetRcsbPreset');
+        } else if (p.kind === 'empty') {
+            console.warn('Using empty representation in TmDetRcsbPreset');
+        } else if (p.kind === 'membrane') {
+            try {
+                representation = await plugin.builders.structure.representation.applyPreset<any>(structureProperties!, MembraneOrientationPreset, presetParams);
+
+                // reset the camera because the membranes render 1st and the structure might not be fully visible
+                requestAnimationFrame(() => plugin.canvas3d?.requestCameraReset());
+            } catch (error) {
+                const msg = 'Membrane calculation failed! - This can happen for tiny structures with only a dozen of residues.';
+                plugin.log.error(msg);
+                console.error(msg);
+                console.error(error);
+
+                // fall back to default representation to show something
+                representation = await plugin.builders.structure.representation.applyPreset(structureProperties!, 'auto', presetParams);
+            }
+        } else if (p.kind === 'nakb') {
+            console.warn('nakb case not implemented in TmDetRcsbPreset');
+        } else {
+            console.log('HERE WE GO:', { structure: structure, structureProps: structureProperties, presetParams: presetParams });
+            //representation = await plugin.builders.structure.representation.applyPreset(structureProperties!, 'auto', presetParams);
+            representation = await plugin.builders.structure.representation.applyPreset(
+                structureProperties!, 'auto', { theme: { globalName: 'tmdet-custom-color-theme' } });
+            await plugin.builders.structure.hierarchy.applyPreset(
+                trajectory, 'default', { representationPreset: TMDET_STRUCTURE_PRESET_ID as any });
+        }
+
+        console.log('STRUCTURE REPRESENTATION:', representation);
+
+        // TODO align with 'motif'?
+        if ((p.kind === 'feature' || p.kind === 'feature-density') && structure?.obj) {
+            console.warn('feature/feature-density case not implemented in TmDetRcsbPreset');
+        }
+
+        if (p.kind === 'density' && structure) {
+            console.warn('density case not implemented in TmDetRcsbPreset');
+        }
+
+        return {
+            model,
+            modelProperties,
+            unitcell,
+            structure,
+            structureProperties,
+            representation
+        };
+    }
+});