def print_stats(self, prefix='') -> None: """ Prints statistics to stdout Args: prefix: Text prefix to prepend to printed data """ stats = self.get_stats() self.print_model_stats(prefix) self.print_chain_stats(prefix) print('{} Num. residues: {}'.format(prefix, stats['num_res'])) print('{} Num. residues with ins. codes: {}'.format( prefix, stats['res_insc'])) print('{} Num. HETATM residues: {}'.format(prefix, stats['res_hetats'])) print('{} Num. ligands or modified residues: {}'.format( prefix, stats['res_ligands'])) print('{} Num. water mol.: {}'.format(prefix, stats['num_wat'])) print('{} Num. atoms: {}'.format(prefix, stats['num_ats'])) if stats['ca_only']: print('Possible CA-Only structure') if self.hetatm[mu.MODRES]: print('Modified residues found') for res in self.hetatm[mu.MODRES]: print(mu.residue_id(res)) if self.hetatm[mu.METAL]: print('Metal/Ion residues found') for res in self.hetatm[mu.METAL]: print(mu.residue_id(res)) if self.hetatm[mu.ORGANIC]: print('Small mol ligands found') for res in self.hetatm[mu.ORGANIC]: print(mu.residue_id(res))
def add_hydrogens(self, ion_res_list, remove_h: bool = True): """ Add hydrogens considering selections in ion_res_list Args: **r_at_list**: dict as Bio.PDB.Residue: Tauromeric Option **remove_h**: Remove Hydrogen atom before adding new ones """ add_h_rules = self.data_library.get_add_h_rules() for res in self.all_residues: if mu.is_hetatm(res): continue if remove_h: mu.remove_H_from_r(res, verbose=False) if res not in self.prev_residue: prev_residue = None else: prev_residue = self.prev_residue[res] error_msg = mu.add_hydrogens_backbone(res, prev_residue) if error_msg: print(error_msg, mu.residue_id(res)) rcode = res.get_resname() if rcode == 'GLY': continue if rcode not in add_h_rules: print(NotAValidResidueError(rcode).message) continue if res in ion_res_list: if rcode != ion_res_list[res]: print('Replacing {} by {}'.format(mu.residue_id(res), ion_res_list[res])) error_msg = mu.add_hydrogens_side( res, self.res_library, ion_res_list[res], add_h_rules[rcode][ion_res_list[res]]) res.resname = ion_res_list[res] else: error_msg = mu.add_hydrogens_side(res, self.res_library, rcode, add_h_rules[rcode]) if error_msg: print(error_msg, mu.residue_id(res)) self.residue_renumbering() self.atom_renumbering() self.modified = True
def fix_backbone_O_atoms(self, r_at: Tuple[Residue, Sequence[str]]) -> bool: """Adding missing backbone atoms not affecting main-chain like O and OXT Args: **r_at**: tuple as [Bio.PDB.Residue, [list of atom ids]] """ res, at_list = r_at print(mu.residue_id(res)) if 'C' not in res: raise NotEnoughAtomsError if len(at_list) == 2 or at_list == ['O']: if 'CA' not in res or 'N' not in res or 'C' not in res: raise NotEnoughAtomsError print(" Adding new atom O") mu.add_new_atom_to_residue(res, 'O', mu.build_coords_O(res)) if 'OXT' in at_list: if 'CA' not in res or 'C' not in res or 'O' not in res: raise NotEnoughAtomsError print(" Adding new atom OXT") mu.add_new_atom_to_residue( res, 'OXT', mu.build_coords_SP2(mu.OINTERNALS[0], res['C'], res['CA'], res['O'])) self.atom_renumbering() self.modified = True return True
def merge_structure(self, new_st: Structure, mod_id: str, ch_id: str, brk_list: Union[Sequence[Atom], Sequence[Sequence[Atom]]], offset: int) -> Union[str, List[str]]: spimp = Superimposer() fixed_ats = [ atm for atm in self.st[mod_id][ch_id].get_atoms() if atm.id == 'CA' ] moving_ats = [] for atm in fixed_ats: moving_ats.append(new_st[0][' '][atm.get_parent().id[1] - offset + 1]['CA']) spimp.set_atoms(fixed_ats, moving_ats) spimp.apply(new_st.get_atoms()) list_res = self.st[mod_id][ch_id].get_list() fixed_gaps = [] for i in range(0, len(self.sequence_data.data[ch_id]['pdb'][mod_id]) - 1): gap_start = self.sequence_data.data[ch_id]['pdb'][mod_id][ i].features[0].location.end gap_end = self.sequence_data.data[ch_id]['pdb'][mod_id][ i + 1].features[0].location.start if [ self.st[mod_id][ch_id][gap_start], self.st[mod_id][ch_id][gap_end] ] not in brk_list: continue pos = 0 while pos < len(list_res) and self.st[mod_id][ch_id].child_list[ pos].id[1] != gap_start: pos += 1 self.remove_residue(self.st[mod_id][ch_id][gap_start], update_int=False) self.remove_residue(self.st[mod_id][ch_id][gap_end], update_int=False) for nres in range(gap_start, gap_end + 1): res = new_st[0][' '][nres - offset + 1].copy() res.id = (' ', nres, ' ') self.st[mod_id][ch_id].insert(pos, res) pos += 1 print("Adding " + mu.residue_id(res)) fixed_gaps.append('{}{}-{}{}/{}'.format(ch_id, gap_start, ch_id, gap_end, mod_id + 1)) print() return fixed_gaps
def fix_side_chain(self, r_at: Tuple[Residue, Sequence[str]]) -> None: """ Fix missing side chain atoms in given residue. Triggers **modified** flag Args: **r_at**: tuple as [Bio.PDB.Residue, [list of atom ids]] """ print(mu.residue_id(r_at[0])) for at_id in r_at[1]: print(" Adding new atom " + at_id) if at_id == 'CB': coords = mu.build_coords_CB(r_at[0]) else: coords = mu.build_coords_from_lib(r_at[0], self.res_library, r_at[0].get_resname(), at_id) mu.add_new_atom_to_residue(r_at[0], at_id, coords) self.atom_renumbering() self.modified = True
def apply(self, mut_map, res_lib, remove_h): """ Perform the individual mutations on the set. """ mutated_res = [] for mut in self.mutations: res = mut['resobj'] #struc[mut['model']][mut['chain']][mut['residue']] rname = res.get_resname().replace(' ', '') # Deleting H if remove_h == 'mut': mu.remove_H_from_r(res, verbose=True) # checking side chain side_atoms = [] bck_atoms = [] for atm in res.get_atoms(): if atm.id in mut_map[rname]['side_atoms']: side_atoms.append(atm.id) else: bck_atoms.append(atm.id) for at_id in ['N', 'CA', 'C']: if at_id not in bck_atoms: sys.exit('#ERROR: Backbone atoms missing for {}, aborting'. format(mu.residue_id(res))) missing_ats = [ at_id for at_id in mut_map[rname]['side_atoms'] if at_id not in side_atoms ] print("Replacing " + mu.residue_id(res) + " into " + self.new_id) in_rules = [] extra_adds = [] # Renaming ats if MOV in mut_map[rname][self.new_id]: for rule in mut_map[rname][self.new_id][MOV]: old_at, new_at = rule.split("-") print(' Renaming {} to {}'.format(old_at, new_at)) if old_at in side_atoms: mu.rename_atom(res, old_at, new_at) else: print('#WARNING: atom {} missing in {}'.format( old_at, mu.residue_id(res))) extra_adds.append(new_at) in_rules.append(old_at) # Deleting atoms if DEL in mut_map[rname][self.new_id]: for at_id in mut_map[rname][self.new_id][DEL]: print(' Deleting {}'.format(at_id)) if at_id in side_atoms: mu.delete_atom(res, at_id) else: print('#WARNING: atom {} already missing in {}'.format( at_id, mu.residue_id(res))) in_rules.append(at_id) # Adding atoms (new_id required as r.resname is still the original) # Adding missing atoms that keep name for at_id in mut_map[rname]['side_atoms']: if at_id not in in_rules and at_id in missing_ats: print(' Adding missing atom {}'.format(at_id)) mu.build_atom(res, at_id, res_lib, self.new_id) for at_id in extra_adds: print(' Adding new atom {}'.format(at_id)) mu.build_atom(res, at_id, res_lib, self.new_id) if ADD in mut_map[rname][self.new_id]: for at_id in mut_map[rname][self.new_id][ADD]: print(' Adding new atom {}'.format(at_id)) mu.build_atom(res, at_id, res_lib, self.new_id) #Renaming residue res.resname = self.new_id mutated_res.append(res) print("") return mutated_res