def test_charge(self):
        """Test that charges are nonzero after charging if the molecule does not contain user charges"""
        # Create a generator that does not know about any molecules
        generator = self.TEMPLATE_GENERATOR()
        # Create a ForceField
        from simtk.openmm.app import ForceField
        forcefield = ForceField()
        # Register the template generator
        forcefield.registerTemplateGenerator(generator.generator)

        # Check that parameterizing a molecule using user-provided charges produces expected charges
        import numpy as np
        from simtk import unit
        molecule = self.molecules[0]
        # Ensure partial charges are initially zero
        assert np.all(molecule.partial_charges / unit.elementary_charge == 0)
        # Add the molecule
        generator.add_molecules(molecule)
        # Create the System
        from simtk.openmm.app import NoCutoff
        openmm_topology = molecule.to_topology().to_openmm()
        system = forcefield.createSystem(openmm_topology,
                                         nonbondedMethod=NoCutoff)
        # Ensure charges are no longer zero
        assert not np.all(
            self.charges_from_system(system) ==
            0), "System has zero charges despite molecule not being charged"
 def __init__(self, forcefields_to_use, forcefield_kwargs=None, use_gaff=True):
     self._forcefield_xmls = forcefields_to_use
     self._forcefield_kwargs = forcefield_kwargs if forcefield_kwargs is not None else {}
     from simtk.openmm.app import ForceField
     self._forcefield = ForceField(*self._forcefield_xmls)
     if use_gaff:
         self._forcefield.registerTemplateGenerator(gaffTemplateGenerator)
def test_generate_ffxml_from_molecules():
    """
    Test generation of single ffxml file from a list of molecules
    """
    # Create a test set of molecules.
    molecules = [createOEMolFromIUPAC(name) for name in IUPAC_molecule_names]
    # Create an ffxml file.
    from openmoltools.forcefield_generators import generateForceFieldFromMolecules

    ffxml = generateForceFieldFromMolecules(molecules)
    # Create a ForceField.
    gaff_xml_filename = utils.get_data_filename("parameters/gaff.xml")
    forcefield = ForceField(gaff_xml_filename)
    try:
        forcefield.loadFile(StringIO(ffxml))
    except Exception as e:
        msg = str(e)
        msg += "ffxml contents:\n"
        for (index, line) in enumerate(ffxml.split("\n")):
            msg += "line %8d : %s\n" % (index, line)
        raise Exception(msg)

    # Parameterize the molecules.
    from openmoltools.forcefield_generators import generateTopologyFromOEMol

    for molecule in molecules:
        # Create topology from molecule.
        topology = generateTopologyFromOEMol(molecule)
        # Create system with forcefield.
        system = forcefield.createSystem(topology)
        # Check potential is finite.
        positions = extractPositionsFromOEMOL(molecule)
        check_potential_is_finite(system, positions)
def test_porin_membrane_system():
    """Test the addition of a ligand to a solvated porin"""
    # pdb file corresponding to a solvated porin
    pdb = PDBFile(
        os.path.join(os.path.dirname(__file__),
                     '../data/porin/solvated-porin.pdb'))
    modeller = app.Modeller(pdb.topology, pdb.positions)
    forcefield = ForceField('amber14-all.xml', 'amber14/tip3pfb.xml')
    platform = mm.Platform.getPlatformByName('CPU')
    modeller.addHydrogens(forcefield=forcefield)
    # rigidWater False is required for ParMed to access water paramters
    system_md = forcefield.createSystem(modeller.topology,
                                        nonbondedMethod=app.PME,
                                        rigidWater=False,
                                        nonbondedCutoff=1 * unit.nanometer)
    ligand_system = PorinMembraneSystem('comp7',
                                        system_md,
                                        modeller.topology,
                                        modeller.positions,
                                        platform,
                                        tolerance=1 * unit.kilojoule /
                                        unit.mole,
                                        max_iterations=200)
    integrator = mm.LangevinIntegrator(300 * unit.kelvin,
                                       1.0 / unit.picoseconds,
                                       2 * unit.femtosecond)
    simulation = app.Simulation(ligand_system.structure.topology,
                                ligand_system.system, integrator, platform)
    simulation.context.setPositions(ligand_system.structure.positions)
    state = simulation.context.getState(getEnergy=True)
    pe = state.getPotentialEnergy()._value
    assert pe < 0.0
Example #5
0
def test_generate_ffxml_from_molecules():
    """
    Test generation of single ffxml file from a list of molecules
    """
    # Create a test set of molecules.
    molecules = [createOEMolFromIUPAC(name) for name in IUPAC_molecule_names]
    # Create an ffxml file.
    from openmoltools.forcefield_generators import generateForceFieldFromMolecules
    ffxml = generateForceFieldFromMolecules(molecules)
    # Create a ForceField.
    gaff_xml_filename = utils.get_data_filename("parameters/gaff.xml")
    forcefield = ForceField(gaff_xml_filename)
    try:
        forcefield.loadFile(StringIO(ffxml))
    except Exception as e:
        msg = str(e)
        msg += "ffxml contents:\n"
        for (index, line) in enumerate(ffxml.split('\n')):
            msg += 'line %8d : %s\n' % (index, line)
        raise Exception(msg)

    # Parameterize the molecules.
    from openmoltools.forcefield_generators import generateTopologyFromOEMol
    for molecule in molecules:
        # Create topology from molecule.
        topology = generateTopologyFromOEMol(molecule)
        # Create system with forcefield.
        system = forcefield.createSystem(topology)
        # Check potential is finite.
        positions = extractPositionsFromOEMOL(molecule)
        check_potential_is_finite(system, positions)
    def test_charge_from_molecules(self):
        """Test that user-specified partial charges are used if requested"""
        # Create a generator that does not know about any molecules
        generator = self.TEMPLATE_GENERATOR()
        # Create a ForceField
        from simtk.openmm.app import ForceField
        forcefield = ForceField()
        # Register the template generator
        forcefield.registerTemplateGenerator(generator.generator)

        # Check that parameterizing a molecule using user-provided charges produces expected charges
        import numpy as np
        from simtk import unit
        molecule = self.molecules[0]
        charges = np.random.random([molecule.n_particles])
        charges += (molecule.total_charge - charges.sum()) / molecule.n_particles
        molecule.partial_charges = unit.Quantity(charges, unit.elementary_charge)
        assert not np.all(molecule.partial_charges / unit.elementary_charge == 0)
        # Add the molecule
        generator.add_molecules(molecule)
        # Create the System
        from simtk.openmm.app import NoCutoff
        openmm_topology = molecule.to_topology().to_openmm()
        system = forcefield.createSystem(openmm_topology, nonbondedMethod=NoCutoff)
        assert self.charges_are_equal(system, molecule)
    def test_add_solvent(self):
        """Test using simtk.opnmm.app.Modeller to add solvent to a small molecule parameterized by template generator"""
        # Select a molecule to add solvent around
        from simtk.openmm.app import NoCutoff, Modeller
        from simtk import unit
        molecule = self.molecules[0]
        openmm_topology = molecule.to_topology().to_openmm()
        openmm_positions = molecule.conformers[0]
        # Try adding solvent without residue template generator; this will fail
        from simtk.openmm.app import ForceField
        forcefield = ForceField('tip3p.xml')
        # Add solvent to a system containing a small molecule
        modeller = Modeller(openmm_topology, openmm_positions)
        try:
            modeller.addSolvent(forcefield, model='tip3p', padding=6.0*unit.angstroms)
        except ValueError as e:
            pass

        # Create a generator that knows about a few molecules
        generator = self.TEMPLATE_GENERATOR(molecules=self.molecules)
        # Add to the forcefield object
        forcefield.registerTemplateGenerator(generator.generator)
        # Add solvent to a system containing a small molecule
        # This should succeed
        modeller.addSolvent(forcefield, model='tip3p', padding=6.0*unit.angstroms)
def test_membraneModeller():
    # pdb file containing a solvated single lipid molecule
    pdb = PDBFile('solvated-lipid.pdb')
    modeller = Modeller(pdb.topology,pdb.positions)
    modeller.modifyTopology()
    forcefield = ForceField('amber14-all.xml', 'amber14/tip3pfb.xml')
    modeller.addHydrogens(forcefield=forcefield)

    system = forcefield.createSystem(modeller.topology,
                                     nonbondedMethod=app.PME,
                                     rigidWater=True,
                                     nonbondedCutoff=1*unit.nanometer)
    integrator = mm.VerletIntegrator(0.5*unit.femtoseconds)
    platform = mm.Platform.getPlatformByName('Reference')
    simulation = app.Simulation(modeller.topology, system, integrator, platform)
    simulation.context.setPositions(modeller.positions)
    simulation.context.setVelocitiesToTemperature(300*unit.kelvin)
    # Minimize the system after adding hydrogens
    tolerance = 0.1*unit.kilojoules_per_mole/unit.angstroms
    simulation.minimizeEnergy(tolerance=tolerance,maxIterations=200)
    simulation.reporters.append(app.StateDataReporter('relax-hydrogens.log',
                                                       1000,
                                                       step=True,
                                                       potentialEnergy=True))
    simulation.step(1000)
def imatinib_timing():
    print("Loading imatinib...")
    # Load the PDB file.
    from simtk.openmm.app import PDBFile
    pdb_filename = utils.get_data_filename("chemicals/imatinib/imatinib.pdb")
    pdb = PDBFile(pdb_filename)
    # Create a ForceField object.
    gaff_xml_filename = utils.get_data_filename("parameters/gaff.xml")
    forcefield = ForceField(gaff_xml_filename)
    # Add the residue template generator.
    from openmoltools.forcefield_generators import gaffTemplateGenerator
    forcefield.registerTemplateGenerator(gaffTemplateGenerator)
    # Parameterize system.
    system = forcefield.createSystem(pdb.topology, nonbondedMethod=NoCutoff)
    integrator = openmm.LangevinIntegrator(300 * unit.kelvin, 5.0 / unit.picoseconds, 1.0 * unit.femtoseconds)
    # Create Context
    context = openmm.Context(system, integrator)
    context.setPositions(pdb.positions)
    integrator.step(100)

    import time
    nsteps = 10000000
    initial_time = time.time()
    integrator.step(nsteps)
    state = context.getState().getPeriodicBoxVectors() # force dynamics
    final_time = time.time()
    elapsed_time = final_time / initial_time
    time_per_step = elapsed_time / float(nsteps)
    print('time per force evaluation is %.3f us' % (time_per_step*1e6))
def imatinib_timing():
    print("Loading imatinib...")
    # Load the PDB file.
    from simtk.openmm.app import PDBFile
    pdb_filename = utils.get_data_filename("chemicals/imatinib/imatinib.pdb")
    pdb = PDBFile(pdb_filename)
    # Create a ForceField object.
    gaff_xml_filename = utils.get_data_filename("parameters/gaff.xml")
    forcefield = ForceField(gaff_xml_filename)
    # Add the residue template generator.
    from openmoltools.forcefield_generators import gaffTemplateGenerator
    forcefield.registerTemplateGenerator(gaffTemplateGenerator)
    # Parameterize system.
    system = forcefield.createSystem(pdb.topology, nonbondedMethod=NoCutoff)
    integrator = openmm.LangevinIntegrator(300 * unit.kelvin,
                                           5.0 / unit.picoseconds,
                                           1.0 * unit.femtoseconds)
    # Create Context
    context = openmm.Context(system, integrator)
    context.setPositions(pdb.positions)
    integrator.step(100)

    import time
    nsteps = 10000000
    initial_time = time.time()
    integrator.step(nsteps)
    state = context.getState().getPeriodicBoxVectors()  # force dynamics
    final_time = time.time()
    elapsed_time = final_time / initial_time
    time_per_step = elapsed_time / float(nsteps)
    print('time per force evaluation is %.3f us' % (time_per_step * 1e6))
Example #11
0
def test_membrane_modeller():
    """Test the addition of hydrogens to a solvated DPPC molecule"""
    # pdb file corresponding to a solvated lipid molecule
    pdb = PDBFile(os.path.join(os.path.dirname(__file__), '../data/dppc/solvated-dppc.pdb'))
    modeller = MembraneModeller(pdb.topology,pdb.positions)
    modeller.modify_topology()
    forcefield = ForceField('amber14-all.xml', 'amber14/tip3pfb.xml')
    modeller.addHydrogens(forcefield=forcefield)

    system = forcefield.createSystem(modeller.topology,
                                     nonbondedMethod=app.PME,
                                     rigidWater=True,
                                     nonbondedCutoff=1*unit.nanometer)
    integrator = mm.VerletIntegrator(0.5*unit.femtoseconds)
    platform = mm.Platform.getPlatformByName('Reference')
    simulation = app.Simulation(modeller.topology, system, integrator, platform)
    simulation.context.setPositions(modeller.positions)
    simulation.context.setVelocitiesToTemperature(300*unit.kelvin)
    # Minimize the system after adding hydrogens
    simulation.minimizeEnergy(maxIterations=200)
    # Run a few MD steps to check the system has no overlaps
    simulation.step(1000)
    state = simulation.context.getState(getEnergy=True)
    pe = state.getPotentialEnergy()._value
    assert pe < 0.0
 def _parse_force_field(self, *args):
     if args[0] == 'TraPPE-UA':
         self.forceField = ForceField(self.TRAPPEUA_FF_PATH)
     elif args[0] == 'OPLS-AA':
         self.forceField = ForceField(self.OPLS_AA_PATH)
     else:
         raise ValueError("Invalid force field.")
     self.forceField_str = args[0]
 def __init__(self, system_options):
     super(DodecaneAcrylateTopologyOptions, self).__init__(system_options)
     self.forceField_str = "TraPPE-UA"
     self.forceField = ForceField(self.TRAPPEUA_FF_PATH)
     self.numDodecane = 0
     self.numSqualane = 0
     self.dodecaneInstructions = None
     self.box_vectors = None
     self.chains = []
     self.branched_chains = []
     self.id_to_sequence = {}
Example #14
0
def test_xtc_reporter_append(tmpdir, get_fn):
    pdb = PDBFile(get_fn('native.pdb'))
    forcefield = ForceField('amber99sbildn.xml', 'amber99_obc.xml')
    # NO PERIODIC BOUNDARY CONDITIONS
    system = forcefield.createSystem(pdb.topology,
                                     nonbondedMethod=CutoffNonPeriodic,
                                     nonbondedCutoff=1.0 * nanometers,
                                     constraints=HBonds,
                                     rigidWater=True)
    integrator = LangevinIntegrator(300 * kelvin, 1.0 / picoseconds,
                                    2.0 * femtoseconds)
    integrator.setConstraintTolerance(0.00001)

    platform = Platform.getPlatformByName('Reference')
    simulation = Simulation(pdb.topology, system, integrator, platform)
    simulation.context.setPositions(pdb.positions)

    simulation.context.setVelocitiesToTemperature(300 * kelvin)

    tmpdir = str(tmpdir)
    xtcfile = os.path.join(tmpdir, 'traj.xtc')
    xtcfile_cp = os.path.join(tmpdir, 'traj_cp.xtc')
    checkpoint = os.path.join(tmpdir, 'checkpoint.chk')
    reporter = XTCReporter(xtcfile, 2)
    simulation.reporters.append(reporter)
    simulation.reporters.append(CheckpointReporter(checkpoint, 10))
    simulation.step(10)
    reporter.close()
    shutil.copyfile(xtcfile, xtcfile_cp)
    system = forcefield.createSystem(pdb.topology,
                                     nonbondedMethod=CutoffNonPeriodic,
                                     nonbondedCutoff=1.0 * nanometers,
                                     constraints=HBonds,
                                     rigidWater=True)
    integrator = LangevinIntegrator(300 * kelvin, 1.0 / picoseconds,
                                    2.0 * femtoseconds)
    integrator.setConstraintTolerance(0.00001)

    platform = Platform.getPlatformByName('Reference')
    simulation = Simulation(pdb.topology, system, integrator, platform)
    simulation.loadCheckpoint(checkpoint)
    reporter = XTCReporter(xtcfile, 2, append=True)
    simulation.reporters.append(reporter)
    simulation.step(10)
    reporter.close()
    xtc_traj = md.load(xtcfile, top=get_fn('native.pdb'))
    xtc_traj_cp = md.load(xtcfile_cp, top=get_fn('native.pdb'))
    eq(xtc_traj.xyz[:5], xtc_traj_cp.xyz)
    eq(xtc_traj.n_frames, 10)
    eq(xtc_traj_cp.n_frames, 5)
    eq(xtc_traj.time[:5], xtc_traj_cp.time)
Example #15
0
def test_gaffResidueTemplateGenerator():
    """
    Test the GAFF residue template generator.
    """

    #
    # Test where we generate parameters for only a ligand.
    #

    # Load the PDB file.
    from simtk.openmm.app import PDBFile
    pdb_filename = utils.get_data_filename("chemicals/imatinib/imatinib.pdb")
    pdb = PDBFile(pdb_filename)
    # Create a ForceField object.
    gaff_xml_filename = utils.get_data_filename("parameters/gaff.xml")
    forcefield = ForceField(gaff_xml_filename)
    # Add the residue template generator.
    from openmoltools.forcefield_generators import gaffTemplateGenerator
    forcefield.registerTemplateGenerator(gaffTemplateGenerator)
    # Parameterize system.
    system = forcefield.createSystem(pdb.topology, nonbondedMethod=NoCutoff)
    # Check potential is finite.
    check_potential_is_finite(system, pdb.positions)
    # Check energy matches prmtop route.
    check_energy_components_vs_prmtop(
        prmtop=utils.get_data_filename('chemicals/imatinib/imatinib.prmtop'),
        inpcrd=utils.get_data_filename('chemicals/imatinib/imatinib.inpcrd'),
        system=system)

    #
    # Test where we generate parameters for only a ligand in a protein.
    #

    # Load the PDB file.
    from simtk.openmm.app import PDBFile
    pdb_filename = utils.get_data_filename(
        "chemicals/proteins/T4-lysozyme-L99A-p-xylene-implicit.pdb")
    pdb = PDBFile(pdb_filename)
    # Create a ForceField object.
    gaff_xml_filename = utils.get_data_filename("parameters/gaff.xml")
    forcefield = ForceField('amber99sb.xml', gaff_xml_filename)
    # Add the residue template generator.
    from openmoltools.forcefield_generators import gaffTemplateGenerator
    forcefield.registerTemplateGenerator(gaffTemplateGenerator)
    # Parameterize system.
    system = forcefield.createSystem(pdb.topology, nonbondedMethod=NoCutoff)
    # Check potential is finite.
    check_potential_is_finite(system, pdb.positions)
 def __init__(self, forcefields_to_use, forcefield_kwargs=None, use_gaff=True):
     self._forcefield_xmls = forcefields_to_use
     self._forcefield_kwargs = forcefield_kwargs if forcefield_kwargs is not None else {}
     from simtk.openmm.app import ForceField
     self._forcefield = ForceField(*self._forcefield_xmls)
     if use_gaff:
         self._forcefield.registerTemplateGenerator(gaffTemplateGenerator)
def calculate_fragment_energetics(frag_no=1):
    """
    * Create an OpenMM system with a fragment.
    * Calculate the energy of the system and print.
    :param frag_no: The number of the fragment being analysed (used to access files).
    """
    os.chdir(f'group2/frag{frag_no}')
    # Necessary due to size of calculation
    sys.setrecursionlimit(15000)

    pdb = PDBFile(f'QUBE_pro_frag{frag_no}.pdb')
    forcefield = ForceField(f'QUBE_pro_frag{frag_no}_plus.xml')

    system = forcefield.createSystem(
        pdb.topology,
        nonbondedMethod=NoCutoff,
    )

    system = apply_opls_combo(system)

    with open(f'QUBE_pro_frag{frag_no}_out.xml', 'w') as outfile:
        serialized_system = XmlSerializer.serialize(system)
        outfile.write(serialized_system)

    # Create the integrator to do Langevin dynamics
    integrator = LangevinIntegrator(
        298.15 * unit.kelvin,  # Temperature of heat bath
        1.0 / unit.picoseconds,  # Friction coefficient
        2.0 * unit.femtoseconds,  # Time step
    )

    platform = Platform.getPlatformByName('CPU')
    simulation = Simulation(pdb.topology, system, integrator, platform)
    simulation.context.setPositions(pdb.positions)
    print('energy from openmm library')
    print(simulation.context.getState(getEnergy=True).getPotentialEnergy())

    structure = parmed.load_file(f'QUBE_pro_frag{frag_no}.pdb')
    energy_comps = parmed.openmm.energy_decomposition_system(structure, system)

    total_energy = 0.0
    for comp in energy_comps:
        total_energy += comp[1]
        print(*comp)

    print(f'Total energy {total_energy: 6.6f}')
    def test_multiple_registration(self):
        """Test registering the template generator with multiple force fields"""
        generator = self.TEMPLATE_GENERATOR(molecules=self.molecules)
        from simtk.openmm.app import ForceField
        NUM_FORCEFIELDS = 2 # number of force fields to test
        forcefields = list()
        for index in range(NUM_FORCEFIELDS):
            forcefield = ForceField()
            forcefield.registerTemplateGenerator(generator.generator)
            forcefields.append(forcefield)

        # Parameterize a molecule in each force field instance
        molecule = self.molecules[0]
        openmm_topology = molecule.to_topology().to_openmm()
        from simtk.openmm.app import NoCutoff
        for forcefield in forcefields:
            system = forcefield.createSystem(openmm_topology, nonbondedMethod=NoCutoff)
            assert system.getNumParticles() == molecule.n_atoms
Example #19
0
def setup(args: ListOfArgs) -> Tuple[PDBFile, int, Simulation]:
    print("Initialization...")
    if args.SIM_RANDOM_SEED == 0:
        random_seed = np.random.randint(2147483647)
    else:
        random_seed = args.SIM_RANDOM_SEED
    print(f"   Loading initial structure: {args.INITIAL_STRUCTURE_PATH}")
    pdb = PDBFile(args.INITIAL_STRUCTURE_PATH)
    print(f"   Loading forcefield file:  {args.FORCEFIELD_PATH}")
    forcefield = ForceField(args.FORCEFIELD_PATH)
    print("   Building system...")
    system = forcefield.createSystem(pdb.topology)
    add_forces_to_system(system, args)
    integrator = get_integrator(random_seed, args)
    print("   Setting up simulation...")
    simulation = Simulation(pdb.topology, system, integrator)
    simulation.context.setPositions(pdb.positions)
    return pdb, random_seed, simulation
Example #20
0
def test_xtc_reporter_append(tmpdir, get_fn):
    pdb = PDBFile(get_fn('native.pdb'))
    forcefield = ForceField('amber99sbildn.xml', 'amber99_obc.xml')
    # NO PERIODIC BOUNDARY CONDITIONS
    system = forcefield.createSystem(pdb.topology, nonbondedMethod=CutoffNonPeriodic,
                                     nonbondedCutoff=1.0 * nanometers, constraints=HBonds, rigidWater=True)
    integrator = LangevinIntegrator(300 * kelvin, 1.0 / picoseconds, 2.0 * femtoseconds)
    integrator.setConstraintTolerance(0.00001)

    platform = Platform.getPlatformByName('Reference')
    simulation = Simulation(pdb.topology, system, integrator, platform)
    simulation.context.setPositions(pdb.positions)

    simulation.context.setVelocitiesToTemperature(300 * kelvin)

    tmpdir = str(tmpdir)
    xtcfile = os.path.join(tmpdir, 'traj.xtc')
    xtcfile_cp = os.path.join(tmpdir, 'traj_cp.xtc')
    checkpoint = os.path.join(tmpdir, 'checkpoint.chk')
    reporter = XTCReporter(xtcfile, 2)
    simulation.reporters.append(reporter)
    simulation.reporters.append(CheckpointReporter(checkpoint, 10))
    simulation.step(10)
    reporter.close()
    shutil.copyfile(xtcfile, xtcfile_cp)
    system = forcefield.createSystem(pdb.topology, nonbondedMethod=CutoffNonPeriodic,
                                     nonbondedCutoff=1.0 * nanometers, constraints=HBonds, rigidWater=True)
    integrator = LangevinIntegrator(300 * kelvin, 1.0 / picoseconds, 2.0 * femtoseconds)
    integrator.setConstraintTolerance(0.00001)

    platform = Platform.getPlatformByName('Reference')
    simulation = Simulation(pdb.topology, system, integrator, platform)
    simulation.loadCheckpoint(checkpoint)
    reporter = XTCReporter(xtcfile, 2, append=True)
    simulation.reporters.append(reporter)
    simulation.step(10)
    reporter.close()
    xtc_traj = md.load(xtcfile, top=get_fn('native.pdb'))
    xtc_traj_cp = md.load(xtcfile_cp, top=get_fn('native.pdb'))
    eq(xtc_traj.xyz[:5], xtc_traj_cp.xyz)
    eq(xtc_traj.n_frames, 10)
    eq(xtc_traj_cp.n_frames, 5)
    eq(xtc_traj.time[:5], xtc_traj_cp.time)
def test_gaffResidueTemplateGenerator():
    """
    Test the GAFF residue template generator.
    """

    #
    # Test where we generate parameters for only a ligand.
    #

    # Load the PDB file.
    from simtk.openmm.app import PDBFile

    pdb_filename = utils.get_data_filename("chemicals/imatinib/imatinib.pdb")
    pdb = PDBFile(pdb_filename)
    # Create a ForceField object.
    gaff_xml_filename = utils.get_data_filename("parameters/gaff.xml")
    forcefield = ForceField(gaff_xml_filename)
    # Add the residue template generator.
    from openmoltools.forcefield_generators import gaffTemplateGenerator

    forcefield.registerTemplateGenerator(gaffTemplateGenerator)
    # Parameterize system.
    system = forcefield.createSystem(pdb.topology, nonbondedMethod=NoCutoff)
    # Check potential is finite.
    check_potential_is_finite(system, pdb.positions)
    # Check energy matches prmtop route.
    check_energy_components_vs_prmtop(
        prmtop=utils.get_data_filename("chemicals/imatinib/imatinib.prmtop"),
        inpcrd=utils.get_data_filename("chemicals/imatinib/imatinib.inpcrd"),
        system=system,
    )

    #
    # Test where we generate parameters for only a ligand in a protein.
    #

    # Load the PDB file.
    from simtk.openmm.app import PDBFile

    pdb_filename = utils.get_data_filename("chemicals/proteins/T4-lysozyme-L99A-p-xylene-implicit.pdb")
    pdb = PDBFile(pdb_filename)
    # Create a ForceField object.
    gaff_xml_filename = utils.get_data_filename("parameters/gaff.xml")
    forcefield = ForceField("amber99sb.xml", gaff_xml_filename)
    # Add the residue template generator.
    from openmoltools.forcefield_generators import gaffTemplateGenerator

    forcefield.registerTemplateGenerator(gaffTemplateGenerator)
    # Parameterize system.
    system = forcefield.createSystem(pdb.topology, nonbondedMethod=NoCutoff)
    # Check potential is finite.
    check_potential_is_finite(system, pdb.positions)
Example #22
0
    def __init__(self, pdb_path, offset_size=2):
        # OpenMM init
        self.pdb_path = pdb_path
        self.pdb = PDBFile(self.pdb_path)
        self.forcefield = ForceField('amber14-all.xml', 'amber14/tip3pfb.xml')
        self.modeller = Modeller(self.pdb.topology, self.pdb.positions)

        # Remove any water that might be present in the PDB file
        self.modeller.deleteWater()

        # Add any hydrogens not present
        self.modeller.addHydrogens(self.forcefield)
        self.system = self.forcefield.createSystem(self.modeller.topology,
                                                   nonbondedMethod=PME,
                                                   nonbondedCutoff=1 *
                                                   u.nanometer,
                                                   constraints=HBonds)
        self.integrator = LangevinIntegrator(300 * u.kelvin, 1 / u.picosecond,
                                             0.002 * u.picoseconds)
        self.simulation = Simulation(self.modeller.topology, self.system,
                                     self.integrator)
        self.pdb_positions = self.modeller.getPositions()

        # Initialize bond dictionary and positions for chemcoord
        self.cc_bonds = {}
        self.offset_size = offset_size
        self._init_pdb_bonds()
        self.set_cc_positions(self.pdb_positions)

        # Perform initial minimization, which updates self.pdb_positions
        min_energy, min_positions = self.run_simulation()

        # Reset the positions after the minimization
        self.set_cc_positions(self.pdb_positions)
        self.torsion_indices = self._get_torsion_indices()
        self.starting_positions = min_positions
        self.starting_torsions = np.array([
            self.zmat.loc[self.torsion_indices[:, 0], 'dihedral'],
            self.zmat.loc[self.torsion_indices[:, 1], 'dihedral']
        ]).T
        self.seed_offsets()
 def test_parameterize(self):
     """Test parameterizing molecules with template generator for all supported force fields"""
     # Test all supported small molecule force fields
     for small_molecule_forcefield in self.TEMPLATE_GENERATOR.INSTALLED_FORCEFIELDS:
         print(f'Testing {small_molecule_forcefield}')
         # Create a generator that knows about a few molecules
         # TODO: Should the generator also load the appropriate force field files into the ForceField object?
         generator = self.TEMPLATE_GENERATOR(molecules=self.molecules, forcefield=small_molecule_forcefield)
         # Check that we have loaded the right force field
         assert generator.forcefield == small_molecule_forcefield
         # Create a ForceField with the appropriate small molecule force field
         from simtk.openmm.app import ForceField
         forcefield = ForceField()
         # Register the template generator
         forcefield.registerTemplateGenerator(generator.generator)
         # Parameterize some molecules
         from simtk.openmm.app import NoCutoff
         from openmmforcefields.utils import Timer
         for molecule in self.molecules:
             openmm_topology = molecule.to_topology().to_openmm()
             with Timer() as t1:
                 system = forcefield.createSystem(openmm_topology, nonbondedMethod=NoCutoff)
             assert system.getNumParticles() == molecule.n_atoms
             # Molecule should now be cached
             with Timer() as t2:
                 system = forcefield.createSystem(openmm_topology, nonbondedMethod=NoCutoff)
             assert system.getNumParticles() == molecule.n_atoms
             assert (t2.interval() < t1.interval())
Example #24
0
 def add_hydrogens_by_openmm(self):
     from simtk.openmm.app import ForceField, Modeller, PDBFile
     from pdbfixer import PDBFixer
     fixer = PDBFixer(self.name)
     field = ForceField('amber99sb.xml', 'tip3p.xml')
     fixer.findMissingResidues()
     fixer.findMissingAtoms()
     fixer.addMissingAtoms()
     fixer.addMissingHydrogens(7.0)
     modeller = Modeller(fixer.topology, fixer.positions)
     modeller.addHydrogens(forcefield=field)
     modeller.deleteWater()
     PDBFile.writeModel(modeller.topology, modeller.positions, open(self.shotname+'_h.pdb', 'w'))
Example #25
0
    def _prep_sim(self, coords, external_forces=[]):

        try:
            from simtk.openmm import Platform, LangevinIntegrator, Vec3
            from simtk.openmm.app import Modeller, ForceField, \
                CutoffNonPeriodic, PME, Simulation, HBonds
            from simtk.unit import angstrom, nanometers, picosecond, \
                kelvin, Quantity, molar
        except ImportError:
            raise ImportError(
                'Please install PDBFixer and OpenMM in order to use ClustENM.')

        positions = Quantity([Vec3(*xyz) for xyz in coords], angstrom)
        modeller = Modeller(self._topology, positions)

        if self._sol == 'imp':
            forcefield = ForceField(*self._force_field)

            system = forcefield.createSystem(modeller.topology,
                                             nonbondedMethod=CutoffNonPeriodic,
                                             nonbondedCutoff=1.0 * nanometers,
                                             constraints=HBonds)

        if self._sol == 'exp':
            forcefield = ForceField(*self._force_field)

            modeller.addSolvent(forcefield,
                                padding=self._padding * nanometers,
                                ionicStrength=self._ionicStrength * molar)

            system = forcefield.createSystem(modeller.topology,
                                             nonbondedMethod=PME,
                                             nonbondedCutoff=1.0 * nanometers,
                                             constraints=HBonds)

        for force in external_forces:
            system.addForce(force)

        integrator = LangevinIntegrator(self._temp * kelvin, 1 / picosecond,
                                        0.002 * picosecond)

        # precision could be mixed, but single is okay.
        platform = self._platform if self._platform is None else Platform.getPlatformByName(
            self._platform)
        properties = None

        if self._platform is None:
            properties = {'Precision': 'single'}
        elif self._platform in ['CUDA', 'OpenCL']:
            properties = {'Precision': 'single'}

        simulation = Simulation(modeller.topology, system, integrator,
                                platform, properties)

        simulation.context.setPositions(modeller.positions)

        return simulation
Example #26
0
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
    """
    from perses.utils.data import get_data_filename
    from perses.utils.openeye import extractPositionsFromOEMol
    # Create OEMol
    molecule = iupac_to_oemol(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)
Example #27
0
    def from_pickle(cls, path, positions=None, forcefield=None, **kwargs):
        if positions is None:
            raise ValueError(
                'Pickled topology files require initial positions.')
        if forcefield is None:
            raise ValueError(
                'Pickled topology files require XML/FRCMOD forcefields.')

        topology = cls._pickle_load(path)
        forcefield = ForceField(*list(process_forcefield(*forcefield)))
        return cls(master=forcefield,
                   topology=topology,
                   positions=positions,
                   path=path,
                   **kwargs)
    def test_jacs_ligands(self):
        """Use template generator to parameterize the Schrodinger JACS set of ligands"""
        from simtk.openmm.app import ForceField, NoCutoff
        jacs_systems = {
            #'bace'     : { 'prefix' : 'Bace' },
            #'cdk2'     : { 'prefix' : 'CDK2' },
            'jnk1'     : { 'prefix' : 'Jnk1' },
            'mcl1'     : { 'prefix' : 'MCL1' },
            #'p38'      : { 'prefix' : 'p38' },
            'ptp1b'    : { 'prefix' : 'PTP1B' },
            'thrombin' : { 'prefix' : 'Thrombin' },
            #'tyk2'     : { 'prefix' : 'Tyk2' },
        }
        for system_name in jacs_systems:
            prefix = jacs_systems[system_name]['prefix']
            # Load molecules
            ligand_sdf_filename = get_data_filename(os.path.join('perses_jacs_systems', system_name, prefix + '_ligands.sdf'))
            print(f'Reading molecules from {ligand_sdf_filename} ...')
            from openforcefield.topology import Molecule
            molecules = Molecule.from_file(ligand_sdf_filename, allow_undefined_stereo=True)
            # Ensure this is a list
            try:
                nmolecules = len(molecules)
            except TypeError:
                molecules = [molecules]

            print(f'Read {len(molecules)} molecules from {ligand_sdf_filename}')
            #molecules = self.filter_molecules(molecules)
            MAX_MOLECULES = len(molecules)
            if 'TRAVIS' in os.environ:
                MAX_MOLECULES = 3
            molecules = molecules[:MAX_MOLECULES]
            print(f'{len(molecules)} molecules remain after filtering')

            # Create template generator with local cache
            cache = os.path.join(get_data_filename(os.path.join('perses_jacs_systems', system_name)), 'cache.json')
            generator = self.TEMPLATE_GENERATOR(molecules=molecules, cache=cache)

            # Create a ForceField
            forcefield = ForceField()
            # Register the template generator
            forcefield.registerTemplateGenerator(generator.generator)

            # Parameterize all molecules
            print(f'Caching all molecules for {system_name} at {cache} ...')
            n_success = 0
            n_failure = 0
            for molecule in molecules:
                openmm_topology = molecule.to_topology().to_openmm()
                try:
                    forcefield.createSystem(openmm_topology, nonbondedMethod=NoCutoff)
                    n_success += 1
                except Exception as e:
                    n_failure += 1
                    print(e)
            print(f'{n_failure}/{n_success+n_failure} ligands failed to parameterize for {system_name}')
Example #29
0
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)

    # Extract positions
    positions = extractPositionsFromOEMOL(molecule)

    return (molecule, system, positions, topology)
def check_hydrogens(molecule, ID):
    # Check that Hydrogens are in structure
    if len(molecule.top.select("name == H")) == 0:
        # If absent, then add Hydrogens using the Amber99sb force-field
        try:
            from simtk.openmm.app import PDBFile, Modeller, ForceField
            pdb = PDBFile(ID + ".pdb")
            modeller = Modeller(pdb.topology, pdb.positions)
            forcefield = ForceField('amber99sb.xml', 'tip3p.xml')
            modeller.addHydrogens(forcefield)
            PDBFile.writeFile(modeller.topology, modeller.positions,
                              open(ID + ".pdb", 'w'))
            molecule = md.load(ID + ".pdb").remove_solvent()
        except:
            warnings.warn(
                """PDB topology missing Hydrogens. Either manually add
            or install OpenMM through SIMTK to automatically correct.""")
            pass
    return molecule
Example #31
0
    def from_pdb(cls,
                 path,
                 forcefield=None,
                 loader=PDBFile,
                 strict=True,
                 **kwargs):
        """
        Loads topology, positions and, potentially, velocities and vectors,
        from a PDB or PDBx file

        Parameters
        ----------
        path : str
            Path to PDB/PDBx file
        forcefields : list of str
            Paths to FFXML and/or FRCMOD forcefields. REQUIRED.

        Returns
        -------
        pdb : SystemHandler
            SystemHandler with topology, positions, and, potentially, velocities and
            box vectors. Forcefields are embedded in the `master` attribute.
        """
        pdb = loader(path)
        box = kwargs.pop('box', pdb.topology.getPeriodicBoxVectors())
        positions = kwargs.pop('positions', pdb.positions)
        velocities = kwargs.pop('velocities', getattr(pdb, 'velocities', None))

        if strict and not forcefield:
            from .md import FORCEFIELDS as forcefield
            logger.info(
                '! Forcefields for PDB not specified. Using default: %s',
                ', '.join(forcefield))
        pdb.forcefield = ForceField(*list(process_forcefield(*forcefield)))

        return cls(master=pdb.forcefield,
                   topology=pdb.topology,
                   positions=positions,
                   velocities=velocities,
                   box=box,
                   path=path,
                   **kwargs)
    def test_add_molecules(self):
        """Test that molecules can be added to template generator after its creation"""
        # Create a generator that does not know about any molecules
        generator = self.TEMPLATE_GENERATOR()
        # Create a ForceField
        from simtk.openmm.app import ForceField
        forcefield = ForceField()
        # Register the template generator
        forcefield.registerTemplateGenerator(generator.generator)

        # Check that parameterizing a molecule fails
        molecule = self.molecules[0]
        from simtk.openmm.app import NoCutoff
        try:
            # This should fail with an exception
            openmm_topology = molecule.to_topology().to_openmm()
            system = forcefield.createSystem(openmm_topology,
                                             nonbondedMethod=NoCutoff)
        except ValueError as e:
            # Exception 'No template found...' is expected
            assert str(e).startswith('No template found')

        # Now add the molecule to the generator and ensure parameterization passes
        generator.add_molecules(molecule)
        openmm_topology = molecule.to_topology().to_openmm()
        try:
            system = forcefield.createSystem(openmm_topology,
                                             nonbondedMethod=NoCutoff)
        except Exception as e:
            print(forcefield._atomTypes.keys())
            from simtk.openmm.app import PDBFile
            PDBFile.writeFile(openmm_topology, molecule.conformers[0])
            raise e
        assert system.getNumParticles() == molecule.n_atoms

        # Add multiple molecules, including repeats
        generator.add_molecules(self.molecules)

        # Ensure all molecules can be parameterized
        for molecule in self.molecules:
            openmm_topology = molecule.to_topology().to_openmm()
            system = forcefield.createSystem(openmm_topology,
                                             nonbondedMethod=NoCutoff)
            assert system.getNumParticles() == molecule.n_atoms
Example #33
0
def _assignNamesFromForceFieldTemplates(topology, system, openmm_forcefields_to_use):
    '''
    Assign Amber atom and residue names from specified forcefield templates.
    Requires OpenMM version >= 5.2.

    ARGUMENTS

    topology
    system
    openmm_forcefields_to_use (list of strings) - list of XML files of forcefields containing templates

    RETURNS

    atoms - list of atom information
    sorted_atom_indices (list of int) - atom indices in order that they appear in forcefield templates, in case re-sorting is required

    '''

    # Assign AMBER atom and residue names.
    from simtk.openmm.app import ForceField
    import simtk.openmm.app.forcefield
    forcefield = ForceField(*openmm_forcefields_to_use)

    data = ForceField._SystemData()
    atomIndices = {}
    for index, atom in enumerate(topology.atoms()):
        data.atoms.append(atom)
        atomIndices[atom] = index

    # Make a list of all bonds
    for bond in topology.bonds():
        if bond[0] in atomIndices and bond[1] in atomIndices:
            data.bonds.append(ForceField._BondData(atomIndices[bond[0]], atomIndices[bond[1]]))

    # Record which atoms are bonded to each other atom
    bondedToAtom = []
    for i in range(len(data.atoms)):
        bondedToAtom.append(set())
        data.atomBonds.append([])
    for i in range(len(data.bonds)):
        bond = data.bonds[i]
        bondedToAtom[bond.atom1].add(bond.atom2)
        bondedToAtom[bond.atom2].add(bond.atom1)
        data.atomBonds[bond.atom1].append(i)
        data.atomBonds[bond.atom2].append(i)

    # Find the template matching each residue and assign atom types.
    sorted_atom_indices = list()
    for chain in topology.chains():
        for res in chain.residues():
            template = None
            matches = None
            # NOTE: Before OpenMM 5.2, was necessary to convert output of _createResidueSignature using the method simtk.openmm.app.forcefield._signatureToString - this is now done within _createResidueSignature
            sig = simtk.openmm.app.forcefield._createResidueSignature([atom.element for atom in res.atoms()])
            if sig != '':
                if sig in forcefield._templateSignatures:
                    for t in forcefield._templateSignatures[sig]:
                        # NOTE: No longer necessary to pass atomIndices in OpenMM > 5.2
                        matches = simtk.openmm.app.forcefield._matchResidue(res, t, bondedToAtom)
                        if matches is not None:
                            template = t
                            break
            if matches is None:
                # Check templates involving virtual sites
                for t in forcefield._templateSignatures[None]:
                    matches = simtk.openmm.app.forcefield._matchResidue(res, t, bondedToAtom)
                    if matches is not None:
                        template = t
                        break
            if matches is None:
                raise ValueError('No template found for residue %d (%s).  This might mean your input topology is missing some atoms or bonds, or possibly that you are using the wrong force field.' % (res.index+1, res.name))

            # Sort matches by order in template.
            atom_indices = [ atom.index for atom in res.atoms() ]
            for local_index in range(len(template.atoms)):
                if local_index in matches:
                    sorted_atom_indices.append(min(atom_indices) + matches.index(local_index))

            for (atom, match) in zip(res.atoms(), matches):
                data.atomType[atom] = template.atoms[match].type
                # Rename atom (JDC).
                atom.name = template.atoms[match].name
                atom.resname = template.name

                for site in template.virtualSites:
                    if match == site.index:
                        data.virtualSites[atom] = site

    return (data.atoms, sorted_atom_indices)
class SystemGenerator(object):
    """
    Utility factory to generate OpenMM Systems from Topology objects.

    Parameters
    ----------
    forcefields_to_use : list of string
        List of the names of ffxml files that will be used in system creation.
    forcefield_kwargs : dict of arguments to createSystem, optional
        Allows specification of various aspects of system creation.
    use_gaff : bool, optional, default=True
        If True, will add the GAFF residue template generator.

    Examples
    --------
    >>> from simtk.openmm import app
    >>> forcefield_kwargs={ 'nonbondedMethod' : app.NoCutoff, 'implicitSolvent' : None, 'constraints' : None }
    >>> system_generator = SystemGenerator(['amber99sbildn.xml'], forcefield_kwargs=forcefield_kwargs)
    >>> from openmmtools.testsystems import AlanineDipeptideVacuum
    >>> testsystem = AlanineDipeptideVacuum()
    >>> system = system_generator.createSystem(testsystem.topology)
    """

    def __init__(self, forcefields_to_use, forcefield_kwargs=None, use_gaff=True):
        self._forcefield_xmls = forcefields_to_use
        self._forcefield_kwargs = forcefield_kwargs if forcefield_kwargs is not None else {}
        from simtk.openmm.app import ForceField
        self._forcefield = ForceField(*self._forcefield_xmls)
        if use_gaff:
            self._forcefield.registerTemplateGenerator(gaffTemplateGenerator)

    def getForceField(self):
        """
        Return the associated ForceField object.

        Returns
        -------
        forcefield : simtk.openmm.app.ForceField
            The current ForceField object.
        """
        return self._forcefield

    def createSystem(self, topology):
        """
        Build a system from specified topology object.

        Parameters
        ----------
        topology : simtk.openmm.app.Topology object
            The topology of the system to construct.

        Returns
        -------
        system : openmm.System
            A system object generated from the topology
        """
        system = self._forcefield.createSystem(topology, **self._forcefield_kwargs)
        return system

    @property
    def ffxmls(self):
        return self._forcefield_xmls

    @property
    def forcefield(self):
        return self._forcefield
    def test_jacs_complexes(self):
        """Use template generator to parameterize the Schrodinger JACS set of complexes"""
        # TODO: Uncomment working systems when we have cleaned up the input files
        jacs_systems = {
            #'bace'     : { 'prefix' : 'Bace' },
            #'cdk2'     : { 'prefix' : 'CDK2' },
            #'jnk1'     : { 'prefix' : 'Jnk1' },
            'mcl1'     : { 'prefix' : 'MCL1' },
            #'p38'      : { 'prefix' : 'p38' },
            #'ptp1b'    : { 'prefix' : 'PTP1B' },
            #'thrombin' : { 'prefix' : 'Thrombin' },
            #'tyk2'     : { 'prefix' : 'Tyk2' },
        }
        for system_name in jacs_systems:
            prefix = jacs_systems[system_name]['prefix']
            # Read molecules
            ligand_sdf_filename = get_data_filename(os.path.join('perses_jacs_systems', system_name, prefix + '_ligands.sdf'))
            print(f'Reading molecules from {ligand_sdf_filename} ...')
            from openforcefield.topology import Molecule
            molecules = Molecule.from_file(ligand_sdf_filename, allow_undefined_stereo=True)
            try:
                nmolecules = len(molecules)
            except TypeError:
                molecules = [molecules]
            print(f'Read {len(molecules)} molecules from {ligand_sdf_filename}')

            # Read ParmEd Structures
            import parmed
            from simtk import unit
            protein_pdb_filename = get_data_filename(os.path.join('perses_jacs_systems', system_name, prefix + '_protein.pdb'))
            from simtk.openmm.app import PDBFile
            print(f'Reading protein from {protein_pdb_filename} ...')
            #protein_structure = parmed.load_file(protein_pdb_filename) # NOTE: This mis-interprets distorted geometry and sequentially-numbered residues that span chain breaks
            pdbfile = PDBFile(protein_pdb_filename)
            protein_structure = parmed.openmm.load_topology(pdbfile.topology, xyz=pdbfile.positions.value_in_unit(unit.angstroms))
            ligand_structures = parmed.load_file(ligand_sdf_filename)
            try:
                nmolecules = len(ligand_structures)
            except TypeError:
                ligand_structures = [ligand_structures]
            assert len(ligand_structures) == len(molecules)

            # Filter molecules
            if 'TRAVIS' in os.environ:
                MAX_MOLECULES = 3
            else:
                MAX_MOLECULES = 6
            molecules = molecules[:MAX_MOLECULES]
            ligand_structures = ligand_structures[:MAX_MOLECULES]
            print(f'{len(molecules)} molecules remain after filtering')

            # Create complexes
            complex_structures = [ (protein_structure + ligand_structure) for ligand_structure in ligand_structures ]

            # Create template generator with local cache
            cache = os.path.join(get_data_filename(os.path.join('perses_jacs_systems', system_name)), 'cache.json')
            generator = self.TEMPLATE_GENERATOR(molecules=molecules, cache=cache)

            # Create a ForceField
            from simtk.openmm.app import ForceField
            forcefield = ForceField(*self.amber_forcefields)
            # Register the template generator
            forcefield.registerTemplateGenerator(generator.generator)

            # Parameterize all complexes
            print(f'Caching all molecules for {system_name} at {cache} ...')
            for ligand_index, complex_structure in enumerate(complex_structures):
                openmm_topology = complex_structure.topology
                molecule = molecules[ligand_index]

                # Delete hydrogens from terminal protein residues
                # TODO: Fix the input files so we don't need to do this
                from simtk.openmm import app
                modeller = app.Modeller(complex_structure.topology, complex_structure.positions)
                residues = [residue for residue in modeller.topology.residues() if residue.name != 'UNL']
                termini_ids = [residues[0].id, residues[-1].id]
                #hs = [atom for atom in modeller.topology.atoms() if atom.element.symbol in ['H'] and atom.residue.name != 'UNL']
                hs = [atom for atom in modeller.topology.atoms() if atom.element.symbol in ['H'] and atom.residue.id in termini_ids]
                modeller.delete(hs)
                from simtk.openmm.app import PDBFile
                modeller.addHydrogens(forcefield)

                # Parameterize protein:ligand complex in vacuum
                print(f' Parameterizing {system_name} : {molecule.to_smiles()} in vacuum...')
                from simtk.openmm.app import NoCutoff
                forcefield.createSystem(modeller.topology, nonbondedMethod=NoCutoff)

                # Parameterize protein:ligand complex in solvent
                print(f' Parameterizing {system_name} : {molecule.to_smiles()} in explicit solvent...')
                from simtk.openmm.app import PME
                modeller.addSolvent(forcefield, padding=0*unit.angstroms, ionicStrength=300*unit.millimolar)
                forcefield.createSystem(modeller.topology, nonbondedMethod=PME)
Example #36
0
def generateResidueTemplate(molecule,
                            residue_atoms=None,
                            normalize=True,
                            gaff_version='gaff'):
    """
    Generate an residue template for simtk.openmm.app.ForceField using GAFF/AM1-BCC.

    This requires the OpenEye toolkit.

    Parameters
    ----------
    molecule : openeye.oechem.OEMol
        The molecule to be parameterized.
        The molecule must have explicit hydrogens.
        Net charge will be inferred from the net formal charge on each molecule.
        Partial charges will be determined automatically using oequacpac and canonical AM1-BCC charging rules.
    residue_atomset : set of OEAtom, optional, default=None
        If not None, only the atoms in this set will be used to construct the residue template
    normalize : bool, optional, default=True
        If True, normalize the molecule by checking aromaticity, adding
        explicit hydrogens, and renaming by IUPAC name.
    gaff_version : str, default = 'gaff'
        One of ['gaff', 'gaff2']; selects which atom types to use.
        

    Returns
    -------
    template : simtk.openmm.app.forcefield._TemplateData
        Residue template for ForceField using atom types and parameters from `gaff.xml` or `gaff2.xml`.
    additional_parameters_ffxml : str
        Contents of ForceField `ffxml` file defining additional parameters from parmchk(2).

    Notes
    -----
    The residue template will be named after the molecule title.
    This method preserves stereochemistry during AM1-BCC charge parameterization.
    Atom names in molecules will be assigned Tripos atom names if any are blank or not unique.

    """
    # Set the template name based on the molecule title plus a globally unique UUID.
    from uuid import uuid4
    template_name = molecule.GetTitle() + '-' + str(uuid4())

    # If any atom names are not unique, atom names
    _ensureUniqueAtomNames(molecule)

    # Compute net formal charge.
    net_charge = _computeNetCharge(molecule)

    # Generate canonical AM1-BCC charges and a reference conformation.
    molecule = get_charges(molecule,
                           strictStereo=False,
                           keep_confs=1,
                           normalize=normalize)

    # DEBUG: This may be necessary.
    molecule.SetTitle('MOL')

    # Create temporary directory for running antechamber.
    import tempfile
    tmpdir = tempfile.mkdtemp()
    prefix = 'molecule'
    input_mol2_filename = os.path.join(tmpdir, prefix + '.tripos.mol2')
    gaff_mol2_filename = os.path.join(tmpdir, prefix + '.gaff.mol2')
    frcmod_filename = os.path.join(tmpdir, prefix + '.frcmod')

    # Write Tripos mol2 file as antechamber input.
    _writeMolecule(molecule, input_mol2_filename, standardize=normalize)

    # Parameterize the molecule with antechamber.
    run_antechamber(template_name,
                    input_mol2_filename,
                    charge_method=None,
                    net_charge=net_charge,
                    gaff_mol2_filename=gaff_mol2_filename,
                    frcmod_filename=frcmod_filename,
                    gaff_version=gaff_version)

    # Read the resulting GAFF mol2 file as a ParmEd structure.
    from openeye import oechem
    ifs = oechem.oemolistream(gaff_mol2_filename)
    ifs.SetFlavor(
        oechem.OEFormat_MOL2, oechem.OEIFlavor_MOL2_DEFAULT
        | oechem.OEIFlavor_MOL2_M2H | oechem.OEIFlavor_MOL2_Forcefield)
    m2h = True
    oechem.OEReadMolecule(ifs, molecule)
    ifs.close()

    # If residue_atoms = None, add all atoms to the residues
    if residue_atoms == None:
        residue_atoms = [atom for atom in molecule.GetAtoms()]

    # Modify partial charges so that charge on residue atoms is integral.
    residue_charge = 0.0
    sum_of_absolute_charge = 0.0
    for atom in residue_atoms:
        charge = atom.GetPartialCharge()
        residue_charge += charge
        sum_of_absolute_charge += abs(charge)
    excess_charge = residue_charge - net_charge
    if sum_of_absolute_charge == 0.0:
        sum_of_absolute_charge = 1.0
    for atom in residue_atoms:
        charge = atom.GetPartialCharge()
        atom.SetPartialCharge(charge + excess_charge *
                              (abs(charge) / sum_of_absolute_charge))

    # Create residue template.
    template = ForceField._TemplateData(template_name)
    for (index, atom) in enumerate(molecule.GetAtoms()):
        atomname = atom.GetName()
        typename = atom.GetType()
        element = Element.getByAtomicNumber(atom.GetAtomicNum())
        charge = atom.GetPartialCharge()
        parameters = {'charge': charge}
        atom_template = ForceField._TemplateAtomData(atomname, typename,
                                                     element, parameters)
        template.atoms.append(atom_template)
    for bond in molecule.GetBonds():
        if (bond.GetBgn() in residue_atoms) and (bond.GetEnd()
                                                 in residue_atoms):
            template.addBondByName(bond.GetBgn().GetName(),
                                   bond.GetEnd().GetName())
        elif (bond.GetBgn() in residue_atoms) and (bond.GetEnd()
                                                   not in residue_atoms):
            template.addExternalBondByName(bond.GetBgn().GetName())
        elif (bond.GetBgn() not in residue_atoms) and (bond.GetEnd()
                                                       in residue_atoms):
            template.addExternalBondByName(bond.GetEnd().GetName())

    # Generate ffxml file contents for parmchk-generated frcmod output.
    leaprc = StringIO('parm = loadamberparams %s' % frcmod_filename)
    params = parmed.amber.AmberParameterSet.from_leaprc(leaprc)
    params = parmed.openmm.OpenMMParameterSet.from_parameterset(params)
    ffxml = StringIO()
    params.write(ffxml)

    return template, ffxml.getvalue()
    def test_cache(self):
        """Test template generator cache capability"""
        from simtk.openmm.app import ForceField, NoCutoff
        with tempfile.TemporaryDirectory() as tmpdirname:
            # Create a generator that also has a database cache
            cache = os.path.join(tmpdirname, 'db.json')
            generator = self.TEMPLATE_GENERATOR(molecules=self.molecules, cache=cache)
            # Create a ForceField
            forcefield = ForceField()
            # Register the template generator
            forcefield.registerTemplateGenerator(generator.generator)
            # Parameterize the molecules
            for molecule in self.molecules:
                openmm_topology = molecule.to_topology().to_openmm()
                forcefield.createSystem(openmm_topology, nonbondedMethod=NoCutoff)

            # Check database contents
            def check_cache(generator, n_expected):
                """
                Check database contains number of expected records

                Parameters
                ----------
                generator : SmallMoleculeTemplateGenerator
                    The generator whose cache should be examined
                n_expected : int
                    Number of expected records
                """
                from tinydb import TinyDB
                db = TinyDB(generator._cache)
                table = db.table(generator._database_table_name)
                db_entries = table.all()
                db.close()
                n_entries = len(db_entries)
                assert (n_entries == n_expected), \
                    "Expected {} entries but database has {}\n db contents: {}".format(n_expected, n_entries, db_entries)

            check_cache(generator, len(self.molecules))

            # Clean up, forcing closure of database
            del forcefield, generator

            # Create a generator that also uses the database cache but has no molecules
            print('Creating new generator with just cache...')
            generator = self.TEMPLATE_GENERATOR(cache=cache)
            # Check database still contains the molecules we expect
            check_cache(generator, len(self.molecules))
            # Create a ForceField
            forcefield = ForceField()
            # Register the template generator
            forcefield.registerTemplateGenerator(generator.generator)
            # Parameterize the molecules; this should succeed
            for molecule in self.molecules:
                openmm_topology = molecule.to_topology().to_openmm()
                forcefield.createSystem(openmm_topology, nonbondedMethod=NoCutoff)
def generateResidueTemplate(molecule, residue_atoms=None, normalize=True, gaff_version='gaff'):
    """
    Generate an residue template for simtk.openmm.app.ForceField using GAFF/AM1-BCC.

    This requires the OpenEye toolkit.

    Parameters
    ----------
    molecule : openeye.oechem.OEMol
        The molecule to be parameterized.
        The molecule must have explicit hydrogens.
        Net charge will be inferred from the net formal charge on each molecule.
        Partial charges will be determined automatically using oequacpac and canonical AM1-BCC charging rules.
    residue_atomset : set of OEAtom, optional, default=None
        If not None, only the atoms in this set will be used to construct the residue template
    normalize : bool, optional, default=True
        If True, normalize the molecule by checking aromaticity, adding
        explicit hydrogens, and renaming by IUPAC name.
    gaff_version : str, default = 'gaff'
        One of ['gaff', 'gaff2']; selects which atom types to use.


    Returns
    -------
    template : simtk.openmm.app.forcefield._TemplateData
        Residue template for ForceField using atom types and parameters from `gaff.xml` or `gaff2.xml`.
    additional_parameters_ffxml : str
        Contents of ForceField `ffxml` file defining additional parameters from parmchk(2).

    Notes
    -----
    The residue template will be named after the molecule title.
    This method preserves stereochemistry during AM1-BCC charge parameterization.
    Atom names in molecules will be assigned Tripos atom names if any are blank or not unique.

    """
    # Set the template name based on the molecule title plus a globally unique UUID.
    from uuid import uuid4
    template_name = molecule.GetTitle() + '-' + str(uuid4())

    # If any atom names are not unique, atom names
    _ensureUniqueAtomNames(molecule)

    # Compute net formal charge.
    net_charge = _computeNetCharge(molecule)

    # Generate canonical AM1-BCC charges and a reference conformation.
    molecule = get_charges(molecule, strictStereo=False, keep_confs=1, normalize=normalize)

    # DEBUG: This may be necessary.
    molecule.SetTitle('MOL')

    # Create temporary directory for running antechamber.
    import tempfile
    tmpdir = tempfile.mkdtemp()
    prefix = 'molecule'
    input_mol2_filename = os.path.join(tmpdir, prefix + '.tripos.mol2')
    gaff_mol2_filename = os.path.join(tmpdir, prefix + '.gaff.mol2')
    frcmod_filename = os.path.join(tmpdir, prefix + '.frcmod')

    # Write Tripos mol2 file as antechamber input.
    _writeMolecule(molecule, input_mol2_filename, standardize=normalize)

    # Parameterize the molecule with antechamber.
    run_antechamber(template_name, input_mol2_filename, charge_method=None, net_charge=net_charge, gaff_mol2_filename=gaff_mol2_filename, frcmod_filename=frcmod_filename, gaff_version=gaff_version)

    # Read the resulting GAFF mol2 file as a ParmEd structure.
    from openeye import oechem
    ifs = oechem.oemolistream(gaff_mol2_filename)
    ifs.SetFlavor(oechem.OEFormat_MOL2, oechem.OEIFlavor_MOL2_DEFAULT | oechem.OEIFlavor_MOL2_M2H | oechem.OEIFlavor_MOL2_Forcefield)
    m2h = True
    oechem.OEReadMolecule(ifs, molecule)
    ifs.close()

    # If residue_atoms = None, add all atoms to the residues
    if residue_atoms == None:
        residue_atoms = [ atom for atom in molecule.GetAtoms() ]

    # Modify partial charges so that charge on residue atoms is integral.
    residue_charge = 0.0
    sum_of_absolute_charge = 0.0
    for atom in residue_atoms:
        charge = atom.GetPartialCharge()
        residue_charge += charge
        sum_of_absolute_charge += abs(charge)
    excess_charge = residue_charge - net_charge
    if sum_of_absolute_charge == 0.0:
        sum_of_absolute_charge = 1.0
    for atom in residue_atoms:
        charge = atom.GetPartialCharge()
        atom.SetPartialCharge( charge + excess_charge * (abs(charge) / sum_of_absolute_charge) )

    # Create residue template.
    template = ForceField._TemplateData(template_name)
    for (index, atom) in enumerate(molecule.GetAtoms()):
        atomname = atom.GetName()
        typename = atom.GetType()
        element = Element.getByAtomicNumber(atom.GetAtomicNum())
        charge = atom.GetPartialCharge()
        parameters = { 'charge' : charge }
        atom_template = ForceField._TemplateAtomData(atomname, typename, element, parameters)
        template.atoms.append(atom_template)
    for bond in molecule.GetBonds():
        if (bond.GetBgn() in residue_atoms) and (bond.GetEnd() in residue_atoms):
            template.addBondByName(bond.GetBgn().GetName(), bond.GetEnd().GetName())
        elif (bond.GetBgn() in residue_atoms) and (bond.GetEnd() not in residue_atoms):
            template.addExternalBondByName(bond.GetBgn().GetName())
        elif (bond.GetBgn() not in residue_atoms) and (bond.GetEnd() in residue_atoms):
            template.addExternalBondByName(bond.GetEnd().GetName())

    # Generate ffxml file contents for parmchk-generated frcmod output.
    leaprc = StringIO('parm = loadamberparams %s' % frcmod_filename)
    params = parmed.amber.AmberParameterSet.from_leaprc(leaprc)
    params = parmed.openmm.OpenMMParameterSet.from_parameterset(params)
    ffxml = StringIO()
    params.write(ffxml)

    return template, ffxml.getvalue()
Example #39
0
def test_reporter(tmpdir, get_fn):
    pdb = PDBFile(get_fn('native.pdb'))
    forcefield = ForceField('amber99sbildn.xml', 'amber99_obc.xml')
    # NO PERIODIC BOUNDARY CONDITIONS
    system = forcefield.createSystem(pdb.topology, nonbondedMethod=CutoffNonPeriodic,
                                     nonbondedCutoff=1.0 * nanometers, constraints=HBonds, rigidWater=True)
    integrator = LangevinIntegrator(300 * kelvin, 1.0 / picoseconds, 2.0 * femtoseconds)
    integrator.setConstraintTolerance(0.00001)

    platform = Platform.getPlatformByName('Reference')
    simulation = Simulation(pdb.topology, system, integrator, platform)
    simulation.context.setPositions(pdb.positions)

    simulation.context.setVelocitiesToTemperature(300 * kelvin)

    tmpdir = str(tmpdir)
    hdf5file = os.path.join(tmpdir, 'traj.h5')
    ncfile = os.path.join(tmpdir, 'traj.nc')
    dcdfile = os.path.join(tmpdir, 'traj.dcd')
    xtcfile = os.path.join(tmpdir, 'traj.xtc')

    reporter = HDF5Reporter(hdf5file, 2, coordinates=True, time=True,
                            cell=True, potentialEnergy=True, kineticEnergy=True, temperature=True,
                            velocities=True)
    reporter2 = NetCDFReporter(ncfile, 2, coordinates=True, time=True, cell=True)
    reporter3 = DCDReporter(dcdfile, 2)
    reporter4 = XTCReporter(xtcfile, 2)

    simulation.reporters.append(reporter)
    simulation.reporters.append(reporter2)
    simulation.reporters.append(reporter3)
    simulation.reporters.append(reporter4)
    simulation.step(100)

    reporter.close()
    reporter2.close()
    reporter3.close()
    reporter4.close()

    with HDF5TrajectoryFile(hdf5file) as f:
        got = f.read()
        eq(got.temperature.shape, (50,))
        eq(got.potentialEnergy.shape, (50,))
        eq(got.kineticEnergy.shape, (50,))
        eq(got.coordinates.shape, (50, 22, 3))
        eq(got.velocities.shape, (50, 22, 3))
        eq(got.cell_lengths, None)
        eq(got.cell_angles, None)
        eq(got.time, 0.002 * 2 * (1 + np.arange(50)))
        assert f.topology == md.load(get_fn('native.pdb')).top

    with NetCDFTrajectoryFile(ncfile) as f:
        xyz, time, cell_lengths, cell_angles = f.read()
        eq(cell_lengths, None)
        eq(cell_angles, None)
        eq(time, 0.002 * 2 * (1 + np.arange(50)))

    hdf5_traj = md.load(hdf5file)
    dcd_traj = md.load(dcdfile, top=get_fn('native.pdb'))
    netcdf_traj = md.load(ncfile, top=get_fn('native.pdb'))
    xtc_traj = md.load(xtcfile, top=get_fn('native.pdb'))

    # we don't have to convert units here, because md.load already
    # handles that
    assert hdf5_traj.unitcell_vectors is None
    eq(hdf5_traj.xyz, netcdf_traj.xyz)
    eq(hdf5_traj.unitcell_vectors, netcdf_traj.unitcell_vectors)
    eq(hdf5_traj.time, netcdf_traj.time)
    eq(xtc_traj.time, netcdf_traj.time)

    eq(dcd_traj.xyz, hdf5_traj.xyz)
    eq(xtc_traj.xyz, dcd_traj.xyz, decimal=3)
Example #40
0
def test_reporter_subset(tmpdir, get_fn):
    pdb = PDBFile(get_fn('native2.pdb'))
    pdb.topology.setUnitCellDimensions([2, 2, 2])
    forcefield = ForceField('amber99sbildn.xml', 'amber99_obc.xml')
    system = forcefield.createSystem(pdb.topology, nonbondedMethod=CutoffPeriodic,
                                     nonbondedCutoff=1 * nanometers, constraints=HBonds, rigidWater=True)
    integrator = LangevinIntegrator(300 * kelvin, 1.0 / picoseconds, 2.0 * femtoseconds)
    integrator.setConstraintTolerance(0.00001)

    platform = Platform.getPlatformByName('Reference')
    simulation = Simulation(pdb.topology, system, integrator, platform)
    simulation.context.setPositions(pdb.positions)

    simulation.context.setVelocitiesToTemperature(300 * kelvin)

    tmpdir = str(tmpdir)
    hdf5file = os.path.join(tmpdir, 'traj.h5')
    ncfile = os.path.join(tmpdir, 'traj.nc')
    dcdfile = os.path.join(tmpdir, 'traj.dcd')
    xtcfile = os.path.join(tmpdir, 'traj.xtc')

    atomSubset = [0, 1, 2, 4, 5]

    reporter = HDF5Reporter(hdf5file, 2, coordinates=True, time=True,
                            cell=True, potentialEnergy=True, kineticEnergy=True, temperature=True,
                            velocities=True, atomSubset=atomSubset)
    reporter2 = NetCDFReporter(ncfile, 2, coordinates=True, time=True,
                               cell=True, atomSubset=atomSubset)
    reporter3 = DCDReporter(dcdfile, 2, atomSubset=atomSubset)
    reporter4 = XTCReporter(xtcfile, 2, atomSubset=atomSubset)

    simulation.reporters.append(reporter)
    simulation.reporters.append(reporter2)
    simulation.reporters.append(reporter3)
    simulation.reporters.append(reporter4)
    simulation.step(100)

    reporter.close()
    reporter2.close()
    reporter3.close()
    reporter4.close()

    t = md.load(get_fn('native.pdb'))
    t.restrict_atoms(atomSubset)

    with HDF5TrajectoryFile(hdf5file) as f:
        got = f.read()
        eq(got.temperature.shape, (50,))
        eq(got.potentialEnergy.shape, (50,))
        eq(got.kineticEnergy.shape, (50,))
        eq(got.coordinates.shape, (50, len(atomSubset), 3))
        eq(got.velocities.shape, (50, len(atomSubset), 3))
        eq(got.cell_lengths, 2 * np.ones((50, 3)))
        eq(got.cell_angles, 90 * np.ones((50, 3)))
        eq(got.time, 0.002 * 2 * (1 + np.arange(50)))
        assert f.topology == md.load(get_fn('native.pdb'), atom_indices=atomSubset).topology

    with NetCDFTrajectoryFile(ncfile) as f:
        xyz, time, cell_lengths, cell_angles = f.read()
        eq(cell_lengths, 20 * np.ones((50, 3)))
        eq(cell_angles, 90 * np.ones((50, 3)))
        eq(time, 0.002 * 2 * (1 + np.arange(50)))
        eq(xyz.shape, (50, len(atomSubset), 3))

    hdf5_traj = md.load(hdf5file)
    dcd_traj = md.load(dcdfile, top=hdf5_traj)
    netcdf_traj = md.load(ncfile, top=hdf5_traj)
    xtc_traj = md.load(xtcfile, top=hdf5_traj)

    # we don't have to convert units here, because md.load already handles that
    eq(hdf5_traj.xyz, netcdf_traj.xyz)
    eq(hdf5_traj.unitcell_vectors, netcdf_traj.unitcell_vectors)
    eq(hdf5_traj.time, netcdf_traj.time)
    eq(xtc_traj.time, netcdf_traj.time)

    eq(dcd_traj.xyz, hdf5_traj.xyz)
    eq(xtc_traj.xyz, hdf5_traj.xyz)
    eq(dcd_traj.unitcell_vectors, hdf5_traj.unitcell_vectors)
def test_generateResidueTemplate():
    """
    Test GAFF residue template generation from OEMol molecules.
    """
    from openeye import oechem, oeiupac

    from pkg_resources import resource_filename

    gaff_xml_filename = utils.get_data_filename("parameters/gaff.xml")

    # Test independent ForceField instances.
    for molecule_name in IUPAC_molecule_names:
        mol = createOEMolFromIUPAC(molecule_name)
        # Generate an ffxml residue template.
        from openmoltools.forcefield_generators import generateResidueTemplate

        [template, ffxml] = generateResidueTemplate(mol)
        # Create a ForceField object.
        forcefield = ForceField(gaff_xml_filename)
        # Add the additional parameters and template to the forcefield.
        forcefield.registerResidueTemplate(template)
        forcefield.loadFile(StringIO(ffxml))
        # Create a Topology from the molecule.
        from openmoltools.forcefield_generators import generateTopologyFromOEMol

        topology = generateTopologyFromOEMol(mol)
        # Parameterize system.
        system = forcefield.createSystem(topology, nonbondedMethod=NoCutoff)
        # Check potential is finite.
        positions = extractPositionsFromOEMOL(mol)
        check_potential_is_finite(system, positions)

    # Test adding multiple molecules to a single ForceField instance.
    forcefield = ForceField(gaff_xml_filename)
    for molecule_name in IUPAC_molecule_names:
        mol = createOEMolFromIUPAC(molecule_name)
        # Generate an ffxml residue template.
        from openmoltools.forcefield_generators import generateResidueTemplate

        [template, ffxml] = generateResidueTemplate(mol)
        # Add the additional parameters and template to the forcefield.
        forcefield.registerResidueTemplate(template)
        forcefield.loadFile(StringIO(ffxml))
        # Create a Topology from the molecule.
        from openmoltools.forcefield_generators import generateTopologyFromOEMol

        topology = generateTopologyFromOEMol(mol)
        # Parameterize system.
        system = forcefield.createSystem(topology, nonbondedMethod=NoCutoff)
        # Check potential is finite.
        positions = extractPositionsFromOEMOL(mol)
        check_potential_is_finite(system, positions)
def generateResidueTemplate(molecule, residue_atoms=None):
    """
    Generate an residue template for simtk.openmm.app.ForceField using GAFF/AM1-BCC.

    This requires the OpenEye toolkit.

    Parameters
    ----------
    molecule : openeye.oechem.OEMol
        The molecule to be parameterized.
        The molecule must have explicit hydrogens.
        Charge will be inferred from the net formal charge.
    residue_atomset : set of OEAtom, optional, default=None
        If not None, only the atoms in this set will be used to construct the residue template

    Returns
    -------
    template : simtk.openmm.app.forcefield._TemplateData
        Residue template for ForceField using atom types and parameters from `gaff.xml`.
    additional_parameters_ffxml : str
        Contents of ForceField `ffxml` file defining additional parameters from parmchk(2).

    Note that this method preserves stereochemistry during AM1-BCC charge parameterization.

    """
    # Generate a unique residue template name to avoid namespace collisions.
    # TODO: Can we come up with a more intelligent name?
    #from uuid import uuid4
    #template_name = str(uuid4())
    template_name = molecule.GetTitle()

    # Compute net formal charge.
    from openeye import oechem
    oechem.OEAssignFormalCharges(molecule)
    charges = [ atom.GetFormalCharge() for atom in molecule.GetAtoms() ]
    net_charge = np.array(charges).sum()

    # Generate canonical AM1-BCC charges and a reference conformation.
    molecule = get_charges(molecule, strictStereo=False, keep_confs=1)

    # Create temporary directory for running antechamber.
    import tempfile
    tmpdir = tempfile.mkdtemp()
    input_mol2_filename = os.path.join(tmpdir, template_name + '.tripos.mol2')
    gaff_mol2_filename = os.path.join(tmpdir, template_name + '.gaff.mol2')
    frcmod_filename = os.path.join(tmpdir, template_name + '.frcmod')

    # Write Tripos mol2 file as antechamber input.
    ofs = oechem.oemolostream(input_mol2_filename)
    oechem.OEWriteMolecule(ofs, molecule)
    ofs.close()

    # Parameterize the molecule with antechamber.
    run_antechamber(template_name, input_mol2_filename, charge_method=None, net_charge=net_charge, gaff_mol2_filename=gaff_mol2_filename, frcmod_filename=frcmod_filename)

    # Read the resulting GAFF mol2 file as a ParmEd structure.
    ifs = oechem.oemolistream(gaff_mol2_filename)
    ifs.SetFlavor(oechem.OEFormat_MOL2, oechem.OEIFlavor_MOL2_DEFAULT | oechem.OEIFlavor_MOL2_M2H | oechem.OEIFlavor_MOL2_Forcefield)
    m2h = True
    oechem.OEReadMolecule(ifs, molecule)
    ifs.close()

    # If residue_atoms = None, add all atoms to the residues
    if residue_atoms == None:
        residue_atoms = [ atom for atom in molecule.GetAtoms() ]

    # Modify partial charges so that charge on residue atoms is integral.
    residue_charge = 0.0
    sum_of_absolute_charge = 0.0
    for atom in residue_atoms:
        charge = atom.GetPartialCharge()
        residue_charge += charge
        sum_of_absolute_charge += abs(charge)
    excess_charge = residue_charge - net_charge
    if sum_of_absolute_charge == 0.0:
        sum_of_absolute_charge = 1.0
    for atom in residue_atoms:
        charge = atom.GetPartialCharge()
        atom.SetPartialCharge( charge + excess_charge * (abs(charge) / sum_of_absolute_charge) )

    # Create residue template.
    template = ForceField._TemplateData(template_name)
    for (index, atom) in enumerate(molecule.GetAtoms()):
        atomname = atom.GetName()
        typename = atom.GetType()
        element = Element.getByAtomicNumber(atom.GetAtomicNum())
        charge = atom.GetPartialCharge()
        parameters = { 'charge' : charge }
        atom_template = ForceField._TemplateAtomData(atomname, typename, element, parameters)
        template.atoms.append(atom_template)
    for bond in molecule.GetBonds():
        if (bond.GetBgn() in residue_atoms) and (bond.GetEnd() in residue_atoms):
            template.addBondByName(bond.GetBgn().GetName(), bond.GetEnd().GetName())
        elif (bond.GetBgn() in residue_atoms) and (bond.GetEnd() not in residue_atoms):
            template.addExternalBondByName(bond.GetBgn().GetName())
        elif (bond.GetBgn() not in residue_atoms) and (bond.GetEnd() in residue_atoms):
            template.addExternalBondByName(bond.GetEnd().GetName())

    # Generate ffxml file contents for parmchk-generated frcmod output.
    leaprc = StringIO("parm = loadamberparams %s" % frcmod_filename)
    params = parmed.amber.AmberParameterSet.from_leaprc(leaprc)
    params = parmed.openmm.OpenMMParameterSet.from_parameterset(params)
    ffxml = StringIO()
    params.write(ffxml)

    return template, ffxml.getvalue()
Example #43
0
class SystemGenerator(object):
    """
    Utility factory to generate OpenMM Systems from Topology objects.

    Parameters
    ----------
    forcefields_to_use : list of string
        List of the names of ffxml files that will be used in system creation.
    forcefield_kwargs : dict of arguments to createSystem, optional
        Allows specification of various aspects of system creation.
    use_gaff : bool, optional, default=True
        If True, will add the GAFF residue template generator.

    Examples
    --------
    >>> from simtk.openmm import app
    >>> forcefield_kwargs={ 'nonbondedMethod' : app.NoCutoff, 'implicitSolvent' : None, 'constraints' : None }
    >>> system_generator = SystemGenerator(['amber99sbildn.xml'], forcefield_kwargs=forcefield_kwargs)
    >>> from openmmtools.testsystems import AlanineDipeptideVacuum
    >>> testsystem = AlanineDipeptideVacuum()
    >>> system = system_generator.createSystem(testsystem.topology)
    """
    def __init__(self,
                 forcefields_to_use,
                 forcefield_kwargs=None,
                 use_gaff=True):
        self._forcefield_xmls = forcefields_to_use
        self._forcefield_kwargs = forcefield_kwargs if forcefield_kwargs is not None else {}
        from simtk.openmm.app import ForceField
        self._forcefield = ForceField(*self._forcefield_xmls)
        if use_gaff:
            self._forcefield.registerTemplateGenerator(gaffTemplateGenerator)

    def getForceField(self):
        """
        Return the associated ForceField object.

        Returns
        -------
        forcefield : simtk.openmm.app.ForceField
            The current ForceField object.
        """
        return self._forcefield

    def createSystem(self, topology):
        """
        Build a system from specified topology object.

        Parameters
        ----------
        topology : simtk.openmm.app.Topology object
            The topology of the system to construct.

        Returns
        -------
        system : openmm.System
            A system object generated from the topology
        """
        system = self._forcefield.createSystem(topology,
                                               **self._forcefield_kwargs)
        return system

    @property
    def ffxmls(self):
        return self._forcefield_xmls

    @property
    def forcefield(self):
        return self._forcefield
Example #44
0
    def addExtraParticles(self, forcefield):
        """Add missing extra particles to the model that are required by a force field.

        Some force fields use "extra particles" that do not represent actual atoms, but still need to be included in
        the System.  Examples include lone pairs, Drude particles, and the virtual sites used in some water models
        to adjust the charge distribution.  Extra particles can be recognized by the fact that their element is None.

        This method is primarily used to add extra particles, but it can also remove them.  It tries to match every
        residue in the Topology to a template in the force field.  If there is no match, it will both add and remove
        extra particles as necessary to make it match.

        Parameters:
         - forcefield (ForceField) the ForceField defining what extra particles should be present
        """
        # Create copies of all residue templates that have had all extra points removed.

        templatesNoEP = {}
        for resName, template in forcefield._templates.iteritems():
            if any(atom.element is None for atom in template.atoms):
                index = 0
                newIndex = {}
                newTemplate = ForceField._TemplateData(resName)
                for i, atom in enumerate(template.atoms):
                    if atom.element is not None:
                        newIndex[i] = index
                        index += 1
                        newTemplate.atoms.append(ForceField._TemplateAtomData(atom.name, atom.type, atom.element))
                for b1, b2 in template.bonds:
                    if b1 in newIndex and b2 in newIndex:
                        newTemplate.bonds.append((newIndex[b1], newIndex[b2]))
                        newTemplate.atoms[newIndex[b1]].bondedTo.append(newIndex[b2])
                        newTemplate.atoms[newIndex[b2]].bondedTo.append(newIndex[b1])
                for b in template.externalBonds:
                    if b in newIndex:
                        newTemplate.externalBonds.append(newIndex[b])
                templatesNoEP[template] = newTemplate

        # Record which atoms are bonded to each other atom, with and without extra particles.

        bondedToAtom = []
        bondedToAtomNoEP = []
        for atom in self.topology.atoms():
            bondedToAtom.append(set())
            bondedToAtomNoEP.append(set())
        for atom1, atom2 in self.topology.bonds():
            bondedToAtom[atom1.index].add(atom2.index)
            bondedToAtom[atom2.index].add(atom1.index)
            if atom1.element is not None and atom2.element is not None:
                bondedToAtomNoEP[atom1.index].add(atom2.index)
                bondedToAtomNoEP[atom2.index].add(atom1.index)

        # If the force field has a DrudeForce, record the types of Drude particles and their parents since we'll
        # need them for picking particle positions.

        drudeTypeMap = {}
        for force in forcefield._forces:
            if isinstance(force, DrudeGenerator):
                for type in force.typeMap:
                    drudeTypeMap[type] = force.typeMap[type][0]

        # Create the new Topology.

        newTopology = Topology()
        newTopology.setUnitCellDimensions(deepcopy(self.topology.getUnitCellDimensions()))
        newAtoms = {}
        newPositions = []*nanometer
        for chain in self.topology.chains():
            newChain = newTopology.addChain()
            for residue in chain.residues():
                newResidue = newTopology.addResidue(residue.name, newChain)

                # Look for a matching template.

                matchFound = False
                signature = _createResidueSignature([atom.element for atom in residue.atoms()])
                if signature in forcefield._templateSignatures:
                    for t in forcefield._templateSignatures[signature]:
                        if _matchResidue(residue, t, bondedToAtom) is not None:
                            matchFound = True
                if matchFound:
                    # Just copy the residue over.

                    for atom in residue.atoms():
                        newAtom = newTopology.addAtom(atom.name, atom.element, newResidue)
                        newAtoms[atom] = newAtom
                        newPositions.append(deepcopy(self.positions[atom.index]))
                else:
                    # There's no matching template.  Try to find one that matches based on everything except
                    # extra points.

                    template = None
                    residueNoEP = Residue(residue.name, residue.index, residue.chain)
                    residueNoEP._atoms = [atom for atom in residue.atoms() if atom.element is not None]
                    if signature in forcefield._templateSignatures:
                        for t in forcefield._templateSignatures[signature]:
                            if t in templatesNoEP:
                                matches = _matchResidue(residueNoEP, templatesNoEP[t], bondedToAtomNoEP)
                                if matches is not None:
                                    template = t;
                                    # Record the corresponding atoms.
                                    matchingAtoms = {}
                                    for atom, match in zip(residueNoEP.atoms(), matches):
                                        templateAtomName = t.atoms[match].name
                                        for templateAtom in template.atoms:
                                            if templateAtom.name == templateAtomName:
                                                matchingAtoms[templateAtom] = atom
                                    break
                    if template is None:
                        raise ValueError('Residue %d (%s) does not match any template defined by the ForceField.' % (residue.index+1, residue.name))

                    # Add the regular atoms.

                    for atom in residue.atoms():
                        if atom.element is not None:
                            newAtoms[atom] = newTopology.addAtom(atom.name, atom.element, newResidue)
                            newPositions.append(deepcopy(self.positions[atom.index]))

                    # Add the extra points.

                    templateAtomPositions = len(template.atoms)*[None]
                    for index, atom in enumerate(template.atoms):
                        if atom in matchingAtoms:
                            templateAtomPositions[index] = self.positions[matchingAtoms[atom].index].value_in_unit(nanometer)
                    for index, atom in enumerate(template.atoms):
                        if atom.element is None:
                            newTopology.addAtom(atom.name, None, newResidue)
                            position = None
                            for site in template.virtualSites:
                                if site.index == index:
                                    # This is a virtual site.  Compute its position by the correct rule.

                                    if site.type == 'average2':
                                        position = site.weights[0]*templateAtomPositions[index+site.atoms[0]] + site.weights[1]*templateAtomPositions[index+site.atoms[1]]
                                    elif site.type == 'average3':
                                        position = site.weights[0]*templateAtomPositions[index+site.atoms[0]] + site.weights[1]*templateAtomPositions[index+site.atoms[1]] + site.weights[2]*templateAtomPositions[index+site.atoms[2]]
                                    elif site.type == 'outOfPlane':
                                        v1 = templateAtomPositions[index+site.atoms[1]] - templateAtomPositions[index+site.atoms[0]]
                                        v2 = templateAtomPositions[index+site.atoms[2]] - templateAtomPositions[index+site.atoms[0]]
                                        cross = Vec3(v1[1]*v2[2]-v1[2]*v2[1], v1[2]*v2[0]-v1[0]*v2[2], v1[0]*v2[1]-v1[1]*v2[0])
                                        position = templateAtomPositions[index+site.atoms[0]] + site.weights[0]*v1 + site.weights[1]*v2 + site.weights[2]*cross
                            if position is None and atom.type in drudeTypeMap:
                                # This is a Drude particle.  Put it on top of its parent atom.

                                for atom2, pos in zip(template.atoms, templateAtomPositions):
                                    if atom2.type in drudeTypeMap[atom.type]:
                                        position = deepcopy(pos)
                            if position is None:
                                # We couldn't figure out the correct position.  As a wild guess, just put it at the center of the residue
                                # and hope that energy minimization will fix it.

                                knownPositions = [x for x in templateAtomPositions if x is not None]
                                position = sum(knownPositions)/len(knownPositions)
                            newPositions.append(position*nanometer)
        for bond in self.topology.bonds():
            if bond[0] in newAtoms and bond[1] in newAtoms:
                newTopology.addBond(newAtoms[bond[0]], newAtoms[bond[1]])
        self.topology = newTopology
        self.positions = newPositions