Example #1
0
def _write_angles(lmp_file: IO, openff_sys: Interchange):
    """Write the Angles section of a LAMMPS data file"""
    from openff.interchange.components.mdtraj import (
        _iterate_angles,
        _store_bond_partners,
    )

    _store_bond_partners(openff_sys.topology.mdtop)

    lmp_file.write("\nAngles\n\n")

    angle_handler = openff_sys["Angles"]
    angle_type_map = dict(enumerate(angle_handler.potentials))

    angle_type_map_inv = dict({v: k for k, v in angle_type_map.items()})

    for angle_idx, angle in enumerate(_iterate_angles(openff_sys.topology.mdtop)):
        # These are "topology indices"
        indices = tuple(a.index for a in angle)
        top_key = TopologyKey(atom_indices=indices)
        pot_key = angle_handler.slot_map[top_key]
        angle_type = angle_type_map_inv[pot_key]

        lmp_file.write(
            "{:d}\t{:d}\t{:d}\t{:d}\t{:d}\n".format(
                angle_idx + 1,
                angle_type + 1,
                indices[0] + 1,
                indices[1] + 1,
                indices[2] + 1,
            )
        )
Example #2
0
def _write_propers(lmp_file: IO, openff_sys: Interchange):
    """Write the Dihedrals section of a LAMMPS data file"""
    from openff.interchange.components.mdtraj import (
        _iterate_propers,
        _store_bond_partners,
    )

    _store_bond_partners(openff_sys.topology.mdtop)

    lmp_file.write("\nDihedrals\n\n")

    proper_handler = openff_sys["ProperTorsions"]
    proper_type_map = dict(enumerate(proper_handler.potentials))

    proper_type_map_inv = dict({v: k for k, v in proper_type_map.items()})

    for proper_idx, proper in enumerate(_iterate_propers(openff_sys.topology.mdtop)):
        # These are "topology indices"
        indices = tuple(a.index for a in proper)
        for top_key, pot_key in proper_handler.slot_map.items():
            if indices == top_key.atom_indices:

                proper_type_idx = proper_type_map_inv[pot_key]

                lmp_file.write(
                    "{:d}\t{:d}\t{:d}\t{:d}\t{:d}\t{:d}\n".format(
                        proper_idx + 1,
                        proper_type_idx + 1,
                        indices[0] + 1,
                        indices[1] + 1,
                        indices[2] + 1,
                        indices[3] + 1,
                    )
                )
Example #3
0
def _write_angles(top_file: IO, openff_sys: "Interchange"):
    if "Angles" not in openff_sys.handlers.keys():
        return

    _store_bond_partners(openff_sys.topology.mdtop)

    top_file.write("[ angles ]\n")
    top_file.write("; ai\taj\tak\tfunc\tr\tk\n")

    angle_handler = openff_sys.handlers["Angles"]

    for angle in _iterate_angles(openff_sys.topology.mdtop):
        indices = (
            angle[0].index,
            angle[1].index,
            angle[2].index,
        )
        for top_key in angle_handler.slot_map:
            if top_key.atom_indices == indices:
                pot_key = angle_handler.slot_map[top_key]

        params = angle_handler.potentials[pot_key].parameters
        k = params["k"].m_as(unit.Unit("kilojoule / mole / radian ** 2"))
        theta = params["angle"].to(unit.degree).magnitude

        top_file.write("{:7d} {:7d} {:7d} {:4s} {:.16g} {:.16g}\n".format(
            indices[0] + 1,  # atom i
            indices[1] + 1,  # atom j
            indices[2] + 1,  # atom k
            str(1),  # angle type (functional form)
            theta,
            k,
        ))

    top_file.write("\n\n")
Example #4
0
def test_iterate_pairs_benzene():
    """Check that bonds in rings are not double-counted with _iterate_pairs.
    This should be fixed by using Topology.nth_degree_neighbors directly"""
    benzene = Molecule.from_smiles("c1ccccc1")
    mdtop = md.Topology.from_openmm(benzene.to_topology().to_openmm())

    _store_bond_partners(mdtop)

    assert len({*_iterate_pairs(mdtop)}) == 21
Example #5
0
def test_iterate_pairs():
    mol = Molecule.from_smiles("C1#CC#CC#C1")

    top = mol.to_topology()

    mdtop = md.Topology.from_openmm(top.to_openmm())

    _store_bond_partners(mdtop)
    pairs = {
        tuple(sorted((atom1.index, atom2.index)))
        for atom1, atom2 in _iterate_pairs(mdtop)
    }
    assert len(pairs) == 3
    assert len([*_iterate_propers(mdtop)]) > len(pairs)
Example #6
0
def _write_dihedrals(top_file: IO, openff_sys: "Interchange"):
    if "ProperTorsions" not in openff_sys.handlers:
        if "RBTorsions" not in openff_sys.handlers:
            if "ImproperTorsions" not in openff_sys.handlers:
                return

    _store_bond_partners(openff_sys.topology.mdtop)

    top_file.write("[ dihedrals ]\n")
    top_file.write(";    i      j      k      l   func\n")

    rb_torsion_handler = openff_sys.handlers.get("RBTorsions", [])
    proper_torsion_handler = openff_sys.handlers.get("ProperTorsions", [])
    improper_torsion_handler = openff_sys.handlers.get("ImproperTorsions", [])

    # TODO: Ensure number of torsions written matches what is expected
    for proper in _iterate_propers(openff_sys.topology.mdtop):
        if proper_torsion_handler:
            for top_key in proper_torsion_handler.slot_map:
                indices = tuple(a.index for a in proper)
                if top_key.atom_indices == indices:
                    pot_key = proper_torsion_handler.slot_map[top_key]
                    params = proper_torsion_handler.potentials[
                        pot_key].parameters

                    k = params["k"].to(unit.Unit("kilojoule / mol")).magnitude
                    periodicity = int(params["periodicity"])
                    phase = params["phase"].to(unit.degree).magnitude
                    idivf = int(params["idivf"]) if "idivf" in params else 1
                    top_file.write(
                        "{:7d} {:7d} {:7d} {:7d} {:6d} {:16g} {:16g} {:7d}\n".
                        format(
                            indices[0] + 1,
                            indices[1] + 1,
                            indices[2] + 1,
                            indices[3] + 1,
                            1,
                            phase,
                            k / idivf,
                            periodicity,
                        ))
        # This should be `if` if a single quartet can be subject to both proper and RB torsions
        if rb_torsion_handler:
            for top_key in rb_torsion_handler.slot_map:
                indices = tuple(a.index for a in proper)
                if top_key.atom_indices == indices:
                    pot_key = rb_torsion_handler.slot_map[top_key]
                    params = rb_torsion_handler.potentials[pot_key].parameters

                    c0 = params["C0"].to(
                        unit.Unit("kilojoule / mol")).magnitude
                    c1 = params["C1"].to(
                        unit.Unit("kilojoule / mol")).magnitude
                    c2 = params["C2"].to(
                        unit.Unit("kilojoule / mol")).magnitude
                    c3 = params["C3"].to(
                        unit.Unit("kilojoule / mol")).magnitude
                    c4 = params["C4"].to(
                        unit.Unit("kilojoule / mol")).magnitude
                    c5 = params["C5"].to(
                        unit.Unit("kilojoule / mol")).magnitude

                    top_file.write(
                        "{:7d} {:7d} {:7d} {:7d} {:6d} "
                        "{:16g} {:16g} {:16g} {:16g} {:16g} {:16g} \n".format(
                            indices[0] + 1,
                            indices[1] + 1,
                            indices[2] + 1,
                            indices[3] + 1,
                            3,
                            c0,
                            c1,
                            c2,
                            c3,
                            c4,
                            c5,
                        ))

    # TODO: Ensure number of torsions written matches what is expected
    for improper in _iterate_impropers(openff_sys.topology.mdtop):
        if improper_torsion_handler:
            for top_key in improper_torsion_handler.slot_map:
                indices = tuple(a.index for a in improper)
                if indices == top_key.atom_indices:
                    key = improper_torsion_handler.slot_map[top_key]
                    params = improper_torsion_handler.potentials[
                        key].parameters

                    k = params["k"].to(unit.Unit("kilojoule / mol")).magnitude
                    periodicity = int(params["periodicity"])
                    phase = params["phase"].to(unit.degree).magnitude
                    idivf = int(params["idivf"])
                    top_file.write(
                        "{:7d} {:7d} {:7d} {:7d} {:6d} {:.16g} {:.16g} {:.16g}\n"
                        .format(
                            indices[0] + 1,
                            indices[1] + 1,
                            indices[2] + 1,
                            indices[3] + 1,
                            4,
                            phase,
                            k / idivf,
                            periodicity,
                        ))
Example #7
0
def _write_atoms(
    top_file: IO,
    openff_sys: "Interchange",
    typemap: Dict,
):
    """Write the [ atoms ] and [ pairs ] sections for a molecule"""
    top_file.write("[ atoms ]\n")
    top_file.write(";num, type, resnum, resname, atomname, cgnr, q, m\n")

    charges = openff_sys.handlers["Electrostatics"].charges

    for atom in openff_sys.topology.mdtop.atoms:
        atom_idx = atom.index
        mass = atom.element.mass
        atom_type = typemap[atom.index]
        res_idx = atom.residue.index
        res_name = str(atom.residue)
        top_key = TopologyKey(atom_indices=(atom_idx, ))
        charge = charges[top_key].m_as(unit.e)
        top_file.write("{:6d} {:18s} {:6d} {:8s} {:8s} {:6d} "
                       "{:18.8f} {:18.8f}\n".format(
                           atom_idx + 1,
                           atom_type,
                           res_idx + 1,
                           res_name,
                           atom_type,
                           atom_idx + 1,
                           charge,
                           mass,
                       ))

    top_file.write("[ pairs ]\n")
    top_file.write("; ai\taj\tfunct\n")

    _store_bond_partners(openff_sys.topology.mdtop)

    try:
        mixing_rule = openff_sys["vdW"].mixing_rule
        scale_lj = openff_sys["vdW"].scale_14
    except LookupError:
        mixing_rule = openff_sys["Buckingham-6"].mixing_rule
        scale_lj = openff_sys["Buckingham-6"].scale_14

    # Use a set to de-duplicate
    pairs: Set[Tuple] = {*_iterate_pairs(openff_sys.topology.mdtop)}
    for pair in pairs:
        indices = [a.index for a in pair]
        indices = sorted(indices)
        parameters1 = _get_lj_parameters(openff_sys, indices[0])
        sigma1 = parameters1["sigma"].to(unit.nanometer).magnitude
        epsilon1 = parameters1["epsilon"].to(
            unit.Unit("kilojoule / mole")).magnitude
        parameters2 = _get_lj_parameters(openff_sys, indices[1])
        sigma2 = parameters2["sigma"].to(unit.nanometer).magnitude
        epsilon2 = parameters2["epsilon"].to(
            unit.Unit("kilojoule / mole")).magnitude
        epsilon_mix = (epsilon1 * epsilon2)**0.5
        if mixing_rule == "lorentz-berthelot":
            sigma_mix = (sigma1 + sigma2) * 0.5
        elif mixing_rule == "geometric":
            sigma_mix = (sigma1 * sigma2)**0.5
        top_file.write("{:7d} {:7d} {:6d} {:16g} {:16g}\n".format(
            indices[0] + 1,
            indices[1] + 1,
            1,
            sigma_mix,
            epsilon_mix * scale_lj,
        ))