UNPKG

molstar

Version:

A comprehensive macromolecular library.

169 lines 7.42 kB
/** * Copyright (c) 2017 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> */ import { __awaiter, __generator } from "tslib"; import { Column } from '../../../mol-data/db'; import { Tokenizer } from '../common/text/tokenizer'; import { FixedColumnProvider as FixedColumn } from '../common/text/column/fixed'; import { ReaderResult as Result } from '../result'; import { Task } from '../../../mol-task'; function createEmptyHeader() { return { title: '', timeInPs: 0, hasVelocities: false, precision: { position: 0, velocity: 0 }, box: [0, 0, 0] }; } function State(tokenizer, runtimeCtx) { return { tokenizer: tokenizer, header: createEmptyHeader(), numberOfAtoms: 0, runtimeCtx: runtimeCtx }; } /** * title string (free format string, optional time in ps after 't=') */ function handleTitleString(state) { var tokenizer = state.tokenizer, header = state.header; var line = Tokenizer.readLine(tokenizer); // skip potential empty lines... if (line.trim().length === 0) { line = Tokenizer.readLine(tokenizer); } var timeOffset = line.lastIndexOf('t='); if (timeOffset >= 0) { header.timeInPs = parseFloat(line.substring(timeOffset + 2)); header.title = line.substring(0, timeOffset).trim(); if (header.title && header.title[header.title.length - 1] === ',') { header.title = header.title.substring(0, header.title.length - 1); } } else { header.title = line; } } /** * number of atoms (free format integer) */ function handleNumberOfAtoms(state) { var tokenizer = state.tokenizer; Tokenizer.markLine(tokenizer); var line = Tokenizer.getTokenString(tokenizer); state.numberOfAtoms = parseInt(line); } /** * This format is fixed, ie. all columns are in a fixed position. * Optionally (for now only yet with trjconv) you can write gro files * with any number of decimal places, the format will then be n+5 * positions with n decimal places (n+1 for velocities) in stead * of 8 with 3 (with 4 for velocities). Upon reading, the precision * will be inferred from the distance between the decimal points * (which will be n+5). Columns contain the following information * (from left to right): * residue number (5 positions, integer) * residue name (5 characters) * atom name (5 characters) * atom number (5 positions, integer) * position (in nm, x y z in 3 columns, each 8 positions with 3 decimal places) * velocity (in nm/ps (or km/s), x y z in 3 columns, each 8 positions with 4 decimal places) */ function handleAtoms(state) { return __awaiter(this, void 0, void 0, function () { var tokenizer, numberOfAtoms, lines, positionSample, precisions, hasVelocities, pO, pW, vO, vW, col, undef, ret; return __generator(this, function (_a) { switch (_a.label) { case 0: tokenizer = state.tokenizer, numberOfAtoms = state.numberOfAtoms; return [4 /*yield*/, Tokenizer.readLinesAsync(tokenizer, numberOfAtoms, state.runtimeCtx, 100000)]; case 1: lines = _a.sent(); positionSample = tokenizer.data.substring(lines.indices[0], lines.indices[1]).substring(20); precisions = positionSample.match(/\.\d+/g); hasVelocities = precisions.length === 6; state.header.hasVelocities = hasVelocities; state.header.precision.position = precisions[0].length - 1; state.header.precision.velocity = hasVelocities ? precisions[3].length - 1 : 0; pO = 20; pW = state.header.precision.position + 5; vO = pO + 3 * pW; vW = state.header.precision.velocity + 4; col = FixedColumn(lines); undef = Column.Undefined(state.numberOfAtoms, Column.Schema.float); ret = { count: state.numberOfAtoms, residueNumber: col(0, 5, Column.Schema.int), residueName: col(5, 5, Column.Schema.str), atomName: col(10, 5, Column.Schema.str), atomNumber: col(15, 5, Column.Schema.int), x: col(pO, pW, Column.Schema.float), y: col(pO + pW, pW, Column.Schema.float), z: col(pO + 2 * pW, pW, Column.Schema.float), vx: hasVelocities ? col(vO, vW, Column.Schema.float) : undef, vy: hasVelocities ? col(vO + vW, vW, Column.Schema.float) : undef, vz: hasVelocities ? col(vO + 2 * vW, vW, Column.Schema.float) : undef, }; return [2 /*return*/, ret]; } }); }); } /** * box vectors (free format, space separated reals), values: * v1(x) v2(y) v3(z) v1(y) v1(z) v2(x) v2(z) v3(x) v3(y), * the last 6 values may be omitted (they will be set to zero). * Gromacs only supports boxes with v1(y)=v1(z)=v2(z)=0. */ function handleBoxVectors(state) { var tokenizer = state.tokenizer; var values = Tokenizer.readLine(tokenizer).trim().split(/\s+/g); state.header.box = [+values[0], +values[1], +values[2]]; } function parseInternal(data, ctx) { return __awaiter(this, void 0, void 0, function () { var tokenizer, structures, state, atoms, result; return __generator(this, function (_a) { switch (_a.label) { case 0: tokenizer = Tokenizer(data); return [4 /*yield*/, ctx.update({ message: 'Parsing...', current: 0, max: data.length })]; case 1: _a.sent(); structures = []; _a.label = 2; case 2: if (!(tokenizer.position < data.length)) return [3 /*break*/, 4]; state = State(tokenizer, ctx); handleTitleString(state); handleNumberOfAtoms(state); return [4 /*yield*/, handleAtoms(state)]; case 3: atoms = _a.sent(); handleBoxVectors(state); structures.push({ header: state.header, atoms: atoms }); return [3 /*break*/, 2]; case 4: result = { structures: structures }; return [2 /*return*/, Result.success(result)]; } }); }); } export function parseGRO(data) { var _this = this; return Task.create('Parse GRO', function (ctx) { return __awaiter(_this, void 0, void 0, function () { return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, parseInternal(data, ctx)]; case 1: return [2 /*return*/, _a.sent()]; } }); }); }); } //# sourceMappingURL=parser.js.map