flow 1.3.0
Kokkos cut-cell IBM incompressible Navier-Stokes solver + pnm pore extraction
Loading...
Searching...
No Matches
test_no_float_operator_casts.py
Go to the documentation of this file.
1#!/usr/bin/env python3
2"""QUALITY_PLAN G.6 guard: no operator-storage view narrows to `float` outside the allow-list.
3
4`MReal` (`mac_cutcell_mg.hpp`) is the operator storage type -- float unless the build defines
5`-DPECLET_FLOW_OPERATOR_DOUBLE` (an `option()` since G.6, was a raw, untested `-DCMAKE_CXX_FLAGS`).
6G.6 templated `IbmOverlayT`/`ibmFillEntry`/`ibmModifyStencil` (cut_cell_ibm.hpp) and the geometry
7build that feeds them (mac_ibm.hpp, flow_ibm.hpp) on `Real`/`mreal` so a double build carries the
8cut-cell overlay in double end to end; this test fails if a NEW hard `(float)` cast or `float`-typed
9operator view creeps back in outside the allow-list below, so the next one has to be typed on
10`mreal`/`MReal` (or exempted with a stated reason) instead.
11
12A hit is IGNORED when: the line is a pure comment (only prose, no code -- these mention "(float)" in
13plain English and are not casts); the whole FILE is allow-listed (an opt-in debug/forensics file
14whose float precision is unrelated to operator correctness, or a file whose ghost-projection overlay
15is a stated, deferred gap -- see the reasons below); or the line carries a `PRECISION-EXEMPT:`
16marker (a deliberate, reasoned exception -- `git grep PRECISION-EXEMPT src/` to read them).
17"""
18import pathlib
19import re
20import sys
21
22SRC = pathlib.Path(__file__).resolve().parents[2] / "src"
23
24CAST = re.compile(r"\‍(\s*float\s*\‍)|static_cast\s*<\s*float\s*>|View<\s*float\s*\*")
25
26# Whole files exempt from this test, with the reason (also stated in the file's own header
27# comment as PRECISION-EXEMPT so a reader of the file sees it too, not just this list).
28FILE_EXEMPT = {
29 "ghost_projection_debug.hpp": (
30 "opt-in forensics (PECLET_FLOW_GP_DEBUG); never feeds a solve, precision is unrelated to "
31 "correctness"
32 ),
33}
34
35
36def is_comment_line(line: str) -> bool:
37 s = line.strip()
38 return s.startswith("//") or s.startswith("/*") or s.startswith("*")
39
40
41def main() -> int:
42 offenders = []
43 for path in sorted(SRC.rglob("*")):
44 if path.suffix not in (".hpp", ".cpp", ".h"):
45 continue
46 if path.name in FILE_EXEMPT:
47 continue
48 for lineno, line in enumerate(path.read_text().splitlines(), 1):
49 if not CAST.search(line):
50 continue
51 if is_comment_line(line):
52 continue
53 if "PRECISION-EXEMPT" in line:
54 continue
55 offenders.append(f"{path.relative_to(SRC.parent)}:{lineno}: {line.strip()}")
56 if offenders:
57 print(
58 "hard (float) casts / float-typed operator views found in src/ outside the "
59 "allow-list (QUALITY_PLAN G.6 -- type on mreal/MReal, or mark "
60 "`// PRECISION-EXEMPT: <reason>` if it is genuinely precision-independent):"
61 )
62 for o in offenders:
63 print(" " + o)
64 return 1
65 print("no un-exempted float operator casts in src/ [OK]")
66 return 0
67
68
69if __name__ == "__main__":
70 sys.exit(main())