__all__ = [
"angle",
"convert",
"length",
"clear_default_units",
"set_default_unit",
"set_default_units",
"set_energy_unit",
"set_internal_units",
"set_length_unit",
"set_mass_unit",
"set_quantity_unit",
"set_si_units",
"set_time_unit",
"GeneralUnit",
"akma_time",
"akma_velocity",
"amp",
"angle_minute",
"angle_minutes",
"angle_second",
"angle_seconds",
"angstrom",
"angstroms",
"angstrom2",
"angstrom3",
"angstroms_per_fs",
"atm",
"atomic_mass_constant",
"bar",
"bohr_radii",
"c",
"cal",
"cal_per_mol",
"celsius",
"centimeter",
"centimeters",
"circumference",
"convert",
"coulomb",
"coulomb_per_mol",
"day",
"degree",
"degrees",
"e_charge",
"electron_mass",
"epsilon0",
"fahrenheit",
"farad",
"faraday",
"feet",
"femtogram",
"femtosecond",
"fg_per_mol",
"fortnight",
"four_pi_eps0",
"g_accel",
"g_per_mol",
"gasr",
"grad",
"gradian",
"gradians",
"gram",
"gon",
"G_newton",
"h_planck",
"h_slash",
"hartree",
"hour",
"hundredweight",
"inch",
"int_cal",
"int_cal_per_mol",
"int_kcal",
"int_kcal_per_mol",
"joule",
"J_per_mol",
"k_boltz",
"kcal",
"kcal_per_mol",
"kelvin",
"kilogram",
"kilojoule",
"kilometer",
"kilometers",
"kilometers_per_hour",
"kg_per_mol",
"kJ_per_mol",
"kph",
"megajoule",
"meter",
"meter2",
"meter3",
"meters",
"meters_per_second",
"mg_per_mol",
"microgram",
"micrometer",
"microsecond",
"miles",
"miles_per_hour",
"milligram",
"millimeter",
"millimeters",
"millisecond",
"minute",
"mmHg",
"mod_electron",
"molar_volume",
"mole",
"mph",
"mu0",
"MJ_per_mol",
"nanogram",
"nanometer",
"nanometers",
"nanometer2",
"nanosecond",
"neutron_mass",
"newton",
"ng_per_mol",
"octant",
"octants",
"one_over_four_pi_eps0",
"ounce",
"pascal",
"pg_per_mol",
"picogram",
"picometer",
"picometers",
"picometer2",
"picometer3",
"picosecond",
"pound",
"proton_mass",
"psi",
"quadrant",
"quadrants",
"radian",
"radians",
"revolution",
"revolutions",
"revs",
"second",
"sextant",
"sextants",
"stone",
"tonne",
"tonne_per_mol",
"ug_per_mol",
"volt",
"watt",
"watt_per_mol",
"week",
"yards",
]
# Imported so that it is pythonized
from ..legacy import Units as _Units # noqa: F401
from .. import use_new_api as _use_new_api
from ..legacy.Units import (
akma_time,
akma_velocity,
amp,
angle_minute,
angle_minutes,
angle_second,
angle_seconds,
angstrom,
angstroms,
angstrom2,
angstrom3,
angstroms_per_fs,
atm,
atomic_mass_constant,
bar,
bohr_radii,
c,
cal,
cal_per_mol,
celsius,
centimeter,
centimeters,
circumference,
convert,
coulomb,
coulomb_per_mol,
day,
degree,
degrees,
e_charge,
electron_mass,
epsilon0,
fahrenheit,
farad,
faraday,
feet,
femtogram,
femtosecond,
fg_per_mol,
fortnight,
four_pi_eps0,
g_accel,
g_per_mol,
gasr,
grad,
gradian,
gradians,
gram,
gon,
G_newton,
h_planck,
h_slash,
hartree,
hour,
hundredweight,
inch,
int_cal,
int_cal_per_mol,
int_kcal,
int_kcal_per_mol,
joule,
J_per_mol,
k_boltz,
kcal,
kcal_per_mol,
kelvin,
kilogram,
kilojoule,
kilometer,
kilometers,
kilometers_per_hour,
kg_per_mol,
kJ_per_mol,
kph,
megajoule,
meter,
meter2,
meter3,
meters,
meters_per_second,
mg_per_mol,
microgram,
micrometer,
microsecond,
miles,
miles_per_hour,
milligram,
millimeter,
millimeters,
millisecond,
minute,
mmHg,
mod_electron,
molar_volume,
mole,
mph,
mu0,
MJ_per_mol,
nanogram,
nanometer,
nanometers,
nanometer2,
nanosecond,
neutron_mass,
newton,
ng_per_mol,
octant,
octants,
one_over_four_pi_eps0,
ounce,
pascal,
pg_per_mol,
picogram,
picometer,
picometers,
picometer2,
picometer3,
picosecond,
pound,
proton_mass,
psi,
quadrant,
quadrants,
radian,
radians,
revolution,
revolutions,
revs,
second,
sextant,
sextants,
stone,
tonne,
tonne_per_mol,
ug_per_mol,
volt,
watt,
watt_per_mol,
week,
yards,
GeneralUnit,
)
_use_new_api()
def _fix_generalunit():
def _generalunit_approx_equal(u, v):
if not hasattr(u, "what"):
u = GeneralUnit(u)
if not hasattr(v, "what"):
v = GeneralUnit(v)
if u.what().endswith("Property"):
return _generalunit_approx_equal(u.value(), v)
elif v.what().endswith("Property"):
return _generalunit_approx_equal(u, v.value())
# make sure that the units are the same
if u.has_same_units(v):
from ..search import approx_equal
return approx_equal(u.value(), v.value())
else:
return False
def _generalunit_to_default(obj):
"""Return a floating point value that represents
this value in default units for this dimension
Example
-------
>>> import sire as sr
>>> l = 5 * sr.units.angstrom
>>> sr.units.set_length_unit(sr.units.picometer)
>>> print(l.to_default())
500.0
"""
return obj.value() / obj.get_default().value()
def __generalunit__getitem__(obj, key):
return obj.get_component(key)
def __generalunit__setitem__(obj, key, value):
obj.set_component(key, value)
return obj
GeneralUnit.approx_equal = _generalunit_approx_equal
GeneralUnit.to_default = _generalunit_to_default
GeneralUnit.__setitem__ = __generalunit__setitem__
GeneralUnit.__getitem__ = __generalunit__getitem__
def __generalunit__bool__(obj):
return not obj.is_zero()
def __generalunit__float__(obj):
if not obj.is_dimensionless():
raise TypeError(
f"You cannot convert the dimensioned value {obj} "
"to a dimensionless floating point number."
)
return obj.value()
def __generalunit__int__(obj):
if not obj.is_dimensionless():
raise TypeError(
f"You cannot convert the dimensioned value {obj} "
"to a dimensionless whole number integer."
)
return int(obj.value())
def __generalunit__abs__(obj):
if obj.value() < 0:
return obj * -1
else:
return obj
def __generalunit__pow__(obj, power):
try:
power = float(power)
except Exception:
raise TypeError(
"unsupported operand type(s) for ^: '%s' and '%s'"
% (obj.__class__.__qualname__, power.__class__.__qualname__)
)
if obj.is_zero():
return obj
elif power == 0:
return obj / obj
value = obj.value() ** power
dims = obj.dimensions()
# Compute the new dimensions, rounding floats to 16 decimal places.
new_dims = [round(dim * power, 16) for dim in dims]
# Make sure the new dimensions are integers.
def is_integer(dim):
return dim == int(dim)
if not all(is_integer(dim) for dim in new_dims):
raise ValueError(
"The exponent must be a factor of all the unit dimensions."
)
# Convert to integers.
new_dims = [int(dim) for dim in new_dims]
return GeneralUnit(value, new_dims)
def __generalunit__sqrt__(obj):
return obj**0.5
GeneralUnit.__bool__ = __generalunit__bool__
GeneralUnit.__float__ = __generalunit__float__
GeneralUnit.__int__ = __generalunit__int__
GeneralUnit.__abs__ = __generalunit__abs__
GeneralUnit.__pow__ = __generalunit__pow__
GeneralUnit.sqrt = __generalunit__sqrt__
if not hasattr(GeneralUnit, "to_default"):
_fix_generalunit()
_names = None
def _get_unit_name(unit):
global _names
if _names is None:
_names = {
mole: "mol",
cal: "cal",
joule: "joule",
int_cal: "int_cal",
kcal: "kcal",
kilojoule: "kJ",
int_kcal: "int_kcal",
angstrom: "Å",
picometer: "pm",
nanometer: "nm",
gram: "g",
kilogram: "kg",
picosecond: "ps",
nanosecond: "ns",
femtosecond: "fs",
}
try:
return _names[unit]
except Exception:
pass
return unit._to_cpp_type()
def _incompatible_units(a, b, typ: str):
raise TypeError(
f"Unit {a.unit_string()} is not a {typ}, and so is "
f"incompatible with {b.unit_string()}."
)
[docs]
def set_quantity_unit(q, name: str = None):
"""
Set the default quantity unit to be used for
output and default conversions
"""
if not q.has_same_units(mole):
_incompatible_units(q, mole, "quantity")
if name is None:
name = _get_unit_name(q)
q.set_as_default(name)
[docs]
def set_energy_unit(energy, name: str = None):
"""
Set the default energy unit to be used for
output and default conversions
"""
if not energy.has_same_units(kcal):
_incompatible_units(energy, kcal, "energy")
if name is None:
name = _get_unit_name(energy)
energy.set_as_default(name)
[docs]
def set_length_unit(length, name: str = None):
"""
Set the default length unit to be used for
output and default conversions
"""
if not length.has_same_units(angstrom):
_incompatible_units(length, angstrom, "length")
if name is None:
name = _get_unit_name(length)
length.set_as_default(name)
[docs]
def set_mass_unit(mass, name: str = None):
"""
Set the default mass unit to be used for
output and default conversions
"""
if not mass.has_same_units(gram):
_incompatible_units(mass, gram, "mass")
if name is None:
name = _get_unit_name(mass)
mass.set_as_default(name)
[docs]
def set_time_unit(time, name: str = None):
"""
Set the default time unit to be used for
output and default conversions
"""
if not time.has_same_units(picosecond):
_incompatible_units(time, picosecond, "time")
if name is None:
name = _get_unit_name(time)
time.set_as_default(name)
[docs]
def clear_default_units():
"""
Clear the current set of default units. Note that you will need
to set some units, or else the code will complain.
"""
GeneralUnit.clear_defaults()
[docs]
def set_default_units(units):
"""
Set the default unit names for the units named in the passed
list of strings.
For example, set_default_units(["m"]) would set the default length
unit to "meters", and will print it out using "m" as the string.
Calling set_default_unit(["kcal", "kcal.mol-1"]) would set the default
molar energy unit to kcal_per_mol, and will print it out
using "kcal.mol-1", and the default energy unit to "kcal", printed
out using "kcal".
All of the strings must be something that can be parsed by
the units grammar in GeneralUnit, and should be units only -
they cannot contain values.
"""
if type(units) is not list:
units = [units]
unit_strings = {}
# parse all the units first
for unit in units:
unit_strings[GeneralUnit(1.0, unit)] = unit
# we have fully parsed units, and only have one of each type
for key in unit_strings.keys():
if hasattr(type(key), "set_as_default"):
key.set_as_default(unit_strings[key])
else:
key.setAsDefault(unit_strings[key])
[docs]
def set_default_unit(unit: str):
"""
Set the default unit name for the unit named in the passed
string.
For example, set_default_unit("m") would set the default length
unit to "meters", and will print it out using "m" as the string.
Calling set_default_unit("kcal.mol-1") would set the default
molar energy unit to kcal_per_mol, and will print it out
using "kcal.mol-1"
The string must be something that can be parsed by
the units grammar in GeneralUnit, and should be units only -
they cannot contain values.
"""
if type(unit) is list:
set_default_units(unit)
else:
set_default_units([unit])
[docs]
def set_si_units(scaled: bool = True):
"""
Switch over to using SI units for output and default conversions
If 'scaled' is true, then units scaled appropriately
for atomic-level simulations are chosen.
In this case, we would use
mass: gram (g)
energy: kilojoule (J)
length: nanometer
time: picosecond
quantity: mole
charge: coulomb (C)
angle: radian
temperature: kelvin (K)
Unscaled, we would use
mass: kilogram (g)
energy: joule (J)
length: meter
time: second
quantity: mole
charge: coulomb (C)
angle: radian
temperature: kelvin (K)
"""
try:
GeneralUnit.clear_defaults()
except AttributeError:
# this happens on load before the new api has been activated
pass
if scaled:
set_default_units(
[
"g",
"kJ",
"nm",
"ps",
"mol",
"C",
"rad",
"K",
"kJ mol-1",
"kJ mol-1 nm-1",
"kJ mol-1 nm-2",
"kJ mol-1 nm-3",
"kJ mol-1 rad-1",
"kJ mol-1 rad-2",
"kJ mol-1 K-1",
"kJ mol-1 K-2",
"kJ mol-1 nm^6",
"kJ mol-1 nm^12",
"kJ mol-1 nm^4",
"J s",
"W",
"J mol-1 s",
"W mol-1",
"N",
"atm",
]
)
else:
set_default_units(
[
"kg",
"J",
"m",
"s",
"mol",
"C",
"rad",
"K",
"J mol-1",
"J mol-1 nm-1",
"J mol-1 nm-2",
"J mol-1 nm-3",
"J mol-1 rad-1",
"J mol-1 rad-2",
"J mol-1 K-1",
"J mol-1 K-2",
"J mol-1 nm^6",
"J mol-1 nm^12",
"J mol-1 nm^4",
"J s",
"W",
"J mol-1 s",
"W mol-1",
"N",
"atm",
]
)
[docs]
def set_internal_units():
"""
Switch over to using default (AKMA-style) units for output
and default conversions.
This uses:
mass: gram (g)
energy: kilocalorie (kcal)
length: angstrom
time: picosecond
quantity: mole
charge: mod_electron charges
"""
try:
GeneralUnit.clear_defaults()
except AttributeError:
# this happens on load before the new api has been activated
pass
set_default_units(
[
"g",
"kcal",
"Å",
"ps",
"|e|",
"°",
"K",
"kcal mol-1",
"kcal mol-1 Å-1",
"kcal mol-1 Å-2",
"kcal mol-1 Å-3",
"kcal mol-1 °-1",
"kcal mol-1 °-2",
"kcal mol-1 K-1",
"kcal mol-1 K-2",
"kcal s",
"kcal s-1",
"kcal mol-1 s",
"kcal mol-1 s-1",
"kcal Å-1",
"kcal mol-1 Å^6",
"kcal mol-1 Å^12",
"kcal mol-1 Å^4",
"atm",
]
)
[docs]
def length(length):
"""Convert the passed argument into a length. This will
return `length` if it is already a length, or it will
convert it into a length with default units if this
is a float or something that can be converted to
a float
"""
try:
return float(length) * angstrom.get_default()
except Exception:
pass
if not isinstance(length, type(angstrom)):
raise TypeError(
f"The value '{length}' of type {type(length)} is "
"not a type that is compatible with a GeneralUnit Length"
)
return length
[docs]
def angle(angle):
"""Convert the passed argument into an angle. This will
return 'angle' if it is already an angle, or will
convert it into an angle with default units if this
is a float or something that can be converted to
a float
"""
try:
return float(angle) * degrees.get_default()
except Exception:
pass
if not isinstance(angle, type(degrees)):
raise TypeError(
f"The value '{angle}' of type {type(angle)} is "
"not a type that is compatible with a GeneralUnit angle"
)
return angle
# set internal units on load
set_internal_units()