use super::collocated::standardize;
use super::scratch::SgsScratch;
use super::sweep::{simulate_scores, snap_fixed};
use crate::foundation::{AlgoError, Lattice, Result};
use crate::geostat::nscore::NormalScore;
use crate::gridding::kriging::SpatialVariogram;
use ndarray::Array2;
pub struct SgsSession {
lattice: Lattice,
variogram: SpatialVariogram,
max_neighbours: usize,
radius: f64,
scratch: SgsScratch,
}
impl SgsSession {
pub fn new(
lattice: Lattice,
variogram: impl Into<SpatialVariogram>,
max_neighbours: usize,
radius: f64,
) -> Result<SgsSession> {
if max_neighbours == 0 || !radius.is_finite() || radius <= 0.0 {
return Err(AlgoError::InvalidArgument(
"SgsSession: need max_neighbours >= 1 and radius > 0".to_string(),
));
}
Ok(SgsSession {
lattice,
variogram: variogram.into(),
max_neighbours,
radius,
scratch: SgsScratch::default(),
})
}
pub fn lattice(&self) -> &Lattice {
&self.lattice
}
pub fn variogram(&self) -> &SpatialVariogram {
&self.variogram
}
pub fn simulate(&mut self, coords: &[[f64; 3]], seed: u64) -> Result<Array2<f64>> {
self.simulate_inner(coords, seed, None)
}
pub fn simulate_collocated(
&mut self,
coords: &[[f64; 3]],
seed: u64,
secondary: &Array2<f64>,
rho: f64,
) -> Result<Array2<f64>> {
self.simulate_inner(coords, seed, Some((secondary, rho)))
}
fn simulate_inner(
&mut self,
coords: &[[f64; 3]],
seed: u64,
collocated: Option<(&Array2<f64>, f64)>,
) -> Result<Array2<f64>> {
if coords.is_empty() {
return Err(AlgoError::EmptyInput(
"SgsSession::simulate: no conditioning data",
));
}
let (ncol, nrow) = (self.lattice.ncol, self.lattice.nrow);
let secondary = match collocated {
Some((sec, rho)) => {
if sec.dim() != (ncol, nrow) {
return Err(AlgoError::InvalidArgument(
"SgsSession::simulate: collocated secondary shape must match the lattice (ncol, nrow)".to_string(),
));
}
Some((standardize(sec), rho))
}
None => None,
};
let zvals: Vec<f64> = coords.iter().map(|c| c[2]).collect();
let ns = NormalScore::fit(&zvals)?;
let fixed = snap_fixed(coords, &self.lattice, &ns);
let sim = simulate_scores(
&self.lattice,
&self.variogram,
self.max_neighbours,
self.radius,
secondary.as_ref(),
seed,
&fixed,
&mut self.scratch,
);
Ok(sim.mapv(|s| ns.back(s)))
}
}