def test_double_conversion(self):

        # Pick some OPLS parameters at random
        params = { 'k0' : 1.38   * u.Unit('kJ/mol'),
                   'k1' : -0.51  * u.Unit('kJ/mol'),
                   'k2' : 2.2    * u.Unit('kJ/mol'),
                   'k3' : -0.25  * u.Unit('kJ/mol'),
                   'k4' : 1.44   * u.Unit('kJ/mol')
                 }

        name = OPLSTorsionPotential().name
        expression = OPLSTorsionPotential().expression
        variables = OPLSTorsionPotential().independent_variables

        opls_connection_type = DihedralType(
                name=name,
                expression=expression,
                independent_variables=variables,
                parameters=params)

        # Convert connection to RB
        ryckaert_connection_type = convert_opls_to_ryckaert(
                opls_connection_type)

        # Convert connection back to OPLS
        final_connection_type = convert_ryckaert_to_opls(
                ryckaert_connection_type)

        assert np.allclose([*opls_connection_type.parameters.values()],
                           [*final_connection_type.parameters.values()])
Пример #2
0
    def test_double_conversion(self, templates):

        # Pick some OPLS parameters at random
        params = {
            'k0': 1.38 * u.Unit('kJ/mol'),
            'k1': -0.51 * u.Unit('kJ/mol'),
            'k2': 2.2 * u.Unit('kJ/mol'),
            'k3': -0.25 * u.Unit('kJ/mol'),
            'k4': 1.44 * u.Unit('kJ/mol')
        }

        opls_torsion_potential = templates['OPLSTorsionPotential']

        name = opls_torsion_potential.name
        expression = opls_torsion_potential.expression
        variables = opls_torsion_potential.independent_variables

        opls_connection_type = DihedralType(name=name,
                                            expression=expression,
                                            independent_variables=variables,
                                            parameters=params)

        # Convert connection to RB
        ryckaert_connection_type = convert_opls_to_ryckaert(
            opls_connection_type)

        # Convert connection back to OPLS
        final_connection_type = convert_ryckaert_to_opls(
            ryckaert_connection_type)

        assert_allclose_units([*opls_connection_type.parameters.values()],
                              [*final_connection_type.parameters.values()],
                              rtol=1e-5,
                              atol=1e-8)
Пример #3
0
    def test_ryckaert_to_opls(self, templates):

        # Pick some RB parameters at random
        params = {
            "c0": 1.53 * u.Unit("kJ/mol"),
            "c1": 0.76 * u.Unit("kJ/mol"),
            "c2": -0.22 * u.Unit("kJ/mol"),
            "c3": 3.55 * u.Unit("kJ/mol"),
            "c4": 0.94 * u.Unit("kJ/mol"),
            "c5": 0.0 * u.Unit("kJ/mol"),
        }

        ryckaert_bellemans_torsion_potential = templates[
            "RyckaertBellemansTorsionPotential"]

        name = ryckaert_bellemans_torsion_potential.name
        expression = ryckaert_bellemans_torsion_potential.expression
        variables = ryckaert_bellemans_torsion_potential.independent_variables

        ryckaert_connection_type = DihedralType(
            name=name,
            expression=expression,
            independent_variables=variables,
            parameters=params,
        )

        # Convert connection to OPLS
        opls_connection_type = convert_ryckaert_to_opls(
            ryckaert_connection_type)

        # Pick some angles to check
        angles = [-2.38, -1.31, -0.44, 0.0, 0.26, 0.92, 1.84, 3.10]

        for angle in angles:
            assert np.isclose(
                float(
                    ryckaert_connection_type.expression.subs([
                        (param, val) for param, val in {
                            **ryckaert_connection_type.parameters,
                            "phi":
                            angle - np.pi,
                        }.items()
                    ])),
                float(
                    opls_connection_type.expression.subs([
                        (param, val) for param, val in {
                            **opls_connection_type.parameters,
                            "phi": angle,
                        }.items()
                    ])),
            )
Пример #4
0
    def test_ryckaert_to_opls(self, templates):

        # Pick some RB parameters at random
        params = {
            'c0': 1.53 * u.Unit('kJ/mol'),
            'c1': 0.76 * u.Unit('kJ/mol'),
            'c2': -0.22 * u.Unit('kJ/mol'),
            'c3': 3.55 * u.Unit('kJ/mol'),
            'c4': 0.94 * u.Unit('kJ/mol'),
            'c5': 0.0 * u.Unit('kJ/mol')
        }

        ryckaert_bellemans_torsion_potential = templates[
            'RyckaertBellemansTorsionPotential']

        name = ryckaert_bellemans_torsion_potential.name
        expression = ryckaert_bellemans_torsion_potential.expression
        variables = ryckaert_bellemans_torsion_potential.independent_variables

        ryckaert_connection_type = DihedralType(
            name=name,
            expression=expression,
            independent_variables=variables,
            parameters=params)

        # Convert connection to OPLS
        opls_connection_type = convert_ryckaert_to_opls(
            ryckaert_connection_type)

        # Pick some angles to check
        angles = [-2.38, -1.31, -0.44, 0.0, 0.26, 0.92, 1.84, 3.10]

        for angle in angles:
            assert np.isclose(
                float(
                    ryckaert_connection_type.expression.subs([
                        (param, val) for param, val in {
                            **ryckaert_connection_type.parameters, 'phi':
                            angle - np.pi
                        }.items()
                    ])),
                float(
                    opls_connection_type.expression.subs([
                        (param, val) for param, val in {
                            **opls_connection_type.parameters, 'phi': angle
                        }.items()
                    ])),
            )
Пример #5
0
    def test_invalid_connection_type(self, templates):
        params = {
            'c0': 1.53 * u.Unit('kJ/mol'),
            'c1': 0.76 * u.Unit('kJ/mol'),
            'c2': -0.22 * u.Unit('kJ/mol'),
            'c3': 3.55 * u.Unit('kJ/mol'),
            'c4': 0.94 * u.Unit('kJ/mol'),
            'c5': 0.0 * u.Unit('kJ/mol')
        }
        ryckaert_bellemans_torsion_potential = templates[
            'RyckaertBellemansTorsionPotential']

        name = ryckaert_bellemans_torsion_potential.name
        expression = ryckaert_bellemans_torsion_potential.expression
        variables = ['phi', 'psi']

        ryckaert_connection_type = DihedralType(
            name=name,
            expression=expression,
            independent_variables=variables,
            parameters=params)

        with pytest.raises(GMSOError, match='Cannot use'):
            opls_connection_type = convert_ryckaert_to_opls(
                ryckaert_connection_type)

        expression = 'c0+c1+c2+c3+c4+c5+phi'
        variables = ryckaert_bellemans_torsion_potential.independent_variables
        ryckaert_connection_type = DihedralType(
            name=name,
            expression=expression,
            independent_variables=variables,
            parameters=params)

        with pytest.raises(GMSOError, match='Cannot use'):
            opls_connection_type = convert_ryckaert_to_opls(
                ryckaert_connection_type)

        # Pick some OPLS parameters at random
        params = {
            'k0': 1.38 * u.Unit('kJ/mol'),
            'k1': -0.51 * u.Unit('kJ/mol'),
            'k2': 2.2 * u.Unit('kJ/mol'),
            'k3': -0.25 * u.Unit('kJ/mol'),
            'k4': 1.44 * u.Unit('kJ/mol')
        }

        opls_torsion_potential = templates['OPLSTorsionPotential']
        name = opls_torsion_potential.name
        expression = opls_torsion_potential.expression
        variables = ['phi', 'psi']

        opls_connection_type = DihedralType(name=name,
                                            expression=expression,
                                            independent_variables=variables,
                                            parameters=params)

        with pytest.raises(GMSOError, match=''):
            ryckaert_connection_type = convert_opls_to_ryckaert(
                opls_connection_type)

        variables = opls_torsion_potential.independent_variables
        expression = 'k0+k1+k2+k3+k4+phi'
        opls_connection_type = DihedralType(name=name,
                                            expression=expression,
                                            independent_variables=variables,
                                            parameters=params)

        with pytest.raises(GMSOError, match=''):
            ryckaert_connection_type = convert_opls_to_ryckaert(
                opls_connection_type)
Пример #6
0
    def test_invalid_connection_type(self, templates):
        params = {
            "c0": 1.53 * u.Unit("kJ/mol"),
            "c1": 0.76 * u.Unit("kJ/mol"),
            "c2": -0.22 * u.Unit("kJ/mol"),
            "c3": 3.55 * u.Unit("kJ/mol"),
            "c4": 0.94 * u.Unit("kJ/mol"),
            "c5": 0.0 * u.Unit("kJ/mol"),
        }
        ryckaert_bellemans_torsion_potential = templates[
            "RyckaertBellemansTorsionPotential"]

        name = ryckaert_bellemans_torsion_potential.name
        expression = (str(ryckaert_bellemans_torsion_potential.expression) +
                      " + 3 * psi")
        variables = ["phi", "psi"]

        ryckaert_connection_type = DihedralType(
            name=name,
            expression=expression,
            independent_variables=variables,
            parameters=params,
        )

        with pytest.raises(GMSOError, match="Cannot use"):
            opls_connection_type = convert_ryckaert_to_opls(
                ryckaert_connection_type)

        expression = "c0+c1+c2+c3+c4+c5+phi"
        variables = ryckaert_bellemans_torsion_potential.independent_variables
        ryckaert_connection_type = DihedralType(
            name=name,
            expression=expression,
            independent_variables=variables,
            parameters=params,
        )

        with pytest.raises(GMSOError, match="Cannot use"):
            opls_connection_type = convert_ryckaert_to_opls(
                ryckaert_connection_type)

        # Pick some OPLS parameters at random
        params = {
            "k0": 1.38 * u.Unit("kJ/mol"),
            "k1": -0.51 * u.Unit("kJ/mol"),
            "k2": 2.2 * u.Unit("kJ/mol"),
            "k3": -0.25 * u.Unit("kJ/mol"),
            "k4": 1.44 * u.Unit("kJ/mol"),
        }

        opls_torsion_potential = templates["OPLSTorsionPotential"]
        name = opls_torsion_potential.name
        expression = (str(opls_torsion_potential.expression) +
                      " + 0.5 * k1 * (1 + cos(psi))")
        variables = ["phi", "psi"]

        opls_connection_type = DihedralType(
            name=name,
            expression=expression,
            independent_variables=variables,
            parameters=params,
        )

        with pytest.raises(GMSOError, match=""):
            ryckaert_connection_type = convert_opls_to_ryckaert(
                opls_connection_type)

        variables = opls_torsion_potential.independent_variables
        expression = "k0+k1+k2+k3+k4+phi"
        opls_connection_type = DihedralType(
            name=name,
            expression=expression,
            independent_variables=variables,
            parameters=params,
        )

        with pytest.raises(GMSOError, match=""):
            ryckaert_connection_type = convert_opls_to_ryckaert(
                opls_connection_type)
Пример #7
0
def _write_dihedral_information(mcf, top):
    """Write the dihedrals in the system.

    Parameters
    ----------
    mcf : file object
        The file object of the Cassandra mcf being written
    top : Topology
        Topology object
    dihedral_style : string
        Dihedral style for Cassandra to use
    """

    # Dihedral info
    header = ("\n!Dihedral Format\n"
              "!index i j k l type parameters\n"
              '!type="none"\n'
              '!type="CHARMM", parms=a0 a1 delta\n'
              '!type="OPLS", parms=c0 c1 c2 c3\n'
              '!type="harmonic", parms=force_constant equilibrium_dihedral\n'
              "\n# Dihedral_Info\n")

    mcf.write(header)

    # TODO: Are impropers buried in dihedrals?
    mcf.write("{:d}\n".format(len(top.dihedrals)))
    for (idx, dihedral) in enumerate(top.dihedrals):
        mcf.write("{:<4d}  "
                  "{:<4d}  "
                  "{:<4d}  "
                  "{:<4d}  "
                  "{:<4d}  ".format(
                      idx + 1,
                      dihedral.connection_members[0].idx + 1,
                      dihedral.connection_members[1].idx + 1,
                      dihedral.connection_members[2].idx + 1,
                      dihedral.connection_members[3].idx + 1,
                  ))
        dihedral_style = _get_dihedral_style(dihedral)
        # If ryckaert, convert to opls
        if dihedral_style == "ryckaert":
            dihedral.connection_type = convert_ryckaert_to_opls(
                dihedral.connection_type)
            dihedral_style = "opls"
        if dihedral_style == "opls":
            mcf.write(
                "{:s}  "
                "{:10.5f}  "
                "{:10.5f}  "
                "{:10.5f}  "
                "{:10.5f}\n".format(
                    dihedral_style,
                    0.5 * dihedral.connection_type.parameters["k0"].in_units(
                        "kJ/mol").value,
                    0.5 * dihedral.connection_type.parameters["k1"].in_units(
                        "kJ/mol").value,
                    0.5 * dihedral.connection_type.parameters["k2"].in_units(
                        "kJ/mol").value,
                    0.5 * dihedral.connection_type.parameters["k3"].in_units(
                        "kJ/mol").value,
                ))
        elif dihedral_style == "charmm":
            mcf.write(
                "{:s}  "
                "{:10.5f}  "
                "{:10.5f}  "
                "{:10.5f}\n".format(
                    dihedral_style,
                    dihedral.connection_type.parameters["k"].in_units(
                        "kJ/mol").value,
                    dihedral.connection_type.parameters["n"],
                    dihedral.connection_type.parameters["phi_eq"].in_units(
                        u.degrees).value,
                ))
        elif dihedral_style == "harmonic":
            mcf.write(
                "{:s}  "
                "{:10.5f}  "
                "{:10.5f}\n".format(
                    dihedral_style,
                    0.5 * dihedral.connection_type.parameters["k"].in_units(
                        "kJ/mol").value,
                    dihedral.connection_type.parameters["phi_eq"].in_units(
                        u.degrees).value,
                ))

        else:
            raise GMSOError(
                "Unsupported dihedral style for Cassandra MCF writer")
Пример #8
0
def write_lammpsdata(topology, filename, atom_style="full"):
    """Output a LAMMPS data file.

    Outputs a LAMMPS data file in the 'full' atom style format.
    Assumes use of 'real' units.
    See http://lammps.sandia.gov/doc/atom_style.html for more information on atom styles.

    Parameters
    ----------
    Topology : `Topology`
        A Topology Object
    filename : str
        Path of the output file
    atom_style : str, optional, default='full'
        Defines the style of atoms to be saved in a LAMMPS data file.
        The following atom styles are currently supported: 'full', 'atomic', 'charge', 'molecular'
        see http://lammps.sandia.gov/doc/atom_style.html for more information on atom styles.

    Notes
    -----
    See http://lammps.sandia.gov/doc/2001/data_format.html for a full description of the LAMMPS data format.
    This is a work in progress, as only atoms, masses, and atom_type information can be written out.

    Some of this function has been adopted from `mdtraj`'s support of the LAMMPSTRJ trajectory format.
    See https://github.com/mdtraj/mdtraj/blob/master/mdtraj/formats/lammpstrj.py for details.

    """
    if atom_style not in ["atomic", "charge", "molecular", "full"]:
        raise ValueError(
            'Atom style "{}" is invalid or is not currently supported'.format(
                atom_style))

    # TODO: Support various unit styles

    box = topology.box

    with open(filename, "w") as data:
        data.write("{} written by topology at {}\n\n".format(
            topology.name if topology.name is not None else "",
            str(datetime.datetime.now()),
        ))
        data.write("{:d} atoms\n".format(topology.n_sites))
        if atom_style in ["full", "molecular"]:
            if topology.n_bonds != 0:
                data.write("{:d} bonds\n".format(topology.n_bonds))
            else:
                data.write("0 bonds\n")
            if topology.n_angles != 0:
                data.write("{:d} angles\n".format(topology.n_angles))
            else:
                data.write("0 angles\n")
            if topology.n_dihedrals != 0:
                data.write("{:d} dihedrals\n\n".format(topology.n_dihedrals))
            else:
                data.write("0 dihedrals\n\n")

        data.write("\n{:d} atom types\n".format(len(topology.atom_types)))
        data.write("{:d} bond types\n".format(len(topology.bond_types)))
        data.write("{:d} angle types\n".format(len(topology.angle_types)))
        data.write("{:d} dihedral types\n".format(len(
            topology.dihedral_types)))

        data.write("\n")

        # Box data
        if allclose_units(
                box.angles,
                u.unyt_array([90, 90, 90], "degree"),
                rtol=1e-5,
                atol=1e-8,
        ):
            warnings.warn("Orthorhombic box detected")
            box.lengths.convert_to_units(u.angstrom)
            for i, dim in enumerate(["x", "y", "z"]):
                data.write("{0:.6f} {1:.6f} {2}lo {2}hi\n".format(
                    0, box.lengths.value[i], dim))
        else:
            warnings.warn("Non-orthorhombic box detected")
            box.lengths.convert_to_units(u.angstrom)
            box.angles.convert_to_units(u.radian)
            vectors = box.get_vectors()
            a, b, c = box.lengths
            alpha, beta, gamma = box.angles

            lx = a
            xy = b * np.cos(gamma)
            xz = c * np.cos(beta)
            ly = np.sqrt(b**2 - xy**2)
            yz = (b * c * np.cos(alpha) - xy * xz) / ly
            lz = np.sqrt(c**2 - xz**2 - yz**2)

            xhi = vectors[0][0]
            yhi = vectors[1][1]
            zhi = vectors[2][2]
            xy = vectors[1][0]
            xz = vectors[2][0]
            yz = vectors[2][1]
            xlo = u.unyt_array(0, xy.units)
            ylo = u.unyt_array(0, xy.units)
            zlo = u.unyt_array(0, xy.units)

            xlo_bound = xlo + u.unyt_array(np.min([0.0, xy, xz, xy + xz]),
                                           xy.units)
            xhi_bound = xhi + u.unyt_array(np.max([0.0, xy, xz, xy + xz]),
                                           xy.units)
            ylo_bound = ylo + u.unyt_array(np.min([0.0, yz]), xy.units)
            yhi_bound = yhi + u.unyt_array(np.max([0.0, yz]), xy.units)
            zlo_bound = zlo
            zhi_bound = zhi

            data.write("{0:.6f} {1:.6f} xlo xhi\n".format(
                xlo_bound.value, xhi_bound.value))
            data.write("{0:.6f} {1:.6f} ylo yhi\n".format(
                ylo_bound.value, yhi_bound.value))
            data.write("{0:.6f} {1:.6f} zlo zhi\n".format(
                zlo_bound.value, zhi_bound.value))
            data.write("{0:.6f} {1:.6f} {2:.6f} xy xz yz\n".format(
                xy.value, xz.value, yz.value))

        # TODO: Get a dictionary of indices and atom types
        if topology.is_typed():
            # Write out mass data
            data.write("\nMasses\n\n")
            for atom_type in topology.atom_types:
                data.write("{:d}\t{:.6f}\t# {}\n".format(
                    topology.atom_types.index(atom_type) + 1,
                    atom_type.mass.in_units(u.g / u.mol).value,
                    atom_type.name,
                ))

            # TODO: Modified cross-interactions
            # Pair coefficients
            data.write("\nPair Coeffs # lj\n\n")
            for idx, param in enumerate(topology.atom_types):
                data.write("{}\t{:.5f}\t{:.5f}\n".format(
                    idx + 1,
                    param.parameters["epsilon"].in_units(
                        u.Unit("kcal/mol")).value,
                    param.parameters["sigma"].in_units(u.angstrom).value,
                ))

            if topology.bonds:
                data.write("\nBond Coeffs\n\n")
                for idx, bond_type in enumerate(topology.bond_types):
                    data.write("{}\t{:.5f}\t{:.5f}\n".format(
                        idx + 1,
                        bond_type.parameters["k"].in_units(
                            u.Unit("kcal/mol/angstrom**2")).value / 2,
                        bond_type.parameters["r_eq"].in_units(
                            u.Unit("angstrom")).value,
                    ))

            if topology.angles:
                data.write("\nAngle Coeffs\n\n")
                for idx, angle_type in enumerate(topology.angle_types):
                    data.write("{}\t{:.5f}\t{:.5f}\n".format(
                        idx + 1,
                        angle_type.parameters["k"].in_units(
                            u.Unit("kcal/mol/radian**2")).value / 2,
                        angle_type.parameters["theta_eq"].in_units(
                            u.Unit("degree")).value,
                    ))

            # TODO: Write out multiple dihedral styles
            if topology.dihedrals:
                data.write("\nDihedral Coeffs\n\n")
                for idx, dihedral_type in enumerate(topology.dihedral_types):
                    rbtorsion = PotentialTemplateLibrary(
                    )["RyckaertBellemansTorsionPotential"]
                    if (dihedral_type.expression == sympify(
                            rbtorsion.expression)
                            or dihedral_type.name == rbtorsion.name):
                        dihedral_type = convert_ryckaert_to_opls(dihedral_type)
                    data.write("{}\t{:.5f}\t{:5f}\t{:5f}\t{:.5f}\n".format(
                        idx + 1,
                        dihedral_type.parameters["k1"].in_units(
                            u.Unit("kcal/mol")).value,
                        dihedral_type.parameters["k2"].in_units(
                            u.Unit("kcal/mol")).value,
                        dihedral_type.parameters["k3"].in_units(
                            u.Unit("kcal/mol")).value,
                        dihedral_type.parameters["k4"].in_units(
                            u.Unit("kcal/mol")).value,
                    ))

        # Atom data
        data.write("\nAtoms\n\n")
        if atom_style == "atomic":
            atom_line = "{index:d}\t{type_index:d}\t{x:.6f}\t{y:.6f}\t{z:.6f}\n"
        elif atom_style == "charge":
            atom_line = "{index:d}\t{type_index:d}\t{charge:.6f}\t{x:.6f}\t{y:.6f}\t{z:.6f}\n"
        elif atom_style == "molecular":
            atom_line = "{index:d}\t{zero:d}\t{type_index:d}\t{x:.6f}\t{y:.6f}\t{z:.6f}\n"
        elif atom_style == "full":
            atom_line = "{index:d}\t{zero:d}\t{type_index:d}\t{charge:.6f}\t{x:.6f}\t{y:.6f}\t{z:.6f}\n"

        for i, site in enumerate(topology.sites):
            data.write(
                atom_line.format(
                    index=topology.sites.index(site) + 1,
                    type_index=topology.atom_types.index(site.atom_type) + 1,
                    zero=0,
                    charge=site.charge.to(u.elementary_charge).value,
                    x=site.position[0].in_units(u.angstrom).value,
                    y=site.position[1].in_units(u.angstrom).value,
                    z=site.position[2].in_units(u.angstrom).value,
                ))

        if topology.bonds:
            data.write("\nBonds\n\n")
            for i, bond in enumerate(topology.bonds):
                data.write("{:d}\t{:d}\t{:d}\t{:d}\n".format(
                    i + 1,
                    topology.bond_types.index(bond.connection_type) + 1,
                    topology.sites.index(bond.connection_members[0]) + 1,
                    topology.sites.index(bond.connection_members[1]) + 1,
                ))

        if topology.angles:
            data.write("\nAngles\n\n")
            for i, angle in enumerate(topology.angles):
                data.write("{:d}\t{:d}\t{:d}\t{:d}\t{:d}\n".format(
                    i + 1,
                    topology.angle_types.index(angle.connection_type) + 1,
                    topology.sites.index(angle.connection_members[0]) + 1,
                    topology.sites.index(angle.connection_members[1]) + 1,
                    topology.sites.index(angle.connection_members[2]) + 1,
                ))

        if topology.dihedrals:
            data.write("\nDihedrals\n\n")
            for i, dihedral in enumerate(topology.dihedrals):
                data.write("{:d}\t{:d}\t{:d}\t{:d}\t{:d}\t{:d}\n".format(
                    i + 1,
                    topology.dihedral_types.index(dihedral.connection_type) +
                    1,
                    topology.sites.index(dihedral.connection_members[0]) + 1,
                    topology.sites.index(dihedral.connection_members[1]) + 1,
                    topology.sites.index(dihedral.connection_members[2]) + 1,
                    topology.sites.index(dihedral.connection_members[3]) + 1,
                ))