Ver Fonte

wip, custom structure props

Alexander Rose há 6 anos atrás
pai
commit
48c8056bd5

+ 1 - 1
src/mol-model-props/common/custom-element-property.ts

@@ -67,7 +67,7 @@ namespace CustomElementProperty {
         function getStatic(e: StructureElement) { return e.unit.model._staticPropertyData[name].get(e.element); }
         function getDynamic(e: StructureElement) { return e.unit.model._staticPropertyData[name].get(e.element); }
 
-        const propertyProvider: CustomPropertyRegistry.Provider = {
+        const propertyProvider: CustomPropertyRegistry.ModelProvider = {
             option: [name, params.display],
             descriptor: Descriptor,
             defaultSelected: !!params.autoAttach,

+ 16 - 12
src/mol-model-props/common/custom-property-registry.ts

@@ -1,39 +1,40 @@
 /**
- * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ * Copyright (c) 2018-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
  *
  * @author David Sehnal <david.sehnal@gmail.com>
+ * @author Alexander Rose <alexander.rose@weirdbyte.de>
  */
 
-import { CustomPropertyDescriptor, Model } from 'mol-model/structure';
+import { CustomPropertyDescriptor, Model, Structure } from 'mol-model/structure';
 import { OrderedMap } from 'immutable';
 import { ParamDefinition } from 'mol-util/param-definition';
 import { Task } from 'mol-task';
 
 export { CustomPropertyRegistry }
 
-class CustomPropertyRegistry {
-    private providers = OrderedMap<string, CustomPropertyRegistry.Provider>().asMutable();
+class CustomPropertyRegistry<T = never> {
+    private providers = OrderedMap<string, CustomPropertyRegistry.Provider<T>>().asMutable();
 
-    getSelect(model: Model) {
+    getSelect(object: T) {
         const values = this.providers.values();
         const options: [string, string][] = [], selected: string[] = [];
         while (true) {
             const v = values.next();
             if (v.done) break;
-            if (!v.value.attachableTo(model)) continue;
+            if (!v.value.attachableTo(object)) continue;
             options.push(v.value.option);
             if (v.value.defaultSelected) selected.push(v.value.option[0]);
         }
         return ParamDefinition.MultiSelect(selected, options);
     }
 
-    getDefault(model: Model) {
+    getDefault(object: T) {
         const values = this.providers.values();
         const selected: string[] = [];
         while (true) {
             const v = values.next();
             if (v.done) break;
-            if (!v.value.attachableTo(model)) continue;
+            if (!v.value.attachableTo(object)) continue;
             if (v.value.defaultSelected) selected.push(v.value.option[0]);
         }
         return selected;
@@ -45,7 +46,7 @@ class CustomPropertyRegistry {
         return this.providers.get(name);
     }
 
-    register(provider: CustomPropertyRegistry.Provider) {
+    register(provider: CustomPropertyRegistry.Provider<T>) {
         this.providers.set(provider.descriptor.name, provider);
     }
 
@@ -55,11 +56,14 @@ class CustomPropertyRegistry {
 }
 
 namespace CustomPropertyRegistry {
-    export interface Provider {
+    export interface Provider<T> {
         option: [string, string],
         defaultSelected: boolean,
         descriptor: CustomPropertyDescriptor<any, any>,
-        attachableTo: (model: Model) => boolean,
-        attach: (model: Model) => Task<boolean>
+        attachableTo: (object: T) => boolean,
+        attach: (object: T) => Task<boolean>
     }
+
+    export type ModelProvider = Provider<Model>
+    export type StructureProvider = Provider<Structure>
 }

+ 56 - 0
src/mol-model-props/computed/secondary-structure.ts

@@ -0,0 +1,56 @@
+/**
+ * Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ *
+ * @author Alexander Rose <alexander.rose@weirdbyte.de>
+ */
+
+import { CustomPropertyDescriptor, Structure } from 'mol-model/structure';
+import { Task } from 'mol-task';
+
+export namespace ComputedSecondaryStructure {
+    export type Property = {} // TODO
+
+    export function get(structure: Structure): Property | undefined {
+        return structure.currentPropertyData.__ComputedSecondaryStructure__;
+    }
+    function set(structure: Structure, prop: Property) {
+        (structure.currentPropertyData.__ComputedSecondaryStructure__ as Property) = prop;
+    }
+
+    export function createAttachTask() {
+        return (structure: Structure) => Task.create('Compute Secondary Structure', async ctx => {
+            if (get(structure)) return true;
+            return await attachFromCifOrCompute(structure, ctx)
+        });
+    }
+
+    export const Descriptor = CustomPropertyDescriptor({
+        isStatic: true,
+        name: 'molstar_computed_secondary_structure',
+        // TODO `cifExport` and `symbol`
+    });
+
+    export async function attachFromCifOrCompute(structure: Structure, params: {
+        // TODO params
+    }) {
+        if (structure.customPropertyDescriptors.has(Descriptor)) return true;
+
+        const compSecStruc = computeSecondaryStructure(structure)
+
+        structure.customPropertyDescriptors.add(Descriptor);
+        set(structure, compSecStruc);
+        return true;
+    }
+}
+
+// export const SecondaryStructureComputationParams = {
+//     oldDefinition: PD.Boolean(true, { description: 'Whether to use the old DSSP convention for the annotation of turns and helices, causes them to be two residues shorter' }),
+//     oldOrdering: PD.Boolean(true, { description: 'Alpha-helices are preferred over 3-10 helices' })
+// }
+// export type SecondaryStructureComputationParams = typeof SecondaryStructureComputationParams
+
+function computeSecondaryStructure(structure: Structure): ComputedSecondaryStructure.Property {
+    // TODO
+    console.log('TODO calc secondary structure')
+    return {}
+}

+ 2 - 1
src/mol-plugin/behavior/dynamic/custom-props.ts

@@ -1,9 +1,10 @@
 /**
- * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ * Copyright (c) 2018-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
  *
  * @author David Sehnal <david.sehnal@gmail.com>
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
  */
 
+export { MolstarSecondaryStructure } from './custom-props/computed/secondary-structure'
 export { PDBeStructureQualityReport } from './custom-props/pdbe/structure-quality-report'
 export { RCSBAssemblySymmetry } from './custom-props/rcsb/assembly-symmetry'

+ 45 - 0
src/mol-plugin/behavior/dynamic/custom-props/computed/secondary-structure.ts

@@ -0,0 +1,45 @@
+/**
+ * Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ *
+ * @author Alexander Rose <alexander.rose@weirdbyte.de>
+ */
+
+import { ParamDefinition as PD } from 'mol-util/param-definition';
+import { PluginBehavior } from '../../../behavior';
+import { CustomPropertyRegistry } from 'mol-model-props/common/custom-property-registry';
+import { ComputedSecondaryStructure } from 'mol-model-props/computed/secondary-structure';
+
+export const MolstarSecondaryStructure = PluginBehavior.create<{ autoAttach: boolean }>({
+    name: 'molstar-computed-secondary-structure-prop',
+    category: 'custom-props',
+    display: { name: 'Computed Secondary Structure' },
+    ctor: class extends PluginBehavior.Handler<{ autoAttach: boolean }> {
+        private attach = ComputedSecondaryStructure.createAttachTask();
+
+        private provider: CustomPropertyRegistry.StructureProvider = {
+            option: [ComputedSecondaryStructure.Descriptor.name, 'Computed Secondary Structure'],
+            descriptor: ComputedSecondaryStructure.Descriptor,
+            defaultSelected: this.params.autoAttach,
+            attachableTo: () => true,
+            attach: this.attach
+        }
+
+        register(): void {
+            this.ctx.customStructureProperties.register(this.provider);
+        }
+
+        update(p: { autoAttach: boolean }) {
+            let updated = this.params.autoAttach !== p.autoAttach
+            this.params.autoAttach = p.autoAttach;
+            this.provider.defaultSelected = p.autoAttach;
+            return updated;
+        }
+
+        unregister() {
+            this.ctx.customStructureProperties.unregister(ComputedSecondaryStructure.Descriptor.name);
+        }
+    },
+    params: () => ({
+        autoAttach: PD.Boolean(false)
+    })
+});

+ 1 - 1
src/mol-plugin/behavior/dynamic/custom-props/pdbe/structure-quality-report.ts

@@ -24,7 +24,7 @@ export const PDBeStructureQualityReport = PluginBehavior.create<{ autoAttach: bo
             this.ctx.fetch
         );
 
-        private provider: CustomPropertyRegistry.Provider = {
+        private provider: CustomPropertyRegistry.ModelProvider = {
             option: [StructureQualityReport.Descriptor.name, 'PDBe Structure Quality Report'],
             descriptor: StructureQualityReport.Descriptor,
             defaultSelected: this.params.autoAttach,

+ 1 - 1
src/mol-plugin/behavior/dynamic/custom-props/rcsb/assembly-symmetry.ts

@@ -21,7 +21,7 @@ export const RCSBAssemblySymmetry = PluginBehavior.create<{ autoAttach: boolean
     ctor: class extends PluginBehavior.Handler<{ autoAttach: boolean }> {
         private attach = AssemblySymmetry.createAttachTask(this.ctx.fetch);
 
-        private provider: CustomPropertyRegistry.Provider = {
+        private provider: CustomPropertyRegistry.ModelProvider = {
             option: [AssemblySymmetry.Descriptor.name, 'RCSB Assembly Symmetry'],
             descriptor: AssemblySymmetry.Descriptor,
             defaultSelected: this.params.autoAttach,

+ 3 - 1
src/mol-plugin/context.ts

@@ -35,6 +35,7 @@ import { SubstructureParentHelper } from './util/substructure-parent-helper';
 import { Representation } from 'mol-repr/representation';
 import { ModifiersKeys } from 'mol-util/input/input-observer';
 import { isProductionMode, isDebugMode } from 'mol-util/debug';
+import { Model, Structure } from 'mol-model/structure';
 
 export class PluginContext {
     private disposed = false;
@@ -99,7 +100,8 @@ export class PluginContext {
         registry: new DataFormatRegistry()
     }
 
-    readonly customModelProperties = new CustomPropertyRegistry();
+    readonly customModelProperties = new CustomPropertyRegistry<Model>();
+    readonly customStructureProperties = new CustomPropertyRegistry<Structure>();
     readonly customParamEditors = new Map<string, StateTransformParameters.Class>();
 
     readonly helpers = {

+ 6 - 2
src/mol-plugin/index.ts

@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ * Copyright (c) 2018-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
  *
  * @author David Sehnal <david.sehnal@gmail.com>
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
@@ -25,6 +25,7 @@ export const DefaultPluginSpec: PluginSpec = {
         PluginSpec.Action(StateActions.DataFormat.OpenFile),
         PluginSpec.Action(StateActions.Structure.CreateComplexRepresentation),
         PluginSpec.Action(StateActions.Structure.EnableModelCustomProps),
+        PluginSpec.Action(StateActions.Structure.EnableStructureCustomProps),
 
         // Volume streaming
         PluginSpec.Action(InitVolumeStreaming),
@@ -35,6 +36,7 @@ export const DefaultPluginSpec: PluginSpec = {
         PluginSpec.Action(StateTransforms.Data.ParseCif),
         PluginSpec.Action(StateTransforms.Data.ParseCcp4),
         PluginSpec.Action(StateTransforms.Data.ParseDsn6),
+
         PluginSpec.Action(StateTransforms.Model.TrajectoryFromMmCif),
         PluginSpec.Action(StateTransforms.Model.TrajectoryFromPDB),
         PluginSpec.Action(StateTransforms.Model.StructureAssemblyFromModel),
@@ -43,13 +45,14 @@ export const DefaultPluginSpec: PluginSpec = {
         PluginSpec.Action(StateTransforms.Model.StructureFromModel),
         PluginSpec.Action(StateTransforms.Model.ModelFromTrajectory),
         PluginSpec.Action(StateTransforms.Model.UserStructureSelection),
-        PluginSpec.Action(StateTransforms.Volume.VolumeFromCcp4),
         PluginSpec.Action(StateTransforms.Representation.StructureRepresentation3D),
         PluginSpec.Action(StateTransforms.Representation.StructureLabels3D),
         PluginSpec.Action(StateTransforms.Representation.ExplodeStructureRepresentation3D),
         PluginSpec.Action(StateTransforms.Representation.UnwindStructureAssemblyRepresentation3D),
         PluginSpec.Action(StateTransforms.Representation.OverpaintStructureRepresentation3D),
         PluginSpec.Action(StateTransforms.Representation.TransparencyStructureRepresentation3D),
+
+        PluginSpec.Action(StateTransforms.Volume.VolumeFromCcp4),
         PluginSpec.Action(StateTransforms.Representation.VolumeRepresentation3D),
 
         PluginSpec.Action(StateActions.Structure.StructureFromSelection),
@@ -60,6 +63,7 @@ export const DefaultPluginSpec: PluginSpec = {
         PluginSpec.Behavior(PluginBehaviors.Representation.DefaultLociLabelProvider),
         PluginSpec.Behavior(PluginBehaviors.Camera.FocusLociOnSelect, { minRadius: 8, extraRadius: 4 }),
         // PluginSpec.Behavior(PluginBehaviors.Labels.SceneLabels),
+        PluginSpec.Behavior(PluginBehaviors.CustomProps.MolstarSecondaryStructure, { autoAttach: true }),
         PluginSpec.Behavior(PluginBehaviors.CustomProps.PDBeStructureQualityReport, { autoAttach: true }),
         PluginSpec.Behavior(PluginBehaviors.CustomProps.RCSBAssemblySymmetry, { autoAttach: true }),
         PluginSpec.Behavior(StructureRepresentationInteraction)

+ 18 - 3
src/mol-plugin/state/actions/structure.ts

@@ -12,7 +12,7 @@ import { PluginStateObject } from '../objects';
 import { StateTransforms } from '../transforms';
 import { Download } from '../transforms/data';
 import { StructureRepresentation3DHelpers } from '../transforms/representation';
-import { CustomModelProperties, StructureSelection } from '../transforms/model';
+import { CustomModelProperties, StructureSelection, CustomStructureProperties } from '../transforms/model';
 import { DataFormatProvider, guessCifVariant } from './data-format';
 import { FileInfo } from 'mol-util/file-info';
 import { Task } from 'mol-task';
@@ -273,10 +273,10 @@ export const UpdateTrajectory = StateAction.build({
 });
 
 export const EnableModelCustomProps = StateAction.build({
-    display: { name: 'Custom Properties', description: 'Enable the addition of custom properties to the model.' },
+    display: { name: 'Custom Model Properties', description: 'Enable the addition of custom properties to the model.' },
     from: PluginStateObject.Molecule.Model,
     params(a, ctx: PluginContext) {
-        if (!a) return { properties: PD.MultiSelect([], [], { description: 'A list of property descriptor ids.' }) };
+        if (!a) return { properties: PD.MultiSelect([], [], { description: 'A list of model property descriptor ids.' }) };
         return { properties: ctx.customModelProperties.getSelect(a.data) };
     },
     isApplicable(a, t, ctx: PluginContext) {
@@ -287,6 +287,21 @@ export const EnableModelCustomProps = StateAction.build({
     return state.updateTree(root);
 });
 
+export const EnableStructureCustomProps = StateAction.build({
+    display: { name: 'Custom Structure Properties', description: 'Enable the addition of custom properties to the structure.' },
+    from: PluginStateObject.Molecule.Structure,
+    params(a, ctx: PluginContext) {
+        if (!a) return { properties: PD.MultiSelect([], [], { description: 'A list of structure property descriptor ids.' }) };
+        return { properties: ctx.customStructureProperties.getSelect(a.data) };
+    },
+    isApplicable(a, t, ctx: PluginContext) {
+        return t.transformer !== CustomStructureProperties;
+    }
+})(({ ref, params, state }, ctx: PluginContext) => {
+    const root = state.build().to(ref).insert(CustomStructureProperties, params);
+    return state.updateTree(root);
+});
+
 export const TransformStructureConformation = StateAction.build({
     display: { name: 'Transform Conformation' },
     from: PluginStateObject.Molecule.Structure,

+ 31 - 4
src/mol-plugin/state/transforms/model.ts

@@ -40,6 +40,7 @@ export { StructureSelection };
 export { UserStructureSelection };
 export { StructureComplexElement };
 export { CustomModelProperties };
+export { CustomStructureProperties };
 
 type TrajectoryFromBlob = typeof TrajectoryFromBlob
 const TrajectoryFromBlob = PluginStateTransform.BuiltIn({
@@ -189,7 +190,8 @@ const StructureAssemblyFromModel = PluginStateTransform.BuiltIn({
         const model = a.data;
         const ids = model.symmetry.assemblies.map(a => [a.id, `${a.id}: ${stringToWords(a.details)}`] as [string, string]);
         ids.push(['deposited', 'Deposited']);
-        return { id: PD.Optional(PD.Select(ids[0][0], ids, { label: 'Asm Id', description: 'Assembly Id' })) };
+        return {
+            id: PD.Optional(PD.Select(ids[0][0], ids, { label: 'Asm Id', description: 'Assembly Id' })) };
     }
 })({
     apply({ a, params }, plugin: PluginContext) {
@@ -432,18 +434,43 @@ const CustomModelProperties = PluginStateTransform.BuiltIn({
 })({
     apply({ a, params }, ctx: PluginContext) {
         return Task.create('Custom Props', async taskCtx => {
-            await attachProps(a.data, ctx, taskCtx, params.properties);
-            return new SO.Molecule.Model(a.data, { label: 'Props', description: `${params.properties.length} Selected` });
+            await attachModelProps(a.data, ctx, taskCtx, params.properties);
+            return new SO.Molecule.Model(a.data, { label: 'Model Props', description: `${params.properties.length} Selected` });
         });
     }
 });
-async function attachProps(model: Model, ctx: PluginContext, taskCtx: RuntimeContext, names: string[]) {
+async function attachModelProps(model: Model, ctx: PluginContext, taskCtx: RuntimeContext, names: string[]) {
     for (const name of names) {
         const p = ctx.customModelProperties.get(name);
         await p.attach(model).runInContext(taskCtx);
     }
 }
 
+type CustomStructureProperties = typeof CustomStructureProperties
+const CustomStructureProperties = PluginStateTransform.BuiltIn({
+    name: 'custom-structure-properties',
+    display: { name: 'Custom Structure Properties' },
+    from: SO.Molecule.Structure,
+    to: SO.Molecule.Structure,
+    params: (a, ctx: PluginContext) => {
+        if (!a) return { properties: PD.MultiSelect([], [], { description: 'A list of property descriptor ids.' }) };
+        return { properties: ctx.customStructureProperties.getSelect(a.data) };
+    }
+})({
+    apply({ a, params }, ctx: PluginContext) {
+        return Task.create('Custom Props', async taskCtx => {
+            await attachStructureProps(a.data, ctx, taskCtx, params.properties);
+            return new SO.Molecule.Structure(a.data, { label: 'Structure Props', description: `${params.properties.length} Selected` });
+        });
+    }
+});
+async function attachStructureProps(structure: Structure, ctx: PluginContext, taskCtx: RuntimeContext, names: string[]) {
+    for (const name of names) {
+        const p = ctx.customStructureProperties.get(name);
+        await p.attach(structure).runInContext(taskCtx);
+    }
+}
+
 export { ShapeFromPly }
 type ShapeFromPly = typeof ShapeFromPly
 const ShapeFromPly = PluginStateTransform.BuiltIn({