From 6c99c575bc0fd1c700b6e83cb39e1c79356f38a2 Mon Sep 17 00:00:00 2001 From: Alexander Rose Date: Thu, 26 Mar 2026 16:23:32 -0700 Subject: [PATCH] Handle CCD bonds with Deuterium atoms --- CHANGELOG.md | 1 + docs/docs/misc/interesting-pdb-entries.md | 5 ++++- .../structure/unit/bonds/intra-compute.ts | 17 ++++++++++++----- 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2ff79950a..25cec5952 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,7 @@ Note that since we don't clearly distinguish between a public and private interf - MolViewSpec - Add `VolumeStreamingExtension` (`molstar_volume_streaming` custom property) - Fix focusing empty selections +- Handle CCD bonds with Deuterium atoms ## [v5.7.0] - 2026-02-28 - Text label improvements diff --git a/docs/docs/misc/interesting-pdb-entries.md b/docs/docs/misc/interesting-pdb-entries.md index 8e5412bc6..2f7671b67 100644 --- a/docs/docs/misc/interesting-pdb-entries.md +++ b/docs/docs/misc/interesting-pdb-entries.md @@ -48,4 +48,7 @@ * CLR (e.g. 3GKI) - four fused rings * Assembly symmetries * 5M30 (Assembly 1, C3 local and pseudo) - * 1RB8 (Assembly 1, I global) \ No newline at end of file + * 1RB8 (Assembly 1, I global) +* Deuterium atoms + * 3CWH (XUL with D and DOD) + * 8TT8 (HOH and other with D) \ No newline at end of file diff --git a/src/mol-model/structure/structure/unit/bonds/intra-compute.ts b/src/mol-model/structure/structure/unit/bonds/intra-compute.ts index 8c0036a15..5302b0f4b 100644 --- a/src/mol-model/structure/structure/unit/bonds/intra-compute.ts +++ b/src/mol-model/structure/structure/unit/bonds/intra-compute.ts @@ -1,5 +1,5 @@ /** - * Copyright (c) 2017-2025 Mol* contributors, licensed under MIT, See LICENSE file for more info. + * Copyright (c) 2017-2026 Mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author David Sehnal * @author Alexander Rose @@ -213,11 +213,14 @@ function findBonds(unit: Unit.Atomic, props: BondComputationProps): IntraUnitBon lastResidue = raI; const aeI = getElementIdx(elemA); - const atomIdA = label_atom_id.value(aI); + const isHa = isHydrogen(aeI); + let atomIdA = label_atom_id.value(aI); + if (isHa && atomIdA.startsWith('D') && compId !== 'DOD') { + atomIdA = 'H' + atomIdA.substring(1); + } const componentPairs = componentMap ? componentMap.get(atomIdA) : void 0; const { indices, count, squaredDistances } = query3d.find(x[aI], y[aI], z[aI], maxRadius); - const isHa = isHydrogen(aeI); const thresholdA = getElementThreshold(aeI); const altA = label_alt_id.value(aI); const metalA = MetalsSet.has(aeI); @@ -248,7 +251,11 @@ function findBonds(unit: Unit.Atomic, props: BondComputationProps): IntraUnitBon const rbI = residueIndex[bI]; // handle "component dictionary" bonds. if (raI === rbI && componentPairs) { - const e = componentPairs.get(label_atom_id.value(bI)!); + let atomIdB = label_atom_id.value(bI)!; + if (isHb && atomIdB.startsWith('D') && compId !== 'DOD') { + atomIdB = 'H' + atomIdB.substring(1); + } + const e = componentPairs.get(atomIdB); if (e) { atomA[atomA.length] = _aI; atomB[atomB.length] = _bI; @@ -284,7 +291,7 @@ function findBonds(unit: Unit.Atomic, props: BondComputationProps): IntraUnitBon if (flag) { atomA[atomA.length] = _aI; atomB[atomB.length] = _bI; - order[order.length] = getIntraBondOrderFromTable(compId, atomIdA, label_atom_id.value(bI)); + order[order.length] = getIntraBondOrderFromTable(compId, label_atom_id.value(aI), label_atom_id.value(bI)); flags[flags.length] = (isMetal ? BondType.Flag.MetallicCoordination : BondType.Flag.Covalent) | BondType.Flag.Computed; key[key.length] = -1;