Browse Source

plugin, trajectory from model and coordinates

Alexander Rose 5 years ago
parent
commit
5636edc1d1

+ 1 - 0
src/mol-plugin/index.ts

@@ -22,6 +22,7 @@ import { VolumeStreamingCustomControls } from '../mol-plugin-ui/custom/volume';
 export const DefaultPluginSpec: PluginSpec = {
     actions: [
         PluginSpec.Action(StateActions.Structure.DownloadStructure),
+        PluginSpec.Action(StateActions.Structure.AddTrajectoryFromModelAndCoordinates),
         PluginSpec.Action(StateActions.Volume.DownloadDensity),
         PluginSpec.Action(StateActions.DataFormat.OpenFile),
         PluginSpec.Action(StateActions.Structure.Create3DRepresentationPreset),

+ 3 - 2
src/mol-plugin/state/actions/data-format.ts

@@ -12,7 +12,7 @@ import { PluginStateObject } from '../objects';
 import { ParamDefinition as PD } from '../../../mol-util/param-definition';
 import { Ccp4Provider, Dsn6Provider, DscifProvider } from './volume';
 import { StateTransforms } from '../transforms';
-import { MmcifProvider, PdbProvider, GroProvider, Provider3dg } from './structure';
+import { MmcifProvider, PdbProvider, GroProvider, Provider3dg, DcdProvider } from './structure';
 import msgpackDecode from '../../../mol-io/common/msgpack/decode'
 import { PlyProvider } from './shape';
 
@@ -57,6 +57,7 @@ export class DataFormatRegistry<D extends PluginStateObject.Data.Binary | Plugin
     constructor() {
         this.add('3dg', Provider3dg)
         this.add('ccp4', Ccp4Provider)
+        this.add('dcd', DcdProvider)
         this.add('dscif', DscifProvider)
         this.add('dsn6', Dsn6Provider)
         this.add('gro', GroProvider)
@@ -155,7 +156,7 @@ type cifVariants = 'dscif' | -1
 export function guessCifVariant(info: FileInfo, data: Uint8Array | string): cifVariants {
     if (info.ext === 'bcif') {
         try {
-            // TODO find a way to run msgpackDecode only once
+            // TODO: find a way to run msgpackDecode only once
             //      now it is run twice, here and during file parsing
             if (msgpackDecode(data as Uint8Array).encoder.startsWith('VolumeServer')) return 'dscif'
         } catch { }

+ 41 - 1
src/mol-plugin/state/actions/structure.ts

@@ -11,7 +11,7 @@ import { ParamDefinition as PD } from '../../../mol-util/param-definition';
 import { PluginStateObject } from '../objects';
 import { StateTransforms } from '../transforms';
 import { Download } from '../transforms/data';
-import { CustomModelProperties, StructureSelectionFromExpression, CustomStructureProperties } from '../transforms/model';
+import { CustomModelProperties, StructureSelectionFromExpression, CustomStructureProperties, CoordinatesFromDcd, TrajectoryFromModelAndCoordinates } from '../transforms/model';
 import { DataFormatProvider, guessCifVariant, DataFormatBuilderOptions } from './data-format';
 import { FileInfo } from '../../../mol-util/file-info';
 import { Task } from '../../../mol-task';
@@ -86,6 +86,21 @@ export const Provider3dg: DataFormatProvider<any> = {
     }
 }
 
+export const DcdProvider: DataFormatProvider<any> = {
+    label: 'DCD',
+    description: 'DCD',
+    stringExtensions: [],
+    binaryExtensions: ['dcd'],
+    isApplicable: (info: FileInfo, data: string) => {
+        return info.ext === 'dcd'
+    },
+    getDefaultBuilder: (ctx: PluginContext, data: StateBuilder.To<PluginStateObject.Data.Binary>, options: DataFormatBuilderOptions, state: State) => {
+        return Task.create('DCD default builder', async taskCtx => {
+            await state.updateTree(data.apply(CoordinatesFromDcd)).runInContext(taskCtx)
+        })
+    }
+}
+
 type StructureFormat = 'pdb' | 'cif' | 'gro' | '3dg'
 
 //
@@ -395,4 +410,29 @@ export const StructureFromSelection = StateAction.build({
     const expression = StructureElement.Loci.toExpression(sel);
     const root = state.build().to(ref).apply(StructureSelectionFromExpression, { expression, label: params.label });
     return state.updateTree(root);
+});
+
+export const AddTrajectoryFromModelAndCoordinates = StateAction.build({
+    display: { name: 'Add Trajectory', description: 'Add trajectory from existing model and coordinates.' },
+    from: PluginStateObject.Root,
+    params(a, ctx: PluginContext) {
+        const state = ctx.state.dataState
+        const models = state.selectQ(q => q.rootsOfType(PluginStateObject.Molecule.Model))
+        const modelOptions = models.map(m => [m.transform.ref, m.obj!.label]) as [string, string][]
+        const coords = state.selectQ(q => q.rootsOfType(PluginStateObject.Molecule.Coordinates))
+        const coordsOptions = coords.map(c => [c.transform.ref, c.obj!.label]) as [string, string][]
+        return {
+            model: PD.Select(modelOptions.length ? modelOptions[0][0] : '', modelOptions),
+            coordinates: PD.Select(coordsOptions.length ? coordsOptions[0][0] : '', coordsOptions)
+        }
+    }
+})(({ ref, params, state }, ctx: PluginContext) => {
+    const dependsOn = [params.model, params.coordinates];
+    const root = state.build().toRoot()
+        .apply(TrajectoryFromModelAndCoordinates, {
+            modelRef: params.model,
+            coordinatesRef: params.coordinates
+        }, { dependsOn })
+        .apply(StateTransforms.Model.ModelFromTrajectory, { modelIndex: 0 })
+    return state.updateTree(createStructureAndVisuals(ctx, root, false));
 });

+ 13 - 1
src/mol-plugin/state/objects.ts

@@ -7,6 +7,7 @@
 
 import { CifFile } from '../../mol-io/reader/cif';
 import { PlyFile } from '../../mol-io/reader/ply/schema';
+import { Coordinates as _Coordinates } from '../../mol-model/structure';
 import { Model as _Model, Structure as _Structure, StructureElement } from '../../mol-model/structure';
 import { VolumeData } from '../../mol-model/volume';
 import { PluginBehavior } from '../../mol-plugin/behavior/behavior';
@@ -19,6 +20,8 @@ import { Dsn6File } from '../../mol-io/reader/dsn6/schema';
 import { ShapeRepresentation } from '../../mol-repr/shape/representation';
 import { Shape as _Shape } from '../../mol-model/shape';
 import { ShapeProvider } from '../../mol-model/shape/provider';
+import { File3DG } from '../../mol-io/reader/3dg/parser';
+import { DcdFile } from '../../mol-io/reader/dcd/parser';
 
 export type TypeClass = 'root' | 'data' | 'prop'
 
@@ -64,6 +67,10 @@ export namespace PluginStateObject {
     export namespace Format {
         export class Json extends Create<any>({ name: 'JSON Data', typeClass: 'Data' }) { }
         export class Cif extends Create<CifFile>({ name: 'CIF File', typeClass: 'Data' }) { }
+        export class Pdb extends Create<CifFile>({ name: 'PDB File', typeClass: 'Data' }) { }
+        export class Gro extends Create<CifFile>({ name: 'GRO File', typeClass: 'Data' }) { }
+        export class _3dg extends Create<CifFile>({ name: '3DG File', typeClass: 'Data' }) { }
+        export class Dcd extends Create<CifFile>({ name: 'DCD File', typeClass: 'Data' }) { }
         export class Ply extends Create<PlyFile>({ name: 'PLY File', typeClass: 'Data' }) { }
         export class Ccp4 extends Create<Ccp4File>({ name: 'CCP4/MRC/MAP File', typeClass: 'Data' }) { }
         export class Dsn6 extends Create<Dsn6File>({ name: 'DSN6/BRIX File', typeClass: 'Data' }) { }
@@ -73,6 +80,10 @@ export namespace PluginStateObject {
             | { kind: 'string', data: string }
             | { kind: 'binary', data: Uint8Array }
             | { kind: 'cif', data: CifFile }
+            | { kind: 'pdb', data: CifFile }
+            | { kind: 'gro', data: CifFile }
+            | { kind: '3dg', data: File3DG }
+            | { kind: 'dcd', data: DcdFile }
             | { kind: 'ccp4', data: Ccp4File }
             | { kind: 'dsn6', data: Dsn6File }
             | { kind: 'ply', data: PlyFile }
@@ -83,8 +94,9 @@ export namespace PluginStateObject {
     }
 
     export namespace Molecule {
-        export class Trajectory extends Create<ReadonlyArray<_Model>>({ name: 'Trajectory', typeClass: 'Object' }) { }
+        export class Coordinates extends Create<_Coordinates>({ name: 'Coordinates', typeClass: 'Object' }) { }
         export class Model extends Create<_Model>({ name: 'Model', typeClass: 'Object' }) { }
+        export class Trajectory extends Create<ReadonlyArray<_Model>>({ name: 'Trajectory', typeClass: 'Object' }) { }
         export class Structure extends Create<_Structure>({ name: 'Structure', typeClass: 'Object' }) { }
 
         export namespace Structure {

+ 50 - 7
src/mol-plugin/state/transforms/model.ts

@@ -9,7 +9,7 @@ import { parsePDB } from '../../../mol-io/reader/pdb/parser';
 import { Vec3, Mat4, Quat } from '../../../mol-math/linear-algebra';
 import { trajectoryFromMmCIF } from '../../../mol-model-formats/structure/mmcif';
 import { trajectoryFromPDB } from '../../../mol-model-formats/structure/pdb';
-import { Model, Queries, QueryContext, Structure, StructureQuery, StructureSelection as Sel, StructureElement } from '../../../mol-model/structure';
+import { Model, Queries, QueryContext, Structure, StructureQuery, StructureSelection as Sel, StructureElement, trajectoryFromModelAndCoordinates, Coordinates } from '../../../mol-model/structure';
 import { PluginContext } from '../../../mol-plugin/context';
 import { MolScriptBuilder } from '../../../mol-script/language/builder';
 import Expression from '../../../mol-script/language/expression';
@@ -28,7 +28,11 @@ import { trajectoryFrom3DG } from '../../../mol-model-formats/structure/3dg';
 import { StructureSelectionQueries } from '../../util/structure-selection-helper';
 import { StructureQueryHelper } from '../../util/structure-query';
 import { ModelStructureRepresentation } from '../representation/model';
+import { parseDcd } from '../../../mol-io/reader/dcd/parser';
+import { coordinatesFromDcd } from '../../../mol-model-formats/structure/dcd';
 
+export { CoordinatesFromDcd };
+export { TrajectoryFromModelAndCoordinates };
 export { TrajectoryFromBlob };
 export { TrajectoryFromMmCif };
 export { TrajectoryFromPDB };
@@ -48,6 +52,45 @@ export { StructureComplexElement };
 export { CustomModelProperties };
 export { CustomStructureProperties };
 
+type CoordinatesFromDcd = typeof CoordinatesFromDcd
+const CoordinatesFromDcd = PluginStateTransform.BuiltIn({
+    name: 'coordinates-from-dcd',
+    display: { name: 'Parse DCD', description: 'Parse DCD binary data.' },
+    from: [SO.Data.Binary],
+    to: SO.Molecule.Coordinates
+})({
+    apply({ a }) {
+        return Task.create('Parse DCD', async ctx => {
+            const parsed = await parseDcd(a.data).runInContext(ctx);
+            if (parsed.isError) throw new Error(parsed.message);
+            const coordinates = await coordinatesFromDcd(parsed.result).runInContext(ctx);
+            return new SO.Molecule.Coordinates(coordinates, { label: a.label, description: a.description });
+        });
+    }
+});
+
+type TrajectoryFromModelAndCoordinates = typeof TrajectoryFromModelAndCoordinates
+const TrajectoryFromModelAndCoordinates = PluginStateTransform.BuiltIn({
+    name: 'trajectory-from-model-and-coordinates',
+    display: { name: 'Trajectory from Model & Coordinates', description: 'Create a trajectory from existing model and coordinates.' },
+    from: SO.Root,
+    to: SO.Molecule.Trajectory,
+    params: {
+        modelRef: PD.Text('', { isHidden: true }),
+        coordinatesRef: PD.Text('', { isHidden: true }),
+    }
+})({
+    apply({ params, dependencies }) {
+        return Task.create('Create trajectory from model and coordinates', async ctx => {
+            const model = dependencies![params.modelRef].data as Model
+            const coordinates = dependencies![params.coordinatesRef].data as Coordinates
+            const trajectory = trajectoryFromModelAndCoordinates(model, coordinates);
+            const props = { label: 'Trajectory', description: `${trajectory.length} model${trajectory.length === 1 ? '' : 's'}` };
+            return new SO.Molecule.Trajectory(trajectory, props);
+        });
+    }
+});
+
 type TrajectoryFromBlob = typeof TrajectoryFromBlob
 const TrajectoryFromBlob = PluginStateTransform.BuiltIn({
     name: 'trajectory-from-blob',
@@ -66,7 +109,7 @@ const TrajectoryFromBlob = PluginStateTransform.BuiltIn({
                 for (const x of xs) models.push(x);
             }
 
-            const props = { label: `Trajectory`, description: `${models.length} model${models.length === 1 ? '' : 's'}` };
+            const props = { label: 'Trajectory', description: `${models.length} model${models.length === 1 ? '' : 's'}` };
             return new SO.Molecule.Trajectory(models, props);
         });
     }
@@ -239,7 +282,7 @@ const StructureAssemblyFromModel = PluginStateTransform.BuiltIn({
     }
 });
 
-const _translation = Vec3.zero(), _m = Mat4.zero(), _n = Mat4.zero();
+const _translation = Vec3(), _m = Mat4(), _n = Mat4();
 type TransformStructureConformation = typeof TransformStructureConformation
 const TransformStructureConformation = PluginStateTransform.BuiltIn({
     name: 'transform-structure-conformation',
@@ -267,14 +310,14 @@ const TransformStructureConformation = PluginStateTransform.BuiltIn({
         Mat4.mul3(m, _n, rot, _m);
 
         const s = Structure.transform(a.data, m);
-        const props = { label: `${a.label}`, description: `Transformed` };
+        const props = { label: `${a.label}`, description: 'Transformed' };
         return new SO.Molecule.Structure(s, props);
     },
     interpolate(src, tar, t) {
         // TODO: optimize
-        const u = Mat4.fromRotation(Mat4.zero(), Math.PI / 180 * src.angle, Vec3.normalize(Vec3.zero(), src.axis));
+        const u = Mat4.fromRotation(Mat4.zero(), Math.PI / 180 * src.angle, Vec3.normalize(Vec3(), src.axis));
         Mat4.setTranslation(u, src.translation);
-        const v = Mat4.fromRotation(Mat4.zero(), Math.PI / 180 * tar.angle, Vec3.normalize(Vec3.zero(), tar.axis));
+        const v = Mat4.fromRotation(Mat4.zero(), Math.PI / 180 * tar.angle, Vec3.normalize(Vec3(), tar.axis));
         Mat4.setTranslation(v, tar.translation);
         const m = SymmetryOperator.slerp(Mat4.zero(), u, v, t);
         const rot = Mat4.getRotation(Quat.zero(), m);
@@ -300,7 +343,7 @@ const TransformStructureConformationByMatrix = PluginStateTransform.BuiltIn({
     },
     apply({ a, params }) {
         const s = Structure.transform(a.data, params.matrix);
-        const props = { label: `${a.label}`, description: `Transformed` };
+        const props = { label: `${a.label}`, description: 'Transformed' };
         return new SO.Molecule.Structure(s, props);
     }
 });