forked from 1b-agent/fieldcraft-upstream
LS-DYNA keyword writer (implicit static and eigenvalue, M3) (#25)
* decks: LS-DYNA keyword writer (long format, implicit static and eigenvalue) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NmAttHhUZTokgPeEJia8sm * decks: LS-DYNA golden files, Jacobian-sign node-order tests, re-reader and refusals Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NmAttHhUZTokgPeEJia8sm * docs: LS-DYNA writer status and deck notes Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NmAttHhUZTokgPeEJia8sm * decks: simplify the LS-DYNA writer (plan decides once, cards written in place, shared test tables) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NmAttHhUZTokgPeEJia8sm * decks: LS-DYNA joins FORMATS (deck.write lsdyna), refusals reported together, shared concentrated loads Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NmAttHhUZTokgPeEJia8sm * decks: LS-DYNA on main's shared deck API (steps parameter, model helpers) 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:
13 files changed
+2353
-3
No files matched your search
@@ -10,7 +10,7 @@ use crate::{CommandKind, CommandSpec, EngineError, Result, Session};
|
||||
pub const WRITE: CommandSpec = CommandSpec {
|
||||
id: "deck.write",
|
||||
label: "Write Solver Deck",
|
||||
params: r#"{"format": "abaqus|nastran", "path": "part.inp", "steps": ["Load"]} — writes the model as a solver deck (formats: modelcraft_decks::FORMATS); `steps` (optional) writes only those steps, as a Nastran run needs (static or frequency steps, not both); fails naming every error of the model check and everything the format cannot express"#,
|
||||
params: r#"{"format": "abaqus|nastran|lsdyna", "path": "part.inp", "steps": ["Load"]} — writes the model as a solver deck (formats: modelcraft_decks::FORMATS); `steps` (optional) writes only those steps, as a Nastran run needs (static or frequency steps, not both); LS-DYNA writes several steps as *CASE analyses (run it with CASE); fails naming every error of the model check and everything the format cannot express"#,
|
||||
kind: CommandKind::Session,
|
||||
run: write,
|
||||
};
|
||||
@@ -77,4 +77,30 @@ mod tests {
|
||||
}
|
||||
let _ = std::fs::remove_dir_all(&dir);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn writes_lsdyna_keyword_decks() {
|
||||
let dir = std::env::temp_dir().join(format!("modelcraft-deck-lsdyna-{}", std::process::id()));
|
||||
std::fs::create_dir_all(&dir).unwrap();
|
||||
let path = dir.join("bar.k");
|
||||
let mut s = Session::default();
|
||||
crate::cmd::define::tests::defined_bar(&mut s);
|
||||
let out = s.execute("deck.write", &json!({"format": "lsdyna", "path": path.to_string_lossy()})).unwrap();
|
||||
let written = std::fs::read_to_string(&path).unwrap();
|
||||
assert_eq!(written, modelcraft_decks::lsdyna::write(&s.model).unwrap().text);
|
||||
assert_eq!(out["format"], "lsdyna");
|
||||
assert!(written.starts_with("*KEYWORD long=y\n") && written.contains("*CASE_BEGIN_2"), "two steps, two cases");
|
||||
// One chosen step: a single analysis, no cases.
|
||||
s.execute("deck.write", &json!({"format": "lsdyna", "path": path.to_string_lossy(), "steps": ["Modes"]})).unwrap();
|
||||
let one = std::fs::read_to_string(&path).unwrap();
|
||||
assert!(one.contains("*CONTROL_IMPLICIT_EIGENVALUE") && !one.contains("*CASE_BEGIN") && !one.contains("*CONTROL_IMPLICIT_SOLUTION"), "{one}");
|
||||
// What LS-DYNA cannot take is named and nothing is written.
|
||||
s.execute("model.load.create", &json!({"name": "heat", "type": "body_force", "set": "all", "vector": [0, 0, 1]})).unwrap();
|
||||
s.execute("model.step.activate", &json!({"step": "Bend", "loads": ["heat"]})).unwrap();
|
||||
let other = dir.join("heat.k");
|
||||
let e = s.execute("deck.write", &json!({"format": "lsdyna", "path": other.to_string_lossy()})).unwrap_err().to_string();
|
||||
assert!(e.contains("not supported by LS-DYNA") && e.contains("load `heat`"), "{e}");
|
||||
assert!(!other.exists());
|
||||
let _ = std::fs::remove_dir_all(&dir);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user