예제 #1
0
    bar_analytical = (f_k_analytical[k1] - f_k_analytical[k])
    bar_error = bar_analytical - df_bar
    print(
        "BAR estimator for reduced free energy from states %d to %d is %f +/- %f"
        % (k, k1, df_bar, ddf_bar))
    stddev_away("BAR estimator", bar_error, ddf_bar)

print("==============================================")
print("             Testing computeEXP               ")
print("==============================================")

print("EXP forward free energy")
for k in range(K - 1):
    if N_k[k] != 0:
        w_F = u_kln[k, k + 1, 0:N_k[k]] - u_kln[k, k, 0:N_k[k]]  # forward work
        results = EXP(w_F)
        df_exp = results['Delta_f']
        ddf_exp = results['dDelta_f']
        exp_analytical = (f_k_analytical[k + 1] - f_k_analytical[k])
        exp_error = exp_analytical - df_exp
        print("df from states %d to %d is %f +/- %f" %
              (k, k + 1, df_exp, ddf_exp))
        stddev_away("df", exp_error, ddf_exp)

print("EXP reverse free energy")
for k in range(1, K):
    if N_k[k] != 0:
        w_R = u_kln[k, k - 1, 0:N_k[k]] - u_kln[k, k, 0:N_k[k]]  # reverse work
        (df_exp, ddf_exp) = EXP(w_R)
        df_exp = -results['Delta_f']
        ddf_exp = results['dDelta_f']
예제 #2
0
def check_alchemical_null_elimination(topology_proposal,
                                      positions,
                                      ncmc_nsteps=50,
                                      NSIGMA_MAX=6.0,
                                      geometry=False):
    """
    Test alchemical elimination engine on null transformations, where some atoms are deleted and then reinserted in a cycle.

    Parameters
    ----------
    topology_proposal : TopologyProposal
        The topology proposal to test.
        This must be a null transformation, where topology_proposal.old_system == topology_proposal.new_system
    ncmc_steps : int, optional, default=50
        Number of NCMC switching steps, or 0 for instantaneous switching.
    NSIGMA_MAX : float, optional, default=6.0
        Number of standard errors away from analytical solution tolerated before Exception is thrown
    geometry : bool, optional, default=None
        If True, will also use geometry engine in the middle of the null transformation.
    """
    # Initialize engine
    from perses.annihilation.ncmc_switching import NCMCEngine
    ncmc_engine = NCMCEngine(temperature=temperature, nsteps=ncmc_nsteps)

    # Make sure that old system and new system are identical.
    if not (topology_proposal.old_system == topology_proposal.new_system):
        raise Exception(
            "topology_proposal must be a null transformation for this test (old_system == new_system)"
        )
    for (k, v) in topology_proposal.new_to_old_atom_map.items():
        if k != v:
            raise Exception(
                "topology_proposal must be a null transformation for this test (retailed atoms must map onto themselves)"
            )

    nequil = 5  # number of equilibration iterations
    niterations = 50  # number of round-trip switching trials
    logP_insert_n = np.zeros([niterations], np.float64)
    logP_delete_n = np.zeros([niterations], np.float64)
    logP_switch_n = np.zeros([niterations], np.float64)
    for iteration in range(nequil):
        [positions, velocities] = simulate(topology_proposal.old_system,
                                           positions)
    for iteration in range(niterations):
        # Equilibrate
        [positions, velocities] = simulate(topology_proposal.old_system,
                                           positions)

        # Check that positions are not NaN
        if (np.any(np.isnan(positions / unit.angstroms))):
            raise Exception("Positions became NaN during equilibration")

        # Delete atoms
        [positions, logP_delete,
         potential_delete] = ncmc_engine.integrate(topology_proposal,
                                                   positions,
                                                   direction='delete')

        # Check that positions are not NaN
        if (np.any(np.isnan(positions / unit.angstroms))):
            raise Exception("Positions became NaN on NCMC deletion")

        # Insert atoms
        [positions, logP_insert,
         potential_insert] = ncmc_engine.integrate(topology_proposal,
                                                   positions,
                                                   direction='insert')

        # Check that positions are not NaN
        if (np.any(np.isnan(positions / unit.angstroms))):
            raise Exception("Positions became NaN on NCMC insertion")

        # Compute probability of switching geometries.
        logP_switch = -(potential_insert - potential_delete)

        # Compute total probability
        logP_delete_n[iteration] = logP_delete
        logP_insert_n[iteration] = logP_insert
        logP_switch_n[iteration] = logP_switch
        #print("Iteration %5d : delete %16.8f kT | insert %16.8f kT | geometry switch %16.8f" % (iteration, logP_delete, logP_insert, logP_switch))

    # Check free energy difference is withing NSIGMA_MAX standard errors of zero.
    logP_n = logP_delete_n + logP_insert_n + logP_switch_n
    work_n = -logP_n
    from pymbar import EXP
    [df, ddf] = EXP(work_n)
    #print("df = %12.6f +- %12.5f kT" % (df, ddf))
    if (abs(df) > NSIGMA_MAX * ddf):
        msg = 'Delta F (%d steps switching) = %f +- %f kT; should be within %f sigma of 0\n' % (
            ncmc_nsteps, df, ddf, NSIGMA_MAX)
        msg += 'delete logP:\n'
        msg += str(logP_delete_n) + '\n'
        msg += 'insert logP:\n'
        msg += str(logP_insert_n) + '\n'
        msg += 'logP:\n'
        msg += str(logP_n) + '\n'
        raise Exception(msg)
예제 #3
0
def overlap_check(reference_system,
                  positions,
                  receptor_atoms,
                  ligand_atoms,
                  platform_name=None,
                  annihilate_electrostatics=True,
                  annihilate_sterics=False,
                  precision=None,
                  nsteps=50,
                  nsamples=200):
    """
    Test overlap between reference system and alchemical system by running a short simulation.

    Parameters
    ----------
    reference_system : simtk.openmm.System
       The reference System object to compare with
    positions : simtk.unit.Quantity with units compatible with nanometers
       The positions to assess energetics for.
    receptor_atoms : list of int
       The list of receptor atoms.
    ligand_atoms : list of int
       The list of ligand atoms to alchemically modify.
    platform_name : str, optional, default=None
       The name of the platform to use for benchmarking.
    annihilate_electrostatics : bool, optional, default=True
       If True, electrostatics will be annihilated; if False, decoupled.
    annihilate_sterics : bool, optional, default=False
       If True, sterics will be annihilated; if False, decoupled.
    nsteps : int, optional, default=50
       Number of molecular dynamics steps between samples.
    nsamples : int, optional, default=100
       Number of samples to collect.

    """

    # Create a fully-interacting alchemical state.
    factory = AbsoluteAlchemicalFactory(reference_system,
                                        ligand_atoms=ligand_atoms)
    alchemical_state = AlchemicalState(0.00, 1.00, 1.00, 1.0)
    alchemical_system = factory.createPerturbedSystem(alchemical_state)

    temperature = 300.0 * units.kelvin
    collision_rate = 5.0 / units.picoseconds
    timestep = 2.0 * units.femtoseconds
    kT = (kB * temperature)

    # Select platform.
    platform = None
    if platform_name:
        platform = openmm.Platform.getPlatformByName(platform_name)

    # Create integrators.
    reference_integrator = openmm.LangevinIntegrator(temperature,
                                                     collision_rate, timestep)
    alchemical_integrator = openmm.VerletIntegrator(timestep)

    # Create contexts.
    if platform:
        reference_context = openmm.Context(reference_system,
                                           reference_integrator, platform)
        alchemical_context = openmm.Context(alchemical_system,
                                            alchemical_integrator, platform)
    else:
        reference_context = openmm.Context(reference_system,
                                           reference_integrator)
        alchemical_context = openmm.Context(alchemical_system,
                                            alchemical_integrator)

    # Collect simulation data.
    reference_context.setPositions(positions)
    du_n = np.zeros([nsamples], np.float64)  # du_n[n] is the
    for sample in range(nsamples):
        # Run dynamics.
        reference_integrator.step(nsteps)

        # Get reference energies.
        reference_state = reference_context.getState(getEnergy=True,
                                                     getPositions=True)
        reference_potential = reference_state.getPotentialEnergy()

        # Get alchemical energies.
        alchemical_context.setPositions(reference_state.getPositions())
        alchemical_state = alchemical_context.getState(getEnergy=True)
        alchemical_potential = alchemical_state.getPotentialEnergy()

        du_n[sample] = (alchemical_potential - reference_potential) / kT

    # Clean up.
    del reference_context, alchemical_context

    # Discard data to equilibration and subsample.
    from pymbar import timeseries
    [t0, g, Neff] = timeseries.detectEquilibration(du_n)
    indices = timeseries.subsampleCorrelatedData(du_n, g=g)
    du_n = du_n[indices]

    # Compute statistics.
    from pymbar import EXP
    [DeltaF, dDeltaF] = EXP(du_n)

    # Raise an exception if the error is larger than 3kT.
    MAX_DEVIATION = 3.0  # kT
    if (dDeltaF > MAX_DEVIATION):
        report = "DeltaF = %12.3f +- %12.3f kT (%5d samples, g = %6.1f)" % (
            DeltaF, dDeltaF, Neff, g)
        raise Exception(report)

    return
    bar_analytical = (f_k_analytical[k1] - f_k_analytical[k])
    bar_error = bar_analytical - df_bar
    print "BAR estimator for reduced free energy from states %d to %d is %f +/- %f" % (
        k, k1, df_bar, ddf_bar)
    print "BAR estimator differs by %f standard deviations" % numpy.abs(
        bar_error / ddf_bar)

print "=============================================="
print "             Testing computeEXP               "
print "=============================================="

print "EXP forward free energy"
for k in range(K - 1):
    if N_k[k] != 0:
        w_F = u_kln[k, k + 1, 0:N_k[k]] - u_kln[k, k, 0:N_k[k]]  # forward work
        (df_exp, ddf_exp) = EXP(w_F)
        exp_analytical = (f_k_analytical[k + 1] - f_k_analytical[k])
        exp_error = exp_analytical - df_exp
        print "df from states %d to %d is %f +/- %f" % (k, k + 1, df_exp,
                                                        ddf_exp)
        print "df differs by %f standard deviations from analytical" % numpy.abs(
            exp_error / ddf_exp)

print "EXP reverse free energy"
for k in range(1, K):
    if N_k[k] != 0:
        w_R = u_kln[k, k - 1, 0:N_k[k]] - u_kln[k, k, 0:N_k[k]]  # reverse work
        (df_exp, ddf_exp) = EXP(w_R)
        df_exp = -df_exp
        exp_analytical = (f_k_analytical[k] - f_k_analytical[k - 1])
        exp_error = exp_analytical - df_exp
예제 #5
0
def check_hybrid_null_elimination(topology_proposal,
                                  positions,
                                  new_positions,
                                  ncmc_nsteps=50,
                                  NSIGMA_MAX=6.0,
                                  geometry=False):
    """
    Test alchemical elimination engine on null transformations, where some atoms are deleted and then reinserted in a cycle.

    Parameters
    ----------
    topology_proposal : TopologyProposal
        The topology proposal to test.
        This must be a null transformation, where topology_proposal.old_system == topology_proposal.new_system
    ncmc_steps : int, optional, default=50
        Number of NCMC switching steps, or 0 for instantaneous switching.
    NSIGMA_MAX : float, optional, default=6.0
        Number of standard errors away from analytical solution tolerated before Exception is thrown
    geometry : bool, optional, default=None
        If True, will also use geometry engine in the middle of the null transformation.
    """
    functions = {
        'lambda_sterics': 'lambda',
        'lambda_electrostatics': 'lambda',
        'lambda_bonds': 'lambda',
        'lambda_angles': 'lambda',
        'lambda_torsions': 'lambda'
    }
    # Initialize engine
    from perses.annihilation.ncmc_switching import NCMCHybridEngine
    ncmc_engine = NCMCHybridEngine(temperature=temperature,
                                   functions=functions,
                                   nsteps=ncmc_nsteps)

    # Make sure that old system and new system are identical.
    # if not (topology_proposal.old_system == topology_proposal.new_system):
    #     raise Exception("topology_proposal must be a null transformation for this test (old_system == new_system)")
    # for (k,v) in topology_proposal.new_to_old_atom_map.items():
    #     if k != v:
    #         raise Exception("topology_proposal must be a null transformation for this test (retailed atoms must map onto themselves)")

    nequil = 5  # number of equilibration iterations
    niterations = 50  # number of round-trip switching trials
    logP_work_n = np.zeros([niterations], np.float64)
    for iteration in range(nequil):
        [positions, velocities] = simulate(topology_proposal.old_system,
                                           positions)
    for iteration in range(niterations):
        # Equilibrate
        [positions, velocities] = simulate(topology_proposal.old_system,
                                           positions)

        # Check that positions are not NaN
        if (np.any(np.isnan(positions / unit.angstroms))):
            raise Exception("Positions became NaN during equilibration")

        # Hybrid NCMC from old to new
        [_, new_old_positions, logP_work,
         logP_energy] = ncmc_engine.integrate(topology_proposal, positions,
                                              positions)

        # Check that positions are not NaN
        if (np.any(np.isnan(positions / unit.angstroms))):
            raise Exception("Positions became NaN on Hybrid NCMC switch")

        # Store log probability associated with work
        logP_work_n[iteration] = logP_work
        #print("Iteration %5d : NCMC work %16.8f kT | NCMC energy %16.8f kT" % (iteration, logP_work, logP_energy))

    # Check free energy difference is withing NSIGMA_MAX standard errors of zero.
    work_n = -logP_work_n
    from pymbar import EXP
    [df, ddf] = EXP(work_n)
    print("df = %12.6f +- %12.5f kT" % (df, ddf))
    if (abs(df) > NSIGMA_MAX * ddf):
        msg = 'Delta F (%d steps switching) = %f +- %f kT; should be within %f sigma of 0\n' % (
            ncmc_nsteps, df, ddf, NSIGMA_MAX)
        msg += 'logP_work_n:\n'
        msg += str(logP_work_n) + '\n'
        raise Exception(msg)
예제 #6
0
  df_bar = results['Delta_f']
  ddf_bar = results['dDelta_f']
  bar_analytical = (f_k_analytical[k1]-f_k_analytical[k]) 
  bar_error = bar_analytical - df_bar
  print("BAR estimator for reduced free energy from states %d to %d is %f +/- %f" % (k,k1,df_bar,ddf_bar)) 
  stddev_away("BAR estimator",bar_error,ddf_bar)

print("==============================================")
print("             Testing computeEXP               ")
print("==============================================")

print("EXP forward free energy")
for k in range(K-1):
  if N_k[k] != 0:
    w_F = u_kln[k, k+1, 0:N_k[k]]   - u_kln[k, k, 0:N_k[k]]       # forward work
    results = EXP(w_F, return_dict=True)
    df_exp = results['Delta_f']
    ddf_exp = results['dDelta_f']
    exp_analytical = (f_k_analytical[k+1]-f_k_analytical[k]) 
    exp_error = exp_analytical - df_exp
    print("df from states %d to %d is %f +/- %f" % (k,k+1,df_exp,ddf_exp)) 
    stddev_away("df",exp_error,ddf_exp)

print("EXP reverse free energy")
for k in range(1,K):
  if N_k[k] != 0:
    w_R = u_kln[k, k-1, 0:N_k[k]] - u_kln[k, k, 0:N_k[k]]         # reverse work                                  
    (df_exp,ddf_exp) = EXP(w_R, return_dict=True)
    df_exp = -results['Delta_f']
    ddf_exp = results['dDelta_f']
    exp_analytical = (f_k_analytical[k]-f_k_analytical[k-1])