Browse Source

add index-pair bond provider

Alexander Rose 5 years ago
parent
commit
31e2cc5f07

+ 69 - 0
src/mol-model-formats/structure/mmcif/bonds/index-pair.ts

@@ -0,0 +1,69 @@
+/**
+ * Copyright (c) 2019 Mol* contributors, licensed under MIT, See LICENSE file for more info.
+ *
+ * @author Alexander Rose <alexander.rose@weirdbyte.de>
+ */
+
+import { Model } from '../../../../mol-model/structure/model/model'
+import { CustomPropertyDescriptor } from '../../../../mol-model/structure';
+import { IntAdjacencyGraph } from '../../../../mol-math/graph';
+import { Column } from '../../../../mol-data/db';
+
+export type IndexPairBonds = IntAdjacencyGraph<number, { readonly order: ArrayLike<number> }>
+
+function getGraph(indexA: ArrayLike<number>, indexB: ArrayLike<number>, _order: ArrayLike<number>, count: number): IndexPairBonds {
+    const builder = new IntAdjacencyGraph.EdgeBuilder(count, indexA, indexB);
+    const order = new Int8Array(builder.slotCount);
+    for (let i = 0, _i = builder.edgeCount; i < _i; i++) {
+        builder.addNextEdge();
+        builder.assignProperty(order, _order[i]);
+    }
+
+    return builder.createGraph({ order });
+}
+
+export namespace IndexPairBonds {
+    export const Descriptor: CustomPropertyDescriptor = {
+        isStatic: true,
+        name: 'index_pair_bonds',
+    }
+
+    export type Data = {
+        pairs: {
+            indexA: Column<number>,
+            indexB: Column<number>
+            order: Column<number>
+        },
+        count: number
+    }
+
+    export function attachFromData(model: Model, data: Data): boolean {
+        if (model.customProperties.has(Descriptor)) return true;
+
+        model.customProperties.add(Descriptor);
+        model._staticPropertyData.__IndexPairBondsData__ = data;
+        return true;
+    }
+
+    function getIndexPairBonds(model: Model) {
+        return model._staticPropertyData.__IndexPairBondsData__ as Data;
+    }
+
+    export const PropName = '__IndexPairBonds__';
+    export function get(model: Model): IndexPairBonds | undefined {
+        if (model._staticPropertyData[PropName]) return model._staticPropertyData[PropName];
+        if (!model.customProperties.has(Descriptor)) return void 0;
+
+        const data = getIndexPairBonds(model);
+        if (!data) return void 0;
+        const { pairs, count } = data
+
+        const indexA = pairs.indexA.toArray()
+        const indexB = pairs.indexB.toArray()
+        const order = pairs.order.toArray()
+
+        const indexPairBonds = getGraph(indexA, indexB, order, count);
+        model._staticPropertyData[PropName] = indexPairBonds;
+        return indexPairBonds;
+    }
+}

+ 0 - 1
src/mol-model-formats/structure/mmcif/bonds/struct_conn.ts

@@ -118,7 +118,6 @@ export namespace StructConn {
             return this._atomIndex;
         }
 
-
         getResidueEntries(residueAIndex: ResidueIndex, residueBIndex: ResidueIndex): ReadonlyArray<StructConn.Entry> {
             return this.getResiduePairIndex().get(_resKey(residueAIndex, residueBIndex)) || _emptyEntry;
         }

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

@@ -17,6 +17,7 @@ import StructureElement from '../../element';
 import { StructConn } from '../../../../../mol-model-formats/structure/mmcif/bonds';
 import { ElementIndex } from '../../../model/indexing';
 import { getInterBondOrderFromTable } from '../../../model/properties/atomic/bonds';
+import { IndexPairBonds } from '../../../../../mol-model-formats/structure/mmcif/bonds/index-pair';
 
 const MAX_RADIUS = 4;
 
@@ -68,6 +69,7 @@ function findPairBonds(unitA: Unit.Atomic, unitB: Unit.Atomic, props: BondComput
 
     const { lookup3d } = unitB;
     const structConn = unitA.model === unitB.model && unitA.model.sourceData.kind === 'mmCIF' ? StructConn.get(unitA.model) : void 0;
+    const indexPairs = unitA.model === unitB.model ? IndexPairBonds.get(unitA.model) : void 0;
 
     // the lookup queries need to happen in the "unitB space".
     // that means imageA = inverseOperB(operA(aI))
@@ -84,6 +86,16 @@ function findPairBonds(unitA: Unit.Atomic, unitB: Unit.Atomic, props: BondComput
         if (isNotIdentity) Vec3.transformMat4(imageA, imageA, imageTransform);
         if (Vec3.squaredDistance(imageA, bCenter) > testDistanceSq) continue;
 
+        if (!props.forceCompute && indexPairs) {
+            for (let i = indexPairs.offset[aI], il = indexPairs.offset[aI + 1]; i < il; ++i) {
+                const _bI = SortedArray.indexOf(unitA.elements, indexPairs.b[i]) as StructureElement.UnitIndex;
+                if (_bI < 0) continue;
+                addBond(_aI, _bI, indexPairs.edgeProps.order[i], BondType.Flag.Covalent, state);
+                bondCount++;
+            }
+            continue // assume `indexPairs` supplies all bonds
+        }
+
         const structConnEntries = props.forceCompute ? void 0 : structConn && structConn.getAtomEntries(aI);
         if (structConnEntries && structConnEntries.length) {
             let added = false;

+ 29 - 16
src/mol-model/structure/structure/unit/bonds/intra-compute.ts

@@ -14,6 +14,7 @@ import { SortedArray } from '../../../../../mol-data/int';
 import { StructConn, ComponentBond } from '../../../../../mol-model-formats/structure/mmcif/bonds';
 import { getIntraBondOrderFromTable } from '../../../model/properties/atomic/bonds';
 import StructureElement from '../../element';
+import { IndexPairBonds } from '../../../../../mol-model-formats/structure/mmcif/bonds/index-pair';
 
 function getGraph(atomA: StructureElement.UnitIndex[], atomB: StructureElement.UnitIndex[], _order: number[], _flags: number[], atomCount: number): IntraUnitBonds {
     const builder = new IntAdjacencyGraph.EdgeBuilder(atomCount, atomA, atomB);
@@ -40,6 +41,7 @@ function _computeBonds(unit: Unit.Atomic, props: BondComputationProps): IntraUni
 
     const structConn = unit.model.sourceData.kind === 'mmCIF' ? StructConn.get(unit.model) : void 0;
     const component = unit.model.sourceData.kind === 'mmCIF' ? ComponentBond.get(unit.model) : void 0;
+    const indexPairs = IndexPairBonds.get(unit.model)
 
     const atomA: StructureElement.UnitIndex[] = [];
     const atomB: StructureElement.UnitIndex[] = [];
@@ -51,6 +53,33 @@ function _computeBonds(unit: Unit.Atomic, props: BondComputationProps): IntraUni
 
     for (let _aI = 0 as StructureElement.UnitIndex; _aI < atomCount; _aI++) {
         const aI =  atoms[_aI];
+
+        if (!props.forceCompute && indexPairs) {
+            for (let i = indexPairs.offset[aI], il = indexPairs.offset[aI + 1]; i < il; ++i) {
+                const _bI = SortedArray.indexOf(unit.elements, indexPairs.b[i]) as StructureElement.UnitIndex;
+                if (_bI < 0) continue;
+                atomA[atomA.length] = _aI;
+                atomB[atomB.length] = _bI;
+                order[order.length] = indexPairs.edgeProps.order[i];
+                flags[flags.length] = BondType.Flag.Covalent;
+            }
+            continue // assume `indexPairs` supplies all bonds
+        }
+
+        const structConnEntries = props.forceCompute ? void 0 : structConn && structConn.getAtomEntries(aI);
+        if (structConnEntries) {
+            for (const se of structConnEntries) {
+                for (const p of se.partners) {
+                    const _bI = SortedArray.indexOf(unit.elements, p.atomIndex) as StructureElement.UnitIndex;
+                    if (_bI < 0) continue;
+                    atomA[atomA.length] = _aI;
+                    atomB[atomB.length] = _bI;
+                    flags[flags.length] = se.flags;
+                    order[order.length] = se.order;
+                }
+            }
+        }
+
         const raI = residueIndex[aI];
         const compId = label_comp_id.value(raI);
 
@@ -72,22 +101,6 @@ function _computeBonds(unit: Unit.Atomic, props: BondComputationProps): IntraUni
         const thresholdA = getElementThreshold(aeI);
         const altA = label_alt_id.value(aI);
         const metalA = MetalsSet.has(aeI);
-        const structConnEntries = props.forceCompute ? void 0 : structConn && structConn.getAtomEntries(aI);
-
-        if (structConnEntries) {
-            for (const se of structConnEntries) {
-                if (se.distance > MAX_RADIUS) continue;
-
-                for (const p of se.partners) {
-                    const _bI = SortedArray.indexOf(unit.elements, p.atomIndex) as StructureElement.UnitIndex;
-                    if (_bI < 0) continue;
-                    atomA[atomA.length] = _aI;
-                    atomB[atomB.length] = _bI;
-                    flags[flags.length] = se.flags;
-                    order[order.length] = se.order;
-                }
-            }
-        }
 
         for (let ni = 0; ni < count; ni++) {
             const _bI = indices[ni];