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
use ;
/// This trait allows us to pass vector valued functions `$\vec{f}(\vec{x},\alpha_1,...\alpha_N$)` in a generic fashion, where
///
/// * `$\vec{x}$` is an independent variable, like time, spatial coordinates and so on,
/// * `$\alpha_j$` are scalar parameter of this function
///
/// The functions must have at least one parameter argument additional ot the location parameter, i.e. a function
/// `$f(\vec{x})$` does not satisfy the trait, but e.g. `$f(\vec{x},\alpha_1)$` does. The function
/// must be vector valued and should produce a vector of the same size as `\vec{x}`. (If you want to
/// add this function to a model this is actually a requirement that will lead to errors, even panics
/// if violated).
/// Unfortunately, requirement on the length of the output vector cannot be enforced by the type system.
/// If it is violated, then calculations using the basis function will return errors in the [SeparableModel](crate::model::SeparableModel).
///
/// # Variadic Functions
///
/// Since Rust does not have variadic functions or generics, this trait is implemented for all functions up to
/// a maximum number of arguments. Right now this is implemented for up to 10 arguments.
///
/// # Generic Parameters
///
/// ## Scalar Type
///
/// The functions must have an interface `Fn(&DVector<ScalarType>,ScalarType)-> DVector<ScalarType>`,
/// `Fn(&DVector<ScalarType>,ScalarType,ScalarType)-> DVector<ScalarType>` and so on.
/// All numeric types, including the return value must be of the same scalar type.
///
/// ## ArgList : The argument list
///
/// This type is of no consequence for the user because it will be correctly inferred when
/// passing a function. It is a [nifty trick](https://geo-ant.github.io/blog/2021/rust-traits-and-variadic-functions/)
/// that allows us to implement this trait for functions taking different arguments. Just FYI: The
/// type reflects the list of parameters `\alpha_j$`, so that for a function `Fn(&DVector<ScalarType>,ScalarType) -> DVector<ScalarType>`
/// it follows that `ArgList=ScalarType`, while for `Fn(&DVector<ScalarType>,ScalarType)-> DVector<ScalarType>` it is `ArgList=(ScalarType,ScalarType)`.