molstar
Version:
A comprehensive macromolecular library.
328 lines • 17.8 kB
JavaScript
"use strict";
/**
* Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Sebastian Bittrich <sebastian.bittrich@rcsb.org>
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.Mol2Encoder = void 0;
var tslib_1 = require("tslib");
var ligand_encoder_1 = require("../ligand-encoder");
var mol_util_1 = require("../../../mol-util");
var util_1 = require("../cif/encoder/util");
var types_1 = require("../../../mol-model/structure/model/types");
// type MOL_TYPE = 'SMALL' | 'BIOPOLYMER' | 'PROTEIN' | 'NUCLEIC_ACID' | 'SACCHARIDE';
// type CHARGE_TYPE = 'NO_CHARGES' | 'DEL_RE' | 'GASTEIGER' | 'GAST_HUCK' | 'HUCKEL' | 'PULLMAN' | 'GAUSS80_CHARGES' | 'AMPAC_CHARGES' | 'MULLIKEN_CHARGES' | 'DICT_ CHARGES' | 'MMFF94_CHARGES' | 'USER_CHARGES';
var NON_METAL_ATOMS = 'H D B C N O F Si P S Cl As Se Br Te I At He Ne Ar Kr Xe Rn'.split(' ');
// specification: http://chemyang.ccnu.edu.cn/ccb/server/AIMMS/mol2.pdf
var Mol2Encoder = /** @class */ (function (_super) {
(0, tslib_1.__extends)(Mol2Encoder, _super);
function Mol2Encoder(encoder, metaInformation, hydrogens) {
var _this = _super.call(this, encoder, metaInformation, hydrogens) || this;
_this.out = mol_util_1.StringBuilder.create();
return _this;
}
Mol2Encoder.prototype._writeCategory = function (category, context) {
var _this = this;
var a = mol_util_1.StringBuilder.create();
var b = mol_util_1.StringBuilder.create();
var _a = (0, util_1.getCategoryInstanceData)(category, context), instance = _a.instance, source = _a.source;
// write header
var name = this.getName(instance, source);
mol_util_1.StringBuilder.writeSafe(this.builder, "# Name: " + name + "\n# Created by " + this.encoder + "\n\n");
var bondMap = this.componentBondData.entries.get(name);
var bondCount = 0;
var atoms = this.getAtoms(instance, source);
mol_util_1.StringBuilder.writeSafe(a, '@<TRIPOS>ATOM\n');
mol_util_1.StringBuilder.writeSafe(b, '@<TRIPOS>BOND\n');
atoms.forEach(function (atom1, label_atom_id1) {
var i1 = atom1.index;
if (bondMap === null || bondMap === void 0 ? void 0 : bondMap.map) {
bondMap.map.get(label_atom_id1).forEach(function (bond, label_atom_id2) {
var atom2 = atoms.get(label_atom_id2);
if (!atom2)
return;
var i2 = atom2.index, type_symbol2 = atom2.type_symbol;
if (i1 < i2 && !_this.skipHydrogen(type_symbol2)) {
var order = bond.order, flags = bond.flags;
var ar = types_1.BondType.is(16 /* Aromatic */, flags);
mol_util_1.StringBuilder.writeSafe(b, ++bondCount + " " + (i1 + 1) + " " + (i2 + 1) + " " + (ar ? 'ar' : order));
mol_util_1.StringBuilder.newline(b);
}
});
}
var sybyl = (bondMap === null || bondMap === void 0 ? void 0 : bondMap.map) ? _this.mapToSybyl(label_atom_id1, atom1.type_symbol, bondMap) : atom1.type_symbol;
mol_util_1.StringBuilder.writeSafe(a, i1 + 1 + " " + label_atom_id1 + " " + atom1.Cartn_x.toFixed(3) + " " + atom1.Cartn_y.toFixed(3) + " " + atom1.Cartn_z.toFixed(3) + " " + sybyl + " 1 " + name + " 0.000\n");
});
// could write something like 'SMALL\nNO_CHARGES', for now let's write **** indicating non-optional, yet missing, string values
mol_util_1.StringBuilder.writeSafe(this.out, "@<TRIPOS>MOLECULE\n" + name + "\n" + atoms.size + " " + bondCount + " 1\n****\n****\n\n");
mol_util_1.StringBuilder.writeSafe(this.out, mol_util_1.StringBuilder.getString(a));
mol_util_1.StringBuilder.writeSafe(this.out, mol_util_1.StringBuilder.getString(b));
mol_util_1.StringBuilder.writeSafe(this.out, "@<TRIPOS>SUBSTRUCTURE\n1 " + name + " 1\n");
};
Mol2Encoder.prototype.count = function (map, ctx, predicate) {
var count = 0;
var iter = map.entries();
var result = iter.next();
while (!result.done) {
if (predicate(result.value[0], result.value[1], ctx)) {
count++;
}
result = iter.next();
}
return count;
};
Mol2Encoder.prototype.orderSum = function (map) {
var sum = 0;
var iter = map.values();
var result = iter.next();
while (!result.done) {
sum += result.value.order;
result = iter.next();
}
return sum;
};
Mol2Encoder.prototype.isNonMetalBond = function (label_atom_id) {
for (var _i = 0, NON_METAL_ATOMS_1 = NON_METAL_ATOMS; _i < NON_METAL_ATOMS_1.length; _i++) {
var a = NON_METAL_ATOMS_1[_i];
if (label_atom_id.startsWith(a))
return true;
}
return false;
};
Mol2Encoder.prototype.extractNonmets = function (map) {
var ret = new Map();
var iter = map.entries();
var result = iter.next();
while (!result.done) {
var _a = result.value, k = _a[0], v = _a[1];
if (this.isNonMetalBond(k)) {
ret.set(k, v);
}
result = iter.next();
}
return ret;
};
// see https://www.sdsc.edu/CCMS/Packages/cambridge/pluto/atom_types.html
// cannot account for covalently bound amino acids etc
Mol2Encoder.prototype.mapToSybyl = function (label_atom_id1, type_symbol1, bondMap) {
// TODO if altLoc: 'Du' // 1.1
// TODO if end of polymeric bond: 'Du' // 1.2
if (type_symbol1 === 'D')
return 'H'; // 1.3
if (type_symbol1 === 'P')
return 'P.3'; // 1.4, 4mpo/ligand?encoding=mol2&auth_seq_id=203 (PO4)
if (type_symbol1 === 'Co' || type_symbol1 === 'Ru')
return type_symbol1 + '.oh'; // 1.5
var bonds = bondMap.map.get(label_atom_id1);
var numBonds = bonds.size;
if (type_symbol1 === 'Ti' || type_symbol1 === 'Cr') { // 1.10
return type_symbol1 + (numBonds <= 4 ? '.th' : '.oh'); // 1.10.1 & 1.10.2
}
if (type_symbol1 === 'C') { // 1.6
if (numBonds >= 4 && this.count(bonds, this, function (_k, v) { return v.order === 1; }) >= 4)
return 'C.3'; // 1.6.1, 3rga/ligand?encoding=mol2&auth_seq_id=307 (MOH)
if (numBonds === 3 && this.isCat(bonds, bondMap))
return 'C.cat'; // 1.6.2, 1acj/ligand?encoding=mol2&auth_seq_id=44 (ARG), 5vjb/ligand?encoding=mol2&auth_seq_id=101 (GAI)
if (numBonds >= 2 && this.count(bonds, this, function (_k, v) { return types_1.BondType.is(16 /* Aromatic */, v.flags); }) >= 2)
return 'C.ar'; // 1.6.3, 1acj/ligand?encoding=mol2&auth_seq_id=30 (PHE), 1acj/ligand?encoding=mol2&auth_seq_id=63 (TYR), 1acj/ligand?encoding=mol2&auth_seq_id=84 (TRP), 1acj/ligand?encoding=mol2&auth_seq_id=999 (THA)
if ((numBonds === 1 || numBonds === 2) && this.count(bonds, this, function (_k, v) { return v.order === 3; }))
return 'C.1'; // 1.6.4, 3i04/ligand?encoding=mol2&auth_asym_id=C&auth_seq_id=900 (CYN)
return 'C.2'; // 1.6.5
}
// most of the time, bonds will equal non-metal bonds
var nonmets = this.count(bonds, this, function (k, _v, ctx) { return ctx.isNonMetalBond(k); }) === bonds.size ? bonds : this.extractNonmets(bonds);
var numNonmets = nonmets.size;
if (type_symbol1 === 'O') { // 1.7
if (numNonmets === 1) { // 1.7.1
if (this.isOC(nonmets, bondMap))
return 'O.co2'; // 1.7.1.1, 4h2v/ligand?encoding=mol2&auth_seq_id=403 (ACT)
if (this.isOP(nonmets, bondMap))
return 'O.co2'; // 1.7.1.2, 4mpo/ligand?encoding=mol2&auth_seq_id=203 (PO4)
}
if (numNonmets >= 2 && this.count(bonds, this, function (_k, v) { return v.order === 1; }) === bonds.size)
return 'O.3'; // 1.7.2, 1acj/ligand?encoding=mol2&auth_seq_id=601 (HOH), 3rga/ligand?encoding=mol2&auth_seq_id=307 (MOH)
return 'O.2'; // 1.7.3, 1acj/ligand?encoding=mol2&auth_seq_id=4 (SER)
}
if (type_symbol1 === 'N') { // 1.8
if (numNonmets === 4 && this.count(nonmets, this, function (_k, v) { return v.order === 1; }) === 4)
return 'N.4'; // 1.8.1, 4ikf/ligand?encoding=mol2&auth_seq_id=403 (NH4)
if (numBonds >= 2 && this.count(bonds, this, function (_k, v) { return types_1.BondType.is(16 /* Aromatic */, v.flags); }) >= 2)
return 'N.ar'; // 1.8.2, 1acj/ligand?encoding=mol2&auth_seq_id=84 (TRP), 1acj/ligand?encoding=mol2&auth_seq_id=999 (THA)
if (numNonmets === 1 && this.count(nonmets, this, function (_k, v) { return v.order === 3; }))
return 'N.1'; // 1.8.3, 3i04/ligand?encoding=mol2&auth_asym_id=C&auth_seq_id=900 (CYN)
if (numNonmets === 2 && this.orderSum(nonmets) === 4)
return 'N.1'; // 1.8.4, 3sbr/ligand?encoding=mol2&auth_seq_id=640&auth_asym_id=D (N2O)
if (numNonmets === 3 && this.hasCOCS(nonmets, bondMap))
return 'N.am'; // 1.8.5, 3zfz/ligand?encoding=mol2&auth_seq_id=1669 (1W8)
if (numNonmets === 3) { // 1.8.6
if (this.count(nonmets, this, function (_k, v) { return v.order > 1; }) === 1)
return 'N.pl3'; // 1.8.6.1, 4hon/ligand?encoding=mol2&auth_seq_id=407 (NO3)
if (this.count(nonmets, this, function (_k, v) { return v.order === 1; }) === 3) {
if (this.isNpl3(nonmets, bondMap))
return 'N.pl3'; // 1.8.6.1.1 & 1.8.6.1.2, 1acj/ligand?encoding=mol2&auth_seq_id=44 (ARG), 5vjb/ligand?encoding=mol2&auth_seq_id=101 (GAI)
}
return 'N.3';
}
return 'N.2'; // 1.8.7, 1acj/ligand?encoding=mol2&auth_seq_id=4 (SER)
}
if (type_symbol1 === 'S') { // 1.9
if (numNonmets === 3 && this.countOfOxygenWithSingleNonmet(nonmets, bondMap) === 1)
return 'S.o'; // 1.9.1, 4i03/ligand?encoding=mol2&auth_seq_id=312 (DMS)
if (numNonmets === 4 && this.countOfOxygenWithSingleNonmet(nonmets, bondMap) === 2)
return 'S.o2'; // 1.9.2, 1udt/ligand?encoding=mol2&auth_seq_id=1000 (VIA)
if (numNonmets >= 2 && this.count(bonds, this, function (_k, v) { return v.order === 1; }) >= 2)
return 'S.3'; // 1.9.3, 3zfz/ligand?encoding=mol2&auth_seq_id=1669 (1W8), 4gpc/ligand?encoding=mol2&auth_seq_id=902 (SO4)
return 'S.2'; // 1.9.4
}
return type_symbol1; // 1.11
};
// 1.8.6.2.1: If one single bond is to an atom that forms a bond of type double, triple, aromatic or
// delocalised .AND. one other single bond is to H then atom_type is N.pl3
// 1.8.6.2.2: If one single bond is to an atom that forms a bond of type double, triple, aromatic or
// delocalised .AND. neither of the other single bonds are to H .AND. sum_of_angles around N .ge. 350 deg then atom_type is N.pl3
// TODO cannot check accurately for delocalized bonds
Mol2Encoder.prototype.isNpl3 = function (nonmets, bondMap) {
var iter = nonmets.keys();
var result = iter.next();
while (!result.done) {
var label_atom_id = result.value;
var adjacentBonds = bondMap.map.get(label_atom_id);
if (this.count(adjacentBonds, this, function (_k, v) { return v.order > 1 || types_1.BondType.is(16 /* Aromatic */, v.flags); })) {
// TODO check accurately for 2nd criterion with coordinates
return true;
}
result = iter.next();
}
return false;
};
// If bond is to carbon .AND. carbon forms a total of 3 bonds, 2 of which are to an oxygen
// forming only 1 non-metal bond then atom_type is O.co2
Mol2Encoder.prototype.isOC = function (nonmets, bondMap) {
var nonmet = nonmets.entries().next().value;
if (!nonmet[0].startsWith('C'))
return false;
var carbonBonds = bondMap.map.get(nonmet[0]);
if (carbonBonds.size !== 3)
return false;
var count = 0;
var iter = carbonBonds.keys();
var result = iter.next();
while (!result.done) {
var label_atom_id = result.value;
if (label_atom_id.startsWith('O')) {
var adjacentBonds = bondMap.map.get(label_atom_id);
if (this.count(adjacentBonds, this, function (k, _v, ctx) { return ctx.isNonMetalBond(k); }) === 1)
count++;
}
result = iter.next();
}
return count === 2;
};
// If bond is to phosphorus .AND. phosphorus forms at least 2 bonds to an oxygen forming
// only 1 non-metal bond then atom_type is O.co2
Mol2Encoder.prototype.isOP = function (nonmets, bondMap) {
var nonmet = nonmets.entries().next().value;
if (!nonmet[0].startsWith('P'))
return false;
var phosphorusBonds = bondMap.map.get(nonmet[0]);
if (phosphorusBonds.size < 2)
return false;
var count = 0;
var iter = phosphorusBonds.keys();
var result = iter.next();
while (!result.done) {
var label_atom_id = result.value;
if (label_atom_id.startsWith('O')) {
var adjacentBonds = bondMap.map.get(label_atom_id);
if (this.count(adjacentBonds, this, function (k, _v, ctx) { return ctx.isNonMetalBond(k); }) === 1)
count++;
}
result = iter.next();
}
return count >= 2;
};
// If num_bond .eq. 3 .AND. all bonds are acyclic .AND. all bonds are to nitrogen .AND. each
// nitrogen forms bonds to 2 other atoms both of which are not oxygen then atom_type is C.cat.
Mol2Encoder.prototype.isCat = function (currentBondMap, bondMap) {
var iter1 = currentBondMap.keys();
var result1 = iter1.next();
while (!result1.done) {
var label_atom_id = result1.value;
if (!label_atom_id.startsWith('N'))
return false;
var adjacentBonds = bondMap.map.get(label_atom_id);
if (adjacentBonds.size < 2)
return false;
var iter2 = adjacentBonds.keys();
var result2 = iter2.next();
while (!result2.done) {
if (result2.value.startsWith('O'))
return false;
result2 = iter2.next();
}
result1 = iter1.next();
}
// TODO ensure no cycles
return true;
};
Mol2Encoder.prototype.countOfOxygenWithSingleNonmet = function (nonmets, bondMap) {
var count = 0;
var iter = nonmets.keys();
var result = iter.next();
while (!result.done) {
var label_atom_id = result.value;
if (label_atom_id.startsWith('O')) {
var adjacentBonds = bondMap.map.get(label_atom_id);
if (this.count(adjacentBonds, this, function (k, _v, ctx) { return ctx.isNonMetalBond(k); }))
count++;
}
result = iter.next();
}
return count;
};
// If num_nonmet .eq. 3 .AND. one bond is to C=O or C=S then atom_type is N.am
Mol2Encoder.prototype.hasCOCS = function (nonmets, bondMap) {
var iter = nonmets.keys();
var result = iter.next();
while (!result.done) {
var label_atom_id = result.value;
if (label_atom_id.startsWith('C')) {
var adjacentBonds = bondMap.map.get(label_atom_id);
if (this.count(adjacentBonds, this, function (k, v) { return k.startsWith('O') || k.startsWith('S') && v.order === 2; }))
return true;
}
result = iter.next();
}
return false;
};
Mol2Encoder.prototype.writeFullCategory = function (sb, category, context) {
var _a = (0, util_1.getCategoryInstanceData)(category, context), instance = _a.instance, source = _a.source;
var fields = instance.fields;
var src = source[0];
if (!src)
return;
var data = src.data;
var it = src.keys();
var key = it.move();
for (var _f = 0; _f < fields.length; _f++) {
var f = fields[_f];
mol_util_1.StringBuilder.writeSafe(sb, "# " + category.name + "." + f.name + ": ");
var val = f.value(key, data, 0);
mol_util_1.StringBuilder.writeSafe(sb, val);
mol_util_1.StringBuilder.newline(sb);
}
mol_util_1.StringBuilder.newline(sb);
};
Mol2Encoder.prototype.encode = function () {
// write meta-information, do so after ctab
if (this.error || this.metaInformation) {
mol_util_1.StringBuilder.writeSafe(this.builder, mol_util_1.StringBuilder.getString(this.meta));
}
mol_util_1.StringBuilder.writeSafe(this.builder, mol_util_1.StringBuilder.getString(this.out));
this.encoded = true;
};
return Mol2Encoder;
}(ligand_encoder_1.LigandEncoder));
exports.Mol2Encoder = Mol2Encoder;
//# sourceMappingURL=encoder.js.map