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
@@ -5,8 +5,8 @@
|
||||
use std::collections::{BTreeMap, BTreeSet};
|
||||
use std::path::PathBuf;
|
||||
|
||||
use modelcraft_decks::{Error, abaqus};
|
||||
use modelcraft_model::{
|
||||
use fieldcraft_decks::{Error, abaqus};
|
||||
use fieldcraft_model::{
|
||||
BeamProfile, BoundaryCondition, Coupling, CouplingKind, Distribution, Dofs, Elastic, ElementFace, ElementKind, Formulation, Integration, Load,
|
||||
Material, Model, OutputVariable, Procedure, ReferencePoint, Section, SectionKind, Set, Step, Symmetry, Target, UnitSystem,
|
||||
};
|
||||
@@ -185,12 +185,12 @@ fn read(deck: &str) -> Parsed {
|
||||
|
||||
fn golden(name: &str, deck: &str) {
|
||||
let path = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("tests/abaqus").join(format!("{name}.inp"));
|
||||
if std::env::var_os("MODELCRAFT_BLESS").is_some() {
|
||||
if std::env::var_os("FIELDCRAFT_BLESS").is_some() {
|
||||
std::fs::create_dir_all(path.parent().unwrap()).unwrap();
|
||||
std::fs::write(&path, deck).unwrap();
|
||||
}
|
||||
let expected = std::fs::read_to_string(&path).unwrap_or_else(|e| panic!("{}: {e} (run with MODELCRAFT_BLESS=1 to write it)", path.display()));
|
||||
assert!(expected == deck, "{name}.inp differs from the written deck (MODELCRAFT_BLESS=1 rewrites it):\n{deck}");
|
||||
let expected = std::fs::read_to_string(&path).unwrap_or_else(|e| panic!("{}: {e} (run with FIELDCRAFT_BLESS=1 to write it)", path.display()));
|
||||
assert!(expected == deck, "{name}.inp differs from the written deck (FIELDCRAFT_BLESS=1 rewrites it):\n{deck}");
|
||||
}
|
||||
|
||||
fn assert_lines_fit(deck: &str) {
|
||||
@@ -513,16 +513,16 @@ fn numbers_read_back_exactly() {
|
||||
#[test]
|
||||
fn largest_labels_longest_numbers_and_names_fit_a_line() {
|
||||
let mut m = Model::default();
|
||||
let base = modelcraft_model::MAX_LABEL - 30;
|
||||
let base = fieldcraft_model::MAX_LABEL - 30;
|
||||
let ugly = -1.234_567_890_123_456_7e-300;
|
||||
let mut xyz = one_element(ElementKind::Hex20).nodes().values().map(|n| n.xyz).collect::<Vec<_>>();
|
||||
xyz[0] = [ugly, ugly, ugly];
|
||||
for (i, p) in xyz.iter().enumerate() {
|
||||
m.set_node(base + i as u32, *p).unwrap();
|
||||
}
|
||||
m.set_element(modelcraft_model::MAX_LABEL, ElementKind::Hex20, (0..20).map(|i| base + i).collect()).unwrap();
|
||||
let long = format!("A{}", "x".repeat(modelcraft_model::MAX_NAME_LEN - 1));
|
||||
m.add_set(&long, Set { elements: vec![modelcraft_model::MAX_LABEL], nodes: (0..20).map(|i| base + i).collect(), ..Set::default() }).unwrap();
|
||||
m.set_element(fieldcraft_model::MAX_LABEL, ElementKind::Hex20, (0..20).map(|i| base + i).collect()).unwrap();
|
||||
let long = format!("A{}", "x".repeat(fieldcraft_model::MAX_NAME_LEN - 1));
|
||||
m.add_set(&long, Set { elements: vec![fieldcraft_model::MAX_LABEL], nodes: (0..20).map(|i| base + i).collect(), ..Set::default() }).unwrap();
|
||||
m.add_material(
|
||||
&long,
|
||||
Material { elastic: Some(Elastic::Isotropic { young: ugly.abs(), poisson: 0.3 }), density: Some(1.0), ..Material::default() },
|
||||
@@ -537,7 +537,7 @@ fn largest_labels_longest_numbers_and_names_fit_a_line() {
|
||||
let deck = abaqus::write(&m).unwrap();
|
||||
assert_lines_fit(&deck);
|
||||
let p = read(&deck);
|
||||
assert_eq!(p.elements[&modelcraft_model::MAX_LABEL].1.len(), 20, "a hex20 continues onto a second line");
|
||||
assert_eq!(p.elements[&fieldcraft_model::MAX_LABEL].1.len(), 20, "a hex20 continues onto a second line");
|
||||
assert_eq!(p.nodes[&base], [ugly; 3]);
|
||||
}
|
||||
|
||||
@@ -704,7 +704,7 @@ fn a_model_that_is_not_ready_is_refused() {
|
||||
}
|
||||
|
||||
/// The cantilever with its steel given each plasticity in turn.
|
||||
fn plastic_cantilever(p: modelcraft_model::Plastic) -> Model {
|
||||
fn plastic_cantilever(p: fieldcraft_model::Plastic) -> Model {
|
||||
let mut m = cantilever();
|
||||
m.replace_material("Steel", Material { plastic: Some(p), ..steel() }).unwrap();
|
||||
m
|
||||
@@ -714,7 +714,7 @@ fn plastic_cantilever(p: modelcraft_model::Plastic) -> Model {
|
||||
/// erosion, failure models of Abaqus/Explicit, are reported.
|
||||
#[test]
|
||||
fn plasticity_is_written_and_failure_reported() {
|
||||
use modelcraft_model::{Damage, Erosion, Hardening, HardeningPoint, Plastic};
|
||||
use fieldcraft_model::{Damage, Erosion, Hardening, HardeningPoint, Plastic};
|
||||
let section = |deck: &str| deck.split("*MATERIAL, NAME=Steel").nth(1).and_then(|s| s.split("*SOLID SECTION").next()).unwrap().to_string();
|
||||
let deck =
|
||||
abaqus::write(&plastic_cantilever(Plastic::Bilinear { yield_stress: 250.0, hardening_modulus: 1000.0, hardening: Hardening::Isotropic }))
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
*HEADING
|
||||
ModelCraft model, units mm-t-s-N-MPa
|
||||
** Written by ModelCraft. The numbers are in one consistent unit system and are not converted.
|
||||
FieldCraft model, units mm-t-s-N-MPa
|
||||
** Written by FieldCraft. The numbers are in one consistent unit system and are not converted.
|
||||
** Nodes
|
||||
*NODE
|
||||
1, 0.0, 0.0, 0.0
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
*HEADING
|
||||
ModelCraft model, units mm-t-s-N-MPa
|
||||
** Written by ModelCraft. The numbers are in one consistent unit system and are not converted.
|
||||
FieldCraft model, units mm-t-s-N-MPa
|
||||
** Written by FieldCraft. The numbers are in one consistent unit system and are not converted.
|
||||
** Nodes
|
||||
*NODE
|
||||
1, 0.0, 0.0, 0.0
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
*HEADING
|
||||
ModelCraft model, units mm-t-s-N-MPa
|
||||
** Written by ModelCraft. The numbers are in one consistent unit system and are not converted.
|
||||
FieldCraft model, units mm-t-s-N-MPa
|
||||
** Written by FieldCraft. The numbers are in one consistent unit system and are not converted.
|
||||
** Nodes
|
||||
*NODE
|
||||
1, 0.0, 0.0, 0.0
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
//! Trusses (rod3), point masses, rotary inertia, springs and dashpots in every deck format:
|
||||
//! what each writes, and what each reports as unsupported.
|
||||
|
||||
use modelcraft_decks::{Error, abaqus, lsdyna, nastran};
|
||||
use modelcraft_model::{
|
||||
use fieldcraft_decks::{Error, abaqus, lsdyna, nastran};
|
||||
use fieldcraft_model::{
|
||||
BoundaryCondition, Direction, Elastic, ElementKind, Formulation, Mass, Material, Model, PointMass, Procedure, ReferencePoint, Section,
|
||||
SectionKind, Set, Spring, Step, Target, UnitSystem,
|
||||
};
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
$ Nastran bulk data written by ModelCraft
|
||||
$ Nastran bulk data written by FieldCraft
|
||||
$ units: mm-t-s-N-MPa
|
||||
SOL 101
|
||||
CEND
|
||||
TITLE = ModelCraft model
|
||||
TITLE = FieldCraft model
|
||||
ECHO = NONE
|
||||
SUBCASE 1
|
||||
SUBTITLE = Bend
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
$ Nastran bulk data written by ModelCraft
|
||||
$ Nastran bulk data written by FieldCraft
|
||||
$ units: unspecified
|
||||
SOL 103
|
||||
CEND
|
||||
TITLE = ModelCraft model
|
||||
TITLE = FieldCraft model
|
||||
ECHO = NONE
|
||||
SUBCASE 1
|
||||
SUBTITLE = Modes
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
$ Nastran bulk data written by ModelCraft
|
||||
$ Nastran bulk data written by FieldCraft
|
||||
$ units: mm-t-s-N-MPa
|
||||
SOL 101
|
||||
CEND
|
||||
TITLE = ModelCraft model
|
||||
TITLE = FieldCraft model
|
||||
ECHO = NONE
|
||||
SUBCASE 1
|
||||
SUBTITLE = Sag
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
//! LS-DYNA deck writer: golden files of our own small models, node-order mappings checked by the
|
||||
//! sign of the element Jacobian, a re-read of our own output, and what the format cannot take.
|
||||
//!
|
||||
//! Golden files live in `tests/lsdyna/`; `MODELCRAFT_BLESS=1 cargo test -p modelcraft-decks`
|
||||
//! Golden files live in `tests/lsdyna/`; `FIELDCRAFT_BLESS=1 cargo test -p fieldcraft-decks`
|
||||
//! rewrites them after an intended change (review the diff).
|
||||
|
||||
use std::collections::{BTreeMap, BTreeSet};
|
||||
|
||||
use modelcraft_decks::{Error, lsdyna};
|
||||
use modelcraft_model::*;
|
||||
use fieldcraft_decks::{Error, lsdyna};
|
||||
use fieldcraft_model::*;
|
||||
|
||||
// ---------------------------------------------------------------------------------------------
|
||||
// Our own models.
|
||||
@@ -200,11 +200,11 @@ fn golden(name: &str, model: &Model) -> lsdyna::Written {
|
||||
let again = lsdyna::write(model).unwrap();
|
||||
assert_eq!(written, again, "deterministic");
|
||||
let path = std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("tests/lsdyna").join(format!("{name}.k"));
|
||||
if std::env::var_os("MODELCRAFT_BLESS").is_some() {
|
||||
if std::env::var_os("FIELDCRAFT_BLESS").is_some() {
|
||||
std::fs::write(&path, &written.text).unwrap();
|
||||
}
|
||||
let expected = std::fs::read_to_string(&path).unwrap_or_else(|e| panic!("{}: {e} (run with MODELCRAFT_BLESS=1)", path.display()));
|
||||
assert!(written.text == expected, "{name}.k differs from the golden file (MODELCRAFT_BLESS=1 rewrites it)");
|
||||
let expected = std::fs::read_to_string(&path).unwrap_or_else(|e| panic!("{}: {e} (run with FIELDCRAFT_BLESS=1)", path.display()));
|
||||
assert!(written.text == expected, "{name}.k differs from the golden file (FIELDCRAFT_BLESS=1 rewrites it)");
|
||||
assert!(written.text.is_ascii());
|
||||
for line in written.text.lines() {
|
||||
assert!(line.len() <= 200 && line == line.trim_end(), "{line:?}");
|
||||
@@ -688,7 +688,7 @@ fn hostile_numbers_stay_within_their_fields() {
|
||||
fn explicit_steps_are_refused_by_every_format() {
|
||||
let mut m = cantilever();
|
||||
m.add_step(step("Impact", Procedure::ExplicitDynamic(ExplicitDynamic::new(1e-3)), &["clamp"], &[]), None).unwrap();
|
||||
for f in modelcraft_decks::FORMATS {
|
||||
for f in fieldcraft_decks::FORMATS {
|
||||
let e = f.write(&m).unwrap_err();
|
||||
assert!(matches!(e, Error::Unsupported { .. }), "{}: {e}", f.name);
|
||||
assert!(e.to_string().contains("step `Impact`: explicit dynamic"), "{}: {e}", f.name);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
*KEYWORD long=y
|
||||
$ Written by ModelCraft: implicit linear analysis, long format (20-column fields).
|
||||
$ Written by FieldCraft: implicit linear analysis, long format (20-column fields).
|
||||
$ Units: mm-t-s-N-MPa (consistent; nothing is converted).
|
||||
*NODE
|
||||
$ nid x y z
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
*KEYWORD long=y
|
||||
$ Written by ModelCraft: implicit linear analysis, long format (20-column fields).
|
||||
$ Written by FieldCraft: implicit linear analysis, long format (20-column fields).
|
||||
$ Units: mm-t-s-N-MPa (consistent; nothing is converted).
|
||||
$ 2 steps are written as *CASE analyses: run LS-DYNA with CASE on its command line.
|
||||
*NODE
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
*KEYWORD long=y
|
||||
$ Written by ModelCraft: implicit linear analysis, long format (20-column fields).
|
||||
$ Written by FieldCraft: implicit linear analysis, long format (20-column fields).
|
||||
$ Units: mm-t-s-N-MPa (consistent; nothing is converted).
|
||||
*NODE
|
||||
$ nid x y z
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
*KEYWORD long=y
|
||||
$ Written by ModelCraft: implicit linear analysis, long format (20-column fields).
|
||||
$ Written by FieldCraft: implicit linear analysis, long format (20-column fields).
|
||||
$ Units: m-kg-s-N-Pa (consistent; nothing is converted).
|
||||
*NODE
|
||||
$ nid x y z
|
||||
|
||||
@@ -2,13 +2,13 @@
|
||||
//! output (grids, elements, constraint sets, case control), node order checked against Nastran's
|
||||
//! own element conventions by Jacobian sign and mid-side positions, and what is unsupported.
|
||||
//!
|
||||
//! Golden files are rewritten with `MODELCRAFT_BLESS=1 cargo test -p modelcraft-decks`.
|
||||
//! Golden files are rewritten with `FIELDCRAFT_BLESS=1 cargo test -p fieldcraft-decks`.
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use modelcraft_decks::nastran;
|
||||
use modelcraft_decks::{Error, with_steps};
|
||||
use modelcraft_model::{
|
||||
use fieldcraft_decks::nastran;
|
||||
use fieldcraft_decks::{Error, with_steps};
|
||||
use fieldcraft_model::{
|
||||
BeamProfile, BoundaryCondition, Coupling, CouplingKind, Distribution, Dofs, Elastic, ElementFace, ElementKind, Formulation, Integration, Load,
|
||||
Material, Model, Procedure, ReferencePoint, Section, SectionKind, Set, Step, Target, UnitSystem,
|
||||
};
|
||||
@@ -266,12 +266,12 @@ fn modes() -> Model {
|
||||
|
||||
fn golden(name: &str, deck: &str) {
|
||||
let path = std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("tests/golden/nastran").join(format!("{name}.bdf"));
|
||||
if std::env::var_os("MODELCRAFT_BLESS").is_some() {
|
||||
if std::env::var_os("FIELDCRAFT_BLESS").is_some() {
|
||||
std::fs::create_dir_all(path.parent().unwrap()).unwrap();
|
||||
std::fs::write(&path, deck).unwrap();
|
||||
}
|
||||
let want = std::fs::read_to_string(&path).unwrap_or_else(|e| panic!("{}: {e} (bless with MODELCRAFT_BLESS=1)", path.display()));
|
||||
assert_eq!(deck, want, "{name}: the deck changed (bless with MODELCRAFT_BLESS=1 after checking it)");
|
||||
let want = std::fs::read_to_string(&path).unwrap_or_else(|e| panic!("{}: {e} (bless with FIELDCRAFT_BLESS=1)", path.display()));
|
||||
assert_eq!(deck, want, "{name}: the deck changed (bless with FIELDCRAFT_BLESS=1 after checking it)");
|
||||
}
|
||||
|
||||
fn unsupported(m: &Model) -> String {
|
||||
@@ -640,7 +640,7 @@ fn steps_are_chosen_and_mixed_solutions_are_refused() {
|
||||
// A modes step holds the clamp but carries no loads.
|
||||
assert!(r.cards("FORCE").next().is_none());
|
||||
assert_eq!(read(&nastran::write(&with_steps(&m, &only(&["Bend"])).unwrap()).unwrap()).sol, 101);
|
||||
let nastran = modelcraft_decks::format("nastran").unwrap();
|
||||
let nastran = fieldcraft_decks::format("nastran").unwrap();
|
||||
assert_eq!(nastran.write_steps(&m, Some(&only(&["Bend"]))).unwrap().text, nastran::write(&with_steps(&m, &only(&["Bend"])).unwrap()).unwrap());
|
||||
|
||||
for bad in [only(&[]), only(&["Nope"]), only(&[&"x".repeat(100_000)]), only(&["", "\u{0}"])] {
|
||||
@@ -740,7 +740,7 @@ fn conflicting_values_and_ids_at_the_top_of_the_range() {
|
||||
/// damage and erosion are reported.
|
||||
#[test]
|
||||
fn plasticity_is_written_as_mats1() {
|
||||
use modelcraft_model::{Erosion, Hardening, HardeningPoint, Plastic};
|
||||
use fieldcraft_model::{Erosion, Hardening, HardeningPoint, Plastic};
|
||||
let with = |p: Plastic| {
|
||||
let mut m = cantilever();
|
||||
m.replace_material("Steel", Material { plastic: Some(p), ..steel() }).unwrap();
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
//! 2D models (plane stress, plane strain, axisymmetric) in every deck format: element names,
|
||||
//! section data, edge surfaces and pressures, centrifugal loads, and what a format cannot write.
|
||||
|
||||
use modelcraft_decks::{Error, abaqus, edge_pressure_loads, lsdyna, nastran};
|
||||
use modelcraft_model::{
|
||||
use fieldcraft_decks::{Error, abaqus, edge_pressure_loads, lsdyna, nastran};
|
||||
use fieldcraft_model::{
|
||||
BoundaryCondition, Elastic, ElementEdge, ElementKind, Formulation, Integration, Load, Material, Model, Procedure, Section, SectionKind, Set,
|
||||
Step, Target, UnitSystem,
|
||||
};
|
||||
|
||||
Reference in new issue
Block a user