R8-a harness: save/load of the coupled state (continue on the same grid, or extrude the slab onto the full duct)
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
12a27c6fca
commit
9867a8b831
@@ -28,13 +28,15 @@
|
||||
mod fluid;
|
||||
#[path = "fsi2_harness/mod.rs"]
|
||||
mod fsi2_harness;
|
||||
#[path = "fsi2_embedded3/state.rs"]
|
||||
mod state;
|
||||
|
||||
use std::cell::RefCell;
|
||||
use std::io::Write as _;
|
||||
|
||||
use fluid::{CX, CY, Contribution, E3Fluid, HALF, Line, R_CYL};
|
||||
use fsi2_harness::{FSI2, Interface, clamp_left, flag_mesh, median, mid_amp};
|
||||
use nalgebra::Vector3;
|
||||
use nalgebra::{DVector, Vector3};
|
||||
use rtx_fea::analysis::{
|
||||
AnalysisConfig, ConvergenceCriteria, DynamicState, NonlinearDynamicAnalysis,
|
||||
};
|
||||
@@ -251,7 +253,26 @@ fn fsi2_on_embedded3() {
|
||||
let flag_geo = Flag::build(&mesh);
|
||||
let zero_c = vec![0.0; 2 * STATIONS];
|
||||
let rest = line_of(0.0, &zero_c, &zero_c, 1.0);
|
||||
let mut fl = E3Fluid::build(ny, nz, speed, rest.clone());
|
||||
// `RTX_E3FSI_LOAD=<dir>`: continue from a saved coupled state (extruded
|
||||
// onto the full duct when the saved nz differs); `RTX_E3FSI_SAVE=<dir>`
|
||||
// saves the state every `RTX_E3FSI_SAVE_EVERY` coupled steps (2000) and at the end.
|
||||
let saved = std::env::var("RTX_E3FSI_LOAD")
|
||||
.ok()
|
||||
.map(|d| state::Saved::load(&d).expect("load the saved state"));
|
||||
let save_dir = std::env::var("RTX_E3FSI_SAVE").ok();
|
||||
let save_every = env_f("RTX_E3FSI_SAVE_EVERY", 2000.0) as usize;
|
||||
let mut fl = E3Fluid::build(ny, nz, speed, rest.clone(), saved.as_ref());
|
||||
if let Some(s) = &saved {
|
||||
println!(
|
||||
" loaded the coupled state at t {:.4} from {} ({}×{}×{} → nz {})",
|
||||
s.t,
|
||||
std::env::var("RTX_E3FSI_LOAD").unwrap(),
|
||||
s.dims[0],
|
||||
s.dims[1],
|
||||
s.dims[2],
|
||||
fl.grid.nz
|
||||
);
|
||||
}
|
||||
let dt = fl.dt;
|
||||
println!(
|
||||
" R8-a FSI2 on embedded3: rigid to {t_rigid} s, coupled to {t_end} s; Aitken rtol {rtol:.1e} floor {floor:.1e} max {max_subit} stall accept {stall_accept}; Newmark γ {gamma}; the body's 2D counterpart = the overset SEMICIRCLE line (ny 62: 94.8 mm, 1.914 Hz)"
|
||||
@@ -268,7 +289,11 @@ fn fsi2_on_embedded3() {
|
||||
let start = std::time::Instant::now();
|
||||
|
||||
// Phase 1: the rigid flag (target 1: the rest state vs CFD2 136.7 / 10.53).
|
||||
let rigid_steps = (t_rigid / dt).round() as usize;
|
||||
let rigid_steps = if saved.is_some() {
|
||||
0
|
||||
} else {
|
||||
(t_rigid / dt).round() as usize
|
||||
};
|
||||
let mut last = ([0.0; 3], Vec::new());
|
||||
for step in 0..rigid_steps {
|
||||
let r = fl.step();
|
||||
@@ -318,7 +343,7 @@ fn fsi2_on_embedded3() {
|
||||
tot0[1],
|
||||
start.elapsed().as_secs_f64()
|
||||
);
|
||||
if rigid_only {
|
||||
if rigid_only && saved.is_none() {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -363,16 +388,34 @@ fn fsi2_on_embedded3() {
|
||||
c
|
||||
};
|
||||
|
||||
let (nodal0, _, _, _) = distribute(&flag_geo, &rest, &contrib0, fl.width);
|
||||
flag.borrow_mut().set_nodal_forces(&nodal0);
|
||||
let mut flag_state = flag.borrow_mut().rest_state().unwrap();
|
||||
let mut committed_nodal = nodal0;
|
||||
// The fluid's own previous line and centreline (its geometry's history).
|
||||
let mut line_n = Line {
|
||||
t: fl.time(),
|
||||
..rest.clone()
|
||||
let (mut flag_state, mut committed_nodal, mut line_n, mut c_fluid_n) = match &saved {
|
||||
Some(s) => {
|
||||
let nodal: Vec<(NodeId, Vector3<f64>)> = flag_geo
|
||||
.interface
|
||||
.wetted
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(k, &id)| (id, Vector3::new(s.nodal[2 * k], s.nodal[2 * k + 1], 0.0)))
|
||||
.collect();
|
||||
let state = DynamicState {
|
||||
displacement: DVector::from_vec(s.disp.clone()),
|
||||
velocity: DVector::from_vec(s.vel.clone()),
|
||||
acceleration: DVector::from_vec(s.acc.clone()),
|
||||
};
|
||||
(state, nodal, s.line.clone(), s.c_fluid.clone())
|
||||
}
|
||||
None => {
|
||||
let (nodal0, _, _, _) = distribute(&flag_geo, &rest, &contrib0, fl.width);
|
||||
flag.borrow_mut().set_nodal_forces(&nodal0);
|
||||
let state = flag.borrow_mut().rest_state().unwrap();
|
||||
// The fluid's own previous line and centreline (its geometry's history).
|
||||
let line = Line {
|
||||
t: fl.time(),
|
||||
..rest.clone()
|
||||
};
|
||||
(state, nodal0, line, zero_c.clone())
|
||||
}
|
||||
};
|
||||
let mut c_fluid_n = zero_c.clone();
|
||||
|
||||
let coupled_steps = ((t_end - fl.time()) / dt).round() as usize;
|
||||
let fl = RefCell::new(fl);
|
||||
@@ -537,6 +580,34 @@ fn fsi2_on_embedded3() {
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
let at_end = step + 1 == coupled_steps;
|
||||
if let Some(dir) = save_dir
|
||||
.as_ref()
|
||||
.filter(|_| at_end || (step + 1) % save_every == 0)
|
||||
{
|
||||
let f = fl.borrow();
|
||||
let g = f.grid;
|
||||
state::Saved {
|
||||
t: t_new,
|
||||
dims: [g.nx, g.ny, g.nz],
|
||||
h: f.h,
|
||||
u: f.field.u.clone(),
|
||||
v: f.field.v.clone(),
|
||||
w: f.field.w.clone(),
|
||||
p: f.field.p.clone(),
|
||||
disp: flag_state.displacement.as_slice().to_vec(),
|
||||
vel: flag_state.velocity.as_slice().to_vec(),
|
||||
acc: flag_state.acceleration.as_slice().to_vec(),
|
||||
line: line_n.clone(),
|
||||
c_fluid: c_fluid_n.clone(),
|
||||
nodal: committed_nodal
|
||||
.iter()
|
||||
.flat_map(|(_, v)| [v.x, v.y])
|
||||
.collect(),
|
||||
}
|
||||
.save(dir)
|
||||
.expect("save the coupled state");
|
||||
}
|
||||
if (step + 1) % 250 == 0 {
|
||||
let w = &uy_series[uy_series.len().saturating_sub(600)..];
|
||||
let (mid, amp) = mid_amp(w);
|
||||
|
||||
Reference in New Issue
Block a user