Introduce a regulator trait

This will provide a common interface for Lorentz product regulators,
curvature regulators, and hopefully all the other regulators too.
This commit is contained in:
Aaron Fenyes 2025-03-27 00:29:27 -07:00
parent 00f60b0e90
commit 126d4c0cce
3 changed files with 75 additions and 35 deletions

View file

@ -1,7 +1,7 @@
use nalgebra::{DMatrix, DVector, DVectorView, Vector3};
use rustc_hash::FxHashMap;
use slab::Slab;
use std::{collections::BTreeSet, sync::atomic::{AtomicU64, Ordering}};
use std::{collections::BTreeSet, rc::Rc, sync::atomic::{AtomicU64, Ordering}};
use sycamore::prelude::*;
use web_sys::{console, wasm_bindgen::JsValue}; /* DEBUG */
@ -132,14 +132,35 @@ impl Element {
}
}
#[derive(Clone, Copy)]
pub trait Regulator {
// get information
fn subjects(&self) -> Vec<ElementKey>;
fn measurement(&self) -> ReadSignal<f64>;
fn set_point(&self) -> Signal<SpecifiedValue>;
// write problem data
fn write_to_problem(&self, problem: &mut ConstraintProblem, elts: &Slab<Element>);
}
pub struct ProductRegulator {
pub subjects: [ElementKey; 2],
pub measurement: ReadSignal<f64>,
pub set_point: Signal<SpecifiedValue>
}
impl ProductRegulator {
impl Regulator for ProductRegulator {
fn subjects(&self) -> Vec<ElementKey> {
self.subjects.into()
}
fn measurement(&self) -> ReadSignal<f64> {
self.measurement
}
fn set_point(&self) -> Signal<SpecifiedValue> {
self.set_point
}
fn write_to_problem(&self, problem: &mut ConstraintProblem, elts: &Slab<Element>) {
self.set_point.with_untracked(|set_pt| {
if let Some(val) = set_pt.value {
@ -169,7 +190,7 @@ type AssemblyMotion<'a> = Vec<ElementMotion<'a>>;
pub struct Assembly {
// elements and regulators
pub elements: Signal<Slab<Element>>,
pub regulators: Signal<Slab<ProductRegulator>>,
pub regulators: Signal<Slab<Rc<dyn Regulator>>>,
// solution variety tangent space. the basis vectors are stored in
// configuration matrix format, ordered according to the elements' column
@ -240,19 +261,23 @@ impl Assembly {
);
}
fn insert_regulator(&self, regulator: ProductRegulator) {
let subjects = regulator.subjects;
let key = self.regulators.update(|regs| regs.insert(regulator));
let subject_regulators = self.elements.with(
|elts| subjects.map(|subj| elts[subj].regulators)
fn insert_regulator(&self, regulator: Rc<dyn Regulator>) {
let subjects = regulator.subjects();
let key = self.regulators.update(
|regs| regs.insert(regulator)
);
let subject_regulators: Vec<_> = self.elements.with(
|elts| subjects.into_iter().map(
|subj| elts[subj].regulators
).collect()
);
for regulators in subject_regulators {
regulators.update(|regs| regs.insert(key));
}
}
pub fn insert_new_regulator(self, subjects: [ElementKey; 2]) {
// create and insert a new regulator
pub fn insert_new_product_regulator(self, subjects: [ElementKey; 2]) {
// create and insert a new product regulator
let measurement = self.elements.map(
move |elts| {
let representations = subjects.map(|subj| elts[subj].representation);
@ -264,26 +289,31 @@ impl Assembly {
}
);
let set_point = create_signal(SpecifiedValue::from_empty_spec());
self.insert_regulator(ProductRegulator {
self.insert_regulator(Rc::new(ProductRegulator {
subjects: subjects,
measurement: measurement,
set_point: set_point
});
}));
/* DEBUG */
// print an updated list of regulators
console::log_1(&JsValue::from("Regulators:"));
self.regulators.with(|regs| {
for (_, reg) in regs.into_iter() {
console::log_5(
&JsValue::from(" "),
&JsValue::from(reg.subjects[0]),
&JsValue::from(reg.subjects[1]),
&JsValue::from(":"),
&reg.set_point.with_untracked(
|set_pt| JsValue::from(set_pt.spec.as_str())
console::log_1(&JsValue::from(format!(
" {:?}: {}",
reg.subjects(),
reg.set_point().with_untracked(
|set_pt| {
let spec = &set_pt.spec;
if spec.is_empty() {
"__".to_string()
} else {
spec.clone()
}
}
)
);
)));
}
});