molstar
Version:
A comprehensive macromolecular library.
571 lines • 28.9 kB
JavaScript
/**
* Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Sebastian Bittrich <sebastian.bittrich@rcsb.org>
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import { __assign, __awaiter, __generator } from "tslib";
import { StructureElement, StructureProperties, Unit } from '../../mol-model/structure';
import { Task } from '../../mol-task';
import { CentroidHelper } from '../../mol-math/geometry/centroid-helper';
import { AccessibleSurfaceAreaParams } from '../../mol-model-props/computed/accessible-surface-area';
import { Vec3 } from '../../mol-math/linear-algebra';
import { getElementMoleculeType } from '../../mol-model/structure/util';
import { AccessibleSurfaceArea } from '../../mol-model-props/computed/accessible-surface-area/shrake-rupley';
import { ParamDefinition as PD } from '../../mol-util/param-definition';
var LARGE_CA_THRESHOLD = 5000;
var DEFAULT_UPDATE_INTERVAL = 10;
var LARGE_CA_UPDATE_INTERVAL = 1;
;
export var ANVILParams = {
numberOfSpherePoints: PD.Numeric(175, { min: 35, max: 700, step: 1 }, { description: 'Number of spheres/directions to test for membrane placement. Original value is 350.' }),
stepSize: PD.Numeric(1, { min: 0.25, max: 4, step: 0.25 }, { description: 'Thickness of membrane slices that will be tested' }),
minThickness: PD.Numeric(20, { min: 10, max: 30, step: 1 }, { description: 'Minimum membrane thickness used during refinement' }),
maxThickness: PD.Numeric(40, { min: 30, max: 50, step: 1 }, { description: 'Maximum membrane thickness used during refinement' }),
asaCutoff: PD.Numeric(40, { min: 10, max: 100, step: 1 }, { description: 'Relative ASA cutoff above which residues will be considered' }),
adjust: PD.Numeric(14, { min: 0, max: 30, step: 1 }, { description: 'Minimum length of membrane-spanning regions (original values: 14 for alpha-helices and 5 for beta sheets). Set to 0 to not optimize membrane thickness.' }),
tmdetDefinition: PD.Boolean(false, { description: "Use TMDET's classification of membrane-favoring amino acids. TMDET's classification shows better performance on porins and other beta-barrel structures." })
};
/** ANVIL-specific (not general) definition of membrane-favoring amino acids */
var ANVIL_DEFINITION = new Set(['ALA', 'CYS', 'GLY', 'HIS', 'ILE', 'LEU', 'MET', 'PHE', 'SER', 'TRP', 'VAL']);
/** TMDET-specific (not general) definition of membrane-favoring amino acids */
var TMDET_DEFINITION = new Set(['LEU', 'ILE', 'VAL', 'PHE', 'MET', 'GLY', 'TRP', 'TYR']);
/**
* Implements:
* Membrane positioning for high- and low-resolution protein structures through a binary classification approach
* Guillaume Postic, Yassine Ghouzam, Vincent Guiraud, and Jean-Christophe Gelly
* Protein Engineering, Design & Selection, 2015, 1–5
* doi: 10.1093/protein/gzv063
*
* ANVIL is derived from TMDET, the corresponding classification of hydrophobic amino acids is provided as optional parameter:
* Gabor E. Tusnady, Zsuzsanna Dosztanyi and Istvan Simon
* Transmembrane proteins in the Protein Data Bank: identification and classification
* Bioinformatics, 2004, 2964-2972
* doi: 10.1093/bioinformatics/bth340
*/
export function computeANVIL(structure, props) {
var _this = this;
return Task.create('Compute Membrane Orientation', function (runtime) { return __awaiter(_this, void 0, void 0, function () {
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, calculate(runtime, structure, props)];
case 1: return [2 /*return*/, _a.sent()];
}
});
}); });
}
// avoiding namespace lookup improved performance in Chrome (Aug 2020)
var v3add = Vec3.add;
var v3clone = Vec3.clone;
var v3create = Vec3.create;
var v3distance = Vec3.distance;
var v3dot = Vec3.dot;
var v3magnitude = Vec3.magnitude;
var v3normalize = Vec3.normalize;
var v3scale = Vec3.scale;
var v3scaleAndAdd = Vec3.scaleAndAdd;
var v3set = Vec3.set;
var v3squaredDistance = Vec3.squaredDistance;
var v3sub = Vec3.sub;
var v3zero = Vec3.zero;
var centroidHelper = new CentroidHelper();
function initialize(structure, props, accessibleSurfaceArea) {
return __awaiter(this, void 0, void 0, function () {
function isPartOfEntity(l) {
return !Unit.isAtomic(l.unit) ? notAtomic() : l.unit.model.atomicHierarchy.residues.label_seq_id.valueKind(l.unit.residueIndex[l.element]) === 0;
}
var l, _a, label_atom_id, label_comp_id, x, y, z, asaCutoff, offsets, exposed, hydrophobic, definition, vec, i, il, unit, elements, j, jl, eI, centroid, k, kl, extent;
return __generator(this, function (_b) {
l = StructureElement.Location.create(structure);
_a = StructureProperties.atom, label_atom_id = _a.label_atom_id, label_comp_id = _a.label_comp_id, x = _a.x, y = _a.y, z = _a.z;
asaCutoff = props.asaCutoff / 100;
centroidHelper.reset();
offsets = new Array();
exposed = new Array();
hydrophobic = new Array();
definition = props.tmdetDefinition ? TMDET_DEFINITION : ANVIL_DEFINITION;
vec = v3zero();
for (i = 0, il = structure.units.length; i < il; ++i) {
unit = structure.units[i];
elements = unit.elements;
l.unit = unit;
for (j = 0, jl = elements.length; j < jl; ++j) {
eI = elements[j];
l.element = eI;
// consider only amino acids in chains
if (getElementMoleculeType(unit, eI) !== 5 /* Protein */ || !isPartOfEntity(l)) {
continue;
}
// only CA is considered for downstream operations
if (label_atom_id(l) !== 'CA' && label_atom_id(l) !== 'BB') {
continue;
}
// original ANVIL only considers canonical amino acids
if (!MaxAsa[label_comp_id(l)]) {
continue;
}
// while iterating use first pass to compute centroid
v3set(vec, x(l), y(l), z(l));
centroidHelper.includeStep(vec);
// keep track of offsets and exposed state to reuse
offsets.push(structure.serialMapping.getSerialIndex(l.unit, l.element));
if (AccessibleSurfaceArea.getValue(l, accessibleSurfaceArea) / MaxAsa[label_comp_id(l)] > asaCutoff) {
exposed.push(structure.serialMapping.getSerialIndex(l.unit, l.element));
hydrophobic.push(isHydrophobic(definition, label_comp_id(l)));
}
}
}
// calculate centroid and extent
centroidHelper.finishedIncludeStep();
centroid = v3clone(centroidHelper.center);
for (k = 0, kl = offsets.length; k < kl; k++) {
setLocation(l, structure, offsets[k]);
v3set(vec, x(l), y(l), z(l));
centroidHelper.radiusStep(vec);
}
extent = 1.2 * Math.sqrt(centroidHelper.radiusSq);
return [2 /*return*/, __assign(__assign({}, props), { structure: structure, offsets: offsets, exposed: exposed, hydrophobic: hydrophobic, centroid: centroid, extent: extent, large: offsets.length > LARGE_CA_THRESHOLD })];
});
});
}
export function calculate(runtime, structure, params) {
return __awaiter(this, void 0, void 0, function () {
var asaProps, accessibleSurfaceArea, ctx, initialHphobHphil, initialMembrane, refinedMembrane, membrane, normalVector, center, extent;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
asaProps = __assign(__assign({}, PD.getDefaultValues(AccessibleSurfaceAreaParams)), { probeSize: 4.0, traceOnly: true, numberOfSpherePoints: 184 });
return [4 /*yield*/, AccessibleSurfaceArea.compute(structure, asaProps).runInContext(runtime)];
case 1:
accessibleSurfaceArea = _a.sent();
return [4 /*yield*/, initialize(structure, params, accessibleSurfaceArea)];
case 2:
ctx = _a.sent();
initialHphobHphil = HphobHphil.initial(ctx);
return [4 /*yield*/, findMembrane(runtime, 'Placing initial membrane...', ctx, generateSpherePoints(ctx, ctx.numberOfSpherePoints), initialHphobHphil)];
case 3:
initialMembrane = (_a.sent());
return [4 /*yield*/, findMembrane(runtime, 'Refining membrane placement...', ctx, findProximateAxes(ctx, initialMembrane), initialHphobHphil)];
case 4:
refinedMembrane = (_a.sent());
membrane = initialMembrane.qmax > refinedMembrane.qmax ? initialMembrane : refinedMembrane;
if (!(ctx.adjust && !ctx.large)) return [3 /*break*/, 6];
return [4 /*yield*/, adjustThickness(runtime, 'Adjusting membrane thickness...', ctx, membrane, initialHphobHphil)];
case 5:
membrane = _a.sent();
_a.label = 6;
case 6:
normalVector = v3zero();
center = v3zero();
v3sub(normalVector, membrane.planePoint1, membrane.planePoint2);
v3normalize(normalVector, normalVector);
v3add(center, membrane.planePoint1, membrane.planePoint2);
v3scale(center, center, 0.5);
extent = adjustExtent(ctx, membrane, center);
return [2 /*return*/, {
planePoint1: membrane.planePoint1,
planePoint2: membrane.planePoint2,
normalVector: normalVector,
centroid: center,
radius: extent
}];
}
});
});
}
var MembraneCandidate;
(function (MembraneCandidate) {
function initial(c1, c2, stats) {
return {
planePoint1: c1,
planePoint2: c2,
stats: stats
};
}
MembraneCandidate.initial = initial;
function scored(spherePoint, planePoint1, planePoint2, stats, qmax, centroid) {
var normalVector = v3zero();
v3sub(normalVector, centroid, spherePoint);
return {
planePoint1: planePoint1,
planePoint2: planePoint2,
stats: stats,
normalVector: normalVector,
spherePoint: spherePoint,
qmax: qmax
};
}
MembraneCandidate.scored = scored;
})(MembraneCandidate || (MembraneCandidate = {}));
function findMembrane(runtime, message, ctx, spherePoints, initialStats) {
return __awaiter(this, void 0, void 0, function () {
var centroid, stepSize, minThickness, maxThickness, large, membrane, qmax, diam, n, nl, spherePoint, diamNorm, sliceStats, qvartemp, i, il, c1, c2, stats, jmax, width, widthl, i, il, hphob, hphil, j, ij, stats, qvaltest;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
centroid = ctx.centroid, stepSize = ctx.stepSize, minThickness = ctx.minThickness, maxThickness = ctx.maxThickness, large = ctx.large;
qmax = 0;
diam = v3zero();
n = 0, nl = spherePoints.length;
_a.label = 1;
case 1:
if (!(n < nl)) return [3 /*break*/, 5];
if (!(runtime.shouldUpdate && message && (n + 1) % (large ? LARGE_CA_UPDATE_INTERVAL : DEFAULT_UPDATE_INTERVAL) === 0)) return [3 /*break*/, 3];
return [4 /*yield*/, runtime.update({ message: message, current: (n + 1), max: nl })];
case 2:
_a.sent();
_a.label = 3;
case 3:
spherePoint = spherePoints[n];
v3sub(diam, centroid, spherePoint);
v3scale(diam, diam, 2);
diamNorm = v3magnitude(diam);
sliceStats = HphobHphil.sliced(ctx, stepSize, spherePoint, diam, diamNorm);
qvartemp = [];
for (i = 0, il = diamNorm - stepSize; i < il; i += stepSize) {
c1 = v3zero();
c2 = v3zero();
v3scaleAndAdd(c1, spherePoint, diam, i / diamNorm);
v3scaleAndAdd(c2, spherePoint, diam, (i + stepSize) / diamNorm);
stats = sliceStats[Math.round(i / stepSize)];
qvartemp.push(MembraneCandidate.initial(c1, c2, stats));
}
jmax = Math.floor((minThickness / stepSize) - 1);
for (width = 0, widthl = maxThickness; width <= widthl;) {
for (i = 0, il = qvartemp.length - 1 - jmax; i < il; i++) {
hphob = 0;
hphil = 0;
for (j = 0; j < jmax; j++) {
ij = qvartemp[i + j];
if (j === 0 || j === jmax - 1) {
hphob += Math.floor(0.5 * ij.stats.hphob);
hphil += 0.5 * ij.stats.hphil;
}
else {
hphob += ij.stats.hphob;
hphil += ij.stats.hphil;
}
}
if (hphob !== 0) {
stats = { hphob: hphob, hphil: hphil };
qvaltest = qValue(stats, initialStats);
if (qvaltest >= qmax) {
qmax = qvaltest;
membrane = MembraneCandidate.scored(spherePoint, qvartemp[i].planePoint1, qvartemp[i + jmax].planePoint2, stats, qmax, centroid);
}
}
}
jmax++;
width = (jmax + 1) * stepSize;
}
_a.label = 4;
case 4:
n++;
return [3 /*break*/, 1];
case 5: return [2 /*return*/, membrane];
}
});
});
}
/** Adjust membrane thickness by maximizing the number of membrane segments. */
function adjustThickness(runtime, message, ctx, membrane, initialHphobHphil) {
return __awaiter(this, void 0, void 0, function () {
var minThickness, large, step, maxThickness, maxNos, optimalThickness, n, nl, p, temp, nos;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
minThickness = ctx.minThickness, large = ctx.large;
step = 0.3;
maxThickness = v3distance(membrane.planePoint1, membrane.planePoint2);
maxNos = membraneSegments(ctx, membrane).length;
optimalThickness = membrane;
n = 0;
nl = Math.ceil((maxThickness - minThickness) / step);
_a.label = 1;
case 1:
if (!(maxThickness > minThickness)) return [3 /*break*/, 5];
n++;
if (!(runtime.shouldUpdate && message && n % (large ? LARGE_CA_UPDATE_INTERVAL : DEFAULT_UPDATE_INTERVAL) === 0)) return [3 /*break*/, 3];
return [4 /*yield*/, runtime.update({ message: message, current: n, max: nl })];
case 2:
_a.sent();
_a.label = 3;
case 3:
p = __assign(__assign({}, ctx), { maxThickness: maxThickness, stepSize: step });
return [4 /*yield*/, findMembrane(runtime, void 0, p, [membrane.spherePoint], initialHphobHphil)];
case 4:
temp = _a.sent();
if (temp) {
nos = membraneSegments(ctx, temp).length;
if (nos > maxNos) {
maxNos = nos;
optimalThickness = temp;
}
}
maxThickness -= step;
return [3 /*break*/, 1];
case 5: return [2 /*return*/, optimalThickness];
}
});
});
}
/** Report auth_seq_ids for all transmembrane segments. Will reject segments that are shorter than the adjust parameter specifies. Missing residues are considered in-membrane. */
function membraneSegments(ctx, membrane) {
var offsets = ctx.offsets, structure = ctx.structure, adjust = ctx.adjust;
var normalVector = membrane.normalVector, planePoint1 = membrane.planePoint1, planePoint2 = membrane.planePoint2;
var units = structure.units;
var _a = structure.serialMapping, elementIndices = _a.elementIndices, unitIndices = _a.unitIndices;
var testPoint = v3zero();
var auth_seq_id = StructureProperties.residue.auth_seq_id;
var d1 = -v3dot(normalVector, planePoint1);
var d2 = -v3dot(normalVector, planePoint2);
var dMin = Math.min(d1, d2);
var dMax = Math.max(d1, d2);
var inMembrane = Object.create(null);
var outMembrane = Object.create(null);
var segments = [];
var authAsymId;
var lastAuthAsymId = null;
var authSeqId;
var lastAuthSeqId = units[0].model.atomicHierarchy.residues.auth_seq_id.value(units[0].chainIndex[0]) - 1;
var startOffset = 0;
var endOffset = 0;
// collect all residues in membrane layer
for (var k = 0, kl = offsets.length; k < kl; k++) {
var unit = units[unitIndices[offsets[k]]];
if (!Unit.isAtomic(unit))
notAtomic();
var elementIndex = elementIndices[offsets[k]];
authAsymId = unit.model.atomicHierarchy.chains.auth_asym_id.value(unit.chainIndex[elementIndex]);
if (authAsymId !== lastAuthAsymId) {
if (!inMembrane[authAsymId])
inMembrane[authAsymId] = new Set();
if (!outMembrane[authAsymId])
outMembrane[authAsymId] = new Set();
lastAuthAsymId = authAsymId;
}
authSeqId = unit.model.atomicHierarchy.residues.auth_seq_id.value(unit.residueIndex[elementIndex]);
v3set(testPoint, unit.conformation.x(elementIndex), unit.conformation.y(elementIndex), unit.conformation.z(elementIndex));
if (_isInMembranePlane(testPoint, normalVector, dMin, dMax)) {
inMembrane[authAsymId].add(authSeqId);
}
else {
outMembrane[authAsymId].add(authSeqId);
}
}
for (var k = 0, kl = offsets.length; k < kl; k++) {
var unit = units[unitIndices[offsets[k]]];
if (!Unit.isAtomic(unit))
notAtomic();
var elementIndex = elementIndices[offsets[k]];
authAsymId = unit.model.atomicHierarchy.chains.auth_asym_id.value(unit.chainIndex[elementIndex]);
authSeqId = unit.model.atomicHierarchy.residues.auth_seq_id.value(unit.residueIndex[elementIndex]);
if (inMembrane[authAsymId].has(authSeqId)) {
// chain change
if (authAsymId !== lastAuthAsymId) {
segments.push({ start: startOffset, end: endOffset });
lastAuthAsymId = authAsymId;
startOffset = k;
endOffset = k;
}
// sequence gaps
if (authSeqId !== lastAuthSeqId + 1) {
if (outMembrane[authAsymId].has(lastAuthSeqId + 1)) {
segments.push({ start: startOffset, end: endOffset });
startOffset = k;
}
lastAuthSeqId = authSeqId;
endOffset = k;
}
else {
lastAuthSeqId++;
endOffset++;
}
}
}
segments.push({ start: startOffset, end: endOffset });
var l = StructureElement.Location.create(structure);
var startAuth;
var endAuth;
var refinedSegments = [];
for (var k = 0, kl = segments.length; k < kl; k++) {
var _b = segments[k], start = _b.start, end = _b.end;
if (start === 0 || end === offsets.length - 1)
continue;
// evaluate residues 1 pos outside of membrane
setLocation(l, structure, offsets[start - 1]);
v3set(testPoint, l.unit.conformation.x(l.element), l.unit.conformation.y(l.element), l.unit.conformation.z(l.element));
var d3 = -v3dot(normalVector, testPoint);
setLocation(l, structure, offsets[end + 1]);
v3set(testPoint, l.unit.conformation.x(l.element), l.unit.conformation.y(l.element), l.unit.conformation.z(l.element));
var d4 = -v3dot(normalVector, testPoint);
if (Math.min(d3, d4) < dMin && Math.max(d3, d4) > dMax) {
// reject this refinement
setLocation(l, structure, offsets[start]);
startAuth = auth_seq_id(l);
setLocation(l, structure, offsets[end]);
endAuth = auth_seq_id(l);
if (Math.abs(startAuth - endAuth) + 1 < adjust) {
return [];
}
refinedSegments.push(segments[k]);
}
}
return refinedSegments;
}
function notAtomic() {
throw new Error('Property only available for atomic models.');
}
/** Filter for membrane residues and calculate the final extent of the membrane layer */
function adjustExtent(ctx, membrane, centroid) {
var offsets = ctx.offsets, structure = ctx.structure;
var normalVector = membrane.normalVector, planePoint1 = membrane.planePoint1, planePoint2 = membrane.planePoint2;
var l = StructureElement.Location.create(structure);
var testPoint = v3zero();
var _a = StructureProperties.atom, x = _a.x, y = _a.y, z = _a.z;
var d1 = -v3dot(normalVector, planePoint1);
var d2 = -v3dot(normalVector, planePoint2);
var dMin = Math.min(d1, d2);
var dMax = Math.max(d1, d2);
var extent = 0;
for (var k = 0, kl = offsets.length; k < kl; k++) {
setLocation(l, structure, offsets[k]);
v3set(testPoint, x(l), y(l), z(l));
if (_isInMembranePlane(testPoint, normalVector, dMin, dMax)) {
var dsq = v3squaredDistance(testPoint, centroid);
if (dsq > extent)
extent = dsq;
}
}
return Math.sqrt(extent);
}
function qValue(currentStats, initialStats) {
if (initialStats.hphob < 1) {
initialStats.hphob = 0.1;
}
if (initialStats.hphil < 1) {
initialStats.hphil += 1;
}
var part_tot = currentStats.hphob + currentStats.hphil;
return (currentStats.hphob * (initialStats.hphil - currentStats.hphil) - currentStats.hphil * (initialStats.hphob - currentStats.hphob)) /
Math.sqrt(part_tot * initialStats.hphob * initialStats.hphil * (initialStats.hphob + initialStats.hphil - part_tot));
}
export function isInMembranePlane(testPoint, normalVector, planePoint1, planePoint2) {
var d1 = -v3dot(normalVector, planePoint1);
var d2 = -v3dot(normalVector, planePoint2);
return _isInMembranePlane(testPoint, normalVector, Math.min(d1, d2), Math.max(d1, d2));
}
function _isInMembranePlane(testPoint, normalVector, min, max) {
var d = -v3dot(normalVector, testPoint);
return d > min && d < max;
}
/** Generates a defined number of points on a sphere with radius = extent around the specified centroid */
function generateSpherePoints(ctx, numberOfSpherePoints) {
var centroid = ctx.centroid, extent = ctx.extent;
var points = [];
var oldPhi = 0, h, theta, phi;
for (var k = 1, kl = numberOfSpherePoints + 1; k < kl; k++) {
h = -1 + 2 * (k - 1) / (2 * numberOfSpherePoints - 1);
theta = Math.acos(h);
phi = (k === 1 || k === numberOfSpherePoints) ? 0 : (oldPhi + 3.6 / Math.sqrt(2 * numberOfSpherePoints * (1 - h * h))) % (2 * Math.PI);
var 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]);
points[k - 1] = point;
oldPhi = phi;
}
return points;
}
/** Generates sphere points close to that of the initial membrane */
function findProximateAxes(ctx, membrane) {
var numberOfSpherePoints = ctx.numberOfSpherePoints, extent = ctx.extent;
var points = generateSpherePoints(ctx, 30000);
var j = 4;
var sphere_pts2 = [];
var s = 2 * extent / numberOfSpherePoints;
while (sphere_pts2.length < numberOfSpherePoints) {
var dsq = (s + j) * (s + j);
sphere_pts2 = [];
for (var i = 0, il = points.length; i < il; i++) {
if (v3squaredDistance(points[i], membrane.spherePoint) < dsq) {
sphere_pts2.push(points[i]);
}
}
j += 0.2;
}
return sphere_pts2;
}
var HphobHphil;
(function (HphobHphil) {
function initial(ctx) {
var exposed = ctx.exposed, hydrophobic = ctx.hydrophobic;
var hphob = 0;
var hphil = 0;
for (var k = 0, kl = exposed.length; k < kl; k++) {
if (hydrophobic[k]) {
hphob++;
}
else {
hphil++;
}
}
return { hphob: hphob, hphil: hphil };
}
HphobHphil.initial = initial;
var testPoint = v3zero();
function sliced(ctx, stepSize, spherePoint, diam, diamNorm) {
var exposed = ctx.exposed, hydrophobic = ctx.hydrophobic, structure = ctx.structure;
var units = structure.units, serialMapping = structure.serialMapping;
var unitIndices = serialMapping.unitIndices, elementIndices = serialMapping.elementIndices;
var sliceStats = [];
for (var i = 0, il = diamNorm - stepSize; i < il; i += stepSize) {
sliceStats[sliceStats.length] = { hphob: 0, hphil: 0 };
}
for (var i = 0, il = exposed.length; i < il; i++) {
var unit = units[unitIndices[exposed[i]]];
var elementIndex = elementIndices[exposed[i]];
v3set(testPoint, unit.conformation.x(elementIndex), unit.conformation.y(elementIndex), unit.conformation.z(elementIndex));
v3sub(testPoint, testPoint, spherePoint);
if (hydrophobic[i]) {
sliceStats[Math.floor(v3dot(testPoint, diam) / diamNorm / stepSize)].hphob++;
}
else {
sliceStats[Math.floor(v3dot(testPoint, diam) / diamNorm / stepSize)].hphil++;
}
}
return sliceStats;
}
HphobHphil.sliced = sliced;
})(HphobHphil || (HphobHphil = {}));
/** Returns true if the definition considers this as membrane-favoring amino acid */
export function isHydrophobic(definition, label_comp_id) {
return definition.has(label_comp_id);
}
/** Accessible surface area used for normalization. ANVIL uses 'Total-Side REL' values from NACCESS, from: Hubbard, S. J., & Thornton, J. M. (1993). naccess. Computer Program, Department of Biochemistry and Molecular Biology, University College London, 2(1). */
export var MaxAsa = {
'ALA': 69.41,
'ARG': 201.25,
'ASN': 106.24,
'ASP': 102.69,
'CYS': 96.75,
'GLU': 134.74,
'GLN': 140.99,
'GLY': 32.33,
'HIS': 147.08,
'ILE': 137.96,
'LEU': 141.12,
'LYS': 163.30,
'MET': 156.64,
'PHE': 164.11,
'PRO': 119.90,
'SER': 78.11,
'THR': 101.70,
'TRP': 211.26,
'TYR': 177.38,
'VAL': 114.28
};
function setLocation(l, structure, serialIndex) {
l.structure = structure;
l.unit = structure.units[structure.serialMapping.unitIndices[serialIndex]];
l.element = structure.serialMapping.elementIndices[serialIndex];
return l;
}
//# sourceMappingURL=algorithm.js.map