Skip to content

Add nucleic acid H-capping and phosphate charge counting#8

Open
Benzoin96485 wants to merge 1 commit into
mainfrom
feat/nucleic-acid-h-capping
Open

Add nucleic acid H-capping and phosphate charge counting#8
Benzoin96485 wants to merge 1 commit into
mainfrom
feat/nucleic-acid-h-capping

Conversation

@Benzoin96485

Copy link
Copy Markdown
Collaborator

Summary

Adds first-class handling of nucleic-acid (DNA/RNA) strand breaks in cluster extraction, so QM clusters containing nucleotides no longer need post-processing scripts to fix capping and net charge.

  • Capping (cap_chains in qp/cluster/spheres.py): nucleic strand breaks are capped with link-atom hydrogens — P–H at severed 5′ phosphates and O3'–H at severed 3′ ends. Uses the vacant tetrahedral direction from the existing phosphate oxygens (OP1/OP2/OP3/O5') and the C3'–O3' axis. Nucleic acids always use H caps, even with capping=2 (ACE/NME stays protein-only).
  • Charge (compute_charge): counts -1 per polymer phosphate (residue with P + OP1/OP2), skips nucleotides already accounted for via the ligand SDF path to avoid double-counting, and gates the protein N/C-terminus and OXT rules to amino acids so they no longer misfire on nucleic bases (which also carry an N atom).
  • Detection: new is_nucleic_residue recognizes standard RNA/DNA resnames and modified bases (e.g. A1C) via sugar-ring + backbone atoms, with '/* primed atom-name compatibility.

H-capping (rather than adding a hydroxyl OP3) is used deliberately to avoid introducing extra terminal-phosphate polarity/charge and protonation ambiguity; the link-atom H simply satisfies the cut valence without changing the formal -1 phosphate charge.

This replaces an ad-hoc fix_step3_caps.py workaround used for an NSUN2 RNA cluster.

Test plan

  • New qp/tests/test_nucleic_cap.py (6 tests, all passing):
    • is_nucleic_residue for standard + modified (A1C) residues
    • P–H / O3'–H caps added only at true strand breaks (no OP3); internal nucleotides untouched
    • capping=2 still H-caps nucleic acids
    • phosphate charge via polymer path (-3 for a 3-phosphate cluster)
    • ligand-oligomer nucleotides not double-counted (0)
    • chain-first nucleotide not given a spurious protein N-terminus +1
  • Regression: existing qp/tests/test_cluster.py protein clusters unchanged

Made with Cursor

Cap nucleic-acid strand breaks with link-atom hydrogens (P-H at 5'
phosphate breaks, O3'-H at 3' breaks) instead of relying on downstream
post-processing scripts. Nucleic acids always use H caps even when
capping=2 (ACE/NME remains protein-only).

Count phosphate charge in compute_charge (-1 per polymer phosphate with
OP1/OP2), skip nucleotides already handled via the ligand SDF path to
avoid double-counting, and gate the protein N/C-terminus rules so they
no longer fire on nucleic bases (which also carry an N atom).

Co-authored-by: Cursor <cursoragent@cursor.com>
Copilot AI review requested due to automatic review settings July 25, 2026 05:34

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds native nucleic-acid (DNA/RNA) handling to cluster extraction so strand breaks are H-capped correctly and polymer phosphate charges are counted without requiring post-processing.

Changes:

  • Added nucleotide detection (is_nucleic_residue) with prime/star atom-name compatibility and new nucleic capping logic in cap_chains (P–H and O3′–H).
  • Updated compute_charge to count -1 per polymer phosphate for nucleic acids, avoid ligand double-counting, and gate protein termini rules to amino acids.
  • Added a focused test suite covering nucleic capping and charge counting.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
qp/cluster/spheres.py Implements nucleic residue detection, nucleic H-capping at strand breaks, and phosphate-based charge counting while preventing protein termini rules from misfiring on bases.
qp/tests/test_nucleic_cap.py Adds unit tests validating nucleic detection, correct capping behavior at strand breaks, and correct phosphate charge counting including ligand skip logic.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread qp/cluster/spheres.py
Comment on lines +946 to +948
Flag for capping group, H (1) or ACE/NME (2). Nucleic acids always
use hydrogen caps (P–H / O3′–H) regardless of this flag when
``capping`` is non-zero.
Comment thread qp/cluster/spheres.py
Comment on lines +763 to +779
def build_o3prime_hydrogen(parent: Residue) -> Optional[Atom]:
"""Cap a dangling O3' with hydrogen (3'-OH link-atom cap)."""
if has_res_atom(parent, "HO3'"):
return None
o3 = get_res_atom(parent, "O3'")
c3 = get_res_atom(parent, "C3'")
if o3 is None or c3 is None:
return None

o_coord = o3.get_coord()
a = _unit_vec(c3.get_coord() - o_coord)
direction = _unit_vec(_TET_COS * a + _TET_SIN * _perpendicular(a))
pos = o_coord + O_H_BOND * direction
name = "HO3'"
atom = Atom(name, pos, 0, 1, " ", name, None, "H")
parent.add(atom)
return atom
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants