diff --git a/src/mol-model-formats/structure/xtc.ts b/src/mol-model-formats/structure/xtc.ts new file mode 100644 index 0000000000000000000000000000000000000000..759e38bc5ba0f10137511858be0ba28745aa3888 --- /dev/null +++ b/src/mol-model-formats/structure/xtc.ts @@ -0,0 +1,34 @@ +/** + * Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info. + * + * @author David Sehnal <david.sehnal@gmail.com> + */ + +import { Task } from '../../mol-task'; +import { XtcFile } from '../../mol-io/reader/xtc/parser'; +import { Coordinates, Frame, Time } from '../../mol-model/structure/coordinates'; +import { Cell } from '../../mol-math/geometry/spacegroup/cell'; + +export function coordinatesFromXtc(file: XtcFile): Task<Coordinates> { + return Task.create('Parse XTC', async ctx => { + await ctx.update('Converting to coordinates'); + + const deltaTime = Time(file.deltaTime, 'step'); + const offsetTime = Time(file.timeOffset, deltaTime.unit); + + const frames: Frame[] = []; + for (let i = 0, il = file.frames.length; i < il; ++i) { + frames.push({ + elementCount: file.frames[i].count, + // TODO: + cell: Cell.empty(), + x: file.frames[i].x, + y: file.frames[i].y, + z: file.frames[i].z, + time: Time(offsetTime.value + deltaTime.value * i, deltaTime.unit) + }); + } + + return Coordinates.create(frames, deltaTime, offsetTime); + }); +} diff --git a/src/mol-plugin-state/formats/structure.ts b/src/mol-plugin-state/formats/structure.ts index 7a6f24d4030fac07dc63d809f62d451ea26f5b29..cffea9967b7743391e7ebda797d8cdbcdcde3d7f 100644 --- a/src/mol-plugin-state/formats/structure.ts +++ b/src/mol-plugin-state/formats/structure.ts @@ -41,9 +41,24 @@ export const DcdProvider = DataFormatProvider({ } }); +export const XtcProvider = DataFormatProvider({ + label: 'XTC', + description: 'XTC', + category: Category, + binaryExtensions: ['xtc'], + parse: (plugin, data) => { + const coordinates = plugin.state.data.build() + .to(data) + .apply(StateTransforms.Model.CoordinatesFromXtc); + + return coordinates.commit(); + } +}); + export const BuiltInStructureFormats = [ ['psf', PsfProvider] as const, ['dcd', DcdProvider] as const, + ['xtc', XtcProvider] as const, ] as const; export type BuildInStructureFormat = (typeof BuiltInStructureFormats)[number][0] \ No newline at end of file diff --git a/src/mol-plugin-state/transforms/model.ts b/src/mol-plugin-state/transforms/model.ts index 1a8ff6355db22ecda2abcbb50d8893574533c899..415072b22f5a0ba8472aa2f5b2982241e05a9649 100644 --- a/src/mol-plugin-state/transforms/model.ts +++ b/src/mol-plugin-state/transforms/model.ts @@ -37,8 +37,11 @@ import { trajectoryFromCifCore } from '../../mol-model-formats/structure/cif-cor import { trajectoryFromCube } from '../../mol-model-formats/structure/cube'; import { parseMol2 } from '../../mol-io/reader/mol2/parser'; import { trajectoryFromMol2 } from '../../mol-model-formats/structure/mol2'; +import { parseXtc } from '../../mol-io/reader/xtc/parser'; +import { coordinatesFromXtc } from '../../mol-model-formats/structure/xtc'; export { CoordinatesFromDcd }; +export { CoordinatesFromXtc }; export { TopologyFromPsf }; export { TrajectoryFromModelAndCoordinates }; export { TrajectoryFromBlob }; @@ -81,6 +84,23 @@ const CoordinatesFromDcd = PluginStateTransform.BuiltIn({ } }); +type CoordinatesFromXtc = typeof CoordinatesFromDcd +const CoordinatesFromXtc = PluginStateTransform.BuiltIn({ + name: 'coordinates-from-xtc', + display: { name: 'Parse XTC', description: 'Parse XTC binary data.' }, + from: [SO.Data.Binary], + to: SO.Molecule.Coordinates +})({ + apply({ a }) { + return Task.create('Parse XTC', async ctx => { + const parsed = await parseXtc(a.data).runInContext(ctx); + if (parsed.isError) throw new Error(parsed.message); + const coordinates = await coordinatesFromXtc(parsed.result).runInContext(ctx); + return new SO.Molecule.Coordinates(coordinates, { label: a.label, description: 'Coordinates' }); + }); + } +}); + type TopologyFromPsf = typeof TopologyFromPsf const TopologyFromPsf = PluginStateTransform.BuiltIn({ name: 'topology-from-psf', diff --git a/webpack.config.common.js b/webpack.config.common.js index a2e035daec4c7407859a9b972a2958c18e870bd4..ff2aba48d7e3cef968804275e7908e5c3efd8e98 100644 --- a/webpack.config.common.js +++ b/webpack.config.common.js @@ -32,13 +32,14 @@ const sharedConfig = { ], }), new webpack.DefinePlugin({ - 'process.env.DEBUG': JSON.stringify(process.env.DEBUG) + 'process.env.DEBUG': JSON.stringify(process.env.DEBUG), + '__MOLSTAR_DEBUG_TIMESTAMP__': webpack.DefinePlugin.runtimeValue(() => `${new Date().valueOf()}`, true) }), new MiniCssExtractPlugin({ filename: 'molstar.css', }), new VersionFile({ extras: { timestamp: `${new Date().valueOf()}` }, packageFile: path.resolve(__dirname, 'package.json'), - templateString: `export const PLUGIN_VERSION = '<%= package.version %>';\nexport const PLUGIN_VERSION_DATE = new Date(<%= extras.timestamp %>);`, + templateString: `export const PLUGIN_VERSION = '<%= package.version %>';\nexport const PLUGIN_VERSION_DATE = new Date(typeof __MOLSTAR_DEBUG_TIMESTAMP__ !== 'undefined' ? __MOLSTAR_DEBUG_TIMESTAMP__ : <%= extras.timestamp %>);`, outputFile: path.resolve(__dirname, 'lib/mol-plugin/version.js') }) ], diff --git a/webpack.config.js b/webpack.config.js index 1289b72ede5d22bd2bbd278155c1480741c15107..16765f511da4e4b459381fecb4f8b4e5c975fadf 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -1,6 +1,5 @@ const { createApp, createExample, createBrowserTest } = require('./webpack.config.common.js'); -const apps = ['viewer']; const examples = ['proteopedia-wrapper', 'basic-wrapper', 'lighting']; const tests = [ 'font-atlas', @@ -10,7 +9,7 @@ const tests = [ ]; module.exports = [ - ...apps.map(createApp), + createApp('viewer', 'molstar'), ...examples.map(createExample), ...tests.map(createBrowserTest) ] \ No newline at end of file