from openff.toolkit.typing.engines.smirnoff import ForceField

from amberimpropertorsionhandler import AmberImproperTorsionHandler

ff = ForceField('result_residues.offxml', 'result_backbone.offxml')
ff.to_file('result_merged.offxml')
Ejemplo n.º 2
0
from openff.toolkit.typing.engines.smirnoff import ForceField
ff = ForceField()
ff.aromaticity_model = 'OEAroModel_MDL'

# Loop over the parameters to convert and their corresponding SMIRNOFF header tags 
for smirnoff_tag, param_dicts in { "Bonds": bond_dicts, "Angles": angle_dicts,
                                   "ProperTorsions": proper_dicts,
                                   "AmberImproperTorsions": improper_dicts,
                                   'LibraryCharges': charge_dicts,
                                   'vdW': nonbond_dicts}.items():
  # Get the parameter handler for the given tag. The
  # "get_parameter_handler" method will initialize an
  # empty handler if none exists yet (as is the case here). 
  handler = ff.get_parameter_handler(smirnoff_tag)

  # Loop over the list of parameter dictionaries, using each one as an input to
  # handler.add_parameter.  This mimics deserializing an OFFXML into a ForceField
  # object, and will do any sanitization that we might otherwise miss
  from openff.toolkit.typing.engines.smirnoff.parameters import DuplicateParameterError
  for param_dict in param_dicts:
    try:
      handler.add_parameter(param_dict)
    except DuplicateParameterError:
      continue
      

# Add the ElectrostaticsHandler, with the proper 1-4 scaling factors
handler = ff.get_parameter_handler('Electrostatics')                
# Write the now-populated forcefield out to OFFXML
ff.to_file('result_residues.offxml')
Ejemplo n.º 3
0
ff.aromaticity_model = 'OEAroModel_MDL'

# Loop over the parameters to convert and their corresponding SMIRNOFF header tags
for smirnoff_tag, param_dicts in {
        "Bonds": bond_dicts,
        "Angles": angle_dicts,
        "ProperTorsions": proper_dicts,
        "AmberImproperTorsions": improper_dicts,
        #'LibraryCharges': charge_dicts,
        #'vdW': nonbond_dicts
}.items():
    # Get the parameter handler for the given tag. The
    # "get_parameter_handler" method will initialize an
    # empty handler if none exists yet (as is the case here).
    handler = ff.get_parameter_handler(smirnoff_tag)

    # Loop over the list of parameter dictionaries, using each one as an input to
    # handler.add_parameter.  This mimics deserializing an OFFXML into a ForceField
    # object, and will do any sanitization that we might otherwise miss
    from openff.toolkit.typing.engines.smirnoff.parameters import DuplicateParameterError
    for param_dict in param_dicts:
        try:
            handler.add_parameter(param_dict)
        except DuplicateParameterError:
            continue

# Add the ElectrostaticsHandler, with the proper 1-4 scaling factors
handler = ff.get_parameter_handler('Electrostatics')
# Write the now-populated forcefield out to OFFXML
ff.to_file('result_backbone.offxml')
Ejemplo n.º 4
0
def _combine_molecules_offxml(
    molecules: List["Ligand"],
    parameters: List[str],
    rfree_data: Dict[str, Dict[str, Union[str, float]]],
    filename: str,
    water_model: Literal["tip3p"] = "tip3p",
):
    """
    Main worker function to build the combined offxmls.
    """

    if sum([molecule.extra_sites.n_sites for molecule in molecules]) > 0:
        raise NotImplementedError(
            "Virtual sites can not be safely converted into offxml format yet."
        )

    if sum([molecule.RBTorsionForce.n_parameters for molecule in molecules]) > 0:
        raise NotImplementedError(
            "RBTorsions can not yet be safely converted into offxml format yet."
        )

    try:
        from chemper.graphs.cluster_graph import ClusterGraph
    except ModuleNotFoundError:
        raise ModuleNotFoundError(
            "chemper is required to make an offxml, please install with `conda install chemper -c conda-forge`."
        )

    fit_ab = False
    # if alpha and beta should be fit
    if "AB" in parameters:
        fit_ab = True

    rfree_codes = set()  # keep track of all rfree codes used by these molecules
    # create the master ff
    offxml = ForceField(allow_cosmetic_attributes=True, load_plugins=True)
    offxml.author = f"QUBEKit_version_{qubekit.__version__}"
    offxml.date = datetime.now().strftime("%Y_%m_%d")
    # get all of the handlers
    _ = offxml.get_parameter_handler("Constraints")
    bond_handler = offxml.get_parameter_handler("Bonds")
    angle_handler = offxml.get_parameter_handler("Angles")
    proper_torsions = offxml.get_parameter_handler("ProperTorsions")
    improper_torsions = offxml.get_parameter_handler("ImproperTorsions")
    _ = offxml.get_parameter_handler(
        "Electrostatics", handler_kwargs={"scale14": 0.8333333333, "version": 0.3}
    )
    using_plugin = False
    if parameters:
        # if we want to optimise the Rfree we need our custom handler
        vdw_handler = offxml.get_parameter_handler(
            "QUBEKitvdWTS", allow_cosmetic_attributes=True
        )
        using_plugin = True
    else:
        vdw_handler = offxml.get_parameter_handler(
            "vdW", allow_cosmetic_attributes=True
        )
    library_charges = offxml.get_parameter_handler("LibraryCharges")

    for molecule in molecules:
        rdkit_mol = molecule.to_rdkit()
        bond_types = molecule.bond_types
        # for each bond type collection create a single smirks pattern
        for bonds in bond_types.values():
            graph = ClusterGraph(
                mols=[rdkit_mol], smirks_atoms_lists=[bonds], layers="all"
            )
            qube_bond = molecule.BondForce[bonds[0]]
            bond_handler.add_parameter(
                parameter_kwargs={
                    "smirks": graph.as_smirks(),
                    "length": qube_bond.length * unit.nanometers,
                    "k": qube_bond.k * unit.kilojoule_per_mole / unit.nanometers**2,
                }
            )

        angle_types = molecule.angle_types
        for angles in angle_types.values():
            graph = ClusterGraph(
                mols=[rdkit_mol],
                smirks_atoms_lists=[angles],
                layers="all",
            )
            qube_angle = molecule.AngleForce[angles[0]]
            angle_handler.add_parameter(
                parameter_kwargs={
                    "smirks": graph.as_smirks(),
                    "angle": qube_angle.angle * unit.radian,
                    "k": qube_angle.k * unit.kilojoule_per_mole / unit.radians**2,
                }
            )

        torsion_types = molecule.dihedral_types
        for dihedrals in torsion_types.values():
            graph = ClusterGraph(
                mols=[rdkit_mol],
                smirks_atoms_lists=[dihedrals],
                layers="all",
            )
            qube_dihedral = molecule.TorsionForce[dihedrals[0]]
            proper_torsions.add_parameter(
                parameter_kwargs={
                    "smirks": graph.as_smirks(),
                    "k1": qube_dihedral.k1 * unit.kilojoule_per_mole,
                    "k2": qube_dihedral.k2 * unit.kilojoule_per_mole,
                    "k3": qube_dihedral.k3 * unit.kilojoule_per_mole,
                    "k4": qube_dihedral.k4 * unit.kilojoule_per_mole,
                    "periodicity1": qube_dihedral.periodicity1,
                    "periodicity2": qube_dihedral.periodicity2,
                    "periodicity3": qube_dihedral.periodicity3,
                    "periodicity4": qube_dihedral.periodicity4,
                    "phase1": qube_dihedral.phase1 * unit.radians,
                    "phase2": qube_dihedral.phase2 * unit.radians,
                    "phase3": qube_dihedral.phase3 * unit.radians,
                    "phase4": qube_dihedral.phase4 * unit.radians,
                    "idivf1": 1,
                    "idivf2": 1,
                    "idivf3": 1,
                    "idivf4": 1,
                }
            )

        improper_types = molecule.improper_types
        for torsions in improper_types.values():
            impropers = [
                (improper[1], improper[0], *improper[2:]) for improper in torsions
            ]
            graph = ClusterGraph(
                mols=[rdkit_mol], smirks_atoms_lists=[impropers], layers="all"
            )
            qube_improper = molecule.ImproperTorsionForce[torsions[0]]
            # we need to multiply each k value by as they will be applied as trefoil see
            # <https://openforcefield.github.io/standards/standards/smirnoff/#impropertorsions> for more details
            # we assume we only have a k2 term for improper torsions via a periodic term
            improper_torsions.add_parameter(
                parameter_kwargs={
                    "smirks": graph.as_smirks(),
                    "k1": qube_improper.k2 * 3 * unit.kilojoule_per_mole,
                    "periodicity1": qube_improper.periodicity2,
                    "phase1": qube_improper.phase2 * unit.radians,
                }
            )

        atom_types = {}
        for atom_index, cip_type in molecule.atom_types.items():
            atom_types.setdefault(cip_type, []).append((atom_index,))
        for sym_set in atom_types.values():
            graph = ClusterGraph(
                mols=[rdkit_mol], smirks_atoms_lists=[sym_set], layers="all"
            )
            qube_non_bond = molecule.NonbondedForce[sym_set[0]]
            rfree_code = _get_parameter_code(
                molecule=molecule, atom_index=sym_set[0][0]
            )
            atom_data = {
                "smirks": graph.as_smirks(),
            }

            if rfree_code in parameters or fit_ab:
                # keep track of present codes to optimise
                rfree_codes.add(rfree_code)
            if using_plugin:
                # this is to be refit
                atom = molecule.atoms[qube_non_bond.atoms[0]]
                atom_data["volume"] = atom.aim.volume * unit.angstroms**3
            else:
                atom_data["epsilon"] = qube_non_bond.epsilon * unit.kilojoule_per_mole
                atom_data["sigma"] = qube_non_bond.sigma * unit.nanometers

            vdw_handler.add_parameter(parameter_kwargs=atom_data)

        charge_data = dict(
            (f"charge{param.atoms[0] + 1}", param.charge * unit.elementary_charge)
            for param in molecule.NonbondedForce
        )
        charge_data["smirks"] = molecule.to_smiles(mapped=True)
        library_charges.add_parameter(parameter_kwargs=charge_data)

    # now loop over all the parameters to be fit and add them as cosmetic attributes
    to_parameterize = []
    for parameter_to_fit in parameters:
        if parameter_to_fit != "AB" and parameter_to_fit in rfree_codes:
            setattr(
                vdw_handler,
                f"{parameter_to_fit.lower()}free",
                unit.Quantity(
                    rfree_data[parameter_to_fit]["r_free"], unit=unit.angstroms
                ),
            )
            to_parameterize.append(f"{parameter_to_fit.lower()}free")
    if fit_ab:
        vdw_handler.alpha = rfree_data["alpha"]
        vdw_handler.beta = rfree_data["beta"]
        to_parameterize.extend(["alpha", "beta"])
    if to_parameterize:
        vdw_handler.add_cosmetic_attribute("parameterize", ", ".join(to_parameterize))

    # now add a water model to the force field
    _add_water_model(
        force_field=offxml, water_model=water_model, using_plugin=using_plugin
    )
    offxml.to_file(filename=filename)