sgrust 0.8.6

A sparse grid library written in Rust.
Documentation
use serde::{Deserialize, Serialize};

use crate::basis::gauss_legendre::GaussLegendre;

use super::{base::Basis, clenshaw_curtis::ClenshawCurtis, custom_nested::CustomNested, gauss_patterson::GaussPatterson, linear::LinearBasis};

#[derive(Serialize, Deserialize)]
#[derive(Hash, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
#[repr(u8)]
#[cfg_attr(feature = "rkyv", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
pub enum GlobalBasisType
{
    Linear = 0,
    ClenshawCurtis = 1,
    GaussPatterson = 2,
    CustomBasis = 3,
    GaussLegendre = 4,
}

#[derive(Serialize, Deserialize)]
#[derive(Clone)]
#[cfg_attr(feature = "rkyv", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
pub struct GlobalBasis
{
    pub basis_type: GlobalBasisType,
    pub custom_rule: Option<CustomNested>,
}
impl GlobalBasis
{
    pub fn new(basis_type: GlobalBasisType) -> Self
    {
        Self { basis_type, custom_rule: None }
    }
}
impl From<GlobalBasisType> for GlobalBasis
{
    fn from(value: GlobalBasisType) -> Self {
        GlobalBasis { basis_type: value, custom_rule: None }
    }
}
impl Basis for GlobalBasis
{
    fn eval(&self, level: u32, index: u32, x: f64) -> f64 {
        match self.basis_type
        {
            GlobalBasisType::Linear => LinearBasis.eval(level, index, x),
            GlobalBasisType::ClenshawCurtis => ClenshawCurtis.eval(level, index, x),
            GlobalBasisType::GaussPatterson => GaussPatterson.eval(level, index, x),
            GlobalBasisType::GaussLegendre => GaussLegendre.eval(level, index, x),
            GlobalBasisType::CustomBasis => if let Some(rule) = &self.custom_rule
            {
                rule.eval(level, index, x)
            }
            else
            {
                panic!("CustomBasis selected but no rule defined.")
            },
        }
    }

    fn eval_deriv(&self, level: u32, index: u32, x: f64) -> f64 {
        match self.basis_type
        {
            GlobalBasisType::Linear => LinearBasis.eval_deriv(level, index, x),
            GlobalBasisType::ClenshawCurtis => ClenshawCurtis.eval_deriv(level, index, x),
            GlobalBasisType::GaussPatterson => GaussPatterson.eval_deriv(level, index, x),
            GlobalBasisType::GaussLegendre => GaussLegendre.eval_deriv(level, index, x),
            GlobalBasisType::CustomBasis => if let Some(rule) = &self.custom_rule
            {
                rule.eval_deriv(level, index, x)
            }
            else
            {
                panic!("CustomBasis selected but no rule defined.")
            },
        }
    }

    fn degree(&self) -> usize {
        match self.basis_type
        {
            GlobalBasisType::Linear => LinearBasis.degree(),
            GlobalBasisType::ClenshawCurtis => ClenshawCurtis.degree(),
            GlobalBasisType::GaussPatterson => GaussPatterson.degree(),
            GlobalBasisType::GaussLegendre => GaussLegendre.degree(),
            GlobalBasisType::CustomBasis => if let Some(rule) = &self.custom_rule
            {
                rule.degree()
            }
            else
            {
                panic!("CustomBasis selected but no rule defined.")
            },
        }
    }

    fn integral(&self, level: u32, index: u32) -> f64 {
        match self.basis_type
        {
            GlobalBasisType::Linear => LinearBasis.integral(level, index),
            GlobalBasisType::ClenshawCurtis => ClenshawCurtis.integral(level, index),
            GlobalBasisType::GaussPatterson => GaussPatterson.integral(level, index),
            GlobalBasisType::GaussLegendre => GaussLegendre.integral(level, index),
            GlobalBasisType::CustomBasis => if let Some(rule) = &self.custom_rule
            {
                rule.integral(level, index)
            }
            else
            {
                panic!("CustomBasis selected but no rule defined.")
            },
        }
    }

    fn basis_type(&self) -> crate::basis::base::BasisFunction {
        match self.basis_type
        {
            GlobalBasisType::Linear => LinearBasis.basis_type(),
            GlobalBasisType::ClenshawCurtis => ClenshawCurtis.basis_type(),
            GlobalBasisType::GaussPatterson => GaussPatterson.basis_type(),
            GlobalBasisType::GaussLegendre => GaussLegendre.basis_type(),
            GlobalBasisType::CustomBasis => if let Some(rule) = &self.custom_rule
            {
                rule.basis_type()
            }
            else
            {
                panic!("CustomBasis selected but no rule defined.")
            },
        }
    }

    fn node(&self, level: u32, index: u32) -> f64 {
        match self.basis_type
        {
            GlobalBasisType::Linear => LinearBasis.node(level, index),
            GlobalBasisType::ClenshawCurtis => ClenshawCurtis.node(level, index),
            GlobalBasisType::GaussPatterson => GaussPatterson.node(level, index),
            GlobalBasisType::GaussLegendre => GaussLegendre.node(level, index),
            GlobalBasisType::CustomBasis => if let Some(rule) = &self.custom_rule
            {
                rule.node(level, index)
            }
            else
            {
                panic!("CustomBasis selected but no rule defined.")
            },
        }
    }

    fn num_nodes(&self, level: u32) -> usize {
        match self.basis_type
        {
            GlobalBasisType::Linear => LinearBasis.num_nodes(level),
            GlobalBasisType::ClenshawCurtis => ClenshawCurtis.num_nodes(level),
            GlobalBasisType::GaussPatterson => GaussPatterson.num_nodes(level),
            GlobalBasisType::GaussLegendre => GaussLegendre.num_nodes(level),
            GlobalBasisType::CustomBasis => if let Some(rule) = &self.custom_rule
            {
                rule.num_nodes(level)
            }
            else
            {
                panic!("CustomBasis selected but no rule defined.")
            },
        }
    }

    fn get_point(&self, level: u32, index: u32) -> f64 {
        match self.basis_type
        {
            GlobalBasisType::Linear => LinearBasis.get_point(level, index),
            GlobalBasisType::ClenshawCurtis => ClenshawCurtis.get_point(level, index),
            GlobalBasisType::GaussPatterson => GaussPatterson.get_point(level, index),
            GlobalBasisType::GaussLegendre => GaussLegendre.get_point(level, index),
            GlobalBasisType::CustomBasis => if let Some(rule) = &self.custom_rule
            {
                rule.get_point(level, index)
            }
            else
            {
                panic!("CustomBasis selected but no rule defined.")
            },
        }
    }

    fn weights(&self, level: u32) -> Vec<f64> {
        match self.basis_type
        {
            GlobalBasisType::Linear => LinearBasis.weights(level),
            GlobalBasisType::ClenshawCurtis => ClenshawCurtis.weights(level),
            GlobalBasisType::GaussPatterson => GaussPatterson.weights(level),
            GlobalBasisType::GaussLegendre => GaussLegendre.weights(level),
            GlobalBasisType::CustomBasis => if let Some(rule) = &self.custom_rule
            {
                rule.weights(level)
            }
            else
            {
                panic!("CustomBasis selected but no rule defined.")
            },
        }
    }

    fn nodes(&self, level: u32) -> Vec<f64> {
        match self.basis_type
        {
            GlobalBasisType::Linear => LinearBasis.nodes(level),
            GlobalBasisType::ClenshawCurtis => ClenshawCurtis.nodes(level),
            GlobalBasisType::GaussPatterson => GaussPatterson.nodes(level),
            GlobalBasisType::GaussLegendre => GaussLegendre.nodes(level),
            GlobalBasisType::CustomBasis => if let Some(rule) = &self.custom_rule
            {
                rule.nodes(level)
            }
            else
            {
                panic!("CustomBasis selected but no rule defined.")
            },
        }
    }
    
    fn quadrature_exactness(&self, level: u32) -> u32 {
        match self.basis_type
        {
            GlobalBasisType::Linear => LinearBasis.quadrature_exactness(level),
            GlobalBasisType::ClenshawCurtis => ClenshawCurtis.quadrature_exactness(level),
            GlobalBasisType::GaussPatterson => GaussPatterson.quadrature_exactness(level),
            GlobalBasisType::GaussLegendre => GaussLegendre.quadrature_exactness(level),
            GlobalBasisType::CustomBasis => if let Some(rule) = &self.custom_rule
            {
                rule.quadrature_exactness(level)
            }
            else
            {
                panic!("CustomBasis selected but no rule defined.")
            },
        }
    }

    fn interpolation_exactness(&self, level: u32) -> u32 {
        match self.basis_type
        {
            GlobalBasisType::Linear => LinearBasis.interpolation_exactness(level),
            GlobalBasisType::ClenshawCurtis => ClenshawCurtis.interpolation_exactness(level),
            GlobalBasisType::GaussPatterson => GaussPatterson.interpolation_exactness(level),
            GlobalBasisType::GaussLegendre => GaussLegendre.interpolation_exactness(level),
            GlobalBasisType::CustomBasis => if let Some(rule) = &self.custom_rule
            {
                rule.interpolation_exactness(level)
            }
            else
            {
                panic!("CustomBasis selected but no rule defined.")
            },
        }
    }
}