From a09e0d487598b7c5290b939331aa7cdcd0c0ac3a Mon Sep 17 00:00:00 2001 From: David Sehnal <david.sehnal@gmail.com> Date: Mon, 25 Jun 2018 20:35:27 +0200 Subject: [PATCH] wip, custom props --- src/mol-model/structure/export/mmcif.ts | 10 ++++---- .../structure/model/formats/mmcif.ts | 6 ++++- .../structure/model/formats/mmcif/bonds.ts | 10 +++++--- src/mol-model/structure/model/model.ts | 15 ++++++++--- .../structure/model/properties/custom.ts | 8 ++++++ .../model/properties/custom/collection.ts | 25 +++++++++++++++++++ .../model/properties/custom/descriptor.ts | 18 +++++++++++++ 7 files changed, 78 insertions(+), 14 deletions(-) create mode 100644 src/mol-model/structure/model/properties/custom.ts create mode 100644 src/mol-model/structure/model/properties/custom/collection.ts create mode 100644 src/mol-model/structure/model/properties/custom/descriptor.ts diff --git a/src/mol-model/structure/export/mmcif.ts b/src/mol-model/structure/export/mmcif.ts index ea699f649..bf93893f0 100644 --- a/src/mol-model/structure/export/mmcif.ts +++ b/src/mol-model/structure/export/mmcif.ts @@ -11,7 +11,7 @@ import { Structure, Element } from '../structure' import { Model } from '../model' import P from '../query/properties' -interface Context { +export interface CifExportContext { structure: Structure, model: Model } @@ -53,7 +53,7 @@ const atom_site_fields: CifField<Element.Location>[] = [ ]; function copy_mmCif_cat(name: keyof mmCIF_Schema) { - return ({ model }: Context) => { + return ({ model }: CifExportContext) => { if (model.sourceData.kind !== 'mmCIF') return CifCategory.Empty; const table = model.sourceData.data[name]; if (!table || !table._rowCount) return CifCategory.Empty; @@ -61,12 +61,12 @@ function copy_mmCif_cat(name: keyof mmCIF_Schema) { }; } -function _entity({ model, structure }: Context): CifCategory { +function _entity({ model, structure }: CifExportContext): CifCategory { const keys = Structure.getEntityKeys(structure); return CifCategory.ofTable('entity', model.entities.data, keys); } -function _atom_site({ structure }: Context): CifCategory { +function _atom_site({ structure }: CifExportContext): CifCategory { return { data: structure, name: 'atom_site', @@ -104,7 +104,7 @@ export function encode_mmCIF_categories(encoder: CifWriter.Encoder, structure: S if (models.length !== 1) throw 'Can\'t export stucture composed from multiple models.'; const model = models[0]; - const ctx: Context[] = [{ structure, model }]; + const ctx: CifExportContext[] = [{ structure, model }]; for (const cat of Categories) { encoder.writeCategory(cat, ctx); diff --git a/src/mol-model/structure/model/formats/mmcif.ts b/src/mol-model/structure/model/formats/mmcif.ts index abd3a7a59..66c2bfc28 100644 --- a/src/mol-model/structure/model/formats/mmcif.ts +++ b/src/mol-model/structure/model/formats/mmcif.ts @@ -24,6 +24,7 @@ import { getSequence } from './mmcif/sequence'; import { sortAtomSite } from './mmcif/sort'; import { mmCIF_Database, mmCIF_Schema } from 'mol-io/reader/cif/schema/mmcif'; import { Element } from '../../../structure' +import { CustomProperties } from '../properties/custom'; import mmCIF_Format = Format.mmCIF type AtomSite = mmCIF_Database['atom_site'] @@ -184,6 +185,7 @@ function createModel(format: mmCIF_Format, atom_site: AtomSite, previous?: Model sourceData: format, modelNum: format.data.atom_site.pdbx_PDB_model_num.value(0), entities, + symmetry: getSymmetry(format), atomicHierarchy, sequence: getSequence(format.data, entities, atomicHierarchy, modifiedResidueNameMap), atomicConformation: getConformation(atom_site), @@ -193,7 +195,9 @@ function createModel(format: mmCIF_Format, atom_site: AtomSite, previous?: Model secondaryStructure: getSecondaryStructureMmCif(format.data, atomicHierarchy), modifiedResidueNameMap }, - symmetry: getSymmetry(format) + customProperties: new CustomProperties(), + _staticPropertyData: Object.create(null), + _dynamicPropertyData: Object.create(null) }; } diff --git a/src/mol-model/structure/model/formats/mmcif/bonds.ts b/src/mol-model/structure/model/formats/mmcif/bonds.ts index 4eb625286..5dd2180ce 100644 --- a/src/mol-model/structure/model/formats/mmcif/bonds.ts +++ b/src/mol-model/structure/model/formats/mmcif/bonds.ts @@ -10,6 +10,8 @@ import { LinkType } from '../../types' import { findEntityIdByAsymId, findAtomIndexByLabelName } from './util' import { Column } from 'mol-data/db' +// TODO: add dynamic property descriptor for this? + export interface StructConn { getResidueEntries(residueAIndex: number, residueBIndex: number): ReadonlyArray<StructConn.Entry> getAtomEntries(atomIndex: number): ReadonlyArray<StructConn.Entry> @@ -100,7 +102,7 @@ export namespace StructConn { export const PropName = '__StructConn__'; export function fromModel(model: Model): StructConn | undefined { - if (model.properties[PropName]) return model.properties[PropName]; + if (model._staticPropertyData[PropName]) return model._staticPropertyData[PropName]; if (model.sourceData.kind !== 'mmCIF') return; const { struct_conn } = model.sourceData.data; @@ -189,7 +191,7 @@ export namespace StructConn { } const ret = new StructConnImpl(entries); - model.properties[PropName] = ret; + model._staticPropertyData[PropName] = ret; return ret; } } @@ -230,7 +232,7 @@ export namespace ComponentBond { export const PropName = '__ComponentBond__'; export function fromModel(model: Model): ComponentBond | undefined { - if (model.properties[PropName]) return model.properties[PropName]; + if (model._staticPropertyData[PropName]) return model._staticPropertyData[PropName]; if (model.sourceData.kind !== 'mmCIF') return const { chem_comp_bond } = model.sourceData.data; @@ -269,7 +271,7 @@ export namespace ComponentBond { entry.add(nameA, nameB, ord, flags); } - model.properties[PropName] = compBond; + model._staticPropertyData[PropName] = compBond; return compBond; } } \ No newline at end of file diff --git a/src/mol-model/structure/model/model.ts b/src/mol-model/structure/model/model.ts index 6ade4fe45..bce90da7e 100644 --- a/src/mol-model/structure/model/model.ts +++ b/src/mol-model/structure/model/model.ts @@ -11,6 +11,7 @@ import { AtomicHierarchy, AtomicConformation } from './properties/atomic' import { ModelSymmetry } from './properties/symmetry' import { CoarseHierarchy, CoarseConformation } from './properties/coarse' import { Entities } from './properties/common'; +import { CustomProperties } from './properties/custom'; import { SecondaryStructure } from './properties/seconday-structure'; //import from_gro from './formats/gro' @@ -35,15 +36,21 @@ interface Model extends Readonly<{ atomicHierarchy: AtomicHierarchy, atomicConformation: AtomicConformation, - /** Various parts of the code can "cache" custom properties here */ properties: { + // secondary structure provided by the input file readonly secondaryStructure: SecondaryStructure, // maps modified residue name to its parent - readonly modifiedResidueNameMap: Map<string, string>, - [customName: string]: any + readonly modifiedResidueNameMap: Map<string, string> }, - // TODO: separate properties to "static" (propagated with trajectory) and "dynamic" (computed for each frame separately) + customProperties: CustomProperties, + + /** + * Not to be accessed directly, each custom property descriptor + * defines property accessors that use this field to store the data. + */ + _staticPropertyData: { [name: string]: any }, + _dynamicPropertyData: { [name: string]: any }, coarseHierarchy: CoarseHierarchy, coarseConformation: CoarseConformation diff --git a/src/mol-model/structure/model/properties/custom.ts b/src/mol-model/structure/model/properties/custom.ts new file mode 100644 index 000000000..d9a06eee1 --- /dev/null +++ b/src/mol-model/structure/model/properties/custom.ts @@ -0,0 +1,8 @@ +/** + * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. + * + * @author David Sehnal <david.sehnal@gmail.com> + */ + +export * from './custom/descriptor' +export * from './custom/collection' \ No newline at end of file diff --git a/src/mol-model/structure/model/properties/custom/collection.ts b/src/mol-model/structure/model/properties/custom/collection.ts new file mode 100644 index 000000000..75dda9b2d --- /dev/null +++ b/src/mol-model/structure/model/properties/custom/collection.ts @@ -0,0 +1,25 @@ +/** + * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. + * + * @author David Sehnal <david.sehnal@gmail.com> + */ + +import { PropertyDescriptor } from './descriptor' + +export class CustomProperties { + private _list: PropertyDescriptor[] = []; + private _set = new Set<PropertyDescriptor>(); + + get all(): ReadonlyArray<PropertyDescriptor> { + return this._list; + } + + add(desc: PropertyDescriptor) { + this._list.push(desc); + this._set.add(desc); + } + + has(desc: PropertyDescriptor): boolean { + return this._set.has(desc); + } +} \ No newline at end of file diff --git a/src/mol-model/structure/model/properties/custom/descriptor.ts b/src/mol-model/structure/model/properties/custom/descriptor.ts new file mode 100644 index 000000000..37af3562b --- /dev/null +++ b/src/mol-model/structure/model/properties/custom/descriptor.ts @@ -0,0 +1,18 @@ +/** + * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. + * + * @author David Sehnal <david.sehnal@gmail.com> + */ + +import { CifWriter } from 'mol-io/writer/cif' +import { CifExportContext } from '../../../export/mmcif'; + +interface PropertyDescriptor { + readonly isStatic: boolean, + readonly name: string, + + /** Given a structure, returns a list of category providers used for export. */ + getCifCategories: (ctx: CifExportContext) => CifWriter.Category.Provider[] +} + +export { PropertyDescriptor } \ No newline at end of file -- GitLab