moleculekit.tools.residue_titration module#

Prepare non-standard residues for pKa titration and fold the result back into per-residue build templates.

The public entry points are capNonstandardResiduesForTitration() and templatesFromTitration(), both dict-in / dict-out ({key: smiles}). The caller runs its own pKa tool (e.g. AcePka) over the titration SMILES and hands the protonated result back; moleculekit never reads the tool’s file formats.

Each residue is built from its full base SMILES (an RCSB ligand descriptor or a caller override), so it carries the complete chemistry even when the deposited structure has a trimmed sidechain. Every outgoing inter-residue bond is then capped with an inert stand-in for its real partner, so the pKa tool sees a chemically sane molecule that titrates the residue’s own groups in a faithful environment. Most caps are neutral (an amide, a methyl); a phosphodiester partner is kept as a phosphate, so an internal nucleotide carries the real, charged backbone environment a terminal one would not:

  • a backbone peptide bond gets an amide cap - acetyl on the N side, N-methyl on the carbonyl C side (the ACE / NME that keep a mid-chain backbone neutral);

  • a sidechain / scaffold crosslink gets an inert cap chosen to keep the junction atom non-titratable: acetyl on a severed nitrogen, N-methyl on an amide carbonyl carbon, and for any other junction a cap reflecting the real partner element (a nitrogen partner gives an amide, an oxygen partner a hydroxyl, a phosphorus partner a phosphate, everything else a methyl). When a condensation crosslink (glycosidic, phosphoester, …) left the junction atom fully valent in the free-form SMILES, the displaced leaving group (the base-SMILES atom absent from the deposited residue) is stripped first;

  • a genuine free terminus or free-ligand end is left uncapped, so the pKa tool assigns its charge (a real C-terminus deprotonates, an N-terminus protonates).

The backbone atoms are located by their structure names (N / C) mapped onto the SMILES; crosslink atoms are found by walking mol.bonds and mapped the same way. Coordinates never affect the returned SMILES - only connectivity does. After titration, templatesFromTitration() strips the caps back off (the residue is a subgraph of its capped molecule) to yield one template SMILES per residue for the builder.

moleculekit.tools.residue_titration.capNonstandardResiduesForTitration(mol, specs, smiles=None, _logger=True)#

Build per-context pKa-titration input SMILES for the non-standard residues, keyed by new_resname or resname.

Each chain-resident NCAA is capped for its chain context, and every scaffold / covalent-ligand residue has its non-peptide crosslink(s) inert- capped the same way (see _cap_residue_smiles()); a genuinely free ligand is passed through uncapped, as is any residue whose backbone or crosslink cannot be capped (a warning is logged and it is titrated whole). Entries are deduplicated by key so an NCAA appearing in several places is titrated once per unique (chemistry, context).

The result is a plain {key: smiles} dict. The caller runs its own pKa tool over the values (e.g. AcePka) and passes the protonated result back to templatesFromTitration() as a dict of the same keys; moleculekit does not read or write any pKa tool’s file format.

Parameters:
Returns:

titration{key: smiles} to titrate, one entry per unique template-requiring residue.

Return type:

dict[str, str]

Raises:

RuntimeError – If a residue needing a template has neither an override in smiles nor a fetchable RCSB SMILES.

moleculekit.tools.residue_titration.templatesFromTitration(mol, specs, protonated, smiles=None)#

Strip the caps off pKa-titrated SMILES back into per-residue templates.

Inverse of capNonstandardResiduesForTitration(), driven by the same mol and specs so no intermediate state has to be carried between the two calls. For each template-requiring chain, scaffold, or covalent- ligand residue, its uncapped anchor is re-derived (_uncapped_residue_smiles()) and used as a relaxed substructure query (_relaxed_query()) to locate that residue’s own atoms inside its protonated, capped SMILES; the matched atoms are extracted (_submol_from_atoms()), dropping the ACE / NME / crosslink caps that fall outside the match. A pKa tool only ever changes protonation state, never the heavy-atom skeleton, so the anchor is guaranteed to be a subgraph of the protonated molecule. Residues titrated whole (genuinely free ligands, or residues whose backbone or crosslink could not be capped) are returned unchanged.

Parameters:
Returns:

templates{key: smiles}, one entry per key, with caps removed and the pKa tool’s protonation applied.

Return type:

dict[str, str]

Raises:

RuntimeError – If protonated is missing a key, a protonated SMILES cannot be parsed, or a residue’s anchor cannot be located inside its protonated SMILES.