# Victor Victor is the overarching class. This has many features and can be rather complicated in its setup: but then a point and click solution that works universally without customisation is a bad solution for molecular modelling. ## Combine vs. Place Like Monster Victor has two main calculation methods: `combine` and `place`. Whereas in Monster these are independent of protein neighbourhood, in Victor they are not thanks to Igor. Victor does the following steps: * Is given a followup to test and the mol objects of its inspiration and the pdb template file. * Calls Monster class * Parameterises the mol * Generates the constraints * Calls Igor * Can do some extras ## Class attributes Core settings controlling its behaviour can be set via class attribute. For example, the warhead conversion methods can be controlled via: * `covalent_definitions` (currently defined only for cysteine) * `warhead_definitions` While other include: * `error_to_catch` * `constraint_function_type` * `work_path` ## Class methods Two key class methods are `Victor.extract_mols` and `Victor.extract_mol`. Also several methods for covalent operations — see [covalent notes](doc_covalents.html) Note that Igor has pyrosetta specific class methods, e.g. downloading electron density for template prep etc. ## Example > The following code may have changed. And several of these methods are Here is a real world usage that uses multiple features: Import pyrosetta and initialised before everything (applies to Igor too): ```python import pyrosetta pyrosetta.init(extra_options='-no_optH false -mute all -ignore_unrecognized_res true -load_PDB_components false') from fragmenstein import Igor, Monster, Victor import logging, csv, json from rdkit import Chem from rdkit.Chem import AllChem ``` configure whither to save and whence to load: ```python Victor.work_path = '../Mpro_fragmenstein' Victor.enable_stdout(logging.WARNING) mpro_folder = '/Users/matteo/Coding/rosettaOps/Mpro' ``` alternatively `Victor.enable_logfile('reanimate.log',logging.DEBUG)` (see [logging notes](doc_logging_and_debugging.html)). add extra constraints that are warhead & protein specific. note that the warhead definitions contain preferred names for the connecting atoms and their neighbours ```python for cname, con in [('chloroacetamide', 'AtomPair H 145A OY 1B HARMONIC 2.1 0.2\n'), ('nitrile', 'AtomPair H 145A NX 1B HARMONIC 2.1 0.2\n'), ('acrylamide', 'AtomPair H 143A OZ 1B HARMONIC 2.1 0.2\n'), ('vinylsulfonamide', 'AtomPair H 143A OZ1 1B HARMONIC 2.1 0.2\n') ]: Victor.add_constraint_to_warhead(name=cname, constraint=con) ``` Here is the definition of a nitrile warhead, for example: {'name': 'nitrile', 'covalent': 'C(=N)*', # zeroth atom is attached to the rest 'covalent_atomnames': ['CX', 'NX', 'CONN1'], 'noncovalent': 'C(#N)', # zeroth atom is attached to the rest 'noncovalent_atomnames': ['CX', 'NX'] } This allows warheads to be mixed and matched. warhead The choice of the protein template is a bit weak. I plan to experiment with minimisation against averaged electron densities. ```python def get_best(hit_codes): return Victor.closest_hit(pdb_filenames=[f'{mpro_folder}/Mpro-{i}_0/Mpro-{i}_0_bound.pdb' for i in hit_codes], target_resi=145, target_chain='A', target_atomname='SG', ligand_resn='LIG') ``` There is a change I require to the pose ```python def pose_fx(pose): pose2pdb = pose.pdb_info().pdb2pose r = pose2pdb(res=41, chain='A') MutateResidue = pyrosetta.rosetta.protocols.simple_moves.MutateResidue MutateResidue(target=r, new_res='HIS').apply(pose) ``` Define all the steps ```python def reanimate(smiles, name, hit_codes): hits = [get_mol(i) for i in hit_codes] best_hit = get_best(hit_codes) Victor.journal.debug(f'{name} - best hit as starting is {best_hit}') apo = best_hit.replace('_bound', '_apo-desolv') print(f'reanimate(smiles="{smiles}", name="{name}", hit_codes={hit_codes})') reanimator = Victor(hits=hits, pdb_filename=apo, ligand_resn='LIG', ligand_resi='1B', covalent_resn='CYS', covalent_resi='145A', pose_fx = pose_fx ) reanimator.place(smiles=smiles, extra_constraint='AtomPair SG 145A NE2 41A HARMONIC 3.5 0.2\n', long_name=name) return reanimator ``` Read the data and do all warhead combinations if covalent. This data is actually from [github.com/postera-ai/COVID_moonshot_submissions](doc_https://github.com/postera-ai/COVID_moonshot_submissions). For which there is a method in `fragmenstein.mpro`. ```python data = csv.DictReader(open('../COVID_moonshot_submissions/covid_submissions_all_info.csv')) issue = [] for row in data: if row['covalent_warhead'] == 'False': pass reanimate(name = row['CID'], hit_codes = row['fragments'].split(','), smiles=row['SMILES']) else: print(f'Covalent: {row["CID"]}') for category in ('acrylamide', 'chloroacetamide', 'vinylsulfonamide', 'nitrile'): if row[category] == 'True': combinations = Victor.make_all_warhead_combinations(row['SMILES'], category) if combinations is None: issue.append(row["CID"]) break for c in combinations: reanimate(name = row['CID']+'-'+c, hit_codes = row['fragments'].split(','), smiles=combinations[c]) break else: print(f'What is {row["CID"]}') issue.append(row["CID"]) ``` ## Methods for inheritance The above could have been customised further, by making a class that inherits Victor and defining `post_params_step`, `post_fragmenstein_step`, `pose_mod_step` or `post_igor_step`, which are empty methods intended to make subclassing Victor easier as these are meant to be overridden —NB `pose_mod_step` is run if not `pose_fx` is given. ## Coordinate constraint The coordinate constraint generated for Igor, the minimiser can be changed from `HARMONIC` (x = mean) to `FLAT_HARMONIC` (tol = max distance of contributing atoms) and `BOUNDED` (fixed penalty potential well). Do note that the reference atom for the constraint is the covalent residue, regardless of whether the ligand is covalent.