Browse Source

struct_conn refactoring

- explicitely between two partners
- use symmetry in intra-unit compute (important, before there where wrong hbonds in e.g. 1XJ9)
Alexander Rose 5 years ago
parent
commit
94ef9f4dbe

+ 21 - 70
src/mol-model-formats/structure/mmcif/bonds/struct_conn.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>
@@ -18,7 +18,6 @@ import { ElementIndex, ResidueIndex } from '../../../../mol-model/structure/mode
 import { getInterBondOrderFromTable } from '../../../../mol-model/structure/model/properties/atomic/bonds';
 
 export interface StructConn {
-    getResidueEntries(residueAIndex: ResidueIndex, residueBIndex: ResidueIndex): ReadonlyArray<StructConn.Entry>,
     getAtomEntries(atomIndex: ElementIndex): ReadonlyArray<StructConn.Entry>,
     readonly entries: ReadonlyArray<StructConn.Entry>
 }
@@ -38,23 +37,11 @@ export namespace StructConn {
                     const strConn = get(model);
                     if (!strConn || strConn.entries.length === 0) return CifWriter.Category.Empty;
 
-                    const foundAtoms = new Set<ElementIndex>();
                     const indices: number[] = [];
-                    for (const entry of strConn.entries) {
-                        const { partners } = entry;
-                        let hasAll = true;
-                        for (let i = 0, _i = partners.length; i < _i; i++) {
-                            const atom = partners[i].atomIndex;
-                            if (foundAtoms.has(atom)) continue;
-                            if (hasAtom(structure, atom)) {
-                                foundAtoms.add(atom);
-                            } else {
-                                hasAll = false;
-                                break;
-                            }
-                        }
-                        if (hasAll) {
-                            indices[indices.length] = entry.rowIndex;
+                    for (const e of strConn.entries) {
+                        if (hasAtom(structure, e.partnerA.atomIndex) &&
+                                hasAtom(structure, e.partnerB.atomIndex)) {
+                            indices[indices.length] = e.rowIndex;
                         }
                     }
 
@@ -71,56 +58,25 @@ export namespace StructConn {
         return false;
     }
 
-    function _resKey(rA: number, rB: number) {
-        if (rA < rB) return `${rA}-${rB}`;
-        return `${rB}-${rA}`;
-    }
     const _emptyEntry: Entry[] = [];
 
     class StructConnImpl implements StructConn {
-        private _residuePairIndex: Map<string, StructConn.Entry[]> | undefined = void 0;
         private _atomIndex: Map<number, StructConn.Entry[]> | undefined = void 0;
 
-        private getResiduePairIndex() {
-            if (this._residuePairIndex) return this._residuePairIndex;
-            this._residuePairIndex = new Map();
-            for (const e of this.entries) {
-                const ps = e.partners;
-                const l = ps.length;
-                for (let i = 0; i < l - 1; i++) {
-                    for (let j = i + i; j < l; j++) {
-                        const key = _resKey(ps[i].residueIndex, ps[j].residueIndex);
-                        if (this._residuePairIndex.has(key)) {
-                            this._residuePairIndex.get(key)!.push(e);
-                        } else {
-                            this._residuePairIndex.set(key, [e]);
-                        }
-                    }
-                }
-            }
-            return this._residuePairIndex;
-        }
-
         private getAtomIndex() {
             if (this._atomIndex) return this._atomIndex;
-            this._atomIndex = new Map();
+            const m = this._atomIndex = new Map();
             for (const e of this.entries) {
-                for (const p of e.partners) {
-                    const key = p.atomIndex;
-                    if (this._atomIndex.has(key)) {
-                        this._atomIndex.get(key)!.push(e);
-                    } else {
-                        this._atomIndex.set(key, [e]);
-                    }
-                }
+                const { partnerA: { atomIndex: iA }, partnerB: { atomIndex: iB } } = e;
+                if (m.has(iA)) m.get(iA)!.push(e);
+                else m.set(iA, [e]);
+
+                if (m.has(iB)) m.get(iB)!.push(e);
+                else m.set(iB, [e]);
             }
             return this._atomIndex;
         }
 
-        getResidueEntries(residueAIndex: ResidueIndex, residueBIndex: ResidueIndex): ReadonlyArray<StructConn.Entry> {
-            return this.getResiduePairIndex().get(_resKey(residueAIndex, residueBIndex)) || _emptyEntry;
-        }
-
         getAtomEntries(atomIndex: ElementIndex): ReadonlyArray<StructConn.Entry> {
             return this.getAtomIndex().get(atomIndex) || _emptyEntry;
         }
@@ -134,7 +90,8 @@ export namespace StructConn {
         distance: number,
         order: number,
         flags: number,
-        partners: { residueIndex: ResidueIndex, atomIndex: ElementIndex, symmetry: string }[]
+        partnerA: { residueIndex: ResidueIndex, atomIndex: ElementIndex, symmetry: string },
+        partnerB: { residueIndex: ResidueIndex, atomIndex: ElementIndex, symmetry: string }
     }
 
     export function attachFromMmCif(model: Model): boolean {
@@ -193,22 +150,14 @@ export namespace StructConn {
             if (!atomName) return void 0;
             const atomIndex = findAtomIndexByLabelName(model, residueIndex, atomName, ps.label_alt_id.value(row));
             if (atomIndex < 0) return void 0;
-            return { residueIndex, atomIndex, symmetry: ps.symmetry.value(row) || '1_555' };
-        }
-
-        const _ps = (row: number) => {
-            const ret = [];
-            let p = _p(row, p1);
-            if (p) ret.push(p);
-            p = _p(row, p2);
-            if (p) ret.push(p);
-            return ret;
+            return { residueIndex, atomIndex, symmetry: ps.symmetry.value(row) };
         }
 
         const entries: StructConn.Entry[] = [];
         for (let i = 0; i < struct_conn._rowCount; i++) {
-            const partners = _ps(i);
-            if (partners.length < 2) continue;
+            const partnerA = _p(i, p1)
+            const partnerB = _p(i, p2)
+            if (partnerA === undefined || partnerB === undefined) continue;
 
             const type = conn_type_id.value(i)
             const orderType = (pdbx_value_order.value(i) || '').toLowerCase();
@@ -240,7 +189,9 @@ export namespace StructConn {
                 case 'metalc': flags = BondType.Flag.MetallicCoordination; break;
             }
 
-            entries.push({ rowIndex: i, flags, order, distance: pdbx_dist_value.value(i), partners });
+            entries.push({
+                rowIndex: i, flags, order, distance: pdbx_dist_value.value(i), partnerA, partnerB
+            });
         }
 
         const ret = new StructConnImpl(entries);

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

@@ -79,16 +79,16 @@ function findPairBonds(unitA: Unit.Atomic, unitB: Unit.Atomic, props: BondComput
         if (structConnEntries && structConnEntries.length) {
             let added = false;
             for (const se of structConnEntries) {
-                for (const p of se.partners) {
-                    if (aI === p.atomIndex) continue;
-
-                    const _bI = SortedArray.indexOf(unitB.elements, p.atomIndex) as StructureElement.UnitIndex;
-                    if (_bI < 0) continue;
-                    // check if the bond is within MAX_RADIUS for this pair of units
-                    if (getDistance(unitA, aI, unitB, p.atomIndex) > MAX_RADIUS) continue;
-                    builder.add(_aI, _bI, { order: se.order, flag: se.flags });
-                    added = true;
-                }
+                const { partnerA, partnerB } = se
+                const p = partnerA.atomIndex === aI ? partnerB : partnerA
+                const _bI = SortedArray.indexOf(unitB.elements, p.atomIndex) as StructureElement.UnitIndex;
+                if (_bI < 0) continue;
+
+                // check if the bond is within MAX_RADIUS for this pair of units
+                if (getDistance(unitA, aI, unitB, p.atomIndex) > MAX_RADIUS) continue;
+
+                builder.add(_aI, _bI, { order: se.order, flag: se.flags });
+                added = true;
             }
             // assume, for an atom, that if any inter unit bond is given
             // all are given and thus we don't need to compute any other

+ 15 - 13
src/mol-model/structure/structure/unit/bonds/intra-compute.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>
@@ -74,20 +74,22 @@ function _computeBonds(unit: Unit.Atomic, props: BondComputationProps): IntraUni
         let hasStructConn = false;
         if (structConnEntries) {
             for (const se of structConnEntries) {
-                for (const p of se.partners) {
-                    if (aI === p.atomIndex) continue;
+                const { partnerA, partnerB } = se
+                // symmetry must be the same for intra-unit bonds
+                if (partnerA.symmetry !== partnerB.symmetry) continue
 
-                    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 p = partnerA.atomIndex === aI ? partnerB : partnerA
+                const _bI = SortedArray.indexOf(unit.elements, p.atomIndex) as StructureElement.UnitIndex;
+                if (_bI < 0) continue;
 
-                    if (!hasStructConn) structConnAdded.clear();
-                    hasStructConn = true;
-                    structConnAdded.add(_bI);
-                }
+                atomA[atomA.length] = _aI;
+                atomB[atomB.length] = _bI;
+                flags[flags.length] = se.flags;
+                order[order.length] = se.order;
+
+                if (!hasStructConn) structConnAdded.clear();
+                hasStructConn = true;
+                structConnAdded.add(_bI);
             }
         }