[us-commits] [ehb54/ultrascan3] aca818: Add SSSR ring perception and expose the perceived ...
emre brookes
noreply at github.com
Sat Aug 8 07:36:10 MDT 2026
Branch: refs/heads/ehb54-issue-980
Home: https://github.com/ehb54/ultrascan3
Commit: aca818535d29d2f0f1742799a0abe5ba3a9a4457
https://github.com/ehb54/ultrascan3/commit/aca818535d29d2f0f1742799a0abe5ba3a9a4457
Author: ehb54 <brookes at uthscsa.edu>
Date: 2026-08-08 (Sat, 08 Aug 2026)
Changed paths:
M us_somo/develop/include/us_hydrodyn_perceive.h
M us_somo/develop/perceiver/DECISIONS.md
M us_somo/develop/perceiver/Makefile
A us_somo/develop/perceiver/tests/sssr.cpp
A us_somo/develop/perceiver/tests/sssr_real.cpp
M us_somo/develop/src/us_hydrodyn_perceive.cpp
Log Message:
-----------
Add SSSR ring perception and expose the perceived bond graph
Prerequisite for the Durchschlag & Zipper volume increments, which charge a
ring-formation decrement once per ring (3-ring 2.1 through >=9-ring 14.1).
The perceiver exposed only an "aromatic" flag and never returned Bonds at all,
so ring sizes and the topology needed to classify a nitrogen or oxygen
environment were unavailable to any caller.
Bonds gains "rings", the smallest set of smallest rings. find_sssr() is
declared in the header so it can be unit-tested on hand-built adjacency with
no geometry involved. A new perceive(atoms, bonds_out, explicit_bonds)
overload hands the graph back; the existing signature delegates to it, so
current callers are unaffected.
SSSR is kept separate from find_rings(), which enumerates every simple 5- or
6-cycle and feeds aromaticity. That is the right input for "is this atom in a
flat conjugated ring" but the wrong one for anything charged per ring: a fused
bicyclic has three simple cycles and circuit rank two. Keeping them apart also
leaves the validated perception untouched, confirmed by the regression figure
holding at 99.833%.
Method is the standard one for molecule-sized graphs: smallest cycle through
each bond, then greedy smallest-first acceptance while a candidate covers a
bond no accepted ring covers, until the circuit rank is reached. Rings beyond
max_ring (12) are not sought, since the consumer charges a single large-ring
term for everything from nine up.
Tests
sssr.cpp 35 checks on hand-built graphs: acyclic shapes, every ring size
3 to 9, ring with substituent, fused bicyclics (naphthalene,
indole, purine) giving two rings rather than three cycles,
spiro, bridged, three-fused, disconnected components,
macrocycle beyond max_ring, idempotency, and that every
reported ring is a genuine cycle. Also checks the arithmetic
the counts drive: one 6-ring decrement reproduces the published
phenylalanine volume, one 5-ring the proline one.
sssr_real.cpp 18 checks on real coordinates through the whole perception
path, over all eight demo structures. Phe {6}, Tyr {6},
Trp {5,6}, His {5}, Pro {5}, DA/DG {5,5,6}, DC/DT {5,6}, and
Ala/Gly/Leu/Ser/Arg ring-free, with every instance of a type
giving an identical signature.
Some demo structures carry physically impossible geometry, which produces
spurious small rings: 1AO6 models LYS536/NZ 0.73 A from LEU583/CG, shorter
than any covalent bond, and 6LYZ has two oxygens 1.22 A apart. This yields 13
cross-residue and 12 three-membered rings across the demo set, none of them
inside a residue, so no residue's own ring count is affected. The tests assert
this as such: a cross-residue ring must be closed by an inter-residue bond that
is neither a backbone link nor a disulfide, and no three-membered ring may lie
within a single residue.
Refs ehb54/ultrascan-tickets#980
Co-Authored-By: Claude Opus 4.8 <noreply at anthropic.com>
To unsubscribe from these emails, change your notification settings at https://github.com/ehb54/ultrascan3/settings/notifications
More information about the us-commits
mailing list