diff --git a/src/apps/structure-info/model.ts b/src/apps/structure-info/model.ts index 7a9919b35299824e78876806371e3497397c96c9..d9d42709d84c9a1b4983cb919814da850b8a3206 100644 --- a/src/apps/structure-info/model.ts +++ b/src/apps/structure-info/model.ts @@ -198,10 +198,24 @@ export function printIHMModels(model: Model) { console.log(Table.formatToString(model.coarseHierarchy.models)); } +export function printModelStats(models: ReadonlyArray<Model>) { + console.log('\nModels\n============='); + + for (const m of models) { + if (m.coarseHierarchy.isDefined) { + console.log(`${m.label} ${m.modelNum}: ${m.atomicHierarchy.atoms._rowCount} atom(s), ${m.coarseHierarchy.spheres.count} sphere(s), ${m.coarseHierarchy.gaussians.count} gaussian(s)`); + } else { + console.log(`${m.label} ${m.modelNum}: ${m.atomicHierarchy.atoms._rowCount} atom(s)`); + } + } + console.log(); +} + async function run(frame: CifFrame, args: Args) { const models = await Model.create(Format.mmCIF(frame)).run(); const structure = Structure.ofModel(models[0]); + if (args.models) printModelStats(models); if (args.seq) printSequence(models[0]); if (args.ihm) printIHMModels(models[0]); if (args.units) printUnits(structure); @@ -230,6 +244,7 @@ const parser = new argparse.ArgumentParser({ parser.addArgument(['--download', '-d'], { help: 'Pdb entry id' }); parser.addArgument(['--file', '-f'], { help: 'filename' }); +parser.addArgument(['--models'], { help: 'print models info', action: 'storeTrue' }); parser.addArgument(['--seq'], { help: 'print sequence', action: 'storeTrue' }); parser.addArgument(['--ihm'], { help: 'print IHM', action: 'storeTrue' }); parser.addArgument(['--units'], { help: 'print units', action: 'storeTrue' }); @@ -243,6 +258,7 @@ interface Args { download?: string, file?: string, + models?:boolean, seq?: boolean, ihm?: boolean, units?: boolean, diff --git a/src/mol-data/db/table.ts b/src/mol-data/db/table.ts index 6f0b9bcced4e182747e5031433a920be3127bb66..b68967dfc55f73985b3256beb0f122a733fa4416 100644 --- a/src/mol-data/db/table.ts +++ b/src/mol-data/db/table.ts @@ -101,6 +101,18 @@ namespace Table { return ret as Table<R>; } + export function window<S extends R, R extends Schema>(table: Table<S>, schema: R, start: number, end: number) { + const ret = Object.create(null); + const columns = Object.keys(schema); + ret._rowCount = view.length; + ret._columns = columns; + ret._schema = schema; + for (const k of columns) { + (ret as any)[k] = Column.window(table[k], start, end); + } + return ret as Table<R>; + } + export function concat<S extends R, R extends Schema>(tables: Table<S>[], schema: R) { const ret = Object.create(null); const columns = Object.keys(schema); diff --git a/src/mol-model/structure/model/formats/mmcif.ts b/src/mol-model/structure/model/formats/mmcif.ts index 924fc7ba96a5dbcb74030fba2ab2eef8aebc0198..4bd2eee7bd7b4ecd40df07003e83c4a2a670c53c 100644 --- a/src/mol-model/structure/model/formats/mmcif.ts +++ b/src/mol-model/structure/model/formats/mmcif.ts @@ -5,89 +5,27 @@ */ import { Column, Table } from 'mol-data/db'; -import { Interval, Segmentation } from 'mol-data/int'; +import { mmCIF_Database, mmCIF_Schema } from 'mol-io/reader/cif/schema/mmcif'; import { Spacegroup, SpacegroupCell, SymmetryOperator } from 'mol-math/geometry'; -import { Vec3, Tensor } from 'mol-math/linear-algebra'; -import { Task } from 'mol-task'; +import { Tensor, Vec3 } from 'mol-math/linear-algebra'; +import { Task, RuntimeContext } from 'mol-task'; 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 { CustomProperties } from '../properties/custom'; 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 { getAtomicHierarchyAndConformation } from './mmcif/atomic'; +import { ComponentBond } from './mmcif/bonds'; +import { getIHMCoarse, EmptyIHMCoarse, IHMData } from './mmcif/ihm'; import { getSecondaryStructureMmCif } from './mmcif/secondary-structure'; import { getSequence } from './mmcif/sequence'; import { sortAtomSite } from './mmcif/sort'; -import { mmCIF_Database, mmCIF_Schema } from 'mol-io/reader/cif/schema/mmcif'; -import { Element } from '../../../structure' -import { CustomProperties } from '../properties/custom'; import mmCIF_Format = Format.mmCIF -import { ComponentBond } from './mmcif/bonds'; -type AtomSite = mmCIF_Database['atom_site'] - -function findModelEnd({ data }: mmCIF_Format, startIndex: number) { - const num = data.atom_site.pdbx_PDB_model_num; - const atomCount = num.rowCount; - if (!num.isDefined) return atomCount; - let endIndex = startIndex + 1; - while (endIndex < atomCount && num.areValuesEqual(startIndex, endIndex)) endIndex++; - return endIndex; -} - -function findHierarchyOffsets(atom_site: AtomSite) { - if (atom_site._rowCount === 0) return { residues: [], chains: [] }; - const start = 0, end = atom_site._rowCount; - const residues = [start as Element], chains = [start as Element]; - - const { label_entity_id, label_asym_id, label_seq_id, auth_seq_id, pdbx_PDB_ins_code, label_comp_id } = atom_site; - - for (let i = start + 1; i < end; i++) { - const newChain = !label_entity_id.areValuesEqual(i - 1, i) || !label_asym_id.areValuesEqual(i - 1, i); - const newResidue = newChain - || !label_seq_id.areValuesEqual(i - 1, i) - || !auth_seq_id.areValuesEqual(i - 1, i) - || !pdbx_PDB_ins_code.areValuesEqual(i - 1, i) - || !label_comp_id.areValuesEqual(i - 1, i); - - if (newResidue) residues[residues.length] = i as Element; - if (newChain) chains[chains.length] = i as Element; - } - return { residues, chains }; -} - -function createHierarchyData(atom_site: AtomSite, offsets: { residues: ArrayLike<number>, chains: ArrayLike<number> }): AtomicData { - const atoms = Table.ofColumns(AtomsSchema, { - type_symbol: Column.ofArray({ array: Column.mapToArray(atom_site.type_symbol, ElementSymbol), schema: Column.Schema.Aliased<ElementSymbol>(Column.Schema.str) }), - label_atom_id: atom_site.label_atom_id, - auth_atom_id: atom_site.auth_atom_id, - label_alt_id: atom_site.label_alt_id, - pdbx_formal_charge: atom_site.pdbx_formal_charge - }); - const residues = Table.view(atom_site, ResiduesSchema, offsets.residues); - // Optimize the numeric columns - Table.columnToArray(residues, 'label_seq_id', Int32Array); - Table.columnToArray(residues, 'auth_seq_id', Int32Array); - const chains = Table.view(atom_site, ChainsSchema, offsets.chains); - return { atoms, residues, chains }; -} - -function getConformation(atom_site: AtomSite): AtomicConformation { - return { - id: UUID.create(), - atomId: atom_site.id, - occupancy: atom_site.occupancy, - B_iso_or_equiv: atom_site.B_iso_or_equiv, - x: atom_site.Cartn_x.toArray({ array: Float32Array }), - y: atom_site.Cartn_y.toArray({ array: Float32Array }), - z: atom_site.Cartn_z.toArray({ array: Float32Array }), - } -} +type AtomSite = mmCIF_Database['atom_site'] function getSymmetry(format: mmCIF_Format): ModelSymmetry { const assemblies = createAssemblies(format); @@ -129,14 +67,6 @@ function getNcsOperators(format: mmCIF_Format) { } return opers; } - -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.chains as Table<ChainsSchema>, b.chains as Table<ChainsSchema>) - && 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 getModifiedResidueNameMap(format: mmCIF_Format) { const data = format.data.pdbx_struct_mod_residue; const map = new Map<string, string>(); @@ -168,35 +98,13 @@ function getAsymIdSerialMap(format: mmCIF_Format) { return map; } -// TODO split IHM data into models as well, atomistic ihm models have `atom_site.ihm_model_id`, -// how to handle it in a generic way, i.e. when there is no ihm data, use `atom_site.pdbx_PDB_model_num` -// but if there is use `atom_site.ihm_model_id`, `ihm_sphere_obj_site.model_id` and -// `ihm_gaussian_obj_site.model_id` for splitting -// - PDBDEV_00000002 is an example for an IHM structure with multiple models -function createModel(format: mmCIF_Format, atom_site: AtomSite, previous?: Model): Model { - const hierarchyOffsets = findHierarchyOffsets(atom_site); - const hierarchyData = createHierarchyData(atom_site, hierarchyOffsets); - - if (previous && isHierarchyDataEqual(previous.atomicHierarchy, hierarchyData)) { - return { - ...previous, - atomicConformation: getConformation(atom_site) - }; - } - - const hierarchySegments: AtomicSegments = { - residueSegments: Segmentation.ofOffsets(hierarchyOffsets.residues, Interval.ofBounds(0, atom_site._rowCount)), - chainSegments: Segmentation.ofOffsets(hierarchyOffsets.chains, Interval.ofBounds(0, atom_site._rowCount)), +function createStandardModel(format: mmCIF_Format, atom_site: AtomSite, entities: Entities, previous?: Model): Model { + const atomic = getAtomicHierarchyAndConformation(format, atom_site, entities, previous); + if (previous && atomic.sameAsPrevious) { + return { ...previous, atomicConformation: atomic.conformation }; } - const entities: Entities = { data: format.data.entity, getEntityIndex: Column.createIndexer(format.data.entity.id) }; - - const hierarchyKeys = getAtomicKeys(hierarchyData, entities, hierarchySegments); - - const atomicHierarchy = { ...hierarchyData, ...hierarchyKeys, ...hierarchySegments }; - - const coarse = getIHMCoarse(format.data, entities); - + const coarse = EmptyIHMCoarse; const label = format.data.entry.id.valueKind(0) === Column.ValueKind.Present ? format.data.entry.id.value(0) : format.data._name; @@ -211,13 +119,47 @@ function createModel(format: mmCIF_Format, atom_site: AtomSite, previous?: Model modelNum: atom_site.pdbx_PDB_model_num.value(0), entities, symmetry: getSymmetry(format), - atomicHierarchy, - sequence: getSequence(format.data, entities, atomicHierarchy, modifiedResidueNameMap), - atomicConformation: getConformation(atom_site), + sequence: getSequence(format.data, entities, atomic.hierarchy, modifiedResidueNameMap), + atomicHierarchy: atomic.hierarchy, + atomicConformation: atomic.conformation, coarseHierarchy: coarse.hierarchy, coarseConformation: coarse.conformation, properties: { - secondaryStructure: getSecondaryStructureMmCif(format.data, atomicHierarchy), + secondaryStructure: getSecondaryStructureMmCif(format.data, atomic.hierarchy), + modifiedResidueNameMap, + asymIdSerialMap + }, + customProperties: new CustomProperties(), + _staticPropertyData: Object.create(null), + _dynamicPropertyData: Object.create(null) + }; +} + +// TODO split IHM data into models as well, atomistic ihm models have `atom_site.ihm_model_id`, +// how to handle it in a generic way, i.e. when there is no ihm data, use `atom_site.pdbx_PDB_model_num` +// but if there is use `atom_site.ihm_model_id`, `ihm_sphere_obj_site.model_id` and +// `ihm_gaussian_obj_site.model_id` for splitting +// - PDBDEV_00000002 is an example for an IHM structure with multiple models +function createModelIHM(format: mmCIF_Format, data: IHMData): Model { + const atomic = getAtomicHierarchyAndConformation(format, data.atom_site, data.entities); + const coarse = getIHMCoarse(data); + const modifiedResidueNameMap = getModifiedResidueNameMap(format); + const asymIdSerialMap = getAsymIdSerialMap(format) + + return { + id: UUID.create(), + label: data.model_name, + sourceData: format, + modelNum: data.model_id, + entities: data.entities, + symmetry: getSymmetry(format), + sequence: getSequence(format.data, data.entities, atomic.hierarchy, modifiedResidueNameMap), + atomicHierarchy: atomic.hierarchy, + atomicConformation: atomic.conformation, + coarseHierarchy: coarse.hierarchy, + coarseConformation: coarse.conformation, + properties: { + secondaryStructure: getSecondaryStructureMmCif(format.data, atomic.hierarchy), modifiedResidueNameMap, asymIdSerialMap }, @@ -231,28 +173,101 @@ function attachProps(model: Model) { ComponentBond.attachFromMmCif(model); } +function findModelEnd(num: Column<number>, startIndex: number) { + const rowCount = num.rowCount; + if (!num.isDefined) return rowCount; + let endIndex = startIndex + 1; + while (endIndex < rowCount && num.areValuesEqual(startIndex, endIndex)) endIndex++; + return endIndex; +} + +async function readStandard(ctx: RuntimeContext, format: mmCIF_Format) { + const atomCount = format.data.atom_site._rowCount; + const entities: Entities = { data: format.data.entity, getEntityIndex: Column.createIndexer(format.data.entity.id) }; + + const models: Model[] = []; + let modelStart = 0; + while (modelStart < atomCount) { + const modelEnd = findModelEnd(format.data.atom_site.pdbx_PDB_model_num, modelStart); + const atom_site = await sortAtomSite(ctx, format.data.atom_site, modelStart, modelEnd); + const model = createStandardModel(format, atom_site, entities, models.length > 0 ? models[models.length - 1] : void 0); + attachProps(model); + models.push(model); + modelStart = modelEnd; + } + return models; +} + +function splitTable<T extends Table<any>>(table: T, col: Column<number>) { + const ret = new Map<number, T>() + const rowCount = table._rowCount; + let modelStart = 0; + while (modelStart < rowCount) { + const modelEnd = findModelEnd(col, modelStart); + const id = col.value(modelStart); + const window = Table.window(table, table._schema, modelStart, modelEnd) as T; + ret.set(id, window); + modelStart = modelEnd; + } + return ret; +} + +async function readIHM(ctx: RuntimeContext, format: mmCIF_Format) { + const { ihm_model_list } = format.data; + const entities: Entities = { data: format.data.entity, getEntityIndex: Column.createIndexer(format.data.entity.id) }; + + const atom_sites = splitTable(format.data.atom_site, format.data.atom_site.ihm_model_id); + const sphere_sites = splitTable(format.data.ihm_sphere_obj_site, format.data.ihm_sphere_obj_site.model_id); + const gauss_sites = splitTable(format.data.ihm_gaussian_obj_site, format.data.ihm_gaussian_obj_site.model_id); + + const models: Model[] = []; + + const { model_id, model_name } = ihm_model_list; + for (let i = 0; i < ihm_model_list._rowCount; i++) { + const id = model_id.value(i); + const data: IHMData = { + model_id: id, + model_name: model_name.value(i), + ihm_model_list, + entities: entities, + atom_site: atom_sites.has(id) ? atom_sites.get(id)! : Table.window(format.data.atom_site, format.data.atom_site._schema, 0, 0), + ihm_sphere_obj_site: sphere_sites.has(id) ? sphere_sites.get(id)! : Table.window(format.data.ihm_sphere_obj_site, format.data.ihm_sphere_obj_site._schema, 0, 0), + ihm_gaussian_obj_site: gauss_sites.has(id) ? gauss_sites.get(id)! : Table.window(format.data.ihm_gaussian_obj_site, format.data.ihm_gaussian_obj_site._schema, 0, 0) + }; + const model = createModelIHM(format, data); + attachProps(model); + models.push(createModelIHM(format, data)); + } + + return models; + + // const atomCount = format.data.atom_site._rowCount; + // const isIHM = format.data.ihm_model_list._rowCount > 0; + + // if (atomCount === 0) { + // return isIHM + // ? [createModel(format, format.data.atom_site, void 0)] + // : []; + // } + + + // const models: Model[] = []; + // let modelStart = 0; + // while (modelStart < atomCount) { + // const modelEnd = findModelEnd(format, modelStart); + // const atom_site = await sortAtomSite(ctx, format.data.atom_site, modelStart, modelEnd); + // const model = createModel(format, atom_site, models.length > 0 ? models[models.length - 1] : void 0); + // attachProps(model); + // models.push(model); + // modelStart = modelEnd; + // } + // return models; +} + function buildModels(format: mmCIF_Format): Task<ReadonlyArray<Model>> { return Task.create('Create mmCIF Model', async ctx => { - const atomCount = format.data.atom_site._rowCount; const isIHM = format.data.ihm_model_list._rowCount > 0; - - if (atomCount === 0) { - return isIHM - ? [createModel(format, format.data.atom_site, void 0)] - : []; - } - - const models: Model[] = []; - let modelStart = 0; - while (modelStart < atomCount) { - const modelEnd = findModelEnd(format, modelStart); - const atom_site = await sortAtomSite(ctx, format.data.atom_site, modelStart, modelEnd); - const model = createModel(format, atom_site, models.length > 0 ? models[models.length - 1] : void 0); - attachProps(model); - models.push(model); - modelStart = modelEnd; - } - return models; + return isIHM ? await readIHM(ctx, format) : await readStandard(ctx, format); }); } diff --git a/src/mol-model/structure/model/formats/mmcif/atomic.ts b/src/mol-model/structure/model/formats/mmcif/atomic.ts new file mode 100644 index 0000000000000000000000000000000000000000..f0b0480fb2110e1f39ef422bb4a7f7534615ab67 --- /dev/null +++ b/src/mol-model/structure/model/formats/mmcif/atomic.ts @@ -0,0 +1,104 @@ +/** + * Copyright (c) 2017-2018 mol* contributors, licensed under MIT, See LICENSE file for more info. + * + * @author David Sehnal <david.sehnal@gmail.com> + */ + +import { Column, Table } from 'mol-data/db'; +import { Interval, Segmentation } from 'mol-data/int'; +import { mmCIF_Database } from 'mol-io/reader/cif/schema/mmcif'; +import UUID from 'mol-util/uuid'; +import { Element } from '../../../../structure'; +import Format from '../../format'; +import Model from '../../model'; +import { AtomicConformation, AtomicData, AtomicHierarchy, AtomicSegments, AtomsSchema, ChainsSchema, ResiduesSchema } from '../../properties/atomic'; +import { getAtomicKeys } from '../../properties/utils/atomic-keys'; +import { ElementSymbol } from '../../types'; +import { Entities } from '../../properties/common'; + +import mmCIF_Format = Format.mmCIF +type AtomSite = mmCIF_Database['atom_site'] + +function findHierarchyOffsets(atom_site: AtomSite) { + if (atom_site._rowCount === 0) return { residues: [], chains: [] }; + + const start = 0, end = atom_site._rowCount; + const residues = [start as Element], chains = [start as Element]; + + const { label_entity_id, label_asym_id, label_seq_id, auth_seq_id, pdbx_PDB_ins_code, label_comp_id } = atom_site; + + for (let i = start + 1; i < end; i++) { + const newChain = !label_entity_id.areValuesEqual(i - 1, i) || !label_asym_id.areValuesEqual(i - 1, i); + const newResidue = newChain + || !label_seq_id.areValuesEqual(i - 1, i) + || !auth_seq_id.areValuesEqual(i - 1, i) + || !pdbx_PDB_ins_code.areValuesEqual(i - 1, i) + || !label_comp_id.areValuesEqual(i - 1, i); + + if (newResidue) residues[residues.length] = i as Element; + if (newChain) chains[chains.length] = i as Element; + } + return { residues, chains }; +} + +function createHierarchyData(atom_site: AtomSite, offsets: { residues: ArrayLike<number>, chains: ArrayLike<number> }): AtomicData { + const atoms = Table.ofColumns(AtomsSchema, { + type_symbol: Column.ofArray({ array: Column.mapToArray(atom_site.type_symbol, ElementSymbol), schema: Column.Schema.Aliased<ElementSymbol>(Column.Schema.str) }), + label_atom_id: atom_site.label_atom_id, + auth_atom_id: atom_site.auth_atom_id, + label_alt_id: atom_site.label_alt_id, + pdbx_formal_charge: atom_site.pdbx_formal_charge + }); + const residues = Table.view(atom_site, ResiduesSchema, offsets.residues); + // Optimize the numeric columns + Table.columnToArray(residues, 'label_seq_id', Int32Array); + Table.columnToArray(residues, 'auth_seq_id', Int32Array); + const chains = Table.view(atom_site, ChainsSchema, offsets.chains); + return { atoms, residues, chains }; +} + +function getConformation(atom_site: AtomSite): AtomicConformation { + return { + id: UUID.create(), + atomId: atom_site.id, + occupancy: atom_site.occupancy, + B_iso_or_equiv: atom_site.B_iso_or_equiv, + x: atom_site.Cartn_x.toArray({ array: Float32Array }), + y: atom_site.Cartn_y.toArray({ array: Float32Array }), + z: atom_site.Cartn_z.toArray({ array: 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.chains as Table<ChainsSchema>, b.chains as Table<ChainsSchema>) + && Table.areEqual(a.residues as Table<ResiduesSchema>, b.residues as Table<ResiduesSchema>) + && Table.areEqual(a.atoms as Table<AtomsSchema>, b.atoms as Table<AtomsSchema>) +} + + +export function getAtomicHierarchyAndConformation(format: mmCIF_Format, atom_site: AtomSite, entities: Entities, previous?: Model) { + const hierarchyOffsets = findHierarchyOffsets(atom_site); + const hierarchyData = createHierarchyData(atom_site, hierarchyOffsets); + + if (previous && isHierarchyDataEqual(previous.atomicHierarchy, hierarchyData)) { + return { + sameAsPrevious: true, + hierarchy: previous.atomicHierarchy, + conformation: getConformation(atom_site) + }; + } + + const hierarchySegments: AtomicSegments = { + residueSegments: Segmentation.ofOffsets(hierarchyOffsets.residues, Interval.ofBounds(0, atom_site._rowCount)), + chainSegments: Segmentation.ofOffsets(hierarchyOffsets.chains, Interval.ofBounds(0, atom_site._rowCount)), + } + + const hierarchyKeys = getAtomicKeys(hierarchyData, entities, hierarchySegments); + const hierarchy: AtomicHierarchy = { ...hierarchyData, ...hierarchyKeys, ...hierarchySegments }; + return { + sameAsPrevious: false, + hierarchy, + conformation: getConformation(atom_site) + }; +} \ No newline at end of file diff --git a/src/mol-model/structure/model/formats/mmcif/bonds/comp.ts b/src/mol-model/structure/model/formats/mmcif/bonds/comp.ts index fe0c4ab4ed029eab636dd4fdd63e888ec2512a87..04d74a0a7910dc3643e785f912e1f2eba400f829 100644 --- a/src/mol-model/structure/model/formats/mmcif/bonds/comp.ts +++ b/src/mol-model/structure/model/formats/mmcif/bonds/comp.ts @@ -43,6 +43,7 @@ export namespace ComponentBond { } export function attachFromMmCif(model: Model): boolean { + if (model.customProperties.has(Descriptor)) return true; if (model.sourceData.kind !== 'mmCIF') return false; const { chem_comp_bond } = model.sourceData.data; if (chem_comp_bond._rowCount === 0) return false; diff --git a/src/mol-model/structure/model/formats/mmcif/ihm.ts b/src/mol-model/structure/model/formats/mmcif/ihm.ts index 8fe3b4f4aea36256e5529e47296782fb6bec975f..f3bd5ad8113a8cfcf9698e9e45cc38deb65dda9a 100644 --- a/src/mol-model/structure/model/formats/mmcif/ihm.ts +++ b/src/mol-model/structure/model/formats/mmcif/ihm.ts @@ -14,24 +14,39 @@ import { Segmentation, Interval } from 'mol-data/int'; import { Mat3, Tensor } from 'mol-math/linear-algebra'; import { Element } from '../../../structure' -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 }; +type AtomSite = mmCIF['atom_site'] +type SphereSite = mmCIF['ihm_sphere_obj_site'] +type GaussSite = mmCIF['ihm_gaussian_obj_site'] +type IHMModels = mmCIF['ihm_model_list'] +export interface IHMData { + model_id: number, + model_name: string, + ihm_model_list: IHMModels, + entities: Entities, + atom_site: AtomSite, + ihm_sphere_obj_site: SphereSite, + ihm_gaussian_obj_site: GaussSite +} + +export const EmptyIHMCoarse = { hierarchy: CoarseHierarchy.Empty, conformation: void 0 as any } + +export function getIHMCoarse(data: IHMData): { hierarchy: CoarseHierarchy, conformation: CoarseConformation } { 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 sphereKeys = getCoarseKeys(sphereData, modelIndex, data.entities); const gaussianData = getData(ihm_gaussian_obj_site); const gaussianConformation = getGaussianConformation(ihm_gaussian_obj_site); - const gaussianKeys = getCoarseKeys(gaussianData, modelIndex, entities); + const gaussianKeys = getCoarseKeys(gaussianData, modelIndex, data.entities); return { hierarchy: { isDefined: true, - models: ihm_model_list, + //models: ihm_model_list, spheres: { ...sphereData, ...sphereKeys }, gaussians: { ...gaussianData, ...gaussianKeys }, }, diff --git a/src/mol-model/structure/model/properties/coarse/hierarchy.ts b/src/mol-model/structure/model/properties/coarse/hierarchy.ts index 1b50e835de9dc560e2c42083e7843bfeb893b7c9..2bcdabbe815d39d0d62a062e9695796294d9688c 100644 --- a/src/mol-model/structure/model/properties/coarse/hierarchy.ts +++ b/src/mol-model/structure/model/properties/coarse/hierarchy.ts @@ -15,8 +15,9 @@ export interface CoarsedElementKeys { 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>, + + // // assign a key to each element, index to the CoarseHierarchy.models table + // modelKey: ArrayLike<number>, /** find index of the residue/feature element where seq_id is included */ findSequenceKey(entityId: string, asym_id: string, seq_id: number): number @@ -38,7 +39,7 @@ export type CoarseElements = CoarsedElementKeys & CoarseElementData export interface CoarseHierarchy { isDefined: boolean, - models: mmCIF['ihm_model_list'], + //models: mmCIF['ihm_model_list'], spheres: CoarseElements, gaussians: CoarseElements } diff --git a/src/mol-model/structure/model/properties/utils/coarse-keys.ts b/src/mol-model/structure/model/properties/utils/coarse-keys.ts index 67539ec4d91a4fca937561d77913ed83f3189fb3..c18dc27ec7d72dc43b3dbab51a4f3e30f80a385f 100644 --- a/src/mol-model/structure/model/properties/utils/coarse-keys.ts +++ b/src/mol-model/structure/model/properties/utils/coarse-keys.ts @@ -92,5 +92,5 @@ export function getCoarseKeys(data: CoarseElementData, modelIndex: (id: number) const { findChainKey, findSequenceKey } = createLookUp(entities, chainMaps, seqMaps); - return { chainKey, entityKey, modelKey, findSequenceKey, findChainKey }; + return { chainKey, entityKey, /*modelKey,*/ findSequenceKey, findChainKey }; } \ No newline at end of file