@jenskrumsieck/moleculesjs
Version:
Some TypeScript Molecule Parsers
118 lines (117 loc) • 5 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const atom_1 = require("./primitives/atom");
const molecule_1 = __importDefault(require("./primitives/molecule"));
const vector3_1 = require("./primitives/vector3");
class CIF {
content;
a;
b;
c;
alpha;
beta;
gamma;
constructor(content) {
this.content = content.replace(/(?:[\r])/g, "");
this.setParameters();
}
static parse(content) {
var cif = new CIF(content);
return cif.parse();
}
parse() {
var loops = this.content.split('loop_');
var molLoop = loops.find(s => s.includes('_atom_site_label'));
var bondLoop = loops.find(s => s.includes('_geom_bond_atom_site_label_1'));
var atoms = this.extractAtoms(molLoop);
var bonds = this.extractBonds(bondLoop, atoms);
return new molecule_1.default({ atoms, bonds });
}
extractAtoms(molLoop) {
let lines = molLoop.split('\n');
let headers = lines.filter(s => s.trim().startsWith('_'));
let body = lines.filter(s => !s.trim().startsWith('_'));
let disorderIndex = headers.indexOf('_atom_site_disorder_group');
let data = [];
for (var i = 0; i < body.length; i++) {
var raw_data = body[i].split(' ');
if (disorderIndex >= 0
&& disorderIndex < raw_data.length
&& raw_data[disorderIndex] == "2" || raw_data.length != headers.length)
continue;
data.push(raw_data);
}
return this.calculateCartesian(data);
}
extractBonds(bondLoop, atoms) {
let lines = bondLoop.split('\n');
let body = lines.filter(s => !s.trim().startsWith('_'));
var bonds = [];
for (var i = 0; i < body.length; i++) {
var raw_data = body[i].split(" ");
let atom1 = raw_data[0];
let atom2 = raw_data[1];
//check if atoms existing
if (atoms.find(s => s.title == atom1) && atoms.find(s => s.title == atom2))
bonds.push({ atom1: atoms.find(s => s.title == atom1), atom2: atoms.find(s => s.title == atom2) });
}
return bonds;
}
cellParameters(type) {
let parameters = [];
let lines = this.content.split('\n');
for (var i = 0; i < lines.length; i++) {
if (lines[i].startsWith("_" + type)) {
//parameter value contains uncertainity in brackets, so strip that
var tmp = lines[i].split(" ");
var value = tmp[tmp.length - 1]; //last item
parameters.push(value.split('(')[0]);
}
}
return parameters;
}
setParameters() {
var lengths = this.cellParameters('cell_length');
var angles = this.cellParameters('cell_angle');
this.a = parseFloat(lengths[0]);
this.b = parseFloat(lengths[1]);
this.c = parseFloat(lengths[2]);
this.alpha = parseFloat(angles[0]);
this.beta = parseFloat(angles[1]);
this.gamma = parseFloat(angles[2]);
}
calculateCartesian(data) {
//variables introduced to deconfuse
var atoms = [];
for (var i = 0; i < data.length; i++) {
//get xyz in fractional coordinates
//1 is label, 2 is x, 3 is y, 4 is z
let xFrac = data[i][2].split('(')[0];
let yFrac = data[i][3].split('(')[0];
let zFrac = data[i][4].split('(')[0];
let angle = Math.PI / 180;
//transformation matrix: see https://en.wikipedia.org/wiki/Fractional_coordinates#Conversion_to_Cartesian_coordinates
//a21, a31, a32 = 0
//a11 = a
//other matrix entries as below:
let a12 = this.b * Math.cos(this.gamma * angle);
let a13 = this.c * Math.cos(this.beta * angle);
let a22 = this.b * Math.sin(this.gamma * angle);
let a23 = this.c * (Math.cos(this.alpha * angle) - Math.cos(this.beta * angle) * Math.cos(this.gamma * angle)) / Math.sin(this.gamma * angle);
let a33 = this.c * (Math.sqrt(1 - Math.pow(Math.cos(this.alpha * angle), 2) - Math.pow(Math.cos(this.beta * angle), 2) - Math.pow(Math.cos(this.gamma * angle), 2) + 2 * Math.cos(this.alpha * angle) * Math.cos(this.beta * angle) * Math.cos(this.gamma * angle))) / Math.sin(this.gamma * angle);
//xyz = [A]*(xyz)_frac
let x = this.a * xFrac + a12 * yFrac + a13 * zFrac;
let y = a22 * yFrac + a23 * zFrac;
let z = a33 * zFrac;
let element = data[i][1];
var atom = new atom_1.Atom(element, new vector3_1.Vector3(x, y, z));
atom.title = data[i][0];
atoms.push(atom);
}
return atoms;
}
}
exports.default = CIF;