def test_generate_endpoint_thermodynamic_states(): """ test whether the hybrid system zero and one thermodynamic states have the appropriate lambda values """ topology_proposal, current_positions, new_positions = utils.generate_solvated_hybrid_test_topology( current_mol_name='propane', proposed_mol_name='pentane', vacuum=False) hybrid_factory = HybridTopologyFactory(topology_proposal, current_positions, new_positions, use_dispersion_correction=True) #get the relevant thermodynamic states: _, _, lambda_zero_thermodynamic_state, lambda_one_thermodynamic_state = utils.generate_endpoint_thermodynamic_states( hybrid_factory.hybrid_system, topology_proposal) # check the parameters for each state lambda_protocol = [ 'lambda_sterics_core', 'lambda_electrostatics_core', 'lambda_sterics_insert', 'lambda_electrostatics_insert', 'lambda_sterics_delete', 'lambda_electrostatics_delete' ] for value in lambda_protocol: if getattr(lambda_zero_thermodynamic_state, value) != 0.: raise Exception( 'Interaction {} not set to 0. at lambda = 0. {} set to {}'. format(value, value, getattr(lambda_one_thermodynamic_state, value))) if getattr(lambda_one_thermodynamic_state, value) != 1.: raise Exception( 'Interaction {} not set to 1. at lambda = 1. {} set to {}'. format(value, value, getattr(lambda_one_thermodynamic_state, value)))
def compare_energies(mol_name="naphthalene", ref_mol_name="benzene"): """ Make an atom map where the molecule at either lambda endpoint is identical, and check that the energies are also the same. """ from openmmtools import alchemy, states from perses.rjmc.topology_proposal import SmallMoleculeSetProposalEngine, TopologyProposal from perses.annihilation.relative import HybridTopologyFactory import simtk.openmm as openmm from perses.utils.openeye import createSystemFromIUPAC from openmoltools.openeye import iupac_to_oemol, generate_conformers mol = iupac_to_oemol(mol_name) mol = generate_conformers(mol, max_confs=1) m, system, positions, topology = createSystemFromIUPAC(mol_name) refmol = iupac_to_oemol(ref_mol_name) refmol = generate_conformers(refmol, max_confs=1) #map one of the rings atom_map = SmallMoleculeSetProposalEngine._get_mol_atom_map(mol, refmol) #now use the mapped atoms to generate a new and old system with identical atoms mapped. This will result in the #same molecule with the same positions for lambda=0 and 1, and ensures a contiguous atom map effective_atom_map = {value: value for value in atom_map.values()} #make a topology proposal with the appropriate data: top_proposal = TopologyProposal(new_topology=topology, new_system=system, old_topology=topology, old_system=system, new_to_old_atom_map=effective_atom_map, new_chemical_state_key="n1", old_chemical_state_key='n2') factory = HybridTopologyFactory(top_proposal, positions, positions) alchemical_system = factory.hybrid_system alchemical_positions = factory.hybrid_positions platform = openmm.Platform.getPlatformByName("Reference") _, _, alch_zero_state, alch_one_state = utils.generate_endpoint_thermodynamic_states( alchemical_system, top_proposal) rp_list = [] for state in [alch_zero_state, alch_one_state]: integrator = openmm.VerletIntegrator(1) context = state.create_context(integrator, platform) samplerstate = states.SamplerState( positions=alchemical_positions, box_vectors=alchemical_system.getDefaultPeriodicBoxVectors()) samplerstate.apply_to_context(context) rp = state.reduced_potential(context) rp_list.append(rp) del context, integrator assert abs(rp_list[0] - rp_list[1]) < 1e-6
def test_generate_endpoint_thermodynamic_states(): topology_proposal, current_positions, new_positions = utils.generate_vacuum_topology_proposal(current_mol_name='propane', proposed_mol_name='pentane') hybrid_factory = HybridTopologyFactory(topology_proposal, current_positions, new_positions, use_dispersion_correction=True) #get the relevant thermodynamic states: _, _, lambda_zero_thermodynamic_state, lambda_one_thermodynamic_state = utils.generate_endpoint_thermodynamic_states(hybrid_factory.hybrid_system, topology_proposal) # check the parameters for each state lambda_protocol = ['lambda_sterics_core','lambda_electrostatics_core','lambda_sterics_insert','lambda_electrostatics_insert','lambda_sterics_delete','lambda_electrostatics_delete'] for value in lambda_protocol: if getattr(lambda_zero_thermodynamic_state, value) != 0.: raise Exception('Interaction {} not set to 0. at lambda = 0. {} set to {}'.format(value,value, getattr(lambda_one_thermodynamic_state, value))) if getattr(lambda_one_thermodynamic_state, value) != 1.: raise Exception('Interaction {} not set to 1. at lambda = 1. {} set to {}'.format(value,value, getattr(lambda_one_thermodynamic_state, value)))
def HybridTopologyFactory_energies( current_mol='toluene', proposed_mol='1,2-bis(trifluoromethyl) benzene'): """ Test whether the difference in the nonalchemical zero and alchemical zero states is the forward valence energy. Also test for the one states. """ from perses.tests.utils import generate_solvated_hybrid_test_topology, generate_endpoint_thermodynamic_states import openmmtools.cache as cache #Just test the solvated system top_proposal, old_positions, _ = generate_solvated_hybrid_test_topology( current_mol_name=current_mol, proposed_mol_name=proposed_mol) #remove the dispersion correction top_proposal._old_system.getForce(3).setUseDispersionCorrection(False) top_proposal._new_system.getForce(3).setUseDispersionCorrection(False) # run geometry engine to generate old and new positions _geometry_engine = FFAllAngleGeometryEngine(metadata=None, use_sterics=False, n_bond_divisions=100, n_angle_divisions=180, n_torsion_divisions=360, verbose=True, storage=None, bond_softening_constant=1.0, angle_softening_constant=1.0, neglect_angles=False) _new_positions, _lp = _geometry_engine.propose(top_proposal, old_positions, beta) _lp_rev = _geometry_engine.logp_reverse(top_proposal, _new_positions, old_positions, beta) # make the hybrid system, reset the CustomNonbondedForce cutoff HTF = HybridTopologyFactory(top_proposal, old_positions, _new_positions) hybrid_system = HTF.hybrid_system nonalch_zero, nonalch_one, alch_zero, alch_one = generate_endpoint_thermodynamic_states( hybrid_system, top_proposal) # compute reduced energies #for the nonalchemical systems... attrib_list = [(nonalch_zero, old_positions, top_proposal._old_system.getDefaultPeriodicBoxVectors()), (alch_zero, HTF._hybrid_positions, hybrid_system.getDefaultPeriodicBoxVectors()), (alch_one, HTF._hybrid_positions, hybrid_system.getDefaultPeriodicBoxVectors()), (nonalch_one, _new_positions, top_proposal._new_system.getDefaultPeriodicBoxVectors())] rp_list = [] for (state, pos, box_vectors) in attrib_list: context, integrator = cache.global_context_cache.get_context(state) samplerstate = SamplerState(positions=pos, box_vectors=box_vectors) samplerstate.apply_to_context(context) rp = state.reduced_potential(context) rp_list.append(rp) #valence energy definitions forward_added_valence_energy = _geometry_engine.forward_final_context_reduced_potential - _geometry_engine.forward_atoms_with_positions_reduced_potential reverse_subtracted_valence_energy = _geometry_engine.reverse_final_context_reduced_potential - _geometry_engine.reverse_atoms_with_positions_reduced_potential nonalch_zero_rp, alch_zero_rp, alch_one_rp, nonalch_one_rp = rp_list[ 0], rp_list[1], rp_list[2], rp_list[3] # print(f"Difference between zeros: {nonalch_zero_rp - alch_zero_rp}; forward added: {forward_added_valence_energy}") # print(f"Difference between ones: {nonalch_zero_rp - alch_zero_rp}; forward added: {forward_added_valence_energy}") assert abs( nonalch_zero_rp - alch_zero_rp + forward_added_valence_energy ) < ENERGY_THRESHOLD, f"The zero state alchemical and nonalchemical energy absolute difference {abs(nonalch_zero_rp - alch_zero_rp + forward_added_valence_energy)} is greater than the threshold of {ENERGY_THRESHOLD}." assert abs( nonalch_one_rp - alch_one_rp + reverse_subtracted_valence_energy ) < ENERGY_THRESHOLD, f"The one state alchemical and nonalchemical energy absolute difference {abs(nonalch_one_rp - alch_one_rp + reverse_subtracted_valence_energy)} is greater than the threshold of {ENERGY_THRESHOLD}." print( f"Abs difference in zero alchemical vs nonalchemical systems: {abs(nonalch_zero_rp - alch_zero_rp + forward_added_valence_energy)}" ) print( f"Abs difference in one alchemical vs nonalchemical systems: {abs(nonalch_one_rp - alch_one_rp + reverse_subtracted_valence_energy)}" )
def run_hybrid_endpoint_overlap(topology_proposal, current_positions, new_positions): """ Test that the variance of the perturbation from lambda={0,1} to the corresponding nonalchemical endpoint is not too large. Parameters ---------- topology_proposal : perses.rjmc.TopologyProposal TopologyProposal object describing the transformation current_positions : np.array, unit-bearing Positions of the initial system new_positions : np.array, unit-bearing Positions of the new system Returns ------- hybrid_endpoint_results : list list of [df, ddf, N_eff] for 1 and 0 """ #create the hybrid system: #hybrid_factory = HybridTopologyFactory(topology_proposal, current_positions, new_positions, use_dispersion_correction=True) hybrid_factory = HybridTopologyFactory( topology_proposal, current_positions, new_positions, use_dispersion_correction=False) # DEBUG #get the relevant thermodynamic states: nonalchemical_zero_thermodynamic_state, nonalchemical_one_thermodynamic_state, lambda_zero_thermodynamic_state, lambda_one_thermodynamic_state = utils.generate_endpoint_thermodynamic_states( hybrid_factory.hybrid_system, topology_proposal) nonalchemical_thermodynamic_states = [ nonalchemical_zero_thermodynamic_state, nonalchemical_one_thermodynamic_state ] alchemical_thermodynamic_states = [ lambda_zero_thermodynamic_state, lambda_one_thermodynamic_state ] #create an MCMCMove, BAOAB with default parameters (but don't restart if we encounter a NaN) mc_move = mcmc.LangevinDynamicsMove(n_restart_attempts=0, n_steps=100) initial_sampler_state = SamplerState( hybrid_factory.hybrid_positions, box_vectors=hybrid_factory.hybrid_system.getDefaultPeriodicBoxVectors( )) hybrid_endpoint_results = [] all_results = [] for lambda_state in (0, 1): result, non, hybrid = run_endpoint_perturbation( alchemical_thermodynamic_states[lambda_state], nonalchemical_thermodynamic_states[lambda_state], initial_sampler_state, mc_move, 100, hybrid_factory, lambda_index=lambda_state) all_results.append(non) all_results.append(hybrid) print('lambda {} : {}'.format(lambda_state, result)) hybrid_endpoint_results.append(result) calculate_cross_variance(all_results) return hybrid_endpoint_results
def run_hybrid_endpoint_overlap(topology_proposal, current_positions, new_positions): """ Test that the variance of the perturbation from lambda={0,1} to the corresponding nonalchemical endpoint is not too large. Parameters ---------- topology_proposal : perses.rjmc.TopologyProposal TopologyProposal object describing the transformation current_positions : np.array, unit-bearing Positions of the initial system new_positions : np.array, unit-bearing Positions of the new system Returns ------- hybrid_endpoint_results : list list of [df, ddf, N_eff] for 1 and 0 """ #create the hybrid system: #hybrid_factory = HybridTopologyFactory(topology_proposal, current_positions, new_positions, use_dispersion_correction=True) hybrid_factory = HybridTopologyFactory(topology_proposal, current_positions, new_positions, use_dispersion_correction=False) # DEBUG #get the relevant thermodynamic states: nonalchemical_zero_thermodynamic_state, nonalchemical_one_thermodynamic_state, lambda_zero_thermodynamic_state, lambda_one_thermodynamic_state = utils.generate_endpoint_thermodynamic_states( hybrid_factory.hybrid_system, topology_proposal) nonalchemical_thermodynamic_states = [nonalchemical_zero_thermodynamic_state, nonalchemical_one_thermodynamic_state] alchemical_thermodynamic_states = [lambda_zero_thermodynamic_state, lambda_one_thermodynamic_state] #create an MCMCMove, BAOAB with default parameters (but don't restart if we encounter a NaN) mc_move = mcmc.LangevinDynamicsMove(n_restart_attempts=0, n_steps=100) initial_sampler_state = SamplerState(hybrid_factory.hybrid_positions, box_vectors=hybrid_factory.hybrid_system.getDefaultPeriodicBoxVectors()) hybrid_endpoint_results = [] all_results = [] for lambda_state in (0, 1): result, non, hybrid = run_endpoint_perturbation(alchemical_thermodynamic_states[lambda_state], nonalchemical_thermodynamic_states[lambda_state], initial_sampler_state, mc_move, 100, hybrid_factory, lambda_index=lambda_state) all_results.append(non) all_results.append(hybrid) print('lambda {} : {}'.format(lambda_state,result)) hybrid_endpoint_results.append(result) calculate_cross_variance(all_results) return hybrid_endpoint_results