UNPKG

molstar

Version:

A comprehensive macromolecular library.

176 lines (175 loc) 7.78 kB
"use strict"; /** * Copyright (c) 2024 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author Alexander Rose <alexander.rose@weirdbyte.de> * @author David Sehnal <david.sehnal@gmail.com> * @author Ludovic Autin <ludovic.autin@gmail.com> */ Object.defineProperty(exports, "__esModule", { value: true }); exports.parseLammpsTrajectory = parseLammpsTrajectory; const mol_task_1 = require("../../../../mol-task"); const tokenizer_1 = require("../../common/text/tokenizer"); const result_1 = require("../../result"); const token_1 = require("../../common/text/column/token"); const db_1 = require("../../../../mol-data/db"); const { readLine, skipWhitespace, eatValue, eatLine, markStart } = tokenizer_1.Tokenizer; function State(tokenizer, runtimeCtx) { return { tokenizer, runtimeCtx, }; } async function handleAtoms(state, count, parts) { const { tokenizer } = state; const columnIndexMap = Object.fromEntries(parts.map((colName, index) => [colName, index])); // declare column x, y, and z by check first caracter to 'x' or 'y' or 'z' // x,y,z = unscaled atom coordinates // xs,ys,zs = scaled atom coordinates this need the boundary box // xu,yu,zu = unwrapped atom coordinates // xsu,ysu,zsu = scaled unwrapped atom coordinates // ix,iy,iz = box image that the atom is in // how should we handle the different scenario ? const xCol = parts.findIndex(p => p[0] === 'x'); const yCol = parts.findIndex(p => p[0] === 'y'); const zCol = parts.findIndex(p => p[0] === 'z'); // retrieve the atom type colum for x only const atomMode = parts[xCol]; // x,xs,xu,xsu const atomId = tokenizer_1.TokenBuilder.create(tokenizer.data, count * 2); const moleculeType = tokenizer_1.TokenBuilder.create(tokenizer.data, count * 2); const atomType = tokenizer_1.TokenBuilder.create(tokenizer.data, count * 2); const x = tokenizer_1.TokenBuilder.create(tokenizer.data, count * 2); const y = tokenizer_1.TokenBuilder.create(tokenizer.data, count * 2); const z = tokenizer_1.TokenBuilder.create(tokenizer.data, count * 2); const { position } = tokenizer; tokenizer.position = position; const n = parts.length; const { length } = tokenizer; let linesAlreadyRead = 0; await (0, mol_task_1.chunkedSubtask)(state.runtimeCtx, 100000, void 0, chunkSize => { const linesToRead = Math.min(count - linesAlreadyRead, chunkSize); for (let i = 0; i < linesToRead; ++i) { for (let j = 0; j < n; ++j) { skipWhitespace(tokenizer); markStart(tokenizer); eatValue(tokenizer); switch (j) { case columnIndexMap['id']: tokenizer_1.TokenBuilder.addUnchecked(atomId, tokenizer.tokenStart, tokenizer.tokenEnd); break; case columnIndexMap['mol']: tokenizer_1.TokenBuilder.addUnchecked(moleculeType, tokenizer.tokenStart, tokenizer.tokenEnd); break; case columnIndexMap['type']: tokenizer_1.TokenBuilder.addUnchecked(atomType, tokenizer.tokenStart, tokenizer.tokenEnd); break; case xCol: tokenizer_1.TokenBuilder.addUnchecked(x, tokenizer.tokenStart, tokenizer.tokenEnd); break; case yCol: tokenizer_1.TokenBuilder.addUnchecked(y, tokenizer.tokenStart, tokenizer.tokenEnd); break; case zCol: tokenizer_1.TokenBuilder.addUnchecked(z, tokenizer.tokenStart, tokenizer.tokenEnd); break; } } // ignore any extra columns eatLine(tokenizer); markStart(tokenizer); } linesAlreadyRead += linesToRead; return linesToRead; }, ctx => ctx.update({ message: 'Parsing...', current: tokenizer.position, max: length })); return { count, atomMode: atomMode, atomId: (0, token_1.TokenColumnProvider)(atomId)(db_1.Column.Schema.int), moleculeId: (0, token_1.TokenColumnProvider)(moleculeType)(db_1.Column.Schema.int), atomType: (0, token_1.TokenColumnProvider)(atomType)(db_1.Column.Schema.int), x: (0, token_1.TokenColumnProvider)(x)(db_1.Column.Schema.float), y: (0, token_1.TokenColumnProvider)(y)(db_1.Column.Schema.float), z: (0, token_1.TokenColumnProvider)(z)(db_1.Column.Schema.float), }; } /** * Possible Attributes from Lammps Dump * see https://docs.lammps.org/dump.html fro more details * possible attributes = id, mol, proc, procp1, type, element, mass, * x, y, z, xs, ys, zs, xu, yu, zu, * xsu, ysu, zsu, ix, iy, iz, * vx, vy, vz, fx, fy, fz, * q, mux, muy, muz, mu, * radius, diameter, omegax, omegay, omegaz, * angmomx, angmomy, angmomz, tqx, tqy, tqz, * c_ID, c_ID[I], f_ID, f_ID[I], v_name, * i_name, d_name, i2_name[I], d2_name[I] * ITEM: BOX BOUNDS xx yy zz * xlo xhi * ylo yhi * zlo zhi */ async function parseInternal(data, ctx) { const tokenizer = (0, tokenizer_1.Tokenizer)(data); const state = State(tokenizer, ctx); const f = { frames: [], times: [], bounds: [], timeOffset: 0.0, deltaTime: 0.0 }; const frames = f.frames; let numAtoms = 0; let timestep = 0; while (tokenizer.tokenEnd < tokenizer.length) { const line = readLine(state.tokenizer).trim(); if (line.includes('ITEM: TIMESTEP')) { timestep = parseInt(readLine(state.tokenizer).trim()); f.times.push(timestep); } else if (line.includes('ITEM: NUMBER OF ATOMS')) { numAtoms = parseInt(readLine(state.tokenizer).trim()); } else if (line.includes('ITEM: ATOMS')) { // this line provide also the style of the output and will give the order of the columns const parts = line.split(' ').slice(2); const frame = await handleAtoms(state, numAtoms, parts); frames.push(frame); } else if (line.includes('ITEM: BOX BOUNDS')) { const tokens = line.split('ITEM: BOX BOUNDS ')[1].split(' '); // Periodicity of the box const px = tokens[0]; const py = tokens[1]; const pz = tokens[2]; // the actual box bounds const xbound = readLine(state.tokenizer).trim().split(' '); const ybound = readLine(state.tokenizer).trim().split(' '); const zbound = readLine(state.tokenizer).trim().split(' '); const xlo = parseFloat(xbound[0]); const xhi = parseFloat(xbound[1]); const ylo = parseFloat(ybound[0]); const yhi = parseFloat(ybound[1]); const zlo = parseFloat(zbound[0]); const zhi = parseFloat(zbound[1]); f.bounds.push({ lower: [xlo, ylo, zlo], length: [xhi - xlo, yhi - ylo, zhi - zlo], periodicity: [px, py, pz] }); } } if (f.times.length >= 1) { f.timeOffset = f.times[0]; } if (f.times.length >= 2) { f.deltaTime = f.times[1] - f.times[0]; } return result_1.ReaderResult.success(f); } function parseLammpsTrajectory(data) { return mol_task_1.Task.create('Parse Lammp Trajectory', async (ctx) => { return await parseInternal(data, ctx); }); }