Make the deformation matrix just the right size

Also, correct the check for whether an element had a column index when
we started. The previous revision would've gotten the wrong answer for
an element without a column index that appeared more than once in the
motion.
This commit is contained in:
Aaron Fenyes 2024-12-18 11:43:54 -08:00
parent e2c5ba0fc7
commit 6df0e855cf

View File

@ -317,36 +317,50 @@ impl Assembly {
console::log_1(&JsValue::from("The assembly is rigid"));
}
const ELEMENT_DIM: usize = 5;
let assembly_dim = self.elements.with(|elts| elts.len());
let mut motion_proj = DMatrix::zeros(ELEMENT_DIM, assembly_dim);
let tan_assembly_dim = self.tangent.with(|tan| tan.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
let mut next_column_index = tan_assembly_dim;
for elt_motion in motion {
match self.elements.with_untracked(|elts| elts[elt_motion.key].column_index) {
Some(column_index) => {
let mut target_columns = motion_proj.columns_mut(0, tan_assembly_dim);
target_columns += self.tangent.with(
|tan| tan.proj(&elt_motion.velocity, column_index)
)
},
None => {
// give the element a column index, even though it's never
// been through a realization, and add its motion to that
// column of the projected motion. this temporarily breaks
// invariant (1), but the invariant will be restored when we
// realize the assembly at the end of the deformation
let mut target_column = motion_proj.column_mut(next_column_index);
target_column += elt_motion.velocity;
self.elements.update_silent(
|elts| elts[elt_motion.key].column_index = Some(next_column_index)
);
// give a column index to each moving element that doesn't have one yet.
// this temporarily breaks invariant (1), but the invariant will be
// restored when we realize the assembly at the end of the deformation.
// in the process, we find out how many matrix columns we'll need to
// hold the deformation
let realized_dim = self.tangent.with(|tan| tan.assembly_dim());
let motion_dim = self.elements.update_silent(|elts| {
let mut next_column_index = realized_dim;
for elt_motion in motion.iter() {
let moving_elt = &mut elts[elt_motion.key];
if moving_elt.column_index.is_none() {
moving_elt.column_index = Some(next_column_index);
next_column_index += 1;
}
}
next_column_index
});
// project the element motions onto the tangent space of the solution
// variety and sum them to get a deformation of the whole assembly. the
// matrix `motion_proj` that holds the deformation has extra columns for
// any moving elements that aren't reflected in the saved tangent space
const ELEMENT_DIM: usize = 5;
let mut motion_proj = DMatrix::zeros(ELEMENT_DIM, motion_dim);
for elt_motion in motion {
// we can unwrap the column index because we know that every moving
// element has one at this point
let column_index = self.elements.with_untracked(
|elts| elts[elt_motion.key].column_index.unwrap()
);
if column_index < realized_dim {
// this element had a column index when we started, so by
// invariant (1), it's reflected in the tangent space
let mut target_columns = motion_proj.columns_mut(0, realized_dim);
target_columns += self.tangent.with(
|tan| tan.proj(&elt_motion.velocity, column_index)
);
} else {
// this element didn't have a column index when we started, so
// by invariant (2), it's unconstrained
let mut target_column = motion_proj.column_mut(column_index);
target_column += elt_motion.velocity;
}
}
// step each element along the mass shell geodesic that matches its