Pause realization while loading assemblies

This avoids redundant realizations as we set an assembly's regulators
during loading. Adding some regulators to the low-curvature assembly
confirms that the feature is working as intended.
This commit is contained in:
Aaron Fenyes 2025-07-02 13:59:22 -07:00
parent 5864017e6f
commit 40d665d8ac
2 changed files with 90 additions and 9 deletions

View file

@ -6,7 +6,8 @@ use crate::{
AppState, AppState,
engine, engine,
engine::DescentHistory, engine::DescentHistory,
assembly::{Assembly, InversiveDistanceRegulator, Point, Sphere} assembly::{Assembly, InversiveDistanceRegulator, Point, Sphere},
specified::SpecifiedValue
}; };
/* DEBUG */ /* DEBUG */
@ -67,6 +68,7 @@ fn load_gen_assemb(assembly: &Assembly) {
// load an example assembly for testing. this code will be removed once we've // load an example assembly for testing. this code will be removed once we've
// built a more formal test assembly system // built a more formal test assembly system
fn load_low_curv_assemb(assembly: &Assembly) { fn load_low_curv_assemb(assembly: &Assembly) {
// create the spheres
let a = 0.75_f64.sqrt(); let a = 0.75_f64.sqrt();
let _ = assembly.try_insert_element( let _ = assembly.try_insert_element(
Sphere::new( Sphere::new(
@ -132,6 +134,56 @@ fn load_low_curv_assemb(assembly: &Assembly) {
engine::sphere(2.0/3.0, 4.0/3.0 * a, 0.0, 1.0/3.0) engine::sphere(2.0/3.0, 4.0/3.0 * a, 0.0, 1.0/3.0)
) )
); );
// impose the desired tangencies and make the sides planar
let index_range = 1..=3;
let [central, assemb_plane] = ["central", "assemb_plane"].map(
|id| assembly.elements_by_id.with_untracked(
|elts_by_id| elts_by_id[id].clone()
)
);
let sides = index_range.clone().map(
|k| assembly.elements_by_id.with_untracked(
|elts_by_id| elts_by_id[&format!("side{k}")].clone()
)
);
let corners = index_range.map(
|k| assembly.elements_by_id.with_untracked(
|elts_by_id| elts_by_id[&format!("corner{k}")].clone()
)
);
for plane in [assemb_plane.clone()].into_iter().chain(sides.clone()) {
// fix the curvature of each plane
let curvature = plane.regulators().with_untracked(
|regs| regs.first().unwrap().clone()
);
curvature.set_point().set(SpecifiedValue::try_from("0".to_string()).unwrap());
}
let all_perpendicular = [central.clone()].into_iter()
.chain(sides.clone())
.chain(corners.clone());
for sphere in all_perpendicular {
// make each side and packed sphere perpendicular to the assembly plane
let right_angle = InversiveDistanceRegulator::new([sphere, assemb_plane.clone()]);
right_angle.set_point.set(SpecifiedValue::try_from("0".to_string()).unwrap());
assembly.insert_regulator(Rc::new(right_angle));
}
for sphere in sides.clone().chain(corners.clone()) {
// make each side and corner sphere tangent to the central sphere
let tangency = InversiveDistanceRegulator::new([sphere.clone(), central.clone()]);
tangency.set_point.set(SpecifiedValue::try_from("-1".to_string()).unwrap());
assembly.insert_regulator(Rc::new(tangency));
}
for (side_index, side) in sides.enumerate() {
// make each side tangent to the two adjacent corner spheres
for (corner_index, corner) in corners.clone().enumerate() {
if side_index != corner_index {
let tangency = InversiveDistanceRegulator::new([side.clone(), corner]);
tangency.set_point.set(SpecifiedValue::try_from("-1".to_string()).unwrap());
assembly.insert_regulator(Rc::new(tangency));
}
}
}
} }
fn load_pointed_assemb(assembly: &Assembly) { fn load_pointed_assemb(assembly: &Assembly) {
@ -192,6 +244,9 @@ pub fn AddRemove() -> View {
let state = use_context::<AppState>(); let state = use_context::<AppState>();
let assembly = &state.assembly; let assembly = &state.assembly;
// pause realization
assembly.keep_realized.set(false);
// clear state // clear state
assembly.regulators.update(|regs| regs.clear()); assembly.regulators.update(|regs| regs.clear());
assembly.elements.update(|elts| elts.clear()); assembly.elements.update(|elts| elts.clear());
@ -206,6 +261,9 @@ pub fn AddRemove() -> View {
"pointed" => load_pointed_assemb(assembly), "pointed" => load_pointed_assemb(assembly),
_ => () _ => ()
}; };
// resume realization
assembly.keep_realized.set(true);
}); });
}); });

View file

@ -552,6 +552,10 @@ pub struct Assembly {
// indexing // indexing
pub elements_by_id: Signal<BTreeMap<String, Rc<dyn Element>>>, pub elements_by_id: Signal<BTreeMap<String, Rc<dyn Element>>>,
// realization control
pub keep_realized: Signal<bool>,
pub needs_realization: Signal<bool>,
// realization diagnostics // realization diagnostics
pub realization_status: Signal<Result<(), String>>, pub realization_status: Signal<Result<(), String>>,
pub descent_history: Signal<DescentHistory> pub descent_history: Signal<DescentHistory>
@ -559,14 +563,30 @@ pub struct Assembly {
impl Assembly { impl Assembly {
pub fn new() -> Assembly { pub fn new() -> Assembly {
Assembly { // create an assembly
let assembly = Assembly {
elements: create_signal(BTreeSet::new()), elements: create_signal(BTreeSet::new()),
regulators: create_signal(BTreeSet::new()), regulators: create_signal(BTreeSet::new()),
tangent: create_signal(ConfigSubspace::zero(0)), tangent: create_signal(ConfigSubspace::zero(0)),
elements_by_id: create_signal(BTreeMap::default()), elements_by_id: create_signal(BTreeMap::default()),
keep_realized: create_signal(true),
needs_realization: create_signal(false),
realization_status: create_signal(Ok(())), realization_status: create_signal(Ok(())),
descent_history: create_signal(DescentHistory::new()) descent_history: create_signal(DescentHistory::new())
} };
// realize the assembly whenever it becomes simultaneously true that
// we're trying to keep it realized and it needs realization
let assembly_for_effect = assembly.clone();
create_effect(move || {
let should_realize = assembly_for_effect.keep_realized.get()
&& assembly_for_effect.needs_realization.get();
if should_realize {
assembly_for_effect.realize();
}
});
assembly
} }
// --- inserting elements and regulators --- // --- inserting elements and regulators ---
@ -627,7 +647,7 @@ impl Assembly {
regulators.update(|regs| regs.insert(regulator.clone())); regulators.update(|regs| regs.insert(regulator.clone()));
} }
// update the realization when the regulator becomes a constraint, or is // request a realization when the regulator becomes a constraint, or is
// edited while acting as a constraint // edited while acting as a constraint
let self_for_effect = self.clone(); let self_for_effect = self.clone();
create_effect(move || { create_effect(move || {
@ -636,7 +656,7 @@ impl Assembly {
console_log!("Updated regulator with subjects {:?}", regulator.subjects()); console_log!("Updated regulator with subjects {:?}", regulator.subjects());
if regulator.try_activate() { if regulator.try_activate() {
self_for_effect.realize(); self_for_effect.needs_realization.set(true);
} }
}); });
@ -731,6 +751,9 @@ impl Assembly {
// save the tangent space // save the tangent space
self.tangent.set_silent(tangent); self.tangent.set_silent(tangent);
// clear the realization request flag
self.needs_realization.set(false);
}, },
Err(message) => { Err(message) => {
// report the realization status. the `Err(message)` we're // report the realization status. the `Err(message)` we're
@ -826,10 +849,10 @@ impl Assembly {
}); });
} }
// bring the configuration back onto the solution variety. this also // request a realization to bring the configuration back onto the
// gets the elements' column indices and the saved tangent space back in // solution variety. this also gets the elements' column indices and the
// sync // saved tangent space back in sync
self.realize(); self.needs_realization.set(true);
} }
} }