178
pAPRika Documentation paprika Feb 17, 2021

pAPRika Documentation

  • Upload
    others

  • View
    8

  • Download
    0

Embed Size (px)

Citation preview

Page 1: pAPRika Documentation

pAPRika Documentation

paprika

Feb 17, 2021

Page 2: pAPRika Documentation
Page 3: pAPRika Documentation

GETTING STARTED

1 Binding free energy 3

2 Binding enthalpy 7

3 Supported Molecular Dynamics Engine 9

4 License 11

5 References 135.1 Installation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 135.2 Workflow . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145.3 pAPRika tutorial 1 - An introduction to APR with Implicit solvent . . . . . . . . . . . . . . . . . . . 225.4 pAPRika tutorial 2 - Explicit Solvent . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 385.5 pAPRika tutorial 3 - K-Cl dissociation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 535.6 pAPRika tutorial 4 - APR/OpenMM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 615.7 pAPRika tutorial 5 - APR/Amber with Plumed restraints . . . . . . . . . . . . . . . . . . . . . . . . 715.8 pAPRika tutorial 6 - APR/Gromacs with Plumed restraints . . . . . . . . . . . . . . . . . . . . . . . 815.9 pAPRika tutorial 7 - APR/NAMD with Colvars restraints . . . . . . . . . . . . . . . . . . . . . . . 945.10 Compiling the Docs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1055.11 API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1055.12 Release History . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163

Python Module Index 165

Index 167

i

Page 4: pAPRika Documentation

ii

Page 5: pAPRika Documentation

pAPRika Documentation

pAPRika is a python toolkit for setting up, running, and analyzing free energy molecular dynamics simulations.

GETTING STARTED 1

Page 6: pAPRika Documentation

pAPRika Documentation

2 GETTING STARTED

Page 7: pAPRika Documentation

CHAPTER

ONE

BINDING FREE ENERGY

In the attach-pull-release (APR) method, a guest molecule is physically pulled out of the host molecule along a definedpath by applying harmonic restraints. The binding free energy is then computed in terms of the sum of the workrequired for (1) attaching restraints to the bound complex, (2) pulling the guest molecule out of the host molecule and(3) releasing the restraints of the unbound complex:

∆𝐺∘bind = −(𝑊attach + 𝑊pull + 𝑊release-conf + 𝑊release-std) (1.1)

In the equation above, the work of releasing the restraints is split into two: 𝑊release-conf and 𝑊release-std. These representsthe work for releasing conformational restraints (applied to host or guest molecules) and the guest’s translational androtational restraints to the standard concentration, respectively. The translational and rotational degrees of freedomof the guest molecule is defined in spherical coordinates (𝑟, 𝜃, 𝜑) and Euler angles (𝛼, 𝛽, 𝛾), respectively. Unlike thework for releasing conformational restraints, the work for releasing the guest’s restraints to the standard concentration

3

Page 8: pAPRika Documentation

pAPRika Documentation

can be evaluated analytically:

𝑡𝑜

𝑊release-std =

𝑅𝑇 ln(︂

𝐶∘

8𝜋2

)︂+

𝑅𝑇 ln(︂∫︁ ∞

0

∫︁ 𝜋

0

∫︁ 2𝜋

0

𝑒−𝛽𝑈(𝑟,𝜃,𝜑)𝑟2sin(𝜃) 𝑑𝜑 𝑑𝜃 𝑑𝑟

)︂+

𝑅𝑇 ln(︂∫︁ 2𝜋

0

∫︁ 𝜋

0

∫︁ 2𝜋

0

𝑒−𝛽𝑈(𝛼,𝛽,𝛾)sin(𝜃) 𝑑𝛼 𝑑𝛽 𝑑𝛾

)︂(1.3)

(1.3)

=

𝑅𝑇 ln(︂

𝐶∘

8𝜋2

)︂+

𝑅𝑇 ln(︂∫︁ ∞

0

∫︁ 𝜋

0

∫︁ 2𝜋

0

𝑒−𝛽𝑈(𝑟,𝜃,𝜑)𝑟2sin(𝜃) 𝑑𝜑 𝑑𝜃 𝑑𝑟

)︂+

𝑅𝑇 ln(︂∫︁ 2𝜋

0

∫︁ 𝜋

0

∫︁ 2𝜋

0

𝑒−𝛽𝑈(𝛼,𝛽,𝛾)sin(𝜃) 𝑑𝛼 𝑑𝛽 𝑑𝛾

)︂(1.3)

For other terms in equation (1.1), the calculation is broken up into a series of independent windows. During theattach and release phase, the force constant of the restraints increases and decreases, respectively. In the pull phase,the distance between the guest and host is discretized from point A (bound) to point B (unbound) by changing theequilibrium position of the distance restraint. The work for each phase can be estimated using either thermodynamicintegration (TI) or the multistate-Bennett-Acceptance-Ratio (MBAR).

𝑡𝑜

𝑊attach,release =∫︁ 1

0

⟨𝐹 ⟩𝜆 𝑑𝜆

𝑊pull =∫︁ 𝐵

𝐴

⟨𝐹 ⟩𝑟 𝑑𝑟(1.5)

(1.5)

=

4 Chapter 1. Binding free energy

Page 9: pAPRika Documentation

pAPRika Documentation

∫︁ 1

0

⟨𝐹 ⟩𝜆 𝑑𝜆𝑊pull= ∫︁ 𝐵

𝐴

⟨𝐹 ⟩𝑟 𝑑𝑟

(1.5)

pAPRika estimates the standard error of the mean (SEM) with either block data analysis or autocorrelation.

5

Page 10: pAPRika Documentation

pAPRika Documentation

6 Chapter 1. Binding free energy

Page 11: pAPRika Documentation

CHAPTER

TWO

BINDING ENTHALPY

The binding enthalpy is the difference in the partial molar enthalpies of the bound complex and the separatedmolecules. Setting up binding enthalpy calculations is more straightforward than the binding free energy if we use thedirect method. In the direct method, the binding enthalpy is obtained from the difference in the mean potential energyof the bound and unbound complex.

∆𝐻bind = ⟨𝑈bound⟩ − ⟨𝑈unbound⟩ (2.1)

In the context of APR simulations, the mean potential energy is estimated from the first and last window. Thesewindows, however, will need to be run for much longer until the fluctuation of the mean potential energy decreasesbelow a desired value. Another way to estimate the binding enthalpy is with the van’t Hoff method:

ln𝐾eq = −∆𝐻

𝑅𝑇+

∆𝑆

𝑅(2.2)

Here, the binding enthalpy is obtained by a linear regression of ln𝐾eq vs 1/𝑇 . The equilibrium constant will need tobe evaluated at different temperatures in order the estimate the binding enthalpy with the van’t Hoff method.

7

Page 12: pAPRika Documentation

pAPRika Documentation

8 Chapter 2. Binding enthalpy

Page 13: pAPRika Documentation

CHAPTER

THREE

SUPPORTED MOLECULAR DYNAMICS ENGINE

Currently, pAPRika can be used to setup and analyze APR simulations with AMBER, OpenMM and GROMACS.These MD engines provides their own interface (e.g., AMBER uses NMR-style restraints). pAPRika also providesmodules to generate Plumed-based restraints, which is supported in a number of MD engines.

Future releases of pAPRika will include support for other MD engines like , NAMD and LAMMPS. Plumed is sup-ported by all of these but for NAMD only NPT simulations can be performed. Hence, a module converting pAPRikarestraints to a Colvars module, which is supported in NAMD and LAMMPS, is also in the works.

Table 1: MD engines that are supported in pAPRika (or planned) and therespective restraint modules it supports.

MD EngineRestraints Module

NMR XML Plumed Colvars

AMBER X X

OpenMM X X**

GROMACS X

NAMD X X

LAMMPS* X X

* Currently not supported but will be available in future releases. ** Supported but have not yet been tested.

9

Page 14: pAPRika Documentation

pAPRika Documentation

10 Chapter 3. Supported Molecular Dynamics Engine

Page 15: pAPRika Documentation

CHAPTER

FOUR

LICENSE

pAPRika is licensed under the BSD 3-Clause license.

11

Page 16: pAPRika Documentation

pAPRika Documentation

12 Chapter 4. License

Page 17: pAPRika Documentation

CHAPTER

FIVE

REFERENCES

1. Velez-Vega, C. & Gilson, M. K. Overcoming Dissipation in the Calculation of Standard Binding Free Energiesby Ligand Extraction. J. Comput. Chem. 34, 2360–2371 (2013).

2. Fenley, A. T., Henriksen, N. M., Muddana, H. S. & Gilson, M. K. Bridging calorimetry and simulation throughprecise calculations of cucurbituril-guest binding enthalpies. J. Chem. Theory Comput. 10, 4069–4078 (2014).

3. Henriksen, N. M., Fenley, A. T. & Gilson, M. K. Computational Calorimetry: High-Precision Calculation ofHostGuest Binding Thermodynamics. J. Chem. Theory Comput. 11, 4377–4394 (2015).

5.1 Installation

We recommend installing pAPRika in a fresh conda environment if possible. There are three ways to install thispackage:

5.1.1 Installing from Conda

To install the latest release of paprika from conda, run:

conda install -c conda-forge paprika

In order to use all features of paprika, you must either have AmberTools (http://ambermd.org/AmberTools.php) inyour $PATH or separately install AmberTools with:

conda install -c conda-forge ambertools=20

Optional dependencies

You can install OpenMM from the omnia channel if you want to run APR simulations with OpenMM:

conda install -c omnia openmm

If you want to run simulations with Plumed-based restraints (needed for running APR in GROMACS) you can compilePlumed from source or install through conda:

conda install -c conda-forge plumed

Although GROMACS is available in conda, a version that is patched with Plumed is currently not available. Therefore,if you want to run GROMACS simulations in paprika you will need to compile from source manually (patched withPlumed).

13

Page 18: pAPRika Documentation

pAPRika Documentation

5.1.2 Installing a stable version from source

To install the a stable version of paprika download the source code from Github. Then, unzip the files and change tothe paprika directory:

tar -xvzf paprika-version.tgzcd pAPRika-version/

Change the name field in devtools/conda-envs/test_env.yaml to be paprika and create the environ-ment:

conda env create -f devtools/conda-envs/test_env.yaml

Activate the environment:

conda activate paprika

and install paprika in the environment:

pip install .

5.1.3 Installing latest from source

To install paprika with the latest features, clone the repository from the master branch on Github:

git clone https://github.com/slochower/pAPRika.git

Change directory to the paprika folder, change the name field in devtools/conda-envs/test_env.yamlto paprika and create the conda environment:

conda env create -f devtools/conda-envs/test_env.yaml

Activate the environment:

conda activate paprika

and install paprika in the environment:

pip install .

5.2 Workflow

This page provides a brief explanation of the workflow to perform APR calculations with pAPRika. For more detailusers are recommended to go through the tutorials, which details further on how to setup and run APR simulationsfrom start to finish.

14 Chapter 5. References

Page 19: pAPRika Documentation

pAPRika Documentation

Fig. 1: Flowchart of the paprika workflow for a typical APR simulation.

5.2. Workflow 15

Page 20: pAPRika Documentation

pAPRika Documentation

5.2.1 Structure Preparation

Aligning the host-guest complex

The starting structure for the APR simulation can be configured with paprika. The APR calculation is most efficient ina rectangular box with the long axis parallel to the pulling axis (reduces the number of water molecules in the system).To make this easy to set up, the Align module provides functions to shift and orient a structure. For example, we cantranslate a structure to the origin and then orient the system to the 𝑧-axis by running

from paprika.build.align import *

translated_structure = translate_to_origin(structure)aligned_structure = zalign(translated_structure, ":GST@C1", ":GST@C2")

Adding dummy atoms

To provide something to pull “against,” we add dummy atoms that are fixed in place with strong positional restraints.These dummy atoms can be added to a the host-guest structure using the Dummy Atoms module in paprika.

from paprika.build.dummy import add_dummy

structure = dummy.add_dummy(structure, residue_name="DM1", z=-6.0)structure = dummy.add_dummy(structure, residue_name="DM2", z=-9.0)structure = dummy.add_dummy(structure, residue_name="DM3", z=-11.2, y=2.2)structure.save("aligned_with_dummy.pdb", overwrite=True)

We will need the mol2 and frcmod files for the dummy atoms, which we will need to generate the AMBER topology

dummy.write_dummy_frcmod(filepath="complex/dummy.frcmod")dummy.write_dummy_mol2(residue_name="DM1", filepath="complex/dm1.mol2")dummy.write_dummy_mol2(residue_name="DM2", filepath="complex/dm2.mol2")dummy.write_dummy_mol2(residue_name="DM3", filepath="complex/dm3.mol2")

Building the topology

Finally, we can use the tleap wrapper to combine all of these components to generate the topology and coordinatefiles.

from paprika.build.system import TLeap

system = TLeap()system.output_prefix = "host-guest-dum"system.pbc_type = Nonesystem.neutralize = False

system.template_lines = ["source leaprc.gaff","HST = loadmol2 host.mol2","GST = loadmol2 guest.mol2","DM1 = loadmol2 dm1.mol2","DM2 = loadmol2 dm2.mol2","DM3 = loadmol2 dm3.mol2","model = loadpdb aligned_with_dummy.pdb",

]system.build()

Solvating the structure

The TLeap wrapper also provides an API for choosing water models when the user wants to solvate their structure.

16 Chapter 5. References

Page 21: pAPRika Documentation

pAPRika Documentation

tleap provides a number of models for both 3-point and 4-point water models. There are also sub-types for eachwater model, e.g. for TIP3P we can choose to use the ForceBalance optimized variant called TIP3P-FB or the host-guest binding optimized model called Bind3P. To choose a water model for solvation we use the set_water_modelmethod of the TLeap wrapper. The method requires the user to specify the water model and optionally the sub-typeas the model_type attibute. The supported water models are:

• spc: None (SPCBOX), “flexible” (SPCFWBOX), “quantum” (QSPCFWBOX)

• opc: None (OPCBOX), “three-point” (OPC3BOX)

• tip3p: None (TIP3PBOX), “flexible” (TIP3PFBOX), “force-balance” (FB3BOX)

• tip4p: None (TIP4PBOX), “ewald” (TIP4PEWBOX), “force-balance” (FB4BOX)

Below is an example for solvating a system with 2000 TIP3P water molecules with ForceBalance optimizedparameters.

from paprika.build.system import TLeapfrom paprika.build.system.utils import PBCBox

system = TLeap()system.output_prefix = "host-guest-dum"system.pbc_type = PBCBox.rectangularsystem.target_waters = 2000system.set_water_model("tip3p", model_type="force-balance")

system.template_lines = ["source leaprc.gaff","HST = loadmol2 host.mol2","GST = loadmol2 guest.mol2","DM1 = loadmol2 dm1.mol2","DM2 = loadmol2 dm2.mol2","DM3 = loadmol2 dm3.mol2","model = loadpdb aligned_with_dummy.pdb",

]system.build()

5.2.2 Defining Restraints

5.2. Workflow 17

Page 22: pAPRika Documentation

pAPRika Documentation

In APR calculations we apply restraints on the host (or protein) and the guest molecules. The restraints can be groupedinto four categories: (1) static restraints, (2) varying restraints, (3) wall restraints and (4) positional restraints.

(1) Static Restraints

Static restraints do not change during the whole APR process and do not affect the free energy. We apply staticrestraints on the host (or protein) molecule to orient the host/protein degrees of freedom. The static restraints arecomposed of distance, angle, and torsional (DAT) restraints based on the choice of anchor atoms. For host-guestsystems, we need to define three anchor atoms [H1,H2,H3] and combined with three dummy atoms [D1,D2,D3],we apply a total of six static restraints on the host molecule (three for the translation and three for orientation).

To generate static restraints we use the function static_DAT_restraints. As an example, to apply a distancerestraint on D1 and H1 with a force constant of 5 kcal/mol/2 we call

from paprika.restraints import static_DAT_restraint

dist_static = static_DAT_restraint(restraint_mask_list = [D1, H1],num_window_list = windows, # list: [len(attach_lambda), len(pull_windows),

→˓len(release_lambda)]ref_structure = structure, # Structure file (PDB)force_constant = 5.0,

)

(2) Varying Restraints

As the name suggests, these restraints change during the APR process. During the attach and release phases, the forceconstants of these restraints changes. In the pull phase, varying restraints can have their equilibrium position change,and this can be used as the restraint to pull the guest molecule out of the host molecule.

To generate varying restraints, we use the DAT_restraint class. The code below shows a restraints r that startsfrom 6.0 Å to 24 Å in the pull phase and stays restrained at 24 Å during the release phase.

from paprika.restraints import DAT_restraint

r = DAT_restraint()r.mask1 = D1r.mask2 = G1r.topology = structurer.auto_apr = Truer.continuous_apr = True

r.attach["target"] = 6.0r.attach["fraction_list"] = attach_lambdar.attach["fc_final"] = 5.0

r.pull["target_final"] = 24.0r.pull["num_windows"] = len(pull_windows)

r.release["target"] = 24.0r.release["fraction_list"] = [1.0] * len(release_lambda)r.release["fc_final"] = 5.0

r.initialize()

Note: The DAT_restraint class can also be used to apply conformational restraints on the host and/or guestmolecule. For example, distance “jack” and dihedral restraints can be applied to cucurbiturils and cyclodextrins host

18 Chapter 5. References

Page 23: pAPRika Documentation

pAPRika Documentation

molecules, respectively, to make the binding site more accessible.

(3) Wall Restraints (optional)

Wall restraints are half-harmonic potentials that is useful for preventing guest molecules from leaving the bindingsite (for weak binding) or preventing the guest molecule from flipping during the attach phase. We still use theDAT_restraint class to generate the restraints but will use the custom_restraint_values method to gen-erate the half-harmonic potential.

Note: custom_restraint_values follows the AMBER NMR-restraint format, see Chapter 27 in the AM-BER20 manual for more details.

Below is an example for generating a “lower wall” restraint that prevents the angle of [D2,G1,G2] from decreasingbelow 91 degrees.

wall_orient = DAT_restraint()wall_orient.mask1 = D1wall_orient.mask2 = G1wall_orient.mask3 = G2wall_orient.topology = structurewall_orient.auto_apr = Truewall_orient.continuous_apr = True

wall_orient.attach["num_windows"] = attach_fractionswall_orient.attach["fc_initial"] = 200.0wall_orient.attach["fc_final"] = 200.0

wall_orient.custom_restraint_values["r1"] = 91.0wall_orient.custom_restraint_values["r2"] = 0.0wall_orient.custom_restraint_values["rk2"] = 200.0wall_orient.custom_restraint_values["rk3"] = 0.0

wall_orient.initialize()

(4) Positional Restraints

Positional restraints in APR simulations are applied to the dummy atoms. Together with static restraints, this providesa laboratory frame of reference for the host-guest complex. Different MD programs handles positional restraintsdifferently. For example, in AMBER you can define positional restraints in the input configuration file using the ntrkeyword (Chapter 19 in the AMBER20 manual). For other programs like GROMACS and NAMD that uses Plumed,positional restraints can be applied using the method add_dummy_atom_restraints().

Note: tleapmay shift the coordinates of the system when it solvates the structure. Applying the positional restraintsbefore the solvating the structure may lead to undesired errors during simulations. Therefore, special care needs to betaken when applying positional restraints. Take a look at tutorials 5 and 6 to see this distinction.

Creating the APR windows and saving restraints to file

To create the windows for the APR calculation we need to parse a varying restraint to the utility functioncreate_window_list. This function will return a list of strings for the APR protocol

window_list = create_window_list(restraints_list)window_list["a000", "a001", ..., "p000", "p001", ...]

5.2. Workflow 19

Page 24: pAPRika Documentation

pAPRika Documentation

It may also be useful to save both the windows list and the restraints to a JSON file so you do not need to redefineagain. The restraints can be saved to a JSON file using the utility function save_restraints.

from paprika.io import save_restraintssave_restraints(restraints_list, filepath="restraints.json")

import jsonwith open("windows.json", "w") as f:

dumped = json.dumps(window_list)f.write(dumped)

Extending/adding more windows

Sometimes it may be necessary to add more windows in the APR calculation due to insufficient overlap betweenneighboring windows. For convenience we can add the windows at the end of the current list instead of inserting themin order. For example, let’s say that we have a defined a restraint that spans from 8.4 to 9.8 Å and we want to add threewindows between 8.6 and 9.0 Å.

r_restraint.pull{'fc': 10.0,'target_initial': None,'target_final': None,'num_windows': None,'target_increment': None,'fraction_increment': None,'fraction_list': None,'target_list': array([8.4, 8.6, 9. , 9.4, 9.8])}

We will just need to append the target_list of this dictionary and reinitialize the restraints

r_restraint.pull["target_list"] = np.append(r_restraint.pull["target_list"], [8.7, 8.→˓8, 8.9])r_restraint.initialize()r_restraint.pull{'fc': 10.0,'target_initial': None,'target_final': None,'num_windows': None,'target_increment': None,'fraction_increment': None,'fraction_list': None,'target_list': array([8.4, 8.6, 9. , 9.4, 9.8, 8.7, 8.8, 8.9])}

We can save the updated restraints to a new file and pass it to the analysis script. The fe_calc class will take care ofthe window ordering thus there is no need to manually order the windows.

5.2.3 Running a Simulation

paprika provides wrappers with the Simulatemodule for a number of MD engines enabling us to run the simulationsin python.

from paprika.simulate import AMBER

simulation = AMBER()simulation.executable = "pmemd.cuda"simulation.gpu_devices = "0"

(continues on next page)

20 Chapter 5. References

Page 25: pAPRika Documentation

pAPRika Documentation

(continued from previous page)

simulation.path = "simulation"simulation.prefix = "equilibration"simulation.coordinates = "minimize.rst7"simulation.ref = "host-guest-dum.rst7"simulation.topology = "host-guest-dum.prmtop"simulation.restraint_file = "disang.rest"

simulation.config_pbc_md()

# Positional restraints on dummy atomssimulation.cntrl["ntr"] = 1simulation.cntrl["restraint_wt"] = 50.0simulation.cntrl["restraintmask"] = "'@DUM'"

print(f"Running equilibration in window {window}...")simulation.run()

5.2.4 Analysis

Once the simulation is complete, the free energy can be obtained using the Analysis module, which will alsoestimate the uncertainties using the bootstrapping method. There are three types of methods that you can do withthe Analysis module: (1) thermodynamic integration with block-data analysis (“ti-block”), (2) multistate Benett-Acceptance-Ratio with block-data analysis (“mbar-block”), and (3) multistate Benett-Acceptance-Ratio with autocor-relation analysis (“mbar-autoc”).

from paprika.analysis import fe_calcfrom paprika.io import load_restraints

restraints_list = load_restraints(filepath="restraints.json")

free_energy = fe_calc()free_energy.prmtop = "host-guest-dum.prmtop"free_energy.trajectory = 'production.nc'free_energy.path = "windows"free_energy.restraint_list = restraints_listfree_energy.collect_data()free_energy.methods = ['ti-block']free_energy.ti_matrix = "full"free_energy.bootcycles = 1000free_energy.compute_free_energy()

We can also estimate the free energy cost of releasing the restraints on the guest molecule semianalytically. To dothis we need to extract the restraints that is specific to the guest molecule. The extract_guest_restraintsfunction from the restraints module and pass this to the analysis object.

import parmed as pmdfrom paprika.restraints.utils import extract_guest_restraints

structure = pmd.load_file("guest.prmtop", "guest.rst7", structure=True)guest_restraints = extract_guest_restraints(structure, restraints_list, guest_resname=→˓"GST")free_energy.compute_ref_state_work(guest_restraints)

The results are stored in the variable results as a python dictionary and you can save this to a JSON file.

5.2. Workflow 21

Page 26: pAPRika Documentation

pAPRika Documentation

print(free_energy.results["pull"]["ti-block"]["fe"])-3.82139135698

from paprika.io import NumpyEncoderwith open("APR_results.json", "w") as f:

dumped = json.dumps(free_energy.results, cls=NumpyEncoder)f.write(dumped)

5.3 pAPRika tutorial 1 - An introduction to APR with Implicit solvent

In this example, we will setup and simulate butane (BUT) as a guest molecule for the host cucurbit[6]uril (CB6).CBs are rigid, symmetric, cyclic host molecules with oxygen atoms around the portal edge of the cavity. We will runthe simulation in implicit solvent, using the Generalized-Born model, for speed and simplicity, using AMBER. Thistutorial assumes familiarity with basic MD procedures.

5.3.1 Initial Setup

The very first step in the calculation is creating a coordinate file for the bound host-guest complex (we usually usePDB format for this part because it works well with tleap). This does not have to perfectly match the bound state byany means (we will later minimize and equilibrate), but this should be a reasonable illustration of the bound complex.This file can be created by hand (in a program like Chimera, VMD, or PyMOL) or by docking the guest into the hostcavity (with MOE, AutoDock, DOCK, . . . ).

In this example, this file is called cb6-but.pdb, in the complex/ directory, and this is what it looks like.

In addition to the coordinate file, we need separate mol2 files for the host and guest molecule that contain the partialatomic charges. For cyclic hosts like CB6, you can specify either a single residue for the entire molecule (this is whatwe do here) or you can provide coordinates and charges for a single monomer and have tleap build the structure(this is a little more tricky).

The mol2 files that we use here (cb6.mol2 and but.mol2) were created by running antechamber -fi pdb-fo mol2 -i <pdb> -o <mol2> -c bcc (I added pl 10 for the host, which reduces the number of pathsthat antechamber takes to traverse the host; see antechamber help for more information).

[4]: import osif not os.path.isdir("complex"):

(continues on next page)

22 Chapter 5. References

Page 27: pAPRika Documentation

pAPRika Documentation

(continued from previous page)

os.makedirs("complex")data = "../../../paprika/data/cb6-but"

Create AMBER coordinate (.rst7 or .inpcrd) and parameter files (.prmtop or .topo) for the host-guest complex

In this example, we will use GAFF parameters for both the host and guest. For the host, parmchk2 has identifiedtwo parameters that are missing from GAFF and added the most similar ones into the supplementary cb6.frcmodfile.

[5]: from paprika.build.system import TLeap

[6]: system = TLeap()system.output_path = "complex"system.pbc_type = Nonesystem.neutralize = False

system.template_lines = ["source leaprc.gaff",f"loadamberparams {data}/cb6.frcmod",f"CB6 = loadmol2 {data}/cb6.mol2",f"BUT = loadmol2 {data}/but.mol2",f"model = loadpdb {data}/cb6-but.pdb","check model","savepdb model vac.pdb","saveamberparm model vac.prmtop vac.rst7"

]system.build()

After running tleap, it is always a good idea to check leap.log. pAPRika does some automated checking of theouptut, but sometimes things slip through. (By default, tleap will append to leap.log.)

Prepare the complex for an APR calculation

Now we are ready to prepare the complex for the attach-pull-release calculation. This involves:

• Aligning the structure so the guest can be pulled along the 𝑧 axis, and

• Adding dummy atoms that are used to orient the host and guest.

To access the host-guest structure in Python, we use the ParmEd Structure class. So we start by loading thevacuum model that we just created. Then, we need to define two atoms on the guest that are placed along the 𝑧 axis.These should be heavy atoms on either end of the guest, the second atom leading the pulling.

These same atoms will be used later for the restraints, so I will name them G1 and G2, using AMBER selection syntax.

5.3. pAPRika tutorial 1 - An introduction to APR with Implicit solvent 23

Page 28: pAPRika Documentation

pAPRika Documentation

Align the pulling axis

[7]: import parmed as pmd

[8]: structure = pmd.load_file("complex/vac.prmtop","complex/vac.rst7",structure=True)

[9]: from paprika.build import align

[10]: G1 = ":BUT@C"G2 = ":BUT@C3"

[11]: aligned_structure = align.zalign(structure, G1, G2)aligned_structure.save("complex/aligned.prmtop", overwrite=True)aligned_structure.save("complex/aligned.rst7", overwrite=True)

/home/peanut/pAPRika/paprika/build/align.py:255: RuntimeWarning: invalid value→˓encountered in true_dividex = np.cross(vector, ref_vector) / np.linalg.norm(np.cross(vector, ref_vector))

Here, the origin is shown as a grey sphere, with the 𝑧 axis drawn as a blue arrow. The coordinates used for this examplewere already aligned, so Python warns that the cross product is zero, but this won’t be the case in general.

Next, we add the dummy atoms. The dummy atoms will be fixed in place during the simulation and are used to orientthe host and guest in the lab frame. The dummy atoms are placed along the 𝑧 axis, behind the host. The dummyatoms are used in distance, angle, and torsion restraints and therefore, the exact positioning of these atoms affects thevalue of those restraints. For a typical host-guest system, like the one here, we generally place the first dummy atom 6Angstroms behind the origin, the second dummy atom 9 Angstroms behind the origin, and the third dummy atom 11.2Angstroms behind the origin and offset about 2.2 Angstroms along the 𝑦 axis. After we add restraints, the positioningof the dummy atoms should be more clear.

Note, these dummy atoms do not interact with the other atoms in the system, and therefore, there is no problem placingthem near host atoms.

24 Chapter 5. References

Page 29: pAPRika Documentation

pAPRika Documentation

Add dummy atoms

[12]: from paprika.build import dummy

[13]: structure = pmd.load_file("complex/aligned.prmtop","complex/aligned.rst7",structure=True)

[14]: structure = dummy.add_dummy(structure, residue_name="DM1", z=-6.0)structure = dummy.add_dummy(structure, residue_name="DM2", z=-9.0)structure = dummy.add_dummy(structure, residue_name="DM3", z=-11.2, y=2.2)

[15]: structure.save("complex/aligned_with_dummy.prmtop", overwrite=True)structure.save("complex/aligned_with_dummy.rst7", overwrite=True)structure.save("complex/aligned_with_dummy.pdb", overwrite=True)

When we solvate the system in tleap, we will need frcmod files for the dummy atoms (otherwise tleap will useGAFF parameters and the dummy atoms will not be non-interacting). There is a convenient method in paprika towrite a frcmod file that only contains a MASS section. For convenience, I am also going to write mol2 files for eachof the dummy atoms. This makes it easy to build up the system, piece-by-piece, if we have a separate mol2 file foreach component of the system: host, guest, dummy atoms.

In principle, an APR calculate can be completed without dummy atoms, by simply lengthening the distance betweenthe host and guest, but the addition of dummy atoms permits an easier way to think about dissociating the guest fromthe host. (Also, in the absence of dummy atoms, it is challenging to pull the guest straight out of the cavity withoutadding additional restraints.)

[16]: dummy.write_dummy_frcmod(filepath="complex/dummy.frcmod")dummy.write_dummy_mol2(residue_name="DM1", filepath="complex/dm1.mol2")dummy.write_dummy_mol2(residue_name="DM2", filepath="complex/dm2.mol2")dummy.write_dummy_mol2(residue_name="DM3", filepath="complex/dm3.mol2")

Now all the pieces are in place to build the system for an APR calculation.

5.3. pAPRika tutorial 1 - An introduction to APR with Implicit solvent 25

Page 30: pAPRika Documentation

pAPRika Documentation

Put it all together

[17]: system = TLeap()system.output_path = "complex"system.pbc_type = Nonesystem.neutralize = False

system.template_lines = ["source leaprc.gaff",f"loadamberparams {data}/cb6.frcmod","loadamberparams dummy.frcmod",f"CB6 = loadmol2 {data}/cb6.mol2",f"BUT = loadmol2 {data}/but.mol2","DM1 = loadmol2 dm1.mol2","DM2 = loadmol2 dm2.mol2","DM3 = loadmol2 dm3.mol2","model = loadpdb aligned_with_dummy.pdb","check model","savepdb model cb6-but-dum.pdb","saveamberparm model cb6-but-dum.prmtop cb6-but-dum.rst7"

]system.build()

Now we have AMBER coordinates and parameters for the cb6-but system with dummy atoms in the appropriateplace and with the proper “dummy” parametesr.

Determine the number of windows

Before we add the restraints, it is helpful to set the 𝜆 fractions that control the strength of the force constants duringattach and release, and to define the distances for the pulling phase.

The attach fractions go from 0 to 1 and we place more points at the bottom of the range to sample the curvatureof 𝑑𝑈/𝑑𝜆. Next, we generally apply a distance restraint until the guest is ~18 Angstroms away from the host, inincrements of 0.4 Angstroms. This distance should be at least twice the Lennard-Jones cutoff in the system. Thesevalues have worked well for us, but this is one aspect that should be carefully checked for new systems.

[14]: attach_string = "0.00 0.40 0.80 1.60 2.40 4.00 5.50 8.65 11.80 18.10 24.40 37.00 49.→˓60 74.80 100.00"attach_fractions = [float(i) / 100 for i in attach_string.split()]

26 Chapter 5. References

Page 31: pAPRika Documentation

pAPRika Documentation

[15]: import numpy as npinitial_distance = 6.0pull_distances = np.arange(0.0 + initial_distance, 18.0 + initial_distance, 1.0)

These values will be used to measure distance relative to the first dummy atom, hence the addition of 6.00.

[16]: release_fractions = []

Later, I will explain why there are no release windows in this calculation.

[17]: windows = [len(attach_fractions), len(pull_distances), len(release_fractions)]print(f"There are {windows} windows in this attach-pull-release calculation.")

There are [15, 18, 0] windows in this attach-pull-release calculation.

Alternatively, we could specify the number of windows for each phase and the force constants and targets will belinearly interpolated. Other ways of specifying these values are documented in the code.

5.3.2 Add restraints using pAPRika

For the host-guest complex, we will apply four different types ot restraints in pAPRika:

• Static restraints: these six restraints keep the host and in the proper orientation during the simulation (necessary),

• Guest restraints: these restraints pull the guest away from the host along the 𝑧 axis (necessary),

• Conformational restraints: these restraints alter the conformational sampling of the host molecule (optional),and

• Wall restraints: these restraints help define the bound state of the guest (optional).

More information on these restraints can be found in:

Henriksen, N.M., Fenley, A.T., and Gilson, M.K. (2015). Computational Calorimetry: High-Precision Calculation ofHost-Guest Binding Thermodynamics. J. Chem. Theory Comput. 11, 4377–4394. DOI

In this example, I will show how to setup the static restraints and the guest restraints.

We have already added the dummy atoms and we have already defined the guest anchor atoms. Now we need to definethe host anchor atoms (H1, H2, and H3) in the above diagram. The host anchors should be heavy atoms distributedaround the cavity (and around the pulling axis). One caveat is that the host anchors should be rigid relative to eachother, so conformational restraints do not shift the alignment of the pulling axis relative to the solvation box. For CB6,I have chosen carbons around the central ridge.

[18]: H1 = ":CB6@C"H2 = ":CB6@C31"H3 = ":CB6@C18"

I’ll also make a shorthand for the dummy atoms.

[19]: D1 = ":DM1"D2 = ":DM2"D3 = ":DM3"

5.3. pAPRika tutorial 1 - An introduction to APR with Implicit solvent 27

Page 32: pAPRika Documentation

pAPRika Documentation

Static restraints

These harmonic restraints are constant throughout the entire simulation. These restraints are used to control thedistances and angles between the host and guest relative to the dummy atom. We have created a special class forthese restrains, static_DAT_restraint, that uses the initial value as the restraint target (this is why the startingstructure should be a reasonable facsimile of the bound state).

Note that these restraints are not “attached” and they don’t need to be “released” – their force constants do not changein magnitude.

The first three static restraints affect the translational distance, angle, and torsion angle between the host and thedummy atoms. These control the position of the host, via the first anchor atom, from moving relative to the dummyatoms.

There is no correct value for the force constants. From experience, we know that a distance force constant of 5.0kcal/mol/Angstrom2 won’t nail down the host and yet it also won’t wander away. Likewise, we have had good resultsusing 100.0 kcal/mol/radian2 for the angle force constant.

[20]: from paprika import restraintsstatic_restraints = []

28 Chapter 5. References

Page 33: pAPRika Documentation

pAPRika Documentation

[21]: structure = pmd.load_file("complex/cb6-but-dum.prmtop","complex/cb6-but-dum.rst7",structure = True)

[22]: r = restraints.static_DAT_restraint(restraint_mask_list = [D1, H1],num_window_list = windows,ref_structure = structure,force_constant = 5.0,amber_index=True)

static_restraints.append(r)

[23]: r = restraints.static_DAT_restraint(restraint_mask_list = [D2, D1, H1],num_window_list = windows,ref_structure = structure,force_constant = 100.0,amber_index=True)

static_restraints.append(r)

[24]: r = restraints.static_DAT_restraint(restraint_mask_list = [D3, D2, D1, H1],num_window_list = windows,ref_structure = structure,force_constant = 100.0,amber_index=True)

static_restraints.append(r)

The next three restraints control the orientation of the host relative to the dummy atoms. These angle and torsionrestraints prevent the host from rotating relative to the dummy atoms.

5.3. pAPRika tutorial 1 - An introduction to APR with Implicit solvent 29

Page 34: pAPRika Documentation

pAPRika Documentation

[25]: r = restraints.static_DAT_restraint(restraint_mask_list = [D1, H1, H2],num_window_list = windows,ref_structure = structure,force_constant = 100.0,amber_index=True)

static_restraints.append(r)

[26]: r = restraints.static_DAT_restraint(restraint_mask_list = [D2, D1, H1, H2],num_window_list = windows,ref_structure = structure,force_constant = 100.0,amber_index=True)

static_restraints.append(r)

[27]: r = restraints.static_DAT_restraint(restraint_mask_list = [D1, H1, H2, H3],num_window_list = windows,ref_structure = structure,force_constant = 100.0,amber_index=True)

static_restraints.append(r)

30 Chapter 5. References

Page 35: pAPRika Documentation

pAPRika Documentation

Guest restraints

Next, we add restraints on the guest. These restraints control the position of the guest and are the key to the attach-pull-release method. During the attach phase, the force constants for these restraints is increased from zero. Duringthe pull phase, the target for the distance restraint is increased (in the orange box, below), translating the guest awayfrom the host cavity. And during the release phase, the force constants are reduced from their “full” value back downto zero.

We use the class DAT_restraint to create these three restraints. We will use the same anchor atoms as before,with the same distance and angle force constants. Note that unlike static_DAT_restraint, we will first createthe restraint, then set the attributes, then initialize the restraint which does some checks to make sure everything iscopacetic.

There are two additional convenience options here:

• auto_apr = True sets the force constant during pull to be the final force constant after attach and sets theinitial restraint target during pull to be the final attach target.

• continuous_apr = True sets the last window of attach to be the same as the first window as pull (andlikewise for release)

Also note, due to a quirk with AMBER, we specify angle and torsion targets in degrees but the force constant usingradians!

5.3. pAPRika tutorial 1 - An introduction to APR with Implicit solvent 31

Page 36: pAPRika Documentation

pAPRika Documentation

[28]: guest_restraints = []

[29]: r = restraints.DAT_restraint()r.mask1 = D1r.mask2 = G1r.topology = structurer.auto_apr = Truer.continuous_apr = Truer.amber_index = True

r.attach["target"] = 6.0 # Angstromsr.attach["fraction_list"] = attach_fractionsr.attach["fc_final"] = 5.0 # kcal/mol/Angstroms**2

r.pull["target_final"] = 24.0 # Angstromsr.pull["num_windows"] = windows[1]

r.initialize()guest_restraints.append(r)

[30]: r = restraints.DAT_restraint()r.mask1 = D2r.mask2 = D1r.mask3 = G1r.topology = structurer.auto_apr = Truer.continuous_apr = Truer.amber_index = True

r.attach["target"] = 180.0 # Degreesr.attach["fraction_list"] = attach_fractionsr.attach["fc_final"] = 100.0 # kcal/mol/radian**2

r.pull["target_final"] = 180.0 # Degreesr.pull["num_windows"] = windows[1]

r.initialize()guest_restraints.append(r)

[31]: r = restraints.DAT_restraint()r.mask1 = D1r.mask2 = G1r.mask3 = G2r.topology = structurer.auto_apr = Truer.continuous_apr = Truer.amber_index = True

r.attach["target"] = 180.0 # Degreesr.attach["fraction_list"] = attach_fractionsr.attach["fc_final"] = 100.0 # kcal/mol/radian**2

r.pull["target_final"] = 180.0 # Degreesr.pull["num_windows"] = windows[1]

r.initialize()guest_restraints.append(r)

32 Chapter 5. References

Page 37: pAPRika Documentation

pAPRika Documentation

Create the directory structure

We use the guest restraints to create a list of windows with the appropriate names and then we create the directories.

[32]: import osfrom paprika.restraints.restraints import create_window_list

window_list = create_window_list(guest_restraints)for window in window_list:

if not os.path.isdir(f"windows/{window}"):os.makedirs(f"windows/{window}")

Next, we ask pAPRika to write the restraint information in each window

In each window, we create a file named disang.rest to hold all of the restraint information that is required to runthe simulation with AMBER. We feed the list of restraints to pAPRika, one by one, and it returns the appropriate line.

The functional form of the restraints is specified in section 25.1 of the AMBER18 manual. Specifically, these restraintshave a square bottom with parabolic sides out to a specific distance and then linear sides beyond that. The squarebottom can be eliminated by setting r2=r3 and the linear extension can be eliminated by setting the the r4 = 999and r1 = 0, creating a harmonic restraint

[33]: from paprika.restraints.amber import amber_restraint_line

host_guest_restraints = (static_restraints + guest_restraints)for window in window_list:

with open(f"windows/{window}/disang.rest", "w") as file:for restraint in host_guest_restraints:

string = amber_restraint_line(restraint, window)if string is not None:

file.write(string)

It is a good idea to open up the disang.rest files and see that the force constants and targets make sense (and thereare no NaN values). Do the force constants for the guest restraints start at zero? Do the targets for the pull slowlyincrease?

5.3.3 Prepare host-guest system

Translation of the guest

For the attach windows, we will use the initial, bound coordinates for the host-guest complex. Only the force constantschange during this phase, so a single set of coordinates is sufficient. For the pull windows, we will translate the guestto the target value of the restraint before solvation, and for the release windows, we will use the coordinates from thefinal pull window.

[34]: import shutil

for window in window_list:if window[0] == "a":

shutil.copy("complex/cb6-but-dum.prmtop", f"windows/{window}/cb6-but-dum.→˓prmtop")

shutil.copy("complex/cb6-but-dum.rst7", f"windows/{window}/cb6-but-dum.rst7")elif window[0] == "p":

structure = pmd.load_file("complex/cb6-but-dum.prmtop", "complex/cb6-but-dum.→˓rst7",

(continues on next page)

5.3. pAPRika tutorial 1 - An introduction to APR with Implicit solvent 33

Page 38: pAPRika Documentation

pAPRika Documentation

(continued from previous page)

structure = True)target_difference = guest_restraints[0].phase['pull']['targets'][int(window[1:

→˓])] - guest_restraints[0].pull['target_initial']print(f"In window {window} we will translate the guest {target_difference:0.

→˓1f} Angstroms.")for atom in structure.atoms:

if atom.residue.name == "BUT":atom.xz += target_difference

structure.save(f"windows/{window}/cb6-but-dum.prmtop", overwrite=True)structure.save(f"windows/{window}/cb6-but-dum.rst7", overwrite=True)

In window p000 we will translate the guest 0.0 Angstroms.In window p001 we will translate the guest 1.1 Angstroms.In window p002 we will translate the guest 2.1 Angstroms.In window p003 we will translate the guest 3.2 Angstroms.In window p004 we will translate the guest 4.2 Angstroms.In window p005 we will translate the guest 5.3 Angstroms.In window p006 we will translate the guest 6.4 Angstroms.In window p007 we will translate the guest 7.4 Angstroms.In window p008 we will translate the guest 8.5 Angstroms.In window p009 we will translate the guest 9.5 Angstroms.In window p010 we will translate the guest 10.6 Angstroms.In window p011 we will translate the guest 11.6 Angstroms.In window p012 we will translate the guest 12.7 Angstroms.In window p013 we will translate the guest 13.8 Angstroms.In window p014 we will translate the guest 14.8 Angstroms.In window p015 we will translate the guest 15.9 Angstroms.In window p016 we will translate the guest 16.9 Angstroms.In window p017 we will translate the guest 18.0 Angstroms.

Before running a simulation, open each window and check that the position of the host and dummy atoms are fixedand that the position of the guest is bound during the attach windows, moves progressively further during pull, and isaway from the host during the release windows.

5.3.4 Simulation

Since we are going to run an implicit solvent simulation, we have everything ready to go. paprika has an ambermodule that can help setting default parameters for the simulation. There are some high level options that we setdirectly, like simulation.path, and then we call the function config_gb_min() to setup reasonable defaultsimulation parameters for a minimization in the Generalized-Born ensemble. After that, we directly modify the simu-lation cntrl section to apply the positional restraints on the dummy atoms.

For this part, you need to have the AMBER executables in your path.

[35]: from paprika.simulate import AMBER

I’m using the logging module to keep track of time.

[36]: import loggingfrom importlib import reloadreload(logging)

logger = logging.getLogger()logging.basicConfig(

format='%(asctime)s %(message)s',

(continues on next page)

34 Chapter 5. References

Page 39: pAPRika Documentation

pAPRika Documentation

(continued from previous page)

datefmt='%Y-%m-%d %I:%M:%S %p',level=logging.INFO

)

Energy Minimization

Run a quick minimization in every window. Note that we need to specify simulation.cntrl["ntr"] = 1 toenable the positional restraints on the dummy atoms.

[37]: for window in window_list:simulation = AMBER()simulation.executable = "sander"

simulation.path = f"windows/{window}/"simulation.prefix = "minimize"

simulation.topology = "cb6-but-dum.prmtop"simulation.coordinates = "cb6-but-dum.rst7"simulation.ref = "cb6-but-dum.rst7"simulation.restraint_file = "disang.rest"

simulation.config_gb_min()simulation.cntrl["ntr"] = 1simulation.cntrl["restraint_wt"] = 50.0simulation.cntrl["restraintmask"] = "'@DUM'"

logging.info(f"Running minimization in window {window}...")simulation.run(overwrite=True)

2020-10-05 12:11:35 PM Running minimization in window a000...2020-10-05 12:11:39 PM Running minimization in window a001...2020-10-05 12:11:43 PM Running minimization in window a002...2020-10-05 12:11:47 PM Running minimization in window a003...2020-10-05 12:11:51 PM Running minimization in window a004...2020-10-05 12:11:55 PM Running minimization in window a005...2020-10-05 12:11:59 PM Running minimization in window a006...2020-10-05 12:12:04 PM Running minimization in window a007...2020-10-05 12:12:08 PM Running minimization in window a008...2020-10-05 12:12:12 PM Running minimization in window a009...2020-10-05 12:12:16 PM Running minimization in window a010...2020-10-05 12:12:20 PM Running minimization in window a011...2020-10-05 12:12:24 PM Running minimization in window a012...2020-10-05 12:12:28 PM Running minimization in window a013...2020-10-05 12:12:33 PM Running minimization in window p000...2020-10-05 12:12:37 PM Running minimization in window p001...2020-10-05 12:12:41 PM Running minimization in window p002...2020-10-05 12:12:45 PM Running minimization in window p003...2020-10-05 12:12:49 PM Running minimization in window p004...2020-10-05 12:12:53 PM Running minimization in window p005...2020-10-05 12:12:57 PM Running minimization in window p006...2020-10-05 12:13:01 PM Running minimization in window p007...2020-10-05 12:13:05 PM Running minimization in window p008...2020-10-05 12:13:09 PM Running minimization in window p009...2020-10-05 12:13:13 PM Running minimization in window p010...2020-10-05 12:13:17 PM Running minimization in window p011...

(continues on next page)

5.3. pAPRika tutorial 1 - An introduction to APR with Implicit solvent 35

Page 40: pAPRika Documentation

pAPRika Documentation

(continued from previous page)

2020-10-05 12:13:21 PM Running minimization in window p012...2020-10-05 12:13:25 PM Running minimization in window p013...2020-10-05 12:13:29 PM Running minimization in window p014...2020-10-05 12:13:33 PM Running minimization in window p015...2020-10-05 12:13:37 PM Running minimization in window p016...2020-10-05 12:13:41 PM Running minimization in window p017...

Production

For simplicity, I am going to skip equilibration and go straight to production!

[38]: for window in window_list:simulation = AMBER()simulation.executable = "sander"

simulation.path = f"windows/{window}/"simulation.prefix = "production"

simulation.topology = "cb6-but-dum.prmtop"simulation.coordinates = "minimize.rst7"simulation.ref = "cb6-but-dum.rst7"simulation.restraint_file = "disang.rest"

simulation.config_gb_md()simulation.cntrl["ntr"] = 1simulation.cntrl["restraint_wt"] = 50.0simulation.cntrl["restraintmask"] = "'@DUM'"

logging.info(f"Running production in window {window}...")simulation.run(overwrite=True)

2020-10-05 12:13:45 PM Running production in window a000...2020-10-05 12:13:48 PM Running production in window a001...2020-10-05 12:13:52 PM Running production in window a002...2020-10-05 12:13:55 PM Running production in window a003...2020-10-05 12:13:59 PM Running production in window a004...2020-10-05 12:14:02 PM Running production in window a005...2020-10-05 12:14:06 PM Running production in window a006...2020-10-05 12:14:09 PM Running production in window a007...2020-10-05 12:14:13 PM Running production in window a008...2020-10-05 12:14:16 PM Running production in window a009...2020-10-05 12:14:19 PM Running production in window a010...2020-10-05 12:14:23 PM Running production in window a011...2020-10-05 12:14:26 PM Running production in window a012...2020-10-05 12:14:30 PM Running production in window a013...2020-10-05 12:14:33 PM Running production in window p000...2020-10-05 12:14:37 PM Running production in window p001...2020-10-05 12:14:40 PM Running production in window p002...2020-10-05 12:14:44 PM Running production in window p003...2020-10-05 12:14:47 PM Running production in window p004...2020-10-05 12:14:51 PM Running production in window p005...2020-10-05 12:14:54 PM Running production in window p006...2020-10-05 12:14:57 PM Running production in window p007...2020-10-05 12:15:01 PM Running production in window p008...2020-10-05 12:15:04 PM Running production in window p009...2020-10-05 12:15:07 PM Running production in window p010...

(continues on next page)

36 Chapter 5. References

Page 41: pAPRika Documentation

pAPRika Documentation

(continued from previous page)

2020-10-05 12:15:11 PM Running production in window p011...2020-10-05 12:15:14 PM Running production in window p012...2020-10-05 12:15:17 PM Running production in window p013...2020-10-05 12:15:21 PM Running production in window p014...2020-10-05 12:15:24 PM Running production in window p015...2020-10-05 12:15:27 PM Running production in window p016...2020-10-05 12:15:31 PM Running production in window p017...

5.3.5 Analysis

Once the simulation is completed, we can using the analysis module to determine the binding free energy. Wesupply the location of the parameter information, a string or list for the file names (wildcards supported), the locationof the windows, and the restraints on the guest.

In this example, we use the method ti-block which determines the free energy using thermodynamic iintegrationand then estimates the standard error of the mean at each data point using blocking analysis. Bootstrapping it used todetermine the uncertainty of the full thermodynamic integral for each phase.

After running compute_free_energy(), a dictionary called results will be populated, that contains the freeenergy and SEM for each phase of the simulation.

[39]: from paprika import analysis

[40]: free_energy = analysis.fe_calc()free_energy.prmtop = "cb6-but-dum.prmtop"free_energy.trajectory = 'production*.nc'free_energy.path = "windows"free_energy.restraint_list = guest_restraintsfree_energy.collect_data()free_energy.methods = ['ti-block']free_energy.ti_matrix = "full"free_energy.bootcycles = 1000free_energy.compute_free_energy()

But what about release? The guest’s rotational and translational degrees of freedom are still restrained releative to theframe of reference of the host. The work to release these restraints is the difference between the chemical potential ofthis state, and the chemical potentials of the separate host and guest at standard concentration. This can be calculatedanalytically without doing additional simulation (see equation 8), using the function compute_ref_state_work.

[41]: free_energy.compute_ref_state_work([guest_restraints[0], guest_restraints[1], None,None, guest_restraints[2], None

])

binding_affinity = -1 * (free_energy.results["attach"]["ti-block"]["fe"] + \free_energy.results["pull"]["ti-block"]["fe"] + \free_energy.results["ref_state_work"])

sem = np.sqrt(free_energy.results["attach"]["ti-block"]["sem"]**2 + \free_energy.results["pull"]["ti-block"]["sem"]**2)

5.3. pAPRika tutorial 1 - An introduction to APR with Implicit solvent 37

Page 42: pAPRika Documentation

pAPRika Documentation

[42]: print(f"The binding affinity for butane and cucurbit[6]uril = {binding_affinity:0.2f}→˓+/- {sem:0.2f} kcal/mol")

The binding affinity for butane and cucurbit[6]uril = -2.98 +/- 5.82 kcal/mol

There is a large uncertainty associated with this calculation because we only simulated for a very short amount of timein each window and we used a large amount of spacing between each window in the pull phase, but the uncertaintywill go down with more time.

The experimental value is −𝑅𝑇 ln(280 * 103𝑀) = -7.44 kcal/mol.

5.4 pAPRika tutorial 2 - Explicit Solvent

In this example, we will setup and simulate butane (BUT) as a guest molecule for the host cucurbit[6]uril (CB6).

Unlike the previous tutorial, in this one, we will solvate the host-guest complex in water with additional Na+ and Cl-ions. This tutorial builds off tutorial 1. I’ve marked new pieces of information with a blue circle, like so:

Since we have a prepared host-guest-dummy setup from the first tutorial, I’m going to skip the initial tleap stepsand go right into initializing the restraints.

The default mode of pAPRika is to detect whether a simulation has completed successfully, and if so, skip that window.This helps when launching mulitple jobs on a cluster or queuing system that might kill jobs after a pre-determined time.That means that running this notebook with the same set of windows as the first tutorial will not re-run the simulationsand the results won’t change. The easiest thing to do is to rename or delete the existing windows directory, if youwould like to compare the results between the two methods.

5.4.1 Initial Setup

[ ]: import osdata = "../../../paprika/data/cb6-but"

Determine the number of windows

Before we add the restraints, it is helpful to set the 𝜆 fractions that control the strength of the force constants duringattach and release, and to define the distances for the pulling phase.

The attach fractions go from 0 to 1 and we place more points at the bottom of the range to sample the curvatureof 𝑑𝑈/𝑑𝜆. Next, we generally apply a distance restraint until the guest is ~18 Angstroms away from the host, inincrements of 0.4 Angstroms. This distance should be at least twice the Lennard-Jones cutoff in the system. Thesevalues have worked well for us, but this is one aspect that should be carefully checked for new systems.

[1]: attach_string = "0.00 0.40 0.80 1.60 2.40 4.00 5.50 8.65 11.80 18.10 24.40 37.00 49.→˓60 74.80 100.00"attach_fractions = [float(i) / 100 for i in attach_string.split()]

[2]: import numpy as npinitial_distance = 6.0pull_distances = np.arange(0.0 + initial_distance, 18.0 + initial_distance, 1.0)

These values will be used to measure distance relative to the first dummy atom, hence the addition of 6.00.

38 Chapter 5. References

Page 43: pAPRika Documentation

pAPRika Documentation

[3]: release_fractions = []

[4]: windows = [len(attach_fractions), len(pull_distances), len(release_fractions)]print(f"There are {windows} windows in this attach-pull-release calculation.")

There are [15, 18, 0] windows in this attach-pull-release calculation.

Alternatively, we could specify the number of windows for each phase and the force constants and targets will belinearly interpolated. Other ways of specifying these values are documented in the code.

5.4.2 Add restraints using pAPRika

pAPRika supports four different types of restraints:

• Static restraints: these six restraints keep the host and in the proper orientation during the simulation (necessary),

• Guest restraints: these restraints pull the guest away from the host along the 𝑧-axis (necessary),

• Conformational restraints: these restraints alter the conformational sampling of the host molecule (optional),and

• Wall restraints: these restraints help define the bound state of the guest (optional).

More information on these restraints can be found in:

Henriksen, N.M., Fenley, A.T., and Gilson, M.K. (2015). Computational Calorimetry: High-Precision Calculation ofHost-Guest Binding Thermodynamics. J. Chem. Theory Comput. 11, 4377–4394. DOI

In this example, I will show how to setup the static restraints and the guest restraints.

We have already added the dummy atoms and we have already defined the guest anchor atoms. Now we need to definethe host anchor atoms (H1, H2, and H3) in the above diagram. The host anchors should be heavy atoms distributedaround the cavity (and around the pulling axis). One caveat is that the host anchors should be rigid relative to eachother, so conformational restraints do not shift the alignment of the pulling axis relative to the solvation box. For CB6,I have chosen carbons around the central ridge.

[5]: G1 = ":BUT@C"G2 = ":BUT@C3"

[6]: H1 = ":CB6@C"H2 = ":CB6@C31"H3 = ":CB6@C18"

I’ll also make a shorthand for the dummy atoms.

[7]: D1 = ":DM1"D2 = ":DM2"D3 = ":DM3"

5.4. pAPRika tutorial 2 - Explicit Solvent 39

Page 44: pAPRika Documentation

pAPRika Documentation

Static restraints

These harmonic restraints are constant throughout the entire simulation. These restraints are used to control thedistances and angles between the host and guest relative to the dummy atom. We have created a special class forthese restrains, static_DAT_restraint, that uses the initial value as the restraint target (this is why the startingstructure should be a reasonable facsimile of the bound state).

Note that these restraints are not “attached” and they don’t need to be “released” – their force constants do not changein magnitude.

The first three static restraints affect the translational distance, angle, and torsion angle between the host and thedummy atoms. These control the position of the host, via the first anchor atom, from moving relative to the dummyatoms.

There is no correct value for the force constants. From experience, we know that a distance force constant of 5.0

kcal/mol/∘A2 won’t nail down the host and yet it also won’t wander away. Likewise, we have had good results using

100.0 kcal/mol/𝑟𝑎𝑑2 for the angle force constant.

[8]: from paprika import restraintsstatic_restraints = []

40 Chapter 5. References

Page 45: pAPRika Documentation

pAPRika Documentation

[9]: import parmed as pmdstructure = pmd.load_file("complex/cb6-but-dum.prmtop", "complex/cb6-but-dum.rst7")

[10]: r = restraints.static_DAT_restraint(restraint_mask_list = [D1, H1],num_window_list = windows,ref_structure = structure,force_constant = 5.0,amber_index=True)

static_restraints.append(r)

[11]: r = restraints.static_DAT_restraint(restraint_mask_list = [D2, D1, H1],num_window_list = windows,ref_structure = structure,force_constant = 100.0,amber_index=True)

static_restraints.append(r)

[12]: r = restraints.static_DAT_restraint(restraint_mask_list = [D3, D2, D1, H1],num_window_list = windows,ref_structure = structure,force_constant = 100.0,amber_index=True)

static_restraints.append(r)

The next three restraints control the orientation of the host relative to the dummy atoms. These angle and torsionrestraints prevent the host from rotating relative to the dummy atoms.

5.4. pAPRika tutorial 2 - Explicit Solvent 41

Page 46: pAPRika Documentation

pAPRika Documentation

[13]: r = restraints.static_DAT_restraint(restraint_mask_list = [D1, H1, H2],num_window_list = windows,ref_structure = structure,force_constant = 100.0,amber_index=True)

static_restraints.append(r)

[14]: r = restraints.static_DAT_restraint(restraint_mask_list = [D2, D1, H1, H2],num_window_list = windows,ref_structure = structure,force_constant = 100.0,amber_index=True)

static_restraints.append(r)

[15]: r = restraints.static_DAT_restraint(restraint_mask_list = [D1, H1, H2, H3],num_window_list = windows,ref_structure = structure,force_constant = 100.0,amber_index=True)

static_restraints.append(r)

42 Chapter 5. References

Page 47: pAPRika Documentation

pAPRika Documentation

Guest restraints

Next, we add restraints on the guest. These restraints control the position of the guest and are the key to the attach-pull-release method. During the attach phase, the force constants for these restraints is increased from zero. Duringthe pull phase, the target for the distance restraint is increased (in the orange box, below), translating the guest awayfrom the host cavity. And during the release phase, the force constants are reduced from their “full” value back downto zero.

We use the class DAT_restraint to create these three restraints. We will use the same anchor atoms as before,with the same distance and angle force constants. Note that unlike static_DAT_restraint, we will first createthe restraint, then set the attributes, then initialize the restraint which does some checks to make sure everything iscopacetic.

There are two additional convenience options here:

• auto_apr = True sets the force constant during pull to be the final force constant after attach and sets theinitial restraint target during pull to be the final attach target.

• continuous_apr = True sets the last window of attach to be the same as the first window as pull (andlikewise for release)

Also note, due to a quirk with AMBER, we specifcy angle and torsion targets in degrees but the force constant usingradians!

5.4. pAPRika tutorial 2 - Explicit Solvent 43

Page 48: pAPRika Documentation

pAPRika Documentation

[16]: guest_restraints = []

[17]: r = restraints.DAT_restraint()r.mask1 = D1r.mask2 = G1r.topology = structurer.auto_apr = Truer.continuous_apr = Truer.amber_index = True

r.attach["target"] = 6.0 # Angstromsr.attach["fraction_list"] = attach_fractionsr.attach["fc_final"] = 5.0 # kcal/mol/Angstroms**2

r.pull["target_final"] = 24.0 # Angstromsr.pull["num_windows"] = windows[1]

r.initialize()guest_restraints.append(r)

[18]: r = restraints.DAT_restraint()r.mask1 = D2r.mask2 = D1r.mask3 = G1r.topology = structurer.auto_apr = Truer.continuous_apr = Truer.amber_index = True

r.attach["target"] = 180.0 # Degreesr.attach["fraction_list"] = attach_fractionsr.attach["fc_final"] = 100.0 # kcal/mol/radian**2

r.pull["target_final"] = 180.0 # Degreesr.pull["num_windows"] = windows[1]

r.initialize()guest_restraints.append(r)

[19]: r = restraints.DAT_restraint()r.mask1 = D1r.mask2 = G1r.mask3 = G2r.topology = structurer.auto_apr = Truer.continuous_apr = Truer.amber_index = True

r.attach["target"] = 180.0 # Degreesr.attach["fraction_list"] = attach_fractionsr.attach["fc_final"] = 100.0 # kcal/mol/radian**2

r.pull["target_final"] = 180.0 # Degreesr.pull["num_windows"] = windows[1]

r.initialize()guest_restraints.append(r)

44 Chapter 5. References

Page 49: pAPRika Documentation

pAPRika Documentation

Create the directory structure

We use the guest restraints to create a list of windows with the appropriate names and then we create the directories.

[20]: import osfrom paprika.restraints.restraints import create_window_list

window_list = create_window_list(guest_restraints)for window in window_list:

os.makedirs(f"windows/{window}")

Next, we ask pAPRika to write the restraint information in each window

In each window, we create a file named disang.rest to hold all of the restraint information that is required to runthe simulation with AMBER. We feed the list of restraints to pAPRika, one by one, and it returns the appropriate line.

The functional form of the restraints is specified in section 25.1 of the AMBER18 manual. Specifically, these restraintshave a square bottom with parabolic sides out to a specific distance and then linear sides beyond that. The squarebottom can be eliminated by setting r2=r3 and the linear extension can be eliminated by setting the the r4 = 999and r1 = 0, creating a harmonic restraint

[21]: from paprika.restraints.amber import amber_restraint_line

host_guest_restraints = (static_restraints + guest_restraints)for window in window_list:

with open(f"windows/{window}/disang.rest", "w") as file:for restraint in host_guest_restraints:

string = amber_restraint_line(restraint, window)if string is not None:

file.write(string)

It is a good idea to open up the disang.rest files and see that the force constants and targets make sense (and thereare no NaN values). Do the force constants for the guest restraints start at zero? Do the targets for the pull slowlyincrease?

Save restraints to a JSON file

The previous code block writes restraints in a format that AMBER uses to run simulations in each window, but pAPRikauses other information stored in the DAT_restraint class in the analysis module. By saving the restraints in a file,it is easy to chunk up setup, simulation, and analysis in different sessions orpython scripts.

Note: the API for saving and loading restraints is not stable and may be moved into another submodule. The outputnotes that pAPRika is not including the entire topology in the restraint JSON, but will contain a reference to the filethat was used to setup th restraints, in this case, cb6-but-dum.prmtop.

[22]: from paprika.io import save_restraints

[23]: save_restraints(host_guest_restraints, filepath="windows/restraints.json")

5.4. pAPRika tutorial 2 - Explicit Solvent 45

Page 50: pAPRika Documentation

pAPRika Documentation

5.4.3 Prepare host-guest system

Translation of the guest (before solvation)

For the attach windows, we will use the initial, bound coordinates for the host-guest complex. Only the force constantschange during this phase, so a single set of coordinates is sufficient. For the pull windows, we will translate the guestto the target value of the restraint before solvation, and for the release windows, we will use the coordinates from thefinal pull window.

[24]: import shutil

for window in window_list:if window[0] == "a":

shutil.copy("complex/cb6-but-dum.prmtop", f"windows/{window}/cb6-but-dum.→˓prmtop")

shutil.copy("complex/cb6-but-dum.rst7", f"windows/{window}/cb6-but-dum.rst7")elif window[0] == "p":

structure = pmd.load_file("complex/cb6-but-dum.prmtop", "complex/cb6-but-dum.→˓rst7",

structure = True)target_difference = guest_restraints[0].phase['pull']['targets'][int(window[1:

→˓])] - guest_restraints[0].pull['target_initial']print(f"In window {window} we will translate the guest {target_difference:0.

→˓1f} Angstroms.")for atom in structure.atoms:

if atom.residue.name == "BUT":atom.xz += target_difference

structure.save(f"windows/{window}/cb6-but-dum.prmtop")structure.save(f"windows/{window}/cb6-but-dum.rst7")

In window p000 we will translate the guest 0.0 Angstroms.In window p001 we will translate the guest 1.1 Angstroms.In window p002 we will translate the guest 2.1 Angstroms.In window p003 we will translate the guest 3.2 Angstroms.In window p004 we will translate the guest 4.2 Angstroms.In window p005 we will translate the guest 5.3 Angstroms.In window p006 we will translate the guest 6.4 Angstroms.In window p007 we will translate the guest 7.4 Angstroms.In window p008 we will translate the guest 8.5 Angstroms.In window p009 we will translate the guest 9.5 Angstroms.In window p010 we will translate the guest 10.6 Angstroms.In window p011 we will translate the guest 11.6 Angstroms.In window p012 we will translate the guest 12.7 Angstroms.In window p013 we will translate the guest 13.8 Angstroms.In window p014 we will translate the guest 14.8 Angstroms.In window p015 we will translate the guest 15.9 Angstroms.In window p016 we will translate the guest 16.9 Angstroms.In window p017 we will translate the guest 18.0 Angstroms.

Before running a simulation, open each window and check that the position of the host and dummy atoms are fixedand that the position of the guest is bound during the attach windows, moves progressively further during pull, and isaway from the host during the release windows.

46 Chapter 5. References

Page 51: pAPRika Documentation

pAPRika Documentation

Solvate each window

Unlike the previous tutorial we will solvate the system in each window.

[25]: from paprika.build.system import TLeap

By default, this will use cubic periodic boundary conditions; we usually use octahedral periodic boundary conditionsto optimize space. Based on experience, 2000 waters is a resaonable amount for CB6, but sometimes it is necessary torun with 2500 or 3000 waters depending on the size of the host and guest molecules. The code below first neutralizesthe system (which does not do anything here) and then adds an additional 6 Na+ and 6 Cl- ions. The counterion speciescan be changed via counter_cation and counter_anion, and the add_ions string can take concentrationsin the form of 0.150M or 0.150m for Molarity or molality, respectively.

Note that when running simulations with periodic boundary conditions, be mindful of the box size relative to theLennard-Jones cutoff.

[26]: for window in window_list:print(f"Solvating system in window {window}.")structure = pmd.load_file(f"windows/{window}/cb6-but-dum.prmtop",

f"windows/{window}/cb6-but-dum.rst7")

if not os.path.exists(f"windows/{window}/cb6-but-dum.pdb"):structure.save(f"windows/{window}/cb6-but-dum.pdb")

system = TLeap()system.output_path = os.path.join("windows", window)system.output_prefix = "cb6-but-dum-sol"

system.target_waters = 2000system.neutralize = Truesystem.add_ions = ["Na+", 6, "Cl-", 6]system.template_lines = [

"source leaprc.gaff","source leaprc.water.tip3p",f"loadamberparams {data}/cb6.frcmod","loadamberparams ../../complex/dummy.frcmod",f"CB6 = loadmol2 {data}/cb6.mol2",f"BUT = loadmol2 {data}/but.mol2","DM1 = loadmol2 ../../complex/dm1.mol2","DM2 = loadmol2 ../../complex/dm2.mol2","DM3 = loadmol2 ../../complex/dm3.mol2","model = loadpdb cb6-but-dum.pdb",

]system.build()

Solvating system in window a000.Solvating system in window a001.Solvating system in window a002.Solvating system in window a003.Solvating system in window a004.Solvating system in window a005.Solvating system in window a006.Solvating system in window a007.Solvating system in window a008.Solvating system in window a009.Solvating system in window a010.Solvating system in window a011.Solvating system in window a012.

(continues on next page)

5.4. pAPRika tutorial 2 - Explicit Solvent 47

Page 52: pAPRika Documentation

pAPRika Documentation

(continued from previous page)

Solvating system in window a013.Solvating system in window p000.Solvating system in window p001.Solvating system in window p002.Solvating system in window p003.Solvating system in window p004.Solvating system in window p005.Solvating system in window p006.Solvating system in window p007.Solvating system in window p008.Solvating system in window p009.Solvating system in window p010.Solvating system in window p011.Solvating system in window p012.Solvating system in window p013.Solvating system in window p014.Solvating system in window p015.Solvating system in window p016.Solvating system in window p017.

48 Chapter 5. References

Page 53: pAPRika Documentation

pAPRika Documentation

5.4.4 Simulation

This is going to look very similar to the the implicit solvent simulation setup, except instead of usingconfig_gb_min and config_gb_sim, we will use config_pdb_min and config_pbc_sim.

For this part, you need to have the AMBER executables in your path.

[27]: from paprika.simulate import AMBER

Run a quick minimization in every window. Note that we need to specify simulation.cntrl["ntr"] = 1 toenable the positional restraints on the dummy atoms.

I’m using the logging module to keep track of time.

5.4. pAPRika tutorial 2 - Explicit Solvent 49

Page 54: pAPRika Documentation

pAPRika Documentation

[28]: import loggingfrom importlib import reloadreload(logging)

logger = logging.getLogger()logging.basicConfig(

format='%(asctime)s %(message)s',datefmt='%Y-%m-%d %I:%M:%S %p',level=logging.INFO

)

Energy Minimization

[29]: for window in window_list:simulation = AMBER()simulation.executable = "mpirun -np 4 pmemd.MPI"

simulation.path = f"windows/{window}/"simulation.prefix = "minimize"

simulation.topology = "cb6-but-dum-sol.prmtop"simulation.coordinates = "cb6-but-dum-sol.rst7"simulation.ref = "cb6-but-dum-sol.rst7"simulation.restraint_file = "disang.rest"

simulation.config_pbc_min()simulation.cntrl["ntr"] = 1simulation.cntrl["restraint_wt"] = 50.0simulation.cntrl["restraintmask"] = "'@DUM'"

logging.info(f"Running minimization in window {window}...")simulation.run()

2020-10-05 12:18:34 PM Running minimization in window a000...2020-10-05 12:19:00 PM Running minimization in window a001...2020-10-05 12:19:26 PM Running minimization in window a002...2020-10-05 12:19:52 PM Running minimization in window a003...2020-10-05 12:20:18 PM Running minimization in window a004...2020-10-05 12:20:45 PM Running minimization in window a005...2020-10-05 12:21:11 PM Running minimization in window a006...2020-10-05 12:21:37 PM Running minimization in window a007...2020-10-05 12:22:03 PM Running minimization in window a008...2020-10-05 12:22:29 PM Running minimization in window a009...2020-10-05 12:22:56 PM Running minimization in window a010...2020-10-05 12:23:22 PM Running minimization in window a011...2020-10-05 12:23:48 PM Running minimization in window a012...2020-10-05 12:24:14 PM Running minimization in window a013...2020-10-05 12:24:40 PM Running minimization in window p000...2020-10-05 12:25:07 PM Running minimization in window p001...2020-10-05 12:25:33 PM Running minimization in window p002...2020-10-05 12:25:59 PM Running minimization in window p003...2020-10-05 12:26:25 PM Running minimization in window p004...2020-10-05 12:26:51 PM Running minimization in window p005...2020-10-05 12:27:17 PM Running minimization in window p006...2020-10-05 12:27:44 PM Running minimization in window p007...2020-10-05 12:28:10 PM Running minimization in window p008...

(continues on next page)

50 Chapter 5. References

Page 55: pAPRika Documentation

pAPRika Documentation

(continued from previous page)

2020-10-05 12:28:36 PM Running minimization in window p009...2020-10-05 12:29:02 PM Running minimization in window p010...2020-10-05 12:29:28 PM Running minimization in window p011...2020-10-05 12:29:54 PM Running minimization in window p012...2020-10-05 12:30:20 PM Running minimization in window p013...2020-10-05 12:30:47 PM Running minimization in window p014...2020-10-05 12:31:13 PM Running minimization in window p015...2020-10-05 12:31:39 PM Running minimization in window p016...2020-10-05 12:32:05 PM Running minimization in window p017...

For simplicity, I am going to skip equilibration and go straight to production!

I’m also going to run a little bit longer in each window, because the additional atoms increases the convergence time.The total simulation time per window, in nanoseconds, is (nstlim) × (dt in fs / 1000) = (50000) × (0.002 / 1000) = 0.1ns. This is still very short and just for demonstration. A production simulation might require as much as 15 ns perwindow for binding free energies and up to 1 us per window for binding enthalpies.

Production Run

[33]: for window in window_list:simulation = AMBER()simulation.executable = "pmemd.cuda"simulation.gpu_devices = 0

simulation.path = f"windows/{window}/"simulation.prefix = "production"

simulation.topology = "cb6-but-dum-sol.prmtop"simulation.coordinates = "minimize.rst7"simulation.ref = "cb6-but-dum-sol.rst7"simulation.restraint_file = "disang.rest"

simulation.config_pbc_md()simulation.cntrl["ntr"] = 1simulation.cntrl["restraint_wt"] = 50.0simulation.cntrl["restraintmask"] = "'@DUM'"simulation.cntrl["nstlim"] = 50000

logging.info(f"Running production in window {window}...")simulation.run(overwrite=True)

2020-10-05 12:42:12 PM Running production in window a000...2020-10-05 12:42:25 PM Running production in window a001...2020-10-05 12:42:38 PM Running production in window a002...2020-10-05 12:42:51 PM Running production in window a003...2020-10-05 12:43:04 PM Running production in window a004...2020-10-05 12:43:18 PM Running production in window a005...2020-10-05 12:43:31 PM Running production in window a006...2020-10-05 12:43:44 PM Running production in window a007...2020-10-05 12:43:57 PM Running production in window a008...2020-10-05 12:44:11 PM Running production in window a009...2020-10-05 12:44:24 PM Running production in window a010...2020-10-05 12:44:37 PM Running production in window a011...2020-10-05 12:44:50 PM Running production in window a012...2020-10-05 12:45:04 PM Running production in window a013...2020-10-05 12:45:17 PM Running production in window p000...

(continues on next page)

5.4. pAPRika tutorial 2 - Explicit Solvent 51

Page 56: pAPRika Documentation

pAPRika Documentation

(continued from previous page)

2020-10-05 12:45:30 PM Running production in window p001...2020-10-05 12:45:43 PM Running production in window p002...2020-10-05 12:45:57 PM Running production in window p003...2020-10-05 12:46:10 PM Running production in window p004...2020-10-05 12:46:23 PM Running production in window p005...2020-10-05 12:46:36 PM Running production in window p006...2020-10-05 12:46:50 PM Running production in window p007...2020-10-05 12:47:03 PM Running production in window p008...2020-10-05 12:47:16 PM Running production in window p009...2020-10-05 12:47:29 PM Running production in window p010...2020-10-05 12:47:43 PM Running production in window p011...2020-10-05 12:47:56 PM Running production in window p012...2020-10-05 12:48:09 PM Running production in window p013...2020-10-05 12:48:22 PM Running production in window p014...2020-10-05 12:48:35 PM Running production in window p015...2020-10-05 12:48:49 PM Running production in window p016...2020-10-05 12:49:02 PM Running production in window p017...

5.4.5 Analysis

We will perform the analysis using restraints saved previously to a JSON file.

Once the simulation is completed, we can using the analysis module to determine the binding free energy. Wesupply the location of the parameter information, a string or list for the file names (wildcards supported), the locationof the windows, and the restraints on the guest.

In this example, we use the method ti-block which determines the free energy using thermodynamic iintegrationand then estimates the standard error of the mean at each data point using blocking analysis. Bootstrapping it used todetermine the uncertainty of the full thermodynamic integral for each phase.

After running compute_free_energy(), a dictionary called results will be populated, that contains the freeenergy and SEM for each phase of the simulation.

[34]: from paprika.io import load_restraints

[35]: guest_restraints = load_restraints("windows/restraints.json")

[36]: from paprika import analysis

[37]: free_energy = analysis.fe_calc()free_energy.prmtop = "cb6-but-dum-sol.prmtop"free_energy.trajectory = 'production*.nc'free_energy.path = "windows"free_energy.restraint_list = guest_restraintsfree_energy.collect_data()free_energy.methods = ['ti-block']free_energy.ti_matrix = "full"free_energy.bootcycles = 1000free_energy.compute_free_energy()

[38]: free_energy.compute_ref_state_work([guest_restraints[0], guest_restraints[1], None,None, guest_restraints[2], None

])

52 Chapter 5. References

Page 57: pAPRika Documentation

pAPRika Documentation

[39]: binding_affinity = -1 * (free_energy.results["attach"]["ti-block"]["fe"] + \free_energy.results["pull"]["ti-block"]["fe"] + \free_energy.results["ref_state_work"])

sem = np.sqrt(free_energy.results["attach"]["ti-block"]["sem"]**2 + \free_energy.results["pull"]["ti-block"]["sem"]**2)

[42]: print(f"The binding affinity for butane and cucurbit[6]uril = {binding_affinity:0.2f}→˓+/- {sem:0.2f} kcal/mol")

The binding affinity for butane and cucurbit[6]uril = -11.62 +/- 1.47 kcal/mol

In the first tutorial, using implicit solvation, the binding affinity estimate was -9.00 +/- 5.53 kcal/mol. Now, the affinityestimate is more favorable, by almost 2 kcal/mol, and we’ve halved the uncertainty. As before, with more windowsand more simulation time per window, this value would continue to be refined.

The experimental value is −𝑅𝑇 ln(280 * 103𝑀) = -7.44 kcal/mol.

5.5 pAPRika tutorial 3 - K-Cl dissociation

In this example, we will setup and simulate KCl dissociation using a single distance restraints. This tutorial willdemonstrate the use of pAPRika besides host-guest systems.

[17]: import osimport json

import numpy as npimport parmed as pmd

from paprika.analysis import fe_calcfrom paprika.build.system import TLeapfrom paprika.io import NumpyEncoderfrom paprika.restraints import amber_restraint_line, create_window_list, DAT_restraintfrom paprika.simulate import AMBER

5.5.1 Specify directory for data

In this case, we just need some initial coordinates. In other cases, we might need mol2 or frcmod files.

[13]: from pathlib import Pathcwd = Path().resolve()k_cl_pdb = os.path.abspath(os.path.join(cwd, "../../paprika/data/k-cl/k-cl.pdb"))

5.5. pAPRika tutorial 3 - K-Cl dissociation 53

Page 58: pAPRika Documentation

pAPRika Documentation

5.5.2 Setup the calculation

Build the vacuum prmtop and inpcrd files

[18]: # Build the model in vacuum

system = TLeap()system.template_lines = [

"source leaprc.water.tip3p","loadamberparams frcmod.ionsjc_tip3p",f"model = loadpdb {k_cl_pdb}",

]system.output_path = "tmp"system.output_prefix = "k-cl"system.pbc_type = Nonesystem.target_waters = Nonesystem.neutralize = Falsesystem.build()

Specify the number of windows for the umbrella sampling

These are overkill; I have been testing how much data we need to converge this calculation and how quickly we canrun a stripped-down version on Travis.

[19]: attach_fractions = np.linspace(0, 1.0, 25)initial_distance = 2.65pull_distances = np.linspace(0 + initial_distance, 16.0 + initial_distance, 40)

Add a single distance restraint between K+ and Cl-

[20]: restraint = DAT_restraint()restraint.continuous_apr = Truerestraint.amber_index = Truerestraint.topology = k_cl_pdbrestraint.mask1 = "@K+"restraint.mask2 = "@Cl-"

restraint.attach["target"] = initial_distancerestraint.attach["fraction_list"] = attach_fractionsrestraint.attach["fc_final"] = 10.0restraint.pull["fc"] = restraint.attach["fc_final"]restraint.pull["target_list"] = pull_distancesrestraint.initialize()

54 Chapter 5. References

Page 59: pAPRika Documentation

pAPRika Documentation

Optionally, add a “wall restraint” to define the bound state and speed convergence

This will apply a harmonic potential that keeps the “guest” Cl- within 3.5 Angstroms.

[21]: wall = DAT_restraint()wall.auto_apr = Falsewall.amber_index = Truewall.topology = k_cl_pdbwall.mask1 = "@K+"wall.mask2 = "@Cl-"

wall.attach["fc_initial"] = 1.0wall.attach["fc_final"] = 1.0

wall.custom_restraint_values["rk2"] = 1.0wall.custom_restraint_values["rk3"] = 1.0wall.custom_restraint_values["r1"] = 0.0wall.custom_restraint_values["r2"] = 3.5wall.custom_restraint_values["r3"] = 3.5wall.custom_restraint_values["r4"] = 999

wall.attach["target"] = 3.5wall.attach["num_windows"] = len(attach_fractions)

wall.initialize()

Create the directories for each window and write the AMBER-style restraint input file

This makes it easy to run each window in parallel as a separate simulation.

[22]: # Create folder for the working directorywindow_list = create_window_list([restraint])for window in window_list:

os.makedirs(f"tmp/windows/{window}", exist_ok=True)

# Write the AMBER restraint files for each windowfor window in window_list:

with open(f"tmp/windows/{window}/disang.rest", "a") as file:if window[0] == "a":

for r in [restraint, wall]:string = amber_restraint_line(r, window)if string is not None:

file.write(string)else:

string = amber_restraint_line(restraint, window)file.write(string)

# Generate the topology and coordinates file for each windowfor window in window_list:

if window[0] == "a":structure = pmd.load_file("tmp/k-cl.prmtop", "tmp/k-cl.rst7", structure=True)for atom in structure.atoms:

if atom.name == "Cl-":atom.xz = 2.65

structure.save(f"tmp/windows/{window}/k-cl.prmtop", overwrite=True)structure.save(f"tmp/windows/{window}/k-cl.rst7", overwrite=True)

(continues on next page)

5.5. pAPRika tutorial 3 - K-Cl dissociation 55

Page 60: pAPRika Documentation

pAPRika Documentation

(continued from previous page)

elif window[0] == "p":structure = pmd.load_file("tmp/k-cl.prmtop", "tmp/k-cl.rst7", structure=True)target_difference = (

restraint.phase["pull"]["targets"][int(window[1:])]- restraint.phase["pull"]["targets"][0]

)print(

f"In window {window} we will translate the guest {target_difference:0.1f}→˓Angstroms."

)for atom in structure.atoms:

if atom.name == "Cl-":atom.xz += target_difference

structure.save(f"tmp/windows/{window}/k-cl.prmtop", overwrite=True)structure.save(f"tmp/windows/{window}/k-cl.rst7", overwrite=True)

In window p000 we will translate the guest 0.0 Angstroms.In window p001 we will translate the guest 0.4 Angstroms.In window p002 we will translate the guest 0.8 Angstroms.In window p003 we will translate the guest 1.2 Angstroms.In window p004 we will translate the guest 1.6 Angstroms.In window p005 we will translate the guest 2.1 Angstroms.In window p006 we will translate the guest 2.5 Angstroms.In window p007 we will translate the guest 2.9 Angstroms.In window p008 we will translate the guest 3.3 Angstroms.In window p009 we will translate the guest 3.7 Angstroms.In window p010 we will translate the guest 4.1 Angstroms.In window p011 we will translate the guest 4.5 Angstroms.In window p012 we will translate the guest 4.9 Angstroms.In window p013 we will translate the guest 5.3 Angstroms.In window p014 we will translate the guest 5.7 Angstroms.In window p015 we will translate the guest 6.2 Angstroms.In window p016 we will translate the guest 6.6 Angstroms.In window p017 we will translate the guest 7.0 Angstroms.In window p018 we will translate the guest 7.4 Angstroms.In window p019 we will translate the guest 7.8 Angstroms.In window p020 we will translate the guest 8.2 Angstroms.In window p021 we will translate the guest 8.6 Angstroms.In window p022 we will translate the guest 9.0 Angstroms.In window p023 we will translate the guest 9.4 Angstroms.In window p024 we will translate the guest 9.8 Angstroms.In window p025 we will translate the guest 10.3 Angstroms.In window p026 we will translate the guest 10.7 Angstroms.In window p027 we will translate the guest 11.1 Angstroms.In window p028 we will translate the guest 11.5 Angstroms.In window p029 we will translate the guest 11.9 Angstroms.In window p030 we will translate the guest 12.3 Angstroms.In window p031 we will translate the guest 12.7 Angstroms.In window p032 we will translate the guest 13.1 Angstroms.In window p033 we will translate the guest 13.5 Angstroms.In window p034 we will translate the guest 13.9 Angstroms.In window p035 we will translate the guest 14.4 Angstroms.In window p036 we will translate the guest 14.8 Angstroms.In window p037 we will translate the guest 15.2 Angstroms.In window p038 we will translate the guest 15.6 Angstroms.In window p039 we will translate the guest 16.0 Angstroms.

56 Chapter 5. References

Page 61: pAPRika Documentation

pAPRika Documentation

Optionally, tweak some parameters, like changing the charge of K+ to 1.3 and Cl- to -1.3

[23]: for window in window_list:structure = pmd.load_file(

f"tmp/windows/{window}/k-cl.prmtop",f"tmp/windows/{window}/k-cl.rst7",structure=True,

)for atom in structure.atoms:

if atom.name == "Cl-":atom.charge = -1.3

elif atom.name == "K+":atom.charge = 1.3

structure.save(f"tmp/windows/{window}/k-cl.prmtop", overwrite=True)structure.save(f"tmp/windows/{window}/k-cl.rst7", overwrite=True)

Solvate the structure in each window to the same number of waters

[24]: for window in window_list:print(f"Solvating window {window}...")

if os.path.exists(f"tmp/windows/{window}/k-cl-sol.prmtop"):print("Skipping...")continue

structure = pmd.load_file(f"tmp/windows/{window}/k-cl.prmtop", f"tmp/windows/{window}/k-cl.rst7"

)

if not os.path.exists(f"tmp/windows/{window}/k-cl.pdb"):structure.save(f"tmp/windows/{window}/k-cl.pdb")

system = TLeap()system.output_path = os.path.join("tmp", "windows", window)system.output_prefix = "k-cl-sol"

system.target_waters = 2000system.neutralize = Falsesystem.template_lines = [

"source leaprc.water.tip3p","model = loadpdb k-cl.pdb"

]system.build()

Solvating window a000...Solvating window a001...Solvating window a002...Solvating window a003...Solvating window a004...Solvating window a005...Solvating window a006...Solvating window a007...Solvating window a008...Solvating window a009...Solvating window a010...Solvating window a011...

(continues on next page)

5.5. pAPRika tutorial 3 - K-Cl dissociation 57

Page 62: pAPRika Documentation

pAPRika Documentation

(continued from previous page)

Solvating window a012...Solvating window a013...Solvating window a014...Solvating window a015...Solvating window a016...Solvating window a017...Solvating window a018...Solvating window a019...Solvating window a020...Solvating window a021...Solvating window a022...Solvating window a023...Solvating window p000...Solvating window p001...Solvating window p002...Solvating window p003...Solvating window p004...Solvating window p005...Solvating window p006...Solvating window p007...Solvating window p008...Solvating window p009...Solvating window p010...Solvating window p011...Solvating window p012...Solvating window p013...Solvating window p014...Solvating window p015...Solvating window p016...Solvating window p017...Solvating window p018...Solvating window p019...Solvating window p020...Solvating window p021...Solvating window p022...Solvating window p023...Solvating window p024...Solvating window p025...Solvating window p026...Solvating window p027...Solvating window p028...Solvating window p029...Solvating window p030...Solvating window p031...Solvating window p032...Solvating window p033...Solvating window p034...Solvating window p035...Solvating window p036...Solvating window p037...Solvating window p038...Solvating window p039...

58 Chapter 5. References

Page 63: pAPRika Documentation

pAPRika Documentation

5.5.3 Run the calculation

We have a few helper functions – like config_pbc_min() and config_pbc_md() – that help setup somesmart defaults for AMBER. (I’ll make a note to work on adding this for the OpenMM side of things.) The simulationscan either be run directly, as indicated below, with simulation.run() or the input file can be written using_amber_write_input_file() and then wrapped using a cluster script (like PBS or whatever).

Energy Minimization

[ ]: for window in window_list:simulation = AMBER()simulation.executable = "pmemd.cuda"

simulation.path = f"tmp/windows/{window}/"simulation.prefix = "minimize"

simulation.topology = "k-cl-sol.prmtop"simulation.coordinates = "k-cl-sol.rst7"simulation.ref = "k-cl-sol.rst7"simulation.restraint_file = "disang.rest"

simulation.config_pbc_min()simulation.cntrl["ntr"] = 1simulation.cntrl["restraint_wt"] = 50.0simulation.cntrl["restraintmask"] = "':1-2'"print(f"Running minimization in window {window}...")simulation.run()

Production Run

[ ]: # Simulatefor window in window_list:

simulation = AMBER()simulation.executable = "pmemd.cuda"

simulation.path = f"tmp/windows/{window}/"simulation.prefix = "production"

simulation.inpcrd = "minimize.rst7"simulation.ref = "k-cl-sol.rst7"simulation.topology = "k-cl-sol.prmtop"simulation.restraint_file = "disang.rest"

simulation.config_pbc_md()simulation.cntrl["nstlim"] = 50000

print(f"Running production in window {window}...")simulation.run()

5.5. pAPRika tutorial 3 - K-Cl dissociation 59

Page 64: pAPRika Documentation

pAPRika Documentation

5.5.4 Analyze the simulation

Setup the analysis

The analysis needs to know about:

• The parameter file that was used for the molecules,

• The simulation path,

• The trajectories, and

• The method to do the analysis (e.g., TI for the free energy with blocking analysis for the SEM)

[ ]: free_energy = fe_calc()free_energy.prmtop = "k-cl-sol.prmtop"free_energy.trajectory = "production*.nc"free_energy.path = "tmp/windows"free_energy.restraint_list = [restraint]free_energy.collect_data()free_energy.methods = ["ti-block", "mbar-block"]free_energy.ti_matrix = "full"free_energy.bootcycles = 100

Run the analysis and save the results

[ ]: free_energy.compute_free_energy()free_energy.compute_ref_state_work([restraint, None, None, None, None, None])

[ ]: with open("./tmp/results.json", "w") as f:dumped = json.dumps(free_energy.results, cls=NumpyEncoder)f.write(dumped)

binding_affinity = -1 * (free_energy.results["attach"]["ti-block"]["fe"]+ free_energy.results["pull"]["ti-block"]["fe"]+ free_energy.results["ref_state_work"]

)

sem = np.sqrt(free_energy.results["attach"]["ti-block"]["sem"] ** 2+ free_energy.results["pull"]["ti-block"]["sem"] ** 2

)

print(f"The binding affinity for K+ (+1.3) and Cl- (-1.3) = {binding_affinity:0.2f} +/-

→˓{sem:0.2f} kcal/mol")

60 Chapter 5. References

Page 65: pAPRika Documentation

pAPRika Documentation

5.6 pAPRika tutorial 4 - APR/OpenMM

In this tutorial, we will perform APR calculations for butane (BUT)–cucurbit[6]uril (CB6). This is a repeat of tutorial1 using OpenMM instead of AMBER as the simulation engine. We will go through the process of converting APRrestraints constructed with pAPRika and AMBER structure files to an OpenMM system.

Since we have a prepared the host-guest-dummy setup from the first tutorial, we will skip the initial tleap steps andgo right into initializing the restraints.

5.6.1 Initialize

[1]: import osimport jsonimport shutilimport numpy as npimport parmed as pmd

Initialize logger

[2]: import loggingfrom importlib import reloadreload(logging)

logger = logging.getLogger()logging.basicConfig(

format='%(asctime)s %(message)s',datefmt='%Y-%m-%d %I:%M:%S %p',level=logging.INFO

)

Define names

We will store the files created in this tutorial in a folder called openmm so we don’t mix files with the previous tutorial.

[3]: base_name = "cb6-but-dum"work_dir = "openmm"complex_dir = "complex"

5.6.2 Generate APR Restraints

NOTE: The only difference here is to set amber_index to False since OpenMM atom numbering starts from 0.

5.6. pAPRika tutorial 4 - APR/OpenMM 61

Page 66: pAPRika Documentation

pAPRika Documentation

Define anchor atoms

See tutorial 1 for the choice of selection

[4]: # Guest atomsG1 = ":BUT@C"G2 = ":BUT@C3"

# Host atomsH1 = ":CB6@C"H2 = ":CB6@C31"H3 = ":CB6@C18"

# Dummy atomsD1 = ":DM1"D2 = ":DM2"D3 = ":DM3"

Determine the number of windows

Before we add the restraints, it is helpful to set the 𝜆 fractions that control the strength of the force constants duringattach and release, and to define the distances for the pulling phase.

The attach fractions go from 0 to 1 and we place more points at the bottom of the range to sample the curvatureof 𝑑𝑈/𝑑𝜆. Next, we generally apply a distance restraint until the guest is ~18 Angstroms away from the host, inincrements of 0.4 Angstroms. This distance should be at least twice the Lennard-Jones cutoff in the system. Thesevalues have worked well for us, but this is one aspect that should be carefully checked for new systems.

[5]: attach_string = "0.00 0.40 0.80 1.60 2.40 4.00 5.50 8.65 11.80 18.10 24.40 37.00 49.→˓60 74.80 100.00"attach_fractions = [float(i) / 100 for i in attach_string.split()]

initial_distance = 6.0pull_distances = np.arange(0.0 + initial_distance, 18.0 + initial_distance, 1.0)

release_fractions = []

windows = [len(attach_fractions), len(pull_distances), len(release_fractions)]logging.info(f"There are {windows} windows in this attach-pull-release calculation.")

2020-08-19 10:30:19 PM There are [15, 18, 0] windows in this attach-pull-release→˓calculation.

Load complex structure

[7]: structure = pmd.load_file(os.path.join(complex_dir, f"{base_name}.prmtop"),os.path.join(complex_dir, f"{base_name}.rst7"),structure = True,

)

62 Chapter 5. References

Page 67: pAPRika Documentation

pAPRika Documentation

Host Static Restraints

See tutorial 1 for an explanation of the static restraints

[ ]: import paprika.restraints as restraints

[8]: static_restraints = []

[9]: r = restraints.static_DAT_restraint(restraint_mask_list = [D1, H1],num_window_list = windows,ref_structure = structure,force_constant = 5.0,amber_index=False)

static_restraints.append(r)

[10]: r = restraints.static_DAT_restraint(restraint_mask_list = [D2, D1, H1],num_window_list = windows,ref_structure = structure,force_constant = 100.0,amber_index=False)

static_restraints.append(r)

[11]: r = restraints.static_DAT_restraint(restraint_mask_list = [D3, D2, D1, H1],num_window_list = windows,ref_structure = structure,force_constant = 100.0,amber_index=False)

static_restraints.append(r)

[12]: r = restraints.static_DAT_restraint(restraint_mask_list = [D1, H1, H2],num_window_list = windows,ref_structure = structure,force_constant = 100.0,amber_index=False)

static_restraints.append(r)

[13]: r = restraints.static_DAT_restraint(restraint_mask_list = [D2, D1, H1, H2],num_window_list = windows,ref_structure = structure,force_constant = 100.0,amber_index=False)

static_restraints.append(r)

[14]: r = restraints.static_DAT_restraint(restraint_mask_list = [D1, H1, H2, H3],num_window_list = windows,ref_structure = structure,force_constant = 100.0,amber_index=False)

static_restraints.append(r)

5.6. pAPRika tutorial 4 - APR/OpenMM 63

Page 68: pAPRika Documentation

pAPRika Documentation

Guest translational and rotational restraints

See tutorial 1 for an explanation of the guest restraints

[15]: guest_restraints = []

[16]: r = restraints.DAT_restraint()r.mask1 = D1r.mask2 = G1r.topology = structurer.auto_apr = Truer.continuous_apr = Truer.amber_index = False

r.attach["target"] = pull_distances[0] # Angstromsr.attach["fraction_list"] = attach_fractionsr.attach["fc_final"] = 5.0 # kcal/mol/Angstroms**2

r.pull["target_final"] = 24.0 # Angstromsr.pull["num_windows"] = windows[1]

r.initialize()guest_restraints.append(r)

[17]: r = restraints.DAT_restraint()r.mask1 = D2r.mask2 = D1r.mask3 = G1r.topology = structurer.auto_apr = Truer.continuous_apr = Truer.amber_index = False

r.attach["target"] = 180.0 # Degreesr.attach["fraction_list"] = attach_fractionsr.attach["fc_final"] = 100.0 # kcal/mol/radian**2

r.pull["target_final"] = 180.0 # Degreesr.pull["num_windows"] = windows[1]

r.initialize()guest_restraints.append(r)

[18]: r = restraints.DAT_restraint()r.mask1 = D1r.mask2 = G1r.mask3 = G2r.topology = structurer.auto_apr = Truer.continuous_apr = Truer.amber_index = False

r.attach["target"] = 180.0 # Degreesr.attach["fraction_list"] = attach_fractionsr.attach["fc_final"] = 100.0 # kcal/mol/radian**2

r.pull["target_final"] = 180.0 # Degrees(continues on next page)

64 Chapter 5. References

Page 69: pAPRika Documentation

pAPRika Documentation

(continued from previous page)

r.pull["num_windows"] = windows[1]

r.initialize()guest_restraints.append(r)

Create APR windows

We use the guest restraints to create a list of windows with the appropriate names and then create the directories.

[19]: from paprika.restraints.restraints import create_window_list

[20]: window_list = create_window_list(guest_restraints)

2020-08-19 10:30:19 PM Restraints appear to be consistent

[21]: for window in window_list:folder = os.path.join(work_dir, window)if not os.path.isdir(folder):

os.makedirs(os.path.join(work_dir, window))

5.6.3 Prepare host-guest system

Translate guest molecule

For the attach windows, we will use the initial, bound coordinates for the host-guest complex. Only the force constantschange during this phase, so a single set of coordinates is sufficient. For the pull windows, we will translate the guestto the target value of the restraint before solvation, and for the release windows, we will use the coordinates from thefinal pull window.

[22]: for window in window_list:if window[0] == "a":

shutil.copy(os.path.join(complex_dir, f"{base_name}.prmtop"),os.path.join(work_dir, window, f"{base_name}.prmtop"))

shutil.copy(os.path.join(complex_dir, f"{base_name}.rst7"),os.path.join(work_dir, window, f"{base_name}.rst7"))

elif window[0] == "p":structure = pmd.load_file(

os.path.join(complex_dir, f"{base_name}.prmtop"),os.path.join(complex_dir, f"{base_name}.rst7"),structure = True

)target_difference = guest_restraints[0].phase['pull']['targets'][int(window[1:

→˓])] -\guest_restraints[0].pull['target_initial']

logging.info(f"In window {window} we will translate the guest {target_→˓difference:0.1f} Angstroms.")

for atom in structure.atoms:if atom.residue.name == "BUT":

atom.xz += target_difference

(continues on next page)

5.6. pAPRika tutorial 4 - APR/OpenMM 65

Page 70: pAPRika Documentation

pAPRika Documentation

(continued from previous page)

structure.save(os.path.join(work_dir, window, f"{base_name}.prmtop"),→˓overwrite=True)

structure.save(os.path.join(work_dir, window, f"{base_name}.rst7"),→˓overwrite=True)

2020-08-19 10:30:19 PM In window p000 we will translate the guest 0.0 Angstroms.2020-08-19 10:30:19 PM In window p001 we will translate the guest 1.1 Angstroms.2020-08-19 10:30:19 PM In window p002 we will translate the guest 2.1 Angstroms.2020-08-19 10:30:19 PM In window p003 we will translate the guest 3.2 Angstroms.2020-08-19 10:30:19 PM In window p004 we will translate the guest 4.2 Angstroms.2020-08-19 10:30:19 PM In window p005 we will translate the guest 5.3 Angstroms.2020-08-19 10:30:19 PM In window p006 we will translate the guest 6.4 Angstroms.2020-08-19 10:30:19 PM In window p007 we will translate the guest 7.4 Angstroms.2020-08-19 10:30:19 PM In window p008 we will translate the guest 8.5 Angstroms.2020-08-19 10:30:19 PM In window p009 we will translate the guest 9.5 Angstroms.2020-08-19 10:30:19 PM In window p010 we will translate the guest 10.6 Angstroms.2020-08-19 10:30:19 PM In window p011 we will translate the guest 11.6 Angstroms.2020-08-19 10:30:19 PM In window p012 we will translate the guest 12.7 Angstroms.2020-08-19 10:30:19 PM In window p013 we will translate the guest 13.8 Angstroms.2020-08-19 10:30:19 PM In window p014 we will translate the guest 14.8 Angstroms.2020-08-19 10:30:19 PM In window p015 we will translate the guest 15.9 Angstroms.2020-08-19 10:30:19 PM In window p016 we will translate the guest 16.9 Angstroms.2020-08-19 10:30:19 PM In window p017 we will translate the guest 18.0 Angstroms.

Create OpenMM system and apply restraints

Here, we will convert the AMBER *.prmtop & *.rst7 to an OpenMM system object for each window and convertit to a XML file. The Generalized Born Implicit Solvent model we will use is HCT, which is equivalent to igb=1in AMBER. Afterwords, we will apply restraints on the dummy atoms using apply_positional_restraintsand the static & guest restraints with apply_dat_restraint.

[23]: import simtk.unit as unitimport simtk.openmm.app as appimport simtk.openmm as openmm

from paprika.restraints.utils import parse_windowfrom paprika.restraints.openmm import apply_positional_restraints, apply_dat_restraint

[24]: for window in window_list:# Current windowfolder = os.path.join(work_dir, window)window_number, phase = parse_window(window)logging.info(f"Creating XML for in window {window}")

# Load Amberprmtop = app.AmberPrmtopFile(os.path.join(folder, f'{base_name}.prmtop'))inpcrd = app.AmberInpcrdFile(os.path.join(folder, f'{base_name}.rst7'))

# Create PDB filewith open(os.path.join(folder, 'system.pdb'), 'w') as file:

app.PDBFile.writeFile(prmtop.topology, inpcrd.positions, file, keepIds=True)

# Create an OpenMM system from the Amber topologysystem = prmtop.createSystem(

nonbondedMethod=app.NoCutoff,

(continues on next page)

66 Chapter 5. References

Page 71: pAPRika Documentation

pAPRika Documentation

(continued from previous page)

constraints=app.HBonds,implicitSolvent=app.HCT,

)

# Apply positional restraints on the dummy atomsapply_positional_restraints(os.path.join(folder, 'system.pdb'), system, force_

→˓group=15)

# Apply host static restraintsfor restraint in static_restraints:

apply_dat_restraint(system, restraint, phase, window_number, force_group=10)

# Apply guest restraintsfor restraint in guest_restraints:

apply_dat_restraint(system, restraint, phase, window_number, force_group=11)

# Save OpenMM system to XML filesystem_xml = openmm.XmlSerializer.serialize(system)with open(os.path.join(folder, 'system.xml'), 'w') as file:

file.write(system_xml)

2020-08-19 10:30:19 PM Creating XML for in window a0002020-08-19 10:30:19 PM Creating XML for in window a0012020-08-19 10:30:19 PM Creating XML for in window a0022020-08-19 10:30:19 PM Creating XML for in window a0032020-08-19 10:30:19 PM Creating XML for in window a0042020-08-19 10:30:19 PM Creating XML for in window a0052020-08-19 10:30:19 PM Creating XML for in window a0062020-08-19 10:30:20 PM Creating XML for in window a0072020-08-19 10:30:20 PM Creating XML for in window a0082020-08-19 10:30:20 PM Creating XML for in window a0092020-08-19 10:30:20 PM Creating XML for in window a0102020-08-19 10:30:20 PM Creating XML for in window a0112020-08-19 10:30:20 PM Creating XML for in window a0122020-08-19 10:30:20 PM Creating XML for in window a0132020-08-19 10:30:20 PM Creating XML for in window p0002020-08-19 10:30:20 PM Creating XML for in window p0012020-08-19 10:30:20 PM Creating XML for in window p0022020-08-19 10:30:20 PM Creating XML for in window p0032020-08-19 10:30:20 PM Creating XML for in window p0042020-08-19 10:30:20 PM Creating XML for in window p0052020-08-19 10:30:20 PM Creating XML for in window p0062020-08-19 10:30:20 PM Creating XML for in window p0072020-08-19 10:30:20 PM Creating XML for in window p0082020-08-19 10:30:20 PM Creating XML for in window p0092020-08-19 10:30:20 PM Creating XML for in window p0102020-08-19 10:30:20 PM Creating XML for in window p0112020-08-19 10:30:20 PM Creating XML for in window p0122020-08-19 10:30:20 PM Creating XML for in window p0132020-08-19 10:30:20 PM Creating XML for in window p0142020-08-19 10:30:20 PM Creating XML for in window p0152020-08-19 10:30:20 PM Creating XML for in window p0162020-08-19 10:30:20 PM Creating XML for in window p017

5.6. pAPRika tutorial 4 - APR/OpenMM 67

Page 72: pAPRika Documentation

pAPRika Documentation

5.6.4 Simulation

For this part, you need to have OpenMM installed and by default the simulations will run on the CPU. See the OpenMMdocumentation if you want to run the simulation on the GPU. We will set the integrator time step to 1 fs with a total of50,000 steps for production run and the temperature is set to 300 K.

Energy Minimization

[25]: for window in window_list:folder = os.path.join(work_dir, window)logging.info(f"Running minimization in window {window}...")

# Load XML and input coordinateswith open(os.path.join(folder, 'system.xml'), 'r') as file:

system = openmm.XmlSerializer.deserialize(file.read())coords = app.PDBFile(os.path.join(folder, 'system.pdb'))

# Integratorintegrator = openmm.LangevinIntegrator(300 * unit.kelvin, 1.0 / unit.picoseconds,

→˓1.0 * unit.femtoseconds)

# Simulation Objectsimulation = app.Simulation(coords.topology, system, integrator)simulation.context.setPositions(coords.positions)

# Minimize Energysimulation.minimizeEnergy(tolerance=1.0*unit.kilojoules_per_mole,

→˓maxIterations=5000)

# Save final coordinatespositions = simulation.context.getState(getPositions=True).getPositions()with open(os.path.join(folder, 'minimized.pdb'), 'w') as file:

app.PDBFile.writeFile(simulation.topology, positions, file, keepIds=True)

2020-08-19 10:30:20 PM Running minimization in window a000...2020-08-19 10:30:21 PM Running minimization in window a001...2020-08-19 10:30:21 PM Running minimization in window a002...2020-08-19 10:30:21 PM Running minimization in window a003...2020-08-19 10:30:21 PM Running minimization in window a004...2020-08-19 10:30:21 PM Running minimization in window a005...2020-08-19 10:30:21 PM Running minimization in window a006...2020-08-19 10:30:21 PM Running minimization in window a007...2020-08-19 10:30:22 PM Running minimization in window a008...2020-08-19 10:30:22 PM Running minimization in window a009...2020-08-19 10:30:22 PM Running minimization in window a010...2020-08-19 10:30:22 PM Running minimization in window a011...2020-08-19 10:30:22 PM Running minimization in window a012...2020-08-19 10:30:22 PM Running minimization in window a013...2020-08-19 10:30:22 PM Running minimization in window p000...2020-08-19 10:30:23 PM Running minimization in window p001...2020-08-19 10:30:23 PM Running minimization in window p002...2020-08-19 10:30:23 PM Running minimization in window p003...2020-08-19 10:30:23 PM Running minimization in window p004...2020-08-19 10:30:23 PM Running minimization in window p005...2020-08-19 10:30:23 PM Running minimization in window p006...2020-08-19 10:30:24 PM Running minimization in window p007...2020-08-19 10:30:24 PM Running minimization in window p008...

(continues on next page)

68 Chapter 5. References

Page 73: pAPRika Documentation

pAPRika Documentation

(continued from previous page)

2020-08-19 10:30:24 PM Running minimization in window p009...2020-08-19 10:30:24 PM Running minimization in window p010...2020-08-19 10:30:24 PM Running minimization in window p011...2020-08-19 10:30:24 PM Running minimization in window p012...2020-08-19 10:30:24 PM Running minimization in window p013...2020-08-19 10:30:25 PM Running minimization in window p014...2020-08-19 10:30:25 PM Running minimization in window p015...2020-08-19 10:30:25 PM Running minimization in window p016...2020-08-19 10:30:25 PM Running minimization in window p017...

• Here we will skip the equilibration step and go straight to production!

Production Run

[26]: for window in window_list:folder = os.path.join(work_dir, window)logging.info(f"Running production in window {window}...")

# Load XML and input coordinateswith open(os.path.join(folder, 'system.xml'), 'r') as file:

system = openmm.XmlSerializer.deserialize(file.read())coords = app.PDBFile(os.path.join(folder, 'minimized.pdb'))

# Integratorintegrator = openmm.LangevinIntegrator(300 * unit.kelvin, 1.0 / unit.picoseconds,

→˓1.0 * unit.femtoseconds)

# Reportersdcd_reporter = app.DCDReporter(os.path.join(folder, 'production.dcd'), 500)state_reporter = app.StateDataReporter(

os.path.join(folder, 'production.log'),500,step=True,kineticEnergy=True,potentialEnergy=True,totalEnergy=True,temperature=True,

)

# Simulation Objectsimulation = app.Simulation(coords.topology, system, integrator)simulation.context.setPositions(coords.positions)simulation.reporters.append(dcd_reporter)simulation.reporters.append(state_reporter)

# MD stepssimulation.step(50000)

# Save final coordinatespositions = simulation.context.getState(getPositions=True).getPositions()with open(os.path.join(folder, 'production.pdb'), 'w') as file:

app.PDBFile.writeFile(simulation.topology, positions, file, keepIds=True)

2020-08-19 10:30:25 PM Running production in window a000...2020-08-19 10:30:28 PM Running production in window a001...2020-08-19 10:30:31 PM Running production in window a002...

(continues on next page)

5.6. pAPRika tutorial 4 - APR/OpenMM 69

Page 74: pAPRika Documentation

pAPRika Documentation

(continued from previous page)

2020-08-19 10:30:33 PM Running production in window a003...2020-08-19 10:30:36 PM Running production in window a004...2020-08-19 10:30:39 PM Running production in window a005...2020-08-19 10:30:42 PM Running production in window a006...2020-08-19 10:30:45 PM Running production in window a007...2020-08-19 10:30:47 PM Running production in window a008...2020-08-19 10:30:50 PM Running production in window a009...2020-08-19 10:30:53 PM Running production in window a010...2020-08-19 10:30:56 PM Running production in window a011...2020-08-19 10:30:59 PM Running production in window a012...2020-08-19 10:31:01 PM Running production in window a013...2020-08-19 10:31:04 PM Running production in window p000...2020-08-19 10:31:07 PM Running production in window p001...2020-08-19 10:31:10 PM Running production in window p002...2020-08-19 10:31:13 PM Running production in window p003...2020-08-19 10:31:15 PM Running production in window p004...2020-08-19 10:31:18 PM Running production in window p005...2020-08-19 10:31:21 PM Running production in window p006...2020-08-19 10:31:24 PM Running production in window p007...2020-08-19 10:31:26 PM Running production in window p008...2020-08-19 10:31:29 PM Running production in window p009...2020-08-19 10:31:32 PM Running production in window p010...2020-08-19 10:31:35 PM Running production in window p011...2020-08-19 10:31:38 PM Running production in window p012...2020-08-19 10:31:40 PM Running production in window p013...2020-08-19 10:31:43 PM Running production in window p014...2020-08-19 10:31:46 PM Running production in window p015...2020-08-19 10:31:49 PM Running production in window p016...2020-08-19 10:31:52 PM Running production in window p017...

5.6.5 Analysis

Once the simulation is completed, we can using the analysis module to determine the binding free energy. Wesupply the location of the parameter information, a string or list for the file names (wildcards supported), the locationof the windows, and the restraints on the guest.

In this example, we use the method ti-block which determines the free energy using thermodynamic iintegrationand then estimates the standard error of the mean at each data point using blocking analysis. Bootstrapping it used todetermine the uncertainty of the full thermodynamic integral for each phase.

After running compute_free_energy(), a dictionary called results will be populated, that contains the freeenergy and SEM for each phase of the simulation.

[27]: import paprika.analysis as analysis

[28]: free_energy = analysis.fe_calc()free_energy.prmtop = "system.pdb"free_energy.trajectory = "production.dcd"free_energy.path = work_dirfree_energy.restraint_list = guest_restraintsfree_energy.collect_data()free_energy.methods = ['ti-block']free_energy.ti_matrix = "diagonal"free_energy.bootcycles = 1000free_energy.compute_free_energy()

70 Chapter 5. References

Page 75: pAPRika Documentation

pAPRika Documentation

[29]: free_energy.compute_ref_state_work([guest_restraints[0], guest_restraints[1], None, None,guest_restraints[2], None

])

binding_affinity = -1 * (free_energy.results["attach"]["ti-block"]["fe"] + \free_energy.results["pull"]["ti-block"]["fe"] + \free_energy.results["ref_state_work"]

)

sem = np.sqrt(free_energy.results["attach"]["ti-block"]["sem"]**2 + \free_energy.results["pull"]["ti-block"]["sem"]**2

)

[30]: print(f"The binding affinity of butane to cucurbit[6]uril = {binding_affinity:0.2f} +/→˓- {sem:0.2f} kcal/mol")

The binding affinity of butane to cucurbit[6]uril = -8.96 +/- 1.14 kcal/mol

The value above is very close to the value obtained from running the APR calculations with Amber.

5.7 pAPRika tutorial 5 - APR/Amber with Plumed restraints

In this tutorial, we will perform APR calculations for the butane (BUT)–cucurbit[6]uril (CB6) host-guest system. Thisis a repeat of Tutorial 1 using Plumed-based restraints and the AMBER MD engine. Plumed is a plugin for MDcodes that can analyze trajectories and perform free-energy calculations on collective variables. It is a versatile pluginthat can interface with a number of MD engines. Here, we will go through the process of converting APR restraintsconstructed with pAPRika to a Plumed file and run a short calculation with sander.

5.7.1 Initialize

Before you start

We will run the simulations in this tutorial using sander (Ambertools) and Plumed. Both of these should beinstalled in your conda environment if you installed pAPRika though the conda route. However, for Plumed towork with sander we first need to make sure the PLUMED_KERNEL environment variable is loaded (the library iscalled libplumedKernel.so). pAPRika should load the Plumed kernel automatically but let’s make sure it isloaded and run the cell below.

[1]: import os'PLUMED_KERNEL' in os.environ.keys()

[1]: False

If it does not exists we will load the environment in this Jupyter Notebook. Since Plumed is installed through condathe kernel will be located in your conda environment library folder. If you are running this on a Mac replace the kernellibrary in the cell below to libplumedKernel.dylib. If you compiled Plumed yourself and then you will needto change the path below.

[2]: os.environ['PLUMED_KERNEL'] = f"{os.environ['CONDA_PREFIX']}/lib/libplumedKernel.so"

5.7. pAPRika tutorial 5 - APR/Amber with Plumed restraints 71

Page 76: pAPRika Documentation

pAPRika Documentation

For running Plumed with Amber outside of this notebook it might be better to export the PLUMED_KERNEL variableinto your .bashrc file.

Note: we can run Plumed with AMBER versions 18 and 20, but version 18 requires you to patch the source codefirst and recompile. Older versions of Amber are not supported. See the Plumed documentation for more detailshttps://www.plumed.org/doc-v2.6/user-doc/html/index.html.

Since we have a prepared the host-guest-dummy setup from the first tutorial, we will skip the initial tleap steps and goright into initializing the restraints.

Define names

We will store the files created in this tutorial in a folder called plumed so we don’t mix files with the previous tutorial.

[3]: base_name = "cb6-but-dum"work_dir = "plumed"complex_dir = "complex"

5.7.2 Configure APR Restraints

Define anchor atoms

See tutorial 1 for the choice of selection

[4]: # Guest atomsG1 = ":BUT@C"G2 = ":BUT@C3"

# Host atomsH1 = ":CB6@C"H2 = ":CB6@C31"H3 = ":CB6@C18"

# Dummy atomsD1 = ":DM1"D2 = ":DM2"D3 = ":DM3"

Determine the number of windows

Before we add the restraints, it is helpful to set the 𝜆 fractions that control the strength of the force constants duringattach and release, and to define the distances for the pulling phase.

The attach fractions go from 0 to 1 and we place more points at the bottom of the range to sample the curvatureof 𝑑𝑈/𝑑𝜆. Next, we generally apply a distance restraint until the guest is ~18 Angstroms away from the host, inincrements of 0.4 Angstroms. This distance should be at least twice the Lennard-Jones cutoff in the system. Thesevalues have worked well for us, but this is one aspect that should be carefully checked for new systems.

[5]: import numpy as np

[6]: attach_string = "0.00 0.40 0.80 1.60 2.40 4.00 5.50 8.65 11.80 18.10 24.40 37.00 49.→˓60 74.80 100.00"attach_fractions = [float(i) / 100 for i in attach_string.split()]

(continues on next page)

72 Chapter 5. References

Page 77: pAPRika Documentation

pAPRika Documentation

(continued from previous page)

initial_distance = 6.0pull_distances = np.arange(0.0 + initial_distance, 18.0 + initial_distance, 1.0)

release_fractions = []

windows = [len(attach_fractions), len(pull_distances), len(release_fractions)]print(f"There are {windows} windows in this attach-pull-release calculation.")

There are [15, 18, 0] windows in this attach-pull-release calculation.

Load structure

[7]: import parmed as pmd

• Load complex structure

[8]: structure = pmd.load_file(os.path.join(complex_dir, f"{base_name}.prmtop"),os.path.join(complex_dir, f"{base_name}.rst7"),structure = True,

)

Host Static Restraints

See tutorial 1 for an explanation of the static restraints

[9]: import paprika.restraints as restraints

[10]: static_restraints = []

[11]: r = restraints.static_DAT_restraint(restraint_mask_list = [D1, H1],num_window_list = windows,ref_structure = structure,force_constant = 5.0,amber_index=True)

static_restraints.append(r)

[12]: r = restraints.static_DAT_restraint(restraint_mask_list = [D2, D1, H1],num_window_list = windows,ref_structure = structure,force_constant = 100.0,amber_index=True)

static_restraints.append(r)

[13]: r = restraints.static_DAT_restraint(restraint_mask_list = [D3, D2, D1, H1],num_window_list = windows,ref_structure = structure,force_constant = 100.0,amber_index=True)

(continues on next page)

5.7. pAPRika tutorial 5 - APR/Amber with Plumed restraints 73

Page 78: pAPRika Documentation

pAPRika Documentation

(continued from previous page)

static_restraints.append(r)

[14]: r = restraints.static_DAT_restraint(restraint_mask_list = [D1, H1, H2],num_window_list = windows,ref_structure = structure,force_constant = 100.0,amber_index=True)

static_restraints.append(r)

[15]: r = restraints.static_DAT_restraint(restraint_mask_list = [D2, D1, H1, H2],num_window_list = windows,ref_structure = structure,force_constant = 100.0,amber_index=True)

static_restraints.append(r)

[16]: r = restraints.static_DAT_restraint(restraint_mask_list = [D1, H1, H2, H3],num_window_list = windows,ref_structure = structure,force_constant = 100.0,amber_index=True)

static_restraints.append(r)

Guest translational and rotational restraints

See tutorial 1 for an explanation of the guest restraints

[17]: guest_restraints = []

[18]: r = restraints.DAT_restraint()r.mask1 = D1r.mask2 = G1r.topology = structurer.auto_apr = Truer.continuous_apr = Truer.amber_index = True

r.attach["target"] = pull_distances[0] # Angstromsr.attach["fraction_list"] = attach_fractionsr.attach["fc_final"] = 5.0 # kcal/mol/Angstroms**2

r.pull["target_final"] = 24.0 # Angstromsr.pull["num_windows"] = windows[1]

r.initialize()guest_restraints.append(r)

[19]: r = restraints.DAT_restraint()r.mask1 = D2

(continues on next page)

74 Chapter 5. References

Page 79: pAPRika Documentation

pAPRika Documentation

(continued from previous page)

r.mask2 = D1r.mask3 = G1r.topology = structurer.auto_apr = Truer.continuous_apr = Truer.amber_index = True

r.attach["target"] = 180.0 # Degreesr.attach["fraction_list"] = attach_fractionsr.attach["fc_final"] = 100.0 # kcal/mol/radian**2

r.pull["target_final"] = 180.0 # Degreesr.pull["num_windows"] = windows[1]

r.initialize()guest_restraints.append(r)

[20]: r = restraints.DAT_restraint()r.mask1 = D1r.mask2 = G1r.mask3 = G2r.topology = structurer.auto_apr = Truer.continuous_apr = Truer.amber_index = True

r.attach["target"] = 180.0 # Degreesr.attach["fraction_list"] = attach_fractionsr.attach["fc_final"] = 100.0 # kcal/mol/radian**2

r.pull["target_final"] = 180.0 # Degreesr.pull["num_windows"] = windows[1]

r.initialize()guest_restraints.append(r)

Create APR windows

We use the guest restraints to create a list of windows with the appropriate names and then create the directories.

[21]: from paprika.restraints.restraints import create_window_list

[22]: window_list = create_window_list(guest_restraints)

[23]: if not os.path.isdir(work_dir):os.makedirs(work_dir)

for window in window_list:folder = os.path.join(work_dir, window)if not os.path.isdir(folder):

os.makedirs(os.path.join(work_dir, window))

5.7. pAPRika tutorial 5 - APR/Amber with Plumed restraints 75

Page 80: pAPRika Documentation

pAPRika Documentation

Write APR restraints to Plumed format

In this section we create an instance of Plumed() from paprika.restraints.plumed, which is a class togenerate the Plumed restraint files. We need to specify the list of restraints used throughout the APR calculations andthe corresponding windows list. In this tutorial we will print the host static restraints and the guest restraints. ThePlumed class includes a method to add restraints to dummy atoms (add_dummy_atoms_to_file) but we willnot do that here. Instead we will use the built-in position restraints feature in Amber (see Simulation section below).

Note: be careful when specifiying the force constants in DAT_restraints. We follow the Amber (and CHARMM)convention where the force constant is already multiplied by a factor of 1/2 but Plumed requires the user to specifythe force constant without this factor, i.e.

𝑈𝑎𝑚𝑏𝑒𝑟 = 𝐾𝑎𝑚𝑏𝑒𝑟(𝑟 − 𝑟0)2 (5.1)

𝑈𝑝𝑙𝑢𝑚𝑒𝑑 =1

2𝑘𝑝𝑙𝑢𝑚𝑒𝑑(𝑟 − 𝑟0)2(5.2)

thus 𝑘𝑝𝑙𝑢𝑚𝑒𝑑 = 2 ×𝐾𝑎𝑚𝑏𝑒𝑟. If Amber force constants was used in generating the DAT_restraints (the case inthis tutorial) we need to set the variable uses_legacy_k to True (this is on by default).

[24]: from paprika.restraints.plumed import Plumed

[25]: restraints_list = (static_restraints + guest_restraints)

plumed = Plumed()plumed.file_name = 'plumed.dat'plumed.path = work_dirplumed.window_list = window_listplumed.restraint_list = restraints_listplumed.uses_legacy_k = True

plumed.dump_to_file()

5.7.3 Prepare host-guest system

Translate guest molecule

For the attach windows, we will use the initial, bound coordinates for the host-guest complex. Only the force constantschange during this phase, so a single set of coordinates is sufficient. For the pull windows, we will translate the guestto the target value of the restraint before solvation, and for the release windows, we will use the coordinates from thefinal pull window.

[26]: import shutil

[27]: for window in window_list:if window[0] == "a":

shutil.copy(os.path.join(complex_dir, f"{base_name}.prmtop"),os.path.join(work_dir, window, f"{base_name}.prmtop"))

shutil.copy(os.path.join(complex_dir, f"{base_name}.rst7"),os.path.join(work_dir, window, f"{base_name}.rst7"))

elif window[0] == "p":structure = pmd.load_file(

os.path.join(complex_dir, f"{base_name}.prmtop"),os.path.join(complex_dir, f"{base_name}.rst7"),

(continues on next page)

76 Chapter 5. References

Page 81: pAPRika Documentation

pAPRika Documentation

(continued from previous page)

structure = True)target_difference = guest_restraints[0].phase['pull']['targets'][int(window[1:

→˓])] -\guest_restraints[0].pull['target_initial']

print(f"In window {window} we will translate the guest {target_difference:0.→˓1f} Angstroms.")

for atom in structure.atoms:if atom.residue.name == "BUT":

atom.xz += target_difference

structure.save(os.path.join(work_dir, window, f"{base_name}.prmtop"),→˓overwrite=True)

structure.save(os.path.join(work_dir, window, f"{base_name}.rst7"),→˓overwrite=True)

In window p000 we will translate the guest 0.0 Angstroms.In window p001 we will translate the guest 1.1 Angstroms.In window p002 we will translate the guest 2.1 Angstroms.In window p003 we will translate the guest 3.2 Angstroms.In window p004 we will translate the guest 4.2 Angstroms.In window p005 we will translate the guest 5.3 Angstroms.In window p006 we will translate the guest 6.4 Angstroms.In window p007 we will translate the guest 7.4 Angstroms.In window p008 we will translate the guest 8.5 Angstroms.In window p009 we will translate the guest 9.5 Angstroms.In window p010 we will translate the guest 10.6 Angstroms.In window p011 we will translate the guest 11.6 Angstroms.In window p012 we will translate the guest 12.7 Angstroms.In window p013 we will translate the guest 13.8 Angstroms.In window p014 we will translate the guest 14.8 Angstroms.In window p015 we will translate the guest 15.9 Angstroms.In window p016 we will translate the guest 16.9 Angstroms.In window p017 we will translate the guest 18.0 Angstroms.

5.7.4 Simulation

Since we are going to run an implicit solvent simulation, we have everything ready to go. pAPRika has an AMBERmodule that can help setting default parameters for the simulation. There are some high level options that we setdirectly, like simulation.path, and then we call the function config_gb_min() to setup reasonable defaultsimulation parameters for a minimization in the Generalized-Born ensemble. After that, we directly modify the simu-lation cntrl section to apply the positional restraints on the dummy atoms.

We will run the simulations with sander but it is also possible and faster to run this with pmemd or pmemd.cudaif you have them installed.

Note: The difference here compared to Tutorial 1 is that instead of specifying a simulation.restraint_filewe will specify simulation.plumed_file.

Note: as explained at the start of this tutorial, make sure that the PLUMED_KERNEL environment variable is setotherwise the simulation will fail to run.

[28]: from paprika.simulate import AMBER

Initialize logger

5.7. pAPRika tutorial 5 - APR/Amber with Plumed restraints 77

Page 82: pAPRika Documentation

pAPRika Documentation

[29]: import loggingfrom importlib import reloadreload(logging)

logger = logging.getLogger()logging.basicConfig(

format='%(asctime)s %(message)s',datefmt='%Y-%m-%d %I:%M:%S %p',level=logging.INFO

)

Energy Minimization

Run a quick minimization in every window. Note that we need to specify simulation.cntrl["ntr"] = 1 toenable the positional restraints on the dummy atoms.

[37]: for window in window_list:simulation = AMBER()simulation.executable = "sander"

simulation.path = f"{work_dir}/{window}/"simulation.prefix = "minimize"

simulation.topology = "cb6-but-dum.prmtop"simulation.coordinates = "cb6-but-dum.rst7"simulation.ref = "cb6-but-dum.rst7"simulation.plumed_file = "plumed.dat"

simulation.config_gb_min()simulation.cntrl["ntr"] = 1simulation.cntrl["restraint_wt"] = 50.0simulation.cntrl["restraintmask"] = "'@DUM'"

logger.info(f"Running minimization in window {window}...")simulation.run(overwrite=True)

2020-10-01 11:18:20 AM Running minimization in window a000...2020-10-01 11:18:31 AM Running minimization in window a001...2020-10-01 11:18:42 AM Running minimization in window a002...2020-10-01 11:18:54 AM Running minimization in window a003...2020-10-01 11:19:05 AM Running minimization in window a004...2020-10-01 11:19:17 AM Running minimization in window a005...2020-10-01 11:19:28 AM Running minimization in window a006...2020-10-01 11:19:42 AM Running minimization in window a007...2020-10-01 11:19:54 AM Running minimization in window a008...2020-10-01 11:20:06 AM Running minimization in window a009...2020-10-01 11:20:18 AM Running minimization in window a010...2020-10-01 11:20:30 AM Running minimization in window a011...2020-10-01 11:20:42 AM Running minimization in window a012...2020-10-01 11:20:53 AM Running minimization in window a013...2020-10-01 11:21:04 AM Running minimization in window p000...2020-10-01 11:21:14 AM Running minimization in window p001...2020-10-01 11:21:26 AM Running minimization in window p002...2020-10-01 11:21:38 AM Running minimization in window p003...2020-10-01 11:21:50 AM Running minimization in window p004...2020-10-01 11:22:01 AM Running minimization in window p005...

(continues on next page)

78 Chapter 5. References

Page 83: pAPRika Documentation

pAPRika Documentation

(continued from previous page)

2020-10-01 11:22:15 AM Running minimization in window p006...2020-10-01 11:22:28 AM Running minimization in window p007...2020-10-01 11:22:40 AM Running minimization in window p008...2020-10-01 11:22:54 AM Running minimization in window p009...2020-10-01 11:23:06 AM Running minimization in window p010...2020-10-01 11:23:19 AM Running minimization in window p011...2020-10-01 11:23:31 AM Running minimization in window p012...2020-10-01 11:23:44 AM Running minimization in window p013...2020-10-01 11:23:55 AM Running minimization in window p014...2020-10-01 11:24:07 AM Running minimization in window p015...2020-10-01 11:24:19 AM Running minimization in window p016...2020-10-01 11:24:30 AM Running minimization in window p017...

Production Run

Here we will skip the equilibration step and go straight to production!

[31]: for window in window_list:simulation = AMBER()simulation.executable = "sander"

simulation.path = f"{work_dir}/{window}/"simulation.prefix = "production"

simulation.topology = "cb6-but-dum.prmtop"simulation.coordinates = "minimize.rst7"simulation.ref = "cb6-but-dum.rst7"simulation.plumed_file = "plumed.dat"

simulation.config_gb_md()simulation.cntrl["ntr"] = 1simulation.cntrl["restraint_wt"] = 50.0simulation.cntrl["restraintmask"] = "'@DUM'"

logger.info(f"Running production in window {window}...")simulation.run(overwrite=True)

2020-10-01 11:12:15 AM Running production in window a000...2020-10-01 11:12:25 AM Running production in window a001...2020-10-01 11:12:34 AM Running production in window a002...2020-10-01 11:12:44 AM Running production in window a003...2020-10-01 11:12:55 AM Running production in window a004...2020-10-01 11:13:06 AM Running production in window a005...2020-10-01 11:13:19 AM Running production in window a006...2020-10-01 11:13:29 AM Running production in window a007...2020-10-01 11:13:39 AM Running production in window a008...2020-10-01 11:13:49 AM Running production in window a009...2020-10-01 11:13:59 AM Running production in window a010...2020-10-01 11:14:10 AM Running production in window a011...2020-10-01 11:14:19 AM Running production in window a012...2020-10-01 11:14:29 AM Running production in window a013...2020-10-01 11:14:39 AM Running production in window p000...2020-10-01 11:14:49 AM Running production in window p001...2020-10-01 11:14:59 AM Running production in window p002...2020-10-01 11:15:10 AM Running production in window p003...2020-10-01 11:15:21 AM Running production in window p004...

(continues on next page)

5.7. pAPRika tutorial 5 - APR/Amber with Plumed restraints 79

Page 84: pAPRika Documentation

pAPRika Documentation

(continued from previous page)

2020-10-01 11:15:33 AM Running production in window p005...2020-10-01 11:15:43 AM Running production in window p006...2020-10-01 11:15:55 AM Running production in window p007...2020-10-01 11:16:05 AM Running production in window p008...2020-10-01 11:16:18 AM Running production in window p009...2020-10-01 11:16:31 AM Running production in window p010...2020-10-01 11:16:45 AM Running production in window p011...2020-10-01 11:16:56 AM Running production in window p012...2020-10-01 11:17:05 AM Running production in window p013...2020-10-01 11:17:16 AM Running production in window p014...2020-10-01 11:17:26 AM Running production in window p015...2020-10-01 11:17:37 AM Running production in window p016...2020-10-01 11:17:49 AM Running production in window p017...

5.7.5 Analysis

Once the simulation is completed, we can using the analysis module to determine the binding free energy. Wesupply the location of the parameter information, a string or list for the file names (wildcards supported), the locationof the windows, and the restraints on the guest.

In this example, we use the method ti-block which determines the free energy using thermodynamic iintegrationand then estimates the standard error of the mean at each data point using blocking analysis. Bootstrapping it used todetermine the uncertainty of the full thermodynamic integral for each phase.

After running compute_free_energy(), a dictionary called results will be populated, that contains the freeenergy and SEM for each phase of the simulation.

[32]: import paprika.analysis as analysis

[33]: free_energy = analysis.fe_calc()free_energy.prmtop = "cb6-but-dum.prmtop"free_energy.trajectory = 'production*.nc'free_energy.path = work_dirfree_energy.restraint_list = guest_restraintsfree_energy.collect_data()free_energy.methods = ['ti-block']free_energy.ti_matrix = "full"free_energy.bootcycles = 1000free_energy.compute_free_energy()

We also need to calculate the free-energy cost of releasing the restraints on the guest molecule.

[34]: free_energy.compute_ref_state_work([guest_restraints[0], guest_restraints[1], None, None,guest_restraints[2], None

])

Then we add the free-energies together and combine the uncertainties to get the binding-free energy

[35]: binding_affinity = -1 * (free_energy.results["attach"]["ti-block"]["fe"] + \free_energy.results["pull"]["ti-block"]["fe"] + \free_energy.results["ref_state_work"]

)

(continues on next page)

80 Chapter 5. References

Page 85: pAPRika Documentation

pAPRika Documentation

(continued from previous page)

sem = np.sqrt(free_energy.results["attach"]["ti-block"]["sem"]**2 + \free_energy.results["pull"]["ti-block"]["sem"]**2

)

[36]: print(f"The binding affinity of butane to cucurbit[6]uril = {binding_affinity:0.2f} +/→˓- {sem:0.2f} kcal/mol")

The binding affinity of butane to cucurbit[6]uril = -7.24 +/- 6.52 kcal/mol

5.8 pAPRika tutorial 6 - APR/Gromacs with Plumed restraints

In this tutorial, we will perform APR calculations for the butane (BUT)–cucurbit[6]uril (CB6) host-guest system.This tutorial is similar to tutorial 5 where Plumed will be used for the restraints but we will be using the GROMACSMD engine instead. One other difference in this tutorial is that we will be performing the simulation with periodicboundary condition (PBC) and explicit water molecules. This is because GROMACS does not support implicit solventcalculations.

5.8.1 Initialize

Before you start

We will run the simulations in this tutorial using GROMACS and Plumed. GROMACS will need to be installed beforeyou can run the simulation part of this tutorial. Plumed, however, should be installed in your conda environment ifyou installed pAPRika though the conda route. To use Plumed we first need to make sure the PLUMED_KERNELenvironment variable is loaded (the library is called libplumedKernel.so). pAPRika should load the Plumedkernel automatically but let’s make sure it is loaded and run the cell below.

[1]: import os'PLUMED_KERNEL' in os.environ.keys()

[1]: True

If it does not exists we will load the environment in this Jupyter Notebook. Since Plumed is installed through condathe kernel will be located in your conda environment library folder. If you are running this on a MacOS, replace thekernel library in the cell below to libplumedKernel.dylib. If you compiled Plumed yourself and then youwill need to change the path below.

[2]: os.environ['PLUMED_KERNEL'] = f"{os.environ['CONDA_PREFIX']}/lib/libplumedKernel.so"

For running Plumed outside of this notebook it might be better to export the PLUMED_KERNEL variable into your.bashrc file.

Note: we can run Plumed with GROMACS versions 2020.2 but the user is required to patch the source code. UnlikeAMBER and LAMMPS, GROMACS does not come with a patched code out-of-the-box and the conda-forge reposi-tory also do not contain a patched version of GROMACS. See the Plumed documentation for more details on how topatch and recompile the GROMACS code https://www.plumed.org/doc-v2.6/user-doc/html/index.html.

Note: We will be running the CB6-BUT host-guest system in explicit solvent because GROMACS does not supportimplicit solvent calculation. Thus, we recommend running the simulation on a GPU.

5.8. pAPRika tutorial 6 - APR/Gromacs with Plumed restraints 81

Page 86: pAPRika Documentation

pAPRika Documentation

Since we have a prepared the host-guest-dummy setup from the first tutorial, we will skip the initial tleap steps andgo right into initializing the restraints. If you haven’t completed tutorial 1 please go back and run the notebook togenerate the starting structure.

Define names

We will store the files created in this tutorial in a folder called gromacs-plumed so we don’t mix files with theprevious tutorial.

[3]: base_name = "cb6-but-dum"work_dir = "gromacs-plumed"complex_dir = "complex"data = "../../../paprika/data/cb6-but"

5.8.2 Configure APR Restraints

Define anchor atoms

See tutorial 1 for the choice of selection

[4]: # Guest atomsG1 = ":BUT@C"G2 = ":BUT@C3"

# Host atomsH1 = ":CB6@C"H2 = ":CB6@C31"H3 = ":CB6@C18"

# Dummy atomsD1 = ":DM1"D2 = ":DM2"D3 = ":DM3"

Determine the number of windows

Before we add the restraints, it is helpful to set the 𝜆 fractions that control the strength of the force constants duringattach and release, and to define the distances for the pulling phase.

The attach fractions go from 0 to 1 and we place more points at the bottom of the range to sample the curvatureof 𝑑𝑈/𝑑𝜆. Next, we generally apply a distance restraint until the guest is ~18 Angstroms away from the host, inincrements of 0.4 Angstroms. This distance should be at least twice the Lennard-Jones cutoff in the system. Thesevalues have worked well for us, but this is one aspect that should be carefully checked for new systems.

[5]: import numpy as np

[6]: attach_string = "0.00 0.40 0.80 1.60 2.40 4.00 5.50 8.65 11.80 18.10 24.40 37.00 49.→˓60 74.80 100.00"attach_fractions = [float(i) / 100 for i in attach_string.split()]

initial_distance = 6.0pull_distances = np.arange(0.0 + initial_distance, 18.0 + initial_distance, 1.0)

(continues on next page)

82 Chapter 5. References

Page 87: pAPRika Documentation

pAPRika Documentation

(continued from previous page)

release_fractions = []

windows = [len(attach_fractions), len(pull_distances), len(release_fractions)]print(f"There are {windows} windows in this attach-pull-release calculation.")

There are [15, 18, 0] windows in this attach-pull-release calculation.

Load structure

[7]: import parmed as pmd

• Load complex structure

[8]: structure = pmd.load_file(os.path.join(complex_dir, f"{base_name}.prmtop"),os.path.join(complex_dir, f"{base_name}.rst7"),structure = True,

)

Host Static Restraints

See tutorial 1 for an explanation of the static restraints.

[9]: import paprika.restraints as restraints

[10]: static_restraints = []

[11]: r = restraints.static_DAT_restraint(restraint_mask_list = [D1, H1],num_window_list = windows,ref_structure = structure,force_constant = 5.0,amber_index=True)

static_restraints.append(r)

[12]: r = restraints.static_DAT_restraint(restraint_mask_list = [D2, D1, H1],num_window_list = windows,ref_structure = structure,force_constant = 100.0,amber_index=True)

static_restraints.append(r)

[13]: r = restraints.static_DAT_restraint(restraint_mask_list = [D3, D2, D1, H1],num_window_list = windows,ref_structure = structure,force_constant = 100.0,amber_index=True)

static_restraints.append(r)

5.8. pAPRika tutorial 6 - APR/Gromacs with Plumed restraints 83

Page 88: pAPRika Documentation

pAPRika Documentation

[14]: r = restraints.static_DAT_restraint(restraint_mask_list = [D1, H1, H2],num_window_list = windows,ref_structure = structure,force_constant = 100.0,amber_index=True)

static_restraints.append(r)

[15]: r = restraints.static_DAT_restraint(restraint_mask_list = [D2, D1, H1, H2],num_window_list = windows,ref_structure = structure,force_constant = 100.0,amber_index=True)

static_restraints.append(r)

[16]: r = restraints.static_DAT_restraint(restraint_mask_list = [D1, H1, H2, H3],num_window_list = windows,ref_structure = structure,force_constant = 100.0,amber_index=True)

static_restraints.append(r)

Guest translational and rotational restraints

See tutorial 1 for an explanation of the guest restraints

[17]: guest_restraints = []

[18]: r = restraints.DAT_restraint()r.mask1 = D1r.mask2 = G1r.topology = structurer.auto_apr = Truer.continuous_apr = Truer.amber_index = True

r.attach["target"] = pull_distances[0] # Angstromsr.attach["fraction_list"] = attach_fractionsr.attach["fc_final"] = 5.0 # kcal/mol/Angstroms**2

r.pull["target_final"] = 24.0 # Angstromsr.pull["num_windows"] = windows[1]

r.initialize()guest_restraints.append(r)

[19]: r = restraints.DAT_restraint()r.mask1 = D2r.mask2 = D1r.mask3 = G1r.topology = structurer.auto_apr = True

(continues on next page)

84 Chapter 5. References

Page 89: pAPRika Documentation

pAPRika Documentation

(continued from previous page)

r.continuous_apr = Truer.amber_index = True

r.attach["target"] = 180.0 # Degreesr.attach["fraction_list"] = attach_fractionsr.attach["fc_final"] = 100.0 # kcal/mol/radian**2

r.pull["target_final"] = 180.0 # Degreesr.pull["num_windows"] = windows[1]

r.initialize()guest_restraints.append(r)

[20]: r = restraints.DAT_restraint()r.mask1 = D1r.mask2 = G1r.mask3 = G2r.topology = structurer.auto_apr = Truer.continuous_apr = Truer.amber_index = True

r.attach["target"] = 180.0 # Degreesr.attach["fraction_list"] = attach_fractionsr.attach["fc_final"] = 100.0 # kcal/mol/radian**2

r.pull["target_final"] = 180.0 # Degreesr.pull["num_windows"] = windows[1]

r.initialize()guest_restraints.append(r)

Create APR windows

We use the guest restraints to create a list of windows with the appropriate names and then create the directories.

[21]: from paprika.restraints.restraints import create_window_list

[22]: window_list = create_window_list(guest_restraints)

[23]: if not os.path.isdir(work_dir):os.makedirs(work_dir)

for window in window_list:folder = os.path.join(work_dir, window)if not os.path.isdir(folder):

os.makedirs(os.path.join(work_dir, window))

5.8. pAPRika tutorial 6 - APR/Gromacs with Plumed restraints 85

Page 90: pAPRika Documentation

pAPRika Documentation

Write APR restraints to Plumed format

In this section we create an instance of Plumed() from paprika.restraints.plumed, which is a class togenerate the Plumed restraint files. We need to specify the list of restraints used throughout the APR calculations andthe corresponding windows list. In this tutorial we will print the host static restraints and the guest restraints. ThePlumed class includes a method to add restraints to dummy atoms (add_dummy_atoms_to_file). We will addthe positional restraints on the dummy atoms after solvation of the host-guest complex.

Note: be careful when specifying the force constants in DAT_restraints. We follow the AMBER (andCHARMM) convention where the force constant is already multiplied by a factor of 1/2 but Plumed requires theuser to specify the force constant without this factor, i.e.

𝑈𝑎𝑚𝑏𝑒𝑟 = 𝐾𝑎𝑚𝑏𝑒𝑟(𝑟 − 𝑟0)2 (5.3)

𝑈𝑝𝑙𝑢𝑚𝑒𝑑 =1

2𝑘𝑝𝑙𝑢𝑚𝑒𝑑(𝑟 − 𝑟0)2(5.4)

thus 𝑘𝑝𝑙𝑢𝑚𝑒𝑑 = 2 ×𝐾𝑎𝑚𝑏𝑒𝑟. If AMBER force constants was used in generating the DAT_restraints (the case inthis tutorial) we need to set the variable uses_legacy_k to True (this is on by default).

[24]: from paprika.restraints.plumed import Plumed

[25]: restraints_list = (static_restraints + guest_restraints)

plumed = Plumed()plumed.file_name = 'plumed.dat'plumed.path = work_dirplumed.window_list = window_listplumed.restraint_list = restraints_listplumed.uses_legacy_k = True

plumed.dump_to_file()

5.8.3 Prepare host-guest system

Translate guest molecule

For the attach windows, we will use the initial, bound coordinates for the host-guest complex. Only the force constantschange during this phase, so a single set of coordinates is sufficient. For the pull windows, we will translate the guestto the target value of the restraint before solvation, and for the release windows, we will use the coordinates from thefinal pull window.

[26]: import shutil

[27]: for window in window_list:if window[0] == "a":

shutil.copy(os.path.join(complex_dir, f"{base_name}.prmtop"),os.path.join(work_dir, window, f"{base_name}.prmtop"))

shutil.copy(os.path.join(complex_dir, f"{base_name}.rst7"),os.path.join(work_dir, window, f"{base_name}.rst7"))

elif window[0] == "p":structure = pmd.load_file(

os.path.join(complex_dir, f"{base_name}.prmtop"),os.path.join(complex_dir, f"{base_name}.rst7"),

(continues on next page)

86 Chapter 5. References

Page 91: pAPRika Documentation

pAPRika Documentation

(continued from previous page)

structure = True)target_difference = guest_restraints[0].phase['pull']['targets'][int(window[1:

→˓])] -\guest_restraints[0].pull['target_initial']

print(f"In window {window} we will translate the guest {target_difference:0.→˓1f} Angstroms.")

for atom in structure.atoms:if atom.residue.name == "BUT":

atom.xz += target_difference

structure.save(os.path.join(work_dir, window, f"{base_name}.prmtop"),→˓overwrite=True)

structure.save(os.path.join(work_dir, window, f"{base_name}.rst7"),→˓overwrite=True)

In window p000 we will translate the guest 0.0 Angstroms.In window p001 we will translate the guest 1.1 Angstroms.In window p002 we will translate the guest 2.1 Angstroms.In window p003 we will translate the guest 3.2 Angstroms.In window p004 we will translate the guest 4.2 Angstroms.In window p005 we will translate the guest 5.3 Angstroms.In window p006 we will translate the guest 6.4 Angstroms.In window p007 we will translate the guest 7.4 Angstroms.In window p008 we will translate the guest 8.5 Angstroms.In window p009 we will translate the guest 9.5 Angstroms.In window p010 we will translate the guest 10.6 Angstroms.In window p011 we will translate the guest 11.6 Angstroms.In window p012 we will translate the guest 12.7 Angstroms.In window p013 we will translate the guest 13.8 Angstroms.In window p014 we will translate the guest 14.8 Angstroms.In window p015 we will translate the guest 15.9 Angstroms.In window p016 we will translate the guest 16.9 Angstroms.In window p017 we will translate the guest 18.0 Angstroms.

Solvate the host-guest system

Here we will solvate the host-guest system in each window with 2000 water molecules. Since Gromacs cannot readin Amber topology and coordinates files we will have to convert them to the appropriate formats. TLeap has a built-in function called TLeap.convert_to_gromacs(), which will convert the Amber files to Gromacs. We alsoneed to add positional restraints on dummy atoms to the plumed.dat file and this is done by invoking the functionplumed.add_dummy_atoms_to_file

[28]: from paprika.build.system import TLeap

[29]: for window in window_list:print(f"Solvating system in {window}.")

structure = pmd.load_file(os.path.join(work_dir, window, f"{base_name}.prmtop"),os.path.join(work_dir, window, f"{base_name}.rst7"),structure=True,

)

(continues on next page)

5.8. pAPRika tutorial 6 - APR/Gromacs with Plumed restraints 87

Page 92: pAPRika Documentation

pAPRika Documentation

(continued from previous page)

if not os.path.exists(os.path.join(work_dir, window, f"{base_name}.pdb")):structure.save(os.path.join(work_dir, window, f"{base_name}.pdb"))

system = TLeap()system.output_path = os.path.join(work_dir, window)system.output_prefix = f"{base_name}-sol"

system.target_waters = 2000system.neutralize = Truesystem.add_ions = ["Na+", 6, "Cl-", 6]system.pbc_type = "rectangular"system.template_lines = [

"source leaprc.gaff","source leaprc.water.tip3p",f"loadamberparams {data}/cb6.frcmod","loadamberparams ../../complex/dummy.frcmod",f"CB6 = loadmol2 {data}/cb6.mol2",f"BUT = loadmol2 {data}/but.mol2","DM1 = loadmol2 ../../complex/dm1.mol2","DM2 = loadmol2 ../../complex/dm2.mol2","DM3 = loadmol2 ../../complex/dm3.mol2","model = loadpdb cb6-but-dum.pdb",

]system.build()

# Convert Amber to Gromacssystem.convert_to_gromacs(overwrite=True)

# Add dummy atom restraints - load in the Gromacs files instead# of the amber files because the coordinates a shifted.structure = pmd.load_file(

os.path.join(work_dir, window, f"{base_name}-sol.top"),xyz=os.path.join(work_dir, window, f"{base_name}-sol.gro"),structure=True

)plumed.add_dummy_atoms_to_file(structure,window=window)

Solvating system in a000.Solvating system in a001.Solvating system in a002.Solvating system in a003.Solvating system in a004.Solvating system in a005.Solvating system in a006.Solvating system in a007.Solvating system in a008.Solvating system in a009.Solvating system in a010.Solvating system in a011.Solvating system in a012.Solvating system in a013.Solvating system in p000.Solvating system in p001.Solvating system in p002.Solvating system in p003.Solvating system in p004.Solvating system in p005.

(continues on next page)

88 Chapter 5. References

Page 93: pAPRika Documentation

pAPRika Documentation

(continued from previous page)

Solvating system in p006.Solvating system in p007.Solvating system in p008.Solvating system in p009.Solvating system in p010.Solvating system in p011.Solvating system in p012.Solvating system in p013.Solvating system in p014.Solvating system in p015.Solvating system in p016.Solvating system in p017.

5.8.4 Simulation

Now that we have a solvated structure and a plumed.dat file with dummy atoms position restraints, we haveeverything ready to go. pAPRika has a GROMACS wrapper module that can help setting default parameters for thesimulation. There are some high level options that we set directly, like simulation.path, and then we call thefunction config_pbc_min() to setup reasonable default simulation parameters for a minimization and productionrun. See the pAPRika documentation for more details.

GROMACS, unlike AMBER and OpenMM, have a higher dependency on CPUs, so more than one processor for everyGPU is preferred to deliver better speed. Setting the number of processors requires using different keyword dependingon how GROMACS was compiled. The cells below were run using GROMACS that is compiled with MPI and hence thesuffix, i.e., gmx_mpi (for a non-MPI version, the executable is usually called gmx). We set the number of processorswith simulation.n_threads = 8 and the GPU device with simulation.gpu_devices = 0.

Note: For host-guest systems I find that the non-MPI version is considerably much faster. Also, 12 CPUs with a singleGPU seems to be a good combination with a non-MPI version.

By default, pAPRika will use -ntomp to specify the number of CPUs when executing mdrun if the executable isgmx_mpi and -nt for gmx. If these default settings do not work with the GROMACS currently installed then we canuse simulation.custom_mdrun_command to override the default, e.g.,

simulation.custom_mdrun_command = "-ntmpi 8 -gpu_id 1"

or

simulation.custom_mdrun_command = "mpirun -np 4 gmx_mpi mdrun -ntomp 8 -gpu_id 4"

Note: We do not need to run grompp beforehand because the simulation wrapper in pAPRika takes care of thisautomatically when we call the simulation.run() method. We also set simulation.grompp_maxwarn =5 to ignore warnings about the total charge of the system (the total charge is slightly off from neutral).

Note: as explained at the start of this tutorial, make sure that the PLUMED_KERNEL environment variable is setotherwise the simulation will fail to run.

[30]: from paprika.simulate import GROMACS

Initialize logger

[31]: import loggingfrom importlib import reloadreload(logging)

(continues on next page)

5.8. pAPRika tutorial 6 - APR/Gromacs with Plumed restraints 89

Page 94: pAPRika Documentation

pAPRika Documentation

(continued from previous page)

logger = logging.getLogger()logging.basicConfig(

format='%(asctime)s %(message)s',datefmt='%Y-%m-%d %I:%M:%S %p',level=logging.INFO

)

Energy Minimization

[32]: for window in window_list:simulation = GROMACS()simulation.executable = "gmx_mpi"simulation.n_threads = 8simulation.gpu_devices = 0

# simulation.custom_mdrun_command = "-ntomp 8 -gpu_id 6"simulation.path = os.path.join(work_dir, window)simulation.maxwarn = 5

simulation.prefix = "minimize"simulation.topology = f"{base_name}-sol.top"simulation.coordinates = f"{base_name}-sol.gro"simulation.plumed_file = "plumed.dat"

simulation.config_pbc_min()

logging.info(f"Running minimization in window {window}...")simulation.run(overwrite=True)

2020-09-25 05:22:17 PM Running minimization in window a000...2020-09-25 05:22:36 PM Running minimization in window a001...2020-09-25 05:22:56 PM Running minimization in window a002...2020-09-25 05:23:15 PM Running minimization in window a003...2020-09-25 05:23:37 PM Running minimization in window a004...2020-09-25 05:23:56 PM Running minimization in window a005...2020-09-25 05:24:16 PM Running minimization in window a006...2020-09-25 05:24:33 PM Running minimization in window a007...2020-09-25 05:24:52 PM Running minimization in window a008...2020-09-25 05:25:12 PM Running minimization in window a009...2020-09-25 05:25:32 PM Running minimization in window a010...2020-09-25 05:25:50 PM Running minimization in window a011...2020-09-25 05:26:10 PM Running minimization in window a012...2020-09-25 05:26:29 PM Running minimization in window a013...2020-09-25 05:26:49 PM Running minimization in window p000...2020-09-25 05:27:08 PM Running minimization in window p001...2020-09-25 05:27:28 PM Running minimization in window p002...2020-09-25 05:27:46 PM Running minimization in window p003...2020-09-25 05:28:05 PM Running minimization in window p004...2020-09-25 05:28:24 PM Running minimization in window p005...2020-09-25 05:28:46 PM Running minimization in window p006...2020-09-25 05:29:04 PM Running minimization in window p007...2020-09-25 05:29:23 PM Running minimization in window p008...2020-09-25 05:29:41 PM Running minimization in window p009...2020-09-25 05:30:01 PM Running minimization in window p010...2020-09-25 05:30:20 PM Running minimization in window p011...2020-09-25 05:30:39 PM Running minimization in window p012...

(continues on next page)

90 Chapter 5. References

Page 95: pAPRika Documentation

pAPRika Documentation

(continued from previous page)

2020-09-25 05:30:58 PM Running minimization in window p013...2020-09-25 05:31:18 PM Running minimization in window p014...2020-09-25 05:31:37 PM Running minimization in window p015...2020-09-25 05:31:56 PM Running minimization in window p016...2020-09-25 05:32:15 PM Running minimization in window p017...

NVT - Equilibration

Here, we will perform 50,000 steps of equilibration with the NVT ensemble.

[34]: for window in window_list:simulation = GROMACS()simulation.executable = "gmx_mpi"simulation.n_threads = 8simulation.gpu_devices = 0

# simulation.custom_mdrun_command = "-ntomp 8 -gpu_id 6"simulation.path = os.path.join(work_dir, window)simulation.maxwarn = 5

simulation.prefix = "equilibration"simulation.topology = f"{base_name}-sol.top"simulation.coordinates = "minimize.gro"simulation.plumed_file = "plumed.dat"

simulation.config_pbc_md(ensemble='nvt')simulation.control["nsteps"] = 50000

logging.info(f"Running equilibration in window {window}...")simulation.run(overwrite=True)

2020-09-25 05:41:42 PM Running equilibration in window a000...2020-09-25 05:42:26 PM Running equilibration in window a001...2020-09-25 05:43:07 PM Running equilibration in window a002...2020-09-25 05:43:49 PM Running equilibration in window a003...2020-09-25 05:44:33 PM Running equilibration in window a004...2020-09-25 05:45:17 PM Running equilibration in window a005...2020-09-25 05:46:01 PM Running equilibration in window a006...2020-09-25 05:46:36 PM Running equilibration in window a007...2020-09-25 05:47:13 PM Running equilibration in window a008...2020-09-25 05:47:54 PM Running equilibration in window a009...2020-09-25 05:48:36 PM Running equilibration in window a010...2020-09-25 05:49:12 PM Running equilibration in window a011...2020-09-25 05:49:56 PM Running equilibration in window a012...2020-09-25 05:50:31 PM Running equilibration in window a013...2020-09-25 05:51:11 PM Running equilibration in window p000...2020-09-25 05:51:53 PM Running equilibration in window p001...2020-09-25 05:52:36 PM Running equilibration in window p002...2020-09-25 05:53:20 PM Running equilibration in window p003...2020-09-25 05:54:02 PM Running equilibration in window p004...2020-09-25 05:54:44 PM Running equilibration in window p005...2020-09-25 05:55:26 PM Running equilibration in window p006...2020-09-25 05:56:09 PM Running equilibration in window p007...2020-09-25 05:56:44 PM Running equilibration in window p008...2020-09-25 05:57:27 PM Running equilibration in window p009...2020-09-25 05:58:05 PM Running equilibration in window p010...2020-09-25 05:58:48 PM Running equilibration in window p011...

(continues on next page)

5.8. pAPRika tutorial 6 - APR/Gromacs with Plumed restraints 91

Page 96: pAPRika Documentation

pAPRika Documentation

(continued from previous page)

2020-09-25 05:59:31 PM Running equilibration in window p012...2020-09-25 06:00:14 PM Running equilibration in window p013...2020-09-25 06:00:59 PM Running equilibration in window p014...2020-09-25 06:01:41 PM Running equilibration in window p015...2020-09-25 06:02:20 PM Running equilibration in window p016...2020-09-25 06:03:02 PM Running equilibration in window p017...

Production Run

We will run the production phase for 50,000 steps. Note: a proper production run would require simulation in the tensof nanoseconds per window.

[35]: for window in window_list:simulation = GROMACS()simulation.executable = "gmx_mpi"simulation.n_threads = 8simulation.gpu_devices = 0

# simulation.custom_mdrun_command = "-ntomp 8 -gpu_id 6"simulation.path = os.path.join(work_dir, window)simulation.maxwarn = 5

simulation.prefix = "production"simulation.topology = f"{base_name}-sol.top"simulation.coordinates = "equilibration.gro"simulation.checkpoint = "equilibration.cpt"simulation.plumed_file = "plumed.dat"

simulation.config_pbc_md(ensemble='npt')simulation.control["nsteps"] = 50000

logging.info(f"Running production in window {window}...")simulation.run(overwrite=True)

2020-09-25 06:04:07 PM Running production in window a000...2020-09-25 06:04:49 PM Running production in window a001...2020-09-25 06:05:33 PM Running production in window a002...2020-09-25 06:06:17 PM Running production in window a003...2020-09-25 06:07:02 PM Running production in window a004...2020-09-25 06:07:45 PM Running production in window a005...2020-09-25 06:08:30 PM Running production in window a006...2020-09-25 06:09:14 PM Running production in window a007...2020-09-25 06:09:56 PM Running production in window a008...2020-09-25 06:10:37 PM Running production in window a009...2020-09-25 06:11:22 PM Running production in window a010...2020-09-25 06:12:04 PM Running production in window a011...2020-09-25 06:12:49 PM Running production in window a012...2020-09-25 06:13:39 PM Running production in window a013...2020-09-25 06:14:23 PM Running production in window p000...2020-09-25 06:15:07 PM Running production in window p001...2020-09-25 06:15:50 PM Running production in window p002...2020-09-25 06:16:35 PM Running production in window p003...2020-09-25 06:17:20 PM Running production in window p004...2020-09-25 06:18:03 PM Running production in window p005...2020-09-25 06:18:55 PM Running production in window p006...2020-09-25 06:19:40 PM Running production in window p007...

(continues on next page)

92 Chapter 5. References

Page 97: pAPRika Documentation

pAPRika Documentation

(continued from previous page)

2020-09-25 06:20:24 PM Running production in window p008...2020-09-25 06:21:13 PM Running production in window p009...2020-09-25 06:21:57 PM Running production in window p010...2020-09-25 06:22:43 PM Running production in window p011...2020-09-25 06:23:28 PM Running production in window p012...2020-09-25 06:24:16 PM Running production in window p013...2020-09-25 06:24:58 PM Running production in window p014...2020-09-25 06:25:43 PM Running production in window p015...2020-09-25 06:26:24 PM Running production in window p016...2020-09-25 06:27:06 PM Running production in window p017...

5.8.5 Analysis

Once the simulation is completed, we can using the Analysis module to determine the binding free energy. Wesupply the location of the parameter information, a string or list for the file names (wildcards supported), the locationof the windows, and the restraints on the guest.

In this example, we use the method ti-block which determines the free energy using thermodynamic iintegrationand then estimates the standard error of the mean at each data point using blocking analysis. Bootstrapping it used todetermine the uncertainty of the full thermodynamic integral for each phase.

After running compute_free_energy(), a dictionary called results will be populated, that contains the freeenergy and SEM for each phase of the simulation.

[36]: import paprika.analysis as analysis

[37]: free_energy = analysis.fe_calc()free_energy.prmtop = "cb6-but-dum-sol.pdb"free_energy.trajectory = 'production*.trr'free_energy.path = work_dirfree_energy.restraint_list = guest_restraintsfree_energy.collect_data()free_energy.methods = ['ti-block']free_energy.ti_matrix = "full"free_energy.bootcycles = 1000free_energy.compute_free_energy()

We also need to calculate the free-energy cost of releasing the restraints on the guest molecule.

[38]: free_energy.compute_ref_state_work([guest_restraints[0], guest_restraints[1], None, None,guest_restraints[2], None

])

Then we add the free-energies together and combine the uncertainties to get the binding-free energy

[39]: binding_affinity = -1 * (free_energy.results["attach"]["ti-block"]["fe"] + \free_energy.results["pull"]["ti-block"]["fe"] + \free_energy.results["ref_state_work"]

)

sem = np.sqrt(free_energy.results["attach"]["ti-block"]["sem"]**2 + \

(continues on next page)

5.8. pAPRika tutorial 6 - APR/Gromacs with Plumed restraints 93

Page 98: pAPRika Documentation

pAPRika Documentation

(continued from previous page)

free_energy.results["pull"]["ti-block"]["sem"]**2)

[40]: print(f"The binding affinity of butane to cucurbit[6]uril = {binding_affinity:0.2f} +/→˓- {sem:0.2f} kcal/mol")

The binding affinity of butane to cucurbit[6]uril = -7.55 +/- 1.58 kcal/mol

5.9 pAPRika tutorial 7 - APR/NAMD with Colvars restraints

In this tutorial, we will perform APR calculations for the butane (BUT)–cucurbit[6]uril (CB6) host-guest system withthe Generalized-Born implicit solvent. This tutorial will use NAMD for the simulation and Colvars for the restraints.Although it is possible to run NAMD with Plumed we will not use Plumed in this tutorial. Users should refer to theprevious tutorial to see how to use Plumed restraints.

Since we have a prepared the host-guest-dummy setup from the first tutorial, we will skip the initial tleap steps andgo right into initializing the restraints. If you haven’t completed tutorial 1 please go back and run the notebook togenerate the starting structure.

5.9.1 Initialize

[1]: import os

Define names

We will store the files created in this tutorial in a folder called namd so we don’t mix files with the previous tutorial.

[2]: base_name = "cb6-but-dum"work_dir = "namd"complex_dir = "complex"data = "../../../paprika/data/cb6-but"

5.9.2 Configure APR Restraints

Define anchor atoms

See tutorial 1 for the choice of selection

[3]: # Guest atomsG1 = ":BUT@C"G2 = ":BUT@C3"

# Host atomsH1 = ":CB6@C"H2 = ":CB6@C31"H3 = ":CB6@C18"

# Dummy atomsD1 = ":DM1"

(continues on next page)

94 Chapter 5. References

Page 99: pAPRika Documentation

pAPRika Documentation

(continued from previous page)

D2 = ":DM2"D3 = ":DM3"

Determine the number of windows

Before we add the restraints, it is helpful to set the 𝜆 fractions that control the strength of the force constants duringattach and release, and to define the distances for the pulling phase.

The attach fractions go from 0 to 1 and we place more points at the bottom of the range to sample the curvatureof 𝑑𝑈/𝑑𝜆. Next, we generally apply a distance restraint until the guest is ~18 Angstroms away from the host, inincrements of 0.4 Angstroms. This distance should be at least twice the Lennard-Jones cutoff in the system. Thesevalues have worked well for us, but this is one aspect that should be carefully checked for new systems.

[4]: import numpy as np

[5]: attach_string = "0.00 0.40 0.80 1.60 2.40 4.00 5.50 8.65 11.80 18.10 24.40 37.00 49.→˓60 74.80 100.00"attach_fractions = [float(i) / 100 for i in attach_string.split()]

initial_distance = 6.0pull_distances = np.arange(0.0 + initial_distance, 18.0 + initial_distance, 1.0)

release_fractions = []

windows = [len(attach_fractions), len(pull_distances), len(release_fractions)]print(f"There are {windows} windows in this attach-pull-release calculation.")

There are [15, 18, 0] windows in this attach-pull-release calculation.

Load structure

[6]: import parmed as pmd

• Load complex structure

[7]: structure = pmd.load_file(os.path.join(complex_dir, f"{base_name}.prmtop"),os.path.join(complex_dir, f"{base_name}.rst7"),structure = True,

)

Host Static Restraints

See tutorial 1 for an explanation of the static restraints.

[8]: import paprika.restraints as restraints

[9]: static_restraints = []

5.9. pAPRika tutorial 7 - APR/NAMD with Colvars restraints 95

Page 100: pAPRika Documentation

pAPRika Documentation

[10]: r = restraints.static_DAT_restraint(restraint_mask_list = [D1, H1],num_window_list = windows,ref_structure = structure,force_constant = 5.0,amber_index=True)

static_restraints.append(r)

[11]: r = restraints.static_DAT_restraint(restraint_mask_list = [D2, D1, H1],num_window_list = windows,ref_structure = structure,force_constant = 100.0,amber_index=True)

static_restraints.append(r)

[12]: r = restraints.static_DAT_restraint(restraint_mask_list = [D3, D2, D1, H1],num_window_list = windows,ref_structure = structure,force_constant = 100.0,amber_index=True)

static_restraints.append(r)

[13]: r = restraints.static_DAT_restraint(restraint_mask_list = [D1, H1, H2],num_window_list = windows,ref_structure = structure,force_constant = 100.0,amber_index=True)

static_restraints.append(r)

[14]: r = restraints.static_DAT_restraint(restraint_mask_list = [D2, D1, H1, H2],num_window_list = windows,ref_structure = structure,force_constant = 100.0,amber_index=True)

static_restraints.append(r)

[15]: r = restraints.static_DAT_restraint(restraint_mask_list = [D1, H1, H2, H3],num_window_list = windows,ref_structure = structure,force_constant = 100.0,amber_index=True)

static_restraints.append(r)

96 Chapter 5. References

Page 101: pAPRika Documentation

pAPRika Documentation

Guest translational and rotational restraints

See tutorial 1 for an explanation of the guest restraints

[16]: guest_restraints = []

[17]: r = restraints.DAT_restraint()r.mask1 = D1r.mask2 = G1r.topology = structurer.auto_apr = Truer.continuous_apr = Truer.amber_index = True

r.attach["target"] = pull_distances[0] # Angstromsr.attach["fraction_list"] = attach_fractionsr.attach["fc_final"] = 5.0 # kcal/mol/Angstroms**2

r.pull["target_final"] = 24.0 # Angstromsr.pull["num_windows"] = windows[1]

r.initialize()guest_restraints.append(r)

[18]: r = restraints.DAT_restraint()r.mask1 = D2r.mask2 = D1r.mask3 = G1r.topology = structurer.auto_apr = Truer.continuous_apr = Truer.amber_index = True

r.attach["target"] = 180.0 # Degreesr.attach["fraction_list"] = attach_fractionsr.attach["fc_final"] = 100.0 # kcal/mol/radian**2

r.pull["target_final"] = 180.0 # Degreesr.pull["num_windows"] = windows[1]

r.initialize()guest_restraints.append(r)

[19]: r = restraints.DAT_restraint()r.mask1 = D1r.mask2 = G1r.mask3 = G2r.topology = structurer.auto_apr = Truer.continuous_apr = Truer.amber_index = True

r.attach["target"] = 180.0 # Degreesr.attach["fraction_list"] = attach_fractionsr.attach["fc_final"] = 100.0 # kcal/mol/radian**2

r.pull["target_final"] = 180.0 # Degrees(continues on next page)

5.9. pAPRika tutorial 7 - APR/NAMD with Colvars restraints 97

Page 102: pAPRika Documentation

pAPRika Documentation

(continued from previous page)

r.pull["num_windows"] = windows[1]

r.initialize()guest_restraints.append(r)

Create APR windows

We use the guest restraints to create a list of windows with the appropriate names and then create the directories.

[20]: from paprika.restraints.restraints import create_window_list

[21]: window_list = create_window_list(guest_restraints)

[22]: if not os.path.isdir(work_dir):os.makedirs(work_dir)

for window in window_list:folder = os.path.join(work_dir, window)if not os.path.isdir(folder):

os.makedirs(os.path.join(work_dir, window))

Write APR restraints to a Colvars module file

In this section we create an instance of Colvars() from paprika.restraints.colvars, which is a classto generate the Colvars restraint files. This class is analogous to the Plumed class. We need to specify the listof restraints used throughout the APR calculations and the corresponding windows list. In this tutorial we will printthe host static restraints and the guest restraints. The Colvars class includes a method to add restraints to dummyatoms (add_dummy_atoms_to_file). We will add the positional restraints on the dummy atoms after generatingthe structures for each window.

Note: be careful when specifying the force constants in DAT_restraints. We follow the AMBER (andCHARMM) convention where the force constant is already multiplied by a factor of 1/2 but Colvars (and Plumed)requires the user to specify the force constant without this factor, i.e.

𝑈𝑎𝑚𝑏𝑒𝑟 = 𝐾𝑎𝑚𝑏𝑒𝑟(𝑟 − 𝑟0)2 (5.5)

𝑈𝑐𝑜𝑙𝑣𝑎𝑟𝑠 =1

2𝑘𝑐𝑜𝑙𝑣𝑎𝑟𝑠(𝑟 − 𝑟0)2(5.6)

thus 𝑘𝑐𝑜𝑙𝑣𝑎𝑟𝑠 = 2 ×𝐾𝑎𝑚𝑏𝑒𝑟. If AMBER force constants was used in generating the DAT_restraints (the case inthis tutorial) we need to set the variable uses_legacy_k to True (this is on by default).

[23]: from paprika.restraints.colvars import Colvars

[24]: restraints_list = (static_restraints + guest_restraints)

colvars = Colvars()colvars.file_name = "colvars.tcl"colvars.path = work_dircolvars.window_list = window_listcolvars.restraint_list = restraints_listcolvars_uses_legacy_k = True

colvars.dump_to_file()

98 Chapter 5. References

Page 103: pAPRika Documentation

pAPRika Documentation

5.9.3 Prepare host-guest system

Translate guest molecule

For the attach windows, we will use the initial, bound coordinates for the host-guest complex. Only the force constantschange during this phase, so a single set of coordinates is sufficient. For the pull windows, we will translate the guestto the target value, and for the release windows, we will use the coordinates from the final pull window.

[25]: import shutil

[26]: for window in window_list:if window[0] == "a":

shutil.copy(os.path.join(complex_dir, f"{base_name}.prmtop"),os.path.join(work_dir, window, f"{base_name}.prmtop"))

shutil.copy(os.path.join(complex_dir, f"{base_name}.rst7"),os.path.join(work_dir, window, f"{base_name}.rst7"))

elif window[0] == "p":structure = pmd.load_file(

os.path.join(complex_dir, f"{base_name}.prmtop"),os.path.join(complex_dir, f"{base_name}.rst7"),structure = True

)target_difference = guest_restraints[0].phase['pull']['targets'][int(window[1:

→˓])] -\guest_restraints[0].pull['target_initial']

print(f"In window {window} we will translate the guest {target_difference:0.→˓1f} Angstroms.")

for atom in structure.atoms:if atom.residue.name == "BUT":

atom.xz += target_difference

structure.save(os.path.join(work_dir, window, f"{base_name}.prmtop"),→˓overwrite=True)

structure.save(os.path.join(work_dir, window, f"{base_name}.rst7"),→˓overwrite=True)

In window p000 we will translate the guest 0.0 Angstroms.In window p001 we will translate the guest 1.1 Angstroms.In window p002 we will translate the guest 2.1 Angstroms.In window p003 we will translate the guest 3.2 Angstroms.In window p004 we will translate the guest 4.2 Angstroms.In window p005 we will translate the guest 5.3 Angstroms.In window p006 we will translate the guest 6.4 Angstroms.In window p007 we will translate the guest 7.4 Angstroms.In window p008 we will translate the guest 8.5 Angstroms.In window p009 we will translate the guest 9.5 Angstroms.In window p010 we will translate the guest 10.6 Angstroms.In window p011 we will translate the guest 11.6 Angstroms.In window p012 we will translate the guest 12.7 Angstroms.In window p013 we will translate the guest 13.8 Angstroms.In window p014 we will translate the guest 14.8 Angstroms.In window p015 we will translate the guest 15.9 Angstroms.In window p016 we will translate the guest 16.9 Angstroms.In window p017 we will translate the guest 18.0 Angstroms.

5.9. pAPRika tutorial 7 - APR/NAMD with Colvars restraints 99

Page 104: pAPRika Documentation

pAPRika Documentation

Add dummy atom restraints

Here we will add positional restraints on the dummy atoms. The reference positions are extracted from the structurefiles we just created in each window.

[27]: for window in window_list:folder = os.path.join(work_dir, window)

structure = pmd.load_file(os.path.join(folder, f"{base_name}.prmtop"),os.path.join(folder, f"{base_name}.rst7"),structure = True

)

colvars.add_dummy_atom_restraints(structure, window)

5.9.4 Simulation

Now that we have prepared the structure and colvars.tcl file for each window, we have everything ready togo. pAPRika comes with a python wrapper for NAMD that can help set up default parameters for the simulation.There are some high level options that we set directly, like simulation.path, and then we call the functionconfig_gb_min() to setup reasonable default simulation parameters for a minimization and production run.The temperature of the system will be controlled with the Langevin thermostat, which is the default. For run-ning simulations with a different thermostat parse the thermostat of choice using the Thermostat Enum class toconfig_gb_md(). For example, if we want to run our simulations with the Lowe-Anderson thermostat:

simulation = NAMD()...simulation.config_gb_md(NAMD.Thermostat.LoweAnderson)simulation.run()

See the pAPRika documentation for more details on the different temperature control algorithm implemented.

Note: NAMD version 2 is similar to GROMACS in that more than one thread for every GPU is preferred to deliverbetter speed. We set the number of processors with simulation.n_threads = 8 and the GPU device withsimulation.gpu_devices = 0. Starting with NAMD version 3 (currently in alpha phase) a smaller number ofn_threads is required per GPU.

[28]: from paprika.simulate import NAMD

Initialize logger

[29]: import loggingfrom importlib import reloadreload(logging)

logger = logging.getLogger()logging.basicConfig(

format='%(asctime)s %(message)s',datefmt='%Y-%m-%d %I:%M:%S %p',level=logging.INFO

)

100 Chapter 5. References

Page 105: pAPRika Documentation

pAPRika Documentation

Energy Minimization

[30]: for window in window_list:simulation = NAMD()simulation.executable = "namd2"simulation.n_threads = 4

# simulation.gpu_devices = 0simulation.path = os.path.join(work_dir, window)

simulation.topology = f"{base_name}.prmtop"simulation.coordinates = f"{base_name}.rst7"simulation.prefix = "minimize"simulation.colvars_file = "colvars.tcl"

simulation.config_gb_min()

logging.info(f"Running minimization in window {window}...")simulation.run(overwrite=True)

2020-10-09 11:31:02 AM Running minimization in window a000...2020-10-09 11:31:07 AM Running minimization in window a001...2020-10-09 11:31:13 AM Running minimization in window a002...2020-10-09 11:31:20 AM Running minimization in window a003...2020-10-09 11:31:25 AM Running minimization in window a004...2020-10-09 11:31:30 AM Running minimization in window a005...2020-10-09 11:31:34 AM Running minimization in window a006...2020-10-09 11:31:39 AM Running minimization in window a007...2020-10-09 11:31:43 AM Running minimization in window a008...2020-10-09 11:31:48 AM Running minimization in window a009...2020-10-09 11:31:53 AM Running minimization in window a010...2020-10-09 11:31:59 AM Running minimization in window a011...2020-10-09 11:32:03 AM Running minimization in window a012...2020-10-09 11:32:08 AM Running minimization in window a013...2020-10-09 11:32:12 AM Running minimization in window p000...2020-10-09 11:32:16 AM Running minimization in window p001...2020-10-09 11:32:21 AM Running minimization in window p002...2020-10-09 11:32:25 AM Running minimization in window p003...2020-10-09 11:32:30 AM Running minimization in window p004...2020-10-09 11:32:34 AM Running minimization in window p005...2020-10-09 11:32:39 AM Running minimization in window p006...2020-10-09 11:32:43 AM Running minimization in window p007...2020-10-09 11:32:48 AM Running minimization in window p008...2020-10-09 11:32:56 AM Running minimization in window p009...2020-10-09 11:33:01 AM Running minimization in window p010...2020-10-09 11:33:05 AM Running minimization in window p011...2020-10-09 11:33:10 AM Running minimization in window p012...2020-10-09 11:33:14 AM Running minimization in window p013...2020-10-09 11:33:19 AM Running minimization in window p014...2020-10-09 11:33:23 AM Running minimization in window p015...2020-10-09 11:33:28 AM Running minimization in window p016...2020-10-09 11:33:32 AM Running minimization in window p017...

5.9. pAPRika tutorial 7 - APR/NAMD with Colvars restraints 101

Page 106: pAPRika Documentation

pAPRika Documentation

Thermalization

Here, we will do a slow heating process to demonstrate the custom_run_command feature of the NAMD wrapper.We will heat the system from 50 K to 300 K in steps of 50 K and will do a total of 500 MD steps for each temperature.

[31]: for window in window_list:simulation = NAMD()simulation.executable = "namd2"simulation.n_threads = 4

# simulation.gpu_devices = 0simulation.path = os.path.join(work_dir, window)

simulation.topology = f"{base_name}.prmtop"simulation.coordinates = f"{base_name}.rst7"simulation.prefix = "thermalization"simulation.checkpoint = "minimize"simulation.colvars_file = "colvars.tcl"

simulation.config_gb_md()

# Slow heatingsimulation.custom_run_commands = [

"for {set temp 50} {$temp <= 300} {incr temp 50} {","langevinTemp $temp","reinitvels $temp","run 500","}",

]

logging.info(f"Running thermalization in window {window}...")simulation.run(overwrite=True)

2020-10-09 11:33:37 AM Running thermalization in window a000...2020-10-09 11:33:39 AM Running thermalization in window a001...2020-10-09 11:33:40 AM Running thermalization in window a002...2020-10-09 11:33:42 AM Running thermalization in window a003...2020-10-09 11:33:44 AM Running thermalization in window a004...2020-10-09 11:33:46 AM Running thermalization in window a005...2020-10-09 11:33:47 AM Running thermalization in window a006...2020-10-09 11:33:49 AM Running thermalization in window a007...2020-10-09 11:33:51 AM Running thermalization in window a008...2020-10-09 11:33:53 AM Running thermalization in window a009...2020-10-09 11:33:54 AM Running thermalization in window a010...2020-10-09 11:33:56 AM Running thermalization in window a011...2020-10-09 11:33:58 AM Running thermalization in window a012...2020-10-09 11:34:00 AM Running thermalization in window a013...2020-10-09 11:34:02 AM Running thermalization in window p000...2020-10-09 11:34:06 AM Running thermalization in window p001...2020-10-09 11:34:09 AM Running thermalization in window p002...2020-10-09 11:34:13 AM Running thermalization in window p003...2020-10-09 11:34:15 AM Running thermalization in window p004...2020-10-09 11:34:17 AM Running thermalization in window p005...2020-10-09 11:34:18 AM Running thermalization in window p006...2020-10-09 11:34:20 AM Running thermalization in window p007...2020-10-09 11:34:22 AM Running thermalization in window p008...2020-10-09 11:34:24 AM Running thermalization in window p009...2020-10-09 11:34:25 AM Running thermalization in window p010...2020-10-09 11:34:27 AM Running thermalization in window p011...

(continues on next page)

102 Chapter 5. References

Page 107: pAPRika Documentation

pAPRika Documentation

(continued from previous page)

2020-10-09 11:34:29 AM Running thermalization in window p012...2020-10-09 11:34:30 AM Running thermalization in window p013...2020-10-09 11:34:32 AM Running thermalization in window p014...2020-10-09 11:34:34 AM Running thermalization in window p015...2020-10-09 11:34:36 AM Running thermalization in window p016...2020-10-09 11:34:37 AM Running thermalization in window p017...

We will skip the equilibration step and go straight to production

Production Run

We will run the production phase for 5,000 steps.

Note: a proper production run would require much longer simulation.

[32]: for window in window_list:simulation = NAMD()simulation.executable = "namd2"simulation.n_threads = 4

# simulation.gpu_devices = 0simulation.path = os.path.join(work_dir, window)

simulation.topology = f"{base_name}.prmtop"simulation.coordinates = f"{base_name}.rst7"simulation.prefix = "production"simulation.checkpoint = "thermalization"simulation.colvars_file = "colvars.tcl"

simulation.config_gb_md()simulation.control["run"] = 5000

logging.info(f"Running production in window {window}...")simulation.run(overwrite=True)

2020-10-09 11:34:39 AM Running production in window a000...2020-10-09 11:34:41 AM Running production in window a001...2020-10-09 11:34:44 AM Running production in window a002...2020-10-09 11:34:46 AM Running production in window a003...2020-10-09 11:34:49 AM Running production in window a004...2020-10-09 11:34:52 AM Running production in window a005...2020-10-09 11:34:54 AM Running production in window a006...2020-10-09 11:34:57 AM Running production in window a007...2020-10-09 11:35:00 AM Running production in window a008...2020-10-09 11:35:02 AM Running production in window a009...2020-10-09 11:35:05 AM Running production in window a010...2020-10-09 11:35:10 AM Running production in window a011...2020-10-09 11:35:15 AM Running production in window a012...2020-10-09 11:35:17 AM Running production in window a013...2020-10-09 11:35:21 AM Running production in window p000...2020-10-09 11:35:25 AM Running production in window p001...2020-10-09 11:35:29 AM Running production in window p002...2020-10-09 11:35:33 AM Running production in window p003...2020-10-09 11:35:36 AM Running production in window p004...2020-10-09 11:35:40 AM Running production in window p005...2020-10-09 11:35:42 AM Running production in window p006...2020-10-09 11:35:46 AM Running production in window p007...

(continues on next page)

5.9. pAPRika tutorial 7 - APR/NAMD with Colvars restraints 103

Page 108: pAPRika Documentation

pAPRika Documentation

(continued from previous page)

2020-10-09 11:35:51 AM Running production in window p008...2020-10-09 11:35:54 AM Running production in window p009...2020-10-09 11:35:58 AM Running production in window p010...2020-10-09 11:36:06 AM Running production in window p011...2020-10-09 11:36:15 AM Running production in window p012...2020-10-09 11:36:21 AM Running production in window p013...2020-10-09 11:36:27 AM Running production in window p014...2020-10-09 11:36:32 AM Running production in window p015...2020-10-09 11:36:37 AM Running production in window p016...2020-10-09 11:36:41 AM Running production in window p017...

5.9.5 Analysis

Once the simulation is completed, we can using the Analysis module to determine the binding free energy. Wesupply the location of the parameter information, a string or list for the file names (wildcards supported), the locationof the windows, and the restraints on the guest.

In this example, we use the method ti-block which determines the free energy using thermodynamic iintegrationand then estimates the standard error of the mean at each data point using blocking analysis. Bootstrapping it used todetermine the uncertainty of the full thermodynamic integral for each phase.

After running compute_free_energy(), a dictionary called results will be populated, that contains the freeenergy and SEM for each phase of the simulation.

[33]: import paprika.analysis as analysis

[35]: free_energy = analysis.fe_calc()free_energy.prmtop = "cb6-but-dum.prmtop"free_energy.trajectory = 'production*.dcd'free_energy.path = work_dirfree_energy.restraint_list = guest_restraintsfree_energy.collect_data()free_energy.methods = ['ti-block']free_energy.ti_matrix = "full"free_energy.bootcycles = 1000free_energy.compute_free_energy()

We also need to calculate the free-energy cost of releasing the restraints on the guest molecule.

[36]: free_energy.compute_ref_state_work([guest_restraints[0], guest_restraints[1], None,None, guest_restraints[2], None

])

Then we add the free-energies together and combine the uncertainties to get the binding-free energy

[37]: binding_affinity = -1 * (free_energy.results["attach"]["ti-block"]["fe"] + \free_energy.results["pull"]["ti-block"]["fe"] + \free_energy.results["ref_state_work"]

)

sem = np.sqrt(free_energy.results["attach"]["ti-block"]["sem"]**2 + \

(continues on next page)

104 Chapter 5. References

Page 109: pAPRika Documentation

pAPRika Documentation

(continued from previous page)

free_energy.results["pull"]["ti-block"]["sem"]**2)

[38]: print(f"The binding affinity of butane to cucurbit[6]uril = {binding_affinity:0.2f} +/→˓- {sem:0.2f} kcal/mol")

The binding affinity of butane to cucurbit[6]uril = -6.16 +/- 4.40 kcal/mol

5.10 Compiling the Docs

The docs for this project are built with [Sphinx](http://www.sphinx-doc.org/en/master/). To compile the docs, firstensure that Sphinx, and the ReadTheDocs theme are installed.:

conda install sphinx nbsphinx sphinx_rtd_theme

Once installed, you can use the Makefile in this directory to compile static HTML pages by:

make html

The compiled docs will be in the _build directory and can be viewed by opening index.html (which may itselfbe inside a directory called html/ depending on what version of Sphinx is installed).

5.11 API

This page provides links to the documentation for classes and modules available in paprika.

• Align API

• Analysis API

• Dummy Atoms API

• Evaluator API

• Restraints API

• Simulation Wrappers API

• System API

• Utils API

5.11.1 Align API

The Align module provide a number of functions to translate and orient molecules that is useful during structurepreparation.

paprika.build.align.zalign(structure, mask1, mask2, axis='z', save=False, filename=None)Aligns the vector formed by atom mask1–mask2 to a reference axis.

Parameters

• structure (parmed.Structure) – Molecular structure containing coordinates.

• mask1 (str) – Selection of first set of atoms.

5.10. Compiling the Docs 105

Page 110: pAPRika Documentation

pAPRika Documentation

• mask2 (str) – Selection of second set of atoms.

• axis (str or list or numpy.ndarray, optional, default=’z’) – Cartesian axis as a string:x, y, and z, or an arbitrary vector as a list. If an array is specified, the axis-vector will benormalized automatically.

• save (bool, optional, default=False) – Whether to save the coordinates (thedefault is False, which does nothing).

• filename (str, optional, default=None) – The filename for the saved coordi-nates (the default is None, which does nothing).

Returns structure – A molecular structure with the coordinates aligned as specified.

Return type parmed.Structure

Examples

>>> # Align a system based on the vector joining BUT@C--BUT@C3 to the z-axis>>> aligned_structure = zalign(structure, ":BUT@C", ":BUT@C3")>>>>>> # Do the same thing but align the system to the y-axis>>> aligned_structure = zalign(structure, ":BUT@C", ":BUT@C3", axis='y')

paprika.build.align.align_principal_axes(structure, atom_mask=None, principal_axis=1,axis='z')

Aligns a chosen principal axis of a system to a user specified axis. This function is based on the method givenin the link: https://www.ks.uiuc.edu/Research/vmd/script_library/scripts/orient/

Parameters

• structure (parmed.Structure) – Molecular structure containing coordinates.

• atom_mask (str, optional, default=None) – A mask that filter specific atomsfor calculating the moment of inertia. This is useful if the molecule is not radially symmetricand you may want to select a subset of atoms that is symmetric for alignment.

• principal_axis (int, optional, default=1) – The particular principal axisto align to (The choices are 1, 2 or 3 with 1 being the principal axis with the largest eigen-value and 3 the lowest.).

• axis (str or list or numpy.ndarray, optional, default=’z’) – The axis vector to align thesystem to (by default the function aligns the principal axes with the largest eigenvalue to thez-axis). If an array is specified, the axis-vector will be normalized automatically.

Returns structure – A molecular structure with it’s principal axis aligned to a vector.

Return type parmed.Structure

Examples

The commands below mimics the example given in the link above in VMD.

>>> # Align largest principal axes to the z-axis>>> structure = align_principal_axes(structure, principal_axis=1, axis='z')>>>>>> # Align second largest principal axes to the y-axis>>> structure = align_principal_axes(structure, principal_axis=2, axis='y')

It is also possible to use only a subset of atoms to determine the principal axes

106 Chapter 5. References

Page 111: pAPRika Documentation

pAPRika Documentation

>>> structure = align_principal_axes(structure, atom_mask="@/C", principal_axis=2,→˓ axis='z')

paprika.build.align.rotate_around_axis(structure, axis, angle)Rotates a system around an axis. The axis can be Cartesian axes (‘x’, ‘y’, and ‘z’) or an arbitrary axis (axis-angle).

Parameters

• structure (parmed.Structure) – Molecular structure containing coordinates.

• axis (str or list or numpy.ndarray) – The axis of rotation. If an array is specified, theaxis-vector will be normalized automatically.

• angle (float) – The angle of rotation in degrees.

Returns structure – A molecular structure with it’s principal axis aligned to a vector.

Return type parmed.Structure

Examples

>>> # Rotate a system around the z axis by 90 degrees>>> structure = rotate_around_axis(structure, axis='z', angle=90.0)>>>>>> # Rotate a system around the axis [1,1,1] by 30 degrees>>> structure = rotate_around_axis(structure, axis=[1,1,1], angle=30.0)

paprika.build.align.get_theta(structure, mask1, mask2, axis)Get the angle (theta) between the vector formed by atom mask1–mask2 and a Cartesian axis.

Parameters

• structure (parmed.Structure) – Molecular structure containing coordinates.

• mask1 (str) – Selection of first set of atoms.

• mask2 (str) – Selection of second set of atoms.

• axis (str or list or numpy.ndarray) – Cartesian axis as a string: x, y, and z, or anarbitrary vector as a list. If an array is specified, the axis vector need not be normalized.

Returns theta – The angle between the masks and the axis.

Return type float

paprika.build.align.get_rotation_matrix(vector, ref_vector)Generate a rotation matrix needed for rotating vector to ref_vector.

Parameters

• vector (numpy.ndarray) – The vector of interest that will be rotated.

• ref_vector (numpy.ndarray) – The reference vector, which vector1 will be rotatedto.

Returns rotation_matrix – A 3x3 rotation matrix.

Return type numpy.ndarray

paprika.build.align.get_principal_axis_vector(structure, principal_axis=1,atom_mask=None)

Return the principal axis vector given a structure.

5.11. API 107

Page 112: pAPRika Documentation

pAPRika Documentation

Parameters

• structure (parmed.Structure) – Molecular structure containing coordinates.

• principal_axis (int, optional, default=1) – The particular principal axisto align to (The choices are 1, 2 or 3 with 1 being the principal axis with the largest eigen-value and 3 the lowest).

• atom_mask (str, optional, default=None) – A mask that filter specific atomsfor calculating the moment of inertia. This is useful if the molecule is not radially symmetricand you may want to select a subset of atoms that is symmetric for alignment.

Returns p_axis – Principal axis vector.

Return type numpy.ndarray

paprika.build.align.check_coordinates(structure, mask)Return the coordinates of an atom selection.

Parameters

• structure (parmed.Structure) – Molecular structure containing coordinates.

• mask (str) – Amber-style atom selection.

Returns mask_com – Coordinates of the selection center of mass.

Return type np.array

paprika.build.align.offset_structure(structure, offset, dimension=None)Return a structure whose coordinates have been shifted by offset.

Parameters

• structure (parmed.Structure) – Molecular structure containing coordinates.

• offset (float or numpy.ndarray) – The offset that will be added to every atom in thestructure.

• dimension (str or list or numpy.ndarray, optional, default=None) – By default thestructure will be moved by offset in all direction if it is a single number, i.e. xyz +offset*[1,1,1]. This variable applies a mask so that you can offset the structure in aspecific direction.

Returns structure – Coordinates of the structure offset by the given amount.

Return type parmed.Structure

Examples

>>> # Offset a structure in the y-axis by 5 Angstrom>>> structure = offset_structure(structure, 5.0, dimension='y')>>>>>> # Offset a structure in the x- and z-axis by 3 Angstrom>>> structure = offset_structure(structure, 3.0, dimension='z')>>>>>> # Offset a structure using a numpy array>>> offset = np.array([0.0, 5.0, 2.0])>>> structure = offset_structure(structure, offset)

paprika.build.align.translate_to_origin(structure, weight='mass', atom_mask=None, di-mension=None)

Translate a structure to the origin based on the centroid of the whole system or a subset of atom(s).

108 Chapter 5. References

Page 113: pAPRika Documentation

pAPRika Documentation

Parameters

• structure (str or parmed.Structure) – Molecular structure containing coordinates.

• weight (str, optional, default="mass") – Calculate the centroid based oneither atomic masses (mass default) or geometric center (geo).

• atom_mask (str, optional, default=None) – Selection of atom(s) if a particu-lar subset is preferred to estimate the centroid.

• dimension (str or list or numpy.ndarray, optional, default=None) – A mask that willfilter the dimensions to which the translation will be applied (by default the system will betranslated in all dimensions).

Returns structure – A molecular structure with the coordinates translated to the origin.

Return type parmed.Structure

Examples

>>> # Translate a structure to the origin>>> translated_structure = translate_to_origin(structure)>>>>>> # Translate the structure only in the z-axis>>> translated_structure = translate_to_origin(structure, dimension='z')>>>>>> # Translate the system based only on the carbon atoms>>> translated_structure = translate_to_origin(structure, atom_mask='@/C')

5.11.2 Analysis API

class paprika.analysis.fe_calcBases: object

Computes the free energy for an APR transformation. After calling compute_free_energy(), the resultsare stored in a dictionary called results in units of kcal/mol.

To get the binding free energy at standard state (G°), we have used the following sign convention:

𝐺 = 𝐺𝑎𝑡𝑡𝑎𝑐ℎ + 𝐺𝑝𝑢𝑙𝑙 −𝐺𝑟𝑒𝑙𝑒𝑎𝑠𝑒 + 𝐺𝑟𝑒𝑓𝑒𝑟𝑒𝑛𝑐𝑒

Note: It would be great to add unit support here from pint.

Warning: This class really ought to be split into a few smaller classes that sublcass a BaseAnalysisclass. There could be separate MBARAnalysis and TIAnalysis classes, for example. This would makeit much more modular and easy to test where TI and MBAR disagree. This could also be used to benchmarkautocorrelation-based and blocking-analysis-based methods for evaluating the statistical inefficiency.

property temperatureThe temperature used during the simulation. This will update (1/kT) as well.

Type float

5.11. API 109

Page 114: pAPRika Documentation

pAPRika Documentation

property prmtopThe .prmtop (topology) file used for the analysis. This should match the topology used for the simulation.

Type os.PathLike

property trajectoryFile name of the trajectories to be analyzed in each window (can include a wildcard).

Type os.PathLike

property pathThe parent directory that contains the simulation windows.

Type os.PathLike

property restraint_listThe list of restraints to be used for analysis.

Type list

property changing_restraintsDictionary containing which restraints change during which phase of the calculation.

Note: This should probably be a private attribute, as this property is determined automatically.

Type dict

property ordersThe sorted order of windows for analysis. In principle, windows could be out-of-order if subsequentadditional sampling was requested.

Note: As far as I know, we have not tested analysis on windows out of order. We imagined that one couldadd additional windows through multiple runs by modifying existing restraints (e.g., restraint values of[0, 0.5, 1.0, 0.8]) and this module would be able to correctly sort the simulation directories and restrainttargets.

Note: This should probably be a private attribute, as this property is determined automatically.

property simulation_dataDictionary containing collected trajectory values for the relevant restraints and windows

Note: This should probably be a private attribute, as this property is determined automatically.

Type dict

property methodsList of analysis methods to be performed. This is a combination of free energy method (e.g., MBAR, TI,. . . ) and de-correlation method (blocking, autocorrelation, . . . ).

Implemented methods are:

• mbar-autoc

• mbar-block

110 Chapter 5. References

Page 115: pAPRika Documentation

pAPRika Documentation

• ti-block

Note: This is really fragile. We should definitely use something like an ENUM here to check for the fewcombinations that we support.

Todo:

• Add ti-autoc.

• Add wham-block.

• Add wham-autoc.

• Clarify naming.

• Look into using pymbar for decorrelation.

Type list

property conservative_subsampleWhether the statistical inefficiency is rounded up to the nearest integer. If False, a non-integer value isused.

Type bool

property bootcyclesThe number of bootstrap iterations for the TI methods.

Default: 1000

Type int

property compute_roiWhether to compute the return on investment (ROI) value for each window. The more negative the ROI,the better the return on investment of computing more frames for this particular window.

Type bool

property compute_largest_neighborWhether to find and store the maximum SEM to the neighbor windows. This is useful if using the“scale_w” approach which is described in Equation (1) in: https://pubs.acs.org/doi/10.1021/acs.jctc.9b00748.

Type bool

property ti_matrixIf full, the TI mean and SEM free energy is computed between all windows (i.e., the energy differencesbetween all windows and all other windows). If diagonal, the mean and SEM of the free energy iscomputed between the first window and all other windows, as well as between all neighboring windows.If endpoints, the mean and SEM free energy is computed between only the first and the last window.

For most cases, diagonal should be sufficient and full is overkill.

Note: This is fragile and we should be checking for the valid strings supported.

Type str

5.11. API 111

Page 116: pAPRika Documentation

pAPRika Documentation

property exact_sem_each_ti_fractionWhether the SEM is computed once for the full data set and then the SEM for each fraction is estimatedbased on the total SEM and the fractional number of uncorrelated data points. If True, the SEM will berecomputed each fraction using just that fraction of the raw data.

Type bool

property fractionsA list of fractions of the total data for which a free energy will be computed. Default is [1.0].

Type list

property resultsA dictionary containing the results. The results dictionary is indexed first by phase, and then by method.That is, results["attach"]["mbar-block"] will contain the results from analyzing the attachphase with the MBAR free energy estimator and blocking analysis used to estimate the SEM.

The final free energy and uncertainty estimate is specified in the fe and sem keys.

If multiple fractions of the data are specified, the free energy and SEM from each fraction are stored in anested dictionary under the keys fraction_fe and fractrion_sem. The number of frames analyzedfor each fraciton is stored under fraction_n_frames.

The full free energy matrix (window-to-window free energy differences) is stored in the fe_matrix en-try. Likewise, the full SEM matrix (window-to-window free energy SEMs) is stored in the sem_matrixentry.

The work to release the guest to standard concentration is stored under ref_state_work, and is nega-tive by convention.

The format of a typical dictionary will resemble this (where I have a omitted the values in the matrices forclarity):

{'attach': {'mbar-block': {'fe': 13.019994367423227,'fe_matrix': array(),'fraction_fe': {'1.0': 13.019994367423227},'fraction_fe_matrix': {'1.0': array()},'fraction_n_frames': {'1.0': 2280000},'fraction_sem': {'1.0': 0.12783177525365627},'fraction_sem_matrix': {'1.0': array()},'n_frames': 2280000,'sem': 0.12783177525365627,'sem_matrix': array()},

'window_order': array([ 0, 1, 2, ..., 12, 13, 14])},'pull': {'mbar-block': {'fe': 5.367885925413715,

'fe_matrix': array(),'fraction_fe': {'1.0': 5.367885925413715},'fraction_fe_matrix': {'1.0': array()},'fraction_n_frames': {'1.0': 2900000},'fraction_sem': {'1.0': 0.21231171453084993},'fraction_sem_matrix': {'1.0': array()},'n_frames': 2900000,'sem': 0.21231171453084993,'sem_matrix': array()},

'window_order': array([ 0, 1, 2, ..., 43, 44, 45])},'ref_state_work': -7.141514582862005}

Note: This will be automatically populated with the outcome of the analysis. Do not directly modifythese values.

112 Chapter 5. References

Page 117: pAPRika Documentation

pAPRika Documentation

Type dict

collect_data(single_prmtop=False)Gather simulation data on the distance, angle, and torsion restraints that change during the simulation.

Parameters single_prmtop (bool) – Whether a single prmtop is read for all windows

identify_changing_restraints()Figure out which restraints change during each phase of the calculation.

Returns changing_restraints – A dictionary containing which restraints change during whichphase of the calculation

Return type dict

determine_window_order()Order the trajectories (i.e., simulation windows) in terms of increasing force constants and targets for eachrestraint.

Returns orders – The sorted order of windows for analysis

Return type dict

read_trajectories(single_prmtop=False)For each each phase and window, and for each non-static restraint, parse the trajectories to get the restraintvalues.

Parameters single_prmtop (bool) – Whether a single prmtop is read for all windows

Returns data – Dictionary containing restraint values for analysis

Return type dict

prepare_data(phase)

run_mbar(phase, prepared_data, method, verbose=False)Compute the free energy matrix for a series of windows. We’ll follow the pymbar nomenclature for datastructures.

Parameters

• phase (str) – The phase of the calculation to analyze.

• prepared_data (np.array) – The list of “prepared data” including the number ofwindows, data points, which restraints are changing, their force constants and targets, andwell as the order of the windows. This probably ought to be redesigned.

• method (str) – The method used to calculate the SEM.

• verbose (bool, optional) – Whether to set the verbose option on pyMBAR.

run_ti(phase, prepared_data, method)Compute the free energy using the TI method.

We compute the partial derivative of the potential (i.e., forces), for each frame, with respect to the changingparameter, either a lambda or target value. The force constants are scaled by the parameter which controlstheir strength: 0 to fc_max.

Potential: U = × fc_max × (values - target)2

Forces during attach: dU/d = fc_max × (values - target)2

Forces during pull: dU/d(target) = 2 × × fc_max × (values - target)

Forces during release: (same as attach)

5.11. API 113

Page 118: pAPRika Documentation

pAPRika Documentation

Then we integrate over the interval covered by or target.

Parameters

• phase (str) – The phase of the calculation to analyze.

• prepared_data (np.array) – The list of “prepared data” including the number ofwindows, data points, which restraints are changing, their force constants and targets, andwell as the order of the windows. This probably ought to be redesigned.

• method (str) – The method used to calculate the SEM.

Note: phase and method should be enum types and tied to class attributes.

Warning: We have only considered whether this will work for the case where the pull phase is asingle distance restraint with a changing target value. This has not been tested for a changing angle ordihedral.

compute_free_energy(phases=['attach', 'pull', 'release'], seed=None)Compute the free energy of binding from a simulation. This function populates the results dictionaryof the fe_calc object.

Parameters

• phases (list) – Which phases of the calculation to analyze.

• seed (int) – Random number seed.

compute_ref_state_work(restraints)Compute the work to place a molecule at standard reference state conditions starting from a state definedby up to six restraints. These are Boresch-style restraints.

Parameters restraints (list) – A list of paprika.restraints.DAT_restraintobjects in order of the six translational and orientational restraints needed to describe theconfiguration of one molecule relative to another. The six restraints are: r, theta, phi, al-pha, beta, gamma and they should be passed to this function in that order. If any of thesecoordinates is not being restrained, use a None in place of a paprika.restraints.DAT_restraint object.

See paprika.analysis.ref_state_work() for details on the calculation.

paprika.analysis.get_factors(n)Return a list of integer factors for a number.

Parameters n (int or float) – Number to factor

Returns sorted – A list of sorted factors.

Return type list

paprika.analysis.get_nearest_max(n)Return the number with the largest number of factors between n 100 and n.

Parameters n (int) – Desired number to factor.

Returns most_factors – The number with the most factors.

Return type int

114 Chapter 5. References

Page 119: pAPRika Documentation

pAPRika Documentation

paprika.analysis.get_block_sem(data_array)Compute the standard error of the mean (SEM) using the blocking method.

Note: This is a conservative approach. Here, we report the maximum SEM determined from blocking analysis(cf. the “plateau” on the blocking curve).

Parameters data_array (np.array) – Array containing data values.

Returns np.max(sems) – The maximum SEM obtained from te blocking curve.

Return type float

paprika.analysis.get_subsampled_indices(N, g, conservative=False)Get the indices of independent (subsampled) frames. This is adapted from the implementation in pymbar.

Parameters

• N (int) – The length of the array to be indexed.

• g (int) – The statistical inefficiency of the data.

• conservative (bool, optional, default=False) – Whether g should berounded up to the nearest integer.

Returns indices – A list of indices that can be used to pull out de-correlated frames from a timeseries.

Return type list

paprika.analysis.load_trajectory(window, trajectory, prmtop, single_prmtop=False)Load a trajectory (or trajectories) and return a pytraj trajectory object.

Parameters

• window (str) – The simulation window to analyze

• trajectory (str or list) – The name or names of the trajectory

• prmtop (str or parmed.Structure) – The parameters for the simulation

• single_prmtop (bool) – Whether a single prmtop is read for all windows

Returns traj – The trajectory of stored as a pytraj object.

Return type pytraj.trajectory

paprika.analysis.read_restraint_data(traj, restraint)Given a trajectory and restraint, read the restraint and return the DAT values.

Parameters

• traj (pytraj.trajectory) – A trajectory, probably loaded by load_trajectory

• restraint (DAT_restraint) – The restraint to analyze

Returns data – The values for this restraint in this window

Return type np.array

paprika.analysis.ref_state_work(temperature, r_fc, r_tg, th_fc, th_tg, ph_fc, ph_tg, a_fc, a_tg,b_fc, b_tg, g_fc, g_tg)

Computes the free energy to release a molecule from some restrained translational and orientational config-uration (relative to another molecule or lab frame) into the reference configuration: standard concentration(1.0/1660.5392 Å3) and unrestrained orientational freedom (82).

5.11. API 115

Page 120: pAPRika Documentation

pAPRika Documentation

The Wikipedia entry on Euler angles is useful.

Assume two molecules (H and G). Three translational and three orientational degrees of freedom define theirrelative configuration. In order to match experimentally reported free energies, we often need to compute thework (free energy) of moving a molecule (G) from a restrained configuration relative to H into the experimentalreference state (usually defined as 1 M, or 1 molecule per 1660.5 Å3)

H3\ [a1] [a2]H2-------H1-------<d1>-------G1-------G2

{t1} {t2} {t3}→˓ G3

Degrees of Freedom-----------------------------------------------------------------id atoms type, spherical coordinate/Euler angle-----------------------------------------------------------------<d1>: H1-G1 distance, r[a1]: H2-H1-G1 angle, theta{t1}: H3-H2-H1-G1 torsion, phi{t2}: H2-H1-G1-G2 torsion, alpha[a2]: H1-G1-G2 angle, beta{t3}: H1-G1-G2-G3 torsion, gamma

Parameters

• temperature (float) – The temperature (in Kelvin) at which the reference state calcu-lation will take place.

• r_fc (float) – The distance, 𝑟, restraint force constant (kcal/mol-Å2).

• r_tg (float) – The distance, 𝑟, restraint target values (Å). The target range is 0 to infinity.

• th_fc (float) – The angle, , restraint force constant (kcal/mol-radian2).

• th_tg (float) – The angle, , restraint target values (radian). The target range is 0 to .

• ph_fc (float) – The torsion, 𝜑, restraint force constant (kcal/mol-radian2).

• ph_tg (float) – The torsion, 𝜑, restraint target values (radian). The target range is 0 to2.

• a_fc (float) – The torsion, , restraint force constant (kcal/mol-radian2).

• a_tg (float) – The torsion, , restraint target values (radian). The target range is 0 to 2.

• b_fc (float) – The angle, , restraint force (kcal/mol-radian2).

• b_tg (float) – The angle, , restraint target values (radian). The target range is 0 to .

• g_fc (float) – The angle, , restraint force (kcal/mol-radian2).

• g_tg (float) – The angle, , restraint target values (radian). The target range is 0 to 2.

Returns RT * np.log(trans * orient) – The free energy associated with releasing the restraints.

Return type float

Note: It would be great if this function accepted (and correctly propagated) units using a library like pint.

116 Chapter 5. References

Page 121: pAPRika Documentation

pAPRika Documentation

paprika.analysis.integrate_bootstraps(x, ys, x_intp=None, matrix='full')Integrate splines created via bootstrapping.

Parameters

• x (np.array) – The x coordinate of the curve to be integrated.

• ys (np.array) – Two dimensional array in which the first dimension is bootcycles andthe second dimension contains the arrays of y values which correspond to the x values andwill be used for integration. The shape of this is (bootcycles, len(x)).

• x_intp (np.array, optional, default=None) – An array which finely interpolates the xvalues. If not provided, it will be generated by adding 100 evenly spaced points betweeneach x value. Default: None.

• matrix (str, optional, default='full`) – If full, the mean and SEM in-tegration is computed between x values. If diagonal, the mean and SEM integration iscomputed between the first value and all other values, as well as the neighboring values toeach value. If endpoints, the integration is computed between only the first and last xvalue.

Returns

• avg_matrix (np.array) – Matrix of the integration mean between each x value (as spec-ified by ‘matrix’)

• sem_matrix (np.array) – Matrix of the uncertainty (SEM) between each x value (asspecified by ‘matrix’)

5.11.3 Dummy Atoms API

paprika.build.dummy.add_dummy(structure, atom_name='DUM', residue_name='DUM',mass=208.0, atomic_number=82, x=0.0, y=0.0, z=0.0)

Add a dummy atom at the specified coordinates to the end of a structure.

Parameters

• structure (str or parmed.Structure) – The structure to be modified

• atom_name (str, optional, default='DUM') – The name of the dummy atom.

• residue_name (str, optional, default='DUM') – The residue name of thedummy atom.

• mass (float, optional, default=208.0) – The mass of the dummy atom.

• atomic_number (int, optional, default=82) – The element of the dummyatom.

• x (float, optional, default=0.0) – The x coordinate of the dummy atom.

• y (float, optional, default=0.0) – The y coordinate of the dummy atom.

• z (float, optional, default=0.0) – The z coordinate of the dummy atom.

Returns structure – The modified structure with dummy atoms added.

Return type parmed.Structure

paprika.build.dummy.write_dummy_frcmod(atom_type='Du', mass='208.00', path='./', file-name='dummy.frcmod', filepath=None)

Write a frcmod file for dummy atoms.

Parameters

5.11. API 117

Page 122: pAPRika Documentation

pAPRika Documentation

• atom_type (str, optional, default='Du') – The atom type of the dummyatom.

• mass (str, optional, default=208.00) – The mass of the dummy atom.

• path (str, optional, default='./) – The directory of the output file, if filepathis not specified.

• filename (str, optional, default='dummy.frcmod`) – The name of theoutput file, if filepath is not specified.

• filepath (str, optional, default=None) – The full path (directory and file)of the output.

paprika.build.dummy.write_dummy_mol2(atom_name='DUM', atom_type='Du',residue_name='DUM', path='./', file-name='dummy.mol2', filepath=None)

Write a mol2 file for dummy atoms.

Parameters

• atom_name (str, optional, default='DUM') – The atom name of the dummyatoms.

• atom_type (str, optional, default='Du') – The atom type of the dummyatoms.

• residue_name (str, optional, default='DUM') – The residue name of thedummy atoms.

• path (str, optional, default='./') – The directory of the output file, iffilepath is not specified.

• filename (str, optional, default='dummy.mol2') – The name of the out-put file, if filepath is not specified.

• filepath (str, optional, default=None) – The full path (directory and file)of the output.

paprika.build.dummy.extract_dummy_atoms(structure, resname=None, serial=True)Extract information about dummy atoms from a parmed structure and returns the information as a dictionary.

Parameters

• structure (parmed.Structure) – The parmed structure object we want to extractfrom

• resname (list) – List of residue name for the dummy atoms (default: [“DM1”, “DM2”,“DM3”])

• serial (bool) – get indices in serial (starts from 1) or index (starts from 0)

Returns dummy_atoms – A dictionary containing positions (pos), index (idx) and mass (mass)of dummy atoms.

Return type dict

118 Chapter 5. References

Page 123: pAPRika Documentation

pAPRika Documentation

5.11.4 Evaluator API

Analysis

This class contains a simulation analysis wrapper for use with the OpenFF Evaluator.

class paprika.evaluator.analyze.AnalyzeBases: object

The Analyze class provides a wrapper function around the analysis of simulations.

classmethod compute_phase_free_energy(phase: str, restraints:List[paprika.restraints.restraints.DAT_restraint],windows_directory: str, topology_name: str,trajectory_mask: str = '*.dcd', bootstrap_cycles:int = 1000, analysis_method: str = 'ti-block')→ Dict[str, Any]

Computes the free energy of a specified phase of an APR calculation.

Parameters

• phase – The phase to analyze. This should be one of 'attach', 'pull' or'release'.

• restraints – A list of the restraints which were used as part of the phase being anal-ysed.

• windows_directory – The directory which contains the final trajectories and topolo-gies from the simulated phase.

• topology_name – The expected file name (not path) of the coordinate file which con-tains topological information about the system.

• trajectory_mask – The pattern to use when searching for the simulated trajectories.

• bootstrap_cycles – The number of bootstrap iterations to perform.

• analysis_method – The analysis method to use.

Returns

Return type The computed free energies (and their uncertainties) in units of kcal / mol

classmethod compute_ref_state_work(temperature: float, guest_restraints:List[paprika.restraints.restraints.DAT_restraint])→ float

Computes the reference state work of the attach phase.

Parameters

• temperature – The temperature at which the calculation was performed in units ofkelvin.

• guest_restraints – The guest restraints which were applied during the pull phase.

Returns

Return type The reference state work in units of kcal / mol.

classmethod symmetry_correction(n_microstates: int, temperature: float)→ floatComputes the free energy corrections to apply to symmetrical guest when the guest is restrained to justone of several possible symmetrical configurations (e.g. butane restrained in a cyclic host).

Parameters

5.11. API 119

Page 124: pAPRika Documentation

pAPRika Documentation

• temperature – The temperature at which the calculation was performed in units ofkelvin.

• n_microstates – The number of different symmetrical microstates that the guest canexist in (e.g. for butane this is two).

Returns

Return type The symmetry correction to apply in units of kcal / mol.

Setup

This class contains a simulation setup wrapper for use with the OpenFF Evaluator.

class paprika.evaluator.setup.SetupBases: object

The Setup class provides a wrapper function around the preparation of the host-guest system and the applica-tion of restraints.

classmethod prepare_host_structure(coordinate_path: str, host_atom_indices:Optional[List[int]] = None) →parmed.structure.Structure

Prepares the coordinates of a host molecule ready for the release phase of an APR calculation. Thiscurrently involves aligning the cavity of the host along the z-axis, and positioning the host so that its centerof geometry at (0, 0, 0).

Notes

The hosts cavity axis is for now determined as the vector orthogonal to the two largest principal compo-nents of the host.

Parameters

• coordinate_path – The path to the coordinate file which contains the host molecule.

• host_atom_indices – The (0-based) indices of the host atoms in the coordinate fileif the file. This may be used if the coordinate file contains more than a single molecule.

Returns

• A ParmEd structure which contains only the aligned and centered host.

• If host_atom_indices are provided, the structure will contain only

• the referenced host atoms.

classmethod prepare_complex_structure(coordinate_path: str, guest_atom_indices:List[int], guest_orientation_mask: str,pull_distance: float, pull_window_index:int, n_pull_windows: int) →parmed.structure.Structure

Prepares the coordinates of a host molecule ready for the pull (+ attach) phase of an APR calculation.

This currently involves aligning the complex so that the guest molecule (or rather, the guest atomsspecified by guest_orientation_mask) is aligned with the z-axis, and the first atom specified byguest_orientation_mask is positioned at (0, 0, 0).

Parameters

120 Chapter 5. References

Page 125: pAPRika Documentation

pAPRika Documentation

• coordinate_path – The path to the coordinate file which contains the guest moleculebound to the host.

• guest_atom_indices – The (0-based) indices of the atoms in the coordinate filewhich correspond to the guest molecule.

• guest_orientation_mask – The string mask which describes which guest atomswill be restrained to keep the molecule aligned to the z-axis and at a specific distance fromthe host. This should be of the form ‘X Y’ where X Y are ParmEd selectors for the twoguest atoms to restrain relative to the dummy atoms.

• pull_distance – The total distance that the guest will be pulled along the z-axis dur-ing the pull phase in units of Angstroms.

• pull_window_index – The index of the window to prepare coordinates for.This determines the distance to place the guest from the host in the returnedstructure. An index of zero corresponds to the guest in its initial position,while an index = n_pull_windows - `` corresponds to the guestpositioned a distance of ``pull_distance away from the host.

• n_pull_windows – The total number of pull windows being used in the calculation.This will determine the distance to move the guest at each window.

Returns

• A ParmEd structure which contains the aligned and positioned host and

• guest molecules.

static add_dummy_atoms_to_structure(structure: parmed.structure.Structure,dummy_atom_offsets: List[numpy.ndarray],offset_coordinates: Optional[numpy.ndarray] =None)

A convenience method to add a number of dummy atoms to an existing ParmEd structure, and to positionthose atoms at a specified set of positions.

Parameters

• structure – The structure to add the dummy atoms to.

• dummy_atom_offsets – The list of positions (defined by a 3-d numpy array) of thedummy atoms to add.

• offset_coordinates – An optional amount to offset each of the dummy atom posi-tions by with shape=(3,).

classmethod build_static_restraints(coordinate_path: str, n_attach_windows: Op-tional[int], n_pull_windows: Optional[int],n_release_windows: Optional[int], re-straint_schemas: List[Dict[str, Any]],use_amber_indices: bool = False) →List[paprika.restraints.restraints.DAT_restraint]

A method to convert a set of static restraints defined by their ‘schemas’ into corresponding``DAT_restraint``objects.

Each ‘schema’ should be a dictionary with:

• an atoms entry with a value of the atom selection make which specifies which atoms the restraintwill apply to

• a force_constant entry which specifies the force constant of the restraint.

5.11. API 121

Page 126: pAPRika Documentation

pAPRika Documentation

These ‘schemas` map directly to the ‘restraints -> static -> restraint’ dictionaries specified in the taproomhost YAML files.

Parameters

• coordinate_path – The path to the coordinate file which the restraints will be appliedto. This should contain either the host or the complex, the dummy atoms and and solvent.

• n_attach_windows – The total number of attach windows being used in the APRcalculation.

• n_pull_windows – The total number of pull windows being used in the APR calcula-tion.

• n_release_windows – The total number of release windows being used in the APRcalculation.

• restraint_schemas – The list of dictionaries which provide the settings to use foreach static restraint to add.

• use_amber_indices – Whether to use amber based (i.e. starting from 1) restraintindices or OpenMM based (i.e. starting from 0) indices.

Returns

Return type The constructed static restraint objects.

classmethod build_conformational_restraints(coordinate_path: str, attach_lambdas:Optional[List[float]], n_pull_windows:Optional[int], release_lambdas:Optional[List[float]], re-straint_schemas: List[Dict[str, Any]],use_amber_indices: bool = False) →List[paprika.restraints.restraints.DAT_restraint]

A method to convert a set of conformational restraints defined by their ‘schemas’ into corresponding``DAT_restraint``objects.

Each ‘schema’ should be a dictionary with:

• an atoms entry with a value of the atom selection make which specifies which atoms the restraintwill apply to

• a force_constant entry which specifies the force constant of the restraint.

• a target entry which specifies the target value of the restraint.

These ‘schemas` map directly to the ‘restraints -> conformational -> restraint’ dictionaries specified in thetaproom host YAML files.

Parameters

• coordinate_path – The path to the coordinate file which the restraints will be appliedto. This should contain either the host or the complex, the dummy atoms and and solvent.

• attach_lambdas – The values ‘lambda’ being used during the attach phase of the APRcalculation.

• n_pull_windows – The total number of pull windows being used in the APR calcula-tion.

• release_lambdas – The values ‘lambda’ being used during the release phase of theAPR calculation.

• restraint_schemas – The list of dictionaries which provide the settings to use foreach conformational restraint to add.

122 Chapter 5. References

Page 127: pAPRika Documentation

pAPRika Documentation

• use_amber_indices – Whether to use amber based (i.e. starting from 1) restraintindices or OpenMM based (i.e. starting from 0) indices.

Returns

Return type The constructed conformational restraint objects.

classmethod build_symmetry_restraints(coordinate_path: str, n_attach_windows:int, restraint_schemas: List[Dict[str, Any]],use_amber_indices: bool = False) →List[paprika.restraints.restraints.DAT_restraint]

A method to convert a set of symmetry restraints defined by their ‘schemas’ into corresponding``DAT_restraint``objects.

Each ‘schema’ should be a dictionary with:

• an atoms entry with a value of the atom selection make which specifies which atoms the restraintwill apply to

• a force_constant entry which specifies the force constant of the restraint.

These ‘schemas` map directly to the ‘restraints -> symmetry_correction -> restraint’ dictionaries specifiedin the taproom guest YAML files.

Parameters

• coordinate_path – The path to the coordinate file which the restraints will be appliedto. This should contain either the host or the complex, the dummy atoms and and solvent.

• n_attach_windows – The total number of attach windows being used in the APRcalculation.

• restraint_schemas – The list of dictionaries which provide the settings to use foreach symmetry restraint to add.

• use_amber_indices – Whether to use amber based (i.e. starting from 1) restraintindices or OpenMM based (i.e. starting from 0) indices.

Returns

Return type The constructed symmetry restraint objects.

classmethod build_wall_restraints(coordinate_path: str, n_attach_windows:int, restraint_schemas: List[Dict[str, Any]],use_amber_indices: bool = False) →List[paprika.restraints.restraints.DAT_restraint]

A method to convert a set of wall restraints defined by their ‘schemas’ into corresponding``DAT_restraint``objects.

Each ‘schema’ should be a dictionary with:

• an atoms entry with a value of the atom selection make which specifies which atoms the restraintwill apply to

• a force_constant entry which specifies the force constant of the restraint.

• a target entry which specifies the target value of the restraint.

These ‘schemas` map directly to the ‘restraints -> wall_restraints -> restraint’ dictionaries specified in thetaproom guest YAML files.

Parameters

• coordinate_path – The path to the coordinate file which the restraints will be appliedto. This should contain either the host or the complex, the dummy atoms and and solvent.

5.11. API 123

Page 128: pAPRika Documentation

pAPRika Documentation

• n_attach_windows – The total number of attach windows being used in the APRcalculation.

• restraint_schemas – The list of dictionaries which provide the settings to use foreach wall restraint to add.

• use_amber_indices – Whether to use amber based (i.e. starting from 1) restraintindices or OpenMM based (i.e. starting from 0) indices.

Returns

Return type The constructed wall restraint objects.

classmethod build_guest_restraints(coordinate_path: str, attach_lambdas:List[float], n_pull_windows: Optional[int],restraint_schemas: List[Dict[str, Any]],use_amber_indices: bool = False) →List[paprika.restraints.restraints.DAT_restraint]

A method to convert a set of guest restraints defined by their ‘schemas’ into corresponding``DAT_restraint``objects.

Each ‘schema’ should be a dictionary with:

• an atoms entry with a value of the atom selection make which specifies which atoms the restraintwill apply to

and additionally a nested attach and pull dictionary with

• a force_constant entry which specifies the force constant of the restraint.

• a target entry which specifies the target value of the restraint.

These ‘schemas` map directly to the ‘restraints -> guest -> restraint’ dictionaries specified in the taproomguest YAML files.

Parameters

• coordinate_path – The path to the coordinate file which the restraints will be appliedto. This should contain either the host or the complex, the dummy atoms and and solvent.

• attach_lambdas – The values ‘lambda’ being used during the attach phase of the APRcalculation.

• n_pull_windows – The total number of pull windows being used in the APR calcula-tion.

• restraint_schemas – The list of dictionaries which provide the settings to use foreach wall restraint to add.

• use_amber_indices – Whether to use amber based (i.e. starting from 1) restraintindices or OpenMM based (i.e. starting from 0) indices.

Returns

Return type The constructed wall restraint objects.

124 Chapter 5. References

Page 129: pAPRika Documentation

pAPRika Documentation

GAFF

Functions for generate GAFF files and parameters.

paprika.evaluator.amber.generate_gaff(mol2_file: str, residue_name: str, output_name:Optional[str] = None, need_gaff_atom_types:Optional[bool] = True, generate_frcmod: Op-tional[bool] = True, directory_path: Optional[str] ='benchmarks', gaff_version: Optional[str] = 'gaff2')

Module to generate GAFF files given a mol2 file.

Parameters

• mol2_file – The name of the mol2 structure file.

• residue_name – The residue name of the molecule.

• output_name – The name for the output file.

• need_gaff_atom_types – Whether to generate GAFF atoms or not. Currently, this isthe only choice.

• gaff_version – The GAFF version to use (“gaff1”, “gaff2”)

• generate_frcmod – Option to generate a GAFF frcmod file.

• directory_path – The working directory where the files will be stored.

Utils

paprika.evaluator.utils.get_benchmarks()Determine the installed taproom benchmarks.

5.11.5 Restraints API

DAT Restraints

class paprika.restraints.restraints.DAT_restraintBases: object

Distance or angle or torsion restraints on atoms in the simulation.

property topologyThe topology file used to initialize the restraints. This can be a PDB file parsed as string or a parmed.Structure object.

Type str or parmed.Structure

property mask1The first atom mask used for the restraint.

Type str

property mask2The second atom mask used for the restraint.

Type str

property mask3The third atom mask used for the restraint. Two atom masks are the minimum requirement to use thisclass.

5.11. API 125

Page 130: pAPRika Documentation

pAPRika Documentation

Type str

property mask4The fourth atom mask used for the restraint. Two atom masks are the minimum requirement to use thisclass.

Type str

property custom_restraint_valuesIn the case a non-harmonic restraint is desired, the pre-calculated values (r1, r2, and so on) can beoverridden with ones from this dictionary. These values will be directly written to the AMBER restraintfile, so the keys must be valid AMBER keywords.

Specifically, for target distance, R:

• R < r1 Linear, with the slope of the “left-hand” parabola at the point R = r1.

• r1 <= R < r2 Parabolic, with restraint energy k2(R r2)2.

• r2 <= R < r3 -> E = 0.

• r3 <= R < r4 Parabolic, with restraint energy k3(R r3)2.

• r4 <= R Linear, with the slope of the “right-hand” parabola at the point R = r4.

In the case of AMBER18, this is covered in section 25.1 of the manual.

For example, a flat bottom restraint can be specified by setting r2 not equal to r3.

>>> from paprika.restraints import DAT_restraint>>> this = DAT_restraint>>> this.custom_restraint_values["r2"] = 0.0>>> this.custom_restraint_values["r3"] = 12.0

The values in this dictionary use default AMBER units for distances and force constants.

This attribute has no effect for OpenMM.

Type dict

property auto_aprIf True, (1) the force constant during the pulling phase will be set to the final force constant from theattach phase, and (2) the initial target during the pulling phase will be equal to the final target from theattach phase. If False, these values must be set manually.

Type bool

property continuous_aprIf True, (1) the final window of the attach phase is used as the first window of the pull phase, and (2) thefinal window of the pull phase is used as the first window of the release phase.

Type bool

property attachDictionary specifying the APR parameters during the attach phase. The dictionary keys are as follows:

• target : The target value for the restraint (mandatory)

• fc_initial : The initial force constant (optional)

• fc_final : The final force constant (optional)

• num_windows : The number of windows (optional)

• fc_increment : The force constant increment (optional)

126 Chapter 5. References

Page 131: pAPRika Documentation

pAPRika Documentation

• fraction_increment : The percentage of the force constant increment (optional)

• fraction_list : The list of force constant percentages (optional)

• fc_list : The list of force constants (will be created if not given)

Note: This is fragile and this could be hardened by making these ENUM and doing much more type-checking.

Type dict

property pullDictionary specifying the APR parameters during the pull phase. The dictionary keys are as follows:

• fc : The force constant for the restraint (mandatory)

• target_initial : The initial target value (optional)

• target_final : The final target value (optional)

• num_windows : The number of windows (optional)

• target_increment : The target value increment (optional)

• fraction_increment : The percentage of the target value increment (optional)

• fraction_list : The list of target value percentages (optional)

• target_list : The list of target values (will be created if not given)

Note: This is fragile and this could be hardened by making these ENUM and doing much more type-checking.

Type dict

property releaseDictionary specifying the APR parameters during the release phase. The dictionary keys are as follows:

• target : The target value for the restraint (mandatory)

• fc_initial : The initial force constant (optional)

• fc_final : The final force constant (optional)

• num_windows : The number of windows (optional)

• fc_increment : The force constant increment (optional)

• fraction_increment : The percentage of the force constant increment (optional)

• fraction_list : The list of force constant percentages (optional)

• fc_list : The list of force constants (will be created if not given)

Note: This is fragile and this could be hardened by making these ENUM and doing much more type-checking.

Type dict

5.11. API 127

Page 132: pAPRika Documentation

pAPRika Documentation

property amber_indexIf True, atom indices starts at 1 instead of 0.

Type bool

instances = []

initialize()Automatically set remaining force constants and targets.

Depending on which values are provided for each phase, a different method will be used to determine thelist of force constants and targets (below).

For attach and release, a target value is required and the method is determined if the following valuesare not None:

• Method 1 : num_windows, fc_initial, fc_final

• Method 1a: num_windows, fc_final

• Method 2 : fc_increment, fc_initial, fc_final

• Method 2a: fc_increment, fc_final

• Method 3 : fraction_list, fc_final

• Method 4 : fraction_increment, fc_final

• Method 5 : fc_list

For pull, a fc value is required and the method is determined if the following values are not None:

• Method 1: num_windows, target_initial, target_final

• Method 1a: num_windows, target_final

• Method 2: target_increment, target_initial, target_final

• Method 2a: target_increment, target_final

• Method 3: fraction_list, target_final

• Method 4: fraction_increment, target_final

• Method 5: target_list

Note: This is unnecessary overengineering.

paprika.restraints.restraints.static_DAT_restraint(restraint_mask_list,num_window_list, ref_structure,force_constant, contin-uous_apr=True, am-ber_index=False)

Create a restraint whose value does not change during a calculation.

Parameters

• restraint_mask_list (list) – A list of masks for which this restraint applies.

• num_window_list (list) – A list of windows during which this restraint will be ap-plied, which should be in the form: [attach windows, pull windows, release windows].

• ref_structure (os.PathLike or parmed.Structure) – The reference structure thatis used to determine the initial, static value for this restraint.

• force_constant (float) – The force constant for this restraint.

128 Chapter 5. References

Page 133: pAPRika Documentation

pAPRika Documentation

• continuous_apr (bool, optional) – Whether this restraint usescontinuous_apr. This must be consistent with existing restraints.

• amber_index (bool, optional) – Whether the atom indices for the restraint shouldbe AMBER-style (starts at 1) or not.

Returns rest – A static restraint.

Return type paprika.restraints.DAT_restraint

paprika.restraints.restraints.check_restraints(restraint_list, cre-ate_window_list=False)

Do basic tests to ensure a list of ``DAT_restraint``s are consistent. This function is also overloaded to createwindow lists as well, which is not ideal.

Parameters

• restraint_list (list) – A list of restraints.

• create_window_list (bool, optional, default=False) – Whether to usethe restraints to create windows for the calculation.

paprika.restraints.restraints.create_window_list(restraint_list)Create list of APR windows. Runs everything through check_restraints because we need to do that.

AMBER Restraints

paprika.restraints.amber.amber_restraint_line(restraint, window)Writes an AMBER NMR-style restraint line for a specific window.

Parameters

• restraint (paprika.restraints.DAT_restraint) – The pAPRika restraint tobe used.

• window (str) – The calculation window that will be used to index the restraint values.

Returns string – A string that can be written to a file that can be read by AMBER.

Return type str

Examples

&rst iat= 3,109, r1= 0.0000, r2= 6.9665, r3= 6.9665, r4= 999.0000,rk2= 5.0000000, rk3= 5.0000000, &end

Or:

&rst iat= -1,-1, igr1=3,4,7,8,21,22,25,26,39,40,43,44,57,58,61,62,75,76,79,80,93,94,97,98, igr2=109,113,115,119,r1= 0.0000, r2= 5.9665, r3= 5.9665, r4= 999.0000,rk2= 5.0000000, rk3= 5.0000000, &end

5.11. API 129

Page 134: pAPRika Documentation

pAPRika Documentation

OpenMM Restraints

A module aimed at applying restraints directly to OpenMM systems.

paprika.restraints.openmm.apply_positional_restraints(coordinate_path: str, system,force_group: int = 15)

A utility function which will add OpenMM harmonic positional restraints to any dummy atoms found within asystem to restrain them to their initial positions.

Parameters

• coordinate_path (str) – The path to the coordinate file which the restraints will beapplied to. This should contain either the host or the complex, the dummy atoms and andsolvent.

• system (openmm.System) – The system object to add the positional restraints to.

• force_group (int, optional) – The force group to add the positional restraints to.

paprika.restraints.openmm.apply_dat_restraint(system, restraint, phase, window_number,flat_bottom=False, force_group=None)

A utility function which takes in pAPRika restraints and applies the restraints to an OpenMM System object.

Parameters

• system (openmm.System) – The system object to add the positional restraints to.

• restraint (list) – List of pAPRika defined restraints

• phase (str) – Phase of calculation (“attach”, “pull” or “release”)

• window_number (int) – The corresponding window number of the current phase

• flat_bottom (bool, optional) – Specify whether the restraint is a flat bottom po-tential

• force_group (int, optional) – The force group to add the positional restraints to.

Plumed Module

class paprika.restraints.plumed.PlumedBases: object

This class converts restraints generated in pAPRika paprika.restraints.DAT_restraint into Plumedrestraints.

Note: The Plumed module is described in the reference below and the source code is available on Githubhttps://github.com/plumed/plumed2

The PLUMED consortium. Promoting transparency and reproducibility in enhanced molecular simulations,Nat. Methods 16, 670 (2019)

Todo: possibly change this module to use the python wrapper of Plumed.

130 Chapter 5. References

Page 135: pAPRika Documentation

pAPRika Documentation

Examples

>>> plumed = Plumed()>>> plumed.file_name = 'plumed.dat'>>> plumed.path = './windows'>>> plumed.window_list = window_list>>> plumed.restraint_list = restraint_list>>> plumed.dump_to_file()

The commands above will write the restraints to windows/*/plumed.dat and contains the Plumed-stylerestraints

UNITS LENGTH=A ENERGY=kcal/mol TIME=ns# Collective variablesc1 : DISTANCE ATOMS=175,150 NOPBCc2 : ANGLE ATOMS=176,175,150 NOPBCc3 : ANGLE ATOMS=175,150,165 NOPBC# Bias potentialRESTRAINT ARG=c7 AT= 6.000 KAPPA= 10.00RESTRAINT ARG=c8 AT= 3.142 KAPPA= 200.00RESTRAINT ARG=c9 AT= 3.142 KAPPA= 200.00

The positional restraints on dummy atoms, however, is not added automatically. This restraints on the dummyatoms can be added to windows/*/plumed.dat using the code below.

>>> for window in window_list:>>> structure = pmd.load_file("topology.prmtop", "coordinates.rst7")>>> plumed.add_dummy_atoms_to_file(structure, window)

This appends the file with the following

# Dummy Atomsdm1: POSITION ATOM=123 NOPBCdm2: POSITION ATOM=124 NOPBCdm3: POSITION ATOM=125 NOPBCRESTRAINT ...ARG=dm1.x,dm1.y,dm1.z,dm2.x,dm2.y,dm2.z,dm3.x,dm3.y,dm3.z,AT=18.600,19.020,27.950,18.600,19.020,24.950,18.600,21.220,22.750,KAPPA=100.0,100.0,100.0,100.0,100.0,100.0,100.0,100.0,100.0,LABEL=dummy... RESTRAINT

property pathThe parent directory that contains the APR simulation windows.

Type os.PathLike

property file_nameThe Plumed file name where the restraints will be written to.

Type str

property window_listThe list of APR windows where the Plumed files will be stored.

Type list

property restraint_listThe list of restraints to convert.

5.11. API 131

Page 136: pAPRika Documentation

pAPRika Documentation

Type list

property uses_legacy_kOption to specify whether the force constant parsed into DAT_restraint uses legacy force constant.

Note: AMBER-style force constants have their value multiplied by a factor of 1/2 whereas GRO-MACS/NAMD-style do not. Plumed follows the GROMACS/NAMD-style convention for the force constantand the equations below demonstrates this point.

𝑈𝐴𝑚𝑏𝑒𝑟 = 𝐾(𝑥− 𝑥0)2𝑈𝑃𝑙𝑢𝑚𝑒𝑑=1

2𝑘(𝑥− 𝑥0)2 ∴ 𝐾𝐴𝑚𝑏𝑒𝑟 =

1

2𝑘𝑃𝑙𝑢𝑚𝑒𝑑 (5.7)

𝑖.𝑒.uses_legacy_k𝑖𝑠𝑠𝑒𝑡𝑡𝑜𝑇𝑟𝑢𝑒(𝑑𝑒𝑓𝑎𝑢𝑙𝑡)𝑡ℎ𝑒𝑓𝑜𝑟𝑐𝑒𝑐𝑜𝑛𝑠𝑡𝑎𝑛𝑡𝑠𝑤𝑖𝑙𝑙𝑏𝑒𝑚𝑢𝑙𝑡𝑖𝑝𝑙𝑖𝑒𝑑𝑏𝑦2.

Type bool

property unitsDictionary of units for Plumed as strings. The dictionary requires the key values of energy, length, time.

Type dict

dump_to_file()Write the Plumed-style restraints to file.

add_dummy_atom_restraints(structure, window, path=None)Add positional restraints on dummy atoms to the restraint files.

Parameters

• structure (os.PathLike or parmed.Structure) – The reference structure that is used todetermine the absolute coordinate of the dummy atoms.

• window (str) – APR window where the structure is stored for extracting the dummy atompositions.

• path (os.PathLike, optional, default=None) – Path of the restraint file. If set toNone (default) self.path will be used.

Colvars Module

class paprika.restraints.colvars.ColvarsBases: paprika.restraints.plumed.Plumed

This class converts restraints generated with paprika.restraints.DAT_restraints into collectivevariables (Colvars) restraints that is available as a plugin in NAMD and LAMMPS.

Note: The Colvars module is described in the reference below and the source code is available on Githubhttps://github.com/Colvars/colvars

Fiorin, G., Klein, M. L. & Hénin, J. Using collective variables to drive molecular dynamics simulations. Mol.Phys. 111, 3345–3362 (2013).

132 Chapter 5. References

Page 137: pAPRika Documentation

pAPRika Documentation

Examples

>>> colvars = Colvars()>>> colvars.file_name = 'colvars.tcl'>>> colvars.path = './windows'>>> colvars.window_list = window_list>>> colvars.restraint_list = restraint_file>>> colvars.dump_to_file()

The commands above will write the restraints to windows/*/colvars.tcl and contains the Colvars-stylerestraints

ColvarsTrajFrequency 500ColvarsRestartFrequency 50000# Collective variablescolvar {name c1distance {

forceNoPBC yesgroup1 { atomNumbers 123 }group2 { atomNumbers 1 }

}}# Bias potentialsharmonic {colvars c1centers 6.0forceConstant 10.0000

}

The positional restraints on dummy atoms, however, is not added automatically. This restraints on the dummyatoms can be added to windows/*/colvars.tcl using the code below.

>>> for window in window_list:>>> structure = pmd.load_file("topology.prmtop", "coordinates.rst7")>>> colvars.add_dummy_atoms_to_file(structure, window)

This appends the file with the following

# Dummy atom position restraintscolvar {name dummyAtomscartesian {

atoms { atomNumbers 123 124 125 }}

}harmonic {colvars dummyAtomscenters ( 0.0, 0.0, -6.0, 0.0, 0.0, -9.0, 0.0, 2.2, -11.2 )forceConstant 100.00

}

property units_from_DATDictionary of units used in the definition of paprika.restraints.DAT_restraints. We have toresort to strings until pAPRika uses Pint units. The dictionary requires the key values of:

• distance (default: Angstrom)

• angle (default: radians)

5.11. API 133

Page 138: pAPRika Documentation

pAPRika Documentation

• k_distance (default: kcal/mol/A^2)

• k_angle (default: kcal/mol/rad^2)

Type dict

property output_freqThe frequency at which the colvars will be printed to *.colvars.traj file.

Type int

dump_to_file()Write the Colvars-style restraints to file.

Utility Modules

paprika.restraints.read_yaml.read_yaml(file)Read Taproom -style YAML-formatted instructions for preparing host-guest systems.

Parameters file (os.PathLike) – A YAML-formatted file.

Returns yaml_data – Dictionary containing simulation setup parameters.

Return type dict

paprika.restraints.read_yaml.multiple_replace(dct, text)Create a regular expression to do multiple find and replace.

paprika.restraints.read_yaml.de_alias(yaml_data)Replace aliased atoms in a taproom recipe.

paprika.restraints.utils.parse_window(window)Utility function to use a path to index a paprika.restraints.DAT_restraint instance.

Parameters window (str) – A string representation of a particular simulation window

Returns

• window_number (int) – The window number.

• phase (str) – The calculation phase.

paprika.restraints.utils.get_restraint_values(restraint, phase, window_number)Extract the values of the restraints (Amber NMR-style) including positions and force constants. See the Amberdocumentation for further explanation on the NMR-style values.

Parameters

• restraint (paprika.restraints.DAT_restraint) – Restraint object to extractthe information from

• phase (str) – Current phase of the window.

• window_number (int) – Current window number.

Returns restraint_values – Dictionary containing the Amber NMR-style values

Return type dict

paprika.restraints.utils.get_bias_potential_type(restraint, phase, window_number)Function to determine the bias potential type for a particular restraint. The possible types of biases are:restraint, upper_walls and lower_walls.

Parameters

134 Chapter 5. References

Page 139: pAPRika Documentation

pAPRika Documentation

• restraint (paprika.restraints.DAT_restraint) – The restraint to extractinformation from

• phase (str) – Current phase of the window

• window_number (int) – Current window number.

Returns bias_type – type of bias potential

Return type str

paprika.restraints.utils.extract_guest_restraints(structure, restraints, guest_resname,dummy_prefix='DM')

Utility function to extract the guest restraints from a list of restraints and return individual restraints in the form[r, theta, phi, alpha, beta, gamma].

If there is no restraint applied to a particular reaction coordinate a None will be inserted.

This function is useful for parsing guest restraints during analysis when computing ref_state_work.

Parameters

• structure (parmed.Structure) – The molecular structure of the system.

• restraints (list) – List of paprika.restraints.DAT_restraint restraints.

• guest_resname (str) – Residue name of the guest molecule.

• dummy_prefix (str, optional, default="DM") – The prefix for the dummyatoms residue name.

Returns guest_restraints – list of guest-specific paprika.restraints.DAT_restraintrestraints.

Return type list

Examples

Extract guest restraints from a list of restraints and compute the work for reference state

>>> guest_restraints = extract_guest_restraints(structure, restraints, "BEN")>>>>>> free_energy = analysis.fe_calc()>>> free_energy.compute_ref_state_work(guest_restraints)>>> print(free_energy["ref_state_work"])

paprika.restraints.utils.restraints_from_ascii(filename)Utility function to read in restraints from a simple ASCII file. This is useful for using VMD to define restraints.Since you can mouse-click bonds, angles and dihedrals in VMD it can be faster to define these restraints. Onescenario for this is when you want to apply conformational restraints on a host molecule based on a number ofdistance, angle and torsional restraints.

The TCL script below is an example of extracting bonds selected in VMD to a file with a comma-separatedformat.

set kbond 10.0set f [open "bond.dat" w]

foreach bond [label list Bonds] {# Bond atom indicesset i1 [lindex [split [lindex $bond 0]] 1]

(continues on next page)

5.11. API 135

Page 140: pAPRika Documentation

pAPRika Documentation

(continued from previous page)

set i2 [lindex [split [lindex $bond 1]] 1]

# Bond atom namesset a1 [[atomselect top "index $i1"] get name]set a2 [[atomselect top "index $i2"] get name]

# Bond atom residset r1 [[atomselect top "index $i1"] get resname]set r2 [[atomselect top "index $i2"] get resname]

# Bond valueset dr [lindex [split [lindex $bond 2]] 1]

# Print atom namesputs $f ":${r1}@${a1},:${r2}@${a2},$dr,$kbond"

}close $f

The output from the TCL script sourced in VMD may look like

:1@C12,:2@C4,12.5,5.0:1@O11,:1@C2,:1@C3,90.0,50.0:1@C12,:1@O13,:1@C14,1@C15,-121.16,6.0

Parameters filename (os.PathLike) – File name of template file.

Returns restraints – A dictionary of restraints containing information of the atoms, target andspring constant.

Return type dict

5.11.6 Simulation Wrappers API

Base Simulation Class

class paprika.simulate.simulation.SimulationBases: object

Base class for a Molecular Dynamics simulation wrapper.

class Ensemble(value)Bases: enum.Enum

An enumeration of the different thermodynamic ensembles.

NVE = 'NVE'

NVT = 'NVT'

NPT = 'NPT'

property pathThe path for the creation and execution of files for this protocol.

Type os.PathLike

property executableThe Molecular Dynamics executable that will be used.

136 Chapter 5. References

Page 141: pAPRika Documentation

pAPRika Documentation

Note: This could be made safer by making an ENUM of sander, pmemd and pmemd.cuda.

Type str

property n_threadsNumber of threads to use for the simulation.

Type int

property gpu_devicesA wrapper around the environmental variable CUDA_VISIBLE_DEVICES.

Type int or str

property plumed_fileThe name of the Plumed-style restraints file.

Note: When running simulations with a MD engine that supports Plumed and other restraint module(s),you can only use one or the other. If both are specified, an Exception will be thrown.

Type os.PathLike

property plumed_kernel_libraryThe file path of the Plumed kernel library if it is different from the default. The default name islibplumedKernel with its extension determined automatically depending on the operating systemand is located in os.environ['CONDA_PREFIX']/lib. This variable is useful for users who didnot install or want to use Plumed from the conda repository.

Type os.PathLike

property topologyThe topology file to simulate.

Type os.PathLike

property coordinatesThe coordinates of the MD system.

Type os.PathLike

property prefixThe prefix for file names generated from this simulation.

property phaseWhich phase of the calculation to simulate.

Note: This could probably be combined with the window attribute for simplicity.

Type str

property windowWhich window of the calculation to simulate.

Type str

5.11. API 137

Page 142: pAPRika Documentation

pAPRika Documentation

property temperatureDesired temperature of the system (Kelvin). Default is 298.15 K.

Type float

property pressureDesired pressure of the system (bar). Default is 1.01325 bar.

Type float

property thermostatDictionary for the thermostat options.

Type dict

property barostatDictionary for the barostat options.

Type dict

property convergedWhether the simulation is converged.

Warning: This is just a placeholder and is not implemented yet.

Type bool

config_gb_min()Place holder function.

config_gb_md()Place holder function.

config_pbc_min()Place holder function.

config_pbc_md()Place holder function.

run()Place holder function.

check_complete()Place holder function.

check_converged()Place holder function

AMBER Simulation Wrapper

class paprika.simulate.amber.AMBERBases: paprika.simulate.simulation.Simulation, abc.ABC

A wrapper for setting parameters and running MD with AMBER.

class Thermostat(value)Bases: enum.Enum

An enumeration of the different thermostat implemented in AMBER (option for ntt).

Off = 0

138 Chapter 5. References

Page 143: pAPRika Documentation

pAPRika Documentation

Berendsen = 1

Andersen = 2

Langevin = 3

OptimizedIsoNoseHoover = 9

StochasticIsoNoseHoover = 10

Bussi = 11

class Barostat(value)Bases: enum.Enum

An enumeration of the different barostat implemented in AMBER (option for barostat).

Off = 0

Berendsen = 1

MonteCarlo = 2

class GBModel(value)Bases: enum.Enum

An enumeration of the different Generalized Born Implicit Solvent model implemented in AMBER (optionfor igb).

Off = 0

HCT = 1

OBC1 = 2

OBC2 = 5

GBn = 7

GBn2 = 8

vacuum = 6

class BoxScaling(value)Bases: enum.Enum

An enumeration of the different PBC scaling options when running constant pressure simulations in AM-BER ( option for ntp).

Off = 0

Isotropic = 1

Anisotropic = 2

Semiisotropic = 3

class Periodicity(value)Bases: enum.Enum

An enumeration of the different periodicity options in AMBER (option for ntb).

Off = 0

ConstantVolume = 1

ConstantPressure = 2

5.11. API 139

Page 144: pAPRika Documentation

pAPRika Documentation

class Constraints(value)Bases: enum.Enum

An enumeration of the different bond constraint options in AMBER (option for ntc).

Off = 1

HBonds = 2

AllBonds = 3

class ForceEvaluation(value)Bases: enum.Enum

An enumeration of the different force evaluation options in AMBER (option for ntf).

All_On = 1

All_Off = 8

HBonds_Off = 2

AllBonds_Off = 3

AllBonds_HAngles_Off = 4

AllBonds_AllAngles_Off = 5

AllBonds_AllAngles_HDihedrals_Off = 6

AllBonds_AllAngles_AllDihedrals_Off = 7

property restraint_fileThe file containing NMR-style restraints for AMBER.

Note: When running AMBER simulations, you can only use either an AMBER NMR-style restraints ora Plumed-style restraints and not both. If both are specified, an Exception will be thrown.

Type os.PathLike

property cntrlAn ordered dictionary of simulation “control” namelist parameters. The main purpose of this class attributeis to make it easy to override certain simulation parameters, such as positional restraints on dummy atoms,and the inclusion of exclusion of the NMR-style APR restraints.

As of AMBER20, these are described, in part, in chapter 20 on pmemd.

Note: I can’t recall why we wanted an OrderedDict here.

Note: This is fragile and this could be hardened by making these ``ENUM``s and doing much more type-checking. These must be valid AMBER keywords or else the simulation will crash. The default keywordsthat are set when this class is initialized are partially overridden by the specific “config” functions detailedbelow.

The default dictionary keys and values are as follows:

• imin : 0

• ntx : 1

140 Chapter 5. References

Page 145: pAPRika Documentation

pAPRika Documentation

• irest : 0

• maxcyc : 0

• ncyc : 0

• dt : 0.002

• nstlim : 5000

• ntpr : 500

• ntwe : 500

• ntwr : 5000

• ntwx : 500

• ntxo : 1

• ioutfm : 1

• ntf : 2

• ntc : 2

• cut : 8

• igb : 0

• tempi : 298.15

• tempo : 298.15

• pres0 : 1.01325

• ntt : Thermostat.Langevin

• gamma_ln : 1.0

• ig : -1

• ntp : BoxScaling.Isotropic

• barostat : Barostat.MonteCarlo

• ntr : None

• restraint_wt : None

• restraintmask : None

• nmropt : 1

• pencut : -1

property ewaldAdditional Ewald summation settings.

Type dict

property wt“Weight” assigned to various simulation parameters. Written to the “&wt” line in the input file.

Type dict

property groupGroup specification for restraints applied to multiple atoms.

5.11. API 141

Page 146: pAPRika Documentation

pAPRika Documentation

Note: I don’t recall ever having to this option and this seems distinct from applying restraints to acollection of atoms.

Type dict

property prefixThe prefix for file names generated from this simulation.

Type str

property pmdOption to apply harmonic restraints on collective variables (umbrella sampling) based on the NFE moduleof Amber. Users need to define the colvars file cv_file for this option to be written in the AMBERinput file. The default values for output_file and output_freq is “pmd.txt” and 500, respectively.

Type dict

property smdOption to run a steered molecular dynamics (SMD) using the NFE module of Amber. Users need to definethe colvars file cv_file for this option to be written in the AMBER input file. The default values foroutput_file and output_freq is “smd.txt” and 500, respectively.

Type dict

config_vac_min()Configure a reasonable input setting for an energy minimization run in vacuum. Users can override theparameters set by this method.

config_vac_md(thermostat=<Thermostat.Langevin: 3>)Configure a reasonable input settings for MD in vacuum. Users can override the parameters set by thismethod.

Parameters thermostat (AMBER.Thermostat, default=Thermostat.Langevin) – Optionto choose one of six thermostats implemented in AMBER, highlighted values in parenthesisare the options set in the input file. (1) Off (0), (2) Berendsen (1), (3) Andersen (2), (4)Langevin (3), (5) OptimizedIsoNoseHoover (9), (6) StochasticIsoNoseHoover (10), and (7)Bussi (11).

config_gb_min(gb_model=<GBModel.HCT: 1>)Configure a reasonable input setting for an energy minimization run with implicit solvent. Users canoverride the parameters set by this method.

Parameters gb_model (AMBER.GBModel, default=GBModel.HCT) – Option to choose dif-ferent implicit solvent model.

config_gb_md(gb_model=<GBModel.HCT: 1>, thermostat=<Thermostat.Langevin: 3>)Configure a reasonable input settings for MD with implicit solvent. Users can override the parameters setby this method.

Parameters

• gb_model (AMBER.GBModel, default=GBModel.HCT) – Option to choose differentimplicit solvent model.

• thermostat (AMBER.Thermostat, default=Thermostat.Langevin) – Option tochoose one of six thermostats implemented in AMBER, highlighted values in parenthesisare the options set in the input file. (1) Off (0), (2) Berendsen (1), (3) Andersen (2), (4)Langevin (3), (5) OptimizedIsoNoseHoover (9), (6) StochasticIsoNoseHoover (10), and(7) Bussi (11).

142 Chapter 5. References

Page 147: pAPRika Documentation

pAPRika Documentation

config_pbc_min()Configure a reasonable input setting for an energy minimization run with periodic boundary conditions.Users can override the parameters set by this method.

config_pbc_md(ensemble=<Ensemble.NPT: 'NPT'>, thermostat=<Thermostat.Langevin: 3>, baro-stat=<Barostat.MonteCarlo: 2>)

Configure a reasonable input setting for a MD run with periodic boundary conditions. Users can overridethe parameters set by this method.

Parameters

• ensemble (Simulation.Ensemble, default=Ensemble.NPT) – Configure a MDsimulation with NVE, NVT or NPT thermodynamic ensemble.

• thermostat (AMBER.Thermostat, default=Thermostat.Langevin) – Option tochoose one of six thermostats implemented in AMBER, highlighted values in parenthesisare the options set in the input file. (1) Off (0), (2) Berendsen (1), (3) Andersen (2), (4)Langevin (3), (5) OptimizedIsoNoseHoover (9), (6) StochasticIsoNoseHoover (10), and(7) Bussi (11).

• barostat (AMBER.Barostat, default=Barostat.MonteCarlo) – Option to choose oneof two barostats implemented in AMBER, highlighted values in parenthesis are the optionsset in the input file. (1) Off (0), (2) Berendsen (1), and (3) Monte Carlo (2).

run(soft_minimize=False, overwrite=False, fail_ok=False)Method to run Molecular Dynamics simulation with AMBER.

Parameters

• soft_minimize (bool, optional, default=False) – Whether to slowlyturn on non-bonded interactions so that restraints get enforced first.

• overwrite (bool, optional, default=False) – Whether to overwrite simu-lation files.

• fail_ok (bool, optional, default=False) – Whether a failing simulationshould stop execution of pAPRika.

check_complete(alternate_file=None)Check for the string “TIMINGS” in self.output file. If “TIMINGS” is found, then the simulationcompleted successfully, as of AMBER20.

Parameters alternate_file (os.PathLike, optional, default=None) – Ifpresent, check for “TIMINGS” in this file rather than self.output.

Returns timings – True if “TIMINGS” is found in file. False, otherwise.

Return type bool

GROMACS Simulation Wrapper

class paprika.simulate.gromacs.GROMACSBases: paprika.simulate.simulation.Simulation, abc.ABC

A wrapper that can be used to set GROMACS simulation parameters.

Todo: possibly modify this module to use the official python wrapper of GROMACS.

Below is an example of the configuration file (gromacs.mdp) generated by the wrapper. The class propertyassociated with defining the configuration variables is shown in brackets.

5.11. API 143

Page 148: pAPRika Documentation

pAPRika Documentation

title = NPT MD Simulation ; [self.title]; Run control [self.control]nsteps = 1500000nstxout = 500nstlog = 500nstenergy = 500nstcalcenergy = 500dt = 0.002integrator = md; Nonbonded options [self.nb_method]cutoff-scheme = Verletns_type = gridnstlist = 10rlist = 0.9rcoulomb = 0.9rvdw = 0.9coulombtype = PMEpme_order = 4fourierspacing = 0.16vdwtype = Cut-offDispCorr = EnerPrespbc = xyz; Bond constraints [self.constraints]constraint-algorithm = lincsconstraints = h-bondslincs_iter = 1lincs_order = 4; Temperature coupling [self.thermostat]tcoupl = v-rescaletc-grps = Systemref_t = 298.15tau_t = 0.1gen_vel = no; Pressure coupling [self.barostat]pcoupl = Berendsenpcoupltype = isotropictau_p = 2.0ref_p = 1.01325compressibility = 4.5e-05

class Thermostat(value)Bases: enum.Enum

An enumeration of the different themostat implemented in GROMACS.

Off = 'no'

Berendsen = 'berendsen'

NoseHoover = 'nose-hoover'

Andersen1 = 'andersen'

Andersen2 = 'andersen-massive'

VelocityRescaling = 'v-rescale'

class Barostat(value)Bases: enum.Enum

An enumeration of the different barostat implemented in GROMACS.

144 Chapter 5. References

Page 149: pAPRika Documentation

pAPRika Documentation

Off = 'no'

Berendsen = 'Berendsen'

ParrinelloRahman = 'Parrinello-Rahman'

MMTK = 'MTTK'

class Integrator(value)Bases: enum.Enum

An enumeration of the different integrators implemented in GROMACS.

LeapFrog = 'md'

VelocityVerlet = 'md-vv'

VelocityVerletAveK = 'md-vv-avek'

LangevinDynamics = 'sd'

BrownianDynamics = 'bd'

class Optimizer(value)Bases: enum.Enum

An enumeration of the different minimization algorithm implemented in GROMACS.

SteepestDescent = 'steep'

ConjugateGradient = 'cg'

Broyden = 'l-bfgs'

class BoxScaling(value)Bases: enum.Enum

An enumeration of the different PBC scaling options when running constant pressure simulations in GRO-MACS.

Isotropic = 'isotropic'

Semiisotropic = 'semiisotropic'

Anisotropic = 'anisotropic'

SurfaceTension = 'surface-tension'

class Constraints(value)Bases: enum.Enum

An enumeration of the different bond constraint options in GROMACS.

Off = 'none'

HBonds = 'h-bonds'

AllBonds = 'all-bonds'

HAngles = 'h-angles'

AllAngles = 'all-angles'

property index_fileGROMACS index file that specifies groups in the system. This is optional in a GROMACS simulation.

Type os.PathLike

5.11. API 145

Page 150: pAPRika Documentation

pAPRika Documentation

property checkpointCheckpoint file (extension is .cpt) for starting a simulation from a previous state.

Type os.PathLike

property controlDictionary for the output control of the MD simulation (frequency of energy, trajectory etc).

Type dict

property nb_methodDictionary for the non-bonded method options (cutoffs and methods).

Type dict

property constraintsDictionary for the bond constraint options (LINCS or SHAKE).

Type dict

property tc_groupsList of groups to apply thermostat “separately” based on the groups defined in the index_file. Belowis an example of applying the thermostat for different groups separately in a GROMACS input file

tcoupl = v-rescaletc-grps = HOST GUEST HOHtau-t = 0.1 0.1 0.1ref-t = 300 300 300

Type list

property prefixThe prefix for file names generated from this simulation.

Type str

property custom_mdrun_commandCustom commands for mdrun. The default commands parsed to mdrun if all the variables are defined is

gmx mdrun -deffnm ``prefix`` -nt ``n_threads`` -gpu_id ``gpu_devices`` -→˓plumed ``plumed.dat``

This is useful depending on how GROMACS was compiled, e.g. if GROMACS is compiled with the MPIlibrary the you will need to use the command below:

mpirun -np 6 gmx_mpi mdrun -deffnm ``prefix`` -ntomp 1 -gpu_id 0 -plumed→˓``plumed.dat``

property grompp_maxwarnMaximum number of warnings for GROMPP to ignore. default=1.

Type int

config_vac_min(optimizer=<Optimizer.SteepestDescent: 'steep'>)Configure a reasonable input setting for a MD run in vacuum. Users can override the parameters set bythis method.

Note: Newer versions of GMX no longer support a “True” vacuum simulation so we have to dothis by creating a “pseudo-PBC” environment. Make sure the coordinates .gro file has an expanded

146 Chapter 5. References

Page 151: pAPRika Documentation

pAPRika Documentation

box, which you can do using gmx editconf. See the discussion on https://gromacs.bioexcel.eu/t/minimization-in-vacuum-without-pbc/110/2.

Parameters optimizer (GROMACS.Optimizer, default=Optimizer.SteepestDescent) –Algorithm for energy minimization, keyword in the parenthesis are the options for the inputfile. (1) SteepestDescent (steep), (2) ConjugateGradient (cg), and (3) Broyden (l-bfgs).

config_vac_md(integrator=<Integrator.LeapFrog: 'md'>, thermo-stat=<Thermostat.VelocityRescaling: 'v-rescale'>)

Configure a reasonable input setting for a MD run in vacuum. Users can override the parameters set bythis method.

Note: Newer versions of GMX no longer support a “True” vacuum simulation so we have todo this by creating a “pseudo-PBC” environment. Make sure the coordinates .gro file has an ex-panded box, which you set using gmx editconf. See the discussion on https://gromacs.bioexcel.eu/t/minimization-in-vacuum-without-pbc/110/2.

Parameters

• integrator (GROMACS.Integrator, default=Integrator.LeapFrog) – Option tochoose the integrator for the MD simulations, keywords in the parenthesis are the optionsfor the input file. (1) LeapFrog (md), (2) VelocityVerlet (md-vv), (3) VelocityVerletAveK(md-vv-avek), (4) LangevinDynamics (sd), and (5) Brownian Dynamics (bd).

• thermostat (GROMACS.Thermostat, default=Thermostat.VelocityRescaling) –Option to choose one of five thermostat implemented in GROMACS, keywords inthe parenthesis are the options for the input file. (1) Off (no), (2) Berendsen(berendsen), (3) NoseHoover (nose-hoover), (4) Andersen1 (andersen), (5) An-dersen2 (andersen-massive), and (6) VelocityRescaling (v-rescale).

config_pbc_min(optimizer=<Optimizer.SteepestDescent: 'steep'>)Configure a reasonable input setting for an energy minimization run with periodic boundary conditions.Users can override the parameters set by this method.

Parameters optimizer (GROMACS.Optimizer, default=Optimizer.SteepestDescent) –Algorithm for energy minimization, keywords in the parenthesis are the options for the inputfile. (1) SteepestDescent (steep), (2) ConjugateGradient (cg), and (3) Broyden (l-bfgs).

config_pbc_md(ensemble=<Ensemble.NPT: 'NPT'>, integrator=<Integrator.LeapFrog:'md'>, thermostat=<Thermostat.VelocityRescaling: 'v-rescale'>, baro-stat=<Barostat.Berendsen: 'Berendsen'>)

Configure a reasonable input setting for a MD run with periodic boundary conditions. Users can overridethe parameters set by this method.

Parameters

• ensemble (Simulation.Ensemble, default=Ensemble.NPT) – Configure a MDsimulation with NVE, NVT or NPT thermodynamic ensemble.

• integrator (GROMACS.Integrator, default=Integrator.LeapFrog) – Option tochoose the integrator for the MD simulations, keywords in the parenthesis are the optionsfor the input file. (1) LeapFrog (md), (2) VelocityVerlet (md-vv), (3) VelocityVerletAveK(md-vv-avek), (4) LangevinDynamics (sd), and (5) Brownian Dynamics (bd).

• thermostat (GROMACS.Thermostat, default=Thermostat.VelocityRescaling) –Option to choose one of five thermostat implemented in GROMACS, keywords in

5.11. API 147

Page 152: pAPRika Documentation

pAPRika Documentation

the parenthesis are the options for the input file. (1) Off (no), (2) Berendsen(berendsen), (3) NoseHoover (nose-hoover), (4) Andersen1 (andersen), (5) An-dersen2 (andersen-massive), and (6) VelocityRescaling (v-rescale).

• barostat (GROMACS.Barostat, default=Barostat.Berendsen) – Option to chooseone of three barostat implemented in GROMACS, keywords in the parenthesis are theoptions for the input file. (1) Off (no), (2) Berendsen (berendsen), (3) ParrinelloRah-man (Parrinello-Rahman), and (4) MMTK (MTTK).

run(run_grompp=True, overwrite=False, fail_ok=False)Method to run Molecular Dynamics simulation with GROMACS.

Parameters

• run_grompp (bool, optional, default=True) – Run GROMPP to generate.tpr file before running MDRUN

• overwrite (bool, optional, default=False) – Whether to overwrite simu-lation files.

• fail_ok (bool, optional, default=False) – Whether a failing simulationshould stop execution of pAPRika.

check_complete(alternate_file=None)Check for the string “step N” in self.output file. If “step N” is found, then the simulation completed.

Parameters alternate_file (os.PathLike, optional, default=None) – Ifpresent, check for “step N” in this file rather than self.output. Default: None

Returns complete – True if “step N” is found in file. False, otherwise.

Return type bool

NAMD Simulation Wrapper

class paprika.simulate.namd.NAMDBases: paprika.simulate.simulation.Simulation, abc.ABC

A wrapper that can be used to set NAMD simulation parameters.

Todo: Add wrapper support for Drude polarizable FF, steered-MD and alchemical calculations

Below is an example of the configuration file (namd.conf) generated by the wrapper. The class propertyassociated with defining the configuration variables is shown in brackets.

## NPT MD Simulation [self.title]# AMBER files [self.topology, self.coordinates]amber yesparmfile cb6-but-dum-sol.prmtopambercoor cb6-but-dum-sol.rst7readexclusions yesscnb 2.0# Previous state [self.checkpoint]bincoordinates equilibration.restart.coorbinvelocities equilibration.restart.velextendedSystem equilibration.restart.xsc# Output control [self.control]outputname equilibration

(continues on next page)

148 Chapter 5. References

Page 153: pAPRika Documentation

pAPRika Documentation

(continued from previous page)

restartFreq 5000dcdFreq 500xstFreq 500outputEnergies 500outputPressure 500timestep 2.0# Nonbonded options [self.nb_method]exclude scaled1-41-4scaling 0.833333cutoff 9.0LJCorrection yesnonbondedFreq 1fullElectFrequency 2switching offwrapAll onmargin 5PME yesPMEGridSpacing 1.0stepspercycle 10# constraints [self.constraints]rigidBonds allrigidIterations 100rigidTolerance 1.0e-8usesettle on# Temperature coupling [self.thermostat]langevin onlangevinDamping 1.0langevinTemp 298.15langevinHydrogen off# Pressure coupling [self.barostat]useGroupPressure yesuseFlexibleCell nouseConstantArea nolangevinPiston onlangevinPistonTarget 1.01325langevinPistonPeriod 200.0langevinPistonDecay 20.0langevinPistonTemp 298.15# Collective variables [self.colvars_file]colvars oncolvarsConfig colvars.tcl# Molecular dynamics [self.control]run 1500000

class Thermostat(value)Bases: enum.Enum

An enumeration of the different themostat implemented in NAMD.

Off = 'no thermostat'

Langevin = 'Langevin dynamics'

tCouple = 'Temperature Coupling'

tRescale = 'Temperature Rescaling'

vRescale = 'Velocity Rescaling'

tReassign = 'Temperature Reassignment'

5.11. API 149

Page 154: pAPRika Documentation

pAPRika Documentation

LoweAnderson = 'Lowe-Andersen dynamics'

class Barostat(value)Bases: enum.Enum

An enumeration of the different barostat implemented in NAMD.

Off = 'no barostat'

Berendsen = 'Berendsen pressure bath'

Langevin = 'Nosé-Hoover Langevin piston'

property colvars_fileThe name of the Colvars restraints file.

Type os.PathLike

property tcl_forcesThe name of a TclForces scripts for applying a user defined force. https://www.ks.uiuc.edu/Research/namd/2.14/ug/node50.html

Note: TclForces can by used to apply forces and/or on-the-fly analysis. An example use if this featurecould be to generate a funnel potential. https://github.com/jeff231li/funnel_potential

Type os.PathLike

property controlDictionary for the output control of the MD simulation (timestep, frequency of energy, trajectory etc).

Type dict

property nb_methodDictionary for the non-bonded method options (cutoffs and methods).

Type dict

property constraintsDictionary for the bond constraint options (rigid bonds and settle/shake).

Type dict

property implicitDictionary for implicit solvent options (Generalized Born Implicit Solvent model).

Type dict

property charmm_parametersA list CHARMM parameter file(s) if running simulations with the CHARMM force field.

Type list

property prefixThe prefix for file names generated from this simulation.

Type str

property checkpointSpecify the prefix file name for the previous simulation (as checkpoint for continuing a simulation). This isneeded to get the coordinates checkpoint.coor, velocities checkpoint.vel and box informationcheckpoint.xsc. Unlike AMBER and GROMACS, NAMD requires the restart files specified insidethe configuration file instead of the command-line argument.

150 Chapter 5. References

Page 155: pAPRika Documentation

pAPRika Documentation

Type str

property cell_basis_vectorsDictionary for the cell basis vectors (cellBasisVector1, cellBasisVector2,cellBasisVector3 and cellOrigin). If not defined, the basis vectors and the origin can becalculated from the positions of the system from the coordinates files.

Type dict

property custom_run_commandsA list of NAMD-supported Tcl commands if a custom run is preferred. The code snippet below shows anexample use of this command for running a simulation with a slow-heating protocol.

>>> simulation.custom_run_commands = [>>> "for {set temp 50} {$temp <= 300} {incr temp 50} {",>>> "langevinTemp $temp",>>> "reinitvels $temp",>>> "run 50000",>>> "}",>>> ]

Type list

property qmForcesDictionary for setting QM/MM simulation parameters in NAMD https://www.ks.uiuc.edu/Research/namd/2.14/ug/node84.html.

Note: qmForces in NAMD can also be used to run simulations with Neural Network Potentials (NNP)https://github.com/RowleyGroup/NNP-MM.

Type dict

config_vac_min()Configure a reasonable input setting for a MD run in vacuum. Users can override the parameters set bythis method.

config_vac_md(thermostat=<Thermostat.Langevin: 'Langevin dynamics'>)Configure a reasonable input settings for MD in vacuum. Users can override the parameters set by thismethod.

Parameters thermostat (NAMD.Thermostat, default=Thermostat.Langevin) – Option tochoose one of six thermostat implemented in NAMD: (1) Langevin, (2) tCouple, (3) tRescale,(4) vRescale, (5) tReassign, (6) LoweAnderson.

config_gb_min()Configure a reasonable input settings for minimization with implicit solvent. Users can override theparameters set by this method.

config_gb_md(thermostat=<Thermostat.Langevin: 'Langevin dynamics'>)Configure a reasonable input settings for MD with implicit solvent. Users can override the parameters setby this method.

Parameters thermostat (NAMD.Thermostat, default=Thermostat.Langevin) – Option tochoose one of six thermostat implemented in NAMD: (1) Langevin, (2) tCouple, (3) tRescale,(4) vRescale, (5) tReassign, (6) LoweAnderson.

5.11. API 151

Page 156: pAPRika Documentation

pAPRika Documentation

config_pbc_min(calculate_cell_vectors=True)Configure a reasonable input setting for an energy minimization run with periodic boundary conditions.Users can override the parameters set by this method.

Parameters calculate_cell_vectors (bool, default=True) – Calculate cell ba-sis vectors based on self.coordinates. This is usually needed at the start of a simula-tion. When continuing from a previous a simulation NAMD reads in the *.xsc file to getthe basis vectors.

config_pbc_md(ensemble=<Ensemble.NPT: 'NPT'>, thermostat=<Thermostat.Langevin: 'Langevindynamics'>, barostat=<Barostat.Langevin: 'Nosé-Hoover Langevin piston'>, calcu-late_cell_vectors=False)

Configure a reasonable input setting for a MD run with periodic boundary conditions. Users can overridethe parameters set by this method.

Parameters

• ensemble (Simulation.Ensemble, default=Ensemble.NPT) – Configure a MDsimulation with NVE, NVT or NPT thermodynamic ensemble.

• thermostat (NAMD.Thermostat, default=Thermostat.Langevin) – Option to chooseone of six thermostat implemented in NAMD: (1) Langevin, (2) tCouple, (3) tRescale, (4)vRescale, (5) tReassign, (6) LoweAnderson.

• barostat (NAMD.Barostat, default=Barostat.Langevin) – Option to choose one oftwo barostat implemented in NAMD: (1) Langevin piston or (2) Berendsen.

• calculate_cell_vectors (bool, default=False) – Calculate cell basis vec-tors based on self.coordinates. This is usually needed at the start of a simulation.When continuing from a previous a simulation NAMD reads in the *.xsc file to get thecell basis vectors.

run(overwrite=True, fail_ok=False)Method to run Molecular Dynamics simulation with NAMD.

Parameters

• overwrite (bool, optional, default=False) – Whether to overwrite simu-lation files.

• fail_ok (bool, optional, default=False) – Whether a failing simulationshould stop execution of pAPRika.

check_complete(alternate_file=None)Check for the string “WallClock” in self.logfile file. If “WallClock” is found, then the simulationcompleted.

Parameters alternate_file (os.PathLike, optional, default=None) – Ifpresent, check for “WallClock” in this file rather than self.logfile. Default: None

Returns complete – True if “WallClock” is found in file. False, otherwise.

Return type bool

152 Chapter 5. References

Page 157: pAPRika Documentation

pAPRika Documentation

5.11.7 System API

TLeap Wrapper

class paprika.build.system.tleap.TLeapBases: object

Class for building AMBER prmtop/rst7 files with TLeap.

Parameters

• add_ions (list, default=None) – A list of additional ions to be added to the sys-tem, specified by the residue name and an indication of the amount: an integer number,the molarity (M), or the molality (m). For example, the following list shows valid exam-ples: add_ions = [‘MG’, 2, ‘Cl-‘, 4, ‘K’, ‘0.150M’, ‘BR’, ‘0.150M’, ‘NA’, ‘0.050m’, ‘F’,‘0.050m’].

• add_ion_residues (list, default=None) – A property formatted list of ions toadd to the system. The format is the same as add_ions except that only integer amountsare allowed. This is set by set_additional_ions.

• buffer_value (float, default=12.0) – The desired solvation buffer value. Thiswill add a layer of water around your solute with the minimum distance to the periodic boxedge defined by buffer_value. If target_waters is set, it will override this value.

• buffer_value_history (list, default=[0]) – The history ofbuffer_value adjustments stored in a list.

• counter_cation (str, default='Na+') – If neutralize is set to True, thiscation will be used.

• counter_anion (str, default='Cl-') – If neutralize is set to True, thisanion will be used.

• cycles_since_last_exp_change (int, default=0) – A count of the numberof buffer_value adjustments since the last exponent change. Should always start at 0.

• exponent (int, default=`) – The initial value used for dynamically adjusting thebuffer value.

• loadpdb_file (str, default=None) – If specified, this PDB file will be loadedvia loadpdb instead of whatever file is specified in the template. This file should bepresent in output_path, or if you specify it with a path, the path must be relative tooutput_path.

• manual_switch_thresh (int, default=``target_waters``**(1./3.))– The threshold difference between waters actually added and target_waters for which wecan safely switch to manual removal of waters. If too large, then there will be big air pocketsin our box. If too small, it will take forever to converge. If the user does not set this value,it will set proportionately to the target_waters.

• max_cycles (int, default=50) – The maximum number of buffer_value ad-justment cycles.

• min_exponent_limit (int, default=-5) – The minimum limit that we let expo-nent get to. If it gets too small, it has no effect on the number of waters added.

• neutralize (bool, default=True) – Whether to neutralize the system with coun-terions.

5.11. API 153

Page 158: pAPRika Documentation

pAPRika Documentation

• output_path (str, default='./') – Directory path where TLeap input files willbe written and executed. Associated input files (frcmod, mol2, pdb, etc) need to presentin that path.

• output_prefix (str, default='build') – Append a prefix to files created bythis module.

• pbc_type (PBCBox, default=PBCBox.cubic) – Type of solvation (cubic, rectangular,octahedral, or None).

• solvent_molecular_mass (float, default=0.018 (for water)) –kg/mol for the solvent. Used for computing the molality.

• target_waters (int, default=None) – The desired number of waters to solvateyour system with. If specified, this will override any buffer_value settings.

• template_file (str, default=None) – Name of template file to read boilerplateTLeap input (e.g., source leaprc. . . lines). Any frcmod/mol2/pdb files which are loaded bythe template must be present in output_path.

• template_lines (list, default=None) – The list of TLeap commands whichare needed to build the system. Either the template_file or the template_linesneeds to be set prior to running build(). Files called for loading should be present inoutput_path (see above).

• unit (str, default='model') – The TLeap unit name.

• waters_added_history (list, default=[0]) – The history of number of wa-ters added which correlate to the values in buffer_value_history.

• model (dict, default={"library": "tip3p", "frcmod": "tip3p","water_box": "TIP3PBOX"}) – The type of water model to solvate the system. UseTLeap.getAmberWater() to specify the water model.

• waters_to_remove (list, default=None) – A list of the water residues to bemanually removed after solvation.

• write_save_lines (bool, default=True) – Whether or not to dosaveamberparm and savepdb when tleap is executed. During optimizationloops it speeds up the process to set as False, but it must be returned to True for the finalexecution.

Example

>>> from paprika.build.system import TLeap>>> from paprika.build.system.utils import PBCBox>>>>>> # Initialize TLeap object>>> system = TLeap()>>> system.output_path = "windows">>> system.output_prefix = "host-guest-sol">>> system.target_waters = 2000>>> system.pbc_type = PBCBox.cubic>>> system.set_water_model("tip3p", model_type="force-balance")>>> system.neutralize = True>>>>>> # template_lines lists all structure files etc.>>> system.template_lines = [>>> "source leaprc.gaff",

(continues on next page)

154 Chapter 5. References

Page 159: pAPRika Documentation

pAPRika Documentation

(continued from previous page)

>>> "loadamberparams host.frcmod",>>> "loadamberparams guest.frcmod",>>> "loadamberparams dummy.frcmod",>>> "GST = loadmol2 guest.mol2",>>> "HST = loadmol2 host.mol2",>>> "DM1 = loadmol2 dm1.mol2",>>> "DM2 = loadmol2 dm2.mol2",>>> "DM3 = loadmol2 dm3.mol2",>>> "model = loadpdb host-guest.pdb",>>> ]>>>>>> # Run TLeap>>> system.build()>>>>>> # Repartition masses of Hydrogen atoms>>> system.repartition_hydrogen_mass()>>>>>> # Convert AMBER files to GROMACS>>> system.convert_to_gromacs()

property add_ionsA list of ions to add to the system.

Type list

property add_ion_residuesA property formatted list of ions to add to the system.

Type list

property buffer_valueThe desired solvation buffer value.

Type float

property buffer_value_historyA list of the history of buffer_value adjustments.

Type list

property counter_cationAMBER-style residue name for the cation.

Type str

property counter_anionAMBER-style residue name for the anion.

Type str

property cycles_since_last_exp_changeNumber of buffer_value adjustments since the last exponent change.

Type int

property exponentThe initial value used for adjusting the buffer_value.

Type int

property loadpdb_fileThe PDB file to load using the TLeap command loadpdb.

5.11. API 155

Page 160: pAPRika Documentation

pAPRika Documentation

Type os.PathLike

property manual_switch_threshThe threshold difference between waters actually added and target_waters for which we can safely switchto manual removal of waters.

Type int

property max_cyclesThe maximum number of buffer_value adjustment cycles.

Type int

property min_exponent_limitThe minimum limit that we let exponent get to.

Type int

property neutralizeAMBER-style residue name for the anion.

Type str

property output_pathDirectory path where TLeap input files will be written and executed. Associated input files (frcmod,mol2, pdb, etc) need to be present in that path.

Type os.PathLike

property output_prefixThe name for the output files.

Type str

property pbc_typeThe periodic box type for the solvated system.

Type PBCBox

property solvent_molecular_massThe molecular mass in kg/mol for the solvent molecule.

Type float

property target_watersNumber of water molecules to add to the system.

Type int

property template_fileSpecify a TLeap template file.

Type os.PathLike

property template_linesList of user-based commands as strings for TLeap.

Type list

property unitThe unit name for the structure in TLeap.

Type str

property waters_added_historyThe history of number of waters added.

156 Chapter 5. References

Page 161: pAPRika Documentation

pAPRika Documentation

Type list

property water_modelThe water model for TLeap to use stored as a dictionary.

Type dict

property waters_to_removeA list of water molecules to remove after solvation.

Type list

property write_save_linesWhether to run saveamberparm and savepdb when TLeap is executed.

Type bool

build(clean_files: bool = True)Build the TLeap system.

Parameters clean_files (bool, optional) – Whether to delete log files after comple-tion.

filter_template()Filter out any template_lines that may interfere with solvation.

write_input()Write a TLeap input file based on template_lines and other things we have set.

run()Execute TLeap.

Returns output – The tleap stdout returned as a list.

Return type list

grep_leap_log()Check for a few keywords in the TLeap output.

check_for_leap_log(log_file='leap.log')Check if leap.log exists in output_path, and if so, delete so the current run doesn’t append.

Parameters log_file (str, optional) – Name of the tleap logfile. Default: leap.log

solvate()Solvate a structure with an exact number of waters or buffer size.

final_solvation_run()Run the solvation with write_save_lines=True.

count_waters()Quickly check the number of waters added for a given buffer size.

Returns waters – Number of water molecules.

Return type int

count_residues(print_results=False)Run and parse TLeap output and return a dictionary of residues in the structure.

Parameters print_results (bool, optional) – Whether to print residues to log file.

Returns residues – Dictionary of added residues and their number

Return type dict

5.11. API 157

Page 162: pAPRika Documentation

pAPRika Documentation

set_additional_ions()Determine whether additional ions (instead of or in addition to neutralization) are requested. . .

Sets:

self.add_ion_residues [list] A processed list of ions and their amounts that can be passed toTLeap.

get_volume()Run and parse TLeap output and return the volume of the structure.

Returns volume – The volume of the structure in cubic angstroms.

Return type float

remove_waters_manually()Remove a few water molecules manually with TLeap to exactly match a desired number of waters.

list_waters()Run and parse TLeap output and return the a list of water residues.

Returns water_residues – A list of the water residues in the structure.

Return type list

adjust_buffer_value()Determine whether to increase or decrease the buffer thickness to match a desired number of waters.

Sets:

self.buffer_value [float] A new buffer size to try.

self.exponent [int] Adjusts the order of magnitude of buffer value changes.

self.cycles_since_last_exp_change [int] Resets this value to 0 when exponent value ischanged to help with the logic gates.

repartition_hydrogen_mass(options=None)Repartitions the masses of Hydrogen atoms in the system by a factor 3 and overwrites the .prmtop file:output_path/output_prefix.prmtop

Parameters options (str, optional) – Optional keyword(s) for the repartitioning andfollowing the parmed.tools.actions documentation the usage is ‘[<mass>] [dowa-ter]’.

convert_to_gromacs(overwrite=False, output_path=None, output_prefix=None,toolkit=<ConversionToolkit.InterMol: 'intermol'>)

Convert AMBER topology and coordinate files to GROMACS format.

Parameters

• overwrite (bool, optional, default=False) – Option to overwrite GRO-MACS .top and .gro files if they already exists in the folder.

• output_path (str, optional, default=None) – Alternate directory pathwhere the AMBER files are located. Default is the path parsed to the TLeap object.

• output_prefix (str, optional, default=None) – Alternate file name pre-fix for the Amber files. Default is the prefix parsed to the TLeap object.

• toolkit (ConversionToolkit, default=ConversionToolkit.InterMol) – Option tochoose the toolkit for converting the AMBER files, ParmEd or InterMol

convert_to_charmm(overwrite=False, output_path=None, output_prefix=None,toolkit=<ConversionToolkit.InterMol: 'intermol'>)

Convert AMBER topology and coordinate files to CHARMM format.

158 Chapter 5. References

Page 163: pAPRika Documentation

pAPRika Documentation

Parameters

• overwrite (bool, optional, default=False) – Option to overwriteCHARMM .psf and .pdb files if they already exists in the folder.

• output_path (str, optional, default=None) – Alternate directory pathwhere the AMBER files are located. Default is the path parsed to the TLeap object.

• output_prefix (str, optional, default=None) – Alternate file name pre-fix for the Amber files. Default is the prefix parsed to the TLeap object.

• toolkit (ConversionToolkit, default=ConversionToolkit.InterMol) – Option tochoose the toolkit for converting the AMBER files, ParmEd or InterMol

convert_to_lammps(pair_style=None, output_path=None, output_prefix=None)Convert AMBER topology and coordinate files to LAMMPS format.

Parameters

• pair_style (str, optional, default=None) – LAMMPS option forpair_style, if set to None (default) the setting will be for a periodic Ewald simu-lation.

• output_path (str, optional, default=None) – Alternate directory pathwhere the AMBER files are located. Default is the path parsed to the TLeap object.

• output_prefix (str, optional, default=None) – Alternate file name pre-fix for the Amber files. Default is the prefix parsed to the TLeap object.

convert_to_desmond(output_path=None, output_prefix=None)Convert AMBER topology and coordinate files to DESMOND format.

Parameters

• output_path (str, optional, default=None) – Alternate directory pathwhere the AMBER files are located. Default is the path parsed to the TLeap object.

• output_prefix (str, optional, default=None) – Alternate file name pre-fix for the Amber files. Default is the prefix parsed to the TLeap object.

set_water_model(model, model_type=None)Specify the water model for TLeap to use. The water model is stored as a dictionary in the variablewater_model.

Parameters

• model (str) – The water model to use, models supported are [“spc”, “opc”, “tip3p”,“tip4p”]. Strings are case-insensitive.

• model_type (str) – The particular type of the water model, default is None andthe key in parenthesis is the water box used in TLeap. Strings are case-insensitive.* spc: None (SPCBOX), “flexible” (SPCFWBOX), “quantum” (QSPCFWBOX) *opc: None (OPCBOX), “three-point” (OPC3BOX) * tip3p: None (TIP3PBOX), “flexi-ble” (TIP3PFBOX), “force-balance” (FB3BOX), “bind3p” (TIP3PBOX) * tip4p: None(TIP4PBOX), “ewald” (TIP4PEWBOX), “force-balance” (FB4BOX)

5.11. API 159

Page 164: pAPRika Documentation

pAPRika Documentation

Utils

class paprika.build.system.utils.ConversionToolkit(value)Bases: enum.Enum

An enumeration of the different toolkits for converting MD files to other formats.

ParmEd = 'parmed'

InterMol = 'intermol'

class paprika.build.system.utils.PBCBox(value)Bases: enum.Enum

An enumeration of the different PBC box used when solvating with TLeap.

cubic = 'cubic'

rectangular = 'rectangular'

octahedral = 'octahedral'

5.11.8 Utils API

class paprika.io.NumpyEncoder(*, skipkeys=False, ensure_ascii=True, check_circular=True, al-low_nan=True, sort_keys=False, indent=None, separators=None,default=None)

Bases: json.encoder.JSONEncoder

Save DAT_restraint as JSON by re-encoding numpy arrays.

default(obj)If input object is an ndarray it will be converted into a dict holding dtype, shape and the data, base64encoded.

Parameters obj (str or parmed.amber.AmberParm) – Input object to encode.

Returns Encoded object.

Return type json.JSONEncoder

paprika.io.json_numpy_obj_hook(dct)Decodes a previously encoded numpy.ndarray with proper shape and dtype.

Parameters dct (dict) – json encoded ndarray.

Returns dct – if input was an encoded ndarray.

Return type numpy.ndarray

paprika.io.save_restraints(restraint_list, filepath='restraints.json')Save a list of paprika.restraints.DAT_restraint to a JSON file.

Parameters

• restraint_list (list) – List of paprika.restraints.DAT_restraint.

• filepath (os.PathLike) – The name of the JSON file to write to.

paprika.io.load_restraints(filepath='restraints.json')Load restraints from a JSON file.

Parameters filepath (os.PathLike) – The name of the JSON file to load.

Returns restraints – List of paprika.restraints.DAT_restraint.

160 Chapter 5. References

Page 165: pAPRika Documentation

pAPRika Documentation

Return type list

paprika.log.config_root_logger(verbose, log_file_path=None)Setup the the root logger’s configuration. The log messages are printed in the terminal and saved in the filespecified by log_file_path (if not None) and printed. Note that logging use sys.stdout to print logging.INFO messages, and stderr for the others. The root logger’s configuration is inherited by the loggers createdby logging.getLogger(name). Different formats are used to display messages on the terminal and onthe log file. For example, in the log file every entry has a timestamp which does not appear in the terminal.Moreover, the log file always shows the module that generate the message, while in the terminal this happensonly for messages of level WARNING and higher.

Parameters

• verbose (bool) – Control the verbosity of the messages printed in the terminal. Thelogger displays messages of level logging.INFO and higher when verbose=False.Otherwise those of level logging.DEBUG and higher are printed.

• log_file_path (str, optional, default = None) – If not None, this is thepath where all the logger’s messages of level logging.DEBUG or higher are saved.

paprika.utils.get_key(dct, value)Get dictionary key given the value.

Note: This function will return a list of keys if there are more than one key with the same value in the orderthey are found.

Parameters

• dct (dict) – Python dictionary to get the key from.

• value (str) – The value to match to the dictionary.

Returns key – The dictionary key that matched the value.

Return type str

paprika.utils.get_dict_without_keys(dct, *keys)Returns a copy of a dictionary without specific keys.

Parameters

• dct (dict) – A python dictionary.

• keys (int or str) – The keys of the dictionary to negate.

Returns new_dict – A new dictionary without *keys.

Return type dict

paprika.utils.override_dict(dct, custom)Overrides dictionary values from that of a custom dictionary.

Parameters

• dct (dict) – Python dictionary to override.

• custom (dict) – A custom dictionary which will overwrite the original dictionary.

paprika.utils.return_parmed_structure(filename)Return a structure object from a filename.

Parameters filename (os.PathLike) – The name of the file to load.

5.11. API 161

Page 166: pAPRika Documentation

pAPRika Documentation

Returns structure

Return type parmed.structure.Structure

paprika.utils.index_from_mask(structure, mask, amber_index=False)Return the atom indicies for a given selection mask.

Parameters

• structure (parmed.structure.Structure) – The structure that contains theatoms

• mask (str) – The atom mask.

• amber_index (bool, optional, default=False) – If true, 1 will be added tothe returned indices.

Returns indices – Atom index or indices corresponding to the mask.

Return type int

paprika.utils.make_window_dirs(window_list, stash_existing=False, path='./', win-dow_dir_name='windows')

Make a series of windows to hold simulation data.

Parameters

• window_list (list) – List of simulation windows. The names in this list will be usedfor the folders.

• stash_existing (bool, optional, default=False) – Whether to move anexisting windows directory to a backup with the current time.

• path (os.PathLike, optional, default='./') – Root path for the directories.

• window_dir_name (os.PathLike, optional, default='windows') –Name for the top level directory.

paprika.utils.strip_prmtop(prmtop, mask=':WAT,:Na+,:Cl-')Strip residues from a structure and write a new parameter file. This could probably also be done with ParmEd.

Parameters

• prmtop (os.PathLike) – Existing Amber parameter file.

• mask (str, optional, default=':WAT,:Na+,:Cl-') – The list of atommasks to strip.

Returns stripped – The stripped topology that can be used to read stripped trajectories withpytraj.

Return type pytraj.topology

paprika.utils.parse_mden(file)Return energies from an AMBER mden file.

Parameters file (os.PathLike) – Name of the Amber output file.

Returns energies – A dictionary containing VDW, electrostatic, bond, angle, dihedral, V14, E14,and total energy.

Return type dict

paprika.utils.parse_mdout(file)Return energies from an AMBER ``mdout` file.

Parameters file (os.PathLike) – Name of Amber output file

162 Chapter 5. References

Page 167: pAPRika Documentation

pAPRika Documentation

Returns energies – A dictionary containing VDW, electrostatic, bond, angle, dihedral, V14, E14,and total energy.

Return type dict

paprika.utils.is_file_and_not_empty(file_path)Util function to check if a file both exists at the specified path and is not empty.

Parameters file_path (os.PathLike) – The file path to check.

Returns That a file both exists at the specified path and is not empty.

Return type bool

5.12 Release History

5.12.1 v1.0.4

• Refactor codes for setup.py and analysis.py modules to allow a smoother integration with OpenFF-Evaluator

• OpenMM restraints code is now decoupled from setup.py and placed in a separate file restraints/openmm.py

• Updated install requirements to Ambertools v20

• Added hydrogen mass repartitioning option to TLeap API module

• Minor bug fixes

5.12.2 v1.0.3

Fixed API compatibility with the new pymbar v3.0.5 and the I/O for ref_structure in thestatic_DAT_restraint function

5.12.3 v1.0.2

Fix parsing of CUDA_VISIBLE_DEVICES class property. This bugfix was intended to go into the v1.0.1 releasebut was accidentally excluded.

5.12.4 v1.0.1

Provides a more robust method to supply a random number seed to the compute_free_energy method.

5.12. Release History 163

Page 168: pAPRika Documentation

pAPRika Documentation

5.12.5 v1.0.0

• The API for paprika.setup and paprika.analyze are now converged.

• OpenMM support is proved by PropertyEstimator.

• The documentation has (mostly) been updated and expanded.

5.12.6 v0.1.1

Minor code cleanup and fix reference values for test cases that were failing in the v0.1.0 release.

5.12.7 v0.1.0

This release enables paprika to work with propertyestimator of the Open Force Field Toolkit, and taproomto setup host-guest calculations with either GAFF or SMIRNOFF-based force fields using AMBER or OpenMM assimulation backends.

5.12.8 v0.0.4

Updates after merging Cookiecutter for Computational Molecular Sciences (CMS) Python Packages and updatingtests to pass.

5.12.9 v0.0.3

Initial code and was used to run SAMPLing.

164 Chapter 5. References

Page 169: pAPRika Documentation

PYTHON MODULE INDEX

ppaprika.build.system.tleap, 153paprika.build.system.utils, 160paprika.evaluator.amber, 125paprika.evaluator.setup, 120paprika.evaluator.utils, 125paprika.io, 160paprika.log, 161paprika.restraints.amber, 129paprika.restraints.colvars, 132paprika.restraints.openmm, 130paprika.restraints.plumed, 130paprika.restraints.read_yaml, 134paprika.restraints.restraints, 125paprika.restraints.utils, 134paprika.simulate.amber, 138paprika.simulate.gromacs, 143paprika.simulate.namd, 148paprika.simulate.simulation, 136paprika.utils, 161

165

Page 170: pAPRika Documentation

pAPRika Documentation

166 Python Module Index

Page 171: pAPRika Documentation

INDEX

Aadd_dummy() (in module paprika.build.dummy), 117add_dummy_atom_restraints() (pa-

prika.restraints.plumed.Plumed method),132

add_dummy_atoms_to_structure() (pa-prika.evaluator.setup.Setup static method),121

add_ion_residues() (pa-prika.build.system.tleap.TLeap property),155

add_ions() (paprika.build.system.tleap.TLeap prop-erty), 155

adjust_buffer_value() (pa-prika.build.system.tleap.TLeap method),158

align_principal_axes() (in module pa-prika.build.align), 106

All_Off (paprika.simulate.amber.AMBER.ForceEvaluationattribute), 140

All_On (paprika.simulate.amber.AMBER.ForceEvaluationattribute), 140

AllAngles (paprika.simulate.gromacs.GROMACS.Constraintsattribute), 145

AllBonds (paprika.simulate.amber.AMBER.Constraintsattribute), 140

AllBonds (paprika.simulate.gromacs.GROMACS.Constraintsattribute), 145

AllBonds_AllAngles_AllDihedrals_Off (pa-prika.simulate.amber.AMBER.ForceEvaluationattribute), 140

AllBonds_AllAngles_HDihedrals_Off (pa-prika.simulate.amber.AMBER.ForceEvaluationattribute), 140

AllBonds_AllAngles_Off (pa-prika.simulate.amber.AMBER.ForceEvaluationattribute), 140

AllBonds_HAngles_Off (pa-prika.simulate.amber.AMBER.ForceEvaluationattribute), 140

AllBonds_Off (paprika.simulate.amber.AMBER.ForceEvaluationattribute), 140

AMBER (class in paprika.simulate.amber), 138AMBER.Barostat (class in paprika.simulate.amber),

139AMBER.BoxScaling (class in pa-

prika.simulate.amber), 139AMBER.Constraints (class in pa-

prika.simulate.amber), 139AMBER.ForceEvaluation (class in pa-

prika.simulate.amber), 140AMBER.GBModel (class in paprika.simulate.amber),

139AMBER.Periodicity (class in pa-

prika.simulate.amber), 139AMBER.Thermostat (class in pa-

prika.simulate.amber), 138amber_index() (pa-

prika.restraints.restraints.DAT_restraintproperty), 127

amber_restraint_line() (in module pa-prika.restraints.amber), 129

Andersen (paprika.simulate.amber.AMBER.Thermostatattribute), 139

Andersen1 (paprika.simulate.gromacs.GROMACS.Thermostatattribute), 144

Andersen2 (paprika.simulate.gromacs.GROMACS.Thermostatattribute), 144

Anisotropic (paprika.simulate.amber.AMBER.BoxScalingattribute), 139

Anisotropic (paprika.simulate.gromacs.GROMACS.BoxScalingattribute), 145

apply_dat_restraint() (in module pa-prika.restraints.openmm), 130

apply_positional_restraints() (in modulepaprika.restraints.openmm), 130

attach() (paprika.restraints.restraints.DAT_restraintproperty), 126

auto_apr() (paprika.restraints.restraints.DAT_restraintproperty), 126

Bbarostat() (paprika.simulate.simulation.Simulation

property), 138

167

Page 172: pAPRika Documentation

pAPRika Documentation

Berendsen (paprika.simulate.amber.AMBER.Barostatattribute), 139

Berendsen (paprika.simulate.amber.AMBER.Thermostatattribute), 138

Berendsen (paprika.simulate.gromacs.GROMACS.Barostatattribute), 145

Berendsen (paprika.simulate.gromacs.GROMACS.Thermostatattribute), 144

Berendsen (paprika.simulate.namd.NAMD.Barostatattribute), 150

bootcycles() (paprika.analysis.fe_calc property),111

BrownianDynamics (pa-prika.simulate.gromacs.GROMACS.Integratorattribute), 145

Broyden (paprika.simulate.gromacs.GROMACS.Optimizerattribute), 145

buffer_value() (paprika.build.system.tleap.TLeapproperty), 155

buffer_value_history() (pa-prika.build.system.tleap.TLeap property),155

build() (paprika.build.system.tleap.TLeap method),157

build_conformational_restraints() (pa-prika.evaluator.setup.Setup class method),122

build_guest_restraints() (pa-prika.evaluator.setup.Setup class method),124

build_static_restraints() (pa-prika.evaluator.setup.Setup class method),121

build_symmetry_restraints() (pa-prika.evaluator.setup.Setup class method),123

build_wall_restraints() (pa-prika.evaluator.setup.Setup class method),123

Bussi (paprika.simulate.amber.AMBER.Thermostat at-tribute), 139

Ccell_basis_vectors() (pa-

prika.simulate.namd.NAMD property), 151changing_restraints() (paprika.analysis.fe_calc

property), 110charmm_parameters() (pa-

prika.simulate.namd.NAMD property), 150check_complete() (pa-

prika.simulate.amber.AMBER method), 143check_complete() (pa-

prika.simulate.gromacs.GROMACS method),148

check_complete() (paprika.simulate.namd.NAMDmethod), 152

check_complete() (pa-prika.simulate.simulation.Simulation method),138

check_converged() (pa-prika.simulate.simulation.Simulation method),138

check_coordinates() (in module pa-prika.build.align), 108

check_for_leap_log() (pa-prika.build.system.tleap.TLeap method),157

check_restraints() (in module pa-prika.restraints.restraints), 129

checkpoint() (paprika.simulate.gromacs.GROMACSproperty), 145

checkpoint() (paprika.simulate.namd.NAMD prop-erty), 150

cntrl() (paprika.simulate.amber.AMBER property),140

collect_data() (paprika.analysis.fe_calc method),113

Colvars (class in paprika.restraints.colvars), 132colvars_file() (paprika.simulate.namd.NAMD

property), 150compute_free_energy() (paprika.analysis.fe_calc

method), 114compute_largest_neighbor() (pa-

prika.analysis.fe_calc property), 111compute_ref_state_work() (pa-

prika.analysis.fe_calc method), 114compute_roi() (paprika.analysis.fe_calc property),

111config_gb_md() (paprika.simulate.amber.AMBER

method), 142config_gb_md() (paprika.simulate.namd.NAMD

method), 151config_gb_md() (pa-

prika.simulate.simulation.Simulation method),138

config_gb_min() (paprika.simulate.amber.AMBERmethod), 142

config_gb_min() (paprika.simulate.namd.NAMDmethod), 151

config_gb_min() (pa-prika.simulate.simulation.Simulation method),138

config_pbc_md() (paprika.simulate.amber.AMBERmethod), 143

config_pbc_md() (pa-prika.simulate.gromacs.GROMACS method),147

config_pbc_md() (paprika.simulate.namd.NAMD

168 Index

Page 173: pAPRika Documentation

pAPRika Documentation

method), 152config_pbc_md() (pa-

prika.simulate.simulation.Simulation method),138

config_pbc_min() (pa-prika.simulate.amber.AMBER method), 142

config_pbc_min() (pa-prika.simulate.gromacs.GROMACS method),147

config_pbc_min() (paprika.simulate.namd.NAMDmethod), 151

config_pbc_min() (pa-prika.simulate.simulation.Simulation method),138

config_root_logger() (in module paprika.log),161

config_vac_md() (paprika.simulate.amber.AMBERmethod), 142

config_vac_md() (pa-prika.simulate.gromacs.GROMACS method),147

config_vac_md() (paprika.simulate.namd.NAMDmethod), 151

config_vac_min() (pa-prika.simulate.amber.AMBER method), 142

config_vac_min() (pa-prika.simulate.gromacs.GROMACS method),146

config_vac_min() (paprika.simulate.namd.NAMDmethod), 151

ConjugateGradient (pa-prika.simulate.gromacs.GROMACS.Optimizerattribute), 145

conservative_subsample() (pa-prika.analysis.fe_calc property), 111

ConstantPressure (pa-prika.simulate.amber.AMBER.Periodicityattribute), 139

ConstantVolume (pa-prika.simulate.amber.AMBER.Periodicityattribute), 139

constraints() (pa-prika.simulate.gromacs.GROMACS property),146

constraints() (paprika.simulate.namd.NAMD prop-erty), 150

continuous_apr() (pa-prika.restraints.restraints.DAT_restraintproperty), 126

control() (paprika.simulate.gromacs.GROMACSproperty), 146

control() (paprika.simulate.namd.NAMD property),150

converged() (paprika.simulate.simulation.Simulation

property), 138ConversionToolkit (class in pa-

prika.build.system.utils), 160convert_to_charmm() (pa-

prika.build.system.tleap.TLeap method),158

convert_to_desmond() (pa-prika.build.system.tleap.TLeap method),159

convert_to_gromacs() (pa-prika.build.system.tleap.TLeap method),158

convert_to_lammps() (pa-prika.build.system.tleap.TLeap method),159

coordinates() (pa-prika.simulate.simulation.Simulation property),137

count_residues() (pa-prika.build.system.tleap.TLeap method),157

count_waters() (paprika.build.system.tleap.TLeapmethod), 157

counter_anion() (paprika.build.system.tleap.TLeapproperty), 155

counter_cation() (pa-prika.build.system.tleap.TLeap property),155

create_window_list() (in module pa-prika.restraints.restraints), 129

cubic (paprika.build.system.utils.PBCBox attribute),160

custom_mdrun_command() (pa-prika.simulate.gromacs.GROMACS property),146

custom_restraint_values() (pa-prika.restraints.restraints.DAT_restraintproperty), 126

custom_run_commands() (pa-prika.simulate.namd.NAMD property), 151

cycles_since_last_exp_change() (pa-prika.build.system.tleap.TLeap property),155

DDAT_restraint (class in pa-

prika.restraints.restraints), 125de_alias() (in module paprika.restraints.read_yaml),

134default() (paprika.io.NumpyEncoder method), 160determine_window_order() (pa-

prika.analysis.fe_calc method), 113dump_to_file() (paprika.restraints.colvars.Colvars

method), 134

Index 169

Page 174: pAPRika Documentation

pAPRika Documentation

dump_to_file() (paprika.restraints.plumed.Plumedmethod), 132

Eewald() (paprika.simulate.amber.AMBER property),

141exact_sem_each_ti_fraction() (pa-

prika.analysis.fe_calc property), 111executable() (paprika.simulate.simulation.Simulation

property), 136exponent() (paprika.build.system.tleap.TLeap prop-

erty), 155extract_dummy_atoms() (in module pa-

prika.build.dummy), 118extract_guest_restraints() (in module pa-

prika.restraints.utils), 135

Ffe_calc (class in paprika.analysis), 109file_name() (paprika.restraints.plumed.Plumed

property), 131filter_template() (pa-

prika.build.system.tleap.TLeap method),157

final_solvation_run() (pa-prika.build.system.tleap.TLeap method),157

fractions() (paprika.analysis.fe_calc property), 112

GGBn (paprika.simulate.amber.AMBER.GBModel at-

tribute), 139GBn2 (paprika.simulate.amber.AMBER.GBModel

attribute), 139generate_gaff() (in module pa-

prika.evaluator.amber), 125get_benchmarks() (in module pa-

prika.evaluator.utils), 125get_bias_potential_type() (in module pa-

prika.restraints.utils), 134get_block_sem() (in module paprika.analysis), 114get_dict_without_keys() (in module pa-

prika.utils), 161get_factors() (in module paprika.analysis), 114get_key() (in module paprika.utils), 161get_nearest_max() (in module paprika.analysis),

114get_principal_axis_vector() (in module pa-

prika.build.align), 107get_restraint_values() (in module pa-

prika.restraints.utils), 134get_rotation_matrix() (in module pa-

prika.build.align), 107

get_subsampled_indices() (in module pa-prika.analysis), 115

get_theta() (in module paprika.build.align), 107get_volume() (paprika.build.system.tleap.TLeap

method), 158gpu_devices() (pa-

prika.simulate.simulation.Simulation property),137

grep_leap_log() (paprika.build.system.tleap.TLeapmethod), 157

GROMACS (class in paprika.simulate.gromacs), 143GROMACS.Barostat (class in pa-

prika.simulate.gromacs), 144GROMACS.BoxScaling (class in pa-

prika.simulate.gromacs), 145GROMACS.Constraints (class in pa-

prika.simulate.gromacs), 145GROMACS.Integrator (class in pa-

prika.simulate.gromacs), 145GROMACS.Optimizer (class in pa-

prika.simulate.gromacs), 145GROMACS.Thermostat (class in pa-

prika.simulate.gromacs), 144grompp_maxwarn() (pa-

prika.simulate.gromacs.GROMACS property),146

group() (paprika.simulate.amber.AMBER property),141

HHAngles (paprika.simulate.gromacs.GROMACS.Constraints

attribute), 145HBonds (paprika.simulate.amber.AMBER.Constraints

attribute), 140HBonds (paprika.simulate.gromacs.GROMACS.Constraints

attribute), 145HBonds_Off (paprika.simulate.amber.AMBER.ForceEvaluation

attribute), 140HCT (paprika.simulate.amber.AMBER.GBModel at-

tribute), 139

Iidentify_changing_restraints() (pa-

prika.analysis.fe_calc method), 113implicit() (paprika.simulate.namd.NAMD property),

150index_file() (paprika.simulate.gromacs.GROMACS

property), 145index_from_mask() (in module paprika.utils), 162initialize() (paprika.restraints.restraints.DAT_restraint

method), 128instances (paprika.restraints.restraints.DAT_restraint

attribute), 128

170 Index

Page 175: pAPRika Documentation

pAPRika Documentation

integrate_bootstraps() (in module pa-prika.analysis), 116

InterMol (paprika.build.system.utils.ConversionToolkitattribute), 160

is_file_and_not_empty() (in module pa-prika.utils), 163

Isotropic (paprika.simulate.amber.AMBER.BoxScalingattribute), 139

Isotropic (paprika.simulate.gromacs.GROMACS.BoxScalingattribute), 145

Jjson_numpy_obj_hook() (in module paprika.io),

160

LLangevin (paprika.simulate.amber.AMBER.Thermostat

attribute), 139Langevin (paprika.simulate.namd.NAMD.Barostat at-

tribute), 150Langevin (paprika.simulate.namd.NAMD.Thermostat

attribute), 149LangevinDynamics (pa-

prika.simulate.gromacs.GROMACS.Integratorattribute), 145

LeapFrog (paprika.simulate.gromacs.GROMACS.Integratorattribute), 145

list_waters() (paprika.build.system.tleap.TLeapmethod), 158

load_restraints() (in module paprika.io), 160load_trajectory() (in module paprika.analysis),

115loadpdb_file() (paprika.build.system.tleap.TLeap

property), 155LoweAnderson (paprika.simulate.namd.NAMD.Thermostat

attribute), 149

Mmake_window_dirs() (in module paprika.utils), 162manual_switch_thresh() (pa-

prika.build.system.tleap.TLeap property),156

mask1() (paprika.restraints.restraints.DAT_restraintproperty), 125

mask2() (paprika.restraints.restraints.DAT_restraintproperty), 125

mask3() (paprika.restraints.restraints.DAT_restraintproperty), 125

mask4() (paprika.restraints.restraints.DAT_restraintproperty), 126

max_cycles() (paprika.build.system.tleap.TLeapproperty), 156

methods() (paprika.analysis.fe_calc property), 110

min_exponent_limit() (pa-prika.build.system.tleap.TLeap property),156

MMTK (paprika.simulate.gromacs.GROMACS.Barostatattribute), 145

modulepaprika.analysis, 109paprika.build.align, 105paprika.build.dummy, 117paprika.build.system.tleap, 153paprika.build.system.utils, 160paprika.evaluator.amber, 125paprika.evaluator.setup, 120paprika.evaluator.utils, 125paprika.io, 160paprika.log, 161paprika.restraints.amber, 129paprika.restraints.colvars, 132paprika.restraints.openmm, 130paprika.restraints.plumed, 130paprika.restraints.read_yaml, 134paprika.restraints.restraints, 125paprika.restraints.utils, 134paprika.simulate.amber, 138paprika.simulate.gromacs, 143paprika.simulate.namd, 148paprika.simulate.simulation, 136paprika.utils, 161

MonteCarlo (paprika.simulate.amber.AMBER.Barostatattribute), 139

multiple_replace() (in module pa-prika.restraints.read_yaml), 134

Nn_threads() (paprika.simulate.simulation.Simulation

property), 137NAMD (class in paprika.simulate.namd), 148NAMD.Barostat (class in paprika.simulate.namd),

150NAMD.Thermostat (class in paprika.simulate.namd),

149nb_method() (paprika.simulate.gromacs.GROMACS

property), 146nb_method() (paprika.simulate.namd.NAMD prop-

erty), 150neutralize() (paprika.build.system.tleap.TLeap

property), 156NoseHoover (paprika.simulate.gromacs.GROMACS.Thermostat

attribute), 144NPT (paprika.simulate.simulation.Simulation.Ensemble

attribute), 136NumpyEncoder (class in paprika.io), 160NVE (paprika.simulate.simulation.Simulation.Ensemble

attribute), 136

Index 171

Page 176: pAPRika Documentation

pAPRika Documentation

NVT (paprika.simulate.simulation.Simulation.Ensembleattribute), 136

OOBC1 (paprika.simulate.amber.AMBER.GBModel

attribute), 139OBC2 (paprika.simulate.amber.AMBER.GBModel

attribute), 139octahedral (paprika.build.system.utils.PBCBox at-

tribute), 160Off (paprika.simulate.amber.AMBER.Barostat at-

tribute), 139Off (paprika.simulate.amber.AMBER.BoxScaling

attribute), 139Off (paprika.simulate.amber.AMBER.Constraints

attribute), 140Off (paprika.simulate.amber.AMBER.GBModel at-

tribute), 139Off (paprika.simulate.amber.AMBER.Periodicity at-

tribute), 139Off (paprika.simulate.amber.AMBER.Thermostat

attribute), 138Off (paprika.simulate.gromacs.GROMACS.Barostat at-

tribute), 144Off (paprika.simulate.gromacs.GROMACS.Constraints

attribute), 145Off (paprika.simulate.gromacs.GROMACS.Thermostat

attribute), 144Off (paprika.simulate.namd.NAMD.Barostat attribute),

150Off (paprika.simulate.namd.NAMD.Thermostat at-

tribute), 149offset_structure() (in module pa-

prika.build.align), 108OptimizedIsoNoseHoover (pa-

prika.simulate.amber.AMBER.Thermostatattribute), 139

orders() (paprika.analysis.fe_calc property), 110output_freq() (paprika.restraints.colvars.Colvars

property), 134output_path() (paprika.build.system.tleap.TLeap

property), 156output_prefix() (paprika.build.system.tleap.TLeap

property), 156override_dict() (in module paprika.utils), 161

Ppaprika.analysis

module, 109paprika.build.align

module, 105paprika.build.dummy

module, 117paprika.build.system.tleap

module, 153paprika.build.system.utils

module, 160paprika.evaluator.amber

module, 125paprika.evaluator.setup

module, 120paprika.evaluator.utils

module, 125paprika.io

module, 160paprika.log

module, 161paprika.restraints.amber

module, 129paprika.restraints.colvars

module, 132paprika.restraints.openmm

module, 130paprika.restraints.plumed

module, 130paprika.restraints.read_yaml

module, 134paprika.restraints.restraints

module, 125paprika.restraints.utils

module, 134paprika.simulate.amber

module, 138paprika.simulate.gromacs

module, 143paprika.simulate.namd

module, 148paprika.simulate.simulation

module, 136paprika.utils

module, 161ParmEd (paprika.build.system.utils.ConversionToolkit

attribute), 160ParrinelloRahman (pa-

prika.simulate.gromacs.GROMACS.Barostatattribute), 145

parse_mden() (in module paprika.utils), 162parse_mdout() (in module paprika.utils), 162parse_window() (in module paprika.restraints.utils),

134path() (paprika.analysis.fe_calc property), 110path() (paprika.restraints.plumed.Plumed property),

131path() (paprika.simulate.simulation.Simulation prop-

erty), 136pbc_type() (paprika.build.system.tleap.TLeap prop-

erty), 156PBCBox (class in paprika.build.system.utils), 160

172 Index

Page 177: pAPRika Documentation

pAPRika Documentation

phase() (paprika.simulate.simulation.Simulation prop-erty), 137

Plumed (class in paprika.restraints.plumed), 130plumed_file() (pa-

prika.simulate.simulation.Simulation property),137

plumed_kernel_library() (pa-prika.simulate.simulation.Simulation property),137

pmd() (paprika.simulate.amber.AMBER property), 142prefix() (paprika.simulate.amber.AMBER property),

142prefix() (paprika.simulate.gromacs.GROMACS prop-

erty), 146prefix() (paprika.simulate.namd.NAMD property),

150prefix() (paprika.simulate.simulation.Simulation

property), 137prepare_complex_structure() (pa-

prika.evaluator.setup.Setup class method),120

prepare_data() (paprika.analysis.fe_calc method),113

prepare_host_structure() (pa-prika.evaluator.setup.Setup class method),120

pressure() (paprika.simulate.simulation.Simulationproperty), 138

prmtop() (paprika.analysis.fe_calc property), 109pull() (paprika.restraints.restraints.DAT_restraint

property), 127

QqmForces() (paprika.simulate.namd.NAMD property),

151

Rread_restraint_data() (in module pa-

prika.analysis), 115read_trajectories() (paprika.analysis.fe_calc

method), 113read_yaml() (in module pa-

prika.restraints.read_yaml), 134rectangular (paprika.build.system.utils.PBCBox at-

tribute), 160ref_state_work() (in module paprika.analysis),

115release() (paprika.restraints.restraints.DAT_restraint

property), 127remove_waters_manually() (pa-

prika.build.system.tleap.TLeap method),158

repartition_hydrogen_mass() (pa-prika.build.system.tleap.TLeap method),

158restraint_file() (pa-

prika.simulate.amber.AMBER property),140

restraint_list() (paprika.analysis.fe_calc prop-erty), 110

restraint_list() (pa-prika.restraints.plumed.Plumed property),131

restraints_from_ascii() (in module pa-prika.restraints.utils), 135

results() (paprika.analysis.fe_calc property), 112return_parmed_structure() (in module pa-

prika.utils), 161rotate_around_axis() (in module pa-

prika.build.align), 107run() (paprika.build.system.tleap.TLeap method), 157run() (paprika.simulate.amber.AMBER method), 143run() (paprika.simulate.gromacs.GROMACS method),

148run() (paprika.simulate.namd.NAMD method), 152run() (paprika.simulate.simulation.Simulation

method), 138run_mbar() (paprika.analysis.fe_calc method), 113run_ti() (paprika.analysis.fe_calc method), 113

Ssave_restraints() (in module paprika.io), 160Semiisotropic (pa-

prika.simulate.amber.AMBER.BoxScalingattribute), 139

Semiisotropic (pa-prika.simulate.gromacs.GROMACS.BoxScalingattribute), 145

set_additional_ions() (pa-prika.build.system.tleap.TLeap method),157

set_water_model() (pa-prika.build.system.tleap.TLeap method),159

Setup (class in paprika.evaluator.setup), 120Simulation (class in paprika.simulate.simulation),

136Simulation.Ensemble (class in pa-

prika.simulate.simulation), 136simulation_data() (paprika.analysis.fe_calc prop-

erty), 110smd() (paprika.simulate.amber.AMBER property), 142solvate() (paprika.build.system.tleap.TLeap

method), 157solvent_molecular_mass() (pa-

prika.build.system.tleap.TLeap property),156

Index 173

Page 178: pAPRika Documentation

pAPRika Documentation

static_DAT_restraint() (in module pa-prika.restraints.restraints), 128

SteepestDescent (pa-prika.simulate.gromacs.GROMACS.Optimizerattribute), 145

StochasticIsoNoseHoover (pa-prika.simulate.amber.AMBER.Thermostatattribute), 139

strip_prmtop() (in module paprika.utils), 162SurfaceTension (pa-

prika.simulate.gromacs.GROMACS.BoxScalingattribute), 145

Ttarget_waters() (paprika.build.system.tleap.TLeap

property), 156tc_groups() (paprika.simulate.gromacs.GROMACS

property), 146tcl_forces() (paprika.simulate.namd.NAMD prop-

erty), 150tCouple (paprika.simulate.namd.NAMD.Thermostat

attribute), 149temperature() (paprika.analysis.fe_calc property),

109temperature() (pa-

prika.simulate.simulation.Simulation property),137

template_file() (paprika.build.system.tleap.TLeapproperty), 156

template_lines() (pa-prika.build.system.tleap.TLeap property),156

thermostat() (paprika.simulate.simulation.Simulationproperty), 138

ti_matrix() (paprika.analysis.fe_calc property), 111TLeap (class in paprika.build.system.tleap), 153topology() (paprika.restraints.restraints.DAT_restraint

property), 125topology() (paprika.simulate.simulation.Simulation

property), 137trajectory() (paprika.analysis.fe_calc property),

110translate_to_origin() (in module pa-

prika.build.align), 108tReassign (paprika.simulate.namd.NAMD.Thermostat

attribute), 149tRescale (paprika.simulate.namd.NAMD.Thermostat

attribute), 149

Uunit() (paprika.build.system.tleap.TLeap property),

156units() (paprika.restraints.plumed.Plumed property),

132

units_from_DAT() (pa-prika.restraints.colvars.Colvars property),133

uses_legacy_k() (pa-prika.restraints.plumed.Plumed property),132

Vvacuum (paprika.simulate.amber.AMBER.GBModel at-

tribute), 139VelocityRescaling (pa-

prika.simulate.gromacs.GROMACS.Thermostatattribute), 144

VelocityVerlet (pa-prika.simulate.gromacs.GROMACS.Integratorattribute), 145

VelocityVerletAveK (pa-prika.simulate.gromacs.GROMACS.Integratorattribute), 145

vRescale (paprika.simulate.namd.NAMD.Thermostatattribute), 149

Wwater_model() (paprika.build.system.tleap.TLeap

property), 157waters_added_history() (pa-

prika.build.system.tleap.TLeap property),156

waters_to_remove() (pa-prika.build.system.tleap.TLeap property),157

window() (paprika.simulate.simulation.Simulationproperty), 137

window_list() (paprika.restraints.plumed.Plumedproperty), 131

write_dummy_frcmod() (in module pa-prika.build.dummy), 117

write_dummy_mol2() (in module pa-prika.build.dummy), 118

write_input() (paprika.build.system.tleap.TLeapmethod), 157

write_save_lines() (pa-prika.build.system.tleap.TLeap property),157

wt() (paprika.simulate.amber.AMBER property), 141

Zzalign() (in module paprika.build.align), 105

174 Index