sgrust 0.8.6

A sparse grid library written in Rust.
Documentation
use std::sync::LazyLock;

use super::base::Basis;

static CC_MAX_LEVEL: u32 = 12;
use crate::tables::clenshaw_curtis_table::*;

#[derive(Clone)]
pub struct ClenshawCurtisCache{ nodes: Vec<Vec<f64>>, weights: Vec<Vec<f64>>}

impl ClenshawCurtisCache
{
    pub fn new(max_level: u32) -> Self
    {        
        let mut nodes = Vec::new();
        let mut weights = Vec::new();
        for level in 0..=max_level
        {
            nodes.push(cc_nodes(level));
            weights.push(cc_weights(level));
        }        
        Self{ nodes, weights}
    }
    pub(crate) fn node(&self, level: u32, index: u32) -> f64
    {
        if level <= CC_MAX_LEVEL
        {
            CC_CACHE.nodes[level as usize][index as usize]
        }
        else
        {
            cc_nodes(level)[index as usize]
        }
    }

    pub fn len(&self) -> usize
    {
        self.nodes.len()
    }

    #[must_use]
    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }
    pub fn weight(&self, level: u32, index: u32) -> f64
    {
        if level <= CC_MAX_LEVEL
        {
            CC_CACHE.weights[level as usize][index as usize]
        }
        else
        {
            cc_weights(level)[index as usize]
        }
    }
    pub fn weights_for_level(&self, level: u32) -> Vec<f64>
    {
        if level <= CC_MAX_LEVEL
        {
            CC_CACHE.weights[level as usize].clone()
        }
        else
        {
            cc_weights(level)
        }
    }

    pub fn nodes_for_level(&self, level: u32) -> Vec<f64>
    {
        if level <= CC_MAX_LEVEL
        {
            CC_CACHE.nodes[level as usize].clone()
        }
        else
        {
            cc_nodes(level)            
        }
    }
}

pub(crate) static CC_CACHE: LazyLock<ClenshawCurtisCache> = LazyLock::new(|| ClenshawCurtisCache::new(CC_MAX_LEVEL));

#[derive(Clone, Copy)]
pub struct ClenshawCurtis;

impl Basis for ClenshawCurtis
{
    fn eval(&self, level: u32, index: u32, x: f64) -> f64 {
        let xl = CC_CACHE.node(level, index  - 1);        
        let xr = CC_CACHE.node(level, index + 1);
        let xm = CC_CACHE.node(level, index);
        if x < xm
        {
            f64::max(0.0, 1.0-(xm-x)/(xm-xl))
        }
        else
        {
            f64::max(0.0, (xr-x)/(xr-xm))
        }
    }
    fn get_point(&self, level: u32, index: u32) -> f64
    {
        CC_CACHE.node(level, index)
    }

    fn eval_deriv(&self, _level: u32, _index: u32, _x: f64) -> f64 {
        panic!("Derivative not implemented for CurtisClenshaw Basis.")
    }

    fn degree(&self) -> usize {
        1
    }

    fn integral(&self, level: u32, index: u32) -> f64 {
        CC_CACHE.weight(level, index)
    }

    fn basis_type(&self) -> super::base::BasisFunction {
        super::base::BasisFunction::ClenshawCurtis
    }

    fn num_nodes(&self, level: u32) -> usize
    {
        cc_num_nodes(level) as usize 
    }
    
    fn node(&self, level: u32, index: u32) -> f64 {
        CC_CACHE.node(level, index)
    }
    
    fn weights(&self, level: u32) -> Vec<f64> {
        CC_CACHE.weights_for_level(level)
    }
    
    fn nodes(&self, level: u32) -> Vec<f64> {
        CC_CACHE.nodes_for_level(level)
    }

    fn quadrature_exactness(&self, level: u32) -> u32
    {
        if level == 0
        {
            1
        }
        else
        {
            2_u32.pow(level) + 1
        }
    }
    fn interpolation_exactness(&self, level: u32) -> u32
    {
        if level == 0
        {
            0
        }
        else
        {
            2_u32.pow(level)
        }
    }

}