{"id":18521768,"url":"https://github.com/simphotonics/unitexpr","last_synced_at":"2026-01-05T21:07:01.046Z","repository":{"id":62586399,"uuid":"425948773","full_name":"simphotonics/unitexpr","owner":"simphotonics","description":"Python units, unit expressions, unit systems, united arrays.","archived":false,"fork":false,"pushed_at":"2022-10-20T17:35:30.000Z","size":200,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-24T04:43:24.893Z","etag":null,"topics":["ndarray","physical-units","python","scientific-computing","si-units","unit","unit-expression"],"latest_commit_sha":null,"homepage":"https://pypi.org/project/unitexpr","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/simphotonics.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2021-11-08T18:23:27.000Z","updated_at":"2023-06-05T05:06:17.000Z","dependencies_parsed_at":"2022-11-03T22:35:49.359Z","dependency_job_id":null,"html_url":"https://github.com/simphotonics/unitexpr","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/simphotonics%2Funitexpr","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/simphotonics%2Funitexpr/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/simphotonics%2Funitexpr/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/simphotonics%2Funitexpr/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/simphotonics","download_url":"https://codeload.github.com/simphotonics/unitexpr/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247670920,"owners_count":20976654,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ndarray","physical-units","python","scientific-computing","si-units","unit","unit-expression"],"created_at":"2024-11-06T17:27:32.985Z","updated_at":"2026-01-05T21:07:00.974Z","avatar_url":"https://github.com/simphotonics.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Unit Expressions For Python\n[![tests](https://github.com/simphotonics/unitexpr/actions/workflows/test.yml/badge.svg)](https://github.com/simphotonics/unitexpr/actions/workflows/test.yml)\n[![docs](https://raw.githubusercontent.com/simphotonics/unitexpr/main/images/docs-badge.svg)](https://unitexpr.simphotonics.com)\n\nAttaching units to numerical quantities is a convenient way to check if\nan expression is valid or an equation is consistent.\nFor example, it makes little sense to add a quantity\nrepresenting weight and one representing distance, or to\nadd seconds and pico-seconds.\n\n\nThe package [`unitexpr`][unitexpr] provides classes and meta-classes that\nmake it trivial to define custom unit systems and [`numpy`][numpy] arrays\nwith support for physical units.\n\nA search on [pypi][pypi] shows that there are a few packages available\nfor doing unit analysis. The most notable I found is [`scimath`][scimath],\nwhich supports unit conversion and working with united numpy arrays.\nFor the purpose of optimization [`scimath`][scimath] computes and stores unit\nexpressions in terms of base units.\n\nThe package [`unitexpr`][unitexpr] stores unit expressions in terms of\nbase units *and* derived units. The advantage is that unit expressions\nretain their form. The cost (in terms of computational time) of keeping\ntrack of derived unit terms is of the order of few microsecond, depending\non the complexity of the unit expression. For more details see\n[benchmarks][benchmarks].\n\nFor example, the constant `m_e*c/h_bar` (where `m_e` is\nthe electron mass, `c` is the velocity of light, `h_bar` is the\nreduced Planck constant) is displayed as `m_e*c*h_bar**-1.0`. In\nterms of SI base units the same constant is given by\nthe less obvious expression: `2589605074819.227*m**-1.0`.\n\n\n\n## Installation\n\nTo install the package [`unitexpr`][unitexpr] use the command:\n```Console\n$ pip install unitexpr\n```\n\n## Usage\n\nThe following sections demonstrate how to create\n[unit expressions](#1-unit-expressions) ,\nwork with [quantity arrays](#2-quantity-arrays),\ndefine [scalar quantities](#3-scalar-quantities),\nand construct [custom unit systems](#custom-unit-systems).\n\n\n### 1. Unit Expressions\n\nUnit expressions are objects with base class `UnitExprBase`.\nEach unit system defines a *unique* unit expression type\nthat is available as a class attribute\n(`.expr_type`). Valid unit expression *terms* for a given unit system are:\n*base units*, *derived units*, *unit expressions*, and *real numbers*.\n\nThe package includes two predefined unit systems with a comprehensive list of\nderived units and physical constants:\n\n* `unitexpr.si_units`: SI Units based on meter, second, kilogram,\nAmpere, Kelvin, mol, and candela,\n* `unitexpr.sc_units`: Semiconductor Units based on nanometer, picosecond,\nelectron mass, Ampere, Kelvin, mol, and candela.\n\n``` python\nfrom unitexpr.si_units import m, s, c, SiUnit\n\n# Accessing the unit expression type of the units system:\nSiUnitExpr = SiUnit.expr_type\nassert type(m/s) == SiUnitExpr\n\n# Examples of unit expressions:\nv = 10.0*m/s\nw = v + 20.0*v\n\n# When adding or subtracting units and unit expression the term on the left\n# side determines the form of the expression. This is best shown in the example\n# below.\n#\n# Note: c is defined as:\n# c = SiUnit('c', 'speed of light', 'velocity', expr=299792458*m/s)\n\n# Defining a derived unit:\nc_sound = SiUnit('c_sound', 'speed of sound', 'velocity', expr=343*m/s)\n\nv1 = c + c_sound\nv2 = c_sound + c\n\nassert v1 == v2\n\nprint(v1) # Prints:  1.0000011441248464*c\nprint(v2) # Prints:  874031.4897959183*c_sound\n```\n\nTip: The methods `proportional_to`\nand `scaling_factor` can be used to\ndetermined if a unit or unit expression is a scaled\nversion of another unit or unit expression:\n\n```Python\n\nfrom unitexpr.si_units import m, s, SiUnit\n\n# Define a derived unit\ncm = SiUnit('cm', name='centimeter', quantity='length', expr=m/100.0)\n\n# Check if units are proportional\nassert cm.proportional_to(m) == True\nassert cm.proportional_to(s) == False\n\n# Get the scaling factor that converts cm to m.\nassert cm.scaling_factor(m) == 100.0\n\n# Get the scaling factor that converts m to cm.\nassert m.scaling_factor(cm) == 0.01\n\n# Get the scaling factor that converts m to s.\nassert m.scaling_factor(s) == None\n```\n\n### 2. Quantity Arrays\n\nTo support scientific calculation\nthe package includes [`qarray`][qarray]\nan extension of numpy's `ndarray`.\n\nThe entries of a [`qarray`][qarray] represent\nthe value of a physical *quantity*\nthat can be expressed in terms of a\nnumerical value and a unit.  The constructor of [`qarray`][qarray]\naccepts the same parameters as the constructor of `ndarray` with\nthe additional optional parameters `unit` (default value 1.0).\nand `info` which can be used to store object documentation.\n\nTo construct a [`qarray`][qarray] from a numerical value or\nan existing array one can use the convenience function\n[quantity][quantity] or the class method `qarray.from_input`.\n\n```Python\nfrom math import pi\n\nfrom unitexpr import qarray\nfrom unitexpr.si_units import m, s, h_bar, m_e, c, SiUnit\n\n# Constructing a qarray with a given shape.\nq = qarray(shape=(2, 2))\nq.fill(10.0)\nprint(\"q = \")\nprint(q)\nprint()\n\na = q*m\nprint(\"a = q*m = \")\nprint(a)\nprint()\n\n# Constructing a qarray from another array.\nb = qarray.from_input(q, unit=s)\n\n# Using the convenience method quantity.\nb = quantity(q, unit=s)\nb.fill(2.0)\n\nprint(\"b =\")\nprint(b)\nprint()\n\nprint(\"a / b =\")\nprint(a/b)\nprint()\n\nprint(\"(a / b)**2 =\")\nprint((a/b) ** 2)\nprint()\n\nPi = SiUnit(\"Pi\", \"Pi\", \"circle constant\", pi * SiUnit.expr_type.one)\n\nprint(\"Pi*a*9.81*m/s**2 =\")\nprint(Pi * a * 9.81 * m / s ** 2)\n```\nRunning the script above produces the following output:\n\u003cdetails\u003e \u003csummary\u003e Click to show the console output. \u003c/summary\u003e\n\n``` Console\n(unitexpr) $ python example/qarray_example.py\nq =\n[[10. 10.]\n [10. 10.]] unit: 1.0\n\na = q*m =\n[[10. 10.]\n [10. 10.]] unit: m\n\nb =\n[[2. 2.]\n [2. 2.]] unit: s\n\na / b =\n[[5. 5.]\n [5. 5.]] unit: m*s**-1.0\n\n(a / b)**2 =\n[[25. 25.]\n [25. 25.]] unit: m**2.0*s**-2.0\n\nPi*a*9.81*m/s**2 =\n[[98.1 98.1]\n [98.1 98.1]] unit: Pi*m**2.0*s**-2.0\n```\n\u003c/details\u003e\n\n\nTip: United arrays can be multiplied with unit expressions.\nAny numerical factor will be multiplied with the array using scalar\nmultiplication. The remaining part of the unit expression will be\nmultiplied with the unit attribute of the array.\n\nUnited array can be added to unit expressions as long as the\nbase units match.\n\nTo retain a numerical factor, for example `pi` as term of the\nunit expression it must be declared as a unit (see the example\nabove).\n\nNote: Units and unit expressions with zero magnitude\nmay `not` be assigned as the unit attribute of qarrays (\nnormalization will fail with a `DivisionByZero` error).\n\n\n### 3. Scalar Quantities\n\nTo represent a `scalar` quantity one can use a zero-dimensional `qarray`.\nThe function `quanity` provides a convenient way to create scalar quantities.\n\n``` Python\nfrom unitexpr import quanity\nfrom unitexpr.sc_units import ps, nm\n\ndt = quantity(5.0, unit=ps, info='Time-integration step size.')\ncavity_length = quantity(1.25e6, unit=nm, info='Optical cavity length.')\n\n# Accessing the quantity value:\nprint(dt.item())      # Prints: 5.0\n\nprint(dt)            # Prints: 5.0 ps\nprint(dt.__repr__()) # qarray(5.0, unit=ps, info='Time-integration step size.')\n\n# quantity expressions:\nprint(dt*cavity_length) # Prints: 6250000.0 ps*nm\n```\n\nTip:  Quantities can be used together with (compatible) units to form\nmathematical expressions.\n\n\n\n## Custom Unit Systems\n\nDefining custom unit systems using the package [`unitexpr`][unitexpr]\nis a simple task consisting of two steps:\ndefining [base unit symbols](#1-defining-base-unit-symbols) and\ndefining the [unit system](#2-defining-a-unit-system)\nby sub-classing [`UnitBase`][UnitBase].\n\n### 1. Defining Base Unit Symbols\n\nIn order to define a unit system, one must first specify the\nbase unit symbols. In the context of this package this is done\nby constructing a tuple with entries of type\n[`UnitSymbol`][UnitSymbol] (an immutable class with\ninstance attributes: `symbol`, `name`, and `quantity`):\n\n``` Python\nfrom unitexpr import UnitSymbol\n\n# Defining unit symbols\nunit_symbols = (\n            UnitSymbol(symbol='m',name='meter',quantity='length'),\n            UnitSymbol(symbol='s',name='second',quantity='time'),\n            UnitSymbol(symbol='kg',name='kilogram',quantity='weight')\n        )\n```\nNote: The attribute `symbol` must be a valid Python identifier.\n\n### 2. Defining a Unit System\n\nA custom unit system can be defined by sub-classing [`UnitBase`][UnitBase]\nspecifying the meta-class [`UnitMeta`][UnitMeta] and the\ncustom base unit symbols as class constructor parameters:\n\n```Python\nfrom unitexpr import UnitBase, UnitMeta\n\n# Defining a unit system using the base unit symbols specified above.\n# Note the use of the metaclass `UnitMeta`.\nclass MetricUnit(UnitBase, metaclass=UnitMeta, unit_symbols=unit_symbols):\n    pass\n\n# Base units are now available as class attributes.\n# For example:\nm = MetricUnit.m\ns = MetricUnit.s\nkg = MetricUnit.kg\n\nassert type(m) == MetricUnit\n\n# Declaring derived units\nc = MetricUnit('c', 'speed of light', 'velocity', expr=299792458*m/s)\n```\nThe base units are constructed during the instantiation of the meta-class\nand are available as class attributes. In the example above the\nbase units are `m`, `s`, and `kg`.\n\nDerived units and unit expressions can be constructed using the operations:\n- multiplication: `J = MetricUnit('J', 'joule', 'energy', expr=N*m)`\n- division: `W = MetricUnit('W', 'watt', 'power', expr=J/s)`\n- scalar multiplication: `c = MetricUnit('c', 'speed of light', 'velocity', expr=299792458*m/s)`\n- exponentiation: `N = MetricUnit('N', 'newton', 'force', expr=kg*m*s**-2)`.\n\nIt is advisable to choose the unit variable name as the unit symbol. For example,\nthe constant `c` (defined above) represents\nthe speed of light and its unit symbol was set to 'c'.\n\nNote: Units and unit expressions extend Python's `namedtuple` and as such are immutable.\n\n## Features and bugs\n\nPlease file feature requests and bugs at the [issue tracker].\nContributions are welcome.\n\n[issue tracker]: https://github.com/simphotonics/unitexpr/issues\n\n[benchmarks]: benchmarks\n\n[numpy]: https://pypi.org/project/numpy/\n\n[pypi]: https://pypi.org\n\n[pytest]: https://pypi.org/project/pytest/\n\n[scimath]: https://pypi.org/project/scimath\n\n[unitexpr]: https://github.com/simphotonics/unitexpr\n\n[UnitSymbol]: http://unitexpr.simphotonics.com/reference/unitexpr/unit_symbol/#UnitSymbol\n\n[UnitBase]: http://unitexpr.simphotonics.com/reference/unitexpr/unit/#UnitBase\n\n[UnitMeta]: http://unitexpr.simphotonics.com/reference/unitexpr/unit/#UnitMeta\n\n[qarray]: http://unitexpr.simphotonics.com/reference/unitexpr/qarray/#qarray\n\n[quantity]: https://unitexpr.simphotonics.com/reference/unitexpr/quantity/","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsimphotonics%2Funitexpr","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsimphotonics%2Funitexpr","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsimphotonics%2Funitexpr/lists"}