|
@@ -59,6 +59,21 @@ export function computeANVIL(structure: Structure, props: ANVILProps) {
|
|
|
});
|
|
|
}
|
|
|
|
|
|
+// avoiding namespace lookup improved performance in Chrome (Aug 2020)
|
|
|
+const v3add = Vec3.add;
|
|
|
+const v3clone = Vec3.clone;
|
|
|
+const v3create = Vec3.create;
|
|
|
+const v3distance = Vec3.distance;
|
|
|
+const v3dot = Vec3.dot;
|
|
|
+const v3magnitude = Vec3.magnitude;
|
|
|
+const v3normalize = Vec3.normalize;
|
|
|
+const v3scale = Vec3.scale;
|
|
|
+const v3scaleAndAdd = Vec3.scaleAndAdd;
|
|
|
+const v3set = Vec3.set;
|
|
|
+const v3squaredDistance = Vec3.squaredDistance;
|
|
|
+const v3sub = Vec3.sub;
|
|
|
+const v3zero = Vec3.zero;
|
|
|
+
|
|
|
const centroidHelper = new CentroidHelper();
|
|
|
async function initialize(runtime: RuntimeContext, structure: Structure, props: ANVILProps): Promise<ANVILContext> {
|
|
|
const l = StructureElement.Location.create(structure);
|
|
@@ -74,7 +89,7 @@ async function initialize(runtime: RuntimeContext, structure: Structure, props:
|
|
|
const accessibleSurfaceArea = await AccessibleSurfaceArea.compute(structure, p).runInContext(runtime);
|
|
|
const asaCutoff = props.asaCutoff / 100;
|
|
|
|
|
|
- const vec = Vec3();
|
|
|
+ const vec = v3zero();
|
|
|
let m = 0;
|
|
|
let n = 0;
|
|
|
for (let i = 0, il = structure.units.length; i < il; ++i) {
|
|
@@ -102,7 +117,7 @@ async function initialize(runtime: RuntimeContext, structure: Structure, props:
|
|
|
}
|
|
|
|
|
|
// while iterating use first pass to compute centroid
|
|
|
- Vec3.set(vec, x(l), y(l), z(l));
|
|
|
+ v3set(vec, x(l), y(l), z(l));
|
|
|
centroidHelper.includeStep(vec);
|
|
|
|
|
|
// keep track of offsets and exposed state to reuse
|
|
@@ -119,10 +134,10 @@ async function initialize(runtime: RuntimeContext, structure: Structure, props:
|
|
|
|
|
|
// calculate centroid and extent
|
|
|
centroidHelper.finishedIncludeStep();
|
|
|
- const centroid = Vec3.clone(centroidHelper.center);
|
|
|
+ const centroid = v3clone(centroidHelper.center);
|
|
|
for (let k = 0, kl = offsets.length; k < kl; k++) {
|
|
|
setLocation(l, structure, offsets[k]);
|
|
|
- Vec3.set(vec, x(l), y(l), z(l));
|
|
|
+ v3set(vec, x(l), y(l), z(l));
|
|
|
centroidHelper.radiusStep(vec);
|
|
|
}
|
|
|
const extent = 1.2 * Math.sqrt(centroidHelper.radiusSq);
|
|
@@ -150,13 +165,13 @@ export async function calculate(runtime: RuntimeContext, structure: Structure, p
|
|
|
membrane = await adjustThickness(runtime, 'Adjusting membrane thickness...', ctx, membrane, initialHphobHphil);
|
|
|
}
|
|
|
|
|
|
- const normalVector = Vec3.zero();
|
|
|
- const center = Vec3.zero();
|
|
|
- Vec3.sub(normalVector, membrane.planePoint1, membrane.planePoint2);
|
|
|
- Vec3.normalize(normalVector, normalVector);
|
|
|
+ const normalVector = v3zero();
|
|
|
+ const center = v3zero();
|
|
|
+ v3sub(normalVector, membrane.planePoint1, membrane.planePoint2);
|
|
|
+ v3normalize(normalVector, normalVector);
|
|
|
|
|
|
- Vec3.add(center, membrane.planePoint1, membrane.planePoint2);
|
|
|
- Vec3.scale(center, center, 0.5);
|
|
|
+ v3add(center, membrane.planePoint1, membrane.planePoint2);
|
|
|
+ v3scale(center, center, 0.5);
|
|
|
const extent = adjustExtent(ctx, membrane, center);
|
|
|
|
|
|
return {
|
|
@@ -187,8 +202,8 @@ namespace MembraneCandidate {
|
|
|
}
|
|
|
|
|
|
export function scored(spherePoint: Vec3, planePoint1: Vec3, planePoint2: Vec3, stats: HphobHphil, qmax: number, centroid: Vec3): MembraneCandidate {
|
|
|
- const normalVector = Vec3();
|
|
|
- Vec3.sub(normalVector, centroid, spherePoint);
|
|
|
+ const normalVector = v3zero();
|
|
|
+ v3sub(normalVector, centroid, spherePoint);
|
|
|
return {
|
|
|
planePoint1,
|
|
|
planePoint2,
|
|
@@ -208,25 +223,25 @@ async function findMembrane(runtime: RuntimeContext, message: string | undefined
|
|
|
let qmax = 0;
|
|
|
|
|
|
// construct slices of thickness 1.0 along the axis connecting the centroid and the spherePoint
|
|
|
- const diam = Vec3();
|
|
|
+ const diam = v3zero();
|
|
|
for (let n = 0, nl = spherePoints.length; n < nl; n++) {
|
|
|
if (runtime?.shouldUpdate && message && (n + 1) % UPDATE_INTERVAL === 0) {
|
|
|
await runtime.update({ message, current: (n + 1), max: nl });
|
|
|
}
|
|
|
|
|
|
const spherePoint = spherePoints[n];
|
|
|
- Vec3.sub(diam, centroid, spherePoint);
|
|
|
- Vec3.scale(diam, diam, 2);
|
|
|
- const diamNorm = Vec3.magnitude(diam);
|
|
|
+ v3sub(diam, centroid, spherePoint);
|
|
|
+ v3scale(diam, diam, 2);
|
|
|
+ const diamNorm = v3magnitude(diam);
|
|
|
const qvartemp = [];
|
|
|
|
|
|
for (let i = 0, il = diamNorm - stepSize; i < il; i += stepSize) {
|
|
|
- const c1 = Vec3();
|
|
|
- const c2 = Vec3();
|
|
|
- Vec3.scaleAndAdd(c1, spherePoint, diam, i / diamNorm);
|
|
|
- Vec3.scaleAndAdd(c2, spherePoint, diam, (i + stepSize) / diamNorm);
|
|
|
- const d1 = -Vec3.dot(diam, c1);
|
|
|
- const d2 = -Vec3.dot(diam, c2);
|
|
|
+ const c1 = v3zero();
|
|
|
+ const c2 = v3zero();
|
|
|
+ v3scaleAndAdd(c1, spherePoint, diam, i / diamNorm);
|
|
|
+ v3scaleAndAdd(c2, spherePoint, diam, (i + stepSize) / diamNorm);
|
|
|
+ const d1 = -v3dot(diam, c1);
|
|
|
+ const d2 = -v3dot(diam, c2);
|
|
|
const dMin = Math.min(d1, d2);
|
|
|
const dMax = Math.max(d1, d2);
|
|
|
|
|
@@ -273,7 +288,7 @@ async function findMembrane(runtime: RuntimeContext, message: string | undefined
|
|
|
async function adjustThickness(runtime: RuntimeContext, message: string | undefined, ctx: ANVILContext, membrane: MembraneCandidate, initialHphobHphil: HphobHphil): Promise<MembraneCandidate> {
|
|
|
const { minThickness } = ctx;
|
|
|
const step = 0.3;
|
|
|
- let maxThickness = Vec3.distance(membrane.planePoint1, membrane.planePoint2);
|
|
|
+ let maxThickness = v3distance(membrane.planePoint1, membrane.planePoint2);
|
|
|
|
|
|
let maxNos = membraneSegments(ctx, membrane).length;
|
|
|
let optimalThickness = membrane;
|
|
@@ -310,12 +325,12 @@ function membraneSegments(ctx: ANVILContext, membrane: MembraneCandidate): Array
|
|
|
const { offsets, structure, adjust } = ctx;
|
|
|
const { normalVector, planePoint1, planePoint2 } = membrane;
|
|
|
const l = StructureElement.Location.create(structure);
|
|
|
- const testPoint = Vec3();
|
|
|
+ const testPoint = v3zero();
|
|
|
const { auth_asym_id } = StructureProperties.chain;
|
|
|
const { auth_seq_id } = StructureProperties.residue;
|
|
|
|
|
|
- const d1 = -Vec3.dot(normalVector!, planePoint1);
|
|
|
- const d2 = -Vec3.dot(normalVector!, planePoint2);
|
|
|
+ const d1 = -v3dot(normalVector!, planePoint1);
|
|
|
+ const d2 = -v3dot(normalVector!, planePoint2);
|
|
|
const dMin = Math.min(d1, d2);
|
|
|
const dMax = Math.max(d1, d2);
|
|
|
|
|
@@ -341,7 +356,7 @@ function membraneSegments(ctx: ANVILContext, membrane: MembraneCandidate): Array
|
|
|
}
|
|
|
|
|
|
authSeqId = auth_seq_id(l);
|
|
|
- Vec3.set(testPoint, l.unit.conformation.x(l.element), l.unit.conformation.y(l.element), l.unit.conformation.z(l.element));
|
|
|
+ v3set(testPoint, l.unit.conformation.x(l.element), l.unit.conformation.y(l.element), l.unit.conformation.z(l.element));
|
|
|
if (_isInMembranePlane(testPoint, normalVector!, dMin, dMax)) {
|
|
|
inMembrane[authAsymId].add(authSeqId);
|
|
|
} else {
|
|
@@ -387,12 +402,12 @@ function membraneSegments(ctx: ANVILContext, membrane: MembraneCandidate): Array
|
|
|
|
|
|
// evaluate residues 1 pos outside of membrane
|
|
|
setLocation(l, structure, offsets[start - 1]);
|
|
|
- Vec3.set(testPoint, l.unit.conformation.x(l.element), l.unit.conformation.y(l.element), l.unit.conformation.z(l.element));
|
|
|
- const d3 = -Vec3.dot(normalVector!, testPoint);
|
|
|
+ v3set(testPoint, l.unit.conformation.x(l.element), l.unit.conformation.y(l.element), l.unit.conformation.z(l.element));
|
|
|
+ const d3 = -v3dot(normalVector!, testPoint);
|
|
|
|
|
|
setLocation(l, structure, offsets[end + 1]);
|
|
|
- Vec3.set(testPoint, l.unit.conformation.x(l.element), l.unit.conformation.y(l.element), l.unit.conformation.z(l.element));
|
|
|
- const d4 = -Vec3.dot(normalVector!, testPoint);
|
|
|
+ v3set(testPoint, l.unit.conformation.x(l.element), l.unit.conformation.y(l.element), l.unit.conformation.z(l.element));
|
|
|
+ const d4 = -v3dot(normalVector!, testPoint);
|
|
|
|
|
|
if (Math.min(d3, d4) < dMin && Math.max(d3, d4) > dMax) {
|
|
|
// reject this refinement
|
|
@@ -415,20 +430,20 @@ function adjustExtent(ctx: ANVILContext, membrane: MembraneCandidate, centroid:
|
|
|
const { offsets, structure } = ctx;
|
|
|
const { normalVector, planePoint1, planePoint2 } = membrane;
|
|
|
const l = StructureElement.Location.create(structure);
|
|
|
- const testPoint = Vec3();
|
|
|
+ const testPoint = v3zero();
|
|
|
const { x, y, z } = StructureProperties.atom;
|
|
|
|
|
|
- const d1 = -Vec3.dot(normalVector!, planePoint1);
|
|
|
- const d2 = -Vec3.dot(normalVector!, planePoint2);
|
|
|
+ const d1 = -v3dot(normalVector!, planePoint1);
|
|
|
+ const d2 = -v3dot(normalVector!, planePoint2);
|
|
|
const dMin = Math.min(d1, d2);
|
|
|
const dMax = Math.max(d1, d2);
|
|
|
let extent = 0;
|
|
|
|
|
|
for (let k = 0, kl = offsets.length; k < kl; k++) {
|
|
|
setLocation(l, structure, offsets[k]);
|
|
|
- Vec3.set(testPoint, x(l), y(l), z(l));
|
|
|
+ v3set(testPoint, x(l), y(l), z(l));
|
|
|
if (_isInMembranePlane(testPoint, normalVector!, dMin, dMax)) {
|
|
|
- const dsq = Vec3.squaredDistance(testPoint, centroid);
|
|
|
+ const dsq = v3squaredDistance(testPoint, centroid);
|
|
|
if (dsq > extent) extent = dsq;
|
|
|
}
|
|
|
}
|
|
@@ -451,13 +466,13 @@ function qValue(currentStats: HphobHphil, initialStats: HphobHphil): number {
|
|
|
}
|
|
|
|
|
|
export function isInMembranePlane(testPoint: Vec3, normalVector: Vec3, planePoint1: Vec3, planePoint2: Vec3): boolean {
|
|
|
- const d1 = -Vec3.dot(normalVector, planePoint1);
|
|
|
- const d2 = -Vec3.dot(normalVector, planePoint2);
|
|
|
+ const d1 = -v3dot(normalVector, planePoint1);
|
|
|
+ const d2 = -v3dot(normalVector, planePoint2);
|
|
|
return _isInMembranePlane(testPoint, normalVector, Math.min(d1, d2), Math.max(d1, d2));
|
|
|
}
|
|
|
|
|
|
function _isInMembranePlane(testPoint: Vec3, normalVector: Vec3, min: number, max: number): boolean {
|
|
|
- const d = -Vec3.dot(normalVector, testPoint);
|
|
|
+ const d = -v3dot(normalVector, testPoint);
|
|
|
return d > min && d < max;
|
|
|
}
|
|
|
|
|
@@ -471,7 +486,7 @@ function generateSpherePoints(ctx: ANVILContext, numberOfSpherePoints: number):
|
|
|
theta = Math.acos(h);
|
|
|
phi = (k === 1 || k === numberOfSpherePoints) ? 0 : (oldPhi + 3.6 / Math.sqrt(numberOfSpherePoints * (1 - h * h))) % (2 * Math.PI);
|
|
|
|
|
|
- const point = Vec3.create(
|
|
|
+ const point = v3create(
|
|
|
extent * Math.sin(phi) * Math.sin(theta) + centroid[0],
|
|
|
extent * Math.cos(theta) + centroid[1],
|
|
|
extent * Math.cos(phi) * Math.sin(theta) + centroid[2]
|
|
@@ -494,7 +509,7 @@ function findProximateAxes(ctx: ANVILContext, membrane: MembraneCandidate): Vec3
|
|
|
const dsq = (s + j) * (s + j);
|
|
|
sphere_pts2 = [];
|
|
|
for (let i = 0, il = points.length; i < il; i++) {
|
|
|
- if (Vec3.squaredDistance(points[i], membrane.spherePoint!) < dsq) {
|
|
|
+ if (v3squaredDistance(points[i], membrane.spherePoint!) < dsq) {
|
|
|
sphere_pts2.push(points[i]);
|
|
|
}
|
|
|
}
|
|
@@ -516,7 +531,7 @@ namespace HphobHphil {
|
|
|
};
|
|
|
}
|
|
|
|
|
|
- const testPoint = Vec3();
|
|
|
+ const testPoint = v3zero();
|
|
|
export function filtered(ctx: ANVILContext, filter?: { normalVector: Vec3, dMin: number, dMax: number }): HphobHphil {
|
|
|
const { exposed, structure } = ctx;
|
|
|
const { label_comp_id } = StructureProperties.atom;
|
|
@@ -528,7 +543,7 @@ namespace HphobHphil {
|
|
|
|
|
|
// testPoints have to be in putative membrane layer
|
|
|
if (filter) {
|
|
|
- Vec3.set(testPoint, l.unit.conformation.x(l.element), l.unit.conformation.y(l.element), l.unit.conformation.z(l.element));
|
|
|
+ v3set(testPoint, l.unit.conformation.x(l.element), l.unit.conformation.y(l.element), l.unit.conformation.z(l.element));
|
|
|
if (!_isInMembranePlane(testPoint, filter.normalVector, filter.dMin, filter.dMax)) {
|
|
|
continue;
|
|
|
}
|