forked from 1b-agent/fieldcraft-upstream
- model: materials gain solver-neutral plastic (bilinear isotropic/kinematic, hardening table, Johnson-Cook with adiabatic heating), damage (Johnson-Cook D1-D5) and erosion (plastic strain); explicit steps gain nonlinear_geometry (default on) and stress_rate (jaumann | green_naghdi). - fem: rotation (Hughes-Winget, Flanagan-Taylor), plasticity (radial return, capped bracketed Newton for Johnson-Cook, damage; the update takes the mechanical strain increment so thermal strains can be subtracted), closed-form hex8 gradients for deformed configurations. - explicit: updated Lagrangian hex8/tet4, per-element material state, erosion with reported energy, plastic work in the energy account. - solver: warns that the linear solver uses the elastic constants of plastic materials (results hash-identical). - decks: Abaqus *PLASTIC (+ Johnson-Cook keywords), Nastran MATS1/TABLES1, LS-DYNA *MAT_PLASTIC_KINEMATIC / *MAT_PIECEWISE_LINEAR_PLASTICITY; what a format cannot express is reported as Unsupported. - engine: model.material.plasticity, model.material.damage (catalogue ready), explicit element probe, eroded elements in the solve summary. Step commits before the rebase onto the DOF framework: branch explicit-x2-steps. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NmAttHhUZTokgPeEJia8sm
127 lines
4.9 KiB
Rust
127 lines
4.9 KiB
Rust
//! What an explicit dynamic run keeps: histories sampled at the history interval and field
|
||
//! frames at the output interval.
|
||
|
||
use serde::Serialize;
|
||
|
||
use crate::elements::Failure;
|
||
|
||
/// The energy account at one time (Belytschko, Liu, Moran, Elkhodary 2014, §6.2.3). The works of
|
||
/// the internal and external forces are integrated with the trapezoidal rule over each
|
||
/// increment's displacement; the constraints' with their impulses (see [`crate::integrate`]).
|
||
#[derive(Debug, Clone, Copy, Default, PartialEq, Serialize)]
|
||
pub struct Energies {
|
||
/// ½ vᵀ M v.
|
||
pub kinetic: f64,
|
||
/// Work of the material stresses: the strain energy for an elastic material.
|
||
pub internal: f64,
|
||
/// Work of the hourglass forces (stored in the stiffness form, dissipated in the viscous one).
|
||
pub hourglass: f64,
|
||
/// Work of the bulk viscosity (dissipated).
|
||
pub viscous: f64,
|
||
/// Work of the loads.
|
||
pub external: f64,
|
||
/// Work of the boundary conditions and rigid walls on the model.
|
||
pub constraint: f64,
|
||
/// Plastic work: the part of `internal` dissipated by plastic flow.
|
||
pub plastic: f64,
|
||
/// Internal energy of the eroded elements when they eroded (part of `internal`).
|
||
pub eroded: f64,
|
||
/// kinetic + internal + hourglass + viscous − external − constraint − the initial kinetic
|
||
/// energy: zero when energy is conserved.
|
||
pub balance: f64,
|
||
}
|
||
|
||
impl Energies {
|
||
/// The balance relative to the largest energy in the account.
|
||
pub fn relative_error(&self, initial_kinetic: f64) -> f64 {
|
||
let scale = [initial_kinetic, self.kinetic, self.internal + self.hourglass + self.viscous, self.external.abs(), self.constraint.abs()]
|
||
.into_iter()
|
||
.fold(0.0, f64::max);
|
||
if scale > 0.0 { self.balance.abs() / scale } else { 0.0 }
|
||
}
|
||
}
|
||
|
||
/// The fields at one time. Vectors that the step's output does not request are empty.
|
||
#[derive(Debug, Clone, PartialEq)]
|
||
pub struct Frame {
|
||
pub time: f64,
|
||
/// Per node in [`ExplicitResult::nodes`] order.
|
||
pub displacement: Vec<[f64; 3]>,
|
||
pub velocity: Vec<[f64; 3]>,
|
||
/// Per element in [`ExplicitResult::elements`] order (one-point elements: one value each):
|
||
/// xx, yy, zz, xy, xz, yz, engineering shear strains.
|
||
pub stress: Vec<[f64; 6]>,
|
||
/// The accumulated strain increments (small strain: the strain; large deformation: the
|
||
/// integral of the rate of deformation, rotated with the material).
|
||
pub strain: Vec<[f64; 6]>,
|
||
/// Per element, with stress output in a model with plasticity: equivalent plastic strain,
|
||
/// damage and temperature.
|
||
pub plastic_strain: Vec<f64>,
|
||
pub damage: Vec<f64>,
|
||
pub temperature: Vec<f64>,
|
||
/// Per element, with stress output: whether it has eroded.
|
||
pub failed: Vec<bool>,
|
||
}
|
||
|
||
/// An element removed from the analysis.
|
||
#[derive(Debug, Clone, Copy, PartialEq, Serialize)]
|
||
pub struct ErodedElement {
|
||
pub label: u32,
|
||
pub time: f64,
|
||
pub failure: Failure,
|
||
/// Its internal energy (stress work) when it eroded.
|
||
pub internal_energy: f64,
|
||
}
|
||
|
||
/// Quantities sampled through the run.
|
||
#[derive(Debug, Clone, Default, PartialEq)]
|
||
pub struct History {
|
||
pub time: Vec<f64>,
|
||
/// The time increment taken at each sample.
|
||
pub increment: Vec<f64>,
|
||
pub energies: Vec<Energies>,
|
||
/// Total momentum M v.
|
||
pub momentum: Vec<[f64; 3]>,
|
||
/// Sum of the forces the boundary conditions and rigid walls exert on the model.
|
||
pub constraint_force: Vec<[f64; 3]>,
|
||
/// The nodes with histories, and per sample their displacement and velocity (in this order).
|
||
pub nodes: Vec<u32>,
|
||
pub displacement: Vec<Vec<[f64; 3]>>,
|
||
pub velocity: Vec<Vec<[f64; 3]>>,
|
||
}
|
||
|
||
/// An element that limits the stable time increment.
|
||
#[derive(Debug, Clone, Copy, PartialEq, Serialize)]
|
||
pub struct ControllingElement {
|
||
pub label: u32,
|
||
/// Its critical increment at rest (no bulk viscosity), before the scale factor.
|
||
pub increment: f64,
|
||
}
|
||
|
||
/// The result of an explicit dynamic step.
|
||
#[derive(Debug, Clone, PartialEq)]
|
||
pub struct ExplicitResult {
|
||
pub step: String,
|
||
/// Node labels with degrees of freedom, sorted.
|
||
pub nodes: Vec<u32>,
|
||
/// Element labels, sorted.
|
||
pub elements: Vec<u32>,
|
||
pub frames: Vec<Frame>,
|
||
pub history: History,
|
||
/// The elements with the smallest critical increments (at most ten), smallest first.
|
||
pub controlling: Vec<ControllingElement>,
|
||
/// The first time increment taken (the scale times the smallest critical increment).
|
||
pub initial_increment: f64,
|
||
pub increments: u64,
|
||
/// The time reached: the step's end time unless the run stopped at the increment cap.
|
||
pub time: f64,
|
||
pub completed: bool,
|
||
pub total_mass: f64,
|
||
/// The energy account at the end.
|
||
pub energy: Energies,
|
||
pub initial_kinetic: f64,
|
||
/// Elements eroded during the run, in the order they eroded.
|
||
pub eroded: Vec<ErodedElement>,
|
||
pub warnings: Vec<String>,
|
||
}
|