123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177 |
- /**
- * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
- *
- * @author David Sehnal <david.sehnal@gmail.com>
- */
- import { Structure, Model } from 'mol-model/structure';
- import { PerformanceMonitor } from 'mol-util/performance-monitor';
- import { Cache } from './cache';
- import Config from '../config';
- import CIF, { CifFrame } from 'mol-io/reader/cif'
- import * as util from 'util'
- import * as fs from 'fs'
- import * as zlib from 'zlib'
- import { Job } from './jobs';
- import { ConsoleLogger } from 'mol-util/console-logger';
- import { ModelPropertiesProvider } from '../property-provider';
- import { trajectoryFromMmCIF } from 'mol-model-formats/structure/mmcif';
- require('util.promisify').shim();
- export enum StructureSourceType {
- File,
- Cache
- }
- export interface StructureInfo {
- sourceType: StructureSourceType;
- readTime: number;
- parseTime: number;
- createModelTime: number;
- attachPropsTime: number;
- sourceId: string,
- entryId: string
- }
- export interface StructureWrapper {
- info: StructureInfo,
- isBinary: boolean,
- key: string,
- approximateSize: number,
- models: ArrayLike<Model>,
- modelMap: Map<number, Model>,
- structureModelMap: Map<number, Structure>,
- propertyProvider: ModelPropertiesProvider | undefined,
- cifFrame: CifFrame,
- cache: object
- }
- export async function createStructureWrapperFromJob(job: Job, propertyProvider: ModelPropertiesProvider | undefined, allowCache = true): Promise<StructureWrapper> {
- if (allowCache && Config.cacheParams.useCache) {
- const ret = StructureCache.get(job.key);
- if (ret) return ret;
- }
- const ret = await readStructureWrapper(job.key, job.sourceId, job.entryId, propertyProvider);
- if (allowCache && Config.cacheParams.useCache) {
- StructureCache.add(ret);
- }
- return ret;
- }
- export const StructureCache = new Cache<StructureWrapper>(s => s.key, s => s.approximateSize);
- const perf = new PerformanceMonitor();
- const readFileAsync = util.promisify(fs.readFile);
- const unzipAsync = util.promisify<zlib.InputType, Buffer>(zlib.unzip);
- async function readFile(filename: string) {
- const isGz = /\.gz$/i.test(filename);
- if (filename.match(/\.bcif/)) {
- let input = await readFileAsync(filename)
- if (isGz) input = await unzipAsync(input);
- const data = new Uint8Array(input.byteLength);
- for (let i = 0; i < input.byteLength; i++) data[i] = input[i];
- return data;
- } else {
- if (isGz) {
- const data = await unzipAsync(await readFileAsync(filename));
- return data.toString('utf8');
- }
- return readFileAsync(filename, 'utf8');
- }
- }
- async function parseCif(data: string|Uint8Array) {
- const comp = CIF.parse(data);
- const parsed = await comp.run();
- if (parsed.isError) throw parsed;
- return parsed.result;
- }
- export async function readStructureWrapper(key: string, sourceId: string | '_local_', entryId: string, propertyProvider: ModelPropertiesProvider | undefined) {
- const filename = sourceId === '_local_' ? entryId : Config.mapFile(sourceId, entryId);
- if (!filename) throw new Error(`Cound not map '${key}' to a valid filename.`);
- if (!fs.existsSync(filename)) throw new Error(`Could not find source file for '${key}'.`);
- perf.start('read');
- let data;
- try {
- data = await readFile(filename);
- } catch (e) {
- ConsoleLogger.error(key, '' + e);
- throw new Error(`Could not read the file for '${key}' from disk.`);
- }
- perf.end('read');
- perf.start('parse');
- const frame = (await parseCif(data)).blocks[0];
- perf.end('parse');
- perf.start('createModel');
- const models = await trajectoryFromMmCIF(frame).run();
- perf.end('createModel');
- const modelMap = new Map<number, Model>();
- for (const m of models) {
- modelMap.set(m.modelNum, m);
- }
- const ret: StructureWrapper = {
- info: {
- sourceType: StructureSourceType.File,
- readTime: perf.time('read'),
- parseTime: perf.time('parse'),
- createModelTime: perf.time('createModel'),
- attachPropsTime: 0, // perf.time('attachProps'),
- sourceId,
- entryId
- },
- isBinary: /\.bcif/.test(filename),
- key,
- approximateSize: typeof data === 'string' ? 2 * data.length : data.length,
- models,
- modelMap,
- structureModelMap: new Map(),
- cifFrame: frame,
- propertyProvider,
- cache: Object.create(null)
- };
- return ret;
- }
- export async function resolveStructure(wrapper: StructureWrapper, modelNum?: number) {
- if (typeof modelNum === 'undefined') modelNum = wrapper.models[0].modelNum;
- if (wrapper.structureModelMap.has(modelNum)) return wrapper.structureModelMap.get(modelNum)!;
- if (!wrapper.modelMap.has(modelNum)) {
- return void 0;
- }
- const model = wrapper.modelMap.get(modelNum)!;
- const structure = Structure.ofModel(model);
- if (wrapper.propertyProvider) {
- const modelProps = wrapper.propertyProvider(model, wrapper.cache);
- for (const p of modelProps) {
- await tryAttach(wrapper.key, p);
- }
- }
- return structure;
- }
- export async function resolveStructures(wrapper: StructureWrapper, modelNums?: number[]) {
- const ret: Structure[] = [];
- for (const n of modelNums || (wrapper.models as Model[]).map(m => m.modelNum)) {
- const s = await resolveStructure(wrapper, n);
- if (s) ret.push(s);
- }
- return ret;
- }
- async function tryAttach(key: string, promise: Promise<any>) {
- try {
- await promise;
- } catch (e) {
- ConsoleLogger.errorId(key, 'Custom prop:' + e);
- }
- }
|