def test_copy(self): sub = Substituent("COCH3") sub = sub.copy(name="COCH3") self.is_COCH3(sub) return
def substitute( session, selection=None, substituents=None, newName=None, guessAttachment=True, modify=True, minimize=False, useRemoteness=False, available=False, newResidue=False, ): if available: substitute_list(session) return if not selection: selection = selected_atoms(session) if not substituents: session.logger.error("missing required \"substituents\" argument") return attached = {} if newName is None: newName = [None for s in substituents] elif any(len(name.strip()) > 4 for name in newName): raise RuntimeError("residue names must be 4 characters or less") elif not all(name.isalnum() for name in newName): raise RuntimeError("invalid residue name: %s" % " ".join(newName)) elif len(substituents) != len(newName): raise RuntimeError( "number of substituents is not the same as the number of new names" ) if not guessAttachment: models, attached = avoidTargets(selection) else: models, attached = guessAttachmentTargets(selection, session) first_pass = True new_structures = [] for ndx, subname in enumerate(substituents): subname = subname.strip() sub = Substituent(subname) # when minimizing, we only want to deal with residues that are close to the substituent # determine the size of the new substituent to limit this if minimize: size = 5 for atom in sub.atoms: d = np.linalg.norm(atom.coords) if d > size: size = d for model in models: if modify and first_pass: conv_res = [] for res in models[model]: if res not in conv_res: conv_res.append(res) if minimize: for chix_res in model.residues: if chix_res in conv_res: continue added_res = False for atom in chix_res.atoms: for target in models[model][res]: d = np.linalg.norm(atom.coord - target.coord) if d < (size + 3): conv_res.append(chix_res) added_res = True break if added_res: break rescol = ResidueCollection(model, convert_residues=conv_res) for res in models[model]: for target in models[model][res]: if attached is not None: end = AtomSpec(attached[target].atomspec) else: end = None # call substitute on the ResidueCollection b/c we need to see # the other residues if minimize=True rescol.substitute( sub.copy(), AtomSpec(target.atomspec), attached_to=end, minimize=minimize, use_greek=useRemoteness, new_residue=newResidue, new_name=newName[ndx], ) rescol.update_chix(model) elif modify and not first_pass: raise RuntimeError("only the first model can be replaced") else: model_copy = model.copy() conv_res = [ model_copy.residues[i] for i in [model.residues.index(res) for res in models[model]] ] # modifying_residues = [model_copy.residues[i] for i in [model.residues.index(res) for res in models[model]]] modifying_residues = [r for r in conv_res] if minimize: for chix_res in model_copy.residues: if chix_res in conv_res: continue added_res = False for res in models[model]: for target in models[model][res]: for atom in chix_res.atoms: d = np.linalg.norm(atom.coord - target.coord) if d < (size + 3): conv_res.append(chix_res) added_res = True break if added_res: break if added_res: break rescol = ResidueCollection(model_copy, convert_residues=conv_res) for residue, res in zip(modifying_residues, models[model]): for target in models[model][res]: if attached is not None: end = AtomSpec(model_copy.atoms[model.atoms.index( attached[target])].atomspec) else: end = None rescol.substitute( sub.copy(), AtomSpec(model_copy.atoms[model.atoms.index( target)].atomspec), attached_to=end, minimize=minimize, use_greek=useRemoteness, new_residue=newResidue, new_name=newName[ndx], ) rescol.update_chix(model_copy) new_structures.append(model_copy) first_pass = False if not modify: session.models.add(new_structures)