1use ndarray::{Array1, Array2, ArrayView1, ArrayView2};
2use num_traits::{FromPrimitive, Zero};
3use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
4
5#[macro_export]
6macro_rules! power {
7 ($x:expr, 1) => {
8 $x
9 };
10 ($x:expr, 2) => {
11 $x * $x
12 };
13 ($x:expr, 3) => {
14 $x * $x * $x
15 };
16 ($x:expr, 4) => {
17 $x * $x * $x * $x
18 };
19 ($x:expr, 5) => {
20 $x * $x * $x * $x * $x
21 };
22 ($x:expr, 6) => {
23 $x * $x * $x * $x * $x * $x
24 };
25}
26
27pub trait MulArray1<RHS> {
28 type Output;
29
30 fn mul_array1(self, rhs: Array1<RHS>) -> Self::Output;
31}
32
33pub trait MulArray2<RHS> {
34 type Output;
35
36 fn mul_array2(self, rhs: Array2<RHS>) -> Result<Self::Output, String>;
37}
38
39pub trait DivArray1<RHS> {
40 type Output;
41
42 fn div_array1(self, rhs: Array1<RHS>) -> Self::Output;
43}
44
45pub trait DivArray2<RHS> {
46 type Output;
47
48 fn div_array2(self, rhs: Array2<RHS>) -> Result<Self::Output, String>;
49}
50
51pub trait QuantityArray2<T> {
52 fn from_raw(raw: ArrayView2<f64>, unit: T) -> Self;
53 fn to_raw(&self) -> Array2<f64>;
54 fn to(&self, unit: T) -> Array2<f64>;
55}
56
57pub trait QuantityArray1<T> {
58 fn from_raw(raw: ArrayView1<f64>, unit: T) -> Self;
59 fn to_raw(&self) -> Array1<f64>;
60 fn to(&self, unit: T) -> Array1<f64>;
61}
62
63pub trait PhysicsQuantity:
64 Copy
65 + FromPrimitive
66 + Zero
67 + Add<Output = Self>
68 + AddAssign
69 + Div<f64, Output = Self>
70 + DivAssign<f64>
71 + Mul<f64, Output = Self>
72 + MulAssign<f64>
73 + Sub<Output = Self>
74 + SubAssign
75 + PartialOrd
76 + Neg<Output = Self>
77 + From<f64>
78{
79 fn as_f64(&self) -> f64;
80 type Unit: PhysicsUnit;
81 fn new(value: f64, unit: Self::Unit) -> Self;
82 fn to(&self, unit: Self::Unit) -> f64;
83 fn zero() -> Self;
84 fn get_tuple(&self) -> (f64, i32);
85 fn abs(self) -> Self;
86 fn from_raw(value: f64) -> Self;
87 fn from_exponential(multiplier: f64, power: i32) -> Self;
88 fn min(self, other: Self) -> Self;
89 fn max(self, other: Self) -> Self;
90 #[deprecated(since = "0.2.9", note = "please use `as_f64()` instead")]
91 fn to_raw(&self) -> f64 {
92 self.as_f64()
93 }
94 #[deprecated(since = "0.2.9", note = "please use `as_f64()` instead")]
95 fn get_value(&self) -> f64 {
96 self.as_f64()
97 }
98 fn get_power(&self) -> i32;
99 fn get_multiplier(&self) -> f64;
100 fn split_value(v: f64) -> (f64, i32);
101 fn is_close(&self, other: &Self, tolerance: &Self) -> bool;
102 fn optimize(&mut self);
103 const INFINITY: Self;
104 const NEG_INFINITY: Self;
105}
106
107pub trait Sqrt<T> {
108 fn sqrt(self) -> T;
109}
110
111impl PhysicsQuantity for f64 {
112 fn as_f64(&self) -> f64 {
113 *self
114 }
115
116 type Unit = NoUnit;
117
118 fn new(value: f64, _unit: Self::Unit) -> Self {
119 value
120 }
121
122 fn to(&self, _unit: Self::Unit) -> f64 {
123 self.as_f64()
124 }
125
126 fn zero() -> Self {
127 0.
128 }
129
130 fn get_tuple(&self) -> (f64, i32) {
131 (self.get_multiplier(), self.get_power())
132 }
133
134 fn abs(self) -> Self {
135 self.abs()
136 }
137
138 fn from_raw(value: f64) -> Self {
139 value
140 }
141
142 fn from_exponential(multiplier: f64, power: i32) -> Self {
143 multiplier * 10_f64.powi(power)
144 }
145
146 fn min(self, other: Self) -> Self {
147 if self < other {
148 self
149 } else {
150 other
151 }
152 }
153
154 fn max(self, other: Self) -> Self {
155 if self > other {
156 self
157 } else {
158 other
159 }
160 }
161 fn get_power(&self) -> i32 {
162 0
163 }
164
165 fn get_multiplier(&self) -> f64 {
166 *self
167 }
168
169 fn split_value(v: f64) -> (f64, i32) {
170 let power = v.abs().log10().floor() as i32;
171 let multiplier = v / 10f64.powi(power);
172 (multiplier, power)
173 }
174
175 fn is_close(&self, other: &Self, tolerance: &Self) -> bool {
176 (self - other).abs() < (*tolerance)
177 }
178
179 fn optimize(&mut self) {}
180
181 const INFINITY: Self = f64::INFINITY;
182 const NEG_INFINITY: Self = f64::NEG_INFINITY;
183}
184pub use crate::power;
185
186pub trait PhysicsUnit {
187 fn name(&self) -> &str;
188 fn base_per_x(&self) -> (f64, i32);
189}
190
191pub enum NoUnit {
192 no_unit,
193}
194
195impl PhysicsUnit for NoUnit {
196 fn name(&self) -> &str {
197 ""
198 }
199
200 fn base_per_x(&self) -> (f64, i32) {
201 (1., 0)
202 }
203}