UNPKG

molstar

Version:

A comprehensive macromolecular library.

247 lines 11.2 kB
/** * 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