Procházet zdrojové kódy

use only unit ids in inter unit graph

not units themselves, so the graph can be reused for structures with same topology but different coordinates
Alexander Rose před 4 roky
rodič
revize
eb71e2c606
23 změnil soubory, kde provedl 174 přidání a 151 odebrání
  1. 6 4
      src/cli/structure-info/model.ts
  2. 3 3
      src/extensions/rcsb/validation-report/prop.ts
  3. 13 8
      src/extensions/rcsb/validation-report/representation.ts
  4. 30 31
      src/mol-math/graph/inter-unit-graph.ts
  5. 6 5
      src/mol-model-props/computed/chemistry/util.ts
  6. 1 1
      src/mol-model-props/computed/chemistry/valence-model.ts
  7. 9 9
      src/mol-model-props/computed/interactions/common.ts
  8. 2 2
      src/mol-model-props/computed/interactions/contacts-builder.ts
  9. 1 1
      src/mol-model-props/computed/interactions/interactions.ts
  10. 6 4
      src/mol-model-props/computed/interactions/refine.ts
  11. 19 15
      src/mol-model-props/computed/representations/interactions-inter-unit-cylinder.ts
  12. 1 1
      src/mol-model-props/computed/themes/interaction-type.ts
  13. 4 3
      src/mol-model/structure/query/queries/filters.ts
  14. 4 4
      src/mol-model/structure/query/queries/generators.ts
  15. 8 7
      src/mol-model/structure/query/queries/modifiers.ts
  16. 3 2
      src/mol-model/structure/structure/carbohydrates/compute.ts
  17. 1 1
      src/mol-model/structure/structure/structure.ts
  18. 2 2
      src/mol-model/structure/structure/unit/bonds.ts
  19. 5 5
      src/mol-model/structure/structure/unit/bonds/data.ts
  20. 3 3
      src/mol-model/structure/structure/unit/bonds/inter-compute.ts
  21. 17 12
      src/mol-repr/structure/visual/bond-inter-unit-cylinder.ts
  22. 18 13
      src/mol-repr/structure/visual/bond-inter-unit-line.ts
  23. 12 15
      src/mol-repr/structure/visual/util/bond.ts

+ 6 - 4
src/cli/structure-info/model.ts

@@ -99,15 +99,17 @@ export function printBonds(structure: Structure, showIntra: boolean, showInter:
         for (const unit of structure.units) {
             if (!Unit.isAtomic(unit)) continue;
 
-            for (const pairBonds of bonds.getConnectedUnits(unit)) {
+            for (const pairBonds of bonds.getConnectedUnits(unit.id)) {
                 if (!pairBonds.areUnitsOrdered || pairBonds.edgeCount === 0) continue;
 
-                const { unitA, unitB } = pairBonds;
-                console.log(`${pairBonds.unitA.id} - ${pairBonds.unitB.id}: ${pairBonds.edgeCount} bond(s)`);
+                const { unitA, unitB, edgeCount } = pairBonds;
+                const uA = structure.unitMap.get(unitA);
+                const uB = structure.unitMap.get(unitB);
+                console.log(`${unitA} - ${unitB}: ${edgeCount} bond(s)`);
 
                 for (const aI of pairBonds.connectedIndices) {
                     for (const bond of pairBonds.getEdges(aI)) {
-                        console.log(`${atomLabel(unitA.model, unitA.elements[aI])} -- ${atomLabel(unitB.model, unitB.elements[bond.indexB])}`);
+                        console.log(`${atomLabel(uA.model, uA.elements[aI])} -- ${atomLabel(uB.model, uB.elements[bond.indexB])}`);
                     }
                 }
             }

+ 3 - 3
src/extensions/rcsb/validation-report/prop.ts

@@ -187,7 +187,7 @@ type InterUnitClashesProps = {
 }
 
 export type IntraUnitClashes = IntAdjacencyGraph<UnitIndex, IntraUnitClashesProps>
-export type InterUnitClashes = InterUnitGraph<Unit.Atomic, UnitIndex, InterUnitClashesProps>
+export type InterUnitClashes = InterUnitGraph<number, UnitIndex, InterUnitClashesProps>
 
 export interface Clashes {
     readonly interUnit: InterUnitClashes
@@ -195,7 +195,7 @@ export interface Clashes {
 }
 
 function createInterUnitClashes(structure: Structure, clashes: ValidationReport['clashes']) {
-    const builder = new InterUnitGraph.Builder<Unit.Atomic, UnitIndex, InterUnitClashesProps>();
+    const builder = new InterUnitGraph.Builder<number, UnitIndex, InterUnitClashesProps>();
     const { a, b, edgeProps: { id, magnitude, distance } } = clashes;
 
     const pA = Vec3(), pB = Vec3();
@@ -204,7 +204,7 @@ function createInterUnitClashes(structure: Structure, clashes: ValidationReport[
         const elementsA = unitA.elements;
         const elementsB = unitB.elements;
 
-        builder.startUnitPair(unitA as Unit.Atomic, unitB as Unit.Atomic);
+        builder.startUnitPair(unitA.id, unitB.id);
 
         for (let i = 0, il = clashes.edgeCount * 2; i < il; ++i) {
             // TODO create lookup

+ 13 - 8
src/extensions/rcsb/validation-report/representation.ts

@@ -159,7 +159,8 @@ function createInterUnitClashCylinderMesh(ctx: VisualContext, structure: Structu
         linkCount: edgeCount,
         position: (posA: Vec3, posB: Vec3, edgeIndex: number) => {
             const b = edges[edgeIndex];
-            const uA = b.unitA, uB = b.unitB;
+            const uA = structure.unitMap.get(b.unitA);
+            const uB = structure.unitMap.get(b.unitB);
             uA.conformation.position(uA.elements[b.indexA], posA);
             uB.conformation.position(uB.elements[b.indexB], posB);
         },
@@ -197,11 +198,13 @@ export function InterUnitClashVisual(materialId: number): ComplexVisual<InterUni
     }, materialId);
 }
 
-function getInterClashBoundingSphere(clashes: InterUnitClashes, elements: number[], boundingSphere: Sphere3D) {
+function getInterClashBoundingSphere(structure: Structure, clashes: InterUnitClashes, elements: number[], boundingSphere: Sphere3D) {
     return CentroidHelper.fromPairProvider(elements.length, (i, pA, pB) => {
         const c = clashes.edges[elements[i]];
-        c.unitA.conformation.position(c.unitA.elements[c.indexA], pA);
-        c.unitB.conformation.position(c.unitB.elements[c.indexB], pB);
+        const uA = structure.unitMap.get(c.unitA);
+        const uB = structure.unitMap.get(c.unitB);
+        uA.conformation.position(uA.elements[c.indexA], pA);
+        uB.conformation.position(uB.elements[c.indexB], pB);
     }, boundingSphere);
 }
 
@@ -209,18 +212,20 @@ function getInterClashLabel(structure: Structure, clashes: InterUnitClashes, ele
     const idx = elements[0];
     if (idx === undefined) return '';
     const c = clashes.edges[idx];
+    const uA = structure.unitMap.get(c.unitA);
+    const uB = structure.unitMap.get(c.unitB);
     const mag = c.props.magnitude.toFixed(2);
     const dist = c.props.distance.toFixed(2);
 
     return [
         `Clash id: ${c.props.id} | Magnitude: ${mag} \u212B | Distance: ${dist} \u212B`,
-        bondLabel(Bond.Location(structure, c.unitA, c.indexA, structure, c.unitB, c.indexB))
+        bondLabel(Bond.Location(structure, uA, c.indexA, structure, uB, c.indexB))
     ].join('</br>');
 }
 
 function InterClashLoci(structure: Structure, clashes: InterUnitClashes, elements: number[]) {
     return DataLoci('inter-clashes', clashes, elements,
-        (boundingSphere: Sphere3D) =>  getInterClashBoundingSphere(clashes, elements, boundingSphere),
+        (boundingSphere: Sphere3D) =>  getInterClashBoundingSphere(structure, clashes, elements, boundingSphere),
         () => getInterClashLabel(structure, clashes, elements));
 }
 
@@ -246,8 +251,8 @@ function createInterClashIterator(structure: Structure): LocationIterator {
     const location = StructureElement.Location.create(structure);
     const getLocation = (groupIndex: number) => {
         const clash = clashes.edges[groupIndex];
-        location.unit = clash.unitA;
-        location.element = clash.unitA.elements[clash.indexA];
+        location.unit = structure.unitMap.get(clash.unitA);
+        location.element = location.unit.elements[clash.indexA];
         return location;
     };
     return LocationIterator(groupCount, instanceCount, getLocation, true);

+ 30 - 31
src/mol-math/graph/inter-unit-graph.ts

@@ -9,46 +9,46 @@ import { UniqueArray } from '../../mol-data/generic';
 
 export { InterUnitGraph };
 
-class InterUnitGraph<Unit extends InterUnitGraph.UnitBase, VertexIndex extends number, EdgeProps extends InterUnitGraph.EdgePropsBase = {}> {
+class InterUnitGraph<UnitId extends number, VertexIndex extends number, EdgeProps extends InterUnitGraph.EdgePropsBase = {}> {
     /** Number of inter-unit edges */
     readonly edgeCount: number
     /** Array of inter-unit edges */
-    readonly edges: ReadonlyArray<InterUnitGraph.Edge<Unit, VertexIndex, EdgeProps>>
+    readonly edges: ReadonlyArray<InterUnitGraph.Edge<UnitId, VertexIndex, EdgeProps>>
     private readonly edgeKeyIndex: Map<string, number>
     private readonly vertexKeyIndex: Map<string, number[]>
 
     /** Get an array of unit-pair-edges that are connected to the given unit */
-    getConnectedUnits(unit: Unit): ReadonlyArray<InterUnitGraph.UnitPairEdges<Unit, VertexIndex, EdgeProps>> {
-        if (!this.map.has(unit.id)) return emptyArray;
-        return this.map.get(unit.id)!;
+    getConnectedUnits(unit: UnitId): ReadonlyArray<InterUnitGraph.UnitPairEdges<UnitId, VertexIndex, EdgeProps>> {
+        if (!this.map.has(unit)) return emptyArray;
+        return this.map.get(unit)!;
     }
 
     /** Index into this.edges */
-    getEdgeIndex(indexA: VertexIndex, unitA: Unit, indexB: VertexIndex, unitB: Unit): number {
-        const edgeKey = InterUnitGraph.getEdgeKey<Unit, VertexIndex>(indexA, unitA, indexB, unitB);
+    getEdgeIndex(indexA: VertexIndex, unitA: UnitId, indexB: VertexIndex, unitB: UnitId): number {
+        const edgeKey = InterUnitGraph.getEdgeKey<UnitId, VertexIndex>(indexA, unitA, indexB, unitB);
         const index = this.edgeKeyIndex.get(edgeKey);
         return index !== undefined ? index : -1;
     }
 
     /** Check if edge exists */
-    hasEdge(indexA: VertexIndex, unitA: Unit, indexB: VertexIndex, unitB: Unit): boolean {
+    hasEdge(indexA: VertexIndex, unitA: UnitId, indexB: VertexIndex, unitB: UnitId): boolean {
         return this.getEdgeIndex(indexA, unitA, indexB, unitB) !== -1;
     }
 
     /** Get inter-unit edge given a pair of indices and units */
-    getEdge(indexA: VertexIndex, unitA: Unit, indexB: VertexIndex, unitB: Unit): InterUnitGraph.Edge<Unit, VertexIndex, EdgeProps> | undefined {
+    getEdge(indexA: VertexIndex, unitA: UnitId, indexB: VertexIndex, unitB: UnitId): InterUnitGraph.Edge<UnitId, VertexIndex, EdgeProps> | undefined {
         const index = this.getEdgeIndex(indexA, unitA, indexB, unitB);
         return index !== -1 ? this.edges[index] : undefined;
     }
 
     /** Indices into this.edges */
-    getEdgeIndices(index: VertexIndex, unit: Unit): ReadonlyArray<number> {
+    getEdgeIndices(index: VertexIndex, unit: UnitId): ReadonlyArray<number> {
         return this.vertexKeyIndex.get(InterUnitGraph.getVertexKey(index, unit)) || [];
     }
 
-    constructor(protected readonly map: Map<number, InterUnitGraph.UnitPairEdges<Unit, VertexIndex, EdgeProps>[]>) {
+    constructor(protected readonly map: Map<number, InterUnitGraph.UnitPairEdges<UnitId, VertexIndex, EdgeProps>[]>) {
         let count = 0;
-        const edges: (InterUnitGraph.Edge<Unit, VertexIndex, EdgeProps>)[] = [];
+        const edges: (InterUnitGraph.Edge<UnitId, VertexIndex, EdgeProps>)[] = [];
         const edgeKeyIndex = new Map<string, number>();
         const vertexKeyIndex = new Map<string, number[]>();
 
@@ -81,7 +81,7 @@ class InterUnitGraph<Unit extends InterUnitGraph.UnitBase, VertexIndex extends n
 }
 
 namespace InterUnitGraph {
-    export class UnitPairEdges<Unit extends UnitBase, VertexIndex extends number, EdgeProps extends EdgePropsBase = {}> {
+    export class UnitPairEdges<UnitId extends number, VertexIndex extends number, EdgeProps extends EdgePropsBase = {}> {
         hasEdges(indexA: VertexIndex) {
             return this.edgeMap.has(indexA);
         }
@@ -92,16 +92,15 @@ namespace InterUnitGraph {
         }
 
         get areUnitsOrdered() {
-            return this.unitA.id < this.unitB.id;
+            return this.unitA < this.unitB;
         }
 
-        constructor(public unitA: Unit, public unitB: Unit,
+        constructor(public unitA: UnitId, public unitB: UnitId,
             public edgeCount: number, public connectedIndices: ReadonlyArray<VertexIndex>,
             private edgeMap: Map<number, EdgeInfo<VertexIndex, EdgeProps>[]>) {
         }
     }
 
-    export type UnitBase = { id: number }
     export type EdgePropsBase = { [name: string]: any }
 
     export interface EdgeInfo<VertexIndex extends number, EdgeProps extends EdgePropsBase = {}> {
@@ -110,20 +109,20 @@ namespace InterUnitGraph {
         readonly props: EdgeProps
     }
 
-    export interface Edge<Unit extends UnitBase, VertexIndex extends number, EdgeProps extends EdgePropsBase = {}> {
-        readonly unitA: Unit,
-        readonly unitB: Unit,
+    export interface Edge<UnitId extends number, VertexIndex extends number, EdgeProps extends EdgePropsBase = {}> {
+        readonly unitA: UnitId,
+        readonly unitB: UnitId,
         readonly indexA: VertexIndex,
         readonly indexB: VertexIndex,
         readonly props: EdgeProps
     }
 
-    export function getEdgeKey<Unit extends UnitBase, VertexIndex extends number>(indexA: VertexIndex, unitA: Unit, indexB: VertexIndex, unitB: Unit) {
-        return `${indexA}|${unitA.id}|${indexB}|${unitB.id}`;
+    export function getEdgeKey<UnitId extends number, VertexIndex extends number>(indexA: VertexIndex, unitA: UnitId, indexB: VertexIndex, unitB: UnitId) {
+        return `${indexA}|${unitA}|${indexB}|${unitB}`;
     }
 
-    export function getVertexKey<Unit extends UnitBase, VertexIndex extends number>(index: VertexIndex, unit: Unit) {
-        return `${index}|${unit.id}`;
+    export function getVertexKey<UnitId extends number, VertexIndex extends number>(index: VertexIndex, unit: UnitId) {
+        return `${index}|${unit}`;
     }
 
     //
@@ -134,18 +133,18 @@ namespace InterUnitGraph {
     }
 
 
-    export class Builder<Unit extends InterUnitGraph.UnitBase, VertexIndex extends number, EdgeProps extends InterUnitGraph.EdgePropsBase = {}> {
-        private uA: Unit
-        private uB: Unit
+    export class Builder<UnitId extends number, VertexIndex extends number, EdgeProps extends InterUnitGraph.EdgePropsBase = {}> {
+        private uA: UnitId
+        private uB: UnitId
         private mapAB: Map<number, EdgeInfo<VertexIndex, EdgeProps>[]>
         private mapBA: Map<number, EdgeInfo<VertexIndex, EdgeProps>[]>
         private linkedA: UniqueArray<VertexIndex, VertexIndex>
         private linkedB: UniqueArray<VertexIndex, VertexIndex>
         private linkCount: number
 
-        private map = new Map<number, UnitPairEdges<Unit, VertexIndex, EdgeProps>[]>();
+        private map = new Map<number, UnitPairEdges<UnitId, VertexIndex, EdgeProps>[]>();
 
-        startUnitPair(unitA: Unit, unitB: Unit) {
+        startUnitPair(unitA: UnitId, unitB: UnitId) {
             this.uA = unitA;
             this.uB = unitB;
             this.mapAB = new Map();
@@ -157,8 +156,8 @@ namespace InterUnitGraph {
 
         finishUnitPair() {
             if (this.linkCount === 0) return;
-            addMapEntry(this.map, this.uA.id, new UnitPairEdges(this.uA, this.uB, this.linkCount, this.linkedA.array, this.mapAB));
-            addMapEntry(this.map, this.uB.id, new UnitPairEdges(this.uB, this.uA, this.linkCount, this.linkedB.array, this.mapBA));
+            addMapEntry(this.map, this.uA, new UnitPairEdges(this.uA, this.uB, this.linkCount, this.linkedA.array, this.mapAB));
+            addMapEntry(this.map, this.uB, new UnitPairEdges(this.uB, this.uA, this.linkCount, this.linkedB.array, this.mapBA));
         }
 
         add(indexA: VertexIndex, indexB: VertexIndex, props: EdgeProps) {
@@ -169,7 +168,7 @@ namespace InterUnitGraph {
             this.linkCount += 1;
         }
 
-        getMap(): Map<number, InterUnitGraph.UnitPairEdges<Unit, VertexIndex, EdgeProps>[]> {
+        getMap(): Map<number, InterUnitGraph.UnitPairEdges<UnitId, VertexIndex, EdgeProps>[]> {
             return this.map;
         }
     }

+ 6 - 5
src/mol-model-props/computed/chemistry/util.ts

@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ * Copyright (c) 2019-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
  *
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
  */
@@ -34,7 +34,7 @@ export function compId(unit: Unit.Atomic, index: StructureElement.UnitIndex) {
 
 export function interBondCount(structure: Structure, unit: Unit.Atomic, index: StructureElement.UnitIndex): number {
     let count = 0;
-    const indices = structure.interUnitBonds.getEdgeIndices(index, unit);
+    const indices = structure.interUnitBonds.getEdgeIndices(index, unit.id);
     for (let i = 0, il = indices.length; i < il; ++i) {
         const b = structure.interUnitBonds.edges[indices[i]];
         if (BondType.isCovalent(b.props.flag)) count += 1;
@@ -75,7 +75,7 @@ export function intraConnectedTo(unit: Unit.Atomic, indexA: StructureElement.Uni
 }
 
 export function interConnectedTo(structure: Structure, unitA: Unit.Atomic, indexA: StructureElement.UnitIndex, unitB: Unit.Atomic, indexB: StructureElement.UnitIndex) {
-    const b = structure.interUnitBonds.getEdge(indexA, unitA, indexB, unitB);
+    const b = structure.interUnitBonds.getEdge(indexA, unitA.id, indexB, unitB.id);
     return b && BondType.isCovalent(b.props.flag);
 }
 
@@ -86,10 +86,11 @@ export function connectedTo(structure: Structure, unitA: Unit.Atomic, indexA: St
 //
 
 export function eachInterBondedAtom(structure: Structure, unit: Unit.Atomic, index: StructureElement.UnitIndex, cb: (unit: Unit.Atomic, index: StructureElement.UnitIndex) => void): void {
-    const indices = structure.interUnitBonds.getEdgeIndices(index, unit);
+    const indices = structure.interUnitBonds.getEdgeIndices(index, unit.id);
     for (let i = 0, il = indices.length; i < il; ++i) {
         const b = structure.interUnitBonds.edges[indices[i]];
-        if (BondType.isCovalent(b.props.flag)) cb(b.unitB, b.indexB);
+        const uB = structure.unitMap.get(b.unitB) as Unit.Atomic;
+        if (BondType.isCovalent(b.props.flag)) cb(uB, b.indexB);
     }
 }
 

+ 1 - 1
src/mol-model-props/computed/chemistry/valence-model.ts

@@ -73,7 +73,7 @@ export function explicitValence (structure: Structure, unit: Unit.Atomic, index:
         if (BondType.isCovalent(flags[i])) v += order[i];
     }
     // inter-unit bonds
-    structure.interUnitBonds.getEdgeIndices(index, unit).forEach(i => {
+    structure.interUnitBonds.getEdgeIndices(index, unit.id).forEach(i => {
         const b = structure.interUnitBonds.edges[i];
         if (BondType.isCovalent(b.props.flag)) v += b.props.order;
     });

+ 9 - 9
src/mol-model-props/computed/interactions/common.ts

@@ -84,25 +84,25 @@ namespace InteractionsIntraContacts {
 }
 
 export { InteractionsInterContacts };
-class InteractionsInterContacts extends InterUnitGraph<Unit, Features.FeatureIndex, InteractionsInterContacts.Props> {
+class InteractionsInterContacts extends InterUnitGraph<number, Features.FeatureIndex, InteractionsInterContacts.Props> {
     private readonly elementKeyIndex: Map<string, number[]>
 
     getContactIndicesForElement(index: StructureElement.UnitIndex, unit: Unit): ReadonlyArray<number> {
-        return this.elementKeyIndex.get(this.getElementKey(index, unit)) || [];
+        return this.elementKeyIndex.get(this.getElementKey(index, unit.id)) || [];
     }
 
-    private getElementKey(index: StructureElement.UnitIndex, unit: Unit): string {
-        return `${index}|${unit.id}`;
+    private getElementKey(index: StructureElement.UnitIndex, unitId: number): string {
+        return `${index}|${unitId}`;
     }
 
-    constructor(map: Map<number, InterUnitGraph.UnitPairEdges<Unit, Features.FeatureIndex, InteractionsInterContacts.Props>[]>, unitsFeatures: IntMap<Features>) {
+    constructor(map: Map<number, InterUnitGraph.UnitPairEdges<number, Features.FeatureIndex, InteractionsInterContacts.Props>[]>, unitsFeatures: IntMap<Features>) {
         super(map);
 
         let count = 0;
         const elementKeyIndex = new Map<string, number[]>();
 
-        const add = (index: StructureElement.UnitIndex, unit: Unit) => {
-            const vertexKey = this.getElementKey(index, unit);
+        const add = (index: StructureElement.UnitIndex, unitId: number) => {
+            const vertexKey = this.getElementKey(index, unitId);
             const e = elementKeyIndex.get(vertexKey);
             if (e === undefined) elementKeyIndex.set(vertexKey, [count]);
             else e.push(count);
@@ -114,13 +114,13 @@ class InteractionsInterContacts extends InterUnitGraph<Unit, Features.FeatureInd
                     pairEdges.getEdges(indexA).forEach(edgeInfo => {
                         const { unitA, unitB } = pairEdges;
 
-                        const { offsets: offsetsA, members: membersA } = unitsFeatures.get(unitA.id);
+                        const { offsets: offsetsA, members: membersA } = unitsFeatures.get(unitA);
                         for (let j = offsetsA[indexA], jl = offsetsA[indexA + 1]; j < jl; ++j) {
                             add(membersA[j], unitA);
                         }
 
                         const { indexB } = edgeInfo;
-                        const { offsets: offsetsB, members: membersB } = unitsFeatures.get(unitB.id);
+                        const { offsets: offsetsB, members: membersB } = unitsFeatures.get(unitB);
                         for (let j = offsetsB[indexB], jl = offsetsB[indexB + 1]; j < jl; ++j) {
                             add(membersB[j], unitB);
                         }

+ 2 - 2
src/mol-model-props/computed/interactions/contacts-builder.ts

@@ -64,11 +64,11 @@ interface InterContactsBuilder {
 
 namespace InterContactsBuilder {
     export function create(): InterContactsBuilder {
-        const builder = new InterUnitGraph.Builder<Unit, Features.FeatureIndex, InteractionsInterContacts.Props>();
+        const builder = new InterUnitGraph.Builder<number, Features.FeatureIndex, InteractionsInterContacts.Props>();
 
         return {
             startUnitPair(unitA: Unit, unitB: Unit) {
-                builder.startUnitPair(unitA, unitB);
+                builder.startUnitPair(unitA.id, unitB.id);
             },
             finishUnitPair() {
                 builder.finishUnitPair();

+ 1 - 1
src/mol-model-props/computed/interactions/interactions.ts

@@ -80,7 +80,7 @@ namespace Interactions {
             const idx = contacts.getDirectedEdgeIndex(indexA, indexB);
             return interactionTypeLabel(contacts.edgeProps.type[idx]);
         } else {
-            const idx = contacts.getEdgeIndex(indexA, unitA, indexB, unitB);
+            const idx = contacts.getEdgeIndex(indexA, unitA.id, indexB, unitB.id);
             return interactionTypeLabel(contacts.edges[idx].props.type);
         }
     }

+ 6 - 4
src/mol-model-props/computed/interactions/refine.ts

@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ * Copyright (c) 2019-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
  *
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
  *
@@ -31,10 +31,12 @@ export function refineInteractions(structure: Structure, interactions: Interacti
 
     for (let i = 0, il = contacts.edgeCount; i < il; ++i) {
         const e = contacts.edges[i];
+        const uA = structure.unitMap.get(e.unitA) as Unit.Atomic;
+        const uB = structure.unitMap.get(e.unitB) as Unit.Atomic;
 
-        const infoA = Features.Info(structure, e.unitA as Unit.Atomic, unitsFeatures.get(e.unitA.id));
+        const infoA = Features.Info(structure, uA, unitsFeatures.get(e.unitA));
         infoA.feature = e.indexA;
-        const infoB = Features.Info(structure, e.unitB as Unit.Atomic, unitsFeatures.get(e.unitB.id));
+        const infoB = Features.Info(structure, uB, unitsFeatures.get(e.unitB));
         infoB.feature = e.indexB;
 
         for (const refiner of contactRefiners) {
@@ -144,7 +146,7 @@ function weakHydrogenBondsRefiner(structure: Structure, interactions: Interactio
         }
 
         // check inter
-        const interIndices = contacts.getEdgeIndices(acc.feature, acc.unit);
+        const interIndices = contacts.getEdgeIndices(acc.feature, acc.unit.id);
         for (let i = 0, il = interIndices.length; i < il; ++i) {
             if (contacts.edges[interIndices[i]].props.type === InteractionType.HydrogenBond) return true;
         }

+ 19 - 15
src/mol-model-props/computed/representations/interactions-inter-unit-cylinder.ts

@@ -38,26 +38,28 @@ function createInterUnitInteractionCylinderMesh(ctx: VisualContext, structure: S
         linkCount: edgeCount,
         position: (posA: Vec3, posB: Vec3, edgeIndex: number) => {
             const { unitA, indexA, unitB, indexB } = edges[edgeIndex];
-            const fA = unitsFeatures.get(unitA.id);
-            const fB = unitsFeatures.get(unitB.id);
+            const fA = unitsFeatures.get(unitA);
+            const fB = unitsFeatures.get(unitB);
+            const uA = structure.unitMap.get(unitA);
+            const uB = structure.unitMap.get(unitB);
 
             Vec3.set(posA, fA.x[indexA], fA.y[indexA], fA.z[indexA]);
-            Vec3.transformMat4(posA, posA, unitA.conformation.operator.matrix);
+            Vec3.transformMat4(posA, posA, uA.conformation.operator.matrix);
 
             Vec3.set(posB, fB.x[indexB], fB.y[indexB], fB.z[indexB]);
-            Vec3.transformMat4(posB, posB, unitB.conformation.operator.matrix);
+            Vec3.transformMat4(posB, posB, uB.conformation.operator.matrix);
         },
         style: (edgeIndex: number) => LinkStyle.Dashed,
         radius: (edgeIndex: number) => {
             const b = edges[edgeIndex];
-            const fA = unitsFeatures.get(b.unitA.id);
+            const fA = unitsFeatures.get(b.unitA);
             tmpLoc.structure = structure;
-            tmpLoc.unit = b.unitA;
-            tmpLoc.element = b.unitA.elements[fA.members[fA.offsets[b.indexA]]];
+            tmpLoc.unit = structure.unitMap.get(b.unitA);
+            tmpLoc.element = tmpLoc.unit.elements[fA.members[fA.offsets[b.indexA]]];
             const sizeA = theme.size.size(tmpLoc);
-            const fB = unitsFeatures.get(b.unitB.id);
-            tmpLoc.unit = b.unitB;
-            tmpLoc.element = b.unitB.elements[fB.members[fB.offsets[b.indexB]]];
+            const fB = unitsFeatures.get(b.unitB);
+            tmpLoc.unit = structure.unitMap.get(b.unitB);
+            tmpLoc.element = tmpLoc.unit.elements[fB.members[fB.offsets[b.indexB]]];
             const sizeB = theme.size.size(tmpLoc);
             return Math.min(sizeA, sizeB) * sizeFactor;
         },
@@ -102,9 +104,11 @@ function getInteractionLoci(pickingId: PickingId, structure: Structure, id: numb
     if (id === objectId) {
         const interactions = InteractionsProvider.get(structure).value!;
         const c = interactions.contacts.edges[groupId];
+        const unitA = structure.unitMap.get(c.unitA);
+        const unitB = structure.unitMap.get(c.unitB);
         return Interactions.Loci(structure, interactions, [
-            { unitA: c.unitA, indexA: c.indexA, unitB: c.unitB, indexB: c.indexB },
-            { unitA: c.unitB, indexA: c.indexB, unitB: c.unitA, indexB: c.indexA },
+            { unitA: unitA, indexA: c.indexA, unitB: unitB, indexB: c.indexB },
+            { unitA: unitB, indexA: c.indexB, unitB: unitA, indexB: c.indexA },
         ]);
     }
     return EmptyLoci;
@@ -119,7 +123,7 @@ function eachInteraction(loci: Loci, structure: Structure, apply: (interval: Int
         const { contacts } = interactions;
 
         for (const c of loci.elements) {
-            const idx = contacts.getEdgeIndex(c.indexA, c.unitA, c.indexB, c.unitB);
+            const idx = contacts.getEdgeIndex(c.indexA, c.unitA.id, c.indexB, c.unitB.id);
             if (idx !== -1) {
                 if (apply(Interval.ofSingleton(idx))) changed = true;
             }
@@ -137,9 +141,9 @@ function createInteractionsIterator(structure: Structure): LocationIterator {
     const { element } = location;
     const getLocation = (groupIndex: number) => {
         const c = contacts.edges[groupIndex];
-        element.unitA = c.unitA;
+        element.unitA = structure.unitMap.get(c.unitA);
         element.indexA = c.indexA;
-        element.unitB = c.unitB;
+        element.unitB = structure.unitMap.get(c.unitB);
         element.indexB = c.indexB;
         return location;
     };

+ 1 - 1
src/mol-model-props/computed/themes/interaction-type.ts

@@ -86,7 +86,7 @@ export function InteractionTypeColorTheme(ctx: ThemeDataContext, props: PD.Value
                     const idx = links.getDirectedEdgeIndex(indexA, indexB);
                     return typeColor(links.edgeProps.type[idx]);
                 } else {
-                    const idx = contacts.getEdgeIndex(indexA, unitA, indexB, unitB);
+                    const idx = contacts.getEdgeIndex(indexA, unitA.id, indexB, unitB.id);
                     return typeColor(contacts.edges[idx].props.type);
                 }
             }

+ 4 - 3
src/mol-model/structure/query/queries/filters.ts

@@ -249,7 +249,7 @@ function checkConnected(ctx: IsConnectedToCtx, structure: Structure) {
         const inputUnit = input.unitMap.get(unit.id) as Unit.Atomic;
 
         const { offset, b, edgeProps: { flags, order } } = inputUnit.bonds;
-        const bondedUnits = interBonds.getConnectedUnits(unit);
+        const bondedUnits = interBonds.getConnectedUnits(unit.id);
         const buCount = bondedUnits.length;
 
         const srcElements = unit.elements;
@@ -278,11 +278,12 @@ function checkConnected(ctx: IsConnectedToCtx, structure: Structure) {
 
             for (let li = 0; li < buCount; li++) {
                 const lu = bondedUnits[li];
-                const bElements = lu.unitB.elements;
+                const bUnit = structure.unitMap.get(lu.unitB) as Unit.Atomic;
+                const bElements = bUnit.elements;
                 const bonds = lu.getEdges(inputIndex);
                 for (let bi = 0, _bi = bonds.length; bi < _bi; bi++) {
                     const bond = bonds[bi];
-                    atomicBond.b.unit = lu.unitB;
+                    atomicBond.b.unit = bUnit;
                     atomicBond.b.element = bElements[bond.indexB];
                     if (!target.hasElement(atomicBond.b)) continue;
                     if (disjunct && structure.hasElement(atomicBond.b)) continue;

+ 4 - 4
src/mol-model/structure/query/queries/generators.ts

@@ -332,11 +332,11 @@ export function bondedAtomicPairs(bondTest?: QueryPredicate): StructureQuery {
 
         // Process inter unit bonds
         for (const bond of interBonds.edges) {
-            atomicBond.a.unit = bond.unitA;
-            atomicBond.a.element = bond.unitA.elements[bond.indexA];
+            atomicBond.a.unit = structure.unitMap.get(bond.unitA) as Unit.Atomic;
+            atomicBond.a.element = atomicBond.a.unit.elements[bond.indexA];
             atomicBond.aIndex = bond.indexA;
-            atomicBond.b.unit = bond.unitB;
-            atomicBond.b.element = bond.unitB.elements[bond.indexB];
+            atomicBond.b.unit = structure.unitMap.get(bond.unitA) as Unit.Atomic;
+            atomicBond.b.element = atomicBond.b.unit.elements[bond.indexB];
             atomicBond.bIndex = bond.indexB;
             atomicBond.order = bond.props.order;
             atomicBond.type = bond.props.flag;

+ 8 - 7
src/mol-model/structure/query/queries/modifiers.ts

@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2017 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ * Copyright (c) 2017-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
  *
  * @author David Sehnal <david.sehnal@gmail.com>
  */
@@ -390,30 +390,31 @@ function expandConnected(ctx: QueryContext, structure: Structure) {
         }
 
         // Process inter unit bonds
-        for (const bondedUnit of interBonds.getConnectedUnits(inputUnitA)) {
-            const currentUnitB = structure.unitMap.get(bondedUnit.unitB.id);
+        for (const bondedUnit of interBonds.getConnectedUnits(inputUnitA.id)) {
+            const currentUnitB = structure.unitMap.get(bondedUnit.unitB);
+            const inputUnitB = inputStructure.unitMap.get(bondedUnit.unitB) as Unit.Atomic;
 
             for (const aI of bondedUnit.connectedIndices) {
                 // check if the element is in the expanded structure
                 if (!SortedArray.has(unit.elements, inputUnitA.elements[aI])) continue;
 
                 for (const bond of bondedUnit.getEdges(aI)) {
-                    const bElement = bondedUnit.unitB.elements[bond.indexB];
+                    const bElement = inputUnitB.elements[bond.indexB];
 
                     // Check if the element is already present:
-                    if ((currentUnitB && SortedArray.has(currentUnitB.elements, bElement)) || builder.has(bondedUnit.unitB.id, bElement)) continue;
+                    if ((currentUnitB && SortedArray.has(currentUnitB.elements, bElement)) || builder.has(bondedUnit.unitB, bElement)) continue;
 
                     atomicBond.a.unit = inputUnitA;
                     atomicBond.aIndex = aI;
                     atomicBond.a.element = inputUnitA.elements[aI];
-                    atomicBond.b.unit = bondedUnit.unitB;
+                    atomicBond.b.unit = inputUnitB;
                     atomicBond.bIndex = bond.indexB;
                     atomicBond.b.element = bElement;
                     atomicBond.type = bond.props.flag;
                     atomicBond.order = bond.props.order;
 
                     if (atomicBond.test(ctx, true)) {
-                        builder.addToUnit(bondedUnit.unitB.id, bElement);
+                        builder.addToUnit(bondedUnit.unitB, bElement);
                     }
                 }
             }

+ 3 - 2
src/mol-model/structure/structure/carbohydrates/compute.ts

@@ -269,12 +269,13 @@ export function computeCarbohydrates(structure: Structure): Carbohydrates {
         const unit = structure.units[i];
         if (!Unit.isAtomic(unit)) continue;
 
-        structure.interUnitBonds.getConnectedUnits(unit).forEach(pairBonds => {
+        structure.interUnitBonds.getConnectedUnits(unit.id).forEach(pairBonds => {
             pairBonds.connectedIndices.forEach(indexA => {
                 pairBonds.getEdges(indexA).forEach(({ props, indexB }) => {
                     if (!BondType.isCovalent(props.flag)) return;
 
-                    const { unitA, unitB } = pairBonds;
+                    const unitA = structure.unitMap.get(pairBonds.unitA) as Unit.Atomic;
+                    const unitB = structure.unitMap.get(pairBonds.unitB) as Unit.Atomic;
                     const ringElementIndicesA = getRingElementIndices(unitA, indexA);
                     const ringElementIndicesB = getRingElementIndices(unitB, indexB);
                     if (ringElementIndicesA.length > 0 && ringElementIndicesB.length > 0) {

+ 1 - 1
src/mol-model/structure/structure/structure.ts

@@ -1077,7 +1077,7 @@ namespace Structure {
         for (const unit of structure.units) {
             if (!validUnit(unit)) continue;
 
-            const bs = unit.lookup3d.boundary.sphere;
+            const bs = unit.boundary.sphere;
             Vec3.transformMat4(imageCenter, bs.center, unit.conformation.operator.matrix);
             const closeUnits = lookup.findUnitIndices(imageCenter[0], imageCenter[1], imageCenter[2], bs.radius + maxRadius);
             for (let i = 0; i < closeUnits.count; i++) {

+ 2 - 2
src/mol-model/structure/structure/unit/bonds.ts

@@ -199,7 +199,7 @@ namespace Bond {
             this.unit = unit;
             this.index = index;
 
-            this.interBondIndices = structure.interUnitBonds.getEdgeIndices(index, unit);
+            this.interBondIndices = structure.interUnitBonds.getEdgeIndices(index, unit.id);
             this.interBondCount = this.interBondIndices.length;
             this.interBondIndex = 0;
 
@@ -218,7 +218,7 @@ namespace Bond {
                 this.intraBondIndex += 1;
             } else if (this.interBondIndex < this.interBondCount) {
                 const b = this.structure.interUnitBonds.edges[this.interBondIndex];
-                this.current.otherUnit = b.unitA !== this.unit ? b.unitA : b.unitB;
+                this.current.otherUnit = this.structure.unitMap.get(b.unitA !== this.unit.id ? b.unitA : b.unitB) as Unit.Atomic;
                 this.current.otherIndex = b.indexA !== this.index ? b.indexA : b.indexB;
                 this.current.type = b.props.flag;
                 this.current.order = b.props.order;

+ 5 - 5
src/mol-model/structure/structure/unit/bonds/data.ts

@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2017-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ * Copyright (c) 2017-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
  *
  * @author David Sehnal <david.sehnal@gmail.com>
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
@@ -20,20 +20,20 @@ namespace IntraUnitBonds {
 
 type InterUnitEdgeProps = { readonly order: number, readonly flag: BondType.Flag }
 
-class InterUnitBonds extends InterUnitGraph<Unit.Atomic, StructureElement.UnitIndex, InterUnitEdgeProps> {
+class InterUnitBonds extends InterUnitGraph<number, StructureElement.UnitIndex, InterUnitEdgeProps> {
     /** Get inter-unit bond given a bond-location */
     getBondFromLocation(l: Bond.Location) {
-        return Unit.isAtomic(l.aUnit) && Unit.isAtomic(l.bUnit) ? this.getEdge(l.aIndex, l.aUnit, l.bIndex, l.bUnit) : undefined;
+        return Unit.isAtomic(l.aUnit) && Unit.isAtomic(l.bUnit) ? this.getEdge(l.aIndex, l.aUnit.id, l.bIndex, l.bUnit.id) : undefined;
     }
 
     /** Get inter-unit bond index given a bond-location */
     getBondIndexFromLocation(l: Bond.Location) {
-        return Unit.isAtomic(l.aUnit) && Unit.isAtomic(l.bUnit) ? this.getEdgeIndex(l.aIndex, l.aUnit, l.bIndex, l.bUnit) : -1;
+        return Unit.isAtomic(l.aUnit) && Unit.isAtomic(l.bUnit) ? this.getEdgeIndex(l.aIndex, l.aUnit.id, l.bIndex, l.bUnit.id) : -1;
     }
 }
 
 namespace InterUnitBonds {
-    export class UnitPairBonds extends InterUnitGraph.UnitPairEdges<Unit.Atomic, StructureElement.UnitIndex, InterUnitEdgeProps> {}
+    export class UnitPairBonds extends InterUnitGraph.UnitPairEdges<number, StructureElement.UnitIndex, InterUnitEdgeProps> {}
     export type BondInfo = InterUnitGraph.EdgeInfo<StructureElement.UnitIndex, InterUnitEdgeProps>
 }
 

+ 3 - 3
src/mol-model/structure/structure/unit/bonds/inter-compute.ts

@@ -33,7 +33,7 @@ function getDistance(unitA: Unit.Atomic, indexA: ElementIndex, unitB: Unit.Atomi
 const _imageTransform = Mat4();
 const _imageA = Vec3();
 
-function findPairBonds(unitA: Unit.Atomic, unitB: Unit.Atomic, props: BondComputationProps, builder: InterUnitGraph.Builder<Unit.Atomic, StructureElement.UnitIndex, InterUnitEdgeProps>) {
+function findPairBonds(unitA: Unit.Atomic, unitB: Unit.Atomic, props: BondComputationProps, builder: InterUnitGraph.Builder<number, StructureElement.UnitIndex, InterUnitEdgeProps>) {
     const { elements: atomsA, residueIndex: residueIndexA } = unitA;
     const { x: xA, y: yA, z: zA } = unitA.model.atomicConformation;
     const { elements: atomsB, residueIndex: residueIndexB } = unitB;
@@ -58,7 +58,7 @@ function findPairBonds(unitA: Unit.Atomic, unitB: Unit.Atomic, props: BondComput
     const { center: bCenter, radius: bRadius } = unitB.boundary.sphere;
     const testDistanceSq = (bRadius + MAX_RADIUS) * (bRadius + MAX_RADIUS);
 
-    builder.startUnitPair(unitA, unitB);
+    builder.startUnitPair(unitA.id, unitB.id);
 
     for (let _aI = 0 as StructureElement.UnitIndex; _aI < atomCount; _aI++) {
         const aI = atomsA[_aI];
@@ -171,7 +171,7 @@ export interface InterBondComputationProps extends BondComputationProps {
 }
 
 function findBonds(structure: Structure, props: InterBondComputationProps) {
-    const builder = new InterUnitGraph.Builder<Unit.Atomic, StructureElement.UnitIndex, InterUnitEdgeProps>();
+    const builder = new InterUnitGraph.Builder<number, StructureElement.UnitIndex, InterUnitEdgeProps>();
 
     if (props.noCompute) {
         // TODO add function that only adds bonds defined in structConn and avoids using

+ 17 - 12
src/mol-repr/structure/visual/bond-inter-unit-cylinder.ts

@@ -42,14 +42,18 @@ function createInterUnitBondCylinderMesh(ctx: VisualContext, structure: Structur
         linkCount: edgeCount,
         referencePosition: (edgeIndex: number) => {
             const b = edges[edgeIndex];
-            let unitA: Unit, unitB: Unit;
+            let unitA: Unit.Atomic, unitB: Unit.Atomic;
             let indexA: StructureElement.UnitIndex, indexB: StructureElement.UnitIndex;
-            if (b.unitA.id < b.unitB.id) {
-                unitA = b.unitA, unitB = b.unitB;
-                indexA = b.indexA, indexB = b.indexB;
-            } else if (b.unitA.id > b.unitB.id) {
-                unitA = b.unitB, unitB = b.unitA;
-                indexA = b.indexB, indexB = b.indexA;
+            if (b.unitA < b.unitB) {
+                unitA = structure.unitMap.get(b.unitA) as Unit.Atomic;
+                unitB = structure.unitMap.get(b.unitB) as Unit.Atomic;
+                indexA = b.indexA;
+                indexB = b.indexB;
+            } else if (b.unitA > b.unitB) {
+                unitA = structure.unitMap.get(b.unitB) as Unit.Atomic;
+                unitB = structure.unitMap.get(b.unitA) as Unit.Atomic;
+                indexA = b.indexB;
+                indexB = b.indexA;
             } else {
                 throw new Error('same units in createInterUnitBondCylinderMesh');
             }
@@ -57,7 +61,8 @@ function createInterUnitBondCylinderMesh(ctx: VisualContext, structure: Structur
         },
         position: (posA: Vec3, posB: Vec3, edgeIndex: number) => {
             const b = edges[edgeIndex];
-            const uA = b.unitA, uB = b.unitB;
+            const uA = structure.unitMap.get(b.unitA);
+            const uB = structure.unitMap.get(b.unitB);
             uA.conformation.position(uA.elements[b.indexA], posA);
             uB.conformation.position(uB.elements[b.indexB], posB);
         },
@@ -78,11 +83,11 @@ function createInterUnitBondCylinderMesh(ctx: VisualContext, structure: Structur
         radius: (edgeIndex: number) => {
             const b = edges[edgeIndex];
             tmpLoc.structure = structure;
-            tmpLoc.unit = b.unitA;
-            tmpLoc.element = b.unitA.elements[b.indexA];
+            tmpLoc.unit = structure.unitMap.get(b.unitA);
+            tmpLoc.element = tmpLoc.unit.elements[b.indexA];
             const sizeA = theme.size.size(tmpLoc);
-            tmpLoc.unit = b.unitB;
-            tmpLoc.element = b.unitB.elements[b.indexB];
+            tmpLoc.unit = structure.unitMap.get(b.unitB);
+            tmpLoc.element = tmpLoc.unit.elements[b.indexB];
             const sizeB = theme.size.size(tmpLoc);
             return Math.min(sizeA, sizeB) * sizeFactor * sizeAspectRatio;
         },

+ 18 - 13
src/mol-repr/structure/visual/bond-inter-unit-line.ts

@@ -42,22 +42,27 @@ function createInterUnitBondLines(ctx: VisualContext, structure: Structure, them
         linkCount: edgeCount,
         referencePosition: (edgeIndex: number) => {
             const b = edges[edgeIndex];
-            let unitA: Unit, unitB: Unit;
+            let unitA: Unit.Atomic, unitB: Unit.Atomic;
             let indexA: StructureElement.UnitIndex, indexB: StructureElement.UnitIndex;
-            if (b.unitA.id < b.unitB.id) {
-                unitA = b.unitA, unitB = b.unitB;
-                indexA = b.indexA, indexB = b.indexB;
-            } else if (b.unitA.id > b.unitB.id) {
-                unitA = b.unitB, unitB = b.unitA;
-                indexA = b.indexB, indexB = b.indexA;
+            if (b.unitA < b.unitB) {
+                unitA = structure.unitMap.get(b.unitA) as Unit.Atomic;
+                unitB = structure.unitMap.get(b.unitB) as Unit.Atomic;
+                indexA = b.indexA;
+                indexB = b.indexB;
+            } else if (b.unitA > b.unitB) {
+                unitA = structure.unitMap.get(b.unitB) as Unit.Atomic;
+                unitB = structure.unitMap.get(b.unitA) as Unit.Atomic;
+                indexA = b.indexB;
+                indexB = b.indexA;
             } else {
-                throw new Error('same units in createInterUnitBondCylinderMesh');
+                throw new Error('same units in createInterUnitBondLines');
             }
             return setRefPosition(tmpRef, structure, unitA, indexA) || setRefPosition(tmpRef, structure, unitB, indexB);
         },
         position: (posA: Vec3, posB: Vec3, edgeIndex: number) => {
             const b = edges[edgeIndex];
-            const uA = b.unitA, uB = b.unitB;
+            const uA = structure.unitMap.get(b.unitA);
+            const uB = structure.unitMap.get(b.unitB);
             uA.conformation.position(uA.elements[b.indexA], posA);
             uB.conformation.position(uB.elements[b.indexB], posB);
         },
@@ -78,11 +83,11 @@ function createInterUnitBondLines(ctx: VisualContext, structure: Structure, them
         radius: (edgeIndex: number) => {
             const b = edges[edgeIndex];
             tmpLoc.structure = structure;
-            tmpLoc.unit = b.unitA;
-            tmpLoc.element = b.unitA.elements[b.indexA];
+            tmpLoc.unit = structure.unitMap.get(b.unitA);
+            tmpLoc.element = tmpLoc.unit.elements[b.indexA];
             const sizeA = theme.size.size(tmpLoc);
-            tmpLoc.unit = b.unitB;
-            tmpLoc.element = b.unitB.elements[b.indexB];
+            tmpLoc.unit = structure.unitMap.get(b.unitB);
+            tmpLoc.element = tmpLoc.unit.elements[b.indexB];
             const sizeB = theme.size.size(tmpLoc);
             return Math.min(sizeA, sizeB) * sizeFactor;
         },

+ 12 - 15
src/mol-repr/structure/visual/util/bond.ts

@@ -78,7 +78,8 @@ export function makeInterBondIgnoreTest(structure: Structure, props: BondProps):
 
     const ignoreHydrogen = (edgeIndex: number) => {
         const b = edges[edgeIndex];
-        const uA = b.unitA, uB = b.unitB;
+        const uA = structure.unitMap.get(b.unitA);
+        const uB = structure.unitMap.get(b.unitB);
         return isHydrogen(uA, uA.elements[b.indexA]) || isHydrogen(uB, uB.elements[b.indexB]);
     };
 
@@ -113,8 +114,8 @@ export namespace BondIterator {
         const location = StructureElement.Location.create(structure);
         const getLocation = (groupIndex: number) => {
             const bond = structure.interUnitBonds.edges[groupIndex];
-            location.unit = bond.unitA;
-            location.element = bond.unitA.elements[bond.indexA];
+            location.unit = structure.unitMap.get(bond.unitA);
+            location.element = location.unit.elements[bond.indexA];
             return location;
         };
         return LocationIterator(groupCount, instanceCount, getLocation, true);
@@ -189,16 +190,12 @@ export function eachIntraBond(loci: Loci, structureGroup: StructureGroup, apply:
 export function getInterBondLoci(pickingId: PickingId, structure: Structure, id: number) {
     const { objectId, groupId } = pickingId;
     if (id === objectId) {
-        const bond = structure.interUnitBonds.edges[groupId];
+        const b = structure.interUnitBonds.edges[groupId];
+        const uA = structure.unitMap.get(b.unitA);
+        const uB = structure.unitMap.get(b.unitB);
         return Bond.Loci(structure, [
-            Bond.Location(
-                structure, bond.unitA, bond.indexA as StructureElement.UnitIndex,
-                structure, bond.unitB, bond.indexB as StructureElement.UnitIndex
-            ),
-            Bond.Location(
-                structure, bond.unitB, bond.indexB as StructureElement.UnitIndex,
-                structure, bond.unitA, bond.indexA as StructureElement.UnitIndex
-            )
+            Bond.Location(structure, uA, b.indexA, structure, uB, b.indexB),
+            Bond.Location(structure, uB, b.indexB, structure, uA, b.indexA)
         ]);
     }
     return EmptyLoci;
@@ -224,14 +221,14 @@ export function eachInterBond(loci: Loci, structure: Structure, apply: (interval
         for (const e of loci.elements) {
             const { unit } = e;
             if (!Unit.isAtomic(unit)) continue;
-            structure.interUnitBonds.getConnectedUnits(unit).forEach(b => {
-                const otherLociIndices = map.get(b.unitB.id);
+            structure.interUnitBonds.getConnectedUnits(unit.id).forEach(b => {
+                const otherLociIndices = map.get(b.unitB);
                 if (otherLociIndices) {
                     OrderedSet.forEach(e.indices, v => {
                         if (!b.connectedIndices.includes(v)) return;
                         b.getEdges(v).forEach(bi => {
                             if (!isMarking || OrderedSet.has(otherLociIndices, bi.indexB)) {
-                                const idx = structure.interUnitBonds.getEdgeIndex(v, unit, bi.indexB, b.unitB);
+                                const idx = structure.interUnitBonds.getEdgeIndex(v, unit.id, bi.indexB, b.unitB);
                                 if (apply(Interval.ofSingleton(idx))) changed = true;
                             }
                         });