use super::NR::{NR, bound_step};
use crate::numerical::BVP_Damp::BVP_utils::elapsed_time;
use log::{error, info, warn};
use nalgebra::DVector;
use std::time::Instant;
impl NR {
pub fn step_damped(&mut self) -> (i32, Option<DVector<f64>>) {
let maxDampIter = self.parameters.clone().unwrap()["maxDampIter"] as usize;
let c = 1e-4;
let now = Instant::now();
let y_k_minus_1 = self.y.clone();
let undamped_step_k_minus_1 = self.step(y_k_minus_1.clone());
let (undamped_step_k_minus_1, F_k_minus_1) = undamped_step_k_minus_1.clone();
let S_k_minus_1 = F_k_minus_1.norm();
info!("\n \n L2 norm of undamped step = {}", S_k_minus_1);
self.custom_timer.linear_system_tac();
*self
.calc_statistics
.entry("number of solving linear systems".to_string())
.or_insert(0) += 1;
info!("\n \n y_k-1 = {}", y_k_minus_1,);
let fbound = bound_step(&y_k_minus_1, &undamped_step_k_minus_1, &self.bounds_vec);
if fbound.is_nan() {
error!("\n \n fbound is NaN \n \n");
panic!()
}
if fbound.is_infinite() {
error!("\n \n fbound is infinite \n \n");
panic!()
}
let mut clipping_flag = false;
let mut lambda = if fbound < 1e-10 {
log::warn!(
"\n No damped step can be taken without violating solution component bounds."
);
clipping_flag = true;
1.0
} else {
fbound
};
let mut k_: usize = 0;
let mut S_k: Option<f64> = None;
let mut damped_step_result: Option<DVector<f64>> = None;
let mut conv: f64 = 0.0;
let mut k = 0;
while k < maxDampIter {
info!(
"\n____________________________________damping iteration = {}_______________________________________",
k
);
if k > 1 {
info!("\n \n damped_step number {} ", k);
}
info!("\n \n Damping coefficient = {}", lambda);
let damped_step_k_minus_1 = lambda * undamped_step_k_minus_1.clone();
info!("damped_step {}", damped_step_k_minus_1);
let y_k: DVector<f64> = y_k_minus_1.clone() - damped_step_k_minus_1;
let y_k_clipped: DVector<f64> = if clipping_flag == true {
self.clip(&y_k, &self.bounds_vec)
} else {
y_k
};
let F_k = self.evaluate_function(y_k_clipped.clone());
let error = F_k.norm();
self.max_error = error;
info!(
"\n \n L2 norm of damped step = {:3}, norm of undamped step = {:3}",
error, S_k_minus_1
);
let convergence_cond_for_step = self.tolerance;
let S_k_temp = error;
let elapsed = now.elapsed();
elapsed_time(elapsed);
if (S_k_temp < S_k_minus_1 * (1.0 - lambda * c))
|| (S_k_temp < convergence_cond_for_step)
{
k_ = k;
S_k = Some(S_k_temp);
damped_step_result = Some(y_k_clipped.clone());
conv = convergence_cond_for_step;
info!(
"\n \n Damping coefficient accepted S_k_plus_1_temp < S_k {}, {},",
S_k_temp, S_k_minus_1,
);
info!(
"norm of undamped step = {} vs convergence criterion = {}",
S_k_temp, convergence_cond_for_step
);
info!("damped step result = {:?}", &damped_step_result);
break;
}
lambda *= 0.5; k_ = k;
S_k = Some(S_k_temp);
k = k + 1;
}
if k_ < maxDampIter {
if S_k.unwrap() > conv {
info!("\n \n Damping coefficient found (solution has not converged yet)");
info!(
"\n \n step norm = {}, weight norm = {}, damped_step_result = {}",
self.max_error,
S_k.unwrap(),
conv
);
assert!(damped_step_result.is_some());
(0, damped_step_result)
} else {
info!("\n \n Damping coefficient found (solution has converged)");
info!(
"\n \n step norm = {}, weight norm = {}, convergence condition = {}",
self.max_error,
S_k.unwrap(),
conv
);
(1, damped_step_result)
}
} else {
warn!("\n \n No damping coefficient found (max damping iterations reached)");
return (-2, None);
}
}
pub fn clip(&self, y: &DVector<f64>, vec_of_bounds: &Vec<(f64, f64)>) -> DVector<f64> {
let mut clipped_y = y.clone();
for (i, y_i) in y.iter().enumerate() {
let (lower_bound, upper_bound) = vec_of_bounds[i];
if y_i.clone() < lower_bound {
info!("y[{}] to clip {} with lower bound {}", i, y_i, lower_bound);
clipped_y[i] = lower_bound;
} else if y_i.clone() > upper_bound {
info!("y[{}] to clip {} with upper bound {}", i, y_i, upper_bound);
clipped_y[i] = upper_bound;
}
}
clipped_y
}
}