diff --git a/src/mol-model/structure/export/mmcif.ts b/src/mol-model/structure/export/mmcif.ts index a5924f652740c6d08ccf44c2802d0008a6be4cc8..d955721395a2fbb3fd5788dee2f8c1c616831ce4 100644 --- a/src/mol-model/structure/export/mmcif.ts +++ b/src/mol-model/structure/export/mmcif.ts @@ -42,9 +42,9 @@ function copy_mmCif_category(name: keyof mmCIF_Schema): CifCategory<CifExportCon const _entity: CifCategory<CifExportContext> = { name: 'entity', - instance({ structures}) { - const keys = Structure.getEntityKeys(structures[0]); - return CifCategory.ofTable(structures[0].model.entities.data, keys); + instance({ structures }) { + const indices = structures[0].entityIndices; + return CifCategory.ofTable(structures[0].model.entities.data, indices); } } diff --git a/src/mol-model/structure/structure/structure.ts b/src/mol-model/structure/structure/structure.ts index 7f41cc5fc2752df73c23c6c2eae557b8c0af5003..c40256f4584fad43821c2368baf110d87d22010d 100644 --- a/src/mol-model/structure/structure/structure.ts +++ b/src/mol-model/structure/structure/structure.ts @@ -18,12 +18,13 @@ import { InterUnitBonds, computeInterUnitBonds } from './unit/links'; import { PairRestraints, CrossLinkRestraint, extractCrossLinkRestraints } from './unit/pair-restraints'; import StructureSymmetry from './symmetry'; import StructureProperties from './properties'; -import { ResidueIndex, ChainIndex } from '../model/indexing'; +import { ResidueIndex, ChainIndex, EntityIndex } from '../model/indexing'; import { Carbohydrates } from './carbohydrates/data'; import { computeCarbohydrates } from './carbohydrates/compute'; import { Vec3 } from 'mol-math/linear-algebra'; import { idFactory } from 'mol-util/id-factory'; import { GridLookup3D } from 'mol-math/geometry'; +import { UUID } from 'mol-util'; class Structure { /** Maps unit.id to unit */ @@ -39,6 +40,9 @@ class Structure { carbohydrates?: Carbohydrates, models?: ReadonlyArray<Model>, model?: Model, + uniqueResidueNames?: Set<string>, + entityIndices?: ReadonlyArray<EntityIndex>, + uniqueAtomicResidueIndices?: ReadonlyMap<UUID, ReadonlyArray<ResidueIndex>>, hashCode: number, elementCount: number, polymerResidueCount: number, @@ -129,6 +133,20 @@ class Structure { return this._props.models; } + get uniqueResidueName() { + return this._props.uniqueResidueNames + || (this._props.uniqueResidueNames = getUniqueResidueNames(this)); + } + + get entityIndices() { + return this._props.entityIndices || (this._props.entityIndices = getEntityIndices(this)); + } + + get uniqueAtomicResidueIndices() { + return this._props.uniqueAtomicResidueIndices + || (this._props.uniqueAtomicResidueIndices = getUniqueAtomicResidueIndices(this)); + } + /** If the structure is based on a single model, return it. Otherwise throw an exception. */ get model(): Model { if (this._props.model) return this._props.model; @@ -176,6 +194,81 @@ function getModels(s: Structure) { return arr.array; } +function getUniqueResidueNames(s: Structure) { + const prop = StructureProperties.residue.label_comp_id; + const names = new Set<string>(); + const loc = StructureElement.create(); + for (const unit of s.units) { + // TODO: support coarse unit? + if (!Unit.isAtomic(unit)) continue; + const residues = Segmentation.transientSegments(unit.model.atomicHierarchy.residueAtomSegments, unit.elements); + loc.unit = unit; + while (residues.hasNext) { + const seg = residues.move(); + loc.element = unit.elements[seg.start]; + names.add(prop(loc)); + } + } + return names; +} + +function getEntityIndices(structure: Structure): ReadonlyArray<EntityIndex> { + const { units } = structure; + const l = StructureElement.create(); + const keys = UniqueArray.create<number, EntityIndex>(); + + for (const unit of units) { + const prop = unit.kind === Unit.Kind.Atomic ? StructureProperties.entity.key : StructureProperties.coarse.entityKey; + + l.unit = unit; + const elements = unit.elements; + + const chainsIt = Segmentation.transientSegments(unit.model.atomicHierarchy.chainAtomSegments, elements); + while (chainsIt.hasNext) { + const chainSegment = chainsIt.move(); + l.element = elements[chainSegment.start]; + const key = prop(l); + UniqueArray.add(keys, key, key); + } + } + + sortArray(keys.array); + return keys.array; +} + +function getUniqueAtomicResidueIndices(structure: Structure): ReadonlyMap<UUID, ReadonlyArray<ResidueIndex>> { + const map = new Map<UUID, UniqueArray<ResidueIndex, ResidueIndex>>(); + const modelIds: UUID[] = []; + + const unitGroups = structure.unitSymmetryGroups; + for (const unitGroup of unitGroups) { + const unit = unitGroup.units[0]; + if (!Unit.isAtomic(unit)) continue; + + let uniqueResidues: UniqueArray<ResidueIndex, ResidueIndex>; + if (map.has(unit.model.id)) uniqueResidues = map.get(unit.model.id)!; + else { + uniqueResidues = UniqueArray.create<ResidueIndex, ResidueIndex>(); + modelIds.push(unit.model.id); + map.set(unit.model.id, uniqueResidues); + } + + const residues = Segmentation.transientSegments(unit.model.atomicHierarchy.residueAtomSegments, unit.elements); + while (residues.hasNext) { + const seg = residues.move(); + UniqueArray.add(uniqueResidues, seg.index, seg.index); + } + } + + const ret = new Map<UUID, ReadonlyArray<ResidueIndex>>(); + for (const id of modelIds) { + const array = map.get(id)!.array; + sortArray(array); + ret.set(id, array) + } + return ret; +} + namespace Structure { export const Empty = new Structure([]); @@ -346,49 +439,6 @@ namespace Structure { } } - export function getEntityKeys(structure: Structure) { - const { units } = structure; - const l = StructureElement.create(); - const keys = UniqueArray.create<number, number>(); - - for (const unit of units) { - const prop = unit.kind === Unit.Kind.Atomic ? StructureProperties.entity.key : StructureProperties.coarse.entityKey; - - l.unit = unit; - const elements = unit.elements; - - const chainsIt = Segmentation.transientSegments(unit.model.atomicHierarchy.chainAtomSegments, elements); - while (chainsIt.hasNext) { - const chainSegment = chainsIt.move(); - l.element = elements[chainSegment.start]; - const key = prop(l); - UniqueArray.add(keys, key, key); - } - } - - sortArray(keys.array); - return keys.array; - } - - export function getUniqueAtomicResidueIndices(structure: Structure, model: Model): ReadonlyArray<ResidueIndex> { - const uniqueResidues = UniqueArray.create<ResidueIndex, ResidueIndex>(); - const unitGroups = structure.unitSymmetryGroups; - for (const unitGroup of unitGroups) { - const unit = unitGroup.units[0]; - if (unit.model !== model || !Unit.isAtomic(unit)) { - continue; - } - - const residues = Segmentation.transientSegments(unit.model.atomicHierarchy.residueAtomSegments, unit.elements); - while (residues.hasNext) { - const seg = residues.move(); - UniqueArray.add(uniqueResidues, seg.index, seg.index); - } - } - sortArray(uniqueResidues.array); - return uniqueResidues.array; - } - const distVec = Vec3.zero(); function unitElementMinDistance(unit: Unit, p: Vec3, eRadius: number) { const { elements, conformation: { position, r } } = unit, dV = distVec; diff --git a/src/servers/model/config.ts b/src/servers/model/config.ts index a18919c842ebc67959c4ef6b86fc09a031b2969c..1bf830d00639fd568c5adebbe8d9bbda7da03cbd 100644 --- a/src/servers/model/config.ts +++ b/src/servers/model/config.ts @@ -51,8 +51,8 @@ const config = { * Paths (relative to the root directory of the model server) to JavaScript files that specify custom properties */ customPropertyProviders: [ - './properties/pdbe', - './properties/rcsb' + // './properties/pdbe', + // './properties/rcsb' ], /** @@ -66,9 +66,9 @@ const config = { mapFile(source: string, id: string) { switch (source.toLowerCase()) { // case 'pdb': return `e:/test/quick/${id}_updated.cif`; - case 'pdb': return `e:/test/mol-star/model/out/${id}_updated.bcif`; - case 'pdb-bcif': return `e:/test/mol-star/model/out/${id}_updated.bcif`; - case 'pdb-cif': return `e:/test/mol-star/model/out/${id}_updated.cif`; + case 'pdb': return `c:/test/mol-star/model/out/${id}_updated.bcif`; + case 'pdb-bcif': return `c:/test/mol-star/model/out/${id}_updated.bcif`; + case 'pdb-cif': return `c:/test/mol-star/model/out/${id}_updated.cif`; default: return void 0; } }