コード例 #1
0
    def serialise_system(self):
        """Create the OpenMM system; parametrise using frost; serialise the system."""

        # Load the molecule using openforcefield
        pdb_file = app.PDBFile(f'{self.molecule.name}.pdb')

        # Now we need the connection info try using smiles string from rdkit
        rdkit = RDKit()
        molecule = Molecule.from_smiles(
            rdkit.get_smiles(f'{self.molecule.name}.pdb'))

        # Make the openMM system
        omm_topology = pdb_file.topology
        off_topology = Topology.from_openmm(omm_topology,
                                            unique_molecules=[molecule])

        # Load the smirnoff99Frosst force field.
        forcefield = ForceField('test_forcefields/smirnoff99Frosst.offxml')

        # Parametrize the topology and create an OpenMM System.
        system = forcefield.create_openmm_system(off_topology)

        # Serialise the OpenMM system into the xml file
        with open('serialised.xml', 'w+') as out:
            out.write(XmlSerializer.serializeSystem(system))
コード例 #2
0
def min_ffxml(mol, ffxml):

    # make copy of the input mol
    oe_mol = oechem.OEGraphMol(mol)

    try:
        # create openforcefield molecule ==> prone to triggering Exception
        off_mol = Molecule.from_openeye(oe_mol)

        # load in force field
        ff = ForceField(ffxml)

        # create components for OpenMM system
        topology = Topology.from_molecules(molecules=[off_mol])

        # create openmm system ==> prone to triggering Exception
        #system = ff.create_openmm_system(topology, charge_from_molecules=[off_mol])
        system = ff.create_openmm_system(topology)

    except Exception as e:
        smilabel = oechem.OEGetSDData(oe_mol, "SMILES QCArchive")
        print( ' >>> openforcefield failed to create OpenMM system: '
               f"'{oe_mol.GetTitle()}' '{smilabel}'")
        print(f"{e}\n")
        return

    print(" >>> successful OpenMM system creation for openforcefield "
         f"mol \"{oe_mol.GetTitle()}\"")
コード例 #3
0
def minimise_energy_all_confs(mol, models = None, epsilon = 4, allow_undefined_stereo = True, **kwargs ):
    from simtk import unit
    from simtk.openmm import LangevinIntegrator
    from simtk.openmm.app import Simulation, HBonds, NoCutoff
    from rdkit import Chem
    from rdkit.Geometry import Point3D
    import mlddec
    import copy
    import tqdm
    mol = Chem.AddHs(mol, addCoords = True)

    if models is None:
        models  = mlddec.load_models(epsilon)
    charges = mlddec.get_charges(mol, models)

    from openforcefield.utils.toolkits import RDKitToolkitWrapper, ToolkitRegistry
    from openforcefield.topology import Molecule, Topology
    from openforcefield.typing.engines.smirnoff import ForceField
    # from openforcefield.typing.engines.smirnoff.forcefield import PME

    import parmed
    import numpy as np

    forcefield = ForceField(get_data_filename("modified_smirnoff99Frosst.offxml")) #FIXME better way of identifying file location

    tmp = copy.deepcopy(mol)
    tmp.RemoveAllConformers() #XXX workround for speed beacuse seemingly openforcefield records all conformer informations, which takes a long time. but I think this is a ill-practice

    molecule = Molecule.from_rdkit(tmp, allow_undefined_stereo = allow_undefined_stereo)
    molecule.partial_charges = unit.Quantity(np.array(charges), unit.elementary_charge)
    topology = Topology.from_molecules(molecule)
    openmm_system = forcefield.create_openmm_system(topology, charge_from_molecules= [molecule])

    structure = parmed.openmm.topsystem.load_topology(topology.to_openmm(), openmm_system)


    system = structure.createSystem(nonbondedMethod=NoCutoff, nonbondedCutoff=1*unit.nanometer, constraints=HBonds)

    integrator = LangevinIntegrator(273*unit.kelvin, 1/unit.picosecond, 0.002*unit.picoseconds)
    simulation = Simulation(structure.topology, system, integrator)

    out_mol = copy.deepcopy(mol)
    for i in tqdm.tqdm(range(out_mol.GetNumConformers())):
        conf = mol.GetConformer(i)
        structure.coordinates =  unit.Quantity(np.array([np.array(conf.GetAtomPosition(i)) for i in range(mol.GetNumAtoms())]), unit.angstroms)

        simulation.context.setPositions(structure.positions)

        simulation.minimizeEnergy()
        # simulation.step(1)

        coords = simulation.context.getState(getPositions = True).getPositions(asNumpy = True).value_in_unit(unit.angstrom)
        conf = out_mol.GetConformer(i)
        for j in range(out_mol.GetNumAtoms()):
            conf.SetAtomPosition(j, Point3D(*coords[j]))

    return out_mol
コード例 #4
0
def build_context(offxml, molfile):
    """ Build an OpenMM Context from a offxml file and a molecule file """
    forcefield = ForceField(offxml, allow_cosmetic_attributes=True)
    molecule = OffMolecule.from_file(molfile)
    system = forcefield.create_openmm_system(molecule.to_topology())
    integrator = openmm.VerletIntegrator(1.0 * unit.femtoseconds)
    platform = openmm.Platform.getPlatformByName('Reference')
    context = openmm.Context(system, integrator, platform)
    return context
コード例 #5
0
ファイル: smirnoff.py プロジェクト: nhenriksen/speakeasy
def create_openmm_system(conversion, molecules):
    """
    Create an OpenMM system using the input MOL2 file and force field file.
    """

    molecule = Molecule.from_openeye(molecules[0])
    topology = Topology.from_molecules([molecule])
    ff = ForceField(conversion.ff)
    system = ff.create_openmm_system(topology)

    return topology, system
コード例 #6
0
def _create_impropers_only_system(
    smiles: str = "CC1=C(C(=O)C2=C(C1=O)N3CC4C(C3(C2COC(=O)N)OC)N4)N",
) -> mm.System:
    """Create a simulation that contains only improper torsion terms,
    by parameterizing with openff-1.2.0 and deleting  all terms but impropers
    """

    molecule = Molecule.from_smiles(smiles, allow_undefined_stereo=True)
    g = esp.Graph(molecule)

    topology = Topology.from_molecules(molecule)
    forcefield = ForceField("openff-1.2.0.offxml")
    openmm_system = forcefield.create_openmm_system(topology)

    # delete all forces except PeriodicTorsionForce
    is_torsion = (
        lambda force: "PeriodicTorsionForce" in force.__class__.__name__)
    for i in range(openmm_system.getNumForces())[::-1]:
        if not is_torsion(openmm_system.getForce(i)):
            openmm_system.removeForce(i)
    assert openmm_system.getNumForces() == 1
    torsion_force = openmm_system.getForce(0)
    assert is_torsion(torsion_force)

    # set k = 0 for any torsion that's not an improper
    indices = set(
        map(
            tuple,
            esp.graphs.utils.offmol_indices.improper_torsion_indices(molecule),
        ))
    num_impropers_retained = 0
    for i in range(torsion_force.getNumTorsions()):
        (
            p1,
            p2,
            p3,
            p4,
            periodicity,
            phase,
            k,
        ) = torsion_force.getTorsionParameters(i)

        if (p1, p2, p3, p4) in indices:
            num_impropers_retained += 1
        else:
            torsion_force.setTorsionParameters(i, p1, p2, p3, p4, periodicity,
                                               phase, 0.0)

    assert (num_impropers_retained > 0
            )  # otherwise this molecule is not a useful test case!

    return openmm_system, topology, g
コード例 #7
0
ファイル: smirnoff.py プロジェクト: nhenriksen/speakeasy
def create_openmm_system_from_smiles(conversion, smiles):
    """
    Create an OpenMM system using SMILES and force field file.
    """

    molecule = Molecule.from_smiles(smiles)
    topology = Topology.from_molecules([molecule])
    ff = ForceField(conversion.ff)
    system = ff.create_openmm_system(topology)

    molecule.generate_conformers(n_conformers=1)

    return topology, system
コード例 #8
0
def min_ffxml(mol, ofs, ffxml):
    """
    Minimize the mol with force field input from FFXML file.

    Parameters
    ----------
    mol : OpenEye single-conformer molecule
    ofs : OpenEye output filestream
    ffxml : string
        name of FFXML file

    """

    # make copy of the input mol
    oe_mol = oechem.OEGraphMol(mol)

    try:
        # create openforcefield molecule ==> prone to triggering Exception
        off_mol = Molecule.from_openeye(oe_mol)

        # load in force field
        ff = ForceField(ffxml)

        # create components for OpenMM system
        topology = Topology.from_molecules(molecules=[off_mol])

        # create openmm system ==> prone to triggering Exception
        #system = ff.create_openmm_system(topology, charge_from_molecules=[off_mol])
        system = ff.create_openmm_system(topology)

    except Exception as e:
        smilabel = oechem.OEGetSDData(oe_mol, "SMILES QCArchive")
        print( ' >>> openforcefield failed to create OpenMM system: '
               f'{oe_mol.GetTitle()} {smilabel}: {e}')
        return

    positions = structure.extractPositionsFromOEMol(oe_mol)

    # minimize structure with ffxml
    newpos, energy = run_openmm(topology, system, positions)

    # save geometry, save energy as tag, write mol to file
    oe_mol.SetCoords(oechem.OEFloatArray(newpos))
    oechem.OESetSDData(oe_mol, "Energy FFXML", str(energy))
    oechem.OEWriteConstMolecule(ofs, oe_mol)

    return
コード例 #9
0
    def _rdkit_parameteriser(cls, mol, **kwargs):
        from rdkit import Chem
        from openforcefield.utils.toolkits import RDKitToolkitWrapper, ToolkitRegistry
        """
        Creates a parameterised system from rdkit molecule

        Parameters
        ----------
        mol : rdkit.Chem.Mol
        """

        try:
            forcefield = ForceField('test_forcefields/smirnoff99Frosst.offxml')
            molecule = Molecule.from_rdkit(
                mol, allow_undefined_stereo=cls.allow_undefined_stereo)
            if hasattr(cls, "_ddec_charger"):
                molecule.partial_charges = unit.Quantity(
                    np.array(cls._ddec_charger(mol, cls.rf)),
                    unit.elementary_charge)
            else:
                from openforcefield.utils.toolkits import AmberToolsToolkitWrapper
                molecule.compute_partial_charges_am1bcc(
                    toolkit_registry=AmberToolsToolkitWrapper())

            topology = Topology.from_molecules(molecule)
            openmm_system = forcefield.create_openmm_system(
                topology, charge_from_molecules=[molecule])

            ligand_pmd = parmed.openmm.topsystem.load_topology(
                topology.to_openmm(), openmm_system, molecule._conformers[0])
        except Exception as e:
            raise ValueError("Parameterisation Failed : {}".format(e))  #TODO

        ligand_pmd.title = cls.smiles

        for i in ligand_pmd.residues:
            i.name = 'LIG'

        tmp_dir = tempfile.mkdtemp()
        # We need all molecules as both pdb files (as packmol input)
        # and mdtraj.Trajectory for restoring bonds later.
        pdb_filename = tempfile.mktemp(suffix=".pdb", dir=tmp_dir)
        Chem.MolToPDBFile(mol, pdb_filename)
        cls.pdb_filename = pdb_filename
        cls.ligand_pmd = ligand_pmd
コード例 #10
0
    def __init__(self, dihedral_benchmark):
        """
        It initializes an OpenMMEnergeticProfile object.

        Parameters
        ----------
        dihedral_benchmark : an peleffybenchmarktools.dihedrals.DihedralBenchmark object
            The DihedralBenchmark object that will be used to obtain the
            energetic profile
        """
        super().__init__(dihedral_benchmark)

        from openforcefield.typing.engines.smirnoff import ForceField

        mol = self.dihedral_benchmark.molecule
        ff = ForceField(mol.forcefield + '.offxml')
        self._omm_top = mol.off_molecule.to_topology()
        self._omm_system = ff.create_openmm_system(self._omm_top)
コード例 #11
0
def main():
    parser = argparse.ArgumentParser(description='Parameterizes a small \
                                     molecule ligand for use with OpenMM \
                                     using OpenFF')
    parser.add_argument('-l',
                        '--ligand',
                        action='store',
                        nargs=1,
                        dest='ligand',
                        help='The ligand .sdf file to generate \
                        parameters for')
    parser.add_argument('-i',
                        '--input_directory',
                        action='store',
                        nargs=1,
                        dest='input',
                        default=['./'],
                        help='Directory where \
                        input pdb files are stored')
    parser.add_argument('-o',
                        '--output_directory',
                        action='store',
                        nargs=1,
                        dest='output',
                        default=['./'],
                        help='Directory where \
                        output log should be written')
    args = vars(parser.parse_args())

    #Load SDF file from minimize_lig.py
    lig_sdf = args['input'][0] + '/' + args['ligand'][0]
    lig_name = lig_sdf.split('.sdf')[-2]

    lig_off_molecule = Molecule(args['output'][0] + '/' + lig_sdf)
    force_field = ForceField('test_forcefields/smirnoff99Frosst.offxml')
    start = time.time()
    ligand_system = force_field.create_openmm_system(
        lig_off_molecule.to_topology())
    end = time.time()
    print(end - start)

    with open(lig_name + '.xml', 'w') as f:
        f.write(XmlSerializer.serialize(ligand_system))
コード例 #12
0
def generateSMIRNOFFStructureRDK(ligand_file):
    """
	Given an RDKit molecule, create an OpenMM System and use to
	generate a ParmEd structure using the SMIRNOFF forcefield parameters.
	"""
    if ligand_file.endswith('.mol'):
        new_file = ligand_file.replace('.mol', '.sdf')
        shutil.copyfile(ligand_file, new_file)
        ligand_file = new_file
    ligand_off_molecule = Molecule.from_file(ligand_file)
    force_field = ForceField('test_forcefields/smirnoff99Frosst.offxml')
    ligand_system = force_field.create_openmm_system(
        ligand_off_molecule.to_topology())
    # Read in the coordinates of the ligand from the PDB file
    Chem.MolToPDBFile(Chem.MolFromMolFile(ligand_file, removeHs=False),
                      "ligand.pdb")
    ligand_pdbfile = PDBFile("ligand.pdb")
    # Convert OpenMM System object containing ligand parameters into a ParmEd Structure.
    ligand_structure = parmed.openmm.load_topology(
        ligand_pdbfile.topology, ligand_system, xyz=ligand_pdbfile.positions)
    return ligand_structure
コード例 #13
0
def test_merge_system():
    """Test merging of a system created from AMBER and another created from SMIRNOFF."""
    from .utils import create_system_from_amber, get_amber_file_path, get_alkethoh_file_path

    # Create System from AMBER
    prmtop_filename, inpcrd_filename = get_amber_file_path(
        'cyclohexane_ethanol_0.4_0.6')
    system0, topology0, positions0 = create_system_from_amber(
        prmtop_filename, inpcrd_filename)

    # TODO:
    from openeye import oechem
    # Load simple OEMol
    alkethoh_mol2_filepath = get_alkethoh_file_path('AlkEthOH_c100')[0]
    ifs = oechem.oemolistream(alkethoh_mol2_filepath)
    mol = oechem.OEMol()
    flavor = oechem.OEIFlavor_Generic_Default | oechem.OEIFlavor_MOL2_Default | oechem.OEIFlavor_MOL2_Forcefield
    ifs.SetFlavor(oechem.OEFormat_MOL2, flavor)
    oechem.OEReadMolecule(ifs, mol)
    oechem.OETriposAtomNames(mol)

    # Load forcefield file.
    AlkEthOH_offxml_filename = utils.get_data_file_path(
        'test_forcefields/Frosst_AlkEthOH.offxml')
    forcefield = ForceField(AlkEthOH_offxml_filename)

    # Create OpenMM System and Topology.
    off_mol = Molecule.from_openeye(mol, allow_undefined_stereo=True)
    off_top = Topology.from_molecules([off_mol])
    system1 = forcefield.create_openmm_system(off_top)
    topology1 = structure.generateTopologyFromOEMol(mol)
    positions1 = structure.extractPositionsFromOEMol(mol)

    structure.merge_system(topology0,
                           topology1,
                           system0,
                           system1,
                           positions0,
                           positions1,
                           verbose=True)
コード例 #14
0
def generateSMIRNOFFStructure(oemol):
    """
    Given an OpenEye molecule (oechem.OEMol), create an OpenMM System and use to
    generate a ParmEd structure using the SMIRNOFF forcefield parameters.

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

    Returns
    -------
    molecule_structure : parmed.Structure
        The resulting Structure

    """
    warnings.warn(DEPRECATION_WARNING_TEXT, PendingDeprecationWarning)
    from openforcefield.topology import Molecule, Topology
    from openforcefield.typing.engines.smirnoff import ForceField

    off_mol = Molecule.from_openeye(oemol)
    off_top = Topology.from_molecules([off_mol])
    mol_ff = ForceField('test_forcefields/smirnoff99Frosst.offxml')

    # Create OpenMM System and Topology.
    omm_top = generateTopologyFromOEMol(oemol)

    # If it's a nonperiodic box, then we can't use default (PME) settings
    if omm_top.getPeriodicBoxVectors() is None:
        mol_ff.get_parameter_handler("Electrostatics", {})._method = 'Coulomb'

    system = mol_ff.create_openmm_system(off_top)

    # Convert to ParmEd structure.
    import parmed
    xyz = extractPositionsFromOEMol(oemol)
    molecule_structure = parmed.openmm.load_topology(omm_top, system, xyz=xyz)

    return molecule_structure
コード例 #15
0
    def _openeye_parameteriser(cls, mol, **kwargs):
        """
        Creates a parameterised system from openeye molecule

        Parameters
        ----------
        mol : oechem.OEMol
        """
        try:
            forcefield = ForceField('test_forcefields/smirnoff99Frosst.offxml')
            molecule = Molecule.from_openeye(
                mol, allow_undefined_stereo=cls.allow_undefined_stereo)
            from openforcefield.utils.toolkits import OpenEyeToolkitWrapper
            molecule.compute_partial_charges_am1bcc(
                toolkit_registry=OpenEyeToolkitWrapper())

            topology = Topology.from_molecules(molecule)
            openmm_system = forcefield.create_openmm_system(
                topology, charge_from_molecules=[molecule])

            ligand_pmd = parmed.openmm.topsystem.load_topology(
                topology.to_openmm(), openmm_system, molecule._conformers[0])
        except Exception as e:
            raise ValueError("Parameterisation Failed : {}".format(e))  #TODO

        ligand_pmd.title = cls.smiles

        for i in ligand_pmd.residues:
            i.name = 'LIG'

        tmp_dir = tempfile.mkdtemp()
        # We need all molecules as both pdb files (as packmol input)
        # and mdtraj.Trajectory for restoring bonds later.
        pdb_filename = tempfile.mktemp(suffix=".pdb", dir=tmp_dir)
        from openeye import oechem  # OpenEye Python toolkits
        oechem.OEWriteMolecule(oechem.oemolostream(pdb_filename), mol)
        cls.pdb_filename = pdb_filename
        cls.ligand_pmd = ligand_pmd
コード例 #16
0
def test_component_combination():
    """Test that a system still yields the same energy after rebuilding it out of its components
    """
    from simtk import openmm
    from .utils import compare_system_energies, get_packmol_pdb_file_path

    # We've had issues where subsequent instances of a molecule might have zero charges
    # Here we'll try to catch this (and also explicitly check the charges) by re-building
    # a system out of its components

    # Create an OpenMM System from mol2 files containing a cyclohexane-ethanol mixture.
    AlkEthOH_offxml_filename = utils.get_data_file_path(
        'test_forcefields/Frosst_AlkEthOH.offxml')
    forcefield = ForceField(AlkEthOH_offxml_filename)
    pdbfile = openmm.app.PDBFile(
        get_packmol_pdb_file_path('cyclohexane_ethanol_0.4_0.6'))
    sdf_file_paths = [
        utils.get_data_file_path(
            os.path.join('systems', 'monomers', name + '.sdf'))
        for name in ('ethanol', 'cyclohexane')
    ]
    molecules = [Molecule.from_file(file_path) for file_path in sdf_file_paths]
    topology = Topology.from_openmm(pdbfile.topology,
                                    unique_molecules=molecules)
    system = forcefield.create_openmm_system(topology)

    # Convert System to a ParmEd Structure
    structure = parmed.openmm.topsystem.load_topology(topology.to_openmm(),
                                                      system,
                                                      pdbfile.positions)

    # Split the Structure into components, then re-compose it out of its components
    tmp = structure.split()
    strs, nums = [], []
    for s, n in tmp:
        strs.append(s)
        nums.append(n)
    nums = [len(n) for n in nums]

    # Re-compose Structure from components
    new_structure = strs[0] * nums[0]
    for idx in range(1, len(nums)):
        new_structure += strs[idx] * nums[idx]
    # Swap in coordinates again
    new_structure.positions = structure.positions

    # Create System
    newsys = new_structure.createSystem(nonbondedMethod=openmm.app.NoCutoff,
                                        constraints=None,
                                        implicitSolvent=None)

    # Cross check energies
    groups0, groups1, energy0, energy1 = compare_system_energies(
        pdbfile.topology,
        pdbfile.topology,
        system,
        newsys,
        pdbfile.positions,
        verbose=False)

    # Also check that that the number of components is equal to the number I expect
    if not len(nums) == 2:
        print("Error: Test system has incorrect number of components.")
        raise Exception(
            'Incorrect number of components in cyclohexane/ethanol test system.'
        )

    # Also check that none of residues have zero charge
    for resnr in range(len(structure.residues)):
        abscharges = [
            abs(structure.residues[resnr].atoms[idx].charge)
            for idx in range(len(structure.residues[resnr].atoms))
        ]
        if sum(abscharges) == 0:
            raise Exception(
                'Error: Residue %s in cyclohexane-ethanol test system has a charge of zero, which is incorrect.'
                % resnr)
コード例 #17
0
    def _build_reduced_system(self, original_force_field, topology, scale_amount=None):
        """Produces an OpenMM system containing only forces for the specified parameter,
         optionally perturbed by the amount specified by `scale_amount`.

        Parameters
        ----------
        original_force_field: openforcefield.typing.engines.smirnoff.ForceField
            The force field to create the system from (and optionally perturb).
        topology: openforcefield.topology.Topology
            The topology of the system to apply the force field to.
        scale_amount: float, optional
            The optional amount to perturb the parameter by.

        Returns
        -------
        simtk.openmm.System
            The created system.
        simtk.unit.Quantity
            The new value of the perturbed parameter.
        """
        # As this method deals mainly with the toolkit, we stick to
        # simtk units here.
        from openforcefield.typing.engines.smirnoff import ForceField

        parameter_tag = self.parameter_key.tag
        parameter_smirks = self.parameter_key.smirks
        parameter_attribute = self.parameter_key.attribute

        original_handler = original_force_field.get_parameter_handler(parameter_tag)
        original_parameter = original_handler.parameters[parameter_smirks]

        if self.use_subset_of_force_field:

            force_field = ForceField()
            handler = copy.deepcopy(original_force_field.get_parameter_handler(parameter_tag))
            force_field.register_parameter_handler(handler)

        else:

            force_field = copy.deepcopy(original_force_field)
            handler = force_field.get_parameter_handler(parameter_tag)

        parameter_index = None
        value_list = None

        if hasattr(original_parameter, parameter_attribute):
            parameter_value = getattr(original_parameter, parameter_attribute)
        else:
            attribute_split = re.split(r'(\d+)', parameter_attribute)

            assert len(parameter_attribute) == 2
            assert hasattr(original_parameter, attribute_split[0])

            parameter_attribute = attribute_split[0]
            parameter_index = int(attribute_split[1]) - 1

            value_list = getattr(original_parameter, parameter_attribute)
            parameter_value = value_list[parameter_index]

        if scale_amount is not None:

            existing_parameter = handler.parameters[parameter_smirks]

            if np.isclose(parameter_value.value_in_unit(parameter_value.unit), 0.0):
                # Careful thought needs to be given to this. Consider cases such as
                # epsilon or sigma where negative values are not allowed.
                parameter_value = (scale_amount if scale_amount > 0.0 else 0.0) * parameter_value.unit
            else:
                parameter_value *= (1.0 + scale_amount)

            if value_list is None:
                setattr(existing_parameter, parameter_attribute, parameter_value)
            else:
                value_list[parameter_index] = parameter_value
                setattr(existing_parameter, parameter_attribute, value_list)

        system = force_field.create_openmm_system(topology)

        if not self.enable_pbc:
            disable_pbc(system)

        return system, parameter_value
コード例 #18
0
        Chem.rdmolops.AssignAtomChiralTagsFromStructure(
            rdkit_mol_h
        )  #very important, else you'll repeat the errors from before

        AllChem.ComputeGasteigerCharges(
            rdkit_mol_h
        )  #thats not at all mandatory nore recommended. It's just to go faster here. Don't do that in your code !!!

        try:
            #here is where the magic happens
            mol = Molecule.from_rdkit(
                rdkit_mol_h)  #create a openff molecule from the rdkit one
            top = mol.to_topology()  #extract the topology

            ligand_system = force_field.create_openmm_system(
                top, charge_from_molecules=[mol]
            )  #create our openmm system (that's the simplest version here)

            #classical setup of an openmm simulation
            #here we'll do just a bit of minimization
            integrator = openmm.LangevinIntegrator(300 * unit.kelvin,
                                                   91 / unit.picosecond,
                                                   0.002 * unit.picoseconds)
            simulation = openmm.app.Simulation(top, ligand_system, integrator)
            simulation.context.setPositions(mol.conformers[0])
            print("     starting minimization")
            state = simulation.context.getState(getEnergy=True, getForces=True)
            print('     Starting pot energy:', state.getPotentialEnergy())
            simulation.minimizeEnergy(tolerance=0, maxIterations=10000)
            state = simulation.context.getState(getPositions=True,
                                                getEnergy=True,
コード例 #19
0
    def serialise_system(self):
        """Create the OpenMM system; parametrise using frost; serialise the system."""

        # Create an openFF molecule from the rdkit molecule
        off_molecule = Molecule.from_rdkit(self.molecule.rdkit_mol,
                                           allow_undefined_stereo=True)

        # Make the OpenMM system
        off_topology = off_molecule.to_topology()

        # Load the smirnoff99Frosst force field.
        forcefield = ForceField('test_forcefields/smirnoff99Frosst.offxml')

        try:
            # Parametrize the topology and create an OpenMM System.
            system = forcefield.create_openmm_system(off_topology)
        except (UnassignedValenceParameterException, TypeError,
                UnassignedValenceParameterException):
            # If this does not work then we have a moleucle that is not in SMIRNOFF so we must add generics
            # and remove the charge handler to get some basic parameters for the moleucle
            new_bond = BondHandler.BondType(
                smirks='[*:1]~[*:2]',
                length="0 * angstrom",
                k="0.0 * angstrom**-2 * mole**-1 * kilocalorie")
            new_angle = AngleHandler.AngleType(
                smirks='[*:1]~[*:2]~[*:3]',
                angle="0.0 * degree",
                k="0.0 * mole**-1 * radian**-2 * kilocalorie")
            new_torsion = ProperTorsionHandler.ProperTorsionType(
                smirks='[*:1]~[*:2]~[*:3]~[*:4]',
                periodicity1="1",
                phase1="0.0 * degree",
                k1="0.0 * mole**-1 * kilocalorie",
                periodicity2="2",
                phase2="180.0 * degree",
                k2="0.0 * mole**-1 * kilocalorie",
                periodicity3="3",
                phase3="0.0 * degree",
                k3="0.0 * mole**-1 * kilocalorie",
                periodicity4="4",
                phase4="180.0 * degree",
                k4="0.0 * mole**-1 * kilocalorie",
                idivf1="1.0",
                idivf2="1.0",
                idivf3="1.0",
                idivf4="1.0")

            new_vdw = vdWHandler.vdWType(smirks='[*:1]',
                                         epsilon=0 *
                                         unit.kilocalories_per_mole,
                                         sigma=0 * unit.angstroms)
            new_generics = {
                'Bonds': new_bond,
                'Angles': new_angle,
                'ProperTorsions': new_torsion,
                'vdW': new_vdw
            }
            for key, val in new_generics.items():
                forcefield.get_parameter_handler(key).parameters.insert(0, val)

            # This has to be removed as sqm will fail with unknown elements
            del forcefield._parameter_handlers['ToolkitAM1BCC']

            # Parametrize the topology and create an OpenMM System.
            system = forcefield.create_openmm_system(off_topology)
            # This will tag the molecule so run.py knows that generics have been used.
            self.fftype = 'generics'

        # Serialise the OpenMM system into the xml file
        with open('serialised.xml', 'w+') as out:
            out.write(XmlSerializer.serializeSystem(system))
コード例 #20
0
ファイル: sample.py プロジェクト: Discngine/3d-editor
async def run(io):
    print(dir(parmed))
    if not os.path.exists(datapath +
                          'complex.xml') or not os.path.exists(datapath +
                                                               'complex.pdb'):
        print('1: loading Ligand molecule')
        ligand_off_molecule = Molecule(datapath + 'ligand.sdf')

        # Load the SMIRNOFF-format Parsley force field

        #force_field = ForceField('openff_unconstrained-1.0.0.offxml')
        print("2: Loading the Force Field")
        force_field = ForceField('openff_unconstrained-1.2.0.offxml')

        # Parametrize the ligand molecule by creating a Topology object from it
        print("3: Create Ligand System")
        ligand_system = force_field.create_openmm_system(
            ligand_off_molecule.to_topology())
        # Read in the coordinates of the ligand from the PDB file
        ligand_pdbfile = PDBFile(datapath + 'ligand.pdb')

        # Convert OpenMM System object containing ligand parameters into a ParmEd Structure.
        print("4: Transforming Ligand System to Parmed")
        ligand_structure = parmed.openmm.load_topology(
            ligand_pdbfile.topology,
            ligand_system,
            xyz=ligand_pdbfile.positions)

        print("5: Loading the protein pdb file")
        receptor_pdbfile = PDBFile(datapath + 'receptor.pdb')

        # Load the AMBER protein force field through OpenMM.
        omm_forcefield = app.ForceField('amber14-all.xml')

        # Parameterize the protein.
        print("6: Create protein system")
        receptor_system = omm_forcefield.createSystem(
            receptor_pdbfile.topology)

        # Convert the protein System into a ParmEd Structure.
        print("7: Convert protein system to parmed")
        receptor_structure = parmed.openmm.load_topology(
            receptor_pdbfile.topology,
            receptor_system,
            xyz=receptor_pdbfile.positions)

        print("8: Combinding protein & ligand system")
        complex_structure = receptor_structure + ligand_structure

        print(dir(complex_structure))
        print("9: Create Openmm system")
        # Convert the Structure to an OpenMM System in vacuum.
        complex_system = complex_structure.createSystem(
            nonbondedMethod=NoCutoff,
            nonbondedCutoff=9.0 * unit.angstrom,
            constraints=HBonds,
            removeCMMotion=False)

        complex_structure.save(datapath + 'complex.pdb', overwrite=True)
        complex_structure = parmed.load_file(datapath + 'complex.pdb')
        with open(datapath + 'complex.xml', 'w') as f:
            f.write(XmlSerializer.serialize(complex_system))

    complex_structure = parmed.load_file(datapath + 'complex.pdb')

    with open(datapath + 'complex.xml', 'r') as f:
        complex_system = XmlSerializer.deserialize(f.read())

    print(dir(complex_structure))
    platform = openmm.Platform.getPlatformByName('OpenCL')
    properties = {'OpenCLPrecision': 'mixed'}
    integrator = openmm.LangevinIntegrator(300 * unit.kelvin,
                                           91 / unit.picosecond,
                                           0.002 * unit.picoseconds)
    simulation = openmm.app.Simulation(complex_structure, complex_system,
                                       integrator, platform)
    simulation.context.setPositions(complex_structure.positions)
    print("     starting minimization")
    state = simulation.context.getState(getEnergy=True, getForces=True)
    lastEnergy = state.getPotentialEnergy()
    potEnergyValue = state.getPotentialEnergy().value_in_unit(
        unit.kilojoules_per_mole)
    m = '     Starting pot energy: {:.3f} kJ/mol'.format(potEnergyValue)
    print(m)
    await io.emit("setMessage", m)
    # io.emit("setMessage", m)
    t0 = time.time()
    emit_freq = 1
    maxIter = 20
    # iterations=1
    for i in range(100):
        simulation.minimizeEnergy(tolerance=0, maxIterations=maxIter)
        state = simulation.context.getState(getPositions=True, getEnergy=True)
        currentEnergy = state.getPotentialEnergy()
        positions = state.getPositions(
            asNumpy=True) * 10  #convert to angstroms
        p = positions._value.flatten().tolist()
        # if(abs(lastEnergy._value-currentEnergy._value)<100):
        #     m ='     Last pot energy:'+ currentEnergy.__str__()+ " step: {}".format(i+1)
        #     await io.emit("setPositions", {'positions':p, 'message':m})
        #     break

        lastEnergy = currentEnergy
        #print("positions", p[0], p[1], p[2])
        m = '     Current pot energy: {:.3f} kJ/mol - step: {:d}'.format(
            currentEnergy.value_in_unit(unit.kilojoules_per_mole), i + 1)
        #print(m)
        if not (i + 1) % emit_freq:
            await io.emit("setPositions", {
                'positions': p,
                'message': m,
                'step': i
            })
            # io.emit("setPositions", {'positions':p, 'message':m})
            # await io.emit("setEnergy", m)
        #simulation.context.setPositions(complex_structure.positions)

    state = simulation.context.getState(getPositions=True,
                                        getEnergy=True,
                                        getForces=True)
    print('     Final pot energy:', state.getPotentialEnergy())
    print("       in ", time.time() - t0)
    return state
コード例 #21
0
ファイル: torsion_scan.py プロジェクト: zeldery/OpenFF-scan
def minimize(dat_file,
             lst_angle,
             pdb_dir,
             sdf_dir,
             coor_dir=None,
             xml_dir=None):
    # The simulation configuration
    time_step = 2 * unit.femtoseconds  # simulation timestep
    temperature = 300 * unit.kelvin  # simulation temperature
    friction = 1 / unit.picosecond  # collision rate
    minimize_tolerance = 1e-5 * unit.kilojoule / unit.mole
    minimize_iteration_step = 1000000
    forcefield = ForceField('openff-1.1.1.offxml')

    list_name, list_atoms = read_data(dat_file)
    list_energies = []
    for i, name in enumerate(list_name):
        pdbfile = PDBFile(pdb_dir + '/' + pdb_format.format(name))
        uni_mol = Molecule.from_file(sdf_dir + '/' + sdf_format.format(name))

        list_energy = []

        previous_structure = pdbfile.getPositions()
        for angle in lst_angle:
            # Load the structure

            topo = pdbfile.topology
            topo_ff = Topology.from_openmm(topo, [uni_mol])
            system = forcefield.create_openmm_system(topo_ff)
            restrain_force = make_restrain_torsion(list_atoms[i], float(angle),
                                                   1e6)
            system.addForce(restrain_force)

            integrator = openmm.LangevinIntegrator(temperature, friction,
                                                   time_step)
            simulation = openmm.app.Simulation(topo, system, integrator)
            #positions = pdbfile.getPositions()
            #simulation.context.setPositions(positions)
            simulation.context.setPositions(previous_structure)
            #simulation.context.setVelocitiesToTemperature(temperature)
            simulation.minimizeEnergy(tolerance=minimize_tolerance,
                                      maxIterations=minimize_iteration_step)
            energy_list = extract_energy(simulation)
            sum_energy = 0.0
            for j in range(len(energy_list) - 1):
                sum_energy += energy_list[j]
            list_energy.append([sum_energy, energy_list[-1]])
            previous_structure = simulation.context.getState(
                getPositions=True).getPositions()
            if coor_dir != None:
                write_xyz(
                    previous_structure, topo,
                    coor_dir + '/' + str(name) + '_' + str(angle) + '.xyz')
            if xml_dir != None:
                write_xml(
                    topo,
                    xml_dir + '/' + str(name) + '_' + str(angle) + '.xml')
        list_energies.append(list_energy)

        # Check
        f = open('check.log', 'a')
        f.write(str(i) + '\n')
        f.close()

    return list_energies
コード例 #22
0
import os

from openforcefield.topology import Molecule as Off_Molecule
from openforcefield.topology import Topology as Off_Topology
from openforcefield.typing.engines.smirnoff import ForceField

test_ff = ForceField("../../forcefield/param_valence.offxml",
                     allow_cosmetic_attributes=True)

for f in os.listdir('.'):
    if f.endswith('mol2'):
        print(f)
        off_molecule = Off_Molecule.from_file(f)
        off_topology = Off_Topology.from_molecules(off_molecule)
        test_ff.create_openmm_system(off_topology)
コード例 #23
0
class MoleculeVacuumSimulation(object):
    """ Simluate a single molecule system in vaccum.

    Parameters
    ----------
    g : `espaloma.Graph`
        Input molecular graph.

    n_samples : `int`
        Number of samples to collect.

    n_steps_per_sample : `int`
        Number of steps between each sample.

    temperature : `float * unit.kelvin`
        Temperature for the simluation.

    collision_rate : `float / unit.picosecond`
        Collision rate.

    timestep : `float * unit.femtosecond`
        Time step.

    Methods
    -------
    simulation_from_graph : Create simluation from molecule.

    run : Run the simluation.

    """
    def __init__(
        self,
        forcefield="test_forcefields/smirnoff99Frosst.offxml",
        n_samples=100,
        n_steps_per_sample=1000,
        temperature=TEMPERATURE,
        collision_rate=COLLISION_RATE,
        step_size=STEP_SIZE,
    ):

        self.n_samples = n_samples
        self.n_steps_per_sample = n_steps_per_sample
        self.temperature = temperature
        self.collision_rate = collision_rate
        self.step_size = step_size

        if isinstance(forcefield, str):
            self.forcefield = ForceField(forcefield)
        else:
            # TODO: type assertion
            self.forcefield = forcefield

    def simulation_from_graph(self, g):
        """ Create simulation from moleucle """
        # assign partial charge
        g.mol.assign_partial_charges("gasteiger")  # faster

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

        # create openmm system
        system = self.forcefield.create_openmm_system(
            topology,
            # TODO:
            # figure out whether `sqm` should be so slow
            charge_from_molecules=[g.mol],
        )

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

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

        import openforcefield

        # get conformer
        g.mol.generate_conformers(
            toolkit_registry=openforcefield.utils.RDKitToolkitWrapper(), )

        # put conformer in simulation
        simulation.context.setPositions(g.mol.conformers[0])

        # minimize energy
        simulation.minimizeEnergy()

        # set velocities
        simulation.context.setVelocitiesToTemperature(self.temperature)

        return simulation

    def run(self, g, in_place=True):
        """ Collect samples from simulation.

        Parameters
        ----------
        g : `esp.Graph`
            Input graph.

        in_place : `bool`
            If ture,

        Returns
        -------
        samples : `torch.Tensor`, `shape=(n_samples, n_nodes, 3)`
            `in_place=True`
            Sample.

        graph : `esp.Graph`
            Modified graph.

        """
        # build simulation
        simulation = self.simulation_from_graph(g)

        # initialize empty list for samples.
        samples = []

        # loop through number of samples
        for _ in range(self.n_samples):

            # run MD for `self.n_steps_per_sample` steps
            simulation.step(self.n_steps_per_sample)

            # append samples to `samples`
            samples.append(
                simulation.context.getState(getPositions=True).getPositions(
                    asNumpy=True).value_in_unit(DISTANCE_UNIT))

        # put samples into an array
        samples = np.array(samples)

        # put samples into tensor
        samples = torch.tensor(samples, dtype=torch.float32)

        if in_place is True:
            g.heterograph.nodes["n1"].data["xyz"] = samples.permute(1, 0, 2)

            # require gradient for force matching
            g.heterograph.nodes["n1"].data["xyz"].requires_grad = True

            return g

        return samples
コード例 #24
0
    def serialise_system(self):
        """Create the OpenMM system; parametrise using frost; serialise the system."""

        # Create an openFF molecule from the rdkit molecule
        off_molecule = Molecule.from_rdkit(self.molecule.rdkit_mol,
                                           allow_undefined_stereo=True)

        # Make the OpenMM system
        off_topology = off_molecule.to_topology()

        forcefield = ForceField("openff_unconstrained-1.0.0.offxml")

        try:
            # Parametrise the topology and create an OpenMM System.
            system = forcefield.create_openmm_system(off_topology)
        except (
                UnassignedValenceParameterException,
                UnassignedBondParameterException,
                UnassignedProperTorsionParameterException,
                UnassignedAngleParameterException,
                UnassignedMoleculeChargeException,
                TypeError,
        ):
            # If this does not work then we have a molecule that is not in SMIRNOFF so we must add generics
            # and remove the charge handler to get some basic parameters for the moleucle
            new_bond = BondHandler.BondType(
                smirks="[*:1]~[*:2]",
                length="0 * angstrom",
                k="0.0 * angstrom**-2 * mole**-1 * kilocalorie",
            )
            new_angle = AngleHandler.AngleType(
                smirks="[*:1]~[*:2]~[*:3]",
                angle="0.0 * degree",
                k="0.0 * mole**-1 * radian**-2 * kilocalorie",
            )
            new_torsion = ProperTorsionHandler.ProperTorsionType(
                smirks="[*:1]~[*:2]~[*:3]~[*:4]",
                periodicity1="1",
                phase1="0.0 * degree",
                k1="0.0 * mole**-1 * kilocalorie",
                periodicity2="2",
                phase2="180.0 * degree",
                k2="0.0 * mole**-1 * kilocalorie",
                periodicity3="3",
                phase3="0.0 * degree",
                k3="0.0 * mole**-1 * kilocalorie",
                periodicity4="4",
                phase4="180.0 * degree",
                k4="0.0 * mole**-1 * kilocalorie",
                idivf1="1.0",
                idivf2="1.0",
                idivf3="1.0",
                idivf4="1.0",
            )
            new_vdw = vdWHandler.vdWType(
                smirks="[*:1]",
                epsilon=0 * unit.kilocalories_per_mole,
                sigma=0 * unit.angstroms,
            )
            new_generics = {
                "Bonds": new_bond,
                "Angles": new_angle,
                "ProperTorsions": new_torsion,
                "vdW": new_vdw,
            }
            for key, val in new_generics.items():
                forcefield.get_parameter_handler(key).parameters.insert(0, val)
            # This has to be removed as sqm will fail with unknown elements
            del forcefield._parameter_handlers["ToolkitAM1BCC"]
            del forcefield._parameter_handlers["Electrostatics"]
            # Parametrize the topology and create an OpenMM System.
            system = forcefield.create_openmm_system(off_topology)
            # This will tag the molecule so run.py knows that generics have been used.
            self.fftype = "generics"
        # Serialise the OpenMM system into the xml file
        with open("serialised.xml", "w+") as out:
            out.write(XmlSerializer.serializeSystem(system))
コード例 #25
0
    path = f'LIG{i}'
    print(f'Processing LIG{i}')

    #    try:
    if 1:
        # DO LIGAND THINGS
        try:
            ligand_off_molecule = Molecule(f'{path}/LIG{i}_h.sdf')
        except Exception as e:
            print(e)
            continue
        ligand_pdbfile = PDBFile(f'{path}/LIG{i}_h.pdb')
        force_field = ForceField(
            'openff_unconstrained-1.1.0.offxml'
        )  #smirnoff99Frosst.offxml') #'openff-1.0.0.offxml')
        ligand_system = force_field.create_openmm_system(
            ligand_off_molecule.to_topology())
        ligand_structure = parmed.openmm.load_topology(
            ligand_pdbfile.topology,
            ligand_system,
            xyz=ligand_pdbfile.positions)
    if 1:
        # DO PROTEIN THINGS
        receptor_file = 'receptor.pdb'
        fixed_receptor_file = f'{path}/fixed_receptor.pdb'
        omm_forcefield = app.ForceField('amber14-all.xml')
        fixer = PDBFixer(receptor_file)  #filename='receptor.pdb')
        missingresidues = fixer.findMissingResidues()
        rezez = fixer.findNonstandardResidues()
        fixer.replaceNonstandardResidues()
        fixer.removeHeterogens(keepWater=False)
        missingatoms = fixer.findMissingAtoms()
コード例 #26
0
                                   amber_struct.positions)
        print(amber_energy)

        # prepare openff system
        mol = Molecule.from_file(f'{prefix}.mol2')
        #mol = Molecule.from_file('%s.mol2' %(prefix))
        #print(mol.to_smiles())
        from utils import fix_carboxylate_bond_orders
        fix_carboxylate_bond_orders(mol)
        print(mol.to_smiles())
        off_top = mol.to_topology()
        #off_top.box_vectors = [[48, 0, 0], [0, 48, 0], [0, 0, 48]] * unit.angstrom
        #print('off_box', off_top.box_vectors)
        #print('amb_box', pmd_struct.box)
        try:
            off_sys = ff.create_openmm_system(mol.to_topology(),)#allow_nonintegral_charges=True)
        except Exception as e:
            print(e)
            continue
        #nonbonded_force = [force for force in off_sys.getForces() if isinstance(force, openmm.NonbondedForce)][0]
        #nonbonded_force.createExceptionsFromBonds([(bond.atom1.molecule_atom_index,
        #                                            bond.atom2.molecule_atom_index) for bond in mol.bonds],
        #                                          )
        #nonbonded_force.set
        with open('off_sys.xml','w') as of:
            of.write(XmlSerializer.serialize(off_sys))
        off_energy = calc_energy(off_sys,
                                 off_top,
                                 amber_struct.positions,
                                 #mol.conformers[0]
                                 )
コード例 #27
0
# In[269]:

print(pdb_file_path)

# In[270]:

from openforcefield.topology import *
from openforcefield.typing.engines.smirnoff import ForceField

omm_topology = pdbfile.topology
off_topology = Topology.from_openmm(omm_topology,
                                    unique_molecules=[acetylacetone])

forcefield = ForceField('openff-1.0.0.offxml')

system = forcefield.create_openmm_system(off_topology)

# In[ ]:

# In[271]:

from simtk import *

# Langevin Dynamics:
time_step = 2 * unit.femtoseconds
temperature = 300 * unit.kelvin
friction = 1 / unit.picosecond  # collision rate
integrator = openmm.LangevinIntegrator(temperature, friction, time_step)

# Lenghth of simulation:
num_steps = 1
コード例 #28
0
def subtract_nonbonded_force(
    g,
    forcefield="test_forcefields/smirnoff99Frosst.offxml",
):

    # get the forcefield from str
    if isinstance(forcefield, str):
        forcefield = ForceField(forcefield)

    # partial charge
    g.mol.assign_partial_charges("gasteiger")  # faster

    # parametrize topology
    topology = g.mol.to_topology()

    # create openmm system
    system = forcefield.create_openmm_system(
        topology,
        charge_from_molecules=[g.mol],
    )

    # use langevin integrator, although it's not super useful here
    integrator = openmm.LangevinIntegrator(TEMPERATURE, COLLISION_RATE,
                                           STEP_SIZE)

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

    # get forces
    forces = list(system.getForces())

    # loop through forces
    for force in forces:
        name = force.__class__.__name__

        # turn off angle
        if "Angle" in name:
            for idx in range(force.getNumAngles()):
                id1, id2, id3, angle, k = force.getAngleParameters(idx)
                force.setAngleParameters(idx, id1, id2, id3, angle, 0.0)

        elif "Bond" in name:
            for idx in range(force.getNumBonds()):
                id1, id2, length, k = force.getBondParameters(idx)
                force.setBondParameters(
                    idx,
                    id1,
                    id2,
                    length,
                    0.0,
                )

        elif "Torsion" in name:
            for idx in range(force.getNumTorsions()):
                (
                    id1,
                    id2,
                    id3,
                    id4,
                    periodicity,
                    phase,
                    k,
                ) = force.getTorsionParameters(idx)
                force.setTorsionParameters(
                    idx,
                    id1,
                    id2,
                    id3,
                    id4,
                    periodicity,
                    phase,
                    0.0,
                )

        force.updateParametersInContext(simulation.context)

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

    # loop through the snapshots
    energies = []
    derivatives = []

    for x in xs:
        simulation.context.setPositions(x)

        state = simulation.context.getState(
            getEnergy=True,
            getParameters=True,
            getForces=True,
        )

        energy = state.getPotentialEnergy().value_in_unit(
            esp.units.ENERGY_UNIT, )

        derivative = state.getForces(asNumpy=True).value_in_unit(
            esp.units.FORCE_UNIT, )

        energies.append(energy)
        derivatives.append(derivative)

    # put energies to a tensor
    energies = torch.tensor(
        energies,
        dtype=torch.get_default_dtype(),
    ).flatten()[None, :]
    derivatives = torch.tensor(
        np.stack(derivatives, axis=1),
        dtype=torch.get_default_dtype(),
    )

    # subtract the energies
    g.heterograph.apply_nodes(
        lambda node: {"u_ref": node.data["u_ref"] - energies},
        ntype="g",
    )

    g.heterograph.apply_nodes(
        lambda node: {"u_ref_prime": node.data["u_ref_prime"] - derivatives},
        ntype="n1",
    )

    return g
コード例 #29
0
ファイル: smirnoffio.py プロジェクト: leucinw/forcebalance
class SMIRNOFF(OpenMM):

    """ Derived from Engine object for carrying out OpenMM calculations that use the SMIRNOFF force field. """

    def __init__(self, name="openmm", **kwargs):
        self.valkwd = ['ffxml', 'pdb', 'mol2', 'platname', 'precision', 'mmopts', 'vsite_bonds', 'implicit_solvent', 'restrain_k', 'freeze_atoms']
        super(SMIRNOFF,self).__init__(name=name, **kwargs)

    def readsrc(self, **kwargs):
        """
        SMIRNOFF simulations always require the following passed in via kwargs:

        Parameters
        ----------
        pdb : string
            Name of a .pdb file containing the topology of the system
        mol2 : list
            A list of .mol2 file names containing the molecule/residue templates of the system

        Also provide 1 of the following, containing the coordinates to be used:
        mol : Molecule
            forcebalance.Molecule object
        coords : string
            Name of a file (readable by forcebalance.Molecule)
            This could be the same as the pdb argument from above.
        """

        pdbfnm = kwargs.get('pdb')
        # Determine the PDB file name.
        if not pdbfnm:
            raise RuntimeError('Name of PDB file not provided.')
        elif not os.path.exists(pdbfnm):
            logger.error("%s specified but doesn't exist\n" % pdbfnm)
            raise RuntimeError

        if 'mol' in kwargs:
            self.mol = kwargs['mol']
        elif 'coords' in kwargs:
            if not os.path.exists(kwargs['coords']):
                logger.error("%s specified but doesn't exist\n" % kwargs['coords'])
                raise RuntimeError
            self.mol = Molecule(kwargs['coords'])
        else:
            logger.error('Must provide either a molecule object or coordinate file.\n')
            raise RuntimeError

        # Here we cannot distinguish the .mol2 files linked by the target
        # vs. the .mol2 files to be provided by the force field.
        # But we can assume that these files should exist when this function is called.

        self.mol2 = kwargs.get('mol2')
        if self.mol2:
            for fnm in self.mol2:
                if not os.path.exists(fnm):
                    if hasattr(self, 'FF') and fnm in self.FF.fnms: continue
                    logger.error("%s doesn't exist" % fnm)
                    raise RuntimeError
        else:
            logger.error("Must provide a list of .mol2 files.\n")

        self.abspdb = os.path.abspath(pdbfnm)
        mpdb = Molecule(pdbfnm)
        for i in ["chain", "atomname", "resid", "resname", "elem"]:
            self.mol.Data[i] = mpdb.Data[i]

        # Store a separate copy of the molecule for reference restraint positions.
        self.ref_mol = deepcopy(self.mol)

    def prepare(self, pbc=False, mmopts={}, **kwargs):

        """
        Prepare the calculation.  Note that we don't create the
        Simulation object yet, because that may depend on MD
        integrator parameters, thermostat, barostat etc.

        This is mostly copied and modified from openmmio.py's OpenMM.prepare(),
        but we are calling ForceField() from the OpenFF toolkit and ignoring
        AMOEBA stuff.
        """
        self.pdb = PDBFile(self.abspdb)

        # Create the OpenFF ForceField object.
        if hasattr(self, 'FF'):
            self.offxml = [self.FF.offxml]
            self.forcefield = self.FF.openff_forcefield
        else:
            self.offxml = listfiles(kwargs.get('offxml'), 'offxml', err=True)
            self.forcefield = OpenFF_ForceField(*self.offxml)

        ## Load mol2 files for smirnoff topology
        openff_mols = []
        for fnm in self.mol2:
            try:
                mol = OffMolecule.from_file(fnm)
            except Exception as e:
                logger.error("Error when loading %s" % fnm)
                raise e
            openff_mols.append(mol)
        self.off_topology = OffTopology.from_openmm(self.pdb.topology, unique_molecules=openff_mols)

        # used in create_simulation()
        self.mod = Modeller(self.pdb.topology, self.pdb.positions)

        ## OpenMM options for setting up the System.
        self.mmopts = dict(mmopts)

        ## Specify frozen atoms and restraint force constant
        if 'restrain_k' in kwargs:
            self.restrain_k = kwargs['restrain_k']
        if 'freeze_atoms' in kwargs:
            self.freeze_atoms = kwargs['freeze_atoms'][:]

        ## Set system options from ForceBalance force field options.
        fftmp = False
        if hasattr(self,'FF'):
            self.mmopts['rigidWater'] = self.FF.rigid_water
            if not all([os.path.exists(f) for f in self.FF.fnms]):
                # If the parameter files don't already exist, create them for the purpose of
                # preparing the engine, but then delete them afterward.
                fftmp = True
                self.FF.make(np.zeros(self.FF.np))

        ## Set system options from periodic boundary conditions.
        self.pbc = pbc
        ## print warning for 'nonbonded_cutoff' keywords
        if 'nonbonded_cutoff' in kwargs:
            logger.warning("nonbonded_cutoff keyword ignored because it's set in the offxml file\n")

        ## Generate OpenMM-compatible positions
        self.xyz_omms = []
        for I in range(len(self.mol)):
            position = self.mol.xyzs[I] * angstrom
            # xyz_omm = [Vec3(i[0],i[1],i[2]) for i in xyz]*angstrom
            # An extra step with adding virtual particles
            # mod = Modeller(self.pdb.topology, xyz_omm)
            # LPW commenting out because we don't have virtual sites yet.
            # mod.addExtraParticles(self.forcefield)
            if self.pbc:
                # Obtain the periodic box
                if self.mol.boxes[I].alpha != 90.0 or self.mol.boxes[I].beta != 90.0 or self.mol.boxes[I].gamma != 90.0:
                    logger.error('OpenMM cannot handle nonorthogonal boxes.\n')
                    raise RuntimeError
                box_omm = np.diag([self.mol.boxes[I].a, self.mol.boxes[I].b, self.mol.boxes[I].c]) * angstrom
            else:
                box_omm = None
            # Finally append it to list.
            self.xyz_omms.append((position, box_omm))

        ## Build a topology and atom lists.
        Top = self.pdb.topology
        Atoms = list(Top.atoms())
        Bonds = [(a.index, b.index) for a, b in list(Top.bonds())]

        # vss = [(i, [system.getVirtualSite(i).getParticle(j) for j in range(system.getVirtualSite(i).getNumParticles())]) \
        #            for i in range(system.getNumParticles()) if system.isVirtualSite(i)]
        self.AtomLists = defaultdict(list)
        self.AtomLists['Mass'] = [a.element.mass.value_in_unit(dalton) if a.element is not None else 0 for a in Atoms]
        self.AtomLists['ParticleType'] = ['A' if m >= 1.0 else 'D' for m in self.AtomLists['Mass']]
        self.AtomLists['ResidueNumber'] = [a.residue.index for a in Atoms]
        self.AtomMask = [a == 'A' for a in self.AtomLists['ParticleType']]
        self.realAtomIdxs = [i for i, a in enumerate(self.AtomMask) if a is True]
        if hasattr(self,'FF') and fftmp:
            for f in self.FF.fnms:
                os.unlink(f)

    def update_simulation(self, **kwargs):

        """
        Create the simulation object, or update the force field
        parameters in the existing simulation object.  This should be
        run when we write a new force field XML file.
        """
        if len(kwargs) > 0:
            self.simkwargs = kwargs

        # Because self.forcefield is being updated in forcebalance.forcefield.FF.make()
        # there is no longer a need to create a new force field object here.
        try:
            self.system = self.forcefield.create_openmm_system(self.off_topology)
        except Exception as error:
            logger.error("Error when creating system for %s" % self.mol2)
            raise error
        # Commenting out all virtual site stuff for now.
        # self.vsinfo = PrepareVirtualSites(self.system)
        self.nbcharges = np.zeros(self.system.getNumParticles())

        #----
        # If the virtual site parameters have changed,
        # the simulation object must be remade.
        #----
        # vsprm = GetVirtualSiteParameters(self.system)
        # if hasattr(self,'vsprm') and len(self.vsprm) > 0 and np.max(np.abs(vsprm - self.vsprm)) != 0.0:
        #     if hasattr(self, 'simulation'):
        #         delattr(self, 'simulation')
        # self.vsprm = vsprm.copy()

        if hasattr(self, 'simulation'):
            UpdateSimulationParameters(self.system, self.simulation)
        else:
            self.create_simulation(**self.simkwargs)

    def optimize(self, shot=0, align=True, crit=1e-4):
        return super(SMIRNOFF,self).optimize(shot=shot, align=align, crit=crit, disable_vsite=True)

    def interaction_energy(self, fraga, fragb):

        """
        Calculate the interaction energy for two fragments.
        Because this creates two new objects and requires passing in the mol2 argument,
        the codes are copied and modified from the OpenMM class.
        """

        self.update_simulation()

        if self.name == 'A' or self.name == 'B':
            logger.error("Don't name the engine A or B!\n")
            raise RuntimeError

        # Create two subengines.
        if hasattr(self,'target'):
            if not hasattr(self,'A'):
                self.A = SMIRNOFF(name="A", mol=self.mol.atom_select(fraga), mol2=self.mol2, target=self.target)
            if not hasattr(self,'B'):
                self.B = SMIRNOFF(name="B", mol=self.mol.atom_select(fragb), mol2=self.mol2, target=self.target)
        else:
            if not hasattr(self,'A'):
                self.A = SMIRNOFF(name="A", mol=self.mol.atom_select(fraga), mol2=self.mol2, platname=self.platname, \
                                  precision=self.precision, offxml=self.offxml, mmopts=self.mmopts)
            if not hasattr(self,'B'):
                self.B = SMIRNOFF(name="B", mol=self.mol.atom_select(fragb), mol2=self.mol2, platname=self.platname, \
                                  precision=self.precision, offxml=self.offxml, mmopts=self.mmopts)

        # Interaction energy needs to be in kcal/mol.
        D = self.energy()
        A = self.A.energy()
        B = self.B.energy()

        return (D - A - B) / 4.184

    def get_smirks_counter(self):
        """Get a counter for the time of appreance of each SMIRKS"""
        smirks_counter = Counter()
        molecule_force_list = self.forcefield.label_molecules(self.off_topology)
        for mol_idx, mol_forces in enumerate(molecule_force_list):
            for force_tag, force_dict in mol_forces.items():
                # e.g. force_tag = 'Bonds'
                for parameter in force_dict.values():
                    smirks_counter[parameter.smirks] += 1
        return smirks_counter
コード例 #30
0
def compute_conformer_energies_from_file(filename):
    # Load in the molecule and its conformers.
    # Note that all conformers of the same molecule are loaded as separate Molecule objects
    # If using a OFF Toolkit version before 0.7.0, loading SDFs through RDKit and OpenEye may provide
    # different behavior in some cases. So, here we force loading through RDKit to ensure the correct behavior
    rdktkw = RDKitToolkitWrapper()
    loaded_molecules = Molecule.from_file(filename, toolkit_registry=rdktkw)
    # Collatate all conformers of the same molecule
    # NOTE: This isn't necessary if you have already loaded or created multi-conformer molecules;
    # it is just needed because our SDF reader does not automatically collapse conformers.
    molecules = [loaded_molecules[0]]
    for molecule in loaded_molecules[1:]:
        if molecule == molecules[-1]:
            for conformer in molecule.conformers:
                molecules[-1].add_conformer(conformer)
        else:
            molecules.append(molecule)

    n_molecules = len(molecules)
    n_conformers = sum([mol.n_conformers for mol in molecules])
    print(
        f'{n_molecules} unique molecule(s) loaded, with {n_conformers} total conformers'
    )

    # Load the openff-1.1.0 force field appropriate for vacuum calculations (without constraints)
    from openforcefield.typing.engines.smirnoff import ForceField
    forcefield = ForceField('openff_unconstrained-1.1.0.offxml')
    # Loop over molecules and minimize each conformer
    for molecule in molecules:
        # If the molecule doesn't have a name, set mol.name to be the hill formula
        if molecule.name == '':
            molecule.name = Topology._networkx_to_hill_formula(
                molecule.to_networkx())
            print('%s : %d conformers' %
                  (molecule.name, molecule.n_conformers))
            # Make a temporary copy of the molecule that we can update for each minimization
        mol_copy = Molecule(molecule)
        # Make an OpenFF Topology so we can parameterize the system
        off_top = molecule.to_topology()
        print(
            f"Parametrizing {molecule.name} (may take a moment to calculate charges)"
        )
        system = forcefield.create_openmm_system(off_top)
        # Use OpenMM to compute initial and minimized energy for all conformers
        integrator = openmm.VerletIntegrator(1 * unit.femtoseconds)
        platform = openmm.Platform.getPlatformByName('Reference')
        omm_top = off_top.to_openmm()
        simulation = openmm.app.Simulation(omm_top, system, integrator,
                                           platform)

        # Print text header
        print(
            'Conformer         Initial PE         Minimized PE       RMS between initial and minimized conformer'
        )
        output = [[
            'Conformer', 'Initial PE (kcal/mol)', 'Minimized PE (kcal/mol)',
            'RMS between initial and minimized conformer (Angstrom)'
        ]]
        for conformer_index, conformer in enumerate(molecule.conformers):
            simulation.context.setPositions(conformer)
            orig_potential = simulation.context.getState(
                getEnergy=True).getPotentialEnergy()
            simulation.minimizeEnergy()
            min_state = simulation.context.getState(getEnergy=True,
                                                    getPositions=True)
            min_potential = min_state.getPotentialEnergy()

            # Calculate the RMSD between the initial and minimized conformer
            min_coords = min_state.getPositions()
            min_coords = np.array([[atom.x, atom.y, atom.z]
                                   for atom in min_coords]) * unit.nanometer
            mol_copy._conformers = None
            mol_copy.add_conformer(conformer)
            mol_copy.add_conformer(min_coords)
            rdmol = mol_copy.to_rdkit()
            rmslist = []
            rdMolAlign.AlignMolConformers(rdmol, RMSlist=rmslist)
            minimization_rms = rmslist[0]

            # Save the minimized conformer to file
            mol_copy._conformers = None
            mol_copy.add_conformer(min_coords)
            mol_copy.to_file(
                f'{molecule.name}_conf{conformer_index+1}_minimized.sdf',
                file_format='sdf')
            print(
                '%5d / %5d : %8.3f kcal/mol %8.3f kcal/mol  %8.3f Angstroms' %
                (conformer_index + 1, molecule.n_conformers,
                 orig_potential / unit.kilocalories_per_mole,
                 min_potential / unit.kilocalories_per_mole, minimization_rms))
            output.append([
                str(conformer_index + 1),
                f'{orig_potential/unit.kilocalories_per_mole:.3f}',
                f'{min_potential/unit.kilocalories_per_mole:.3f}',
                f'{minimization_rms:.3f}'
            ])
            # Write the results out to CSV
        with open(f'{molecule.name}.csv', 'w') as of:
            for line in output:
                of.write(','.join(line) + '\n')
                # Clean up OpenMM Simulation
        del simulation, integrator