forked from 1b-agent/fieldcraft-upstream
Rename the project to FieldCraft
Crates fieldcraft-*, binaries fieldcraft and fieldcraft-cli, the .fieldcraft file (format tag fieldcraft/1, manifest fieldcraft.json), FIELDCRAFT_* environment variables, the MCP server name, egui widget ids (fc_*), the app icon document FieldCraft.icon and its generated family, docs and licences. No compatibility shim: no files of the earlier name exist. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NmAttHhUZTokgPeEJia8sm
This commit is contained in:
1 parent
9bc4e1b182
commit
d5bd74570f
268 files changed
+1666
-1666
No files matched your search
+10
-10
@@ -6,7 +6,7 @@
|
||||
//! # Layout
|
||||
//!
|
||||
//! The deck is *flat*: nodes, elements, sets, materials, sections and couplings sit at model level,
|
||||
//! with no parts, assembly or instances. ModelCraft has one mesh with model-wide labels and no
|
||||
//! with no parts, assembly or instances. FieldCraft has one mesh with model-wide labels and no
|
||||
//! instance transforms, so a part/assembly wrapper would only prefix every set name with an
|
||||
//! instance name (`Part-1-1.root`) and bring the 80-character limit on the joined name closer. When
|
||||
//! the model gains several parts or instances the writer switches to the part/assembly form.
|
||||
@@ -53,7 +53,7 @@
|
||||
//!
|
||||
//! # Element types
|
||||
//!
|
||||
//! | ModelCraft | Solid section | Shell section | Beam | Rod |
|
||||
//! | FieldCraft | Solid section | Shell section | Beam | Rod |
|
||||
//! |---|---|---|---|---|
|
||||
//! | tet4 | C3D4 (H) | | | |
|
||||
//! | tet10 | C3D10 (H) | | | |
|
||||
@@ -76,7 +76,7 @@
|
||||
//! differs by direction and a spring along a skew fixed vector are reported (they need a local
|
||||
//! orientation, not written yet).
|
||||
//!
|
||||
//! | ModelCraft | Plane stress | Plane strain | Axisymmetric |
|
||||
//! | FieldCraft | Plane stress | Plane strain | Axisymmetric |
|
||||
//! |---|---|---|---|
|
||||
//! | tri3 | CPS3 | CPE3 | CAX3 |
|
||||
//! | tri6 | CPS6 | CPE6 | CAX6 |
|
||||
@@ -115,7 +115,7 @@
|
||||
use std::collections::{BTreeMap, BTreeSet};
|
||||
use std::fmt::Write as _;
|
||||
|
||||
use modelcraft_model::{
|
||||
use fieldcraft_model::{
|
||||
BeamProfile, BoundaryCondition, CouplingKind, Elastic, Element, ElementKind, Hardening, Integration, Load, Model, OutputVariable, Plastic,
|
||||
Procedure, Resolved, Section, SectionKind, Step, Symmetry, Target,
|
||||
};
|
||||
@@ -330,10 +330,10 @@ fn discrete_groups<'r>(model: &Model, r: &'r Resolved) -> Result<Vec<DiscreteGro
|
||||
let mut next = model.elements().keys().next_back().map_or(1, |l| l.saturating_add(1));
|
||||
let mut label = || -> Result<u32> {
|
||||
let l = next;
|
||||
if l > modelcraft_model::MAX_LABEL {
|
||||
if l > fieldcraft_model::MAX_LABEL {
|
||||
return Err(Error::Limit(format!(
|
||||
"no element label left below {} for point masses, springs and dashpots",
|
||||
modelcraft_model::MAX_LABEL as u64 + 1
|
||||
fieldcraft_model::MAX_LABEL as u64 + 1
|
||||
)));
|
||||
}
|
||||
next += 1;
|
||||
@@ -371,7 +371,7 @@ fn discrete_groups<'r>(model: &Model, r: &'r Resolved) -> Result<Vec<DiscreteGro
|
||||
}
|
||||
for s in &r.springs {
|
||||
let what = s.kind();
|
||||
let line = matches!(s.direction, modelcraft_model::ResolvedDirection::Line(_));
|
||||
let line = matches!(s.direction, fieldcraft_model::ResolvedDirection::Line(_));
|
||||
let (element_type, dofs, nodes) = match (s.second, crate::axis_dof(s.direction), line) {
|
||||
(Some(b), _, true) => (if s.dashpot { "DASHPOTA" } else { "SPRINGA" }, String::new(), vec![s.first, b]),
|
||||
(Some(b), Some(d), false) => (if s.dashpot { "DASHPOT2" } else { "SPRING2" }, format!("{d}, {d}"), vec![s.first, b]),
|
||||
@@ -556,7 +556,7 @@ impl<'a> StepLoads<'a> {
|
||||
/// `everything` is every element and the section sets that hold them (gravity on the whole
|
||||
/// model).
|
||||
fn new(model: &'a Model, r: &'a Resolved, step: &'a Step, everything: &'a (Vec<&'a str>, Vec<u32>)) -> StepLoads<'a> {
|
||||
let axisymmetric = r.extent() == Some(modelcraft_model::Extent::Revolved);
|
||||
let axisymmetric = r.extent() == Some(fieldcraft_model::Extent::Revolved);
|
||||
let mut s = StepLoads { concentrated: crate::concentrated_loads(model, r, &step.loads), axisymmetric, ..StepLoads::default() };
|
||||
let (mut gravity, mut body) = (Vec::new(), Vec::new());
|
||||
for name in &step.loads {
|
||||
@@ -637,8 +637,8 @@ impl Deck {
|
||||
None => "units not specified".to_string(),
|
||||
};
|
||||
self.line("*HEADING");
|
||||
self.line(&format!("ModelCraft model, {units}"));
|
||||
self.comment("Written by ModelCraft. The numbers are in one consistent unit system and are not converted.");
|
||||
self.line(&format!("FieldCraft model, {units}"));
|
||||
self.comment("Written by FieldCraft. The numbers are in one consistent unit system and are not converted.");
|
||||
}
|
||||
|
||||
fn nodes(&mut self, model: &Model) -> Result<()> {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
//! Solver decks: the solver-neutral model written as Abaqus input, Nastran bulk data and LS-DYNA
|
||||
//! keyword files. Each format is its own module (`abaqus`, `nastran`, `lsdyna`), written from the
|
||||
//! vendor's public reference manual in our own words; examples and expected files are our own.
|
||||
//! Writers read [`modelcraft_model::Model`] and its `resolve()` result, never another format.
|
||||
//! Writers read [`fieldcraft_model::Model`] and its `resolve()` result, never another format.
|
||||
//!
|
||||
//! Writers produce text; saving it is the caller's business (the engine's `deck.write`), so the
|
||||
//! crate stays free of the file system. [`FORMATS`] lists every writer by the name `deck.write`
|
||||
@@ -15,8 +15,8 @@ pub mod nastran;
|
||||
|
||||
use std::collections::{BTreeMap, BTreeSet};
|
||||
|
||||
use modelcraft_model::nodal::edge_pressure;
|
||||
use modelcraft_model::{Diagnostic, Load, Model, Resolved, ResolvedDirection};
|
||||
use fieldcraft_model::nodal::edge_pressure;
|
||||
use fieldcraft_model::{Diagnostic, Load, Model, Resolved, ResolvedDirection};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, thiserror::Error)]
|
||||
pub enum Error {
|
||||
@@ -25,7 +25,7 @@ pub enum Error {
|
||||
Unsupported { format: &'static str, what: String },
|
||||
/// The model is not ready to write (its check failed).
|
||||
#[error(transparent)]
|
||||
Model(#[from] modelcraft_model::Error),
|
||||
Model(#[from] fieldcraft_model::Error),
|
||||
#[error("limit reached: {0}")]
|
||||
Limit(String),
|
||||
}
|
||||
@@ -70,11 +70,11 @@ impl Format {
|
||||
/// stay (the check warns about the ones no step uses).
|
||||
pub fn with_steps(model: &Model, names: &[String]) -> Result<Model> {
|
||||
if names.is_empty() {
|
||||
return Err(Error::Model(modelcraft_model::Error::Invalid("choose at least one step to write".into())));
|
||||
return Err(Error::Model(fieldcraft_model::Error::Invalid("choose at least one step to write".into())));
|
||||
}
|
||||
if let Some(n) = names.iter().find(|n| model.step(n).is_none()) {
|
||||
let shown: String = n.chars().take(modelcraft_model::MAX_NAME_LEN).collect();
|
||||
return Err(Error::Model(modelcraft_model::Error::NotFound(format!("step `{shown}`"))));
|
||||
let shown: String = n.chars().take(fieldcraft_model::MAX_NAME_LEN).collect();
|
||||
return Err(Error::Model(fieldcraft_model::Error::NotFound(format!("step `{shown}`"))));
|
||||
}
|
||||
let mut out = model.clone();
|
||||
let dropped: Vec<String> = model.steps().iter().map(|s| s.name.clone()).filter(|s| !names.contains(s)).collect();
|
||||
@@ -84,7 +84,7 @@ pub fn with_steps(model: &Model, names: &[String]) -> Result<Model> {
|
||||
Ok(out)
|
||||
}
|
||||
|
||||
/// A fluid step: solved by ModelCraft's lattice Boltzmann solver, never written to a deck.
|
||||
/// A fluid step: solved by FieldCraft's lattice Boltzmann solver, never written to a deck.
|
||||
pub(crate) fn fluid_step(format: &'static str, step: &str) -> Error {
|
||||
Error::Unsupported { format, what: format!("fluid step `{step}` (solve it with solve.fluid; write the structural steps only)") }
|
||||
}
|
||||
@@ -155,7 +155,7 @@ pub fn concentrated_loads<'a>(model: &Model, r: &Resolved, active: impl IntoIter
|
||||
|
||||
/// The consistent nodal forces (degrees of freedom 1 and 2) of the active pressures on a 2D
|
||||
/// model's element edges, for formats that write them as concentrated loads: the model's edge
|
||||
/// integration ([`modelcraft_model::nodal::edge_pressure`]), a positive pressure pushing
|
||||
/// integration ([`fieldcraft_model::nodal::edge_pressure`]), a positive pressure pushing
|
||||
/// into the element, summed per node and direction; zero sums are left out.
|
||||
pub fn edge_pressure_loads<'a>(model: &Model, r: &Resolved, active: impl IntoIterator<Item = &'a str>) -> Result<BTreeMap<(u32, u8), f64>> {
|
||||
let mut out: BTreeMap<(u32, u8), f64> = BTreeMap::new();
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
//!
|
||||
//! Every mapping is checked by the sign of the element Jacobian in the tests.
|
||||
|
||||
use modelcraft_model::{ElementKind, Formulation, Integration, SectionKind};
|
||||
use fieldcraft_model::{ElementKind, Formulation, Integration, SectionKind};
|
||||
|
||||
/// How an element is written: its keyword and its node list in LS-DYNA order.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||
|
||||
@@ -61,7 +61,7 @@ mod elements;
|
||||
|
||||
use std::collections::{BTreeMap, BTreeSet};
|
||||
|
||||
use modelcraft_model::{
|
||||
use fieldcraft_model::{
|
||||
BoundaryCondition, CouplingKind, Diagnostic, Dofs, Elastic, Element, ElementKind, Hardening, Load, Material, Model, OutputVariable, Plastic,
|
||||
Procedure, Resolved, ResolvedDirection, Section, SectionKind, Step, Target,
|
||||
};
|
||||
@@ -102,7 +102,7 @@ const MAX_SHELL_POINTS: u32 = 10;
|
||||
|
||||
/// A resolved model that breaks its own invariants (unreachable after `resolve`).
|
||||
fn broken(what: String) -> Error {
|
||||
Error::Model(modelcraft_model::Error::Invalid(format!("inconsistent resolved model: {what}")))
|
||||
Error::Model(fieldcraft_model::Error::Invalid(format!("inconsistent resolved model: {what}")))
|
||||
}
|
||||
|
||||
/// One `*PART`: a section's elements of one kind.
|
||||
@@ -159,7 +159,7 @@ fn write_with(model: &Model, r: &Resolved) -> Result<Written> {
|
||||
let cases = if steps.len() > 1 { steps.len() } else { 0 };
|
||||
|
||||
d.line("*KEYWORD long=y");
|
||||
d.comment("Written by ModelCraft: implicit linear analysis, long format (20-column fields).");
|
||||
d.comment("Written by FieldCraft: implicit linear analysis, long format (20-column fields).");
|
||||
d.comment(&format!("Units: {} (consistent; nothing is converted).", model.units().label()));
|
||||
if cases > 0 {
|
||||
d.comment(&format!("{cases} steps are written as *CASE analyses: run LS-DYNA with CASE on its command line."));
|
||||
@@ -676,7 +676,7 @@ fn discrete(d: &mut Deck, model: &Model, r: &Resolved, plan: &Plan) -> Result<()
|
||||
let limit = |what: &str| Error::Limit(format!("no {what} id left for point masses, springs and dashpots"));
|
||||
let mut eid = model.elements().keys().next_back().copied().unwrap_or(0);
|
||||
let mut next_eid = || -> Result<u32> {
|
||||
eid = eid.checked_add(1).filter(|e| *e <= modelcraft_model::MAX_LABEL).ok_or_else(|| limit("element"))?;
|
||||
eid = eid.checked_add(1).filter(|e| *e <= fieldcraft_model::MAX_LABEL).ok_or_else(|| limit("element"))?;
|
||||
Ok(eid)
|
||||
};
|
||||
d.comment("Point masses");
|
||||
@@ -754,7 +754,7 @@ fn discrete(d: &mut Deck, model: &Model, r: &Resolved, plan: &Plan) -> Result<()
|
||||
while taken.contains(&node) {
|
||||
node = node.checked_add(1).ok_or_else(|| limit("node"))?;
|
||||
}
|
||||
if node > modelcraft_model::MAX_LABEL {
|
||||
if node > fieldcraft_model::MAX_LABEL {
|
||||
return Err(limit("node"));
|
||||
}
|
||||
ground.push((node, model.label_xyz(s.first).ok_or_else(|| broken(format!("node {}", s.first)))?));
|
||||
|
||||
@@ -52,7 +52,7 @@ mod card;
|
||||
use std::collections::{BTreeMap, BTreeSet};
|
||||
use std::fmt::Write as _;
|
||||
|
||||
use modelcraft_model::{
|
||||
use fieldcraft_model::{
|
||||
BeamProfile, Coupling, CouplingKind, Dofs, Elastic, ElementKind, Formulation, Hardening, Integration, Load, MAX_LABEL, Model, OutputVariable,
|
||||
Plastic, Procedure, Resolved, SectionKind, Step,
|
||||
};
|
||||
@@ -688,9 +688,9 @@ impl<'m> Deck<'m> {
|
||||
|
||||
fn emit(&self) -> Result<String> {
|
||||
let mut out = String::new();
|
||||
out.push_str("$ Nastran bulk data written by ModelCraft\n");
|
||||
out.push_str("$ Nastran bulk data written by FieldCraft\n");
|
||||
let _ = writeln!(out, "$ units: {}", self.model.units().label());
|
||||
let _ = writeln!(out, "SOL {}\nCEND\nTITLE = ModelCraft model\nECHO = NONE", self.sol);
|
||||
let _ = writeln!(out, "SOL {}\nCEND\nTITLE = FieldCraft model\nECHO = NONE", self.sol);
|
||||
for (i, sub) in self.subcases.iter().enumerate() {
|
||||
let _ = writeln!(out, "SUBCASE {}", i + 1);
|
||||
let title: String = format!(" SUBTITLE = {}", sub.step.name).chars().take(72).collect();
|
||||
@@ -945,7 +945,7 @@ impl<'m> Deck<'m> {
|
||||
}
|
||||
|
||||
/// A `PLOAD4` for one element face, positive pushing into the element.
|
||||
fn pressure(&self, sid: u32, f: modelcraft_model::ElementFace, magnitude: f64) -> Option<Card> {
|
||||
fn pressure(&self, sid: u32, f: fieldcraft_model::ElementFace, magnitude: f64) -> Option<Card> {
|
||||
let el = self.model.element(f.element)?;
|
||||
let card = Card::new("PLOAD4").int(sid).int(f.element);
|
||||
if el.kind.dimension() == 2 {
|
||||
@@ -1010,7 +1010,7 @@ fn plasticity(out: &mut String, name: &str, mid: u32, young: f64, plastic: &Plas
|
||||
write_named(out, &format!("stress-strain curve of {name}"), tid, Card::new("TABLES1").int(tid).end_line().reals(curve).text("ENDT"))
|
||||
}
|
||||
(Plastic::Table { .. }, None) | (Plastic::JohnsonCook { .. }, _) => {
|
||||
Err(Error::Model(modelcraft_model::Error::Invalid(format!("material `{name}`: its plasticity was not planned for MATS1"))))
|
||||
Err(Error::Model(fieldcraft_model::Error::Invalid(format!("material `{name}`: its plasticity was not planned for MATS1"))))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user