molstar
Version:
A comprehensive macromolecular library.
182 lines • 8.98 kB
JavaScript
"use strict";
/**
* Copyright (c) 2019 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.addStructureContacts = exports.addUnitContacts = exports.ContactsParams = void 0;
var tslib_1 = require("tslib");
var int_1 = require("../../../mol-data/int");
var linear_algebra_1 = require("../../../mol-math/linear-algebra");
var structure_1 = require("../../../mol-model/structure");
var atomic_1 = require("../../../mol-model/structure/model/properties/atomic");
var lookup3d_1 = require("../../../mol-model/structure/structure/util/lookup3d");
var param_definition_1 = require("../../../mol-util/param-definition");
var util_1 = require("../chemistry/util");
var features_1 = require("./features");
exports.ContactsParams = {
lineOfSightDistFactor: param_definition_1.ParamDefinition.Numeric(1.0, { min: 0, max: 3, step: 0.1 }),
};
var MAX_LINE_OF_SIGHT_DISTANCE = 3;
function validPair(structure, infoA, infoB) {
var indexA = infoA.members[infoA.offsets[infoA.feature]];
var indexB = infoB.members[infoB.offsets[infoB.feature]];
if (indexA === indexB && infoA.unit === infoB.unit)
return false; // no self interaction
var altA = (0, util_1.altLoc)(infoA.unit, indexA);
var altB = (0, util_1.altLoc)(infoB.unit, indexB);
if (altA && altB && altA !== altB)
return false; // incompatible alternate location id
if (infoA.unit.residueIndex[infoA.unit.elements[indexA]] === infoB.unit.residueIndex[infoB.unit.elements[indexB]] && infoA.unit === infoB.unit)
return false; // same residue
// e.g. no hbond if donor and acceptor are bonded
if ((0, util_1.connectedTo)(structure, infoA.unit, indexA, infoB.unit, indexB))
return false;
return true;
}
//
function invalidAltLoc(unitA, indexA, unitB, indexB) {
var altA = (0, util_1.altLoc)(unitA, indexA);
var altB = (0, util_1.altLoc)(unitB, indexB);
return altA && altB && altA !== altB;
}
function isMember(element, info) {
var feature = info.feature, offsets = info.offsets, members = info.members;
for (var i = offsets[feature], il = offsets[feature + 1]; i < il; ++i) {
if (members[i] === element)
return true;
}
return false;
}
var tmpVec = (0, linear_algebra_1.Vec3)();
var tmpVecA = (0, linear_algebra_1.Vec3)();
var tmpVecB = (0, linear_algebra_1.Vec3)();
// need to use a separate context for structure.lookup3d.find because of nested queries
var lineOfSightLookupCtx = (0, lookup3d_1.StructureLookup3DResultContext)();
function checkLineOfSight(structure, infoA, infoB, distFactor) {
var featureA = infoA.feature;
var featureB = infoB.feature;
var indexA = infoA.members[infoA.offsets[featureA]];
var indexB = infoB.members[infoB.offsets[featureB]];
features_1.Features.position(tmpVecA, infoA);
features_1.Features.position(tmpVecB, infoB);
linear_algebra_1.Vec3.scale(tmpVec, linear_algebra_1.Vec3.add(tmpVec, tmpVecA, tmpVecB), 0.5);
var distMax = distFactor * MAX_LINE_OF_SIGHT_DISTANCE;
var _a = structure.lookup3d.find(tmpVec[0], tmpVec[1], tmpVec[2], distMax, lineOfSightLookupCtx), count = _a.count, indices = _a.indices, units = _a.units, squaredDistances = _a.squaredDistances;
if (count === 0)
return true;
for (var r = 0; r < count; ++r) {
var i = indices[r];
var unit = units[r];
if (!structure_1.Unit.isAtomic(unit))
continue;
var element = (0, util_1.typeSymbol)(unit, i);
// allow hydrogens
if (element === "H" /* H */)
continue;
var vdw = (0, atomic_1.VdwRadius)(element);
// check distance
if (vdw * vdw * distFactor * distFactor <= squaredDistances[r])
continue;
// allow different altlocs
if (invalidAltLoc(unit, i, infoA.unit, indexA) || invalidAltLoc(unit, i, infoB.unit, indexB))
continue;
// allow member atoms
if ((infoA.unit === unit && isMember(i, infoA)) || (infoB.unit === unit && isMember(i, infoB)))
continue;
unit.conformation.position(unit.elements[i], tmpVec);
// allow atoms at the center of functional groups
if (linear_algebra_1.Vec3.squaredDistance(tmpVec, tmpVecA) < 1 || linear_algebra_1.Vec3.squaredDistance(tmpVec, tmpVecB) < 1)
continue;
return false;
}
return true;
}
/**
* Add all intra-unit contacts, i.e. pairs of features
*/
function addUnitContacts(structure, unit, features, builder, testers, props) {
for (var _i = 0, testers_1 = testers; _i < testers_1.length; _i++) {
var tester = testers_1[_i];
_addUnitContacts(structure, unit, features, builder, tester, props);
}
}
exports.addUnitContacts = addUnitContacts;
function _addUnitContacts(structure, unit, features, builder, tester, props) {
var x = features.x, y = features.y, z = features.z;
var _a = features.subset(tester.requiredFeatures), lookup3d = _a.lookup3d, subsetIndices = _a.indices;
var infoA = features_1.Features.Info(structure, unit, features);
var infoB = (0, tslib_1.__assign)({}, infoA);
var distFactor = props.lineOfSightDistFactor;
for (var t = 0, tl = int_1.OrderedSet.size(subsetIndices); t < tl; ++t) {
var i = int_1.OrderedSet.getAt(subsetIndices, t);
var _b = lookup3d.find(x[i], y[i], z[i], tester.maxDistance), count = _b.count, indices = _b.indices, squaredDistances = _b.squaredDistances;
if (count === 0)
continue;
infoA.feature = i;
for (var r = 0; r < count; ++r) {
var j = int_1.OrderedSet.getAt(subsetIndices, indices[r]);
if (j <= i)
continue;
infoB.feature = j;
if (!validPair(structure, infoA, infoB))
continue;
var type = tester.getType(structure, infoA, infoB, squaredDistances[r]);
if (type && checkLineOfSight(structure, infoA, infoB, distFactor)) {
builder.add(i, j, type);
}
}
}
}
var _imageTransform = (0, linear_algebra_1.Mat4)();
/**
* Add all inter-unit contacts, i.e. pairs of features
*/
function addStructureContacts(structure, unitA, featuresA, unitB, featuresB, builder, testers, props) {
var countA = featuresA.count, xA = featuresA.x, yA = featuresA.y, zA = featuresA.z;
var lookup3d = featuresB.lookup3d;
// the lookup queries need to happen in the "unitB space".
// that means imageA = inverseOperB(operA(i))
var imageTransform = linear_algebra_1.Mat4.mul(_imageTransform, unitB.conformation.operator.inverse, unitA.conformation.operator.matrix);
var isNotIdentity = !linear_algebra_1.Mat4.isIdentity(imageTransform);
var imageA = (0, linear_algebra_1.Vec3)();
var maxDistance = Math.max.apply(Math, testers.map(function (t) { return t.maxDistance; }));
var _a = lookup3d.boundary.sphere, center = _a.center, radius = _a.radius;
var testDistanceSq = (radius + maxDistance) * (radius + maxDistance);
var distFactor = props.lineOfSightDistFactor;
var infoA = features_1.Features.Info(structure, unitA, featuresA);
var infoB = features_1.Features.Info(structure, unitB, featuresB);
builder.startUnitPair(unitA, unitB);
for (var i = 0; i < countA; ++i) {
linear_algebra_1.Vec3.set(imageA, xA[i], yA[i], zA[i]);
if (isNotIdentity)
linear_algebra_1.Vec3.transformMat4(imageA, imageA, imageTransform);
if (linear_algebra_1.Vec3.squaredDistance(imageA, center) > testDistanceSq)
continue;
var _b = lookup3d.find(imageA[0], imageA[1], imageA[2], maxDistance), indices = _b.indices, count = _b.count, squaredDistances = _b.squaredDistances;
if (count === 0)
continue;
infoA.feature = i;
for (var r = 0; r < count; ++r) {
var j = indices[r];
infoB.feature = j;
if (!validPair(structure, infoA, infoB))
continue;
var distanceSq = squaredDistances[r];
for (var _i = 0, testers_2 = testers; _i < testers_2.length; _i++) {
var tester = testers_2[_i];
if (distanceSq < tester.maxDistance * tester.maxDistance) {
var type = tester.getType(structure, infoA, infoB, distanceSq);
if (type && checkLineOfSight(structure, infoA, infoB, distFactor)) {
builder.add(i, j, type);
break;
}
}
}
}
}
builder.finishUnitPair();
}
exports.addStructureContacts = addStructureContacts;
//# sourceMappingURL=contacts.js.map