sim_lib_femm_function/
model_value.rs1use std::any::Any;
7
8use sim_kernel::{
9 ClassId, ClassRef, Cx, DefaultFactory, Expr, Factory, Object, ObjectEncode, ObjectEncoding,
10 Result as KernelResult, Symbol, Value,
11};
12use sim_lib_femm_core::{Formulation, PhysicsKind};
13use sim_lib_femm_mesh::FemmModel;
14
15#[derive(Clone)]
32pub struct ModelValue {
33 pub model: FemmModel,
35}
36
37impl Object for ModelValue {
38 fn display(&self, _cx: &mut Cx) -> KernelResult<String> {
39 Ok(format!(
40 "#<femm-model {}:{}>",
41 self.model.id.0, self.model.name
42 ))
43 }
44
45 fn as_any(&self) -> &dyn Any {
46 self
47 }
48}
49
50impl sim_kernel::ObjectCompat for ModelValue {
51 fn class(&self, cx: &mut Cx) -> KernelResult<ClassRef> {
52 if let Some(class) = cx
53 .registry()
54 .class_by_symbol(&Symbol::qualified("femm", "Model"))
55 {
56 return Ok(class.clone());
57 }
58 DefaultFactory.class_stub(ClassId(34), Symbol::qualified("femm", "Model"))
59 }
60 fn as_expr(&self, cx: &mut Cx) -> KernelResult<Expr> {
61 sim_citizen::constructor_expr(cx, self)
62 }
63 fn as_table(&self, cx: &mut Cx) -> KernelResult<Value> {
64 cx.factory().table(vec![
65 (
66 Symbol::new("kind"),
67 cx.factory().string("femm-model".to_owned())?,
68 ),
69 (
70 Symbol::new("id"),
71 cx.factory().string(self.model.id.0.to_string())?,
72 ),
73 (
74 Symbol::new("name"),
75 cx.factory().string(self.model.name.to_string())?,
76 ),
77 (
78 Symbol::new("query-kind"),
79 cx.factory().string("solution".to_owned())?,
80 ),
81 ])
82 }
83 fn as_object_encoder(&self) -> Option<&dyn ObjectEncode> {
84 Some(self)
85 }
86}
87
88impl ObjectEncode for ModelValue {
89 fn object_encoding(&self, _cx: &mut Cx) -> KernelResult<ObjectEncoding> {
90 Ok(ObjectEncoding::Constructor {
91 class: model_class_symbol(),
92 args: model_constructor_args(self),
93 })
94 }
95}
96
97impl sim_citizen::Citizen for ModelValue {
98 fn citizen_symbol() -> Symbol {
99 model_class_symbol()
100 }
101
102 fn citizen_version() -> u32 {
103 1
104 }
105
106 fn citizen_arity() -> usize {
107 5
108 }
109
110 fn citizen_fields() -> &'static [&'static str] {
111 &["id", "name", "physics", "formulation", "params"]
112 }
113}
114
115pub fn model_value(model: FemmModel) -> ModelValue {
117 ModelValue { model }
118}
119
120fn model_class_symbol() -> Symbol {
121 Symbol::qualified("femm", "Model")
122}
123
124fn model_constructor_args(value: &ModelValue) -> Vec<Expr> {
125 vec![
126 Expr::Symbol(Symbol::new("v1")),
127 int_expr(value.model.id.0),
128 Expr::String(value.model.name.to_string()),
129 Expr::String(physics_name(&value.model.physics).to_owned()),
130 Expr::String(formulation_name(&value.model.formulation).to_owned()),
131 Expr::List(
132 value
133 .model
134 .inputs
135 .iter()
136 .map(|param| Expr::String(param.name.to_string()))
137 .collect(),
138 ),
139 ]
140}
141
142fn int_expr(value: impl ToString) -> Expr {
143 Expr::Number(sim_kernel::NumberLiteral {
144 domain: Symbol::qualified("citizen", "int"),
145 canonical: value.to_string(),
146 })
147}
148
149fn physics_name(physics: &PhysicsKind) -> &'static str {
150 match physics {
151 PhysicsKind::Magnetostatic => "magnetostatic",
152 PhysicsKind::MagneticsHarmonic => "magnetics-harmonic",
153 PhysicsKind::Electrostatic => "electrostatic",
154 PhysicsKind::HeatSteady => "heat-steady",
155 PhysicsKind::CurrentSteady => "current-steady",
156 }
157}
158
159fn formulation_name(formulation: &Formulation) -> &'static str {
160 match formulation {
161 Formulation::Planar => "planar",
162 Formulation::Axisymmetric => "axisymmetric",
163 }
164}