molstar
Version:
A comprehensive macromolecular library.
210 lines (206 loc) • 8.97 kB
JavaScript
"use strict";
/**
* Copyright (c) 2020-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author David Sehnal <david.sehnal@gmail.com>
* @author Panagiotis Tourlas <panagiot_tourlov@hotmail.com>
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.formalChargeMapper = formalChargeMapper;
exports.handleAtoms = handleAtoms;
exports.handleBonds = handleBonds;
exports.handleFormalCharges = handleFormalCharges;
exports.handlePropertiesBlock = handlePropertiesBlock;
exports.parseMol = parseMol;
const db_1 = require("../../../mol-data/db");
const mol_task_1 = require("../../../mol-task");
const token_1 = require("../common/text/column/token");
const tokenizer_1 = require("../common/text/tokenizer");
const result_1 = require("../result");
/*
The atom lines in a .mol file have the following structure:
xxxxx.xxxxyyyyy.yyyyzzzzz.zzzz aaaddcccssshhhbbbvvvHHHrrriiimmmnnneee
---------------------------------------------------------------------
Below is a breakdown of each component and its start/end indices:
xxxxx.xxxx (X COORDINATE, 1-10)
yyyyy.yyyy (Y COORDINATE, 10-20)
zzzzz.zzzz (Z COORDINATE, 20-30)
_ (30 IS EMPTY)
aaa (ATOM SYMBOL, 31-34)
dd (MASS DIFF, 34-36)
ccc (FORMAL CHARGE, 36-39)
sss (ATOM STEREO PARITY, 39-42)
hhh (HYDROGEN COUNT+1, 42-45)
bbb (STEREO CARE BOX, 45-48)
vvv (VALENCE, 48-51)
HHH (H0 DESIGNATOR, 51-54)
rrr (UNUSED, 54-57)
iii (UNUSED, 57-60)
mmm (ATOM-ATOM MAPPING NUMBER, 60-63)
nnn (INVERSION/RETENTION FLAG, 63-66)
eee (EXACT CHANGE FLAG, 66-69)
*/
/**
* @param key - The value found at the atom block.
* @returns The actual formal charge based on the mapping.
*/
function formalChargeMapper(key) {
switch (key) {
case 7: return -3;
case 6: return -2;
case 5: return -1;
case 0: return 0;
case 3: return 1;
case 2: return 2;
case 1: return 3;
case 4: return 0;
default:
console.error(`Value ${key} is outside the 0-7 range, defaulting to 0.`);
return 0;
}
}
function handleAtoms(tokenizer, count) {
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 type_symbol = tokenizer_1.TokenBuilder.create(tokenizer.data, count * 2);
const formal_charge = tokenizer_1.TokenBuilder.create(tokenizer.data, count * 2);
for (let i = 0; i < count; ++i) {
tokenizer_1.Tokenizer.markLine(tokenizer);
const { tokenStart: s, position } = tokenizer;
tokenizer_1.Tokenizer.trim(tokenizer, s, s + 10);
tokenizer_1.TokenBuilder.addUnchecked(x, tokenizer.tokenStart, tokenizer.tokenEnd);
tokenizer_1.Tokenizer.trim(tokenizer, s + 10, s + 20);
tokenizer_1.TokenBuilder.addUnchecked(y, tokenizer.tokenStart, tokenizer.tokenEnd);
tokenizer_1.Tokenizer.trim(tokenizer, s + 20, s + 30);
tokenizer_1.TokenBuilder.addUnchecked(z, tokenizer.tokenStart, tokenizer.tokenEnd);
tokenizer_1.Tokenizer.trim(tokenizer, s + 31, s + 34);
tokenizer_1.TokenBuilder.addUnchecked(type_symbol, tokenizer.tokenStart, tokenizer.tokenEnd);
tokenizer_1.Tokenizer.trim(tokenizer, s + 36, s + 39);
tokenizer_1.TokenBuilder.addUnchecked(formal_charge, tokenizer.tokenStart, tokenizer.tokenEnd);
tokenizer.position = position;
}
return {
count,
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),
type_symbol: (0, token_1.TokenColumnProvider)(type_symbol)(db_1.Column.Schema.str),
formal_charge: (0, token_1.TokenColumnProvider)(formal_charge)(db_1.Column.Schema.int)
};
}
function handleBonds(tokenizer, count) {
const atomIdxA = tokenizer_1.TokenBuilder.create(tokenizer.data, count * 2);
const atomIdxB = tokenizer_1.TokenBuilder.create(tokenizer.data, count * 2);
const order = tokenizer_1.TokenBuilder.create(tokenizer.data, count * 2);
for (let i = 0; i < count; ++i) {
tokenizer_1.Tokenizer.markLine(tokenizer);
const { tokenStart: s, position } = tokenizer;
tokenizer_1.Tokenizer.trim(tokenizer, s, s + 3);
tokenizer_1.TokenBuilder.addUnchecked(atomIdxA, tokenizer.tokenStart, tokenizer.tokenEnd);
tokenizer_1.Tokenizer.trim(tokenizer, s + 3, s + 6);
tokenizer_1.TokenBuilder.addUnchecked(atomIdxB, tokenizer.tokenStart, tokenizer.tokenEnd);
tokenizer_1.Tokenizer.trim(tokenizer, s + 6, s + 9);
tokenizer_1.TokenBuilder.addUnchecked(order, tokenizer.tokenStart, tokenizer.tokenEnd);
tokenizer.position = position;
}
return {
count,
atomIdxA: (0, token_1.TokenColumnProvider)(atomIdxA)(db_1.Column.Schema.int),
atomIdxB: (0, token_1.TokenColumnProvider)(atomIdxB)(db_1.Column.Schema.int),
order: (0, token_1.TokenColumnProvider)(order)(db_1.Column.Schema.int)
};
}
function handleFormalCharges(tokenizer, lineStart, formalCharges) {
tokenizer_1.Tokenizer.trim(tokenizer, lineStart + 6, lineStart + 9);
const numOfCharges = parseInt(tokenizer_1.Tokenizer.getTokenString(tokenizer));
for (let i = 0; i < numOfCharges; ++i) {
/*
M CHG 3 1 -1 2 0 2 -1
| | | | |
| | | | |__charge2 (etc.)
| | | |
| | | |__atomIdx2
| | |
| | |__charge1
| |
| |__atomIdx1 (cursor at position 12)
|
|___numOfCharges
*/
const offset = 9 + (i * 8);
tokenizer_1.Tokenizer.trim(tokenizer, lineStart + offset, lineStart + offset + 4);
const _atomIdx = tokenizer_1.Tokenizer.getTokenString(tokenizer);
formalCharges.atomIdx.push(+_atomIdx);
tokenizer_1.Tokenizer.trim(tokenizer, lineStart + offset + 4, lineStart + offset + 8);
const _charge = tokenizer_1.Tokenizer.getTokenString(tokenizer);
formalCharges.charge.push(+_charge);
}
/* Once the line is read, move to the next one. */
tokenizer_1.Tokenizer.eatLine(tokenizer);
}
function handleAttachmentPoints(line) {
const tokens = line.trim().split(/\s+/g);
const points = [];
for (let i = 1; i < tokens.length; i += 2) {
const atomIdx = +tokens[i];
const kind = +tokens[i + 1] || 0;
points.push({ atomIdx, kind });
}
return points;
}
/** Call an appropriate handler based on the property type.
*/
function handlePropertiesBlock(tokenizer) {
const _atomIdx = [];
const _charge = [];
const _formalCharges = { atomIdx: _atomIdx, charge: _charge };
let attachmentPoints = undefined;
while (tokenizer.position < tokenizer.length) {
const { position: s } = tokenizer;
tokenizer_1.Tokenizer.trim(tokenizer, s + 3, s + 6);
const propertyType = tokenizer_1.Tokenizer.getTokenString(tokenizer);
if (propertyType === 'END')
break;
tokenizer_1.Tokenizer.eatLine(tokenizer);
switch (propertyType) {
case 'CHG':
handleFormalCharges(tokenizer, s, _formalCharges);
break;
case 'APO':
attachmentPoints = handleAttachmentPoints(tokenizer_1.Tokenizer.getTokenString(tokenizer).substring(3));
break;
default:
break;
}
}
const formalCharges = {
atomIdx: db_1.Column.ofIntArray(_formalCharges.atomIdx),
charge: db_1.Column.ofIntArray(_formalCharges.charge)
};
return { formalCharges, attachmentPoints };
}
function parseInternal(data) {
const tokenizer = (0, tokenizer_1.Tokenizer)(data);
const title = tokenizer_1.Tokenizer.readLine(tokenizer).trim();
const program = tokenizer_1.Tokenizer.readLine(tokenizer).trim();
const comment = tokenizer_1.Tokenizer.readLine(tokenizer).trim();
const counts = tokenizer_1.Tokenizer.readLine(tokenizer);
const atomCount = +counts.substr(0, 3), bondCount = +counts.substr(3, 3);
const atoms = handleAtoms(tokenizer, atomCount);
const bonds = handleBonds(tokenizer, bondCount);
const result = {
title,
program,
comment,
atoms,
bonds,
...handlePropertiesBlock(tokenizer),
};
return result_1.ReaderResult.success(result);
}
function parseMol(data) {
return mol_task_1.Task.create('Parse Mol', async () => {
return parseInternal(data);
});
}