molstar
Version:
A comprehensive macromolecular library.
149 lines (148 loc) • 9.65 kB
JavaScript
"use strict";
/**
* Copyright (c) 2023 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Sebastian Bittrich <sebastian.bittrich@rcsb.org>
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.ChemicalComponentPreset = exports.ChemicalCompontentTrajectoryHierarchyPreset = void 0;
const param_definition_1 = require("../../../mol-util/param-definition");
const mol_state_1 = require("../../../mol-state");
const transforms_1 = require("../../../mol-plugin-state/transforms");
const representation_preset_1 = require("../../../mol-plugin-state/builder/structure/representation-preset");
const mmcif_1 = require("../../../mol-model-formats/structure/mmcif");
const minimize_rmsd_1 = require("../../../mol-math/linear-algebra/3d/minimize-rmsd");
const set_1 = require("../../../mol-util/set");
const hierarchy_preset_1 = require("../../../mol-plugin-state/builder/structure/hierarchy-preset");
const string_1 = require("../../../mol-util/string");
const CCDParams = (a, plugin) => ({
representationPresetParams: param_definition_1.ParamDefinition.Optional(param_definition_1.ParamDefinition.Group(representation_preset_1.StructureRepresentationPresetProvider.CommonParams)),
showOriginalCoordinates: param_definition_1.ParamDefinition.Optional(param_definition_1.ParamDefinition.Boolean(true, { description: `Show original coordinates for 'model' and 'ideal' structure and do not align them.` })),
shownCoordinateType: param_definition_1.ParamDefinition.Select('ideal', param_definition_1.ParamDefinition.arrayToOptions(['ideal', 'model', 'both']), { description: `What coordinate sets are visible.` }),
aromaticBonds: param_definition_1.ParamDefinition.Boolean(false, { description: 'Display aromatic bonds with dashes' }),
...hierarchy_preset_1.TrajectoryHierarchyPresetProvider.CommonParams(a, plugin)
});
exports.ChemicalCompontentTrajectoryHierarchyPreset = (0, hierarchy_preset_1.TrajectoryHierarchyPresetProvider)({
id: 'preset-trajectory-ccd',
display: {
name: 'Chemical Component', group: 'Preset',
description: 'Shows molecules from the Chemical Component Dictionary.'
},
isApplicable: o => {
return mmcif_1.CCDFormat.is(o.data.representative.sourceData);
},
params: CCDParams,
async apply(trajectory, params, plugin) {
var _a, _b;
const tr = (_b = (_a = mol_state_1.StateObjectRef.resolveAndCheck(plugin.state.data, trajectory)) === null || _a === void 0 ? void 0 : _a.obj) === null || _b === void 0 ? void 0 : _b.data;
if (!tr)
return {};
const builder = plugin.builders.structure;
const idealModel = await builder.createModel(trajectory, { modelIndex: 0 });
const idealModelProperties = await builder.insertModelProperties(idealModel, params.modelProperties, { isCollapsed: true });
const idealStructure = await builder.createStructure(idealModelProperties || idealModel, { name: 'model', params: {} });
const idealStructureProperties = await builder.insertStructureProperties(idealStructure, params.structureProperties);
const representationPreset = params.representationPreset || exports.ChemicalComponentPreset.id;
const representationPresetParams = params.representationPresetParams || {};
if (representationPresetParams.ignoreHydrogens === undefined)
representationPresetParams.ignoreHydrogens = true;
// degenerate case where either model or ideal coordinates are missing
if (tr.frameCount !== 2) {
const coordinateType = mmcif_1.CCDFormat.CoordinateType.get(idealModel.obj.data);
await builder.representation.applyPreset(idealStructureProperties, representationPreset, { ...representationPresetParams, coordinateType });
return { models: [idealModel], structures: [idealStructure] };
}
const modelModel = await builder.createModel(trajectory, { modelIndex: 1 });
const modelModelProperties = await builder.insertModelProperties(modelModel, params.modelProperties, { isCollapsed: true });
const modelStructure = await builder.createStructure(modelModelProperties || modelModel, { name: 'model', params: {} });
const modelStructureProperties = await builder.insertStructureProperties(modelStructure, params.structureProperties);
// align ideal and model coordinates
if (!params.showOriginalCoordinates) {
const [a, b] = getPositionTables(idealStructure.obj.data, modelStructure.obj.data);
if (!a) {
plugin.log.warn(`Cannot align chemical components whose atom sets are disjoint.`);
}
else {
const { bTransform, rmsd } = minimize_rmsd_1.MinimizeRmsd.compute({ a, b });
await transform(plugin, modelStructure.cell, bTransform);
plugin.log.info(`Superposed [model] and [ideal] with RMSD ${rmsd.toFixed(2)}.`);
}
}
await builder.representation.applyPreset(idealStructureProperties, representationPreset, { ...representationPresetParams, aromaticBonds: params.aromaticBonds, coordinateType: 'ideal', isHidden: params.shownCoordinateType === 'model' });
await builder.representation.applyPreset(modelStructureProperties, representationPreset, { ...representationPresetParams, aromaticBonds: params.aromaticBonds, coordinateType: 'model', isHidden: params.shownCoordinateType === 'ideal' });
return { models: [idealModel, modelModel], structures: [idealStructure, modelStructure] };
}
});
function getPositionTables(s1, s2) {
const m1 = getAtomIdSerialMap(s1);
const m2 = getAtomIdSerialMap(s2);
const intersecting = set_1.SetUtils.intersection(new Set(m1.keys()), new Set(m2.keys()));
const ret = [
minimize_rmsd_1.MinimizeRmsd.Positions.empty(intersecting.size),
minimize_rmsd_1.MinimizeRmsd.Positions.empty(intersecting.size)
];
let o = 0;
intersecting.forEach(k => {
ret[0].x[o] = s1.model.atomicConformation.x[m1.get(k)];
ret[0].y[o] = s1.model.atomicConformation.y[m1.get(k)];
ret[0].z[o] = s1.model.atomicConformation.z[m1.get(k)];
ret[1].x[o] = s2.model.atomicConformation.x[m2.get(k)];
ret[1].y[o] = s2.model.atomicConformation.y[m2.get(k)];
ret[1].z[o] = s2.model.atomicConformation.z[m2.get(k)];
o++;
});
return ret;
}
function getAtomIdSerialMap(structure) {
const map = new Map();
const { label_atom_id } = structure.model.atomicHierarchy.atoms;
for (let i = 0, il = label_atom_id.rowCount; i < il; ++i) {
const id = label_atom_id.value(i);
if (!map.has(id))
map.set(id, map.size);
}
return map;
}
function transform(plugin, s, matrix) {
const b = plugin.state.data.build().to(s)
.insert(transforms_1.StateTransforms.Model.TransformStructureConformation, { transform: { name: 'matrix', params: { data: matrix, transpose: false } } });
return plugin.runTask(plugin.state.data.updateTree(b));
}
exports.ChemicalComponentPreset = (0, representation_preset_1.StructureRepresentationPresetProvider)({
id: 'preset-structure-representation-chemical-component',
display: {
name: 'Chemical Component', group: 'Miscellaneous',
description: `Show 'Ideal' and 'Model' coordinates of chemical components.`
},
isApplicable: o => {
return mmcif_1.CCDFormat.is(o.data.model.sourceData);
},
params: () => ({
...representation_preset_1.StructureRepresentationPresetProvider.CommonParams,
aromaticBonds: param_definition_1.ParamDefinition.Boolean(true),
coordinateType: param_definition_1.ParamDefinition.Select('ideal', param_definition_1.ParamDefinition.arrayToOptions(['ideal', 'model'])),
isHidden: param_definition_1.ParamDefinition.Boolean(false),
}),
async apply(ref, params, plugin) {
var _a, _b, _c, _d, _e, _f;
const structureCell = mol_state_1.StateObjectRef.resolveAndCheck(plugin.state.data, ref);
if (!structureCell)
return {};
const { aromaticBonds, coordinateType, isHidden } = params;
const components = {
[coordinateType]: await (0, representation_preset_1.presetStaticComponent)(plugin, structureCell, 'all', { label: (0, string_1.capitalize)(coordinateType), tags: [coordinateType] })
};
const structure = structureCell.obj.data;
const { update, builder, typeParams } = representation_preset_1.StructureRepresentationPresetProvider.reprBuilder(plugin, params);
const representations = {
[coordinateType]: builder.buildRepresentation(update, components[coordinateType], { type: 'ball-and-stick', typeParams: { ...typeParams, aromaticBonds } }, { initialState: { isHidden } }),
};
// sync UI state
if (((_b = (_a = components[coordinateType]) === null || _a === void 0 ? void 0 : _a.cell) === null || _b === void 0 ? void 0 : _b.state) && isHidden) {
mol_state_1.StateTransform.assignState(components[coordinateType].cell.state, { isHidden });
}
await update.commit({ revertOnError: true });
await representation_preset_1.StructureRepresentationPresetProvider.updateFocusRepr(plugin, structure, (_d = (_c = params.theme) === null || _c === void 0 ? void 0 : _c.focus) === null || _d === void 0 ? void 0 : _d.name, (_f = (_e = params.theme) === null || _e === void 0 ? void 0 : _e.focus) === null || _f === void 0 ? void 0 : _f.params);
return { components, representations };
}
});