rsl_interpolation/types/
steffen.rs1use crate::Accelerator;
2use crate::DomainError;
3use crate::InterpType;
4use crate::Interpolation;
5use crate::InterpolationError;
6use crate::types::utils::{check_if_inbounds, check1d_data};
7
8const MIN_SIZE: usize = 3;
9
10pub struct Steffen;
18
19impl<T> InterpType<T> for Steffen
20where
21 T: crate::Num,
22{
23 type Interpolation = SteffenInterp<T>;
24
25 fn build(&self, xa: &[T], ya: &[T]) -> Result<SteffenInterp<T>, InterpolationError> {
40 check1d_data(xa, ya, MIN_SIZE)?;
41 let size = xa.len();
42
43 let h0 = xa[1] - xa[0];
46 let s0 = (ya[1] - ya[0]) / h0;
47
48 let mut y_prime = Vec::<T>::with_capacity(size);
50 y_prime.push(s0);
51
52 let one = T::one();
55 let half = T::from(0.5).unwrap();
56
57 for i in 1..(size - 1) {
58 let hi = xa[i + 1] - xa[i];
60 let him1 = xa[i] - xa[i - 1];
61
62 let si = (ya[i + 1] - ya[i]) / hi;
64 let sim1 = (ya[i] - ya[i - 1]) / him1;
65
66 let pi = (sim1 * hi + si * him1) / (him1 + hi);
68
69 let min1 = si.abs().min(half * pi.abs());
70 let min2 = sim1.abs().min(min1);
71 y_prime.push((steffen_copysign(one, sim1) + steffen_copysign(one, si)) * min2);
72 }
73
74 y_prime.push((ya[size - 1] - ya[size - 2]) / (xa[size - 1] - xa[size - 2]));
79
80 let mut a = Vec::<T>::with_capacity(size - 1);
82 let mut b = Vec::<T>::with_capacity(size - 1);
83 let mut c = Vec::<T>::with_capacity(size - 1);
84 let mut d = Vec::<T>::with_capacity(size - 1);
85
86 let two = T::from(2.0).unwrap();
87 let three = T::from(3.0).unwrap();
88 for i in 0..(size - 1) {
89 let hi = xa[i + 1] - xa[i];
90 let si = (ya[i + 1] - ya[i]) / hi;
91
92 a.push((y_prime[i] + y_prime[i + 1] - two * si) / hi.powi(2));
94 b.push((three * si - two * y_prime[i] - y_prime[i + 1]) / hi);
95 c.push(y_prime[i]);
96 d.push(ya[i]);
97 }
98
99 let state = SteffenInterp {
100 a,
101 b,
102 c,
103 d,
104 y_prime,
105 };
106
107 Ok(state)
108 }
109
110 fn name(&self) -> &str {
111 "Steffen"
112 }
113
114 fn min_size(&self) -> usize {
115 MIN_SIZE
116 }
117}
118
119#[allow(dead_code)]
127pub struct SteffenInterp<T>
128where
129 T: crate::Num,
130{
131 a: Vec<T>,
132 b: Vec<T>,
133 c: Vec<T>,
134 d: Vec<T>,
135 y_prime: Vec<T>,
136}
137
138impl<T> Interpolation<T> for SteffenInterp<T>
139where
140 T: crate::Num,
141{
142 #[allow(unused_variables)]
143 fn eval(&self, xa: &[T], ya: &[T], x: T, acc: &mut Accelerator) -> Result<T, DomainError> {
144 check_if_inbounds(xa, x)?;
145 let index = acc.find(xa, x);
146
147 let xlo = xa[index];
148 let delx = x - xlo;
149 let a = self.a[index];
150 let b = self.b[index];
151 let c = self.c[index];
152 let d = self.d[index];
153
154 Ok(d + delx * (c + delx * (b + delx * a)))
155 }
156
157 #[allow(unused_variables)]
158 fn eval_deriv(
159 &self,
160 xa: &[T],
161 ya: &[T],
162 x: T,
163 acc: &mut Accelerator,
164 ) -> Result<T, DomainError> {
165 check_if_inbounds(xa, x)?;
166 let index = acc.find(xa, x);
167
168 let xlo = xa[index];
169 let delx = x - xlo;
170 let a = self.a[index];
171 let b = self.b[index];
172 let c = self.c[index];
173
174 let two = T::from(2.0).unwrap();
175 let three = T::from(3.0).unwrap();
176
177 Ok(c + delx * (two * b + delx * three * a))
178 }
179
180 #[allow(unused_variables)]
181 fn eval_deriv2(
182 &self,
183 xa: &[T],
184 ya: &[T],
185 x: T,
186 acc: &mut Accelerator,
187 ) -> Result<T, DomainError> {
188 check_if_inbounds(xa, x)?;
189 let index = acc.find(xa, x);
190
191 let xlo = xa[index];
192 let delx = x - xlo;
193 let a = self.a[index];
194 let b = self.b[index];
195
196 let two = T::from(2.0).unwrap();
197 let six = T::from(6.0).unwrap();
198
199 Ok(six * delx * a + two * b)
200 }
201
202 #[allow(unused_variables)]
203 fn eval_integ(
204 &self,
205 xa: &[T],
206 ya: &[T],
207 a: T,
208 b: T,
209 acc: &mut Accelerator,
210 ) -> Result<T, DomainError> {
211 check_if_inbounds(xa, a)?;
212 check_if_inbounds(xa, b)?;
213 let index_a = acc.find(xa, a);
214 let index_b = acc.find(xa, b);
215
216 let quarter = T::from(0.25).unwrap();
217 let half = T::from(0.5).unwrap();
218 let third = T::from(1.0 / 3.0).unwrap();
219 let mut result = T::zero();
220
221 for i in index_a..=index_b {
222 let xlo = xa[i];
223 let xhi = xa[i + 1];
224
225 let dx = xhi - xlo;
226
227 if dx.is_zero() {
229 continue;
230 }
231
232 let x1 = if i == index_a { a - xlo } else { T::zero() };
233 let x2 = if i == index_b { b - xlo } else { xhi - xlo };
234
235 let x12 = x1.powi(2);
236 let x22 = x2.powi(2);
237
238 result += quarter * self.a[i] * (x22.powi(2) - x12.powi(2));
239 result += third * self.b[i] * (x22 * x2 - x12 * x1);
240 result += half * self.c[i] * (x22 - x12);
241 result += self.d[i] * (x2 - x1);
242 }
243
244 Ok(result)
245 }
246}
247
248fn steffen_copysign<T>(x: T, y: T) -> T
249where
250 T: crate::Num,
251{
252 if (x.is_sign_negative() & y.is_sign_positive()) | (x.is_sign_positive() & y.is_sign_negative())
253 {
254 -x
255 } else {
256 x
257 }
258}