unitforge 0.5.9__tar.gz → 0.5.11__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.
- {unitforge-0.5.9 → unitforge-0.5.11}/Cargo.lock +2 -2
- {unitforge-0.5.9 → unitforge-0.5.11}/Cargo.toml +2 -2
- {unitforge-0.5.9 → unitforge-0.5.11}/PKG-INFO +3 -1
- {unitforge-0.5.9 → unitforge-0.5.11}/install_hooks.sh +0 -0
- {unitforge-0.5.9 → unitforge-0.5.11}/src/lib.rs +6 -2
- unitforge-0.5.11/src/quantities/heat_capacity.rs +76 -0
- unitforge-0.5.11/src/quantities/thermal_conductance.rs +42 -0
- {unitforge-0.5.9 → unitforge-0.5.11}/src/relations.rs +10 -5
- {unitforge-0.5.9 → unitforge-0.5.11}/test.sh +0 -0
- {unitforge-0.5.9 → unitforge-0.5.11}/tests/quantities.rs +64 -0
- {unitforge-0.5.9 → unitforge-0.5.11}/tests/quantity_core/metadata.rs +1 -0
- {unitforge-0.5.9 → unitforge-0.5.11}/tests/test_quantities.py +29 -0
- unitforge-0.5.11/tests/thermal_transient.rs +226 -0
- {unitforge-0.5.9 → unitforge-0.5.11}/tests/typecheck/mypy_smoke.py +22 -0
- {unitforge-0.5.9 → unitforge-0.5.11}/unitforge_macros/Cargo.toml +1 -1
- unitforge-0.5.9/python/unitforge/__init__.pyi +0 -3413
- unitforge-0.5.9/python/unitforge/py.typed +0 -0
- {unitforge-0.5.9 → unitforge-0.5.11}/.gitignore +0 -0
- {unitforge-0.5.9 → unitforge-0.5.11}/.gitlab-ci.yml +0 -0
- {unitforge-0.5.9 → unitforge-0.5.11}/Readme.md +0 -0
- {unitforge-0.5.9 → unitforge-0.5.11}/Readme_py.md +0 -0
- {unitforge-0.5.9 → unitforge-0.5.11}/pyproject.toml +0 -0
- {unitforge-0.5.9 → unitforge-0.5.11}/python/unitforge/__init__.py +0 -0
- {unitforge-0.5.9 → unitforge-0.5.11}/scripts/generate_python_stubs.py +0 -0
- {unitforge-0.5.9 → unitforge-0.5.11}/src/errors.rs +0 -0
- {unitforge-0.5.9 → unitforge-0.5.11}/src/impl_macros.rs +0 -0
- {unitforge-0.5.9 → unitforge-0.5.11}/src/internal.rs +0 -0
- {unitforge-0.5.9 → unitforge-0.5.11}/src/prelude.rs +0 -0
- {unitforge-0.5.9 → unitforge-0.5.11}/src/quantities/acceleration.rs +0 -0
- {unitforge-0.5.9 → unitforge-0.5.11}/src/quantities/angle.rs +0 -0
- {unitforge-0.5.9 → unitforge-0.5.11}/src/quantities/angular_acceleration.rs +0 -0
- {unitforge-0.5.9 → unitforge-0.5.11}/src/quantities/angular_velocity.rs +0 -0
- {unitforge-0.5.9 → unitforge-0.5.11}/src/quantities/area.rs +0 -0
- {unitforge-0.5.9 → unitforge-0.5.11}/src/quantities/area_of_moment.rs +0 -0
- {unitforge-0.5.9 → unitforge-0.5.11}/src/quantities/charge.rs +0 -0
- {unitforge-0.5.9 → unitforge-0.5.11}/src/quantities/compliance.rs +0 -0
- {unitforge-0.5.9 → unitforge-0.5.11}/src/quantities/density.rs +0 -0
- {unitforge-0.5.9 → unitforge-0.5.11}/src/quantities/density_rate.rs +0 -0
- {unitforge-0.5.9 → unitforge-0.5.11}/src/quantities/density_temperature.rs +0 -0
- {unitforge-0.5.9 → unitforge-0.5.11}/src/quantities/density_temperature_rate.rs +0 -0
- {unitforge-0.5.9 → unitforge-0.5.11}/src/quantities/distance.rs +0 -0
- {unitforge-0.5.9 → unitforge-0.5.11}/src/quantities/force.rs +0 -0
- {unitforge-0.5.9 → unitforge-0.5.11}/src/quantities/force_area.rs +0 -0
- {unitforge-0.5.9 → unitforge-0.5.11}/src/quantities/force_distance.rs +0 -0
- {unitforge-0.5.9 → unitforge-0.5.11}/src/quantities/force_div_distance_power_four.rs +0 -0
- {unitforge-0.5.9 → unitforge-0.5.11}/src/quantities/force_per_volume.rs +0 -0
- {unitforge-0.5.9 → unitforge-0.5.11}/src/quantities/force_stress.rs +0 -0
- {unitforge-0.5.9 → unitforge-0.5.11}/src/quantities/force_volume.rs +0 -0
- {unitforge-0.5.9 → unitforge-0.5.11}/src/quantities/frequency.rs +0 -0
- {unitforge-0.5.9 → unitforge-0.5.11}/src/quantities/heat_flux.rs +0 -0
- {unitforge-0.5.9 → unitforge-0.5.11}/src/quantities/inverse_angle.rs +0 -0
- {unitforge-0.5.9 → unitforge-0.5.11}/src/quantities/inverse_area.rs +0 -0
- {unitforge-0.5.9 → unitforge-0.5.11}/src/quantities/inverse_distance.rs +0 -0
- {unitforge-0.5.9 → unitforge-0.5.11}/src/quantities/inverse_stress.rs +0 -0
- {unitforge-0.5.9 → unitforge-0.5.11}/src/quantities/inverse_temperature.rs +0 -0
- {unitforge-0.5.9 → unitforge-0.5.11}/src/quantities/mass.rs +0 -0
- {unitforge-0.5.9 → unitforge-0.5.11}/src/quantities/mass_per_distance.rs +0 -0
- {unitforge-0.5.9 → unitforge-0.5.11}/src/quantities/molar_mass.rs +0 -0
- {unitforge-0.5.9 → unitforge-0.5.11}/src/quantities/power.rs +0 -0
- {unitforge-0.5.9 → unitforge-0.5.11}/src/quantities/pressure_rate.rs +0 -0
- {unitforge-0.5.9 → unitforge-0.5.11}/src/quantities/rotational_stiffness.rs +0 -0
- {unitforge-0.5.9 → unitforge-0.5.11}/src/quantities/specific_energy.rs +0 -0
- {unitforge-0.5.9 → unitforge-0.5.11}/src/quantities/specific_gas_constant.rs +0 -0
- {unitforge-0.5.9 → unitforge-0.5.11}/src/quantities/specific_heat_capacity.rs +0 -0
- {unitforge-0.5.9 → unitforge-0.5.11}/src/quantities/stiffness.rs +0 -0
- {unitforge-0.5.9 → unitforge-0.5.11}/src/quantities/strain.rs +0 -0
- {unitforge-0.5.9 → unitforge-0.5.11}/src/quantities/strain_squared.rs +0 -0
- {unitforge-0.5.9 → unitforge-0.5.11}/src/quantities/stress.rs +0 -0
- {unitforge-0.5.9 → unitforge-0.5.11}/src/quantities/stress_cubed.rs +0 -0
- {unitforge-0.5.9 → unitforge-0.5.11}/src/quantities/stress_per_temperature.rs +0 -0
- {unitforge-0.5.9 → unitforge-0.5.11}/src/quantities/stress_rate.rs +0 -0
- {unitforge-0.5.9 → unitforge-0.5.11}/src/quantities/stress_rate_per_temperature.rs +0 -0
- {unitforge-0.5.9 → unitforge-0.5.11}/src/quantities/stress_squared.rs +0 -0
- {unitforge-0.5.9 → unitforge-0.5.11}/src/quantities/temperature.rs +0 -0
- {unitforge-0.5.9 → unitforge-0.5.11}/src/quantities/temperature_gradient.rs +0 -0
- {unitforge-0.5.9 → unitforge-0.5.11}/src/quantities/thermal_conductivity.rs +0 -0
- {unitforge-0.5.9 → unitforge-0.5.11}/src/quantities/time.rs +0 -0
- {unitforge-0.5.9 → unitforge-0.5.11}/src/quantities/universal_gas_constant.rs +0 -0
- {unitforge-0.5.9 → unitforge-0.5.11}/src/quantities/velocity.rs +0 -0
- {unitforge-0.5.9 → unitforge-0.5.11}/src/quantities/velocity_squared.rs +0 -0
- {unitforge-0.5.9 → unitforge-0.5.11}/src/quantities/voltage.rs +0 -0
- {unitforge-0.5.9 → unitforge-0.5.11}/src/quantities/volume.rs +0 -0
- {unitforge-0.5.9 → unitforge-0.5.11}/src/quantities/volumetric_energy_density.rs +0 -0
- {unitforge-0.5.9 → unitforge-0.5.11}/src/quantities/volumetric_heat_capacity.rs +0 -0
- {unitforge-0.5.9 → unitforge-0.5.11}/src/quantities.template.rs +0 -0
- {unitforge-0.5.9 → unitforge-0.5.11}/src/small_linalg/bindings/matrix3_py.template.rs +0 -0
- {unitforge-0.5.9 → unitforge-0.5.11}/src/small_linalg/bindings/vector3_py.template.rs +0 -0
- {unitforge-0.5.9 → unitforge-0.5.11}/src/small_linalg/matrix2.rs +0 -0
- {unitforge-0.5.9 → unitforge-0.5.11}/src/small_linalg/matrix2x3.rs +0 -0
- {unitforge-0.5.9 → unitforge-0.5.11}/src/small_linalg/matrix3.rs +0 -0
- {unitforge-0.5.9 → unitforge-0.5.11}/src/small_linalg/matrix3x2.rs +0 -0
- {unitforge-0.5.9 → unitforge-0.5.11}/src/small_linalg/vector2.rs +0 -0
- {unitforge-0.5.9 → unitforge-0.5.11}/src/small_linalg/vector3.rs +0 -0
- {unitforge-0.5.9 → unitforge-0.5.11}/tests/common/mod.rs +0 -0
- {unitforge-0.5.9 → unitforge-0.5.11}/tests/matrix2.rs +0 -0
- {unitforge-0.5.9 → unitforge-0.5.11}/tests/matrix2x3.rs +0 -0
- {unitforge-0.5.9 → unitforge-0.5.11}/tests/matrix3.rs +0 -0
- {unitforge-0.5.9 → unitforge-0.5.11}/tests/matrix3x2.rs +0 -0
- {unitforge-0.5.9 → unitforge-0.5.11}/tests/ndarray_dot.rs +0 -0
- {unitforge-0.5.9 → unitforge-0.5.11}/tests/quantity_core/constants.rs +0 -0
- {unitforge-0.5.9 → unitforge-0.5.11}/tests/quantity_core/construction.rs +0 -0
- {unitforge-0.5.9 → unitforge-0.5.11}/tests/quantity_core/enum_iter.rs +0 -0
- {unitforge-0.5.9 → unitforge-0.5.11}/tests/quantity_core/normalization.rs +0 -0
- {unitforge-0.5.9 → unitforge-0.5.11}/tests/quantity_core/plain_storage.rs +0 -0
- {unitforge-0.5.9 → unitforge-0.5.11}/tests/quantity_core/relations.rs +0 -0
- {unitforge-0.5.9 → unitforge-0.5.11}/tests/quantity_core/runtime_quantity.rs +0 -0
- {unitforge-0.5.9 → unitforge-0.5.11}/tests/quantity_core/scalar_edges.rs +0 -0
- {unitforge-0.5.9 → unitforge-0.5.11}/tests/quantity_core.rs +0 -0
- {unitforge-0.5.9 → unitforge-0.5.11}/tests/quantity_serde.rs +0 -0
- {unitforge-0.5.9 → unitforge-0.5.11}/tests/small_linalg_edge_cases.rs +0 -0
- {unitforge-0.5.9 → unitforge-0.5.11}/tests/small_linalg_interfaces.rs +0 -0
- {unitforge-0.5.9 → unitforge-0.5.11}/tests/test_small_linalg.py +0 -0
- {unitforge-0.5.9 → unitforge-0.5.11}/tests/vector2.rs +0 -0
- {unitforge-0.5.9 → unitforge-0.5.11}/tests/vector3.rs +0 -0
- {unitforge-0.5.9 → unitforge-0.5.11}/unitforge_macros/src/lib.rs +0 -0
|
@@ -351,7 +351,7 @@ checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
|
|
|
351
351
|
|
|
352
352
|
[[package]]
|
|
353
353
|
name = "unitforge"
|
|
354
|
-
version = "0.5.
|
|
354
|
+
version = "0.5.11"
|
|
355
355
|
dependencies = [
|
|
356
356
|
"ndarray",
|
|
357
357
|
"num-traits",
|
|
@@ -367,7 +367,7 @@ dependencies = [
|
|
|
367
367
|
|
|
368
368
|
[[package]]
|
|
369
369
|
name = "unitforge_macros"
|
|
370
|
-
version = "0.5.
|
|
370
|
+
version = "0.5.11"
|
|
371
371
|
dependencies = [
|
|
372
372
|
"regex",
|
|
373
373
|
]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[package]
|
|
2
2
|
name = "unitforge"
|
|
3
|
-
version = "0.5.
|
|
3
|
+
version = "0.5.11"
|
|
4
4
|
edition = "2021"
|
|
5
5
|
authors = ["Dr.Q team <info@askdrq.com>", "Henrik Stromberg <henrik@askdrq.com>"]
|
|
6
6
|
description = "A library for unit and quantity consistent computations in Rust"
|
|
@@ -20,7 +20,7 @@ pyo3 = { version = "0.28.3", features = ["extension-module", "auto-initialize",
|
|
|
20
20
|
numpy = { version = "0.28.0", optional = true }
|
|
21
21
|
strum = { version = "0.28.0", optional = true }
|
|
22
22
|
strum_macros = { version = "0.28.0", optional = true }
|
|
23
|
-
unitforge_macros = { version = "0.5.
|
|
23
|
+
unitforge_macros = { version = "0.5.11", path = "unitforge_macros" }
|
|
24
24
|
|
|
25
25
|
[features]
|
|
26
26
|
default = []
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: unitforge
|
|
3
|
-
Version: 0.5.
|
|
3
|
+
Version: 0.5.11
|
|
4
4
|
Classifier: Programming Language :: Python :: 3
|
|
5
5
|
Classifier: Programming Language :: Rust
|
|
6
6
|
Classifier: License :: OSI Approved :: MIT License
|
|
@@ -9,7 +9,9 @@ Classifier: Topic :: Scientific/Engineering :: Physics
|
|
|
9
9
|
Requires-Dist: numpy>=2.2.0
|
|
10
10
|
Summary: A library for unit and quantity consistent computations in Rust
|
|
11
11
|
Keywords: units,quantities,simulation,physics
|
|
12
|
+
Author: Dr.Q team <info@askdrq.com>, Henrik Stromberg <henrik@askdrq.com>
|
|
12
13
|
Author-email: "Dr.Q team" <info@askdrq.com>, Henrik Stromberg <henrik@askdrq.com>
|
|
14
|
+
License: MIT
|
|
13
15
|
Requires-Python: >=3.7
|
|
14
16
|
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
|
|
15
17
|
Project-URL: Repository, https://gitlab.com/henrikjstromberg/unitforge
|
|
File without changes
|
|
@@ -95,6 +95,8 @@ pub mod quantities {
|
|
|
95
95
|
pub use frequency::*;
|
|
96
96
|
pub mod heat_flux;
|
|
97
97
|
pub use heat_flux::*;
|
|
98
|
+
pub mod heat_capacity;
|
|
99
|
+
pub use heat_capacity::*;
|
|
98
100
|
pub mod inverse_distance;
|
|
99
101
|
pub use inverse_distance::*;
|
|
100
102
|
pub mod inverse_area;
|
|
@@ -107,10 +109,10 @@ pub mod quantities {
|
|
|
107
109
|
pub use molar_mass::*;
|
|
108
110
|
pub mod mass_per_distance;
|
|
109
111
|
pub use mass_per_distance::*;
|
|
110
|
-
pub mod power;
|
|
111
|
-
pub use power::*;
|
|
112
112
|
pub mod pressure_rate;
|
|
113
113
|
pub use pressure_rate::*;
|
|
114
|
+
pub mod power;
|
|
115
|
+
pub use power::*;
|
|
114
116
|
pub mod force_distance;
|
|
115
117
|
pub use force_distance::*;
|
|
116
118
|
pub mod force_stress;
|
|
@@ -145,6 +147,8 @@ pub mod quantities {
|
|
|
145
147
|
pub use temperature::*;
|
|
146
148
|
pub mod temperature_gradient;
|
|
147
149
|
pub use temperature_gradient::*;
|
|
150
|
+
pub mod thermal_conductance;
|
|
151
|
+
pub use thermal_conductance::*;
|
|
148
152
|
pub mod inverse_temperature;
|
|
149
153
|
pub use inverse_temperature::*;
|
|
150
154
|
pub mod thermal_conductivity;
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
//! Heat capacity of a finite amount of material, in energy per temperature.
|
|
2
|
+
//!
|
|
3
|
+
//! With `ndarray`, use scalar operators in `mapv` to divide by time and
|
|
4
|
+
//! `QuantityDot` for contractions (including borrowed views). Multiplication
|
|
5
|
+
//! through `MulArray1`/`MulArray2` remains elementwise.
|
|
6
|
+
//!
|
|
7
|
+
//! ```
|
|
8
|
+
//! # #[cfg(feature = "ndarray")] {
|
|
9
|
+
//! use ndarray::{arr1, Array1, Array2};
|
|
10
|
+
//! use unitforge::*;
|
|
11
|
+
//!
|
|
12
|
+
//! let volumetric = VolumetricHeatCapacity::new(2.0, VolumetricHeatCapacityUnit::kJ_mcbK);
|
|
13
|
+
//! let volume = Volume::new(0.5, VolumeUnit::mcb);
|
|
14
|
+
//! let mut capacitance = Array2::<HeatCapacity>::zeros((2, 2));
|
|
15
|
+
//! capacitance[(0, 0)] += volumetric * volume;
|
|
16
|
+
//! let temperature = arr1(&[Temperature::new(300.0, TemperatureUnit::K); 2]);
|
|
17
|
+
//! let delta_time = Time::new(2.0, TimeUnit::s);
|
|
18
|
+
//! let conductance: Array2<ThermalConductance> = capacitance.mapv(|c| c / delta_time);
|
|
19
|
+
//! let energy: Array1<Energy> = QuantityDot::dot(&capacitance.view(), &temperature.view());
|
|
20
|
+
//! let power: Array1<Power> = energy.mapv(|e| e / delta_time);
|
|
21
|
+
//! let power_from_conductance: Array1<Power> = QuantityDot::dot(&conductance, &temperature);
|
|
22
|
+
//! assert!(power[0].is_close(&power_from_conductance[0], &Power::new(1e-6, PowerUnit::W)));
|
|
23
|
+
//! # }
|
|
24
|
+
//! ```
|
|
25
|
+
//!
|
|
26
|
+
//! Incompatible quantities cannot be added:
|
|
27
|
+
//! ```compile_fail
|
|
28
|
+
//! use unitforge::*;
|
|
29
|
+
//! let capacity = HeatCapacity::new(1.0, HeatCapacityUnit::J_K);
|
|
30
|
+
//! let conductance = ThermalConductance::new(1.0, ThermalConductanceUnit::W_K);
|
|
31
|
+
//! let _ = capacity + conductance;
|
|
32
|
+
//! ```
|
|
33
|
+
//!
|
|
34
|
+
//! A dimensionless divisor preserves heat capacity; converting to conductance
|
|
35
|
+
//! requires a typed `Time`:
|
|
36
|
+
//! ```compile_fail
|
|
37
|
+
//! use unitforge::*;
|
|
38
|
+
//! let capacity = HeatCapacity::new(1.0, HeatCapacityUnit::J_K);
|
|
39
|
+
//! let conductance: ThermalConductance = capacity / 2.0;
|
|
40
|
+
//! ```
|
|
41
|
+
|
|
42
|
+
use crate::impl_macros::macros::*;
|
|
43
|
+
|
|
44
|
+
#[cfg_attr(feature = "strum", derive(EnumIter))]
|
|
45
|
+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
|
46
|
+
#[derive(Copy, Clone, PartialEq, Debug, Hash, Eq)]
|
|
47
|
+
#[cfg_attr(feature = "pyo3", pyclass(eq, eq_int, from_py_object))]
|
|
48
|
+
pub enum HeatCapacityUnit {
|
|
49
|
+
J_K,
|
|
50
|
+
kJ_K,
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
impl HeatCapacityUnit {
|
|
54
|
+
pub const fn base_per_x_const(self) -> (f64, i32) {
|
|
55
|
+
match self {
|
|
56
|
+
Self::J_K => (1.0, 0),
|
|
57
|
+
Self::kJ_K => (1.0, 3),
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
impl PhysicsUnit for HeatCapacityUnit {
|
|
63
|
+
fn name(&self) -> &str {
|
|
64
|
+
match self {
|
|
65
|
+
Self::J_K => "J/K",
|
|
66
|
+
Self::kJ_K => "kJ/K",
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
fn base_per_x(&self) -> (f64, i32) {
|
|
71
|
+
(*self).base_per_x_const()
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
impl_quantity!(HeatCapacity, HeatCapacityUnit, [HeatCapacityUnit::J_K]);
|
|
76
|
+
impl_div_with_self_to_f64!(HeatCapacity);
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
use crate::impl_macros::macros::*;
|
|
2
|
+
|
|
3
|
+
#[cfg_attr(feature = "strum", derive(EnumIter))]
|
|
4
|
+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
|
5
|
+
#[derive(Copy, Clone, PartialEq, Debug, Hash, Eq)]
|
|
6
|
+
#[cfg_attr(feature = "pyo3", pyclass(eq, eq_int, from_py_object))]
|
|
7
|
+
pub enum ThermalConductanceUnit {
|
|
8
|
+
mW_K,
|
|
9
|
+
W_K,
|
|
10
|
+
kW_K,
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
impl ThermalConductanceUnit {
|
|
14
|
+
pub const fn base_per_x_const(self) -> (f64, i32) {
|
|
15
|
+
match self {
|
|
16
|
+
ThermalConductanceUnit::mW_K => (1., -3),
|
|
17
|
+
ThermalConductanceUnit::W_K => (1., 0),
|
|
18
|
+
ThermalConductanceUnit::kW_K => (1., 3),
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
impl PhysicsUnit for ThermalConductanceUnit {
|
|
24
|
+
fn name(&self) -> &str {
|
|
25
|
+
match self {
|
|
26
|
+
ThermalConductanceUnit::mW_K => "mW/K",
|
|
27
|
+
ThermalConductanceUnit::W_K => "W/K",
|
|
28
|
+
ThermalConductanceUnit::kW_K => "kW/K",
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
fn base_per_x(&self) -> (f64, i32) {
|
|
33
|
+
(*self).base_per_x_const()
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
impl_quantity!(
|
|
38
|
+
ThermalConductance,
|
|
39
|
+
ThermalConductanceUnit,
|
|
40
|
+
[ThermalConductanceUnit::W_K]
|
|
41
|
+
);
|
|
42
|
+
impl_div_with_self_to_f64!(ThermalConductance);
|
|
@@ -28,6 +28,16 @@ impl_mul_relation_with_other!(Distance, InverseArea, InverseDistance);
|
|
|
28
28
|
impl_mul_relation_with_other!(InverseDistance, Area, Distance);
|
|
29
29
|
impl_mul_relation_with_other!(Velocity, Time, Distance);
|
|
30
30
|
impl_mul_relation_with_other!(Force, Distance, ForceDistance);
|
|
31
|
+
impl_mul_relation_with_other!(Power, Time, ForceDistance);
|
|
32
|
+
impl_mul_relation_with_other!(Force, Velocity, Power);
|
|
33
|
+
impl_mul_relation_with_other!(HeatFlux, Area, Power);
|
|
34
|
+
impl_mul_relation_with_other!(ThermalConductivity, TemperatureGradient, HeatFlux);
|
|
35
|
+
impl_mul_relation_with_other!(TemperatureGradient, Distance, Temperature);
|
|
36
|
+
impl_mul_relation_with_other!(ThermalConductivity, Distance, ThermalConductance);
|
|
37
|
+
impl_mul_relation_with_other!(ThermalConductance, Temperature, Power);
|
|
38
|
+
impl_mul_relation_with_other!(VolumetricHeatCapacity, Volume, HeatCapacity);
|
|
39
|
+
impl_mul_relation_with_other!(ThermalConductance, Time, HeatCapacity);
|
|
40
|
+
impl_mul_relation_with_other!(HeatCapacity, Temperature, ForceDistance);
|
|
31
41
|
impl_mul_relation_with_other!(Force, Area, ForceArea);
|
|
32
42
|
impl_mul_relation_with_other!(ForceArea, Distance, ForceVolume);
|
|
33
43
|
impl_mul_relation_with_other!(AreaOfMoment, Stress, ForceArea);
|
|
@@ -80,12 +90,7 @@ impl_mul_relation_with_self!(Strain, StrainSquared);
|
|
|
80
90
|
impl_mul_relation_with_self!(Stress, StressSquared);
|
|
81
91
|
impl_mul_relation_with_other!(Stress, StressSquared, StressCubed);
|
|
82
92
|
impl_mul_relation_with_self!(AngularVelocity, AngularAcceleration);
|
|
83
|
-
impl_mul_relation_with_other!(ThermalConductivity, TemperatureGradient, HeatFlux);
|
|
84
|
-
impl_mul_relation_with_other!(TemperatureGradient, Distance, Temperature);
|
|
85
|
-
impl_mul_relation_with_other!(HeatFlux, Area, Power);
|
|
86
|
-
impl_mul_relation_with_other!(Power, Time, ForceDistance);
|
|
87
93
|
impl_mul_relation_with_other!(ForceDistance, Frequency, Power);
|
|
88
|
-
impl_mul_relation_with_other!(Force, Velocity, Power);
|
|
89
94
|
impl_mul_relation_with_other!(Density, SpecificHeatCapacity, VolumetricHeatCapacity);
|
|
90
95
|
impl_mul_relation_with_other!(VolumetricHeatCapacity, Temperature, VolumetricEnergyDensity);
|
|
91
96
|
impl_mul_relation_with_other!(SpecificHeatCapacity, Temperature, SpecificEnergy);
|
|
File without changes
|
|
@@ -361,6 +361,70 @@ mod test_thermo_and_rates {
|
|
|
361
361
|
));
|
|
362
362
|
}
|
|
363
363
|
|
|
364
|
+
#[test]
|
|
365
|
+
fn thermal_quantities_convert_and_relate_to_energy() {
|
|
366
|
+
let conductivity = ThermalConductivity::new(1.0, ThermalConductivityUnit::kW_mK);
|
|
367
|
+
assert!(crate::approx_eq(
|
|
368
|
+
conductivity.to(ThermalConductivityUnit::mW_mK),
|
|
369
|
+
1_000_000.0,
|
|
370
|
+
1e-6
|
|
371
|
+
));
|
|
372
|
+
|
|
373
|
+
let gradient = TemperatureGradient::new(2.0, TemperatureGradientUnit::K_m);
|
|
374
|
+
let flux = ThermalConductivity::new(1.0, ThermalConductivityUnit::kW_mK) * gradient;
|
|
375
|
+
assert!(crate::approx_eq(flux.to(HeatFluxUnit::kW_msq), 2.0, 1e-12));
|
|
376
|
+
|
|
377
|
+
let area = Area::new(0.5, AreaUnit::msq);
|
|
378
|
+
let power = flux * area;
|
|
379
|
+
assert!(crate::approx_eq(power.to(PowerUnit::W), 1000.0, 1e-12));
|
|
380
|
+
|
|
381
|
+
let duration = Time::new(30.0, TimeUnit::s);
|
|
382
|
+
let energy = power * duration;
|
|
383
|
+
assert!(crate::approx_eq(energy.to(EnergyUnit::J), 30_000.0, 1e-12));
|
|
384
|
+
assert!(crate::approx_eq(
|
|
385
|
+
(energy / duration).to(PowerUnit::kW),
|
|
386
|
+
1.0,
|
|
387
|
+
1e-12
|
|
388
|
+
));
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
#[test]
|
|
392
|
+
fn thermal_conductance_relates_conductivity_length_and_power() {
|
|
393
|
+
let conductivity = ThermalConductivity::new(200.0, ThermalConductivityUnit::W_mK);
|
|
394
|
+
let characteristic_length = Distance::new(0.05, DistanceUnit::m);
|
|
395
|
+
let conductance = conductivity * characteristic_length;
|
|
396
|
+
assert!(crate::approx_eq(
|
|
397
|
+
conductance.to(ThermalConductanceUnit::W_K),
|
|
398
|
+
10.0,
|
|
399
|
+
1e-12
|
|
400
|
+
));
|
|
401
|
+
|
|
402
|
+
let temperature_difference = Temperature::new(15.0, TemperatureUnit::K);
|
|
403
|
+
let power = conductance * temperature_difference;
|
|
404
|
+
assert!(crate::approx_eq(power.to(PowerUnit::W), 150.0, 1e-12));
|
|
405
|
+
|
|
406
|
+
assert!(crate::approx_eq(
|
|
407
|
+
(power / conductance).to(TemperatureUnit::K),
|
|
408
|
+
15.0,
|
|
409
|
+
1e-12
|
|
410
|
+
));
|
|
411
|
+
assert!(crate::approx_eq(
|
|
412
|
+
(power / temperature_difference).to(ThermalConductanceUnit::W_K),
|
|
413
|
+
10.0,
|
|
414
|
+
1e-12
|
|
415
|
+
));
|
|
416
|
+
assert!(crate::approx_eq(
|
|
417
|
+
(conductance / conductivity).to(DistanceUnit::m),
|
|
418
|
+
0.05,
|
|
419
|
+
1e-12
|
|
420
|
+
));
|
|
421
|
+
assert!(crate::approx_eq(
|
|
422
|
+
(conductance / characteristic_length).to(ThermalConductivityUnit::W_mK),
|
|
423
|
+
200.0,
|
|
424
|
+
1e-12
|
|
425
|
+
));
|
|
426
|
+
}
|
|
427
|
+
|
|
364
428
|
#[test]
|
|
365
429
|
fn specific_and_molar_gas_constants_relate_through_molar_mass() {
|
|
366
430
|
let molar_mass = MolarMass::new(28.97, MolarMassUnit::g_mol);
|
|
@@ -34,6 +34,7 @@ fn quantity_kind_id_is_stored_in_memory_optimal_layout() {
|
|
|
34
34
|
#[test]
|
|
35
35
|
fn quantity_kind_ids_are_unique_and_non_zero() {
|
|
36
36
|
let ids = [
|
|
37
|
+
<HeatCapacity as QuantityKindId>::KIND_ID,
|
|
37
38
|
<Acceleration as QuantityKindId>::KIND_ID,
|
|
38
39
|
<Angle as QuantityKindId>::KIND_ID,
|
|
39
40
|
<AngularAcceleration as QuantityKindId>::KIND_ID,
|
|
@@ -2,6 +2,35 @@ import pytest
|
|
|
2
2
|
from unitforge import *
|
|
3
3
|
|
|
4
4
|
|
|
5
|
+
def test_heat_capacity_thermal_relations():
|
|
6
|
+
volumetric = VolumetricHeatCapacity(2.0, VolumetricHeatCapacityUnit.kJ_mcbK)
|
|
7
|
+
volume = Volume(0.5, VolumeUnit.mcb)
|
|
8
|
+
capacity = volumetric * volume
|
|
9
|
+
assert isinstance(capacity, HeatCapacity)
|
|
10
|
+
assert capacity.to(HeatCapacityUnit.J_K) == pytest.approx(1000.0)
|
|
11
|
+
assert capacity.to(HeatCapacityUnit.kJ_K) == pytest.approx(1.0)
|
|
12
|
+
assert volume * volumetric == capacity
|
|
13
|
+
assert capacity / volume == volumetric
|
|
14
|
+
assert capacity / volumetric == volume
|
|
15
|
+
time = Time(2.0, TimeUnit.s)
|
|
16
|
+
conductance = capacity / time
|
|
17
|
+
assert isinstance(conductance, ThermalConductance)
|
|
18
|
+
assert conductance.to(ThermalConductanceUnit.W_K) == pytest.approx(500.0)
|
|
19
|
+
assert conductance * time == capacity
|
|
20
|
+
assert time * conductance == capacity
|
|
21
|
+
assert capacity / conductance == time
|
|
22
|
+
temperature = Temperature(300.0, TemperatureUnit.K)
|
|
23
|
+
energy = capacity * temperature
|
|
24
|
+
assert isinstance(energy, Energy)
|
|
25
|
+
assert energy.to(EnergyUnit.J) == pytest.approx(300000.0)
|
|
26
|
+
assert temperature * capacity == energy
|
|
27
|
+
assert energy / temperature == capacity
|
|
28
|
+
assert energy / capacity == temperature
|
|
29
|
+
assert (energy / time).to(PowerUnit.W) == pytest.approx(150000.0)
|
|
30
|
+
with pytest.raises(TypeError):
|
|
31
|
+
_ = capacity + conductance
|
|
32
|
+
|
|
33
|
+
|
|
5
34
|
def test_inverse_stress_from_stress_division():
|
|
6
35
|
stress = Stress(2.0, StressUnit.Pa)
|
|
7
36
|
inverse = 1 / stress
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
use num_traits::Zero;
|
|
2
|
+
use unitforge::*;
|
|
3
|
+
|
|
4
|
+
fn close<Q: PhysicsQuantity>(actual: Q, expected: Q) {
|
|
5
|
+
// Match the precision supported by each storage configuration.
|
|
6
|
+
let epsilon = if cfg!(feature = "storage-f32") {
|
|
7
|
+
1e-5
|
|
8
|
+
} else {
|
|
9
|
+
1e-10
|
|
10
|
+
};
|
|
11
|
+
let tolerance = expected.abs() * epsilon + Q::from_raw(epsilon);
|
|
12
|
+
assert!(
|
|
13
|
+
actual.is_close(&expected, &tolerance),
|
|
14
|
+
"physical values differ"
|
|
15
|
+
);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
#[test]
|
|
19
|
+
fn scalar_thermal_relations_in_both_orders_and_inverses() {
|
|
20
|
+
let volumetric = VolumetricHeatCapacity::new(2.0, VolumetricHeatCapacityUnit::kJ_mcbK);
|
|
21
|
+
let volume = Volume::new(0.5, VolumeUnit::mcb);
|
|
22
|
+
let capacity = HeatCapacity::new(1000.0, HeatCapacityUnit::J_K);
|
|
23
|
+
let time = Time::new(2000.0, TimeUnit::ms);
|
|
24
|
+
let conductance = ThermalConductance::new(0.5, ThermalConductanceUnit::kW_K);
|
|
25
|
+
let temperature = Temperature::new(300.0, TemperatureUnit::K);
|
|
26
|
+
let energy = Energy::new(300.0, EnergyUnit::kNm);
|
|
27
|
+
|
|
28
|
+
let assembled: HeatCapacity = volumetric * volume;
|
|
29
|
+
close(assembled, capacity);
|
|
30
|
+
close(volume * volumetric, capacity);
|
|
31
|
+
close(capacity / volume, volumetric);
|
|
32
|
+
close(capacity / volumetric, volume);
|
|
33
|
+
close(conductance * time, capacity);
|
|
34
|
+
close(time * conductance, capacity);
|
|
35
|
+
let rate: ThermalConductance = capacity / time;
|
|
36
|
+
close(rate, conductance);
|
|
37
|
+
close(capacity / conductance, time);
|
|
38
|
+
let stored_energy: Energy = capacity * temperature;
|
|
39
|
+
close(stored_energy, energy);
|
|
40
|
+
close(temperature * capacity, energy);
|
|
41
|
+
close(energy / temperature, capacity);
|
|
42
|
+
close(energy / capacity, temperature);
|
|
43
|
+
let power: Power = stored_energy / time;
|
|
44
|
+
close(power, Power::new(150000.0, PowerUnit::W));
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
#[test]
|
|
48
|
+
fn capacity_units_signed_arithmetic_and_registration() {
|
|
49
|
+
let capacity = HeatCapacity::new(1.0, HeatCapacityUnit::kJ_K);
|
|
50
|
+
close(capacity, HeatCapacity::new(1000.0, HeatCapacityUnit::J_K));
|
|
51
|
+
assert_eq!(capacity.to(HeatCapacityUnit::kJ_K), 1.0);
|
|
52
|
+
assert_eq!(capacity.to(HeatCapacityUnit::J_K), 1000.0);
|
|
53
|
+
let mut accumulated = HeatCapacity::zero();
|
|
54
|
+
accumulated += capacity;
|
|
55
|
+
accumulated -= capacity * 0.25;
|
|
56
|
+
close(accumulated, HeatCapacity::new(750.0, HeatCapacityUnit::J_K));
|
|
57
|
+
close(-capacity + capacity, HeatCapacity::zero());
|
|
58
|
+
close(capacity / 2.0, 0.5 * capacity);
|
|
59
|
+
assert!(capacity > -capacity);
|
|
60
|
+
assert!((capacity / HeatCapacity::new(250.0, HeatCapacityUnit::J_K) - 4.0).abs() < 1e-5);
|
|
61
|
+
assert_ne!(HeatCapacity::KIND_ID, 0);
|
|
62
|
+
assert_ne!(HeatCapacity::KIND_ID, ThermalConductance::KIND_ID);
|
|
63
|
+
let runtime = Unit::HeatCapacityUnit(HeatCapacityUnit::kJ_K).to_quantity(1.0);
|
|
64
|
+
assert_eq!(runtime, Quantity::HeatCapacityQuantity(capacity));
|
|
65
|
+
let result = (runtime / Quantity::TimeQuantity(Time::new(2.0, TimeUnit::s))).unwrap();
|
|
66
|
+
assert_eq!(
|
|
67
|
+
result,
|
|
68
|
+
Quantity::ThermalConductanceQuantity(ThermalConductance::new(
|
|
69
|
+
500.0,
|
|
70
|
+
ThermalConductanceUnit::W_K
|
|
71
|
+
))
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
#[test]
|
|
76
|
+
fn exceptional_values_follow_quantity_semantics() {
|
|
77
|
+
let zero = HeatCapacity::zero();
|
|
78
|
+
let time_zero = Time::zero();
|
|
79
|
+
assert!((zero / time_zero).is_nan());
|
|
80
|
+
assert!((zero / zero).is_nan());
|
|
81
|
+
close(
|
|
82
|
+
HeatCapacity::new(-2.0, HeatCapacityUnit::J_K) / Time::new(2.0, TimeUnit::s),
|
|
83
|
+
ThermalConductance::new(-1.0, ThermalConductanceUnit::W_K),
|
|
84
|
+
);
|
|
85
|
+
assert!((HeatCapacity::new(1.0, HeatCapacityUnit::J_K) / time_zero)
|
|
86
|
+
.to(ThermalConductanceUnit::W_K)
|
|
87
|
+
.is_infinite());
|
|
88
|
+
assert!(HeatCapacity::nan().is_nan());
|
|
89
|
+
#[cfg(not(any(feature = "storage-f64", feature = "storage-f32")))]
|
|
90
|
+
{
|
|
91
|
+
assert!(HeatCapacity::from_exponential(1.0, MAX_ABS_QUANTITY_POWER)
|
|
92
|
+
.to(HeatCapacityUnit::J_K)
|
|
93
|
+
.is_infinite());
|
|
94
|
+
close(
|
|
95
|
+
HeatCapacity::from_exponential(1.0, -MAX_ABS_QUANTITY_POWER),
|
|
96
|
+
zero,
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
#[cfg(feature = "serde")]
|
|
102
|
+
#[test]
|
|
103
|
+
fn capacity_serialization_roundtrip() {
|
|
104
|
+
let original = HeatCapacity::new(-0.125, HeatCapacityUnit::kJ_K);
|
|
105
|
+
let restored: HeatCapacity =
|
|
106
|
+
serde_json::from_str(&serde_json::to_string(&original).unwrap()).unwrap();
|
|
107
|
+
close(restored, original);
|
|
108
|
+
let unit: HeatCapacityUnit =
|
|
109
|
+
serde_json::from_str(&serde_json::to_string(&HeatCapacityUnit::kJ_K).unwrap()).unwrap();
|
|
110
|
+
assert_eq!(unit, HeatCapacityUnit::kJ_K);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
#[cfg(feature = "strum")]
|
|
114
|
+
#[test]
|
|
115
|
+
fn capacity_units_are_registered_for_iteration() {
|
|
116
|
+
use strum::IntoEnumIterator;
|
|
117
|
+
assert_eq!(
|
|
118
|
+
HeatCapacityUnit::iter().collect::<Vec<_>>(),
|
|
119
|
+
vec![HeatCapacityUnit::J_K, HeatCapacityUnit::kJ_K]
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
#[cfg(feature = "ndarray")]
|
|
124
|
+
mod arrays {
|
|
125
|
+
use super::*;
|
|
126
|
+
use ndarray::{arr1, arr2, s, Array1, Array2};
|
|
127
|
+
|
|
128
|
+
fn capacity(value: f64) -> HeatCapacity {
|
|
129
|
+
HeatCapacity::new(value, HeatCapacityUnit::J_K)
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
#[test]
|
|
133
|
+
fn backward_euler_both_routes() {
|
|
134
|
+
let mut c = Array2::<HeatCapacity>::zeros((2, 2));
|
|
135
|
+
let volumetric = VolumetricHeatCapacity::new(2.0, VolumetricHeatCapacityUnit::kJ_mcbK);
|
|
136
|
+
c[(0, 0)] += volumetric * Volume::new(0.001, VolumeUnit::mcb);
|
|
137
|
+
c[(0, 1)] += HeatCapacity::new(0.001, HeatCapacityUnit::kJ_K);
|
|
138
|
+
c[(1, 0)] += capacity(1.0);
|
|
139
|
+
c[(1, 1)] += capacity(3.0);
|
|
140
|
+
let t = arr1(&[300.0, 400.0]).mapv(|v| Temperature::new(v, TemperatureUnit::K));
|
|
141
|
+
let time = Time::new(2.0, TimeUnit::s);
|
|
142
|
+
let k: Array2<ThermalConductance> = c.mapv(|v| v / time);
|
|
143
|
+
assert_eq!(k.dim(), c.dim());
|
|
144
|
+
for (actual, expected) in k.iter().zip([1.0, 0.5, 0.5, 1.5]) {
|
|
145
|
+
close(
|
|
146
|
+
*actual,
|
|
147
|
+
ThermalConductance::new(expected, ThermalConductanceUnit::W_K),
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
let energy: Array1<Energy> = QuantityDot::dot(&c, &t);
|
|
151
|
+
close(energy[0], Energy::new(1000.0, EnergyUnit::J));
|
|
152
|
+
close(energy[1], Energy::new(1500.0, EnergyUnit::J));
|
|
153
|
+
let p: Array1<Power> = energy.mapv(|v| v / time);
|
|
154
|
+
let other: Array1<Power> = QuantityDot::dot(&k, &t);
|
|
155
|
+
assert_eq!(p.len(), 2);
|
|
156
|
+
for ((a, b), expected) in p.iter().zip(other.iter()).zip([500.0, 750.0]) {
|
|
157
|
+
close(*a, Power::new(expected, PowerUnit::W));
|
|
158
|
+
close(*a, *b);
|
|
159
|
+
}
|
|
160
|
+
#[cfg(feature = "serde")]
|
|
161
|
+
{
|
|
162
|
+
let restored: Array2<HeatCapacity> =
|
|
163
|
+
serde_json::from_str(&serde_json::to_string(&c).unwrap()).unwrap();
|
|
164
|
+
assert_eq!(restored.dim(), c.dim());
|
|
165
|
+
for (a, b) in restored.iter().zip(c.iter()) {
|
|
166
|
+
close(*a, *b);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
#[test]
|
|
172
|
+
fn rectangular_strided_views_and_cancellation() {
|
|
173
|
+
let c = arr2(&[[2.0, 99.0, -1.0, 99.0, 0.0], [0.0, 99.0, 3.0, 99.0, -2.0]]).mapv(capacity);
|
|
174
|
+
let c_view = c.slice(s![.., ..;2]);
|
|
175
|
+
let t = arr1(&[300.0, 99.0, 600.0, 99.0, 400.0])
|
|
176
|
+
.mapv(|v| Temperature::new(v, TemperatureUnit::K));
|
|
177
|
+
let t_view = t.slice(s![..;2]);
|
|
178
|
+
let energy: Array1<Energy> = QuantityDot::dot(&c_view, &t_view);
|
|
179
|
+
close(energy[0], Energy::zero());
|
|
180
|
+
close(energy[1], Energy::new(1000.0, EnergyUnit::J));
|
|
181
|
+
let time = Time::new(2.0, TimeUnit::s);
|
|
182
|
+
let power: Array1<Power> = energy.mapv(|v| v / time);
|
|
183
|
+
let k = c_view.mapv(|v| v / time);
|
|
184
|
+
let other: Array1<Power> = QuantityDot::dot(&k.view(), &t_view);
|
|
185
|
+
for (a, b) in power.iter().zip(other.iter()) {
|
|
186
|
+
close(*a, *b);
|
|
187
|
+
}
|
|
188
|
+
let vv: Energy = QuantityDot::dot(&c_view.row(0), &t_view);
|
|
189
|
+
close(vv, Energy::zero());
|
|
190
|
+
let vm: Array1<Energy> = QuantityDot::dot(&t_view, &c_view.t());
|
|
191
|
+
for (a, b) in vm.iter().zip(energy.iter()) {
|
|
192
|
+
close(*a, *b);
|
|
193
|
+
}
|
|
194
|
+
let temperatures = arr2(&[[300.0, 0.0], [600.0, 1.0], [400.0, -1.0]])
|
|
195
|
+
.mapv(|v| Temperature::new(v, TemperatureUnit::K));
|
|
196
|
+
let mm: Array2<Energy> = QuantityDot::dot(&c_view, &temperatures.view());
|
|
197
|
+
assert_eq!(mm.dim(), (2, 2));
|
|
198
|
+
close(mm[(0, 0)], Energy::zero());
|
|
199
|
+
close(mm[(1, 0)], energy[1]);
|
|
200
|
+
close(mm[(0, 1)], Energy::new(-1.0, EnergyUnit::J));
|
|
201
|
+
close(mm[(1, 1)], Energy::new(5.0, EnergyUnit::J));
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
#[test]
|
|
205
|
+
fn contraction_dimensions_must_match() {
|
|
206
|
+
let c = Array2::from_elem((2, 3), capacity(1.0));
|
|
207
|
+
let t = Array1::from_elem(2, Temperature::new(300.0, TemperatureUnit::K));
|
|
208
|
+
let tm = Array2::from_elem((2, 4), Temperature::new(300.0, TemperatureUnit::K));
|
|
209
|
+
assert!(std::panic::catch_unwind(|| QuantityDot::dot(&c.view(), &t.view())).is_err());
|
|
210
|
+
assert!(std::panic::catch_unwind(|| QuantityDot::dot(&c.view(), &tm.view())).is_err());
|
|
211
|
+
assert!(std::panic::catch_unwind(|| QuantityDot::dot(&c.row(0), &t.view())).is_err());
|
|
212
|
+
assert!(std::panic::catch_unwind(|| QuantityDot::dot(&c.row(0), &tm.view())).is_err());
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
#[test]
|
|
216
|
+
fn quantity_array_conversion() {
|
|
217
|
+
let c = Array2::<HeatCapacity>::from_raw(
|
|
218
|
+
arr2(&[[0.001, -0.002]]).view(),
|
|
219
|
+
HeatCapacityUnit::kJ_K,
|
|
220
|
+
);
|
|
221
|
+
close(c[(0, 0)], capacity(1.0));
|
|
222
|
+
close(c[(0, 1)], capacity(-2.0));
|
|
223
|
+
let v = Array1::<HeatCapacity>::from_raw(arr1(&[0.003]).view(), HeatCapacityUnit::kJ_K);
|
|
224
|
+
close(v[0], capacity(3.0));
|
|
225
|
+
}
|
|
226
|
+
}
|
|
@@ -11,6 +11,18 @@ from unitforge import (
|
|
|
11
11
|
ForceAreaUnit,
|
|
12
12
|
Force,
|
|
13
13
|
ForceUnit,
|
|
14
|
+
HeatCapacity,
|
|
15
|
+
HeatCapacityUnit,
|
|
16
|
+
Power,
|
|
17
|
+
Temperature,
|
|
18
|
+
TemperatureUnit,
|
|
19
|
+
ThermalConductance,
|
|
20
|
+
Time,
|
|
21
|
+
TimeUnit,
|
|
22
|
+
Volume,
|
|
23
|
+
VolumeUnit,
|
|
24
|
+
VolumetricHeatCapacity,
|
|
25
|
+
VolumetricHeatCapacityUnit,
|
|
14
26
|
Matrix3,
|
|
15
27
|
Moment,
|
|
16
28
|
MomentUnit,
|
|
@@ -25,6 +37,16 @@ force_scaled: Force = force * 2.0
|
|
|
25
37
|
force_ratio: float = force / Force(3.0, ForceUnit.N)
|
|
26
38
|
dynamic_product: Energy = force * distance
|
|
27
39
|
|
|
40
|
+
volumetric: VolumetricHeatCapacity = VolumetricHeatCapacity(2.0, VolumetricHeatCapacityUnit.kJ_mcbK)
|
|
41
|
+
volume: Volume = Volume(0.5, VolumeUnit.mcb)
|
|
42
|
+
capacity: HeatCapacity = volumetric * volume
|
|
43
|
+
capacity_in_kj: float = capacity.to(HeatCapacityUnit.kJ_K)
|
|
44
|
+
step: Time = Time(2.0, TimeUnit.s)
|
|
45
|
+
conductance: ThermalConductance = capacity / step
|
|
46
|
+
temperature: Temperature = Temperature(300.0, TemperatureUnit.K)
|
|
47
|
+
thermal_energy: Energy = capacity * temperature
|
|
48
|
+
heat_rate: Power = thermal_energy / step
|
|
49
|
+
|
|
28
50
|
vector: Vector3 = Vector3.from_list([1.0, 2.0, 3.0], ForceUnit.N)
|
|
29
51
|
vector_first: Any = vector[0]
|
|
30
52
|
vector_norm: Any = vector.norm()
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[package]
|
|
2
2
|
name = "unitforge_macros"
|
|
3
|
-
version = "0.5.
|
|
3
|
+
version = "0.5.11"
|
|
4
4
|
edition = "2021"
|
|
5
5
|
authors = ["Dr.Q team <info@askdrq.com>", "Henrik Stromberg <henrik@askdrq.com>"]
|
|
6
6
|
description = "Proc macros for generating units, quantities, and Python bindings in unitforge"
|