diff --git a/package-lock.json b/package-lock.json index 2d93002f4e7b77be351e8e4eb333e62b3f5807b4..c1e108171140e7de69fdc590f15d660d717faef1 100644 Binary files a/package-lock.json and b/package-lock.json differ diff --git a/package.json b/package.json index fc7b94070b8354b925e1ea4564eef34fa45161db..23e18880b61b541eae8b34c8e21c38539d3e9c2b 100644 --- a/package.json +++ b/package.json @@ -85,7 +85,7 @@ "argparse": "^1.0.10", "express": "^4.16.3", "gl": "^4.0.4", - "material-ui": "^1.0.0-beta.46", + "material-ui": "~1.0.0-beta.43", "node-fetch": "^2.1.2", "react": "^16.3.2", "react-dom": "^16.3.2", diff --git a/src/apps/structure-info/model.ts b/src/apps/structure-info/model.ts index 1bc3b500b28e524f48acd0ed3df60cd0414e4266..15ee55fd8578f3d636fe1173b980fd6990d42f38 100644 --- a/src/apps/structure-info/model.ts +++ b/src/apps/structure-info/model.ts @@ -30,7 +30,7 @@ async function readPdbFile(path: string) { } export function atomLabel(model: Model, aI: number) { - const { atoms, residues, chains, residueSegments, chainSegments } = model.hierarchy + const { atoms, residues, chains, residueSegments, chainSegments } = model.atomicHierarchy const { label_atom_id } = atoms const { label_comp_id, label_seq_id } = residues const { label_asym_id } = chains @@ -92,10 +92,10 @@ export function printUnits(structure: Structure) { } else if (Unit.isCoarse(l.unit)) { console.log(`Coarse unit ${unit.id} (${Unit.isSpheres(l.unit) ? 'spheres' : 'gaussians'}): ${size} elements.`); - const props = Queries.props.coarse_grained; + const props = Queries.props.coarse; const seq = l.unit.model.sequence; - for (let j = 0, _j = Math.min(size, 10); j < _j; j++) { + for (let j = 0, _j = Math.min(size, 3); j < _j; j++) { l.element = OrderedSet.getAt(elements, j); const residues: string[] = []; @@ -104,16 +104,16 @@ export function printUnits(structure: Structure) { for (let e = start; e <= end; e++) residues.push(compId(e)); console.log(`${props.asym_id(l)}:${start}-${end} (${residues.join('-')}) ${props.asym_id(l)} [${props.x(l).toFixed(2)}, ${props.y(l).toFixed(2)}, ${props.z(l).toFixed(2)}]`); } - if (size > 10) console.log(`...`); + if (size > 3) console.log(`...`); } } } export function printIHMModels(model: Model) { - if (!model.coarseGrained.isDefined) return false; + if (!model.coarseHierarchy.isDefined) return false; console.log('IHM Models\n============='); - console.log(Table.formatToString(model.coarseGrained.modelList)); + console.log(Table.formatToString(model.coarseHierarchy.models)); } async function run(mmcif: mmCIF_Database) { diff --git a/src/mol-geo/representation/structure/spacefill.ts b/src/mol-geo/representation/structure/spacefill.ts index 1946f810388add6a316106575e1393a5c3798d44..db82405148603f4167fc66e3a9f7deaba9f872f4 100644 --- a/src/mol-geo/representation/structure/spacefill.ts +++ b/src/mol-geo/representation/structure/spacefill.ts @@ -39,7 +39,7 @@ function createSpacefillMesh(unit: Unit, detail: number) { if (Unit.isAtomic(unit)) { radius = Queries.props.atom.vdw_radius } else if (Unit.isSpheres(unit)) { - radius = Queries.props.coarse_grained.sphere_radius + radius = Queries.props.coarse.sphere_radius } else { console.warn('Unsupported unit type') return meshBuilder.getMesh() diff --git a/src/mol-geo/theme/structure/color/chain-id.ts b/src/mol-geo/theme/structure/color/chain-id.ts index 95e305be302a3a1d0c86c2175cec389cde5d50b7..d521d6036c9f12edaa560e8ba87be14b9bc76fb6 100644 --- a/src/mol-geo/theme/structure/color/chain-id.ts +++ b/src/mol-geo/theme/structure/color/chain-id.ts @@ -18,11 +18,11 @@ function createChainIdMap(unit: Unit) { let count: number let asym_id: Column<string> if (Unit.isAtomic(unit)) { - asym_id = unit.model.hierarchy.chains.label_asym_id - count = unit.model.hierarchy.chains._rowCount + asym_id = unit.model.atomicHierarchy.chains.label_asym_id + count = unit.model.atomicHierarchy.chains._rowCount } else if (Unit.isCoarse(unit)) { - asym_id = unit.sites.asym_id - count = unit.sites.count + asym_id = unit.coarseElements.asym_id + count = unit.coarseElements.count } else { console.warn('Unknown unit type') return { map, count: index } @@ -51,7 +51,7 @@ export function chainIdColorData(props: StructureColorDataProps) { if (Unit.isAtomic(unit)) { asym_id = Queries.props.chain.label_asym_id } else if (Unit.isCoarse(unit)) { - asym_id = Queries.props.coarse_grained.asym_id + asym_id = Queries.props.coarse.asym_id } const l = Element.Location() diff --git a/src/mol-geo/theme/structure/color/element-symbol.ts b/src/mol-geo/theme/structure/color/element-symbol.ts index 815985b3347c57eb88bf4c47ad219939f2be1c7c..affedfac08a2ca695894d76ff1177370a827b2e8 100644 --- a/src/mol-geo/theme/structure/color/element-symbol.ts +++ b/src/mol-geo/theme/structure/color/element-symbol.ts @@ -23,7 +23,7 @@ export function elementSymbolColor(element: ElementSymbol): Color { export function elementSymbolColorData(props: StructureColorDataProps) { const { group: { units, elements }, vertexMap } = props - const { type_symbol } = units[0].model.hierarchy.atoms + const { type_symbol } = units[0].model.atomicHierarchy.atoms return createAttributeOrElementColor(vertexMap, { colorFn: (elementIdx: number) => { const e = elements[elementIdx] diff --git a/src/mol-geo/theme/structure/size/element.ts b/src/mol-geo/theme/structure/size/element.ts index 8bf99acc04942e56183eeb840b458222ac3668ad..741ba136f322274b9e72abee37168e56d481fb62 100644 --- a/src/mol-geo/theme/structure/size/element.ts +++ b/src/mol-geo/theme/structure/size/element.ts @@ -17,7 +17,7 @@ export function elementSizeData(props: StructureSizeDataProps) { if (Unit.isAtomic(unit)) { radius = Queries.props.atom.vdw_radius } else if (Unit.isSpheres(unit)) { - radius = Queries.props.coarse_grained.sphere_radius + radius = Queries.props.coarse.sphere_radius } const l = Element.Location() l.unit = unit diff --git a/src/mol-math/linear-algebra/3d/mat3.ts b/src/mol-math/linear-algebra/3d/mat3.ts index cd577776b23b29e6abbd21049ae009ce42ce3a50..c72dc713dba2f2c51e76ae986e1f39474f09bdc5 100644 --- a/src/mol-math/linear-algebra/3d/mat3.ts +++ b/src/mol-math/linear-algebra/3d/mat3.ts @@ -104,6 +104,10 @@ namespace Mat3 { return Mat3.copy(Mat3.zero(), a); } + export function setValue(a: Mat3, i: number, j: number, value: number) { + a[3 * j + i] = value; + } + /** * Copy the values from one Mat3 to another */ diff --git a/src/mol-math/linear-algebra/tensor.ts b/src/mol-math/linear-algebra/tensor.ts index 976e410e1b0fb96055c435cabd873cb868791be9..4bcae46f7bd0db8987d0036ed8590ba804cd1d9c 100644 --- a/src/mol-math/linear-algebra/tensor.ts +++ b/src/mol-math/linear-algebra/tensor.ts @@ -4,7 +4,7 @@ * @author David Sehnal <david.sehnal@gmail.com> */ -import { Mat4, Vec3, Vec4 } from './3d' +import { Mat4, Vec3, Vec4, Mat3 } from './3d' export interface Tensor { data: Tensor.Data, space: Tensor.Space } @@ -65,6 +65,16 @@ export namespace Tensor { return mat; } + export function toMat3(space: Space, data: Tensor.Data): Mat3 { + if (space.rank !== 2) throw new Error('Invalid tensor rank'); + const mat = Mat3.zero(); + const d0 = Math.min(3, space.dimensions[0]), d1 = Math.min(3, space.dimensions[1]); + for (let i = 0; i < d0; i++) { + for (let j = 0; j < d1; j++) Mat3.setValue(mat, i, j, space.get(data, i, j)); + } + return mat; + } + export function toVec3(space: Space, data: Tensor.Data): Vec3 { if (space.rank !== 1) throw new Error('Invalid tensor rank'); const vec = Vec3.zero(); diff --git a/src/mol-model/structure/export/mmcif.ts b/src/mol-model/structure/export/mmcif.ts index 65ded0cbbcb3c48f51824ca0649699f9c3f350e7..d7f4491a64738c7009e719bd0672ce8d8741bb75 100644 --- a/src/mol-model/structure/export/mmcif.ts +++ b/src/mol-model/structure/export/mmcif.ts @@ -96,7 +96,7 @@ const atom_site: Encoder.CategoryDefinition<Element.Location> = { str('auth_asym_id', P.chain.auth_asym_id), int('pdbx_PDB_model_num', P.unit.model_num), - str('pdbx_operator_name', P.unit.operator_name) + str('operator_name', P.unit.operator_name) ] }; diff --git a/src/mol-model/structure/model/format.ts b/src/mol-model/structure/model/format.ts index d463c30d70af897445b2293aca0726a14d53119a..2fa1f8ae1880d87643f6923b8a266c6693a151f5 100644 --- a/src/mol-model/structure/model/format.ts +++ b/src/mol-model/structure/model/format.ts @@ -4,15 +4,15 @@ * @author David Sehnal <david.sehnal@gmail.com> */ -import { File as GroFile } from 'mol-io/reader/gro/schema' +// import { File as GroFile } from 'mol-io/reader/gro/schema' import { mmCIF_Database } from 'mol-io/reader/cif/schema/mmcif' type Format = - | Format.gro + // | Format.gro | Format.mmCIF namespace Format { - export interface gro { kind: 'gro', data: GroFile } + // export interface gro { kind: 'gro', data: GroFile } export interface mmCIF { kind: 'mmCIF', data: mmCIF_Database } } diff --git a/src/mol-model/structure/model/formats/gro.ts b/src/mol-model/structure/model/formats/gro.ts index 46a9cd1652087d59eb597918ac25fa29f34d68a1..5e53509740ac866421ad7f736d9e91057b6d23be 100644 --- a/src/mol-model/structure/model/formats/gro.ts +++ b/src/mol-model/structure/model/formats/gro.ts @@ -1,153 +1,154 @@ -/** - * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. - * - * @author Alexander Rose <alexander.rose@weirdbyte.de> - */ - -import UUID from 'mol-util/uuid' -import { Column, Table } from 'mol-data/db' -import { Interval, Segmentation } from 'mol-data/int' -import { Atoms } from 'mol-io/reader/gro/schema' -import Format from '../format' -import Model from '../model' -import { AtomicConformation, AtomicData, AtomsSchema, ResiduesSchema, ChainsSchema, AtomicSegments } from '../properties/atomic' -import { CoarseGrainedHierarchy } from '../properties/coarse-grained/hierarchy' -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'; -import { ModelSymmetry } from '../properties/symmetry'; - -type HierarchyOffsets = { residues: ArrayLike<number>, chains: ArrayLike<number> } - -function findHierarchyOffsets(atomsData: Atoms, bounds: Interval) { - const start = Interval.start(bounds), end = Interval.end(bounds); - const residues = [start], chains = [start]; - - const { residueName, residueNumber } = atomsData; - - for (let i = start + 1; i < end; i++) { - const newResidue = !residueNumber.areValuesEqual(i - 1, i) - || !residueName.areValuesEqual(i - 1, i); - console.log(residueName.value(i - 1), residueName.value(i), residueNumber.value(i - 1), residueNumber.value(i), newResidue) - if (newResidue) residues[residues.length] = i; - } - console.log(residues, residues.length) - return { residues, chains }; -} - -function guessElementSymbol (value: string) { - return ElementSymbol(guessElement(value)); -} - -function createHierarchyData(atomsData: Atoms, offsets: HierarchyOffsets): AtomicData { - console.log(atomsData.atomName) - const atoms = Table.ofColumns(AtomsSchema, { - type_symbol: Column.ofArray({ array: Column.mapToArray(atomsData.atomName, guessElementSymbol), schema: Column.Schema.Aliased<ElementSymbol>(Column.Schema.str) }), - label_atom_id: atomsData.atomName, - auth_atom_id: atomsData.atomName, - label_alt_id: Column.Undefined(atomsData.count, Column.Schema.str), - pdbx_formal_charge: Column.Undefined(atomsData.count, Column.Schema.int) - }); - - const residues = Table.view(Table.ofColumns(ResiduesSchema, { - group_PDB: Column.Undefined(atomsData.count, Column.Schema.Aliased<'ATOM' | 'HETATM'>(Column.Schema.str)), - label_comp_id: atomsData.residueName, - auth_comp_id: atomsData.residueName, - label_seq_id: atomsData.residueNumber, - auth_seq_id: atomsData.residueNumber, - pdbx_PDB_ins_code: Column.Undefined(atomsData.count, Column.Schema.str), - }), ResiduesSchema, offsets.residues); - // Optimize the numeric columns - Table.columnToArray(residues, 'label_seq_id', Int32Array); - Table.columnToArray(residues, 'auth_seq_id', Int32Array); - - // const chains = Table.ofColumns(Hierarchy.ChainsSchema, { - // label_asym_id: Column.ofConst('A', atomsData.count, Column.Schema.str), - // auth_asym_id: Column.ofConst('A', atomsData.count, Column.Schema.str), - // label_entity_id: Column.Undefined(atomsData.count, Column.Schema.str) - // }); - - const chains = Table.ofUndefinedColumns(ChainsSchema, 0); - - return { atoms, residues, chains }; -} - -function getConformation(atoms: Atoms): AtomicConformation { - return { - id: UUID.create(), - atomId: atoms.atomNumber, - occupancy: Column.Undefined(atoms.count, Column.Schema.int), - B_iso_or_equiv: Column.Undefined(atoms.count, Column.Schema.float), - x: Column.mapToArray(atoms.x, x => x * 10, Float32Array), - y: Column.mapToArray(atoms.y, y => y * 10, Float32Array), - z: Column.mapToArray(atoms.z, z => z * 10, Float32Array) - } -} - -function isHierarchyDataEqual(a: AtomicData, b: AtomicData) { - // need to cast because of how TS handles type resolution for interfaces https://github.com/Microsoft/TypeScript/issues/15300 - return Table.areEqual(a.residues as Table<ResiduesSchema>, b.residues as Table<ResiduesSchema>) - && Table.areEqual(a.atoms as Table<AtomsSchema>, b.atoms as Table<AtomsSchema>) -} - -function createModel(format: gro_Format, modelNum: number, previous?: Model): Model { - const structure = format.data.structures[modelNum]; - const bounds = Interval.ofBounds(0, structure.atoms.count); - - const hierarchyOffsets = findHierarchyOffsets(structure.atoms, bounds); - const hierarchyData = createHierarchyData(structure.atoms, hierarchyOffsets); - - if (previous && isHierarchyDataEqual(previous.hierarchy, hierarchyData)) { - return { - ...previous, - atomSiteConformation: getConformation(structure.atoms) - }; - } - - const hierarchySegments: AtomicSegments = { - residueSegments: Segmentation.ofOffsets(hierarchyOffsets.residues, bounds), - chainSegments: Segmentation.ofOffsets(hierarchyOffsets.chains, bounds), - } - - // 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.fromAtomicHierarchy(hierarchy), - atomSiteConformation: getConformation(structure.atoms), - coarseGrained: CoarseGrainedHierarchy.Empty, - symmetry: ModelSymmetry.Default, - atomCount: structure.atoms.count - }; -} - -function buildModels(format: gro_Format): ReadonlyArray<Model> { - const models: Model[] = []; - - format.data.structures.forEach((_, i) => { - const model = createModel(format, i, models.length > 0 ? models[models.length - 1] : void 0); - models.push(model); - }); - return models; -} - -export default buildModels; \ No newline at end of file +// TODO: make this work when the time comes. +// /** +// * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. +// * +// * @author Alexander Rose <alexander.rose@weirdbyte.de> +// */ + +// import { Column, Table } from 'mol-data/db'; +// import { Interval, Segmentation } from 'mol-data/int'; +// import { mmCIF_Schema as mmCIF } from 'mol-io/reader/cif/schema/mmcif'; +// import { Atoms } from 'mol-io/reader/gro/schema'; +// import UUID from 'mol-util/uuid'; +// import Format from '../format'; +// import Model from '../model'; +// import { AtomicConformation, AtomicData, AtomicSegments, AtomsSchema, ChainsSchema, ResiduesSchema } from '../properties/atomic'; +// import { CoarseHierarchy } from '../properties/coarse'; +// import { Entities } from '../properties/common'; +// import Sequence from '../properties/sequence'; +// import { ModelSymmetry } from '../properties/symmetry'; +// import { guessElement } from '../properties/utils/guess-element'; +// import { getAtomicKeys } from '../properties/utils/keys'; +// import { ElementSymbol } from '../types'; + +// import gro_Format = Format.gro + +// type HierarchyOffsets = { residues: ArrayLike<number>, chains: ArrayLike<number> } + +// function findHierarchyOffsets(atomsData: Atoms, bounds: Interval) { +// const start = Interval.start(bounds), end = Interval.end(bounds); +// const residues = [start], chains = [start]; + +// const { residueName, residueNumber } = atomsData; + +// for (let i = start + 1; i < end; i++) { +// const newResidue = !residueNumber.areValuesEqual(i - 1, i) +// || !residueName.areValuesEqual(i - 1, i); +// console.log(residueName.value(i - 1), residueName.value(i), residueNumber.value(i - 1), residueNumber.value(i), newResidue) +// if (newResidue) residues[residues.length] = i; +// } +// console.log(residues, residues.length) +// return { residues, chains }; +// } + +// function guessElementSymbol (value: string) { +// return ElementSymbol(guessElement(value)); +// } + +// function createHierarchyData(atomsData: Atoms, offsets: HierarchyOffsets): AtomicData { +// console.log(atomsData.atomName) +// const atoms = Table.ofColumns(AtomsSchema, { +// type_symbol: Column.ofArray({ array: Column.mapToArray(atomsData.atomName, guessElementSymbol), schema: Column.Schema.Aliased<ElementSymbol>(Column.Schema.str) }), +// label_atom_id: atomsData.atomName, +// auth_atom_id: atomsData.atomName, +// label_alt_id: Column.Undefined(atomsData.count, Column.Schema.str), +// pdbx_formal_charge: Column.Undefined(atomsData.count, Column.Schema.int) +// }); + +// const residues = Table.view(Table.ofColumns(ResiduesSchema, { +// group_PDB: Column.Undefined(atomsData.count, Column.Schema.Aliased<'ATOM' | 'HETATM'>(Column.Schema.str)), +// label_comp_id: atomsData.residueName, +// auth_comp_id: atomsData.residueName, +// label_seq_id: atomsData.residueNumber, +// auth_seq_id: atomsData.residueNumber, +// pdbx_PDB_ins_code: Column.Undefined(atomsData.count, Column.Schema.str), +// }), ResiduesSchema, offsets.residues); +// // Optimize the numeric columns +// Table.columnToArray(residues, 'label_seq_id', Int32Array); +// Table.columnToArray(residues, 'auth_seq_id', Int32Array); + +// // const chains = Table.ofColumns(Hierarchy.ChainsSchema, { +// // label_asym_id: Column.ofConst('A', atomsData.count, Column.Schema.str), +// // auth_asym_id: Column.ofConst('A', atomsData.count, Column.Schema.str), +// // label_entity_id: Column.Undefined(atomsData.count, Column.Schema.str) +// // }); + +// const chains = Table.ofUndefinedColumns(ChainsSchema, 0); + +// return { atoms, residues, chains }; +// } + +// function getConformation(atoms: Atoms): AtomicConformation { +// return { +// id: UUID.create(), +// atomId: atoms.atomNumber, +// occupancy: Column.Undefined(atoms.count, Column.Schema.int), +// B_iso_or_equiv: Column.Undefined(atoms.count, Column.Schema.float), +// x: Column.mapToArray(atoms.x, x => x * 10, Float32Array), +// y: Column.mapToArray(atoms.y, y => y * 10, Float32Array), +// z: Column.mapToArray(atoms.z, z => z * 10, Float32Array) +// } +// } + +// function isHierarchyDataEqual(a: AtomicData, b: AtomicData) { +// // need to cast because of how TS handles type resolution for interfaces https://github.com/Microsoft/TypeScript/issues/15300 +// return Table.areEqual(a.residues as Table<ResiduesSchema>, b.residues as Table<ResiduesSchema>) +// && Table.areEqual(a.atoms as Table<AtomsSchema>, b.atoms as Table<AtomsSchema>) +// } + +// function createModel(format: gro_Format, modelNum: number, previous?: Model): Model { +// const structure = format.data.structures[modelNum]; +// const bounds = Interval.ofBounds(0, structure.atoms.count); + +// const hierarchyOffsets = findHierarchyOffsets(structure.atoms, bounds); +// const hierarchyData = createHierarchyData(structure.atoms, hierarchyOffsets); + +// if (previous && isHierarchyDataEqual(previous.atomicHierarchy, hierarchyData)) { +// return { +// ...previous, +// atomicConformation: getConformation(structure.atoms) +// }; +// } + +// const hierarchySegments: AtomicSegments = { +// residueSegments: Segmentation.ofOffsets(hierarchyOffsets.residues, bounds), +// chainSegments: Segmentation.ofOffsets(hierarchyOffsets.chains, bounds), +// } + +// // 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 = getAtomicKeys(hierarchyData, entities, hierarchySegments); +// const atomicHierarchy = { ...hierarchyData, ...hierarchyKeys, ...hierarchySegments }; +// return { +// id: UUID.create(), +// sourceData: format, +// modelNum, +// atomicHierarchy, +// entities, +// sequence: Sequence.fromAtomicHierarchy(atomicHierarchy), +// atomicConformation: getConformation(structure.atoms), +// coarseHierarchy: CoarseHierarchy.Empty, +// coarseConformation: void 0 as any, +// symmetry: ModelSymmetry.Default +// }; +// } + +// function buildModels(format: gro_Format): ReadonlyArray<Model> { +// const models: Model[] = []; + +// format.data.structures.forEach((_, i) => { +// const model = createModel(format, i, models.length > 0 ? models[models.length - 1] : void 0); +// models.push(model); +// }); +// return models; +// } + +// export default buildModels; \ No newline at end of file diff --git a/src/mol-model/structure/model/formats/mmcif.ts b/src/mol-model/structure/model/formats/mmcif.ts index 22644e2fa2ef1fdbb7909b6a825275110fa5e24b..3f68d54440d673ad55a30bd8b7e6fefec442df8d 100644 --- a/src/mol-model/structure/model/formats/mmcif.ts +++ b/src/mol-model/structure/model/formats/mmcif.ts @@ -4,23 +4,23 @@ * @author David Sehnal <david.sehnal@gmail.com> */ -import UUID from 'mol-util/uuid' -import { Column, Table } from 'mol-data/db' -import { Interval, Segmentation } from 'mol-data/int' -import Format from '../format' -import Model from '../model' -import { AtomsSchema, ResiduesSchema, ChainsSchema, AtomicData, AtomicSegments, AtomicConformation } from '../properties/atomic' -import { ModelSymmetry } from '../properties/symmetry' -import findHierarchyKeys from '../utils/hierarchy-keys' -import { ElementSymbol} from '../types' -import createAssemblies from './mmcif/assembly' - -import mmCIF_Format = Format.mmCIF -import { getSequence } from './mmcif/sequence'; -import { Entities } from '../properties/common'; -import { coarseGrainedFromIHM } from './mmcif/ihm'; +import { Column, Table } from 'mol-data/db'; +import { Interval, Segmentation } from 'mol-data/int'; import { Spacegroup, SpacegroupCell } from 'mol-math/geometry'; import { Vec3 } from 'mol-math/linear-algebra'; +import UUID from 'mol-util/uuid'; +import Format from '../format'; +import Model from '../model'; +import { AtomicConformation, AtomicData, AtomicSegments, AtomsSchema, ChainsSchema, ResiduesSchema } from '../properties/atomic'; +import { Entities } from '../properties/common'; +import { ModelSymmetry } from '../properties/symmetry'; +import { getAtomicKeys } from '../properties/utils/atomic-keys'; +import { ElementSymbol } from '../types'; +import { createAssemblies } from './mmcif/assembly'; +import { getIHMCoarse } from './mmcif/ihm'; +import { getSequence } from './mmcif/sequence'; + +import mmCIF_Format = Format.mmCIF function findModelBounds({ data }: mmCIF_Format, startIndex: number) { const num = data.atom_site.pdbx_PDB_model_num; @@ -120,10 +120,10 @@ function createModel(format: mmCIF_Format, bounds: Interval, previous?: Model): const hierarchyOffsets = findHierarchyOffsets(format, bounds); const hierarchyData = createHierarchyData(format, bounds, hierarchyOffsets); - if (previous && isHierarchyDataEqual(previous.hierarchy, hierarchyData)) { + if (previous && isHierarchyDataEqual(previous.atomicHierarchy, hierarchyData)) { return { ...previous, - atomSiteConformation: getConformation(format, bounds) + atomicConformation: getConformation(format, bounds) }; } @@ -134,21 +134,23 @@ function createModel(format: mmCIF_Format, bounds: Interval, previous?: Model): const entities: Entities = { data: format.data.entity, getEntityIndex: Column.createIndexer(format.data.entity.id) }; - const hierarchyKeys = findHierarchyKeys(hierarchyData, entities, hierarchySegments); + const hierarchyKeys = getAtomicKeys(hierarchyData, entities, hierarchySegments); + + const atomicHierarchy = { ...hierarchyData, ...hierarchyKeys, ...hierarchySegments }; - const hierarchy = { ...hierarchyData, ...hierarchyKeys, ...hierarchySegments }; + const coarse = getIHMCoarse(format.data, entities); return { id: UUID.create(), sourceData: format, modelNum: format.data.atom_site.pdbx_PDB_model_num.value(Interval.start(bounds)), entities, - hierarchy, - sequence: getSequence(format.data, entities, hierarchy), - atomSiteConformation: getConformation(format, bounds), - coarseGrained: coarseGrainedFromIHM(format.data, entities), - symmetry: getSymmetry(format), - atomCount: Interval.size(bounds) + atomicHierarchy, + sequence: getSequence(format.data, entities, atomicHierarchy), + atomicConformation: getConformation(format, bounds), + coarseHierarchy: coarse.hierarchy, + coarseConformation: coarse.conformation, + symmetry: getSymmetry(format) }; } diff --git a/src/mol-model/structure/model/formats/mmcif/assembly.ts b/src/mol-model/structure/model/formats/mmcif/assembly.ts index 2315133d4cb83c7219207a9690f5b55ca148db9b..48720596c26741364f2acc6306ae47ba87ad3426 100644 --- a/src/mol-model/structure/model/formats/mmcif/assembly.ts +++ b/src/mol-model/structure/model/formats/mmcif/assembly.ts @@ -12,7 +12,7 @@ import { Queries as Q, Query } from '../../../query' import mmCIF_Format = Format.mmCIF -export default function create(format: mmCIF_Format): ReadonlyArray<Assembly> { +export function createAssemblies(format: mmCIF_Format): ReadonlyArray<Assembly> { const { pdbx_struct_assembly } = format.data; if (!pdbx_struct_assembly._rowCount) return []; diff --git a/src/mol-model/structure/model/formats/mmcif/bonds.ts b/src/mol-model/structure/model/formats/mmcif/bonds.ts index 7bd6ec6f9d732ace52744af95756aa1a80292fc0..95ac32d4d36ffcebcc35064cd69e5d5b790f1ba9 100644 --- a/src/mol-model/structure/model/formats/mmcif/bonds.ts +++ b/src/mol-model/structure/model/formats/mmcif/bonds.ts @@ -118,7 +118,7 @@ export namespace StructConn { const _p = (row: number, ps: typeof p1) => { if (ps.label_asym_id.valueKind(row) !== Column.ValueKind.Present) return void 0; const asymId = ps.label_asym_id.value(row) - const residueIndex = model.hierarchy.findResidueKey( + const residueIndex = model.atomicHierarchy.findResidueKey( findEntityIdByAsymId(model, asymId), ps.label_comp_id.value(row), asymId, diff --git a/src/mol-model/structure/model/formats/mmcif/ihm.ts b/src/mol-model/structure/model/formats/mmcif/ihm.ts index 5eab89ab00f1343d56e65a7ce44b630e67e670d4..1dfdc1c1d36a15658b7c88da88f7741382596ad0 100644 --- a/src/mol-model/structure/model/formats/mmcif/ihm.ts +++ b/src/mol-model/structure/model/formats/mmcif/ihm.ts @@ -5,50 +5,81 @@ */ import { mmCIF_Database as mmCIF, mmCIF_Schema } from 'mol-io/reader/cif/schema/mmcif' -import { CoarseGrainedHierarchy } from '../../properties/coarse-grained/hierarchy' +import { CoarseHierarchy, CoarseConformation, CoarseElementData, CoarseSphereConformation, CoarseGaussianConformation } from '../../properties/coarse' import { Entities } from '../../properties/common'; import { Column } from 'mol-data/db'; +import { getCoarseKeys } from '../../properties/utils/coarse-keys'; +import { UUID } from 'mol-util'; +import { Segmentation, Interval } from 'mol-data/int'; +import { Mat3, Tensor } from 'mol-math/linear-algebra'; -function coarseGrainedFromIHM(data: mmCIF, entities: Entities): CoarseGrainedHierarchy { - if (data.ihm_model_list._rowCount === 0) return CoarseGrainedHierarchy.Empty; +export function getIHMCoarse(data: mmCIF, entities: Entities): { hierarchy: CoarseHierarchy, conformation: CoarseConformation } { + if (data.ihm_model_list._rowCount === 0) return { hierarchy: CoarseHierarchy.Empty, conformation: void 0 as any }; const { ihm_model_list, ihm_sphere_obj_site, ihm_gaussian_obj_site } = data; const modelIndex = Column.createIndexer(ihm_model_list.model_id); + const sphereData = getData(ihm_sphere_obj_site); + const sphereConformation = getSphereConformation(ihm_sphere_obj_site); + const sphereKeys = getCoarseKeys(sphereData, modelIndex, entities); + + const gaussianData = getData(ihm_gaussian_obj_site); + const gaussianConformation = getGaussianConformation(ihm_gaussian_obj_site); + const gaussianKeys = getCoarseKeys(gaussianData, modelIndex, entities); + return { - isDefined: true, - modelList: ihm_model_list, - spheres: getSpheres(ihm_sphere_obj_site, entities, modelIndex), - gaussians: getGaussians(ihm_gaussian_obj_site, entities, modelIndex) + hierarchy: { + isDefined: true, + models: ihm_model_list, + spheres: { ...sphereData, ...sphereKeys }, + gaussians: { ...gaussianData, ...gaussianKeys }, + }, + conformation: { + id: UUID.create(), + spheres: sphereConformation, + gaussians: gaussianConformation + } }; } -function getSpheres(data: mmCIF['ihm_sphere_obj_site'], entities: Entities, modelIndex: (id: number) => number): CoarseGrainedHierarchy.Spheres { - const { Cartn_x, Cartn_y, Cartn_z, object_radius: radius, rmsf } = data; - const x = Cartn_x.toArray({ array: Float32Array }); - const y = Cartn_y.toArray({ array: Float32Array }); - const z = Cartn_z.toArray({ array: Float32Array }); - return { count: x.length, ...getCommonColumns(data, entities, modelIndex), x, y, z, radius, rmsf }; +function getSphereConformation(data: mmCIF['ihm_sphere_obj_site']): CoarseSphereConformation { + return { + x: data.Cartn_x.toArray({ array: Float32Array }), + y: data.Cartn_y.toArray({ array: Float32Array }), + z: data.Cartn_z.toArray({ array: Float32Array }), + radius: data.object_radius.toArray({ array: Float32Array }), + rmsf: data.rmsf.toArray({ array: Float32Array }) + }; } -function getGaussians(data: mmCIF['ihm_gaussian_obj_site'], entities: Entities, modelIndex: (id: number) => number): CoarseGrainedHierarchy.Gaussians { - const { mean_Cartn_x, mean_Cartn_y, mean_Cartn_z, weight, covariance_matrix } = data; - const x = mean_Cartn_x.toArray({ array: Float32Array }); - const y = mean_Cartn_y.toArray({ array: Float32Array }); - const z = mean_Cartn_z.toArray({ array: Float32Array }); - return { count: x.length, ...getCommonColumns(data, entities, modelIndex), x, y, z, weight, covariance_matrix, matrix_space: mmCIF_Schema.ihm_gaussian_obj_site.covariance_matrix.space }; -} +function getGaussianConformation(data: mmCIF['ihm_gaussian_obj_site']): CoarseGaussianConformation { + const matrix_space = mmCIF_Schema.ihm_gaussian_obj_site.covariance_matrix.space; + const covariance_matrix: Mat3[] = []; + const { covariance_matrix: cm } = data; -function getCommonColumns(data: mmCIF['ihm_sphere_obj_site'] | mmCIF['ihm_gaussian_obj_site'], entities: Entities, modelIndex: (id: number) => number) { - const { model_id, entity_id, seq_id_begin, seq_id_end, asym_id } = data; + for (let i = 0, _i = cm.rowCount; i < _i; i++) { + covariance_matrix[i] = Tensor.toMat3(matrix_space, cm.value(i)); + } return { - entityKey: Column.mapToArray(entity_id, id => entities.getEntityIndex(id), Int32Array), - modelKey: Column.mapToArray(model_id, modelIndex, Int32Array), - asym_id, - seq_id_begin, - seq_id_end + x: data.mean_Cartn_x.toArray({ array: Float32Array }), + y: data.mean_Cartn_y.toArray({ array: Float32Array }), + z: data.mean_Cartn_z.toArray({ array: Float32Array }), + weight: data.weight.toArray({ array: Float32Array }), + covariance_matrix }; } -export { coarseGrainedFromIHM } \ No newline at end of file +function getChainSegments(asym_id: Column<string>) { + const offsets = [0]; + for (let i = 1, _i = asym_id.rowCount; i < _i; i++) { + if (!asym_id.areValuesEqual(i - 1, i)) offsets[offsets.length] = i; + } + + return Segmentation.ofOffsets(offsets, Interval.ofBounds(0, asym_id.rowCount)); +} + +function getData(data: mmCIF['ihm_sphere_obj_site'] | mmCIF['ihm_gaussian_obj_site']): CoarseElementData { + const { model_id, entity_id, seq_id_begin, seq_id_end, asym_id } = data; + return { count: model_id.rowCount, entity_id, model_id, asym_id, seq_id_begin, seq_id_end, chainSegments: getChainSegments(asym_id) }; +} \ No newline at end of file diff --git a/src/mol-model/structure/model/formats/mmcif/util.ts b/src/mol-model/structure/model/formats/mmcif/util.ts index a03d511f54dd47643b4cc8b2189fdb532e994e7e..1817e1c22868410ce6529934aa279e3096654189 100644 --- a/src/mol-model/structure/model/formats/mmcif/util.ts +++ b/src/mol-model/structure/model/formats/mmcif/util.ts @@ -16,9 +16,9 @@ export function findEntityIdByAsymId(model: Model, asymId: string) { } export function findAtomIndexByLabelName(model: Model, residueIndex: number, atomName: string, altLoc: string | null) { - const { segmentMap, segments } = model.hierarchy.residueSegments + const { segmentMap, segments } = model.atomicHierarchy.residueSegments const idx = segmentMap[residueIndex] - const { label_atom_id, label_alt_id } = model.hierarchy.atoms; + const { label_atom_id, label_alt_id } = model.atomicHierarchy.atoms; for (let i = segments[idx], n = segments[idx + 1]; i <= n; ++i) { if (label_atom_id.value(i) === atomName && (!altLoc || label_alt_id.value(i) === altLoc)) return i; } diff --git a/src/mol-model/structure/model/model.ts b/src/mol-model/structure/model/model.ts index eb7d5024a4a0d524f59bee9a2328c2eae4cbeec2..0a1725d48fa174c42fb08d30cbc0d45b6b990610 100644 --- a/src/mol-model/structure/model/model.ts +++ b/src/mol-model/structure/model/model.ts @@ -9,10 +9,10 @@ import Format from './format' import Sequence from './properties/sequence' import { AtomicHierarchy, AtomicConformation } from './properties/atomic' import { ModelSymmetry } from './properties/symmetry' -import { CoarseGrainedHierarchy } from './properties/coarse-grained/hierarchy' +import { CoarseHierarchy, CoarseConformation } from './properties/coarse' import { Entities } from './properties/common'; -import from_gro from './formats/gro' +//import from_gro from './formats/gro' import from_mmCIF from './formats/mmcif' /** @@ -31,11 +31,11 @@ interface Model extends Readonly<{ entities: Entities, sequence: Sequence, - hierarchy: AtomicHierarchy, - atomSiteConformation: AtomicConformation, - coarseGrained: CoarseGrainedHierarchy, + atomicHierarchy: AtomicHierarchy, + atomicConformation: AtomicConformation, - atomCount: number, + coarseHierarchy: CoarseHierarchy, + coarseConformation: CoarseConformation }> { } { } @@ -43,22 +43,10 @@ interface Model extends Readonly<{ namespace Model { export function create(format: Format) { switch (format.kind) { - case 'gro': return from_gro(format); + //case 'gro': return from_gro(format); case 'mmCIF': return from_mmCIF(format); } } - // export function spatialLookup(model: Model): GridLookup { - // if (model['@spatialLookup']) return model['@spatialLookup']!; - // const lookup = GridLookup(model.conformation); - // model['@spatialLookup'] = lookup; - // return lookup; - // } - // export function bonds(model: Model): Bonds { - // if (model['@bonds']) return model['@bonds']!; - // const bonds = computeBonds(model); - // model['@bonds'] = bonds; - // return bonds; - // } } export default Model \ No newline at end of file diff --git a/src/mol-model/structure/model/properties/atomic/hierarchy.ts b/src/mol-model/structure/model/properties/atomic/hierarchy.ts index 02ef4dd5d7666fd8956d12d14b62bd3c664c7b6d..fe50e990b242ece24021f6f8eee514388e95d6da 100644 --- a/src/mol-model/structure/model/properties/atomic/hierarchy.ts +++ b/src/mol-model/structure/model/properties/atomic/hierarchy.ts @@ -8,7 +8,6 @@ import { Column, Table } from 'mol-data/db' import { Segmentation } from 'mol-data/int' import { mmCIF_Schema as mmCIF } from 'mol-io/reader/cif/schema/mmcif' import { ElementSymbol} from '../../types' -import { Keys } from '../common'; export const AtomsSchema = { type_symbol: Column.Schema.Aliased<ElementSymbol>(mmCIF.atom_site.type_symbol), @@ -52,9 +51,21 @@ export interface AtomicSegments { chainSegments: Segmentation } -export interface AtomicKeys extends Keys { +export interface AtomicKeys { + // indicate whether the keys form an increasing sequence and within each chain, sequence numbers + // are in increasing order. + // monotonous sequences enable for example faster secondary structure assignment. + isMonotonous: boolean, + // assign a key to each residue index. - residueKey: Column<number>, + residueKey: ArrayLike<number>, + // assign a key to each chain index + chainKey: ArrayLike<number>, + // assigne a key to each chain index + // also index to the Entities table. + entityKey: ArrayLike<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/properties/coarse-grained/conformation.ts b/src/mol-model/structure/model/properties/coarse-grained/conformation.ts deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/src/mol-model/structure/model/properties/coarse-grained/hierarchy.ts b/src/mol-model/structure/model/properties/coarse-grained/hierarchy.ts deleted file mode 100644 index 12dd042cd1df9d3d75fc15a17ca4bd621d469495..0000000000000000000000000000000000000000 --- a/src/mol-model/structure/model/properties/coarse-grained/hierarchy.ts +++ /dev/null @@ -1,53 +0,0 @@ -/** - * 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' -import { Tensor } from 'mol-math/linear-algebra'; -import { Column } from 'mol-data/db'; - -interface CoarseGrainedHierarchy { - isDefined: boolean, - modelList: mmCIF['ihm_model_list'], - spheres: CoarseGrainedHierarchy.Spheres, - gaussians: CoarseGrainedHierarchy.Gaussians -} - -namespace CoarseGrainedHierarchy { - export const Empty: CoarseGrainedHierarchy = { isDefined: false } as any; - - export const enum ElementType { Sphere, Gaussian } - - export interface SiteBase { - asym_id: string, - seq_id_begin: number, - seq_id_end: number - } - - export interface Sphere extends SiteBase { - radius: number, - rmsf: number - } - - export interface Gaussian extends SiteBase { - weight: number, - covariance_matrix: Tensor.Data - } - - type Common = { - count: number, - x: ArrayLike<number>, - y: ArrayLike<number>, - z: ArrayLike<number>, - modelKey: ArrayLike<number>, - entityKey: ArrayLike<number> - } - - export type SitesBase = Common & { [P in keyof SiteBase]: Column<SiteBase[P]> } - export type Spheres = Common & { [P in keyof Sphere]: Column<Sphere[P]> } - export type Gaussians = Common & { matrix_space: Tensor.Space } & { [P in keyof Gaussian]: Column<Gaussian[P]> } -} - -export { CoarseGrainedHierarchy } \ No newline at end of file diff --git a/src/mol-model/structure/model/properties/coarse.ts b/src/mol-model/structure/model/properties/coarse.ts new file mode 100644 index 0000000000000000000000000000000000000000..d1fc3decf25a10a9a54c5924d5c4cdfaa7ab556a --- /dev/null +++ b/src/mol-model/structure/model/properties/coarse.ts @@ -0,0 +1,8 @@ +/** + * Copyright (c) 2017 mol* contributors, licensed under MIT, See LICENSE file for more info. + * + * @author David Sehnal <david.sehnal@gmail.com> + */ + +export * from './coarse/conformation' +export * from './coarse/hierarchy' \ No newline at end of file diff --git a/src/mol-model/structure/model/properties/coarse/conformation.ts b/src/mol-model/structure/model/properties/coarse/conformation.ts new file mode 100644 index 0000000000000000000000000000000000000000..4298b80bdb8fd043149520f2b5b50d56aae59212 --- /dev/null +++ b/src/mol-model/structure/model/properties/coarse/conformation.ts @@ -0,0 +1,30 @@ +/** + * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. + * + * @author David Sehnal <david.sehnal@gmail.com> + */ + +import UUID from 'mol-util/uuid' +import { Mat3 } from 'mol-math/linear-algebra'; + +export interface CoarseConformation { + id: UUID, + spheres: CoarseSphereConformation, + gaussians: CoarseGaussianConformation +} + +export interface CoarseSphereConformation { + x: ArrayLike<number>, + y: ArrayLike<number>, + z: ArrayLike<number>, + radius: ArrayLike<number>, + rmsf: ArrayLike<number> +} + +export interface CoarseGaussianConformation { + x: ArrayLike<number>, + y: ArrayLike<number>, + z: ArrayLike<number>, + weight: ArrayLike<number>, + covariance_matrix: ArrayLike<Mat3> +} \ No newline at end of file diff --git a/src/mol-model/structure/model/properties/coarse/hierarchy.ts b/src/mol-model/structure/model/properties/coarse/hierarchy.ts new file mode 100644 index 0000000000000000000000000000000000000000..fedb463c9e7b015de3485ef2c2a90b2798df71ec --- /dev/null +++ b/src/mol-model/structure/model/properties/coarse/hierarchy.ts @@ -0,0 +1,49 @@ +/** + * 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' +import { Column } from 'mol-data/db' +import { Segmentation } from 'mol-data/int'; + +export interface CoarsedElementKeys { + // indicate whether the keys form an increasing sequence and within each chain, sequence numbers + // are in increasing order. + // monotonous sequences enable for example faster secondary structure assignment. + isMonotonous: boolean, + + // assign a key to each element + chainKey: ArrayLike<number>, + // assign a key to each element, index to the Model.entities.data table + entityKey: ArrayLike<number>, + // assign a key to each element, index to the CoarseHierarchy.models table + modelKey: ArrayLike<number>, + + findChainKey(entityId: string, asym_id: string): number +} + +export interface CoarseElementData { + count: number, + entity_id: Column<string>, + model_id: Column<number>, + asym_id: Column<string>, + seq_id_begin: Column<number>, + seq_id_end: Column<number>, + + chainSegments: Segmentation +} + +export type CoarseElements = CoarsedElementKeys & CoarseElementData + +export interface CoarseHierarchy { + isDefined: boolean, + models: mmCIF['ihm_model_list'], + spheres: CoarseElements, + gaussians: CoarseElements +} + +export namespace CoarseHierarchy { + export const Empty: CoarseHierarchy = { isDefined: false } as any; +} \ 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 index e70712cbbf3e5c68f731da2f70afde1acb5e2846..9dadbc95ac9d951e4d175949655012b0222a52a5 100644 --- a/src/mol-model/structure/model/properties/common.ts +++ b/src/mol-model/structure/model/properties/common.ts @@ -5,24 +5,8 @@ */ import { mmCIF_Database as mmCIF } from 'mol-io/reader/cif/schema/mmcif' -import { Column } from 'mol-data/db'; export interface Entities { data: mmCIF['entity'], getEntityIndex(id: string): number -} - -export interface Keys { - // indicate whether the keys form an increasing sequence and within each chain, sequence numbers - // are in increasing order. - // monotonous sequences enable for example faster secondary structure assignment. - isMonotonous: boolean, - - // assign a key to each chain index - chainKey: Column<number>, - // assigne a key to each chain index - // also index to the Entities table. - entityKey: Column<number>, - - findChainKey(entityId: string, label_asym_id: string): number } \ No newline at end of file diff --git a/src/mol-model/structure/model/utils/hierarchy-keys.ts b/src/mol-model/structure/model/properties/utils/atomic-keys.ts similarity index 90% rename from src/mol-model/structure/model/utils/hierarchy-keys.ts rename to src/mol-model/structure/model/properties/utils/atomic-keys.ts index aabfe1b4a6bb9bed1633ab748d382aa935316588..1cfec2f0348e902f39787c3f2c0510687caef256 100644 --- a/src/mol-model/structure/model/utils/hierarchy-keys.ts +++ b/src/mol-model/structure/model/properties/utils/atomic-keys.ts @@ -4,10 +4,9 @@ * @author David Sehnal <david.sehnal@gmail.com> */ -import { Column } from 'mol-data/db' -import { AtomicData, AtomicSegments, AtomicKeys } from '../properties/atomic' +import { AtomicData, AtomicSegments, AtomicKeys } from '../atomic' import { Interval, Segmentation } from 'mol-data/int' -import { Entities } from '../properties/common'; +import { Entities } from '../common' function getResidueId(comp_id: string, seq_id: number, ins_code: string) { return `${comp_id} ${seq_id} ${ins_code}`; @@ -62,7 +61,7 @@ function missingEntity(k: string) { throw new Error(`Missing entity entry for entity id '${k}'.`); } -function create(data: AtomicData, entities: Entities, segments: AtomicSegments): AtomicKeys { +export function getAtomicKeys(data: AtomicData, entities: Entities, segments: AtomicSegments): AtomicKeys { const { chains, residues } = data; const chainMaps = new Map<number, Map<string, number>>(), chainCounter = { index: 0 }; @@ -110,12 +109,10 @@ function create(data: AtomicData, entities: Entities, segments: AtomicSegments): return { isMonotonous: isMonotonous && checkMonotonous(entityKey) && checkMonotonous(chainKey) && checkMonotonous(residueKey), - residueKey: Column.ofIntArray(residueKey), - chainKey: Column.ofIntArray(chainKey), - entityKey: Column.ofIntArray(entityKey), + residueKey: residueKey, + chainKey: chainKey, + entityKey: entityKey, findChainKey, findResidueKey }; -} - -export default create; \ No newline at end of file +} \ No newline at end of file diff --git a/src/mol-model/structure/model/properties/utils/coarse-keys.ts b/src/mol-model/structure/model/properties/utils/coarse-keys.ts new file mode 100644 index 0000000000000000000000000000000000000000..6ef72039a5f3fa35705364b38d24d2e4bef00553 --- /dev/null +++ b/src/mol-model/structure/model/properties/utils/coarse-keys.ts @@ -0,0 +1,84 @@ +/** + * Copyright (c) 2017 mol* contributors, licensed under MIT, See LICENSE file for more info. + * + * @author David Sehnal <david.sehnal@gmail.com> + */ + +import { Entities } from '../common'; +import { CoarseElementData, CoarsedElementKeys } from '../coarse'; + +function getElementKey(map: Map<string, number>, key: string, counter: { index: number }) { + if (map.has(key)) return map.get(key)!; + const ret = counter.index++; + map.set(key, ret); + return ret; +} + +function getElementSubstructureKeyMap(map: Map<number, Map<string, number>>, key: number) { + if (map.has(key)) return map.get(key)!; + const ret = new Map<string, number>(); + map.set(key, ret); + return ret; +} + +function createLookUp(entities: Entities, chain: Map<number, Map<string, number>>) { + const getEntKey = entities.getEntityIndex; + const findChainKey: CoarsedElementKeys['findChainKey'] = (e, c) => { + let eKey = getEntKey(e); + if (eKey < 0) return -1; + const cm = chain.get(eKey)!; + if (!cm.has(c)) return -1; + return cm.get(c)!; + } + return { findChainKey }; +} + +function checkMonotonous(xs: ArrayLike<number>) { + for (let i = 1, _i = xs.length; i < _i; i++) { + if (xs[i] < xs[i - 1]) { + return false; + } + } + return true; +} + +function missingEntity(k: string) { + throw new Error(`Missing entity entry for entity id '${k}'.`); +} + +function missingModel(k: string) { + throw new Error(`Missing entity entry for model id '${k}'.`); +} + +export function getCoarseKeys(data: CoarseElementData, modelIndex: (id: number) => number, entities: Entities): CoarsedElementKeys { + const { model_id, entity_id, asym_id, count, chainSegments } = data; + + const chainMaps = new Map<number, Map<string, number>>(), chainCounter = { index: 0 }; + const chainKey = new Int32Array(count); + const entityKey = new Int32Array(count); + const modelKey = new Int32Array(count); + + for (let i = 0; i < count; i++) { + entityKey[i] = entities.getEntityIndex(entity_id.value(i)); + if (entityKey[i] < 0) missingEntity(entity_id.value(i)); + modelKey[i] = modelIndex(model_id.value(i)); + if (modelKey[i] < 0) missingModel('' + model_id.value(i)); + } + + for (let cI = 0; cI < chainSegments.count; cI++) { + const start = chainSegments.segments[cI], end = chainSegments.segments[cI + 1]; + const map = getElementSubstructureKeyMap(chainMaps, entityKey[start]); + const key = getElementKey(map, asym_id.value(start), chainCounter); + for (let i = start; i < end; i++) chainKey[i] = key; + } + + const { findChainKey } = createLookUp(entities, chainMaps); + + return { + isMonotonous: checkMonotonous(entityKey) && checkMonotonous(chainKey), + chainKey: chainKey, + entityKey: entityKey, + modelKey: modelKey, + findChainKey + }; +} \ No newline at end of file diff --git a/src/mol-model/structure/model/utils/guess-element.ts b/src/mol-model/structure/model/properties/utils/guess-element.ts similarity index 100% rename from src/mol-model/structure/model/utils/guess-element.ts rename to src/mol-model/structure/model/properties/utils/guess-element.ts diff --git a/src/mol-model/structure/query/generators.ts b/src/mol-model/structure/query/generators.ts index ac9df85096b1680ea2cd0f9a193c7713e69b0843..01445a1dad2933947020a5ab53f7b8d44502232a 100644 --- a/src/mol-model/structure/query/generators.ts +++ b/src/mol-model/structure/query/generators.ts @@ -80,8 +80,8 @@ function atomGroupsSegmented({ entityTest, chainTest, residueTest, atomTest }: A const elements = unit.elements; builder.beginUnit(unit.id); - const chainsIt = Segmentation.transientSegments(unit.model.hierarchy.chainSegments, elements); - const residuesIt = Segmentation.transientSegments(unit.model.hierarchy.residueSegments, elements); + const chainsIt = Segmentation.transientSegments(unit.model.atomicHierarchy.chainSegments, elements); + const residuesIt = Segmentation.transientSegments(unit.model.atomicHierarchy.residueSegments, elements); while (chainsIt.hasNext) { const chainSegment = chainsIt.move(); l.element = OrderedSet.getAt(elements, chainSegment.start); @@ -174,8 +174,8 @@ function atomGroupsGrouped({ entityTest, chainTest, residueTest, atomTest, group l.unit = unit; const elements = unit.elements; - const chainsIt = Segmentation.transientSegments(unit.model.hierarchy.chainSegments, elements); - const residuesIt = Segmentation.transientSegments(unit.model.hierarchy.residueSegments, elements); + const chainsIt = Segmentation.transientSegments(unit.model.atomicHierarchy.chainSegments, elements); + const residuesIt = Segmentation.transientSegments(unit.model.atomicHierarchy.residueSegments, elements); while (chainsIt.hasNext) { const chainSegment = chainsIt.move(); l.element = OrderedSet.getAt(elements, chainSegment.start); diff --git a/src/mol-model/structure/query/properties.ts b/src/mol-model/structure/query/properties.ts index fc2a066ad957730fe49ec9a884ffb47a822156e6..a4d4ad5b3d38a50dcc50cdf596f26373883af42f 100644 --- a/src/mol-model/structure/query/properties.ts +++ b/src/mol-model/structure/query/properties.ts @@ -29,61 +29,61 @@ const atom = { x: Element.property(l => l.unit.conformation.x(l.element)), y: Element.property(l => l.unit.conformation.y(l.element)), z: Element.property(l => l.unit.conformation.z(l.element)), - id: Element.property(l => !Unit.isAtomic(l.unit) ? notAtomic() : l.unit.model.atomSiteConformation.atomId.value(l.element)), - occupancy: Element.property(l => !Unit.isAtomic(l.unit) ? notAtomic() : l.unit.model.atomSiteConformation.occupancy.value(l.element)), - B_iso_or_equiv: Element.property(l => !Unit.isAtomic(l.unit) ? notAtomic() : l.unit.model.atomSiteConformation.B_iso_or_equiv.value(l.element)), + id: Element.property(l => !Unit.isAtomic(l.unit) ? notAtomic() : l.unit.model.atomicConformation.atomId.value(l.element)), + occupancy: Element.property(l => !Unit.isAtomic(l.unit) ? notAtomic() : l.unit.model.atomicConformation.occupancy.value(l.element)), + B_iso_or_equiv: Element.property(l => !Unit.isAtomic(l.unit) ? notAtomic() : l.unit.model.atomicConformation.B_iso_or_equiv.value(l.element)), // Hierarchy - type_symbol: Element.property(l => !Unit.isAtomic(l.unit) ? notAtomic() : l.unit.model.hierarchy.atoms.type_symbol.value(l.element)), - label_atom_id: Element.property(l => !Unit.isAtomic(l.unit) ? notAtomic() : l.unit.model.hierarchy.atoms.label_atom_id.value(l.element)), - auth_atom_id: Element.property(l => !Unit.isAtomic(l.unit) ? notAtomic() : l.unit.model.hierarchy.atoms.auth_atom_id.value(l.element)), - label_alt_id: Element.property(l => !Unit.isAtomic(l.unit) ? notAtomic() : l.unit.model.hierarchy.atoms.label_alt_id.value(l.element)), - pdbx_formal_charge: Element.property(l => !Unit.isAtomic(l.unit) ? notAtomic() : l.unit.model.hierarchy.atoms.pdbx_formal_charge.value(l.element)), + type_symbol: Element.property(l => !Unit.isAtomic(l.unit) ? notAtomic() : l.unit.model.atomicHierarchy.atoms.type_symbol.value(l.element)), + label_atom_id: Element.property(l => !Unit.isAtomic(l.unit) ? notAtomic() : l.unit.model.atomicHierarchy.atoms.label_atom_id.value(l.element)), + auth_atom_id: Element.property(l => !Unit.isAtomic(l.unit) ? notAtomic() : l.unit.model.atomicHierarchy.atoms.auth_atom_id.value(l.element)), + label_alt_id: Element.property(l => !Unit.isAtomic(l.unit) ? notAtomic() : l.unit.model.atomicHierarchy.atoms.label_alt_id.value(l.element)), + pdbx_formal_charge: Element.property(l => !Unit.isAtomic(l.unit) ? notAtomic() : l.unit.model.atomicHierarchy.atoms.pdbx_formal_charge.value(l.element)), // Derived - vdw_radius: Element.property(l => !Unit.isAtomic(l.unit) ? notAtomic() : VdwRadius(l.unit.model.hierarchy.atoms.type_symbol.value(l.element))), + vdw_radius: Element.property(l => !Unit.isAtomic(l.unit) ? notAtomic() : VdwRadius(l.unit.model.atomicHierarchy.atoms.type_symbol.value(l.element))), } const residue = { - key: Element.property(l => !Unit.isAtomic(l.unit) ? notAtomic() : l.unit.model.hierarchy.residueKey.value(l.unit.residueIndex[l.element])), - - group_PDB: Element.property(l => !Unit.isAtomic(l.unit) ? notAtomic() : l.unit.model.hierarchy.residues.group_PDB.value(l.unit.residueIndex[l.element])), - label_comp_id: Element.property(l => !Unit.isAtomic(l.unit) ? notAtomic() : l.unit.model.hierarchy.residues.label_comp_id.value(l.unit.residueIndex[l.element])), - auth_comp_id: Element.property(l => !Unit.isAtomic(l.unit) ? notAtomic() : l.unit.model.hierarchy.residues.auth_comp_id.value(l.unit.residueIndex[l.element])), - label_seq_id: Element.property(l => !Unit.isAtomic(l.unit) ? notAtomic() : l.unit.model.hierarchy.residues.label_seq_id.value(l.unit.residueIndex[l.element])), - auth_seq_id: Element.property(l => !Unit.isAtomic(l.unit) ? notAtomic() : l.unit.model.hierarchy.residues.auth_seq_id.value(l.unit.residueIndex[l.element])), - pdbx_PDB_ins_code: Element.property(l => !Unit.isAtomic(l.unit) ? notAtomic() : l.unit.model.hierarchy.residues.pdbx_PDB_ins_code.value(l.unit.residueIndex[l.element])) + key: Element.property(l => !Unit.isAtomic(l.unit) ? notAtomic() : l.unit.model.atomicHierarchy.residueKey[l.unit.residueIndex[l.element]]), + + group_PDB: Element.property(l => !Unit.isAtomic(l.unit) ? notAtomic() : l.unit.model.atomicHierarchy.residues.group_PDB.value(l.unit.residueIndex[l.element])), + label_comp_id: Element.property(l => !Unit.isAtomic(l.unit) ? notAtomic() : l.unit.model.atomicHierarchy.residues.label_comp_id.value(l.unit.residueIndex[l.element])), + auth_comp_id: Element.property(l => !Unit.isAtomic(l.unit) ? notAtomic() : l.unit.model.atomicHierarchy.residues.auth_comp_id.value(l.unit.residueIndex[l.element])), + label_seq_id: Element.property(l => !Unit.isAtomic(l.unit) ? notAtomic() : l.unit.model.atomicHierarchy.residues.label_seq_id.value(l.unit.residueIndex[l.element])), + auth_seq_id: Element.property(l => !Unit.isAtomic(l.unit) ? notAtomic() : l.unit.model.atomicHierarchy.residues.auth_seq_id.value(l.unit.residueIndex[l.element])), + pdbx_PDB_ins_code: Element.property(l => !Unit.isAtomic(l.unit) ? notAtomic() : l.unit.model.atomicHierarchy.residues.pdbx_PDB_ins_code.value(l.unit.residueIndex[l.element])) } const chain = { - key: Element.property(l => !Unit.isAtomic(l.unit) ? notAtomic() : l.unit.model.hierarchy.chainKey.value(l.unit.chainIndex[l.element])), + key: Element.property(l => !Unit.isAtomic(l.unit) ? notAtomic() : l.unit.model.atomicHierarchy.chainKey[l.unit.chainIndex[l.element]]), - label_asym_id: Element.property(l => !Unit.isAtomic(l.unit) ? notAtomic() : l.unit.model.hierarchy.chains.label_asym_id.value(l.unit.chainIndex[l.element])), - auth_asym_id: Element.property(l => !Unit.isAtomic(l.unit) ? notAtomic() : l.unit.model.hierarchy.chains.auth_asym_id.value(l.unit.chainIndex[l.element])), - label_entity_id: Element.property(l => !Unit.isAtomic(l.unit) ? notAtomic() : l.unit.model.hierarchy.chains.label_entity_id.value(l.unit.chainIndex[l.element])) + label_asym_id: Element.property(l => !Unit.isAtomic(l.unit) ? notAtomic() : l.unit.model.atomicHierarchy.chains.label_asym_id.value(l.unit.chainIndex[l.element])), + auth_asym_id: Element.property(l => !Unit.isAtomic(l.unit) ? notAtomic() : l.unit.model.atomicHierarchy.chains.auth_asym_id.value(l.unit.chainIndex[l.element])), + label_entity_id: Element.property(l => !Unit.isAtomic(l.unit) ? notAtomic() : l.unit.model.atomicHierarchy.chains.label_entity_id.value(l.unit.chainIndex[l.element])) } -const coarse_grained = { +const coarse = { key: atom.key, - modelKey: Element.property(l => !Unit.isCoarse(l.unit) ? notCoarse() : l.unit.sites.modelKey[l.element]), - entityKey: Element.property(l => !Unit.isCoarse(l.unit) ? notCoarse() : l.unit.sites.entityKey[l.element]), + modelKey: Element.property(l => !Unit.isCoarse(l.unit) ? notCoarse() : l.unit.coarseElements.modelKey[l.element]), + entityKey: Element.property(l => !Unit.isCoarse(l.unit) ? notCoarse() : l.unit.coarseElements.entityKey[l.element]), x: atom.x, y: atom.y, z: atom.z, - asym_id: Element.property(l => !Unit.isCoarse(l.unit) ? notCoarse() : l.unit.sites.asym_id.value(l.element)), - seq_id_begin: Element.property(l => !Unit.isCoarse(l.unit) ? notCoarse() : l.unit.sites.seq_id_begin.value(l.element)), - seq_id_end: Element.property(l => !Unit.isCoarse(l.unit) ? notCoarse() : l.unit.sites.seq_id_end.value(l.element)), + asym_id: Element.property(l => !Unit.isCoarse(l.unit) ? notCoarse() : l.unit.coarseElements.asym_id.value(l.element)), + seq_id_begin: Element.property(l => !Unit.isCoarse(l.unit) ? notCoarse() : l.unit.coarseElements.seq_id_begin.value(l.element)), + seq_id_end: Element.property(l => !Unit.isCoarse(l.unit) ? notCoarse() : l.unit.coarseElements.seq_id_end.value(l.element)), - sphere_radius: Element.property(l => !Unit.isSpheres(l.unit) ? notCoarse('spheres') : l.unit.sites.radius.value(l.element)), - sphere_rmsf: Element.property(l => !Unit.isSpheres(l.unit) ? notCoarse('spheres') : l.unit.sites.rmsf.value(l.element)), + sphere_radius: Element.property(l => !Unit.isSpheres(l.unit) ? notCoarse('spheres') : l.unit.coarseConformation.radius[l.element]), + sphere_rmsf: Element.property(l => !Unit.isSpheres(l.unit) ? notCoarse('spheres') : l.unit.coarseConformation.rmsf[l.element]), - gaussian_weight: Element.property(l => !Unit.isGaussians(l.unit) ? notCoarse('gaussians') : l.unit.sites.weight.value(l.element)), - gaussian_covariance_matrix: Element.property(l => !Unit.isGaussians(l.unit) ? notCoarse('gaussians') : l.unit.sites.covariance_matrix.value(l.element)) + gaussian_weight: Element.property(l => !Unit.isGaussians(l.unit) ? notCoarse('gaussians') : l.unit.coarseConformation.weight[l.element]), + gaussian_covariance_matrix: Element.property(l => !Unit.isGaussians(l.unit) ? notCoarse('gaussians') : l.unit.coarseConformation.covariance_matrix[l.element]) } -function eK(l: Element.Location) { return !Unit.isAtomic(l.unit) ? notAtomic() : l.unit.model.hierarchy.entityKey.value(l.unit.chainIndex[l.element]); } +function eK(l: Element.Location) { return !Unit.isAtomic(l.unit) ? notAtomic() : l.unit.model.atomicHierarchy.entityKey[l.unit.chainIndex[l.element]]; } const entity = { key: eK, @@ -112,7 +112,7 @@ const Properties = { chain, entity, unit, - coarse_grained + coarse } type Properties = typeof Properties diff --git a/src/mol-model/structure/structure/structure.ts b/src/mol-model/structure/structure/structure.ts index c2a2ecd38aea3292c2adc63de607733040cd0aa7..efe4e8bde3ba92dd75c98953f01ccc5ec4e3370a 100644 --- a/src/mol-model/structure/structure/structure.ts +++ b/src/mol-model/structure/structure/structure.ts @@ -13,6 +13,7 @@ import Element from './element' import Unit from './unit' import { StructureLookup3D } from './util/lookup3d'; import StructureSymmetry from './symmetry'; +import { CoarseElements } from '../model/properties/coarse'; class Structure { readonly unitMap: IntMap<Unit>; @@ -90,7 +91,7 @@ namespace Structure { } export function ofModel(model: Model): Structure { - const chains = model.hierarchy.chainSegments; + const chains = model.atomicHierarchy.chainSegments; const builder = new StructureBuilder(); for (let c = 0; c < chains.count; c++) { @@ -98,21 +99,27 @@ namespace Structure { builder.addUnit(Unit.Kind.Atomic, model, SymmetryOperator.Default, elements); } - const cs = model.coarseGrained; + const cs = model.coarseHierarchy; if (cs.isDefined) { if (cs.spheres.count > 0) { - const elements = SortedArray.ofBounds(0, cs.spheres.count); - builder.addUnit(Unit.Kind.Spheres, model, SymmetryOperator.Default, elements); + addCoarseUnits(builder, model, model.coarseHierarchy.spheres, Unit.Kind.Spheres); } if (cs.gaussians.count > 0) { - const elements = SortedArray.ofBounds(0, cs.spheres.count); - builder.addUnit(Unit.Kind.Gaussians, model, SymmetryOperator.Default, elements); + addCoarseUnits(builder, model, model.coarseHierarchy.gaussians, Unit.Kind.Gaussians); } } return builder.getStructure(); } + function addCoarseUnits(builder: StructureBuilder, model: Model, elements: CoarseElements, kind: Unit.Kind) { + const { chainSegments } = elements; + for (let cI = 0; cI < chainSegments.count; cI++) { + const elements = SortedArray.ofBounds(chainSegments.segments[cI], chainSegments.segments[cI + 1]); + builder.addUnit(kind, model, SymmetryOperator.Default, elements); + } + } + export class StructureBuilder { private units: Unit[] = []; diff --git a/src/mol-model/structure/structure/unit.ts b/src/mol-model/structure/structure/unit.ts index 7ede3f8a7568f207ea00d2766f88bb2f0f7a6495..4ea70f014d413e7d14967ae769c2d500cb0cdf24 100644 --- a/src/mol-model/structure/structure/unit.ts +++ b/src/mol-model/structure/structure/unit.ts @@ -7,10 +7,10 @@ import { SymmetryOperator } from 'mol-math/geometry/symmetry-operator' import { Model } from '../model' import { GridLookup3D, Lookup3D } from 'mol-math/geometry' -import { CoarseGrainedHierarchy } from '../model/properties/coarse-grained/hierarchy'; import { SortedArray } from 'mol-data/int'; import { idFactory } from 'mol-util/id-factory'; import { IntraUnitBonds, computeIntraUnitBonds } from './unit/bonds' +import { CoarseElements, CoarseSphereConformation, CoarseGaussianConformation } from '../model/properties/coarse'; // A building block of a structure that corresponds to an atomic or a coarse grained representation // 'conveniently grouped together'. @@ -26,9 +26,9 @@ namespace Unit { export function create(id: number, kind: Kind, model: Model, operator: SymmetryOperator, elements: SortedArray): Unit { switch (kind) { - case Kind.Atomic: return new Atomic(id, unitIdFactory(), model, elements, SymmetryOperator.createMapping(operator, model.atomSiteConformation)); - case Kind.Spheres: return createCoarse(id, unitIdFactory(), model, Kind.Spheres, model.coarseGrained.spheres, elements, SymmetryOperator.createMapping(operator, model.atomSiteConformation)); - case Kind.Gaussians: return createCoarse(id, unitIdFactory(), model, Kind.Gaussians, model.coarseGrained.gaussians, elements, SymmetryOperator.createMapping(operator, model.atomSiteConformation)); + case Kind.Atomic: return new Atomic(id, unitIdFactory(), model, elements, SymmetryOperator.createMapping(operator, model.atomicConformation)); + case Kind.Spheres: return createCoarse(id, unitIdFactory(), model, Kind.Spheres, elements, SymmetryOperator.createMapping(operator, model.coarseConformation.spheres)); + case Kind.Gaussians: return createCoarse(id, unitIdFactory(), model, Kind.Gaussians, elements, SymmetryOperator.createMapping(operator, model.coarseConformation.gaussians)); } } @@ -78,13 +78,13 @@ namespace Unit { applyOperator(id: number, operator: SymmetryOperator, dontCompose = false): Unit { const op = dontCompose ? operator : SymmetryOperator.compose(this.conformation.operator, operator); - return new Atomic(id, this.invariantId, this.model, this.elements, SymmetryOperator.createMapping(op, this.model.atomSiteConformation)); + return new Atomic(id, this.invariantId, this.model, this.elements, SymmetryOperator.createMapping(op, this.model.atomicConformation)); } private _lookup3d?: Lookup3D = void 0; get lookup3d() { if (this._lookup3d) return this._lookup3d; - const { x, y, z } = this.model.atomSiteConformation; + const { x, y, z } = this.model.atomicConformation; this._lookup3d = GridLookup3D({ x, y, z, indices: this.elements }); return this._lookup3d; } @@ -103,62 +103,64 @@ namespace Unit { this.elements = elements; this.conformation = conformation; - this.residueIndex = model.hierarchy.residueSegments.segmentMap; - this.chainIndex = model.hierarchy.chainSegments.segmentMap; + this.residueIndex = model.atomicHierarchy.residueSegments.segmentMap; + this.chainIndex = model.atomicHierarchy.chainSegments.segmentMap; } } - // Coarse grained representations. - export interface CoarseBase<S extends CoarseGrainedHierarchy.SitesBase> extends Base { - readonly sites: S - } - - class Coarse<S extends CoarseGrainedHierarchy.SitesBase> implements CoarseBase<S> { - readonly kind: Kind; + class Coarse<K extends Kind.Gaussians | Kind.Spheres, C extends CoarseSphereConformation | CoarseGaussianConformation> implements Base { + readonly kind: K; readonly id: number; readonly invariantId: number; readonly elements: SortedArray; readonly model: Model; readonly conformation: SymmetryOperator.ArrayMapping; - readonly sites: S; + + readonly coarseElements: CoarseElements; + readonly coarseConformation: C; getChild(elements: SortedArray): Unit { if (elements.length === this.elements.length) return this as any as Unit /** lets call this an ugly temporary hack */; - return createCoarse(this.id, this.invariantId, this.model, this.kind, this.sites, elements, this.conformation); + return createCoarse(this.id, this.invariantId, this.model, this.kind, elements, this.conformation); } applyOperator(id: number, operator: SymmetryOperator, dontCompose = false): Unit { const op = dontCompose ? operator : SymmetryOperator.compose(this.conformation.operator, operator); - return createCoarse(id, this.invariantId, this.model, this.kind, this.sites, this.elements, SymmetryOperator.createMapping(op, this.sites)); + return createCoarse(id, this.invariantId, this.model, this.kind, this.elements, SymmetryOperator.createMapping(op, this.getCoarseElements())); } private _lookup3d?: Lookup3D = void 0; get lookup3d() { if (this._lookup3d) return this._lookup3d; - const { x, y, z } = this.sites; - // TODO: support sphere radius + const { x, y, z } = this.getCoarseElements(); + // TODO: support sphere radius? this._lookup3d = GridLookup3D({ x, y, z, indices: this.elements }); return this._lookup3d; } - constructor(id: number, invariantId: number, model: Model, kind: Kind, sites: S, elements: SortedArray, conformation: SymmetryOperator.ArrayMapping) { + private getCoarseElements() { + return this.kind === Kind.Spheres ? this.model.coarseConformation.spheres : this.model.coarseConformation.gaussians; + } + + constructor(id: number, invariantId: number, model: Model, kind: K, elements: SortedArray, conformation: SymmetryOperator.ArrayMapping) { this.kind = kind; this.id = id; this.invariantId = invariantId; this.model = model; this.elements = elements; this.conformation = conformation; - this.sites = sites; + this.coarseElements = kind === Kind.Spheres ? model.coarseHierarchy.spheres : model.coarseHierarchy.gaussians; + this.coarseConformation = (kind === Kind.Spheres ? model.coarseConformation.spheres : model.coarseConformation.gaussians) as C; } } - function createCoarse<S extends CoarseGrainedHierarchy.SitesBase>(id: number, invariantId: number, model: Model, kind: Kind, sites: S, elements: SortedArray, conformation: SymmetryOperator.ArrayMapping): Unit { - return new Coarse(id, invariantId, model, kind, sites, elements, conformation) as any as Unit /** lets call this an ugly temporary hack */; + function createCoarse<K extends Kind.Gaussians | Kind.Spheres>(id: number, invariantId: number, model: Model, kind: K, elements: SortedArray, conformation: SymmetryOperator.ArrayMapping): Unit { + return new Coarse(id, invariantId, model, kind, elements, conformation) as any as Unit /** lets call this an ugly temporary hack */; } - export interface Spheres extends CoarseBase<CoarseGrainedHierarchy.Spheres> { kind: Kind.Spheres } - export interface Gaussians extends CoarseBase<CoarseGrainedHierarchy.Gaussians> { kind: Kind.Gaussians } + export class Spheres extends Coarse<Kind.Spheres, CoarseSphereConformation> { } + export class Gaussians extends Coarse<Kind.Gaussians, CoarseGaussianConformation> { } } export default Unit; \ No newline at end of file diff --git a/src/mol-model/structure/structure/unit/bonds/intra-compute.ts b/src/mol-model/structure/structure/unit/bonds/intra-compute.ts index 2d8f9af0240a0a0fb13bff6f5354c0fcd78b9cc3..9cd4a9ed1839ec43517ce9e9c46ecb06eb8d31f7 100644 --- a/src/mol-model/structure/structure/unit/bonds/intra-compute.ts +++ b/src/mol-model/structure/structure/unit/bonds/intra-compute.ts @@ -109,11 +109,11 @@ function computePerAtomBonds(atomA: number[], atomB: number[], _order: number[], function _computeBonds(unit: Unit.Atomic, params: BondComputationParameters): IntraUnitBonds { const MAX_RADIUS = 3; - const { x, y, z } = unit.model.atomSiteConformation; + const { x, y, z } = unit.model.atomicConformation; const atomCount = unit.elements.length; const { elements: atoms, residueIndex } = unit; - const { type_symbol, label_atom_id, label_alt_id } = unit.model.hierarchy.atoms; - const { label_comp_id } = unit.model.hierarchy.residues; + const { type_symbol, label_atom_id, label_alt_id } = unit.model.atomicHierarchy.atoms; + const { label_comp_id } = unit.model.atomicHierarchy.residues; const query3d = unit.lookup3d; const structConn = unit.model.sourceData.kind === 'mmCIF' ? StructConn.create(unit.model) : void 0 diff --git a/src/perf-tests/structure.ts b/src/perf-tests/structure.ts index 4070cca0b782bfbc4a2d6f71ae7deb41b155f181..92831adec5440d24c6a0eee1e44491ccfca12211 100644 --- a/src/perf-tests/structure.ts +++ b/src/perf-tests/structure.ts @@ -371,7 +371,7 @@ export namespace PropertyAccess { // return; console.log('bs', baseline(models[0])); - console.log('sp', sumProperty(structures[0], l => l.unit.model.atomSiteConformation.atomId.value(l.element))); + console.log('sp', sumProperty(structures[0], l => l.unit.model.atomicConformation.atomId.value(l.element))); //console.log(sumPropertySegmented(structures[0], l => l.unit.model.atomSiteConformation.atomId.value(l.element))); //console.log(sumPropertySegmentedMutable(structures[0], l => l.unit.model.conformation.atomId.value(l.element)); @@ -418,7 +418,7 @@ export namespace PropertyAccess { console.log(Selection.structureCount(q2r)); //console.log(q1(structures[0])); - const col = models[0].atomSiteConformation.atomId.value; + const col = models[0].atomicConformation.atomId.value; const suite = new B.Suite(); suite //.add('test q', () => q1(structures[0]))