Add nucleic acid H-capping and phosphate charge counting#8
Open
Benzoin96485 wants to merge 1 commit into
Open
Conversation
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>
There was a problem hiding this comment.
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 incap_chains(P–H and O3′–H). - Updated
compute_chargeto count-1per 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 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 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 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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.
cap_chainsinqp/cluster/spheres.py): nucleic strand breaks are capped with link-atom hydrogens —P–Hat severed 5′ phosphates andO3'–Hat severed 3′ ends. Uses the vacant tetrahedral direction from the existing phosphate oxygens (OP1/OP2/OP3/O5') and theC3'–O3'axis. Nucleic acids always use H caps, even withcapping=2(ACE/NME stays protein-only).compute_charge): counts-1per polymer phosphate (residue withP+OP1/OP2), skips nucleotides already accounted for via the ligand SDF path to avoid double-counting, and gates the protein N/C-terminus andOXTrules to amino acids so they no longer misfire on nucleic bases (which also carry anNatom).is_nucleic_residuerecognizes 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-1phosphate charge.This replaces an ad-hoc
fix_step3_caps.pyworkaround used for an NSUN2 RNA cluster.Test plan
qp/tests/test_nucleic_cap.py(6 tests, all passing):is_nucleic_residuefor standard + modified (A1C) residuesP–H/O3'–Hcaps added only at true strand breaks (noOP3); internal nucleotides untouchedcapping=2still H-caps nucleic acids-3for a 3-phosphate cluster)0)+1qp/tests/test_cluster.pyprotein clusters unchangedMade with Cursor