### Install PyRosetta via pyrosetta-help Source: https://github.com/matteoferla/fragmenstein/blob/master/documentation/00_installation.md Installation method using environment variables for credentials. ```bash pip install pyrosetta-help PYROSETTA_USERNAME=👾👾👾 PYROSETTA_PASSWORD=👾👾👾 install_pyrosetta ``` -------------------------------- ### Start the Fragmenstein Web UI Source: https://github.com/matteoferla/fragmenstein/blob/master/web/README.md Execute the startup script from the web directory to initialize the backend and frontend services. ```bash cd web ./start.sh ``` -------------------------------- ### Install PyRosetta via Installer Source: https://github.com/matteoferla/fragmenstein/blob/master/documentation/00_installation.md Modern method for installing PyRosetta without requiring manual password handling. ```bash pip install pyrosetta-installer python -c 'import pyrosetta_installer; pyrosetta_installer.install_pyrosetta()' ``` -------------------------------- ### Install PLIP Source: https://github.com/matteoferla/fragmenstein/blob/master/documentation/00_installation.md Installation commands for PLIP and its OpenBabel dependency using conda. ```bash conda install -c conda-forge openbabel lxml conda install -c conda-forge --no-deps plip ``` -------------------------------- ### Install Fragmenstein Dependencies Source: https://github.com/matteoferla/fragmenstein/blob/master/colab-notebooks/colab_fragmenstein_Wictor.ipynb Installs necessary libraries and configures the environment for Fragmenstein. Includes error reporting setup and specific workarounds for Colab environment constraints. ```python #@title Installation import sys #@markdown Press the play button on the top right hand side of this cell #@markdown once you have checked the settings. #@markdown You will be notified that this notebook is not from Google, that is normal. #@markdown Send error messages to errors.matteoferla.com for logging? #@markdown See [notebook-error-reporter repo for more](https://github.com/matteoferla/notebook-error-reporter) report_errors = False #@param {type:"boolean"} if report_errors: !pip install notebook-error-reporter from notebook_error_reporter import ErrorServer # noqa it is an option install es = ErrorServer(url='https://errors.matteoferla.com', notebook='fragmenstein') es.enable() !pip install -U -q typing_extensions>=4.9 !pip install -U -q typeguard>=4.1.5 # weird glitch of the week: try: from typing_extensions import Buffer # needed by some external dependency somewhere except ImportError: import typing_extensions typing_extensions.Buffer = None !pip install -q rdkit rdkit-to-params biopython pyrosetta-help jsme_notebook !pip install -q --upgrade plotly # Installation for PLIP # this wrongly assumes Mamba and Colab will stay at 3.10 for ever... !wget -qnc https://github.com/conda-forge/miniforge/releases/latest/download/Mambaforge-Linux-x86_64.sh # Mamba at 3.10 #!wget -qnc https://github.com/conda-forge/miniforge/releases/download/23.3.1-1/Mambaforge-23.3.1-1-Linux-x86_64.sh !bash Mambaforge-Linux-x86_64.sh -bfp /usr/local python_version = f'{sys.version_info.major}.{sys.version_info.minor}' sys.path.append(f'/usr/local/lib/python{python_version}/site-packages') !mamba config --set auto_update_conda false # PLIP gets confused. Weird install !mamba install -y -c conda-forge openbabel lxml !mamba install -y -c conda-forge --no-deps plip import os from importlib import reload import pyrosetta_help as ph from typing import * # Colab no longer runs on 3.7 # keeping this just in case it's needed again # hack to enable the backport: import sys if sys.version_info.major != 3 or sys.version_info.minor < 8: !pip install -q singledispatchmethod import functools from singledispatchmethod import singledispatchmethod # noqa it's okay, PyCharm, I am not a technoluddite functools.singledispatchmethod = singledispatchmethod !pip install -q typing_extensions import typing_extensions import typing for key, fun in typing_extensions.__dict__.items(): if key not in typing.__dict__: setattr(typing, key, fun) ``` -------------------------------- ### Install Fragmenstein Source: https://github.com/matteoferla/fragmenstein/blob/master/documentation/00_installation.md Standard installation command for the Fragmenstein package. ```bash python -m pip install fragmenstein ``` -------------------------------- ### Setup SQLite Database Connection Source: https://github.com/matteoferla/fragmenstein/blob/master/documentation/further-detail/pipeline.md Initializes the SQLite database for storing results. Ensures data is automatically committed. ```python import os, re from sqlitedict import SqliteDict import json results = SqliteDict(db_name, encode=json.dumps, decode=json.loads, autocommit=True) ``` -------------------------------- ### Install PyRosetta with Google Drive Option Source: https://github.com/matteoferla/fragmenstein/blob/master/colab-notebooks/colab_fragmenstein.ipynb Installs PyRosetta, with an option to download a release to Google Drive for faster subsequent installations. Requires PyRosetta academic license credentials. ```python download_to_drive = False #@param {type:"boolean"} download_path = '.' #@param {type:"string"} username = 'boltzmann' #@param {type:"string"} username.strip().lower() password = 'constant' #@param {type:"string"} hash_comparison_required = True #@param {type:"boolean"} if download_to_drive and not use_drive: raise ValueError('You said False to `use_drive` and True to `download_to_drive`? Very funny.') elif download_to_drive: ph.download_pyrosetta(username=username, password=password, path=download_path, hash_comparison_required=hash_comparison_required) else: pass ph.install_pyrosetta(username=username, password=password, path=download_path, hash_comparison_required=hash_comparison_required) reload(ph) ``` -------------------------------- ### Install PyRosetta via Terminal Source: https://github.com/matteoferla/fragmenstein/blob/master/documentation/00_installation.md Legacy method for downloading and installing PyRosetta using curl and tar. ```bash curl -u 👾👾👾:👾👾👾https://graylab.jhu.edu/download/PyRosetta4/archive/release/PyRosetta4.Release.python38.linux/PyRosetta4.Release.python38.linux.release-NNN.tar.bz2 -o a.tar.bz2 tar -xf a.tar.bz2 cd PyRosetta4.Release.python38.linux sudo pip3 install . ``` -------------------------------- ### Setup Molecule and Reference Dropdowns Source: https://github.com/matteoferla/fragmenstein/blob/master/colab-notebooks/colab_playground.ipynb Configures dropdown widgets for selecting a molecule to manipulate and a reference molecule. The 'options' should be populated with molecule names. ```python mol_dropdown = widgets.Dropdown( options=names, tooltip='The molecule to move', description='Molecule to rototranslate:', disabled=False, ) ref_dropdown = widgets.Dropdown( options=names, description='Ref molecule:', disabled=False, ) ``` -------------------------------- ### Install Fragmenstein and Dependencies Source: https://github.com/matteoferla/fragmenstein/blob/master/colab-notebooks/colab_fragmenstein.ipynb Installs the Fragmenstein package and its dependencies using pip. Includes a commented-out alternative for installing from a development branch. ```bash !pip install smallworld_api fragmenstein # Hey, future me, debugging are we? try: # os.system('pip install git+https://github.com/matteoferla/Fragmenstein.git@dev-teo3') ``` -------------------------------- ### Initialize Igor from PDB File Source: https://github.com/matteoferla/fragmenstein/blob/master/documentation/further-detail/igor.md Alternative initialization for Igor using a PDB file path. This method is useful when starting from existing PDB structures. ```python Igor.from_pdbfile(pdb_file, constraint_filename) ``` -------------------------------- ### Example Slurm Script for Fragmenstein Pipeline Source: https://github.com/matteoferla/fragmenstein/blob/master/documentation/04_cmd.md This script is designed to be submitted to a Slurm cluster for running Fragmenstein pipelines. It includes environment variable setup, conda activation, and the main pipeline execution command. Ensure that the necessary environment variables like EXPERIMENT, TEMPLATE, HITS, and COMBO are set before submission. ```bash #!/bin/bash # Some note for myself on usage # submit via: # export EXPERIMENT='_foo'; export TEMPLATE='protein.pdb'; export HITS='hits.sdf'; # export COMBO=2; export SLACK_WEBHOOK=''; # sbatch /mtn/someshared-drive/frag.slurm.sh; #SBATCH --job-name=fragmenstein #SBATCH --chdir=/mtn/someshared-drive/mferla #SBATCH --output=/mtn/someshared-drive/logs/slurm-error_%x_%j.log #SBATCH --error=/mtn/someshared-drive/logs/slurm-error_%x_%j.log #SBATCH --clusters=clustername-this-is-cluster-specific #SBATCH --partition=this-is-kind-of-the-group-and-is-cluster-specific #SBATCH --nodes=1 #SBATCH --exclusive #SBATCH --export=NONE,SLACK_WEBHOOK,COMBO,EXPERIMENT,TEMPLATE,HITS # ------------------------------------------------------- # Some slurm fluff for logs export SUBMITTER_HOST=$HOST export HOST=$( hostname ) export USER=${USER:-$(users)} export DATA=/mtn/someshared-drive export HOME=$DATA/$USER; # homeless source /etc/os-release; echo "Running $SLURM_JOB_NAME ($SLURM_JOB_ID) as $USER in $HOST which runs $PRETTY_NAME submitted from $SUBMITTER_HOST" echo "Request had cpus=$SLURM_JOB_CPUS_PER_NODE mem=$SLURM_MEM_PER_NODE tasks=$SLURM_NTASKS jobID=$SLURM_JOB_ID partition=$SLURM_JOB_PARTITION jobName=$SLURM_JOB_NAME" echo "Started at $SLURM_JOB_START_TIME" echo "job_pid=$SLURM_TASK_PID job_gid=$SLURM_JOB_GID topology_addr=$SLURM_TOPOLOGY_ADDR home=$HOME cwd=$PWD" # ------------------------------------------------------- # Some conda fluff # assuming you have an appropriate conda installed in `$HOME/conda-slurm` source $HOME/conda-slurm/etc/profile.d/conda.sh conda activate base; # or whatever pwd; export EXPERIMENT=${EXPERIMENT:-'fragduo'} export COMBO=${COMBO:-2} export TEMPLATE=${TEMPLATE:-'template.pdb'} export HITS=${HITS:-'hits.sdf'} export LD_LIBRARY_PATH=$CONDA_PREFIX/lib:$CONDA_PREFIX; #export N_CORES=$(cat /proc/cpuinfo | grep processor | wc -l); export N_CORES=$SLURM_CPUS_ON_NODE; nice -19 fragmenstein pipeline \ --template $TEMPLATE \ --input $HITS \ --n_cores $(($N_CORES - 1)) \ --suffix _$EXPERIMENT \ --max_tasks 5000 \ --sw_databases REAL-Database-22Q1.smi.anon \ --combination_size $COMBO \ --workfolder /tmp/$EXPERIMENT \ --timeout 600; rm -rf /tmp/$EXPERIMENT; curl -X POST -H 'Content-type: application/json' --data '{"text":"'$EXPERIMENT' x2 complete"}' $SLACK_WEBHOOK # ------------------------------------------------------- echo 'complete' exit 0 ``` -------------------------------- ### Install and Enable Colab Widgets Source: https://github.com/matteoferla/fragmenstein/blob/master/colab-notebooks/colab_fragmenstein_Wictor.ipynb Installs the py3Dmol package and enables custom widget manager for Google Colaboratory. ```python !pip install py3Dmol -q from google.colab import output # noqa (It's a colaboratory specific repo) output.enable_custom_widget_manager() ``` -------------------------------- ### Install Fragmenstein and Dependencies Source: https://github.com/matteoferla/fragmenstein/blob/master/colab-notebooks/colab_fragmenstein_Wictor.ipynb Installs the smallworld_api and fragmenstein packages. This is a prerequisite for using Fragmenstein functionalities. ```python !pip install smallworld_api fragmenstein -q ``` -------------------------------- ### Example ringcore expansion data structure Source: https://github.com/matteoferla/fragmenstein/blob/master/documentation/monster/no_template.md The dictionary structure returned by _get_expansion_data for a ringcore atom. ```json { '_ori_name': 'toluene', '_ori_i': -1, '_ori_is': '[0, 5, 4, 3, 2, 1]', '_neighbors': '[[1, 5], [4, 6, 0], [3, 5], [2, 4], [1, 3], [0, 2]]', '_xs': '[1.5, 0.75, -0.75, -1.5, -0.75, 0.75]', '_ys': '[0.0, 1.299, 1.299, 0.0, -1.299, -1.299]', '_zs': '[0.0, 0.0, 0.0, 0.0, 0.0, 0.0]', '_elements': '["C", "C", "C", "C", "C", "C"]', '_bonds': '[["AROMATIC", "AROMATIC"], ["AROMATIC", "SINGLE", "AROMATIC"], ["AROMATIC", "AROMATIC"], ["AROMATIC", "AROMATIC"], ["AROMATIC", "AROMATIC"], ["AROMATIC", "AROMATIC"]]'} ``` -------------------------------- ### Setup Rotation and Distance Widgets Source: https://github.com/matteoferla/fragmenstein/blob/master/colab-notebooks/colab_playground.ipynb Sets up integer text widgets for specifying rotation angles in degrees and distances in Angstroms. Default values are set to 0. ```python theta_text = widgets.IntText( value=0, description='Angle [°]', disabled=False ) distance_text = widgets.IntText( value=0, description='Distance [Å]', disabled=False ) ``` -------------------------------- ### Custom Mapping Format Example 1 Source: https://github.com/matteoferla/fragmenstein/blob/master/documentation/monster/custom_mapping.md Illustrates the basic format for custom mapping, where keys are hit names and values are dictionaries mapping hit atom index to followup atom index. ```python mapping = { 'hit1': {1:1,2:5} 'hit2': {3:3,4:4,4:6}} ``` -------------------------------- ### Create Molecule Widgets Source: https://github.com/matteoferla/fragmenstein/blob/master/colab-notebooks/colab_playground.ipynb Sets up interactive widgets for molecule creation, including text input for molecule names and buttons to add or discard molecules. This requires `ipywidgets` and `jsme-notebook` to be installed. ```python from jsme_notebook import JSMENotebook from IPython.display import display import ipywidgets as widgets from rdkit import Chem from rdkit.Chem import AllChem from fragmenstein import display_mols import re, os # ------------------------------------------------- name_input = widgets.Text(description='Name molecule', value='') add_button = widgets.Button(description="Add molecule", icon='plus') clear_button = widgets.Button(description="Discard molecules", icon='trash') ``` -------------------------------- ### Setup Atom Index and Translation Widgets Source: https://github.com/matteoferla/fragmenstein/blob/master/colab-notebooks/colab_playground.ipynb Initializes integer text widgets for specifying atom indices and translation distances along the X, Y, and Z axes. Default values are set to 0. ```python atom_idx0_text = widgets.IntText( value=0, description='1st atom:', disabled=False ) atom_idx1_text = widgets.IntText( value=1, description='2nd atom:', disabled=False ) atom_idx2_text = widgets.IntText( value=1, description='3rd atom:', disabled=False ) x_text = widgets.IntText( value=0, description='x [Å]', disabled=False ) y_text = widgets.IntText( value=0, description='y [Å]', disabled=False ) z_text = widgets.IntText( value=0, description='z [Å]', disabled=False ) ``` -------------------------------- ### Instantiate and Use Wictor Source: https://github.com/matteoferla/fragmenstein/blob/master/documentation/notes/no_minimisation.md Instantiate the custom `Wictor` class with provided molecular data and perform combination. This example assumes `Mac1` is available for demo data. ```python Wictor = ... # see above from fragmenstein.demo import Mac1 Wictor.capture_rdkit_log() #Wictor.enable_stdout() Wictor.error_to_catch = () wicky = Wictor(hits=Mac1.get_n_filtered_mols(2), pdb_block=Mac1.get_template(), ) wicky.combine() wicky.to_nglview() ``` -------------------------------- ### Custom Mapping Format Example 2 (Special Index -1) Source: https://github.com/matteoferla/fragmenstein/blob/master/documentation/monster/custom_mapping.md Demonstrates the use of the special followup index -1, which signifies that the hit index is not provided. This is for clarity and not intended for direct use. ```python mapping = { 'hit1': {1:1,2:5, 3:-1} 'hit2': {3:3,4:4,4:6}} ``` -------------------------------- ### Initialize Project Settings Source: https://github.com/matteoferla/fragmenstein/blob/master/documentation/further-detail/pipeline.md Sets up project-specific variables like input folder, number of cores, output path, and database name. ```python project = 'mergers' input_foldername = 'input' ############################################## cores = 20 out_path = f'{project}' db_name = f'{project}.sqlite' ############################################## ``` -------------------------------- ### Define Function to Get Best Hit PDB Filename Source: https://github.com/matteoferla/fragmenstein/blob/master/documentation/further-detail/victor.md A function that determines the closest hit PDB file from a list of hit codes, targeting a specific residue and atom. This is used to select a starting point for reanimation. ```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') ``` -------------------------------- ### Set up Fragmenstein Working Directories Source: https://github.com/matteoferla/fragmenstein/blob/master/colab-notebooks/colab_fragmenstein_Wictor.ipynb Creates necessary directories for Fragmenstein data, input, and output. Changes the current working directory to 'fragmenstein_data'. ```python # make folders in _path working_folder = 'fragmenstein_data' input_folder = 'input' output_folder = 'output' if not os.path.exists(working_folder): os.mkdir(working_folder) os.chdir('fragmenstein_data') for folder in (input_folder, output_folder): if not os.path.exists(folder): os.mkdir(folder) ``` -------------------------------- ### Initialize and Minimize with Igor Source: https://github.com/matteoferla/fragmenstein/blob/master/documentation/further-detail/igor.md Initialize Igor with a Pose and constraint filename, then run minimization for a specified number of steps. Ensure pose is a pyrossetta.Pose instance. ```python e = Igor(pose, constraint_filename) e.minimize(10) ``` -------------------------------- ### Initialize and place a molecule Source: https://github.com/matteoferla/fragmenstein/blob/master/documentation/further-detail/changelog_0.6.md Demonstrates the standard workflow for initializing a Monster object and placing a molecule. ```python monster = Monster(hits) monster.place(mol) monster.positioned_mol ``` -------------------------------- ### Configure File Paths and Environment Source: https://github.com/matteoferla/fragmenstein/blob/master/documentation/further-detail/pipeline.md Sets up directory paths and ensures the target folder exists for output files. ```python title = 'Fragmenstein NSP3 Mergers' #gitfolder=f'/well/brc/matteo/{repo_name}' gitfolder=f'/well/brc/matteo/NSP3/git-repo' sdfile=f'{gitfolder}/{folder}/mergers.sdf' xlsfile=f'{gitfolder}/{folder}/mergers.xlsx' targetfolder=f'{gitfolder}/{folder}' import os, re if not os.path.exists(targetfolder): os.mkdir(targetfolder) target = 'Mike' #target = 'Excel' #target = 'Frag' ``` -------------------------------- ### Initialize and Execute Fragmenstein Merger Source: https://github.com/matteoferla/fragmenstein/blob/master/documentation/monster/monster_full.md Demonstrates loading hit molecules, initializing the Fragmenstein merger with a followup compound, and generating output structures. ```python hits = [Chem.MolFromMolFile(f'../Mpro/Mpro-{i}_0/Mpro-{i}_0.mol') for i in ('x0692', 'x0305', 'x1249')] followup = Chem.MolFromSmiles('CCNc1nc(CCS)c(C#N)cc1CN1C(CCS)CN(C(C)=O)CC1') monster = Fragmenstein(followup, hits) #monster = Fragmenstein(followup, hits, draw=True) for verbosity in a Jupyter notebook monster.make_pse('test.pse') display(monster.scaffold) display(monster.chimera) # merger of hits but with atoms made to match the to-be-aligned mol display(monster.positioned_mol) # followup aligned # further alignments... not correct way of tho monster.initial_mol = new_mol aligned = monster.place_from_map(new_mol) ``` -------------------------------- ### Initialize Visualization Environment Source: https://github.com/matteoferla/fragmenstein/blob/master/colab-notebooks/colab_fragmenstein_Wictor.ipynb Imports necessary IPython and ipywidgets modules and defines a helper function for HTML headers. ```python from IPython.display import clear_output, HTML, display from ipywidgets import interact, interactive, fixed, interact_manual import ipywidgets as widgets headerify: Callable[[str], HTML] = lambda header: HTML(f'

{header}

') clear_output() ``` -------------------------------- ### Install Fragmenstein Dependencies Source: https://github.com/matteoferla/fragmenstein/blob/master/colab-notebooks/colab_fragmenstein.ipynb Installs necessary Python packages for Fragmenstein, including py3Dmol, rdkit, and pyrosetta-help. It also includes a check for Colab environment and optional installation of notebook-error-reporter and typing_extensions for older Python versions. ```python #@title Installation #@markdown Press the play button on the top right hand side of this cell #@markdown once you have checked the settings. #@markdown You will be notified that this notebook is not from Google, that is normal. #@markdown Send error messages to errors.matteoferla.com for logging? #@markdown See [notebook-error-reporter repo for more](https://github.com/matteoferla/notebook-error-reporter) report_errors = False #@param {type:"boolean"} if report_errors: !pip install notebook-error-reporter from notebook_error_reporter import ErrorServer es = ErrorServer(url='https://errors.matteoferla.com', notebook='fragmenstein') es.enable() !pip install -q py3Dmol rdkit rdkit-to-params biopython pyrosetta-help jsme_notebook !pip install -q --upgrade plotly import os import py3Dmol from importlib import reload import pyrosetta_help as ph from typing import * # Muppet-proofing: are we in colab? assert ph.get_shell_mode() == 'colab', 'This is a colab notebook, if running in Jupyter notebook, the installation is different' # Colab still runs on 3.7 # hack to enable the backport: import sys if sys.version_info.major != 3 or sys.version_info.minor < 8: !pip install -q singledispatchmethod import functools from singledispatchmethod import singledispatchmethod # noqa it's okay, PyCharm, I am not a technoluddite functools.singledispatchmethod = singledispatchmethod !pip install -q typing_extensions import typing_extensions import typing for key, fun in typing_extensions.__dict__.items(): if key not in typing.__dict__: setattr(typing, key, fun) ``` -------------------------------- ### Fragmenstein Pipeline Help Source: https://github.com/matteoferla/fragmenstein/blob/master/documentation/04_cmd.md Display the command-line usage and available options for the pipeline tool. ```text usage: fragmenstein pipeline [-h] -t TEMPLATE -i INPUT [-o OUTPUT] [-r RANKING] [-c CUTOFF] [-q QUICK] [-d SW_DIST] [-l SW_LENGTH] [-b SW_DATABASES [SW_DATABASES ...]] [-s SUFFIX] [--workfolder WORKFOLDER] [--victor VICTOR] [-n N_CORES] [-m COMBINATION_SIZE] [-k TOP_MERGERS] [-e TIMEOUT] [-x MAX_TASKS] [-z BLACKLIST] [-j WEIGHTS] [-v] options: -h, --help show this help message and exit -t TEMPLATE, --template TEMPLATE Template PDB file -i INPUT, --input INPUT Hits SDF file -o OUTPUT, --output OUTPUT Output folder -r RANKING, --ranking RANKING Ranking method -c CUTOFF, --cutoff CUTOFF Joining cutoff -q QUICK, --quick QUICK Quick reanimation -d SW_DIST, --sw_dist SW_DIST SmallWorld distance -l SW_LENGTH, --sw_length SW_LENGTH SmallWorld length -b SW_DATABASES [SW_DATABASES ...], --sw_databases SW_DATABASES [SW_DATABASES ...] SmallWorld databases. Accepts multiple -s SUFFIX, --suffix SUFFIX Suffix for output files --workfolder WORKFOLDER Location to put the temp files --victor VICTOR Which victor to use: Victor, OpenVictor or Wictor -n N_CORES, --n_cores N_CORES Number of cores -m COMBINATION_SIZE, --combination_size COMBINATION_SIZE Number of hits to combine in one step -k TOP_MERGERS, --top_mergers TOP_MERGERS Max number of mergers to followup up on -e TIMEOUT, --timeout TIMEOUT Timeout for each merger -x MAX_TASKS, --max_tasks MAX_TASKS Max number of combinations to try in a batch -z BLACKLIST, --blacklist BLACKLIST Blacklist file -j WEIGHTS, --weights WEIGHTS JSON weights file -v, --verbose verbose ``` -------------------------------- ### Configure Fragmenstein Logging and Settings Source: https://context7.com/matteoferla/fragmenstein/llms.txt Demonstrates how to configure logging levels (stdout and file) and working directory for Fragmenstein. Also shows how to adjust Monster settings and access the logger directly. ```python from fragmenstein import Victor, Igor import logging # Enable stdout logging Victor.enable_stdout(logging.INFO) # Or log to file Victor.enable_logfile('fragmenstein.log', logging.DEBUG) # Set working directory for output files Victor.work_path = 'output/' # Access the logger directly Victor.journal.info("Starting Fragmenstein run") # Configure Monster settings via Victor Victor.monster_throw_on_discard = False # Don't raise error when hits are discarded Victor.monster_mmff_minisation = True # Enable MMFF minimization in Monster Victor.quick_reanimation = False # Full minimization attempts # Configure via environment variables # export FRAGMENSTEIN_MONSTER_THROW_ON_DISCARD=false # export FRAGMENSTEIN_WORK_PATH=/tmp/fragmenstein ``` -------------------------------- ### Install Fragmenstein Dependencies Source: https://github.com/matteoferla/fragmenstein/blob/master/colab-notebooks/colab_playground.ipynb Installs required Python packages for Fragmenstein, py3Dmol, and related tools. Ensure this runs before importing modules that depend on these packages. ```bash !pip install -q py3Dmol fragmenstein smallworld-api notebook-error-reporter jsme_notebook ``` -------------------------------- ### Refresh Python Site Packages Source: https://github.com/matteoferla/fragmenstein/blob/master/colab-notebooks/colab_fragmenstein_Wictor.ipynb Ensures that the Python environment is up-to-date with installed packages. ```python # refresh imports import site site.main() ``` -------------------------------- ### Initialize PyRosetta Environment Source: https://github.com/matteoferla/fragmenstein/blob/master/colab-notebooks/colab_fragmenstein.ipynb Configures PyRosetta with specific options for ligand handling and logging. ```python #@title Start PyRosetta #@markdown Leave alone and just run it. #@markdown Only one that you might want to change is `ignore_waters` #@markdown as merging a ligand with its watershell may be a reasonable thing to do #@markdown in extreme circumstances —like not even Chuck Norris could find a followup. import pyrosetta, logging import pyrosetta_help as ph #@markdown Do not optimise hydrogen on loading: no_optH = False #@param {type:"boolean"} #@markdown Ignore (True) or raise error (False) if novel residue (e.g. ligand) — **don't tick this**. ignore_unrecognized_res = False #@param {type:"boolean"} #@markdown Use autogenerated PDB residues are often weird (bad geometry, wrong match, protonated etc.): —best do it properly and parameterise it, so **don't tick this**. load_PDB_components = False #@param {type:"boolean"} #@markdown Ignore all waters: ignore_waters = True #@param {type:"boolean"} extra_options = ph.make_option_string(no_optH=no_optH, ex1=None, ex2=None, mute='all', ignore_unrecognized_res=ignore_unrecognized_res, load_PDB_components=load_PDB_components, ignore_waters=ignore_waters) # capture to log # circuitous as I needed to debug... logger = ph.configure_logger() logger.handlers[0].setLevel(logging.WARNING) # logging.WARNING = 30 pyrosetta.init(extra_options=extra_options, #set_logging_handler=True ) ``` -------------------------------- ### Initialize Molecule Management Widgets Source: https://github.com/matteoferla/fragmenstein/blob/master/colab-notebooks/colab_playground.ipynb Sets up the UI components for molecule input and display, including a JSME editor and a grid layout for controls. ```python output = widgets.Output(layout={'border': '1px solid black'}) uploader = widgets.FileUpload(icon='upload') jsme = JSMENotebook() # outputs to display as is not a widget grid = widgets.GridspecLayout(1, 4) grid[0,0] = name_input grid[0,1] = add_button grid[0,2] = uploader grid[0,3] = clear_button display(grid, output) ``` -------------------------------- ### Initialize Laboratory with PLIP Source: https://github.com/matteoferla/fragmenstein/blob/master/documentation/02_usage.md Enable PLIP interaction prediction within the Laboratory wrapper. ```python lab = Laboratory(pdbblock=pdbblock, run_plip=True) ``` -------------------------------- ### Minimize with Coordinate Constraints Source: https://github.com/matteoferla/fragmenstein/blob/master/documentation/further-detail/igor.md Run minimization with coordinate constraints. If no constraints are in the file, `default_coord_constraint=True` will enforce constraints to the starting coordinates. ```python e.minimise(default_coord_constraint=True) ``` -------------------------------- ### Initialize Pyrosetta and Prepare Protein Template Source: https://github.com/matteoferla/fragmenstein/blob/master/documentation/further-detail/pipeline.md Initializes Pyrosetta, downloads a CCP4 map, and prepares a protein template from a PDB file with non-standard residue parameters. It then relaxes the pose using energy-based restraints and saves the result. Finally, it uses PyMOL to clean the template by removing a specific residue and saving it. ```python pdbcode = '6WOJ' # ADP bound. from fragmenstein import Victor, Igor Igor.download_map(pdbcode, pdbcode+'.ccp4') # topology from rdkit_to_params import Params p = Params.from_smiles_w_pdbfile(pdb_file='mono.pdb', smiles='Nc1ncnc2n(cnc12)[C@@H]3O[C@H](CO[P@@]([O-])(=O)O[P@@]([O-])(=O)OC[C@H]4O[C@@H](O)[C@H](O)[C@@H]4O)[C@@H](O)[C@H]3O', name='APR', proximityBonding=False) p.dump('APR.params') # start import pyrosetta pyrosetta.init(extra_options='-no_optH false -mute all -ex1 -ex2 -ignore_unrecognized_res false -load_PDB_components false -ignore_waters false') #import nglview #nglview.show_rosetta(p.test()) params_file = 'APR.params' pdbfile = 'mono.pdb' # 6WOJ manually inspected. pose = pyrosetta.Pose() params_paths = pyrosetta.rosetta.utility.vector1_string() params_paths.extend([params_file]) pyrosetta.generate_nonstandard_residue_set(pose, params_paths) pyrosetta.rosetta.core.import_pose.pose_from_file(pose, pdbfile) Igor.relax_with_ED(pose=pose, ccp4_file=pdbcode+'.ccp4') pose.dump_pdb('mono.r.pdb') # this part makes no sense, but is just an example —in reality checking the result visually would make more sense. # or it could be done in Pyrosetta. import pymol2 with pymol2.PyMOL() as pymol: pymol.cmd.load('mono.r.pdb') pymol.cmd.remove('resn APR') pymol.cmd.save('template.pdb') ``` -------------------------------- ### Use Monster without Pyrosetta Source: https://github.com/matteoferla/fragmenstein/blob/master/documentation/03_examples.md Import and use the Monster class from Fragmenstein without requiring Pyrosetta to be installed. Useful for licensing reasons. ```python from fragmenstein import Monster ``` -------------------------------- ### Setup Axis Selection Dropdowns Source: https://github.com/matteoferla/fragmenstein/blob/master/colab-notebooks/colab_playground.ipynb Configures dropdown widgets for selecting rotation or translation axes (X, Y, Z). Default selections are 'x' and 'y'. ```python axis0_dropdown = widgets.Dropdown( options=['x', 'y', 'z'], value='x', description='1st axis:', disabled=False, ) axis1_dropdown = widgets.Dropdown( options=['x', 'y', 'z'], value='y', description='2nd axis:', disabled=False, ) ``` -------------------------------- ### Initialize Pyrosetta with Helper Function Source: https://github.com/matteoferla/fragmenstein/blob/master/documentation/03_examples.md Initialize Pyrosetta using a helper function from the pyrosetta_help module for cleaner option string generation. ```python import pyrosetta from pyrosetta_help import make_option_string extras = make_option_string(no_optH=False, mute='all', ignore_unrecognized_res=False, load_PDB_components=False) pyrosetta.init(extra_options=extras) ``` -------------------------------- ### Get SMILES from Dictionary Source: https://github.com/matteoferla/fragmenstein/blob/master/colab-notebooks/colab_fragmenstein.ipynb Retrieves the SMILES string for a given molecule name from a pre-parsed SMILES dictionary. Issues a warning if the name is not found. ```python def get_smiles(filename: str, smilesdex: Dict[str, str]) -> Union[None, str]: name = os.path.splitext(filename)[0] if name in smilesdex: return smilesdex[name] else: warn(f'Could not find matching SMILES to {name}') return None ``` -------------------------------- ### Initialize Pyrosetta and Import Fragmenstein Classes Source: https://github.com/matteoferla/fragmenstein/blob/master/documentation/further-detail/victor.md Initializes the pyrosetta library with specific options and imports necessary classes from the fragmenstein package. Ensure pyrosetta is initialized before other imports. ```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 ``` -------------------------------- ### Import Fragmenstein without PyRosetta Source: https://github.com/matteoferla/fragmenstein/blob/master/documentation/notes/no_minimisation.md Import `Victor` from Fragmenstein. A `RuntimeWarning` will indicate that PyRosetta is not installed and a mock object is loaded. Calls to PyRosetta-dependent methods will fail. ```python from fragmenstein import Victor # RuntimeWarning: PyRosetta is not installed. A mock object is loaded. Any calls will fail. from fragmenstein import __version__ as fragn_version print(fragn_version) # 0.9.12.6 ``` -------------------------------- ### Initialize Pyrosetta with Options Source: https://github.com/matteoferla/fragmenstein/blob/master/documentation/03_examples.md Initialize Pyrosetta with specific options to control behavior like H-bond optimization and unrecognized residue handling. ```python import pyrosetta pyrosetta.init(extra_options='-no_optH false -mute all -ignore_unrecognized_res false -load_PDB_components false') ``` -------------------------------- ### Enable Debug Logging for Victor Source: https://github.com/matteoferla/fragmenstein/blob/master/documentation/notes/troubleshooting_example.md Enable stdout logging for the Victor class at the DEBUG level to get more detailed information during execution. This is useful for diagnosing cryptic errors. ```python import logging Victor.enable_stdout(level=logging.DEBUG) ``` -------------------------------- ### Initialize Fragmenstein Laboratory Source: https://github.com/matteoferla/fragmenstein/blob/master/colab-notebooks/colab_fragmenstein.ipynb Sets up the Fragmenstein Laboratory with specified parameters like working path, cutoffs, and error handling. It then combines hits using the provided PDB block and covalent residue information. ```python import os, re import pyrosetta, logging import pandas as pd from rdkit import Chem from fragmenstein import Victor, Laboratory Victor.work_path = output_folder Victor.monster_throw_on_discard = True # stop this merger if a fragment cannot be used. Victor.monster_joining_cutoff = joining_cutoff # Å Victor.quick_reanimation = quick_reananimation # for the impatient Victor.error_to_catch = Exception # stop the whole laboratory otherwise #Victor.enable_stdout(logging.ERROR) Victor.enable_logfile(os.path.join(output_folder, 'demo.log'), logging.ERROR) # calculate ! lab = Laboratory(pdbblock=pdbblock, covalent_resi=covalent_resi) n_cores = 1 #@param {type:"integer"} combinations:pd.DataFrame = lab.combine(hits, n_cores=n_cores) ``` -------------------------------- ### Import Necessary Libraries for Molecule Manipulation Source: https://github.com/matteoferla/fragmenstein/blob/master/colab-notebooks/colab_playground.ipynb Imports essential libraries for molecule manipulation, including Fragmenstein, ipywidgets, RDKit, and SmallWorld API. Ensure these libraries are installed before use. ```python from warnings import warn from fragmenstein import Walton, Monster from ipywidgets import TwoByTwoLayout from IPython.display import clear_output, display, HTML from functools import partial from rdkit import Chem, Geometry from rdkit.Chem import PandasTools import pandas as pd from smallworld_api import SmallWorld from warnings import warn from threading import Lock from jsme_notebook.rdkit import JSMERDKit ``` -------------------------------- ### Initialize PyRosetta with Generalised Potentials Source: https://github.com/matteoferla/fragmenstein/blob/master/documentation/further-detail/generalised_potentials.md Configure PyRosetta options to enable the beta_genpot scorefunction. This must be done during the initial call to pyrosetta.init. ```python import pyrosetta_help as ph import pyrosetta extra_options= ph.make_option_string(no_optH=False, ex1=True, ex2=True, gen_potential=True, score=dict(weights='beta_genpot_cart'), #mute='all', ignore_unrecognized_res=False, # raise error if unrecognized load_PDB_components=False, ignore_waters=False) # weights can be one of ['beta_genpot', 'beta_genpot_cart', 'beta_genpot_cst', 'beta_genpot_soft'] pyrosetta.init(extra_options=extra_options) # no idea why I get this, but it is not an issue: # core.init.score_function_corrections: [ WARNING ] Flag -beta_nov16 is set but either -weights are also specified or this is being used with the genpot score function. Not changing input weights file! # core.init.score_function_corrections: [ WARNING ] Flag -gen_potential is set but -weights are also specified. Not changing input weights file! scorefxn = pyrosetta.get_fa_scorefxn() assert scorefxn.get_name() == 'beta_genpot_cart' ``` -------------------------------- ### Configure Fragmenstein Wictor and Laboratory Source: https://github.com/matteoferla/fragmenstein/blob/master/colab-notebooks/colab_fragmenstein_Wictor.ipynb Sets up global parameters for Wictor and Laboratory, including working path, error handling, and logging. Ensure output_folder is defined before execution. ```python import os, re, logging import pandas as pd from rdkit import Chem from fragmenstein import Wictor, Laboratory Wictor.work_path = output_folder Wictor.monster_throw_on_discard = True # stop this merger if a fragment cannot be used. Wictor.monster_joining_cutoff = joining_cutoff # Å Wictor.error_to_catch = Exception # stop the whole laboratory otherwise Wictor.enable_stdout(logging.ERROR) Wictor.enable_logfile(os.path.join(output_folder, 'demo.log'), logging.ERROR) Laboratory.Victor = Wictor ``` -------------------------------- ### Custom Mapping Format Example 3 (Special Index -2) Source: https://github.com/matteoferla/fragmenstein/blob/master/documentation/monster/custom_mapping.md Shows the use of the special followup index -2, which indicates that the hit atom index will not match any followup index. ```python mapping = { 'hit1': {1:1,2:5, 3:-2} 'hit2': {3:3,4:4,4:6}} ``` -------------------------------- ### Load Demo Data with Mac1 Source: https://github.com/matteoferla/fragmenstein/blob/master/documentation/03_examples.md Load template and hit list data using the Mac1 class from fragmenstein.demo. Useful for testing. ```python from fragmenstein.demo import MPro, Mac1 pdbblock: str = Mac1.get_template() hitname: str = ... for hitname in Mac1.get_hit_list(): Mac1.get_hit(hitname) ... ``` -------------------------------- ### Initialize Fragmenstein Environment Source: https://github.com/matteoferla/fragmenstein/blob/master/colab-notebooks/colab_playground.ipynb Sets up the Fragmenstein environment by importing necessary classes and configuring logging. This snippet also initializes the `Walton` object, which is a core component for running Fragmenstein. ```python from fragmenstein import Walton, display_mols, Victor import logging Victor.enable_stdout(logging.ERROR) walton = Walton([]) ``` -------------------------------- ### Initialize and Run Fragmenstein Laboratory Source: https://github.com/matteoferla/fragmenstein/blob/master/colab-notebooks/colab_fragmenstein_Wictor.ipynb Initializes the Laboratory with a PDB block and covalent residue information, then runs the combination process. Requires `pdbblock` and `covalent_resi` to be defined. ```python # calculate ! lab = Laboratory(pdbblock=pdbblock, covalent_resi=covalent_resi) n_cores = 1 #@param {type:"integer"} combinations:pd.DataFrame = lab.combine(hits, n_cores=n_cores) ``` -------------------------------- ### Load Molecules from GitHub Repository Source: https://github.com/matteoferla/fragmenstein/blob/master/colab-notebooks/colab_fragmenstein_Wictor.ipynb Fetches molecular files from a GitHub repository and parses them. Requires PyGithub installation. The `_content2mol` function handles individual file content, and `hits_from_github` orchestrates the retrieval from a specified folder. ```python !pip install PyGithub from github import Github from github.ContentFile import ContentFile import os from typing import Tuple, List from rdkit import Chem # ------------------------------------------------------- def _content2mol(content:ContentFile) -> Chem.Mol: if content.path.count('-') > 1: return # "molfiles/diamond-x0158_B.mol" filename = os.path.split(content.path)[1] if not some_filter(filename): return None mol: Chem.Mol = Chem.MolFromMolBlock( content.decoded_content.decode('utf8') ) mol.SetProp('_Name', filename) return mol def get_repo(username:str, repo_name:str) -> Github: return Github().get_user(username).get_repo(repo_name) def hits_from_github(username:str, repo_name:str, folder:str) -> List[Chem.Mol]: repo = get_repo(username, repo_name) return list(filter(lambda x: x is not None, map(_content2mol, repo.get_contents(folder)))) # ----------------- Change these: all_hits:List[Chem.Mol] = hits_from_github(username='matteoferla', repo_name='NSP3-macrodomain', folder='molfiles') hits = all_hits[:20] pdbblock:str = get_repo(username='matteoferla', repo_name='NSP3-macrodomain').get_contents("molfiles/template.pdb").decoded_content.decode('utf8') ``` -------------------------------- ### Fragmenstein CLI: Full Pipeline with SmallWorld Catalogue Search Source: https://context7.com/matteoferla/fragmenstein/llms.txt Command to run the full Fragmenstein pipeline, including SmallWorld catalogue search, with specified parameters for template, input hits, cores, combination size, database, length, timeout, and output. ```bash fragmenstein pipeline \ --template template.pdb \ --input hits.sdf \ --n_cores 8 \ --combination_size 2 \ --sw_databases REAL-Database-22Q1.smi.anon \ --sw_length 50 \ --timeout 600 \ --output results/ ``` -------------------------------- ### Generate and Augment Chemical Results Table Source: https://github.com/matteoferla/fragmenstein/blob/master/documentation/further-detail/pipeline.md Example script to generate a chemical results table from an SQLite database, calculate atom counts for hits, and assign new columns for atom differences. Requires RDKit and Fragmenstein. ```python ############################################## project = 'mergers' from fragmenstein import Victor Victor.work_path = project db_name = f'{project}.sqlite' result_table = get_table(db_name, mols=True) #result_table # shoot. I forgot to count atoms in hits... atom_Ns = {} for folder in ('newinputs',): #'input', 'UCSF2-hits', 'frags'): for file in os.listdir(folder): if '.mol' in file: mol = Chem.MolFromMolFile(os.path.join(folder, file), sanitize=False) if mol is None: atom_Ns[file.replace('.mol','')] = 0 # float nan? else: mol = Chem.GetMolFrags(mol, asMols=True)[0] # just in case atom_Ns[file.replace('.mol','')] = mol.GetNumAtoms() # add atom n hit_counter = lambda hits: sum([atom_Ns[hit] for hit in hits]) merge_counter = lambda row: row.N_hit_atoms - row.N_unconstrained_atoms - row.N_constrained_atoms result_table = result_table.assign(N_hit_atoms=result_table.regarded.apply(hit_counter)) result_table = result_table.assign(N_diff_atoms=result_table.apply(merge_counter, axis='columns')) result_table ```