molstar
Version:
A comprehensive macromolecular library.
346 lines (345 loc) • 16.1 kB
JavaScript
/**
* Copyright (c) 2017-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author David Sehnal <david.sehnal@gmail.com>
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import { __assign, __awaiter, __generator } from "tslib";
import { UUID } from '../../../mol-util/uuid';
import { CustomProperties } from '../../custom-property';
import { calcModelCenter, getAsymIdCount } from './util';
import { Vec3 } from '../../../mol-math/linear-algebra';
import { Coordinates } from '../coordinates';
import { Task } from '../../../mol-task';
import { IndexPairBonds } from '../../../mol-model-formats/structure/property/bonds/index-pair';
import { createModels } from '../../../mol-model-formats/structure/basic/parser';
import { MmcifFormat } from '../../../mol-model-formats/structure/mmcif';
import { ModelSymmetry } from '../../../mol-model-formats/structure/property/symmetry';
import { Column } from '../../../mol-data/db';
import { CustomModelProperty } from '../../../mol-model-props/common/custom-model-property';
import { ArrayTrajectory } from '../trajectory';
import { ModelSecondaryStructure } from '../../../mol-model-formats/structure/property/secondary-structure';
{ }
export var Model;
(function (Model) {
function _trajectoryFromModelAndCoordinates(model, coordinates) {
var trajectory = [];
var frames = coordinates.frames;
var srcIndex = model.atomicHierarchy.atomSourceIndex;
var isIdentity = Column.isIdentity(srcIndex);
var srcIndexArray = isIdentity ? void 0 : srcIndex.toArray({ array: Int32Array });
var coarseGrained = isCoarseGrained(model);
var elementCount = model.atomicHierarchy.atoms._rowCount;
for (var i = 0, il = frames.length; i < il; ++i) {
var f = frames[i];
if (f.elementCount !== elementCount) {
throw new Error("Frame element count mismatch, got ".concat(f.elementCount, " but expected ").concat(elementCount, "."));
}
var m = __assign(__assign({}, model), { id: UUID.create22(), modelNum: i, atomicConformation: Coordinates.getAtomicConformation(f, model.atomicConformation.atomId, srcIndexArray),
// TODO: add support for supplying sphere and gaussian coordinates in addition to atomic coordinates?
// coarseConformation: coarse.conformation,
customProperties: new CustomProperties(), _staticPropertyData: Object.create(null), _dynamicPropertyData: Object.create(null) });
if (f.cell) {
var symmetry = ModelSymmetry.fromCell(f.cell.size, f.cell.anglesInRadians);
ModelSymmetry.Provider.set(m, symmetry);
}
Model.TrajectoryInfo.set(m, { index: i, size: frames.length });
Model.CoarseGrained.set(m, coarseGrained);
trajectory.push(m);
}
return { trajectory: trajectory, srcIndexArray: srcIndexArray };
}
function trajectoryFromModelAndCoordinates(model, coordinates) {
return new ArrayTrajectory(_trajectoryFromModelAndCoordinates(model, coordinates).trajectory);
}
Model.trajectoryFromModelAndCoordinates = trajectoryFromModelAndCoordinates;
function trajectoryFromTopologyAndCoordinates(topology, coordinates) {
var _this = this;
return Task.create('Create Trajectory', function (ctx) { return __awaiter(_this, void 0, void 0, function () {
var models, model, trajectory, bondData, indexPairBonds, coarseGrained, index, _a, trajectory_1, m;
return __generator(this, function (_b) {
switch (_b.label) {
case 0: return [4 /*yield*/, createModels(topology.basic, topology.sourceData, ctx)];
case 1:
models = _b.sent();
if (models.frameCount === 0)
throw new Error('found no model');
model = models.representative;
trajectory = _trajectoryFromModelAndCoordinates(model, coordinates).trajectory;
bondData = { pairs: topology.bonds, count: model.atomicHierarchy.atoms._rowCount };
indexPairBonds = IndexPairBonds.fromData(bondData);
coarseGrained = isCoarseGrained(model);
index = 0;
for (_a = 0, trajectory_1 = trajectory; _a < trajectory_1.length; _a++) {
m = trajectory_1[_a];
IndexPairBonds.Provider.set(m, indexPairBonds);
Model.TrajectoryInfo.set(m, { index: index++, size: trajectory.length });
Model.CoarseGrained.set(m, coarseGrained);
}
return [2 /*return*/, new ArrayTrajectory(trajectory)];
}
});
}); });
}
Model.trajectoryFromTopologyAndCoordinates = trajectoryFromTopologyAndCoordinates;
var CenterProp = '__Center__';
function getCenter(model) {
if (model._dynamicPropertyData[CenterProp])
return model._dynamicPropertyData[CenterProp];
var center = calcModelCenter(model.atomicConformation, model.coarseConformation);
model._dynamicPropertyData[CenterProp] = center;
return center;
}
Model.getCenter = getCenter;
function invertIndex(xs) {
var invertedIndex = new Int32Array(xs.rowCount);
var isIdentity = false;
for (var i = 0, _i = xs.rowCount; i < _i; i++) {
var x = xs.value(i);
if (x !== i)
isIdentity = false;
invertedIndex[x] = i;
}
return { isIdentity: isIdentity, invertedIndex: invertedIndex };
}
var InvertedAtomSrcIndexProp = '__InvertedAtomSrcIndex__';
function getInvertedAtomSourceIndex(model) {
if (model._staticPropertyData[InvertedAtomSrcIndexProp])
return model._staticPropertyData[InvertedAtomSrcIndexProp];
var index = invertIndex(model.atomicHierarchy.atomSourceIndex);
model._staticPropertyData[InvertedAtomSrcIndexProp] = index;
return index;
}
Model.getInvertedAtomSourceIndex = getInvertedAtomSourceIndex;
var TrajectoryInfoProp = '__TrajectoryInfo__';
Model.TrajectoryInfo = {
get: function (model) {
return model._dynamicPropertyData[TrajectoryInfoProp] || { index: 0, size: 1 };
},
set: function (model, trajectoryInfo) {
return model._dynamicPropertyData[TrajectoryInfoProp] = trajectoryInfo;
}
};
var AsymIdCountProp = '__AsymIdCount__';
Model.AsymIdCount = {
get: function (model) {
if (model._dynamicPropertyData[AsymIdCountProp])
return model._dynamicPropertyData[AsymIdCountProp];
var asymIdCount = getAsymIdCount(model);
model._dynamicPropertyData[AsymIdCountProp] = asymIdCount;
return asymIdCount;
},
};
Model.AsymIdOffset = CustomModelProperty.createSimple('asym_id_offset', 'static');
Model.Index = CustomModelProperty.createSimple('index', 'static');
Model.MaxIndex = CustomModelProperty.createSimple('max_index', 'static');
function getRoot(model) {
return model.parent || model;
}
Model.getRoot = getRoot;
function areHierarchiesEqual(a, b) {
return a.atomicHierarchy === b.atomicHierarchy && a.coarseHierarchy === b.coarseHierarchy;
}
Model.areHierarchiesEqual = areHierarchiesEqual;
var CoordinatesHistoryProp = '__CoordinatesHistory__';
Model.CoordinatesHistory = {
get: function (model) {
return model._staticPropertyData[CoordinatesHistoryProp];
},
set: function (model, coordinatesHistory) {
return model._staticPropertyData[CoordinatesHistoryProp] = coordinatesHistory;
}
};
var CoarseGrainedProp = '__CoarseGrained__';
Model.CoarseGrained = {
get: function (model) {
return model._staticPropertyData[CoarseGrainedProp];
},
set: function (model, coarseGrained) {
return model._staticPropertyData[CoarseGrainedProp] = coarseGrained;
}
};
/**
* Has typical coarse grained atom names (BB, SC1) or less than three times as many
* atoms as polymer residues (C-alpha only models).
*/
function isCoarseGrained(model) {
var coarseGrained = Model.CoarseGrained.get(model);
if (coarseGrained === undefined) {
var polymerResidueCount = 0;
var polymerType = model.atomicHierarchy.derived.residue.polymerType;
for (var i = 0; i < polymerType.length; ++i) {
if (polymerType[i] !== 0 /* PolymerType.NA */)
polymerResidueCount += 1;
}
// check for coarse grained atom names
var hasBB = false, hasSC1 = false;
var _a = model.atomicHierarchy.atoms, label_atom_id = _a.label_atom_id, atomCount = _a._rowCount;
for (var i = 0; i < atomCount; ++i) {
var atomName = label_atom_id.value(i);
if (!hasBB && atomName === 'BB')
hasBB = true;
if (!hasSC1 && atomName === 'SC1')
hasSC1 = true;
if (hasBB && hasSC1)
break;
}
coarseGrained = (hasBB && hasSC1) || (polymerResidueCount && atomCount
? atomCount / polymerResidueCount < 3
: false);
Model.CoarseGrained.set(model, coarseGrained);
}
return coarseGrained;
}
Model.isCoarseGrained = isCoarseGrained;
//
function hasCarbohydrate(model) {
return model.properties.saccharideComponentMap.size > 0;
}
Model.hasCarbohydrate = hasCarbohydrate;
function hasProtein(model) {
var subtype = model.entities.subtype;
for (var i = 0, il = subtype.rowCount; i < il; ++i) {
if (subtype.value(i).startsWith('polypeptide'))
return true;
}
return false;
}
Model.hasProtein = hasProtein;
function hasNucleic(model) {
var subtype = model.entities.subtype;
for (var i = 0, il = subtype.rowCount; i < il; ++i) {
var s = subtype.value(i);
if (s.endsWith('ribonucleotide hybrid') || s.endsWith('ribonucleotide'))
return true;
}
return false;
}
Model.hasNucleic = hasNucleic;
function isFromPdbArchive(model) {
if (!MmcifFormat.is(model.sourceData))
return false;
var db = model.sourceData.data.db;
for (var i = 0, il = db.database_2.database_id.rowCount; i < il; ++i) {
if (db.database_2.database_id.value(i) === 'pdb')
return true;
}
return false;
}
Model.isFromPdbArchive = isFromPdbArchive;
function hasPdbId(model) {
if (!MmcifFormat.is(model.sourceData))
return false;
return (
// 4 character PDB id
model.entryId.match(/^[1-9][a-z0-9]{3,3}$/i) !== null ||
// long PDB id
model.entryId.match(/^pdb_[0-9]{4,4}[1-9][a-z0-9]{3,3}$/i) !== null);
}
Model.hasPdbId = hasPdbId;
function hasSecondaryStructure(model) {
if (MmcifFormat.is(model.sourceData)) {
var db = model.sourceData.data.db;
return (db.struct_conf.id.isDefined ||
db.struct_sheet_range.id.isDefined);
}
else {
return ModelSecondaryStructure.Provider.isApplicable(model);
}
}
Model.hasSecondaryStructure = hasSecondaryStructure;
var tmpAngles90 = Vec3.create(1.5707963, 1.5707963, 1.5707963); // in radians
var tmpLengths1 = Vec3.create(1, 1, 1);
function hasCrystalSymmetry(model) {
var _a;
var spacegroup = (_a = ModelSymmetry.Provider.get(model)) === null || _a === void 0 ? void 0 : _a.spacegroup;
return !!spacegroup && !(spacegroup.num === 1 &&
Vec3.equals(spacegroup.cell.anglesInRadians, tmpAngles90) &&
Vec3.equals(spacegroup.cell.size, tmpLengths1));
}
Model.hasCrystalSymmetry = hasCrystalSymmetry;
function isFromXray(model) {
if (!MmcifFormat.is(model.sourceData))
return false;
var db = model.sourceData.data.db;
for (var i = 0; i < db.exptl.method.rowCount; i++) {
var v = db.exptl.method.value(i).toUpperCase();
if (v.indexOf('DIFFRACTION') >= 0)
return true;
}
return false;
}
Model.isFromXray = isFromXray;
function isFromEm(model) {
if (!MmcifFormat.is(model.sourceData))
return false;
var db = model.sourceData.data.db;
for (var i = 0; i < db.exptl.method.rowCount; i++) {
var v = db.exptl.method.value(i).toUpperCase();
if (v.indexOf('MICROSCOPY') >= 0)
return true;
}
return false;
}
Model.isFromEm = isFromEm;
function isFromNmr(model) {
if (!MmcifFormat.is(model.sourceData))
return false;
var db = model.sourceData.data.db;
for (var i = 0; i < db.exptl.method.rowCount; i++) {
var v = db.exptl.method.value(i).toUpperCase();
if (v.indexOf('NMR') >= 0)
return true;
}
return false;
}
Model.isFromNmr = isFromNmr;
function hasXrayMap(model) {
if (!MmcifFormat.is(model.sourceData))
return false;
// Check exprimental method to exclude models solved with
// 'ELECTRON CRYSTALLOGRAPHY' which also have structure factors
if (!isFromXray(model))
return false;
var db = model.sourceData.data.db;
var status_code_sf = db.pdbx_database_status.status_code_sf;
return status_code_sf.isDefined && status_code_sf.value(0) === 'REL';
}
Model.hasXrayMap = hasXrayMap;
/**
* Also checks for `content_type` of 'associated EM volume' to exclude cases
* like 6TEK which are solved with 'X-RAY DIFFRACTION' but have an related
* EMDB entry of type 'other EM volume'.
*/
function hasEmMap(model) {
if (!MmcifFormat.is(model.sourceData))
return false;
var db = model.sourceData.data.db;
var _a = db.pdbx_database_related, db_name = _a.db_name, content_type = _a.content_type;
for (var i = 0, il = db.pdbx_database_related._rowCount; i < il; ++i) {
if (db_name.value(i).toUpperCase() === 'EMDB' && content_type.value(i) === 'associated EM volume') {
return true;
}
}
return false;
}
Model.hasEmMap = hasEmMap;
function hasDensityMap(model) {
if (!MmcifFormat.is(model.sourceData))
return false;
return hasXrayMap(model) || hasEmMap(model);
}
Model.hasDensityMap = hasDensityMap;
function probablyHasDensityMap(model) {
if (!MmcifFormat.is(model.sourceData))
return false;
var db = model.sourceData.data.db;
return hasDensityMap(model) || (
// check if from pdb archive but missing relevant meta data
hasPdbId(model) && (!db.exptl.method.isDefined ||
(isFromXray(model) && (!db.pdbx_database_status.status_code_sf.isDefined ||
db.pdbx_database_status.status_code_sf.valueKind(0) === 2 /* Column.ValueKind.Unknown */)) ||
(isFromEm(model) && (!db.pdbx_database_related.db_name.isDefined))));
}
Model.probablyHasDensityMap = probablyHasDensityMap;
})(Model || (Model = {}));