From 971a7ca7e279827e7a7b6129200899a3a20aac8a Mon Sep 17 00:00:00 2001 From: Aaron Fenyes Date: Tue, 17 Dec 2024 21:24:38 -0800 Subject: [PATCH] Check tangent space sync when deforming Only give elements column indices once they've actually been through a realization. Ignore motions of elements that haven't been through a realization. Get the dimensions of the projected motion matrix from the saved tangent space, not the current number of elements. --- app-proto/src/assembly.rs | 53 ++++++++++++++++++++++++++++----------- app-proto/src/engine.rs | 31 +++++++++++++++-------- 2 files changed, 59 insertions(+), 25 deletions(-) diff --git a/app-proto/src/assembly.rs b/app-proto/src/assembly.rs index 07b0aba..ec480ac 100644 --- a/app-proto/src/assembly.rs +++ b/app-proto/src/assembly.rs @@ -33,8 +33,9 @@ pub struct Element { pub serial: u64, // the configuration matrix column index that was assigned to this element - // last time the assembly was realized - column_index: usize + // last time the assembly was realized, or `None` if the assembly has never + // been realized with this element in it + column_index: Option } impl Element { @@ -62,7 +63,7 @@ impl Element { representation: create_signal(representation), constraints: create_signal(BTreeSet::default()), serial: serial, - column_index: 0 + column_index: None } } @@ -145,7 +146,7 @@ impl Assembly { Assembly { elements: create_signal(Slab::new()), constraints: create_signal(Slab::new()), - tangent: create_signal(ConfigSubspace::zero()), + tangent: create_signal(ConfigSubspace::zero(0)), elements_by_id: create_signal(FxHashMap::default()) } } @@ -216,7 +217,7 @@ impl Assembly { // index the elements self.elements.update_silent(|elts| { for (index, (_, elt)) in elts.into_iter().enumerate() { - elt.column_index = index; + elt.column_index = Some(index); } }); @@ -228,8 +229,8 @@ impl Assembly { for (_, cst) in csts { if cst.active.get_untracked() && cst.lorentz_prod_valid.get_untracked() { let subjects = cst.subjects; - let row = elts[subjects.0].column_index; - let col = elts[subjects.1].column_index; + let row = elts[subjects.0].column_index.unwrap(); + let col = elts[subjects.1].column_index.unwrap(); gram_to_be.push_sym(row, col, cst.lorentz_prod.get_untracked()); } } @@ -239,7 +240,7 @@ impl Assembly { // Gram matrix let mut guess_to_be = DMatrix::::zeros(5, elts.len()); for (_, elt) in elts { - let index = elt.column_index; + let index = elt.column_index.unwrap(); gram_to_be.push_sym(index, index, 1.0); guess_to_be.set_column(index, &elt.representation.get_clone_untracked()); } @@ -286,7 +287,7 @@ impl Assembly { // read out the solution for (_, elt) in self.elements.get_clone_untracked() { elt.representation.update( - |rep| rep.set_column(0, &config.column(elt.column_index)) + |rep| rep.set_column(0, &config.column(elt.column_index.unwrap())) ); } @@ -309,14 +310,27 @@ impl Assembly { } const ELEMENT_DIM: usize = 5; - let assembly_dim = self.elements.with(|elts| elts.len()); + let assembly_dim = self.tangent.with(|tan| tan.assembly_dim()); let mut motion_proj = DMatrix::zeros(ELEMENT_DIM, assembly_dim); // project the element motions onto the tangent space of the solution // variety, and sum them to get a deformation of the whole assembly for elt_motion in motion { - let column_index = self.elements.with(|elts| elts[elt_motion.key].column_index); - motion_proj += self.tangent.with(|tan| tan.proj(&elt_motion.velocity, column_index)); + match self.elements.with_untracked(|elts| elts[elt_motion.key].column_index) { + Some(column_index) => { + motion_proj += self.tangent.with( + |tan| tan.proj(&elt_motion.velocity, column_index) + ) + }, + None => { + console::log_1(&JsValue::from( + format!( + "Ignoring motion of fresh element \"{}\"", + self.elements.with_untracked(|elts| elts[elt_motion.key].id.clone()) + ) + )) + } + } } // step each element along the mass shell geodesic that matches its @@ -326,9 +340,18 @@ impl Assembly { // element is on the 1 mass shell for (_, elt) in self.elements.get_clone_untracked() { elt.representation.update_silent(|rep| { - let rep_next = &*rep + motion_proj.column(elt.column_index); - let normalizer = rep_next.dot(&(&*Q * &rep_next)); - rep.set_column(0, &(rep_next / normalizer)); + match elt.column_index { + Some(column_index) => { + let rep_next = &*rep + motion_proj.column(column_index); + let normalizer = rep_next.dot(&(&*Q * &rep_next)); + rep.set_column(0, &(rep_next / normalizer)); + }, + None => { + console::log_1(&JsValue::from( + format!("No velocity to unpack for fresh element \"{}\"", elt.id) + )) + } + }; }); } diff --git a/app-proto/src/engine.rs b/app-proto/src/engine.rs index 2f06035..36998bd 100644 --- a/app-proto/src/engine.rs +++ b/app-proto/src/engine.rs @@ -88,11 +88,17 @@ impl PartialMatrix { // --- configuration subspaces --- #[derive(Clone)] -pub struct ConfigSubspace(Vec>); +pub struct ConfigSubspace { + assembly_dim: usize, + basis: Vec> +} impl ConfigSubspace { - pub fn zero() -> ConfigSubspace { - ConfigSubspace(Vec::new()) + pub fn zero(assembly_dim: usize) -> ConfigSubspace { + ConfigSubspace { + assembly_dim: assembly_dim, + basis: Vec::new() + } } // approximate the kernel of a symmetric endomorphism of the configuration @@ -119,12 +125,18 @@ impl ConfigSubspace { format!("Eigenvalues used to find kernel: {}", eig.eigenvalues) )); - ConfigSubspace(basis.collect()) + ConfigSubspace { + assembly_dim: assembly_dim, + basis: basis.collect() + } } pub fn dim(&self) -> usize { - let ConfigSubspace(basis) = self; - basis.len() + self.basis.len() + } + + pub fn assembly_dim(&self) -> usize { + self.assembly_dim } // find the projection onto this subspace of the motion where the element @@ -133,8 +145,7 @@ impl ConfigSubspace { // for the zero subspace, this method's behavior doesn't match its name: it // panics rather than returning zero pub fn proj(&self, v: &DVectorView, column_index: usize) -> DMatrix { - let ConfigSubspace(basis) = self; - basis.into_iter().map( + self.basis.iter().map( |b| b.column(column_index).dot(&v) * b ).sum() } @@ -325,14 +336,14 @@ pub fn realize_gram( state = better_state; history.backoff_steps.push(backoff_steps); }, - None => return (state.config, ConfigSubspace::zero(), false, history) + None => return (state.config, ConfigSubspace::zero(assembly_dim), false, history) }; } let success = state.loss < tol; let tangent = if success { ConfigSubspace::symmetric_kernel(hess, assembly_dim) } else { - ConfigSubspace::zero() + ConfigSubspace::zero(assembly_dim) }; (state.config, tangent, success, history) }