UNPKG

molstar

Version:

A comprehensive macromolecular library.

372 lines 18.5 kB
/** * Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author David Sehnal <david.sehnal@gmail.com> */ import { __assign, __awaiter, __generator } from "tslib"; import * as path from 'path'; import { CifWriter } from '../../../mol-io/writer/cif'; import { Structure, StructureQuery, StructureSelection } from '../../../mol-model/structure'; import { encode_mmCIF_categories } from '../../../mol-model/structure/export/mmcif'; import { ConsoleLogger } from '../../../mol-util/console-logger'; import { now } from '../../../mol-util/now'; import { PerformanceMonitor } from '../../../mol-util/performance-monitor'; import { ModelServerConfig as Config } from '../config'; import { createModelPropertiesProviderFromConfig } from '../property-provider'; import { VERSION } from '../version'; import { createStructureWrapperFromJobEntry, resolveStructures } from './structure-wrapper'; var CifField = CifWriter.Field; import { splitCamelCase } from '../../../mol-util/string'; import { ComponentBond } from '../../../mol-model-formats/structure/property/bonds/chem_comp'; import { SdfWriter } from '../../../mol-io/writer/sdf'; import { MolWriter } from '../../../mol-io/writer/mol'; import { Mol2Writer } from '../../../mol-io/writer/mol2'; import { MolEncoder } from '../../../mol-io/writer/mol/encoder'; import { Mol2Encoder } from '../../../mol-io/writer/mol2/encoder'; import { ComponentAtom } from '../../../mol-model-formats/structure/property/atoms/chem_comp'; import { Mat4 } from '../../../mol-math/linear-algebra'; import { GlobalModelTransformInfo } from '../../../mol-model/structure/model/properties/global-transform'; var perf = new PerformanceMonitor(); var _propertyProvider; function propertyProvider() { if (_propertyProvider) return _propertyProvider; _propertyProvider = createModelPropertiesProviderFromConfig() || (function () { return []; }); return _propertyProvider; } export function resolveJob(job) { return __awaiter(this, void 0, void 0, function () { return __generator(this, function (_a) { if (job.responseFormat.tarball) { return [2 /*return*/, resolveMultiFile(job)]; } else { return [2 /*return*/, resolveSingleFile(job)]; } return [2 /*return*/]; }); }); } var SharedParams = { encoderName: "ModelServer " + VERSION }; var SharedLigandWritingParams = __assign(__assign({}, SharedParams), { hydrogens: true }); function createEncoder(job) { switch (job.responseFormat.encoding) { case 'bcif': return CifWriter.createEncoder(__assign(__assign({}, SharedParams), { binary: true, binaryAutoClassifyEncoding: true })); case 'sdf': ensureCompatibleQueryType(job); return SdfWriter.createEncoder(__assign({}, SharedLigandWritingParams)); case 'mol': ensureCompatibleQueryType(job); return MolWriter.createEncoder(__assign({}, SharedLigandWritingParams)); case 'mol2': ensureCompatibleQueryType(job); return Mol2Writer.createEncoder(__assign({}, SharedLigandWritingParams)); default: return CifWriter.createEncoder(__assign(__assign({}, SharedParams), { binary: false, binaryAutoClassifyEncoding: true })); } } function ensureCompatibleQueryType(job) { job.entries.forEach(function (e) { if (e.queryDefinition.niceName !== 'Ligand') { throw Error("sdf, mol and mol2 encoding are only available for queries of type 'Ligand'"); } }); } function resolveSingleFile(job) { return __awaiter(this, void 0, void 0, function () { var encoder, headerMap, _i, _a, entry, hasDataBlock, structure, header, i, e_1; return __generator(this, function (_b) { switch (_b.label) { case 0: ConsoleLogger.logId(job.id, 'Query', "Starting (format: " + job.responseFormat.encoding + ")."); encoder = createEncoder(job); headerMap = new Map(); _i = 0, _a = job.entries; _b.label = 1; case 1: if (!(_i < _a.length)) return [3 /*break*/, 7]; entry = _a[_i]; hasDataBlock = false; _b.label = 2; case 2: _b.trys.push([2, 5, , 6]); return [4 /*yield*/, createStructureWrapperFromJobEntry(entry, propertyProvider())]; case 3: structure = _b.sent(); header = structure.cifFrame.header.toUpperCase(); if (headerMap.has(header)) { i = headerMap.get(header) + 1; headerMap.set(header, i); header += ' ' + i; } else { headerMap.set(header, 0); } encoder.startDataBlock(header); hasDataBlock = true; return [4 /*yield*/, resolveJobEntry(entry, structure, encoder)]; case 4: _b.sent(); return [3 /*break*/, 6]; case 5: e_1 = _b.sent(); if (job.entries.length === 1) { throw e_1; } else { if (!hasDataBlock) { createErrorDataBlock(entry, encoder); } doError(entry, encoder, e_1); ConsoleLogger.errorId(entry.job.id, '' + e_1); } return [3 /*break*/, 6]; case 6: _i++; return [3 /*break*/, 1]; case 7: ConsoleLogger.logId(job.id, 'Query', 'Encoding.'); encoder.encode(); encoder.writeTo(job.writer); return [2 /*return*/]; } }); }); } function getFilename(i, entry, header, encoding) { return i + "_" + header.toLowerCase() + "_" + splitCamelCase(entry.queryDefinition.name.replace(/\s/g, '_'), '-').toLowerCase() + "." + encoding; } function resolveMultiFile(job) { return __awaiter(this, void 0, void 0, function () { var i, _i, _a, entry, encoder, hasDataBlock, header, structure, e_2; return __generator(this, function (_b) { switch (_b.label) { case 0: ConsoleLogger.logId(job.id, 'Query', 'Starting.'); i = 0; _i = 0, _a = job.entries; _b.label = 1; case 1: if (!(_i < _a.length)) return [3 /*break*/, 8]; entry = _a[_i]; encoder = createEncoder(job); hasDataBlock = false; header = ''; _b.label = 2; case 2: _b.trys.push([2, 5, , 6]); return [4 /*yield*/, createStructureWrapperFromJobEntry(entry, propertyProvider())]; case 3: structure = _b.sent(); header = structure.cifFrame.header; encoder.startDataBlock(structure.cifFrame.header); hasDataBlock = true; return [4 /*yield*/, resolveJobEntry(entry, structure, encoder)]; case 4: _b.sent(); return [3 /*break*/, 6]; case 5: e_2 = _b.sent(); if (!hasDataBlock) { header = createErrorDataBlock(entry, encoder); } ConsoleLogger.errorId(entry.job.id, '' + e_2); doError(entry, encoder, e_2); return [3 /*break*/, 6]; case 6: ConsoleLogger.logId(job.id, 'Query', "Encoding " + entry.key + "/" + entry.queryDefinition.name); encoder.encode(); job.writer.beginEntry(getFilename(++i, entry, header, job.responseFormat.encoding), encoder.getSize()); encoder.writeTo(job.writer); job.writer.endEntry(); ConsoleLogger.logId(job.id, 'Query', "Written " + entry.key + "/" + entry.queryDefinition.name); _b.label = 7; case 7: _i++; return [3 /*break*/, 1]; case 8: return [2 /*return*/]; } }); }); } function createErrorDataBlock(job, encoder) { var header; if (job.sourceId === '_local_') header = path.basename(job.entryId).replace(/[^a-z0-9\-]/gi, '').toUpperCase(); else header = job.entryId.replace(/[^a-z0-9\-]/gi, '').toUpperCase(); encoder.startDataBlock(header); return header; } function resolveJobEntry(entry, structure, encoder) { return __awaiter(this, void 0, void 0, function () { var sourceStructures, structures, _i, sourceStructures_1, s, _a, _b, modelNums_1, queries, result, i, s, stats, e_3; return __generator(this, function (_c) { switch (_c.label) { case 0: ConsoleLogger.logId(entry.job.id, 'Query', "Start " + entry.key + "/" + entry.queryDefinition.name + "."); _c.label = 1; case 1: _c.trys.push([1, 7, 8, 9]); perf.start('query'); return [4 /*yield*/, resolveStructures(structure, entry.modelNums)]; case 2: sourceStructures = _c.sent(); if (!sourceStructures.length) throw new Error('Model not available'); structures = sourceStructures; if (!entry.queryDefinition.structureTransform) return [3 /*break*/, 6]; structures = []; _i = 0, sourceStructures_1 = sourceStructures; _c.label = 3; case 3: if (!(_i < sourceStructures_1.length)) return [3 /*break*/, 6]; s = sourceStructures_1[_i]; _b = (_a = structures).push; return [4 /*yield*/, entry.queryDefinition.structureTransform(entry.normalizedParams, s)]; case 4: _b.apply(_a, [_c.sent()]); _c.label = 5; case 5: _i++; return [3 /*break*/, 3]; case 6: modelNums_1 = entry.modelNums || structure.models.map(function (m) { return m.modelNum; }); queries = structures.map(function (s) { return entry.queryDefinition.query(entry.normalizedParams, s, modelNums_1); }); result = []; for (i = 0; i < structures.length; i++) { s = StructureSelection.unionStructure(StructureQuery.run(queries[i], structures[i], { timeoutMs: Config.queryTimeoutMs })); if (s.elementCount > 0) { if (!entry.transform || Mat4.isIdentity(entry.transform)) { result.push(s); } else { result.push(Structure.transform(s, entry.transform)); } } } perf.end('query'); ConsoleLogger.logId(entry.job.id, 'Query', "Queried " + entry.key + "/" + entry.queryDefinition.name + "."); perf.start('encode'); encoder.binaryEncodingProvider = getEncodingProvider(structure); // TODO: this actually needs to "reversible" in case of error. encoder.writeCategory(_model_server_result, entry); encoder.writeCategory(_model_server_params, entry); if (entry.queryDefinition.niceName === 'Ligand') { if (encoder instanceof MolEncoder) { encoder.setComponentAtomData(ComponentAtom.Provider.get(structure.models[0])); } if (encoder instanceof MolEncoder || encoder instanceof Mol2Encoder) { encoder.setComponentBondData(ComponentBond.Provider.get(structure.models[0])); } } // TODO propagate data for cif/bcif as well? if (!entry.copyAllCategories && entry.queryDefinition.filter) encoder.setFilter(entry.queryDefinition.filter); if (result.length > 0) encode_mmCIF_categories(encoder, result, { copyAllCategories: entry.copyAllCategories }); else ConsoleLogger.logId(entry.job.id, 'Warning', "Empty result for Query " + entry.key + "/" + entry.queryDefinition.name); if (entry.transform && !Mat4.isIdentity(entry.transform)) GlobalModelTransformInfo.writeMmCif(encoder, entry.transform); if (!entry.copyAllCategories && entry.queryDefinition.filter) encoder.setFilter(); perf.end('encode'); stats = { structure: structure, queryTimeMs: perf.time('query'), encodeTimeMs: perf.time('encode'), resultSize: result.reduce(function (n, s) { return n + s.elementCount; }, 0) }; encoder.writeCategory(_model_server_stats, stats); ConsoleLogger.logId(entry.job.id, 'Query', "Written " + entry.key + "/" + entry.queryDefinition.name + "."); return [2 /*return*/, encoder]; case 7: e_3 = _c.sent(); ConsoleLogger.errorId(entry.job.id, e_3); doError(entry, encoder, e_3); return [3 /*break*/, 9]; case 8: encoder.binaryEncodingProvider = void 0; return [7 /*endfinally*/]; case 9: return [2 /*return*/]; } }); }); } function getEncodingProvider(structure) { if (!structure.isBinary) return void 0; return CifWriter.createEncodingProviderFromCifFrame(structure.cifFrame); } function doError(entry, encoder, e) { encoder.writeCategory(_model_server_result, entry); encoder.writeCategory(_model_server_params, entry); encoder.writeCategory(_model_server_error, '' + e); } var maxTime = Config.queryTimeoutMs; export function abortingObserver(p) { if (now() - p.root.progress.startedTime > maxTime) { p.requestAbort("Exceeded maximum allowed time for a query (" + maxTime + "ms)"); } } function string(name, str, isSpecified) { if (isSpecified) { return CifField.str(name, function (i, d) { return str(d, i); }, { valueKind: function (i, d) { return isSpecified(d) ? 0 /* Present */ : 1 /* NotPresent */; } }); } return CifField.str(name, function (i, d) { return str(d, i); }); } function int32(name, value) { return CifField.int(name, function (i, d) { return value(d); }); } var _model_server_result_fields = [ string('job_id', function (ctx) { return '' + ctx.job.id; }), string('datetime_utc', function (ctx) { return ctx.job.datetime_utc; }), string('server_version', function (ctx) { return VERSION; }), string('query_name', function (ctx) { return ctx.queryDefinition.name; }), string('source_id', function (ctx) { return ctx.sourceId; }), string('entry_id', function (ctx) { return ctx.entryId; }), ]; var _model_server_params_fields = [ string('name', function (ctx, i) { return ctx[i][0]; }), string('value', function (ctx, i) { return ctx[i][1]; }) ]; var _model_server_error_fields = [ string('message', function (ctx, i) { return ctx; }) ]; var _model_server_stats_fields = [ int32('io_time_ms', function (ctx) { return ctx.structure.info.readTime | 0; }), int32('parse_time_ms', function (ctx) { return ctx.structure.info.parseTime | 0; }), // int32<Stats>('attach_props_time_ms', ctx => ctx.structure.info.attachPropsTime | 0), int32('create_model_time_ms', function (ctx) { return ctx.structure.info.createModelTime | 0; }), int32('query_time_ms', function (ctx) { return ctx.queryTimeMs | 0; }), int32('encode_time_ms', function (ctx) { return ctx.encodeTimeMs | 0; }), int32('element_count', function (ctx) { return ctx.resultSize | 0; }), ]; var _model_server_result = { name: 'model_server_result', instance: function (job) { return CifWriter.categoryInstance(_model_server_result_fields, { data: job, rowCount: 1 }); } }; var _model_server_error = { name: 'model_server_error', instance: function (message) { return CifWriter.categoryInstance(_model_server_error_fields, { data: message, rowCount: 1 }); } }; var _model_server_params = { name: 'model_server_params', instance: function (job) { var params = []; for (var _i = 0, _a = Object.keys(job.normalizedParams); _i < _a.length; _i++) { var k = _a[_i]; params.push([k, JSON.stringify(job.normalizedParams[k])]); } return CifWriter.categoryInstance(_model_server_params_fields, { data: params, rowCount: params.length }); } }; var _model_server_stats = { name: 'model_server_stats', instance: function (stats) { return CifWriter.categoryInstance(_model_server_stats_fields, { data: stats, rowCount: 1 }); } }; //# sourceMappingURL=query.js.map