diff --git a/src/apps/domain-annotation-server/mapping.ts b/src/apps/domain-annotation-server/mapping.ts index da87d9b4698b6e8db3014c4a8dd52e8d0717095e..0ab03c359bfa9e11acc8d7f0cd82bf0378586ca8 100644 --- a/src/apps/domain-annotation-server/mapping.ts +++ b/src/apps/domain-annotation-server/mapping.ts @@ -112,6 +112,6 @@ function getDomain(name: string, schema: any, allData: any) { return domains.length > 0 ? { name, domains: Table.ofRows({ ...S.Base, ...schema }, domains), - mappings: Table.ofRows(S.mapping, mappings) + mappings: Table.ofRows<S.mapping>(S.mapping, mappings) } : void 0; } \ No newline at end of file diff --git a/src/mol-data/db/column.ts b/src/mol-data/db/column.ts index 93461e8a8613cad9b4be6f25a833d897f93a1aa7..b50672afbb7cb0673c8ea8850db4976e18a74d13 100644 --- a/src/mol-data/db/column.ts +++ b/src/mol-data/db/column.ts @@ -132,6 +132,10 @@ namespace Column { return createFirstIndexMapOfColumn(column); } + export function createIndexer<T>(column: Column<T>) { + return createIndexerOfColumn(column); + } + export function mapToArray<T, S>(column: Column<T>, f: (v: T) => S, ctor?: ArrayCtor<S>): ArrayLike<S> { return mapToArrayImpl<T, S>(column, f, ctor || Array); } @@ -174,6 +178,15 @@ function createFirstIndexMapOfColumn<T>(c: Column<T>): Map<T, number> { return map; } +function createIndexerOfColumn<T>(c: Column<T>): (value: T) => number { + const map = new Map<T, number>(); + for (let i = 0, _i = c.rowCount; i < _i; i++) { + const v = c.value(i); + if (!map.has(v)) map.set(c.value(i), i); + } + return v => map.has(v) ? map.get(v)! : -1; +} + function constColumn<T extends Column.Schema>(v: T['T'], rowCount: number, schema: T, valueKind: Column.ValueKind): Column<T['T']> { const value: Column<T['T']>['value'] = row => v; return { diff --git a/src/mol-data/db/table.ts b/src/mol-data/db/table.ts index cac162233387ca44e924942752b1b54c7b7298fc..df96dacbe89704440f0b79ea526f1c3e96b5c1f0 100644 --- a/src/mol-data/db/table.ts +++ b/src/mol-data/db/table.ts @@ -58,7 +58,7 @@ namespace Table { return ret; } - export function ofRows<S extends Schema, R extends Table<S> = Table<S>>(schema: Schema, rows: ArrayLike<Row<S>>): R { + export function ofRows<S extends Schema, R extends Table<S> = Table<S>>(schema: Schema, rows: ArrayLike<Partial<Row<S>>>): R { const ret = Object.create(null); const rowCount = rows.length; const columns = Object.keys(schema); @@ -83,7 +83,7 @@ namespace Table { ret._columns = columns; ret._schema = schema; for (const k of columns) { - (ret as any)[k] = Column.ofArray({ array: arrays[k], schema: schema[k] }) + (ret as any)[k] = typeof arrays[k] !== 'undefined' ? Column.ofArray({ array: arrays[k], schema: schema[k] }) : Column.Undefined(ret._rowCount, schema[k]); } return ret as R; } diff --git a/src/mol-model/structure/export/mmcif.ts b/src/mol-model/structure/export/mmcif.ts index 9635dd78b7f07c8a90f82d0c370a247361fdce92..3958a39faf09c85e7d07a2daca46530a396674df 100644 --- a/src/mol-model/structure/export/mmcif.ts +++ b/src/mol-model/structure/export/mmcif.ts @@ -102,10 +102,10 @@ const atom_site: Encoder.CategoryDefinition<Element.Location> = { function entityProvider({ model }: Context): Encoder.CategoryInstance { return { - data: model.hierarchy.entities, - definition: Encoder.CategoryDefinition.ofTable('entity', model.hierarchy.entities), - keys: () => Iterator.Range(0, model.hierarchy.entities._rowCount - 1), - rowCount: model.hierarchy.entities._rowCount + data: model.entities.data, + definition: Encoder.CategoryDefinition.ofTable('entity', model.entities.data), + keys: () => Iterator.Range(0, model.entities.data._rowCount - 1), + rowCount: model.entities.data._rowCount } } diff --git a/src/mol-model/structure/model/formats/gro.ts b/src/mol-model/structure/model/formats/gro.ts index 84b30517ef2a92103d7b583dd10c9b5617fba3e5..cad8c441a624c1401684d7b8f285d78259908d60 100644 --- a/src/mol-model/structure/model/formats/gro.ts +++ b/src/mol-model/structure/model/formats/gro.ts @@ -16,9 +16,11 @@ import CoarseGrained from '../properties/coarse-grained' import findHierarchyKeys from '../utils/hierarchy-keys' import { guessElement } from '../utils/guess-element' import { ElementSymbol} from '../types' +import { mmCIF_Schema as mmCIF } from 'mol-io/reader/cif/schema/mmcif' import gro_Format = Format.gro import Sequence from '../properties/sequence'; +import { Entities } from '../properties/common'; type HierarchyOffsets = { residues: ArrayLike<number>, chains: ArrayLike<number> } @@ -71,9 +73,8 @@ function createHierarchyData(atomsData: Atoms, offsets: HierarchyOffsets): Hiera // }); const chains = Table.ofUndefinedColumns(Hierarchy.ChainsSchema, 0); - const entities = Table.ofUndefinedColumns(Hierarchy.EntitySchema, 0); - return { atoms, residues, chains, entities }; + return { atoms, residues, chains }; } function getConformation(atoms: Atoms): Conformation { @@ -112,13 +113,25 @@ function createModel(format: gro_Format, modelNum: number, previous?: Model): Mo residueSegments: Segmentation.ofOffsets(hierarchyOffsets.residues, bounds), chainSegments: Segmentation.ofOffsets(hierarchyOffsets.chains, bounds), } - const hierarchyKeys = findHierarchyKeys(hierarchyData, hierarchySegments); + + // TODO: create a better mock entity + const entityTable = Table.ofRows<mmCIF['entity']>(mmCIF.entity, [{ + id: '0', + src_method: 'syn', + type: 'polymer', + pdbx_number_of_molecules: 1 + }]); + + const entities: Entities = { data: entityTable, getEntityIndex: Column.createIndexer(entityTable.id) }; + + const hierarchyKeys = findHierarchyKeys(hierarchyData, entities, hierarchySegments); const hierarchy = { ...hierarchyData, ...hierarchyKeys, ...hierarchySegments }; return { id: UUID.create(), sourceData: format, modelNum, hierarchy, + entities, sequence: Sequence.fromHierarchy(hierarchy), conformation: getConformation(structure.atoms), coarseGrained: CoarseGrained.Empty, diff --git a/src/mol-model/structure/model/formats/mmcif.ts b/src/mol-model/structure/model/formats/mmcif.ts index b06ed9ef235258ff8919ae3ca9b787dc7e54e7d2..d88ca8ac714ff7ec3a1b37f667870f00d65313bc 100644 --- a/src/mol-model/structure/model/formats/mmcif.ts +++ b/src/mol-model/structure/model/formats/mmcif.ts @@ -19,6 +19,7 @@ import createAssemblies from './mmcif/assembly' import mmCIF_Format = Format.mmCIF import { getSequence } from './mmcif/sequence'; +import { Entities } from '../properties/common'; function findModelBounds({ data }: mmCIF_Format, startIndex: number) { const num = data.atom_site.pdbx_PDB_model_num; @@ -63,7 +64,7 @@ function createHierarchyData({ data }: mmCIF_Format, bounds: Interval, offsets: Table.columnToArray(residues, 'label_seq_id', Int32Array); Table.columnToArray(residues, 'auth_seq_id', Int32Array); const chains = Table.view(atom_site, Hierarchy.ChainsSchema, offsets.chains); - return { atoms, residues, chains, entities: data.entity }; + return { atoms, residues, chains }; } function getConformation({ data }: mmCIF_Format, bounds: Interval): Conformation { @@ -106,7 +107,10 @@ function createModel(format: mmCIF_Format, bounds: Interval, previous?: Model): residueSegments: Segmentation.ofOffsets(hierarchyOffsets.residues, bounds), chainSegments: Segmentation.ofOffsets(hierarchyOffsets.chains, bounds), } - const hierarchyKeys = findHierarchyKeys(hierarchyData, hierarchySegments); + + const entities: Entities = { data: format.data.entity, getEntityIndex: Column.createIndexer(format.data.entity.id) }; + + const hierarchyKeys = findHierarchyKeys(hierarchyData, entities, hierarchySegments); const hierarchy = { ...hierarchyData, ...hierarchyKeys, ...hierarchySegments }; @@ -114,8 +118,9 @@ function createModel(format: mmCIF_Format, bounds: Interval, previous?: Model): id: UUID.create(), sourceData: format, modelNum: format.data.atom_site.pdbx_PDB_model_num.value(Interval.start(bounds)), + entities, hierarchy, - sequence: getSequence(format.data, hierarchy), + sequence: getSequence(format.data, entities, hierarchy), conformation: getConformation(format, bounds), coarseGrained: CoarseGrained.Empty, symmetry: getSymmetry(format), diff --git a/src/mol-model/structure/model/formats/mmcif/ihm.ts b/src/mol-model/structure/model/formats/mmcif/ihm.ts new file mode 100644 index 0000000000000000000000000000000000000000..879b4fb842e26b1581ef57647aa48c69ba9ab9f5 --- /dev/null +++ b/src/mol-model/structure/model/formats/mmcif/ihm.ts @@ -0,0 +1,6 @@ +/** + * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. + * + * @author David Sehnal <david.sehnal@gmail.com> + */ + diff --git a/src/mol-model/structure/model/formats/mmcif/sequence.ts b/src/mol-model/structure/model/formats/mmcif/sequence.ts index 85bb572baa8cda811bc7fd69956ddfe3d93bf47b..ccba6849b3719825cbe067a8d4eb5a7e45c2816e 100644 --- a/src/mol-model/structure/model/formats/mmcif/sequence.ts +++ b/src/mol-model/structure/model/formats/mmcif/sequence.ts @@ -8,8 +8,9 @@ import { mmCIF_Database as mmCIF } from 'mol-io/reader/cif/schema/mmcif' import Sequence from '../../properties/sequence' import { Column } from 'mol-data/db'; import { Hierarchy } from '../../properties/hierarchy'; +import { Entities } from '../../properties/common'; -export function getSequence(cif: mmCIF, hierarchy: Hierarchy): Sequence { +export function getSequence(cif: mmCIF, entities: Entities, hierarchy: Hierarchy): Sequence { if (!cif.entity_poly_seq._rowCount) return Sequence.fromHierarchy(hierarchy); const { entity_id, num, mon_id } = cif.entity_poly_seq; @@ -24,7 +25,7 @@ export function getSequence(cif: mmCIF, hierarchy: Hierarchy): Sequence { i++; const id = entity_id.value(start); - byEntityKey[hierarchy.findEntityKey(id)] = { entityId: id, compId: Column.window(mon_id, start, i), num: Column.window(num, start, i) } + byEntityKey[entities.getEntityIndex(id)] = { entityId: id, compId: Column.window(mon_id, start, i), num: Column.window(num, start, i) } } return { byEntityKey }; diff --git a/src/mol-model/structure/model/model.ts b/src/mol-model/structure/model/model.ts index daf777734e10bad5e7f6ffb5801cb56c1c147e57..9652cf5b18c8c4c5fe20f7d717d1720b954b640e 100644 --- a/src/mol-model/structure/model/model.ts +++ b/src/mol-model/structure/model/model.ts @@ -11,6 +11,7 @@ import Hierarchy from './properties/hierarchy' import Conformation from './properties/conformation' import Symmetry from './properties/symmetry' import CoarseGrained from './properties/coarse-grained' +import { Entities } from './properties/common'; import from_gro from './formats/gro' import from_mmCIF from './formats/mmcif' @@ -27,7 +28,9 @@ interface Model extends Readonly<{ sourceData: Format, + entities: Entities, sequence: Sequence, + hierarchy: Hierarchy, conformation: Conformation, symmetry: Symmetry, diff --git a/src/mol-model/structure/model/properties/coarse-grained.ts b/src/mol-model/structure/model/properties/coarse-grained.ts index 725493ff1d571801fa5cd9bd69cb3af4ac605c63..730724114f5e94809911a5b36d3042a9a6292c94 100644 --- a/src/mol-model/structure/model/properties/coarse-grained.ts +++ b/src/mol-model/structure/model/properties/coarse-grained.ts @@ -4,12 +4,42 @@ * @author David Sehnal <david.sehnal@gmail.com> */ +import { mmCIF_Database as mmCIF } from 'mol-io/reader/cif/schema/mmcif' +import { Tensor } from 'mol-math/linear-algebra'; +import { Column } from 'mol-data/db'; + interface CoarseGrained { - // TODO + modelList: mmCIF['ihm_model_list'], + spheres: { [P in keyof CoarseGrained.Sphere]: Column<CoarseGrained.Sphere[P]> }, + gaussians: { [P in keyof CoarseGrained.Gaussian]: Column<CoarseGrained.Gaussian[P]> } } namespace CoarseGrained { - export const Empty: CoarseGrained = { }; + export const Empty: CoarseGrained = { } as any; + + interface Site { + // index to the Model.hierarchy.entities table + entityKey: number, + // index to the CoarseGrained.modelList table + modelKey: number, + + asym_id: string, + seq_id_begin: number, + seq_id_end: number, + x: number, + y: number, + z: number + } + + export interface Sphere extends Site { + radius: number, + rmsf: number + } + + export interface Gaussian extends Site { + weight: number, + covarianceMatrix: Tensor.Data + } } export default CoarseGrained; \ No newline at end of file diff --git a/src/mol-model/structure/model/properties/common.ts b/src/mol-model/structure/model/properties/common.ts new file mode 100644 index 0000000000000000000000000000000000000000..aa5d93aaec136b39e51f2b22b1b5de3d6bde2c65 --- /dev/null +++ b/src/mol-model/structure/model/properties/common.ts @@ -0,0 +1,14 @@ +/** + * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. + * + * @author David Sehnal <david.sehnal@gmail.com> + */ + +import { mmCIF_Database as mmCIF } from 'mol-io/reader/cif/schema/mmcif' + +interface Entities { + data: mmCIF['entity'], + getEntityIndex(id: string): number +} + +export { Entities } \ No newline at end of file diff --git a/src/mol-model/structure/model/properties/hierarchy.ts b/src/mol-model/structure/model/properties/hierarchy.ts index 773e091d845fb23e1dda9c2c887df824d2b55c70..8987e070d05fedebd486019339635772bc04d96c 100644 --- a/src/mol-model/structure/model/properties/hierarchy.ts +++ b/src/mol-model/structure/model/properties/hierarchy.ts @@ -40,15 +40,15 @@ export const ChainsSchema = { export type ChainsSchema = typeof ChainsSchema export interface Chains extends Table<ChainsSchema> { } -export const EntitySchema = mmCIF['entity'] -export type EntitySchema = typeof EntitySchema -export interface Entities extends Table<EntitySchema> { } +// export const EntitySchema = mmCIF['entity'] +// export type EntitySchema = typeof EntitySchema +// export interface Entities extends Table<EntitySchema> { } export interface Data { atoms: Atoms, residues: Residues, chains: Chains, - entities: Entities + //entities: Entities } export interface Segments { @@ -70,7 +70,6 @@ export interface Keys { // also index to the Entities table. entityKey: Column<number>, - findEntityKey(id: string): number, findChainKey(entityId: string, label_asym_id: string): number, findResidueKey(entityId: string, label_asym_id: string, label_comp_id: string, auth_seq_id: number, pdbx_PDB_ins_code: string): number } diff --git a/src/mol-model/structure/model/utils/hierarchy-keys.ts b/src/mol-model/structure/model/utils/hierarchy-keys.ts index c09484245f80c577b7a948624a56cc469be9adc5..d70a26a94abdaeba5be60d137bccb7360d2b8820 100644 --- a/src/mol-model/structure/model/utils/hierarchy-keys.ts +++ b/src/mol-model/structure/model/utils/hierarchy-keys.ts @@ -7,6 +7,7 @@ import { Column } from 'mol-data/db' import { Data, Segments, Keys } from '../properties/hierarchy' import { Interval, Segmentation } from 'mol-data/int' +import { Entities } from '../properties/common'; function getResidueId(comp_id: string, seq_id: number, ins_code: string) { return `${comp_id} ${seq_id} ${ins_code}`; @@ -26,24 +27,26 @@ function getElementSubstructureKeyMap(map: Map<number, Map<string, number>>, key return ret; } -function createLookUp(entity: Map<string, number>, chain: Map<number, Map<string, number>>, residue: Map<number, Map<string, number>>) { - const findEntityKey: Keys['findEntityKey'] = (id) => entity.has(id) ? entity.get(id)! : -1; +function createLookUp(entities: Entities, chain: Map<number, Map<string, number>>, residue: Map<number, Map<string, number>>) { + const getEntKey = entities.getEntityIndex; const findChainKey: Keys['findChainKey'] = (e, c) => { - if (!entity.has(e)) return -1; - const cm = chain.get(entity.get(e)!)!; + let eKey = getEntKey(e); + if (eKey < 0) return -1; + const cm = chain.get(eKey)!; if (!cm.has(c)) return -1; return cm.get(c)!; } const findResidueKey: Keys['findResidueKey'] = (e, c, name, seq, ins) => { - if (!entity.has(e)) return -1; - const cm = chain.get(entity.get(e)!)!; + let eKey = getEntKey(e); + if (eKey < 0) return -1; + const cm = chain.get(eKey)!; if (!cm.has(c)) return -1; const rm = residue.get(cm.get(c)!)! const id = getResidueId(name, seq, ins); if (!rm.has(id)) return -1; return rm.get(id)!; } - return { findEntityKey, findChainKey, findResidueKey }; + return { findChainKey, findResidueKey }; } function checkMonotonous(xs: ArrayLike<number>) { @@ -55,10 +58,13 @@ function checkMonotonous(xs: ArrayLike<number>) { return true; } -function create(data: Data, segments: Segments): Keys { - const { chains, residues, entities } = data; +function missingEntity(k: string) { + throw new Error(`Missing entity entry for entity id '${k}'.`); +} + +function create(data: Data, entities: Entities, segments: Segments): Keys { + const { chains, residues } = data; - const entityMap = Column.createFirstIndexMap(entities.id); const chainMaps = new Map<number, Map<string, number>>(), chainCounter = { index: 0 }; const residueMaps = new Map<number, Map<string, number>>(), residueCounter = { index: 0 }; @@ -78,7 +84,8 @@ function create(data: Data, segments: Segments): Keys { const chainSegment = chainsIt.move(); const cI = chainSegment.index; - const eKey = entityMap.get(label_entity_id.value(cI)) || 0; + let eKey = entities.getEntityIndex(label_entity_id.value(cI)); + if (eKey < 0) missingEntity(label_entity_id.value(cI)); const chainMap = getElementSubstructureKeyMap(chainMaps, eKey); const cKey = getElementKey(chainMap, label_asym_id.value(cI), chainCounter); @@ -99,14 +106,13 @@ function create(data: Data, segments: Segments): Keys { } } - const { findEntityKey, findChainKey, findResidueKey } = createLookUp(entityMap, chainMaps, residueMaps); + const { findChainKey, findResidueKey } = createLookUp(entities, chainMaps, residueMaps); return { isMonotonous: isMonotonous && checkMonotonous(entityKey) && checkMonotonous(chainKey) && checkMonotonous(residueKey), residueKey: Column.ofIntArray(residueKey), chainKey: Column.ofIntArray(chainKey), entityKey: Column.ofIntArray(entityKey), - findEntityKey, findChainKey, findResidueKey }; diff --git a/src/mol-model/structure/query/properties.ts b/src/mol-model/structure/query/properties.ts index 2ed1ac4e41911bfe8f4af9e47637788fc0561625..811c64a8996d4622de2b2ad40893790584ba99f0 100644 --- a/src/mol-model/structure/query/properties.ts +++ b/src/mol-model/structure/query/properties.ts @@ -59,16 +59,16 @@ function eK(l: Element.Location) { return !Unit.isAtomic(l.unit) ? notAtomic() : const entity = { key: eK, - id: Element.property(l => l.unit.hierarchy.entities.id.value(eK(l))), - type: Element.property(l => l.unit.hierarchy.entities.type.value(eK(l))), - src_method: Element.property(l => l.unit.hierarchy.entities.src_method.value(eK(l))), - pdbx_description: Element.property(l => l.unit.hierarchy.entities.pdbx_description.value(eK(l))), - formula_weight: Element.property(l => l.unit.hierarchy.entities.formula_weight.value(eK(l))), - pdbx_number_of_molecules: Element.property(l => l.unit.hierarchy.entities.pdbx_number_of_molecules.value(eK(l))), - details: Element.property(l => l.unit.hierarchy.entities.details.value(eK(l))), - pdbx_mutation: Element.property(l => l.unit.hierarchy.entities.pdbx_mutation.value(eK(l))), - pdbx_fragment: Element.property(l => l.unit.hierarchy.entities.pdbx_fragment.value(eK(l))), - pdbx_ec: Element.property(l => l.unit.hierarchy.entities.pdbx_ec.value(eK(l))) + id: Element.property(l => l.unit.model.entities.data.id.value(eK(l))), + type: Element.property(l => l.unit.model.entities.data.type.value(eK(l))), + src_method: Element.property(l => l.unit.model.entities.data.src_method.value(eK(l))), + pdbx_description: Element.property(l => l.unit.model.entities.data.pdbx_description.value(eK(l))), + formula_weight: Element.property(l => l.unit.model.entities.data.formula_weight.value(eK(l))), + pdbx_number_of_molecules: Element.property(l => l.unit.model.entities.data.pdbx_number_of_molecules.value(eK(l))), + details: Element.property(l => l.unit.model.entities.data.details.value(eK(l))), + pdbx_mutation: Element.property(l => l.unit.model.entities.data.pdbx_mutation.value(eK(l))), + pdbx_fragment: Element.property(l => l.unit.model.entities.data.pdbx_fragment.value(eK(l))), + pdbx_ec: Element.property(l => l.unit.model.entities.data.pdbx_ec.value(eK(l))) } const unit = {