Beispiel #1
0
def compare_single_mol_systems(mol, force_field):

    top = mol.to_topology()
    top.box_vectors = _box_vectors

    try:
        toolkit_sys = force_field.create_openmm_system(
            top,
            charge_from_molecules=[mol],
        )
    except (
        UnassignedBondParameterException,
        UnassignedAngleParameterException,
        UnassignedProperTorsionParameterException,
    ):
        pytest.xfail(f"Molecule failed! (missing valence parameters)\t{mol.to_inchi()}")

    toolkit_energy = _get_openmm_energies(
        toolkit_sys, box_vectors=_box_vectors, positions=mol.conformers[0]
    )

    openff_sys = Interchange.from_smirnoff(force_field=force_field, topology=top)
    openff_sys.positions = mol.conformers[0]
    system_energy = get_openmm_energies(openff_sys, combine_nonbonded_forces=True)

    toolkit_energy.compare(
        system_energy,
        custom_tolerances={
            "Bond": 1e-6 * kj_mol,
            "Angle": 1e-6 * kj_mol,
            "Torsion": 4e-5 * kj_mol,
            "Nonbonded": 1e-5 * kj_mol,
        },
    )
Beispiel #2
0
    def test_from_openmm_pdbfile(self, argon_ff, argon_top):
        pdb_file_path = get_test_file_path("10-argons.pdb")
        pdbfile = openmm.app.PDBFile(pdb_file_path)

        mol = Molecule.from_smiles("[#18]")
        top = OFFBioTop.from_openmm(pdbfile.topology, unique_molecules=[mol])
        top.mdtop = md.Topology.from_openmm(top.to_openmm())
        box = pdbfile.topology.getPeriodicBoxVectors()
        box = box.value_in_unit(nm) * unit.nanometer

        out = Interchange.from_smirnoff(argon_ff, top)
        out.box = box
        out.positions = pdbfile.getPositions()

        assert np.allclose(
            out.positions.to(unit.nanometer).magnitude,
            pdbfile.getPositions().value_in_unit(nm),
        )

        get_openmm_energies(out, hard_cutoff=True).compare(
            _get_openmm_energies(
                omm_sys=argon_ff.create_openmm_system(top),
                box_vectors=pdbfile.topology.getPeriodicBoxVectors(),
                positions=pdbfile.getPositions(),
                hard_cutoff=True,
            )
        )
def test_from_openmm_single_mols(mol, n_mols):
    """
    Test that ForceField.create_openmm_system and Interchange.to_openmm produce
    objects with similar energies

    TODO: Tighten tolerances
    TODO: Test periodic and non-periodic
    """

    parsley = ForceField(get_test_file_path("parsley.offxml"))

    mol = Molecule.from_smiles(mol)
    mol.generate_conformers(n_conformers=1)
    top = Topology.from_molecules(n_mols * [mol])
    mol.conformers[0] -= np.min(mol.conformers) * simtk_unit.angstrom

    top.box_vectors = np.eye(3) * np.asarray([15, 15, 15]) * simtk_unit.nanometer

    if n_mols == 1:
        positions = mol.conformers[0]
    elif n_mols == 2:
        positions = np.vstack(
            [mol.conformers[0], mol.conformers[0] + 3 * simtk_unit.nanometer]
        )
        positions = positions * simtk_unit.angstrom

    toolkit_system = parsley.create_openmm_system(top)

    native_system = Interchange.from_smirnoff(
        force_field=parsley, topology=top
    ).to_openmm()

    toolkit_energy = _get_openmm_energies(
        omm_sys=toolkit_system,
        box_vectors=toolkit_system.getDefaultPeriodicBoxVectors(),
        positions=positions,
    )
    native_energy = _get_openmm_energies(
        omm_sys=native_system,
        box_vectors=native_system.getDefaultPeriodicBoxVectors(),
        positions=positions,
    )

    toolkit_energy.compare(native_energy)
Beispiel #4
0
    def test_from_toolkit_packmol_boxes(self, pdb_path, unique_molecules):
        """
        Test loading some pre-prepared PACKMOL-generated systems.

        These use PDB files already prepared in the toolkit because PDB files are a pain.
        """
        ff = ForceField("openff-1.0.0.offxml")

        pdb_file_path = get_data_file_path("systems/packmol_boxes/" + pdb_path)
        pdbfile = openmm.app.PDBFile(pdb_file_path)
        top = OFFBioTop.from_openmm(
            pdbfile.topology,
            unique_molecules=unique_molecules,
        )
        top.mdtop = md.Topology.from_openmm(top.to_openmm())
        box = pdbfile.topology.getPeriodicBoxVectors()
        box = box.value_in_unit(nm) * unit.nanometer

        out = Interchange.from_smirnoff(ff, top)
        out.box = box
        out.positions = pdbfile.getPositions()

        assert np.allclose(
            out.positions.to(unit.nanometer).magnitude,
            pdbfile.getPositions().value_in_unit(nm),
        )

        get_openmm_energies(
            out,
            hard_cutoff=True,
            combine_nonbonded_forces=True,
        ).compare(
            _get_openmm_energies(
                omm_sys=ff.create_openmm_system(top),
                box_vectors=pdbfile.topology.getPeriodicBoxVectors(),
                positions=pdbfile.getPositions(),
                hard_cutoff=True,
            )
        )
def test_water_dimer():
    tip3p = ForceField(get_test_file_path("tip3p.offxml"))
    water = Molecule.from_smiles("O")
    top = Topology.from_molecules(2 * [water])
    top.mdtop = md.Topology.from_openmm(top.to_openmm())

    pdbfile = openmm.app.PDBFile(get_test_file_path("water-dimer.pdb"))

    positions = pdbfile.positions

    openff_sys = Interchange.from_smirnoff(tip3p, top)
    openff_sys.positions = positions
    openff_sys.box = [10, 10, 10] * unit.nanometer

    omm_energies = get_openmm_energies(
        openff_sys,
        hard_cutoff=True,
        electrostatics=False,
    )

    toolkit_energies = _get_openmm_energies(
        tip3p.create_openmm_system(top),
        openff_sys.box,
        openff_sys.positions,
        hard_cutoff=True,
        electrostatics=False,
    )

    omm_energies.compare(toolkit_energies)

    # TODO: Fix GROMACS energies by handling SETTLE constraints
    # gmx_energies, _ = get_gromacs_energies(openff_sys)
    # compare_gromacs_openmm(omm_energies=omm_energies, gmx_energies=gmx_energies)

    openff_sys["Electrostatics"].method = "cutoff"
    omm_energies_cutoff = get_gromacs_energies(openff_sys)
    lmp_energies = get_lammps_energies(openff_sys)

    lmp_energies.compare(omm_energies_cutoff)
def test_energies_single_mol(constrained, mol_smi):
    import mbuild as mb

    mol = Molecule.from_smiles(mol_smi)
    mol.generate_conformers(n_conformers=1)
    mol.name = "FOO"
    top = mol.to_topology()
    top.box_vectors = None  # [10, 10, 10] * simtk_unit.nanometer

    if constrained:
        parsley = ForceField("openff-1.0.0.offxml")
    else:
        parsley = ForceField("openff_unconstrained-1.0.0.offxml")

    off_sys = Interchange.from_smirnoff(parsley, top)

    off_sys.handlers["Electrostatics"].method = "cutoff"

    mol.to_file("out.xyz", file_format="xyz")
    compound: mb.Compound = mb.load("out.xyz")
    packed_box: mb.Compound = mb.fill_box(compound=compound,
                                          n_compounds=1,
                                          box=mb.Box(lengths=[10, 10, 10]))

    positions = packed_box.xyz * unit.nanometer
    off_sys.positions = positions

    # Compare directly to toolkit's reference implementation
    omm_energies = get_openmm_energies(off_sys, round_positions=8)
    omm_reference = parsley.create_openmm_system(top)
    reference_energies = _get_openmm_energies(
        omm_sys=omm_reference,
        box_vectors=off_sys.box,
        positions=off_sys.positions,
        round_positions=8,
    )

    omm_energies.compare(reference_energies)

    mdp = "cutoff_hbonds" if constrained else "auto"
    # Compare GROMACS writer and OpenMM export
    gmx_energies = get_gromacs_energies(off_sys, mdp=mdp)

    custom_tolerances = {
        "Bond": 2e-5 * simtk_unit.kilojoule_per_mole,
        "Electrostatics": 2 * simtk_unit.kilojoule_per_mole,
        "vdW": 2 * simtk_unit.kilojoule_per_mole,
        "Nonbonded": 2 * simtk_unit.kilojoule_per_mole,
        "Angle": 1e-4 * simtk_unit.kilojoule_per_mole,
    }

    gmx_energies.compare(
        omm_energies,
        custom_tolerances=custom_tolerances,
    )

    if not constrained:
        other_energies = get_openmm_energies(
            off_sys,
            round_positions=8,
            hard_cutoff=True,
            electrostatics=True,
        )
        lmp_energies = get_lammps_energies(off_sys)
        custom_tolerances = {
            "vdW": 5.0 * simtk_unit.kilojoule_per_mole,
            "Electrostatics": 5.0 * simtk_unit.kilojoule_per_mole,
        }
        lmp_energies.compare(other_energies,
                             custom_tolerances=custom_tolerances)
def test_packmol_boxes(toolkit_file_path):
    # TODO: Isolate a set of systems here instead of using toolkit data
    # TODO: Fix nonbonded energy differences
    from openff.toolkit.utils import get_data_file_path

    pdb_file_path = get_data_file_path(toolkit_file_path)
    pdbfile = openmm.app.PDBFile(pdb_file_path)

    ethanol = Molecule.from_smiles("CCO")
    cyclohexane = Molecule.from_smiles("C1CCCCC1")
    omm_topology = pdbfile.topology
    off_topology = OFFBioTop.from_openmm(
        omm_topology, unique_molecules=[ethanol, cyclohexane])
    off_topology.mdtop = md.Topology.from_openmm(omm_topology)

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

    off_sys = Interchange.from_smirnoff(parsley, off_topology)

    off_sys.box = np.asarray(
        pdbfile.topology.getPeriodicBoxVectors().value_in_unit(
            simtk_unit.nanometer))
    off_sys.positions = pdbfile.positions

    sys_from_toolkit = parsley.create_openmm_system(off_topology)

    omm_energies = get_openmm_energies(off_sys,
                                       hard_cutoff=True,
                                       electrostatics=False)
    reference = _get_openmm_energies(
        sys_from_toolkit,
        off_sys.box,
        off_sys.positions,
        hard_cutoff=True,
        electrostatics=False,
    )

    omm_energies.compare(
        reference,
        custom_tolerances={
            "Electrostatics": 2e-2 * simtk_unit.kilojoule_per_mole,
        },
    )

    # custom_tolerances={"HarmonicBondForce": 1.0}

    # Compare GROMACS writer and OpenMM export
    gmx_energies = get_gromacs_energies(off_sys, electrostatics=False)

    omm_energies_rounded = get_openmm_energies(
        off_sys,
        round_positions=8,
        hard_cutoff=True,
        electrostatics=False,
    )

    omm_energies_rounded.compare(
        other=gmx_energies,
        custom_tolerances={
            "Angle": 1e-2 * simtk_unit.kilojoule_per_mole,
            "Torsion": 1e-2 * simtk_unit.kilojoule_per_mole,
            "Electrostatics": 3200 * simtk_unit.kilojoule_per_mole,
        },
    )
Beispiel #8
0
def compare_condensed_systems(mol, force_field):
    from openff.evaluator import unit as evaluator_unit
    from openff.evaluator.utils.packmol import pack_box

    mass_density = 500 * evaluator_unit.kilogram / evaluator_unit.meter ** 3

    trj, assigned_residue_names = pack_box(
        molecules=[mol], number_of_copies=[100], mass_density=mass_density
    )

    try:
        openff_top = Topology.from_openmm(trj.top.to_openmm(), unique_molecules=[mol])
    except ValueError:
        print(f"Molecule failed! (conversion from OpenMM)\t{mol.to_inchi()}")
        return

    box_vectors = trj.unitcell_vectors[0] * simtk_unit.nanometer
    openff_top.box_vectors = box_vectors

    try:
        toolkit_sys = force_field.create_openmm_system(
            openff_top,
            charge_from_molecules=[mol],
        )

    except (
        UnassignedBondParameterException,
        UnassignedAngleParameterException,
        UnassignedProperTorsionParameterException,
    ):
        print(f"Molecule failed! (missing valence parameters)\t{mol.to_inchi()}")
        return

    positions = trj.xyz[0] * simtk_unit.nanometer
    toolkit_energy = _get_openmm_energies(
        toolkit_sys,
        box_vectors=box_vectors,
        positions=positions,
    )

    openff_sys = Interchange.from_smirnoff(force_field=force_field, topology=openff_top)
    openff_sys.box = box_vectors
    openff_sys.positions = trj.xyz[0] * unit.nanometer

    new_sys = openff_sys.to_openmm(combine_nonbonded_forces=True)

    system_energy = _get_openmm_energies(
        new_sys,
        box_vectors=box_vectors,
        positions=positions,
    )

    # Where energies to not precisely match, inspect all parameters in each force
    try:
        toolkit_energy.compare(
            system_energy,
            custom_tolerances={
                "Bond": 1e-6 * kj_mol,
                "Angle": 1e-6 * kj_mol,
                "Torsion": 4e-5 * kj_mol,
                "Nonbonded": 1e-5 * kj_mol,
            },
        )
    except EnergyError as e:
        if "Torsion" in str(e):
            _compare_torsion_forces(
                _get_force(toolkit_sys, openmm.PeriodicTorsionForce),
                _get_force(new_sys, openmm.PeriodicTorsionForce),
            )
        if "Nonbonded" in str(e):
            _compare_nonbonded_settings(
                _get_force(toolkit_sys, openmm.NonbondedForce),
                _get_force(new_sys, openmm.NonbondedForce),
            )
            _compare_nonbonded_parameters(
                _get_force(toolkit_sys, openmm.NonbondedForce),
                _get_force(new_sys, openmm.NonbondedForce),
            )
        if "Bond" in str(e):
            raise e
        if "Angle" in str(e):
            raise e