forked from glen/dyna3
Enforce the validity of set point specifications
Make a regulator's set point specification private, and split the set point into a private writable signal and a public read-only signal. The set point can now be initialized only through the factory method `insert_new_regulator` and changed only through the setter method `try_specify_set_point`, which both ensure that the set point specification is valid and consistent with the set point.
This commit is contained in:
parent
bbd0835a8f
commit
f2e84fb64a
3 changed files with 74 additions and 52 deletions
|
@ -6,10 +6,8 @@ use crate::{
|
|||
AppState,
|
||||
assembly::{
|
||||
Assembly,
|
||||
Regulator,
|
||||
Element
|
||||
},
|
||||
engine::Q
|
||||
}
|
||||
};
|
||||
|
||||
/* DEBUG */
|
||||
|
@ -199,49 +197,8 @@ pub fn AddRemove() -> View {
|
|||
(subject_vec[0].clone(), subject_vec[1].clone())
|
||||
}
|
||||
);
|
||||
let measurement = state.assembly.elements.map(
|
||||
move |elts| {
|
||||
let reps = (
|
||||
elts[subjects.0].representation.get_clone(),
|
||||
elts[subjects.1].representation.get_clone()
|
||||
);
|
||||
reps.0.dot(&(&*Q * reps.1))
|
||||
}
|
||||
);
|
||||
let set_point = create_signal(None);
|
||||
state.assembly.insert_regulator(Regulator {
|
||||
subjects: subjects,
|
||||
measurement: measurement,
|
||||
set_point: set_point,
|
||||
set_point_spec: create_signal(String::new())
|
||||
});
|
||||
state.assembly.insert_new_regulator(subjects);
|
||||
state.selection.update(|sel| sel.clear());
|
||||
|
||||
/* DEBUG */
|
||||
// print updated regulator list
|
||||
console::log_1(&JsValue::from("Regulators:"));
|
||||
state.assembly.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(":"),
|
||||
&JsValue::from(reg.set_point.get_untracked())
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
// update the realization when the regulator becomes
|
||||
// a constraint, or is edited while acting as a constraint
|
||||
create_effect(move || {
|
||||
console::log_1(&JsValue::from(
|
||||
format!("Updated constraint with subjects ({}, {})", subjects.0, subjects.1)
|
||||
));
|
||||
if set_point.with(|set_pt| set_pt.is_some()) {
|
||||
state.assembly.realize();
|
||||
}
|
||||
});
|
||||
}
|
||||
) { "🔗" }
|
||||
select(bind:value=assembly_name) { /* DEBUG */ // example assembly chooser
|
||||
|
|
|
@ -5,7 +5,7 @@ use std::{collections::BTreeSet, sync::atomic::{AtomicU64, Ordering}};
|
|||
use sycamore::prelude::*;
|
||||
use web_sys::{console, wasm_bindgen::JsValue}; /* DEBUG */
|
||||
|
||||
use crate::engine::{realize_gram, local_unif_to_std, ConfigSubspace, PartialMatrix};
|
||||
use crate::engine::{Q, local_unif_to_std, realize_gram, ConfigSubspace, PartialMatrix};
|
||||
|
||||
// the types of the keys we use to access an assembly's elements and regulators
|
||||
pub type ElementKey = usize;
|
||||
|
@ -111,21 +111,38 @@ impl Element {
|
|||
}
|
||||
}
|
||||
|
||||
// `set_point_spec` must always be a valid specification of `set_point`
|
||||
// `set_point_spec` is always a valid specification of `set_point`
|
||||
// ┌────────────┬─────────────────────────────────────────────────────┐
|
||||
// │`set_point` │ `set_point_spec` │
|
||||
// ┝━━━━━━━━━━━━┿━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┥
|
||||
// │`Some(x)` │ a string that parses to the floating-point value `x`│
|
||||
// ├────────────┼─────────────────────────────────────────────────────┤
|
||||
// │`None` │ the empty string │
|
||||
// └────────────┴─────────────────────────────────────────────────────┘
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct Regulator {
|
||||
pub subjects: (ElementKey, ElementKey),
|
||||
pub measurement: ReadSignal<f64>,
|
||||
pub set_point: Signal<Option<f64>>,
|
||||
pub set_point_spec: Signal<String>
|
||||
pub set_point: ReadSignal<Option<f64>>,
|
||||
|
||||
set_point_writable: Signal<Option<f64>>,
|
||||
set_point_spec: Signal<String>
|
||||
}
|
||||
|
||||
impl Regulator {
|
||||
pub fn get_set_point_spec_clone(&self) -> String {
|
||||
self.set_point_spec.get_clone()
|
||||
}
|
||||
|
||||
pub fn get_set_point_spec_clone_untracked(&self) -> String {
|
||||
self.set_point_spec.get_clone_untracked()
|
||||
}
|
||||
|
||||
pub fn try_specify_set_point(&self, spec: String) -> bool {
|
||||
match spec.parse::<f64>() {
|
||||
Err(_) if !spec.is_empty() => false,
|
||||
set_pt => {
|
||||
self.set_point.set(set_pt.ok());
|
||||
self.set_point_writable.set(set_pt.ok());
|
||||
self.set_point_spec.set(spec);
|
||||
true
|
||||
}
|
||||
|
@ -227,6 +244,54 @@ impl Assembly {
|
|||
subject_regulators.1.update(|regs| regs.insert(key));
|
||||
}
|
||||
|
||||
pub fn insert_new_regulator(self, subjects: (ElementKey, ElementKey)) {
|
||||
// create and insert a new regulator
|
||||
let measurement = self.elements.map(
|
||||
move |elts| {
|
||||
let reps = (
|
||||
elts[subjects.0].representation.get_clone(),
|
||||
elts[subjects.1].representation.get_clone()
|
||||
);
|
||||
reps.0.dot(&(&*Q * reps.1))
|
||||
}
|
||||
);
|
||||
let set_point_writable = create_signal(None);
|
||||
let set_point = set_point_writable.split().0;
|
||||
self.insert_regulator(Regulator {
|
||||
subjects: subjects,
|
||||
measurement: measurement,
|
||||
set_point: set_point,
|
||||
set_point_writable: set_point_writable,
|
||||
set_point_spec: create_signal(String::new())
|
||||
});
|
||||
|
||||
/* DEBUG */
|
||||
// print updated regulator list
|
||||
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(":"),
|
||||
&JsValue::from(reg.set_point.get_untracked())
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
// update the realization when the regulator becomes a constraint, or is
|
||||
// edited while acting as a constraint
|
||||
create_effect(move || {
|
||||
console::log_1(&JsValue::from(
|
||||
format!("Updated constraint with subjects ({}, {})", subjects.0, subjects.1)
|
||||
));
|
||||
if set_point.with(|set_pt| set_pt.is_some()) {
|
||||
self.realize();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// --- realization ---
|
||||
|
||||
pub fn realize(&self) {
|
||||
|
|
|
@ -20,14 +20,14 @@ use crate::{
|
|||
#[component(inline_props)]
|
||||
fn RegulatorInput(regulator: Regulator) -> View {
|
||||
let valid = create_signal(true);
|
||||
let value = create_signal(regulator.set_point_spec.get_clone_untracked());
|
||||
let value = create_signal(regulator.get_set_point_spec_clone_untracked());
|
||||
|
||||
// this closure resets the input value to the regulator's set point
|
||||
// specification, which is always a valid specification
|
||||
let reset_value = move || {
|
||||
batch(|| {
|
||||
valid.set(true);
|
||||
value.set(regulator.set_point_spec.get_clone());
|
||||
value.set(regulator.get_set_point_spec_clone());
|
||||
})
|
||||
};
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue