I am done

This commit is contained in:
2024-10-30 22:14:35 +01:00
parent 720dc28c09
commit 40e2a747cf
36901 changed files with 5011519 additions and 0 deletions

View File

@ -0,0 +1,453 @@
# isort:skip_file
"""
Dimensional analysis and unit systems.
This module defines dimension/unit systems and physical quantities. It is
based on a group-theoretical construction where dimensions are represented as
vectors (coefficients being the exponents), and units are defined as a dimension
to which we added a scale.
Quantities are built from a factor and a unit, and are the basic objects that
one will use when doing computations.
All objects except systems and prefixes can be used in SymPy expressions.
Note that as part of a CAS, various objects do not combine automatically
under operations.
Details about the implementation can be found in the documentation, and we
will not repeat all the explanations we gave there concerning our approach.
Ideas about future developments can be found on the `Github wiki
<https://github.com/sympy/sympy/wiki/Unit-systems>`_, and you should consult
this page if you are willing to help.
Useful functions:
- ``find_unit``: easily lookup pre-defined units.
- ``convert_to(expr, newunit)``: converts an expression into the same
expression expressed in another unit.
"""
from .dimensions import Dimension, DimensionSystem
from .unitsystem import UnitSystem
from .util import convert_to
from .quantities import Quantity
from .definitions.dimension_definitions import (
amount_of_substance, acceleration, action, area,
capacitance, charge, conductance, current, energy,
force, frequency, impedance, inductance, length,
luminous_intensity, magnetic_density,
magnetic_flux, mass, momentum, power, pressure, temperature, time,
velocity, voltage, volume
)
Unit = Quantity
speed = velocity
luminosity = luminous_intensity
magnetic_flux_density = magnetic_density
amount = amount_of_substance
from .prefixes import (
# 10-power based:
yotta,
zetta,
exa,
peta,
tera,
giga,
mega,
kilo,
hecto,
deca,
deci,
centi,
milli,
micro,
nano,
pico,
femto,
atto,
zepto,
yocto,
# 2-power based:
kibi,
mebi,
gibi,
tebi,
pebi,
exbi,
)
from .definitions import (
percent, percents,
permille,
rad, radian, radians,
deg, degree, degrees,
sr, steradian, steradians,
mil, angular_mil, angular_mils,
m, meter, meters,
kg, kilogram, kilograms,
s, second, seconds,
A, ampere, amperes,
K, kelvin, kelvins,
mol, mole, moles,
cd, candela, candelas,
g, gram, grams,
mg, milligram, milligrams,
ug, microgram, micrograms,
t, tonne, metric_ton,
newton, newtons, N,
joule, joules, J,
watt, watts, W,
pascal, pascals, Pa, pa,
hertz, hz, Hz,
coulomb, coulombs, C,
volt, volts, v, V,
ohm, ohms,
siemens, S, mho, mhos,
farad, farads, F,
henry, henrys, H,
tesla, teslas, T,
weber, webers, Wb, wb,
optical_power, dioptre, D,
lux, lx,
katal, kat,
gray, Gy,
becquerel, Bq,
km, kilometer, kilometers,
dm, decimeter, decimeters,
cm, centimeter, centimeters,
mm, millimeter, millimeters,
um, micrometer, micrometers, micron, microns,
nm, nanometer, nanometers,
pm, picometer, picometers,
ft, foot, feet,
inch, inches,
yd, yard, yards,
mi, mile, miles,
nmi, nautical_mile, nautical_miles,
angstrom, angstroms,
ha, hectare,
l, L, liter, liters,
dl, dL, deciliter, deciliters,
cl, cL, centiliter, centiliters,
ml, mL, milliliter, milliliters,
ms, millisecond, milliseconds,
us, microsecond, microseconds,
ns, nanosecond, nanoseconds,
ps, picosecond, picoseconds,
minute, minutes,
h, hour, hours,
day, days,
anomalistic_year, anomalistic_years,
sidereal_year, sidereal_years,
tropical_year, tropical_years,
common_year, common_years,
julian_year, julian_years,
draconic_year, draconic_years,
gaussian_year, gaussian_years,
full_moon_cycle, full_moon_cycles,
year, years,
G, gravitational_constant,
c, speed_of_light,
elementary_charge,
hbar,
planck,
eV, electronvolt, electronvolts,
avogadro_number,
avogadro, avogadro_constant,
boltzmann, boltzmann_constant,
stefan, stefan_boltzmann_constant,
R, molar_gas_constant,
faraday_constant,
josephson_constant,
von_klitzing_constant,
Da, dalton, amu, amus, atomic_mass_unit, atomic_mass_constant,
me, electron_rest_mass,
gee, gees, acceleration_due_to_gravity,
u0, magnetic_constant, vacuum_permeability,
e0, electric_constant, vacuum_permittivity,
Z0, vacuum_impedance,
coulomb_constant, electric_force_constant,
atmosphere, atmospheres, atm,
kPa,
bar, bars,
pound, pounds,
psi,
dHg0,
mmHg, torr,
mmu, mmus, milli_mass_unit,
quart, quarts,
ly, lightyear, lightyears,
au, astronomical_unit, astronomical_units,
planck_mass,
planck_time,
planck_temperature,
planck_length,
planck_charge,
planck_area,
planck_volume,
planck_momentum,
planck_energy,
planck_force,
planck_power,
planck_density,
planck_energy_density,
planck_intensity,
planck_angular_frequency,
planck_pressure,
planck_current,
planck_voltage,
planck_impedance,
planck_acceleration,
bit, bits,
byte,
kibibyte, kibibytes,
mebibyte, mebibytes,
gibibyte, gibibytes,
tebibyte, tebibytes,
pebibyte, pebibytes,
exbibyte, exbibytes,
)
from .systems import (
mks, mksa, si
)
def find_unit(quantity, unit_system="SI"):
"""
Return a list of matching units or dimension names.
- If ``quantity`` is a string -- units/dimensions containing the string
`quantity`.
- If ``quantity`` is a unit or dimension -- units having matching base
units or dimensions.
Examples
========
>>> from sympy.physics import units as u
>>> u.find_unit('charge')
['C', 'coulomb', 'coulombs', 'planck_charge', 'elementary_charge']
>>> u.find_unit(u.charge)
['C', 'coulomb', 'coulombs', 'planck_charge', 'elementary_charge']
>>> u.find_unit("ampere")
['ampere', 'amperes']
>>> u.find_unit('angstrom')
['angstrom', 'angstroms']
>>> u.find_unit('volt')
['volt', 'volts', 'electronvolt', 'electronvolts', 'planck_voltage']
>>> u.find_unit(u.inch**3)[:9]
['L', 'l', 'cL', 'cl', 'dL', 'dl', 'mL', 'ml', 'liter']
"""
unit_system = UnitSystem.get_unit_system(unit_system)
import sympy.physics.units as u
rv = []
if isinstance(quantity, str):
rv = [i for i in dir(u) if quantity in i and isinstance(getattr(u, i), Quantity)]
dim = getattr(u, quantity)
if isinstance(dim, Dimension):
rv.extend(find_unit(dim))
else:
for i in sorted(dir(u)):
other = getattr(u, i)
if not isinstance(other, Quantity):
continue
if isinstance(quantity, Quantity):
if quantity.dimension == other.dimension:
rv.append(str(i))
elif isinstance(quantity, Dimension):
if other.dimension == quantity:
rv.append(str(i))
elif other.dimension == Dimension(unit_system.get_dimensional_expr(quantity)):
rv.append(str(i))
return sorted(set(rv), key=lambda x: (len(x), x))
# NOTE: the old units module had additional variables:
# 'density', 'illuminance', 'resistance'.
# They were not dimensions, but units (old Unit class).
__all__ = [
'Dimension', 'DimensionSystem',
'UnitSystem',
'convert_to',
'Quantity',
'amount_of_substance', 'acceleration', 'action', 'area',
'capacitance', 'charge', 'conductance', 'current', 'energy',
'force', 'frequency', 'impedance', 'inductance', 'length',
'luminous_intensity', 'magnetic_density',
'magnetic_flux', 'mass', 'momentum', 'power', 'pressure', 'temperature', 'time',
'velocity', 'voltage', 'volume',
'Unit',
'speed',
'luminosity',
'magnetic_flux_density',
'amount',
'yotta',
'zetta',
'exa',
'peta',
'tera',
'giga',
'mega',
'kilo',
'hecto',
'deca',
'deci',
'centi',
'milli',
'micro',
'nano',
'pico',
'femto',
'atto',
'zepto',
'yocto',
'kibi',
'mebi',
'gibi',
'tebi',
'pebi',
'exbi',
'percent', 'percents',
'permille',
'rad', 'radian', 'radians',
'deg', 'degree', 'degrees',
'sr', 'steradian', 'steradians',
'mil', 'angular_mil', 'angular_mils',
'm', 'meter', 'meters',
'kg', 'kilogram', 'kilograms',
's', 'second', 'seconds',
'A', 'ampere', 'amperes',
'K', 'kelvin', 'kelvins',
'mol', 'mole', 'moles',
'cd', 'candela', 'candelas',
'g', 'gram', 'grams',
'mg', 'milligram', 'milligrams',
'ug', 'microgram', 'micrograms',
't', 'tonne', 'metric_ton',
'newton', 'newtons', 'N',
'joule', 'joules', 'J',
'watt', 'watts', 'W',
'pascal', 'pascals', 'Pa', 'pa',
'hertz', 'hz', 'Hz',
'coulomb', 'coulombs', 'C',
'volt', 'volts', 'v', 'V',
'ohm', 'ohms',
'siemens', 'S', 'mho', 'mhos',
'farad', 'farads', 'F',
'henry', 'henrys', 'H',
'tesla', 'teslas', 'T',
'weber', 'webers', 'Wb', 'wb',
'optical_power', 'dioptre', 'D',
'lux', 'lx',
'katal', 'kat',
'gray', 'Gy',
'becquerel', 'Bq',
'km', 'kilometer', 'kilometers',
'dm', 'decimeter', 'decimeters',
'cm', 'centimeter', 'centimeters',
'mm', 'millimeter', 'millimeters',
'um', 'micrometer', 'micrometers', 'micron', 'microns',
'nm', 'nanometer', 'nanometers',
'pm', 'picometer', 'picometers',
'ft', 'foot', 'feet',
'inch', 'inches',
'yd', 'yard', 'yards',
'mi', 'mile', 'miles',
'nmi', 'nautical_mile', 'nautical_miles',
'angstrom', 'angstroms',
'ha', 'hectare',
'l', 'L', 'liter', 'liters',
'dl', 'dL', 'deciliter', 'deciliters',
'cl', 'cL', 'centiliter', 'centiliters',
'ml', 'mL', 'milliliter', 'milliliters',
'ms', 'millisecond', 'milliseconds',
'us', 'microsecond', 'microseconds',
'ns', 'nanosecond', 'nanoseconds',
'ps', 'picosecond', 'picoseconds',
'minute', 'minutes',
'h', 'hour', 'hours',
'day', 'days',
'anomalistic_year', 'anomalistic_years',
'sidereal_year', 'sidereal_years',
'tropical_year', 'tropical_years',
'common_year', 'common_years',
'julian_year', 'julian_years',
'draconic_year', 'draconic_years',
'gaussian_year', 'gaussian_years',
'full_moon_cycle', 'full_moon_cycles',
'year', 'years',
'G', 'gravitational_constant',
'c', 'speed_of_light',
'elementary_charge',
'hbar',
'planck',
'eV', 'electronvolt', 'electronvolts',
'avogadro_number',
'avogadro', 'avogadro_constant',
'boltzmann', 'boltzmann_constant',
'stefan', 'stefan_boltzmann_constant',
'R', 'molar_gas_constant',
'faraday_constant',
'josephson_constant',
'von_klitzing_constant',
'Da', 'dalton', 'amu', 'amus', 'atomic_mass_unit', 'atomic_mass_constant',
'me', 'electron_rest_mass',
'gee', 'gees', 'acceleration_due_to_gravity',
'u0', 'magnetic_constant', 'vacuum_permeability',
'e0', 'electric_constant', 'vacuum_permittivity',
'Z0', 'vacuum_impedance',
'coulomb_constant', 'electric_force_constant',
'atmosphere', 'atmospheres', 'atm',
'kPa',
'bar', 'bars',
'pound', 'pounds',
'psi',
'dHg0',
'mmHg', 'torr',
'mmu', 'mmus', 'milli_mass_unit',
'quart', 'quarts',
'ly', 'lightyear', 'lightyears',
'au', 'astronomical_unit', 'astronomical_units',
'planck_mass',
'planck_time',
'planck_temperature',
'planck_length',
'planck_charge',
'planck_area',
'planck_volume',
'planck_momentum',
'planck_energy',
'planck_force',
'planck_power',
'planck_density',
'planck_energy_density',
'planck_intensity',
'planck_angular_frequency',
'planck_pressure',
'planck_current',
'planck_voltage',
'planck_impedance',
'planck_acceleration',
'bit', 'bits',
'byte',
'kibibyte', 'kibibytes',
'mebibyte', 'mebibytes',
'gibibyte', 'gibibytes',
'tebibyte', 'tebibytes',
'pebibyte', 'pebibytes',
'exbibyte', 'exbibytes',
'mks', 'mksa', 'si',
]

View File

@ -0,0 +1,265 @@
from .unit_definitions import (
percent, percents,
permille,
rad, radian, radians,
deg, degree, degrees,
sr, steradian, steradians,
mil, angular_mil, angular_mils,
m, meter, meters,
kg, kilogram, kilograms,
s, second, seconds,
A, ampere, amperes,
K, kelvin, kelvins,
mol, mole, moles,
cd, candela, candelas,
g, gram, grams,
mg, milligram, milligrams,
ug, microgram, micrograms,
t, tonne, metric_ton,
newton, newtons, N,
joule, joules, J,
watt, watts, W,
pascal, pascals, Pa, pa,
hertz, hz, Hz,
coulomb, coulombs, C,
volt, volts, v, V,
ohm, ohms,
siemens, S, mho, mhos,
farad, farads, F,
henry, henrys, H,
tesla, teslas, T,
weber, webers, Wb, wb,
optical_power, dioptre, D,
lux, lx,
katal, kat,
gray, Gy,
becquerel, Bq,
km, kilometer, kilometers,
dm, decimeter, decimeters,
cm, centimeter, centimeters,
mm, millimeter, millimeters,
um, micrometer, micrometers, micron, microns,
nm, nanometer, nanometers,
pm, picometer, picometers,
ft, foot, feet,
inch, inches,
yd, yard, yards,
mi, mile, miles,
nmi, nautical_mile, nautical_miles,
ha, hectare,
l, L, liter, liters,
dl, dL, deciliter, deciliters,
cl, cL, centiliter, centiliters,
ml, mL, milliliter, milliliters,
ms, millisecond, milliseconds,
us, microsecond, microseconds,
ns, nanosecond, nanoseconds,
ps, picosecond, picoseconds,
minute, minutes,
h, hour, hours,
day, days,
anomalistic_year, anomalistic_years,
sidereal_year, sidereal_years,
tropical_year, tropical_years,
common_year, common_years,
julian_year, julian_years,
draconic_year, draconic_years,
gaussian_year, gaussian_years,
full_moon_cycle, full_moon_cycles,
year, years,
G, gravitational_constant,
c, speed_of_light,
elementary_charge,
hbar,
planck,
eV, electronvolt, electronvolts,
avogadro_number,
avogadro, avogadro_constant,
boltzmann, boltzmann_constant,
stefan, stefan_boltzmann_constant,
R, molar_gas_constant,
faraday_constant,
josephson_constant,
von_klitzing_constant,
Da, dalton, amu, amus, atomic_mass_unit, atomic_mass_constant,
me, electron_rest_mass,
gee, gees, acceleration_due_to_gravity,
u0, magnetic_constant, vacuum_permeability,
e0, electric_constant, vacuum_permittivity,
Z0, vacuum_impedance,
coulomb_constant, coulombs_constant, electric_force_constant,
atmosphere, atmospheres, atm,
kPa, kilopascal,
bar, bars,
pound, pounds,
psi,
dHg0,
mmHg, torr,
mmu, mmus, milli_mass_unit,
quart, quarts,
angstrom, angstroms,
ly, lightyear, lightyears,
au, astronomical_unit, astronomical_units,
planck_mass,
planck_time,
planck_temperature,
planck_length,
planck_charge,
planck_area,
planck_volume,
planck_momentum,
planck_energy,
planck_force,
planck_power,
planck_density,
planck_energy_density,
planck_intensity,
planck_angular_frequency,
planck_pressure,
planck_current,
planck_voltage,
planck_impedance,
planck_acceleration,
bit, bits,
byte,
kibibyte, kibibytes,
mebibyte, mebibytes,
gibibyte, gibibytes,
tebibyte, tebibytes,
pebibyte, pebibytes,
exbibyte, exbibytes,
curie, rutherford
)
__all__ = [
'percent', 'percents',
'permille',
'rad', 'radian', 'radians',
'deg', 'degree', 'degrees',
'sr', 'steradian', 'steradians',
'mil', 'angular_mil', 'angular_mils',
'm', 'meter', 'meters',
'kg', 'kilogram', 'kilograms',
's', 'second', 'seconds',
'A', 'ampere', 'amperes',
'K', 'kelvin', 'kelvins',
'mol', 'mole', 'moles',
'cd', 'candela', 'candelas',
'g', 'gram', 'grams',
'mg', 'milligram', 'milligrams',
'ug', 'microgram', 'micrograms',
't', 'tonne', 'metric_ton',
'newton', 'newtons', 'N',
'joule', 'joules', 'J',
'watt', 'watts', 'W',
'pascal', 'pascals', 'Pa', 'pa',
'hertz', 'hz', 'Hz',
'coulomb', 'coulombs', 'C',
'volt', 'volts', 'v', 'V',
'ohm', 'ohms',
'siemens', 'S', 'mho', 'mhos',
'farad', 'farads', 'F',
'henry', 'henrys', 'H',
'tesla', 'teslas', 'T',
'weber', 'webers', 'Wb', 'wb',
'optical_power', 'dioptre', 'D',
'lux', 'lx',
'katal', 'kat',
'gray', 'Gy',
'becquerel', 'Bq',
'km', 'kilometer', 'kilometers',
'dm', 'decimeter', 'decimeters',
'cm', 'centimeter', 'centimeters',
'mm', 'millimeter', 'millimeters',
'um', 'micrometer', 'micrometers', 'micron', 'microns',
'nm', 'nanometer', 'nanometers',
'pm', 'picometer', 'picometers',
'ft', 'foot', 'feet',
'inch', 'inches',
'yd', 'yard', 'yards',
'mi', 'mile', 'miles',
'nmi', 'nautical_mile', 'nautical_miles',
'ha', 'hectare',
'l', 'L', 'liter', 'liters',
'dl', 'dL', 'deciliter', 'deciliters',
'cl', 'cL', 'centiliter', 'centiliters',
'ml', 'mL', 'milliliter', 'milliliters',
'ms', 'millisecond', 'milliseconds',
'us', 'microsecond', 'microseconds',
'ns', 'nanosecond', 'nanoseconds',
'ps', 'picosecond', 'picoseconds',
'minute', 'minutes',
'h', 'hour', 'hours',
'day', 'days',
'anomalistic_year', 'anomalistic_years',
'sidereal_year', 'sidereal_years',
'tropical_year', 'tropical_years',
'common_year', 'common_years',
'julian_year', 'julian_years',
'draconic_year', 'draconic_years',
'gaussian_year', 'gaussian_years',
'full_moon_cycle', 'full_moon_cycles',
'year', 'years',
'G', 'gravitational_constant',
'c', 'speed_of_light',
'elementary_charge',
'hbar',
'planck',
'eV', 'electronvolt', 'electronvolts',
'avogadro_number',
'avogadro', 'avogadro_constant',
'boltzmann', 'boltzmann_constant',
'stefan', 'stefan_boltzmann_constant',
'R', 'molar_gas_constant',
'faraday_constant',
'josephson_constant',
'von_klitzing_constant',
'Da', 'dalton', 'amu', 'amus', 'atomic_mass_unit', 'atomic_mass_constant',
'me', 'electron_rest_mass',
'gee', 'gees', 'acceleration_due_to_gravity',
'u0', 'magnetic_constant', 'vacuum_permeability',
'e0', 'electric_constant', 'vacuum_permittivity',
'Z0', 'vacuum_impedance',
'coulomb_constant', 'coulombs_constant', 'electric_force_constant',
'atmosphere', 'atmospheres', 'atm',
'kPa', 'kilopascal',
'bar', 'bars',
'pound', 'pounds',
'psi',
'dHg0',
'mmHg', 'torr',
'mmu', 'mmus', 'milli_mass_unit',
'quart', 'quarts',
'angstrom', 'angstroms',
'ly', 'lightyear', 'lightyears',
'au', 'astronomical_unit', 'astronomical_units',
'planck_mass',
'planck_time',
'planck_temperature',
'planck_length',
'planck_charge',
'planck_area',
'planck_volume',
'planck_momentum',
'planck_energy',
'planck_force',
'planck_power',
'planck_density',
'planck_energy_density',
'planck_intensity',
'planck_angular_frequency',
'planck_pressure',
'planck_current',
'planck_voltage',
'planck_impedance',
'planck_acceleration',
'bit', 'bits',
'byte',
'kibibyte', 'kibibytes',
'mebibyte', 'mebibytes',
'gibibyte', 'gibibytes',
'tebibyte', 'tebibytes',
'pebibyte', 'pebibytes',
'exbibyte', 'exbibytes',
'curie', 'rutherford',
]

View File

@ -0,0 +1,43 @@
from sympy.physics.units import Dimension
angle = Dimension(name="angle") # type: Dimension
# base dimensions (MKS)
length = Dimension(name="length", symbol="L")
mass = Dimension(name="mass", symbol="M")
time = Dimension(name="time", symbol="T")
# base dimensions (MKSA not in MKS)
current = Dimension(name='current', symbol='I') # type: Dimension
# other base dimensions:
temperature = Dimension("temperature", "T") # type: Dimension
amount_of_substance = Dimension("amount_of_substance") # type: Dimension
luminous_intensity = Dimension("luminous_intensity") # type: Dimension
# derived dimensions (MKS)
velocity = Dimension(name="velocity")
acceleration = Dimension(name="acceleration")
momentum = Dimension(name="momentum")
force = Dimension(name="force", symbol="F")
energy = Dimension(name="energy", symbol="E")
power = Dimension(name="power")
pressure = Dimension(name="pressure")
frequency = Dimension(name="frequency", symbol="f")
action = Dimension(name="action", symbol="A")
area = Dimension("area")
volume = Dimension("volume")
# derived dimensions (MKSA not in MKS)
voltage = Dimension(name='voltage', symbol='U') # type: Dimension
impedance = Dimension(name='impedance', symbol='Z') # type: Dimension
conductance = Dimension(name='conductance', symbol='G') # type: Dimension
capacitance = Dimension(name='capacitance') # type: Dimension
inductance = Dimension(name='inductance') # type: Dimension
charge = Dimension(name='charge', symbol='Q') # type: Dimension
magnetic_density = Dimension(name='magnetic_density', symbol='B') # type: Dimension
magnetic_flux = Dimension(name='magnetic_flux') # type: Dimension
# Dimensions in information theory:
information = Dimension(name='information') # type: Dimension

View File

@ -0,0 +1,407 @@
from sympy.physics.units.definitions.dimension_definitions import current, temperature, amount_of_substance, \
luminous_intensity, angle, charge, voltage, impedance, conductance, capacitance, inductance, magnetic_density, \
magnetic_flux, information
from sympy.core.numbers import (Rational, pi)
from sympy.core.singleton import S as S_singleton
from sympy.physics.units.prefixes import kilo, mega, milli, micro, deci, centi, nano, pico, kibi, mebi, gibi, tebi, pebi, exbi
from sympy.physics.units.quantities import PhysicalConstant, Quantity
One = S_singleton.One
#### UNITS ####
# Dimensionless:
percent = percents = Quantity("percent", latex_repr=r"\%")
percent.set_global_relative_scale_factor(Rational(1, 100), One)
permille = Quantity("permille")
permille.set_global_relative_scale_factor(Rational(1, 1000), One)
# Angular units (dimensionless)
rad = radian = radians = Quantity("radian", abbrev="rad")
radian.set_global_dimension(angle)
deg = degree = degrees = Quantity("degree", abbrev="deg", latex_repr=r"^\circ")
degree.set_global_relative_scale_factor(pi/180, radian)
sr = steradian = steradians = Quantity("steradian", abbrev="sr")
mil = angular_mil = angular_mils = Quantity("angular_mil", abbrev="mil")
# Base units:
m = meter = meters = Quantity("meter", abbrev="m")
# gram; used to define its prefixed units
g = gram = grams = Quantity("gram", abbrev="g")
# NOTE: the `kilogram` has scale factor 1000. In SI, kg is a base unit, but
# nonetheless we are trying to be compatible with the `kilo` prefix. In a
# similar manner, people using CGS or gaussian units could argue that the
# `centimeter` rather than `meter` is the fundamental unit for length, but the
# scale factor of `centimeter` will be kept as 1/100 to be compatible with the
# `centi` prefix. The current state of the code assumes SI unit dimensions, in
# the future this module will be modified in order to be unit system-neutral
# (that is, support all kinds of unit systems).
kg = kilogram = kilograms = Quantity("kilogram", abbrev="kg")
kg.set_global_relative_scale_factor(kilo, gram)
s = second = seconds = Quantity("second", abbrev="s")
A = ampere = amperes = Quantity("ampere", abbrev='A')
ampere.set_global_dimension(current)
K = kelvin = kelvins = Quantity("kelvin", abbrev='K')
kelvin.set_global_dimension(temperature)
mol = mole = moles = Quantity("mole", abbrev="mol")
mole.set_global_dimension(amount_of_substance)
cd = candela = candelas = Quantity("candela", abbrev="cd")
candela.set_global_dimension(luminous_intensity)
# derived units
newton = newtons = N = Quantity("newton", abbrev="N")
kilonewton = kilonewtons = kN = Quantity("kilonewton", abbrev="kN")
kilonewton.set_global_relative_scale_factor(kilo, newton)
meganewton = meganewtons = MN = Quantity("meganewton", abbrev="MN")
meganewton.set_global_relative_scale_factor(mega, newton)
joule = joules = J = Quantity("joule", abbrev="J")
watt = watts = W = Quantity("watt", abbrev="W")
pascal = pascals = Pa = pa = Quantity("pascal", abbrev="Pa")
hertz = hz = Hz = Quantity("hertz", abbrev="Hz")
# CGS derived units:
dyne = Quantity("dyne")
dyne.set_global_relative_scale_factor(One/10**5, newton)
erg = Quantity("erg")
erg.set_global_relative_scale_factor(One/10**7, joule)
# MKSA extension to MKS: derived units
coulomb = coulombs = C = Quantity("coulomb", abbrev='C')
coulomb.set_global_dimension(charge)
volt = volts = v = V = Quantity("volt", abbrev='V')
volt.set_global_dimension(voltage)
ohm = ohms = Quantity("ohm", abbrev='ohm', latex_repr=r"\Omega")
ohm.set_global_dimension(impedance)
siemens = S = mho = mhos = Quantity("siemens", abbrev='S')
siemens.set_global_dimension(conductance)
farad = farads = F = Quantity("farad", abbrev='F')
farad.set_global_dimension(capacitance)
henry = henrys = H = Quantity("henry", abbrev='H')
henry.set_global_dimension(inductance)
tesla = teslas = T = Quantity("tesla", abbrev='T')
tesla.set_global_dimension(magnetic_density)
weber = webers = Wb = wb = Quantity("weber", abbrev='Wb')
weber.set_global_dimension(magnetic_flux)
# CGS units for electromagnetic quantities:
statampere = Quantity("statampere")
statcoulomb = statC = franklin = Quantity("statcoulomb", abbrev="statC")
statvolt = Quantity("statvolt")
gauss = Quantity("gauss")
maxwell = Quantity("maxwell")
debye = Quantity("debye")
oersted = Quantity("oersted")
# Other derived units:
optical_power = dioptre = diopter = D = Quantity("dioptre")
lux = lx = Quantity("lux", abbrev="lx")
# katal is the SI unit of catalytic activity
katal = kat = Quantity("katal", abbrev="kat")
# gray is the SI unit of absorbed dose
gray = Gy = Quantity("gray")
# becquerel is the SI unit of radioactivity
becquerel = Bq = Quantity("becquerel", abbrev="Bq")
# Common mass units
mg = milligram = milligrams = Quantity("milligram", abbrev="mg")
mg.set_global_relative_scale_factor(milli, gram)
ug = microgram = micrograms = Quantity("microgram", abbrev="ug", latex_repr=r"\mu\text{g}")
ug.set_global_relative_scale_factor(micro, gram)
# Atomic mass constant
Da = dalton = amu = amus = atomic_mass_unit = atomic_mass_constant = PhysicalConstant("atomic_mass_constant")
t = metric_ton = tonne = Quantity("tonne", abbrev="t")
tonne.set_global_relative_scale_factor(mega, gram)
# Electron rest mass
me = electron_rest_mass = Quantity("electron_rest_mass", abbrev="me")
# Common length units
km = kilometer = kilometers = Quantity("kilometer", abbrev="km")
km.set_global_relative_scale_factor(kilo, meter)
dm = decimeter = decimeters = Quantity("decimeter", abbrev="dm")
dm.set_global_relative_scale_factor(deci, meter)
cm = centimeter = centimeters = Quantity("centimeter", abbrev="cm")
cm.set_global_relative_scale_factor(centi, meter)
mm = millimeter = millimeters = Quantity("millimeter", abbrev="mm")
mm.set_global_relative_scale_factor(milli, meter)
um = micrometer = micrometers = micron = microns = \
Quantity("micrometer", abbrev="um", latex_repr=r'\mu\text{m}')
um.set_global_relative_scale_factor(micro, meter)
nm = nanometer = nanometers = Quantity("nanometer", abbrev="nm")
nm.set_global_relative_scale_factor(nano, meter)
pm = picometer = picometers = Quantity("picometer", abbrev="pm")
pm.set_global_relative_scale_factor(pico, meter)
ft = foot = feet = Quantity("foot", abbrev="ft")
ft.set_global_relative_scale_factor(Rational(3048, 10000), meter)
inch = inches = Quantity("inch")
inch.set_global_relative_scale_factor(Rational(1, 12), foot)
yd = yard = yards = Quantity("yard", abbrev="yd")
yd.set_global_relative_scale_factor(3, feet)
mi = mile = miles = Quantity("mile")
mi.set_global_relative_scale_factor(5280, feet)
nmi = nautical_mile = nautical_miles = Quantity("nautical_mile")
nmi.set_global_relative_scale_factor(6076, feet)
angstrom = angstroms = Quantity("angstrom", latex_repr=r'\r{A}')
angstrom.set_global_relative_scale_factor(Rational(1, 10**10), meter)
# Common volume and area units
ha = hectare = Quantity("hectare", abbrev="ha")
l = L = liter = liters = Quantity("liter", abbrev="l")
dl = dL = deciliter = deciliters = Quantity("deciliter", abbrev="dl")
dl.set_global_relative_scale_factor(Rational(1, 10), liter)
cl = cL = centiliter = centiliters = Quantity("centiliter", abbrev="cl")
cl.set_global_relative_scale_factor(Rational(1, 100), liter)
ml = mL = milliliter = milliliters = Quantity("milliliter", abbrev="ml")
ml.set_global_relative_scale_factor(Rational(1, 1000), liter)
# Common time units
ms = millisecond = milliseconds = Quantity("millisecond", abbrev="ms")
millisecond.set_global_relative_scale_factor(milli, second)
us = microsecond = microseconds = Quantity("microsecond", abbrev="us", latex_repr=r'\mu\text{s}')
microsecond.set_global_relative_scale_factor(micro, second)
ns = nanosecond = nanoseconds = Quantity("nanosecond", abbrev="ns")
nanosecond.set_global_relative_scale_factor(nano, second)
ps = picosecond = picoseconds = Quantity("picosecond", abbrev="ps")
picosecond.set_global_relative_scale_factor(pico, second)
minute = minutes = Quantity("minute")
minute.set_global_relative_scale_factor(60, second)
h = hour = hours = Quantity("hour")
hour.set_global_relative_scale_factor(60, minute)
day = days = Quantity("day")
day.set_global_relative_scale_factor(24, hour)
anomalistic_year = anomalistic_years = Quantity("anomalistic_year")
anomalistic_year.set_global_relative_scale_factor(365.259636, day)
sidereal_year = sidereal_years = Quantity("sidereal_year")
sidereal_year.set_global_relative_scale_factor(31558149.540, seconds)
tropical_year = tropical_years = Quantity("tropical_year")
tropical_year.set_global_relative_scale_factor(365.24219, day)
common_year = common_years = Quantity("common_year")
common_year.set_global_relative_scale_factor(365, day)
julian_year = julian_years = Quantity("julian_year")
julian_year.set_global_relative_scale_factor((365 + One/4), day)
draconic_year = draconic_years = Quantity("draconic_year")
draconic_year.set_global_relative_scale_factor(346.62, day)
gaussian_year = gaussian_years = Quantity("gaussian_year")
gaussian_year.set_global_relative_scale_factor(365.2568983, day)
full_moon_cycle = full_moon_cycles = Quantity("full_moon_cycle")
full_moon_cycle.set_global_relative_scale_factor(411.78443029, day)
year = years = tropical_year
#### CONSTANTS ####
# Newton constant
G = gravitational_constant = PhysicalConstant("gravitational_constant", abbrev="G")
# speed of light
c = speed_of_light = PhysicalConstant("speed_of_light", abbrev="c")
# elementary charge
elementary_charge = PhysicalConstant("elementary_charge", abbrev="e")
# Planck constant
planck = PhysicalConstant("planck", abbrev="h")
# Reduced Planck constant
hbar = PhysicalConstant("hbar", abbrev="hbar")
# Electronvolt
eV = electronvolt = electronvolts = PhysicalConstant("electronvolt", abbrev="eV")
# Avogadro number
avogadro_number = PhysicalConstant("avogadro_number")
# Avogadro constant
avogadro = avogadro_constant = PhysicalConstant("avogadro_constant")
# Boltzmann constant
boltzmann = boltzmann_constant = PhysicalConstant("boltzmann_constant")
# Stefan-Boltzmann constant
stefan = stefan_boltzmann_constant = PhysicalConstant("stefan_boltzmann_constant")
# Molar gas constant
R = molar_gas_constant = PhysicalConstant("molar_gas_constant", abbrev="R")
# Faraday constant
faraday_constant = PhysicalConstant("faraday_constant")
# Josephson constant
josephson_constant = PhysicalConstant("josephson_constant", abbrev="K_j")
# Von Klitzing constant
von_klitzing_constant = PhysicalConstant("von_klitzing_constant", abbrev="R_k")
# Acceleration due to gravity (on the Earth surface)
gee = gees = acceleration_due_to_gravity = PhysicalConstant("acceleration_due_to_gravity", abbrev="g")
# magnetic constant:
u0 = magnetic_constant = vacuum_permeability = PhysicalConstant("magnetic_constant")
# electric constat:
e0 = electric_constant = vacuum_permittivity = PhysicalConstant("vacuum_permittivity")
# vacuum impedance:
Z0 = vacuum_impedance = PhysicalConstant("vacuum_impedance", abbrev='Z_0', latex_repr=r'Z_{0}')
# Coulomb's constant:
coulomb_constant = coulombs_constant = electric_force_constant = \
PhysicalConstant("coulomb_constant", abbrev="k_e")
atmosphere = atmospheres = atm = Quantity("atmosphere", abbrev="atm")
kPa = kilopascal = Quantity("kilopascal", abbrev="kPa")
kilopascal.set_global_relative_scale_factor(kilo, Pa)
bar = bars = Quantity("bar", abbrev="bar")
pound = pounds = Quantity("pound") # exact
psi = Quantity("psi")
dHg0 = 13.5951 # approx value at 0 C
mmHg = torr = Quantity("mmHg")
atmosphere.set_global_relative_scale_factor(101325, pascal)
bar.set_global_relative_scale_factor(100, kPa)
pound.set_global_relative_scale_factor(Rational(45359237, 100000000), kg)
mmu = mmus = milli_mass_unit = Quantity("milli_mass_unit")
quart = quarts = Quantity("quart")
# Other convenient units and magnitudes
ly = lightyear = lightyears = Quantity("lightyear", abbrev="ly")
au = astronomical_unit = astronomical_units = Quantity("astronomical_unit", abbrev="AU")
# Fundamental Planck units:
planck_mass = Quantity("planck_mass", abbrev="m_P", latex_repr=r'm_\text{P}')
planck_time = Quantity("planck_time", abbrev="t_P", latex_repr=r't_\text{P}')
planck_temperature = Quantity("planck_temperature", abbrev="T_P",
latex_repr=r'T_\text{P}')
planck_length = Quantity("planck_length", abbrev="l_P", latex_repr=r'l_\text{P}')
planck_charge = Quantity("planck_charge", abbrev="q_P", latex_repr=r'q_\text{P}')
# Derived Planck units:
planck_area = Quantity("planck_area")
planck_volume = Quantity("planck_volume")
planck_momentum = Quantity("planck_momentum")
planck_energy = Quantity("planck_energy", abbrev="E_P", latex_repr=r'E_\text{P}')
planck_force = Quantity("planck_force", abbrev="F_P", latex_repr=r'F_\text{P}')
planck_power = Quantity("planck_power", abbrev="P_P", latex_repr=r'P_\text{P}')
planck_density = Quantity("planck_density", abbrev="rho_P", latex_repr=r'\rho_\text{P}')
planck_energy_density = Quantity("planck_energy_density", abbrev="rho^E_P")
planck_intensity = Quantity("planck_intensity", abbrev="I_P", latex_repr=r'I_\text{P}')
planck_angular_frequency = Quantity("planck_angular_frequency", abbrev="omega_P",
latex_repr=r'\omega_\text{P}')
planck_pressure = Quantity("planck_pressure", abbrev="p_P", latex_repr=r'p_\text{P}')
planck_current = Quantity("planck_current", abbrev="I_P", latex_repr=r'I_\text{P}')
planck_voltage = Quantity("planck_voltage", abbrev="V_P", latex_repr=r'V_\text{P}')
planck_impedance = Quantity("planck_impedance", abbrev="Z_P", latex_repr=r'Z_\text{P}')
planck_acceleration = Quantity("planck_acceleration", abbrev="a_P",
latex_repr=r'a_\text{P}')
# Information theory units:
bit = bits = Quantity("bit")
bit.set_global_dimension(information)
byte = bytes = Quantity("byte")
kibibyte = kibibytes = Quantity("kibibyte")
mebibyte = mebibytes = Quantity("mebibyte")
gibibyte = gibibytes = Quantity("gibibyte")
tebibyte = tebibytes = Quantity("tebibyte")
pebibyte = pebibytes = Quantity("pebibyte")
exbibyte = exbibytes = Quantity("exbibyte")
byte.set_global_relative_scale_factor(8, bit)
kibibyte.set_global_relative_scale_factor(kibi, byte)
mebibyte.set_global_relative_scale_factor(mebi, byte)
gibibyte.set_global_relative_scale_factor(gibi, byte)
tebibyte.set_global_relative_scale_factor(tebi, byte)
pebibyte.set_global_relative_scale_factor(pebi, byte)
exbibyte.set_global_relative_scale_factor(exbi, byte)
# Older units for radioactivity
curie = Ci = Quantity("curie", abbrev="Ci")
rutherford = Rd = Quantity("rutherford", abbrev="Rd")

View File

@ -0,0 +1,590 @@
"""
Definition of physical dimensions.
Unit systems will be constructed on top of these dimensions.
Most of the examples in the doc use MKS system and are presented from the
computer point of view: from a human point, adding length to time is not legal
in MKS but it is in natural system; for a computer in natural system there is
no time dimension (but a velocity dimension instead) - in the basis - so the
question of adding time to length has no meaning.
"""
from __future__ import annotations
import collections
from functools import reduce
from sympy.core.basic import Basic
from sympy.core.containers import (Dict, Tuple)
from sympy.core.singleton import S
from sympy.core.sorting import default_sort_key
from sympy.core.symbol import Symbol
from sympy.core.sympify import sympify
from sympy.matrices.dense import Matrix
from sympy.functions.elementary.trigonometric import TrigonometricFunction
from sympy.core.expr import Expr
from sympy.core.power import Pow
class _QuantityMapper:
_quantity_scale_factors_global: dict[Expr, Expr] = {}
_quantity_dimensional_equivalence_map_global: dict[Expr, Expr] = {}
_quantity_dimension_global: dict[Expr, Expr] = {}
def __init__(self, *args, **kwargs):
self._quantity_dimension_map = {}
self._quantity_scale_factors = {}
def set_quantity_dimension(self, quantity, dimension):
"""
Set the dimension for the quantity in a unit system.
If this relation is valid in every unit system, use
``quantity.set_global_dimension(dimension)`` instead.
"""
from sympy.physics.units import Quantity
dimension = sympify(dimension)
if not isinstance(dimension, Dimension):
if dimension == 1:
dimension = Dimension(1)
else:
raise ValueError("expected dimension or 1")
elif isinstance(dimension, Quantity):
dimension = self.get_quantity_dimension(dimension)
self._quantity_dimension_map[quantity] = dimension
def set_quantity_scale_factor(self, quantity, scale_factor):
"""
Set the scale factor of a quantity relative to another quantity.
It should be used only once per quantity to just one other quantity,
the algorithm will then be able to compute the scale factors to all
other quantities.
In case the scale factor is valid in every unit system, please use
``quantity.set_global_relative_scale_factor(scale_factor)`` instead.
"""
from sympy.physics.units import Quantity
from sympy.physics.units.prefixes import Prefix
scale_factor = sympify(scale_factor)
# replace all prefixes by their ratio to canonical units:
scale_factor = scale_factor.replace(
lambda x: isinstance(x, Prefix),
lambda x: x.scale_factor
)
# replace all quantities by their ratio to canonical units:
scale_factor = scale_factor.replace(
lambda x: isinstance(x, Quantity),
lambda x: self.get_quantity_scale_factor(x)
)
self._quantity_scale_factors[quantity] = scale_factor
def get_quantity_dimension(self, unit):
from sympy.physics.units import Quantity
# First look-up the local dimension map, then the global one:
if unit in self._quantity_dimension_map:
return self._quantity_dimension_map[unit]
if unit in self._quantity_dimension_global:
return self._quantity_dimension_global[unit]
if unit in self._quantity_dimensional_equivalence_map_global:
dep_unit = self._quantity_dimensional_equivalence_map_global[unit]
if isinstance(dep_unit, Quantity):
return self.get_quantity_dimension(dep_unit)
else:
return Dimension(self.get_dimensional_expr(dep_unit))
if isinstance(unit, Quantity):
return Dimension(unit.name)
else:
return Dimension(1)
def get_quantity_scale_factor(self, unit):
if unit in self._quantity_scale_factors:
return self._quantity_scale_factors[unit]
if unit in self._quantity_scale_factors_global:
mul_factor, other_unit = self._quantity_scale_factors_global[unit]
return mul_factor*self.get_quantity_scale_factor(other_unit)
return S.One
class Dimension(Expr):
"""
This class represent the dimension of a physical quantities.
The ``Dimension`` constructor takes as parameters a name and an optional
symbol.
For example, in classical mechanics we know that time is different from
temperature and dimensions make this difference (but they do not provide
any measure of these quantites.
>>> from sympy.physics.units import Dimension
>>> length = Dimension('length')
>>> length
Dimension(length)
>>> time = Dimension('time')
>>> time
Dimension(time)
Dimensions can be composed using multiplication, division and
exponentiation (by a number) to give new dimensions. Addition and
subtraction is defined only when the two objects are the same dimension.
>>> velocity = length / time
>>> velocity
Dimension(length/time)
It is possible to use a dimension system object to get the dimensionsal
dependencies of a dimension, for example the dimension system used by the
SI units convention can be used:
>>> from sympy.physics.units.systems.si import dimsys_SI
>>> dimsys_SI.get_dimensional_dependencies(velocity)
{Dimension(length, L): 1, Dimension(time, T): -1}
>>> length + length
Dimension(length)
>>> l2 = length**2
>>> l2
Dimension(length**2)
>>> dimsys_SI.get_dimensional_dependencies(l2)
{Dimension(length, L): 2}
"""
_op_priority = 13.0
# XXX: This doesn't seem to be used anywhere...
_dimensional_dependencies = {} # type: ignore
is_commutative = True
is_number = False
# make sqrt(M**2) --> M
is_positive = True
is_real = True
def __new__(cls, name, symbol=None):
if isinstance(name, str):
name = Symbol(name)
else:
name = sympify(name)
if not isinstance(name, Expr):
raise TypeError("Dimension name needs to be a valid math expression")
if isinstance(symbol, str):
symbol = Symbol(symbol)
elif symbol is not None:
assert isinstance(symbol, Symbol)
obj = Expr.__new__(cls, name)
obj._name = name
obj._symbol = symbol
return obj
@property
def name(self):
return self._name
@property
def symbol(self):
return self._symbol
def __str__(self):
"""
Display the string representation of the dimension.
"""
if self.symbol is None:
return "Dimension(%s)" % (self.name)
else:
return "Dimension(%s, %s)" % (self.name, self.symbol)
def __repr__(self):
return self.__str__()
def __neg__(self):
return self
def __add__(self, other):
from sympy.physics.units.quantities import Quantity
other = sympify(other)
if isinstance(other, Basic):
if other.has(Quantity):
raise TypeError("cannot sum dimension and quantity")
if isinstance(other, Dimension) and self == other:
return self
return super().__add__(other)
return self
def __radd__(self, other):
return self.__add__(other)
def __sub__(self, other):
# there is no notion of ordering (or magnitude) among dimension,
# subtraction is equivalent to addition when the operation is legal
return self + other
def __rsub__(self, other):
# there is no notion of ordering (or magnitude) among dimension,
# subtraction is equivalent to addition when the operation is legal
return self + other
def __pow__(self, other):
return self._eval_power(other)
def _eval_power(self, other):
other = sympify(other)
return Dimension(self.name**other)
def __mul__(self, other):
from sympy.physics.units.quantities import Quantity
if isinstance(other, Basic):
if other.has(Quantity):
raise TypeError("cannot sum dimension and quantity")
if isinstance(other, Dimension):
return Dimension(self.name*other.name)
if not other.free_symbols: # other.is_number cannot be used
return self
return super().__mul__(other)
return self
def __rmul__(self, other):
return self.__mul__(other)
def __truediv__(self, other):
return self*Pow(other, -1)
def __rtruediv__(self, other):
return other * pow(self, -1)
@classmethod
def _from_dimensional_dependencies(cls, dependencies):
return reduce(lambda x, y: x * y, (
d**e for d, e in dependencies.items()
), 1)
def has_integer_powers(self, dim_sys):
"""
Check if the dimension object has only integer powers.
All the dimension powers should be integers, but rational powers may
appear in intermediate steps. This method may be used to check that the
final result is well-defined.
"""
return all(dpow.is_Integer for dpow in dim_sys.get_dimensional_dependencies(self).values())
# Create dimensions according to the base units in MKSA.
# For other unit systems, they can be derived by transforming the base
# dimensional dependency dictionary.
class DimensionSystem(Basic, _QuantityMapper):
r"""
DimensionSystem represents a coherent set of dimensions.
The constructor takes three parameters:
- base dimensions;
- derived dimensions: these are defined in terms of the base dimensions
(for example velocity is defined from the division of length by time);
- dependency of dimensions: how the derived dimensions depend
on the base dimensions.
Optionally either the ``derived_dims`` or the ``dimensional_dependencies``
may be omitted.
"""
def __new__(cls, base_dims, derived_dims=(), dimensional_dependencies={}):
dimensional_dependencies = dict(dimensional_dependencies)
def parse_dim(dim):
if isinstance(dim, str):
dim = Dimension(Symbol(dim))
elif isinstance(dim, Dimension):
pass
elif isinstance(dim, Symbol):
dim = Dimension(dim)
else:
raise TypeError("%s wrong type" % dim)
return dim
base_dims = [parse_dim(i) for i in base_dims]
derived_dims = [parse_dim(i) for i in derived_dims]
for dim in base_dims:
if (dim in dimensional_dependencies
and (len(dimensional_dependencies[dim]) != 1 or
dimensional_dependencies[dim].get(dim, None) != 1)):
raise IndexError("Repeated value in base dimensions")
dimensional_dependencies[dim] = Dict({dim: 1})
def parse_dim_name(dim):
if isinstance(dim, Dimension):
return dim
elif isinstance(dim, str):
return Dimension(Symbol(dim))
elif isinstance(dim, Symbol):
return Dimension(dim)
else:
raise TypeError("unrecognized type %s for %s" % (type(dim), dim))
for dim in dimensional_dependencies.keys():
dim = parse_dim(dim)
if (dim not in derived_dims) and (dim not in base_dims):
derived_dims.append(dim)
def parse_dict(d):
return Dict({parse_dim_name(i): j for i, j in d.items()})
# Make sure everything is a SymPy type:
dimensional_dependencies = {parse_dim_name(i): parse_dict(j) for i, j in
dimensional_dependencies.items()}
for dim in derived_dims:
if dim in base_dims:
raise ValueError("Dimension %s both in base and derived" % dim)
if dim not in dimensional_dependencies:
# TODO: should this raise a warning?
dimensional_dependencies[dim] = Dict({dim: 1})
base_dims.sort(key=default_sort_key)
derived_dims.sort(key=default_sort_key)
base_dims = Tuple(*base_dims)
derived_dims = Tuple(*derived_dims)
dimensional_dependencies = Dict({i: Dict(j) for i, j in dimensional_dependencies.items()})
obj = Basic.__new__(cls, base_dims, derived_dims, dimensional_dependencies)
return obj
@property
def base_dims(self):
return self.args[0]
@property
def derived_dims(self):
return self.args[1]
@property
def dimensional_dependencies(self):
return self.args[2]
def _get_dimensional_dependencies_for_name(self, dimension):
if isinstance(dimension, str):
dimension = Dimension(Symbol(dimension))
elif not isinstance(dimension, Dimension):
dimension = Dimension(dimension)
if dimension.name.is_Symbol:
# Dimensions not included in the dependencies are considered
# as base dimensions:
return dict(self.dimensional_dependencies.get(dimension, {dimension: 1}))
if dimension.name.is_number or dimension.name.is_NumberSymbol:
return {}
get_for_name = self._get_dimensional_dependencies_for_name
if dimension.name.is_Mul:
ret = collections.defaultdict(int)
dicts = [get_for_name(i) for i in dimension.name.args]
for d in dicts:
for k, v in d.items():
ret[k] += v
return {k: v for (k, v) in ret.items() if v != 0}
if dimension.name.is_Add:
dicts = [get_for_name(i) for i in dimension.name.args]
if all(d == dicts[0] for d in dicts[1:]):
return dicts[0]
raise TypeError("Only equivalent dimensions can be added or subtracted.")
if dimension.name.is_Pow:
dim_base = get_for_name(dimension.name.base)
dim_exp = get_for_name(dimension.name.exp)
if dim_exp == {} or dimension.name.exp.is_Symbol:
return {k: v * dimension.name.exp for (k, v) in dim_base.items()}
else:
raise TypeError("The exponent for the power operator must be a Symbol or dimensionless.")
if dimension.name.is_Function:
args = (Dimension._from_dimensional_dependencies(
get_for_name(arg)) for arg in dimension.name.args)
result = dimension.name.func(*args)
dicts = [get_for_name(i) for i in dimension.name.args]
if isinstance(result, Dimension):
return self.get_dimensional_dependencies(result)
elif result.func == dimension.name.func:
if isinstance(dimension.name, TrigonometricFunction):
if dicts[0] in ({}, {Dimension('angle'): 1}):
return {}
else:
raise TypeError("The input argument for the function {} must be dimensionless or have dimensions of angle.".format(dimension.func))
else:
if all(item == {} for item in dicts):
return {}
else:
raise TypeError("The input arguments for the function {} must be dimensionless.".format(dimension.func))
else:
return get_for_name(result)
raise TypeError("Type {} not implemented for get_dimensional_dependencies".format(type(dimension.name)))
def get_dimensional_dependencies(self, name, mark_dimensionless=False):
dimdep = self._get_dimensional_dependencies_for_name(name)
if mark_dimensionless and dimdep == {}:
return {Dimension(1): 1}
return dict(dimdep.items())
def equivalent_dims(self, dim1, dim2):
deps1 = self.get_dimensional_dependencies(dim1)
deps2 = self.get_dimensional_dependencies(dim2)
return deps1 == deps2
def extend(self, new_base_dims, new_derived_dims=(), new_dim_deps=None):
deps = dict(self.dimensional_dependencies)
if new_dim_deps:
deps.update(new_dim_deps)
new_dim_sys = DimensionSystem(
tuple(self.base_dims) + tuple(new_base_dims),
tuple(self.derived_dims) + tuple(new_derived_dims),
deps
)
new_dim_sys._quantity_dimension_map.update(self._quantity_dimension_map)
new_dim_sys._quantity_scale_factors.update(self._quantity_scale_factors)
return new_dim_sys
def is_dimensionless(self, dimension):
"""
Check if the dimension object really has a dimension.
A dimension should have at least one component with non-zero power.
"""
if dimension.name == 1:
return True
return self.get_dimensional_dependencies(dimension) == {}
@property
def list_can_dims(self):
"""
Useless method, kept for compatibility with previous versions.
DO NOT USE.
List all canonical dimension names.
"""
dimset = set()
for i in self.base_dims:
dimset.update(set(self.get_dimensional_dependencies(i).keys()))
return tuple(sorted(dimset, key=str))
@property
def inv_can_transf_matrix(self):
"""
Useless method, kept for compatibility with previous versions.
DO NOT USE.
Compute the inverse transformation matrix from the base to the
canonical dimension basis.
It corresponds to the matrix where columns are the vector of base
dimensions in canonical basis.
This matrix will almost never be used because dimensions are always
defined with respect to the canonical basis, so no work has to be done
to get them in this basis. Nonetheless if this matrix is not square
(or not invertible) it means that we have chosen a bad basis.
"""
matrix = reduce(lambda x, y: x.row_join(y),
[self.dim_can_vector(d) for d in self.base_dims])
return matrix
@property
def can_transf_matrix(self):
"""
Useless method, kept for compatibility with previous versions.
DO NOT USE.
Return the canonical transformation matrix from the canonical to the
base dimension basis.
It is the inverse of the matrix computed with inv_can_transf_matrix().
"""
#TODO: the inversion will fail if the system is inconsistent, for
# example if the matrix is not a square
return reduce(lambda x, y: x.row_join(y),
[self.dim_can_vector(d) for d in sorted(self.base_dims, key=str)]
).inv()
def dim_can_vector(self, dim):
"""
Useless method, kept for compatibility with previous versions.
DO NOT USE.
Dimensional representation in terms of the canonical base dimensions.
"""
vec = []
for d in self.list_can_dims:
vec.append(self.get_dimensional_dependencies(dim).get(d, 0))
return Matrix(vec)
def dim_vector(self, dim):
"""
Useless method, kept for compatibility with previous versions.
DO NOT USE.
Vector representation in terms of the base dimensions.
"""
return self.can_transf_matrix * Matrix(self.dim_can_vector(dim))
def print_dim_base(self, dim):
"""
Give the string expression of a dimension in term of the basis symbols.
"""
dims = self.dim_vector(dim)
symbols = [i.symbol if i.symbol is not None else i.name for i in self.base_dims]
res = S.One
for (s, p) in zip(symbols, dims):
res *= s**p
return res
@property
def dim(self):
"""
Useless method, kept for compatibility with previous versions.
DO NOT USE.
Give the dimension of the system.
That is return the number of dimensions forming the basis.
"""
return len(self.base_dims)
@property
def is_consistent(self):
"""
Useless method, kept for compatibility with previous versions.
DO NOT USE.
Check if the system is well defined.
"""
# not enough or too many base dimensions compared to independent
# dimensions
# in vector language: the set of vectors do not form a basis
return self.inv_can_transf_matrix.is_square

View File

@ -0,0 +1,219 @@
"""
Module defining unit prefixe class and some constants.
Constant dict for SI and binary prefixes are defined as PREFIXES and
BIN_PREFIXES.
"""
from sympy.core.expr import Expr
from sympy.core.sympify import sympify
from sympy.core.singleton import S
class Prefix(Expr):
"""
This class represent prefixes, with their name, symbol and factor.
Prefixes are used to create derived units from a given unit. They should
always be encapsulated into units.
The factor is constructed from a base (default is 10) to some power, and
it gives the total multiple or fraction. For example the kilometer km
is constructed from the meter (factor 1) and the kilo (10 to the power 3,
i.e. 1000). The base can be changed to allow e.g. binary prefixes.
A prefix multiplied by something will always return the product of this
other object times the factor, except if the other object:
- is a prefix and they can be combined into a new prefix;
- defines multiplication with prefixes (which is the case for the Unit
class).
"""
_op_priority = 13.0
is_commutative = True
def __new__(cls, name, abbrev, exponent, base=sympify(10), latex_repr=None):
name = sympify(name)
abbrev = sympify(abbrev)
exponent = sympify(exponent)
base = sympify(base)
obj = Expr.__new__(cls, name, abbrev, exponent, base)
obj._name = name
obj._abbrev = abbrev
obj._scale_factor = base**exponent
obj._exponent = exponent
obj._base = base
obj._latex_repr = latex_repr
return obj
@property
def name(self):
return self._name
@property
def abbrev(self):
return self._abbrev
@property
def scale_factor(self):
return self._scale_factor
def _latex(self, printer):
if self._latex_repr is None:
return r'\text{%s}' % self._abbrev
return self._latex_repr
@property
def base(self):
return self._base
def __str__(self):
return str(self._abbrev)
def __repr__(self):
if self.base == 10:
return "Prefix(%r, %r, %r)" % (
str(self.name), str(self.abbrev), self._exponent)
else:
return "Prefix(%r, %r, %r, %r)" % (
str(self.name), str(self.abbrev), self._exponent, self.base)
def __mul__(self, other):
from sympy.physics.units import Quantity
if not isinstance(other, (Quantity, Prefix)):
return super().__mul__(other)
fact = self.scale_factor * other.scale_factor
if isinstance(other, Prefix):
if fact == 1:
return S.One
# simplify prefix
for p in PREFIXES:
if PREFIXES[p].scale_factor == fact:
return PREFIXES[p]
return fact
return self.scale_factor * other
def __truediv__(self, other):
if not hasattr(other, "scale_factor"):
return super().__truediv__(other)
fact = self.scale_factor / other.scale_factor
if fact == 1:
return S.One
elif isinstance(other, Prefix):
for p in PREFIXES:
if PREFIXES[p].scale_factor == fact:
return PREFIXES[p]
return fact
return self.scale_factor / other
def __rtruediv__(self, other):
if other == 1:
for p in PREFIXES:
if PREFIXES[p].scale_factor == 1 / self.scale_factor:
return PREFIXES[p]
return other / self.scale_factor
def prefix_unit(unit, prefixes):
"""
Return a list of all units formed by unit and the given prefixes.
You can use the predefined PREFIXES or BIN_PREFIXES, but you can also
pass as argument a subdict of them if you do not want all prefixed units.
>>> from sympy.physics.units.prefixes import (PREFIXES,
... prefix_unit)
>>> from sympy.physics.units import m
>>> pref = {"m": PREFIXES["m"], "c": PREFIXES["c"], "d": PREFIXES["d"]}
>>> prefix_unit(m, pref) # doctest: +SKIP
[millimeter, centimeter, decimeter]
"""
from sympy.physics.units.quantities import Quantity
from sympy.physics.units import UnitSystem
prefixed_units = []
for prefix in prefixes.values():
quantity = Quantity(
"%s%s" % (prefix.name, unit.name),
abbrev=("%s%s" % (prefix.abbrev, unit.abbrev)),
is_prefixed=True,
)
UnitSystem._quantity_dimensional_equivalence_map_global[quantity] = unit
UnitSystem._quantity_scale_factors_global[quantity] = (prefix.scale_factor, unit)
prefixed_units.append(quantity)
return prefixed_units
yotta = Prefix('yotta', 'Y', 24)
zetta = Prefix('zetta', 'Z', 21)
exa = Prefix('exa', 'E', 18)
peta = Prefix('peta', 'P', 15)
tera = Prefix('tera', 'T', 12)
giga = Prefix('giga', 'G', 9)
mega = Prefix('mega', 'M', 6)
kilo = Prefix('kilo', 'k', 3)
hecto = Prefix('hecto', 'h', 2)
deca = Prefix('deca', 'da', 1)
deci = Prefix('deci', 'd', -1)
centi = Prefix('centi', 'c', -2)
milli = Prefix('milli', 'm', -3)
micro = Prefix('micro', 'mu', -6, latex_repr=r"\mu")
nano = Prefix('nano', 'n', -9)
pico = Prefix('pico', 'p', -12)
femto = Prefix('femto', 'f', -15)
atto = Prefix('atto', 'a', -18)
zepto = Prefix('zepto', 'z', -21)
yocto = Prefix('yocto', 'y', -24)
# https://physics.nist.gov/cuu/Units/prefixes.html
PREFIXES = {
'Y': yotta,
'Z': zetta,
'E': exa,
'P': peta,
'T': tera,
'G': giga,
'M': mega,
'k': kilo,
'h': hecto,
'da': deca,
'd': deci,
'c': centi,
'm': milli,
'mu': micro,
'n': nano,
'p': pico,
'f': femto,
'a': atto,
'z': zepto,
'y': yocto,
}
kibi = Prefix('kibi', 'Y', 10, 2)
mebi = Prefix('mebi', 'Y', 20, 2)
gibi = Prefix('gibi', 'Y', 30, 2)
tebi = Prefix('tebi', 'Y', 40, 2)
pebi = Prefix('pebi', 'Y', 50, 2)
exbi = Prefix('exbi', 'Y', 60, 2)
# https://physics.nist.gov/cuu/Units/binary.html
BIN_PREFIXES = {
'Ki': kibi,
'Mi': mebi,
'Gi': gibi,
'Ti': tebi,
'Pi': pebi,
'Ei': exbi,
}

View File

@ -0,0 +1,152 @@
"""
Physical quantities.
"""
from sympy.core.expr import AtomicExpr
from sympy.core.symbol import Symbol
from sympy.core.sympify import sympify
from sympy.physics.units.dimensions import _QuantityMapper
from sympy.physics.units.prefixes import Prefix
class Quantity(AtomicExpr):
"""
Physical quantity: can be a unit of measure, a constant or a generic quantity.
"""
is_commutative = True
is_real = True
is_number = False
is_nonzero = True
is_physical_constant = False
_diff_wrt = True
def __new__(cls, name, abbrev=None,
latex_repr=None, pretty_unicode_repr=None,
pretty_ascii_repr=None, mathml_presentation_repr=None,
is_prefixed=False,
**assumptions):
if not isinstance(name, Symbol):
name = Symbol(name)
if abbrev is None:
abbrev = name
elif isinstance(abbrev, str):
abbrev = Symbol(abbrev)
# HACK: These are here purely for type checking. They actually get assigned below.
cls._is_prefixed = is_prefixed
obj = AtomicExpr.__new__(cls, name, abbrev)
obj._name = name
obj._abbrev = abbrev
obj._latex_repr = latex_repr
obj._unicode_repr = pretty_unicode_repr
obj._ascii_repr = pretty_ascii_repr
obj._mathml_repr = mathml_presentation_repr
obj._is_prefixed = is_prefixed
return obj
def set_global_dimension(self, dimension):
_QuantityMapper._quantity_dimension_global[self] = dimension
def set_global_relative_scale_factor(self, scale_factor, reference_quantity):
"""
Setting a scale factor that is valid across all unit system.
"""
from sympy.physics.units import UnitSystem
scale_factor = sympify(scale_factor)
if isinstance(scale_factor, Prefix):
self._is_prefixed = True
# replace all prefixes by their ratio to canonical units:
scale_factor = scale_factor.replace(
lambda x: isinstance(x, Prefix),
lambda x: x.scale_factor
)
scale_factor = sympify(scale_factor)
UnitSystem._quantity_scale_factors_global[self] = (scale_factor, reference_quantity)
UnitSystem._quantity_dimensional_equivalence_map_global[self] = reference_quantity
@property
def name(self):
return self._name
@property
def dimension(self):
from sympy.physics.units import UnitSystem
unit_system = UnitSystem.get_default_unit_system()
return unit_system.get_quantity_dimension(self)
@property
def abbrev(self):
"""
Symbol representing the unit name.
Prepend the abbreviation with the prefix symbol if it is defines.
"""
return self._abbrev
@property
def scale_factor(self):
"""
Overall magnitude of the quantity as compared to the canonical units.
"""
from sympy.physics.units import UnitSystem
unit_system = UnitSystem.get_default_unit_system()
return unit_system.get_quantity_scale_factor(self)
def _eval_is_positive(self):
return True
def _eval_is_constant(self):
return True
def _eval_Abs(self):
return self
def _eval_subs(self, old, new):
if isinstance(new, Quantity) and self != old:
return self
def _latex(self, printer):
if self._latex_repr:
return self._latex_repr
else:
return r'\text{{{}}}'.format(self.args[1] \
if len(self.args) >= 2 else self.args[0])
def convert_to(self, other, unit_system="SI"):
"""
Convert the quantity to another quantity of same dimensions.
Examples
========
>>> from sympy.physics.units import speed_of_light, meter, second
>>> speed_of_light
speed_of_light
>>> speed_of_light.convert_to(meter/second)
299792458*meter/second
>>> from sympy.physics.units import liter
>>> liter.convert_to(meter**3)
meter**3/1000
"""
from .util import convert_to
return convert_to(self, other, unit_system)
@property
def free_symbols(self):
"""Return free symbols from quantity."""
return set()
@property
def is_prefixed(self):
"""Whether or not the quantity is prefixed. Eg. `kilogram` is prefixed, but `gram` is not."""
return self._is_prefixed
class PhysicalConstant(Quantity):
"""Represents a physical constant, eg. `speed_of_light` or `avogadro_constant`."""
is_physical_constant = True

View File

@ -0,0 +1,6 @@
from sympy.physics.units.systems.mks import MKS
from sympy.physics.units.systems.mksa import MKSA
from sympy.physics.units.systems.natural import natural
from sympy.physics.units.systems.si import SI
__all__ = ['MKS', 'MKSA', 'natural', 'SI']

View File

@ -0,0 +1,82 @@
from sympy.core.singleton import S
from sympy.functions.elementary.miscellaneous import sqrt
from sympy.physics.units import UnitSystem, centimeter, gram, second, coulomb, charge, speed_of_light, current, mass, \
length, voltage, magnetic_density, magnetic_flux
from sympy.physics.units.definitions import coulombs_constant
from sympy.physics.units.definitions.unit_definitions import statcoulomb, statampere, statvolt, volt, tesla, gauss, \
weber, maxwell, debye, oersted, ohm, farad, henry, erg, ampere, coulomb_constant
from sympy.physics.units.systems.mks import dimsys_length_weight_time
One = S.One
dimsys_cgs = dimsys_length_weight_time.extend(
[],
new_dim_deps={
# Dimensional dependencies for derived dimensions
"impedance": {"time": 1, "length": -1},
"conductance": {"time": -1, "length": 1},
"capacitance": {"length": 1},
"inductance": {"time": 2, "length": -1},
"charge": {"mass": S.Half, "length": S(3)/2, "time": -1},
"current": {"mass": One/2, "length": 3*One/2, "time": -2},
"voltage": {"length": -One/2, "mass": One/2, "time": -1},
"magnetic_density": {"length": -One/2, "mass": One/2, "time": -1},
"magnetic_flux": {"length": 3*One/2, "mass": One/2, "time": -1},
}
)
cgs_gauss = UnitSystem(
base_units=[centimeter, gram, second],
units=[],
name="cgs_gauss",
dimension_system=dimsys_cgs)
cgs_gauss.set_quantity_scale_factor(coulombs_constant, 1)
cgs_gauss.set_quantity_dimension(statcoulomb, charge)
cgs_gauss.set_quantity_scale_factor(statcoulomb, centimeter**(S(3)/2)*gram**(S.Half)/second)
cgs_gauss.set_quantity_dimension(coulomb, charge)
cgs_gauss.set_quantity_dimension(statampere, current)
cgs_gauss.set_quantity_scale_factor(statampere, statcoulomb/second)
cgs_gauss.set_quantity_dimension(statvolt, voltage)
cgs_gauss.set_quantity_scale_factor(statvolt, erg/statcoulomb)
cgs_gauss.set_quantity_dimension(volt, voltage)
cgs_gauss.set_quantity_dimension(gauss, magnetic_density)
cgs_gauss.set_quantity_scale_factor(gauss, sqrt(gram/centimeter)/second)
cgs_gauss.set_quantity_dimension(tesla, magnetic_density)
cgs_gauss.set_quantity_dimension(maxwell, magnetic_flux)
cgs_gauss.set_quantity_scale_factor(maxwell, sqrt(centimeter**3*gram)/second)
# SI units expressed in CGS-gaussian units:
cgs_gauss.set_quantity_scale_factor(coulomb, 10*speed_of_light*statcoulomb)
cgs_gauss.set_quantity_scale_factor(ampere, 10*speed_of_light*statcoulomb/second)
cgs_gauss.set_quantity_scale_factor(volt, 10**6/speed_of_light*statvolt)
cgs_gauss.set_quantity_scale_factor(weber, 10**8*maxwell)
cgs_gauss.set_quantity_scale_factor(tesla, 10**4*gauss)
cgs_gauss.set_quantity_scale_factor(debye, One/10**18*statcoulomb*centimeter)
cgs_gauss.set_quantity_scale_factor(oersted, sqrt(gram/centimeter)/second)
cgs_gauss.set_quantity_scale_factor(ohm, 10**5/speed_of_light**2*second/centimeter)
cgs_gauss.set_quantity_scale_factor(farad, One/10**5*speed_of_light**2*centimeter)
cgs_gauss.set_quantity_scale_factor(henry, 10**5/speed_of_light**2/centimeter*second**2)
# Coulomb's constant:
cgs_gauss.set_quantity_dimension(coulomb_constant, 1)
cgs_gauss.set_quantity_scale_factor(coulomb_constant, 1)
__all__ = [
'ohm', 'tesla', 'maxwell', 'speed_of_light', 'volt', 'second', 'voltage',
'debye', 'dimsys_length_weight_time', 'centimeter', 'coulomb_constant',
'farad', 'sqrt', 'UnitSystem', 'current', 'charge', 'weber', 'gram',
'statcoulomb', 'gauss', 'S', 'statvolt', 'oersted', 'statampere',
'dimsys_cgs', 'coulomb', 'magnetic_density', 'magnetic_flux', 'One',
'length', 'erg', 'mass', 'coulombs_constant', 'henry', 'ampere',
'cgs_gauss',
]

View File

@ -0,0 +1,156 @@
from sympy.core.singleton import S
from sympy.core.numbers import pi
from sympy.physics.units import DimensionSystem, hertz, kilogram
from sympy.physics.units.definitions import (
G, Hz, J, N, Pa, W, c, g, kg, m, s, meter, gram, second, newton,
joule, watt, pascal)
from sympy.physics.units.definitions.dimension_definitions import (
acceleration, action, energy, force, frequency, momentum,
power, pressure, velocity, length, mass, time)
from sympy.physics.units.prefixes import PREFIXES, prefix_unit
from sympy.physics.units.prefixes import (
kibi, mebi, gibi, tebi, pebi, exbi
)
from sympy.physics.units.definitions import (
cd, K, coulomb, volt, ohm, siemens, farad, henry, tesla, weber, dioptre,
lux, katal, gray, becquerel, inch, hectare, liter, julian_year,
gravitational_constant, speed_of_light, elementary_charge, planck, hbar,
electronvolt, avogadro_number, avogadro_constant, boltzmann_constant,
stefan_boltzmann_constant, atomic_mass_constant, molar_gas_constant,
faraday_constant, josephson_constant, von_klitzing_constant,
acceleration_due_to_gravity, magnetic_constant, vacuum_permittivity,
vacuum_impedance, coulomb_constant, atmosphere, bar, pound, psi, mmHg,
milli_mass_unit, quart, lightyear, astronomical_unit, planck_mass,
planck_time, planck_temperature, planck_length, planck_charge,
planck_area, planck_volume, planck_momentum, planck_energy, planck_force,
planck_power, planck_density, planck_energy_density, planck_intensity,
planck_angular_frequency, planck_pressure, planck_current, planck_voltage,
planck_impedance, planck_acceleration, bit, byte, kibibyte, mebibyte,
gibibyte, tebibyte, pebibyte, exbibyte, curie, rutherford, radian, degree,
steradian, angular_mil, atomic_mass_unit, gee, kPa, ampere, u0, kelvin,
mol, mole, candela, electric_constant, boltzmann, angstrom
)
dimsys_length_weight_time = DimensionSystem([
# Dimensional dependencies for MKS base dimensions
length,
mass,
time,
], dimensional_dependencies={
# Dimensional dependencies for derived dimensions
"velocity": {"length": 1, "time": -1},
"acceleration": {"length": 1, "time": -2},
"momentum": {"mass": 1, "length": 1, "time": -1},
"force": {"mass": 1, "length": 1, "time": -2},
"energy": {"mass": 1, "length": 2, "time": -2},
"power": {"length": 2, "mass": 1, "time": -3},
"pressure": {"mass": 1, "length": -1, "time": -2},
"frequency": {"time": -1},
"action": {"length": 2, "mass": 1, "time": -1},
"area": {"length": 2},
"volume": {"length": 3},
})
One = S.One
# Base units:
dimsys_length_weight_time.set_quantity_dimension(meter, length)
dimsys_length_weight_time.set_quantity_scale_factor(meter, One)
# gram; used to define its prefixed units
dimsys_length_weight_time.set_quantity_dimension(gram, mass)
dimsys_length_weight_time.set_quantity_scale_factor(gram, One)
dimsys_length_weight_time.set_quantity_dimension(second, time)
dimsys_length_weight_time.set_quantity_scale_factor(second, One)
# derived units
dimsys_length_weight_time.set_quantity_dimension(newton, force)
dimsys_length_weight_time.set_quantity_scale_factor(newton, kilogram*meter/second**2)
dimsys_length_weight_time.set_quantity_dimension(joule, energy)
dimsys_length_weight_time.set_quantity_scale_factor(joule, newton*meter)
dimsys_length_weight_time.set_quantity_dimension(watt, power)
dimsys_length_weight_time.set_quantity_scale_factor(watt, joule/second)
dimsys_length_weight_time.set_quantity_dimension(pascal, pressure)
dimsys_length_weight_time.set_quantity_scale_factor(pascal, newton/meter**2)
dimsys_length_weight_time.set_quantity_dimension(hertz, frequency)
dimsys_length_weight_time.set_quantity_scale_factor(hertz, One)
# Other derived units:
dimsys_length_weight_time.set_quantity_dimension(dioptre, 1 / length)
dimsys_length_weight_time.set_quantity_scale_factor(dioptre, 1/meter)
# Common volume and area units
dimsys_length_weight_time.set_quantity_dimension(hectare, length**2)
dimsys_length_weight_time.set_quantity_scale_factor(hectare, (meter**2)*(10000))
dimsys_length_weight_time.set_quantity_dimension(liter, length**3)
dimsys_length_weight_time.set_quantity_scale_factor(liter, meter**3/1000)
# Newton constant
# REF: NIST SP 959 (June 2019)
dimsys_length_weight_time.set_quantity_dimension(gravitational_constant, length ** 3 * mass ** -1 * time ** -2)
dimsys_length_weight_time.set_quantity_scale_factor(gravitational_constant, 6.67430e-11*m**3/(kg*s**2))
# speed of light
dimsys_length_weight_time.set_quantity_dimension(speed_of_light, velocity)
dimsys_length_weight_time.set_quantity_scale_factor(speed_of_light, 299792458*meter/second)
# Planck constant
# REF: NIST SP 959 (June 2019)
dimsys_length_weight_time.set_quantity_dimension(planck, action)
dimsys_length_weight_time.set_quantity_scale_factor(planck, 6.62607015e-34*joule*second)
# Reduced Planck constant
# REF: NIST SP 959 (June 2019)
dimsys_length_weight_time.set_quantity_dimension(hbar, action)
dimsys_length_weight_time.set_quantity_scale_factor(hbar, planck / (2 * pi))
__all__ = [
'mmHg', 'atmosphere', 'newton', 'meter', 'vacuum_permittivity', 'pascal',
'magnetic_constant', 'angular_mil', 'julian_year', 'weber', 'exbibyte',
'liter', 'molar_gas_constant', 'faraday_constant', 'avogadro_constant',
'planck_momentum', 'planck_density', 'gee', 'mol', 'bit', 'gray', 'kibi',
'bar', 'curie', 'prefix_unit', 'PREFIXES', 'planck_time', 'gram',
'candela', 'force', 'planck_intensity', 'energy', 'becquerel',
'planck_acceleration', 'speed_of_light', 'dioptre', 'second', 'frequency',
'Hz', 'power', 'lux', 'planck_current', 'momentum', 'tebibyte',
'planck_power', 'degree', 'mebi', 'K', 'planck_volume',
'quart', 'pressure', 'W', 'joule', 'boltzmann_constant', 'c', 'g',
'planck_force', 'exbi', 's', 'watt', 'action', 'hbar', 'gibibyte',
'DimensionSystem', 'cd', 'volt', 'planck_charge', 'angstrom',
'dimsys_length_weight_time', 'pebi', 'vacuum_impedance', 'planck',
'farad', 'gravitational_constant', 'u0', 'hertz', 'tesla', 'steradian',
'josephson_constant', 'planck_area', 'stefan_boltzmann_constant',
'astronomical_unit', 'J', 'N', 'planck_voltage', 'planck_energy',
'atomic_mass_constant', 'rutherford', 'elementary_charge', 'Pa',
'planck_mass', 'henry', 'planck_angular_frequency', 'ohm', 'pound',
'planck_pressure', 'G', 'avogadro_number', 'psi', 'von_klitzing_constant',
'planck_length', 'radian', 'mole', 'acceleration',
'planck_energy_density', 'mebibyte', 'length',
'acceleration_due_to_gravity', 'planck_temperature', 'tebi', 'inch',
'electronvolt', 'coulomb_constant', 'kelvin', 'kPa', 'boltzmann',
'milli_mass_unit', 'gibi', 'planck_impedance', 'electric_constant', 'kg',
'coulomb', 'siemens', 'byte', 'atomic_mass_unit', 'm', 'kibibyte',
'kilogram', 'lightyear', 'mass', 'time', 'pebibyte', 'velocity',
'ampere', 'katal',
]

View File

@ -0,0 +1,46 @@
"""
MKS unit system.
MKS stands for "meter, kilogram, second".
"""
from sympy.physics.units import UnitSystem
from sympy.physics.units.definitions import gravitational_constant, hertz, joule, newton, pascal, watt, speed_of_light, gram, kilogram, meter, second
from sympy.physics.units.definitions.dimension_definitions import (
acceleration, action, energy, force, frequency, momentum,
power, pressure, velocity, length, mass, time)
from sympy.physics.units.prefixes import PREFIXES, prefix_unit
from sympy.physics.units.systems.length_weight_time import dimsys_length_weight_time
dims = (velocity, acceleration, momentum, force, energy, power, pressure,
frequency, action)
units = [meter, gram, second, joule, newton, watt, pascal, hertz]
all_units = []
# Prefixes of units like gram, joule, newton etc get added using `prefix_unit`
# in the for loop, but the actual units have to be added manually.
all_units.extend([gram, joule, newton, watt, pascal, hertz])
for u in units:
all_units.extend(prefix_unit(u, PREFIXES))
all_units.extend([gravitational_constant, speed_of_light])
# unit system
MKS = UnitSystem(base_units=(meter, kilogram, second), units=all_units, name="MKS", dimension_system=dimsys_length_weight_time, derived_units={
power: watt,
time: second,
pressure: pascal,
length: meter,
frequency: hertz,
mass: kilogram,
force: newton,
energy: joule,
velocity: meter/second,
acceleration: meter/(second**2),
})
__all__ = [
'MKS', 'units', 'all_units', 'dims',
]

View File

@ -0,0 +1,54 @@
"""
MKS unit system.
MKS stands for "meter, kilogram, second, ampere".
"""
from __future__ import annotations
from sympy.physics.units.definitions import Z0, ampere, coulomb, farad, henry, siemens, tesla, volt, weber, ohm
from sympy.physics.units.definitions.dimension_definitions import (
capacitance, charge, conductance, current, impedance, inductance,
magnetic_density, magnetic_flux, voltage)
from sympy.physics.units.prefixes import PREFIXES, prefix_unit
from sympy.physics.units.systems.mks import MKS, dimsys_length_weight_time
from sympy.physics.units.quantities import Quantity
dims = (voltage, impedance, conductance, current, capacitance, inductance, charge,
magnetic_density, magnetic_flux)
units = [ampere, volt, ohm, siemens, farad, henry, coulomb, tesla, weber]
all_units: list[Quantity] = []
for u in units:
all_units.extend(prefix_unit(u, PREFIXES))
all_units.extend(units)
all_units.append(Z0)
dimsys_MKSA = dimsys_length_weight_time.extend([
# Dimensional dependencies for base dimensions (MKSA not in MKS)
current,
], new_dim_deps={
# Dimensional dependencies for derived dimensions
"voltage": {"mass": 1, "length": 2, "current": -1, "time": -3},
"impedance": {"mass": 1, "length": 2, "current": -2, "time": -3},
"conductance": {"mass": -1, "length": -2, "current": 2, "time": 3},
"capacitance": {"mass": -1, "length": -2, "current": 2, "time": 4},
"inductance": {"mass": 1, "length": 2, "current": -2, "time": -2},
"charge": {"current": 1, "time": 1},
"magnetic_density": {"mass": 1, "current": -1, "time": -2},
"magnetic_flux": {"length": 2, "mass": 1, "current": -1, "time": -2},
})
MKSA = MKS.extend(base=(ampere,), units=all_units, name='MKSA', dimension_system=dimsys_MKSA, derived_units={
magnetic_flux: weber,
impedance: ohm,
current: ampere,
voltage: volt,
inductance: henry,
conductance: siemens,
magnetic_density: tesla,
charge: coulomb,
capacitance: farad,
})

View File

@ -0,0 +1,27 @@
"""
Naturalunit system.
The natural system comes from "setting c = 1, hbar = 1". From the computer
point of view it means that we use velocity and action instead of length and
time. Moreover instead of mass we use energy.
"""
from sympy.physics.units import DimensionSystem
from sympy.physics.units.definitions import c, eV, hbar
from sympy.physics.units.definitions.dimension_definitions import (
action, energy, force, frequency, length, mass, momentum,
power, time, velocity)
from sympy.physics.units.prefixes import PREFIXES, prefix_unit
from sympy.physics.units.unitsystem import UnitSystem
# dimension system
_natural_dim = DimensionSystem(
base_dims=(action, energy, velocity),
derived_dims=(length, mass, time, momentum, force, power, frequency)
)
units = prefix_unit(eV, PREFIXES)
# unit system
natural = UnitSystem(base_units=(hbar, eV, c), units=units, name="Natural system")

View File

@ -0,0 +1,377 @@
"""
SI unit system.
Based on MKSA, which stands for "meter, kilogram, second, ampere".
Added kelvin, candela and mole.
"""
from __future__ import annotations
from sympy.physics.units import DimensionSystem, Dimension, dHg0
from sympy.physics.units.quantities import Quantity
from sympy.core.numbers import (Rational, pi)
from sympy.core.singleton import S
from sympy.functions.elementary.miscellaneous import sqrt
from sympy.physics.units.definitions.dimension_definitions import (
acceleration, action, current, impedance, length, mass, time, velocity,
amount_of_substance, temperature, information, frequency, force, pressure,
energy, power, charge, voltage, capacitance, conductance, magnetic_flux,
magnetic_density, inductance, luminous_intensity
)
from sympy.physics.units.definitions import (
kilogram, newton, second, meter, gram, cd, K, joule, watt, pascal, hertz,
coulomb, volt, ohm, siemens, farad, henry, tesla, weber, dioptre, lux,
katal, gray, becquerel, inch, liter, julian_year, gravitational_constant,
speed_of_light, elementary_charge, planck, hbar, electronvolt,
avogadro_number, avogadro_constant, boltzmann_constant, electron_rest_mass,
stefan_boltzmann_constant, Da, atomic_mass_constant, molar_gas_constant,
faraday_constant, josephson_constant, von_klitzing_constant,
acceleration_due_to_gravity, magnetic_constant, vacuum_permittivity,
vacuum_impedance, coulomb_constant, atmosphere, bar, pound, psi, mmHg,
milli_mass_unit, quart, lightyear, astronomical_unit, planck_mass,
planck_time, planck_temperature, planck_length, planck_charge, planck_area,
planck_volume, planck_momentum, planck_energy, planck_force, planck_power,
planck_density, planck_energy_density, planck_intensity,
planck_angular_frequency, planck_pressure, planck_current, planck_voltage,
planck_impedance, planck_acceleration, bit, byte, kibibyte, mebibyte,
gibibyte, tebibyte, pebibyte, exbibyte, curie, rutherford, radian, degree,
steradian, angular_mil, atomic_mass_unit, gee, kPa, ampere, u0, c, kelvin,
mol, mole, candela, m, kg, s, electric_constant, G, boltzmann
)
from sympy.physics.units.prefixes import PREFIXES, prefix_unit
from sympy.physics.units.systems.mksa import MKSA, dimsys_MKSA
derived_dims = (frequency, force, pressure, energy, power, charge, voltage,
capacitance, conductance, magnetic_flux,
magnetic_density, inductance, luminous_intensity)
base_dims = (amount_of_substance, luminous_intensity, temperature)
units = [mol, cd, K, lux, hertz, newton, pascal, joule, watt, coulomb, volt,
farad, ohm, siemens, weber, tesla, henry, candela, lux, becquerel,
gray, katal]
all_units: list[Quantity] = []
for u in units:
all_units.extend(prefix_unit(u, PREFIXES))
all_units.extend(units)
all_units.extend([mol, cd, K, lux])
dimsys_SI = dimsys_MKSA.extend(
[
# Dimensional dependencies for other base dimensions:
temperature,
amount_of_substance,
luminous_intensity,
])
dimsys_default = dimsys_SI.extend(
[information],
)
SI = MKSA.extend(base=(mol, cd, K), units=all_units, name='SI', dimension_system=dimsys_SI, derived_units={
power: watt,
magnetic_flux: weber,
time: second,
impedance: ohm,
pressure: pascal,
current: ampere,
voltage: volt,
length: meter,
frequency: hertz,
inductance: henry,
temperature: kelvin,
amount_of_substance: mole,
luminous_intensity: candela,
conductance: siemens,
mass: kilogram,
magnetic_density: tesla,
charge: coulomb,
force: newton,
capacitance: farad,
energy: joule,
velocity: meter/second,
})
One = S.One
SI.set_quantity_dimension(radian, One)
SI.set_quantity_scale_factor(ampere, One)
SI.set_quantity_scale_factor(kelvin, One)
SI.set_quantity_scale_factor(mole, One)
SI.set_quantity_scale_factor(candela, One)
# MKSA extension to MKS: derived units
SI.set_quantity_scale_factor(coulomb, One)
SI.set_quantity_scale_factor(volt, joule/coulomb)
SI.set_quantity_scale_factor(ohm, volt/ampere)
SI.set_quantity_scale_factor(siemens, ampere/volt)
SI.set_quantity_scale_factor(farad, coulomb/volt)
SI.set_quantity_scale_factor(henry, volt*second/ampere)
SI.set_quantity_scale_factor(tesla, volt*second/meter**2)
SI.set_quantity_scale_factor(weber, joule/ampere)
SI.set_quantity_dimension(lux, luminous_intensity / length ** 2)
SI.set_quantity_scale_factor(lux, steradian*candela/meter**2)
# katal is the SI unit of catalytic activity
SI.set_quantity_dimension(katal, amount_of_substance / time)
SI.set_quantity_scale_factor(katal, mol/second)
# gray is the SI unit of absorbed dose
SI.set_quantity_dimension(gray, energy / mass)
SI.set_quantity_scale_factor(gray, meter**2/second**2)
# becquerel is the SI unit of radioactivity
SI.set_quantity_dimension(becquerel, 1 / time)
SI.set_quantity_scale_factor(becquerel, 1/second)
#### CONSTANTS ####
# elementary charge
# REF: NIST SP 959 (June 2019)
SI.set_quantity_dimension(elementary_charge, charge)
SI.set_quantity_scale_factor(elementary_charge, 1.602176634e-19*coulomb)
# Electronvolt
# REF: NIST SP 959 (June 2019)
SI.set_quantity_dimension(electronvolt, energy)
SI.set_quantity_scale_factor(electronvolt, 1.602176634e-19*joule)
# Avogadro number
# REF: NIST SP 959 (June 2019)
SI.set_quantity_dimension(avogadro_number, One)
SI.set_quantity_scale_factor(avogadro_number, 6.02214076e23)
# Avogadro constant
SI.set_quantity_dimension(avogadro_constant, amount_of_substance ** -1)
SI.set_quantity_scale_factor(avogadro_constant, avogadro_number / mol)
# Boltzmann constant
# REF: NIST SP 959 (June 2019)
SI.set_quantity_dimension(boltzmann_constant, energy / temperature)
SI.set_quantity_scale_factor(boltzmann_constant, 1.380649e-23*joule/kelvin)
# Stefan-Boltzmann constant
# REF: NIST SP 959 (June 2019)
SI.set_quantity_dimension(stefan_boltzmann_constant, energy * time ** -1 * length ** -2 * temperature ** -4)
SI.set_quantity_scale_factor(stefan_boltzmann_constant, pi**2 * boltzmann_constant**4 / (60 * hbar**3 * speed_of_light ** 2))
# Atomic mass
# REF: NIST SP 959 (June 2019)
SI.set_quantity_dimension(atomic_mass_constant, mass)
SI.set_quantity_scale_factor(atomic_mass_constant, 1.66053906660e-24*gram)
# Molar gas constant
# REF: NIST SP 959 (June 2019)
SI.set_quantity_dimension(molar_gas_constant, energy / (temperature * amount_of_substance))
SI.set_quantity_scale_factor(molar_gas_constant, boltzmann_constant * avogadro_constant)
# Faraday constant
SI.set_quantity_dimension(faraday_constant, charge / amount_of_substance)
SI.set_quantity_scale_factor(faraday_constant, elementary_charge * avogadro_constant)
# Josephson constant
SI.set_quantity_dimension(josephson_constant, frequency / voltage)
SI.set_quantity_scale_factor(josephson_constant, 0.5 * planck / elementary_charge)
# Von Klitzing constant
SI.set_quantity_dimension(von_klitzing_constant, voltage / current)
SI.set_quantity_scale_factor(von_klitzing_constant, hbar / elementary_charge ** 2)
# Acceleration due to gravity (on the Earth surface)
SI.set_quantity_dimension(acceleration_due_to_gravity, acceleration)
SI.set_quantity_scale_factor(acceleration_due_to_gravity, 9.80665*meter/second**2)
# magnetic constant:
SI.set_quantity_dimension(magnetic_constant, force / current ** 2)
SI.set_quantity_scale_factor(magnetic_constant, 4*pi/10**7 * newton/ampere**2)
# electric constant:
SI.set_quantity_dimension(vacuum_permittivity, capacitance / length)
SI.set_quantity_scale_factor(vacuum_permittivity, 1/(u0 * c**2))
# vacuum impedance:
SI.set_quantity_dimension(vacuum_impedance, impedance)
SI.set_quantity_scale_factor(vacuum_impedance, u0 * c)
# Electron rest mass
SI.set_quantity_dimension(electron_rest_mass, mass)
SI.set_quantity_scale_factor(electron_rest_mass, 9.1093837015e-31*kilogram)
# Coulomb's constant:
SI.set_quantity_dimension(coulomb_constant, force * length ** 2 / charge ** 2)
SI.set_quantity_scale_factor(coulomb_constant, 1/(4*pi*vacuum_permittivity))
SI.set_quantity_dimension(psi, pressure)
SI.set_quantity_scale_factor(psi, pound * gee / inch ** 2)
SI.set_quantity_dimension(mmHg, pressure)
SI.set_quantity_scale_factor(mmHg, dHg0 * acceleration_due_to_gravity * kilogram / meter**2)
SI.set_quantity_dimension(milli_mass_unit, mass)
SI.set_quantity_scale_factor(milli_mass_unit, atomic_mass_unit/1000)
SI.set_quantity_dimension(quart, length ** 3)
SI.set_quantity_scale_factor(quart, Rational(231, 4) * inch**3)
# Other convenient units and magnitudes
SI.set_quantity_dimension(lightyear, length)
SI.set_quantity_scale_factor(lightyear, speed_of_light*julian_year)
SI.set_quantity_dimension(astronomical_unit, length)
SI.set_quantity_scale_factor(astronomical_unit, 149597870691*meter)
# Fundamental Planck units:
SI.set_quantity_dimension(planck_mass, mass)
SI.set_quantity_scale_factor(planck_mass, sqrt(hbar*speed_of_light/G))
SI.set_quantity_dimension(planck_time, time)
SI.set_quantity_scale_factor(planck_time, sqrt(hbar*G/speed_of_light**5))
SI.set_quantity_dimension(planck_temperature, temperature)
SI.set_quantity_scale_factor(planck_temperature, sqrt(hbar*speed_of_light**5/G/boltzmann**2))
SI.set_quantity_dimension(planck_length, length)
SI.set_quantity_scale_factor(planck_length, sqrt(hbar*G/speed_of_light**3))
SI.set_quantity_dimension(planck_charge, charge)
SI.set_quantity_scale_factor(planck_charge, sqrt(4*pi*electric_constant*hbar*speed_of_light))
# Derived Planck units:
SI.set_quantity_dimension(planck_area, length ** 2)
SI.set_quantity_scale_factor(planck_area, planck_length**2)
SI.set_quantity_dimension(planck_volume, length ** 3)
SI.set_quantity_scale_factor(planck_volume, planck_length**3)
SI.set_quantity_dimension(planck_momentum, mass * velocity)
SI.set_quantity_scale_factor(planck_momentum, planck_mass * speed_of_light)
SI.set_quantity_dimension(planck_energy, energy)
SI.set_quantity_scale_factor(planck_energy, planck_mass * speed_of_light**2)
SI.set_quantity_dimension(planck_force, force)
SI.set_quantity_scale_factor(planck_force, planck_energy / planck_length)
SI.set_quantity_dimension(planck_power, power)
SI.set_quantity_scale_factor(planck_power, planck_energy / planck_time)
SI.set_quantity_dimension(planck_density, mass / length ** 3)
SI.set_quantity_scale_factor(planck_density, planck_mass / planck_length**3)
SI.set_quantity_dimension(planck_energy_density, energy / length ** 3)
SI.set_quantity_scale_factor(planck_energy_density, planck_energy / planck_length**3)
SI.set_quantity_dimension(planck_intensity, mass * time ** (-3))
SI.set_quantity_scale_factor(planck_intensity, planck_energy_density * speed_of_light)
SI.set_quantity_dimension(planck_angular_frequency, 1 / time)
SI.set_quantity_scale_factor(planck_angular_frequency, 1 / planck_time)
SI.set_quantity_dimension(planck_pressure, pressure)
SI.set_quantity_scale_factor(planck_pressure, planck_force / planck_length**2)
SI.set_quantity_dimension(planck_current, current)
SI.set_quantity_scale_factor(planck_current, planck_charge / planck_time)
SI.set_quantity_dimension(planck_voltage, voltage)
SI.set_quantity_scale_factor(planck_voltage, planck_energy / planck_charge)
SI.set_quantity_dimension(planck_impedance, impedance)
SI.set_quantity_scale_factor(planck_impedance, planck_voltage / planck_current)
SI.set_quantity_dimension(planck_acceleration, acceleration)
SI.set_quantity_scale_factor(planck_acceleration, speed_of_light / planck_time)
# Older units for radioactivity
SI.set_quantity_dimension(curie, 1 / time)
SI.set_quantity_scale_factor(curie, 37000000000*becquerel)
SI.set_quantity_dimension(rutherford, 1 / time)
SI.set_quantity_scale_factor(rutherford, 1000000*becquerel)
# check that scale factors are the right SI dimensions:
for _scale_factor, _dimension in zip(
SI._quantity_scale_factors.values(),
SI._quantity_dimension_map.values()
):
dimex = SI.get_dimensional_expr(_scale_factor)
if dimex != 1:
# XXX: equivalent_dims is an instance method taking two arguments in
# addition to self so this can not work:
if not DimensionSystem.equivalent_dims(_dimension, Dimension(dimex)): # type: ignore
raise ValueError("quantity value and dimension mismatch")
del _scale_factor, _dimension
__all__ = [
'mmHg', 'atmosphere', 'inductance', 'newton', 'meter',
'vacuum_permittivity', 'pascal', 'magnetic_constant', 'voltage',
'angular_mil', 'luminous_intensity', 'all_units',
'julian_year', 'weber', 'exbibyte', 'liter',
'molar_gas_constant', 'faraday_constant', 'avogadro_constant',
'lightyear', 'planck_density', 'gee', 'mol', 'bit', 'gray',
'planck_momentum', 'bar', 'magnetic_density', 'prefix_unit', 'PREFIXES',
'planck_time', 'dimex', 'gram', 'candela', 'force', 'planck_intensity',
'energy', 'becquerel', 'planck_acceleration', 'speed_of_light',
'conductance', 'frequency', 'coulomb_constant', 'degree', 'lux', 'planck',
'current', 'planck_current', 'tebibyte', 'planck_power', 'MKSA', 'power',
'K', 'planck_volume', 'quart', 'pressure', 'amount_of_substance',
'joule', 'boltzmann_constant', 'Dimension', 'c', 'planck_force', 'length',
'watt', 'action', 'hbar', 'gibibyte', 'DimensionSystem', 'cd', 'volt',
'planck_charge', 'dioptre', 'vacuum_impedance', 'dimsys_default', 'farad',
'charge', 'gravitational_constant', 'temperature', 'u0', 'hertz',
'capacitance', 'tesla', 'steradian', 'planck_mass', 'josephson_constant',
'planck_area', 'stefan_boltzmann_constant', 'base_dims',
'astronomical_unit', 'radian', 'planck_voltage', 'impedance',
'planck_energy', 'Da', 'atomic_mass_constant', 'rutherford', 'second', 'inch',
'elementary_charge', 'SI', 'electronvolt', 'dimsys_SI', 'henry',
'planck_angular_frequency', 'ohm', 'pound', 'planck_pressure', 'G', 'psi',
'dHg0', 'von_klitzing_constant', 'planck_length', 'avogadro_number',
'mole', 'acceleration', 'information', 'planck_energy_density',
'mebibyte', 's', 'acceleration_due_to_gravity', 'electron_rest_mass',
'planck_temperature', 'units', 'mass', 'dimsys_MKSA', 'kelvin', 'kPa',
'boltzmann', 'milli_mass_unit', 'planck_impedance', 'electric_constant',
'derived_dims', 'kg', 'coulomb', 'siemens', 'byte', 'magnetic_flux',
'atomic_mass_unit', 'm', 'kibibyte', 'kilogram', 'One', 'curie', 'u',
'time', 'pebibyte', 'velocity', 'ampere', 'katal',
]

View File

@ -0,0 +1,150 @@
from sympy.physics.units.systems.si import dimsys_SI
from sympy.core.numbers import pi
from sympy.core.singleton import S
from sympy.core.symbol import Symbol
from sympy.functions.elementary.complexes import Abs
from sympy.functions.elementary.exponential import log
from sympy.functions.elementary.miscellaneous import sqrt
from sympy.functions.elementary.trigonometric import (acos, atan2, cos)
from sympy.physics.units.dimensions import Dimension
from sympy.physics.units.definitions.dimension_definitions import (
length, time, mass, force, pressure, angle
)
from sympy.physics.units import foot
from sympy.testing.pytest import raises
def test_Dimension_definition():
assert dimsys_SI.get_dimensional_dependencies(length) == {length: 1}
assert length.name == Symbol("length")
assert length.symbol == Symbol("L")
halflength = sqrt(length)
assert dimsys_SI.get_dimensional_dependencies(halflength) == {length: S.Half}
def test_Dimension_error_definition():
# tuple with more or less than two entries
raises(TypeError, lambda: Dimension(("length", 1, 2)))
raises(TypeError, lambda: Dimension(["length"]))
# non-number power
raises(TypeError, lambda: Dimension({"length": "a"}))
# non-number with named argument
raises(TypeError, lambda: Dimension({"length": (1, 2)}))
# symbol should by Symbol or str
raises(AssertionError, lambda: Dimension("length", symbol=1))
def test_str():
assert str(Dimension("length")) == "Dimension(length)"
assert str(Dimension("length", "L")) == "Dimension(length, L)"
def test_Dimension_properties():
assert dimsys_SI.is_dimensionless(length) is False
assert dimsys_SI.is_dimensionless(length/length) is True
assert dimsys_SI.is_dimensionless(Dimension("undefined")) is False
assert length.has_integer_powers(dimsys_SI) is True
assert (length**(-1)).has_integer_powers(dimsys_SI) is True
assert (length**1.5).has_integer_powers(dimsys_SI) is False
def test_Dimension_add_sub():
assert length + length == length
assert length - length == length
assert -length == length
raises(TypeError, lambda: length + foot)
raises(TypeError, lambda: foot + length)
raises(TypeError, lambda: length - foot)
raises(TypeError, lambda: foot - length)
# issue 14547 - only raise error for dimensional args; allow
# others to pass
x = Symbol('x')
e = length + x
assert e == x + length and e.is_Add and set(e.args) == {length, x}
e = length + 1
assert e == 1 + length == 1 - length and e.is_Add and set(e.args) == {length, 1}
assert dimsys_SI.get_dimensional_dependencies(mass * length / time**2 + force) == \
{length: 1, mass: 1, time: -2}
assert dimsys_SI.get_dimensional_dependencies(mass * length / time**2 + force -
pressure * length**2) == \
{length: 1, mass: 1, time: -2}
raises(TypeError, lambda: dimsys_SI.get_dimensional_dependencies(mass * length / time**2 + pressure))
def test_Dimension_mul_div_exp():
assert 2*length == length*2 == length/2 == length
assert 2/length == 1/length
x = Symbol('x')
m = x*length
assert m == length*x and m.is_Mul and set(m.args) == {x, length}
d = x/length
assert d == x*length**-1 and d.is_Mul and set(d.args) == {x, 1/length}
d = length/x
assert d == length*x**-1 and d.is_Mul and set(d.args) == {1/x, length}
velo = length / time
assert (length * length) == length ** 2
assert dimsys_SI.get_dimensional_dependencies(length * length) == {length: 2}
assert dimsys_SI.get_dimensional_dependencies(length ** 2) == {length: 2}
assert dimsys_SI.get_dimensional_dependencies(length * time) == {length: 1, time: 1}
assert dimsys_SI.get_dimensional_dependencies(velo) == {length: 1, time: -1}
assert dimsys_SI.get_dimensional_dependencies(velo ** 2) == {length: 2, time: -2}
assert dimsys_SI.get_dimensional_dependencies(length / length) == {}
assert dimsys_SI.get_dimensional_dependencies(velo / length * time) == {}
assert dimsys_SI.get_dimensional_dependencies(length ** -1) == {length: -1}
assert dimsys_SI.get_dimensional_dependencies(velo ** -1.5) == {length: -1.5, time: 1.5}
length_a = length**"a"
assert dimsys_SI.get_dimensional_dependencies(length_a) == {length: Symbol("a")}
assert dimsys_SI.get_dimensional_dependencies(length**pi) == {length: pi}
assert dimsys_SI.get_dimensional_dependencies(length**(length/length)) == {length: Dimension(1)}
raises(TypeError, lambda: dimsys_SI.get_dimensional_dependencies(length**length))
assert length != 1
assert length / length != 1
length_0 = length ** 0
assert dimsys_SI.get_dimensional_dependencies(length_0) == {}
# issue 18738
a = Symbol('a')
b = Symbol('b')
c = sqrt(a**2 + b**2)
c_dim = c.subs({a: length, b: length})
assert dimsys_SI.equivalent_dims(c_dim, length)
def test_Dimension_functions():
raises(TypeError, lambda: dimsys_SI.get_dimensional_dependencies(cos(length)))
raises(TypeError, lambda: dimsys_SI.get_dimensional_dependencies(acos(angle)))
raises(TypeError, lambda: dimsys_SI.get_dimensional_dependencies(atan2(length, time)))
raises(TypeError, lambda: dimsys_SI.get_dimensional_dependencies(log(length)))
raises(TypeError, lambda: dimsys_SI.get_dimensional_dependencies(log(100, length)))
raises(TypeError, lambda: dimsys_SI.get_dimensional_dependencies(log(length, 10)))
assert dimsys_SI.get_dimensional_dependencies(pi) == {}
assert dimsys_SI.get_dimensional_dependencies(cos(1)) == {}
assert dimsys_SI.get_dimensional_dependencies(cos(angle)) == {}
assert dimsys_SI.get_dimensional_dependencies(atan2(length, length)) == {}
assert dimsys_SI.get_dimensional_dependencies(log(length / length, length / length)) == {}
assert dimsys_SI.get_dimensional_dependencies(Abs(length)) == {length: 1}
assert dimsys_SI.get_dimensional_dependencies(Abs(length / length)) == {}
assert dimsys_SI.get_dimensional_dependencies(sqrt(-1)) == {}

View File

@ -0,0 +1,95 @@
from sympy.core.symbol import symbols
from sympy.matrices.dense import (Matrix, eye)
from sympy.physics.units.definitions.dimension_definitions import (
action, current, length, mass, time,
velocity)
from sympy.physics.units.dimensions import DimensionSystem
def test_extend():
ms = DimensionSystem((length, time), (velocity,))
mks = ms.extend((mass,), (action,))
res = DimensionSystem((length, time, mass), (velocity, action))
assert mks.base_dims == res.base_dims
assert mks.derived_dims == res.derived_dims
def test_list_dims():
dimsys = DimensionSystem((length, time, mass))
assert dimsys.list_can_dims == (length, mass, time)
def test_dim_can_vector():
dimsys = DimensionSystem(
[length, mass, time],
[velocity, action],
{
velocity: {length: 1, time: -1}
}
)
assert dimsys.dim_can_vector(length) == Matrix([1, 0, 0])
assert dimsys.dim_can_vector(velocity) == Matrix([1, 0, -1])
dimsys = DimensionSystem(
(length, velocity, action),
(mass, time),
{
time: {length: 1, velocity: -1}
}
)
assert dimsys.dim_can_vector(length) == Matrix([0, 1, 0])
assert dimsys.dim_can_vector(velocity) == Matrix([0, 0, 1])
assert dimsys.dim_can_vector(time) == Matrix([0, 1, -1])
dimsys = DimensionSystem(
(length, mass, time),
(velocity, action),
{velocity: {length: 1, time: -1},
action: {mass: 1, length: 2, time: -1}})
assert dimsys.dim_vector(length) == Matrix([1, 0, 0])
assert dimsys.dim_vector(velocity) == Matrix([1, 0, -1])
def test_inv_can_transf_matrix():
dimsys = DimensionSystem((length, mass, time))
assert dimsys.inv_can_transf_matrix == eye(3)
def test_can_transf_matrix():
dimsys = DimensionSystem((length, mass, time))
assert dimsys.can_transf_matrix == eye(3)
dimsys = DimensionSystem((length, velocity, action))
assert dimsys.can_transf_matrix == eye(3)
dimsys = DimensionSystem((length, time), (velocity,), {velocity: {length: 1, time: -1}})
assert dimsys.can_transf_matrix == eye(2)
def test_is_consistent():
assert DimensionSystem((length, time)).is_consistent is True
def test_print_dim_base():
mksa = DimensionSystem(
(length, time, mass, current),
(action,),
{action: {mass: 1, length: 2, time: -1}})
L, M, T = symbols("L M T")
assert mksa.print_dim_base(action) == L**2*M/T
def test_dim():
dimsys = DimensionSystem(
(length, mass, time),
(velocity, action),
{velocity: {length: 1, time: -1},
action: {mass: 1, length: 2, time: -1}}
)
assert dimsys.dim == 3

View File

@ -0,0 +1,86 @@
from sympy.core.mul import Mul
from sympy.core.numbers import Rational
from sympy.core.singleton import S
from sympy.core.symbol import (Symbol, symbols)
from sympy.physics.units import Quantity, length, meter, W
from sympy.physics.units.prefixes import PREFIXES, Prefix, prefix_unit, kilo, \
kibi
from sympy.physics.units.systems import SI
x = Symbol('x')
def test_prefix_operations():
m = PREFIXES['m']
k = PREFIXES['k']
M = PREFIXES['M']
dodeca = Prefix('dodeca', 'dd', 1, base=12)
assert m * k is S.One
assert m * W == W / 1000
assert k * k == M
assert 1 / m == k
assert k / m == M
assert dodeca * dodeca == 144
assert 1 / dodeca == S.One / 12
assert k / dodeca == S(1000) / 12
assert dodeca / dodeca is S.One
m = Quantity("fake_meter")
SI.set_quantity_dimension(m, S.One)
SI.set_quantity_scale_factor(m, S.One)
assert dodeca * m == 12 * m
assert dodeca / m == 12 / m
expr1 = kilo * 3
assert isinstance(expr1, Mul)
assert expr1.args == (3, kilo)
expr2 = kilo * x
assert isinstance(expr2, Mul)
assert expr2.args == (x, kilo)
expr3 = kilo / 3
assert isinstance(expr3, Mul)
assert expr3.args == (Rational(1, 3), kilo)
assert expr3.args == (S.One/3, kilo)
expr4 = kilo / x
assert isinstance(expr4, Mul)
assert expr4.args == (1/x, kilo)
def test_prefix_unit():
m = Quantity("fake_meter", abbrev="m")
m.set_global_relative_scale_factor(1, meter)
pref = {"m": PREFIXES["m"], "c": PREFIXES["c"], "d": PREFIXES["d"]}
q1 = Quantity("millifake_meter", abbrev="mm")
q2 = Quantity("centifake_meter", abbrev="cm")
q3 = Quantity("decifake_meter", abbrev="dm")
SI.set_quantity_dimension(q1, length)
SI.set_quantity_scale_factor(q1, PREFIXES["m"])
SI.set_quantity_scale_factor(q1, PREFIXES["c"])
SI.set_quantity_scale_factor(q1, PREFIXES["d"])
res = [q1, q2, q3]
prefs = prefix_unit(m, pref)
assert set(prefs) == set(res)
assert {v.abbrev for v in prefs} == set(symbols("mm,cm,dm"))
def test_bases():
assert kilo.base == 10
assert kibi.base == 2
def test_repr():
assert eval(repr(kilo)) == kilo
assert eval(repr(kibi)) == kibi

View File

@ -0,0 +1,575 @@
import warnings
from sympy.core.add import Add
from sympy.core.function import (Function, diff)
from sympy.core.numbers import (Number, Rational)
from sympy.core.singleton import S
from sympy.core.symbol import (Symbol, symbols)
from sympy.functions.elementary.complexes import Abs
from sympy.functions.elementary.exponential import (exp, log)
from sympy.functions.elementary.miscellaneous import sqrt
from sympy.functions.elementary.trigonometric import sin
from sympy.integrals.integrals import integrate
from sympy.physics.units import (amount_of_substance, area, convert_to, find_unit,
volume, kilometer, joule, molar_gas_constant,
vacuum_permittivity, elementary_charge, volt,
ohm)
from sympy.physics.units.definitions import (amu, au, centimeter, coulomb,
day, foot, grams, hour, inch, kg, km, m, meter, millimeter,
minute, quart, s, second, speed_of_light, bit,
byte, kibibyte, mebibyte, gibibyte, tebibyte, pebibyte, exbibyte,
kilogram, gravitational_constant, electron_rest_mass)
from sympy.physics.units.definitions.dimension_definitions import (
Dimension, charge, length, time, temperature, pressure,
energy, mass
)
from sympy.physics.units.prefixes import PREFIXES, kilo
from sympy.physics.units.quantities import PhysicalConstant, Quantity
from sympy.physics.units.systems import SI
from sympy.testing.pytest import raises
k = PREFIXES["k"]
def test_str_repr():
assert str(kg) == "kilogram"
def test_eq():
# simple test
assert 10*m == 10*m
assert 10*m != 10*s
def test_convert_to():
q = Quantity("q1")
q.set_global_relative_scale_factor(S(5000), meter)
assert q.convert_to(m) == 5000*m
assert speed_of_light.convert_to(m / s) == 299792458 * m / s
assert day.convert_to(s) == 86400*s
# Wrong dimension to convert:
assert q.convert_to(s) == q
assert speed_of_light.convert_to(m) == speed_of_light
expr = joule*second
conv = convert_to(expr, joule)
assert conv == joule*second
def test_Quantity_definition():
q = Quantity("s10", abbrev="sabbr")
q.set_global_relative_scale_factor(10, second)
u = Quantity("u", abbrev="dam")
u.set_global_relative_scale_factor(10, meter)
km = Quantity("km")
km.set_global_relative_scale_factor(kilo, meter)
v = Quantity("u")
v.set_global_relative_scale_factor(5*kilo, meter)
assert q.scale_factor == 10
assert q.dimension == time
assert q.abbrev == Symbol("sabbr")
assert u.dimension == length
assert u.scale_factor == 10
assert u.abbrev == Symbol("dam")
assert km.scale_factor == 1000
assert km.func(*km.args) == km
assert km.func(*km.args).args == km.args
assert v.dimension == length
assert v.scale_factor == 5000
def test_abbrev():
u = Quantity("u")
u.set_global_relative_scale_factor(S.One, meter)
assert u.name == Symbol("u")
assert u.abbrev == Symbol("u")
u = Quantity("u", abbrev="om")
u.set_global_relative_scale_factor(S(2), meter)
assert u.name == Symbol("u")
assert u.abbrev == Symbol("om")
assert u.scale_factor == 2
assert isinstance(u.scale_factor, Number)
u = Quantity("u", abbrev="ikm")
u.set_global_relative_scale_factor(3*kilo, meter)
assert u.abbrev == Symbol("ikm")
assert u.scale_factor == 3000
def test_print():
u = Quantity("unitname", abbrev="dam")
assert repr(u) == "unitname"
assert str(u) == "unitname"
def test_Quantity_eq():
u = Quantity("u", abbrev="dam")
v = Quantity("v1")
assert u != v
v = Quantity("v2", abbrev="ds")
assert u != v
v = Quantity("v3", abbrev="dm")
assert u != v
def test_add_sub():
u = Quantity("u")
v = Quantity("v")
w = Quantity("w")
u.set_global_relative_scale_factor(S(10), meter)
v.set_global_relative_scale_factor(S(5), meter)
w.set_global_relative_scale_factor(S(2), second)
assert isinstance(u + v, Add)
assert (u + v.convert_to(u)) == (1 + S.Half)*u
assert isinstance(u - v, Add)
assert (u - v.convert_to(u)) == S.Half*u
def test_quantity_abs():
v_w1 = Quantity('v_w1')
v_w2 = Quantity('v_w2')
v_w3 = Quantity('v_w3')
v_w1.set_global_relative_scale_factor(1, meter/second)
v_w2.set_global_relative_scale_factor(1, meter/second)
v_w3.set_global_relative_scale_factor(1, meter/second)
expr = v_w3 - Abs(v_w1 - v_w2)
assert SI.get_dimensional_expr(v_w1) == (length/time).name
Dq = Dimension(SI.get_dimensional_expr(expr))
assert SI.get_dimension_system().get_dimensional_dependencies(Dq) == {
length: 1,
time: -1,
}
assert meter == sqrt(meter**2)
def test_check_unit_consistency():
u = Quantity("u")
v = Quantity("v")
w = Quantity("w")
u.set_global_relative_scale_factor(S(10), meter)
v.set_global_relative_scale_factor(S(5), meter)
w.set_global_relative_scale_factor(S(2), second)
def check_unit_consistency(expr):
SI._collect_factor_and_dimension(expr)
raises(ValueError, lambda: check_unit_consistency(u + w))
raises(ValueError, lambda: check_unit_consistency(u - w))
raises(ValueError, lambda: check_unit_consistency(u + 1))
raises(ValueError, lambda: check_unit_consistency(u - 1))
raises(ValueError, lambda: check_unit_consistency(1 - exp(u / w)))
def test_mul_div():
u = Quantity("u")
v = Quantity("v")
t = Quantity("t")
ut = Quantity("ut")
v2 = Quantity("v")
u.set_global_relative_scale_factor(S(10), meter)
v.set_global_relative_scale_factor(S(5), meter)
t.set_global_relative_scale_factor(S(2), second)
ut.set_global_relative_scale_factor(S(20), meter*second)
v2.set_global_relative_scale_factor(S(5), meter/second)
assert 1 / u == u**(-1)
assert u / 1 == u
v1 = u / t
v2 = v
# Pow only supports structural equality:
assert v1 != v2
assert v1 == v2.convert_to(v1)
# TODO: decide whether to allow such expression in the future
# (requires somehow manipulating the core).
# assert u / Quantity('l2', dimension=length, scale_factor=2) == 5
assert u * 1 == u
ut1 = u * t
ut2 = ut
# Mul only supports structural equality:
assert ut1 != ut2
assert ut1 == ut2.convert_to(ut1)
# Mul only supports structural equality:
lp1 = Quantity("lp1")
lp1.set_global_relative_scale_factor(S(2), 1/meter)
assert u * lp1 != 20
assert u**0 == 1
assert u**1 == u
# TODO: Pow only support structural equality:
u2 = Quantity("u2")
u3 = Quantity("u3")
u2.set_global_relative_scale_factor(S(100), meter**2)
u3.set_global_relative_scale_factor(Rational(1, 10), 1/meter)
assert u ** 2 != u2
assert u ** -1 != u3
assert u ** 2 == u2.convert_to(u)
assert u ** -1 == u3.convert_to(u)
def test_units():
assert convert_to((5*m/s * day) / km, 1) == 432
assert convert_to(foot / meter, meter) == Rational(3048, 10000)
# amu is a pure mass so mass/mass gives a number, not an amount (mol)
# TODO: need better simplification routine:
assert str(convert_to(grams/amu, grams).n(2)) == '6.0e+23'
# Light from the sun needs about 8.3 minutes to reach earth
t = (1*au / speed_of_light) / minute
# TODO: need a better way to simplify expressions containing units:
t = convert_to(convert_to(t, meter / minute), meter)
assert t.simplify() == Rational(49865956897, 5995849160)
# TODO: fix this, it should give `m` without `Abs`
assert sqrt(m**2) == m
assert (sqrt(m))**2 == m
t = Symbol('t')
assert integrate(t*m/s, (t, 1*s, 5*s)) == 12*m*s
assert (t * m/s).integrate((t, 1*s, 5*s)) == 12*m*s
def test_issue_quart():
assert convert_to(4 * quart / inch ** 3, meter) == 231
assert convert_to(4 * quart / inch ** 3, millimeter) == 231
def test_electron_rest_mass():
assert convert_to(electron_rest_mass, kilogram) == 9.1093837015e-31*kilogram
assert convert_to(electron_rest_mass, grams) == 9.1093837015e-28*grams
def test_issue_5565():
assert (m < s).is_Relational
def test_find_unit():
assert find_unit('coulomb') == ['coulomb', 'coulombs', 'coulomb_constant']
assert find_unit(coulomb) == ['C', 'coulomb', 'coulombs', 'planck_charge', 'elementary_charge']
assert find_unit(charge) == ['C', 'coulomb', 'coulombs', 'planck_charge', 'elementary_charge']
assert find_unit(inch) == [
'm', 'au', 'cm', 'dm', 'ft', 'km', 'ly', 'mi', 'mm', 'nm', 'pm', 'um', 'yd',
'nmi', 'feet', 'foot', 'inch', 'mile', 'yard', 'meter', 'miles', 'yards',
'inches', 'meters', 'micron', 'microns', 'angstrom', 'angstroms', 'decimeter',
'kilometer', 'lightyear', 'nanometer', 'picometer', 'centimeter', 'decimeters',
'kilometers', 'lightyears', 'micrometer', 'millimeter', 'nanometers', 'picometers',
'centimeters', 'micrometers', 'millimeters', 'nautical_mile', 'planck_length',
'nautical_miles', 'astronomical_unit', 'astronomical_units']
assert find_unit(inch**-1) == ['D', 'dioptre', 'optical_power']
assert find_unit(length**-1) == ['D', 'dioptre', 'optical_power']
assert find_unit(inch ** 2) == ['ha', 'hectare', 'planck_area']
assert find_unit(inch ** 3) == [
'L', 'l', 'cL', 'cl', 'dL', 'dl', 'mL', 'ml', 'liter', 'quart', 'liters', 'quarts',
'deciliter', 'centiliter', 'deciliters', 'milliliter',
'centiliters', 'milliliters', 'planck_volume']
assert find_unit('voltage') == ['V', 'v', 'volt', 'volts', 'planck_voltage']
assert find_unit(grams) == ['g', 't', 'Da', 'kg', 'me', 'mg', 'ug', 'amu', 'mmu', 'amus',
'gram', 'mmus', 'grams', 'pound', 'tonne', 'dalton', 'pounds',
'kilogram', 'kilograms', 'microgram', 'milligram', 'metric_ton',
'micrograms', 'milligrams', 'planck_mass', 'milli_mass_unit', 'atomic_mass_unit',
'electron_rest_mass', 'atomic_mass_constant']
def test_Quantity_derivative():
x = symbols("x")
assert diff(x*meter, x) == meter
assert diff(x**3*meter**2, x) == 3*x**2*meter**2
assert diff(meter, meter) == 1
assert diff(meter**2, meter) == 2*meter
def test_quantity_postprocessing():
q1 = Quantity('q1')
q2 = Quantity('q2')
SI.set_quantity_dimension(q1, length*pressure**2*temperature/time)
SI.set_quantity_dimension(q2, energy*pressure*temperature/(length**2*time))
assert q1 + q2
q = q1 + q2
Dq = Dimension(SI.get_dimensional_expr(q))
assert SI.get_dimension_system().get_dimensional_dependencies(Dq) == {
length: -1,
mass: 2,
temperature: 1,
time: -5,
}
def test_factor_and_dimension():
assert (3000, Dimension(1)) == SI._collect_factor_and_dimension(3000)
assert (1001, length) == SI._collect_factor_and_dimension(meter + km)
assert (2, length/time) == SI._collect_factor_and_dimension(
meter/second + 36*km/(10*hour))
x, y = symbols('x y')
assert (x + y/100, length) == SI._collect_factor_and_dimension(
x*m + y*centimeter)
cH = Quantity('cH')
SI.set_quantity_dimension(cH, amount_of_substance/volume)
pH = -log(cH)
assert (1, volume/amount_of_substance) == SI._collect_factor_and_dimension(
exp(pH))
v_w1 = Quantity('v_w1')
v_w2 = Quantity('v_w2')
v_w1.set_global_relative_scale_factor(Rational(3, 2), meter/second)
v_w2.set_global_relative_scale_factor(2, meter/second)
expr = Abs(v_w1/2 - v_w2)
assert (Rational(5, 4), length/time) == \
SI._collect_factor_and_dimension(expr)
expr = Rational(5, 2)*second/meter*v_w1 - 3000
assert (-(2996 + Rational(1, 4)), Dimension(1)) == \
SI._collect_factor_and_dimension(expr)
expr = v_w1**(v_w2/v_w1)
assert ((Rational(3, 2))**Rational(4, 3), (length/time)**Rational(4, 3)) == \
SI._collect_factor_and_dimension(expr)
def test_dimensional_expr_of_derivative():
l = Quantity('l')
t = Quantity('t')
t1 = Quantity('t1')
l.set_global_relative_scale_factor(36, km)
t.set_global_relative_scale_factor(1, hour)
t1.set_global_relative_scale_factor(1, second)
x = Symbol('x')
y = Symbol('y')
f = Function('f')
dfdx = f(x, y).diff(x, y)
dl_dt = dfdx.subs({f(x, y): l, x: t, y: t1})
assert SI.get_dimensional_expr(dl_dt) ==\
SI.get_dimensional_expr(l / t / t1) ==\
Symbol("length")/Symbol("time")**2
assert SI._collect_factor_and_dimension(dl_dt) ==\
SI._collect_factor_and_dimension(l / t / t1) ==\
(10, length/time**2)
def test_get_dimensional_expr_with_function():
v_w1 = Quantity('v_w1')
v_w2 = Quantity('v_w2')
v_w1.set_global_relative_scale_factor(1, meter/second)
v_w2.set_global_relative_scale_factor(1, meter/second)
assert SI.get_dimensional_expr(sin(v_w1)) == \
sin(SI.get_dimensional_expr(v_w1))
assert SI.get_dimensional_expr(sin(v_w1/v_w2)) == 1
def test_binary_information():
assert convert_to(kibibyte, byte) == 1024*byte
assert convert_to(mebibyte, byte) == 1024**2*byte
assert convert_to(gibibyte, byte) == 1024**3*byte
assert convert_to(tebibyte, byte) == 1024**4*byte
assert convert_to(pebibyte, byte) == 1024**5*byte
assert convert_to(exbibyte, byte) == 1024**6*byte
assert kibibyte.convert_to(bit) == 8*1024*bit
assert byte.convert_to(bit) == 8*bit
a = 10*kibibyte*hour
assert convert_to(a, byte) == 10240*byte*hour
assert convert_to(a, minute) == 600*kibibyte*minute
assert convert_to(a, [byte, minute]) == 614400*byte*minute
def test_conversion_with_2_nonstandard_dimensions():
good_grade = Quantity("good_grade")
kilo_good_grade = Quantity("kilo_good_grade")
centi_good_grade = Quantity("centi_good_grade")
kilo_good_grade.set_global_relative_scale_factor(1000, good_grade)
centi_good_grade.set_global_relative_scale_factor(S.One/10**5, kilo_good_grade)
charity_points = Quantity("charity_points")
milli_charity_points = Quantity("milli_charity_points")
missions = Quantity("missions")
milli_charity_points.set_global_relative_scale_factor(S.One/1000, charity_points)
missions.set_global_relative_scale_factor(251, charity_points)
assert convert_to(
kilo_good_grade*milli_charity_points*millimeter,
[centi_good_grade, missions, centimeter]
) == S.One * 10**5 / (251*1000) / 10 * centi_good_grade*missions*centimeter
def test_eval_subs():
energy, mass, force = symbols('energy mass force')
expr1 = energy/mass
units = {energy: kilogram*meter**2/second**2, mass: kilogram}
assert expr1.subs(units) == meter**2/second**2
expr2 = force/mass
units = {force:gravitational_constant*kilogram**2/meter**2, mass:kilogram}
assert expr2.subs(units) == gravitational_constant*kilogram/meter**2
def test_issue_14932():
assert (log(inch) - log(2)).simplify() == log(inch/2)
assert (log(inch) - log(foot)).simplify() == -log(12)
p = symbols('p', positive=True)
assert (log(inch) - log(p)).simplify() == log(inch/p)
def test_issue_14547():
# the root issue is that an argument with dimensions should
# not raise an error when the `arg - 1` calculation is
# performed in the assumptions system
from sympy.physics.units import foot, inch
from sympy.core.relational import Eq
assert log(foot).is_zero is None
assert log(foot).is_positive is None
assert log(foot).is_nonnegative is None
assert log(foot).is_negative is None
assert log(foot).is_algebraic is None
assert log(foot).is_rational is None
# doesn't raise error
assert Eq(log(foot), log(inch)) is not None # might be False or unevaluated
x = Symbol('x')
e = foot + x
assert e.is_Add and set(e.args) == {foot, x}
e = foot + 1
assert e.is_Add and set(e.args) == {foot, 1}
def test_issue_22164():
warnings.simplefilter("error")
dm = Quantity("dm")
SI.set_quantity_dimension(dm, length)
SI.set_quantity_scale_factor(dm, 1)
bad_exp = Quantity("bad_exp")
SI.set_quantity_dimension(bad_exp, length)
SI.set_quantity_scale_factor(bad_exp, 1)
expr = dm ** bad_exp
# deprecation warning is not expected here
SI._collect_factor_and_dimension(expr)
def test_issue_22819():
from sympy.physics.units import tonne, gram, Da
from sympy.physics.units.systems.si import dimsys_SI
assert tonne.convert_to(gram) == 1000000*gram
assert dimsys_SI.get_dimensional_dependencies(area) == {length: 2}
assert Da.scale_factor == 1.66053906660000e-24
def test_issue_20288():
from sympy.core.numbers import E
from sympy.physics.units import energy
u = Quantity('u')
v = Quantity('v')
SI.set_quantity_dimension(u, energy)
SI.set_quantity_dimension(v, energy)
u.set_global_relative_scale_factor(1, joule)
v.set_global_relative_scale_factor(1, joule)
expr = 1 + exp(u**2/v**2)
assert SI._collect_factor_and_dimension(expr) == (1 + E, Dimension(1))
def test_issue_24062():
from sympy.core.numbers import E
from sympy.physics.units import impedance, capacitance, time, ohm, farad, second
R = Quantity('R')
C = Quantity('C')
T = Quantity('T')
SI.set_quantity_dimension(R, impedance)
SI.set_quantity_dimension(C, capacitance)
SI.set_quantity_dimension(T, time)
R.set_global_relative_scale_factor(1, ohm)
C.set_global_relative_scale_factor(1, farad)
T.set_global_relative_scale_factor(1, second)
expr = T / (R * C)
dim = SI._collect_factor_and_dimension(expr)[1]
assert SI.get_dimension_system().is_dimensionless(dim)
exp_expr = 1 + exp(expr)
assert SI._collect_factor_and_dimension(exp_expr) == (1 + E, Dimension(1))
def test_issue_24211():
from sympy.physics.units import time, velocity, acceleration, second, meter
V1 = Quantity('V1')
SI.set_quantity_dimension(V1, velocity)
SI.set_quantity_scale_factor(V1, 1 * meter / second)
A1 = Quantity('A1')
SI.set_quantity_dimension(A1, acceleration)
SI.set_quantity_scale_factor(A1, 1 * meter / second**2)
T1 = Quantity('T1')
SI.set_quantity_dimension(T1, time)
SI.set_quantity_scale_factor(T1, 1 * second)
expr = A1*T1 + V1
# should not throw ValueError here
SI._collect_factor_and_dimension(expr)
def test_prefixed_property():
assert not meter.is_prefixed
assert not joule.is_prefixed
assert not day.is_prefixed
assert not second.is_prefixed
assert not volt.is_prefixed
assert not ohm.is_prefixed
assert centimeter.is_prefixed
assert kilometer.is_prefixed
assert kilogram.is_prefixed
assert pebibyte.is_prefixed
def test_physics_constant():
from sympy.physics.units import definitions
for name in dir(definitions):
quantity = getattr(definitions, name)
if not isinstance(quantity, Quantity):
continue
if name.endswith('_constant'):
assert isinstance(quantity, PhysicalConstant), f"{quantity} must be PhysicalConstant, but is {type(quantity)}"
assert quantity.is_physical_constant, f"{name} is not marked as physics constant when it should be"
for const in [gravitational_constant, molar_gas_constant, vacuum_permittivity, speed_of_light, elementary_charge]:
assert isinstance(const, PhysicalConstant), f"{const} must be PhysicalConstant, but is {type(const)}"
assert const.is_physical_constant, f"{const} is not marked as physics constant when it should be"
assert not meter.is_physical_constant
assert not joule.is_physical_constant

View File

@ -0,0 +1,55 @@
from sympy.concrete.tests.test_sums_products import NS
from sympy.core.singleton import S
from sympy.functions.elementary.miscellaneous import sqrt
from sympy.physics.units import convert_to, coulomb_constant, elementary_charge, gravitational_constant, planck
from sympy.physics.units.definitions.unit_definitions import angstrom, statcoulomb, coulomb, second, gram, centimeter, erg, \
newton, joule, dyne, speed_of_light, meter, farad, henry, statvolt, volt, ohm
from sympy.physics.units.systems import SI
from sympy.physics.units.systems.cgs import cgs_gauss
def test_conversion_to_from_si():
assert convert_to(statcoulomb, coulomb, cgs_gauss) == coulomb/2997924580
assert convert_to(coulomb, statcoulomb, cgs_gauss) == 2997924580*statcoulomb
assert convert_to(statcoulomb, sqrt(gram*centimeter**3)/second, cgs_gauss) == centimeter**(S(3)/2)*sqrt(gram)/second
assert convert_to(coulomb, sqrt(gram*centimeter**3)/second, cgs_gauss) == 2997924580*centimeter**(S(3)/2)*sqrt(gram)/second
# SI units have an additional base unit, no conversion in case of electromagnetism:
assert convert_to(coulomb, statcoulomb, SI) == coulomb
assert convert_to(statcoulomb, coulomb, SI) == statcoulomb
# SI without electromagnetism:
assert convert_to(erg, joule, SI) == joule/10**7
assert convert_to(erg, joule, cgs_gauss) == joule/10**7
assert convert_to(joule, erg, SI) == 10**7*erg
assert convert_to(joule, erg, cgs_gauss) == 10**7*erg
assert convert_to(dyne, newton, SI) == newton/10**5
assert convert_to(dyne, newton, cgs_gauss) == newton/10**5
assert convert_to(newton, dyne, SI) == 10**5*dyne
assert convert_to(newton, dyne, cgs_gauss) == 10**5*dyne
def test_cgs_gauss_convert_constants():
assert convert_to(speed_of_light, centimeter/second, cgs_gauss) == 29979245800*centimeter/second
assert convert_to(coulomb_constant, 1, cgs_gauss) == 1
assert convert_to(coulomb_constant, newton*meter**2/coulomb**2, cgs_gauss) == 22468879468420441*meter**2*newton/(2500000*coulomb**2)
assert convert_to(coulomb_constant, newton*meter**2/coulomb**2, SI) == 22468879468420441*meter**2*newton/(2500000*coulomb**2)
assert convert_to(coulomb_constant, dyne*centimeter**2/statcoulomb**2, cgs_gauss) == centimeter**2*dyne/statcoulomb**2
assert convert_to(coulomb_constant, 1, SI) == coulomb_constant
assert NS(convert_to(coulomb_constant, newton*meter**2/coulomb**2, SI)) == '8987551787.36818*meter**2*newton/coulomb**2'
assert convert_to(elementary_charge, statcoulomb, cgs_gauss)
assert convert_to(angstrom, centimeter, cgs_gauss) == 1*centimeter/10**8
assert convert_to(gravitational_constant, dyne*centimeter**2/gram**2, cgs_gauss)
assert NS(convert_to(planck, erg*second, cgs_gauss)) == '6.62607015e-27*erg*second'
spc = 25000*second/(22468879468420441*centimeter)
assert convert_to(ohm, second/centimeter, cgs_gauss) == spc
assert convert_to(henry, second**2/centimeter, cgs_gauss) == spc*second
assert convert_to(volt, statvolt, cgs_gauss) == 10**6*statvolt/299792458
assert convert_to(farad, centimeter, cgs_gauss) == 299792458**2*centimeter/10**5

View File

@ -0,0 +1,86 @@
from sympy.physics.units import DimensionSystem, joule, second, ampere
from sympy.core.numbers import Rational
from sympy.core.singleton import S
from sympy.physics.units.definitions import c, kg, m, s
from sympy.physics.units.definitions.dimension_definitions import length, time
from sympy.physics.units.quantities import Quantity
from sympy.physics.units.unitsystem import UnitSystem
from sympy.physics.units.util import convert_to
def test_definition():
# want to test if the system can have several units of the same dimension
dm = Quantity("dm")
base = (m, s)
# base_dim = (m.dimension, s.dimension)
ms = UnitSystem(base, (c, dm), "MS", "MS system")
ms.set_quantity_dimension(dm, length)
ms.set_quantity_scale_factor(dm, Rational(1, 10))
assert set(ms._base_units) == set(base)
assert set(ms._units) == {m, s, c, dm}
# assert ms._units == DimensionSystem._sort_dims(base + (velocity,))
assert ms.name == "MS"
assert ms.descr == "MS system"
def test_str_repr():
assert str(UnitSystem((m, s), name="MS")) == "MS"
assert str(UnitSystem((m, s))) == "UnitSystem((meter, second))"
assert repr(UnitSystem((m, s))) == "<UnitSystem: (%s, %s)>" % (m, s)
def test_convert_to():
A = Quantity("A")
A.set_global_relative_scale_factor(S.One, ampere)
Js = Quantity("Js")
Js.set_global_relative_scale_factor(S.One, joule*second)
mksa = UnitSystem((m, kg, s, A), (Js,))
assert convert_to(Js, mksa._base_units) == m**2*kg*s**-1/1000
def test_extend():
ms = UnitSystem((m, s), (c,))
Js = Quantity("Js")
Js.set_global_relative_scale_factor(1, joule*second)
mks = ms.extend((kg,), (Js,))
res = UnitSystem((m, s, kg), (c, Js))
assert set(mks._base_units) == set(res._base_units)
assert set(mks._units) == set(res._units)
def test_dim():
dimsys = UnitSystem((m, kg, s), (c,))
assert dimsys.dim == 3
def test_is_consistent():
dimension_system = DimensionSystem([length, time])
us = UnitSystem([m, s], dimension_system=dimension_system)
assert us.is_consistent == True
def test_get_units_non_prefixed():
from sympy.physics.units import volt, ohm
unit_system = UnitSystem.get_unit_system("SI")
units = unit_system.get_units_non_prefixed()
for prefix in ["giga", "tera", "peta", "exa", "zetta", "yotta", "kilo", "hecto", "deca", "deci", "centi", "milli", "micro", "nano", "pico", "femto", "atto", "zepto", "yocto"]:
for unit in units:
assert isinstance(unit, Quantity), f"{unit} must be a Quantity, not {type(unit)}"
assert not unit.is_prefixed, f"{unit} is marked as prefixed"
assert not unit.is_physical_constant, f"{unit} is marked as physics constant"
assert not unit.name.name.startswith(prefix), f"Unit {unit.name} has prefix {prefix}"
assert volt in units
assert ohm in units
def test_derived_units_must_exist_in_unit_system():
for unit_system in UnitSystem._unit_systems.values():
for preferred_unit in unit_system.derived_units.values():
units = preferred_unit.atoms(Quantity)
for unit in units:
assert unit in unit_system._units, f"Unit {unit} is not in unit system {unit_system}"

View File

@ -0,0 +1,178 @@
from sympy.core.containers import Tuple
from sympy.core.numbers import pi
from sympy.core.power import Pow
from sympy.core.symbol import symbols
from sympy.core.sympify import sympify
from sympy.printing.str import sstr
from sympy.physics.units import (
G, centimeter, coulomb, day, degree, gram, hbar, hour, inch, joule, kelvin,
kilogram, kilometer, length, meter, mile, minute, newton, planck,
planck_length, planck_mass, planck_temperature, planck_time, radians,
second, speed_of_light, steradian, time, km)
from sympy.physics.units.util import convert_to, check_dimensions
from sympy.testing.pytest import raises
from sympy.functions.elementary.miscellaneous import sqrt
def NS(e, n=15, **options):
return sstr(sympify(e).evalf(n, **options), full_prec=True)
L = length
T = time
def test_dim_simplify_add():
# assert Add(L, L) == L
assert L + L == L
def test_dim_simplify_mul():
# assert Mul(L, T) == L*T
assert L*T == L*T
def test_dim_simplify_pow():
assert Pow(L, 2) == L**2
def test_dim_simplify_rec():
# assert Mul(Add(L, L), T) == L*T
assert (L + L) * T == L*T
def test_convert_to_quantities():
assert convert_to(3, meter) == 3
assert convert_to(mile, kilometer) == 25146*kilometer/15625
assert convert_to(meter/second, speed_of_light) == speed_of_light/299792458
assert convert_to(299792458*meter/second, speed_of_light) == speed_of_light
assert convert_to(2*299792458*meter/second, speed_of_light) == 2*speed_of_light
assert convert_to(speed_of_light, meter/second) == 299792458*meter/second
assert convert_to(2*speed_of_light, meter/second) == 599584916*meter/second
assert convert_to(day, second) == 86400*second
assert convert_to(2*hour, minute) == 120*minute
assert convert_to(mile, meter) == 201168*meter/125
assert convert_to(mile/hour, kilometer/hour) == 25146*kilometer/(15625*hour)
assert convert_to(3*newton, meter/second) == 3*newton
assert convert_to(3*newton, kilogram*meter/second**2) == 3*meter*kilogram/second**2
assert convert_to(kilometer + mile, meter) == 326168*meter/125
assert convert_to(2*kilometer + 3*mile, meter) == 853504*meter/125
assert convert_to(inch**2, meter**2) == 16129*meter**2/25000000
assert convert_to(3*inch**2, meter) == 48387*meter**2/25000000
assert convert_to(2*kilometer/hour + 3*mile/hour, meter/second) == 53344*meter/(28125*second)
assert convert_to(2*kilometer/hour + 3*mile/hour, centimeter/second) == 213376*centimeter/(1125*second)
assert convert_to(kilometer * (mile + kilometer), meter) == 2609344 * meter ** 2
assert convert_to(steradian, coulomb) == steradian
assert convert_to(radians, degree) == 180*degree/pi
assert convert_to(radians, [meter, degree]) == 180*degree/pi
assert convert_to(pi*radians, degree) == 180*degree
assert convert_to(pi, degree) == 180*degree
# https://github.com/sympy/sympy/issues/26263
assert convert_to(sqrt(meter**2 + meter**2.0), meter) == sqrt(meter**2 + meter**2.0)
assert convert_to((meter**2 + meter**2.0)**2, meter) == (meter**2 + meter**2.0)**2
def test_convert_to_tuples_of_quantities():
from sympy.core.symbol import symbols
alpha, beta = symbols('alpha beta')
assert convert_to(speed_of_light, [meter, second]) == 299792458 * meter / second
assert convert_to(speed_of_light, (meter, second)) == 299792458 * meter / second
assert convert_to(speed_of_light, Tuple(meter, second)) == 299792458 * meter / second
assert convert_to(joule, [meter, kilogram, second]) == kilogram*meter**2/second**2
assert convert_to(joule, [centimeter, gram, second]) == 10000000*centimeter**2*gram/second**2
assert convert_to(299792458*meter/second, [speed_of_light]) == speed_of_light
assert convert_to(speed_of_light / 2, [meter, second, kilogram]) == meter/second*299792458 / 2
# This doesn't make physically sense, but let's keep it as a conversion test:
assert convert_to(2 * speed_of_light, [meter, second, kilogram]) == 2 * 299792458 * meter / second
assert convert_to(G, [G, speed_of_light, planck]) == 1.0*G
assert NS(convert_to(meter, [G, speed_of_light, hbar]), n=7) == '6.187142e+34*gravitational_constant**0.5000000*hbar**0.5000000/speed_of_light**1.500000'
assert NS(convert_to(planck_mass, kilogram), n=7) == '2.176434e-8*kilogram'
assert NS(convert_to(planck_length, meter), n=7) == '1.616255e-35*meter'
assert NS(convert_to(planck_time, second), n=6) == '5.39125e-44*second'
assert NS(convert_to(planck_temperature, kelvin), n=7) == '1.416784e+32*kelvin'
assert NS(convert_to(convert_to(meter, [G, speed_of_light, planck]), meter), n=10) == '1.000000000*meter'
# similar to https://github.com/sympy/sympy/issues/26263
assert convert_to(sqrt(meter**2 + second**2.0), [meter, second]) == sqrt(meter**2 + second**2.0)
assert convert_to((meter**2 + second**2.0)**2, [meter, second]) == (meter**2 + second**2.0)**2
# similar to https://github.com/sympy/sympy/issues/21463
assert convert_to(1/(beta*meter + meter), 1/meter) == 1/(beta*meter + meter)
assert convert_to(1/(beta*meter + alpha*meter), 1/kilometer) == (1/(kilometer*beta/1000 + alpha*kilometer/1000))
def test_eval_simplify():
from sympy.physics.units import cm, mm, km, m, K, kilo
from sympy.core.symbol import symbols
x, y = symbols('x y')
assert (cm/mm).simplify() == 10
assert (km/m).simplify() == 1000
assert (km/cm).simplify() == 100000
assert (10*x*K*km**2/m/cm).simplify() == 1000000000*x*kelvin
assert (cm/km/m).simplify() == 1/(10000000*centimeter)
assert (3*kilo*meter).simplify() == 3000*meter
assert (4*kilo*meter/(2*kilometer)).simplify() == 2
assert (4*kilometer**2/(kilo*meter)**2).simplify() == 4
def test_quantity_simplify():
from sympy.physics.units.util import quantity_simplify
from sympy.physics.units import kilo, foot
from sympy.core.symbol import symbols
x, y = symbols('x y')
assert quantity_simplify(x*(8*kilo*newton*meter + y)) == x*(8000*meter*newton + y)
assert quantity_simplify(foot*inch*(foot + inch)) == foot**2*(foot + foot/12)/12
assert quantity_simplify(foot*inch*(foot*foot + inch*(foot + inch))) == foot**2*(foot**2 + foot/12*(foot + foot/12))/12
assert quantity_simplify(2**(foot/inch*kilo/1000)*inch) == 4096*foot/12
assert quantity_simplify(foot**2*inch + inch**2*foot) == 13*foot**3/144
def test_quantity_simplify_across_dimensions():
from sympy.physics.units.util import quantity_simplify
from sympy.physics.units import ampere, ohm, volt, joule, pascal, farad, second, watt, siemens, henry, tesla, weber, hour, newton
assert quantity_simplify(ampere*ohm, across_dimensions=True, unit_system="SI") == volt
assert quantity_simplify(6*ampere*ohm, across_dimensions=True, unit_system="SI") == 6*volt
assert quantity_simplify(volt/ampere, across_dimensions=True, unit_system="SI") == ohm
assert quantity_simplify(volt/ohm, across_dimensions=True, unit_system="SI") == ampere
assert quantity_simplify(joule/meter**3, across_dimensions=True, unit_system="SI") == pascal
assert quantity_simplify(farad*ohm, across_dimensions=True, unit_system="SI") == second
assert quantity_simplify(joule/second, across_dimensions=True, unit_system="SI") == watt
assert quantity_simplify(meter**3/second, across_dimensions=True, unit_system="SI") == meter**3/second
assert quantity_simplify(joule/second, across_dimensions=True, unit_system="SI") == watt
assert quantity_simplify(joule/coulomb, across_dimensions=True, unit_system="SI") == volt
assert quantity_simplify(volt/ampere, across_dimensions=True, unit_system="SI") == ohm
assert quantity_simplify(ampere/volt, across_dimensions=True, unit_system="SI") == siemens
assert quantity_simplify(coulomb/volt, across_dimensions=True, unit_system="SI") == farad
assert quantity_simplify(volt*second/ampere, across_dimensions=True, unit_system="SI") == henry
assert quantity_simplify(volt*second/meter**2, across_dimensions=True, unit_system="SI") == tesla
assert quantity_simplify(joule/ampere, across_dimensions=True, unit_system="SI") == weber
assert quantity_simplify(5*kilometer/hour, across_dimensions=True, unit_system="SI") == 25*meter/(18*second)
assert quantity_simplify(5*kilogram*meter/second**2, across_dimensions=True, unit_system="SI") == 5*newton
def test_check_dimensions():
x = symbols('x')
assert check_dimensions(inch + x) == inch + x
assert check_dimensions(length + x) == length + x
# after subs we get 2*length; check will clear the constant
assert check_dimensions((length + x).subs(x, length)) == length
assert check_dimensions(newton*meter + joule) == joule + meter*newton
raises(ValueError, lambda: check_dimensions(inch + 1))
raises(ValueError, lambda: check_dimensions(length + 1))
raises(ValueError, lambda: check_dimensions(length + time))
raises(ValueError, lambda: check_dimensions(meter + second))
raises(ValueError, lambda: check_dimensions(2 * meter + second))
raises(ValueError, lambda: check_dimensions(2 * meter + 3 * second))
raises(ValueError, lambda: check_dimensions(1 / second + 1 / meter))
raises(ValueError, lambda: check_dimensions(2 * meter*(mile + centimeter) + km))

View File

@ -0,0 +1,205 @@
"""
Unit system for physical quantities; include definition of constants.
"""
from typing import Dict as tDict, Set as tSet
from sympy.core.add import Add
from sympy.core.function import (Derivative, Function)
from sympy.core.mul import Mul
from sympy.core.power import Pow
from sympy.core.singleton import S
from sympy.physics.units.dimensions import _QuantityMapper
from sympy.physics.units.quantities import Quantity
from .dimensions import Dimension
class UnitSystem(_QuantityMapper):
"""
UnitSystem represents a coherent set of units.
A unit system is basically a dimension system with notions of scales. Many
of the methods are defined in the same way.
It is much better if all base units have a symbol.
"""
_unit_systems = {} # type: tDict[str, UnitSystem]
def __init__(self, base_units, units=(), name="", descr="", dimension_system=None, derived_units: tDict[Dimension, Quantity]={}):
UnitSystem._unit_systems[name] = self
self.name = name
self.descr = descr
self._base_units = base_units
self._dimension_system = dimension_system
self._units = tuple(set(base_units) | set(units))
self._base_units = tuple(base_units)
self._derived_units = derived_units
super().__init__()
def __str__(self):
"""
Return the name of the system.
If it does not exist, then it makes a list of symbols (or names) of
the base dimensions.
"""
if self.name != "":
return self.name
else:
return "UnitSystem((%s))" % ", ".join(
str(d) for d in self._base_units)
def __repr__(self):
return '<UnitSystem: %s>' % repr(self._base_units)
def extend(self, base, units=(), name="", description="", dimension_system=None, derived_units: tDict[Dimension, Quantity]={}):
"""Extend the current system into a new one.
Take the base and normal units of the current system to merge
them to the base and normal units given in argument.
If not provided, name and description are overridden by empty strings.
"""
base = self._base_units + tuple(base)
units = self._units + tuple(units)
return UnitSystem(base, units, name, description, dimension_system, {**self._derived_units, **derived_units})
def get_dimension_system(self):
return self._dimension_system
def get_quantity_dimension(self, unit):
qdm = self.get_dimension_system()._quantity_dimension_map
if unit in qdm:
return qdm[unit]
return super().get_quantity_dimension(unit)
def get_quantity_scale_factor(self, unit):
qsfm = self.get_dimension_system()._quantity_scale_factors
if unit in qsfm:
return qsfm[unit]
return super().get_quantity_scale_factor(unit)
@staticmethod
def get_unit_system(unit_system):
if isinstance(unit_system, UnitSystem):
return unit_system
if unit_system not in UnitSystem._unit_systems:
raise ValueError(
"Unit system is not supported. Currently"
"supported unit systems are {}".format(
", ".join(sorted(UnitSystem._unit_systems))
)
)
return UnitSystem._unit_systems[unit_system]
@staticmethod
def get_default_unit_system():
return UnitSystem._unit_systems["SI"]
@property
def dim(self):
"""
Give the dimension of the system.
That is return the number of units forming the basis.
"""
return len(self._base_units)
@property
def is_consistent(self):
"""
Check if the underlying dimension system is consistent.
"""
# test is performed in DimensionSystem
return self.get_dimension_system().is_consistent
@property
def derived_units(self) -> tDict[Dimension, Quantity]:
return self._derived_units
def get_dimensional_expr(self, expr):
from sympy.physics.units import Quantity
if isinstance(expr, Mul):
return Mul(*[self.get_dimensional_expr(i) for i in expr.args])
elif isinstance(expr, Pow):
return self.get_dimensional_expr(expr.base) ** expr.exp
elif isinstance(expr, Add):
return self.get_dimensional_expr(expr.args[0])
elif isinstance(expr, Derivative):
dim = self.get_dimensional_expr(expr.expr)
for independent, count in expr.variable_count:
dim /= self.get_dimensional_expr(independent)**count
return dim
elif isinstance(expr, Function):
args = [self.get_dimensional_expr(arg) for arg in expr.args]
if all(i == 1 for i in args):
return S.One
return expr.func(*args)
elif isinstance(expr, Quantity):
return self.get_quantity_dimension(expr).name
return S.One
def _collect_factor_and_dimension(self, expr):
"""
Return tuple with scale factor expression and dimension expression.
"""
from sympy.physics.units import Quantity
if isinstance(expr, Quantity):
return expr.scale_factor, expr.dimension
elif isinstance(expr, Mul):
factor = 1
dimension = Dimension(1)
for arg in expr.args:
arg_factor, arg_dim = self._collect_factor_and_dimension(arg)
factor *= arg_factor
dimension *= arg_dim
return factor, dimension
elif isinstance(expr, Pow):
factor, dim = self._collect_factor_and_dimension(expr.base)
exp_factor, exp_dim = self._collect_factor_and_dimension(expr.exp)
if self.get_dimension_system().is_dimensionless(exp_dim):
exp_dim = 1
return factor ** exp_factor, dim ** (exp_factor * exp_dim)
elif isinstance(expr, Add):
factor, dim = self._collect_factor_and_dimension(expr.args[0])
for addend in expr.args[1:]:
addend_factor, addend_dim = \
self._collect_factor_and_dimension(addend)
if not self.get_dimension_system().equivalent_dims(dim, addend_dim):
raise ValueError(
'Dimension of "{}" is {}, '
'but it should be {}'.format(
addend, addend_dim, dim))
factor += addend_factor
return factor, dim
elif isinstance(expr, Derivative):
factor, dim = self._collect_factor_and_dimension(expr.args[0])
for independent, count in expr.variable_count:
ifactor, idim = self._collect_factor_and_dimension(independent)
factor /= ifactor**count
dim /= idim**count
return factor, dim
elif isinstance(expr, Function):
fds = [self._collect_factor_and_dimension(arg) for arg in expr.args]
dims = [Dimension(1) if self.get_dimension_system().is_dimensionless(d[1]) else d[1] for d in fds]
return (expr.func(*(f[0] for f in fds)), *dims)
elif isinstance(expr, Dimension):
return S.One, expr
else:
return expr, Dimension(1)
def get_units_non_prefixed(self) -> tSet[Quantity]:
"""
Return the units of the system that do not have a prefix.
"""
return set(filter(lambda u: not u.is_prefixed and not u.is_physical_constant, self._units))

View File

@ -0,0 +1,265 @@
"""
Several methods to simplify expressions involving unit objects.
"""
from functools import reduce
from collections.abc import Iterable
from typing import Optional
from sympy import default_sort_key
from sympy.core.add import Add
from sympy.core.containers import Tuple
from sympy.core.mul import Mul
from sympy.core.power import Pow
from sympy.core.sorting import ordered
from sympy.core.sympify import sympify
from sympy.core.function import Function
from sympy.matrices.exceptions import NonInvertibleMatrixError
from sympy.physics.units.dimensions import Dimension, DimensionSystem
from sympy.physics.units.prefixes import Prefix
from sympy.physics.units.quantities import Quantity
from sympy.physics.units.unitsystem import UnitSystem
from sympy.utilities.iterables import sift
def _get_conversion_matrix_for_expr(expr, target_units, unit_system):
from sympy.matrices.dense import Matrix
dimension_system = unit_system.get_dimension_system()
expr_dim = Dimension(unit_system.get_dimensional_expr(expr))
dim_dependencies = dimension_system.get_dimensional_dependencies(expr_dim, mark_dimensionless=True)
target_dims = [Dimension(unit_system.get_dimensional_expr(x)) for x in target_units]
canon_dim_units = [i for x in target_dims for i in dimension_system.get_dimensional_dependencies(x, mark_dimensionless=True)]
canon_expr_units = set(dim_dependencies)
if not canon_expr_units.issubset(set(canon_dim_units)):
return None
seen = set()
canon_dim_units = [i for i in canon_dim_units if not (i in seen or seen.add(i))]
camat = Matrix([[dimension_system.get_dimensional_dependencies(i, mark_dimensionless=True).get(j, 0) for i in target_dims] for j in canon_dim_units])
exprmat = Matrix([dim_dependencies.get(k, 0) for k in canon_dim_units])
try:
res_exponents = camat.solve(exprmat)
except NonInvertibleMatrixError:
return None
return res_exponents
def convert_to(expr, target_units, unit_system="SI"):
"""
Convert ``expr`` to the same expression with all of its units and quantities
represented as factors of ``target_units``, whenever the dimension is compatible.
``target_units`` may be a single unit/quantity, or a collection of
units/quantities.
Examples
========
>>> from sympy.physics.units import speed_of_light, meter, gram, second, day
>>> from sympy.physics.units import mile, newton, kilogram, atomic_mass_constant
>>> from sympy.physics.units import kilometer, centimeter
>>> from sympy.physics.units import gravitational_constant, hbar
>>> from sympy.physics.units import convert_to
>>> convert_to(mile, kilometer)
25146*kilometer/15625
>>> convert_to(mile, kilometer).n()
1.609344*kilometer
>>> convert_to(speed_of_light, meter/second)
299792458*meter/second
>>> convert_to(day, second)
86400*second
>>> 3*newton
3*newton
>>> convert_to(3*newton, kilogram*meter/second**2)
3*kilogram*meter/second**2
>>> convert_to(atomic_mass_constant, gram)
1.660539060e-24*gram
Conversion to multiple units:
>>> convert_to(speed_of_light, [meter, second])
299792458*meter/second
>>> convert_to(3*newton, [centimeter, gram, second])
300000*centimeter*gram/second**2
Conversion to Planck units:
>>> convert_to(atomic_mass_constant, [gravitational_constant, speed_of_light, hbar]).n()
7.62963087839509e-20*hbar**0.5*speed_of_light**0.5/gravitational_constant**0.5
"""
from sympy.physics.units import UnitSystem
unit_system = UnitSystem.get_unit_system(unit_system)
if not isinstance(target_units, (Iterable, Tuple)):
target_units = [target_units]
def handle_Adds(expr):
return Add.fromiter(convert_to(i, target_units, unit_system)
for i in expr.args)
if isinstance(expr, Add):
return handle_Adds(expr)
elif isinstance(expr, Pow) and isinstance(expr.base, Add):
return handle_Adds(expr.base) ** expr.exp
expr = sympify(expr)
target_units = sympify(target_units)
if isinstance(expr, Function):
expr = expr.together()
if not isinstance(expr, Quantity) and expr.has(Quantity):
expr = expr.replace(lambda x: isinstance(x, Quantity),
lambda x: x.convert_to(target_units, unit_system))
def get_total_scale_factor(expr):
if isinstance(expr, Mul):
return reduce(lambda x, y: x * y,
[get_total_scale_factor(i) for i in expr.args])
elif isinstance(expr, Pow):
return get_total_scale_factor(expr.base) ** expr.exp
elif isinstance(expr, Quantity):
return unit_system.get_quantity_scale_factor(expr)
return expr
depmat = _get_conversion_matrix_for_expr(expr, target_units, unit_system)
if depmat is None:
return expr
expr_scale_factor = get_total_scale_factor(expr)
return expr_scale_factor * Mul.fromiter(
(1/get_total_scale_factor(u)*u)**p for u, p in
zip(target_units, depmat))
def quantity_simplify(expr, across_dimensions: bool=False, unit_system=None):
"""Return an equivalent expression in which prefixes are replaced
with numerical values and all units of a given dimension are the
unified in a canonical manner by default. `across_dimensions` allows
for units of different dimensions to be simplified together.
`unit_system` must be specified if `across_dimensions` is True.
Examples
========
>>> from sympy.physics.units.util import quantity_simplify
>>> from sympy.physics.units.prefixes import kilo
>>> from sympy.physics.units import foot, inch, joule, coulomb
>>> quantity_simplify(kilo*foot*inch)
250*foot**2/3
>>> quantity_simplify(foot - 6*inch)
foot/2
>>> quantity_simplify(5*joule/coulomb, across_dimensions=True, unit_system="SI")
5*volt
"""
if expr.is_Atom or not expr.has(Prefix, Quantity):
return expr
# replace all prefixes with numerical values
p = expr.atoms(Prefix)
expr = expr.xreplace({p: p.scale_factor for p in p})
# replace all quantities of given dimension with a canonical
# quantity, chosen from those in the expression
d = sift(expr.atoms(Quantity), lambda i: i.dimension)
for k in d:
if len(d[k]) == 1:
continue
v = list(ordered(d[k]))
ref = v[0]/v[0].scale_factor
expr = expr.xreplace({vi: ref*vi.scale_factor for vi in v[1:]})
if across_dimensions:
# combine quantities of different dimensions into a single
# quantity that is equivalent to the original expression
if unit_system is None:
raise ValueError("unit_system must be specified if across_dimensions is True")
unit_system = UnitSystem.get_unit_system(unit_system)
dimension_system: DimensionSystem = unit_system.get_dimension_system()
dim_expr = unit_system.get_dimensional_expr(expr)
dim_deps = dimension_system.get_dimensional_dependencies(dim_expr, mark_dimensionless=True)
target_dimension: Optional[Dimension] = None
for ds_dim, ds_dim_deps in dimension_system.dimensional_dependencies.items():
if ds_dim_deps == dim_deps:
target_dimension = ds_dim
break
if target_dimension is None:
# if we can't find a target dimension, we can't do anything. unsure how to handle this case.
return expr
target_unit = unit_system.derived_units.get(target_dimension)
if target_unit:
expr = convert_to(expr, target_unit, unit_system)
return expr
def check_dimensions(expr, unit_system="SI"):
"""Return expr if units in addends have the same
base dimensions, else raise a ValueError."""
# the case of adding a number to a dimensional quantity
# is ignored for the sake of SymPy core routines, so this
# function will raise an error now if such an addend is
# found.
# Also, when doing substitutions, multiplicative constants
# might be introduced, so remove those now
from sympy.physics.units import UnitSystem
unit_system = UnitSystem.get_unit_system(unit_system)
def addDict(dict1, dict2):
"""Merge dictionaries by adding values of common keys and
removing keys with value of 0."""
dict3 = {**dict1, **dict2}
for key, value in dict3.items():
if key in dict1 and key in dict2:
dict3[key] = value + dict1[key]
return {key:val for key, val in dict3.items() if val != 0}
adds = expr.atoms(Add)
DIM_OF = unit_system.get_dimension_system().get_dimensional_dependencies
for a in adds:
deset = set()
for ai in a.args:
if ai.is_number:
deset.add(())
continue
dims = []
skip = False
dimdict = {}
for i in Mul.make_args(ai):
if i.has(Quantity):
i = Dimension(unit_system.get_dimensional_expr(i))
if i.has(Dimension):
dimdict = addDict(dimdict, DIM_OF(i))
elif i.free_symbols:
skip = True
break
dims.extend(dimdict.items())
if not skip:
deset.add(tuple(sorted(dims, key=default_sort_key)))
if len(deset) > 1:
raise ValueError(
"addends have incompatible dimensions: {}".format(deset))
# clear multiplicative constants on Dimensions which may be
# left after substitution
reps = {}
for m in expr.atoms(Mul):
if any(isinstance(i, Dimension) for i in m.args):
reps[m] = m.func(*[
i for i in m.args if not i.is_number])
return expr.xreplace(reps)