molstar
Version:
A comprehensive macromolecular library.
292 lines (291 loc) • 14 kB
JavaScript
"use strict";
/**
* Copyright (c) 2018-2022 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.isTrace = exports.isH = exports.isHydrogen = exports.getStructureConformationAndRadius = exports.getUnitConformationAndRadius = exports.DefaultCommonSurfaceProps = exports.CommonSurfaceParams = exports.getConformation = exports.ensureReasonableResolution = exports.getVolumeSliceInfo = exports.includesUnitKind = exports.UnitKindOptions = exports.UnitKindInfo = exports.createUnitsTransform = exports.getAltResidueLociFromId = exports.getAltResidueLoci = exports.getResidueLoci = void 0;
var tslib_1 = require("tslib");
var structure_1 = require("../../../../mol-model/structure");
var linear_algebra_1 = require("../../../../mol-math/linear-algebra");
var transform_data_1 = require("../../../../mol-geo/geometry/transform-data");
var int_1 = require("../../../../mol-data/int");
var loci_1 = require("../../../../mol-model/loci");
var atomic_1 = require("../../../../mol-model/structure/model/properties/atomic");
var array_1 = require("../../../../mol-util/array");
var param_definition_1 = require("../../../../mol-util/param-definition");
var boundary_1 = require("../../../../mol-math/geometry/boundary");
var geometry_1 = require("../../../../mol-math/geometry");
/** Return a Loci for the elements of a whole residue the elementIndex belongs to. */
function getResidueLoci(structure, unit, elementIndex) {
var elements = unit.elements, model = unit.model;
if (int_1.OrderedSet.indexOf(elements, elementIndex) !== -1) {
var _a = model.atomicHierarchy.residueAtomSegments, index = _a.index, offsets = _a.offsets;
var rI = index[elementIndex];
var _indices = [];
for (var i = offsets[rI], il = offsets[rI + 1]; i < il; ++i) {
var unitIndex = int_1.OrderedSet.indexOf(elements, i);
if (unitIndex !== -1)
_indices.push(unitIndex);
}
var indices = int_1.OrderedSet.ofSortedArray(int_1.SortedArray.ofSortedArray(_indices));
return structure_1.StructureElement.Loci(structure, [{ unit: unit, indices: indices }]);
}
return loci_1.EmptyLoci;
}
exports.getResidueLoci = getResidueLoci;
/**
* Return a Loci for the elements of a whole residue the elementIndex belongs to but
* restrict to elements that have the same label_alt_id or none
*/
function getAltResidueLoci(structure, unit, elementIndex) {
var elements = unit.elements, model = unit.model;
var label_alt_id = model.atomicHierarchy.atoms.label_alt_id;
var elementAltId = label_alt_id.value(elementIndex);
if (int_1.OrderedSet.indexOf(elements, elementIndex) !== -1) {
var index = model.atomicHierarchy.residueAtomSegments.index;
var rI = index[elementIndex];
return getAltResidueLociFromId(structure, unit, rI, elementAltId);
}
return structure_1.StructureElement.Loci(structure, []);
}
exports.getAltResidueLoci = getAltResidueLoci;
function getAltResidueLociFromId(structure, unit, residueIndex, elementAltId) {
var elements = unit.elements, model = unit.model;
var label_alt_id = model.atomicHierarchy.atoms.label_alt_id;
var offsets = model.atomicHierarchy.residueAtomSegments.offsets;
var _indices = [];
for (var i = offsets[residueIndex], il = offsets[residueIndex + 1]; i < il; ++i) {
var unitIndex = int_1.OrderedSet.indexOf(elements, i);
if (unitIndex !== -1) {
var altId = label_alt_id.value(i);
if (elementAltId === altId || altId === '') {
_indices.push(unitIndex);
}
}
}
var indices = int_1.OrderedSet.ofSortedArray(int_1.SortedArray.ofSortedArray(_indices));
return structure_1.StructureElement.Loci(structure, [{ unit: unit, indices: indices }]);
}
exports.getAltResidueLociFromId = getAltResidueLociFromId;
function createUnitsTransform(structureGroup, includeParent, transformData) {
var child = structureGroup.structure.child;
var units = includeParent && child
? structureGroup.group.units.filter(function (u) { return child.unitMap.has(u.id); })
: structureGroup.group.units;
var unitCount = units.length;
var n = unitCount * 16;
var array = transformData && transformData.aTransform.ref.value.length >= n ? transformData.aTransform.ref.value : new Float32Array(n);
for (var i = 0; i < unitCount; i++) {
linear_algebra_1.Mat4.toArray(units[i].conformation.operator.matrix, array, i * 16);
}
return (0, transform_data_1.createTransform)(array, unitCount, transformData);
}
exports.createUnitsTransform = createUnitsTransform;
exports.UnitKindInfo = {
'atomic': {},
'spheres': {},
'gaussians': {},
};
exports.UnitKindOptions = param_definition_1.ParamDefinition.objectToOptions(exports.UnitKindInfo);
function includesUnitKind(unitKinds, unit) {
for (var i = 0, il = unitKinds.length; i < il; ++i) {
if (structure_1.Unit.isAtomic(unit) && unitKinds[i] === 'atomic')
return true;
if (structure_1.Unit.isSpheres(unit) && unitKinds[i] === 'spheres')
return true;
if (structure_1.Unit.isGaussians(unit) && unitKinds[i] === 'gaussians')
return true;
}
return false;
}
exports.includesUnitKind = includesUnitKind;
//
var DefaultMaxCells = 500000000;
function getVolumeSliceInfo(box, resolution, maxCells) {
if (maxCells === void 0) { maxCells = DefaultMaxCells; }
var size = geometry_1.Box3D.size((0, linear_algebra_1.Vec3)(), box);
linear_algebra_1.Vec3.ceil(size, size);
size.sort(function (a, b) { return b - a; }); // descending
var maxAreaCells = Math.floor(Math.cbrt(maxCells) * Math.cbrt(maxCells));
var area = size[0] * size[1];
var areaCells = Math.ceil(area / (resolution * resolution));
return { area: area, areaCells: areaCells, maxAreaCells: maxAreaCells };
}
exports.getVolumeSliceInfo = getVolumeSliceInfo;
/**
* Guard against overly high resolution for the given box size.
* Internally it uses the largest 2d slice of the box to determine the
* maximum resolution to account for the 2d texture layout on the GPU.
*/
function ensureReasonableResolution(box, props, maxCells) {
if (maxCells === void 0) { maxCells = DefaultMaxCells; }
var _a = getVolumeSliceInfo(box, props.resolution, maxCells), area = _a.area, areaCells = _a.areaCells, maxAreaCells = _a.maxAreaCells;
var resolution = areaCells > maxAreaCells ? Math.sqrt(area / maxAreaCells) : props.resolution;
return tslib_1.__assign(tslib_1.__assign({}, props), { resolution: resolution });
}
exports.ensureReasonableResolution = ensureReasonableResolution;
function getConformation(unit) {
switch (unit.kind) {
case 0 /* Unit.Kind.Atomic */: return unit.model.atomicConformation;
case 1 /* Unit.Kind.Spheres */: return unit.model.coarseConformation.spheres;
case 2 /* Unit.Kind.Gaussians */: return unit.model.coarseConformation.gaussians;
}
}
exports.getConformation = getConformation;
exports.CommonSurfaceParams = {
ignoreHydrogens: param_definition_1.ParamDefinition.Boolean(false, { description: 'Whether or not to include hydrogen atoms in the surface calculation.' }),
traceOnly: param_definition_1.ParamDefinition.Boolean(false, { description: 'Whether or not to only use trace atoms in the surface calculation.' }),
includeParent: param_definition_1.ParamDefinition.Boolean(false, { description: 'Include elements of the parent structure in surface calculation to get a surface patch of the current structure.' }),
};
exports.DefaultCommonSurfaceProps = param_definition_1.ParamDefinition.getDefaultValues(exports.CommonSurfaceParams);
var v = (0, linear_algebra_1.Vec3)();
function squaredDistance(x, y, z, center) {
return linear_algebra_1.Vec3.squaredDistance(linear_algebra_1.Vec3.set(v, x, y, z), center);
}
/** marks `indices` for filtering/ignoring in `id` when not in `elements` */
function filterId(id, elements, indices) {
var start = 0;
var end = elements.length;
for (var i = 0, il = indices.length; i < il; ++i) {
var idx = int_1.SortedArray.indexOfInRange(elements, indices[i], start, end);
if (idx === -1) {
id[i] = -2;
}
else {
id[i] = idx;
start = idx;
}
}
}
function getUnitConformationAndRadius(structure, unit, sizeTheme, props) {
var ignoreHydrogens = props.ignoreHydrogens, traceOnly = props.traceOnly, includeParent = props.includeParent;
var rootUnit = includeParent ? structure.root.unitMap.get(unit.id) : unit;
var _a = getConformation(rootUnit), x = _a.x, y = _a.y, z = _a.z;
var elements = rootUnit.elements;
var _b = unit.boundary.sphere, center = _b.center, sphereRadius = _b.radius;
var extraRadius = (2 + 1.5) * 2; // TODO should be twice (the max vdW/sphere radius plus the probe radius)
var radiusSq = (sphereRadius + extraRadius) * (sphereRadius + extraRadius);
var indices;
var id;
if (ignoreHydrogens || traceOnly || (includeParent && rootUnit !== unit)) {
var _indices = [];
var _id = [];
for (var i = 0, il = elements.length; i < il; ++i) {
var eI = elements[i];
if (ignoreHydrogens && isHydrogen(rootUnit, eI))
continue;
if (traceOnly && !isTrace(rootUnit, eI))
continue;
if (includeParent && squaredDistance(x[eI], y[eI], z[eI], center) > radiusSq)
continue;
_indices.push(eI);
_id.push(i);
}
indices = int_1.SortedArray.ofSortedArray(_indices);
id = _id;
}
else {
indices = elements;
id = (0, array_1.fillSerial)(new Int32Array(indices.length));
}
if (includeParent && rootUnit !== unit) {
filterId(id, unit.elements, indices);
}
var position = { indices: indices, x: x, y: y, z: z, id: id };
var boundary = unit === rootUnit ? unit.boundary : (0, boundary_1.getBoundary)(position);
var l = structure_1.StructureElement.Location.create(structure, rootUnit);
var radius = function (index) {
l.element = index;
return sizeTheme.size(l);
};
return { position: position, boundary: boundary, radius: radius };
}
exports.getUnitConformationAndRadius = getUnitConformationAndRadius;
function getStructureConformationAndRadius(structure, sizeTheme, ignoreHydrogens, traceOnly) {
var l = structure_1.StructureElement.Location.create(structure);
var xs;
var ys;
var zs;
var rs;
var id;
if (ignoreHydrogens || traceOnly) {
var _xs = [];
var _ys = [];
var _zs = [];
var _rs = [];
var _id = [];
for (var i = 0, m = 0, il = structure.units.length; i < il; ++i) {
var unit = structure.units[i];
var elements = unit.elements;
var _a = unit.conformation, x = _a.x, y = _a.y, z = _a.z;
l.unit = unit;
for (var j = 0, jl = elements.length; j < jl; ++j) {
var eI = elements[j];
if (ignoreHydrogens && isHydrogen(unit, eI))
continue;
if (traceOnly && !isTrace(unit, eI))
continue;
_xs.push(x(eI));
_ys.push(y(eI));
_zs.push(z(eI));
l.element = eI;
_rs.push(sizeTheme.size(l));
_id.push(m + j);
}
m += elements.length;
}
xs = _xs, ys = _ys, zs = _zs, rs = _rs;
id = _id;
}
else {
var elementCount = structure.elementCount;
var _xs = new Float32Array(elementCount);
var _ys = new Float32Array(elementCount);
var _zs = new Float32Array(elementCount);
var _rs = new Float32Array(elementCount);
for (var i = 0, m = 0, il = structure.units.length; i < il; ++i) {
var unit = structure.units[i];
var elements = unit.elements;
var _b = unit.conformation, x = _b.x, y = _b.y, z = _b.z;
l.unit = unit;
for (var j = 0, jl = elements.length; j < jl; ++j) {
var eI = elements[j];
var mj = m + j;
_xs[mj] = x(eI);
_ys[mj] = y(eI);
_zs[mj] = z(eI);
l.element = eI;
_rs[mj] = sizeTheme.size(l);
}
m += elements.length;
}
xs = _xs, ys = _ys, zs = _zs, rs = _rs;
id = (0, array_1.fillSerial)(new Uint32Array(elementCount));
}
var position = { indices: int_1.OrderedSet.ofRange(0, id.length), x: xs, y: ys, z: zs, id: id };
var radius = function (index) { return rs[index]; };
return { position: position, radius: radius };
}
exports.getStructureConformationAndRadius = getStructureConformationAndRadius;
var _H = atomic_1.AtomicNumbers['H'];
function isHydrogen(unit, element) {
if (structure_1.Unit.isCoarse(unit))
return false;
return unit.model.atomicHierarchy.derived.atom.atomicNumber[element] === _H;
}
exports.isHydrogen = isHydrogen;
function isH(atomicNumber, element) {
return atomicNumber[element] === _H;
}
exports.isH = isH;
function isTrace(unit, element) {
if (structure_1.Unit.isCoarse(unit))
return true;
var atomId = unit.model.atomicHierarchy.atoms.label_atom_id.value(element);
if (atomId === 'CA' || atomId === 'BB' || atomId === 'P')
return true;
return false;
}
exports.isTrace = isTrace;