molstar
Version:
A comprehensive macromolecular library.
247 lines • 11.2 kB
JavaScript
/**
* Copyright (c) 2019-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*
* based in part on NGL (https://github.com/arose/ngl)
*/
import { Unit } from '../../../mol-model/structure';
import { Features } from './features';
export function refineInteractions(structure, interactions) {
var contacts = interactions.contacts, unitsContacts = interactions.unitsContacts, unitsFeatures = interactions.unitsFeatures;
var contactRefiners = [
hydrophobicRefiner(structure, interactions),
weakHydrogenBondsRefiner(structure, interactions),
saltBridgeRefiner(structure, interactions),
piStackingRefiner(structure, interactions),
metalCoordinationRefiner(structure, interactions),
];
for (var i = 0, il = contacts.edgeCount; i < il; ++i) {
var e = contacts.edges[i];
var uA = structure.unitMap.get(e.unitA);
var uB = structure.unitMap.get(e.unitB);
var infoA = Features.Info(structure, uA, unitsFeatures.get(e.unitA));
infoA.feature = e.indexA;
var infoB = Features.Info(structure, uB, unitsFeatures.get(e.unitB));
infoB.feature = e.indexB;
for (var _i = 0, contactRefiners_1 = contactRefiners; _i < contactRefiners_1.length; _i++) {
var refiner = contactRefiners_1[_i];
if (refiner.isApplicable(e.props.type))
refiner.handleInterContact(i, infoA, infoB);
}
}
//
var ucKeys = unitsContacts.keys();
while (true) {
var _a = ucKeys.next(), done = _a.done, value = _a.value;
if (done)
break;
var contacts_1 = unitsContacts.get(value);
var features = unitsFeatures.get(value);
var unit = structure.unitMap.get(value);
if (!Unit.isAtomic(unit))
continue;
var infoA = Features.Info(structure, unit, features);
var infoB = Features.Info(structure, unit, features);
for (var _b = 0, contactRefiners_2 = contactRefiners; _b < contactRefiners_2.length; _b++) {
var refiner = contactRefiners_2[_b];
refiner.startUnit(unit, contacts_1, features);
}
for (var i = 0, il = contacts_1.edgeCount * 2; i < il; ++i) {
infoA.feature = contacts_1.a[i];
infoB.feature = contacts_1.b[i];
// console.log(i, contacts.a[i], contacts.b[i])
for (var _c = 0, contactRefiners_3 = contactRefiners; _c < contactRefiners_3.length; _c++) {
var refiner = contactRefiners_3[_c];
if (refiner.isApplicable(contacts_1.edgeProps.type[i]))
refiner.handleIntraContact(i, infoA, infoB);
}
}
}
}
/**
* For atoms interacting with several atoms in the same residue
* only the one with the closest distance is kept.
*/
function hydrophobicRefiner(structure, interactions) {
var contacts = interactions.contacts;
/* keep only closest contact between residues */
var handleResidueContact = function (dist, edge, key, map, set) {
var _a = map.get(key) || [Infinity, -1], minDist = _a[0], minIndex = _a[1];
if (dist < minDist) {
if (minIndex !== -1)
set(minIndex);
map.set(key, [dist, edge]);
}
else {
set(edge);
}
};
function handleEdge(edge, infoA, infoB, map, set) {
var elementA = infoA.members[infoA.offsets[infoA.feature]];
var elementB = infoB.members[infoB.offsets[infoB.feature]];
var residueA = infoA.unit.getResidueIndex(elementA);
var residueB = infoB.unit.getResidueIndex(elementB);
var keyA = elementA + "|" + infoA.unit.id + "|" + residueB + "|" + infoB.unit.id + "|A";
var keyB = elementB + "|" + infoB.unit.id + "|" + residueA + "|" + infoA.unit.id + "|B";
var dist = Features.distance(infoA, infoB);
handleResidueContact(dist, edge, keyA, map, set);
handleResidueContact(dist, edge, keyB, map, set);
}
var residueInterMap = new Map();
var setInterFiltered = function (i) { return contacts.edges[i].props.flag = 1 /* Filtered */; };
var residueIntraMap;
var setIntraFiltered;
return {
isApplicable: function (type) { return type === 6 /* Hydrophobic */; },
handleInterContact: function (index, infoA, infoB) {
handleEdge(index, infoA, infoB, residueInterMap, setInterFiltered);
},
startUnit: function (unit, contacts, features) {
residueIntraMap = new Map();
setIntraFiltered = function (i) { return contacts.edgeProps.flag[i] = 1 /* Filtered */; };
},
handleIntraContact: function (index, infoA, infoB) {
handleEdge(index, infoA, infoB, residueIntraMap, setIntraFiltered);
}
};
}
/**
* Remove weak hydrogen bonds when the acceptor is involved in
* a normal/strong hydrogen bond
*/
function weakHydrogenBondsRefiner(structure, interactions) {
var contacts = interactions.contacts;
var hasHydrogenBond = function (infoA, infoB) {
var acc = infoA.types[infoA.feature] === 9 /* WeakHydrogenDonor */ ? infoB : infoA;
// check intra
var eI = acc.members[acc.offsets[acc.feature]];
var _a = interactions.unitsContacts.get(acc.unit.id), type = _a.edgeProps.type, _b = _a.elementsIndex, offsets = _b.offsets, indices = _b.indices;
for (var i = offsets[eI], il = offsets[eI + 1]; i < il; ++i) {
if (type[indices[i]] === 4 /* HydrogenBond */)
return true;
}
// check inter
var interIndices = contacts.getEdgeIndices(acc.feature, acc.unit.id);
for (var i = 0, il = interIndices.length; i < il; ++i) {
if (contacts.edges[interIndices[i]].props.type === 4 /* HydrogenBond */)
return true;
}
return false;
};
return {
isApplicable: function (type) { return type === 8 /* WeakHydrogenBond */; },
handleInterContact: function (index, infoA, infoB) {
if (hasHydrogenBond(infoA, infoB)) {
contacts.edges[index].props.flag = 1 /* Filtered */;
}
},
startUnit: function () { },
handleIntraContact: function (index, infoA, infoB) {
if (hasHydrogenBond(infoA, infoB)) {
var flag = interactions.unitsContacts.get(infoA.unit.id).edgeProps.flag;
flag[index] = 1 /* Filtered */;
}
}
};
}
/**
* Filter inter-unit contact `index` if there is a contact of `types` between its members
*/
function filterInter(types, index, infoA, infoB, contacts) {
var offsetsA = infoA.offsets, featureA = infoA.feature;
var offsetsB = infoB.offsets, featureB = infoB.feature;
for (var i = offsetsA[featureA], il = offsetsA[featureA + 1]; i < il; ++i) {
var aI = infoA.members[i];
var indices = contacts.getContactIndicesForElement(aI, infoA.unit);
for (var k = 0, kl = indices.length; k < kl; ++k) {
var cI = indices[k];
if (types.includes(contacts.edges[cI].props.type)) {
for (var j = offsetsB[featureB], jl = offsetsB[featureB + 1]; j < jl; ++j) {
var bI = infoB.members[j];
if (contacts.getContactIndicesForElement(bI, infoB.unit).includes(cI)) {
contacts.edges[index].props.flag = 1 /* Filtered */;
return;
}
}
}
}
}
}
/**
* Filter intra-unit contact `index` if there is a contact of `types` between its members
*/
function filterIntra(types, index, infoA, infoB, contacts) {
var _a = contacts.edgeProps, type = _a.type, flag = _a.flag, _b = contacts.elementsIndex, offsets = _b.offsets, indices = _b.indices;
var offsetsA = infoA.offsets, featureA = infoA.feature;
var offsetsB = infoB.offsets, featureB = infoB.feature;
for (var i = offsetsA[featureA], il = offsetsA[featureA + 1]; i < il; ++i) {
var aI = infoA.members[i];
for (var k = offsets[aI], kl = offsets[aI + 1]; k < kl; ++k) {
var cI = indices[k];
if (types.includes(type[cI])) {
for (var j = offsetsB[featureB], jl = offsetsB[featureB + 1]; j < jl; ++j) {
var bI = infoB.members[j];
for (var l = offsets[bI], ll = offsets[bI + 1]; l < ll; ++l) {
if (cI === indices[l]) {
flag[index] = 1 /* Filtered */;
return;
}
}
}
}
}
}
}
/**
* Remove hydrogen bonds (normal and weak) between groups that also form
* an ionic interaction between each other
*/
function saltBridgeRefiner(structure, interactions) {
var contacts = interactions.contacts;
return {
isApplicable: function (type) { return type === 1 /* Ionic */; },
handleInterContact: function (index, infoA, infoB) {
filterInter([4 /* HydrogenBond */, 8 /* WeakHydrogenBond */], index, infoA, infoB, contacts);
},
startUnit: function () { },
handleIntraContact: function (index, infoA, infoB) {
filterIntra([4 /* HydrogenBond */, 8 /* WeakHydrogenBond */], index, infoA, infoB, interactions.unitsContacts.get(infoA.unit.id));
}
};
}
/**
* Remove hydrophobic and cation-pi interactions between groups that also form
* a pi-stacking interaction between each other
*/
function piStackingRefiner(structure, interactions) {
var contacts = interactions.contacts;
return {
isApplicable: function (type) { return type === 6 /* Hydrophobic */ || type === 2 /* CationPi */; },
handleInterContact: function (index, infoA, infoB) {
filterInter([3 /* PiStacking */], index, infoA, infoB, contacts);
},
startUnit: function () { },
handleIntraContact: function (index, infoA, infoB) {
filterIntra([3 /* PiStacking */], index, infoA, infoB, interactions.unitsContacts.get(infoA.unit.id));
}
};
}
/**
* Remove ionic interactions between groups that also form
* a metal coordination between each other
*/
function metalCoordinationRefiner(structure, interactions) {
var contacts = interactions.contacts;
return {
isApplicable: function (type) { return type === 1 /* Ionic */; },
handleInterContact: function (index, infoA, infoB) {
filterInter([7 /* MetalCoordination */], index, infoA, infoB, contacts);
},
startUnit: function () { },
handleIntraContact: function (index, infoA, infoB) {
filterIntra([7 /* MetalCoordination */], index, infoA, infoB, interactions.unitsContacts.get(infoA.unit.id));
}
};
}
//# sourceMappingURL=refine.js.map