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.
This commit is contained in:
Aaron Fenyes 2024-12-17 21:24:38 -08:00
parent 4fd79b9e47
commit 971a7ca7e2
2 changed files with 59 additions and 25 deletions

View File

@ -33,8 +33,9 @@ pub struct Element {
pub serial: u64, pub serial: u64,
// the configuration matrix column index that was assigned to this element // the configuration matrix column index that was assigned to this element
// last time the assembly was realized // last time the assembly was realized, or `None` if the assembly has never
column_index: usize // been realized with this element in it
column_index: Option<usize>
} }
impl Element { impl Element {
@ -62,7 +63,7 @@ impl Element {
representation: create_signal(representation), representation: create_signal(representation),
constraints: create_signal(BTreeSet::default()), constraints: create_signal(BTreeSet::default()),
serial: serial, serial: serial,
column_index: 0 column_index: None
} }
} }
@ -145,7 +146,7 @@ impl Assembly {
Assembly { Assembly {
elements: create_signal(Slab::new()), elements: create_signal(Slab::new()),
constraints: 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()) elements_by_id: create_signal(FxHashMap::default())
} }
} }
@ -216,7 +217,7 @@ impl Assembly {
// index the elements // index the elements
self.elements.update_silent(|elts| { self.elements.update_silent(|elts| {
for (index, (_, elt)) in elts.into_iter().enumerate() { 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 { for (_, cst) in csts {
if cst.active.get_untracked() && cst.lorentz_prod_valid.get_untracked() { if cst.active.get_untracked() && cst.lorentz_prod_valid.get_untracked() {
let subjects = cst.subjects; let subjects = cst.subjects;
let row = elts[subjects.0].column_index; let row = elts[subjects.0].column_index.unwrap();
let col = elts[subjects.1].column_index; let col = elts[subjects.1].column_index.unwrap();
gram_to_be.push_sym(row, col, cst.lorentz_prod.get_untracked()); gram_to_be.push_sym(row, col, cst.lorentz_prod.get_untracked());
} }
} }
@ -239,7 +240,7 @@ impl Assembly {
// Gram matrix // Gram matrix
let mut guess_to_be = DMatrix::<f64>::zeros(5, elts.len()); let mut guess_to_be = DMatrix::<f64>::zeros(5, elts.len());
for (_, elt) in elts { for (_, elt) in elts {
let index = elt.column_index; let index = elt.column_index.unwrap();
gram_to_be.push_sym(index, index, 1.0); gram_to_be.push_sym(index, index, 1.0);
guess_to_be.set_column(index, &elt.representation.get_clone_untracked()); guess_to_be.set_column(index, &elt.representation.get_clone_untracked());
} }
@ -286,7 +287,7 @@ impl Assembly {
// read out the solution // read out the solution
for (_, elt) in self.elements.get_clone_untracked() { for (_, elt) in self.elements.get_clone_untracked() {
elt.representation.update( 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; 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); let mut motion_proj = DMatrix::zeros(ELEMENT_DIM, assembly_dim);
// project the element motions onto the tangent space of the solution // project the element motions onto the tangent space of the solution
// variety, and sum them to get a deformation of the whole assembly // variety, and sum them to get a deformation of the whole assembly
for elt_motion in motion { for elt_motion in motion {
let column_index = self.elements.with(|elts| elts[elt_motion.key].column_index); match self.elements.with_untracked(|elts| elts[elt_motion.key].column_index) {
motion_proj += self.tangent.with(|tan| tan.proj(&elt_motion.velocity, 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 // step each element along the mass shell geodesic that matches its
@ -326,9 +340,18 @@ impl Assembly {
// element is on the 1 mass shell // element is on the 1 mass shell
for (_, elt) in self.elements.get_clone_untracked() { for (_, elt) in self.elements.get_clone_untracked() {
elt.representation.update_silent(|rep| { elt.representation.update_silent(|rep| {
let rep_next = &*rep + motion_proj.column(elt.column_index); match elt.column_index {
Some(column_index) => {
let rep_next = &*rep + motion_proj.column(column_index);
let normalizer = rep_next.dot(&(&*Q * &rep_next)); let normalizer = rep_next.dot(&(&*Q * &rep_next));
rep.set_column(0, &(rep_next / normalizer)); rep.set_column(0, &(rep_next / normalizer));
},
None => {
console::log_1(&JsValue::from(
format!("No velocity to unpack for fresh element \"{}\"", elt.id)
))
}
};
}); });
} }

View File

@ -88,11 +88,17 @@ impl PartialMatrix {
// --- configuration subspaces --- // --- configuration subspaces ---
#[derive(Clone)] #[derive(Clone)]
pub struct ConfigSubspace(Vec<DMatrix<f64>>); pub struct ConfigSubspace {
assembly_dim: usize,
basis: Vec<DMatrix<f64>>
}
impl ConfigSubspace { impl ConfigSubspace {
pub fn zero() -> ConfigSubspace { pub fn zero(assembly_dim: usize) -> ConfigSubspace {
ConfigSubspace(Vec::new()) ConfigSubspace {
assembly_dim: assembly_dim,
basis: Vec::new()
}
} }
// approximate the kernel of a symmetric endomorphism of the configuration // approximate the kernel of a symmetric endomorphism of the configuration
@ -119,12 +125,18 @@ impl ConfigSubspace {
format!("Eigenvalues used to find kernel: {}", eig.eigenvalues) format!("Eigenvalues used to find kernel: {}", eig.eigenvalues)
)); ));
ConfigSubspace(basis.collect()) ConfigSubspace {
assembly_dim: assembly_dim,
basis: basis.collect()
}
} }
pub fn dim(&self) -> usize { pub fn dim(&self) -> usize {
let ConfigSubspace(basis) = self; self.basis.len()
basis.len() }
pub fn assembly_dim(&self) -> usize {
self.assembly_dim
} }
// find the projection onto this subspace of the motion where the element // 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 // for the zero subspace, this method's behavior doesn't match its name: it
// panics rather than returning zero // panics rather than returning zero
pub fn proj(&self, v: &DVectorView<f64>, column_index: usize) -> DMatrix<f64> { pub fn proj(&self, v: &DVectorView<f64>, column_index: usize) -> DMatrix<f64> {
let ConfigSubspace(basis) = self; self.basis.iter().map(
basis.into_iter().map(
|b| b.column(column_index).dot(&v) * b |b| b.column(column_index).dot(&v) * b
).sum() ).sum()
} }
@ -325,14 +336,14 @@ pub fn realize_gram(
state = better_state; state = better_state;
history.backoff_steps.push(backoff_steps); 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 success = state.loss < tol;
let tangent = if success { let tangent = if success {
ConfigSubspace::symmetric_kernel(hess, assembly_dim) ConfigSubspace::symmetric_kernel(hess, assembly_dim)
} else { } else {
ConfigSubspace::zero() ConfigSubspace::zero(assembly_dim)
}; };
(state.config, tangent, success, history) (state.config, tangent, success, history)
} }