def _validate_compatibility(top): """Check compatability of topology object with GROMACS TOP format""" templates = PotentialTemplateLibrary() lennard_jones_potential = templates['LennardJonesPotential'] harmonic_bond_potential = templates['HarmonicBondPotential'] harmonic_angle_potential = templates['HarmonicAnglePotential'] accepted_potentials = [lennard_jones_potential, harmonic_bond_potential, harmonic_angle_potential] check_compatibility(top, accepted_potentials)
def convert_ryckaert_to_opls(ryckaert_connection_type): """Convert Ryckaert-Bellemans dihedral to OPLS. NOTE: the conventions defining the dihedral angle are different for OPLS and RB torsions. OPLS torsions are defined with phi_cis = 0 while RB torsions are defined as phi_trans = 0. """ templates = PotentialTemplateLibrary() ryckaert_bellemans_torsion_potential = templates[ "RyckaertBellemansTorsionPotential"] opls_torsion_potential = templates["OPLSTorsionPotential"] valid_connection_type = False if (ryckaert_connection_type.independent_variables == ryckaert_bellemans_torsion_potential.independent_variables): if (sympy.simplify(ryckaert_connection_type.expression - ryckaert_bellemans_torsion_potential.expression) == 0): valid_connection_type = True if not valid_connection_type: raise GMSOError("Cannot use convert_ryckaert_to_opls " "function to convert a ConnectionType that is not an " "RyckaertBellemansTorsionPotential") c0 = ryckaert_connection_type.parameters["c0"] c1 = ryckaert_connection_type.parameters["c1"] c2 = ryckaert_connection_type.parameters["c2"] c3 = ryckaert_connection_type.parameters["c3"] c4 = ryckaert_connection_type.parameters["c4"] c5 = ryckaert_connection_type.parameters["c5"] if c5 != 0.0: raise GMSOError("Cannot convert Ryckaert-Bellemans dihedral " "to OPLS dihedral if c5 is not equal to zero.") converted_params = { "k0": 2.0 * (c0 + c1 + c2 + c3 + c4), "k1": (-2.0 * c1 - (3.0 / 2.0) * c3), "k2": (-c2 - c4), "k3": ((-1.0 / 2.0) * c3), "k4": ((-1.0 / 4.0) * c4), } name = opls_torsion_potential.name expression = opls_torsion_potential.expression variables = opls_torsion_potential.independent_variables opls_connection_type = gmso.DihedralType( name=name, expression=expression, independent_variables=variables, parameters=converted_params, ) return opls_connection_type
def convert_ryckaert_to_opls(ryckaert_connection_type): """Convert Ryckaert-Bellemans dihedral to OPLS NOTE: the conventions defining the dihedral angle are different for OPLS and RB torsions. OPLS torsions are defined with phi_cis = 0 while RB torsions are defined as phi_trans = 0. """ templates = PotentialTemplateLibrary() ryckaert_bellemans_torsion_potential = templates[ 'RyckaertBellemansTorsionPotential'] opls_torsion_potential = templates['OPLSTorsionPotential'] valid_connection_type = False if (ryckaert_connection_type.independent_variables == ryckaert_bellemans_torsion_potential.independent_variables): if sympy.simplify( ryckaert_connection_type.expression - ryckaert_bellemans_torsion_potential.expression) == 0: valid_connection_type = True if not valid_connection_type: raise GMSOError('Cannot use convert_ryckaert_to_opls ' 'function to convert a ConnectionType that is not an ' 'RyckaertBellemansTorsionPotential') c0 = ryckaert_connection_type.parameters['c0'] c1 = ryckaert_connection_type.parameters['c1'] c2 = ryckaert_connection_type.parameters['c2'] c3 = ryckaert_connection_type.parameters['c3'] c4 = ryckaert_connection_type.parameters['c4'] c5 = ryckaert_connection_type.parameters['c5'] if c5 != 0.0: raise GMSOError('Cannot convert Ryckaert-Bellemans dihedral ' 'to OPLS dihedral if c5 is not equal to zero.') converted_params = { 'k0': 2. * (c0 + c1 + c2 + c3 + c4), 'k1': (-2. * c1 - (3. / 2.) * c3), 'k2': (-c2 - c4), 'k3': ((-1. / 2.) * c3), 'k4': ((-1. / 4.) * c4) } name = opls_torsion_potential.name expression = opls_torsion_potential.expression variables = opls_torsion_potential.independent_variables opls_connection_type = gmso.DihedralType(name=name, expression=expression, independent_variables=variables, parameters=converted_params) return opls_connection_type
def test_class_method(self): template = PotentialTemplateLibrary()['HarmonicBondPotential'] params = {'k': 1.0 * u.dimensionless, 'r_eq': 1.0 * u.dimensionless} harmonic_potential_from_template = ParametricPotential.from_template(template, params) harmonic_potential = ParametricPotential(name='HarmonicBondPotential', expression='0.5 * k * (r-r_eq)**2', independent_variables={'r'}, parameters=params) assert harmonic_potential.name == harmonic_potential_from_template.name assert harmonic_potential.expression == harmonic_potential_from_template.expression assert harmonic_potential.independent_variables == harmonic_potential_from_template.independent_variables
def test_noble_mie_xml(self): ff = ForceField(get_path('noble_mie.xml')) templates = PotentialTemplateLibrary() ref_expr = templates['MiePotential'].expression assert len(ff.atom_types) == 4 assert len(ff.bond_types) == 0 assert len(ff.angle_types) == 0 assert len(ff.dihedral_types) == 0 for (name, atom_type) in ff.atom_types.items(): assert sympy.simplify(atom_type.expression - ref_expr) == 0 assert allclose(ff.atom_types['Ne'].parameters['epsilon'], 0.26855713 * u.Unit('kJ/mol')) assert allclose(ff.atom_types['Ne'].parameters['sigma'], 2.794 * u.Angstrom) assert allclose(ff.atom_types['Ne'].parameters['n'], 11 * u.dimensionless) assert allclose(ff.atom_types['Ne'].parameters['m'], 6 * u.dimensionless) assert ff.atom_types['Ne'].charge.value == 0 assert allclose(ff.atom_types['Ar'].parameters['epsilon'], 1.01519583 * u.Unit('kJ/mol')) assert allclose(ff.atom_types['Ar'].parameters['sigma'], 3.405 * u.Angstrom) assert allclose(ff.atom_types['Ar'].parameters['n'], 13 * u.dimensionless) assert allclose(ff.atom_types['Ar'].parameters['m'], 6 * u.dimensionless) assert ff.atom_types['Ar'].charge.value == 0 assert allclose(ff.atom_types['Kr'].parameters['epsilon'], 1.46417678 * u.Unit('kJ/mol')) assert allclose(ff.atom_types['Kr'].parameters['sigma'], 3.645 * u.Angstrom) assert allclose(ff.atom_types['Kr'].parameters['n'], 14 * u.dimensionless) assert allclose(ff.atom_types['Kr'].parameters['m'], 6 * u.dimensionless) assert ff.atom_types['Kr'].charge.value == 0 assert allclose(ff.atom_types['Xe'].parameters['epsilon'], 2.02706587 * u.Unit('kJ/mol')) assert allclose(ff.atom_types['Xe'].parameters['sigma'], 3.964 * u.Angstrom) assert allclose(ff.atom_types['Xe'].parameters['n'], 14 * u.dimensionless) assert allclose(ff.atom_types['Xe'].parameters['m'], 6 * u.dimensionless) assert ff.atom_types['Xe'].charge.value == 0
def convert_opls_to_ryckaert(opls_connection_type): """Convert an OPLS dihedral to Ryckaert-Bellemans dihedral. Equations taken/modified from: http://manual.gromacs.org/documentation/2019/ reference-manual/functions/bonded-interactions.html NOTE: the conventions defining the dihedral angle are different for OPLS and RB torsions. OPLS torsions are defined with phi_cis = 0 while RB torsions are defined as phi_trans = 0. """ templates = PotentialTemplateLibrary() opls_torsion_potential = templates["OPLSTorsionPotential"] valid_connection_type = False if (opls_connection_type.independent_variables == opls_torsion_potential.independent_variables): if (sympy.simplify(opls_connection_type.expression - opls_torsion_potential.expression) == 0): valid_connection_type = True if not valid_connection_type: raise GMSOError("Cannot use convert_opls_to_ryckaert " "function to convert a ConnectionType that is not an " "OPLSTorsionPotential") f0 = opls_connection_type.parameters["k0"] f1 = opls_connection_type.parameters["k1"] f2 = opls_connection_type.parameters["k2"] f3 = opls_connection_type.parameters["k3"] f4 = opls_connection_type.parameters["k4"] converted_params = { "c0": (f2 + 0.5 * (f0 + f1 + f3)), "c1": (0.5 * (-f1 + 3.0 * f3)), "c2": (-f2 + 4.0 * f4), "c3": (-2.0 * f3), "c4": (-4.0 * f4), "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 = gmso.DihedralType( name=name, expression=expression, independent_variables=variables, parameters=converted_params, ) return ryckaert_connection_type
def convert_opls_to_ryckaert(opls_connection_type): """Convert an OPLS dihedral to Ryckaert-Bellemans dihedral Equations taken/modified from: http://manual.gromacs.org/documentation/2019/ reference-manual/functions/bonded-interactions.html NOTE: the conventions defining the dihedral angle are different for OPLS and RB torsions. OPLS torsions are defined with phi_cis = 0 while RB torsions are defined as phi_trans = 0. """ templates = PotentialTemplateLibrary() opls_torsion_potential = templates['OPLSTorsionPotential'] valid_connection_type = False if (opls_connection_type.independent_variables == opls_torsion_potential.independent_variables): if sympy.simplify(opls_connection_type.expression - opls_torsion_potential.expression) == 0: valid_connection_type = True if not valid_connection_type: raise GMSOError('Cannot use convert_opls_to_ryckaert ' 'function to convert a ConnectionType that is not an ' 'OPLSTorsionPotential') f0 = opls_connection_type.parameters['k0'] f1 = opls_connection_type.parameters['k1'] f2 = opls_connection_type.parameters['k2'] f3 = opls_connection_type.parameters['k3'] f4 = opls_connection_type.parameters['k4'] converted_params = { 'c0': (f2 + 0.5 * (f0 + f1 + f3)), 'c1': (0.5 * (-f1 + 3. * f3)), 'c2': (-f2 + 4. * f4), 'c3': (-2. * f3), 'c4': (-4. * f4), 'c5': 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 = gmso.DihedralType( name=name, expression=expression, independent_variables=variables, parameters=converted_params) return ryckaert_connection_type
def _accepted_potentials(): templates = PotentialTemplateLibrary() lennard_jones_potential = templates['LennardJonesPotential'] harmonic_bond_potential = templates['HarmonicBondPotential'] harmonic_angle_potential = templates['HarmonicAnglePotential'] periodic_torsion_potential = templates['PeriodicTorsionPotential'] rb_torsion_potential = templates['RyckaertBellemansTorsionPotential'] accepted_potentials = [ lennard_jones_potential, harmonic_bond_potential, harmonic_angle_potential, periodic_torsion_potential, rb_torsion_potential, ] return accepted_potentials
def _accepted_potentials(): """List of accepted potentials that GROMACS can support.""" templates = PotentialTemplateLibrary() lennard_jones_potential = templates["LennardJonesPotential"] harmonic_bond_potential = templates["HarmonicBondPotential"] harmonic_angle_potential = templates["HarmonicAnglePotential"] periodic_torsion_potential = templates["PeriodicTorsionPotential"] rb_torsion_potential = templates["RyckaertBellemansTorsionPotential"] accepted_potentials = [ lennard_jones_potential, harmonic_bond_potential, harmonic_angle_potential, periodic_torsion_potential, rb_torsion_potential, ] return accepted_potentials
def test_class_method(self): template = PotentialTemplateLibrary()["HarmonicBondPotential"] params = {"k": 1.0 * u.dimensionless, "r_eq": 1.0 * u.dimensionless} harmonic_potential_from_template = ParametricPotential.from_template( template, params) harmonic_potential = ParametricPotential( name="HarmonicBondPotential", expression="0.5 * k * (r-r_eq)**2", independent_variables={"r"}, parameters=params, ) assert harmonic_potential.name == harmonic_potential_from_template.name assert (harmonic_potential.expression == harmonic_potential_from_template.expression) assert (harmonic_potential.independent_variables == harmonic_potential_from_template.independent_variables)
def test_ethane_periodic(self, typed_ethane): from gmso.lib.potential_templates import PotentialTemplateLibrary per_torsion = PotentialTemplateLibrary()["PeriodicTorsionPotential"] params = { "k": 10 * u.Unit("kJ / mol"), "phi_eq": 15 * u.Unit("degree"), "n": 3 * u.Unit("dimensionless") } periodic_dihedral_type = gmso.core.potential.Potential.from_template( per_torsion, params) for dihedral in typed_ethane.dihedrals: dihedral.connection_type = periodic_dihedral_type typed_ethane.update_connection_types() write_top(typed_ethane, 'system.top') struct = pmd.load_file('system.top') assert len(struct.dihedrals) == 9
def templates(self): return PotentialTemplateLibrary()
import datetime import networkx as nx import sympy import unyt as u from gmso import __version__ from gmso.core.topology import Topology from gmso.lib.potential_templates import PotentialTemplateLibrary from gmso.utils.compatibility import check_compatibility from gmso.utils.conversions import convert_ryckaert_to_opls from gmso.exceptions import GMSOError __all__ = ["write_mcf"] potential_templates = PotentialTemplateLibrary() def write_mcf(top, filename): """Generate a Cassandra MCF from a gmso.core.Topology object. The MCF file stores the topology information for a single species (i.e., compound) in the Cassandra Monte Carlo software (https://cassandra.nd.edu). The gmso.Topology object provided to this function should therefore be for a single molecule with the relevant forcefield parameters. One MCF file will be required for each unique species in the system. Parameters ---------- top : gmso.core.Topology
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, ))
def test_noble_mie_xml(self): ff = ForceField(get_path("noble_mie.xml")) templates = PotentialTemplateLibrary() ref_expr = templates["MiePotential"].expression assert len(ff.atom_types) == 4 assert len(ff.bond_types) == 0 assert len(ff.angle_types) == 0 assert len(ff.dihedral_types) == 0 for (name, atom_type) in ff.atom_types.items(): assert sympy.simplify(atom_type.expression - ref_expr) == 0 assert_allclose_units( ff.atom_types["Ne"].parameters["epsilon"], 0.26855713 * u.Unit("kJ/mol"), rtol=1e-5, atol=1e-8, ) assert_allclose_units( ff.atom_types["Ne"].parameters["sigma"], 2.794 * u.Angstrom, rtol=1e-5, atol=1e-8, ) assert_allclose_units( ff.atom_types["Ne"].parameters["n"], 11 * u.dimensionless, rtol=1e-5, atol=1e-8, ) assert_allclose_units( ff.atom_types["Ne"].parameters["m"], 6 * u.dimensionless, rtol=1e-5, atol=1e-8, ) assert ff.atom_types["Ne"].charge.value == 0 assert_allclose_units( ff.atom_types["Ar"].parameters["epsilon"], 1.01519583 * u.Unit("kJ/mol"), rtol=1e-5, atol=1e-8, ) assert_allclose_units( ff.atom_types["Ar"].parameters["sigma"], 3.405 * u.Angstrom, rtol=1e-5, atol=1e-8, ) assert_allclose_units( ff.atom_types["Ar"].parameters["n"], 13 * u.dimensionless, rtol=1e-5, atol=1e-8, ) assert_allclose_units( ff.atom_types["Ar"].parameters["m"], 6 * u.dimensionless, rtol=1e-5, atol=1e-8, ) assert ff.atom_types["Ar"].charge.value == 0 assert_allclose_units( ff.atom_types["Kr"].parameters["epsilon"], 1.46417678 * u.Unit("kJ/mol"), rtol=1e-5, atol=1e-8, ) assert_allclose_units( ff.atom_types["Kr"].parameters["sigma"], 3.645 * u.Angstrom, rtol=1e-5, atol=1e-8, ) assert_allclose_units( ff.atom_types["Kr"].parameters["n"], 14 * u.dimensionless, rtol=1e-5, atol=1e-8, ) assert_allclose_units( ff.atom_types["Kr"].parameters["m"], 6 * u.dimensionless, rtol=1e-5, atol=1e-8, ) assert ff.atom_types["Kr"].charge.value == 0 assert_allclose_units( ff.atom_types["Xe"].parameters["epsilon"], 2.02706587 * u.Unit("kJ/mol"), rtol=1e-5, atol=1e-8, ) assert_allclose_units( ff.atom_types["Xe"].parameters["sigma"], 3.964 * u.Angstrom, rtol=1e-5, atol=1e-8, ) assert_allclose_units( ff.atom_types["Xe"].parameters["n"], 14 * u.dimensionless, rtol=1e-5, atol=1e-8, ) assert_allclose_units( ff.atom_types["Xe"].parameters["m"], 6 * u.dimensionless, rtol=1e-5, atol=1e-8, ) assert ff.atom_types["Xe"].charge.value == 0
def test_singleton_behavior(self, templates): assert id(templates) == id(PotentialTemplateLibrary()) assert id(PotentialTemplateLibrary()) == id(PotentialTemplateLibrary())