STAR
Cal STAR — firmware, DAQ server, and engine design
Loading...
Searching...
No Matches
test_accel_outcomes.py
Go to the documentation of this file.
1"""The accelerator must distinguish "can't handle this" from "didn't converge".
2
3Both used to surface as a bare None, which made them impossible to tell apart at
4the call site or in instrumentation. They mean opposite things:
5
6 NOT_HANDLED no implementation exists for this config -- Python is the only
7 one, so the fallback is mandatory and does real work.
8 NO_SOLUTION the physics ran and did not converge. Measured over 102 such
9 candidates, the Python fallback then failed on every one, so that
10 fallback is re-deriving "infeasible" at full cost.
11
12Only the second is a candidate for ever being short-circuited. Conflating them
13would make that change unsafe, because skipping the fallback on NOT_HANDLED would
14silently drop every config the accelerator doesn't cover.
15
16The public evaluate/solve/chamber_solve keep the plain-None contract; these tests
17also pin that, since every caller keys on `is None`.
18"""
19from __future__ import annotations
20
21import copy
22from pathlib import Path
23
24import pytest
25
26ROOT = Path(__file__).resolve().parents[1]
27PA = 101325.0
28
29
30@pytest.fixture(scope="module")
31def rig():
32 from engine import accel
33 from engine.core.runner import PintleEngineRunner
34 from engine.pipeline.io import load_config
35 if not accel.available():
36 pytest.skip("numba unavailable")
37 cfg = load_config(str(ROOT / "configs/canonical/impinging.yaml"))
38 return cfg, PintleEngineRunner(cfg)
39
40
42 from engine import accel
43 cfg, r = rig
44 res, oc = accel.evaluate_ex(cfg, r.cea_cache, 4.0e6, 4.0e6, PA)
45 assert oc is accel.Outcome.OK
46 assert res is not None and res["Pc"] > 0
47
48
50 """Tank pressures below the chamber: the physics runs and gives up."""
51 from engine import accel
52 cfg, r = rig
53 res, oc = accel.evaluate_ex(cfg, r.cea_cache, 1.2e5, 1.2e5, PA)
54 assert res is None
55 assert oc is accel.Outcome.NO_SOLUTION, (
56 "a non-converged solve must NOT report NOT_HANDLED -- that would mark a "
57 "skippable fallback as mandatory"
58 )
59
60
62 """Film cooling has no port; the accelerator must say so, not 'no solution'."""
63 from engine import accel
64 cfg, r = rig
65 bad = copy.deepcopy(cfg)
66 bad.film_cooling.enabled = True
67 res, oc = accel.evaluate_ex(bad, r.cea_cache, 4.0e6, 4.0e6, PA)
68 assert res is None
69 assert oc is accel.Outcome.NOT_HANDLED, (
70 "an unsupported config must NOT report NO_SOLUTION -- short-circuiting "
71 "that would silently drop the only implementation that can run it"
72 )
73
74
76 from engine import accel
77 cfg, r = rig
78 assert accel.solve_ex(cfg, 4.0e6, 4.0e6, 2.4e6)[1] is accel.Outcome.OK
79 assert accel.chamber_solve_ex(cfg, r.cea_cache, 4.0e6, 4.0e6)[1] is accel.Outcome.OK
80 bad = copy.deepcopy(cfg)
81 bad.film_cooling.enabled = True
82 assert accel.solve_ex(bad, 4.0e6, 4.0e6, 2.4e6)[1] is accel.Outcome.NOT_HANDLED
83 assert accel.chamber_solve_ex(bad, r.cea_cache, 4.0e6, 4.0e6)[1] is accel.Outcome.NOT_HANDLED
84
85
87 """Callers key on `is None`; the *_ex split must not have changed that."""
88 from engine import accel
89 cfg, r = rig
90 ok = accel.evaluate(cfg, r.cea_cache, 4.0e6, 4.0e6, PA)
91 assert isinstance(ok, dict), "evaluate() must still return the plain result dict"
92 assert accel.evaluate(cfg, r.cea_cache, 1.2e5, 1.2e5, PA) is None
93 assert isinstance(accel.solve(cfg, 4.0e6, 4.0e6, 2.4e6), tuple)
94 assert isinstance(accel.chamber_solve(cfg, r.cea_cache, 4.0e6, 4.0e6), tuple)
test_plain_api_still_returns_bare_none_or_result(rig)