diff --git a/src/mol-model-props/computed/interactions/hydrogen-bonds.ts b/src/mol-model-props/computed/interactions/hydrogen-bonds.ts
index f6021978c047171c53ed3df3a15e61c76a25db18..37bc77ffc86f158c637861023661a5a4ba680b32 100644
--- a/src/mol-model-props/computed/interactions/hydrogen-bonds.ts
+++ b/src/mol-model-props/computed/interactions/hydrogen-bonds.ts
@@ -68,8 +68,11 @@ function addUnitHydrogenDonors(structure: Structure, unit: Unit.Atomic, builder:
const { totalH } = getUnitValenceModel(structure, unit)
const { elements } = unit
const { x, y, z } = unit.model.atomicConformation
+ const { elementAromaticRingIndices } = unit.rings
for (let i = 0 as StructureElement.UnitIndex, il = elements.length; i < il; ++i) {
+ if (elementAromaticRingIndices.has(i)) continue;
+
const element = typeSymbol(unit, i)
if ((
// include both nitrogen atoms in histidine due to
@@ -99,7 +102,7 @@ function addUnitWeakHydrogenDonors(structure: Structure, unit: Unit.Atomic, buil
(
bondToElementCount(structure, unit, i, Elements.N) > 0 ||
bondToElementCount(structure, unit, i, Elements.O) > 0 ||
- inAromaticRingWithElectronNegativeElement(structure, unit, i)
+ inAromaticRingWithElectronNegativeElement(unit, i)
)
) {
builder.add(FeatureType.WeakHydrogenDonor, FeatureGroup.None, x[elements[i]], y[elements[i]], z[elements[i]], i)
@@ -107,27 +110,21 @@ function addUnitWeakHydrogenDonors(structure: Structure, unit: Unit.Atomic, buil
}
}
-function inAromaticRingWithElectronNegativeElement(structure: Structure, unit: Unit.Atomic, index: StructureElement.UnitIndex) {
- return false // TODO
- // if (!a.isAromatic()) return false
-
- // const ringData = a.residueType.getRings()
- // if (!ringData) return false
-
- // let hasElement = false
- // const rings = ringData.rings
- // rings.forEach(ring => {
- // if (hasElement) return // already found one
- // if (ring.some(idx => (a.index - a.residueAtomOffset) === idx)) { // in ring
- // hasElement = ring.some(idx => {
- // const atomTypeId = a.residueType.atomTypeIdList[ idx ]
- // const number = a.atomMap.get(atomTypeId).number
- // return number === Elements.N || number === Elements.O
- // })
- // }
- // })
-
- // return hasElement
+function inAromaticRingWithElectronNegativeElement(unit: Unit.Atomic, index: StructureElement.UnitIndex) {
+ const { elementAromaticRingIndices, all } = unit.rings
+ const ringIndices = elementAromaticRingIndices.get(index)
+ if (ringIndices === undefined) return false
+
+ for (let i = 0, il = ringIndices.length; i < il; ++i) {
+ const ring = all[ringIndices[i]]
+ for (let j = 0, jl = ring.length; j < jl; ++j) {
+ const element = typeSymbol(unit, ring[j])
+ if (element === Elements.N || element === Elements.O) {
+ return true
+ }
+ }
+ }
+ return false
}
/**
@@ -137,12 +134,15 @@ function addUnitHydrogenAcceptors(structure: Structure, unit: Unit.Atomic, build
const { charge, implicitH, idealGeometry } = getUnitValenceModel(structure, unit)
const { elements } = unit
const { x, y, z } = unit.model.atomicConformation
+ const { elementAromaticRingIndices } = unit.rings
const add = (i: StructureElement.UnitIndex) => {
builder.add(FeatureType.HydrogenAcceptor, FeatureGroup.None, x[elements[i]], y[elements[i]], z[elements[i]], i)
}
for (let i = 0 as StructureElement.UnitIndex, il = elements.length; i < il; ++i) {
+ if (elementAromaticRingIndices.has(i)) continue;
+
const element = typeSymbol(unit, i)
if (element === Elements.O) {
// Basically assume all oxygen atoms are acceptors!
diff --git a/src/mol-model/structure/structure/unit/rings.ts b/src/mol-model/structure/structure/unit/rings.ts
index d9f1024ef8a600fa073247726020ada8b9ccff16..40296716a076b33880557c844ed2193dadeb3192 100644
--- a/src/mol-model/structure/structure/unit/rings.ts
+++ b/src/mol-model/structure/structure/unit/rings.ts
@@ -25,6 +25,7 @@ class UnitRings {
private _byFingerprint?: ReadonlyMap<UnitRing.Fingerprint, ReadonlyArray<UnitRings.Index>>;
private _index?: {
readonly elementRingIndices: ReadonlyMap<StructureElement.UnitIndex, UnitRings.Index[]>,
+ readonly elementAromaticRingIndices: ReadonlyMap<StructureElement.UnitIndex, UnitRings.Index[]>,
readonly ringComponentIndex: ReadonlyArray<UnitRings.ComponentIndex>,
readonly ringComponents: ReadonlyArray<ReadonlyArray<UnitRings.Index>>
};
@@ -32,7 +33,7 @@ class UnitRings {
private get index() {
if (this._index) return this._index;
- this._index = createIndex(this.all);
+ this._index = createIndex(this.all, this.aromaticRings);
return this._index;
}
@@ -42,11 +43,15 @@ class UnitRings {
return this._byFingerprint;
}
- /** Maps atom index inside a Unit to the smallest ring index (an atom can be part of more than one ring) */
+ /** Maps atom index inside a Unit to ring indices (an atom can be part of more than one ring) */
get elementRingIndices() {
return this.index.elementRingIndices;
}
+ get elementAromaticRingIndices() {
+ return this.index.elementAromaticRingIndices;
+ }
+
/** Maps UnitRings.Index to index to ringComponents */
get ringComponentIndex() {
return this.index.ringComponentIndex;
diff --git a/src/mol-model/structure/structure/unit/rings/compute.ts b/src/mol-model/structure/structure/unit/rings/compute.ts
index 177ed65a17098855d5f90be8badd07af9af55a15..db31f0f6900e95aeeb729f0c9e3cafbe9eaaa205 100644
--- a/src/mol-model/structure/structure/unit/rings/compute.ts
+++ b/src/mol-model/structure/structure/unit/rings/compute.ts
@@ -253,8 +253,9 @@ function buildFinderprint(elements: string[], offset: number) {
type RingIndex = import('../rings').UnitRings.Index
type RingComponentIndex = import('../rings').UnitRings.ComponentIndex
-export function createIndex(rings: ArrayLike<SortedArray<StructureElement.UnitIndex>>) {
+export function createIndex(rings: ArrayLike<SortedArray<StructureElement.UnitIndex>>, aromaticRings: ReadonlyArray<RingIndex>) {
const elementRingIndices: Map<StructureElement.UnitIndex, RingIndex[]> = new Map();
+ const elementAromaticRingIndices: Map<StructureElement.UnitIndex, RingIndex[]> = new Map();
// for each ring atom, assign all rings that it is present in
for (let rI = 0 as RingIndex, _rI = rings.length; rI < _rI; rI++) {
@@ -266,6 +267,17 @@ export function createIndex(rings: ArrayLike<SortedArray<StructureElement.UnitIn
}
}
+ // for each ring atom, assign all aromatic rings that it is present in
+ for (let aI = 0, _aI = aromaticRings.length; aI < _aI; aI++) {
+ const rI = aromaticRings[aI]
+ const r = rings[rI];
+ for (let i = 0, _i = r.length; i < _i; i++) {
+ const e = r[i];
+ if (elementAromaticRingIndices.has(e)) elementAromaticRingIndices.get(e)!.push(rI);
+ else elementAromaticRingIndices.set(e, [rI]);
+ }
+ }
+
// create a graph where vertices are rings, edge if two rings share at least one atom
const graph = new IntAdjacencyGraph.UniqueEdgeBuilder(rings.length);
for (let rI = 0 as RingIndex, _rI = rings.length; rI < _rI; rI++) {
@@ -296,5 +308,5 @@ export function createIndex(rings: ArrayLike<SortedArray<StructureElement.UnitIn
ringComponents[ringComponentIndex[rI]].push(rI);
}
- return { elementRingIndices, ringComponentIndex, ringComponents };
+ return { elementRingIndices, elementAromaticRingIndices, ringComponentIndex, ringComponents };
}
\ No newline at end of file