STAR
Cal STAR — firmware, DAQ server, and engine design
Loading...
Searching...
No Matches
measurements.py
Go to the documentation of this file.
1"""Measured values in place of the model's assumptions.
2
3``apply_measurements(cfg)`` returns a copy of the config with every measurement written where the
4assumed number used to enter, so every caller of the engine (forward mode, Time-Series, Layer 1)
5uses it without knowing it exists. ``calibration_state(cfg)`` says, per forward-mode calibration
6key, whether it is measured and by what.
7
8 cd_O, cd_F discharge.<side>: a fixed Cd (the discharge model's Re and inlet terms off)
9 em combustion.efficiency: rupe_Em_opt = E_m, curvature 0 (E_m flat in M)
10 d32_O_um, d32_F_um spray.smd.d32_measured_*: held at the measured value
11 nozzle_efficiency chamber_geometry.nozzle_efficiency
12 chug_frequency_hz reference only: forward mode shows it beside the model's
13"""
14from __future__ import annotations
15
16from typing import Any, Dict
17
18
19def _m(cfg: Any, key: str):
20 ms = getattr(cfg, "measurements", None)
21 return getattr(ms, key, None) if ms is not None else None
22
23
24def apply_measurements(cfg: Any) -> Any:
25 """A copy of ``cfg`` with its measurements applied; ``cfg`` itself when it has none."""
26 if getattr(cfg, "measurements", None) is None:
27 return cfg
28 c = cfg.model_copy(deep=True)
29 for k, side in (("cd_O", "oxidizer"), ("cd_F", "fuel")):
30 mv = _m(c, k)
31 if mv is not None:
32 cd = float(mv.value)
33 c.discharge[side] = c.discharge[side].model_copy(update={
34 "inlet_geometry": None, "inlet_radius_ratio": None, "use_geometry_cd": False,
35 "Cd_inf": cd, "Cd_min": cd, "a_Re": 0.0, "cd_inf_max": cd, "cd_inf_min_geom": cd})
36 em = _m(c, "em")
37 if em is not None:
38 c.combustion.efficiency.rupe_Em_opt = float(em.value)
39 c.combustion.efficiency.rupe_Em_curvature = 0.0
40 for k, f in (("d32_O_um", "d32_measured_O"), ("d32_F_um", "d32_measured_F")):
41 mv = _m(c, k)
42 if mv is not None:
43 setattr(c.spray.smd, f, float(mv.value) * 1e-6)
44 zn = _m(c, "nozzle_efficiency")
45 if zn is not None and getattr(c, "chamber_geometry", None) is not None:
46 c.chamber_geometry.nozzle_efficiency = float(zn.value)
47 return c
48
49
50#: Forward-mode calibration key -> the measurements that close it (all of them needed).
51CLOSES = {
52 "cd": ("cd_O", "cd_F"),
53 "em": ("em",),
54 "smd": ("d32_O_um", "d32_F_um"),
55 "nozzle": ("nozzle_efficiency",),
56}
57
58
59def calibration_state(cfg: Any) -> Dict[str, Dict[str, Any]]:
60 """Per calibration key: ``{"state": "measured"|"partial"|"assumed", "sources": [...]}``."""
61 out: Dict[str, Dict[str, Any]] = {}
62 for key, needs in CLOSES.items():
63 got = [(n, _m(cfg, n)) for n in needs]
64 have = [(n, mv) for n, mv in got if mv is not None]
65 state = "measured" if len(have) == len(needs) else ("partial" if have else "assumed")
66 out[key] = {"state": state, "sources": [f"{n}: {mv.value:g} ({mv.source})" for n, mv in have]}
67 return out
Dict[str, Dict[str, Any]] calibration_state(Any cfg)