# Tutorial for alchemical free energy calculations using using AWH
## Case study: Extracting the oil-water partition coefficient for a small molecule
In this tutorial, we will use the accelerated weight histogram (AWH) method to calculate the partitioning free energy of a chosen small molecule between water and oil (cyclohexane). Partitioning is calculated as the difference in solvation free energies into the two solvents following the thermodynamic cycle. Here, an alchemical reaction coordinate is sampled using AWH, which provides an easy-to-use, computationally efficient, and fast-converging method to calculate PMFs along physical and alchemical reaction coordinates. The tutorial is performed using the coarse-grained Martini force field ([Martini web site](http://www.cgmartini.nl)) for speed, yet the same procedure is directly applicable to atomistic force fields.
## The workflow in a nutshell
* Choose a small molecule
* Insert the small molecule into water and cyclohexane
* Energy-minimize these two systems
* Run an AWH simulation where the small molecule appears and disappears many times
* Construct the PMF profile from the weight histogram and extract ΔG for both solvents
* Calculate the partititioning free energy ΔΔG based on the thermodynamic cycle
## Learning outcomes
* Set up alchemical simulations using GROMACS
* Understand the meaning of the key simulation parameters
* Understand the working principle of AWH
* Understand the outputs of AWH
## Alchemical transitions & Thermodynamic cycles
* Partitioning free energies could be calculated using equilibrium simulations in a two-phase solvent (water & oil), but sampling could be limited in case the solute is very hydrophobic/philic.
* Alternatively, we could use physical reaction coordinates to 'pull' the molecule from one phase to another and extract the PMF, but this typically leads to large hysteresis effects.
* In simulations, we can also perform alchemical transitions and exploit thermodynamic cycles.
* In an alchemical simulation, we make molecules disappear/appear, or change into other molecules.
* Here, we use the cycle below, in which the dim solutes refer to them being decoupled from the system, i.e. they do not interact with the solvent, but retain their internal interactions. Alternatively, this could be drawn as them being in vacuum.
* To estimate $ \Delta G^\mathrm{partitioning}_\mathrm{water-oil} $, we make a round around the circle, sum all the contributions. This must be equal to 0, since we returned to the starting point, and free energy is a state function (independent of the path).
* This provides us with a simple way to calculate partitioning free energies based on the solvation energies into oil and water phases, which can be calculated using an alhemical simulations.
File ~/Library/Python/3.9/lib/python/site-packages/nglview/base.py:10, in _singleton.<locals>.getinstance()
8 def getinstance():
9 if cls not in instances:
---> 10 instances[cls] = cls()
11 return instances[cls]
File ~/Library/Python/3.9/lib/python/site-packages/nglview/color.py:47, in _ColormakerRegistry.__init__(self, *args, **kwargs)
45 try:
46 get_ipython() # only display in notebook
---> 47 self._ipython_display_()
48 except NameError:
49 pass
File ~/Library/Python/3.9/lib/python/site-packages/nglview/color.py:54, in _ColormakerRegistry._ipython_display_(self, **kwargs)
52 if self._ready:
53 return
---> 54 super()._ipython_display_(**kwargs)
AttributeError: 'super' object has no attribute '_ipython_display_'
%% Cell type:markdown id: tags:
First select a small molecule from the [Martini 3 small molecule library](https://github.com/ricalessandri/Martini3-small-molecules/). Then download the corresponding structure (.gro) file by changing the "TOLU" in the command below
## Generate two solvent boxes and insert the small molecule
* Let's first take a look at the gmx solvate tool and its options.
%% Cell type:code id: tags:
``` python
!gmxsolvate-h
```
%% Cell type:markdown id: tags:
Look at the options. We can select the size of the simulation box with "-box". Alternatively, we can tell how many solvent molecules to insert with "-maxsol". Here, we will generate a cubic box with 800 solvent molecules. The radius needs to be adjusted to account for the large size of Martini water beads.
Now we will generate the topology for the system with 1 solute molecule and 800 waters. We have a template file available, into which we will simply change the name of the chosen solute.
Let's see if the box size has converged. With isotropic pressure coupling all box vectors are equal (cubic box), so it is enough to look at the x component ("Box-X"), which can be extracted from the output files with "gmx energy". We then plot it.
%% Cell type:code id: tags:
``` python
!echo"Box-X"|gmxenergy-feq_w.edr-obox_w.xvg
importmatplotlib.pyplotasplt
importnumpyasnp
box=np.loadtxt('box_w.xvg',comments=['#','@'])
plt.plot(box[:,0],box[:,1])
plt.xlabel('Time (ps)')
plt.ylabel('Box edge (nm)')
plt.show()
```
%% Cell type:markdown id: tags:
The system should look well converged, so we can proceed to the AWH simulation.
## AWH simulation
If we have an equilibrated system, we can proceed to the alchemical AWH run. Let's first take a look at the mdp file template. Some key parameters include:
* "free energy" turns on the alchemical calculation
* "couple-lambda0/1" set what is on/off at different lambda values
* "couple-moltype" is the name of the molecule to solvate. This will be changed in the next step
* "couple-intramol" sets whether bonded and intra-molecular non-bonded interactions are coupled.
* "init-lambda-state" sets the state where the simulation starts defined as the element of the vectors below
* "vdw/coul_lambdas" sets the scaling factors for LJ and electrostatic interactions for the different lambda states (here 30). The scaling parameters of the last one (0,0) correspond to a non-interacting molecule (couple-lambda0=none), and this is the initial state (init-lambda-state=30).
* "calc-lambda-neighbors" sets the number of neighbors for which dH will be calculated. 1 for typical BAR, -1 means all neighbors, in line with MBAR and AWH
* "sc_alpha/sigma/power" set the shape of the soft-core potential used to rid issues at lambda values close to 0 or 1
* AWH parameters here!
%% Cell type:code id: tags:
``` python
!catMDPs/awh.mdp
```
%% Cell type:markdown id: tags:
Let's change the name of the molecule to couple in the mdp file to the chosen one.
%% Cell type:code id: tags:
``` python
!sed"s/TOCOUPLE/{MOLNAME}/"MDPs/awh.mdp>awh.mdp
```
%% Cell type:markdown id: tags:
Now we'll generate the tpr and run the awh simulation.
%% Cell type:code id: tags:
``` python
!gmxgrompp-fawh.mdp-ceq_w.gro-ptopol_w.top-oawh_w
!gmxmdrun-deffnmawh_w-v
```
%% Cell type:markdown id: tags:
## Analyze the AWH run
Here, we run the tool "gmx awh" to extract the PMF and other profiles stored in the energy file. The tool outputs a file every "awh-nstout" steps (see mdp file), so we put them in a folder, find the last file, move it to the parent folder, and delete the others.
%% Cell type:code id: tags:
``` python
# THE LASTFILE DOES NOT WORK (GETS BRACKETS AROUND FILENAME)
!catpmf_w.xvg|awk'/ 0.000/ {print "The solvation free energy for water is " $2} /30.000/ {print "- " $2 " kJ/mol"}'
```
%% Cell type:markdown id: tags:
Now let's visualize the result. Let's first plot the resulting PMF and the coordinate bias. If the PMF does not have higher curvatures than what can be described by the bias generated using Gaussians, these should look identical (the bias is needed to obtain the target distribution = flat). Here, for uncharged molecules, the first 10 lambdas are equal, as they correspond to turning of the charges. The 20 consecutive ones correspond to turning of the Lennard-Jones interactions (van der Waals forces + steric repulsion). The solvation free energy is obtained as PMF($\lambda=1$) - PMF($\lambda=0$).
%% Cell type:code id: tags:
``` python
importmatplotlib.pyplotasplt
importnumpyasnp
pmf=np.loadtxt('pmf_w.xvg',comments=['#','@'])
plt.plot(pmf[:,0],pmf[:,2])
plt.plot(pmf[:,0],pmf[:,1])
plt.legend(['Coordinate bias','PMF'])
plt.xlabel('$\lambda$')
plt.ylabel('PMF (kJ/mol)')
plt.show()
```
%% Cell type:markdown id: tags:
Let's now look at some other AWH outputs. The target distribution was set to be uniform, and depending on the simulation length, we will have better or worse convergence to it. The error in the target distribution can be checked from the output file.
%% Cell type:code id: tags:
``` python
importmatplotlib.pyplotasplt
importnumpyasnp
pmf=np.loadtxt('pmf_w.xvg',comments=['#','@'])
plt.plot(pmf[:,0],pmf[:,4],'b')
plt.plot(pmf[:,0],pmf[:,5],'r')
plt.legend(['Reference value distribution','Target ref value distribution'])
plt.xlabel('$\lambda$')
plt.ylabel('PMF (kJ/mol)')
plt.show()
```
%% Cell type:code id: tags:
``` python
!greperrorpmf_w.xvg
```
%% Cell type:markdown id: tags:
Finally, we'll check the friction metric, which tells how easy it is to diffuse in the alchemical space along $\lambda$.
%% Cell type:code id: tags:
``` python
importmatplotlib.pyplotasplt
importnumpyasnp
pmf=np.loadtxt('pmf_w.xvg',comments=['#','@'])
plt.plot(pmf[:,0],pmf[:,6],'b')
plt.ylabel('Friction metric')
plt.xlabel('$\lambda$')
plt.show()
```
%% Cell type:markdown id: tags:
Now, we will finally extract the free energy of solvating the chosen solute in water.
%% Cell type:code id: tags:
``` python
!catpmf_w.xvg|awk'/ 0.000/ {print "The solvation free energy for water is " $2} /30.000/ {print "- " $2 " kJ/mol"}'
```
%% Output
cat: pmf_chex.xvg: No such file or directory
%% Cell type:markdown id: tags:
Now we will repeat the calculation for hexadecane in one block.