molstar
Version:
A comprehensive macromolecular library.
163 lines (162 loc) • 5.96 kB
JavaScript
/**
* Copyright (c) 2019-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports._parseDcd = _parseDcd;
exports.parseDcd = parseDcd;
const result_1 = require("../result");
const mol_task_1 = require("../../../mol-task");
const binary_1 = require("../../common/binary");
function _parseDcd(data) {
// http://www.ks.uiuc.edu/Research/vmd/plugins/molfile/dcdplugin.html
// The DCD format is structured as follows
// (FORTRAN UNFORMATTED, with Fortran data type descriptions):
// HDR NSET ISTRT NSAVC 5-ZEROS NATOM-NFREAT DELTA 9-ZEROS
// `CORD' #files step 1 step zeroes (zero) timestep (zeroes)
// interval
// C*4 INT INT INT 5INT INT DOUBLE 9INT
// ==========================================================================
// NTITLE TITLE
// INT (=2) C*MAXTITL
// (=32)
// ==========================================================================
// NATOM
// #atoms
// INT
// ==========================================================================
// X(I), I=1,NATOM (DOUBLE)
// Y(I), I=1,NATOM
// Z(I), I=1,NATOM
// ==========================================================================
const dv = new DataView(data.buffer);
const header = Object.create(null);
const frames = [];
let nextPos = 0;
// header block
const intView = new Int32Array(data.buffer, 0, 23);
const ef = intView[0] !== dv.getInt32(0); // endianess flag
// swap byte order when big endian (84 indicates little endian)
if (intView[0] !== 84) {
const n = data.byteLength;
for (let i = 0; i < n; i += 4) {
dv.setFloat32(i, dv.getFloat32(i), true);
}
}
if (intView[0] !== 84) {
throw new Error('dcd bad format, header block start');
}
// format indicator, should read 'CORD'
const formatString = String.fromCharCode(dv.getUint8(4), dv.getUint8(5), dv.getUint8(6), dv.getUint8(7));
if (formatString !== 'CORD') {
throw new Error('dcd bad format, format string');
}
let isCharmm = false;
let extraBlock = false;
let fourDims = false;
// version field in charmm, unused in X-PLOR
if (intView[22] !== 0) {
isCharmm = true;
if (intView[12] !== 0)
extraBlock = true;
if (intView[13] === 1)
fourDims = true;
}
header.NSET = intView[2];
header.ISTART = intView[3];
header.NSAVC = intView[4];
header.NAMNF = intView[10];
if (isCharmm) {
header.DELTA = dv.getFloat32(44, ef);
}
else {
header.DELTA = dv.getFloat64(44, ef);
}
if (intView[22] !== 84) {
throw new Error('dcd bad format, header block end');
}
nextPos = nextPos + 21 * 4 + 8;
// title block
const titleEnd = dv.getInt32(nextPos, ef);
const titleStart = nextPos + 1;
if ((titleEnd - 4) % 80 !== 0) {
throw new Error('dcd bad format, title block start');
}
header.TITLE = (0, binary_1.uint8ToString)(data.subarray(titleStart, titleEnd));
if (dv.getInt32(titleStart + titleEnd + 4 - 1, ef) !== titleEnd) {
throw new Error('dcd bad format, title block end');
}
nextPos = nextPos + titleEnd + 8;
// natom block
if (dv.getInt32(nextPos, ef) !== 4) {
throw new Error('dcd bad format, natom block start');
}
header.NATOM = dv.getInt32(nextPos + 4, ef);
if (dv.getInt32(nextPos + 8, ef) !== 4) {
throw new Error('dcd bad format, natom block end');
}
nextPos = nextPos + 4 + 8;
// fixed atoms block
if (header.NAMNF > 0) {
// TODO read coordinates and indices of fixed atoms
throw new Error('dcd format with fixed atoms unsupported, aborting');
}
// frames
const natom = header.NATOM;
const natom4 = natom * 4;
for (let i = 0, n = header.NSET; i < n; ++i) {
const frame = Object.create(null);
frame.elementCount = natom;
if (extraBlock) {
nextPos += 4; // block start
frame.cell = [
dv.getFloat64(nextPos, ef),
dv.getFloat64(nextPos + 1, ef),
dv.getFloat64(nextPos + 2 * 8, ef),
dv.getFloat64(nextPos + 3 * 8, ef),
dv.getFloat64(nextPos + 4 * 8, ef),
dv.getFloat64(nextPos + 5 * 8, ef)
];
nextPos += 48;
nextPos += 4; // block end
}
// xyz coordinates
for (let j = 0; j < 3; ++j) {
if (dv.getInt32(nextPos, ef) !== natom4) {
throw new Error(`dcd bad format, coord block start: ${i}, ${j}`);
}
nextPos += 4; // block start
const c = new Float32Array(data.buffer, nextPos, natom);
if (j === 0)
frame.x = c;
else if (j === 1)
frame.y = c;
else
frame.z = c;
nextPos += natom4;
if (dv.getInt32(nextPos, ef) !== natom4) {
throw new Error(`dcd bad format, coord block end: ${i}, ${j}`);
}
nextPos += 4; // block end
}
if (fourDims) {
const bytes = dv.getInt32(nextPos, ef);
nextPos += 4 + bytes + 4; // block start + skip + block end
}
frames.push(frame);
}
return { header, frames };
}
function parseDcd(data) {
return mol_task_1.Task.create('Parse DCD', async (ctx) => {
try {
const dcdFile = _parseDcd(data);
return result_1.ReaderResult.success(dcdFile);
}
catch (e) {
return result_1.ReaderResult.error(e);
}
});
}
;