FEP¶

10/7/2026¶

Paper

print view

In [12]:
%%html
<script src="https://bits.csb.pitt.edu/preamble.js"></script>
<style>:root {--jp-cell-prompt-width: 32px}</style>

Alchemical Free Energy Computation¶

No description has been provided for this image

Define a coupling parameter $\lambda$ of the potential energy function $U$ that controls the contribution of the change:

$$ U(r^N,\lambda)= \sum_{j \in \text{not ligand}} \sum_{i \in \text{ligand}} \mathbf{\lambda} \epsilon_{i,j}\biggl[\left(\frac{r_{0ij}}{r_{ij}} \right)^{12} - 2\left(\frac{r_{0ij}}{r_{ij}} \right)^{6} \biggr] + \sum_\text{all other}\sum_\text{pairs} \epsilon_{i,j}\biggl[\left(\frac{r_{0ij}}{r_{ij}} \right)^{12} - 2\left(\frac{r_{0ij}}{r_{ij}} \right)^{6} \biggr] + \cdots$$

Free energy perturbation¶

You can calculate the free energy change of a perturbation ($\lambda_A \rightarrow \lambda_B$) using the Zwanzig equation:

$$ \small \Delta f = - \ln \frac{\int e^{-u(\mathbf{r}^N,\lambda_B)}\,d\mathbf{r}^N} {\int e^{-u(\mathbf{r}^N,\lambda_A)}\,d\mathbf{r}^N} = - \ln \frac{\int e^{-\Delta u_{B-A}(\mathbf{r}^N)}e^{-u(\mathbf{r}^N,\lambda_A)}\,d\mathbf{r}^N} {\int e^{-u(\mathbf{r}^N,\lambda_A)}\,d\mathbf{r}^N} $$

$$\Large \Delta f = -\ln \left\langle e^{-\Delta u_{B-A}(\mathbf{r}^N)} \right\rangle_{\mathbf{A}} \approx -\ln \left[ \frac{1}{N} \sum_{\mathbf{r}_n^N \in \mathrm{MD}_{\lambda_A}} e^{-\Delta u_{B-A}(\mathbf{r}_n^N)} \right] $$ Reminder: $u(r^N)$ is the reduced potential energy $u=U/(k_B T)$ and $f$ is the reduced free energy $f=F/(k_B T)$.

What are we doing again?¶

We have different potential energy functions... No description has been provided for this image

...and we can draw samples (through simulation) from their equilibrium distribution (presumably).

No description has been provided for this image

Theory Meets Practice¶

  • How to compute free energy differences between alchemical states?
  • How to define alchemical states?
  • How to sample alchemical states?
  • A statistical issue...
  • Evaluation of results?
No description has been provided for this image

How to compute free energy differences between alchemical states?¶

Zwanzig (also called one-sided exponential re-weighting) tends to do the worst - high variance and error when overlap is poor.

  • But is one-sided - only need one simulation

Bennett Acceptance Ratio (BAR)¶

Estimate the free energy difference using equilibrium samples from both states.

Define $\Delta u_{i,j}(\mathbf{r}^N)=u_j(\mathbf{r}^N)-u_i(\mathbf{r}^N)$ and $\Delta f_{i,j}=f_j-f_i$.

For equal numbers of samples from states $i$ and $j$, solve numerically for $\Delta f_{i,j}$:

$$\Large \begin{eqnarray} \sum_{r^N \in \lambda_i \mathrm{MD}} \frac{1}{1 + e^{\Delta u_{i,j}(r^N) - \Delta f_{i,j}}} \nonumber =\sum_{r^N \in \lambda_{j} \mathrm{MD}} \frac{1}{1 + e^{- \Delta u_{i,j}(r^N) + \Delta f_{i,j}}} \end{eqnarray}$$

  • Evaluate both potentials on every sampled configuration.
  • Combines information from both directions, emphasizing configurations in the overlap region.
  • A maximum-likelihood estimator with asymptotically minimum variance under standard sampling assumptions.
  • Usually more statistically efficient than one-sided Zwanzig—but cannot compensate for missing overlap or inadequate sampling.

Shirts MR, Bair E, Hooker G, Pande VS. Equilibrium free energies from nonequilibrium measurements using maximum-likelihood methods. Physical review letters. 2003 Oct 2;91(14):140601. Bennett CH. Efficient estimation of free energy differences from Monte Carlo data. Journal of Computational Physics. 1976 Oct 1;22(2):245-68.

BAR Intuition¶

$$ \begin{eqnarray} \sum_{r^N \in \lambda_i \mathrm{MD}} \frac{1}{1 + e^{\Delta u_{i,j}(r^N) - \Delta f_{i,j}}} \nonumber =\sum_{r^N \in \lambda_{j} \mathrm{MD}} \frac{1}{1 + e^{- \Delta u_{i,j}(r^N) + \Delta f_{i,j}}} \end{eqnarray}$$

Given a configuration, which simulation probably produced it?

The equilibrium probability density of configuration $\mathbf{r}^N$ in state $j$ is $$ p_j(\mathbf{r}^N)=\frac{e^{-u_j(\mathbf{r}^N)}}{Z_j}. $$ $$ \frac{p_i(r^N)}{p_j(r^N)} = \frac{e^{-u_i(r^N)}/Z_i}{e^{-u_j(r^N)}/Z_j} = e^{\Delta u_{i,j}(r^N) - \Delta f_{i,j}}$$

Pool equal numbers of samples from states $i$ and $j$. By Bayes' rule, the probability that a configuration came from $j$ is $$ P(j\mid\mathbf{r}^N) =\frac{p_j(\mathbf{r}^N)}{p_j(\mathbf{r}^N)+p_i(\mathbf{r}^N)} =\frac{1}{1+e^{\Delta u_{i,j}(\mathbf{r}^N)-\Delta f_{i,j}}}, $$ BAR adjusts $\Delta f$ until the total probability assigned to the opposite source is equal in both sample sets.

No description has been provided for this image
No description has been provided for this image

Multistate Bennett Acceptance Ratio (MBAR)¶

This extends BAR to all states at once. Given $K$ $\lambda_k$ simulations:

$$ f_i = -\ln \sum_{n=1}^{N_{\mathrm{tot}}} \frac{e^{-u_i(\mathbf{r}_n^N)}} {\sum_{k=1}^{K} N_k e^{f_k-u_k(\mathbf{r}_n^N)}}. $$

We solve (numerically) for the $K$ free energies $f_k$. There are nice packages to do this (pymbar).

When will MBAR be overkill?

No description has been provided for this image

Thermodynamic Integration¶

With TI we use the derivatives of the free energy with respect to $\lambda$. This is less sensitive to overlap requirements, but suffers from bias in the numerical quadrature (integration).

$$ \frac{df}{d\lambda} = \frac{d}{d\lambda}\left[-\ln Z(\lambda)\right] = \frac{d}{d\lambda}\left[ -\ln \int e^{-u(\mathbf{r}^N,\lambda)}\,d\mathbf{r}^N \right] = \left\langle \frac{\partial u(\mathbf{r}^N,\lambda)}{\partial\lambda} \right\rangle_\lambda $$

$$ \Delta f = \int_0^1 \left\langle \frac{\partial u(\mathbf{r}^N,\lambda)}{\partial\lambda} \right\rangle_\lambda\,d\lambda \approx \sum_{k=1}^{K} w_k \left\langle \frac{\partial u(\mathbf{r}^N,\lambda)}{\partial\lambda} \right\rangle_{\lambda_k} $$

where the weights $w_k$ correspond to a particular choice of numerical integration.

This requires that we compute $\frac{\partial}{\partial\lambda}u(\mathbf{r}^N,\lambda)$

When is that easy?

$$U_\lambda(\mathbf r)=\lambda U(\mathbf r) \quad\Longrightarrow\quad \frac{dF}{d\lambda} =\left\langle\frac{\partial U_\lambda}{\partial\lambda}\right\rangle_\lambda =\boxed{\langle U(\mathbf r)\rangle_\lambda}$$

Defining the Alchemical State¶

Especially with TI, a simple linear scaling, $U(r_N, \lambda) = \lambda U(r_N)$, has numerical issues. (Why?)

Instead, a soft-core potential is used:

$$U({r_N},\lambda) = 4\epsilon_{ij} {\lambda} \left(\frac{1}{(\alpha(1-{\lambda}) + (r_{ij}/\sigma_{ij})^6)^2} - \frac{1}{\alpha(1-{\lambda}) + (r_{ij}/\sigma_{ij})^6}\right)$$

No description has been provided for this image

How to sample alchemical states?¶

Simplest method is independent trajectories (replicas).

No description has been provided for this image

What are the distributions on the right?

Sampling Equilibrium¶

A long enough MD can sample an equilibrium distribution, but it is not the only choice...

MCMC¶

Metropolis-Hastings¶

The Metropolis–Hastings algorithm can draw samples from any probability distribution with probability density $P(x)$, provided that we know a function $f(x)$ proportional to the density $P$ and the values of $f(x)$ can be calculated Wikipedia.

Initialization:

  • Need $g(x\mid y)$ that suggests a candidate for the next sample value $x$, given the previous sample value $y$. This is defined using a move set of perturbations you can apply to your system and might be called the proposal density or jumping distribution. Typically $g(x\mid y) = g(y\mid x)$, if not Hastings provides a correction.
  • Need $f(x)$ whose value is proportional to $P(x)$
  • Pick an initial configuration $x_0$

Metropolis-Hastings (continued)¶

For each iteration $t$:

  • Generate a candidate $x'$ for the next sample by picking from the distribution $g(x'\mid x_t)$
  • Calculate the acceptance ratio $\alpha = f(x')/f(x_t)$ (for symmetric proposals $g(x'\mid x)=g(x\mid x')$)
    • $\alpha = f(x')/f(x_t) = P(x')/P(x_t)$
  • Accept or reject:
    • Generate a uniform random number $r_u \in [0, 1]$
    • If $r_u \le \alpha$, then accept: $x_{t+1} = x'$
    • If $r_u > \alpha$, then reject: $x_{t+1} = x_t$

Why does this work?¶

We are essentially constructing (a very very large) Markov state model with transition probabilities $P(x'\mid x)$

If the transition probabilities fulfills detailed balance: $$P(x'\mid x)P(x) = P(x\mid x')P(x')$$

then there exists a stationary distribution $\pi$. That is, under reasonable assumptions (e.g. ergodicity), enough sampling will converge to $P(x)$.

With Metropolis, the transition probability is the product of the acceptance probability $A$ and the proposal probability $g$:

$$P(x'|x) = g(x'|x) A(x',x)$$

Plug this into the detailed balance equation and show that $$A(x', x) = \min\left(1, \frac{P(x')}{P(x)} \frac{g(x \mid x')}{g(x' \mid x)}\right)$$ fullfills detailed balance.

MCMC: Markov chain Monte Carlo¶

No description has been provided for this image

Metropolis-Hastings is one of a family of algorithms for stochastically sampling a probability distribution by constructing a Markov chain.

Although the algorithm produces a trajectory of states, it does not produce correct dynamics. What does this mean?

Ideally MCMC will get to equilibrium faster than traditional dynamics.

Move set can be non-physical, but must be ergodic.

Jin SS, Ju H, Jung HJ. Adaptive Markov chain Monte Carlo algorithms for Bayesian inference: recent advances and comparative study. Structure and Infrastructure Engineering. 2019 Nov 2;15(11):1548-65.

Assign2/3 Revisited¶

In [7]:
import openmm
from openmm.app import *
from openmm import *
from openmm.unit import *
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
import scipy, os
import argparse
import scipy.signal

def dihedral(p1, p2, p3, p4):
    '''Return dihedral angle in radians between provided points.
    This is the same calculation used by OpenMM for force calculations. '''
    v12 = np.array(p1-p2)
    v32 = np.array(p3-p2)
    v34 = np.array(p3-p4)
    
    #compute cross products 
    cp0 = np.cross(v12,v32)
    cp1 = np.cross(v32,v34)
    
    #get angle between cross products
    dot = np.dot(cp0,cp1)
    if dot != 0:
        norm1 = np.dot(cp0,cp0)
        norm2 = np.dot(cp1,cp1)
        dot /= np.sqrt(norm1*norm2)
        
    if dot > 1.0:
        dot = 1.0
    elif dot < -1.0:
        dot = -1.0

    if dot > 0.99 or dot < -0.99:
        #close to acos singularity, so use asin isntead
        cross = np.cross(cp0,cp1)
        scale = np.dot(cp0,cp0)*np.dot(cp1,cp1)
        angle = np.arcsin(np.sqrt(np.dot(cross,cross)/scale))
        if dot < 0.0:
            angle = np.pi - angle
    else:
        angle = np.arccos(dot)
    
    #figure out sign
    sdot = np.dot(v12,cp1)
    angle *= np.sign(sdot)
    return angle
    
    
def make_rotation_matrix(p1, p2, angle):
    '''Make a rotation matrix for rotating angle radians about the p2-p1 axis'''
    # https://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_and_angle
    vec = np.array((p2-p1))
    x,y,z = vec/np.linalg.norm(vec)
    cos = np.cos(angle)
    sin = np.sin(angle)
    R = np.array([[cos+x*x*(1-cos), x*y*(1-cos)-z*sin, x*z*(1-cos)+y*sin],
                  [y*x*(1-cos)+z*sin, cos+y*y*(1-cos), y*z*(1-cos)-x*sin],
                  [z*x*(1-cos)-y*sin, z*y*(1-cos)+x*sin, cos+z*z*(1-cos)]])
    return R
    
    
def moving_atoms(pdb,a=1,b=2):
    '''Identify the atoms on the b side of a dihedral with the central
    atoms a and b.  This is not the most efficient algorithm, but 
    for small molecules it really does not matter.
    A boolean mask of these atoms is returned.'''
    moving = np.zeros(pdb.topology.getNumAtoms())
    moving[b] = 1
    moving[a] = -1
    changed = True
    while changed:
        changed = False
        for b in pdb.topology.bonds():
            if (moving[b.atom1.index] + moving[b.atom2.index]) == 1:
                moving[b.atom1.index] = moving[b.atom2.index] = 1
                changed = True
    moving[1] = 0    
    return moving.astype(bool)      
In [8]:
# read file
pdb = PDBFile('data/gly.pdb')

# setup openmm system using amber 14 forcefield which defines the potential energy function
ff = ForceField('amber14-all.xml')
system = ff.createSystem(pdb.topology,ignoreExternalBonds=True)
# we aren't actually simulating, but need a simulation object to calculate energies
integrator = VerletIntegrator(1*femtosecond)
simulation = Simulation(pdb.topology, system, integrator)

# store atom positions
# note that more code is necessary for this code to be a general solution
# as opposed to only working with our carefully prepared inputs
origpos = np.array(pdb.getPositions()._value)
newpos = origpos.copy()

aindex, bindex = 1,2
capos = origpos[aindex]
cpos = origpos[bindex]

# a boolean mask of the atoms that should be rotated around the dihedral
mask = moving_atoms(pdb, aindex, bindex)
In [9]:
def get_energy(d):
    '''Return energy for amino acid at given dihedral value d (in degrees)'''
    R = make_rotation_matrix(capos,cpos,np.deg2rad(d))    
    newpos[mask] = np.matmul(R,origpos[mask].T).T     
    # setPositions to newpos in simulation 
    simulation.context.setPositions(newpos)
    # get simulation.context state, fetching energy
    state = simulation.context.getState(getEnergy=True)
    # record the energy
    return state.getPotentialEnergy()
    
energies = []
angles = []
for d in range(0,360,1):
    # record the energy
    energies.append(get_energy(d))
    # record the dihedral
    d = dihedral(*newpos[:4])
    if d < 0: d += 2*np.pi
    angles.append(np.rad2deg(d))
In [10]:
E = [e._value for e in energies] # unitless for numpy manipulation
T = 300*kelvin
weights = np.array([np.exp(-e/(MOLAR_GAS_CONSTANT_R*T)) for e in energies])
Z = weights.sum()
probs = weights/Z
In [11]:
plt.figure(figsize=(8,4),dpi=300); plt.plot(angles,probs); plt.xlabel("Dihedral (Degrees)"); plt.ylabel("Probability (at 300K)"); plt.xlim(0,360); plt.title('GLY');
No description has been provided for this image

Implementing MCMC¶

In [12]:
def run_mcmc(scale=360,steps=100000,T=300*kelvin,initd=0):    
    '''Return unnormalized distribution of angles from MCMC'''
    anglecnts = np.zeros(360)
    d = initd
    lastE = get_energy(d)
    lastP = np.exp(-lastE/(MOLAR_GAS_CONSTANT_R*T))
    # d is last evaluated dihedral
    for t in range(steps):    
        #propose a move
        dprime = (d + (2*np.random.random()-1)*scale)%360

        R = make_rotation_matrix(capos,cpos,np.deg2rad(dprime))    
        newpos[mask] = np.matmul(R,origpos[mask].T).T

        # setPositions to newpos in simulation 
        simulation.context.setPositions(newpos)
        state = simulation.context.getState(getEnergy=True)
        Eprime = state.getPotentialEnergy()
        Pprime = np.exp(-Eprime/(MOLAR_GAS_CONSTANT_R*T))
        # Metropolis
        if Pprime >= lastP or (np.random.random() < Pprime/lastP): # make move
            d = dprime
            anglecnts[int(np.trunc(d))] += 1
            lastP = Pprime
            lastE = Eprime
        else:
            anglecnts[int(np.trunc(d))] += 1
    return anglecnts,d
In [13]:
cnts, d = run_mcmc(steps=100000)
P = cnts/cnts.sum()
In [14]:
plt.figure(figsize=(8,4),dpi=300); plt.plot(angles,probs); plt.xlabel("Dihedral (Degrees)"); plt.ylabel("Probability (at 300K)"); plt.xlim(0,360)
plt.bar(angles,P,width=1.0,color='gold');
No description has been provided for this image

Effect of move set choice?¶

How will changing the scale factor below change how the algorithm behaves?

In [16]:
dprime = (d + (2*np.random.random()-1)*scale)%360
In [17]:
%%html
<div id="mcmcscale" style="width: 500px"></div>
<script>
$('head').append('<link rel="stylesheet" href="https://bits.csb.pitt.edu/asker.js/themes/asker.default.css" />');

    var divid = '#mcmcscale';
	jQuery(divid).asker({
	    id: divid,
	    question: "A smaller scale will make the convergence to the target probability distribution...",
		answers: ['Slower','Faster','Inaccurate','Nonergodic'],
        server: "https://bits.csb.pitt.edu/asker.js/example/asker.cgi",
		charter: chartmaker})
    
$(".jp-InputArea .o:contains(html)").closest('.jp-InputArea').hide();


</script>
In [39]:
cnts = np.zeros(360)
fig = plt.figure(figsize=(8,4)); plt.xlabel("Dihedral (Degrees)"); plt.ylabel("Probability (at 300K)"); plt.xlim(0,360); plt.plot(angles,probs); 
ax = plt.gca()
N = 20
lastd = 0
def make_fig(i):
    global cnts, lastd #the horror!
    C, lastd = run_mcmc(steps=500,initd=lastd)
    cnts += C
    P = cnts/cnts.sum()
    ax.bar(angles,P,width=1.0,color=cm.hot(i/N),alpha=.8);

anim = FuncAnimation(fig,make_fig,frames=range(N),interval=500)
video = anim.to_html5_video()
plt.close()     
In [40]:
html = display.HTML(video)
display.display(html)
Your browser does not support the video tag.
In [41]:
cnts = np.zeros(360)
fig = plt.figure(figsize=(8,4)); plt.xlabel("Dihedral (Degrees)"); plt.ylabel("Probability (at 300K)"); plt.xlim(0,360); plt.plot(angles,probs); 
ax = plt.gca()
N = 20
lastd = 0
def make_fig(i):
    global cnts, lastd #the horror!
    C, lastd = run_mcmc(scale=5,steps=500,initd=lastd)
    cnts += C
    P = cnts/cnts.sum()
    ax.bar(angles,P,width=1.0,color=cm.hot(i/N),alpha=.8);

anim = FuncAnimation(fig,make_fig,frames=range(N),interval=500)
video = anim.to_html5_video()
plt.close()     
In [42]:
html = display.HTML(video)
display.display(html)
Your browser does not support the video tag.

Metropolis algorithm step $t$ for MonteCarloBarostat¶

No description has been provided for this image
  1. Generate a candidate $x'$ from distribution $g(x' | x_t)$
    • $\Delta V = A r$, $A$ is a scale factor, $r$ is a uniform random number [-1,1]
    • Box is scaled to achieve $\Delta V$ - molecules are moved farther apart to be less dense (or closer to be more dense)
  2. Calculate a weight function
    • $\Delta W=\Delta E+P\Delta V-Nk_{B}T \text{ln}\left(\frac{V+\Delta V}{V}\right)$
    • $\Delta E$ is change in potential energy due to box resizing
  3. Accept or reject
    • If $\Delta W \le 0$
      • Leave the box resized
    • Else $\Delta W \gt 0$
      • Keep box resized with probability $e^{-\frac{\Delta W }{ k_B T}}$
In [19]:
import py3Dmol
import openmm
from openmm.app import *
from openmm.unit import *
from openmm.openmm import *

modeller = Modeller(Topology(),[])
forcefield = ForceField('amber14-all.xml', 'amber14/tip3p.xml')
modeller.addSolvent(forcefield,boxSize=(5,5,5),ionicStrength=.01*molar)

system = forcefield.createSystem(modeller.topology,  nonbondedMethod=PME,constraints=HBonds)
barostat = MonteCarloBarostat(1*atmospheres, 300*kelvin, 250)
system.addForce(barostat)

simulation = Simulation(modeller.topology, system, LangevinIntegrator(300*kelvin,1/picosecond,2*femtosecond))
simulation.context.setPositions(modeller.positions)
simulation.minimizeEnergy()
simulation.reporters.append(StateDataReporter('outputp.txt', 1, step=True, volume=True,
        potentialEnergy=True, kineticEnergy=True, totalEnergy=True, temperature=True))


simulation.step(25000)
In [21]:
import pandas as pd
datap = pd.read_csv('outputp.txt')
datap['Box Volume (nm^3)'].plot()
plt.legend(); plt.xlabel('Frame');
No description has been provided for this image

Hamiltonian Replica Exchange¶

We want our sampled conformations to overlap between alchemical states, so let's allow our trajectories to move between alchemical states to speed up mixing.

If we're careful, we can do this and still sample the correct (Boltzmann) distributions of each state.

No description has been provided for this image

Metropolis Criteria¶

We don't want to arbitrarily move between alchemical states. We will only swap conformations between states if they are reasonably likely in the new state.

Consider two alchemical states $i, j$ with corresponding conformations $r^N_i$, $r^N_j$. Then we will swap with probability:

$$\Large \begin{split}P_{\text{accept}}(i, r^N_i, j, r^N_j) &= \text{min}\left( 1, \frac{ e^{-\left[u_i(r^N_j) + u_j(r^N_i)\right]}}{e^{-\left[u_i(r^N_i) + u_j(r^N_j)\right]}} \right) \\ &= \text{min}\left( 1, e^\left[-\Delta u_{ij}(r^N_i) - \Delta u_{ji}(r^N_j)\right] \right) \end{split}$$ Given enough sampling, this will converge to the correct distributions while enhancing mixing (the different alchemical states will have overlapping conformations).

Gibbs sampling considers swapping between all alchemical states at once (not just neighbors).

Relative Free Energy Calculations (FEP)¶

Instead of removing the ligand, convert the ligand to a different ligand to get a $\Delta\Delta G$

No description has been provided for this image

FEP Topologies¶

Need to identify the atoms that should stay the same - the maximum common substructure (MCS).

Rings require special treatment.

No description has been provided for this image

FEP Topologies¶

No description has been provided for this image

Two methods for dealing with changing atoms:

A single topology (left side): atoms interconvert between molecules (e.g., a hydrogen can become a carbon).

A dual topology (right side): atoms interconvert to "dummy" atoms.

Choice largely depends on software package, although fewer dummy atoms is assumed to be better.

Which topology has fewer dummy atoms?

What do we do with $\lambda$?

No description has been provided for this image

FEP Networks¶

FEP is usually used during lead optimization to evaluate possible (small) modifications to a lead compound.

No description has been provided for this image

FEP Networks¶

Where things get exciting is when we perform FEP calculations not only with respect to the known ligand, but between putative ligands.

This lets us compute cycle closure error.

How would you exploit this if you were the computational biologist in charge of running FEP calculations at a large pharmaceutical with a large computing budget (assume the dominant source of error is insufficient sampling)?

FEP Networks¶

Intelligent network choices can increase the accuracy of calculations.

No description has been provided for this image

Yang Q, Burchett W, Steeno GS, Liu S, Yang M, Mobley DL, Hou X. Optimal designs for pairwise calculation: An application to free energy perturbation in minimizing prediction variability. Journal of computational chemistry. 2020 Jan 30;41(3):247-57.

Relative vs Absolute¶

No description has been provided for this image

Chen W, Cui D, Abel R, Friesner RA, Wang L. Accurate calculation of absolute protein-ligand binding free energies. 2022

https://openfree.energy/¶

Key Points¶

  • FEP: Free Energy Perturbation
    • Important: Need correct binding pose
  • Can estimate free energy differences along alchemical paths
    • Need overlapping samples: can increase with replica-exchange
    • Need to compute $\Delta f$: MBAR, TI
  • ABFE vs RBFE
  • FEP networks
    • cycle closure
  • MCMC
    • samples equilibrium distributions with relative probabilities
    • useful moves can be nonphysical