forked from 1b-agent/fieldcraft-upstream
Model definition: sets by geometry name, materials, sections, couplings, BCs, loads, steps, check (#16)
* model: split nodes and elements into a mesh module (no behaviour change) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NmAttHhUZTokgPeEJia8sm * model: sets by geometry name, materials and units, sections, couplings, BCs, loads, steps and the check Sets bind to persistent geometry names through the mesh's geometry tags (element, element face/edge and node classification) and resolve against the current mesh, so they survive a remesh. Steps list their active loads and boundary conditions explicitly. Model::check names every missing or bad item; Model::resolve gives the writers' view. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NmAttHhUZTokgPeEJia8sm * engine: model definition commands (sets, materials, sections, RPs, couplings, BCs, loads, steps, tags, check) Each definition has create/edit/delete with its model JSON form as parameters; model.step.activate and model.activity drive the explicit step table; mesh.tag records where the mesh lies on the geometry; model.check and model.set.resolve report against the current mesh. Hostile params run against an empty and a fully defined session. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NmAttHhUZTokgPeEJia8sm * docs: model definition in architecture and roadmap Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NmAttHhUZTokgPeEJia8sm * model, engine: review cleanups Validated deserialization (a file replays through the checked methods), interned geometry tags by index, set resolution with tag bitsets and sorted vectors, one delete policy (a load or BC listed by a step is in use), shared helpers (context, remove_existing, step_mut, opt/req/name/listed), dead code removed, Resolved without a per-element section map. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NmAttHhUZTokgPeEJia8sm * model: mesh-independent force distribution, tractions, stable reference point labels Force and moment on a set default to a total, split by consistent nodal weights over the set's faces (or equally over a node set); per_node is an explicit opt-in. Traction is force per area. resolve() expands them to nodal values for every writer and the solver. Reference points keep a stored node label taken from the top of the label range. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NmAttHhUZTokgPeEJia8sm --------- Co-authored-by: jyviko <2501648+jyviko@users.noreply.github.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
23 files changed
+4296
-268
No files matched your search
@@ -1,11 +1,14 @@
|
||||
//! The command registry. Each area has its own module; [`ALL`] lists every command.
|
||||
|
||||
pub(crate) mod define;
|
||||
mod geometry;
|
||||
mod mesh;
|
||||
mod model;
|
||||
mod tags;
|
||||
|
||||
use modelcraft_model::MAX_LABEL;
|
||||
use serde_json::Value;
|
||||
use serde::Deserialize;
|
||||
use serde_json::{Value, json};
|
||||
|
||||
use crate::{CommandSpec, EngineError, Result};
|
||||
|
||||
@@ -22,6 +25,37 @@ pub static ALL: &[CommandSpec] = &[
|
||||
mesh::QUALITY,
|
||||
mesh::DELAUNAY_POINTS,
|
||||
mesh::SURFACE_CHECK,
|
||||
tags::TAG,
|
||||
tags::TAG_CLEAR,
|
||||
model::UNITS,
|
||||
model::CHECK,
|
||||
model::SET_RESOLVE,
|
||||
define::SET_CREATE,
|
||||
define::SET_EDIT,
|
||||
define::SET_DELETE,
|
||||
define::MATERIAL_CREATE,
|
||||
define::MATERIAL_EDIT,
|
||||
define::MATERIAL_DELETE,
|
||||
define::SECTION_CREATE,
|
||||
define::SECTION_EDIT,
|
||||
define::SECTION_DELETE,
|
||||
define::REFERENCE_POINT_CREATE,
|
||||
define::REFERENCE_POINT_EDIT,
|
||||
define::REFERENCE_POINT_DELETE,
|
||||
define::COUPLING_CREATE,
|
||||
define::COUPLING_EDIT,
|
||||
define::COUPLING_DELETE,
|
||||
define::BOUNDARY_CONDITION_CREATE,
|
||||
define::BOUNDARY_CONDITION_EDIT,
|
||||
define::BOUNDARY_CONDITION_DELETE,
|
||||
define::LOAD_CREATE,
|
||||
define::LOAD_EDIT,
|
||||
define::LOAD_DELETE,
|
||||
define::STEP_CREATE,
|
||||
define::STEP_EDIT,
|
||||
define::STEP_DELETE,
|
||||
define::STEP_ACTIVATE,
|
||||
define::ACTIVITY,
|
||||
];
|
||||
|
||||
/// A required label parameter (1..=u32::MAX; the model checks its own range).
|
||||
@@ -72,3 +106,25 @@ pub(crate) fn optional_number(p: &Value, key: &str, default: f64) -> Result<f64>
|
||||
Some(v) => v.as_f64().ok_or_else(|| EngineError::Params(format!("`{key}` must be a number"))),
|
||||
}
|
||||
}
|
||||
|
||||
/// The `name` parameter.
|
||||
pub(crate) fn name(p: &Value) -> Result<&str> {
|
||||
p.get("name").and_then(Value::as_str).ok_or_else(|| EngineError::Params("`name` must be a name".into()))
|
||||
}
|
||||
|
||||
/// An optional parameter read as `T`'s JSON form; `None` when it is absent.
|
||||
pub(crate) fn opt<'a, T: Deserialize<'a>>(p: &'a Value, key: &str) -> Result<Option<T>> {
|
||||
p.get(key).map(|v| T::deserialize(v).map_err(|e| EngineError::Params(format!("`{key}`: {e}")))).transpose()
|
||||
}
|
||||
|
||||
/// A required parameter read as `T`'s JSON form.
|
||||
pub(crate) fn req<'a, T: Deserialize<'a>>(p: &'a Value, key: &str) -> Result<T> {
|
||||
opt(p, key)?.ok_or_else(|| EngineError::Params(format!("`{key}` is required")))
|
||||
}
|
||||
|
||||
/// Entries listed in a report: the first ones, and how many there are.
|
||||
pub(crate) const LISTED: usize = 100;
|
||||
|
||||
pub(crate) fn listed<T: serde::Serialize>(v: &[T]) -> Value {
|
||||
json!({"count": v.len(), "labels": v.get(..LISTED).unwrap_or(v)})
|
||||
}
|
||||
Reference in new issue
Block a user