示例#1
0
    def test_create_with_template_generator(self):
        """Test SystemGenerator creation with small molecule residue template generators"""
        SMALL_MOLECULE_FORCEFIELDS = SystemGenerator.SMALL_MOLECULE_FORCEFIELDS if not CI else [
            'gaff-2.11', 'openff-1.1.0'
        ]
        for small_molecule_forcefield in SMALL_MOLECULE_FORCEFIELDS:
            # Create a generator that defines AMBER and small molecule force fields
            generator = SystemGenerator(
                forcefields=self.amber_forcefields,
                small_molecule_forcefield=small_molecule_forcefield)

            # Create a generator that also has a database cache
            with tempfile.TemporaryDirectory() as tmpdirname:
                cache = os.path.join(tmpdirname, 'db.json')
                # Create a new database file
                generator = SystemGenerator(
                    forcefields=self.amber_forcefields,
                    cache=cache,
                    small_molecule_forcefield=small_molecule_forcefield)
                del generator
                # Reopen it (with cache still empty)
                generator = SystemGenerator(
                    forcefields=self.amber_forcefields,
                    cache=cache,
                    small_molecule_forcefield=small_molecule_forcefield)
                del generator
示例#2
0
def generate_parameters(molecule,
                        basepath='json-files',
                        small_molecule_forcefield='openff-1.1.0'):
    """
    Generate JSON parameter cache for a molecule in f'{basepath}/{molecule.name}.json'

    Parameters
    ----------
    molecule : openforcefield.topology.Molecule
        The molecule to parameterize

    """
    # Create generator
    import os
    cache_filename = f'parallel/{molecule.name}.json'
    if os.path.exists:
        return

    # Generate and cache parameters
    from openmmforcefields.generators import SystemGenerator
    system_generator = SystemGenerator(
        small_molecule_forcefield=small_molecule_forcefield,
        molecules=[molecule],
        cache=cache_filename)
    try:
        system_generator.create_system(molecule.to_topology().to_openmm())
    except Exception as e:
        print(f'FAILED: {molecule.smiles}')
        print(e)

    del system_generator
    def test_parameterize_molecules_from_creation(self):
        """Test that SystemGenerator can parameterize pre-specified molecules in vacuum"""
        from openmmforcefields.generators import SystemGenerator

        for name, testsystem in self.testsystems.items():
            print(testsystem)
            molecules = testsystem['molecules']

            for small_molecule_forcefield in SystemGenerator.SMALL_MOLECULE_FORCEFIELDS:
                # Create a SystemGenerator for this force field
                generator = SystemGenerator(forcefields=self.amber_forcefields,
                                                small_molecule_forcefield=small_molecule_forcefield,
                                                molecules=molecules)

                # Parameterize molecules
                from openmmforcefields.utils import Timer
                for molecule in molecules:
                    openmm_topology = molecule.to_topology().to_openmm()
                    with Timer() as t1:
                        system = generator.create_system(openmm_topology)
                    assert system.getNumParticles() == molecule.n_atoms
                    # Molecule should now be cached
                    with Timer() as t2:
                        system = generator.create_system(openmm_topology)
                    assert system.getNumParticles() == molecule.n_atoms
                    assert (t2.interval() < t1.interval())
示例#4
0
    def omm_system(input_sdf,
                   input_system,
                   forcefield,
                   input_path,
                   ff_files=[],
                   template_ff='gaff-2.11'):
        

        
        from openmmforcefields.generators import SystemGenerator, GAFFTemplateGenerator
        from openff.toolkit.topology import Molecule
        
        
        # maybe possible to add same parameters that u give forcefield.createSystem() function
        forcefield_kwargs ={'constraints' : app.HBonds,
                            'rigidWater' : True,
                            'removeCMMotion' : False,
                            'hydrogenMass' : 4*amu }
		
        system_generator = SystemGenerator(forcefields=ff_files, 
                                           small_molecule_forcefield=template_ff,
                                           forcefield_kwargs=forcefield_kwargs, 
                                           cache='db.json')
        

        input_sdfs=[]
        for idx, sdf in enumerate(input_sdf, 1):
        
            
            path_sdf=f'{input_path}/{sdf}'

            if not os.path.exists(path_sdf):
                
                print(f'\tFile {path_sdf} not found!')
            else:
                print(f'\tAdding extra SDF file {idx} to pre-system: {path_sdf}')
                input_sdfs.append(path_sdf)
                       

        molecules = Molecule.from_file(*input_sdfs, file_format='sdf')
        
        print(molecules)
        
        system = system_generator.create_system(topology=input_system.topology)#, molecules=molecules)
        
        
        gaff = GAFFTemplateGenerator(molecules=molecules, forcefield=template_ff)
        gaff.add_molecules(molecules)
        print(gaff)
        forcefield.registerTemplateGenerator(gaff.generator)
        
        #forcefield.registerResidueTemplate(template)
        
        print(system)
        print(forcefield)
        
        
        return system, forcefield
    def test_barostat(self):
        """Test that barostat addition works correctly"""
        # Create a protein SystemGenerator
        generator = SystemGenerator(forcefields=self.amber_forcefields)

        # Create a template barostat
        from simtk.openmm import MonteCarloBarostat
        from simtk import unit
        pressure = 0.95 * unit.atmospheres
        temperature = 301.0 * unit.kelvin
        frequency = 23
        generator.barostat = MonteCarloBarostat(pressure, temperature,
                                                frequency)

        # Load a PDB file
        import os
        from simtk.openmm.app import PDBFile
        pdb_filename = get_data_filename(
            os.path.join('perses_jacs_systems', 'bace',
                         'Bace_protein_fixed.pdb'))
        pdbfile = PDBFile(pdb_filename)

        # 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(pdbfile.topology, pdbfile.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()

        # Create a System
        system = generator.create_system(modeller.topology)

        # Check barostat is present
        forces = {
            force.__class__.__name__: force
            for force in system.getForces()
        }
        assert 'MonteCarloBarostat' in forces.keys()

        # Check barostat parameters
        force = forces['MonteCarloBarostat']
        assert force.getDefaultPressure() == pressure
        assert force.getDefaultTemperature() == temperature
        assert force.getFrequency() == frequency
    def test_forcefield_kwargs(self):
        """Test that forcefield_kwargs and nonbonded method specifications work correctly"""
        from simtk import unit
        forcefield_kwargs = {'hydrogenMass': 4 * unit.amu}
        from openmmforcefields.generators import SystemGenerator

        for name, testsystem in self.testsystems.items():
            print(testsystem)
            molecules = testsystem['molecules']

            for small_molecule_forcefield in SystemGenerator.SMALL_MOLECULE_FORCEFIELDS:
                # Create a SystemGenerator for this force field
                from simtk import openmm
                from simtk.openmm import app
                generator = SystemGenerator(
                    forcefields=self.amber_forcefields,
                    small_molecule_forcefield=small_molecule_forcefield,
                    forcefield_kwargs=forcefield_kwargs,
                    periodic_forcefield_kwargs={'nonbondedMethod': app.LJPME},
                    nonperiodic_forcefield_kwargs={
                        'nonbondedMethod': app.CutoffNonPeriodic
                    },
                    molecules=molecules)

                # Parameterize molecules
                for molecule in molecules:
                    # Create non-periodic Topology
                    nonperiodic_openmm_topology = molecule.to_topology(
                    ).to_openmm()
                    system = generator.create_system(
                        nonperiodic_openmm_topology)
                    forces = {
                        force.__class__.__name__: force
                        for force in system.getForces()
                    }
                    assert forces['NonbondedForce'].getNonbondedMethod(
                    ) == openmm.NonbondedForce.CutoffNonPeriodic, "Expected CutoffNonPeriodic, got {forces['NonbondedForce'].getNonbondedMethod()}"

                    # Create periodic Topology
                    import numpy as np
                    import copy
                    box_vectors = unit.Quantity(np.diag([30, 30, 30]),
                                                unit.angstrom)
                    periodic_openmm_topology = copy.deepcopy(
                        nonperiodic_openmm_topology)
                    periodic_openmm_topology.setPeriodicBoxVectors(box_vectors)
                    system = generator.create_system(periodic_openmm_topology)
                    forces = {
                        force.__class__.__name__: force
                        for force in system.getForces()
                    }
                    assert forces['NonbondedForce'].getNonbondedMethod(
                    ) == openmm.NonbondedForce.LJPME, "Expected LJPME, got {forces['NonbondedForce'].getNonbondedMethod()}"
示例#7
0
    def test_cache(self):
        """Test that SystemGenerator correctly manages a cache"""
        from openmmforcefields.generators import SystemGenerator
        from openmmforcefields.utils import Timer

        timing = dict(
        )  # timing[(small_molecule_forcefield, smiles)] is the time (in seconds) to parameterize molecule the first time
        with tempfile.TemporaryDirectory() as tmpdirname:
            # Create a single shared cache for all force fields
            cache = os.path.join(tmpdirname, 'db.json')
            # Test that we can parameterize all molecules for all test systems
            SMALL_MOLECULE_FORCEFIELDS = SystemGenerator.SMALL_MOLECULE_FORCEFIELDS if not CI else [
                'gaff-2.11', 'openff-1.1.0'
            ]
            for small_molecule_forcefield in SMALL_MOLECULE_FORCEFIELDS:
                # Create a SystemGenerator
                generator = SystemGenerator(
                    forcefields=self.amber_forcefields,
                    small_molecule_forcefield=small_molecule_forcefield,
                    cache=cache)
                # Add molecules for each test system separately
                for name, testsystem in self.testsystems.items():
                    molecules = testsystem['molecules']
                    # Add molecules
                    generator.add_molecules(molecules)

                    # Parameterize molecules
                    for molecule in molecules:
                        openmm_topology = molecule.to_topology().to_openmm()
                        with Timer() as timer:
                            system = generator.create_system(openmm_topology)
                        assert system.getNumParticles() == molecule.n_atoms
                        # Record time
                        timing[(small_molecule_forcefield,
                                molecule.to_smiles())] = timer.interval()

            # Molecules should now be cached; test timing is faster the second time
            # Test that we can parameterize all molecules for all test systems
            SMALL_MOLECULE_FORCEFIELDS = SystemGenerator.SMALL_MOLECULE_FORCEFIELDS if not CI else [
                'gaff-2.11', 'openff-1.1.0'
            ]
            for small_molecule_forcefield in SMALL_MOLECULE_FORCEFIELDS:
                # Create a SystemGenerator
                generator = SystemGenerator(
                    forcefields=self.amber_forcefields,
                    small_molecule_forcefield=small_molecule_forcefield,
                    cache=cache)
                # Add molecules for each test system separately
                for name, testsystem in self.testsystems.items():
                    molecules = testsystem['molecules']
                    # We don't need to add molecules that are already defined in the cache

                    # Parameterize molecules
                    for molecule in molecules:
                        openmm_topology = molecule.to_topology().to_openmm()
                        with Timer() as timer:
                            system = generator.create_system(openmm_topology)
                        assert system.getNumParticles() == molecule.n_atoms
示例#8
0
def test_small_molecule_proposals():
    """
    Make sure the small molecule proposal engine generates molecules
    """
    list_of_smiles = ['CCCC','CCCCC','CCCCCC']
    list_of_mols = []
    for smi in list_of_smiles:
        mol = smiles_to_oemol(smi)
        list_of_mols.append(mol)
    molecules = [Molecule.from_openeye(mol) for mol in list_of_mols]
    stats_dict = defaultdict(lambda: 0)
    system_generator = SystemGenerator(forcefields = forcefield_files, barostat=barostat, forcefield_kwargs=forcefield_kwargs, nonperiodic_forcefield_kwargs=nonperiodic_forcefield_kwargs,
                                         small_molecule_forcefield = small_molecule_forcefield, molecules=molecules, cache=None)
    proposal_engine = topology_proposal.SmallMoleculeSetProposalEngine(list_of_mols, system_generator)
    initial_system, initial_positions, initial_topology,  = OEMol_to_omm_ff(list_of_mols[0], system_generator)

    proposal = proposal_engine.propose(initial_system, initial_topology)

    for i in range(50):
        #positions are ignored here, and we don't want to run the geometry engine
        new_proposal = proposal_engine.propose(proposal.old_system, proposal.old_topology)
        stats_dict[new_proposal.new_chemical_state_key] += 1
        #check that the molecule it generated is actually the smiles we expect
        matching_molecules = [res for res in proposal.new_topology.residues() if res.name=='MOL']
        if len(matching_molecules) != 1:
            raise ValueError("More than one residue with the same name!")
        mol_res = matching_molecules[0]
        oemol = generateOEMolFromTopologyResidue(mol_res)
        smiles = SmallMoleculeSetProposalEngine.canonicalize_smiles(oechem.OEMolToSmiles(oemol))
        assert smiles == proposal.new_chemical_state_key
        proposal = new_proposal
示例#9
0
def test_mapping_strength_levels(pairs_of_smiles=[('Cc1ccccc1','c1ccc(cc1)N'),('CC(c1ccccc1)','O=C(c1ccccc1)'),('Oc1ccccc1','Sc1ccccc1')],test=True):

    correct_results = {0:{'default': (3,2), 'weak':(3,2), 'strong':(4,3)},
                       1:{'default': (7,3), 'weak':(6,2), 'strong':(7,3)},
                       2:{'default': (1,1), 'weak':(1,1), 'strong':(2,2)}}

    mapping = ['weak','default','strong']

    for example in mapping:
        for index, (lig_a, lig_b) in enumerate(pairs_of_smiles):
            print(f"conducting {example} mapping with ligands {lig_a}, {lig_b}")
            initial_molecule = smiles_to_oemol(lig_a)
            proposed_molecule = smiles_to_oemol(lig_b)
            molecules = [Molecule.from_openeye(mol) for mol in [initial_molecule, proposed_molecule]]
            system_generator = SystemGenerator(forcefields = forcefield_files, barostat=barostat, forcefield_kwargs=forcefield_kwargs,nonperiodic_forcefield_kwargs=nonperiodic_forcefield_kwargs,
                                                 small_molecule_forcefield = 'gaff-1.81', molecules=molecules, cache=None)
            proposal_engine = SmallMoleculeSetProposalEngine([initial_molecule, proposed_molecule], system_generator)
            initial_system, initial_positions, initial_topology = OEMol_to_omm_ff(initial_molecule, system_generator)
            print(f"running now with map strength {example}")
            proposal = proposal_engine.propose(initial_system, initial_topology, map_strength = example)
            print(lig_a, lig_b,'length OLD and NEW atoms',len(proposal.unique_old_atoms), len(proposal.unique_new_atoms))
            if test:
                render_atom_mapping(f'{index}-{example}.png', initial_molecule, proposed_molecule, proposal._new_to_old_atom_map)
                assert ( (len(proposal.unique_old_atoms), len(proposal.unique_new_atoms)) == correct_results[index][example]), f"the mapping failed, correct results are {correct_results[index][example]}"
                print(f"the mapping worked!!!")
            print()
示例#10
0
文件: openeye.py 项目: LaYeqa/perses
def system_generator_wrapper(oemols,
                            barostat = None,
                            forcefield_files = ['amber14/protein.ff14SB.xml', 'amber14/tip3p.xml'],
                            forcefield_kwargs = {'removeCMMotion': False, 'ewaldErrorTolerance': 1e-4, 'constraints' : app.HBonds, 'hydrogenMass' : 4 * unit.amus},
                            nonperiodic_forcefield_kwargs = {'nonbondedMethod': app.NoCutoff},
                            small_molecule_forcefield = 'gaff-2.11',
                            **kwargs
                            ):
    """
    make a system generator (vacuum) for a small molecule

    Parameters
    ----------
    oemols : list of openeye.oechem.OEMol
        oemols
    barostat : openmm.MonteCarloBarostat, default None
        barostat
    forcefield_files : list of str
        pointers to protein forcefields and solvent
    forcefield_kwargs : dict
        dict of forcefield_kwargs
    nonperiodic_forcefield_kwargs : dict
        dict of args for non-periodic system
    small_molecule_forcefield : str
        pointer to small molecule forcefield to use

    Returns
    -------
    system_generator : openmmforcefields.generators.SystemGenerator
    """
    from openff.toolkit.topology import Molecule
    from openmmforcefields.generators import SystemGenerator
    system_generator = SystemGenerator(forcefields = forcefield_files, barostat=barostat, forcefield_kwargs=forcefield_kwargs,nonperiodic_forcefield_kwargs=nonperiodic_forcefield_kwargs,
                                         small_molecule_forcefield = small_molecule_forcefield, molecules=[Molecule.from_openeye(oemol) for oemol in oemols], cache=None)
    return system_generator
    def test_complex(self):
        """Test parameterizing a protein:ligand complex in vacuum"""
        from openmmforcefields.generators import SystemGenerator
        for name, testsystem in self.testsystems.items():
            print(f'Testing parameterization of {name} in vacuum')
            molecules = testsystem['molecules']
            # Select a complex from the set
            ligand_index = 0
            complex_structure = testsystem['complex_structures'][ligand_index]
            molecule = molecules[ligand_index]
            openmm_topology = complex_structure.topology

            cache = os.path.join(
                get_data_filename(os.path.join('perses_jacs_systems', name)),
                'cache.json')

            # Create a system in vacuum
            from simtk.openmm.app import NoCutoff
            forcefield_kwargs = {'nonbondedMethod': NoCutoff}
            generator = SystemGenerator(forcefields=self.amber_forcefields,
                                        forcefield_kwargs=forcefield_kwargs,
                                        molecules=molecules,
                                        cache=cache)
            system = generator.create_system(openmm_topology)
            assert system.getNumParticles() == len(complex_structure.atoms)

            # Update SystemGenerator to build periodic systems
            from simtk.openmm.app import PME
            generator.forcefield_kwargs = {'nonbondedMethod': PME}

            # Create solvated structure
            from simtk.openmm import app
            from simtk import unit
            modeller = app.Modeller(complex_structure.topology,
                                    complex_structure.positions)
            modeller.addSolvent(generator.forcefield,
                                padding=0 * unit.angstroms,
                                ionicStrength=300 * unit.millimolar)

            # Create a system with solvent and ions
            system = generator.create_system(modeller.topology)
            assert system.getNumParticles() == len(
                list(modeller.topology.atoms()))

            with open('test.pdb', 'w') as outfile:
                app.PDBFile.writeFile(modeller.topology, modeller.positions,
                                      outfile)
示例#12
0
    def baseline_energy(self, g, suffix=None):
        if suffix is None:
            suffix = "_" + self.forcefield

        from openmmforcefields.generators import SystemGenerator

        # define a system generator
        system_generator = SystemGenerator(
            small_molecule_forcefield=self.forcefield, )

        mol = g.mol
        # mol.assign_partial_charges("formal_charge")
        # create system
        system = system_generator.create_system(
            topology=mol.to_topology().to_openmm(),
            molecules=mol,
        )

        # parameterize topology
        topology = g.mol.to_topology().to_openmm()

        integrator = openmm.LangevinIntegrator(TEMPERATURE, COLLISION_RATE,
                                               STEP_SIZE)

        # create simulation
        simulation = Simulation(topology=topology,
                                system=system,
                                integrator=integrator)

        us = []

        xs = (Quantity(
            g.nodes["n1"].data["xyz"].detach().numpy(),
            esp.units.DISTANCE_UNIT,
        ).value_in_unit(unit.nanometer).transpose((1, 0, 2)))

        for x in xs:
            simulation.context.setPositions(x)
            us.append(
                simulation.context.getState(
                    getEnergy=True).getPotentialEnergy().value_in_unit(
                        esp.units.ENERGY_UNIT))

        g.nodes["g"].data["u%s" % suffix] = torch.tensor(us)[None, :]

        return g
    def test_parameterize_molecules_specified_during_create_system(self):
        """Test that SystemGenerator can parameterize molecules specified during create_system"""
        from openmmforcefields.generators import SystemGenerator

        for name, testsystem in self.testsystems.items():
            molecules = testsystem['molecules']

            for small_molecule_forcefield in SystemGenerator.SMALL_MOLECULE_FORCEFIELDS:
                # Create a SystemGenerator for this force field
                generator = SystemGenerator(forcefields=self.amber_forcefields,
                                                small_molecule_forcefield=small_molecule_forcefield)

                # Parameterize molecules
                from openmmforcefields.utils import Timer
                for molecule in molecules:
                    openmm_topology = molecule.to_topology().to_openmm()
                    # Specify molecules during system creation
                    system = generator.create_system(openmm_topology, molecules=molecules)
示例#14
0
def create_simple_protein_system_generator():
    from openmmforcefields.generators import SystemGenerator
    barostat = None
    forcefield_files = ['amber14/protein.ff14SB.xml', 'amber14/tip3p.xml']
    forcefield_kwargs = {'removeCMMotion': False, 'ewaldErrorTolerance': 1e-4, 'constraints' : app.HBonds, 'hydrogenMass' : 4 * unit.amus}
    nonperiodic_forcefield_kwargs={'nonbondedMethod': app.NoCutoff}

    system_generator = SystemGenerator(forcefields = forcefield_files, barostat=barostat, forcefield_kwargs=forcefield_kwargs, nonperiodic_forcefield_kwargs=nonperiodic_forcefield_kwargs,
                                         small_molecule_forcefield = 'gaff-2.11', molecules=None, cache=None)
    return system_generator
示例#15
0
文件: md.py 项目: choderalab/espaloma
    def simulation_from_graph(self, g):
        """ Create simulation from moleucle """
        # assign partial charge
        if self.charge_method is not None:
            g.mol.assign_partial_charges(self.charge_method)

        # parameterize topology
        topology = g.mol.to_topology().to_openmm()

        generator = SystemGenerator(
            small_molecule_forcefield=self.forcefield,
            molecules=[g.mol],
        )

        # create openmm system
        system = generator.create_system(topology, )

        # set epsilon minimum to 0.05 kJ/mol
        for force in system.getForces():
            if "Nonbonded" in force.__class__.__name__:
                force.setNonbondedMethod(openmm.NonbondedForce.NoCutoff)
                for particle_index in range(force.getNumParticles()):
                    charge, sigma, epsilon = force.getParticleParameters(
                        particle_index)
                    if epsilon < EPSILON_MIN:
                        force.setParticleParameters(particle_index, charge,
                                                    sigma, EPSILON_MIN)

        # use langevin integrator
        integrator = openmm.LangevinIntegrator(self.temperature,
                                               self.collision_rate,
                                               self.step_size)

        # initialize simulation
        simulation = Simulation(
            topology=topology,
            system=system,
            integrator=integrator,
            platform=openmm.Platform.getPlatformByName("Reference"),
        )

        return simulation
示例#16
0
def hmr_driver(mol, ff_name):
    """Given an OpenFF Molecule, run a short 4 fs HMR simulation. This function is adapted from
    https://github.com/openforcefield/openforcefields/issues/19#issuecomment-689816995"""
    print(
        f"Running HMR with force field {ff_name} and molecule with SMILES {mol.to_smiles()}"
    )

    forcefield_kwargs = {
        "constraints": app.HBonds,
        "rigidWater": True,
        "removeCMMotion": False,
        "hydrogenMass":
        4 * unit.amu,  # Does this also _subtract_ mass from heavy atoms?:w
    }

    system_generator = SystemGenerator(
        small_molecule_forcefield=ff_name,
        forcefield_kwargs=forcefield_kwargs,
        molecules=mol,
    )
    system = system_generator.create_system(mol.to_topology().to_openmm())

    temperature = 300 * unit.kelvin
    collision_rate = 1.0 / unit.picoseconds
    timestep = 4.0 * unit.femtoseconds

    integrator = openmm.LangevinIntegrator(temperature, collision_rate,
                                           timestep)
    context = openmm.Context(system, integrator)
    mol.generate_conformers(n_conformers=1)
    context.setPositions(mol.conformers[0])

    # Run for 10 ps
    integrator.step(2500)

    state = context.getState(getEnergy=True)
    pot = state.getPotentialEnergy()
    # OpenMM will silenty "fail" if energies aren't explicitly checked
    if np.isnan(pot / pot.unit):
        raise NANEnergyError()
    def test_add_molecules(self):
        """Test that Molecules can be added to SystemGenerator later"""
        from openmmforcefields.generators import SystemGenerator

        for small_molecule_forcefield in SystemGenerator.SMALL_MOLECULE_FORCEFIELDS:
            # Create a SystemGenerator for this force field
            generator = SystemGenerator(forcefields=self.amber_forcefields,
                                            small_molecule_forcefield=small_molecule_forcefield)

            # Add molecules for each test system separately
            for name, testsystem in self.testsystems.items():
                molecules = testsystem['molecules']
                # Add molecules
                generator.add_molecules(molecules)

                # Parameterize molecules
                from openmmforcefields.utils import Timer
                for molecule in molecules:
                    openmm_topology = molecule.to_topology().to_openmm()
                    with Timer() as t1:
                        system = generator.create_system(openmm_topology)
                    assert system.getNumParticles() == molecule.n_atoms
                    # Molecule should now be cached
                    with Timer() as t2:
                        system = generator.create_system(openmm_topology)
                    assert system.getNumParticles() == molecule.n_atoms
                    assert (t2.interval() < t1.interval())
示例#18
0
def test_OEMol_to_omm_ff(molecule=smiles_to_oemol('CC')):
    """
    Generating openmm objects for simulation from an OEMol object

    Parameters
    ----------
    molecule : openeye.oechem.OEMol

    Returns
    -------
    system : openmm.System
        openmm system object
    positions : unit.quantity
        positions of the system
    topology : app.topology.Topology
        openmm compatible topology object
    """
    import simtk.openmm.app as app
    import simtk.unit as unit
    from perses.utils.openeye import OEMol_to_omm_ff
    from simtk import openmm
    from openmmforcefields.generators import SystemGenerator
    from openff.toolkit.topology import Molecule

    #default arguments for SystemGenerators
    barostat = None
    forcefield_files = ['amber14/protein.ff14SB.xml', 'amber14/tip3p.xml']
    forcefield_kwargs = {
        'removeCMMotion': False,
        'ewaldErrorTolerance': 1e-4,
        'nonbondedMethod': app.NoCutoff,
        'constraints': app.HBonds,
        'hydrogenMass': 4 * unit.amus
    }
    small_molecule_forcefield = 'gaff-2.11'
    system_generator = SystemGenerator(
        forcefields=forcefield_files,
        barostat=barostat,
        forcefield_kwargs=forcefield_kwargs,
        small_molecule_forcefield=small_molecule_forcefield,
        molecules=[Molecule.from_openeye(molecule)],
        cache=None)

    system, positions, topology = OEMol_to_omm_ff(molecule, system_generator)

    assert (type(system) == type(openmm.System())
            ), "An openmm.System has not been generated from OEMol_to_omm_ff()"

    return system, positions, topology
示例#19
0
def generate_atp(phase = 'vacuum'):
    """
    modify the AlanineDipeptideVacuum test system to be parametrized with amber14ffsb in vac or solvent (tip3p)
    """
    import openmmtools.testsystems as ts
    from openmmforcefields.generators import SystemGenerator
    atp = ts.AlanineDipeptideVacuum(constraints = app.HBonds, hydrogenMass = 4 * unit.amus)


    forcefield_files = ['gaff.xml', 'amber14/protein.ff14SB.xml', 'amber14/tip3p.xml']

    if phase == 'vacuum':
        barostat = None
        system_generator = SystemGenerator(forcefield_files,
                                       barostat = barostat,
                                       forcefield_kwargs = {'removeCMMotion': False,
                                                            'ewaldErrorTolerance': 1e-4,
                                                            'constraints' : app.HBonds,
                                                            'hydrogenMass' : 4 * unit.amus},
                                        nonperiodic_forcefield_kwargs = {'nonbondedMethod': app.NoCutoff},
                                        small_molecule_forcefield = 'gaff-2.11', molecules = None, cache = None)

        atp.system = system_generator.create_system(atp.topology) #update the parametrization scheme to amberff14sb

    elif phase == 'solvent':
        barostat = openmm.MonteCarloBarostat(1.0 * unit.atmosphere, 300 * unit.kelvin, 50)

        system_generator = SystemGenerator(forcefield_files,
                                   barostat = barostat,
                                   forcefield_kwargs = {'removeCMMotion': False,
                                                        'ewaldErrorTolerance': 1e-4,
                                                        'nonbondedMethod': app.PME,
                                                        'constraints' : app.HBonds,
                                                        'hydrogenMass' : 4 * unit.amus},
                                    small_molecule_forcefield = 'gaff-2.11', molecules = None, cache = None)

    if phase == 'solvent':
        modeller = app.Modeller(atp.topology, atp.positions)
        modeller.addSolvent(system_generator._forcefield, model='tip3p', padding=9*unit.angstroms, ionicStrength=0.15*unit.molar)
        solvated_topology = modeller.getTopology()
        solvated_positions = modeller.getPositions()

        # canonicalize the solvated positions: turn tuples into np.array
        atp.positions = unit.quantity.Quantity(value = np.array([list(atom_pos) for atom_pos in solvated_positions.value_in_unit_system(unit.md_unit_system)]), unit = unit.nanometers)
        atp.topology = solvated_topology

        atp.system = system_generator.create_system(atp.topology)


    return atp, system_generator
示例#20
0
def run():
    # Create initial model system, topology, and positions.
    smiles_list = ["CC", "CCC", "CCCC"]

    initial_molecule = smiles_to_oemol("CC")
    molecules = [Molecule.from_openeye(initial_molecule)]

    system_generator = SystemGenerator(molecules=molecules)

    initial_sys, initial_pos, initial_top = OEMol_to_omm_ff(
        initial_molecule, system_generator)

    smiles = "CC"
    stats = {ms: 0 for ms in smiles_list}
    # Run parameters
    temperature = 300.0 * unit.kelvin  # temperature
    pressure = 1.0 * unit.atmospheres  # pressure
    collision_rate = 5.0 / unit.picoseconds  # collision rate for Langevin dynamics

    # Create proposal metadata, such as the list of molecules to sample (SMILES here)
    # proposal_metadata = {"smiles_list": smiles_list}
    list_of_oemols = []
    for smile in smiles_list:
        oemol = smiles_to_oemol(smile)
        list_of_oemols.append(oemol)

    transformation = topology_proposal.SmallMoleculeSetProposalEngine(
        list_of_oemols=list_of_oemols, system_generator=system_generator)
    # transformation = topology_proposal.SingleSmallMolecule(proposal_metadata)

    # Initialize weight calculation engine, along with its metadata
    bias_calculator = bias_engine.MinimizedPotentialBias(smiles_list)

    # Initialize NCMC engines.
    switching_timestep = (1.0 * unit.femtosecond
                          )  # Timestep for NCMC velocity Verlet integrations
    switching_nsteps = 10  # Number of steps to use in NCMC integration
    switching_functions = {  # Functional schedules to use in terms of `lambda`, which is switched from 0->1 for creation and 1->0 for deletion
        "lambda_sterics": "lambda",
        "lambda_electrostatics": "lambda",
        "lambda_bonds": "lambda",
        "lambda_angles": "sqrt(lambda)",
        "lambda_torsions": "lambda",
    }
    ncmc_engine = ncmc_switching.NCMCEngine(
        temperature=temperature,
        timestep=switching_timestep,
        nsteps=switching_nsteps,
        functions=switching_functions,
    )

    # Initialize GeometryEngine
    geometry_metadata = {"data": 0}  # currently ignored
    geometry_engine = geometry.FFAllAngleGeometryEngine(geometry_metadata)

    # Run a number of iterations.
    niterations = 50
    system = initial_sys
    topology = initial_top
    positions = initial_pos
    current_log_weight = bias_calculator.g_k(smiles)
    n_accepted = 0
    propagate = True
    for i in range(niterations):
        # Store old (system, topology, positions).

        # Propose a transformation from one chemical species to another.
        state_metadata = {"molecule_smiles": smiles}
        top_proposal = transformation.propose(
            system, topology, positions, state_metadata)  # Get a new molecule

        # QUESTION: What about instead initializing StateWeight once, and then using
        # log_state_weight = state_weight.computeLogStateWeight(new_topology, new_system, new_metadata)?
        log_weight = bias_calculator.g_k(
            top_proposal.metadata["molecule_smiles"])

        # Perform alchemical transformation.

        # Alchemically eliminate atoms being removed.

        [ncmc_old_positions,
         ncmc_elimination_logp] = ncmc_engine.integrate(top_proposal,
                                                        positions,
                                                        direction="delete")

        # Generate coordinates for new atoms and compute probability ratio of old and new probabilities.
        # QUESTION: Again, maybe we want to have the geometry engine initialized once only?
        geometry_proposal = geometry_engine.propose(
            top_proposal.new_to_old_atom_map,
            top_proposal.new_system,
            system,
            ncmc_old_positions,
        )

        # Alchemically introduce new atoms.
        [ncmc_new_positions, ncmc_introduction_logp
         ] = ncmc_engine.integrate(top_proposal,
                                   geometry_proposal.new_positions,
                                   direction="insert")

        # Compute total log acceptance probability, including all components.
        logp_accept = (top_proposal.logp_proposal + geometry_proposal.logp +
                       ncmc_elimination_logp + ncmc_introduction_logp +
                       log_weight / log_weight.unit -
                       current_log_weight / current_log_weight.unit)

        # Accept or reject.
        if ((logp_accept >= 0.0) or
            (np.random.uniform() < np.exp(logp_accept))) and not np.any(
                np.isnan(ncmc_new_positions)):
            # Accept.
            n_accepted += 1
            (system, topology, positions, current_log_weight, smiles) = (
                top_proposal.new_system,
                top_proposal.new_topology,
                ncmc_new_positions,
                log_weight,
                top_proposal.metadata["molecule_smiles"],
            )
        else:
            # Reject.
            logging.debug("reject")
        stats[smiles] += 1
        print(positions)
        if propagate:
            p_system = copy.deepcopy(system)
            integrator = openmm.LangevinIntegrator(temperature, collision_rate,
                                                   switching_timestep)
            context = openmm.Context(p_system, integrator)
            context.setPositions(positions)
            print(context.getState(getEnergy=True).getPotentialEnergy())
            integrator.step(1000)
            state = context.getState(getPositions=True)
            positions = state.getPositions(asNumpy=True)
            del context, integrator, p_system

    print("The total number accepted was %d out of %d iterations" %
          (n_accepted, niterations))
    print(stats)
示例#21
0
    def __init__(self,
                 protein_filename,
                 mutation_chain_id,
                 mutation_residue_id,
                 proposed_residue,
                 phase='complex',
                 conduct_endstate_validation=True,
                 ligand_input=None,
                 ligand_index=0,
                 water_model='tip3p',
                 ionic_strength=0.15 * unit.molar,
                 forcefield_files=['amber14/protein.ff14SB.xml', 'amber14/tip3p.xml'],
                 barostat=openmm.MonteCarloBarostat(1.0 * unit.atmosphere, temperature, 50),
                 forcefield_kwargs={'removeCMMotion': False, 'ewaldErrorTolerance': 0.00025, 'constraints' : app.HBonds, 'hydrogenMass' : 4 * unit.amus},
                 periodic_forcefield_kwargs={'nonbondedMethod': app.PME},
                 nonperiodic_forcefield_kwargs=None,
                 small_molecule_forcefields='gaff-2.11',
                 complex_box_dimensions=None,
                 apo_box_dimensions=None,
                 flatten_torsions=False,
                 flatten_exceptions=False,
                 repartitioned_endstate=None,
                 **kwargs):
        """
        arguments
            protein_filename : str
                path to protein (to mutate); .pdb
            mutation_chain_id : str
                name of the chain to be mutated
            mutation_residue_id : str
                residue id to change
            proposed_residue : str
                three letter code of the residue to mutate to
            phase : str, default complex
                if phase == vacuum, then the complex will not be solvated with water; else, it will be solvated with tip3p
            conduct_endstate_validation : bool, default True
                whether to conduct an endstate validation of the HybridTopologyFactory. If using the RepartitionedHybridTopologyFactory,
                endstate validation cannot and will not be conducted.
            ligand_file : str, default None
                path to ligand of interest (i.e. small molecule or protein); .sdf or .pdb
            ligand_index : int, default 0
                which ligand to use
            water_model : str, default 'tip3p'
                solvent model to use for solvation
            ionic_strength : float * unit.molar, default 0.15 * unit.molar
                the total concentration of ions (both positive and negative) to add using Modeller.
                This does not include ions that are added to neutralize the system.
                Note that only monovalent ions are currently supported.
            forcefield_files : list of str, default ['amber14/protein.ff14SB.xml', 'amber14/tip3p.xml']
                forcefield files for proteins and solvent
            barostat : openmm.MonteCarloBarostat, default openmm.MonteCarloBarostat(1.0 * unit.atmosphere, 300 * unit.kelvin, 50)
                barostat to use
            forcefield_kwargs : dict, default {'removeCMMotion': False, 'ewaldErrorTolerance': 1e-4, 'constraints' : app.HBonds, 'hydrogenMass' : 4 * unit.amus}
                forcefield kwargs for system parametrization
            periodic_forcefield_kwargs : dict, default {'nonbondedMethod': app.PME}
                periodic forcefield kwargs for system parametrization
            nonperiodic_forcefield_kwargs : dict, default None
                non-periodic forcefield kwargs for system parametrization
            small_molecule_forcefields : str, default 'gaff-2.11'
                the forcefield string for small molecule parametrization
            complex_box_dimensions : Vec3, default None
                define box dimensions of complex phase;
                if None, padding is 1nm
            apo_box_dimensions :  Vec3, default None
                define box dimensions of apo phase phase;
                if None, padding is 1nm
            flatten_torsions : bool, default False
                in the htf, flatten torsions involving unique new atoms at lambda = 0 and unique old atoms are lambda = 1
            flatten_exceptions : bool, default False
                in the htf, flatten exceptions involving unique new atoms at lambda = 0 and unique old atoms at lambda = 1
            repartitioned_endstate : int, default None
                the endstate (0 or 1) at which to build the RepartitionedHybridTopologyFactory. By default, this is None,
                meaning a vanilla HybridTopologyFactory will be built.
        TODO : allow argument for spectator ligands besides the 'ligand_file'

        """

        # First thing to do is load the apo protein to mutate...
        protein_pdbfile = open(protein_filename, 'r')
        protein_pdb = app.PDBFile(protein_pdbfile)
        protein_pdbfile.close()
        protein_positions, protein_topology, protein_md_topology = protein_pdb.positions, protein_pdb.topology, md.Topology.from_openmm(protein_pdb.topology)
        protein_topology = protein_md_topology.to_openmm()
        protein_n_atoms = protein_md_topology.n_atoms

        # Load the ligand, if present
        molecules = []
        if ligand_input:
            if isinstance(ligand_input, str):
                if ligand_input.endswith('.sdf'): # small molecule
                        ligand_mol = createOEMolFromSDF(ligand_input, index=ligand_index)
                        molecules.append(Molecule.from_openeye(ligand_mol, allow_undefined_stereo=False))
                        ligand_positions, ligand_topology = extractPositionsFromOEMol(ligand_mol),  forcefield_generators.generateTopologyFromOEMol(ligand_mol)
                        ligand_md_topology = md.Topology.from_openmm(ligand_topology)
                        ligand_n_atoms = ligand_md_topology.n_atoms

                if ligand_input.endswith('pdb'): # protein
                    ligand_pdbfile = open(ligand_input, 'r')
                    ligand_pdb = app.PDBFile(ligand_pdbfile)
                    ligand_pdbfile.close()
                    ligand_positions, ligand_topology, ligand_md_topology = ligand_pdb.positions, ligand_pdb.topology, md.Topology.from_openmm(
                        ligand_pdb.topology)
                    ligand_n_atoms = ligand_md_topology.n_atoms

            elif isinstance(ligand_input, oechem.OEMol): # oemol object
                molecules.append(Molecule.from_openeye(ligand_input, allow_undefined_stereo=False))
                ligand_positions, ligand_topology = extractPositionsFromOEMol(ligand_input),  forcefield_generators.generateTopologyFromOEMol(ligand_input)
                ligand_md_topology = md.Topology.from_openmm(ligand_topology)
                ligand_n_atoms = ligand_md_topology.n_atoms

            else:
                _logger.warning(f'ligand filetype not recognised. Please provide a path to a .pdb or .sdf file')
                return

            # Now create a complex
            complex_md_topology = protein_md_topology.join(ligand_md_topology)
            complex_topology = complex_md_topology.to_openmm()
            complex_positions = unit.Quantity(np.zeros([protein_n_atoms + ligand_n_atoms, 3]), unit=unit.nanometers)
            complex_positions[:protein_n_atoms, :] = protein_positions
            complex_positions[protein_n_atoms:, :] = ligand_positions

        # Now for a system_generator
        self.system_generator = SystemGenerator(forcefields=forcefield_files,
                                                barostat=barostat,
                                                forcefield_kwargs=forcefield_kwargs,
                                                periodic_forcefield_kwargs=periodic_forcefield_kwargs,
                                                nonperiodic_forcefield_kwargs=nonperiodic_forcefield_kwargs,
                                                small_molecule_forcefield=small_molecule_forcefields,
                                                molecules=molecules,
                                                cache=None)

        # Solvate apo and complex...
        apo_input = list(self._solvate(protein_topology, protein_positions, water_model, phase, ionic_strength, apo_box_dimensions))
        inputs = [apo_input]
        if ligand_input:
            inputs.append(self._solvate(complex_topology, complex_positions, water_model, phase, ionic_strength, complex_box_dimensions))

        geometry_engine = FFAllAngleGeometryEngine(metadata=None,
                                                use_sterics=False,
                                                n_bond_divisions=100,
                                                n_angle_divisions=180,
                                                n_torsion_divisions=360,
                                                verbose=True,
                                                storage=None,
                                                bond_softening_constant=1.0,
                                                angle_softening_constant=1.0,
                                                neglect_angles = False,
                                                use_14_nonbondeds = True)


        # Run pipeline...
        htfs = []
        for (top, pos, sys) in inputs:
            point_mutation_engine = PointMutationEngine(wildtype_topology=top,
                                                                 system_generator=self.system_generator,
                                                                 chain_id=mutation_chain_id, # Denote the chain id allowed to mutate (it's always a string variable)
                                                                 max_point_mutants=1,
                                                                 residues_allowed_to_mutate=[mutation_residue_id], # The residue ids allowed to mutate
                                                                 allowed_mutations=[(mutation_residue_id, proposed_residue)], # The residue ids allowed to mutate with the three-letter code allowed to change
                                                                 aggregate=True) # Always allow aggregation

            topology_proposal = point_mutation_engine.propose(sys, top)

            # Only validate energy bookkeeping if the WT and proposed residues do not involve rings
            old_res = [res for res in top.residues() if res.id == mutation_residue_id][0]
            validate_bool = False if old_res.name in ring_amino_acids or proposed_residue in ring_amino_acids else True
            new_positions, logp_proposal = geometry_engine.propose(topology_proposal, pos, beta,
                                                                   validate_energy_bookkeeping=validate_bool)
            logp_reverse = geometry_engine.logp_reverse(topology_proposal, new_positions, pos, beta,
                                                        validate_energy_bookkeeping=validate_bool)

            if repartitioned_endstate is None:
                factory = HybridTopologyFactory
            elif repartitioned_endstate in [0, 1]:
                factory = RepartitionedHybridTopologyFactory

            forward_htf = factory(topology_proposal=topology_proposal,
                                  current_positions=pos,
                                  new_positions=new_positions,
                                  use_dispersion_correction=False,
                                  functions=None,
                                  softcore_alpha=None,
                                  bond_softening_constant=1.0,
                                  angle_softening_constant=1.0,
                                  soften_only_new=False,
                                  neglected_new_angle_terms=[],
                                  neglected_old_angle_terms=[],
                                  softcore_LJ_v2=True,
                                  softcore_electrostatics=True,
                                  softcore_LJ_v2_alpha=0.85,
                                  softcore_electrostatics_alpha=0.3,
                                  softcore_sigma_Q=1.0,
                                  interpolate_old_and_new_14s=flatten_exceptions,
                                  omitted_terms=None,
                                  endstate=repartitioned_endstate,
                                  flatten_torsions=flatten_torsions)

            if not topology_proposal.unique_new_atoms:
                assert geometry_engine.forward_final_context_reduced_potential == None, f"There are no unique new atoms but the geometry_engine's final context reduced potential is not None (i.e. {self._geometry_engine.forward_final_context_reduced_potential})"
                assert geometry_engine.forward_atoms_with_positions_reduced_potential == None, f"There are no unique new atoms but the geometry_engine's forward atoms-with-positions-reduced-potential in not None (i.e. { self._geometry_engine.forward_atoms_with_positions_reduced_potential})"
            else:
                added_valence_energy = geometry_engine.forward_final_context_reduced_potential - geometry_engine.forward_atoms_with_positions_reduced_potential

            if not topology_proposal.unique_old_atoms:
                assert geometry_engine.reverse_final_context_reduced_potential == None, f"There are no unique old atoms but the geometry_engine's final context reduced potential is not None (i.e. {self._geometry_engine.reverse_final_context_reduced_potential})"
                assert geometry_engine.reverse_atoms_with_positions_reduced_potential == None, f"There are no unique old atoms but the geometry_engine's atoms-with-positions-reduced-potential in not None (i.e. { self._geometry_engine.reverse_atoms_with_positions_reduced_potential})"
                subtracted_valence_energy = 0.0
            else:
                subtracted_valence_energy = geometry_engine.reverse_final_context_reduced_potential - geometry_engine.reverse_atoms_with_positions_reduced_potential


            if conduct_endstate_validation and repartitioned_endstate is None:
                zero_state_error, one_state_error = validate_endstate_energies(forward_htf._topology_proposal, forward_htf, added_valence_energy, subtracted_valence_energy, beta=beta, ENERGY_THRESHOLD=ENERGY_THRESHOLD)
                if zero_state_error > ENERGY_THRESHOLD:
                    _logger.warning(f"Reduced potential difference of the nonalchemical and alchemical Lambda = 0 state is above the threshold ({ENERGY_THRESHOLD}): {zero_state_error}")
                if one_state_error > ENERGY_THRESHOLD:
                    _logger.warning(f"Reduced potential difference of the nonalchemical and alchemical Lambda = 1 state is above the threshold ({ENERGY_THRESHOLD}): {one_state_error}")
            else:
                pass

            htfs.append(forward_htf)

        self.apo_htf = htfs[0]
        self.complex_htf = htfs[1] if ligand_input else None
示例#22
0
class PointMutationExecutor(object):
    """
    Simple, stripped-down class to create a protein-ligand system and allow a mutation of a protein.
    this will allow support for the creation of _two_ relative free energy calculations:
        1. 'wildtype' - 'point mutant' complex hybrid.
        2. 'wildtype' - 'point mutant' protein hybrid (i.e. with ligand of interest unbound)

    Example (create full point mutation executor and run parallel tempering on both complex and apo phases):
        from pkg_resources import resource_filename

        protein_path = 'data/perses_jacs_systems/thrombin/Thrombin_protein.pdb'
        ligands_path = 'data/perses_jacs_systems/thrombin/Thrombin_ligands.sdf'
        protein_filename = resource_filename('openmmforcefields', protein_path)
        ligand_input = resource_filename('openmmforcefields', ligands_path)

        pm_delivery = PointMutationExecutor(protein_filename=protein_filename,
                                    mutation_chain_id='2',
                                    mutation_residue_id='198',
                                     proposed_residue='THR',
                                     phase='complex',
                                     conduct_endstate_validation=False,
                                     ligand_input=ligand_input,
                                     ligand_index=0,
                                     forcefield_files=['amber14/protein.ff14SB.xml', 'amber14/tip3p.xml'],
                                     barostat=openmm.MonteCarloBarostat(1.0 * unit.atmosphere, temperature, 50),
                                     forcefield_kwargs={'removeCMMotion': False, 'ewaldErrorTolerance': 1e-4, 'nonbondedMethod': app.PME, 'constraints' : app.HBonds, 'hydrogenMass' : 4 * unit.amus},
                                     small_molecule_forcefields='gaff-2.11')

        complex_htf = pm_delivery.get_complex_htf()
        apo_htf = pm_delivery.get_apo_htf()

        # Now we can build the hybrid repex samplers
        from perses.annihilation.lambda_protocol import LambdaProtocol
        from openmmtools.multistate import MultiStateReporter
        from perses.samplers.multistate import HybridRepexSampler
        from openmmtools import mcmc

        suffix = 'run'; selection = 'not water'; checkpoint_interval = 10; n_states = 11; n_cycles = 5000

        for htf in [complex_htf, apo_htf]:
            lambda_protocol = LambdaProtocol(functions='default')
            reporter_file = 'reporter.nc'
            reporter = MultiStateReporter(reporter_file, analysis_particle_indices = htf.hybrid_topology.select(selection), checkpoint_interval = checkpoint_interval)
            hss = HybridRepexSampler(mcmc_moves=mcmc.LangevinSplittingDynamicsMove(timestep= 4.0 * unit.femtoseconds,
                                                                                  collision_rate=5.0 / unit.picosecond,
                                                                                  n_steps=250,
                                                                                  reassign_velocities=False,
                                                                                  n_restart_attempts=20,
                                                                                  splitting="V R R R O R R R V",
                                                                                  constraint_tolerance=1e-06),
                                                                                  hybrid_factory=htf, online_analysis_interval=10)
            hss.setup(n_states=n_states, temperature=300*unit.kelvin, storage_file=reporter, lambda_protocol=lambda_protocol, endstates=False)
            hss.extend(n_cycles)

    """
    def __init__(self,
                 protein_filename,
                 mutation_chain_id,
                 mutation_residue_id,
                 proposed_residue,
                 phase='complex',
                 conduct_endstate_validation=True,
                 ligand_input=None,
                 ligand_index=0,
                 water_model='tip3p',
                 ionic_strength=0.15 * unit.molar,
                 forcefield_files=['amber14/protein.ff14SB.xml', 'amber14/tip3p.xml'],
                 barostat=openmm.MonteCarloBarostat(1.0 * unit.atmosphere, temperature, 50),
                 forcefield_kwargs={'removeCMMotion': False, 'ewaldErrorTolerance': 0.00025, 'constraints' : app.HBonds, 'hydrogenMass' : 4 * unit.amus},
                 periodic_forcefield_kwargs={'nonbondedMethod': app.PME},
                 nonperiodic_forcefield_kwargs=None,
                 small_molecule_forcefields='gaff-2.11',
                 complex_box_dimensions=None,
                 apo_box_dimensions=None,
                 flatten_torsions=False,
                 flatten_exceptions=False,
                 repartitioned_endstate=None,
                 **kwargs):
        """
        arguments
            protein_filename : str
                path to protein (to mutate); .pdb
            mutation_chain_id : str
                name of the chain to be mutated
            mutation_residue_id : str
                residue id to change
            proposed_residue : str
                three letter code of the residue to mutate to
            phase : str, default complex
                if phase == vacuum, then the complex will not be solvated with water; else, it will be solvated with tip3p
            conduct_endstate_validation : bool, default True
                whether to conduct an endstate validation of the HybridTopologyFactory. If using the RepartitionedHybridTopologyFactory,
                endstate validation cannot and will not be conducted.
            ligand_file : str, default None
                path to ligand of interest (i.e. small molecule or protein); .sdf or .pdb
            ligand_index : int, default 0
                which ligand to use
            water_model : str, default 'tip3p'
                solvent model to use for solvation
            ionic_strength : float * unit.molar, default 0.15 * unit.molar
                the total concentration of ions (both positive and negative) to add using Modeller.
                This does not include ions that are added to neutralize the system.
                Note that only monovalent ions are currently supported.
            forcefield_files : list of str, default ['amber14/protein.ff14SB.xml', 'amber14/tip3p.xml']
                forcefield files for proteins and solvent
            barostat : openmm.MonteCarloBarostat, default openmm.MonteCarloBarostat(1.0 * unit.atmosphere, 300 * unit.kelvin, 50)
                barostat to use
            forcefield_kwargs : dict, default {'removeCMMotion': False, 'ewaldErrorTolerance': 1e-4, 'constraints' : app.HBonds, 'hydrogenMass' : 4 * unit.amus}
                forcefield kwargs for system parametrization
            periodic_forcefield_kwargs : dict, default {'nonbondedMethod': app.PME}
                periodic forcefield kwargs for system parametrization
            nonperiodic_forcefield_kwargs : dict, default None
                non-periodic forcefield kwargs for system parametrization
            small_molecule_forcefields : str, default 'gaff-2.11'
                the forcefield string for small molecule parametrization
            complex_box_dimensions : Vec3, default None
                define box dimensions of complex phase;
                if None, padding is 1nm
            apo_box_dimensions :  Vec3, default None
                define box dimensions of apo phase phase;
                if None, padding is 1nm
            flatten_torsions : bool, default False
                in the htf, flatten torsions involving unique new atoms at lambda = 0 and unique old atoms are lambda = 1
            flatten_exceptions : bool, default False
                in the htf, flatten exceptions involving unique new atoms at lambda = 0 and unique old atoms at lambda = 1
            repartitioned_endstate : int, default None
                the endstate (0 or 1) at which to build the RepartitionedHybridTopologyFactory. By default, this is None,
                meaning a vanilla HybridTopologyFactory will be built.
        TODO : allow argument for spectator ligands besides the 'ligand_file'

        """

        # First thing to do is load the apo protein to mutate...
        protein_pdbfile = open(protein_filename, 'r')
        protein_pdb = app.PDBFile(protein_pdbfile)
        protein_pdbfile.close()
        protein_positions, protein_topology, protein_md_topology = protein_pdb.positions, protein_pdb.topology, md.Topology.from_openmm(protein_pdb.topology)
        protein_topology = protein_md_topology.to_openmm()
        protein_n_atoms = protein_md_topology.n_atoms

        # Load the ligand, if present
        molecules = []
        if ligand_input:
            if isinstance(ligand_input, str):
                if ligand_input.endswith('.sdf'): # small molecule
                        ligand_mol = createOEMolFromSDF(ligand_input, index=ligand_index)
                        molecules.append(Molecule.from_openeye(ligand_mol, allow_undefined_stereo=False))
                        ligand_positions, ligand_topology = extractPositionsFromOEMol(ligand_mol),  forcefield_generators.generateTopologyFromOEMol(ligand_mol)
                        ligand_md_topology = md.Topology.from_openmm(ligand_topology)
                        ligand_n_atoms = ligand_md_topology.n_atoms

                if ligand_input.endswith('pdb'): # protein
                    ligand_pdbfile = open(ligand_input, 'r')
                    ligand_pdb = app.PDBFile(ligand_pdbfile)
                    ligand_pdbfile.close()
                    ligand_positions, ligand_topology, ligand_md_topology = ligand_pdb.positions, ligand_pdb.topology, md.Topology.from_openmm(
                        ligand_pdb.topology)
                    ligand_n_atoms = ligand_md_topology.n_atoms

            elif isinstance(ligand_input, oechem.OEMol): # oemol object
                molecules.append(Molecule.from_openeye(ligand_input, allow_undefined_stereo=False))
                ligand_positions, ligand_topology = extractPositionsFromOEMol(ligand_input),  forcefield_generators.generateTopologyFromOEMol(ligand_input)
                ligand_md_topology = md.Topology.from_openmm(ligand_topology)
                ligand_n_atoms = ligand_md_topology.n_atoms

            else:
                _logger.warning(f'ligand filetype not recognised. Please provide a path to a .pdb or .sdf file')
                return

            # Now create a complex
            complex_md_topology = protein_md_topology.join(ligand_md_topology)
            complex_topology = complex_md_topology.to_openmm()
            complex_positions = unit.Quantity(np.zeros([protein_n_atoms + ligand_n_atoms, 3]), unit=unit.nanometers)
            complex_positions[:protein_n_atoms, :] = protein_positions
            complex_positions[protein_n_atoms:, :] = ligand_positions

        # Now for a system_generator
        self.system_generator = SystemGenerator(forcefields=forcefield_files,
                                                barostat=barostat,
                                                forcefield_kwargs=forcefield_kwargs,
                                                periodic_forcefield_kwargs=periodic_forcefield_kwargs,
                                                nonperiodic_forcefield_kwargs=nonperiodic_forcefield_kwargs,
                                                small_molecule_forcefield=small_molecule_forcefields,
                                                molecules=molecules,
                                                cache=None)

        # Solvate apo and complex...
        apo_input = list(self._solvate(protein_topology, protein_positions, water_model, phase, ionic_strength, apo_box_dimensions))
        inputs = [apo_input]
        if ligand_input:
            inputs.append(self._solvate(complex_topology, complex_positions, water_model, phase, ionic_strength, complex_box_dimensions))

        geometry_engine = FFAllAngleGeometryEngine(metadata=None,
                                                use_sterics=False,
                                                n_bond_divisions=100,
                                                n_angle_divisions=180,
                                                n_torsion_divisions=360,
                                                verbose=True,
                                                storage=None,
                                                bond_softening_constant=1.0,
                                                angle_softening_constant=1.0,
                                                neglect_angles = False,
                                                use_14_nonbondeds = True)


        # Run pipeline...
        htfs = []
        for (top, pos, sys) in inputs:
            point_mutation_engine = PointMutationEngine(wildtype_topology=top,
                                                                 system_generator=self.system_generator,
                                                                 chain_id=mutation_chain_id, # Denote the chain id allowed to mutate (it's always a string variable)
                                                                 max_point_mutants=1,
                                                                 residues_allowed_to_mutate=[mutation_residue_id], # The residue ids allowed to mutate
                                                                 allowed_mutations=[(mutation_residue_id, proposed_residue)], # The residue ids allowed to mutate with the three-letter code allowed to change
                                                                 aggregate=True) # Always allow aggregation

            topology_proposal = point_mutation_engine.propose(sys, top)

            # Only validate energy bookkeeping if the WT and proposed residues do not involve rings
            old_res = [res for res in top.residues() if res.id == mutation_residue_id][0]
            validate_bool = False if old_res.name in ring_amino_acids or proposed_residue in ring_amino_acids else True
            new_positions, logp_proposal = geometry_engine.propose(topology_proposal, pos, beta,
                                                                   validate_energy_bookkeeping=validate_bool)
            logp_reverse = geometry_engine.logp_reverse(topology_proposal, new_positions, pos, beta,
                                                        validate_energy_bookkeeping=validate_bool)

            if repartitioned_endstate is None:
                factory = HybridTopologyFactory
            elif repartitioned_endstate in [0, 1]:
                factory = RepartitionedHybridTopologyFactory

            forward_htf = factory(topology_proposal=topology_proposal,
                                  current_positions=pos,
                                  new_positions=new_positions,
                                  use_dispersion_correction=False,
                                  functions=None,
                                  softcore_alpha=None,
                                  bond_softening_constant=1.0,
                                  angle_softening_constant=1.0,
                                  soften_only_new=False,
                                  neglected_new_angle_terms=[],
                                  neglected_old_angle_terms=[],
                                  softcore_LJ_v2=True,
                                  softcore_electrostatics=True,
                                  softcore_LJ_v2_alpha=0.85,
                                  softcore_electrostatics_alpha=0.3,
                                  softcore_sigma_Q=1.0,
                                  interpolate_old_and_new_14s=flatten_exceptions,
                                  omitted_terms=None,
                                  endstate=repartitioned_endstate,
                                  flatten_torsions=flatten_torsions)

            if not topology_proposal.unique_new_atoms:
                assert geometry_engine.forward_final_context_reduced_potential == None, f"There are no unique new atoms but the geometry_engine's final context reduced potential is not None (i.e. {self._geometry_engine.forward_final_context_reduced_potential})"
                assert geometry_engine.forward_atoms_with_positions_reduced_potential == None, f"There are no unique new atoms but the geometry_engine's forward atoms-with-positions-reduced-potential in not None (i.e. { self._geometry_engine.forward_atoms_with_positions_reduced_potential})"
            else:
                added_valence_energy = geometry_engine.forward_final_context_reduced_potential - geometry_engine.forward_atoms_with_positions_reduced_potential

            if not topology_proposal.unique_old_atoms:
                assert geometry_engine.reverse_final_context_reduced_potential == None, f"There are no unique old atoms but the geometry_engine's final context reduced potential is not None (i.e. {self._geometry_engine.reverse_final_context_reduced_potential})"
                assert geometry_engine.reverse_atoms_with_positions_reduced_potential == None, f"There are no unique old atoms but the geometry_engine's atoms-with-positions-reduced-potential in not None (i.e. { self._geometry_engine.reverse_atoms_with_positions_reduced_potential})"
                subtracted_valence_energy = 0.0
            else:
                subtracted_valence_energy = geometry_engine.reverse_final_context_reduced_potential - geometry_engine.reverse_atoms_with_positions_reduced_potential


            if conduct_endstate_validation and repartitioned_endstate is None:
                zero_state_error, one_state_error = validate_endstate_energies(forward_htf._topology_proposal, forward_htf, added_valence_energy, subtracted_valence_energy, beta=beta, ENERGY_THRESHOLD=ENERGY_THRESHOLD)
                if zero_state_error > ENERGY_THRESHOLD:
                    _logger.warning(f"Reduced potential difference of the nonalchemical and alchemical Lambda = 0 state is above the threshold ({ENERGY_THRESHOLD}): {zero_state_error}")
                if one_state_error > ENERGY_THRESHOLD:
                    _logger.warning(f"Reduced potential difference of the nonalchemical and alchemical Lambda = 1 state is above the threshold ({ENERGY_THRESHOLD}): {one_state_error}")
            else:
                pass

            htfs.append(forward_htf)

        self.apo_htf = htfs[0]
        self.complex_htf = htfs[1] if ligand_input else None

    def get_complex_htf(self):
        return self.complex_htf

    def get_apo_htf(self):
        return self.apo_htf


    def _solvate(self,
               topology,
               positions,
               water_model,
               phase,
               ionic_strength,
               box_dimensions=None):
        """
        Generate a solvated topology, positions, and system for a given input topology and positions.
        For generating the system, the forcefield files provided in the constructor will be used.

        Parameters
        ----------
        topology : app.Topology
            Topology of the system to solvate
        positions : [n, 3] ndarray of Quantity nm
            the positions of the unsolvated system
        forcefield : SystemGenerator.forcefield
            forcefield file of solvent to add
        water_model : str
            solvent model to use for solvation
        phase : str
            if phase == vacuum, then the complex will not be solvated with water; else, it will be solvated with tip3p
        ionic_strength : float * unit.molar
            the total concentration of ions (both positive and negative) to add using Modeller.
            This does not include ions that are added to neutralize the system.
            Note that only monovalent ions are currently supported.

        Returns
        -------
        solvated_topology : app.Topology
            Topology of the system with added waters
        solvated_positions : [n + 3(n_waters), 3] ndarray of Quantity nm
            Solvated positions
        solvated_system : openmm.System
            The parameterized system, containing a barostat if one was specified.
        """
        modeller = app.Modeller(topology, positions)

        # Now we have to add missing atoms
        if phase != 'vacuum':
            _logger.info(f"solvating at {ionic_strength} using {water_model}")
            if not box_dimensions:
                modeller.addSolvent(self.system_generator.forcefield, model=water_model, padding=0.9 * unit.nanometers, ionicStrength=ionic_strength)
            else:
                modeller.addSolvent(self.system_generator.forcefield, model=water_model, boxSize=box_dimensions, ionicStrength=ionic_strength)
        else:
            pass

        solvated_topology = modeller.getTopology()
        if box_dimensions:
            solvated_topology.setUnitCellDimensions(box_dimensions)
        solvated_positions = modeller.getPositions()

        # Canonicalize the solvated positions: turn tuples into np.array
        solvated_positions = unit.quantity.Quantity(value=np.array([list(atom_pos) for atom_pos in solvated_positions.value_in_unit_system(unit.md_unit_system)]), unit=unit.nanometers)
        solvated_system = self.system_generator.create_system(solvated_topology)

        return solvated_topology, solvated_positions, solvated_system
示例#23
0
def create_systems(topologies_dict,
                   positions_dict,
                   output_directory,
                   project_prefix,
                   solvate=True):
    """
    Generate the systems ready for equilibrium simulations from a dictionary of topologies and positions

    Parameters
    ----------
    topologies_dict : dict of str: app.Topoology
        A dictionary of the topologies to prepare, indexed by SMILES strings
    positions_dict : dict of str: unit.Quantity array
        A dictionary of positions for the corresponding topologies, indexed by SMILES strings
    output_directory : str
        Location of output files
    project_prefix : str
        What to prepend to the names of files for this run
    solvate : bool, default True
        Whether to solvate the systems
    """
    barostat = openmm.MonteCarloBarostat(1.0 * unit.atmosphere, temperature,
                                         50)

    system_generator = SystemGenerator(
        [
            'amber14/protein.ff14SB.xml', 'gaff.xml', 'amber14/tip3p.xml',
            'MCL1_ligands.xml'
        ],
        barostat=barostat,
        forcefield_kwargs={
            'constraints': app.HBonds,
            'hydrogenMass': 4 * unit.amus
        },
        periodic_forcefield_kwargs={'nonbondedMethod': app.PME})

    list_of_smiles = list(topologies_dict.keys())

    initial_smiles = list_of_smiles[0]

    initial_topology = topologies_dict[initial_smiles]
    initial_positions = positions_dict[initial_smiles]

    if solvate:
        solvated_initial_positions, solvated_topology, solvated_system = solvate_system(
            initial_topology.to_openmm(), initial_positions, system_generator)
    else:
        solvated_initial_positions = initial_positions
        solvated_topology = initial_topology
        solvated_system = system_generator.create_system(solvated_topology)

    md_topology = md.Topology.from_openmm(solvated_topology)

    if solvate:
        num_added = md_topology.n_residues - initial_topology.n_residues

    if not os.path.exists(output_directory):
        os.mkdir(output_directory)

    np.save("{}/{}_{}_initial.npy".format(output_directory, project_prefix, 0),
            (solvated_initial_positions, md_topology, solvated_system,
             initial_smiles))

    for i in tqdm.trange(1, len(list_of_smiles)):

        smiles = list_of_smiles[i]

        topology = topologies_dict[smiles]
        positions = positions_dict[smiles]

        if solvate:
            solvated_positions, solvated_topology, solvated_system = solvate_system(
                topology.to_openmm(),
                positions,
                system_generator,
                padding=None,
                num_added=num_added)
        else:
            solvated_positions = initial_positions
            solvated_topology = initial_topology
            solvated_system = system_generator.create_system(solvated_topology)

        np.save(
            "{}/{}_{}_initial.npy".format(output_directory, project_prefix, i),
            (solvated_positions, md.Topology.from_openmm(solvated_topology),
             solvated_system, smiles))
示例#24
0
    def _generate_openmm_system(self,
                                molecule: "offtop.Molecule",
                                method: str,
                                keywords: Dict = None) -> "openmm.System":
        """
        Generate an OpenMM System object from the input molecule method and basis.
        """
        from openmmforcefields.generators import SystemGenerator
        from simtk.openmm import app
        from simtk import unit

        # create a hash based on the input options
        hashstring = molecule.to_smiles(
            isomeric=True, explicit_hydrogens=True, mapped=True) + method
        for value in keywords.values():
            hashstring += str(value)
        key = hashlib.sha256(hashstring.encode()).hexdigest()

        # now look for the system?
        if key in self._CACHE:
            system = self._get_cache(key)
        else:
            # make the system from the inputs
            # set up available options for openmm
            _constraint_types = {
                "hbonds": app.HBonds,
                "allbonds": app.AllBonds,
                "hangles": app.HAngles
            }
            _periodic_nonbond_types = {
                "ljpme": app.LJPME,
                "pme": app.PME,
                "ewald": app.Ewald
            }
            _non_periodic_nonbond_types = {
                "nocutoff": app.NoCutoff,
                "cutoffnonperiodic": app.CutoffNonPeriodic
            }

            if "constraints" in keywords:
                constraints = keywords["constraints"]
                try:
                    forcefield_kwargs = {
                        "constraints": _constraint_types[constraints.lower()]
                    }
                except (KeyError, AttributeError):
                    raise ValueError(
                        f"constraint '{constraints}' not supported, valid constraints are {_constraint_types.keys()}"
                    )
            else:
                forcefield_kwargs = None

            nonbondedmethod = keywords.get("nonbondedMethod", None)
            if nonbondedmethod is not None:
                if nonbondedmethod.lower() in _periodic_nonbond_types:
                    periodic_forcefield_kwargs = {
                        "nonbondedMethod":
                        _periodic_nonbond_types[nonbondedmethod.lower()]
                    }
                    nonperiodic_forcefield_kwargs = None
                elif nonbondedmethod.lower() in _non_periodic_nonbond_types:
                    periodic_forcefield_kwargs = None
                    nonperiodic_forcefield_kwargs = {
                        "nonbondedMethod":
                        _non_periodic_nonbond_types[nonbondedmethod.lower()]
                    }
                else:
                    raise ValueError(
                        f"nonbondedmethod '{nonbondedmethod}' not supported, valid nonbonded methods are periodic: {_periodic_nonbond_types.keys()}"
                        f" or non_periodic: {_non_periodic_nonbond_types.keys()}."
                    )
            else:
                periodic_forcefield_kwargs = None
                nonperiodic_forcefield_kwargs = None

            # now start the system generator
            system_generator = SystemGenerator(
                small_molecule_forcefield=method,
                forcefield_kwargs=forcefield_kwargs,
                nonperiodic_forcefield_kwargs=nonperiodic_forcefield_kwargs,
                periodic_forcefield_kwargs=periodic_forcefield_kwargs,
            )
            topology = molecule.to_topology()

            system = system_generator.create_system(
                topology=topology.to_openmm(), molecules=[molecule])
            self._cache_it(key, system)
        return system
示例#25
0
checkpoint_filename = "equilibrated_checkpoint_5ns.chk"
traj_output_filename = "equilibrated_traj_5ns.xtc"

# Define the barostat for the system
barostat = mm.MonteCarloBarostat(pressure, temperature)

# Load and sort ligands
molecules = Molecule.from_file(input_ligands_sdf)
ligand_names = ["larotrectinib", "selitrectinib", "repotrectinib"]
ligand_dict = dict(zip(ligand_names, molecules))  # Create dict for easy access later

# Make the SystemGenerator
system_generator = SystemGenerator(
    forcefields=[protein_forcefield, solvation_forcefield],
    barostat=barostat,
    periodic_forcefield_kwargs={"nonbondedMethod": app.PME},
    small_molecule_forcefield=small_molecule_forcefield,
    molecules=ligand_dict[chosen_ligand],
)

# Read in the PDB and create an OpenMM topology
pdbfile = app.PDBFile(input_pdb)
protein_topology, protein_positions = pdbfile.topology, pdbfile.positions

# Add ligand to topology - credit to @hannahbrucemacdonald for help here
print("--> Combining protein and ligand topologies")
off_ligand_topology = Topology.from_molecules(ligand_dict[chosen_ligand])
ligand_topology = off_ligand_topology.to_openmm()
ligand_positions = ligand_dict[chosen_ligand].conformers[0]

md_protein_topology = md.Topology.from_openmm(
示例#26
0
pdb = app.PDBFile('bstate.pdb')
molecule = Molecule.from_smiles('CCCCO')

forcefield_kwargs = {'constraints': app.HBonds, 'removeCMMotion': False}
periodic_forcefield_kwargs = {
    'nonbondedMethod': app.LJPME,
    'nonbondedCutoff': 1 * nanometer
}
membrane_barostat = MonteCarloMembraneBarostat(
    1 * bar, 0.0 * bar * nanometer, 308 * kelvin,
    MonteCarloMembraneBarostat.XYIsotropic, MonteCarloMembraneBarostat.ZFree,
    15)
system_generator = SystemGenerator(
    forcefields=['amber/lipid17.xml', 'amber/tip3p_standard.xml'],
    small_molecule_forcefield='gaff-2.11',
    barostat=membrane_barostat,
    forcefield_kwargs=forcefield_kwargs,
    periodic_forcefield_kwargs=periodic_forcefield_kwargs)

system = system_generator.create_system(pdb.topology, molecules=molecule)
integrator = LangevinIntegrator(300 * kelvin, 1 / picosecond,
                                0.002 * picosecond)

platform = Platform.getPlatformByName('CUDA')

simulation = app.Simulation(pdb.topology, system, integrator, platform)
simulation.context.setPositions(pdb.positions)

simulation.loadState('parent.xml')
simulation.reporters.append(
    StateDataReporter('seg.nfo',

platform = openmm.Platform.getPlatformByName('OpenCL')
platform.setPropertyDefaultValue('Precision', 'mixed')

'''
---SYSTEM PREPARATION---
    setup AM1-BCC charges for the solute, add solvent, set non-bonded method etc
'''
ligand_mol = Molecule.from_file('ethanol.sdf', file_format='sdf')

forcefield_kwargs = {'constraints': app.HBonds, 'rigidWater': True, 'removeCMMotion': True, 'hydrogenMass': 4 * unit.amu }

system_generator = SystemGenerator(
    forcefields=['amber/ff14SB.xml', 'amber/tip4pew_standard.xml'],
    small_molecule_forcefield='gaff-2.11',
    molecules=[ligand_mol],
    forcefield_kwargs=forcefield_kwargs)

ligand_pdb = PDBFile('ethanol.pdb')

modeller = Modeller(ligand_pdb.topology, ligand_pdb.positions)

modeller.addSolvent(system_generator.forcefield, model='tip4pew', padding=12.0 * unit.angstroms)

system = system_generator.forcefield.createSystem(modeller.topology, nonbondedMethod=PME,
        nonbondedCutoff=9.0 * unit.angstroms, constraints=HBonds)

'''
---FINISHED SYSTEM PREPARATION---
'''
示例#28
0
class PDBLigandSystemBuilder:
    class Config(Config):
        __slots__ = ['pdb_file_name', 'ligand_file_name']

        def update(self, k, v):
            self.__dict__[k] = v

        def __init__(self, config_dict):
            self.relax_ligand = config_dict['relax_ligand']
            self.use_pdbfixer = config_dict['use_pdbfixer']
            self.tempdir = None
            self.method = config_dict['method']
            self.pdb_file_name = config_dict['pdb_file_name']
            self.ligand_file_name = config_dict['ligand_file_name']
            self.explicit = config_dict['explicit']
            self.config_dict = config_dict

        def get_obj(self):
            return PDBLigandSystemBuilder(self)

    def __init__(self, config_: Config):
        self.config = config_
        self.logger = make_message_writer(self.config.verbose, self.__class__.__name__)
        with self.logger("__init__") as logger:
            self.boxvec = None
            self.explicit = self.config.explicit
            self.system = None
            ofs = oechem.oemolistream(self.config.ligand_file_name)
            oemol = oechem.OEMol()
            oechem.OEReadMolecule(ofs, oemol)
            ofs.close()
            self.inital_ligand_smiles = oechem.OEMolToSmiles(oemol)
            self.params_written = 0
            self.mol = Molecule.from_openeye(oemol, allow_undefined_stereo=True)
            fixer = PDBFixer(self.config.pdb_file_name)
            
            if self.config.use_pdbfixer:
                logger.log("Fixing with PDBFixer")

                fixer.findMissingResidues()
                fixer.findNonstandardResidues()
                fixer.replaceNonstandardResidues()
                fixer.removeHeterogens(keepWater=False)
                fixer.findMissingAtoms()
                fixer.addMissingAtoms()
                fixer.addMissingHydrogens(7.0)



                logger.log("Found missing residues: ", fixer.missingResidues)
                logger.log("Found missing terminals residues: ", fixer.missingTerminals)
                logger.log("Found missing atoms:", fixer.missingAtoms)
                logger.log("Found nonstandard residues:", fixer.nonstandardResidues)


            self.config.pdb_file_name = f"{self.config.tempdir(main_context=True)}/inital_fixed.pdb"
            with open(self.config.pdb_file_name, 'w') as f:
                app.PDBFile.writeFile(fixer.topology, fixer.positions, f)
            cmd.reinitialize()
            cmd.load(self.config.pdb_file_name)
            cmd.load(self.config.ligand_file_name, "UNL")
            cmd.alter("UNL", "resn='UNL'")
            cmd.save("{}".format(self.config.pdb_file_name))

    def get_mobile(self):
        return len(self.pdb.positions)


    def __setup_system_ex_mm(self):
        with self.logger("__setup_system_ex_mm") as logger:
            if "openmm_system_generator" not in self.__dict__:
                amber_forcefields = ['amber/protein.ff14SB.xml', 'amber/phosaa10', 'amber/tip3p_standard.xml']
                small_molecule_forcefield = 'openff-1.1.0'
                # small_molecule_forcefield = 'gaff-2.11'
                self.openmm_system_generator = SystemGenerator(forcefields=amber_forcefields,
                                                               forcefield_kwargs=self.params,
                                                               molecules=[self.mol],
                                                               small_molecule_forcefield=small_molecule_forcefield,
                                                               )

            else:
                self.openmm_system_generator.add_molecules([self.mol])

            self.modeller = app.Modeller(self.topology, self.positions)
            self.modeller.addSolvent(self.openmm_system_generator.forcefield, model='tip3p',
                                     ionicStrength=100 * unit.millimolar, padding=1.0 * unit.nanometers)
            self.boxvec = self.modeller.getTopology().getPeriodicBoxVectors()
            self.topology, self.positions = self.modeller.getTopology(), self.modeller.getPositions()
            self.system = self.openmm_system_generator.create_system(self.topology)
            self.system.setDefaultPeriodicBoxVectors(*self.modeller.getTopology().getPeriodicBoxVectors())

            with open("{}".format(self.config.pdb_file_name), 'w') as f:
                app.PDBFile.writeFile(self.topology, self.positions, file=f, keepIds=True)
                logger.log("wrote ", "{}".format(self.config.pdb_file_name))
            with open("{}".format(self.config.pdb_file_name), 'r') as f:
                self.pdb = app.PDBFile(f)
        return self.system, self.topology, self.positions

    def __setup_system_ex_amber(self, pdbfile: str = None):
        with self.logger("__setup_system_ex_amber") as logger:
            try:
                with tempfile.TemporaryDirectory() as dirpath:
                    dirpath = self.config.tempdir()

                    # Move inital file over to new system.
                    shutil.copy(pdbfile, f"{dirpath}/init.pdb")

                    # Assign charges and extract new ligand
                    cmd.reinitialize()
                    cmd.load(f'{dirpath}/init.pdb')
                    cmd.remove("polymer")
                    cmd.remove("resn HOH or resn Cl or resn Na")
                    cmd.save(f'{dirpath}/lig.pdb')
                    cmd.save(f'{dirpath}/lig.mol2')
                    ifs = oechem.oemolistream(f'{dirpath}/lig.pdb')
                    oemol = oechem.OEMol()
                    oechem.OEReadMolecule(ifs, oemol)
                    ifs.close()
                    ofs = oechem.oemolostream()
                    oemol.SetTitle("UNL")
                    oechem.OEAddExplicitHydrogens(oemol)
                    oequacpac.OEAssignCharges(oemol, oequacpac.OEAM1BCCCharges())
                    if ofs.open(f'{dirpath}/charged.mol2'):
                        oechem.OEWriteMolecule(ofs, oemol)
                    ofs.close()

                    # remove hydrogens and ligand from PDB
                    cmd.reinitialize()
                    cmd.load(f'{dirpath}/init.pdb')
                    cmd.remove("not polymer")
                    cmd.remove("hydrogens")
                    cmd.save(f'{dirpath}/apo.pdb')

                    with working_directory(dirpath):
                        subprocess.run(
                            f'antechamber -i lig.pdb -fi pdb -o lig.mol2 -fo mol2 -pf y -an y -a charged.mol2 -fa mol2 -ao crg'.split(
                                " "), check=True, capture_output=True)
                        subprocess.run(f'parmchk2 -i lig.mol2 -f mol2 -o lig.frcmod'.split(" "), check=True,
                                       capture_output=True)
                        try:
                            subprocess.run('pdb4amber -i apo.pdb -o apo_new.pdb --reduce --dry'.split(" "), check=True,
                                           capture_output=True)
                        except subprocess.CalledProcessError as e:
                            logger.error("Known bug, pdb4amber returns error when there was no error", e.stdout, e.stderr)
                            pass

                        # Wrap tleap
                        with open('leap.in', 'w+') as leap:
                            leap.write("source leaprc.protein.ff14SB\n")
                            leap.write("source leaprc.water.tip4pew\n")
                            leap.write("source leaprc.phosaa10\n")
                            leap.write("source leaprc.gaff2\n")
                            leap.write("set default PBRadii mbondi3\n")
                            leap.write("rec = loadPDB apo_new.pdb # May need full filepath?\n")
                            leap.write("saveAmberParm rec apo.prmtop apo.inpcrd\n")
                            leap.write("lig = loadmol2 lig.mol2\n")
                            leap.write("loadAmberParams lig.frcmod\n")
                            leap.write("saveAmberParm lig lig.prmtop lig.inpcrd\n")
                            leap.write("com = combine {rec lig}\n")
                            leap.write("saveAmberParm com us_com.prmtop us_com.inpcrd\n")
                            leap.write("solvateBox com TIP4PEWBOX 12\n")
                            leap.write("addions com Na+ 5\n")
                            leap.write("addions com Cl- 5\n")
                            leap.write("saveAmberParm com com.prmtop com.inpcrd\n")
                            leap.write("quit\n")
                        try:
                            subprocess.run('tleap -f leap.in'.split(" "), check=True, capture_output=True)
                        except subprocess.CalledProcessError as e:
                            logger.error("tleap error", e.output.decode("UTF-8"))
                            exit()

                        prmtop = app.AmberPrmtopFile(f'com.prmtop')
                        inpcrd = app.AmberInpcrdFile(f'com.inpcrd')

                    for comp in ['us_com', 'com', 'apo', 'lig']:
                        for ext in ['prmtop', 'inpcrd']:
                            shutil.copy(f'{dirpath}/{comp}.{ext}',
                                        f"{self.config.tempdir()}/{comp}_{self.params_written}.{ext}")

                    self.system = prmtop.createSystem(**self.params)
                    if self.config.relax_ligand:
                        mod_parms = copy.deepcopy(self.params)
                        mod_parms['constraints'] = None
                        self._unconstrained_system = prmtop.createSystem(**mod_parms)
                    self.boxvec = self.system.getDefaultPeriodicBoxVectors()
                    self.topology, self.positions = prmtop.topology, inpcrd.positions
                    with open("{}".format(self.config.pdb_file_name), 'w') as f:
                        app.PDBFile.writeFile(self.topology, self.positions, file=f, keepIds=True)
                        logger.log("wrote ", "{}".format(self.config.pdb_file_name))
                    with open("{}".format(self.config.pdb_file_name), 'r') as f:
                        self.pdb = app.PDBFile(f)
                    self.params_written += 1

                    return self.system, self.topology, self.positions
            except Exception as e:
                logger.error("EXCEPTION CAUGHT BAD SPOT", e)

    def __setup_system_im(self, pdbfile: str = None):
        with self.logger("__setup_system_im") as logger:
            try:
                with tempfile.TemporaryDirectory() as dirpath:
                    dirpath = self.config.tempdir()

                    # Move inital file over to new system.
                    shutil.copy(pdbfile, f"{dirpath}/init.pdb")

                    # Assign charges and extract new ligand
                    cmd.reinitialize()
                    cmd.load(f'{dirpath}/init.pdb')
                    cmd.remove("polymer")
                    cmd.remove("resn HOH or resn Cl or resn Na")
                    cmd.save(f'{dirpath}/lig.pdb')
                    cmd.save(f'{dirpath}/lig.mol2')
                    ifs = oechem.oemolistream(f'{dirpath}/lig.pdb')
                    oemol = oechem.OEMol()
                    oechem.OEReadMolecule(ifs, oemol)
                    ifs.close()
                    ofs = oechem.oemolostream()
                    oemol.SetTitle("UNL")
                    oechem.OEAddExplicitHydrogens(oemol)
                    oequacpac.OEAssignCharges(oemol, oequacpac.OEAM1BCCCharges())
                    if ofs.open(f'{dirpath}/charged.mol2'):
                        oechem.OEWriteMolecule(ofs, oemol)
                    ofs.close()

                    # remove hydrogens and ligand from PDB
                    cmd.reinitialize()
                    cmd.load(f'{dirpath}/init.pdb')
                    cmd.remove("not polymer")
                    cmd.remove("hydrogens")
                    cmd.save(f'{dirpath}/apo.pdb')

                    with working_directory(dirpath):
                        subprocess.run(
                            f'antechamber -i lig.pdb -fi pdb -o lig.mol2 -fo mol2 -pf y -an y -a charged.mol2 -fa mol2 -ao crg'.split(
                                " "), check=True, capture_output=True)
                        subprocess.run(f'parmchk2 -i lig.mol2 -f mol2 -o lig.frcmod'.split(" "), check=True,
                                       capture_output=True)
                        try:
                            subprocess.run('pdb4amber -i apo.pdb -o apo_new.pdb --reduce --dry'.split(" "), check=True,
                                           capture_output=True)
                        except subprocess.CalledProcessError as e:
                            logger.error("Known bug, pdb4amber returns error when there was no error", e.stdout, e.stderr)
                            pass

                        # Wrap tleap
                        with open('leap.in', 'w+') as leap:
                            leap.write("source leaprc.protein.ff14SBonlysc\n")
                            leap.write("source leaprc.phosaa10\n")
                            leap.write("source leaprc.gaff2\n")
                            leap.write("set default PBRadii mbondi3\n")
                            leap.write("rec = loadPDB apo_new.pdb # May need full filepath?\n")
                            leap.write("saveAmberParm rec apo.prmtop apo.inpcrd\n")
                            leap.write("lig = loadmol2 lig.mol2\n")
                            leap.write("loadAmberParams lig.frcmod\n")
                            leap.write("saveAmberParm lig lig.prmtop lig.inpcrd\n")
                            leap.write("com = combine {rec lig}\n")
                            leap.write("saveAmberParm com com.prmtop com.inpcrd\n")
                            leap.write("quit\n")
                        try:
                            subprocess.run('tleap -f leap.in'.split(" "), check=True, capture_output=True)
                        except subprocess.CalledProcessError as e:
                            logger.error("tleap error", e.output.decode("UTF-8"))
                            exit()

                        prmtop = app.AmberPrmtopFile(f'com.prmtop')
                        inpcrd = app.AmberInpcrdFile(f'com.inpcrd')

                    for comp in ['com', 'apo', 'lig']:
                        for ext in ['prmtop', 'inpcrd']:
                            shutil.copy(f'{dirpath}/{comp}.{ext}',
                                        f"{self.config.tempdir()}/{comp}_{self.params_written}.{ext}")

                    self.system = prmtop.createSystem(**self.params)

                    if self.config.relax_ligand:
                        mod_parms = copy.deepcopy(self.params)
                        mod_parms['constraints'] = None
                        self._unconstrained_system = prmtop.createSystem(**mod_parms)
                    self.boxvec = self.system.getDefaultPeriodicBoxVectors()
                    self.topology, self.positions = prmtop.topology, inpcrd.positions
                    with open("{}".format(self.config.pdb_file_name), 'w') as f:
                        app.PDBFile.writeFile(self.topology, self.positions, file=f, keepIds=True)
                        logger.log("wrote ", "{}".format(self.config.pdb_file_name))
                    with open("{}".format(self.config.pdb_file_name), 'r') as f:
                        self.pdb = app.PDBFile(f)
                    self.params_written += 1

                    return self.system, self.topology, self.positions
            except Exception as e:
                logger.error("EXCEPTION CAUGHT BAD SPOT", e)

    def get_system(self, params):
        """

        :param params:
        :return:
        """
        with self.logger("get_system") as logger:
            self.params = params

            logger.log("Loading inital system", self.config.pdb_file_name)
            self.pdb = app.PDBFile(self.config.pdb_file_name)
            self.topology, self.positions = self.pdb.topology, self.pdb.positions

            if self.config.explicit and self.config.method == 'amber':
                self.system, self.topology, self.positions = self.__setup_system_ex_amber(
                    pdbfile=self.config.pdb_file_name)
            elif self.config.explicit:
                self.system, self.topology, self.positions = self.__setup_system_ex_mm()
            else:
                self.system, self.topology, self.positions = self.__setup_system_im(pdbfile=self.config.pdb_file_name)

        return self.system

    def reload_system(self, ln: str, smis: oechem.OEMol, old_pdb: str, is_oe_already: bool = False):
        with self.logger("reload_system") as logger:
            logger.log("Loading {} with new smiles {}".format(old_pdb, ln))
            with tempfile.TemporaryDirectory() as dirpath:
                ofs = oechem.oemolostream("{}/newlig.mol2".format(dirpath))
                oechem.OEWriteMolecule(ofs, smis)
                ofs.close()
                cmd.reinitialize()
                cmd.load(old_pdb)
                cmd.remove("not polymer")
                cmd.load("{}/newlig.mol2".format(dirpath), "UNL")
                cmd.alter("UNL", "resn='UNL'")
                cmd.alter("UNL", "chain='A'")
                self.config.pdb_file_name = self.config.tempdir() + "reloaded.pdb"
                cmd.save(self.config.pdb_file_name)
                cmd.save(self.config.tempdir() + "apo.pdb")

                with open(self.config.pdb_file_name, 'r') as f:
                    self.pdb = app.PDBFile(f)
                self.positions, self.topology = self.pdb.getPositions(), self.pdb.getTopology()

                if self.config.explicit and self.config.method == 'amber':
                    self.system, self.topology, self.positions = self.__setup_system_ex_amber(
                        pdbfile=self.config.pdb_file_name)
                elif self.config.explicit:
                    self.system, self.topology, self.positions = self.__setup_system_ex_mm()
                else:
                    self.system, self.topology, self.positions = self.__setup_system_im( pdbfile=self.config.pdb_file_name)

        return self.system

    def get_selection_ids(self, select_cmd):
        with tempfile.TemporaryDirectory() as dirname:
            with open(f'{dirname}/get_selection_ids.pdb', 'w') as f:
                app.PDBFile.writeFile(self.get_topology(),
                                      self.get_positions(),
                                      file=f)
            cmd.reinitialize()
            cmd.load(f'{dirname}/get_selection_ids.pdb', format='pdb')
            cmd.select("sele", select_cmd)
            stored.ids = list()
            cmd.iterate("sele", expression="stored.ids.append(ID)")
            ids = [int(i - 1) for i in list(stored.ids)]
        return ids

    def get_selection_solvent(self):
        ids = [i - 2 for i in self.get_selection_ids("not polymer and not (resn UNL)")]
        if len(ids) == 0:
            return []
        if not ((min(ids) >= 0) and (max(ids) < len(self.positions))):
            self.logger.static_failure("get_selection_solvent", min(ids), max(ids), len(self.positions), exit_all=True)
        return ids

    def get_selection_ligand(self):
        ids = [i for i in self.get_selection_ids("resn UNL")]
        if len(ids) == 0:
            return []
        if not ((min(ids) >= 0) and (max(ids) < len(self.positions))):
            self.logger.static_failure("get_selection_ligand", min(ids), max(ids), len(self.positions), exit_all=True)
        return ids

    def get_selection_protein(self):
        ids = self.get_selection_ids("polymer")
        if len(ids) == 0:
            return []
        if not ((min(ids) >= 0) and (max(ids) < len(self.positions))):
            self.logger.static_failure("get_selection_protein", min(ids), max(ids), len(self.positions), exit_all=True)
        return ids

    def get_topology(self):
        return self.topology

    def get_positions(self):
        return self.positions
示例#29
0
    receptor_structure = parmed.load_file(receptor_file)
    ligand_structure = parmed.load_file(
        f'{output_prefix}/LIG{ligand_ndx}_h.pdb')
    complex_structure = receptor_structure + ligand_structure

    barostat = openmm.MonteCarloBarostat(pressure, temperature)
    forcefield_kwargs = {
        'removeCMMotion': False,
        'ewaldErrorTolerance': 5e-04,
        'nonbondedMethod': app.PME,
        'constraints': None,
        'rigidWater': False
    }
    system_generator = SystemGenerator(
        forcefields=[protein_forcefield, solvation_forcefield],
        barostat=barostat,
        forcefield_kwargs=forcefield_kwargs,
        molecules=[ligand],
        small_molecule_forcefield=small_molecule_forcefield)

    modeller = app.Modeller(complex_structure.topology,
                            complex_structure.positions)
    modeller.addSolvent(system_generator.forcefield,
                        model='tip3p',
                        padding=solvent_padding,
                        ionicStrength=ionic_strength)

    system = system_generator.create_system(modeller.topology)
    solvated_structure = parmed.openmm.load_topology(modeller.topology,
                                                     system,
                                                     xyz=modeller.positions)
 def test_create(self):
     """Test SystemGenerator creation with only OpenMM ffxml force fields"""
     # Create an empty system generator
     generator = SystemGenerator()