UNPKG

molstar

Version:

A comprehensive macromolecular library.

182 lines (181 loc) 8.55 kB
"use strict"; /** * Copyright (c) 2023-2025 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author Adam Midlik <midlik@gmail.com> * @author David Sehnal <david.sehnal@gmail.com> */ Object.defineProperty(exports, "__esModule", { value: true }); exports.ParseFormatMvsToMolstar = void 0; exports.convertMvsToMolstar = convertMvsToMolstar; exports.mvsSanityCheckIssues = mvsSanityCheckIssues; exports.mvsSanityCheck = mvsSanityCheck; const object_1 = require("../../../../mol-util/object.js"); const tree_utils_1 = require("../generic/tree-utils.js"); const mvs_tree_1 = require("../mvs/mvs-tree.js"); /** Convert `format` parameter of `parse` node in `MolstarTree` * into `format` and `is_binary` parameters in `MolstarTree` */ exports.ParseFormatMvsToMolstar = { // trajectory mmcif: { format: 'cif', is_binary: false }, bcif: { format: 'cif', is_binary: true }, pdb: { format: 'pdb', is_binary: false }, pdbqt: { format: 'pdbqt', is_binary: false }, gro: { format: 'gro', is_binary: false }, xyz: { format: 'xyz', is_binary: false }, mol: { format: 'mol', is_binary: false }, sdf: { format: 'sdf', is_binary: false }, mol2: { format: 'mol2', is_binary: false }, lammpstrj: { format: 'lammpstrj', is_binary: false }, // coordinates xtc: { format: 'xtc', is_binary: true }, nctraj: { format: 'nctraj', is_binary: true }, dcd: { format: 'dcd', is_binary: true }, trr: { format: 'trr', is_binary: true }, // topology psf: { format: 'psf', is_binary: false }, prmtop: { format: 'prmtop', is_binary: false }, top: { format: 'top', is_binary: false }, // maps map: { format: 'map', is_binary: true }, dx: { format: 'dx', is_binary: false }, dxbin: { format: 'dxbin', is_binary: true }, }; const TopologyFormats = new Set(['psf', 'prmtop', 'top']); /** Conversion rules for conversion from `MVSTree` (with all parameter values) to `MolstarTree` */ const mvsToMolstarConversionRules = { 'download': node => ({ subtree: [] }), 'parse': (node, parent) => { const { format, is_binary } = exports.ParseFormatMvsToMolstar[node.params.format]; if ((parent === null || parent === void 0 ? void 0 : parent.kind) === 'download') { return { subtree: [ { kind: 'download', params: { ...parent.params, is_binary }, custom: parent.custom, ref: parent.ref }, { kind: 'parse', params: { ...node.params, format }, custom: node.custom, ref: node.ref } ] }; } else { console.warn('"parse" node is not being converted, this is suspicious'); return { subtree: [ { kind: 'parse', params: { ...node.params, format }, custom: node.custom, ref: node.ref } ] }; } }, 'coordinates': (node, parent) => { if ((parent === null || parent === void 0 ? void 0 : parent.kind) !== 'parse') throw new Error(`Parent of "coordinates" must be "parse", not "${parent === null || parent === void 0 ? void 0 : parent.kind}".`); const { format } = exports.ParseFormatMvsToMolstar[parent.params.format]; return { subtree: [ { kind: 'coordinates', params: { format }, custom: node.custom, ref: node.ref } ] }; }, 'structure': (node, parent) => { if ((parent === null || parent === void 0 ? void 0 : parent.kind) !== 'parse') throw new Error(`Parent of "structure" must be "parse", not "${parent === null || parent === void 0 ? void 0 : parent.kind}".`); const { format } = exports.ParseFormatMvsToMolstar[parent.params.format]; if (TopologyFormats.has(parent.params.format)) { if (!node.params.coordinates_ref) { throw new Error(`"structure" node with topology format "${parent.params.format}" must have "coordinates_ref" parameter.`); } return { subtree: [ { kind: 'topology_with_coordinates', params: { format, coordinates_ref: node.params.coordinates_ref } }, { kind: 'model', params: (0, object_1.pickObjectKeys)(node.params, ['model_index']) }, { kind: 'structure', params: (0, object_1.omitObjectKeys)(node.params, ['block_header', 'block_index', 'model_index', 'coordinates_ref']), custom: node.custom, ref: node.ref }, ] }; } else if (node.params.coordinates_ref) { return { subtree: [ { kind: 'trajectory', params: { format, ...(0, object_1.pickObjectKeys)(node.params, ['block_header', 'block_index']) } }, { kind: 'model', params: { model_index: 0 } }, { kind: 'trajectory_with_coordinates', params: { coordinates_ref: node.params.coordinates_ref } }, { kind: 'model', params: (0, object_1.pickObjectKeys)(node.params, ['model_index']) }, { kind: 'structure', params: (0, object_1.omitObjectKeys)(node.params, ['block_header', 'block_index', 'model_index', 'coordinates_ref']), custom: node.custom, ref: node.ref }, ] }; } else { return { subtree: [ { kind: 'trajectory', params: { format, ...(0, object_1.pickObjectKeys)(node.params, ['block_header', 'block_index']) } }, { kind: 'model', params: (0, object_1.pickObjectKeys)(node.params, ['model_index']) }, { kind: 'structure', params: (0, object_1.omitObjectKeys)(node.params, ['block_header', 'block_index', 'model_index', 'coordinates_ref']), custom: node.custom, ref: node.ref }, ] }; } }, }; /** Node kinds in `MolstarTree` that it makes sense to condense */ const molstarNodesToCondense = new Set(['download', 'parse', 'trajectory', 'model']); /** Convert MolViewSpec tree into MolStar tree */ function convertMvsToMolstar(mvsTree, sourceUrl) { const full = (0, tree_utils_1.addDefaults)(mvsTree, mvs_tree_1.MVSTreeSchema); if (sourceUrl) (0, tree_utils_1.resolveUris)(full, sourceUrl, ['uri', 'url']); const converted = (0, tree_utils_1.convertTree)(full, mvsToMolstarConversionRules); if (converted.kind !== 'root') throw new Error("Root's type is not 'root' after conversion from MVS tree to Molstar tree."); const condensed = (0, tree_utils_1.condenseTree)(converted, molstarNodesToCondense); return condensed; } function fileExtensionMatches(filename, extensions) { filename = filename.toLowerCase(); return extensions.some(ext => ext === '*' || filename.endsWith(ext)); } const StructureFormatExtensions = { // trajectory mmcif: ['.cif', '.mmif'], bcif: ['.bcif'], pdb: ['.pdb', '.ent'], pdbqt: ['.pdbqt'], gro: ['.gro'], xyz: ['.xyz'], mol: ['.mol'], sdf: ['.sdf'], mol2: ['.mol2'], lammpstrj: ['.lammpstrj'], // coordinates xtc: ['.xtc'], nctraj: ['.nc', '.nctraj'], dcd: ['.dcd'], trr: ['.trr'], // topology psf: ['.psf'], prmtop: ['.prmtop', '.parm7'], top: ['.top'], // volumes map: ['.map', '.ccp4', '.mrc', '.mrcs'], dx: ['.dx'], dxbin: ['.dxbin'], }; /** Run some sanity check on a MVSTree. Return a list of potential problems (`undefined` if there are none) */ function mvsSanityCheckIssues(tree) { const result = []; (0, tree_utils_1.dfs)(tree, (node, parent) => { if (node.kind === 'parse' && (parent === null || parent === void 0 ? void 0 : parent.kind) === 'download') { const source = parent.params.url; const extensions = StructureFormatExtensions[node.params.format]; if (!fileExtensionMatches(source, extensions)) { result.push(`Parsing data from ${source} as ${node.params.format} format might be a mistake. The file extension doesn't match recommended file extensions (${extensions.join(', ')})`); } } }); return result.length > 0 ? result : undefined; } /** Run some sanity check on a MVSTree and print potential issues to the console. */ function mvsSanityCheck(tree) { const issues = mvsSanityCheckIssues(tree); if (issues) { console.warn('There are potential issues in the MVS tree:'); for (const issue of issues) { console.warn(' ', issue); } } }