Skip to content
Merged
12 changes: 12 additions & 0 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,15 @@ jobs:
- uses: actions/checkout@v4
- name: Run tests (ndarray)
run: cargo test --release --features "ndarray approx"
test_nalgebra:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run tests (nalgebra)
run: cargo test --release --features "nalgebra approx"
test_num_dual:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run tests (num-dual)
run: cargo test --release --features "num-dual approx"
2 changes: 1 addition & 1 deletion .github/workflows/test_python.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,4 @@ jobs:
maturin build --release --out dist
pip install si-units --no-index --find-links dist --force-reinstall
- name: Test with pytest
run: pytest example/extend_quantity/test.py
run: pytest --doctest-modules example/extend_quantity/test.py
7 changes: 6 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [0.11.0] - 2025-09-28
### Added
- Added core functionalities for quantities with underlying data structures from `nalgebra`. [#92](https://github.com/itt-ustutt/quantity/pull/92)
- Added automatic differentiation capabilities from the `num-dual` crate. [#92](https://github.com/itt-ustutt/quantity/pull/92)

## [0.10.6] - 2025-06-24
## Changed
### Changed
- Updated the optional num-dual dependency to 0.11.2. [#91](https://github.com/itt-ustutt/quantity/pull/91)

## [0.10.5] - 2025-06-03
Expand Down
19 changes: 11 additions & 8 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
[package]
name = "quantity"
version = "0.10.6"
version = "0.11.0"
authors = [
"Philipp Rehner <prehner@ethz.ch>",
"Gernot Bauer <bauer@itt.uni-stuttgart.de>",
]
rust-version = "1.81"
edition = "2021"
rust-version = "1.87"
edition = "2024"
license = "MIT OR Apache-2.0"
description = "Representation of quantites, i.e. of unit valued scalars and arrays."
homepage = "https://github.com/itt-ustutt/quantity"
Expand All @@ -29,17 +29,20 @@ num-traits = "0.2"
document-features = "0.2"
## Use N-dimensional arrays from the [ndarray] crate as value of a quantity.
ndarray = { version = "0.16", optional = true }
## Use dynamic or static arrays from the [nalgebra] crate as value of a quantity.
nalgebra = { version = "0.34", optional = true }
approx = { version = "0.5", optional = true }
pyo3 = { version = "0.23", optional = true }
numpy = { version = "0.23", optional = true }
## Use generalized (hyper-)dual numbers from the [num-dual] crate as value of a quantity.
num-dual = { version = "0.11.2", optional = true }
pyo3 = { version = "0.26", optional = true }
numpy = { version = "0.26", optional = true }
num-dual = { version = "0.12", optional = true }

[features]
default = []
## Use generalized (hyper-)dual numbers from the [num-dual] crate as value of a quantity.
num-dual = ["dep:num-dual", "nalgebra"]
## Directly use (scalar) quantities in Python interfaces through [pyo3] and the [si-units](https://pypi.org/project/si-units/) package.
python = ["pyo3"]
## Use scalar and array quantities in Python interfaces through [pyo3], [numpy], and the [si-units](https://pypi.org/project/si-units/) package.
python_numpy = ["python", "numpy", "ndarray"]
python_numpy = ["python", "numpy/nalgebra", "ndarray", "nalgebra"]
## Enable approximate comparisons through the [approx] crate.
approx = ["dep:approx", "ndarray?/approx"]
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ Add this to your `Cargo.toml`:

```
[dependencies]
quantity = "0.10"
quantity = "0.11"
```

## Examples
Expand All @@ -24,7 +24,7 @@ Calculate pressure of an ideal gas.

```rust
let temperature = 25.0 * CELSIUS;
let volume = 1.5 * METER.powi(3);
let volume = 1.5 * METER.powi::<P3>();
let moles = 75.0 * MOL;
let pressure = moles * RGAS * temperature / volume;
println!("{:.5}", pressure); // 123.94785 kPa
Expand All @@ -36,19 +36,19 @@ Calculate the gravitational pull of the moon on the earth.
let mass_earth = 5.9724e24 * KILOGRAM;
let mass_moon = 7.346e22 * KILOGRAM;
let distance = 383.398 * KILO * METER;
let force = G * mass_earth * mass_moon / distance.powi(2);
let force = G * mass_earth * mass_moon / distance.powi::<P2>();
println!("{:.5e}", force); // 1.99208e26 N
```

Calculate the pressure distribution in the atmosphere using the barometric formula.

```rust
let z = SIArray1::linspace(1.0 * METER, 70.0 * KILO * METER, 10)?;
let g = 9.81 * METER / SECOND.powi(2);
let z = Quantity::linspace(1.0 * METER, 70.0 * KILO * METER, 10);
let g = 9.81 * METER / SECOND.powi::<P2>();
let m = 28.949 * GRAM / MOL;
let t = 10.0 * CELSIUS;
let p0 = BAR;
let pressure = p0 * (-&z * m * g).to_reduced(RGAS * t)?.mapv(f64::exp);
let pressure = ((-z.clone() * m * g) / (RGAS * t)).mapv(f64::exp) * p0;
for i in 0..10 {
println!("z = {:8.5} p = {:9.5}", z.get(i), pressure.get(i));
}
Expand Down
5 changes: 3 additions & 2 deletions example/extend_quantity/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
[package]
name = "extend_quantity"
version = "0.1.0"
edition = "2021"
edition = "2024"

[lib]
name = "extend_quantity"
crate-type = ["cdylib"]

[dependencies]
pyo3 = { version = "0.23", features = ["extension-module", "abi3-py39"] }
pyo3 = { version = "0.26", features = ["extension-module", "abi3-py39"] }
quantity = { version = "*", path = "../../", features = ["python_numpy"] }
ndarray = "0.16"
nalgebra = "0.34"
9 changes: 9 additions & 0 deletions example/extend_quantity/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use pyo3::pymodule;

#[pymodule]
mod extend_quantity {
use nalgebra::{DMatrix, DVector};
use ndarray::Array1;
use pyo3::pyfunction;
use quantity::*;
Expand Down Expand Up @@ -34,4 +35,12 @@ mod extend_quantity {
fn law_of_cosines2(a: Length, b: Length, c: Length) -> Angle {
Angle::acos((a * a + b * b - c * c).convert_into(2.0 * a * b))
}

#[pyfunction]
fn test_nalgebra(
pressure: Pressure<DMatrix<f64>>,
volume: Volume<DVector<f64>>,
) -> Energy<DVector<f64>> {
pressure * volume
}
}
11 changes: 11 additions & 0 deletions example/extend_quantity/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,14 @@ def test_array():
>>> ideal_gas_array(T, V, N)
array([ 826.31900987, 1058.09851279]) Pa
"""

def test_nalgebra():
"""
>>> from extend_quantity import test_nalgebra
>>> import si_units as si
>>> import numpy as np
>>> p = np.array([[1, 2], [3, 4]]) * si.BAR
>>> V = np.array([1, 2]) * si.LITER
>>> test_nalgebra(p, V)
array([ 500., 1100.]) J
"""
8 changes: 4 additions & 4 deletions si-units/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ authors = [
"Philipp Rehner <prehner@ethz.ch>",
"Gernot Bauer <bauer@itt.uni-stuttgart.de>",
]
rust-version = "1.81"
edition = "2021"
rust-version = "1.87"
edition = "2024"
license = "MIT OR Apache-2.0"
description = "Representation of SI unit valued scalars and arrays."
homepage = "https://github.com/itt-ustutt/quantity/tree/master/si-units"
Expand All @@ -22,7 +22,7 @@ crate-type = ["cdylib"]

[dependencies]
ndarray = "0.16"
numpy = "0.23"
pyo3 = { version = "0.23", features = ["extension-module", "abi3-py39"] }
numpy = "0.26"
pyo3 = { version = "0.26", features = ["extension-module", "abi3-py39"] }
regex = "1.11"
thiserror = "2.0"
8 changes: 4 additions & 4 deletions si-units/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,12 @@ pub enum QuantityError {

#[pyclass(name = "SIObject", module = "si_units._core", frozen)]
pub struct PySIObject {
value: PyObject,
value: Py<PyAny>,
unit: SIUnit,
}

impl PySIObject {
fn new(value: PyObject, unit: SIUnit) -> Self {
fn new(value: Py<PyAny>, unit: SIUnit) -> Self {
Self { value, unit }
}

Expand Down Expand Up @@ -93,7 +93,7 @@ impl PySIObject {
.ok()
}

fn __richcmp__(&self, py: Python, other: &Self, op: CompareOp) -> PyResult<PyObject> {
fn __richcmp__(&self, py: Python, other: &Self, op: CompareOp) -> PyResult<Py<PyAny>> {
self.check_units(other).and_then(|_| match op {
CompareOp::Eq => self.value.call_method1(py, "__eq__", (&other.value,)),
CompareOp::Ne => self.value.call_method1(py, "__ne__", (&other.value,)),
Expand Down Expand Up @@ -240,7 +240,7 @@ impl PySIObject {
}

#[getter]
fn get_shape(&self, py: Python) -> PyResult<PyObject> {
fn get_shape(&self, py: Python) -> PyResult<Py<PyAny>> {
self.value.getattr(py, "shape")
}

Expand Down
Loading
Loading