def fill_serial_numbers(pdb: Pdb): """The reduce program can add hydrogens to ligands, those hydrogens will have no atom serial numbers RDKit will give parse error on a PDB block with atoms without an atom serial number. This method adds serial ids and bonds those hydrogens to their heavy atom based on it's name Args: pdb: The pdb to fill serial ids in """ model = pdb.model() max_serial_number = max( [a.atom_id() for a in model.atoms() if a.atom_id()]) for mol in model.molecules(generic=True): for a in mol.atoms(element='H'): if a.atom_id() != 0: continue max_serial_number += 1 # a.atom_id() is not a setter, so set it using private prop a._id = max_serial_number hgrp = a.name()[1] bonded = False for heavy in mol.atoms(exclude='H'): oname = heavy.name() if len(oname) > 1 and oname[1] == hgrp: logger.info('Binding {0}:{1} with {2}:{3}'.format( a.atom_id(), a.name(), heavy.atom_id(), heavy.name())) heavy.bond(a) bonded = True if not bonded: logger.warning('Unable to bind {0}:{1} to heavy atom'.format( a.atom_id(), a.name()))
def remove_unwanted_molecules(pdb: Pdb): """Remove unwanted molecules from model Cleans pdb by removing molecules which: * Have name in UNWANTED_HETEROS list * Is out side LIGAND_MAX_MASS..LIGAND_MIN_MASS mass range * Have name already processed (aka removes duplicates) Removing is done in-place. Args: pdb: Atomium PDB entry containing possible unwanted molecules """ unique_names = set() model = pdb.model() for mol in sorted(model.molecules(generic=True), key=lambda m: m.molecule_id()): is_unwanted = mol.name() in UNWANTED_HETEROS in_mass_range = LIGAND_MIN_MASS < mol.mass() < LIGAND_MAX_MASS seen_before = mol.name() in unique_names if is_unwanted or not in_mass_range or seen_before: model.remove_molecule(mol) else: unique_names.add(mol.name())
def ligands(pdb: Pdb, ligand_expo: Dict[str, Mol]) -> List[Ligand]: """Ligands of a pdb Args: pdb: The pdb ligand_expo: Dictionary with molecules of ligand expo Raises: NoLigands: When PDB has no ligands Returns: List of ligands, ordered by name """ model = pdb.model() ligs = {} for amol in model.molecules(generic=True): amol_id = amol.molecule_id() # Workaround for atomium 0.8 as to handle molecules with resID 0 # NOTE: was fixed in 0.11.1, but other changes break kripo if amol_id[1:]=="": amol._id = amol_id + '0' amol_id = amol.molecule_id() lig_id = pdb.code().lower() + '_' + amol.name() + '_1_' + amol_id[0] + '_' + amol_id[1:] try: lig = ligand_expo[lig_id] plig = protonate_molecule(lig) ligs[lig_id] = Ligand(amol, plig) except KeyError: logger.warning('Unable to find {0} in ligand expo db, skipping'.format(lig_id)) pass if not ligs: raise NoLigands() return sorted(ligs.values(), key=lambda l: l.name())
def ligands(pdb: Pdb, ligand_expo: Dict[str, Mol]) -> List[Ligand]: """Ligands of a pdb Args: pdb: The pdb ligand_expo: Dictionary with molecules of ligand expo Raises: NoLigands: When PDB has no ligands Returns: List of ligands, ordered by name """ model = pdb.model() ligs = {} for amol in model.molecules(generic=True): amol_id = amol.molecule_id() lig_id = pdb.code().lower() + '_' + amol.name( ) + '_1_' + amol_id[0] + '_' + amol_id[1:] try: lig = ligand_expo[lig_id] plig = protonate_molecule(lig) ligs[lig_id] = Ligand(amol, plig) except KeyError: logger.warning( 'Unable to find {0} in ligand expo db, skipping'.format( lig_id)) pass if not ligs: raise NoLigands() return sorted(ligs.values(), key=lambda l: l.name())
def remove_non_contacting_molecules(pdb: Pdb): """Remove unwanted molecules from model Cleans pdb by removing molecules which: * Is more then MAX_CONTACT_DISTANCE away from protein Removing is done in-place. Args: pdb: Atomium PDB entry containing possible unwanted molecules """ model = pdb.model() for mol in sorted(model.molecules(generic=True), key=lambda m: m.molecule_id()): in_contact_with_protein = ligand_contacts_protein(mol, model) if not in_contact_with_protein: try: model.remove_molecule(mol) except KeyError: # in 1efr was unable to delete atom with key 22969, ignore error pass