Ligands#

Ligand detection, preparation, parameter I/O, and fragmentation are available from the public tmol.ligand package.

Ligand typing, preparation, fragmentation, and serialization.

class tmol.ligand.FragmentConnection(fragment_id: int, partner_fragment_id: int, connection_name: str, partner_connection_name: str, atom_name: str, partner_atom_name: str, bond_type: str)[source]#

Bases: object

One directed side of a cut bond.

class tmol.ligand.LigandFragmentDefinition(ligand_name: str, atom_to_fragment: Mapping[str, int], fragment_ids: tuple[int, ...], fragment_preparations: tuple[LigandPreparation, ...], connections: tuple[FragmentConnection, ...])[source]#

Bases: object

Structure-independent definition of one fragmented ligand type.

class tmol.ligand.LigandPreparation(residue_type: RawResidueType, partial_charges: dict[str, float], cartbonded_params: CartRes, atom_type_elements: dict[str, str] | None = None)[source]#

Bases: object

The unified abstraction both ligand-pipeline paths converge on.

A LigandPreparation is everything tmol needs to inject one ligand into a ParameterDatabase: the residue type definition, partial charges, cartbonded parameters, and (optionally) the element mapping for any new atom-type names introduced.

Both pipeline entry points produce this same struct:

  • AtomArray / SMILES pathtmol.ligand.prepare_single_ligand() types the (already protonated, already charged) SMILES-derived molecule, builds the residue, and extracts cartbonded params, returning one LigandPreparation per ligand.

  • Params-file pathtmol.ligand._params_file.load_params_file() parses a .tmol YAML and returns list[LigandPreparation] describing the residues defined in that file.

Either list is then handed to inject_ligand_preparations(), the single chokepoint that extends the ParameterDatabase. Tests can equally roundtrip AtomArray LigandPreparation .tmol LigandPreparation and expect bit-equivalent injection.

exception tmol.ligand.LigandPreparationError[source]#

Bases: RuntimeError

A detected ligand could not be prepared, registered, or retained.

Raised by prepare_ligands() (and the prepare_ligands=True IO paths) when strict_ligands=True and a non-standard residue is skipped or fails preparation, instead of silently dropping it. Pass strict_ligands=False to downgrade these failures to warnings.

exception tmol.ligand.OpenBabelUnavailableError[source]#

Bases: RuntimeError

Raised when an OB-fallback helper is called but openbabel is missing.

tmol.ligand.apply_fragment_connections(pose_stack, mapping: FragmentedLigandPoseMapping)[source]#

Install fragment cut bonds and rebuild all inter-block bond separations.

tmol.ligand.build_split_block_mapping(pose_stack, resolved_mapping: FragmentedLigandPoseMapping)[source]#

Build a SplitBlockMapping from a fragmented PoseStack.

Ensures the original (unfragmented) block types are present in the PackedBlockTypes of the returned PoseStack, then records for each fragment block: its pose/block indices, its group within that pose, the index of the original block type, and the per-atom mapping split_atom → orig_atom.

Fragment block-type names are expected to follow the convention "ORIGNAME.FRAGMENT_ID" (e.g. "LIG.0").

Returns the (possibly PBT-extended) PoseStack and the SplitBlockMapping.

tmol.ligand.detect_nonstandard_residues(atom_array: AtomArray, canonical_ordering: CanonicalOrdering) list[NonStandardResidueInfo][source]#

Detect residues in an AtomArray that are not in tmol’s database.

Any residue whose 3-letter code is not in the canonical ordering is returned for preparation, regardless of whether it is a ligand, modified amino acid, or modified nucleotide.

Parameters:
  • atom_array – Biotite AtomArray from a CIF or PDB file.

  • canonical_ordering – The current tmol CanonicalOrdering, which defines known residue types.

Returns:

A list of NonStandardResidueInfo objects, one per unique unknown residue name.

tmol.ligand.expand_fragmented_ligands(structure: AtomArray | AtomArrayStack, definitions: Sequence[LigandFragmentDefinition]) tuple[AtomArray | AtomArrayStack, FragmentedLigandPoseMapping][source]#

Replace each annotated ligand residue with contiguous fragment residues.

tmol.ligand.fragment_ids_from_atom_array(atom_array: AtomArray) ndarray | None[source]#

Return validated fragment IDs, or None when no split is requested.

tmol.ligand.get_chem_comp_type(res_name: str) str | None[source]#

Look up the CCD chemical component type for a residue name.

Parameters:

res_name – Three-letter residue code.

Returns:

The CCD type string (e.g. “NON-POLYMER”, “L-PEPTIDE LINKING”), or None if the code is not found in the CCD.

tmol.ligand.inject_ligand_preparations(param_db: ParameterDatabase, preparations: list[LigandPreparation], *, strict_atom_types: bool = False) ParameterDatabase[source]#

Inject a batch of LigandPreparation records into a database.

The single chokepoint both pipeline paths use — given a list of prepared ligands (regardless of whether they came from a .tmol file or an AtomArray), this function aggregates their residue types, atom types, charges, and cartbonded params and evolves the input ParameterDatabase exactly once via tmol.database.inject_residue_params().

Residues whose name already exists in param_db are silently skipped so repeat injection is idempotent.

Parameters:
  • param_db – Base database (not modified).

  • preparations – One LigandPreparation per ligand to register.

  • strict_atom_types – If True, raise when an atom type’s element cannot be resolved from any preparation’s atom_type_elements — otherwise fall back to a name-based heuristic and emit a warning.

Returns:

A new frozen ParameterDatabase extended with all provided preparations.

tmol.ligand.inject_params_file(param_db: ParameterDatabase, path: str | Path, *, strict_atom_types: bool = False) ParameterDatabase[source]#

Load a single .tmol file and inject it into a ParameterDatabase.

tmol.ligand.inject_params_files(param_db: ParameterDatabase, paths: list[str | Path], *, strict_atom_types: bool = False) ParameterDatabase[source]#

Load multiple .tmol files and inject them in one shot.

tmol.ligand.ligand_smiles_from_atom_array(atom_array: AtomArray, *, res_name: str | None = None, with_atom_map: bool = False) str[source]#

Derive a canonical SMILES for a ligand AtomArray from its bond table.

The SMILES is derived purely from the input atoms and their explicit bonds (never a residue-code / CCD-template lookup, never geometry-based bond perception). Geometry-based bond-order corrections are still applied for motifs the input encodes inconsistently (carboxylates).

Parameters:
  • atom_array – The ligand sub-array (heavy + optional hydrogen atoms).

  • res_name – Residue code, used only for log/error messages.

  • with_atom_map – Tag heavy atoms with source-index map numbers for CIF atom naming downstream.

Returns:

A canonical SMILES string.

Raises:

ValueError – If the AtomArray carries no bond table (bond orders must be supplied by the input; a bonds-absent ligand such as a plain PDB cannot be prepared without guessing chemistry), or if no SMILES could be derived from the bonds present.

tmol.ligand.load_params_file(path: str | Path) list[LigandPreparation][source]#

Load a tmol params YAML file as a list of LigandPreparation.

The returned list is the same abstraction the AtomArray pipeline produces (see tmol.ligand.prepare_single_ligand()), so the caller can pass it directly to tmol.ligand._registry.inject_ligand_preparations() regardless of which input form (file or AtomArray) it came from.

The .tmol schema is the nested chemical: / elec: / cartbonded: shape — files using the legacy flat schema (top-level residues: etc.) raise a ValueError pointing at the migration.

tmol.ligand.nonstandard_residue_info_from_mol2(mol2_path: str | Path, res_name: str | None = None) NonStandardResidueInfo[source]#

Construct NonStandardResidueInfo from a ligand Mol2 file.

Low-level reader retained for the DUD-80 SMILES->params parity harness (it reads both the OpenBabel-generated and Rosetta ground-truth mol2 files). Preserves Tripos aromatic flags, atom-type subtypes, and per-atom partial charges, avoiding lossy rdkit<->biotite round-trips.

tmol.ligand.nonstandard_residue_info_from_mol2_block(mol2_block: str, res_name: str | None = None) NonStandardResidueInfo[source]#

Construct NonStandardResidueInfo from an in-memory mol2 string.

In-memory analogue of nonstandard_residue_info_from_mol2() — parses a TRIPOS mol2 block directly, with no temp-file write/read. Preferred for high-throughput SMILES batches (see nonstandard_residue_info_from_smiles_via_mol2()).

tmol.ligand.nonstandard_residue_info_from_smiles_via_mol2(smiles: str, res_name: str | None = None, *, ph: float = 7.4, protonate: bool = True, seed: int | None = None) NonStandardResidueInfo[source]#

Construct NonStandardResidueInfo from a SMILES via the mol2 route.

Implements the canonical ligand-prep protocol end to end:

  1. normalize bare radical oxygens ([O] -> [O-]) so source carboxylate/sulfonate notation has a well-defined charge,

  2. optionally pKa-protonate the SMILES with Dimorphite-DL (protonate),

  3. generate a 3D mol2 with MMFF94 partial charges via OpenBabel (kept in memory as a string — no temp file), then

  4. read that mol2 with nonstandard_residue_info_from_mol2_block().

This never builds a biotite atom-array from an RDKit embedding and never recomputes MMFF on a reconstructed graph — the OpenBabel MMFF94 charges flow through untouched (skip_protonation / authoritative charges are set by the mol2 reader), so fused-ring aromatics keep correct charges.

Parameters:
  • smiles – Ligand SMILES string.

  • res_name – Three-letter residue name (default inferred / "LG1").

  • ph – Target pH for the Dimorphite protonation step.

  • protonate – When True (default) run Dimorphite on smiles first; set False to pin an already-protonated SMILES verbatim.

  • seed – Fixed RNG seed for reproducible 3D coordinates; None is random.

Raises:
  • OpenBabelUnavailableError – If the openbabel package is missing (this path requires it for the SMILES -> mol2 conversion).

  • ValueError – If OpenBabel cannot build a charged mol2 for smiles.

tmol.ligand.prepare_ligand_from_cif(cif_path: str, *, param_db: ParameterDatabase | None = None, ph: float = 7.4, strict_atom_types: bool = False, res_name: str | None = None, sample_proton_chi: bool = True) tuple[ParameterDatabase, CanonicalOrdering][source]#

Prepare a single ligand from a CIF file and inject it into a database.

Runs the same full pipeline as prepare_ligand_from_smiles(); the only CIF-specific step is the front end. A SMILES is derived from the CIF ligand’s explicit bond table (never geometry perception, never a CCD lookup) and run through the SMILES -> mol2 -> params path (protonation, 3D conformer, MMFF94 charges). The prepared residue’s heavy-atom names are then mapped back to the CIF atom names via the atom-order map carried through the round-trip.

Parameters:
  • cif_path – Path to the ligand CIF file.

  • param_db – Base database (not modified); defaults to the tmol default.

  • ph – Target pH for protonation.

  • strict_atom_types – Fail on unknown atom-type element mappings.

  • res_name – Optional residue name override.

  • sample_proton_chi – Whether to emit proton-chi samples.

Returns:

A (ParameterDatabase, CanonicalOrdering) with the ligand injected.

tmol.ligand.prepare_ligand_from_mol2(mol2_path: str, *, param_db: ParameterDatabase | None = None, strict_atom_types: bool = False, res_name: str | None = None, sample_proton_chi: bool = True) tuple[ParameterDatabase, CanonicalOrdering][source]#

Prepare a single ligand from a Tripos mol2 file and inject it.

Reads atom names, coordinates, bond orders, and MMFF94 partial charges verbatim from the mol2 (no SMILES or OpenBabel 3D generation step).

Parameters:
  • mol2_path – Path to the ligand mol2 file.

  • param_db – Base database (not modified); defaults to the tmol default.

  • strict_atom_types – Fail on unknown atom-type element mappings.

  • res_name – Optional residue name override.

  • sample_proton_chi – Whether to emit proton-chi samples.

Returns:

A (ParameterDatabase, CanonicalOrdering) with the ligand injected.

tmol.ligand.prepare_ligand_from_smiles(smiles: str, *, param_db: ParameterDatabase | None = None, ph: float = 7.4, strict_atom_types: bool = False, res_name: str | None = None, protonate: bool = True, sample_proton_chi: bool = True, seed: int | None = None) tuple[ParameterDatabase, CanonicalOrdering][source]#

Prepare a single ligand from a SMILES string and inject it into a database.

Follows the canonical ligand-prep protocol: Dimorphite-DL pKa-protonates the SMILES at ph, OpenBabel generates a 3D mol2 with MMFF94 partial charges, and that mol2 is read verbatim (atom names, coordinates, charges, and bond orders preserved). The MMFF94 charges flow through untouched — there is no biotite atom-array round-trip or MMFF recompute. This path requires the optional openbabel package.

Parameters:
  • smiles – Ligand SMILES to protonate and prepare.

  • param_db – Base parameter database; defaults to the TMol database.

  • ph – Target pH used when protonate is true.

  • strict_atom_types – Fail instead of falling back for unknown atom types.

  • res_name – Optional residue-name override.

  • protonate – When True (default) Dimorphite protonates smiles first; set False to pin an already-protonated SMILES verbatim.

  • sample_proton_chi – Emit chi samples for rotatable polar hydrogens.

  • seed – Fixed RNG seed for reproducible 3D coordinates; None is random.

Returns:

A (ParameterDatabase, CanonicalOrdering) with the ligand injected.

tmol.ligand.prepare_ligands(atom_array: AtomArray, param_db: ParameterDatabase | None = None, ph: float = 7.4, strict_atom_types: bool = False, params_files: list[str] | None = None, params_output: str | None = None, sample_proton_chi: bool = True, strict_ligands: bool = True, return_fragment_definitions: bool = False) tuple[source]#

Detect, prepare, and register all non-standard residues.

Scans the input AtomArray for residues not in the ParameterDatabase, runs each through the unified SMILES→OpenBabel mol2→typing→residue-build pipeline, and returns a new ParameterDatabase with the ligand data injected.

Parameters:
  • atom_array – A biotite AtomArray from a CIF or PDB file.

  • param_db – The base ParameterDatabase (not modified). If None, the default database is used.

  • ph – Target pH for ligand protonation (Dimorphite-DL on derived SMILES).

  • strict_atom_types – If True, fail when unknown atom-type element mappings are encountered during registration.

  • params_files – Optional list of tmol YAML params file paths to inject before detection. Residues defined in these files skip the RDKit/OB preparation pipeline.

  • params_output – Optional path to write all prepared ligand data to a tmol YAML params file for later reuse.

  • sample_proton_chi – Whether to emit PROTON_CHI samples in the built residue type.

  • strict_ligands – If True (default), raise LigandPreparationError when a detected non-standard residue is skipped (metal-containing or covalently linked) or fails preparation, instead of silently dropping it. If False, such residues are logged as warnings and skipped, leaving them to be filtered out during pose construction.

  • return_fragment_definitions – Internal/context-building option. If True, include definitions derived from tmol_fragment_id annotations as the third return value.

Returns:

A (ParameterDatabase, CanonicalOrdering) tuple. When return_fragment_definitions is true, a third element containing the structure-independent ligand fragment definitions is returned. The returned ParameterDatabase is a new instance with all detected ligands injected; the input param_db is not modified.

Raises:

LigandPreparationError – If strict_ligands and any detected ligand cannot be prepared and registered.

tmol.ligand.prepare_ligands_from_smiles(smiles, *, param_db: ParameterDatabase | None = None, ph: float = 7.4, strict_atom_types: bool = False, protonate: bool = True, sample_proton_chi: bool = True, seed: int | None = None) tuple[ParameterDatabase, dict][source]#

Prepare one residue type per SMILES, naming them LG1, LG2, …

Returns the extended database and a {smiles: residue name} mapping.

tmol.ligand.prepare_single_ligand(ligand_info: NonStandardResidueInfo, sample_proton_chi: bool = True, name_source: NonStandardResidueInfo | None = None) LigandPreparation[source]#

Build a LigandPreparation from a SMILES-derived ligand.

This is the final, naming-and-typing step of the unified pipeline. Its input must already be fully resolved chemistry: explicit hydrogens at the desired protonation state and authoritative per-atom partial charges (the OpenBabel MMFF94 charges produced by the SMILES -> mol2 step). Protonation and charge generation are not done here – they happen upstream in tmol.ligand._detect.nonstandard_residue_info_from_smiles_via_mol2().

Charges are mapped onto atoms by stable RDKit index (source atom order), so they are independent of the atom renaming below and never recomputed.

Returns a LigandPreparation – the same struct tmol.ligand._params_file.load_params_file() produces for each residue defined in a .tmol file, so the AtomArray-driven path and the params-file path converge on a single abstraction that inject_ligand_preparations() consumes.

Parameters:
  • ligand_info – A SMILES-derived ligand (skip_protonation=True with authoritative partial_charges). Raw CIF/atom-array ligands must be routed through prepare_ligands() / prepare_ligand_from_cif().

  • sample_proton_chi – Whether to emit proton-chi samples.

  • name_source – Optional ligand whose atom names the prepared residue should adopt (mapped to the prepared heavy atoms via the atom-order map). On the unified CIF path this is the original CIF ligand. Defaults to ligand_info.

Raises:

ValueError – If ligand_info lacks explicit hydrogens / authoritative charges (there is no charge-generation fallback).

tmol.ligand.read_params_file(path: str | Path) RawResidueType[source]#

Read a Rosetta .params file into a RawResidueType.

Parses ATOM, BOND, ICOOR_INTERNAL, and NBR_ATOM records. Other records are silently ignored.

Parameters:

path – Path to the .params file.

Returns:

A RawResidueType populated from the params file.

tmol.ligand.recombine_fragmented_ligands(structure: AtomArray | AtomArrayStack, pose_stack) AtomArray | AtomArrayStack[source]#

Restore original residue identities on exported ligand fragments.

Uses pose_stack.split_block_mapping to identify which residues in structure are split-block fragments and what their original PDB identity should be. Atoms are matched by the residue label stored in the pose’s PDBInfo (which is what biotite_from_pose_stack writes to res_id).

tmol.ligand.unsplit_pose_stack(pose_stack)[source]#

Reconstruct an unsplit PoseStack from one containing split (fragment) blocks.

Each group of split blocks sharing a (pose_ind, group_ind) in the PoseStack’s split_block_mapping is collapsed back into a single block of the corresponding original block type. Atom coordinates are gathered from the fragment blocks using the per-entry split_to_orig_atom_inds arrays; atoms present in the original type but absent from all fragments are left at zero.

Inter-residue connections between fragment blocks are removed (they become intra-block interactions in the original). External connections from a fragment block to a non-fragment block are transferred to the reconstructed original block.

Returns a new PoseStack with split_block_mapping=None.

tmol.ligand.write_params_file(preparation: LigandPreparation | list[LigandPreparation], path: str | Path, format: str = 'rosetta') None[source]#

Write a ligand LigandPreparation as a Rosetta .params or tmol .tmol.

Parameters:
  • preparation – A LigandPreparation (its residue_type / partial_charges / cartbonded_params are used), or a list of them.

  • path

    Output path. Its meaning depends on the format and whether a list was passed:

    • single preparation -> path is the output file (either format);

    • "rosetta" + list -> path is a directory; each preparation is written to <path>/<residue_type.name>.params (a .params holds a single residue);

    • "tmol" (single or list) -> path is a single file holding all residues.

  • format"rosetta" (classic Rosetta .params) or "tmol" (tmol YAML .tmol).

tmol.ligand.write_params_from_mol2(mol2_path: str | Path, out_path: str | Path, *, res_name: str | None = None, sample_proton_chi: bool = True, format: str = 'rosetta') None[source]#

Build params from a mol2 file and write Rosetta .params or tmol .tmol.

Parameters:
  • mol2_path – Input Tripos mol2 (names, coords, charges preserved verbatim).

  • out_path – Output file path (see write_params_file()).

  • res_name – Optional residue name override.

  • sample_proton_chi – Whether to emit PROTON_CHI samples.

  • format"rosetta" or "tmol".

Public constants#

FRAGMENT_ID_ANNOTATION

str(object='') -> str str(bytes_or_buffer[, encoding[, errors]]) -> str

MAX_FRAGMENT_CONNECTIONS

int([x]) -> integer int(x, base=10) -> integer

MIN_FRAGMENT_HEAVY_ATOMS

int([x]) -> integer int(x, base=10) -> integer

TMOL_FORMAT_VERSION

str(object='') -> str str(bytes_or_buffer[, encoding[, errors]]) -> str