use std::any::Any;
use sim_kernel::{
ClassId, ClassRef, Cx, DefaultFactory, Expr, Factory, Object, ObjectEncode, ObjectEncoding,
Result as KernelResult, Symbol, Value,
};
use sim_lib_femm_core::{Formulation, PhysicsKind};
use sim_lib_femm_mesh::FemmModel;
#[derive(Clone)]
pub struct ModelValue {
pub model: FemmModel,
}
impl Object for ModelValue {
fn display(&self, _cx: &mut Cx) -> KernelResult<String> {
Ok(format!(
"#<femm-model {}:{}>",
self.model.id.0, self.model.name
))
}
fn as_any(&self) -> &dyn Any {
self
}
}
impl sim_kernel::ObjectCompat for ModelValue {
fn class(&self, cx: &mut Cx) -> KernelResult<ClassRef> {
if let Some(class) = cx
.registry()
.class_by_symbol(&Symbol::qualified("femm", "Model"))
{
return Ok(class.clone());
}
DefaultFactory.class_stub(ClassId(34), Symbol::qualified("femm", "Model"))
}
fn as_expr(&self, cx: &mut Cx) -> KernelResult<Expr> {
sim_citizen::constructor_expr(cx, self)
}
fn as_table(&self, cx: &mut Cx) -> KernelResult<Value> {
cx.factory().table(vec![
(
Symbol::new("kind"),
cx.factory().string("femm-model".to_owned())?,
),
(
Symbol::new("id"),
cx.factory().string(self.model.id.0.to_string())?,
),
(
Symbol::new("name"),
cx.factory().string(self.model.name.to_string())?,
),
(
Symbol::new("query-kind"),
cx.factory().string("solution".to_owned())?,
),
])
}
fn as_object_encoder(&self) -> Option<&dyn ObjectEncode> {
Some(self)
}
}
impl ObjectEncode for ModelValue {
fn object_encoding(&self, _cx: &mut Cx) -> KernelResult<ObjectEncoding> {
Ok(ObjectEncoding::Constructor {
class: model_class_symbol(),
args: model_constructor_args(self),
})
}
}
impl sim_citizen::Citizen for ModelValue {
fn citizen_symbol() -> Symbol {
model_class_symbol()
}
fn citizen_version() -> u32 {
1
}
fn citizen_arity() -> usize {
5
}
fn citizen_fields() -> &'static [&'static str] {
&["id", "name", "physics", "formulation", "params"]
}
}
pub fn model_value(model: FemmModel) -> ModelValue {
ModelValue { model }
}
fn model_class_symbol() -> Symbol {
Symbol::qualified("femm", "Model")
}
fn model_constructor_args(value: &ModelValue) -> Vec<Expr> {
vec![
Expr::Symbol(Symbol::new("v1")),
int_expr(value.model.id.0),
Expr::String(value.model.name.to_string()),
Expr::String(physics_name(&value.model.physics).to_owned()),
Expr::String(formulation_name(&value.model.formulation).to_owned()),
Expr::List(
value
.model
.inputs
.iter()
.map(|param| Expr::String(param.name.to_string()))
.collect(),
),
]
}
fn int_expr(value: impl ToString) -> Expr {
Expr::Number(sim_kernel::NumberLiteral {
domain: Symbol::qualified("citizen", "int"),
canonical: value.to_string(),
})
}
fn physics_name(physics: &PhysicsKind) -> &'static str {
match physics {
PhysicsKind::Magnetostatic => "magnetostatic",
PhysicsKind::MagneticsHarmonic => "magnetics-harmonic",
PhysicsKind::Electrostatic => "electrostatic",
PhysicsKind::HeatSteady => "heat-steady",
PhysicsKind::CurrentSteady => "current-steady",
}
}
fn formulation_name(formulation: &Formulation) -> &'static str {
match formulation {
Formulation::Planar => "planar",
Formulation::Axisymmetric => "axisymmetric",
}
}