{"id":30331813,"url":"https://github.com/juliaphysics/dynamicquantities.jl","last_synced_at":"2026-04-02T18:43:19.314Z","repository":{"id":172918390,"uuid":"649931064","full_name":"JuliaPhysics/DynamicQuantities.jl","owner":"JuliaPhysics","description":"Efficient and type-stable physical quantities in Julia","archived":false,"fork":false,"pushed_at":"2025-09-14T19:18:09.000Z","size":3431,"stargazers_count":148,"open_issues_count":33,"forks_count":25,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-10-10T17:22:32.212Z","etag":null,"topics":["dimensional-analysis","julia","physics","science","scientific-computing","units"],"latest_commit_sha":null,"homepage":"https://ai.damtp.cam.ac.uk/dynamicquantities/dev","language":"Julia","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/JuliaPhysics.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"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":"2023-06-06T00:46:46.000Z","updated_at":"2025-09-24T17:39:39.000Z","dependencies_parsed_at":"2023-10-05T03:11:00.487Z","dependency_job_id":"1c28ef6e-4579-4e53-ad69-e58fc8873cc3","html_url":"https://github.com/JuliaPhysics/DynamicQuantities.jl","commit_stats":{"total_commits":640,"total_committers":11,"mean_commits":58.18181818181818,"dds":0.07343750000000004,"last_synced_commit":"9681769360699ebf50c5184e5ddf540105b47699"},"previous_names":["symbolicml/dynamicunits.jl","juliaphysics/dynamicquantities.jl"],"tags_count":51,"template":false,"template_full_name":null,"purl":"pkg:github/JuliaPhysics/DynamicQuantities.jl","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JuliaPhysics%2FDynamicQuantities.jl","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JuliaPhysics%2FDynamicQuantities.jl/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JuliaPhysics%2FDynamicQuantities.jl/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JuliaPhysics%2FDynamicQuantities.jl/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/JuliaPhysics","download_url":"https://codeload.github.com/JuliaPhysics/DynamicQuantities.jl/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JuliaPhysics%2FDynamicQuantities.jl/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":281049519,"owners_count":26435496,"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-26T02:00:06.575Z","response_time":61,"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":["dimensional-analysis","julia","physics","science","scientific-computing","units"],"created_at":"2025-08-18T03:06:56.283Z","updated_at":"2026-04-02T18:43:19.309Z","avatar_url":"https://github.com/JuliaPhysics.png","language":"Julia","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n\n\u003cimg src=\"https://github.com/JuliaPhysics/DynamicQuantities.jl/assets/7593028/10b1e6b8-f1c5-43bc-97e6-4ddb4c175293\" width=500\u003e\n\n\n[![Dev](https://img.shields.io/badge/docs-dev-blue.svg)](https://juliaphysics.github.io/DynamicQuantities.jl/dev/)\n[![Build Status](https://github.com/JuliaPhysics/DynamicQuantities.jl/actions/workflows/CI.yml/badge.svg?branch=main)](https://github.com/JuliaPhysics/DynamicQuantities.jl/actions/workflows/CI.yml?query=branch%3Amain)\n[![codecov](https://codecov.io/gh/JuliaPhysics/DynamicQuantities.jl/branch/main/graph/badge.svg?token=TAos20cgRZ)](https://codecov.io/gh/JuliaPhysics/DynamicQuantities.jl)\n[![Aqua QA](https://raw.githubusercontent.com/JuliaTesting/Aqua.jl/master/badge.svg)](https://github.com/JuliaTesting/Aqua.jl)\n\n\u003c/div\u003e\n  \nDynamicQuantities defines a simple statically-typed `Quantity` type for Julia.\nPhysical dimensions are stored as a *value*, as opposed to a parametric type, as in [Unitful.jl](https://github.com/PainterQubits/Unitful.jl).\nThis can greatly improve both runtime performance, by avoiding type instabilities, and startup time, as it avoids overspecializing methods.\n\n- [Performance](#performance)\n- [Usage](#usage)\n  - [Constants](#constants)\n  - [Symbolic Units](#symbolic-units)\n    - [Custom Units](#custom-units)\n    - [Affine Units](#affine-units)\n  - [Arrays](#arrays)\n  - [Unitful](#unitful)\n- [Types](#types)\n\n## Performance\n\nDynamicQuantities can greatly outperform Unitful\nwhen the compiler cannot infer dimensions in a function:\n\n```julia-repl\njulia\u003e using BenchmarkTools, DynamicQuantities; import Unitful\n\njulia\u003e dyn_uni = 0.2u\"m/s\"\n0.2 m s⁻¹\n\njulia\u003e unitful = convert(Unitful.Quantity, dyn_uni)\n0.2 m s⁻¹\n\njulia\u003e f(x, i) = x ^ i * 0.3;\n\njulia\u003e @btime f($dyn_uni, 1);\n  2.708 ns (0 allocations: 0 bytes)\n\njulia\u003e @btime f($unitful, 1);\n  2.597 μs (30 allocations: 1.33 KiB)\n```\n\n**Note the μ and n: this is a 1000x speedup!**\nHere, the DynamicQuantities quantity object allows the compiler to build a function that is type stable,\nwhile the Unitful quantity object, which stores its dimensions in the type, requires type inference at runtime.\n\nHowever, if the dimensions in your function *can* be inferred by the compiler,\nthen you can get better speeds with Unitful:\n\n```julia-repl\njulia\u003e g(x) = x ^ 2 * 0.3;\n\njulia\u003e @btime g($dyn_uni);\n  1.791 ns (0 allocations: 0 bytes)\n\njulia\u003e @btime g($unitful);\n  1.500 ns (0 allocations: 0 bytes)\n```\n\nWhile both of these are type stable,\nbecause Unitful parametrizes the type on the dimensions, functions can specialize\nto units and the compiler can optimize away units from the code.\n\n## Usage\n\nYou can create a `Quantity` object \nby using the convenience macro `u\"...\"`:\n\n```julia-repl\njulia\u003e x = 0.3u\"km/s\"\n300.0 m s⁻¹\n\njulia\u003e y = 42 * u\"kg\"\n42.0 kg\n```\n\nor by importing explicitly:\n\n```julia-repl\njulia\u003e using DynamicQuantities: kPa\n\njulia\u003e room_temp = 100kPa\n100000.0 m⁻¹ kg s⁻²\n```\n\nNote that `Units` is an exported submodule, so you can\nalso access this as `Units.kPa`. You may like to define\n\n```julia-repl\njulia\u003e const U = Units\n```\n\nso that you can simply write, say, `U.kPa` or `C.m_e`.\n\nThis supports a wide range of SI base and derived units, with common\nprefixes.\n\nYou can also construct values explicitly with the `Quantity` type,\nwith a value and keyword arguments for the powers of the physical dimensions\n(`mass`, `length`, `time`, `current`, `temperature`, `luminosity`, `amount`):\n\n```julia-repl\njulia\u003e x = Quantity(300.0, length=1, time=-1)\n300.0 m s⁻¹\n```\n\nElementary calculations with `+, -, *, /, ^, sqrt, cbrt, abs` are supported:\n\n```julia-repl\njulia\u003e x * y\n12600.0 m kg s⁻¹\n\njulia\u003e x / y\n7.142857142857143 m kg⁻¹ s⁻¹\n\njulia\u003e x ^ 3\n2.7e7 m³ s⁻³\n\njulia\u003e x ^ -1\n0.0033333333333333335 m⁻¹ s\n\njulia\u003e sqrt(x)\n17.320508075688775 m¹ᐟ² s⁻¹ᐟ²\n\njulia\u003e x ^ 1.5\n5196.152422706632 m³ᐟ² s⁻³ᐟ²\n```\n\nEach of these values has the same type, which means we don't need to perform type inference at runtime.\n\nFurthermore, we can do dimensional analysis by detecting `DimensionError`:\n\n```julia-repl\njulia\u003e x + 3 * x\n1.2 m¹ᐟ² kg\n\njulia\u003e x + y\nERROR: DimensionError: 0.3 m¹ᐟ² kg and 10.2 kg² s⁻² have incompatible dimensions\n```\n\nThe dimensions of a `Quantity` can be accessed either with `dimension(quantity)` for the entire `Dimensions` object:\n\n```julia-repl\njulia\u003e dimension(x)\nm¹ᐟ² kg\n```\n\nor with `umass`, `ulength`, etc., for the various dimensions:\n\n```julia-repl\njulia\u003e umass(x)\n1//1\n\njulia\u003e ulength(x)\n1//2\n```\n\nFinally, you can strip units with `ustrip`:\n\n```julia-repl\njulia\u003e ustrip(x)\n0.2\n```\n\nYou can also convert a quantity to a desired unit and *then* strip the units\nusing a two-argument version of `ustrip`:\n\n```julia-repl\njulia\u003e ustrip(u\"km\", 1000u\"m\")\n1.0\n\njulia\u003e ustrip(u\"minute\", 60u\"s\")\n1.0\n```\n\nThis is equivalent to `ustrip(quantity / unit)` but performs dimension checks first.\n\n### Constants\n\nThere are a variety of physical constants accessible\nvia the `Constants` submodule:\n\n```julia-repl\njulia\u003e Constants.c\n2.99792458e8 m s⁻¹\n```\n\nwhich you may like to define as\n\n```julia-repl\njulia\u003e const C = Constants\n```\n\nThese can also be used inside the `u\"...\"` macro:\n\n```julia-repl\njulia\u003e u\"Constants.c * Hz\"\n2.99792458e8 m s⁻²\n```\n\nSimilarly, you can just import each individual constant:\n\n```julia-repl\njulia\u003e using DynamicQuantities.Constants: h\n```\n\nFor the full list, see the [docs](https://symbolicml.org/DynamicQuantities.jl/dev/constants/).\n\n\n### Symbolic Units\n\nYou can also choose to not eagerly convert to SI base units,\ninstead leaving the units as the user had written them.\nFor example:\n\n```julia-repl\njulia\u003e q = 100us\"cm * kPa\"\n100.0 cm kPa\n\njulia\u003e q^2\n10000.0 cm² kPa²\n```\n\nYou can convert to regular SI base units with\n`uexpand`:\n\n```julia-repl\njulia\u003e uexpand(q^2)\n1.0e6 kg² s⁻⁴\n```\n\nThis also works with constants:\n\n```julia-repl\njulia\u003e x = us\"Constants.c * Hz\"\n1.0 Hz c\n\njulia\u003e x^2\n1.0 Hz² c²\n\njulia\u003e uexpand(x^2)\n8.987551787368176e16 m² s⁻⁴\n```\n\nYou can also convert a quantity in regular base SI units to symbolic units with the `|\u003e` infix operator\n```julia-repl\njulia\u003e 5e-9u\"m\" |\u003e us\"nm\"\n5.0 nm\n```\n\nYou can also convert between different symbolic units.\n(Note that you can write this more explicitly\nwith `uconvert(us\"nm\", 5e-9u\"m\")`.)\n\n\nFinally, you can also import these directly:\n\n```julia-repl\njulia\u003e using DynamicQuantities.SymbolicUnits: cm\n```\n\nor constants:\n\n```julia-repl\njulia\u003e using DynamicQuantities.SymbolicConstants: h\n```\n\nNote that `SymbolicUnits` and `SymbolicConstants` are exported,\nso you can simply access these as `SymbolicUnits.cm` and `SymbolicConstants.h`,\nrespectively.\n\n\n#### Custom Units\n\nYou can create custom units with the `@register_unit` macro:\n\n```julia-repl\njulia\u003e @register_unit OneFiveV 1.5u\"V\"\n```\n\nand then use it in calculations normally:\n\n```julia-repl\njulia\u003e x = us\"OneFiveV\"\n1.0 OneFiveV\n\njulia\u003e x * 10u\"A\" |\u003e us\"W\"\n15.0 W\n\njulia\u003e 3us\"V\" |\u003e us\"OneFiveV\"\n2.0 OneFiveV\n```\n\n#### Affine Units\n\nYou can also use \"*affine*\" units such as Celsius or Fahrenheit,\nusing the `ua\"...\"` string macro:\n\n```julia-repl\njulia\u003e room_temp = 22ua\"degC\"\n295.15 K\n\njulia\u003e freezing = 32ua\"degF\"\n273.15 K\n```\n\nThese are regular `Quantity{Float64,Dimensions{...}}` objects, meaning that you\ncan use them in the same way as regular quantities, including taking differences.\n\nTo convert back, you can use the two-argument `ustrip` with the particular affine unit:\n\n```julia-repl\njulia\u003e ustrip(ua\"degC\", 295.15u\"K\")\n22.0\n```\n\n### Arrays\n\nFor working with an array of quantities that have the same dimensions,\nyou can use a `QuantityArray`:\n\n```julia-repl\njulia\u003e ar = rand(3)u\"m/s\"\n3-element QuantityArray(::Vector{Float64}, ::Quantity{Float64, Dimensions{FRInt32}}):\n 0.2729202669351497 m s⁻¹\n 0.992546340360901 m s⁻¹\n 0.16863543422972482 m s⁻¹\n```\n\nThis `QuantityArray` is a subtype `\u003c:AbstractArray{Quantity{Float64,Dimensions{...}},1}`,\nmeaning that indexing a specific element will return a `Quantity`:\n\n```julia-repl\njulia\u003e ar[2]\n0.992546340360901 m s⁻¹\n\njulia\u003e ar[2] *= 2\n1.985092680721802 m s⁻¹\n\njulia\u003e ar[2] += 0.5u\"m/s\"\n2.485092680721802 m s⁻¹\n```\n\nThis also has a custom broadcasting interface which\nallows the compiler to avoid redundant dimension calculations,\nrelative to if you had simply used an array of quantities:\n\n```julia-repl\njulia\u003e f(v) = v^2 * 1.5;\n\njulia\u003e @btime $f.(xa) setup=(xa = randn(100000) .* u\"km/s\");\n  109.500 μs (2 allocations: 3.81 MiB)\n\njulia\u003e @btime $f.(qa) setup=(xa = randn(100000) .* u\"km/s\"; qa = QuantityArray(xa));\n  50.917 μs (3 allocations: 781.34 KiB)\n```\n\nSo we can see the `QuantityArray` version saves on both time and memory.\n\nBy default, DynamicQuantities will create a `QuantityArray` from an `AbstractArray`, similarly to how a `Quantity` is created from a scalar in the [Usage](@ref) examples:\n\n```julia-repl\njulia\u003e x = (1:3)us\"km/h\"\n3-element QuantityArray(::StepRangeLen{Float64, ...}, ::Quantity{Float64, SymbolicDimensions{...}}):\n 1.0 km h⁻¹\n 2.0 km h⁻¹\n 3.0 km h⁻¹\n```\n\n### Unitful\n\nDynamicQuantities allows you to convert back and forth from Unitful.jl:\n\n```julia-repl\njulia\u003e using Unitful: Unitful, @u_str; import DynamicQuantities\n\njulia\u003e x = 0.5u\"km/s\"\n0.5 km s⁻¹\n\njulia\u003e y = convert(DynamicQuantities.Quantity, x)\n500.0 m s⁻¹\n\njulia\u003e y2 = y^2 * 0.3\n75000.0 m² s⁻²\n\njulia\u003e x2 = convert(Unitful.Quantity, y2)\n75000.0 m² s⁻²\n\njulia\u003e x^2*0.3 == x2\ntrue\n```\n\n## Types\n\nBoth a `Quantity`'s values and dimensions are of arbitrary type. The default\n`Dimensions` (for the `u\"...\"` macro) performs exponent tracking for SI units,\nand `SymbolicDimensions` (for the `us\"...\"` macro) performs exponent tracking\nfor all known unit and constant symbols, using a sparse array.\n\nYou can create custom spaces dimension spaces by simply creating\na Julia struct subtyped to `AbstractDimensions`:\n\n```julia-repl\njulia\u003e struct CookiesAndMilk{R} \u003c: AbstractDimensions{R}\n           cookies::R\n           milk::R\n       end\n\njulia\u003e cookie_rate = Quantity(0.9, CookiesAndMilk(cookies=1, milk=-1))\n0.9 cookies milk⁻¹\n\njulia\u003e total_milk = Quantity(103, CookiesAndMilk(milk=1))\n103 milk\n\njulia\u003e total_cookies = cookie_rate * total_milk\n92.7 cookies\n```\n\nExponents are tracked by default with the type `FRInt32` (alias for `FixedRational{Int32, 25200}`),\nwhich represents rational numbers with an integer numerator and fixed denominator.\nThis is much faster than `Rational`.\n\n```julia-repl\njulia\u003e typeof(0.5u\"kg\")\nQuantity{Float64, Dimensions{FRInt32}}\n```\n\nYou can change the type of the value field by initializing with a value\nexplicitly of the desired type.\n\n```julia-repl\njulia\u003e typeof(Quantity(Float16(0.5), mass=1, length=1))\nQuantity{Float16, Dimensions{FRInt32}}\n```\n\nor by conversion:\n\n```julia-repl\njulia\u003e typeof(convert(Quantity{Float16}, 0.5u\"m/s\"))\nQuantity{Float16, Dimensions{FRInt32}}\n```\n\nFor many applications, using `FRInt8` (alias for `FixedRational{Int8,12}`)\nwill suffice as the base dimensions type,\nand can be faster as it means the entire `Dimensions`\nstruct will fit into 64 bits.\nYou can change the type of the dimensions field by passing\nthe type you wish to use as the second argument to `Quantity`:\n\n```julia-repl\njulia\u003e using DynamicQuantities\n\njulia\u003e R8 = Dimensions{FRInt8};\n\njulia\u003e R32 = Dimensions{FRInt32};\n\njulia\u003e q8 = [Quantity{Float64,R8}(randn(), length=rand(-2:2)) for i in 1:1000];\n\njulia\u003e q32 = [Quantity{Float64,R32}(randn(), length=rand(-2:2)) for i in 1:1000];\n\njulia\u003e f(x) = @. x ^ 2 * 0.5;\n\njulia\u003e @btime f($q8);\n  1.433 μs (3 allocations: 15.77 KiB)\n\njulia\u003e @btime f($q32);\n  1.883 μs (4 allocations: 39.12 KiB)\n```\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjuliaphysics%2Fdynamicquantities.jl","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjuliaphysics%2Fdynamicquantities.jl","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjuliaphysics%2Fdynamicquantities.jl/lists"}