{"id":32178584,"url":"https://github.com/openforcefield/openff-units","last_synced_at":"2026-01-08T00:16:58.801Z","repository":{"id":38398297,"uuid":"333961580","full_name":"openforcefield/openff-units","owner":"openforcefield","description":"A common units module for the OpenFF software stack","archived":false,"fork":false,"pushed_at":"2025-10-14T19:58:55.000Z","size":333,"stargazers_count":9,"open_issues_count":7,"forks_count":4,"subscribers_count":16,"default_branch":"main","last_synced_at":"2025-10-21T20:58:12.143Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/openforcefield.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":".github/CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2021-01-28T21:30:44.000Z","updated_at":"2025-10-14T19:59:00.000Z","dependencies_parsed_at":"2023-10-19T03:45:06.633Z","dependency_job_id":"460d4689-50b9-40cd-b36f-5780c989386d","html_url":"https://github.com/openforcefield/openff-units","commit_stats":{"total_commits":121,"total_committers":6,"mean_commits":"20.166666666666668","dds":"0.30578512396694213","last_synced_commit":"1187d0c3c48fde9ec6ec58589d13b01a3bdb1338"},"previous_names":[],"tags_count":17,"template":false,"template_full_name":null,"purl":"pkg:github/openforcefield/openff-units","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/openforcefield%2Fopenff-units","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/openforcefield%2Fopenff-units/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/openforcefield%2Fopenff-units/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/openforcefield%2Fopenff-units/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/openforcefield","download_url":"https://codeload.github.com/openforcefield/openff-units/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/openforcefield%2Fopenff-units/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":280333502,"owners_count":26312845,"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","status":"online","status_checked_at":"2025-10-21T02:00:06.614Z","response_time":58,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":[],"created_at":"2025-10-21T20:58:06.610Z","updated_at":"2026-01-08T00:16:58.794Z","avatar_url":"https://github.com/openforcefield.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"openff-units\n==============================\n[//]: # (Badges)\n[![CI Status](https://github.com/openforcefield/openff-units/workflows/CI/badge.svg)](https://github.com/openforcefield/openff-units/actions?query=workflow%3ACI)\n[![codecov](https://codecov.io/gh/openforcefield/openff-units/branch/main/graph/badge.svg)](https://codecov.io/gh/openforcefield/openff-units/branch/main)\n[![pre-commit](https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit\u0026logoColor=white)](https://github.com/pre-commit/pre-commit)\n[![pre-commit.ci status](https://results.pre-commit.ci/badge/github/openforcefield/openff-units/main.svg)](https://results.pre-commit.ci/latest/github/openforcefield/openff-units/main)\n[![conda](https://img.shields.io/conda/v/conda-forge/openff-units.svg)](https://anaconda.org/conda-forge/openff-units)\n\n\nA common units module for the OpenFF software stack\n\n**Please note that there may still be some changes to the API prior to a stable 1.0.0 release.**\n\nThis package provides a common unit registry for all OpenFF packages to use in order to ensure consistent unit definitions across the software ecosystem.\n\nThe unit definitions are currently sourced from the NIST 2018 [CODATA](https://physics.nist.gov/cuu/Constants/), but may be updated in future versions as new CODATA updates are made.\n\nWhile this repository is based on [Pint](https://pint.readthedocs.io/en/0.16.1/), the main classes (`Unit`, `Quantity`, and `Measurement`) have been slightly modified in order to provide non-dynamic, more readily serialisable representations.\n\n### Installation\n\nInstall via `mamba` or a replacement:\n\n```shell\nmamba install openff-units -c conda-forge\n```\n\n#### Developer installation\n\nClone, install dev dependencies via Conda into a new environment, and finally install in editable mode with Pip:\n\n```shell\ngit clone https://github.com/openforcefield/openff-units.git\ncd openff-units\nconda create -n openff-units-dev -f devtools/conda-envs/test_env.yaml\nconda run -n openff-units-dev pip install --no-deps -e .\n```\n\nThe important detail, as of December 2025, is the `--no-deps` argument.\n### Getting Started\n\nBelow shows how to tag a number with a unit (generating a `Quantity` object),\nget its magnitude with and without units, convert to another unit, and also get its magnitude after converting to another unit.\n\n```python3\n\u003e\u003e\u003e from openff.units import Quantity\n\u003e\u003e\u003e bond_length = Quantity(1.4, \"angstrom\")\n\u003e\u003e\u003e bond_length\n\u003cQuantity(1.4, 'angstrom')\u003e\n\u003e\u003e\u003e bond_length.magnitude\n1.4\n\u003e\u003e\u003e bond_length.to(\"nanometer\")\n\u003cQuantity(0.14, 'nanometer')\u003e\n\u003e\u003e\u003e bond_length.m_as(\"nanometer\")\n0.14\n```\n\nOne could also do the [Pint tutorial](https://pint.readthedocs.io/en/0.16.1/tutorial.html#tutorial) using the `unit` object above as a drop-in replacement for `ureg` in the tutorial.\n\n### Serialization\n\nScalar quantities can be serialized to strings using the built-in `str()` function and deserialized using the `unit.Quantity` constructor.\n\n```python3\n\u003e\u003e\u003e k = Quantity(10, \"kilocalorie / mol / nanometer**2\")\n\u003e\u003e\u003e k\n\u003cQuantity(10.0, 'kilocalorie / mole / nanometer ** 2')\u003e\n\u003e\u003e\u003e str(k)\n'10.0 kcal / mol / nm ** 2'\n\u003e\u003e\u003e Quantity(str(k))\n\u003cQuantity(10.0, 'kilocalorie / mole / nanometer ** 2')\u003e\n```\n\n### OpenMM Interoperability\n\nFor compatibility with [OpenMM units](http://docs.openmm.org/latest/api-python/app.html#units), a submodule (`openff.units.openmm`) with conversion functions (`to_openmm`, `from_openmm`) is also provided.\n\n```python3\n\u003e\u003e\u003e from openff.units import Quantity\n\u003e\u003e\u003e from openff.units.openmm import to_openmm, from_openmm\n\u003e\u003e\u003e distance = Quantity(24.0, \"meter\")\n\u003e\u003e\u003e converted = to_openmm(distance)\n\u003e\u003e\u003e converted\n24.0 m\n\u003e\u003e\u003e type(converted)\n\u003cclass 'openmm.unit.quantity.Quantity'\u003e\n\u003e\u003e\u003e roundtripped = from_openmm(converted)\n\u003e\u003e\u003e roundtripped\n\u003cQuantity(24.0, 'meter')\u003e\n\u003e\u003e\u003e type(roundtripped)\npint.Quantity\n```\n\nAn effort is made to convert from OpenMM constructs, such as when OpenMM provides array-like data as a list of `Vec3` objects:into Pint's wrapped NumPy arrays:\n\n```python3\n\u003e\u003e\u003e from openmm import app\n\u003e\u003e\u003e positions = app.PDBFile(\"top.pdb\").getPositions()\n\u003e\u003e\u003e positions\nQuantity(value=[Vec3(x=-0.07890000000000001, y=-0.0198, z=-0.0), Vec3(x=-0.0006000000000000001, y=0.039200000000000006, z=-0.0), Vec3(x=0.07950000000000002, y=-0.0194, z=0.0), Vec3(x=0.9211, y=0.9802, z=1.0), Vec3(x=0.9994000000000001, y=1.0392, z=1.0), Vec3(x=1.0795000000000001, y=0.9805999999999999, z=1.0)], unit=nanometer)\n\u003e\u003e\u003e type(positions)\n\u003cclass 'openmm.unit.quantity.Quantity'\u003e\n\u003e\u003e\u003e type(positions._value)\n\u003cclass 'list'\u003e\n\u003e\u003e\u003e type(positions._value[0])\n\u003cclass 'openmm.vec3.Vec3'\u003e\n\u003e\u003e\u003e converted = from_openmm(positions)\n\u003e\u003e\u003e converted\n\u003cQuantity([[-7.8900e-02 -1.9800e-02 -0.0000e+00]\n [-6.0000e-04  3.9200e-02 -0.0000e+00]\n [ 7.9500e-02 -1.9400e-02  0.0000e+00]\n [ 9.2110e-01  9.8020e-01  1.0000e+00]\n [ 9.9940e-01  1.0392e+00  1.0000e+00]\n [ 1.0795e+00  9.8060e-01  1.0000e+00]], 'nanometer')\u003e\n\u003e\u003e\u003e converted.m\narray([[-7.8900e-02, -1.9800e-02, -0.0000e+00],\n       [-6.0000e-04,  3.9200e-02, -0.0000e+00],\n       [ 7.9500e-02, -1.9400e-02,  0.0000e+00],\n       [ 9.2110e-01,  9.8020e-01,  1.0000e+00],\n       [ 9.9940e-01,  1.0392e+00,  1.0000e+00],\n       [ 1.0795e+00,  9.8060e-01,  1.0000e+00]])\n\u003e\u003e\u003e type(converted)\n\u003cclass 'openff.units.units.Quantity'\u003e\n\u003e\u003e\u003e type(converted.m)\n\u003cclass 'numpy.ndarray'\u003e\n```\n#### Dealing with multiple unit packages\n\nYou may find yourself needing to normalize a quantity to a particular unit package, while accepting inputs from either `openff.units` or `openmm.unit`. The [`ensure_quantity`] function simplifies this. It takes as arguments a quantity object from either unit solution and a string (`\"openff\"` or `\"openmm\"`) indicating the desired unit type, and returns a quantity from that package. If the quantity argument is already the requested type, the function short-circuits, so it should not introduce substantial overhead compared to simply requiring the target quantity type.\n\n[`ensure_quantity`]: https://docs.openforcefield.org/projects/units/en/stable/api/generated/openff.units.ensure_quantity.html\n\n```python3\n\u003e\u003e\u003e from openff.units import Quantity, ensure_quantity\n\u003e\u003e\u003e ensure_quantity(Quantity(4.0, \"angstrom\"), \"openff\")\n\u003cQuantity(4.0, 'angstrom')\u003e  # OpenFF\n\u003e\u003e\u003e ensure_quantity(Quantity(4.0, \"angstrom\"), \"openmm\")\n4.0 A\n\u003e\u003e\u003e\n\u003e\u003e\u003e import openmm.unit\n\u003e\u003e\u003e ensure_quantity(openmm.unit.Quantity(4.0, openmm.unit.angstrom), \"openmm\")\n4.0 A\n\u003e\u003e\u003e ensure_quantity(openmm.unit.Quantity(4.0, openmm.unit.angstrom), \"openff\")\n\u003cQuantity(4.0, 'angstrom')\u003e  # OpenFF\n```\n\n### Known issues\n\nThere is a quirk with cached unit registry definitions that could cause issues when running tests in parallel (i.e. with `pytest-xdist`). See [Issue #111](https://github.com/openforcefield/openff-units/issues/111) for more details. This was fixed in version 0.3.1.\n\n### Copyright\n\nCopyright (c) 2021, Open Force Field Initiative\n\n\n#### Acknowledgements\n \nProject based on the \n[Computational Molecular Science Python Cookiecutter](https://github.com/molssi/cookiecutter-cms) version 1.5.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fopenforcefield%2Fopenff-units","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fopenforcefield%2Fopenff-units","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fopenforcefield%2Fopenff-units/lists"}