diff --git a/src/mol-model/structure/structure/structure.ts b/src/mol-model/structure/structure/structure.ts index 27c0c467c3840d914236663d3a71e0df15987f10..e36e78fac760d072f09d723804fdfd58eb1be9c6 100644 --- a/src/mol-model/structure/structure/structure.ts +++ b/src/mol-model/structure/structure/structure.ts @@ -27,6 +27,7 @@ import { idFactory } from '../../../mol-util/id-factory'; import { GridLookup3D } from '../../../mol-math/geometry'; import { UUID } from '../../../mol-util'; import { CustomProperties } from '../common/custom-property'; +import { AtomicHierarchy } from '../model/properties/atomic'; class Structure { /** Maps unit.id to unit */ @@ -379,26 +380,32 @@ namespace Structure { const chains = model.atomicHierarchy.chainAtomSegments; const builder = new StructureBuilder(void 0, void 0); - for (let c = 0; c < chains.count; c++) { + for (let c = 0 as ChainIndex; c < chains.count; c++) { const start = chains.offsets[c]; + // set to true for chains that consist of "single atom residues", + // note that it assumes there are no "zero atom residues" + let singleAtomResidues = AtomicHierarchy.chainResidueCount(model.atomicHierarchy, c) === chains.offsets[c + 1] - chains.offsets[c] + // merge all consecutive "single atom chains" with same entity id while (c + 1 < chains.count && chains.offsets[c + 1] - chains.offsets[c] === 1 && chains.offsets[c + 2] - chains.offsets[c + 1] === 1 ) { c++; - const e1 = model.atomicHierarchy.index.getEntityFromChain(c as ChainIndex); + singleAtomResidues = true + const e1 = model.atomicHierarchy.index.getEntityFromChain(c); const e2 = model.atomicHierarchy.index.getEntityFromChain(c + 1 as ChainIndex); if (e1 !== e2) break } const elements = SortedArray.ofBounds(start as ElementIndex, chains.offsets[c + 1] as ElementIndex); - if (isWaterChain(model, c as ChainIndex)) { - partitionAtomicUnit(model, elements, builder); - } else if (elements.length > 200000) { - partitionAtomicUnitPerResidue(model, elements, builder); + if (singleAtomResidues) { + partitionAtomicUnitByAtom(model, elements, builder); + } else if (elements.length > 200000 || isWaterChain(model, c)) { + // split up very large chains e.g. lipid bilayers, micelles or water with explicit H + partitionAtomicUnitByResidue(model, elements, builder); } else { builder.addUnit(Unit.Kind.Atomic, model, SymmetryOperator.Default, elements); } @@ -422,9 +429,9 @@ namespace Structure { return model.entities.data.type.value(e) === 'water'; } - function partitionAtomicUnit(model: Model, indices: SortedArray, builder: StructureBuilder) { + function partitionAtomicUnitByAtom(model: Model, indices: SortedArray, builder: StructureBuilder) { const { x, y, z } = model.atomicConformation; - const lookup = GridLookup3D({ x, y, z, indices }, Vec3.create(64, 64, 64)); + const lookup = GridLookup3D({ x, y, z, indices }, 8192); const { offset, count, array } = lookup.buckets; for (let i = 0, _i = offset.length; i < _i; i++) { @@ -437,7 +444,8 @@ namespace Structure { } } - function partitionAtomicUnitPerResidue(model: Model, indices: SortedArray, builder: StructureBuilder) { + // keeps atoms of residues together + function partitionAtomicUnitByResidue(model: Model, indices: SortedArray, builder: StructureBuilder) { model.atomicHierarchy.residueAtomSegments.offsets const startIndices: number[] = [] @@ -446,12 +454,12 @@ namespace Structure { const residueIt = Segmentation.transientSegments(model.atomicHierarchy.residueAtomSegments, indices) while (residueIt.hasNext) { const residueSegment = residueIt.move(); - startIndices[startIndices.length] = residueSegment.start - endIndices[endIndices.length] = residueSegment.end + startIndices[startIndices.length] = indices[residueSegment.start] + endIndices[endIndices.length] = indices[residueSegment.end] } const { x, y, z } = model.atomicConformation; - const lookup = GridLookup3D({ x, y, z, indices: SortedArray.ofSortedArray(startIndices) }, Vec3.create(256, 256, 256)); + const lookup = GridLookup3D({ x, y, z, indices: SortedArray.ofSortedArray(startIndices) }, 8192); const { offset, count, array } = lookup.buckets; for (let i = 0, _i = offset.length; i < _i; i++) { @@ -463,7 +471,7 @@ namespace Structure { set[set.length] = l; } } - builder.addUnit(Unit.Kind.Atomic, model, SymmetryOperator.Default, SortedArray.ofSortedArray(set)); + builder.addUnit(Unit.Kind.Atomic, model, SymmetryOperator.Default, SortedArray.ofSortedArray(new Int32Array(set))); } }