diff --git a/pdb2pqr/biomolecule.py b/pdb2pqr/biomolecule.py index 40a21ea3..59d73b99 100644 --- a/pdb2pqr/biomolecule.py +++ b/pdb2pqr/biomolecule.py @@ -767,9 +767,13 @@ def apply_name_scheme(self, forcefield_): rname != residue.name ): if len(rname) == 4 and rname[0] in ("C", "N"): - # Remove the C/N prefix to keep the protonation state of the residue - # in the terminal residues - rname = rname[1:] + if rname[1:] == "TER": + # Preserve explicit terminal names produced by the force field. + pass + else: + # Remove the C/N prefix to keep the protonation state of the residue + # in the terminal residues. + rname = rname[1:] elif rname.startswith("NEUTRAL-"): # Remove the NEUTRAL-C and NEUTRAL-N prefixes to keep protonation state rname = rname[9:] diff --git a/tests/core_test.py b/tests/core_test.py index 62ba8205..280b73c3 100644 --- a/tests/core_test.py +++ b/tests/core_test.py @@ -5,6 +5,9 @@ import common import pytest +from pdb2pqr import aa +from pdb2pqr.biomolecule import Biomolecule + # fmt: off #: Protein-nucleic acid complexes PROTEIN_NUCLEIC_SET = {"4UN3"} @@ -114,6 +117,38 @@ def test_broken_backbone(input_pdb, tmp_path): ) +@pytest.mark.parametrize( + ("forcefield_name", "expected_name"), + [ + pytest.param("CTER", "CTER", id="preserve-cter"), + pytest.param("NTER", "NTER", id="preserve-nter"), + pytest.param("CGLU", "GLU", id="strip-c-prefix"), + pytest.param("NHIS", "HIS", id="strip-n-prefix"), + ], +) +def test_terminal_forcefield_names_preserve_termini(forcefield_name, expected_name): + """Terminal renaming keeps CTER/NTER intact while stripping residue prefixes.""" + + class DummyForcefield: + def get_names(self, resname, atomname): + return forcefield_name, atomname + + atom = type("Atom", (), {"name": "CA", "res_name": None})() + residue = object.__new__(aa.Amino) + residue.name = "GLU" + residue.ffname = "GLU" + residue.is_n_term = True + residue.is_c_term = False + residue.atoms = [atom] + + biomolecule = Biomolecule.__new__(Biomolecule) + biomolecule.residues = [residue] + + biomolecule.apply_name_scheme(DummyForcefield()) + + assert atom.res_name == expected_name + + @pytest.mark.parametrize( "input_pdb, expected_pqr", [pytest.param("cterm_hid.pdb", "cterm_hid_out.pqr", id="C-terminal HID")],