forked from 1b-agent/fieldcraft-upstream
Nastran bulk data writer (SOL 101/103) and deck.write steps (M3) (#24)
* Nastran bulk data writer: fixed-format entries, exact large-field reals, SOL 101/103 decks Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NmAttHhUZTokgPeEJia8sm * Nastran writer tests: golden decks, a re-reader of our output, node order against Nastran's conventions Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NmAttHhUZTokgPeEJia8sm * docs: Nastran writer in the roadmap, parity table and deck notes Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NmAttHhUZTokgPeEJia8sm * Nastran writer: simplify planning (subcases, one property table), stream cards into the deck, write through the VFS ElementKind::corner_count/is_quadratic and Dofs::bits/from_bits join the model. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NmAttHhUZTokgPeEJia8sm * Nastran joins the shared deck formats; deck.write chooses steps for every format nastran::write_resolved is the FORMATS row; Format::write_steps and with_steps write a subset of steps (a Nastran run is static or frequency steps); problems go through the shared unsupported(). 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:
14 files changed
+2266
-5
No files matched your search
+32
-1
@@ -10,6 +10,7 @@
|
||||
#![forbid(unsafe_code)]
|
||||
|
||||
pub mod abaqus;
|
||||
pub mod nastran;
|
||||
|
||||
use std::collections::{BTreeMap, BTreeSet};
|
||||
|
||||
@@ -52,10 +53,40 @@ impl Format {
|
||||
let text = (self.writer)(model, &resolved)?;
|
||||
Ok(Deck { text, warnings: resolved.warnings })
|
||||
}
|
||||
|
||||
/// Write only the named steps (in the model's order), or every step when `steps` is `None`;
|
||||
/// for runs that hold some steps only, such as a Nastran run (static or frequency steps).
|
||||
pub fn write_steps(&self, model: &Model, steps: Option<&[String]>) -> Result<Deck> {
|
||||
match steps {
|
||||
None => self.write(model),
|
||||
Some(names) => self.write(&with_steps(model, names)?),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The model with only the named steps, in its own order. Definitions the dropped steps used
|
||||
/// 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())));
|
||||
}
|
||||
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 mut out = model.clone();
|
||||
let dropped: Vec<String> = model.steps().iter().map(|s| s.name.clone()).filter(|s| !names.contains(s)).collect();
|
||||
for name in dropped {
|
||||
out.remove_step(&name)?;
|
||||
}
|
||||
Ok(out)
|
||||
}
|
||||
|
||||
/// Every deck format, one row per writer.
|
||||
pub const FORMATS: &[Format] = &[Format { name: "abaqus", extension: "inp", writer: abaqus::write_resolved }];
|
||||
pub const FORMATS: &[Format] = &[
|
||||
Format { name: "abaqus", extension: "inp", writer: abaqus::write_resolved },
|
||||
Format { name: "nastran", extension: "bdf", writer: nastran::write_resolved },
|
||||
];
|
||||
|
||||
/// The format called `name`.
|
||||
pub fn format(name: &str) -> Option<&'static Format> {
|
||||
|
||||
Reference in new issue
Block a user