Crate funspace[−][src]
Expand description
Funspace
Collection of function spaces.
A function space is made up of elements of basis functions. Every function in the function space can be represented as a linear combination of basis functions, represented by real/complex coefficients (spectral space).
Implemented function spaces:
Chebyshev
(Orthogonal), seechebyshev()
ChebDirichlet
(Composite), seecheb_dirichlet()
ChebNeumann
(Composite), seecheb_neumann()
FourierC2c
(Orthogonal), seefourier_c2c()
FourierR2c
(Orthogonal), seefourier_r2c()
Transform
A transform describes a change from the physical space to the function
space. For example, a fourier transform describes a transform from
values of a function on a regular grid to coefficents of sine/cosine
polynomials. This is analogous to other function spaces. The transforms
are implemented by the Transform
trait.
Example
Apply forward transform of 1d array in cheb_dirichlet
space
use funspace::{Transform, cheb_dirichlet};
use ndarray::prelude::*;
use ndarray::Array1;
let mut cd = cheb_dirichlet::<f64>(5);
let mut input = array![1., 2., 3., 4., 5.];
let output: Array1<f64> = cd.forward(&mut input, 0);
Differentiation
One key advantage representing a function with coefficents in
the function space is its ease of differentiation. Differentiation in
fourier space becomes multiplication with the wavenumbe vector.
Differentiation in Chebyshev space is done by a recurrence
relation and almost as fast as in Fourier space.
Each base implements a differentiation method, which must be applied on
an array of coefficents. This is defined by the Differentiate
trait.
Example
Apply differentiation
use funspace::{Transform, Differentiate, Basics, fourier_r2c};
use ndarray::prelude::*;
use ndarray::Array1;
use num_complex::Complex;
// Define base
let mut fo = fourier_r2c(8);
// Get coordinates in physical space
let x = fo.coords().clone();
let mut v = x.mapv(|xi: f64| (2. * xi).sin());
// Transform to physical space
let vhat: Array1<Complex<f64>> = fo.forward(&mut v, 0);
// Apply differentiation twice along first axis
let mut dvhat = fo.differentiate(&vhat, 2, 0);
// Transform back to spectral space
let dv: Array1<f64> = fo.backward(&mut dvhat, 0);
// Compare with correct derivative
for (exp, ist) in x
.mapv(|xi: f64| -4. * (2. * xi).sin())
.iter()
.zip(dv.iter())
{
assert!((exp - ist).abs() < 1e-5);
}
Composite Bases
Bases like those of fourier polynomials or chebyshev polynomials are considered orthonormal bases, i.e. the dot product of each individual polynomial with any other of its set vanishes and the dot product with itself is unity. In these cases, the mass matrix is equal to the identity matrix. However, other function spaces can be constructed by a linearly combiningn the orthonormal basis functions. By doing so, one can construct bases which satisfy particular boundary conditions like dirichlet (zero at the ends) or neumann (zero derivative at the ends). This is usefull for solving partial differential equations. When expressed in those composite function space, the boundary condition is automatically satisfied. This is known as the Galerkin Method.
To switch from its composite form to the orthonormal form, each base implements
a FromOrtho
trait, which defines the transform to_ortho
and from_ortho
.
If the base is already orthogonal, the input will be returned, otherwise it
is transformed from the composite space to the orthonormal space.
Note that the size of the composite space is usually
less than its orthogonal counterpart. Therefore the output array must
not maintain the same shape (but its dimensionality is conserved).
Example
Transform composite space cheb_dirichlet
to its orthogonal counterpart
chebyshev
. Note that cheb_dirichlet
has 6 spectral coefficients,
while the chebyshev
bases has 8.
use funspace::{Transform, FromOrtho, Basics};
use funspace::{cheb_dirichlet, chebyshev};
use std::f64::consts::PI;
use ndarray::prelude::*;
use ndarray::Array1;
use num_complex::Complex;
// Define base
let mut ch = chebyshev(8);
let mut cd = cheb_dirichlet(8);
// Get coordinates in physical space
let x = ch.coords().clone();
let mut v = x.mapv(|xi: f64| (PI / 2. * xi).cos());
// Transform to physical space
let ch_vhat: Array1<f64> = ch.forward(&mut v, 0);
let cd_vhat: Array1<f64> = cd.forward(&mut v, 0);
// Send array to orthogonal space (cheb_dirichlet
// to chebyshev in this case)
let cd_vhat_ortho = cd.to_ortho(&cd_vhat, 0);
// Both arrays are equal, because field was
// initialized with correct boundary conditions,
// i.e. dirichlet ones
for (exp, ist) in ch_vhat.iter().zip(cd_vhat_ortho.iter()) {
assert!((exp - ist).abs() < 1e-5);
}
// However, if the physical field values do not
// satisfy dirichlet boundary conditions, they
// will be enforced by the transform to cheb_dirichle
// and ultimately the transformed values will deviate
// from a pure chebyshev transform (which does not)
// enfore the boundary conditions.
let mut v = x.mapv(|xi: f64| (PI / 2. * xi).sin());
let ch_vhat: Array1<f64> = ch.forward(&mut v, 0);
let cd_vhat: Array1<f64> = cd.forward(&mut v, 0);
let cd_vhat_ortho = cd.to_ortho(&cd_vhat, 0);
// They will deviate
println!("chebyshev : {:?}", ch_vhat);
println!("cheb_dirichlet: {:?}", cd_vhat_ortho);
Multidimensional Spaces
A collection of bases makes up a Space, on which one can again defines operations
along a specfic dimension (= axis). But special care must be taken in order to transform
a field from the physical space to the spectral space on how the transforms
are chained in a multidimensional space. Not all combinations are possible.
For example, cheb_dirichlet
is a real-to-real transform,
while fourier_r2c
defines a real-to-complex transform.
So, for a given real valued physical field, the chebyshev transform must be applied
before the fourier transform in the forward transform, and in opposite order in
the backward transform.
Note: Currently funspace
supports 1- 2- and 3 - dimensional spaces.
Example
Apply transform from physical to spectral in a two-dimensional space
use funspace::{fourier_r2c, cheb_dirichlet, Space2, BaseSpace};
use ndarray::prelude::*;
use std::f64::consts::PI;
use num_complex::Complex;
// Define the space and allocate arrays
let mut space = Space2::new(&fourier_r2c(5), &cheb_dirichlet(5));
let mut v: Array2<f64> = space.ndarray_physical();
// Set some field values
let x = space.coords_axis(0);
let y = space.coords_axis(1);
for (i,xi) in x.iter().enumerate() {
for (j,yi) in y.iter().enumerate() {
v[[i,j]] = xi.sin() * (PI/2.*yi).cos();
}
}
// Transform forward (vhat is complex)
let mut vhat = space.forward(&mut v);
// Transform backward (v is real)
let v = space.backward(&mut vhat);
Re-exports
pub use crate::enums::BaseAll;
pub use crate::enums::BaseC2c;
pub use crate::enums::BaseR2c;
pub use crate::enums::BaseR2r;
pub use crate::traits::Basics;
pub use crate::traits::Differentiate;
pub use crate::traits::DifferentiatePar;
pub use crate::traits::FromOrtho;
pub use crate::traits::FromOrthoPar;
pub use crate::traits::LaplacianInverse;
pub use crate::traits::Transform;
pub use crate::traits::TransformKind;
pub use crate::traits::TransformPar;
pub use space1::Space1;
pub use space2::Space2;
pub use space3::Space3;
pub use space_traits::BaseSpace;
pub use types::FloatNum;
pub use types::Scalar;
Modules
Function spaces of type Chebyshev
Inidividual enums for all bases who transform either real-to-real, real-to-complex or complex-to-complex plus a collective enum of enums, which combines these three types and which can be used to put all Bases in a single array.
Function spaces of type Fourier
One-dmensional space
Two-dmensional space
Three-dmensional space
Common traits for space, independent of dimensionality
Collection of usefull traits for function spaces
Collection of Types for funspace
Collection of general functions
Functions
Function space with Dirichlet boundary conditions
Functions space for inhomogeneous Dirichlet boundary conditions
Function space with Neumann boundary conditions
Functions space for inhomogeneous Neumann boundary conditions
Function space for Chebyshev Polynomials
Function space for Fourier Polynomials
Function space for Fourier Polynomials (Real-to-complex)