forked from StudioInfinity/dyna3
Test curvature drift during position nudging
The test fails, as expected, if you disable sphere normalization by making `Sphere::normalize_mut_rep` do nothing. Since the tests aren't built for WebAssembly, we have to replace `console::log` with `console_log!` in all of the functions they use. We'll eventually want to do this replacement everywhere.
This commit is contained in:
parent
f4e5c34fde
commit
0cfdd59e23
3 changed files with 76 additions and 38 deletions
|
@ -46,6 +46,9 @@ features = [
|
|||
dyna3 = { path = ".", default-features = false, features = ["dev"] }
|
||||
wasm-bindgen-test = "0.3.34"
|
||||
|
||||
[lints.rust]
|
||||
unexpected_cfgs = { level = "warn", check-cfg = ["cfg(sycamore_force_ssr)"] }
|
||||
|
||||
[profile.release]
|
||||
opt-level = "s" # optimize for small code size
|
||||
debug = true # include debug symbols
|
||||
|
|
|
@ -623,9 +623,7 @@ impl Assembly {
|
|||
create_effect(move || {
|
||||
/* DEBUG */
|
||||
// log the regulator update
|
||||
console::log_1(&JsValue::from(
|
||||
format!("Updated regulator with subjects {:?}", regulator.subjects())
|
||||
));
|
||||
console_log!("Updated regulator with subjects {:?}", regulator.subjects());
|
||||
|
||||
if regulator.try_activate() {
|
||||
self_for_effect.realize();
|
||||
|
@ -634,10 +632,10 @@ impl Assembly {
|
|||
|
||||
/* DEBUG */
|
||||
// print an updated list of regulators
|
||||
console::log_1(&JsValue::from("Regulators:"));
|
||||
console_log!("Regulators:");
|
||||
self.regulators.with_untracked(|regs| {
|
||||
for reg in regs.into_iter() {
|
||||
console::log_1(&JsValue::from(format!(
|
||||
console_log!(
|
||||
" {:?}: {}",
|
||||
reg.subjects(),
|
||||
reg.set_point().with_untracked(
|
||||
|
@ -650,7 +648,7 @@ impl Assembly {
|
|||
}
|
||||
}
|
||||
)
|
||||
)));
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -681,19 +679,11 @@ impl Assembly {
|
|||
|
||||
/* DEBUG */
|
||||
// log the Gram matrix
|
||||
console::log_1(&JsValue::from("Gram matrix:"));
|
||||
problem.gram.log_to_console();
|
||||
console_log!("Gram matrix:\n{}", problem.gram);
|
||||
|
||||
/* DEBUG */
|
||||
// log the initial configuration matrix
|
||||
console::log_1(&JsValue::from("Old configuration:"));
|
||||
for j in 0..problem.guess.nrows() {
|
||||
let mut row_str = String::new();
|
||||
for k in 0..problem.guess.ncols() {
|
||||
row_str.push_str(format!(" {:>8.3}", problem.guess[(j, k)]).as_str());
|
||||
}
|
||||
console::log_1(&JsValue::from(row_str));
|
||||
}
|
||||
console_log!("Old configuration:{:>8.3}", problem.guess);
|
||||
|
||||
// look for a configuration with the given Gram matrix
|
||||
let (config, tangent, success, history) = realize_gram(
|
||||
|
@ -702,16 +692,14 @@ impl Assembly {
|
|||
|
||||
/* DEBUG */
|
||||
// report the outcome of the search
|
||||
console::log_1(&JsValue::from(
|
||||
if success {
|
||||
"Target accuracy achieved!"
|
||||
} else {
|
||||
"Failed to reach target accuracy"
|
||||
}
|
||||
));
|
||||
console::log_2(&JsValue::from("Steps:"), &JsValue::from(history.scaled_loss.len() - 1));
|
||||
console::log_2(&JsValue::from("Loss:"), &JsValue::from(*history.scaled_loss.last().unwrap()));
|
||||
console::log_2(&JsValue::from("Tangent dimension:"), &JsValue::from(tangent.dim()));
|
||||
if success {
|
||||
console_log!("Target accuracy achieved!")
|
||||
} else {
|
||||
console_log!("Failed to reach target accuracy")
|
||||
}
|
||||
console_log!("Steps: {}", history.scaled_loss.len() - 1);
|
||||
console_log!("Loss: {}", *history.scaled_loss.last().unwrap());
|
||||
console_log!("Tangent dimension: {}", tangent.dim());
|
||||
|
||||
if success {
|
||||
// read out the solution
|
||||
|
@ -804,9 +792,7 @@ impl Assembly {
|
|||
elt.normalize_mut_rep(rep);
|
||||
},
|
||||
None => {
|
||||
console::log_1(&JsValue::from(
|
||||
format!("No velocity to unpack for fresh element \"{}\"", elt.id())
|
||||
))
|
||||
console_log!("No velocity to unpack for fresh element \"{}\"", elt.id())
|
||||
}
|
||||
};
|
||||
});
|
||||
|
@ -823,6 +809,8 @@ impl Assembly {
|
|||
mod tests {
|
||||
use super::*;
|
||||
|
||||
use crate::engine;
|
||||
|
||||
#[test]
|
||||
#[should_panic(expected = "Sphere \"sphere\" should be indexed before writing problem data")]
|
||||
fn unindexed_element_test() {
|
||||
|
@ -848,4 +836,50 @@ mod tests {
|
|||
}.pose(&mut ConstraintProblem::new(2));
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn curvature_drift_test() {
|
||||
const INITIAL_RADIUS: f64 = 0.25;
|
||||
let _ = create_root(|| {
|
||||
// set up an assembly containing a single sphere centered at the
|
||||
// origin
|
||||
let assembly = Assembly::new();
|
||||
let sphere_id = "sphere0";
|
||||
let _ = assembly.try_insert_element(
|
||||
// we create the sphere by hand for two reasons: to choose the
|
||||
// curvature (which can affect drift rate) and to make the test
|
||||
// independent of `Sphere::default`
|
||||
Sphere::new(
|
||||
String::from(sphere_id),
|
||||
String::from("Sphere 0"),
|
||||
[0.75_f32, 0.75_f32, 0.75_f32],
|
||||
engine::sphere(0.0, 0.0, 0.0, INITIAL_RADIUS)
|
||||
)
|
||||
);
|
||||
|
||||
// nudge the sphere repeatedly along the `z` axis
|
||||
const STEP_SIZE: f64 = 0.0025;
|
||||
const STEP_CNT: usize = 400;
|
||||
let sphere = assembly.elements_by_id.with(|elts_by_id| elts_by_id[sphere_id].clone());
|
||||
let velocity = DVector::from_column_slice(&[0.0, 0.0, STEP_SIZE, 0.0]);
|
||||
for _ in 0..STEP_CNT {
|
||||
assembly.deform(
|
||||
vec![
|
||||
ElementMotion {
|
||||
element: sphere.clone(),
|
||||
velocity: velocity.as_view()
|
||||
}
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
// check how much the sphere's curvature has drifted
|
||||
const INITIAL_HALF_CURV: f64 = 0.5 / INITIAL_RADIUS;
|
||||
const DRIFT_TOL: f64 = 0.015;
|
||||
let final_half_curv = sphere.representation().with_untracked(
|
||||
|rep| rep[Sphere::CURVATURE_COMPONENT]
|
||||
);
|
||||
assert!((final_half_curv / INITIAL_HALF_CURV - 1.0).abs() < DRIFT_TOL);
|
||||
});
|
||||
}
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
use lazy_static::lazy_static;
|
||||
use nalgebra::{Const, DMatrix, DVector, DVectorView, Dyn, SymmetricEigen};
|
||||
use std::fmt::{Display, Error, Formatter};
|
||||
use web_sys::{console, wasm_bindgen::JsValue}; /* DEBUG */
|
||||
|
||||
// --- elements ---
|
||||
|
@ -109,15 +110,6 @@ impl PartialMatrix {
|
|||
}
|
||||
}
|
||||
|
||||
/* DEBUG */
|
||||
pub fn log_to_console(&self) {
|
||||
for &MatrixEntry { index: (row, col), value } in self {
|
||||
console::log_1(&JsValue::from(
|
||||
format!(" {} {} {}", row, col, value)
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
fn freeze(&self, a: &DMatrix<f64>) -> DMatrix<f64> {
|
||||
let mut result = a.clone();
|
||||
for &MatrixEntry { index, value } in self {
|
||||
|
@ -143,6 +135,15 @@ impl PartialMatrix {
|
|||
}
|
||||
}
|
||||
|
||||
impl Display for PartialMatrix {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
|
||||
for &MatrixEntry { index: (row, col), value } in self {
|
||||
writeln!(f, " {row} {col} {value}")?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoIterator for PartialMatrix {
|
||||
type Item = MatrixEntry;
|
||||
type IntoIter = std::vec::IntoIter<Self::Item>;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue