UNPKG

molstar

Version:

A comprehensive macromolecular library.

300 lines (299 loc) 11.8 kB
/** * Copyright (c) 2022 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author Alexander Rose <alexander.rose@weirdbyte.de> */ import { __awaiter, __generator } from "tslib"; import { Task } from '../../../mol-task'; import { Tokenizer, TokenBuilder } from '../common/text/tokenizer'; import { ReaderResult as Result } from '../result'; import { TokenColumnProvider as TokenColumn } from '../common/text/column/token'; import { Column, Table } from '../../../mol-data/db'; // https://manual.gromacs.org/2021-current/reference-manual/file-formats.html#top var AtomsSchema = { nr: Column.Schema.Int(), type: Column.Schema.Str(), resnr: Column.Schema.Int(), residu: Column.Schema.Str(), atom: Column.Schema.Str(), cgnr: Column.Schema.Int(), charge: Column.Schema.Float(), mass: Column.Schema.Float(), }; var BondsSchema = { ai: Column.Schema.Int(), aj: Column.Schema.Int(), }; var MoleculesSchema = { compound: Column.Schema.Str(), molCount: Column.Schema.Int(), }; var readLine = Tokenizer.readLine, markLine = Tokenizer.markLine, skipWhitespace = Tokenizer.skipWhitespace, markStart = Tokenizer.markStart, eatValue = Tokenizer.eatValue, eatLine = Tokenizer.eatLine; function State(tokenizer, runtimeCtx) { return { tokenizer: tokenizer, runtimeCtx: runtimeCtx, }; } var reField = /\[ (.+) \]/; var reWhitespace = /\s+/; function handleMoleculetype(state) { var tokenizer = state.tokenizer; var molName = undefined; while (tokenizer.tokenEnd < tokenizer.length) { skipWhitespace(tokenizer); var c = tokenizer.data[tokenizer.position]; if (c === '[') break; if (c === ';' || c === '*') { markLine(tokenizer); continue; } if (molName !== undefined) throw new Error('more than one molName'); var line = readLine(tokenizer); molName = line.split(reWhitespace)[0]; } if (molName === undefined) throw new Error('missing molName'); return molName; } function handleAtoms(state) { var tokenizer = state.tokenizer; var nr = TokenBuilder.create(tokenizer.data, 64); var type = TokenBuilder.create(tokenizer.data, 64); var resnr = TokenBuilder.create(tokenizer.data, 64); var residu = TokenBuilder.create(tokenizer.data, 64); var atom = TokenBuilder.create(tokenizer.data, 64); var cgnr = TokenBuilder.create(tokenizer.data, 64); var charge = TokenBuilder.create(tokenizer.data, 64); var mass = TokenBuilder.create(tokenizer.data, 64); while (tokenizer.tokenEnd < tokenizer.length) { skipWhitespace(tokenizer); var c = tokenizer.data[tokenizer.position]; if (c === '[') break; if (c === ';' || c === '*') { markLine(tokenizer); continue; } for (var j = 0; j < 8; ++j) { skipWhitespace(tokenizer); markStart(tokenizer); eatValue(tokenizer); switch (j) { case 0: TokenBuilder.add(nr, tokenizer.tokenStart, tokenizer.tokenEnd); break; case 1: TokenBuilder.add(type, tokenizer.tokenStart, tokenizer.tokenEnd); break; case 2: TokenBuilder.add(resnr, tokenizer.tokenStart, tokenizer.tokenEnd); break; case 3: TokenBuilder.add(residu, tokenizer.tokenStart, tokenizer.tokenEnd); break; case 4: TokenBuilder.add(atom, tokenizer.tokenStart, tokenizer.tokenEnd); break; case 5: TokenBuilder.add(cgnr, tokenizer.tokenStart, tokenizer.tokenEnd); break; case 6: TokenBuilder.add(charge, tokenizer.tokenStart, tokenizer.tokenEnd); break; case 7: TokenBuilder.add(mass, tokenizer.tokenStart, tokenizer.tokenEnd); break; } } // ignore any extra columns markLine(tokenizer); } return Table.ofColumns(AtomsSchema, { nr: TokenColumn(nr)(Column.Schema.int), type: TokenColumn(type)(Column.Schema.str), resnr: TokenColumn(resnr)(Column.Schema.int), residu: TokenColumn(residu)(Column.Schema.str), atom: TokenColumn(atom)(Column.Schema.str), cgnr: TokenColumn(cgnr)(Column.Schema.int), charge: TokenColumn(charge)(Column.Schema.float), mass: TokenColumn(mass)(Column.Schema.float), }); } function handleBonds(state) { var tokenizer = state.tokenizer; var ai = TokenBuilder.create(tokenizer.data, 64); var aj = TokenBuilder.create(tokenizer.data, 64); while (tokenizer.tokenEnd < tokenizer.length) { skipWhitespace(tokenizer); var c = tokenizer.data[tokenizer.position]; if (c === '[') break; if (c === ';' || c === '*') { markLine(tokenizer); continue; } for (var j = 0; j < 2; ++j) { skipWhitespace(tokenizer); markStart(tokenizer); eatValue(tokenizer); switch (j) { case 0: TokenBuilder.add(ai, tokenizer.tokenStart, tokenizer.tokenEnd); break; case 1: TokenBuilder.add(aj, tokenizer.tokenStart, tokenizer.tokenEnd); break; } } // ignore any extra columns markLine(tokenizer); } return Table.ofColumns(BondsSchema, { ai: TokenColumn(ai)(Column.Schema.int), aj: TokenColumn(aj)(Column.Schema.int), }); } function handleSystem(state) { var tokenizer = state.tokenizer; var system = undefined; while (tokenizer.tokenEnd < tokenizer.length) { skipWhitespace(tokenizer); var c = tokenizer.data[tokenizer.position]; if (c === '[') break; if (c === ';' || c === '*') { markLine(tokenizer); continue; } if (system !== undefined) throw new Error('more than one system'); system = readLine(tokenizer).trim(); } if (system === undefined) throw new Error('missing system'); return system; } function handleMolecules(state) { var tokenizer = state.tokenizer; var compound = TokenBuilder.create(tokenizer.data, 64); var molCount = TokenBuilder.create(tokenizer.data, 64); while (tokenizer.tokenEnd < tokenizer.length) { skipWhitespace(tokenizer); if (tokenizer.position >= tokenizer.length) break; var c = tokenizer.data[tokenizer.position]; if (c === '[') break; if (c === ';' || c === '*') { markLine(tokenizer); continue; } for (var j = 0; j < 2; ++j) { skipWhitespace(tokenizer); markStart(tokenizer); eatValue(tokenizer); switch (j) { case 0: TokenBuilder.add(compound, tokenizer.tokenStart, tokenizer.tokenEnd); break; case 1: TokenBuilder.add(molCount, tokenizer.tokenStart, tokenizer.tokenEnd); break; } } // ignore any extra columns eatLine(tokenizer); markStart(tokenizer); } return Table.ofColumns(MoleculesSchema, { compound: TokenColumn(compound)(Column.Schema.str), molCount: TokenColumn(molCount)(Column.Schema.int), }); } function parseInternal(data, ctx) { return __awaiter(this, void 0, void 0, function () { function addMol() { if (currentMolName && currentCompound.atoms) { result.compounds[currentMolName] = currentCompound; currentCompound = {}; currentMolName = ''; } } var t, state, result, prevPosition, currentCompound, currentMolName, line, fieldMatch, fieldName; return __generator(this, function (_a) { switch (_a.label) { case 0: t = Tokenizer(data); state = State(t, ctx); result = Object.create(null); prevPosition = 0; result.compounds = {}; currentCompound = {}; currentMolName = ''; _a.label = 1; case 1: if (!(t.tokenEnd < t.length)) return [3 /*break*/, 4]; if (!(t.position - prevPosition > 100000 && ctx.shouldUpdate)) return [3 /*break*/, 3]; prevPosition = t.position; return [4 /*yield*/, ctx.update({ current: t.position, max: t.length })]; case 2: _a.sent(); _a.label = 3; case 3: line = readLine(state.tokenizer).trim(); if (!line || line[0] === '*' || line[0] === ';') { return [3 /*break*/, 1]; } if (line.startsWith('#include')) { throw new Error('#include statements not allowed'); } if (line.startsWith('[')) { fieldMatch = line.match(reField); if (fieldMatch === null) throw new Error('expected field name'); fieldName = fieldMatch[1]; if (fieldName === 'moleculetype') { addMol(); currentMolName = handleMoleculetype(state); } else if (fieldName === 'atoms') { currentCompound.atoms = handleAtoms(state); } else if (fieldName === 'bonds') { currentCompound.bonds = handleBonds(state); } else if (fieldName === 'system') { result.system = handleSystem(state); } else if (fieldName === 'molecules') { addMol(); // add the last compound result.molecules = handleMolecules(state); } else { while (t.tokenEnd < t.length) { if (t.data[t.position] === '[') break; markLine(t); } } } return [3 /*break*/, 1]; case 4: return [2 /*return*/, Result.success(result)]; } }); }); } export function parseTop(data) { var _this = this; return Task.create('Parse TOP', 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()]; } }); }); }); }