forked from 1b-agent/fieldcraft-upstream
engine: report a held face as the temperature extreme to scripts
The results reply named the fluid's 79.69 °C cell as the maximum while the app showed the face held at 80 °C. It now names that face, by body and face as for wall heat, so a script reads what the legend shows. Part of #157.
This commit is contained in:
1 parent
7e3eaa14f2
commit
6b87dc508d
2 files changed
+36
-6
No files matched your search
@@ -403,9 +403,24 @@ pub fn plot_with_surfaces(
|
||||
/// Per displayed surface triangle, the temperature its obstacle face is held at, when the step's
|
||||
/// domain holds that face at one and the result is of the current model.
|
||||
fn held_temperatures(session: &crate::Session, r: &FluidResult, base: &fieldcraft_render::DisplayMesh, bodies: &[&str]) -> Vec<Option<f64>> {
|
||||
let none = || vec![None; base.surface_tris.len()];
|
||||
let faces = held_faces(session, r);
|
||||
let held: std::collections::BTreeMap<_, _> = faces.iter().map(|h| ((h.body.as_str(), h.index), h.value)).collect();
|
||||
base.surface_tris.iter().map(|t| bodies.get(t.body as usize).and_then(|name| held.get(&(*name, t.face)).copied())).collect()
|
||||
}
|
||||
|
||||
/// An obstacle face the step's fluid domain holds at a temperature.
|
||||
pub struct HeldFace {
|
||||
pub body: String,
|
||||
pub face: String,
|
||||
pub index: u32,
|
||||
pub value: f64,
|
||||
}
|
||||
|
||||
/// The faces the step's fluid domain holds at a temperature, when the result is of the current
|
||||
/// model (a stale result was solved with other conditions).
|
||||
pub fn held_faces(session: &crate::Session, r: &FluidResult) -> Vec<HeldFace> {
|
||||
if session.latest_result(&r.step).is_some_and(|(_, current)| !current) {
|
||||
return none();
|
||||
return Vec::new();
|
||||
}
|
||||
let Some(thermal) = session
|
||||
.model
|
||||
@@ -414,10 +429,10 @@ fn held_temperatures(session: &crate::Session, r: &FluidResult, base: &fieldcraf
|
||||
.and_then(|d| session.model.fluid_domain(d))
|
||||
.and_then(|d| d.thermal.as_ref())
|
||||
else {
|
||||
return none();
|
||||
return Vec::new();
|
||||
};
|
||||
let design = session.design.as_deref();
|
||||
let mut held = std::collections::BTreeMap::new();
|
||||
let mut out = Vec::new();
|
||||
for sb in &thermal.surfaces {
|
||||
let (fieldcraft_model::ThermalCondition::Temperature { value }, fieldcraft_model::Entity::Face(face)) = (&sb.condition, &sb.face.entity)
|
||||
else {
|
||||
@@ -425,10 +440,10 @@ fn held_temperatures(session: &crate::Session, r: &FluidResult, base: &fieldcraf
|
||||
};
|
||||
let index = design.and_then(|d| d.bodies.iter().find(|b| b.name == sb.face.body)).and_then(|b| b.face_index(face));
|
||||
if let Some(index) = index {
|
||||
held.insert((sb.face.body.as_str(), index), *value);
|
||||
out.push(HeldFace { body: sb.face.body.clone(), face: face.clone(), index, value: *value });
|
||||
}
|
||||
}
|
||||
base.surface_tris.iter().map(|t| bodies.get(t.body as usize).and_then(|name| held.get(&(*name, t.face)).copied())).collect()
|
||||
out
|
||||
}
|
||||
|
||||
/// The colours a flow plot is drawn in.
|
||||
@@ -650,6 +665,9 @@ pub(crate) mod tests {
|
||||
assert!(at.is_some(), "{:?}", c.max);
|
||||
let held: Vec<f64> = fp.wall_values.iter().filter_map(|(_, v)| *v).collect();
|
||||
assert!(!held.is_empty() && held.iter().all(|t| *t == 80.0), "{held:?}");
|
||||
// A script reads the same maximum as the app shows: the held face.
|
||||
let reply = s.results_report();
|
||||
assert_eq!(reply["contour"]["range"]["max"], json!({"body": "Body1", "face": face, "value": 80.0}), "{reply}");
|
||||
// The headless picture draws the held face in the top band's colour.
|
||||
let p = crate::view::Palette::LIGHT;
|
||||
let top = bands_color(&p.contour, p.contour_over, &c.bands, c.bands.band(80.0).unwrap());
|
||||
|
||||
@@ -722,6 +722,18 @@ impl Session {
|
||||
out[k.as_str()] = x;
|
||||
}
|
||||
}
|
||||
// A face held beyond the fluid's range is the extreme, as the legend shows it.
|
||||
if v.contour == Some(Field::Temperature) && out["contour"]["range"].is_object() {
|
||||
for h in crate::flow::held_faces(self, f) {
|
||||
let end = json!({"body": h.body, "face": h.face, "value": h.value});
|
||||
let range = &mut out["contour"]["range"];
|
||||
if range["max"]["value"].as_f64().is_some_and(|m| h.value > m) {
|
||||
range["max"] = end;
|
||||
} else if range["min"]["value"].as_f64().is_some_and(|m| h.value < m) {
|
||||
range["min"] = end;
|
||||
}
|
||||
}
|
||||
}
|
||||
if v.contour == Some(Field::WallHeatFlux)
|
||||
&& let Ok(faces) = crate::flow::wall::faces(self, f, v.pick())
|
||||
{
|
||||
|
||||
Reference in new issue
Block a user