def test_ncmc_engine_molecule(): """ Check alchemical elimination for alanine dipeptide in vacuum with 0, 1, 2, and 50 switching steps. """ molecule_names = ['pentane', 'biphenyl', 'imatinib'] #if os.environ.get("TRAVIS", None) == 'true': # molecule_names = ['pentane'] for molecule_name in molecule_names: from perses.tests.utils import createSystemFromIUPAC [molecule, system, positions, topology] = createSystemFromIUPAC(molecule_name) natoms = system.getNumParticles() # DEBUG print(molecule_name) from openeye import oechem ofs = oechem.oemolostream('%s.mol2' % molecule_name) oechem.OEWriteMol2File(ofs, molecule) ofs.close() # Eliminate half of the molecule # TODO: Use a more rigorous scheme to make sure we are really cutting the molecule in half and not just eliminating hydrogens or something. new_to_old_atom_map = { atom.index : atom.index for atom in topology.atoms() if str(atom.element.name) in ['carbon','nitrogen'] } # DEBUG print(new_to_old_atom_map) from perses.rjmc.topology_proposal import TopologyProposal topology_proposal = TopologyProposal( new_topology=topology, new_system=system, old_topology=topology, old_system=system, old_chemical_state_key='', new_chemical_state_key='', logp_proposal=0.0, new_to_old_atom_map=new_to_old_atom_map, metadata={'test':0.0}) for ncmc_nsteps in [0, 1, 50]: f = partial(check_alchemical_null_elimination, topology_proposal, positions, ncmc_nsteps=ncmc_nsteps) f.description = "Testing alchemical null elimination for '%s' with %d NCMC steps" % (molecule_name, ncmc_nsteps) yield f
def generate_vacuum_hybrid_topology(mol_name="naphthalene", ref_mol_name="benzene"): from topology_proposal import SmallMoleculeSetProposalEngine, TopologyProposal import simtk.openmm.app as app from openmoltools import forcefield_generators from perses.tests.utils import createOEMolFromIUPAC, createSystemFromIUPAC, get_data_filename m, unsolv_old_system, pos_old, top_old = createSystemFromIUPAC(mol_name) refmol = createOEMolFromIUPAC(ref_mol_name) initial_smiles = oechem.OEMolToSmiles(m) final_smiles = oechem.OEMolToSmiles(refmol) gaff_xml_filename = get_data_filename("data/gaff.xml") forcefield = app.ForceField(gaff_xml_filename, 'tip3p.xml') forcefield.registerTemplateGenerator(forcefield_generators.gaffTemplateGenerator) solvated_system = forcefield.createSystem(top_old) gaff_filename = get_data_filename('data/gaff.xml') system_generator = SystemGenerator([gaff_filename, 'amber99sbildn.xml', 'tip3p.xml']) geometry_engine = FFAllAngleGeometryEngine() proposal_engine = SmallMoleculeSetProposalEngine( [initial_smiles, final_smiles], system_generator, residue_name=mol_name) #generate topology proposal topology_proposal = proposal_engine.propose(solvated_system, top_old) #generate new positions with geometry engine new_positions, _ = geometry_engine.propose(topology_proposal, pos_old, beta) return topology_proposal, pos_old, new_positions
def generate_hybrid_test_topology(mol_name="naphthalene", ref_mol_name="benzene"): """ Generate a test topology proposal and positions for the hybrid test. """ from perses.rjmc.topology_proposal import SmallMoleculeSetProposalEngine, TopologyProposal from perses.tests.utils import createOEMolFromIUPAC, createSystemFromIUPAC mol = createOEMolFromIUPAC(mol_name) m, system, positions, topology = createSystemFromIUPAC(mol_name) refmol = createOEMolFromIUPAC(ref_mol_name) #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') return top_proposal, positions
def test_ncmc_hybrid_explicit_engine_molecule(): """ Check alchemical elimination for alanine dipeptide in vacuum with 0, 1, 2, and 50 switching steps. """ #mols_and_refs = [['naphthalene', 'benzene'], ['pentane', 'propane'], ['biphenyl', 'benzene'], ['octane','propane']] mols_and_refs = [['pentane', 'propane']] if os.environ.get("TRAVIS", None) == 'true': mols_and_refs = [['naphthalene', 'benzene']] for mol_ref in mols_and_refs: from perses.tests.utils import createSystemFromIUPAC [molecule, system, positions, topology] = createSystemFromIUPAC(mol_ref[0]) #topology_proposal, new_positions = generate_hybrid_test_topology(mol_name=mol_ref[0], ref_mol_name=mol_ref[1]) topology_proposal, positions = generate_solvated_hybrid_test_topology( mol_name=mol_ref[0], ref_mol_name=mol_ref[1]) for ncmc_nsteps in [0, 1, 50]: f = partial(check_alchemical_hybrid_elimination_bar, topology_proposal, positions, ncmc_nsteps=ncmc_nsteps) f.description = "Testing alchemical null elimination for '%s' with %d NCMC steps" % ( mol_ref[0], ncmc_nsteps) yield f
def generate_solvated_hybrid_test_topology(current_mol_name="naphthalene", proposed_mol_name="benzene"): """ Generate a test solvated topology proposal, current positions, and new positions triplet from two IUPAC molecule names. Parameters ---------- current_mol_name : str, optional name of the first molecule proposed_mol_name : str, optional name of the second molecule Returns ------- topology_proposal : perses.rjmc.topology_proposal The topology proposal representing the transformation current_positions : np.array, unit-bearing The positions of the initial system new_positions : np.array, unit-bearing The positions of the new system """ import simtk.openmm.app as app from openmoltools import forcefield_generators from perses.tests.utils import createOEMolFromIUPAC, createSystemFromIUPAC, get_data_filename current_mol, unsolv_old_system, pos_old, top_old = createSystemFromIUPAC(current_mol_name) proposed_mol = createOEMolFromIUPAC(proposed_mol_name) initial_smiles = oechem.OEMolToSmiles(current_mol) final_smiles = oechem.OEMolToSmiles(proposed_mol) gaff_xml_filename = get_data_filename("data/gaff.xml") forcefield = app.ForceField(gaff_xml_filename, 'tip3p.xml') forcefield.registerTemplateGenerator(forcefield_generators.gaffTemplateGenerator) modeller = app.Modeller(top_old, pos_old) modeller.addSolvent(forcefield, model='tip3p', padding=9.0*unit.angstrom) solvated_topology = modeller.getTopology() solvated_positions = modeller.getPositions() solvated_system = forcefield.createSystem(solvated_topology, nonbondedMethod=app.PME, removeCMMotion=False) barostat = openmm.MonteCarloBarostat(1.0*unit.atmosphere, temperature, 50) solvated_system.addForce(barostat) gaff_filename = get_data_filename('data/gaff.xml') system_generator = SystemGenerator([gaff_filename, 'amber99sbildn.xml', 'tip3p.xml'], barostat=barostat, forcefield_kwargs={'removeCMMotion': False, 'nonbondedMethod': app.PME}) geometry_engine = geometry.FFAllAngleGeometryEngine() proposal_engine = SmallMoleculeSetProposalEngine( [initial_smiles, final_smiles], system_generator, residue_name=current_mol_name) #generate topology proposal topology_proposal = proposal_engine.propose(solvated_system, solvated_topology) #generate new positions with geometry engine new_positions, _ = geometry_engine.propose(topology_proposal, solvated_positions, beta) return topology_proposal, solvated_positions, new_positions
def test_ncmc_engine_molecule(): """ Check alchemical elimination for alanine dipeptide in vacuum with 0, 1, 2, and 50 switching steps. """ molecule_names = ['pentane', 'biphenyl', 'imatinib'] #if os.environ.get("TRAVIS", None) == 'true': # molecule_names = ['pentane'] for molecule_name in molecule_names: from perses.tests.utils import createSystemFromIUPAC [molecule, system, positions, topology] = createSystemFromIUPAC(molecule_name) natoms = system.getNumParticles() # DEBUG print(molecule_name) from openeye import oechem ofs = oechem.oemolostream('%s.mol2' % molecule_name) oechem.OEWriteMol2File(ofs, molecule) ofs.close() # Eliminate half of the molecule # TODO: Use a more rigorous scheme to make sure we are really cutting the molecule in half and not just eliminating hydrogens or something. new_to_old_atom_map = { atom.index: atom.index for atom in topology.atoms() if str(atom.element.name) in ['carbon', 'nitrogen'] } # DEBUG print(new_to_old_atom_map) from perses.rjmc.topology_proposal import TopologyProposal topology_proposal = TopologyProposal( new_topology=topology, new_system=system, old_topology=topology, old_system=system, old_chemical_state_key='', new_chemical_state_key='', logp_proposal=0.0, new_to_old_atom_map=new_to_old_atom_map, metadata={'test': 0.0}) for ncmc_nsteps in [0, 1, 50]: f = partial(check_alchemical_null_elimination, topology_proposal, positions, ncmc_nsteps=ncmc_nsteps) f.description = "Testing alchemical null elimination for '%s' with %d NCMC steps" % ( molecule_name, ncmc_nsteps) yield f
def generate_vacuum_topology_proposal(current_mol_name="benzene", proposed_mol_name="toluene"): """ Generate a test vacuum topology proposal, current positions, and new positions triplet from two IUPAC molecule names. Parameters ---------- current_mol_name : str, optional name of the first molecule proposed_mol_name : str, optional name of the second molecule Returns ------- topology_proposal : perses.rjmc.topology_proposal The topology proposal representing the transformation current_positions : np.array, unit-bearing The positions of the initial system new_positions : np.array, unit-bearing The positions of the new system """ from openmoltools import forcefield_generators from perses.tests.utils import createOEMolFromIUPAC, createSystemFromIUPAC, get_data_filename current_mol, unsolv_old_system, pos_old, top_old = createSystemFromIUPAC(current_mol_name) proposed_mol = createOEMolFromIUPAC(proposed_mol_name) initial_smiles = oechem.OEMolToSmiles(current_mol) final_smiles = oechem.OEMolToSmiles(proposed_mol) gaff_xml_filename = get_data_filename("data/gaff.xml") forcefield = app.ForceField(gaff_xml_filename, 'tip3p.xml') forcefield.registerTemplateGenerator(forcefield_generators.gaffTemplateGenerator) solvated_system = forcefield.createSystem(top_old, removeCMMotion=False) gaff_filename = get_data_filename('data/gaff.xml') system_generator = SystemGenerator([gaff_filename, 'amber99sbildn.xml', 'tip3p.xml'], forcefield_kwargs={'removeCMMotion': False, 'nonbondedMethod': app.NoCutoff}) geometry_engine = geometry.FFAllAngleGeometryEngine() proposal_engine = SmallMoleculeSetProposalEngine( [initial_smiles, final_smiles], system_generator, residue_name=current_mol_name) #generate topology proposal topology_proposal = proposal_engine.propose(solvated_system, top_old, current_mol=current_mol, proposed_mol=proposed_mol) #generate new positions with geometry engine new_positions, _ = geometry_engine.propose(topology_proposal, pos_old, beta) return topology_proposal, pos_old, new_positions
def generate_solvated_hybrid_test_topology(mol_name="naphthalene", ref_mol_name="benzene"): from perses.rjmc.topology_proposal import SmallMoleculeSetProposalEngine, TopologyProposal import simtk.openmm.app as app from openmoltools import forcefield_generators from perses.tests.utils import createOEMolFromIUPAC, createSystemFromIUPAC, get_data_filename mol = createOEMolFromIUPAC(mol_name) m, unsolv_system, pos, top = createSystemFromIUPAC(mol_name) refmol = createOEMolFromIUPAC(ref_mol_name) gaff_xml_filename = get_data_filename("data/gaff.xml") forcefield = app.ForceField(gaff_xml_filename, 'tip3p.xml') forcefield.registerTemplateGenerator( forcefield_generators.gaffTemplateGenerator) #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()} modeller = app.Modeller(top, pos) modeller.addSolvent(forcefield, model='tip3p', padding=9.0 * unit.angstrom) topology = modeller.getTopology() positions = modeller.getPositions() system = forcefield.createSystem(topology, nonbondedMethod=app.PME) n_atoms_old_system = unsolv_system.getNumParticles() n_atoms_after_solvation = system.getNumParticles() for i in range(n_atoms_old_system, n_atoms_after_solvation): effective_atom_map[i] = i 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') return top_proposal, positions
def test_ncmc_alchemical_integrator_stability_molecules(): """ Test NCMCAlchemicalIntegrator """ molecule_names = ['pentane', 'biphenyl', 'imatinib'] #if os.environ.get("TRAVIS", None) == 'true': # molecule_names = ['pentane'] for molecule_name in molecule_names: from perses.tests.utils import createSystemFromIUPAC [molecule, system, positions, topology] = createSystemFromIUPAC(molecule_name) # Eliminate half of the molecule # TODO: Use a more rigorous scheme to make sure we are really cutting the molecule in half and not just eliminating hydrogens or something. alchemical_atoms = [ index for index in range(int(system.getNumParticles()/2)) ] # Create an alchemically-modified system. from alchemy import AbsoluteAlchemicalFactory alchemical_factory = AbsoluteAlchemicalFactory(system, ligand_atoms=alchemical_atoms, annihilate_electrostatics=True, annihilate_sterics=True) # Return the alchemically-modified system in fully-interacting form. alchemical_system = alchemical_factory.createPerturbedSystem() # Create an NCMC switching integrator. from perses.annihilation.ncmc_switching import NCMCVVAlchemicalIntegrator temperature = 300.0 * unit.kelvin nsteps = 10 # number of steps to run integration for functions = { 'lambda_sterics' : 'lambda', 'lambda_electrostatics' : 'lambda^0.5', 'lambda_torsions' : 'lambda', 'lambda_angles' : 'lambda^2' } ncmc_integrator = NCMCVVAlchemicalIntegrator(temperature, alchemical_system, functions, direction='delete', nsteps=nsteps, timestep=1.0*unit.femtoseconds) # Create a Context context = openmm.Context(alchemical_system, ncmc_integrator) context.setPositions(positions) # Run the integrator ncmc_integrator.step(nsteps) # Check positions are finite positions = context.getState(getPositions=True).getPositions(asNumpy=True) if np.isnan(np.any(positions / positions.unit)): raise Exception('NCMCAlchemicalIntegrator gave NaN positions') if np.isnan(ncmc_integrator.getLogAcceptanceProbability(context)): raise Exception('NCMCAlchemicalIntegrator gave NaN logAcceptanceProbability') del context, ncmc_integrator
def test_ncmc_hybrid_explicit_engine_molecule(): """ Check alchemical elimination for alanine dipeptide in vacuum with 0, 1, 2, and 50 switching steps. """ #mols_and_refs = [['naphthalene', 'benzene'], ['pentane', 'propane'], ['biphenyl', 'benzene'], ['octane','propane']] mols_and_refs=[['pentane', 'propane']] if os.environ.get("TRAVIS", None) == 'true': mols_and_refs = [['naphthalene', 'benzene']] for mol_ref in mols_and_refs: from perses.tests.utils import createSystemFromIUPAC [molecule, system, positions, topology] = createSystemFromIUPAC(mol_ref[0]) #topology_proposal, new_positions = generate_hybrid_test_topology(mol_name=mol_ref[0], ref_mol_name=mol_ref[1]) topology_proposal, positions = generate_solvated_hybrid_test_topology(mol_name=mol_ref[0], ref_mol_name=mol_ref[1]) for ncmc_nsteps in [0, 1, 50]: f = partial(check_alchemical_hybrid_elimination_bar, topology_proposal, positions, ncmc_nsteps=ncmc_nsteps) f.description = "Testing alchemical null elimination for '%s' with %d NCMC steps" % (mol_ref[0], ncmc_nsteps) yield f
def test_ncmc_engine_molecule(): """ Check alchemical elimination for alanine dipeptide in vacuum with 0, 1, 2, and 50 switching steps. """ molecule_names = ['imatinib', 'pentane', 'biphenyl'] if os.environ.get("TRAVIS", None) == 'true': molecule_names = ['pentane'] for molecule_name in molecule_names: from perses.tests.utils import createSystemFromIUPAC [molecule, system, positions, topology] = createSystemFromIUPAC(molecule_name) natoms = system.getNumParticles() # Eliminate half of the molecule # TODO: Use a more rigorous scheme to make sure we are really cutting the molecule in half and not just eliminating hydrogens or something. new_to_old_atom_map = { index: index for index in range(int(natoms / 2)) } from perses.rjmc.topology_proposal import TopologyProposal topology_proposal = TopologyProposal( new_topology=topology, new_system=system, old_topology=topology, old_system=system, old_chemical_state_key='', new_chemical_state_key='', logp_proposal=0.0, new_to_old_atom_map=new_to_old_atom_map, metadata={'test': 0.0}) for ncmc_nsteps in [0, 1, 50]: f = partial(check_alchemical_null_elimination, topology_proposal, positions, ncmc_nsteps=ncmc_nsteps) f.description = "Testing alchemical null elimination for '%s' with %d NCMC steps" % ( molecule_name, ncmc_nsteps) yield f
def generate_solvated_hybrid_test_topology(mol_name="naphthalene", ref_mol_name="benzene"): from perses.rjmc.topology_proposal import SmallMoleculeSetProposalEngine, TopologyProposal import simtk.openmm.app as app from openmoltools import forcefield_generators from perses.tests.utils import createOEMolFromIUPAC, createSystemFromIUPAC, get_data_filename mol = createOEMolFromIUPAC(mol_name) m, unsolv_system, pos, top = createSystemFromIUPAC(mol_name) refmol = createOEMolFromIUPAC(ref_mol_name) gaff_xml_filename = get_data_filename("data/gaff.xml") forcefield = app.ForceField(gaff_xml_filename, 'tip3p.xml') forcefield.registerTemplateGenerator(forcefield_generators.gaffTemplateGenerator) #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()} modeller = app.Modeller(top, pos) modeller.addSolvent(forcefield, model='tip3p', padding=9.0*unit.angstrom) topology = modeller.getTopology() positions = modeller.getPositions() system = forcefield.createSystem(topology, nonbondedMethod=app.PME) n_atoms_old_system = unsolv_system.getNumParticles() n_atoms_after_solvation = system.getNumParticles() for i in range(n_atoms_old_system, n_atoms_after_solvation): effective_atom_map[i] = i 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') return top_proposal, positions
def generate_hybrid_test_topology(mol_name="naphthalene", ref_mol_name="benzene"): """ Generate a test topology proposal and positions for the hybrid test. """ from perses.rjmc.topology_proposal import SmallMoleculeSetProposalEngine, TopologyProposal from perses.tests.utils import createOEMolFromIUPAC, createSystemFromIUPAC mol = createOEMolFromIUPAC(mol_name) m, system, positions, topology = createSystemFromIUPAC(mol_name) refmol = createOEMolFromIUPAC(ref_mol_name) #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') return top_proposal, positions
def test_ncmc_engine_molecule(): """ Check alchemical elimination for alanine dipeptide in vacuum with 0, 1, 2, and 50 switching steps. """ molecule_names = ['pentane', 'biphenyl', 'imatinib'] if os.environ.get("TRAVIS", None) == 'true': molecule_names = ['pentane'] for molecule_name in molecule_names: from perses.tests.utils import createSystemFromIUPAC [molecule, system, positions, topology] = createSystemFromIUPAC(molecule_name) natoms = system.getNumParticles() # Eliminate half of the molecule # TODO: Use a more rigorous scheme to make sure we are really cutting the molecule in half and not just eliminating hydrogens or something. new_to_old_atom_map = { index : index for index in range(int(natoms/2)) } from perses.rjmc.topology_proposal import TopologyProposal topology_proposal = TopologyProposal( new_topology=topology, new_system=system, old_topology=topology, old_system=system, old_chemical_state_key='', new_chemical_state_key='', logp_proposal=0.0, new_to_old_atom_map=new_to_old_atom_map, metadata={'test':0.0}) for ncmc_nsteps in [0, 1, 50]: f = partial(check_alchemical_null_elimination, topology_proposal, positions, ncmc_nsteps=ncmc_nsteps) f.description = "Testing alchemical null elimination for '%s' with %d NCMC steps" % (molecule_name, ncmc_nsteps) yield f
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 perses.rjmc.topology_proposal import SmallMoleculeSetProposalEngine, TopologyProposal from perses.annihilation.new_relative import HybridTopologyFactory import simtk.openmm as openmm from perses.tests.utils import createOEMolFromIUPAC, createSystemFromIUPAC mol_name = "naphthalene" ref_mol_name = "benzene" mol = createOEMolFromIUPAC(mol_name) m, system, positions, topology = createSystemFromIUPAC(mol_name) refmol = createOEMolFromIUPAC(ref_mol_name) #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 integrator = openmm.VerletIntegrator(1) platform = openmm.Platform.getPlatformByName("Reference") context = openmm.Context(alchemical_system, integrator, platform) context.setPositions(alchemical_positions) functions = { 'lambda_sterics' : '2*lambda * step(0.5 - lambda) + (1.0 - step(0.5 - lambda))', 'lambda_electrostatics' : '2*(lambda - 0.5) * step(lambda - 0.5)', 'lambda_bonds' : 'lambda', 'lambda_angles' : 'lambda', 'lambda_torsions' : 'lambda' } #set all to zero for parm in functions.keys(): context.setParameter(parm, 0.0) initial_energy = context.getState(getEnergy=True).getPotentialEnergy() #set all to one for parm in functions.keys(): context.setParameter(parm, 1.0) final_energy = context.getState(getEnergy=True).getPotentialEnergy() if np.abs(final_energy - initial_energy) > 1.0e-6*unit.kilojoule_per_mole: raise Exception("The energy at the endpoints was not equal for molecule %s" % mol_name)
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 perses.rjmc.topology_proposal import SmallMoleculeSetProposalEngine, TopologyProposal from perses.annihilation.new_relative import HybridTopologyFactory import simtk.openmm as openmm from perses.tests.utils import createOEMolFromIUPAC, createSystemFromIUPAC mol_name = "naphthalene" ref_mol_name = "benzene" mol = createOEMolFromIUPAC(mol_name) m, system, positions, topology = createSystemFromIUPAC(mol_name) refmol = createOEMolFromIUPAC(ref_mol_name) #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 integrator = openmm.VerletIntegrator(1) platform = openmm.Platform.getPlatformByName("Reference") context = openmm.Context(alchemical_system, integrator, platform) context.setPositions(alchemical_positions) functions = { 'lambda_sterics': '2*lambda * step(0.5 - lambda) + (1.0 - step(0.5 - lambda))', 'lambda_electrostatics': '2*(lambda - 0.5) * step(lambda - 0.5)', 'lambda_bonds': 'lambda', 'lambda_angles': 'lambda', 'lambda_torsions': 'lambda' } #set all to zero for parm in functions.keys(): context.setParameter(parm, 0.0) initial_energy = context.getState(getEnergy=True).getPotentialEnergy() #set all to one for parm in functions.keys(): context.setParameter(parm, 1.0) final_energy = context.getState(getEnergy=True).getPotentialEnergy() if np.abs(final_energy - initial_energy) > 1.0e-6 * unit.kilojoule_per_mole: raise Exception( "The energy at the endpoints was not equal for molecule %s" % mol_name)
def test_logp_forward_check_for_vacuum_topology_proposal(current_mol_name = 'propane', proposed_mol_name = 'octane', num_iterations = 100, neglect_angles = True): """ Generate a test vacuum topology proposal, current positions, and new positions triplet from two IUPAC molecule names. Assert that the logp_forward < 1e3. This assertion will fail if the proposal order tool proposed the placement of the a carbon before a previously defined carbon in the alkane. Parameters ---------- current_mol_name : str, optional name of the first molecule proposed_mol_name : str, optional name of the second molecule Returns ------- topology_proposal : perses.rjmc.topology_proposal The topology proposal representing the transformation current_positions : np.array, unit-bearing The positions of the initial system new_positions : np.array, unit-bearing The positions of the new system """ from openmoltools import forcefield_generators from perses.tests.utils import createOEMolFromIUPAC, createSystemFromIUPAC, get_data_filename current_mol, unsolv_old_system, pos_old, top_old = createSystemFromIUPAC(current_mol_name) proposed_mol = createOEMolFromIUPAC(proposed_mol_name) initial_smiles = oechem.OEMolToSmiles(current_mol) final_smiles = oechem.OEMolToSmiles(proposed_mol) gaff_xml_filename = get_data_filename("data/gaff.xml") forcefield = app.ForceField(gaff_xml_filename, 'tip3p.xml') forcefield.registerTemplateGenerator(forcefield_generators.gaffTemplateGenerator) solvated_system = forcefield.createSystem(top_old, removeCMMotion=False) gaff_filename = get_data_filename('data/gaff.xml') system_generator = SystemGenerator([gaff_filename, 'amber99sbildn.xml', 'tip3p.xml'], forcefield_kwargs={'removeCMMotion': False, 'nonbondedMethod': app.NoCutoff}) geometry_engine = geometry.FFAllAngleGeometryEngine(n_bond_divisions=100, n_angle_divisions=180, n_torsion_divisions=360, neglect_angles = neglect_angles) proposal_engine = SmallMoleculeSetProposalEngine( [initial_smiles, final_smiles], system_generator, residue_name=current_mol_name) #generate topology proposal topology_proposal = proposal_engine.propose(solvated_system, top_old, current_mol=current_mol, proposed_mol=proposed_mol) # show atom mapping filename = str(current_mol_name)+str(proposed_mol_name)+'.pdf' render_atom_mapping(filename,current_mol,proposed_mol,topology_proposal.new_to_old_atom_map) total_works = [] for _ in range(num_iterations): #generate new positions with geometry engine new_positions, logp_forward = geometry_engine.propose(topology_proposal, pos_old, beta) logp_reverse = geometry_engine.logp_reverse(topology_proposal, new_positions, pos_old, beta) #now just render forward and backward work work_fwd = logp_forward + geometry_engine.forward_final_context_reduced_potential - geometry_engine.forward_atoms_with_positions_reduced_potential work_bkwd = logp_reverse + geometry_engine.reverse_atoms_with_positions_reduced_potential - geometry_engine.reverse_final_context_reduced_potential total_work = logp_forward - logp_reverse + geometry_engine.forward_final_context_reduced_potential - geometry_engine.reverse_final_context_reduced_potential total_works.append(total_work) print("forward, backward works : {}, {}".format(work_fwd, work_bkwd)) print("total_work: {}".format(total_work)) assert abs(work_fwd - work_bkwd - total_work) < 1, "The difference of fwd and backward works is not equal to the total work (within 1kT)" assert logp_forward < 1e3, "A heavy atom was proposed in an improper order"
def generate_topology_proposal(old_mol_iupac="pentane", new_mol_iupac="butane"): """ Utility function to generate a topologyproposal for tests Parameters ---------- old_mol_iupac : str, optional name of old mol, default pentane new_mol_iupac : str, optional name of new mol, default butane Returns ------- topology_proposal : perses.rjmc.topology_proposal.TopologyProposal the topology proposal corresponding to the given transformation old_positions : [n, 3] np.ndarray of float positions of old mol new_positions : [m, 3] np.ndarray of float positions of new mol """ from perses.rjmc.topology_proposal import TwoMoleculeSetProposalEngine, SystemGenerator from perses.rjmc.geometry import FFAllAngleGeometryEngine from perses.tests.utils import createSystemFromIUPAC, get_data_filename import openmoltools.forcefield_generators as forcefield_generators from io import StringIO from openmmtools.constants import kB temperature = 300.0 * unit.kelvin kT = kB * temperature beta = 1.0 / kT gaff_filename = get_data_filename("data/gaff.xml") forcefield_files = [gaff_filename, 'amber99sbildn.xml'] #generate systems and topologies old_mol, old_system, old_positions, old_topology = createSystemFromIUPAC( old_mol_iupac) new_mol, new_system, new_positions, new_topology = createSystemFromIUPAC( new_mol_iupac) #set names old_mol.SetTitle("MOL") new_mol.SetTitle("MOL") #generate forcefield and ProposalEngine #ffxml=forcefield_generators.generateForceFieldFromMolecules([old_mol, new_mol]) system_generator = SystemGenerator( forcefield_files, forcefield_kwargs={'removeCMMotion': False}) proposal_engine = TwoMoleculeSetProposalEngine(old_mol, new_mol, system_generator, residue_name="pentane") geometry_engine = FFAllAngleGeometryEngine() #create a TopologyProposal topology_proposal = proposal_engine.propose(old_system, old_topology) new_positions_geometry, _ = geometry_engine.propose( topology_proposal, old_positions, beta) return topology_proposal, old_positions, new_positions_geometry
def test_ncmc_alchemical_integrator_stability_molecules(): """ Test NCMCAlchemicalIntegrator """ molecule_names = ['pentane', 'biphenyl', 'imatinib'] if os.environ.get("TRAVIS", None) == 'true': molecule_names = ['pentane'] for molecule_name in molecule_names: from perses.tests.utils import createSystemFromIUPAC [molecule, system, positions, topology] = createSystemFromIUPAC(molecule_name) # Eliminate half of the molecule # TODO: Use a more rigorous scheme to make sure we are really cutting the molecule in half and not just eliminating hydrogens or something. alchemical_atoms = [ index for index in range(int(system.getNumParticles() / 2)) ] # Create an alchemically-modified system. from alchemy import AbsoluteAlchemicalFactory alchemical_factory = AbsoluteAlchemicalFactory( system, ligand_atoms=alchemical_atoms, annihilate_electrostatics=True, annihilate_sterics=True) # Return the alchemically-modified system in fully-interacting form. alchemical_system = alchemical_factory.createPerturbedSystem() # Create an NCMC switching integrator. from perses.annihilation.ncmc_switching import NCMCVVAlchemicalIntegrator temperature = 300.0 * unit.kelvin functions = { 'lambda_sterics': 'lambda', 'lambda_electrostatics': 'lambda^0.5', 'lambda_torsions': 'lambda', 'lambda_angles': 'lambda^2' } ncmc_integrator = NCMCVVAlchemicalIntegrator(temperature, alchemical_system, functions, direction='delete', nsteps=10, timestep=1.0 * unit.femtoseconds) # Create a Context context = openmm.Context(alchemical_system, ncmc_integrator) context.setPositions(positions) # Run the integrator ncmc_integrator.step(1) # Check positions are finite positions = context.getState(getPositions=True).getPositions( asNumpy=True) if np.isnan(np.any(positions / positions.unit)): raise Exception('NCMCAlchemicalIntegrator gave NaN positions') if np.isnan(ncmc_integrator.getLogAcceptanceProbability(context)): raise Exception( 'NCMCAlchemicalIntegrator gave NaN logAcceptanceProbability') del context, ncmc_integrator