1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
//! A zero-dependency library for physics, mathematics and engineering
//! computation.
//!
//! # What this is for
//!
//! Every routine here is written so that something about it can be
//! *checked*: against a closed form, against a conservation law, against an
//! independent implementation of the same quantity, or against an exact
//! identity over integers. A test that only asserts a function ran is not
//! evidence. Where a result is approximate its error has a stated bound
//! derived from the method; where it is exact the assertion uses `==`.
//!
//! That principle decides the shape of the API. Solvers return
//! [`Result`] rather than panicking on non-convergence, so a caller can
//! tell "did not converge" from "converged to this". Functions validate
//! their arguments, and the guards are written `!(x > 0.0)` rather than
//! `x <= 0.0` so that NaN is rejected too. Physical constants come from
//! one table, [`math::constants`], and the values fixed by the 2019 SI
//! redefinition are exact.
//!
//! # Finding your way around
//!
//! The crate is wide -- 71 top-level modules. `docs/MODULE_MAP.md` in the
//! repository is a generated map of every module with its size and
//! summary. The rough shape:
//!
//! | Area | Modules |
//! |---|---|
//! | Numeric primitives | [`core`], [`math`], [`linalg`], [`numerical`], [`special`] |
//! | Exact and symbolic | [`exact`], [`discrete`], [`graph`], [`codes`] |
//! | Classical physics | [`classical`], [`gravitation`], [`solid_mechanics`], [`continuum_mechanics`], [`resonance`] |
//! | Thermal and statistical | [`thermodynamics`], [`statistical_mechanics`], [`radiation`] |
//! | Electromagnetic | [`electromagnetism`], [`electronics`], [`rf`], [`photonics`], [`plasma`], [`magnetohydrodynamics`] |
//! | Waves and signals | [`waves`], [`optics`], [`acoustics`], [`transforms`], [`dsp`], [`signal_processing`], [`audio`] |
//! | Fluids | [`fluids`], [`cfd`], [`fluid_instabilities`], [`propulsion`] |
//! | Modern physics | [`relativity`], [`general_relativity`], [`quantum`], [`particle_physics`], [`nuclear`], [`neutronics`] |
//! | Space | [`astrophysics`] |
//! | PDE solvers | [`fem`], [`sim`], [`fields`], [`vector_calculus`] |
//! | Life and chemistry | [`chemistry`], [`biophysics`] |
//! | Probability and data | [`statistics`], [`stochastic`], [`monte_carlo`], [`information_theory`], [`learn`] |
//! | Decisions | [`optimization`], [`finance`] |
//! | Geometry | [`geometry`], [`curves`], [`trigonometry`], [`quaternion`], [`manifold`], [`spatial`], [`mesh`] |
//! | Patterns | [`fractals`], [`patterns`], [`nonlinear`] |
//! | Reference and utility | [`units`], [`materials`], [`color_science`], [`control_systems`], [`atmosphere`], [`geophysics`], [`error`] |
//!
//! # Conventions
//!
//! **Units are SI** unless a function's documentation says otherwise, and
//! angles are radians. [`units`] converts, and [`units::quantity`] carries
//! dimensions in the type so that adding a velocity to a time is an error
//! rather than a number.
//!
//! **`f64` throughout**, except where exactness is the point: [`exact`]
//! works over arbitrary-precision integers and rationals, and
//! [`units::dimensional`] computes null spaces over
//! [`exact::rational::Rational`] because a group of quantities is exactly
//! dimensionless or it is not.
//!
//! **Randomness comes from [`monte_carlo::Rng`]**, a linear congruential
//! generator that returns its raw state. The low bits therefore have a
//! short period, so use [`monte_carlo::Rng::below`] for any small-integer
//! draw rather than `next_u64() % n`.
//!
//! # Example
//!
//! ```
//! use rust_physics_engine::units::quantity::{Dim, Quantity};
//!
//! let v = Quantity::new(3.0, Dim::new(1, 0, -1, 0, 0, 0, 0)); // m/s
//! let t = Quantity::new(2.0, Dim::TIME);
//! assert_eq!(v.mul(&t).unwrap().dim, Dim::LENGTH); // exactly a length
//! assert!(v.add(&t).is_err()); // and not a time
//! ```
// Style allowances for a numerics codebase: index loops mirror the math
// notation in matrix/stencil kernels, and public signatures follow the
// roadmap's frozen APIs even where clippy would prefer fewer arguments or
// simpler types.
// Argument guards use the negated form `!(x > 0.0)` on purpose: unlike
// `x <= 0.0`, it also rejects NaN inputs.