1use std::collections::VecDeque;
2
3use crate::types::utils::integ_eval;
4use crate::types::utils::{check1d_data, check_if_inbounds};
5use crate::Accelerator;
6use crate::DomainError;
7use crate::InterpType;
8use crate::Interpolation;
9use crate::InterpolationError;
10
11const MIN_SIZE: usize = 5;
12
13#[doc(alias = "gsl_interp_akima")]
18pub struct Akima;
19
20impl<T> InterpType<T> for Akima
21where
22 T: crate::Num,
23{
24 type Interpolation = AkimaInterp<T>;
25
26 fn build(&self, xa: &[T], ya: &[T]) -> Result<AkimaInterp<T>, InterpolationError> {
41 check1d_data(xa, ya, MIN_SIZE)?;
42
43 let size = xa.len();
44 let two = T::from(2.0).unwrap();
45 let three = T::from(3.0).unwrap();
46
47 let mut m = VecDeque::<T>::with_capacity(size);
49 for i in 0..=size - 2 {
50 m.push_back((ya[i + 1] - ya[i]) / (xa[i + 1] - xa[i]));
51 }
52
53 m.push_front(two * m[0] - m[1]);
55 m.push_front(three * m[1] - two * m[2]);
56 m.push_back(two * m[size] - m[size - 1]);
57 m.push_back(three * m[size] - two * m[size - 1]);
58 let m = m.make_contiguous().to_vec();
59
60 let (b, c, d) = akima_calc(xa, &m);
61
62 let state = AkimaInterp { b, c, d, m };
63 Ok(state)
64 }
65
66 fn name(&self) -> &str {
67 "Akima"
68 }
69
70 fn min_size(&self) -> usize {
71 MIN_SIZE
72 }
73}
74
75#[allow(dead_code)]
83#[doc(alias = "gsl_akima_interp")]
84pub struct AkimaInterp<T>
85where
86 T: crate::Num,
87{
88 b: Vec<T>,
89 c: Vec<T>,
90 d: Vec<T>,
91 m: Vec<T>,
92}
93
94impl<T> Interpolation<T> for AkimaInterp<T>
95where
96 T: crate::Num,
97{
98 fn eval(&self, xa: &[T], ya: &[T], x: T, acc: &mut Accelerator) -> Result<T, DomainError> {
99 akima_eval(xa, ya, (&self.b, &self.c, &self.d), x, acc)
100 }
101
102 #[allow(unused_variables)]
103 fn eval_deriv(
104 &self,
105 xa: &[T],
106 ya: &[T],
107 x: T,
108 acc: &mut Accelerator,
109 ) -> Result<T, DomainError> {
110 akima_eval_deriv(xa, (&self.b, &self.c, &self.d), x, acc)
111 }
112
113 #[allow(unused_variables)]
114 fn eval_deriv2(
115 &self,
116 xa: &[T],
117 ya: &[T],
118 x: T,
119 acc: &mut Accelerator,
120 ) -> Result<T, DomainError> {
121 akima_eval_deriv2(xa, (&self.c, &self.d), x, acc)
122 }
123
124 fn eval_integ(
125 &self,
126 xa: &[T],
127 ya: &[T],
128 a: T,
129 b: T,
130 acc: &mut Accelerator,
131 ) -> Result<T, DomainError> {
132 akima_eval_integ(xa, ya, (&self.b, &self.c, &self.d), a, b, acc)
133 }
134}
135
136pub struct AkimaPeriodic;
143
144impl<T> InterpType<T> for AkimaPeriodic
145where
146 T: crate::Num,
147{
148 type Interpolation = AkimaPeriodicInterp<T>;
149
150 fn build(&self, xa: &[T], ya: &[T]) -> Result<AkimaPeriodicInterp<T>, InterpolationError> {
165 check1d_data(xa, ya, MIN_SIZE)?;
166
167 let size = xa.len();
168
169 let mut m = VecDeque::<T>::with_capacity(size + 3);
171 for i in 0..=size - 2 {
172 m.push_back((ya[i + 1] - ya[i]) / (xa[i + 1] - xa[i]));
173 }
174
175 m.push_front(m[size - 1 - 1]);
177 m.push_front(m[size - 1 - 1]);
178 m.push_back(m[2]);
179 m.push_back(m[3]);
180 let m = m.make_contiguous().to_vec();
181
182 let (b, c, d) = akima_calc(xa, &m);
183
184 let state = AkimaPeriodicInterp { b, c, d, m };
185 Ok(state)
186 }
187
188 fn name(&self) -> &str {
189 "Akima Periodic"
190 }
191
192 fn min_size(&self) -> usize {
193 MIN_SIZE
194 }
195}
196
197#[allow(dead_code)]
205#[doc(alias = "gsl_interp_akima_periodic")]
206pub struct AkimaPeriodicInterp<T>
207where
208 T: crate::Num,
209{
210 c: Vec<T>,
211 b: Vec<T>,
212 d: Vec<T>,
213 m: Vec<T>,
214}
215
216impl<T> Interpolation<T> for AkimaPeriodicInterp<T>
217where
218 T: crate::Num,
219{
220 fn eval(&self, xa: &[T], ya: &[T], x: T, acc: &mut Accelerator) -> Result<T, DomainError> {
221 akima_eval(xa, ya, (&self.b, &self.c, &self.d), x, acc)
222 }
223
224 #[allow(unused_variables)]
225 fn eval_deriv(
226 &self,
227 xa: &[T],
228 ya: &[T],
229 x: T,
230 acc: &mut Accelerator,
231 ) -> Result<T, DomainError> {
232 akima_eval_deriv(xa, (&self.b, &self.c, &self.d), x, acc)
233 }
234
235 #[allow(unused_variables)]
236 fn eval_deriv2(
237 &self,
238 xa: &[T],
239 ya: &[T],
240 x: T,
241 acc: &mut Accelerator,
242 ) -> Result<T, DomainError> {
243 akima_eval_deriv2(xa, (&self.c, &self.d), x, acc)
244 }
245
246 fn eval_integ(
247 &self,
248 xa: &[T],
249 ya: &[T],
250 a: T,
251 b: T,
252 acc: &mut Accelerator,
253 ) -> Result<T, DomainError> {
254 akima_eval_integ(xa, ya, (&self.b, &self.c, &self.d), a, b, acc)
255 }
256}
257
258fn akima_eval<T>(
261 xa: &[T],
262 ya: &[T],
263 state: (&[T], &[T], &[T]),
264 x: T,
265 acc: &mut Accelerator,
266) -> Result<T, DomainError>
267where
268 T: crate::Num,
269{
270 check_if_inbounds(xa, x)?;
271 let index = acc.find(xa, x);
272
273 let xlo = xa[index];
274 let delx = x - xlo;
275 let b = state.0[index];
276 let c = state.1[index];
277 let d = state.2[index];
278
279 Ok(ya[index] + delx * (b + delx * (c + d * delx)))
280}
281
282fn akima_eval_deriv<T>(
283 xa: &[T],
284 state: (&[T], &[T], &[T]),
285 x: T,
286 acc: &mut Accelerator,
287) -> Result<T, DomainError>
288where
289 T: crate::Num,
290{
291 check_if_inbounds(xa, x)?;
292 let two = T::from(2).unwrap();
293 let three = T::from(3).unwrap();
294
295 let index = acc.find(xa, x);
296
297 let xlo = xa[index];
298 let delx = x - xlo;
299 let b = state.0[index];
300 let c = state.1[index];
301 let d = state.2[index];
302
303 Ok(b + delx * (two * c + three * d * delx))
304}
305
306#[inline(always)]
307fn akima_eval_deriv2<T>(
308 xa: &[T],
309 state: (&[T], &[T]),
310 x: T,
311 acc: &mut Accelerator,
312) -> Result<T, DomainError>
313where
314 T: crate::Num,
315{
316 check_if_inbounds(xa, x)?;
317 let two = T::from(2).unwrap();
318 let six = T::from(6).unwrap();
319
320 let index = acc.find(xa, x);
321
322 let xlo = xa[index];
323 let delx = x - xlo;
324 let c = state.0[index];
325 let d = state.1[index];
326
327 Ok(two * c + six * d * delx)
328}
329
330fn akima_eval_integ<T>(
331 xa: &[T],
332 ya: &[T],
333 state: (&[T], &[T], &[T]),
334 a: T,
335 b: T,
336 acc: &mut Accelerator,
337) -> Result<T, DomainError>
338where
339 T: crate::Num,
340{
341 check_if_inbounds(xa, a)?;
342 check_if_inbounds(xa, b)?;
343 let index_a = acc.find(xa, a);
344 let index_b = acc.find(xa, b);
345 let bs = state.0;
346 let cs = state.1;
347 let ds = state.2;
348
349 let quarter = T::from(0.25).unwrap();
350 let half = T::from(0.5).unwrap();
351 let third = T::from(1.0 / 3.0).unwrap();
352 let mut result = T::zero();
353
354 for i in index_a..=index_b {
355 let xlo = xa[i];
356 let xhi = xa[i + 1];
357 let ylo = ya[i];
358
359 let dx = xhi - xlo;
360
361 if dx.is_zero() {
363 continue;
364 }
365
366 if (i == index_a) | (i == index_b) {
367 let x1 = if i == index_a { a } else { xlo };
368 let x2 = if i == index_b { b } else { xhi };
369 result += integ_eval(ylo, bs[i], cs[i], ds[i], xlo, x1, x2);
370 } else {
371 result += dx * (ylo + dx * (half * bs[i] + dx * (third * cs[i] + quarter * ds[i] * dx)))
372 }
373 }
374 Ok(result)
375}
376
377fn akima_calc<T>(xa: &[T], m: &[T]) -> (Vec<T>, Vec<T>, Vec<T>)
379where
380 T: crate::Num,
381{
382 let size = xa.len();
383 let two = T::from(2.0).unwrap();
384 let three = T::from(3.0).unwrap();
385 let mut b = Vec::<T>::with_capacity(size - 1);
386 let mut c = Vec::<T>::with_capacity(size - 1);
387 let mut d = Vec::<T>::with_capacity(size - 1);
388
389 for i in 0..size - 1 {
390 let ne = (m[i + 3] - m[i + 2]).abs() + (m[i + 1] - m[i]).abs();
391 if ne.is_zero() {
392 b.push(m[i + 2]);
393 c.push(T::zero());
394 d.push(T::zero());
395 } else {
396 let hi = xa[i + 1] - xa[i];
397 let nenext = (m[i + 4] - m[i + 3]).abs() + (m[i + 2] - m[i + 1]).abs();
398 let ai = (m[i + 1] - m[i]).abs() / ne;
399 let ai_plus1: T;
400 let tli_plus1: T;
401 if nenext.is_zero() {
402 tli_plus1 = m[i + 2];
403 } else {
404 ai_plus1 = (m[i + 2] - m[i + 1]).abs() / nenext;
405 tli_plus1 = (T::one() - ai_plus1) * m[i + 2] + ai_plus1 * m[i + 3];
406 }
407 b.push((T::one() - ai) * m[i + 1] + ai * m[i + 2]);
408 c.push((three * m[i + 2] - two * b[i] - tli_plus1) / hi);
409 d.push((b[i] + tli_plus1 - two * m[i + 2]) / hi.powi(2));
410 }
411 }
412 (b, c, d)
413}