molstar
Version:
A comprehensive macromolecular library.
184 lines (183 loc) • 8.56 kB
JavaScript
"use strict";
/**
* Copyright (c) 2023 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
* @author David Sehnal <david.sehnal@gmail.com>
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.MmcifStructure = exports.MmcifAssembly = void 0;
const int_1 = require("../../../../mol-data/int.js");
const geometry_1 = require("../../../../mol-math/geometry.js");
const linear_algebra_1 = require("../../../../mol-math/linear-algebra.js");
const symmetry_1 = require("../../../../mol-model-formats/structure/property/symmetry.js");
const custom_structure_property_1 = require("../../../../mol-model-props/common/custom-structure-property.js");
const structure_1 = require("../../../../mol-model/structure.js");
const symmetry_2 = require("../../../../mol-model/structure/model/properties/symmetry.js");
const objects_1 = require("../../../../mol-plugin-state/objects.js");
const transformer_1 = require("../../../../mol-state/transformer.js");
const mol_task_1 = require("../../../../mol-task/index.js");
const mol_util_1 = require("../../../../mol-util/index.js");
const param_definition_1 = require("../../../../mol-util/param-definition.js");
const util_1 = require("../util.js");
function createModelChainMap(model) {
const builder = new structure_1.Structure.StructureBuilder();
const units = new Map();
const { label_asym_id, _rowCount } = model.atomicHierarchy.chains;
const { offsets } = model.atomicHierarchy.chainAtomSegments;
for (let i = 0; i < _rowCount; i++) {
const elements = int_1.SortedArray.ofBounds(offsets[i], offsets[i + 1]);
const unit = builder.addUnit(structure_1.Unit.Kind.Atomic, model, geometry_1.SymmetryOperator.Default, elements, structure_1.Unit.Trait.FastBoundary);
units.set(label_asym_id.value(i), unit);
}
return units;
}
function buildAssembly(model, assembly) {
const coordinateSystem = geometry_1.SymmetryOperator.create(assembly.id, linear_algebra_1.Mat4.identity(), { assembly: { id: assembly.id, operId: 0, operList: [] } });
const assembler = structure_1.Structure.Builder({
coordinateSystem,
label: model.label,
});
const units = createModelChainMap(model);
for (const g of assembly.operatorGroups) {
for (const oper of g.operators) {
for (const id of g.asymIds) {
const u = units.get(id);
if (u) {
assembler.addWithOperator(u, oper);
}
else {
console.log(`missing asymId '${id}'`);
}
}
}
}
return assembler.getStructure();
}
const MmcifAssembly = objects_1.PluginStateTransform.BuiltIn({
name: 'mmcif-assembly',
display: { name: 'Mmcif Assembly' },
from: objects_1.PluginStateObject.Molecule.Model,
to: objects_1.PluginStateObject.Molecule.Structure,
params: {
id: param_definition_1.ParamDefinition.Text('', { label: 'Asm Id', description: 'Assembly Id (use empty for the 1st assembly)' }),
}
})({
canAutoUpdate({ newParams }) {
return true;
},
apply({ a, params }, plugin) {
return mol_task_1.Task.create('Build Structure', async (ctx) => {
const model = a.data;
let id = params.id;
let asm = void 0;
const symmetry = symmetry_1.ModelSymmetry.Provider.get(model);
// if no id is specified, use the 1st assembly.
if (!id && symmetry && symmetry.assemblies.length !== 0) {
id = symmetry.assemblies[0].id;
}
if (!symmetry || symmetry.assemblies.length === 0) {
plugin.log.warn(`Model '${model.entryId}' has no assembly, returning model structure.`);
}
else {
asm = symmetry_2.Symmetry.findAssembly(model, id || '');
if (!asm) {
plugin.log.warn(`Model '${model.entryId}' has no assembly called '${id}', returning model structure.`);
}
}
const base = structure_1.Structure.ofModel(model);
if (!asm) {
const label = { label: 'Model', description: structure_1.Structure.elementDescription(base) };
return new objects_1.PluginStateObject.Molecule.Structure(base, label);
}
const s = buildAssembly(model, asm);
const objProps = { label: `Assembly ${id}`, description: structure_1.Structure.elementDescription(s) };
return new objects_1.PluginStateObject.Molecule.Structure(s, objProps);
});
},
update({ newParams, oldParams }) {
return (0, mol_util_1.deepEqual)(newParams, oldParams)
? transformer_1.StateTransformer.UpdateResult.Unchanged
: transformer_1.StateTransformer.UpdateResult.Recreate;
},
dispose({ b }) {
b === null || b === void 0 ? void 0 : b.data.customPropertyDescriptors.dispose();
}
});
exports.MmcifAssembly = MmcifAssembly;
const UnitsByEntity = custom_structure_property_1.CustomStructureProperty.createSimple('units_by_entity', 'root');
function getUnitsByEntity(structure) {
if (UnitsByEntity.get(structure).value) {
return UnitsByEntity.get(structure).value;
}
const atomicIndex = structure.model.atomicHierarchy.index;
const spheresIndex = structure.model.coarseHierarchy.spheres;
const map = new Map();
for (const ug of structure.unitSymmetryGroups) {
const u = ug.units[0];
let e;
if (structure_1.Unit.isAtomic(u)) {
e = atomicIndex.getEntityFromChain(u.chainIndex[u.elements[0]]);
}
else if (structure_1.Unit.isSpheres(u)) {
e = spheresIndex.getEntityFromChain(u.coarseElements.chainElementSegments.index[u.elements[0]]);
}
else {
continue;
}
if (!map.has(e))
map.set(e, []);
const entityUnits = map.get(e);
for (let i = 0, il = ug.units.length; i < il; ++i) {
entityUnits.push(ug.units[i]);
}
}
UnitsByEntity.set(structure, { value: map }, map);
return map;
}
const MmcifStructure = objects_1.PluginStateTransform.BuiltIn({
name: 'mmcif-structure',
display: { name: 'Mmcif Structure' },
from: objects_1.PluginStateObject.Root,
to: objects_1.PluginStateObject.Molecule.Structure,
params: {
structureRef: param_definition_1.ParamDefinition.Text(''),
entityId: param_definition_1.ParamDefinition.Text(''),
cellSize: param_definition_1.ParamDefinition.Numeric(500, { min: 0, max: 10000, step: 100 }),
}
})({
canAutoUpdate({ newParams }) {
return true;
},
apply({ a, params, dependencies }) {
return mol_task_1.Task.create('Build Structure', async (ctx) => {
const parent = dependencies[params.structureRef].data;
const { entities } = parent.model;
const idx = entities.getEntityIndex(params.entityId);
const unitsByEntity = getUnitsByEntity(parent);
const units = unitsByEntity.get(idx) || [];
const unitCount = units.length;
let structure;
if (unitCount > 1 && units.every(u => u.conformation.operator.isIdentity)) {
const mergedUnits = (0, util_1.partitionUnits)(units, params.cellSize);
structure = structure_1.Structure.create(mergedUnits);
}
else {
structure = structure_1.Structure.create(units);
}
// could also use _struct_ref.pdbx_db_accession to point to uniprot with _struct_ref.db_name == UNP
const label = entities.data.pdbx_description.value(idx).join(', ') || 'model';
const description = `*Entity id* ${entities.data.id.value(idx)} *src_method* ${entities.data.src_method.value(idx)} *type* ${entities.data.type.value(idx)}`;
return new objects_1.PluginStateObject.Molecule.Structure(structure, { label, description: description });
});
},
update({ newParams, oldParams }) {
return (0, mol_util_1.deepEqual)(newParams, oldParams)
? transformer_1.StateTransformer.UpdateResult.Unchanged
: transformer_1.StateTransformer.UpdateResult.Recreate;
},
dispose({ b }) {
b === null || b === void 0 ? void 0 : b.data.customPropertyDescriptors.dispose();
}
});
exports.MmcifStructure = MmcifStructure;