use crate::errors::SGError;
use crate::utilities::float::Float;
use crate::basis::linear::POW2_F64;
use crate::{basis::base::Basis, const_generic::{iterators::grid_iterator::GridIteratorT, storage::SparseGridData}};
#[inline]
#[allow(clippy::too_many_arguments)]
pub(crate) fn eval_boundary<const D: usize, const DIM_OUT: usize, BASIS: Basis, T: Float +std::ops::AddAssign, Iterator: GridIteratorT<D>>(storage: &SparseGridData<D>, basis: &[BASIS; D], x: &[f64; D],
dim: usize, value: T, iterator: &mut Iterator, alpha: &[[T; DIM_OUT]], result: &mut [T; DIM_OUT]) -> Result<(), SGError>
{
let x_t: T = T::from(x[dim]);
let mut level = 0;
loop
{
let node_index = iterator.index().ok_or(SGError::InvalidIteratorSequence)?;
let work_index = storage[node_index].index[dim];
if level > 0
{
let new_value = basis[dim].eval_t(level, work_index, x_t);
if dim == D - 1
{
T::accumulate(result, &alpha[node_index], value * new_value);
}
else
{
eval_boundary(storage, basis, x, dim + 1, value * new_value, iterator, alpha, result)?;
}
}
else
{
if iterator.reset_to_left_level_zero(dim)
{
let seq_l = iterator.index().ok_or(SGError::InvalidIteratorSequence)?;
let new_value_l = basis[dim].eval_t(0, 0, x_t);
if dim == D - 1
{
T::accumulate(result, &alpha[seq_l], value * new_value_l);
}
else
{
eval_boundary(storage, basis, x, dim + 1, value * new_value_l, iterator, alpha, result)?;
}
}
if iterator.reset_to_right_level_zero(dim)
{
let seq_r = iterator.index().ok_or(SGError::InvalidIteratorSequence)?;
let new_value_r = basis[dim].eval_t(0, 1, x_t);
if dim == D - 1
{
T::accumulate(result, &alpha[seq_r], value * new_value_r);
}
else
{
eval_boundary(storage, basis, x, dim + 1, value * new_value_r, iterator, alpha, result)?;
}
}
}
if iterator.is_leaf()
{
break;
}
let x = x[dim];
if level > 0
{
let xh = x * POW2_F64[level as usize];
let wi = work_index as f64;
if (xh - wi).abs() < 1e-15
{
break;
}
if xh > wi && !iterator.right_child(dim)
{
break;
}
if xh <= wi && !iterator.left_child(dim)
{
break;
}
}
else
{
if x.abs() < 1e-15 || (x-1.0).abs() < 1e-15
{
break;
}
if !iterator.reset_to_level_one(dim)
{
break;
}
}
level += 1;
}
iterator.reset_to_left_level_zero(dim);
Ok(())
}