unitx 0.13.0__tar.gz → 0.13.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {unitx-0.13.0 → unitx-0.13.2}/CHANGELOG.md +36 -0
- unitx-0.13.0/README.md → unitx-0.13.2/PKG-INFO +90 -6
- unitx-0.13.0/PKG-INFO → unitx-0.13.2/README.md +62 -30
- {unitx-0.13.0 → unitx-0.13.2}/docs/catalogue.md +53 -5
- {unitx-0.13.0 → unitx-0.13.2}/docs/custom-units.md +12 -1
- unitx-0.13.2/docs/images/blackbody.svg +1003 -0
- {unitx-0.13.0 → unitx-0.13.2}/docs/migration.md +15 -0
- {unitx-0.13.0 → unitx-0.13.2}/docs/stdlib.md +66 -9
- {unitx-0.13.0 → unitx-0.13.2}/docs/typing.md +3 -1
- {unitx-0.13.0 → unitx-0.13.2}/docs/units.md +6 -0
- {unitx-0.13.0 → unitx-0.13.2}/pyproject.toml +23 -2
- {unitx-0.13.0 → unitx-0.13.2}/src/unitx/quantity.py +0 -4
- {unitx-0.13.0 → unitx-0.13.2}/src/unitx/si/__init__.py +2 -2
- {unitx-0.13.0 → unitx-0.13.2}/src/unitx/si/constants.py +113 -1
- {unitx-0.13.0 → unitx-0.13.2}/src/unitx/singleunit.py +24 -4
- unitx-0.13.2/src/unitx/time.py +148 -0
- {unitx-0.13.0 → unitx-0.13.2}/src/unitx/unitparser.py +115 -76
- {unitx-0.13.0 → unitx-0.13.2}/src/unitx/unitregistry.py +8 -3
- {unitx-0.13.0 → unitx-0.13.2}/tests/test_si.py +62 -3
- {unitx-0.13.0 → unitx-0.13.2}/tests/test_singleunit.py +35 -0
- unitx-0.13.2/tests/test_time.py +259 -0
- {unitx-0.13.0 → unitx-0.13.2}/tests/test_unitparser.py +4 -3
- {unitx-0.13.0 → unitx-0.13.2}/tests/typing/check_math_time.py +10 -7
- {unitx-0.13.0 → unitx-0.13.2}/tests/typing/check_si.py +14 -1
- unitx-0.13.0/docs/images/blackbody.png +0 -0
- unitx-0.13.0/src/unitx/time.py +0 -104
- unitx-0.13.0/tests/test_time.py +0 -100
- {unitx-0.13.0 → unitx-0.13.2}/.github/workflows/ci.yml +0 -0
- {unitx-0.13.0 → unitx-0.13.2}/.github/workflows/release.yml +0 -0
- {unitx-0.13.0 → unitx-0.13.2}/.gitignore +0 -0
- {unitx-0.13.0 → unitx-0.13.2}/CONTRIBUTING.md +0 -0
- {unitx-0.13.0 → unitx-0.13.2}/LICENSE +0 -0
- {unitx-0.13.0 → unitx-0.13.2}/benchmarks/numpy_writes.py +0 -0
- {unitx-0.13.0 → unitx-0.13.2}/conftest.py +0 -0
- {unitx-0.13.0 → unitx-0.13.2}/docs/README.md +0 -0
- {unitx-0.13.0 → unitx-0.13.2}/docs/affine.md +0 -0
- {unitx-0.13.0 → unitx-0.13.2}/docs/display.md +0 -0
- {unitx-0.13.0 → unitx-0.13.2}/docs/numpy.md +0 -0
- {unitx-0.13.0 → unitx-0.13.2}/docs/scalars.md +0 -0
- {unitx-0.13.0 → unitx-0.13.2}/examples/README.md +0 -0
- {unitx-0.13.0 → unitx-0.13.2}/examples/blackbody.ipynb +0 -0
- {unitx-0.13.0 → unitx-0.13.2}/examples/damped_oscillator.ipynb +0 -0
- {unitx-0.13.0 → unitx-0.13.2}/examples/gaussian_wavepacket.ipynb +0 -0
- {unitx-0.13.0 → unitx-0.13.2}/examples/optical_attenuation.ipynb +0 -0
- {unitx-0.13.0 → unitx-0.13.2}/examples/pendulum_uncertainty.ipynb +0 -0
- {unitx-0.13.0 → unitx-0.13.2}/pyrightconfig.json +0 -0
- {unitx-0.13.0 → unitx-0.13.2}/src/unitx/__init__.py +0 -0
- {unitx-0.13.0 → unitx-0.13.2}/src/unitx/_constnamespace.py +0 -0
- {unitx-0.13.0 → unitx-0.13.2}/src/unitx/_conversion.py +0 -0
- {unitx-0.13.0 → unitx-0.13.2}/src/unitx/_display.py +0 -0
- {unitx-0.13.0 → unitx-0.13.2}/src/unitx/_immutable.py +0 -0
- {unitx-0.13.0 → unitx-0.13.2}/src/unitx/_numerics.py +0 -0
- {unitx-0.13.0 → unitx-0.13.2}/src/unitx/_numpy.py +0 -0
- {unitx-0.13.0 → unitx-0.13.2}/src/unitx/_numpy_typing.py +0 -0
- {unitx-0.13.0 → unitx-0.13.2}/src/unitx/_unicode.py +0 -0
- {unitx-0.13.0 → unitx-0.13.2}/src/unitx/affinequantity.py +0 -0
- {unitx-0.13.0 → unitx-0.13.2}/src/unitx/affineunit.py +0 -0
- {unitx-0.13.0 → unitx-0.13.2}/src/unitx/dimension.py +0 -0
- {unitx-0.13.0 → unitx-0.13.2}/src/unitx/exceptions.py +0 -0
- {unitx-0.13.0 → unitx-0.13.2}/src/unitx/factor.py +0 -0
- {unitx-0.13.0 → unitx-0.13.2}/src/unitx/math.py +0 -0
- {unitx-0.13.0 → unitx-0.13.2}/src/unitx/monomial.py +0 -0
- {unitx-0.13.0 → unitx-0.13.2}/src/unitx/py.typed +0 -0
- {unitx-0.13.0 → unitx-0.13.2}/src/unitx/si/bases.py +0 -0
- {unitx-0.13.0 → unitx-0.13.2}/src/unitx/si/units.py +0 -0
- {unitx-0.13.0 → unitx-0.13.2}/src/unitx/unit.py +0 -0
- {unitx-0.13.0 → unitx-0.13.2}/tests/__init__.py +0 -0
- {unitx-0.13.0 → unitx-0.13.2}/tests/_notebooks.py +0 -0
- {unitx-0.13.0 → unitx-0.13.2}/tests/example_typing/check_blackbody.py +0 -0
- {unitx-0.13.0 → unitx-0.13.2}/tests/numpy_typing/check_math.py +0 -0
- {unitx-0.13.0 → unitx-0.13.2}/tests/numpy_typing/check_numpy.py +0 -0
- {unitx-0.13.0 → unitx-0.13.2}/tests/test_affine.py +0 -0
- {unitx-0.13.0 → unitx-0.13.2}/tests/test_affinequantity.py +0 -0
- {unitx-0.13.0 → unitx-0.13.2}/tests/test_builtin_definitions.py +0 -0
- {unitx-0.13.0 → unitx-0.13.2}/tests/test_dimension.py +0 -0
- {unitx-0.13.0 → unitx-0.13.2}/tests/test_display.py +0 -0
- {unitx-0.13.0 → unitx-0.13.2}/tests/test_examples.py +0 -0
- {unitx-0.13.0 → unitx-0.13.2}/tests/test_factor.py +0 -0
- {unitx-0.13.0 → unitx-0.13.2}/tests/test_immutable.py +0 -0
- {unitx-0.13.0 → unitx-0.13.2}/tests/test_import.py +0 -0
- {unitx-0.13.0 → unitx-0.13.2}/tests/test_math.py +0 -0
- {unitx-0.13.0 → unitx-0.13.2}/tests/test_math_numpy.py +0 -0
- {unitx-0.13.0 → unitx-0.13.2}/tests/test_monomial.py +0 -0
- {unitx-0.13.0 → unitx-0.13.2}/tests/test_numeric.py +0 -0
- {unitx-0.13.0 → unitx-0.13.2}/tests/test_numpy.py +0 -0
- {unitx-0.13.0 → unitx-0.13.2}/tests/test_numpy_affine.py +0 -0
- {unitx-0.13.0 → unitx-0.13.2}/tests/test_numpy_differentiation.py +0 -0
- {unitx-0.13.0 → unitx-0.13.2}/tests/test_numpy_integration.py +0 -0
- {unitx-0.13.0 → unitx-0.13.2}/tests/test_numpy_multi_outputs.py +0 -0
- {unitx-0.13.0 → unitx-0.13.2}/tests/test_numpy_mutation.py +0 -0
- {unitx-0.13.0 → unitx-0.13.2}/tests/test_numpy_outputs.py +0 -0
- {unitx-0.13.0 → unitx-0.13.2}/tests/test_numpy_products.py +0 -0
- {unitx-0.13.0 → unitx-0.13.2}/tests/test_numpy_statistics.py +0 -0
- {unitx-0.13.0 → unitx-0.13.2}/tests/test_quantity.py +0 -0
- {unitx-0.13.0 → unitx-0.13.2}/tests/test_siunitx_display.py +0 -0
- {unitx-0.13.0 → unitx-0.13.2}/tests/test_typing.py +0 -0
- {unitx-0.13.0 → unitx-0.13.2}/tests/test_unicode.py +0 -0
- {unitx-0.13.0 → unitx-0.13.2}/tests/test_unicode_units.py +0 -0
- {unitx-0.13.0 → unitx-0.13.2}/tests/test_unit.py +0 -0
- {unitx-0.13.0 → unitx-0.13.2}/tests/test_unit_definition.py +0 -0
- {unitx-0.13.0 → unitx-0.13.2}/tests/test_unitregistry.py +0 -0
- {unitx-0.13.0 → unitx-0.13.2}/tests/test_warnings.py +0 -0
- {unitx-0.13.0 → unitx-0.13.2}/tests/typing/check_affine.py +0 -0
- {unitx-0.13.0 → unitx-0.13.2}/tests/typing/check_quantity.py +0 -0
|
@@ -1,5 +1,41 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [Unreleased]
|
|
4
|
+
|
|
5
|
+
## [0.13.2] - 2026-10-22
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- `unitx.time.from_datetime()` and `to_datetime()` explicitly convert aware
|
|
10
|
+
datetimes and Unix-referenced affine time points, including custom known
|
|
11
|
+
epoch coordinates. Import preserves integer ns; export rounds once to
|
|
12
|
+
microseconds with ties to even and defaults to UTC.
|
|
13
|
+
- `SingleUnit.from_name(name)` constructs a single unit from a registered name
|
|
14
|
+
or name alias, including permitted prefixes, without accepting symbol spellings.
|
|
15
|
+
|
|
16
|
+
### Changed
|
|
17
|
+
|
|
18
|
+
- Clock functions in `unitx.time` return `AffineQuantity[int]` points in ns.
|
|
19
|
+
Point subtraction returns a duration Quantity; point addition and
|
|
20
|
+
multiplicative point arithmetic are rejected. Duration adapters are unchanged.
|
|
21
|
+
Clock domains remain untagged; only compare/subtract readings from the same context.
|
|
22
|
+
- Clarify process-wide registration and unsupported concurrent registry access.
|
|
23
|
+
- Expand the README with a runnable blackbody example and a theme-aware SVG plot.
|
|
24
|
+
|
|
25
|
+
### Internal
|
|
26
|
+
|
|
27
|
+
- Route name-only parsing through `SingleUnit.from_name()`, clarify recursive-descent
|
|
28
|
+
grammar, and remove a duplicate NumPy comparison branch.
|
|
29
|
+
|
|
30
|
+
## [0.13.1] - 2026-10-22
|
|
31
|
+
|
|
32
|
+
### Added
|
|
33
|
+
|
|
34
|
+
- Public `unitx.si.au`, `nu` and `Planck` read-only namespaces of SI-valued
|
|
35
|
+
atomic, electron-mass natural, and Planck scales. These are physical
|
|
36
|
+
Quantities, not parser registrations or implicit conversion contexts.
|
|
37
|
+
- Export the existing `Particle` namespace directly from `unitx.si`.
|
|
38
|
+
|
|
3
39
|
## [0.13.0] - 2026-10-21
|
|
4
40
|
|
|
5
41
|
### Added
|
|
@@ -1,3 +1,31 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: unitx
|
|
3
|
+
Version: 0.13.2
|
|
4
|
+
Summary: Physical units, quantities, and unit conversion with exact unit algebra, type hints, and NumPy integration.
|
|
5
|
+
Project-URL: Homepage, https://github.com/DaitTHU/unitx
|
|
6
|
+
Project-URL: Documentation, https://github.com/DaitTHU/unitx/blob/main/docs/README.md
|
|
7
|
+
Project-URL: Source, https://github.com/DaitTHU/unitx
|
|
8
|
+
Project-URL: Changelog, https://github.com/DaitTHU/unitx/blob/main/CHANGELOG.md
|
|
9
|
+
Project-URL: Issues, https://github.com/DaitTHU/unitx/issues
|
|
10
|
+
Author: Dait
|
|
11
|
+
License-Expression: MIT
|
|
12
|
+
License-File: LICENSE
|
|
13
|
+
Keywords: SI units,dimensional analysis,engineering,exact arithmetic,logarithmic units,numpy,physical constants,physical quantities,physics,quantity,scientific computing,temperature conversion,unit,unit algebra,unit conversion,units
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.15
|
|
19
|
+
Classifier: Topic :: Scientific/Engineering :: Physics
|
|
20
|
+
Requires-Python: >=3.12
|
|
21
|
+
Provides-Extra: numpy
|
|
22
|
+
Requires-Dist: numpy>=2.1; extra == 'numpy'
|
|
23
|
+
Provides-Extra: test
|
|
24
|
+
Requires-Dist: pyright>=1.1.414; extra == 'test'
|
|
25
|
+
Requires-Dist: pytest>=8; extra == 'test'
|
|
26
|
+
Requires-Dist: ruff>=0.8; extra == 'test'
|
|
27
|
+
Description-Content-Type: text/markdown
|
|
28
|
+
|
|
1
29
|
# unitx
|
|
2
30
|
|
|
3
31
|
[](https://pypi.org/project/unitx/)
|
|
@@ -74,7 +102,12 @@ Use `.isclose()` for approximate comparisons.
|
|
|
74
102
|
Use `@` for an absolute coordinate reading and `*` for a linear difference:
|
|
75
103
|
|
|
76
104
|
```pycon
|
|
77
|
-
>>>
|
|
105
|
+
>>> difference = 20 * si.degC # A temperature difference of 20 degrees
|
|
106
|
+
>>> room = 20 @ si.degC # A reading of 20 degrees Celsius
|
|
107
|
+
>>> difference.value_in(si.K)
|
|
108
|
+
20
|
|
109
|
+
>>> room.value_in(si.K)
|
|
110
|
+
Fraction(5863, 20)
|
|
78
111
|
>>> print(room.to(si.degF))
|
|
79
112
|
68 °F
|
|
80
113
|
>>> print(room + 5 * si.K)
|
|
@@ -87,6 +120,9 @@ True
|
|
|
87
120
|
```
|
|
88
121
|
|
|
89
122
|
Points are `AffineQuantity` objects; differences are `Quantity` objects.
|
|
123
|
+
Multiplying by `si.degC` constructs a difference; use `@` or the explicit
|
|
124
|
+
`AffineQuantity(20, si.degC)` constructor for an absolute reading.
|
|
125
|
+
Adding two points raises `TypeError`; subtract them to obtain a difference.
|
|
90
126
|
Use `.to_quantity()` to turn a point into an ordinary physical quantity for
|
|
91
127
|
further arithmetic. Read the [point and difference guide](https://github.com/DaitTHU/unitx/blob/main/docs/affine.md)
|
|
92
128
|
for temperature, dBm/dBW/dBV, and logarithmic ratio rules.
|
|
@@ -109,8 +145,13 @@ True
|
|
|
109
145
|
```
|
|
110
146
|
|
|
111
147
|
`unitx.math` checks units for roots, trigonometry, exponentials, logarithms,
|
|
112
|
-
`hypot`, and `atan2`. `unitx.time` returns
|
|
113
|
-
|
|
148
|
+
`hypot`, and `atan2`. `unitx.time` returns `AffineQuantity[int]` clock readings
|
|
149
|
+
in nanoseconds; subtract readings from the same clock to obtain a Quantity
|
|
150
|
+
duration. It also adapts durations to `sleep` and `datetime.timedelta`, and
|
|
151
|
+
converts aware `datetime` objects to and from Unix time points with
|
|
152
|
+
`time.from_datetime()` / `time.to_datetime()`.
|
|
153
|
+
Readings do not carry clock, process, or thread identities; mixing clock
|
|
154
|
+
contexts is not detected.
|
|
114
155
|
See [standard-library enhancements](https://github.com/DaitTHU/unitx/blob/main/docs/stdlib.md)
|
|
115
156
|
for the supported functions, numerical backends, and clock semantics.
|
|
116
157
|
|
|
@@ -136,6 +177,19 @@ units. Comparisons return boolean masks. Supported reductions, integration,
|
|
|
136
177
|
gradients, and output buffers follow the [NumPy support matrix](https://github.com/DaitTHU/unitx/blob/main/docs/numpy.md).
|
|
137
178
|
Array assignment and augmented arithmetic preserve the destination unit and dtype.
|
|
138
179
|
|
|
180
|
+
Exact unit algebra preserves the scale `1/100` for centimetres to metres.
|
|
181
|
+
Applying that scale to a numerical array follows NumPy's dtype, rounding, and
|
|
182
|
+
overflow rules; it does not turn the array into exact rational numbers:
|
|
183
|
+
|
|
184
|
+
```python
|
|
185
|
+
from fractions import Fraction
|
|
186
|
+
|
|
187
|
+
exact = Quantity(1, 'cm').value_in('m')
|
|
188
|
+
approximate = Quantity(np.array([1.0]), 'cm').value_in('m')
|
|
189
|
+
assert exact == Fraction(1, 100)
|
|
190
|
+
assert Fraction(float(approximate[0])) != exact # Binary float approximates 1/100
|
|
191
|
+
```
|
|
192
|
+
|
|
139
193
|
Use `.value` or `.value_in(unit)` at plotting and external-library boundaries.
|
|
140
194
|
`np.asarray(quantity)` and `np.array(quantity)` raise TypeError to prevent
|
|
141
195
|
implicit unit removal. NumPy's type stubs do not describe every wrapped
|
|
@@ -143,10 +197,40 @@ operation; see the [typing guide](https://github.com/DaitTHU/unitx/blob/main/doc
|
|
|
143
197
|
|
|
144
198
|
The [physics notebooks](https://github.com/DaitTHU/unitx/blob/main/examples/README.md)
|
|
145
199
|
cover blackbody radiation, damped motion, wave-packet spreading, attenuation,
|
|
146
|
-
and measurement uncertainty.
|
|
147
|
-
|
|
200
|
+
and measurement uncertainty.
|
|
201
|
+
|
|
202
|
+
## Blackbody radiation
|
|
203
|
+
|
|
204
|
+
Install plotting support with `pip install 'unitx[numpy]' matplotlib`, then run
|
|
205
|
+
this complete example. Planck's formula keeps units and constants throughout;
|
|
206
|
+
NumPy broadcasts the wavelength column against three temperatures. Convert the
|
|
207
|
+
spectral radiance to a readable display unit before plotting:
|
|
208
|
+
|
|
209
|
+
```python
|
|
210
|
+
import numpy as np
|
|
211
|
+
from matplotlib import pyplot as plt
|
|
212
|
+
|
|
213
|
+
from unitx.si import SI, si
|
|
214
|
+
|
|
215
|
+
wavelength = np.linspace(0.01, 3, 100)[:, None] * si.um
|
|
216
|
+
temperature = np.array([3000, 4000, 5000]) * si.K
|
|
217
|
+
exponent = SI.h * SI.c / (wavelength * SI.kB * temperature)
|
|
218
|
+
radiance = 2 * SI.h * SI.c**2 / (wavelength**5 * np.expm1(exponent))
|
|
219
|
+
radiance = radiance.to('kW/sr/m2/nm')
|
|
220
|
+
|
|
221
|
+
fig, ax = plt.subplots(figsize=(7, 4), layout='constrained')
|
|
222
|
+
ax.plot(wavelength.value, radiance.value)
|
|
223
|
+
ax.set(
|
|
224
|
+
xlabel=f'Wavelength [{wavelength.unit}]',
|
|
225
|
+
ylabel=f'Spectral radiance [{radiance.unit}]',
|
|
226
|
+
title='Blackbody radiation',
|
|
227
|
+
)
|
|
228
|
+
ax.legend([f'T = {value}' for value in temperature], framealpha=1)
|
|
229
|
+
ax.grid(True, alpha=0.25)
|
|
230
|
+
plt.show()
|
|
231
|
+
```
|
|
148
232
|
|
|
149
|
-

|
|
150
234
|
|
|
151
235
|
## Read more
|
|
152
236
|
|
|
@@ -1,27 +1,3 @@
|
|
|
1
|
-
Metadata-Version: 2.5
|
|
2
|
-
Name: unitx
|
|
3
|
-
Version: 0.13.0
|
|
4
|
-
Summary: A modern, intuitive unit library, with exact unit algebra, expressive type hints, and NumPy integration.
|
|
5
|
-
Project-URL: Homepage, https://github.com/DaitTHU/unitx
|
|
6
|
-
Project-URL: Issues, https://github.com/DaitTHU/unitx/issues
|
|
7
|
-
Author: Dait
|
|
8
|
-
License-Expression: MIT
|
|
9
|
-
License-File: LICENSE
|
|
10
|
-
Classifier: Programming Language :: Python :: 3
|
|
11
|
-
Classifier: Programming Language :: Python :: 3.12
|
|
12
|
-
Classifier: Programming Language :: Python :: 3.13
|
|
13
|
-
Classifier: Programming Language :: Python :: 3.14
|
|
14
|
-
Classifier: Programming Language :: Python :: 3.15
|
|
15
|
-
Classifier: Topic :: Scientific/Engineering :: Physics
|
|
16
|
-
Requires-Python: >=3.12
|
|
17
|
-
Provides-Extra: numpy
|
|
18
|
-
Requires-Dist: numpy>=2.1; extra == 'numpy'
|
|
19
|
-
Provides-Extra: test
|
|
20
|
-
Requires-Dist: pyright>=1.1.414; extra == 'test'
|
|
21
|
-
Requires-Dist: pytest>=8; extra == 'test'
|
|
22
|
-
Requires-Dist: ruff>=0.8; extra == 'test'
|
|
23
|
-
Description-Content-Type: text/markdown
|
|
24
|
-
|
|
25
1
|
# unitx
|
|
26
2
|
|
|
27
3
|
[](https://pypi.org/project/unitx/)
|
|
@@ -98,7 +74,12 @@ Use `.isclose()` for approximate comparisons.
|
|
|
98
74
|
Use `@` for an absolute coordinate reading and `*` for a linear difference:
|
|
99
75
|
|
|
100
76
|
```pycon
|
|
101
|
-
>>>
|
|
77
|
+
>>> difference = 20 * si.degC # A temperature difference of 20 degrees
|
|
78
|
+
>>> room = 20 @ si.degC # A reading of 20 degrees Celsius
|
|
79
|
+
>>> difference.value_in(si.K)
|
|
80
|
+
20
|
|
81
|
+
>>> room.value_in(si.K)
|
|
82
|
+
Fraction(5863, 20)
|
|
102
83
|
>>> print(room.to(si.degF))
|
|
103
84
|
68 °F
|
|
104
85
|
>>> print(room + 5 * si.K)
|
|
@@ -111,6 +92,9 @@ True
|
|
|
111
92
|
```
|
|
112
93
|
|
|
113
94
|
Points are `AffineQuantity` objects; differences are `Quantity` objects.
|
|
95
|
+
Multiplying by `si.degC` constructs a difference; use `@` or the explicit
|
|
96
|
+
`AffineQuantity(20, si.degC)` constructor for an absolute reading.
|
|
97
|
+
Adding two points raises `TypeError`; subtract them to obtain a difference.
|
|
114
98
|
Use `.to_quantity()` to turn a point into an ordinary physical quantity for
|
|
115
99
|
further arithmetic. Read the [point and difference guide](https://github.com/DaitTHU/unitx/blob/main/docs/affine.md)
|
|
116
100
|
for temperature, dBm/dBW/dBV, and logarithmic ratio rules.
|
|
@@ -133,8 +117,13 @@ True
|
|
|
133
117
|
```
|
|
134
118
|
|
|
135
119
|
`unitx.math` checks units for roots, trigonometry, exponentials, logarithms,
|
|
136
|
-
`hypot`, and `atan2`. `unitx.time` returns
|
|
137
|
-
|
|
120
|
+
`hypot`, and `atan2`. `unitx.time` returns `AffineQuantity[int]` clock readings
|
|
121
|
+
in nanoseconds; subtract readings from the same clock to obtain a Quantity
|
|
122
|
+
duration. It also adapts durations to `sleep` and `datetime.timedelta`, and
|
|
123
|
+
converts aware `datetime` objects to and from Unix time points with
|
|
124
|
+
`time.from_datetime()` / `time.to_datetime()`.
|
|
125
|
+
Readings do not carry clock, process, or thread identities; mixing clock
|
|
126
|
+
contexts is not detected.
|
|
138
127
|
See [standard-library enhancements](https://github.com/DaitTHU/unitx/blob/main/docs/stdlib.md)
|
|
139
128
|
for the supported functions, numerical backends, and clock semantics.
|
|
140
129
|
|
|
@@ -160,6 +149,19 @@ units. Comparisons return boolean masks. Supported reductions, integration,
|
|
|
160
149
|
gradients, and output buffers follow the [NumPy support matrix](https://github.com/DaitTHU/unitx/blob/main/docs/numpy.md).
|
|
161
150
|
Array assignment and augmented arithmetic preserve the destination unit and dtype.
|
|
162
151
|
|
|
152
|
+
Exact unit algebra preserves the scale `1/100` for centimetres to metres.
|
|
153
|
+
Applying that scale to a numerical array follows NumPy's dtype, rounding, and
|
|
154
|
+
overflow rules; it does not turn the array into exact rational numbers:
|
|
155
|
+
|
|
156
|
+
```python
|
|
157
|
+
from fractions import Fraction
|
|
158
|
+
|
|
159
|
+
exact = Quantity(1, 'cm').value_in('m')
|
|
160
|
+
approximate = Quantity(np.array([1.0]), 'cm').value_in('m')
|
|
161
|
+
assert exact == Fraction(1, 100)
|
|
162
|
+
assert Fraction(float(approximate[0])) != exact # Binary float approximates 1/100
|
|
163
|
+
```
|
|
164
|
+
|
|
163
165
|
Use `.value` or `.value_in(unit)` at plotting and external-library boundaries.
|
|
164
166
|
`np.asarray(quantity)` and `np.array(quantity)` raise TypeError to prevent
|
|
165
167
|
implicit unit removal. NumPy's type stubs do not describe every wrapped
|
|
@@ -167,10 +169,40 @@ operation; see the [typing guide](https://github.com/DaitTHU/unitx/blob/main/doc
|
|
|
167
169
|
|
|
168
170
|
The [physics notebooks](https://github.com/DaitTHU/unitx/blob/main/examples/README.md)
|
|
169
171
|
cover blackbody radiation, damped motion, wave-packet spreading, attenuation,
|
|
170
|
-
and measurement uncertainty.
|
|
171
|
-
|
|
172
|
+
and measurement uncertainty.
|
|
173
|
+
|
|
174
|
+
## Blackbody radiation
|
|
175
|
+
|
|
176
|
+
Install plotting support with `pip install 'unitx[numpy]' matplotlib`, then run
|
|
177
|
+
this complete example. Planck's formula keeps units and constants throughout;
|
|
178
|
+
NumPy broadcasts the wavelength column against three temperatures. Convert the
|
|
179
|
+
spectral radiance to a readable display unit before plotting:
|
|
180
|
+
|
|
181
|
+
```python
|
|
182
|
+
import numpy as np
|
|
183
|
+
from matplotlib import pyplot as plt
|
|
184
|
+
|
|
185
|
+
from unitx.si import SI, si
|
|
186
|
+
|
|
187
|
+
wavelength = np.linspace(0.01, 3, 100)[:, None] * si.um
|
|
188
|
+
temperature = np.array([3000, 4000, 5000]) * si.K
|
|
189
|
+
exponent = SI.h * SI.c / (wavelength * SI.kB * temperature)
|
|
190
|
+
radiance = 2 * SI.h * SI.c**2 / (wavelength**5 * np.expm1(exponent))
|
|
191
|
+
radiance = radiance.to('kW/sr/m2/nm')
|
|
192
|
+
|
|
193
|
+
fig, ax = plt.subplots(figsize=(7, 4), layout='constrained')
|
|
194
|
+
ax.plot(wavelength.value, radiance.value)
|
|
195
|
+
ax.set(
|
|
196
|
+
xlabel=f'Wavelength [{wavelength.unit}]',
|
|
197
|
+
ylabel=f'Spectral radiance [{radiance.unit}]',
|
|
198
|
+
title='Blackbody radiation',
|
|
199
|
+
)
|
|
200
|
+
ax.legend([f'T = {value}' for value in temperature], framealpha=1)
|
|
201
|
+
ax.grid(True, alpha=0.25)
|
|
202
|
+
plt.show()
|
|
203
|
+
```
|
|
172
204
|
|
|
173
|
-

|
|
174
206
|
|
|
175
207
|
## Read more
|
|
176
208
|
|
|
@@ -10,9 +10,11 @@ True
|
|
|
10
10
|
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
-
`unitx.si`
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
`unitx.si` provides read-only namespaces: lowercase `si` contains ready-to-use
|
|
14
|
+
units and coordinate descriptors; uppercase `SI` contains physical-constant
|
|
15
|
+
Quantities. `Particle` contains particle data, while `au`, `nu` and `Planck`
|
|
16
|
+
contain physical unit scales expressed as SI Quantities.
|
|
17
|
+
Importing unitx initializes this catalogue.
|
|
16
18
|
|
|
17
19
|
## Available groups
|
|
18
20
|
|
|
@@ -43,8 +45,8 @@ For the complete definitions see [unit source](../src/unitx/si/units.py) and
|
|
|
43
45
|
|
|
44
46
|
`SI` includes the seven SI defining constants, plus constants such as hbar,
|
|
45
47
|
G, mu0, epsilon0, me, mp, mn, alpha and the Wien displacement constants.
|
|
46
|
-
Particle data are
|
|
47
|
-
`
|
|
48
|
+
Particle data are available from `from unitx.si import Particle`; the existing
|
|
49
|
+
`unitx.si.constants.Particle` import remains supported.
|
|
48
50
|
|
|
49
51
|
Defining decimal values are stored using Decimal/int magnitudes. Measured
|
|
50
52
|
constants carry the digits in the catalogue; Quantity does not attach an
|
|
@@ -59,6 +61,52 @@ from predefined `SI.hbar`, whose numerical magnitude is expressed in ordinary
|
|
|
59
61
|
J s units. See [symbolic factors](scalars.md#symbolic-factors-and-pi) and
|
|
60
62
|
[exact extra scales](custom-units.md#exact-extra-scales).
|
|
61
63
|
|
|
64
|
+
## Atomic, natural and Planck scales
|
|
65
|
+
|
|
66
|
+
```pycon
|
|
67
|
+
>>> from unitx.si import Particle, Planck, au, nu
|
|
68
|
+
>>> Particle.me is SI.me
|
|
69
|
+
True
|
|
70
|
+
>>> au.length is SI.a0
|
|
71
|
+
True
|
|
72
|
+
>>> # A physical length equal to three Bohr radii:
|
|
73
|
+
>>> length = 3 * au.length
|
|
74
|
+
>>> float((length / au.length).value_in(''))
|
|
75
|
+
3.0
|
|
76
|
+
>>> nu.velocity is SI.c
|
|
77
|
+
True
|
|
78
|
+
>>> Planck.length.unit == si.m
|
|
79
|
+
True
|
|
80
|
+
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
| Namespace | Convention | Representative scales |
|
|
84
|
+
| --- | --- | --- |
|
|
85
|
+
| `au` | Hartree atomic units: ħ = e = mₑ = 4πε₀ = 1 | `length` (Bohr radius), `energy` (Hartree), `time`, `charge` |
|
|
86
|
+
| `nu` | Electron-mass natural units: c = ħ = mₑ = ε₀ = 1 | `length` (reduced electron Compton wavelength), `energy`, `charge = sqrt(ε₀ ħ c)` |
|
|
87
|
+
| `Planck` | c = ħ = G = kB = 1 | `mass`, `length`, `time`, `energy`, `temperature` |
|
|
88
|
+
|
|
89
|
+
All three expose `velocity`, `action`, `mass`, `energy`, `momentum`, `length`
|
|
90
|
+
and `time`. `au` and `nu` also expose `permittivity`, `force`, `charge`,
|
|
91
|
+
`current`, `charge_density`, `electric_potential`, `electric_field`,
|
|
92
|
+
`electric_dipole_moment`, `electric_quadrupole_moment`,
|
|
93
|
+
`electric_polarizability`, `magnetic_flux_density`, `magnetic_dipole_moment`
|
|
94
|
+
and `magnetizability`. `au` and `Planck` expose `temperature`.
|
|
95
|
+
|
|
96
|
+
The atomic magnetic dipole scale is **twice** the Bohr magneton. In `nu`,
|
|
97
|
+
the elementary charge has numerical value sqrt(4πα); other natural-unit
|
|
98
|
+
conventions need not use the electron mass or this charge normalization.
|
|
99
|
+
`Planck` uses ħ rather than h and does not select a charge convention.
|
|
100
|
+
|
|
101
|
+
These attributes are **Quantities**, not Unit objects accepted as `.to()`
|
|
102
|
+
targets. Divide by a scale and use `.value_in('')` to obtain a dimensionless
|
|
103
|
+
number, or multiply a number by a scale to construct a physical quantity.
|
|
104
|
+
The namespaces do not activate cross-dimension conversion or register new
|
|
105
|
+
parser spellings. In particular, `si.au` and `Unit('au')` still mean the
|
|
106
|
+
astronomical unit; `au.length` is the atomic length scale.
|
|
107
|
+
All derived scales inherit the catalogue's finite numerical precision and
|
|
108
|
+
lack of uncertainty propagation.
|
|
109
|
+
|
|
62
110
|
## Spelling and scale conventions
|
|
63
111
|
|
|
64
112
|
Symbols and names are case-sensitive. Lowercase `k` is kilo and uppercase
|
|
@@ -131,7 +131,18 @@ The registry and spelling rules live in `unitx.unitregistry`; parsing expression
|
|
|
131
131
|
does not change unit definitions. A parser instance caches only a successful
|
|
132
132
|
result; failed parses may be retried after a definition is added. Registration
|
|
133
133
|
preserves existing valid spellings and validates before updating its indexes.
|
|
134
|
-
|
|
134
|
+
The registry is shared by all users of unitx in the current process; a Python
|
|
135
|
+
attribute namespace does not create an isolated registry. Conflicting names or
|
|
136
|
+
symbols raise `UnitRegistryError` rather than replace an existing definition.
|
|
137
|
+
|
|
138
|
+
Registration is not thread-safe: validation and updates to the spelling indexes
|
|
139
|
+
are not protected by a shared lock. Neither concurrent registration nor parsing
|
|
140
|
+
while another thread registers a unit is supported. Register custom units during
|
|
141
|
+
single-threaded initialization, before starting worker threads. Applications
|
|
142
|
+
that register later must synchronize both registration and all registry reads.
|
|
143
|
+
Validation failure leaves the indexes unchanged; this guarantee does not imply
|
|
144
|
+
an atomic transaction for concurrent readers. Independent registry contexts
|
|
145
|
+
are not provided.
|
|
135
146
|
|
|
136
147
|
Quantity definitions require positive finite `int`, `Fraction`, `Decimal`, or
|
|
137
148
|
`float` magnitudes. Prefer `Fraction` or `Decimal` for exact scales. Floats use
|