def test_ring_breaking_detection(): """ Test the detection of ring-breaking transformations. """ from perses.rjmc.topology_proposal import SmallMoleculeSetProposalEngine from perses.tests.utils import createOEMolFromIUPAC from perses.tests.utils import render_atom_mapping molecule1 = createOEMolFromIUPAC("naphthalene") molecule2 = createOEMolFromIUPAC("benzene") # Allow ring breaking new_to_old_atom_map = SmallMoleculeSetProposalEngine._get_mol_atom_map( molecule1, molecule2, allow_ring_breaking=True) if not len(new_to_old_atom_map) > 0: filename = 'mapping-error.png' render_atom_mapping(filename, molecule1, molecule2, new_to_old_atom_map) msg = 'Napthalene -> benzene transformation with allow_ring_breaking=True is not returning a valid mapping\n' msg += 'Wrote atom mapping to %s for inspection; please check this.' % filename msg += str(new_to_old_atom_map) raise Exception(msg) new_to_old_atom_map = SmallMoleculeSetProposalEngine._get_mol_atom_map( molecule1, molecule2, allow_ring_breaking=False) if not len(new_to_old_atom_map) == 0: filename = 'mapping-error.png' render_atom_mapping(filename, molecule1, molecule2, new_to_old_atom_map) msg = 'Napthalene -> benzene transformation with allow_ring_breaking=False is erroneously allowing ring breaking\n' msg += 'Wrote atom mapping to %s for inspection; please check this.' % filename msg += str(new_to_old_atom_map) raise Exception(msg)
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 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_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_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 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 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 createSystemFromIUPAC(iupac_name): """ Create an openmm system out of an oemol Parameters ---------- iupac_name : str IUPAC name Returns ------- molecule : openeye.OEMol OEMol molecule system : openmm.System object OpenMM system positions : [n,3] np.array of floats Positions topology : openmm.app.Topology object Topology """ # Create OEMol molecule = createOEMolFromIUPAC(iupac_name) # Generate a topology. from openmoltools.forcefield_generators import generateTopologyFromOEMol topology = generateTopologyFromOEMol(molecule) # Initialize a forcefield with GAFF. # TODO: Fix path for `gaff.xml` since it is not yet distributed with OpenMM from simtk.openmm.app import ForceField gaff_xml_filename = get_data_filename('data/gaff.xml') forcefield = ForceField(gaff_xml_filename) # Generate template and parameters. from openmoltools.forcefield_generators import generateResidueTemplate [template, ffxml] = generateResidueTemplate(molecule) # Register the template. forcefield.registerResidueTemplate(template) # Add the parameters. forcefield.loadFile(StringIO(ffxml)) # Create the system. system = forcefield.createSystem(topology, removeCMMotion=False) # Extract positions positions = extractPositionsFromOEMOL(molecule) return (molecule, system, positions, topology)
def createSystemFromIUPAC(iupac_name): """ Create an openmm system out of an oemol Parameters ---------- iupac_name : str IUPAC name Returns ------- molecule : openeye.OEMol OEMol molecule system : openmm.System object OpenMM system positions : [n,3] np.array of floats Positions topology : openmm.app.Topology object Topology """ # Create OEMol molecule = createOEMolFromIUPAC(iupac_name) # Generate a topology. from openmoltools.forcefield_generators import generateTopologyFromOEMol topology = generateTopologyFromOEMol(molecule) # Initialize a forcefield with GAFF. # TODO: Fix path for `gaff.xml` since it is not yet distributed with OpenMM from simtk.openmm.app import ForceField gaff_xml_filename = get_data_filename('data/gaff.xml') forcefield = ForceField(gaff_xml_filename) # Generate template and parameters. from openmoltools.forcefield_generators import generateResidueTemplate [template, ffxml] = generateResidueTemplate(molecule) # Register the template. forcefield.registerResidueTemplate(template) # Add the parameters. forcefield.loadFile(StringIO(ffxml)) # Create the system. system = forcefield.createSystem(topology, removeCMMotion=False) # Extract positions positions = extractPositionsFromOEMOL(molecule) return (molecule, system, positions, topology)
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_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_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 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 generate_vacuum_topology_proposal(current_mol_name="benzene", proposed_mol_name="toluene", forcefield_kwargs=None, system_generator_kwargs=None): """ Generate a test vacuum topology proposal, current positions, and new positions triplet from two IUPAC molecule names. Constraints are added to the system by default. To override this, set ``forcefield_kwargs = None``. Parameters ---------- current_mol_name : str, optional name of the first molecule proposed_mol_name : str, optional name of the second molecule forcefield_kwargs : dict, optional, default=None Additional arguments to ForceField in addition to 'removeCMMotion': False, 'nonbondedMethod': app.NoCutoff system_generator_kwargs : dict, optional, default=None Dict passed onto SystemGenerator 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 gaff_filename = get_data_filename('data/gaff.xml') default_forcefield_kwargs = {'removeCMMotion': False, 'nonbondedMethod': app.NoCutoff, 'constraints' : app.HBonds} forcefield_kwargs = default_forcefield_kwargs.update(forcefield_kwargs) if (forcefield_kwargs is not None) else default_forcefield_kwargs system_generator_kwargs = system_generator_kwargs if (system_generator_kwargs is not None) else dict() system_generator = SystemGenerator([gaff_filename, 'amber99sbildn.xml', 'tip3p.xml'], forcefield_kwargs=forcefield_kwargs, **system_generator_kwargs) old_oemol = createOEMolFromIUPAC(current_mol_name) from openmoltools.forcefield_generators import generateTopologyFromOEMol old_topology = generateTopologyFromOEMol(old_oemol) old_positions = extractPositionsFromOEMOL(old_oemol) old_smiles = oechem.OEMolToSmiles(old_oemol) old_system = system_generator.build_system(old_topology) new_oemol = createOEMolFromIUPAC(proposed_mol_name) new_smiles = oechem.OEMolToSmiles(new_oemol) geometry_engine = geometry.FFAllAngleGeometryEngine() proposal_engine = SmallMoleculeSetProposalEngine( [old_smiles, new_smiles], system_generator, residue_name=current_mol_name) #generate topology proposal topology_proposal = proposal_engine.propose(old_system, old_topology, current_mol=old_oemol, proposed_mol=new_oemol) # show atom mapping filename = str(current_mol_name)+str(proposed_mol_name)+'.pdf' render_atom_mapping(filename, old_oemol, new_oemol, topology_proposal.new_to_old_atom_map) #generate new positions with geometry engine new_positions, _ = geometry_engine.propose(topology_proposal, old_positions, beta) # DEBUG: Zero out bonds and angles for one system #print('Zeroing bonds of old system') #for force in topology_proposal.old_system.getForces(): # if force.__class__.__name__ == 'HarmonicAngleForce': # for index in range(force.getNumAngles()): # p1, p2, p3, angle, K = force.getAngleParameters(index) # K *= 0.0 # force.setAngleParameters(index, p1, p2, p3, angle, K) # if False and force.__class__.__name__ == 'HarmonicBondForce': # for index in range(force.getNumBonds()): # p1, p2, r0, K = force.getBondParameters(index) # K *= 0.0 # force.setBondParameters(index, p1, p2, r0, K) # DEBUG : Box vectors #box_vectors = np.eye(3) * 100 * unit.nanometers #topology_proposal.old_system.setDefaultPeriodicBoxVectors(box_vectors[0,:], box_vectors[1,:], box_vectors[2,:]) #topology_proposal.new_system.setDefaultPeriodicBoxVectors(box_vectors[0,:], box_vectors[1,:], box_vectors[2,:]) return topology_proposal, old_positions, new_positions
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 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)