use log::info;
use nalgebra::{DMatrix, DVector};
use rayon::prelude::*;
use std::collections::HashMap;
use std::sync::Mutex;
pub fn refine_all_grid(
y_DMatrix: &DMatrix<f64>,
x_mesh: &DVector<f64>,
) -> (Vec<f64>, DMatrix<f64>, usize) {
let mut h: Vec<f64> = Vec::new();
for i in 0..x_mesh.len() - 1 {
let h_i = x_mesh[i + 1] - x_mesh[i];
h.push(h_i);
}
let (n_rows, _) = y_DMatrix.shape();
let mut new_grid: Vec<f64> = Vec::new();
let mut biased_i = 0;
let number_of_nonzero_keys = x_mesh.len() - 1;
let mut new_initial_guess: DMatrix<f64> =
DMatrix::zeros(n_rows, x_mesh.len() + number_of_nonzero_keys);
for i in 0..x_mesh.len() - 1 {
let y = y_DMatrix.column(i);
new_grid.push(x_mesh[i]);
let h_i = x_mesh[i + 1] - x_mesh[i];
let x_new = x_mesh[i] + h_i * 0.5;
new_grid.push(x_new);
new_initial_guess.column_mut(biased_i).copy_from(&y);
biased_i += 1;
let y_pl_1 = y_DMatrix.column(i + 1);
let dy_i = y_pl_1 - y;
let column_to_add = y + &dy_i * 0.5;
new_initial_guess
.column_mut(biased_i as usize)
.copy_from(&column_to_add);
biased_i += 1;
}
let y_last = y_DMatrix.column(x_mesh.len() - 1);
new_grid.push(x_mesh[x_mesh.len() - 1]);
new_initial_guess
.column_mut(biased_i as usize)
.copy_from(&y_last);
log::info!("created new grid of length {}", new_grid.len());
log::info!(
"\n \n new_initial_guess of shape{:?}",
new_initial_guess.shape()
);
assert_eq!(new_initial_guess.len(), new_grid.len() * n_rows);
(new_grid, new_initial_guess, number_of_nonzero_keys)
}
pub fn refine_all_grid_par(
y_DMatrix: &DMatrix<f64>,
x_mesh: &DVector<f64>,
) -> (Vec<f64>, DMatrix<f64>, usize) {
let (n_rows, _) = y_DMatrix.shape();
let number_of_nonzero_keys = x_mesh.len() - 1;
let mut new_grid: Vec<f64> = Vec::with_capacity(x_mesh.len() + number_of_nonzero_keys);
let mut new_initial_guess: DMatrix<f64> =
DMatrix::zeros(n_rows, x_mesh.len() + number_of_nonzero_keys);
let grid_data: Vec<(f64, f64, DVector<f64>)> = (0..x_mesh.len() - 1)
.into_par_iter()
.map(|i| {
let h_i = x_mesh[i + 1] - x_mesh[i];
let x_new = x_mesh[i] + h_i * 0.5;
let y = y_DMatrix.column(i);
let y_pl_1 = y_DMatrix.column(i + 1);
let dy_i = y_pl_1 - y;
let column_to_add = y + &dy_i * 0.5;
(x_mesh[i], x_new, column_to_add)
})
.collect();
let mut biased_i = 0;
for (i, (x_orig, x_new, interpolated)) in grid_data.into_iter().enumerate() {
new_grid.push(x_orig);
new_grid.push(x_new);
let y = y_DMatrix.column(i);
new_initial_guess.column_mut(biased_i).copy_from(&y);
biased_i += 1;
new_initial_guess
.column_mut(biased_i)
.copy_from(&interpolated);
biased_i += 1;
}
let y_last = y_DMatrix.column(x_mesh.len() - 1);
new_grid.push(x_mesh[x_mesh.len() - 1]);
new_initial_guess.column_mut(biased_i).copy_from(&y_last);
log::info!("created new grid of length {}", new_grid.len());
log::info!("new_initial_guess of shape{:?}", new_initial_guess.shape());
assert_eq!(new_initial_guess.len(), new_grid.len() * n_rows);
(new_grid, new_initial_guess, number_of_nonzero_keys)
}
pub fn easy_grid_refinement(
y_DMatrix: &DMatrix<f64>,
x_mesh: &DVector<f64>,
tolerance: f64,
) -> (Vec<f64>, DMatrix<f64>, usize) {
info!(
"shape of solution {}, {}",
y_DMatrix.nrows(),
y_DMatrix.ncols()
);
info!("x_mesh len {:?}", x_mesh.len());
let (n_rows, _) = y_DMatrix.shape();
let mut new_grid: Vec<f64> = Vec::new();
let mut mark: DVector<i32> = DVector::zeros(x_mesh.len());
for (j, y) in y_DMatrix.row_iter().enumerate() {
let y_j_max = y.max();
let y_j_min = y.min();
let delta = tolerance * (y_j_max - y_j_min);
info!("for component j: {} delta {}", j, delta);
for i in 1..x_mesh.len() - 1 {
let tau_i = (y[i] - y[i - 1]).abs();
if tau_i > delta {
info!("tau {} for i {}", tau_i, i);
mark[i - 1] = 1;
}
}
info!(
"\n \n for row {} mark: {:?} len {} \n \n",
j,
mark,
mark.len()
);
}
let total_new_points: i32 = mark.sum();
log::info!("total new points to add: {}", total_new_points);
let mut biased_i = 0;
let mut new_initial_guess: DMatrix<f64> =
DMatrix::zeros(n_rows, x_mesh.len() + total_new_points as usize);
for i in 0..x_mesh.len() {
let y = y_DMatrix.column(i);
new_grid.push(x_mesh[i]);
new_initial_guess.column_mut(biased_i).copy_from(&y);
biased_i += 1;
if mark[i] != 0_i32 && i < x_mesh.len() - 1 {
let h_i = x_mesh[i + 1] - x_mesh[i];
let x_new = x_mesh[i] + h_i * 0.5;
new_grid.push(x_new);
let y_pl_1 = y_DMatrix.column(i + 1);
let dy_i = y_pl_1 - y;
let column_to_add = y + &dy_i * 0.5;
new_initial_guess
.column_mut(biased_i as usize)
.copy_from(&column_to_add);
biased_i += 1;
}
}
log::info!("created new grid of length {}", new_grid.len());
log::info!(
"\n \n new_initial_guess of shape{:?}",
new_initial_guess.shape()
);
assert_eq!(new_initial_guess.len(), new_grid.len() * n_rows);
(new_grid, new_initial_guess, total_new_points as usize)
}
pub fn easy_grid_refinement_par(
y_DMatrix: &DMatrix<f64>,
x_mesh: &DVector<f64>,
tolerance: f64,
) -> (Vec<f64>, DMatrix<f64>, usize) {
info!(
"shape of solution {}, {}",
y_DMatrix.nrows(),
y_DMatrix.ncols()
);
info!("x_mesh len {:?}", x_mesh.len());
let (n_rows, _) = y_DMatrix.shape();
let mut new_grid: Vec<f64> = Vec::new();
let mark = Mutex::new(DVector::zeros(x_mesh.len()));
y_DMatrix
.row_iter()
.enumerate()
.par_bridge()
.for_each(|(j, y)| {
let y_j_max = y.max();
let y_j_min = y.min();
let delta = tolerance * (y_j_max - y_j_min);
info!("for component j: {} delta {}", j, delta);
let mut local_mark = Vec::new();
for i in 1..x_mesh.len() - 1 {
let tau_i = (y[i] - y[i - 1]).abs();
if tau_i > delta {
info!("tau {} for i {}", tau_i, i);
local_mark.push(i - 1);
}
}
if !local_mark.is_empty() {
let mut global_mark = mark.lock().unwrap();
for &idx in &local_mark {
global_mark[idx] = 1;
}
}
info!("for row {} found {} intervals to mark", j, local_mark.len());
});
let mark = mark.into_inner().unwrap();
let total_new_points: i32 = mark.sum();
log::info!("total new points to add: {}", total_new_points);
let mut biased_i = 0;
let mut new_initial_guess: DMatrix<f64> =
DMatrix::zeros(n_rows, x_mesh.len() + total_new_points as usize);
for i in 0..x_mesh.len() {
let y = y_DMatrix.column(i);
new_grid.push(x_mesh[i]);
new_initial_guess.column_mut(biased_i).copy_from(&y);
biased_i += 1;
if mark[i] != 0_i32 && i < x_mesh.len() - 1 {
let h_i = x_mesh[i + 1] - x_mesh[i];
let x_new = x_mesh[i] + h_i * 0.5;
new_grid.push(x_new);
let y_pl_1 = y_DMatrix.column(i + 1);
let dy_i = y_pl_1 - y;
let column_to_add = y + &dy_i * 0.5;
new_initial_guess
.column_mut(biased_i as usize)
.copy_from(&column_to_add);
biased_i += 1;
}
}
log::info!("created new grid of length {}", new_grid.len());
log::info!("new_initial_guess of shape{:?}", new_initial_guess.shape());
assert_eq!(new_initial_guess.len(), new_grid.len() * n_rows);
(new_grid, new_initial_guess, total_new_points as usize)
}
pub fn pearson_grid_refinement(
y_DMatrix: &DMatrix<f64>,
x_mesh: &DVector<f64>,
d: f64,
C: f64,
) -> (Vec<f64>, DMatrix<f64>, usize) {
let mut h: Vec<f64> = Vec::new();
for i in 0..x_mesh.len() - 1 {
let h_i = x_mesh[i + 1] - x_mesh[i];
h.push(h_i);
}
let (n_rows, _) = y_DMatrix.shape();
let mut new_grid: Vec<f64> = Vec::new();
let mut mark: HashMap<usize, i32> = HashMap::new();
for (j, y) in y_DMatrix.clone().row_iter().enumerate() {
let threshold = 1e-4;
let y_j_max = y.max();
let y_j_min = y.min();
let delta = d * (y_j_max - y_j_min);
info!("delta {} for component j: {}", delta, j);
for i in 0..x_mesh.len() {
if !mark.contains_key(&i) {
mark.insert(i, 0); }
if x_mesh.len() - 1 > i && i > 0 {
let tau_i = (y[i] - y[i - 1]).abs();
let both_ys_are_not_too_small =
(y[i].abs() > threshold) & (y[i + 1].abs() > threshold);
if tau_i > delta && both_ys_are_not_too_small {
info!(
"tau {:3} ({:3}, {:3})> delta {:3} for i {}",
tau_i,
y[i],
y[i - 1],
delta,
i
);
let N = if (tau_i / delta) as i32 >= 1 {
(tau_i / delta) as i32
} else {
1
};
let current_N = *mark.get(&i).unwrap_or(&0);
if N > current_N {
mark.insert(i - 1, N);
}
}
} } let non_zero_keys: Vec<usize> = mark
.iter()
.filter(|&(_, &value)| value != 0)
.map(|(key, _)| *key)
.collect();
info!(
"\n \n for row {} found intervals to be refined: {:?} of length {} \n \n",
j,
non_zero_keys,
non_zero_keys.len()
);
}
for i in 1..x_mesh.len() - 1 {
let buffer_condition_1 = h[i] / h[i - 1] <= C; let buffer_condition_2 = h[i] / h[i - 1] >= 1.0 / C; if !buffer_condition_1 {
log::info!(
"bufferization at index {} needed, as h[i]/h[i-1] <= C, h[i], h[i-1] = {} , {}",
i,
h[i],
h[i - 1]
);
if (i - 1) != 0 {
let current_N = *mark.get(&(i - 1)).unwrap_or(&0);
if 1 > current_N {
mark.insert(i - 1, 1);
}
}
}
if !buffer_condition_2 {
log::info!(
"bufferization at index {} needed, as h[i]/h[i-1] >= 1.0/C, h[i], h[i-1] = {} , {}",
i,
h[i],
h[i - 1]
);
let current_N = *mark.get(&i).unwrap_or(&0);
if 1 > current_N {
mark.insert(i - 1, 1);
}
}
}
let total_new_points: i32 = mark.values().sum();
log::info!("total new points to add: {}", total_new_points);
let mut biased_i = 0;
let mut new_initial_guess: DMatrix<f64> =
DMatrix::zeros(n_rows, x_mesh.len() + total_new_points as usize);
for i in 0..x_mesh.len() {
let y = y_DMatrix.column(i);
if mark.get(&i).unwrap() != &0 {
let N = *mark.get(&i).unwrap();
if i < x_mesh.len() - 1 {
let h_i = x_mesh[i + 1] - x_mesh[i];
for k in 0..N + 1 {
let x_new = x_mesh[i] + h_i * (k as f64) / (N as f64 + 1.0);
if k != 0 {
log::info!("\n \n points added: {} at index {} ", x_new, i);
}
new_grid.push(x_new);
}
let y_pl_1 = y_DMatrix.column(i + 1);
let dy_i = y_pl_1 - y;
for k in 0..N + 1 {
let column_to_add = y + &dy_i * (k as f64) / (N as f64 + 1.0);
if k != 0 {
}
new_initial_guess
.column_mut(biased_i as usize)
.copy_from(&column_to_add);
biased_i += 1;
}
} else {
new_grid.push(x_mesh[i]);
new_initial_guess.column_mut(biased_i).copy_from(&y);
biased_i += 1;
}
} else {
new_grid.push(x_mesh[i]);
new_initial_guess.column_mut(biased_i).copy_from(&y);
biased_i += 1;
} }
log::info!("created new grid of length {}", new_grid.len());
log::info!(
"\n \n new_initial_guess of shape{:?}",
new_initial_guess.shape()
);
assert_eq!(new_initial_guess.len(), new_grid.len() * n_rows);
(new_grid, new_initial_guess, total_new_points as usize)
}
pub fn pearson_grid_refinement_par(
y_DMatrix: &DMatrix<f64>,
x_mesh: &DVector<f64>,
d: f64,
C: f64,
) -> (Vec<f64>, DMatrix<f64>, usize) {
let mut h: Vec<f64> = Vec::new();
for i in 0..x_mesh.len() - 1 {
let h_i = x_mesh[i + 1] - x_mesh[i];
h.push(h_i);
}
let (n_rows, _) = y_DMatrix.shape();
let mut new_grid: Vec<f64> = Vec::new();
let mark = Mutex::new(HashMap::new());
y_DMatrix
.clone()
.row_iter()
.enumerate()
.par_bridge()
.for_each(|(j, y)| {
let threshold = 1e-4;
let y_j_max = y.max();
let y_j_min = y.min();
let delta = d * (y_j_max - y_j_min);
info!("delta {} for component j: {}", delta, j);
let mut local_marks = Vec::new();
for i in 0..x_mesh.len() {
if x_mesh.len() - 1 > i && i > 0 {
let tau_i = (y[i] - y[i - 1]).abs();
let both_ys_are_not_too_small =
(y[i].abs() > threshold) & (y[i + 1].abs() > threshold);
if tau_i > delta && both_ys_are_not_too_small {
let N = if (tau_i / delta) as i32 >= 1 {
(tau_i / delta) as i32
} else {
1
};
local_marks.push((i - 1, N));
}
}
}
if !local_marks.is_empty() {
let mut global_mark = mark.lock().unwrap();
for (idx, N) in local_marks {
let current_N = *global_mark.get(&idx).unwrap_or(&0);
if N > current_N {
global_mark.insert(idx, N);
}
}
}
});
let mut mark = mark.into_inner().unwrap();
for i in 1..x_mesh.len() - 1 {
let buffer_condition_1 = h[i] / h[i - 1] <= C;
let buffer_condition_2 = h[i] / h[i - 1] >= 1.0 / C;
if !buffer_condition_1 && (i - 1) != 0 {
let current_N = *mark.get(&(i - 1)).unwrap_or(&0);
if 1 > current_N {
mark.insert(i - 1, 1);
}
}
if !buffer_condition_2 {
let current_N = *mark.get(&i).unwrap_or(&0);
if 1 > current_N {
mark.insert(i - 1, 1);
}
}
}
let total_new_points: i32 = mark.values().sum();
log::info!("total new points to add: {}", total_new_points);
let mut biased_i = 0;
let mut new_initial_guess: DMatrix<f64> =
DMatrix::zeros(n_rows, x_mesh.len() + total_new_points as usize);
for i in 0..x_mesh.len() {
let y = y_DMatrix.column(i);
if mark.get(&i).unwrap_or(&0) != &0 {
let N = *mark.get(&i).unwrap();
if i < x_mesh.len() - 1 {
let h_i = x_mesh[i + 1] - x_mesh[i];
for k in 0..N + 1 {
let x_new = x_mesh[i] + h_i * (k as f64) / (N as f64 + 1.0);
new_grid.push(x_new);
}
let y_pl_1 = y_DMatrix.column(i + 1);
let dy_i = y_pl_1 - y;
for k in 0..N + 1 {
let column_to_add = y + &dy_i * (k as f64) / (N as f64 + 1.0);
new_initial_guess
.column_mut(biased_i as usize)
.copy_from(&column_to_add);
biased_i += 1;
}
} else {
new_grid.push(x_mesh[i]);
new_initial_guess.column_mut(biased_i).copy_from(&y);
biased_i += 1;
}
} else {
new_grid.push(x_mesh[i]);
new_initial_guess.column_mut(biased_i).copy_from(&y);
biased_i += 1;
}
}
assert_eq!(new_initial_guess.len(), new_grid.len() * n_rows);
(new_grid, new_initial_guess, total_new_points as usize)
}
pub fn grcar_smooke_grid_refinement(
y_DMatrix: &DMatrix<f64>,
x_mesh: &DVector<f64>,
d: f64,
g: f64,
C: f64,
) -> (Vec<f64>, DMatrix<f64>, usize) {
info!("old mesh len {:?}", x_mesh.len());
info!(
"shape of solution {}, {}",
y_DMatrix.nrows(),
y_DMatrix.ncols()
);
for (j, y) in y_DMatrix.clone().row_iter().enumerate() {
log::debug!("row {} : y= {:}", j, y);
}
let mut h: Vec<f64> = Vec::new();
for i in 0..x_mesh.len() - 1 {
let h_i = x_mesh[i + 1] - x_mesh[i];
h.push(h_i);
}
let (n_rows, _) = y_DMatrix.shape();
let mut new_grid: Vec<f64> = Vec::new();
let mut mark: HashMap<usize, i32> = HashMap::new();
for (j, y) in y_DMatrix.clone().row_iter().enumerate() {
info!("y= {:}, {:?}", y[0], y[y.len() - 1]);
let threshold = 1e-4;
let y_j_max = y.max();
let y_j_min = y.min();
let delta = d * (y_j_max - y_j_min);
info!(
"delta {} ({}, {}) for component j: {}",
delta, y_j_max, y_j_min, j
);
let mut list_dy_dx_i = Vec::new();
for i in 0..x_mesh.len() - 1 {
let dy_i = y[i + 1] - y[i];
let h_i = h[i];
let dy_dx_i = dy_i / h_i;
list_dy_dx_i.push(dy_dx_i);
}
let list_dy_dx_i_min = list_dy_dx_i
.iter()
.cloned()
.min_by(|a, b| a.total_cmp(b))
.unwrap();
let list_dy_dx_i_max = list_dy_dx_i
.iter()
.cloned()
.max_by(|a, b| a.total_cmp(b))
.unwrap();
let derivative_range = list_dy_dx_i_max - list_dy_dx_i_min;
let gamma = g * derivative_range;
info!("gamma {} for component j: {}", gamma, j);
for i in 0..x_mesh.len() {
if !mark.contains_key(&i) {
mark.insert(i, 0); }
if x_mesh.len() - 1 > i && i > 0 {
let dy_i = y[i + 1] - y[i];
let h_i = h[i];
let dy_dx_i = dy_i / h_i;
let dy_i_min_1 = y[i] - y[i - 1];
let h_i_min_1 = h[i - 1];
let dy_dx_i_min_1 = dy_i_min_1 / h_i_min_1;
let eta_i = (dy_dx_i - dy_dx_i_min_1).abs();
let tau_i = (y[i] - y[i - 1]).abs();
let both_ys_are_not_too_small =
(y[i].abs() > threshold) & (y[i + 1].abs() > threshold);
if (tau_i > delta && both_ys_are_not_too_small)
|| (eta_i > gamma && both_ys_are_not_too_small)
{
info!(
"tau {:3} ({:3}, {:3})> delta {:3} for i {}",
tau_i,
y[i],
y[i - 1],
delta,
i
);
info!(
"eta {:3} ({:3}, {:3})> gamma {:3} for i {}",
eta_i, dy_dx_i, dy_dx_i_min_1, gamma, i
);
let N = if (tau_i / delta) as i32 >= 1 {
(tau_i / delta) as i32
} else {
1
};
info!(" conditions vaiolation at index {}, => N = {}", i, N);
let current_N = *mark.get(&i).unwrap_or(&0);
if N > current_N {
mark.insert(i - 1, N);
}
}
} } let non_zero_keys: Vec<usize> = mark
.iter()
.filter(|&(_, &value)| value != 0)
.map(|(key, _)| *key)
.collect();
info!(
"\n \n for row {} found intervals to be refined: {:?} of length {} \n \n",
j,
non_zero_keys,
non_zero_keys.len()
);
}
for i in 1..x_mesh.len() - 1 {
let buffer_condition_1 = h[i] / h[i - 1] <= C; let buffer_condition_2 = h[i] / h[i - 1] >= 1.0 / C; if !buffer_condition_1 {
log::info!(
"bufferization at index {} needed, as h[i]/h[i-1] <= C, h[i], h[i-1] = {} , {}",
i,
h[i],
h[i - 1]
);
if (i - 1) != 0 {
let current_N = *mark.get(&(i - 1)).unwrap_or(&0);
if 1 > current_N {
mark.insert(i - 1, 1);
}
}
}
if !buffer_condition_2 {
log::info!(
"bufferization at index {} needed, as h[i]/h[i-1] >= 1.0/C, h[i], h[i-1] = {} , {}",
i,
h[i],
h[i - 1]
);
let current_N = *mark.get(&i).unwrap_or(&0);
if 1 > current_N {
mark.insert(i - 1, 1);
}
}
}
let total_new_points: i32 = mark.values().sum();
log::info!("total new points to add: {}", total_new_points);
let mut biased_i = 0;
let mut new_initial_guess: DMatrix<f64> =
DMatrix::zeros(n_rows, x_mesh.len() + total_new_points as usize);
for i in 0..x_mesh.len() {
let y = y_DMatrix.column(i);
if mark.get(&i).unwrap() != &0 {
let N = *mark.get(&i).unwrap();
if i < x_mesh.len() - 1 {
let h_i = x_mesh[i + 1] - x_mesh[i];
for k in 0..N + 1 {
let x_new = x_mesh[i] + h_i * (k as f64) / (N as f64 + 1.0);
if k != 0 {
log::info!("\n \n points added: {} at index {} ", x_new, i);
}
new_grid.push(x_new);
}
let y_pl_1 = y_DMatrix.column(i + 1);
let dy_i = y_pl_1 - y;
for k in 0..N + 1 {
let column_to_add = y + &dy_i * (k as f64) / (N as f64 + 1.0);
if k != 0 {
log::info!(
"\n \n column added: {} at index {} ",
column_to_add,
biased_i
);
}
new_initial_guess
.column_mut(biased_i as usize)
.copy_from(&column_to_add);
biased_i += 1;
}
} else {
new_grid.push(x_mesh[i]);
new_initial_guess.column_mut(biased_i).copy_from(&y);
biased_i += 1;
}
} else {
new_grid.push(x_mesh[i]);
new_initial_guess.column_mut(biased_i).copy_from(&y);
biased_i += 1;
} }
log::info!("created new grid of length {}", new_grid.len());
log::info!(
"\n \n new_initial_guess of shape{:?}",
new_initial_guess.shape()
);
assert_eq!(new_initial_guess.len(), new_grid.len() * n_rows);
(new_grid, new_initial_guess, total_new_points as usize)
}
pub fn grcar_smooke_grid_refinement_par(
y_DMatrix: &DMatrix<f64>,
x_mesh: &DVector<f64>,
d: f64,
g: f64,
C: f64,
) -> (Vec<f64>, DMatrix<f64>, usize) {
let mut h: Vec<f64> = Vec::new();
for i in 0..x_mesh.len() - 1 {
let h_i = x_mesh[i + 1] - x_mesh[i];
h.push(h_i);
}
let (n_rows, _) = y_DMatrix.shape();
let mut new_grid: Vec<f64> = Vec::new();
let mark = Mutex::new(HashMap::new());
y_DMatrix
.clone()
.row_iter()
.enumerate()
.par_bridge()
.for_each(|(j, y)| {
let threshold = 1e-4;
let y_j_max = y.max();
let y_j_min = y.min();
let delta = d * (y_j_max - y_j_min);
info!(
"delta {} ({}, {}) for component j: {}",
delta, y_j_max, y_j_min, j
);
let mut list_dy_dx_i = Vec::new();
for i in 0..x_mesh.len() - 1 {
let dy_i = y[i + 1] - y[i];
let h_i = h[i];
let dy_dx_i = dy_i / h_i;
list_dy_dx_i.push(dy_dx_i);
}
let list_dy_dx_i_min = list_dy_dx_i
.iter()
.cloned()
.min_by(|a, b| a.total_cmp(b))
.unwrap();
let list_dy_dx_i_max = list_dy_dx_i
.iter()
.cloned()
.max_by(|a, b| a.total_cmp(b))
.unwrap();
let derivative_range = list_dy_dx_i_max - list_dy_dx_i_min;
let gamma = g * derivative_range;
info!("gamma {} for component j: {}", gamma, j);
let mut local_marks = Vec::new();
for i in 0..x_mesh.len() {
if x_mesh.len() - 1 > i && i > 0 {
let dy_i = y[i + 1] - y[i];
let h_i = h[i];
let dy_dx_i = dy_i / h_i;
let dy_i_min_1 = y[i] - y[i - 1];
let h_i_min_1 = h[i - 1];
let dy_dx_i_min_1 = dy_i_min_1 / h_i_min_1;
let eta_i = (dy_dx_i - dy_dx_i_min_1).abs();
let tau_i = (y[i] - y[i - 1]).abs();
let both_ys_are_not_too_small =
(y[i].abs() > threshold) & (y[i + 1].abs() > threshold);
if (tau_i > delta && both_ys_are_not_too_small)
|| (eta_i > gamma && both_ys_are_not_too_small)
{
info!(
"tau {:3} ({:3}, {:3})> delta {:3} for i {}",
tau_i,
y[i],
y[i - 1],
delta,
i
);
info!(
"eta {:3} ({:3}, {:3})> gamma {:3} for i {}",
eta_i, dy_dx_i, dy_dx_i_min_1, gamma, i
);
let N = if (tau_i / delta) as i32 >= 1 {
(tau_i / delta) as i32
} else {
1
};
local_marks.push((i - 1, N));
info!(" conditions vaiolation at index {}, => N = {}", i, N);
}
}
}
if !local_marks.is_empty() {
let mut global_mark = mark.lock().unwrap();
for (idx, N) in local_marks {
let current_N = *global_mark.get(&idx).unwrap_or(&0);
if N > current_N {
global_mark.insert(idx, N);
}
}
}
});
let mut mark = mark.into_inner().unwrap();
for i in 1..x_mesh.len() - 1 {
let buffer_condition_1 = h[i] / h[i - 1] <= C;
let buffer_condition_2 = h[i] / h[i - 1] >= 1.0 / C;
if !buffer_condition_1 && (i - 1) != 0 {
log::info!(
"bufferization at index {} needed, as h[i]/h[i-1] <= C, h[i], h[i-1] = {} , {}",
i,
h[i],
h[i - 1]
);
let current_N = *mark.get(&(i - 1)).unwrap_or(&0);
if 1 > current_N {
mark.insert(i - 1, 1);
}
}
if !buffer_condition_2 {
log::info!(
"bufferization at index {} needed, as h[i]/h[i-1] >= 1.0/C, h[i], h[i-1] = {} , {}",
i,
h[i],
h[i - 1]
);
let current_N = *mark.get(&i).unwrap_or(&0);
if 1 > current_N {
mark.insert(i - 1, 1);
}
}
}
let total_new_points: i32 = mark.values().sum();
log::info!("total new points to add: {}", total_new_points);
let mut biased_i = 0;
let mut new_initial_guess: DMatrix<f64> =
DMatrix::zeros(n_rows, x_mesh.len() + total_new_points as usize);
for i in 0..x_mesh.len() {
let y = y_DMatrix.column(i);
if mark.get(&i).unwrap_or(&0) != &0 {
let N = *mark.get(&i).unwrap();
if i < x_mesh.len() - 1 {
let h_i = x_mesh[i + 1] - x_mesh[i];
for k in 0..N + 1 {
let x_new = x_mesh[i] + h_i * (k as f64) / (N as f64 + 1.0);
log::info!("\n \n points added: {} at index {} ", x_new, i);
new_grid.push(x_new);
}
let y_pl_1 = y_DMatrix.column(i + 1);
let dy_i = y_pl_1 - y;
for k in 0..N + 1 {
let column_to_add = y + &dy_i * (k as f64) / (N as f64 + 1.0);
log::info!(
"\n \n column added: {} at index {} ",
column_to_add,
biased_i
);
new_initial_guess
.column_mut(biased_i as usize)
.copy_from(&column_to_add);
biased_i += 1;
}
} else {
new_grid.push(x_mesh[i]);
new_initial_guess.column_mut(biased_i).copy_from(&y);
biased_i += 1;
}
} else {
new_grid.push(x_mesh[i]);
new_initial_guess.column_mut(biased_i).copy_from(&y);
biased_i += 1;
}
}
log::info!("created new grid of length {}", new_grid.len());
log::info!(
"\n \n new_initial_guess of shape{:?}",
new_initial_guess.shape()
);
assert_eq!(new_initial_guess.len(), new_grid.len() * n_rows);
(new_grid, new_initial_guess, total_new_points as usize)
}
pub fn scipy_grid_refinement(
y_DMatrix: &DMatrix<f64>,
x_mesh: &DVector<f64>,
tolerance: f64,
residual: Option<DVector<f64>>,
) -> (Vec<f64>, DMatrix<f64>, usize) {
let nrows = y_DMatrix.nrows();
let residuals = residual.expect("residual vector is required for scipy grid refinement");
let mut insert_1 = Vec::new();
let mut insert_2 = Vec::new();
let m = residuals.len();
for j in 0..(m - 1) {
if residuals[j] > tolerance && residuals[j] < 100.0 * tolerance {
insert_1.push(j);
} else if residuals[j] >= 100.0 * tolerance {
insert_2.push(j);
}
}
let nodes_added = insert_1.len() + 2 * insert_2.len();
info!("nodes to add {}", nodes_added);
if nodes_added > 0 {
let new_grid = modify_mesh(&x_mesh, &insert_1, &insert_2);
let new_grid: Vec<f64> = new_grid.iter().cloned().collect();
let new_initial_guess = interpolate_solution(
&y_DMatrix,
insert_1.as_slice(),
insert_2.as_slice(),
&new_grid,
);
assert_eq!(new_initial_guess.len(), new_grid.len() * nrows);
(new_grid, new_initial_guess, nodes_added as usize)
} else {
info!("no refinement needed");
let x_mesh: Vec<f64> = x_mesh.iter().cloned().collect();
(x_mesh.clone(), y_DMatrix.clone(), 0_usize)
}
}
pub fn modify_mesh(x: &DVector<f64>, insert_1: &[usize], insert_2: &[usize]) -> DVector<f64> {
let mut new_points = x.iter().cloned().collect::<Vec<f64>>();
for &i in insert_1 {
let mid = 0.5 * (x[i] + x[i + 1]);
new_points.push(mid);
}
for &i in insert_2 {
let p1 = (2.0 * x[i] + x[i + 1]) / 3.0;
let p2 = (x[i] + 2.0 * x[i + 1]) / 3.0;
new_points.push(p1);
new_points.push(p2);
}
new_points.sort_by(|a, b| a.partial_cmp(b).unwrap());
DVector::from_vec(new_points)
}
pub fn interpolate_solution(
y: &DMatrix<f64>,
insert_1: &[usize],
insert_2: &[usize],
new_x: &[f64],
) -> DMatrix<f64> {
let (n_rows, old_ncols) = y.shape();
let mut new_y = DMatrix::zeros(n_rows, new_x.len());
let mut col_idx = 0;
let mut mark: HashMap<usize, i32> = HashMap::new();
for &i in insert_1 {
mark.insert(i, 1);
}
for &i in insert_2 {
mark.insert(i, 2);
}
for i in 0..old_ncols {
new_y.column_mut(col_idx).copy_from(&y.column(i));
col_idx += 1;
if let Some(&N) = mark.get(&i) {
if i < old_ncols - 1 {
let y_curr = y.column(i);
let y_next = y.column(i + 1);
let dy = y_next - y_curr;
for k in 1..=N {
let t = k as f64 / (N as f64 + 1.0);
let interpolated = y_curr + &dy * t;
info!("interpolated: {:?} for col {}", interpolated, col_idx);
new_y.column_mut(col_idx).copy_from(&interpolated);
col_idx += 1;
}
}
}
}
new_y
}