UNPKG

molstar

Version:

A comprehensive macromolecular library.

346 lines (345 loc) 16.1 kB
/** * 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 = {}));