# Path: perses/rjmc/geometry.py
# def check_dimensionality(quantity, compatible_units):
#     """
#     Ensure that the specified quantity has units compatible with specified unit.
# 
#     Parameters
#     ----------
#     quantity : simtk.unit.Quantity or float
#         The quantity to be checked
#     compatible_units : simtk.unit.Quantity or simtk.unit.Unit or float
#         Ensure ``quantity`` is either float or numpy array (if ``float`` specified) or is compatible with the specified units
# 
#     Raises
#     ------
#     ValueError if the specified quantity does not have the appropriate dimensionality or type
# 
#     Returns
#     -------
#     is_compatible : bool
#         Returns True if dimensionality is as requested
# 
#     """
#     if unit.is_quantity(compatible_units) or unit.is_unit(compatible_units):
#         try:
#             from simtk.unit.quantity import is_dimensionless
#         except ModuleNotFoundError:
#             from openmm.unit.quantity import is_dimensionless
#         if not is_dimensionless(quantity / compatible_units):
#             raise ValueError('{} does not have units compatible with expected {}'.format(quantity, compatible_units))
#     elif compatible_units == float:
#         if not (isinstance(quantity, float) or isinstance(quantity, np.ndarray)):
#             raise ValueError("'{}' expected to be a float, but was instead {}".format(quantity, type(quantity)))
#     else:
#         raise ValueError("Don't know how to handle compatible_units of {}".format(compatible_units))
# 
#     # Units are compatible if they pass this point
#     return True
# 
# Path: perses/tests/test_geometry_engine.py
# def _get_internal_from_omm(atom_coords, bond_coords, angle_coords, torsion_coords):
#     """
#     Given four atom positions in cartesians, will output the internal positions in spherical coords
# 
#     Parameters
#     ----------
#     atom_coords : unit.Quantity(np.array([x,y,z]), unit = unit.nanometers)
#         x, y, and z cartesians of an atom
#     bond_coords : unit.Quantity(np.array([x,y,z]), unit = unit.nanometers)
#         x, y, and z cartesians of a bond atom
#     angle_coords : unit.Quantity(np.array([x,y,z]), unit = unit.nanometers)
#         x, y, and z cartesians of an angle atom
#     torsion_coords : unit.Quantity(np.array([x,y,z]), unit = unit.nanometers)
#         x, y, and z cartesians of a torsion atom
# 
#     Returns
#     -------
#     r : float
#         radial distance in unit.nanometers
#     theta : float
#         bond angle in radians
#     phi : float
#         torsion angle in radians
#     """
#     #master system, will be used for all three
#     sys = openmm.System()
#     platform = openmm.Platform.getPlatformByName("Reference")
#     for i in range(4):
#         sys.addParticle(1.0*unit.amu)
# 
#     #first, the bond length:
#     bond_sys = openmm.System()
#     bond_sys.addParticle(1.0*unit.amu)
#     bond_sys.addParticle(1.0*unit.amu)
#     bond_force = openmm.CustomBondForce("r")
#     bond_force.addBond(0, 1, [])
#     bond_sys.addForce(bond_force)
#     bond_integrator = openmm.VerletIntegrator(1*unit.femtoseconds)
#     bond_context = openmm.Context(bond_sys, bond_integrator, platform)
#     bond_context.setPositions([atom_coords, bond_coords])
#     bond_state = bond_context.getState(getEnergy=True)
#     r = bond_state.getPotentialEnergy()/unit.kilojoule_per_mole
#     del bond_sys, bond_context, bond_integrator
# 
#     #now, the angle:
#     angle_sys = copy.deepcopy(sys)
#     angle_force = openmm.CustomAngleForce("theta")
#     angle_force.addAngle(0,1,2,[])
#     angle_sys.addForce(angle_force)
#     angle_integrator = openmm.VerletIntegrator(1*unit.femtoseconds)
#     angle_context = openmm.Context(angle_sys, angle_integrator, platform)
#     angle_context.setPositions([atom_coords, bond_coords, angle_coords, torsion_coords])
#     angle_state = angle_context.getState(getEnergy=True)
#     theta = angle_state.getPotentialEnergy()/unit.kilojoule_per_mole
#     del angle_sys, angle_context, angle_integrator
# 
#     #finally, the torsion:
#     torsion_sys = copy.deepcopy(sys)
#     torsion_force = openmm.CustomTorsionForce("theta")
#     torsion_force.addTorsion(0,1,2,3,[])
#     torsion_sys.addForce(torsion_force)
#     torsion_integrator = openmm.VerletIntegrator(1*unit.femtoseconds)
#     torsion_context = openmm.Context(torsion_sys, torsion_integrator, platform)
#     torsion_context.setPositions([atom_coords, bond_coords, angle_coords, torsion_coords])
#     torsion_state = torsion_context.getState(getEnergy=True)
#     phi = torsion_state.getPotentialEnergy()/unit.kilojoule_per_mole
#     del torsion_sys, torsion_context, torsion_integrator
# 
#     return r, theta, phi


import simtk.openmm as openmm
import simtk.unit as unit
import numpy as np
import os
    import perses.rjmc.geometry as geometry
    import simtk.openmm as openmm
    import perses.rjmc.geometry as geometry
    import simtk.openmm as openmm
from openmmtools.constants import kB
from perses.rjmc.geometry import check_dimensionality
from perses.tests.test_geometry_engine import _get_internal_from_omm
    from perses.rjmc import geometry
################################################################################
# Global parameters
################################################################################
temperature = 300.0 * unit.kelvin # unit-bearing temperature
kT = kB * temperature # unit-bearing thermal energy
beta = 1.0/kT # unit-bearing inverse thermal energy
CARBON_MASS = 12.01 # float (implicitly in units of AMU)
REFERENCE_PLATFORM = openmm.Platform.getPlatformByName("Reference")
running_on_github_actions = os.environ.get('GITHUB_ACTIONS', None) == 'true'
#########################################
# Tests
#########################################


# Path: perses/rjmc/geometry.py
# def check_dimensionality(quantity, compatible_units):
#     """
#     Ensure that the specified quantity has units compatible with specified unit.
# 
#     Parameters
#     ----------
#     quantity : simtk.unit.Quantity or float
#         The quantity to be checked
#     compatible_units : simtk.unit.Quantity or simtk.unit.Unit or float
#         Ensure ``quantity`` is either float or numpy array (if ``float`` specified) or is compatible with the specified units
# 
#     Raises
#     ------
#     ValueError if the specified quantity does not have the appropriate dimensionality or type
# 
#     Returns
#     -------
#     is_compatible : bool
#         Returns True if dimensionality is as requested
# 
#     """
#     if unit.is_quantity(compatible_units) or unit.is_unit(compatible_units):
#         try:
#             from simtk.unit.quantity import is_dimensionless
#         except ModuleNotFoundError:
#             from openmm.unit.quantity import is_dimensionless
#         if not is_dimensionless(quantity / compatible_units):
#             raise ValueError('{} does not have units compatible with expected {}'.format(quantity, compatible_units))
#     elif compatible_units == float:
#         if not (isinstance(quantity, float) or isinstance(quantity, np.ndarray)):
#             raise ValueError("'{}' expected to be a float, but was instead {}".format(quantity, type(quantity)))
#     else:
#         raise ValueError("Don't know how to handle compatible_units of {}".format(compatible_units))
# 
#     # Units are compatible if they pass this point
#     return True
# 
# Path: perses/tests/test_geometry_engine.py
# def _get_internal_from_omm(atom_coords, bond_coords, angle_coords, torsion_coords):
#     """
#     Given four atom positions in cartesians, will output the internal positions in spherical coords
# 
#     Parameters
#     ----------
#     atom_coords : unit.Quantity(np.array([x,y,z]), unit = unit.nanometers)
#         x, y, and z cartesians of an atom
#     bond_coords : unit.Quantity(np.array([x,y,z]), unit = unit.nanometers)
#         x, y, and z cartesians of a bond atom
#     angle_coords : unit.Quantity(np.array([x,y,z]), unit = unit.nanometers)
#         x, y, and z cartesians of an angle atom
#     torsion_coords : unit.Quantity(np.array([x,y,z]), unit = unit.nanometers)
#         x, y, and z cartesians of a torsion atom
# 
#     Returns
#     -------
#     r : float
#         radial distance in unit.nanometers
#     theta : float
#         bond angle in radians
#     phi : float
#         torsion angle in radians
#     """
#     #master system, will be used for all three
#     sys = openmm.System()
#     platform = openmm.Platform.getPlatformByName("Reference")
#     for i in range(4):
#         sys.addParticle(1.0*unit.amu)
# 
#     #first, the bond length:
#     bond_sys = openmm.System()
#     bond_sys.addParticle(1.0*unit.amu)
#     bond_sys.addParticle(1.0*unit.amu)
#     bond_force = openmm.CustomBondForce("r")
#     bond_force.addBond(0, 1, [])
#     bond_sys.addForce(bond_force)
#     bond_integrator = openmm.VerletIntegrator(1*unit.femtoseconds)
#     bond_context = openmm.Context(bond_sys, bond_integrator, platform)
#     bond_context.setPositions([atom_coords, bond_coords])
#     bond_state = bond_context.getState(getEnergy=True)
#     r = bond_state.getPotentialEnergy()/unit.kilojoule_per_mole
#     del bond_sys, bond_context, bond_integrator
# 
#     #now, the angle:
#     angle_sys = copy.deepcopy(sys)
#     angle_force = openmm.CustomAngleForce("theta")
#     angle_force.addAngle(0,1,2,[])
#     angle_sys.addForce(angle_force)
#     angle_integrator = openmm.VerletIntegrator(1*unit.femtoseconds)
#     angle_context = openmm.Context(angle_sys, angle_integrator, platform)
#     angle_context.setPositions([atom_coords, bond_coords, angle_coords, torsion_coords])
#     angle_state = angle_context.getState(getEnergy=True)
#     theta = angle_state.getPotentialEnergy()/unit.kilojoule_per_mole
#     del angle_sys, angle_context, angle_integrator
# 
#     #finally, the torsion:
#     torsion_sys = copy.deepcopy(sys)
#     torsion_force = openmm.CustomTorsionForce("theta")
#     torsion_force.addTorsion(0,1,2,3,[])
#     torsion_sys.addForce(torsion_force)
#     torsion_integrator = openmm.VerletIntegrator(1*unit.femtoseconds)
#     torsion_context = openmm.Context(torsion_sys, torsion_integrator, platform)
#     torsion_context.setPositions([atom_coords, bond_coords, angle_coords, torsion_coords])
#     torsion_state = torsion_context.getState(getEnergy=True)
#     phi = torsion_state.getPotentialEnergy()/unit.kilojoule_per_mole
#     del torsion_sys, torsion_context, torsion_integrator
# 
#     return r, theta, phi


# Path: perses/tests/test_coordinate_numba.py
import simtk.openmm as openmm
import simtk.unit as unit
import numpy as np
import os
    import perses.rjmc.geometry as geometry
    import simtk.openmm as openmm
    import perses.rjmc.geometry as geometry
    import simtk.openmm as openmm
from openmmtools.constants import kB
from perses.rjmc.geometry import check_dimensionality
from perses.tests.test_geometry_engine import _get_internal_from_omm
    from perses.rjmc import geometry

################################################################################
# Global parameters
################################################################################
temperature = 300.0 * unit.kelvin # unit-bearing temperature
kT = kB * temperature # unit-bearing thermal energy
beta = 1.0/kT # unit-bearing inverse thermal energy
CARBON_MASS = 12.01 # float (implicitly in units of AMU)
REFERENCE_PLATFORM = openmm.Platform.getPlatformByName("Reference")
running_on_github_actions = os.environ.get('GITHUB_ACTIONS', None) == 'true'
#########################################
# Tests
#########################################


def test_coordinate_conversion():