forked from 1b-agent/fieldcraft-upstream
fem, solver: thermal strain in nonlinear static steps
Temperatures now strain the material in nonlinear steps instead of being refused. At finite strain the deformation gradient splits multiplicatively, F = F_m F_theta with F_theta = diag(1 + alpha_i dT) at each point: the material sees F_m and the loops run on the thermally expanded volume J_theta dV0 (mixed elements project det F_m), so the tangent stays consistent. At small strain the split is additive, and elements on their linear stiffness take the equivalent nodal forces as a dead load. The step's temperatures are its temperature loads, or the steady conduction of its temperature conditions and heat loads (one-way coupling, as the linear coupled step); both at once are refused. They ramp with the load factor from each material's reference temperature. Johnson-Cook plasticity softens at the point's temperature. Verified: free expansion and a fully constrained neo-Hookean block at 20 % thermal stretch, full and hybrid (exact); a bar held at its ends heated past yield (exact); the linear limit and the conducted temperatures against the linear solvers; tangents by central differences with a temperature field. 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
53adab54c2
commit
3f9e9e30d8
8 files changed
+492
-94
No files matched your search
@@ -387,7 +387,7 @@ fn nonlinear_steps_fail_cleanly() {
|
||||
step.set_procedure(Procedure::NonlinearStatic(bad.clone()));
|
||||
assert!(capped.model.replace_step(step).is_err(), "{bad:?}");
|
||||
}
|
||||
// Refused by name: incompatible modes, a hybrid St Venant–Kirchhoff element, temperature.
|
||||
// Refused by name: incompatible modes, a hybrid St Venant–Kirchhoff element, centrifugal loads.
|
||||
let mut im = grid([2, 1, 1], ElementKind::Hex8, |q| q);
|
||||
im.define(iso(100.0, 0.3), None, incompatible(), nonlinear());
|
||||
im.fixed("root", |q| near(q[0], 0.0));
|
||||
@@ -402,10 +402,13 @@ fn nonlinear_steps_fail_cleanly() {
|
||||
hy.load("p", Load::Pressure { set: "end".into(), magnitude: 1.0 });
|
||||
let err = solve_nonlinear(&hy.model, None, &Limits::default()).unwrap_err().to_string();
|
||||
assert!(err.contains("hybrid elements of a St Venant–Kirchhoff material"), "{err}");
|
||||
hy.load("hot", Load::Temperature { target: Target::Set("root".into()), value: 50.0 });
|
||||
hy.load("spin", Load::Centrifugal { angular_velocity: 10.0, point: [0.0; 3], axis: [0.0, 0.0, 1.0], set: None });
|
||||
neo_hookean(&mut hy, 100.0, 0.3);
|
||||
let mut m = hy.model.material("Mat").unwrap().clone();
|
||||
m.density = Some(1.0);
|
||||
hy.model.replace_material("Mat", m).unwrap();
|
||||
let err = solve_nonlinear(&hy.model, None, &Limits::default()).unwrap_err().to_string();
|
||||
assert!(err.contains("temperature loads"), "{err}");
|
||||
assert!(err.contains("centrifugal loads"), "{err}");
|
||||
// A model that can move freely: the first tangent is singular, named like the linear solver.
|
||||
let mut free = grid([2, 1, 1], ElementKind::Hex8, |q| q);
|
||||
free.define(iso(100.0, 0.3), None, full(), nonlinear());
|
||||
|
||||
Reference in new issue
Block a user