def run_script(session): from chimerax.atomic import selected_atoms from chimerax.build_structure import modify_atom from chimerax.build_structure.mod import ParamError from chimerax.core.errors import UserError sel = selected_atoms(session) if len(sel) != 1: raise UserError('Please select a single atom!') sel = sel[0] current_num_bonds = len(sel.neighbors) current_color = sel.color try: modify_atom(sel, sel.element, current_num_bonds + 1, connect_back=False, res_name=sel.residue.name) sel.color = current_color except ParamError as e: # If modify_atom throws an error at the previous step, it will have deleted # any attached hydrogens and not put them back. We need to put them back here. modify_atom(sel, sel.element, current_num_bonds, connect_back=False, res_name=sel.residue.name) sel.color = current_color raise UserError(str(e))
def add_oxt(session, residue): catom = residue.find_atom('C') resname = residue.name if catom is None: session.logger.warning('Residue {} {}{} has no C atom!'.format( residue.name, residue.chain_id, residue.number)) return color = catom.color for n in catom.neighbors: if n.name == 'OXT': session.logger.warning( 'Chain {} already has a C-terminal OXT. Skipping.') return if n.residue != residue: raise UserError( 'Residue {} {}{} is not a C-terminal residue!'.format( residue.name, residue.chain_id, residue.number)) from chimerax.build_structure import modify_atom from chimerax.atomic import Element atoms = modify_atom(catom, catom.element, 3, res_name=residue.name) for a in atoms: if a.element.name == 'H': break modify_atom(a, Element.get_element('O'), 1, name='OXT', res_name=residue.name) catom.color = color session.logger.info('Added a C-terminal OXT to chain {}'.format( residue.chain_id))
def run_script(session): from chimerax.atomic import selected_residues from chimerax.build_structure import modify_atom from chimerax.build_structure.mod import ParamError from chimerax.core.errors import UserError sel = selected_residues(session) if len(sel) != 1 or sel[0].name not in ('ASP', 'GLU'): raise UserError('Please select a single ASP or GLU residue!') sel = sel[0] if sel.name == 'ASP': pos = 'D' else: pos = 'E' o_atom = sel.find_atom(f'O{pos}2') other_o = sel.find_atom(f'O{pos}1') if o_atom is None or other_o is None: raise UserError( 'Selected acid sidechain is missing one or both of its oxygen atoms!' ) if len(o_atom.neighbors) != 1 or len(other_o.neighbors) != 1: raise UserError( 'Selected acid sidechain already has a substituent on its carboxyl group!' ) new_h = modify_atom(o_atom, o_atom.element, 2, connect_back=False, res_name=sel.name)[1] new_h.color = [255, 255, 255, 255]
def break_disulfide(cys1, cys2): from chimerax.core.errors import UserError from chimerax.atomic import Atoms s1 = cys1.find_atom('SG') s2 = cys2.find_atom('SG') if s1 is None or s2 is None: raise UserError( 'Missing SG atom! Are both residues complete cysteines?') if s2 not in s1.neighbors: raise UserError('These residues are not disulfide bonded!') has_hydrogens = ('H' in cys1.atoms.element_names) b = Atoms((s1, s2)).intra_bonds[0] b.delete() if has_hydrogens: from chimerax.build_structure import modify_atom modify_atom(s1, s1.element, 2, res_name='CYS', connect_back=False) modify_atom(s2, s2.element, 2, res_name='CYS', connect_back=False)
def add_missing_md_template_atoms(session, residue, md_template, residue_indices, template_indices): import numpy template_extra_indices = [ i for i in range(len(md_template.atoms)) if i not in template_indices ] if not len(template_extra_indices): return template_extra_bonds = set([ b for b in md_template.bonds if any([i in template_extra_indices for i in b]) ]) from collections import defaultdict stub_map = defaultdict(list) # stub_map maps an existing atom in the residue to any atoms in the MD # template that should be connected to it, but aren't yet modelled. found_bonds = set() for b in template_extra_bonds: i1, i2 = b i1_index = numpy.where(template_indices == i1)[0] i2_index = numpy.where(template_indices == i2)[0] if not len(i1_index) and not len(i2_index): continue if len(i2_index): i1, i2 = i2, i1 i1_index = i2_index i1_index = i1_index[0] res_atom = residue.atoms[residue_indices[i1_index]] # if not res_atom: # raise RuntimeError("Atom {} should be in residue, but isn't".format(ccd_atom.name)) stub_map[res_atom].append(i2) found_bonds.add(b) template_extra_bonds = template_extra_bonds.difference(found_bonds) if len(template_extra_bonds): err_str = ( 'MD template {} for residue {} {}{}{} contains extra atoms that are not in ' 'a coordinate template, and are not directly connected to existing ' 'atoms. Since MD templates do not explicitly provide geometry,' 'these atoms will not be built.').format(md_template.name, residue.name, residue.chain_id, residue.number, residue.insertion_code) session.logger.warning(err_str) seen = set() for new_atom_list in stub_map.values(): for i in new_atom_list: if i in seen: err_str = ( 'The atom {} in MD template {} bonds to more than ' 'one existing atom in residue {}. Since MD templates do ' 'not explicitly specify geometry, this type of atom addition ' 'is not currently supported. The resulting residue will ' 'contain only those atoms which the MD and coordinate templates ' 'have in common').format(md_template.atoms[i].name, md_template.name, residue.name) raise UserError(err_str) seen.add(i) from chimerax.atomic import Element from chimerax.build_structure import modify_atom for existing_atom, new_indices in stub_map.items(): num_new_atoms = len(new_indices) num_existing_neighbors = len(existing_atom.neighbors) num_bonds = len(existing_atom.neighbors) + num_new_atoms new_tatoms = [md_template.atoms[i] for i in new_indices] from chimerax.build_structure.mod import ParamError try: modified_atoms = modify_atom(existing_atom, existing_atom.element, num_bonds, res_name=residue.name) except ParamError: err_str = ( 'Failed to add atoms {} to atom {} because this will ' 'lead to having {} atoms attached, which is more than its ' 'assigned geometry can support. This is probably due to an ' 'error in the MD template ({}). If this template is built ' 'into ISOLDE, please report this using Help/Report a bug' ).format([a.name for a in new_tatoms], existing_atom.name, num_existing_neighbors + len(new_tatoms), md_template.name) raise UserError(err_str) new_atoms = modified_atoms[1:] for na, ta in zip(new_atoms, new_tatoms): modify_atom(na, Element.get_element(ta.element.atomic_number), 1, name=ta.name, res_name=residue.name)