use std::ops::Range;
use crate::geometry::ellipsoid::Ellipsoid;
use crate::spatial_database::group_provider::GroupProvider;
use crate::spatial_database::ConditioningProvider;
use crate::spatial_database::FilterMapResult;
use crate::spatial_database::FilterMappedIterNearest;
use crate::spatial_database::SpatialAcceleratedDB;
use crate::systems::lu::LUSystem;
use crate::systems::solved_systems::SolvedLUSystem;
use crate::systems::solved_systems::SolvedSystemBuilder;
use crate::variography::model_variograms::composite::CompositeVariogram;
use rand::rngs::StdRng;
use rand::seq::SliceRandom;
use rand::SeedableRng;
use ultraviolet::DVec3;
use crate::group_operators::ConditioningParams;
use rayon::prelude::*;
pub fn estimate(
conditioning_data: &impl ConditioningProvider<Data = f64>,
conditioning_params: &ConditioningParams,
vgram: &CompositeVariogram,
ellipsoid: Ellipsoid,
groups: &GroupProvider,
kriging_type: impl SolvedSystemBuilder,
) -> Vec<f64> {
let local_system = LUSystem::new(groups.max_group_size(), conditioning_params.max_n_cond);
(0..groups.n_groups())
.into_par_iter()
.map_with(
(
ellipsoid.clone(),
local_system.clone(),
vec![],
vec![],
vec![],
vec![],
),
|(ellipsoid, local_system, h_buffer, pt_buffer, var_buffer, ind_buffer), group_idx| {
let group = groups.get_group(group_idx);
let center = group.iter().fold(DVec3::zero(), |mut acc, x| {
acc += x.center();
acc
}) / (group.len() as f64);
ellipsoid.translate_to(center);
let (_, cond_values, mut supports, sufficiently_conditioned) =
conditioning_data.query(¢er, ellipsoid, conditioning_params);
let n_cond = supports.len();
if sufficiently_conditioned {
supports.extend_from_slice(group);
local_system.build_cov_matrix(
n_cond,
group.len(),
&supports,
vgram,
h_buffer,
pt_buffer,
var_buffer,
ind_buffer,
);
let Ok(mut solved_system) = kriging_type.build(local_system) else {
return vec![f64::NAN; group.len()];
};
solved_system.populate_cond_values_est(cond_values.as_slice());
return solved_system.estimate();
}
vec![f64::NAN; group.len()]
},
)
.flatten()
.collect::<Vec<f64>>()
}
pub fn simulate(
conditioning_data: &impl ConditioningProvider<Data = f64>,
data_conditioning_params: &ConditioningParams,
sim_conditioning_params: &ConditioningParams,
vgram: &CompositeVariogram,
ellipsoid: Ellipsoid,
groups: &GroupProvider,
kriging_type: impl SolvedSystemBuilder,
) -> Vec<f64> {
let mut rng = StdRng::from_entropy();
let mut simulation_path = (0..groups.n_groups()).collect::<Vec<_>>();
simulation_path.shuffle(&mut rng);
let simulation_order = simulation_path.iter().enumerate().fold(
vec![0; groups.n_nodes()],
|mut simulation_order, (i, group_idx)| {
let group_range = groups.get_group_range(*group_idx);
simulation_order[group_range].fill(i);
simulation_order
},
);
let sim_location_db =
SpatialAcceleratedDB::new(groups.get_supports().to_vec(), simulation_order);
let sim_conditioned = (0..groups.n_groups())
.into_par_iter()
.map_with(ellipsoid.clone(), |ellipsoid, group_idx| {
let group = groups.get_group(group_idx);
let center = group.iter().fold(DVec3::zero(), |mut acc, x| {
acc += x.center();
acc
}) / (group.len() as f64);
ellipsoid.translate_to(center);
let (_, _cond_values, _supports, sufficiently_conditioned) =
conditioning_data.query(¢er, ellipsoid, data_conditioning_params);
sufficiently_conditioned
})
.collect::<Vec<_>>();
let local_system = LUSystem::new(
groups.max_group_size(),
data_conditioning_params.max_n_cond + sim_conditioning_params.max_n_cond,
);
pub enum Action<T> {
Insert(Range<usize>, T),
Nullify(Range<usize>),
}
let actions = simulation_path
.par_iter()
.copied()
.enumerate()
.map_with(
(
ellipsoid.clone(),
local_system.clone(),
vec![],
vec![],
vec![],
vec![],
),
|(ellipsoid, local_system, h_buffer, pt_buffer, var_buffer, ind_buffer),
(sim_step, group_idx)| {
let group = groups.get_group(group_idx);
let group_range = groups.get_group_range(group_idx);
if !sim_conditioned[group_idx] {
return Action::Nullify(group_range);
}
let center = group.iter().fold(DVec3::zero(), |mut acc, x| {
acc += x.center();
acc
}) / (group.len() as f64);
ellipsoid.translate_to(center);
let (_, cond_values, mut supports, sufficiently_conditioned) =
conditioning_data.query(¢er, ellipsoid, data_conditioning_params);
let sim_query = FilterMappedIterNearest::new(&sim_location_db, |elem| {
if !ellipsoid.may_contain_local_point_at_sq_dist(elem.sq_dist) {
return FilterMapResult::ExitEarly;
}
let group_ind = simulation_path[elem.data];
if elem.data < sim_step && sim_conditioned[group_ind] {
FilterMapResult::Mapped(elem)
} else {
FilterMapResult::Ignore
}
});
let (sim_cond_inds, _, sim_supports, _) =
sim_query.query(¢er, ellipsoid, sim_conditioning_params);
supports.extend_from_slice(&sim_supports);
let n_cond = supports.len();
if sufficiently_conditioned {
supports.extend_from_slice(group);
local_system.build_cov_matrix(
n_cond,
group.len(),
&supports,
vgram,
h_buffer,
pt_buffer,
var_buffer,
ind_buffer,
);
let Ok(solved_system) = kriging_type.build(local_system) else {
return Action::Nullify(group_range);
};
return Action::Insert(
group_range,
(solved_system, sim_cond_inds, cond_values),
);
}
Action::Nullify(group_range)
},
)
.collect::<Vec<_>>();
let mut out = vec![0.0; groups.n_nodes()];
for action in actions {
match action {
Action::Insert(range, (mut solved_system, sim_cond_inds, mut cond_values)) => {
cond_values.extend(sim_cond_inds.into_iter().map(|i| out[i]));
solved_system.populate_cond_values_sim(&cond_values, &mut rng);
let sim_values = solved_system.simulate();
out[range].copy_from_slice(&sim_values);
}
Action::Nullify(range) => {
out[range].fill(f64::NAN);
}
}
}
out
}