From 4dae9bbca689e473caffea9994a0af08dc1d00bc Mon Sep 17 00:00:00 2001 From: Spencer Bryngelson Date: Fri, 11 Sep 2026 18:18:38 -0400 Subject: [PATCH 1/2] Require the full inflow state when grcbc_in is enabled A GRCBC subsonic inflow relaxes the boundary towards a prescribed state, so that state has to be given in full: velocity, pressure, partial densities and volume fractions. The validator checked only that the boundary type was -7. Leaving alpha_rho_in and alpha_in unset does not fail; the boundary keeps the default sentinel and the solution diverges over a few hundred steps, surfacing as an ICFL abort far from the cause. That cost me two runs before I compared against a case that worked, which is a poor way to learn that four parameters are mandatory rather than three. The check accepts every example case in the tree and rejects exactly the configuration that diverged. Claude-Session: https://claude.ai/code/session_01HMJ7cycfo7kTFSFq5yhHLG --- toolchain/mfc/case_validator.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/toolchain/mfc/case_validator.py b/toolchain/mfc/case_validator.py index 1da790a90..e09ad07c2 100644 --- a/toolchain/mfc/case_validator.py +++ b/toolchain/mfc/case_validator.py @@ -1793,6 +1793,14 @@ def check_grcbc(self): if grcbc_in: # Check if EITHER beg OR end is set to -7 self.prohibit(bc_beg != -7 and bc_end != -7, f"Subsonic Inflow (grcbc_in) requires bc_{dir}%beg = -7 or bc_{dir}%end = -7") + # The relaxation drives the boundary towards a prescribed state, so that state has to be given in + # full. An unset component keeps its default sentinel and the boundary diverges over a few hundred + # steps rather than failing outright, which is a hard failure to read backwards from an ICFL abort. + num_fluids = self.get("num_fluids", 1) + missing = [n for n in (f"bc_{dir}%pres_in", f"bc_{dir}%vel_in(1)") if self.get(n) is None] + missing += [f"bc_{dir}%alpha_rho_in({i})" for i in range(1, num_fluids + 1) if self.get(f"bc_{dir}%alpha_rho_in({i})") is None] + missing += [f"bc_{dir}%alpha_in({i})" for i in range(1, num_fluids + 1) if self.get(f"bc_{dir}%alpha_in({i})") is None] + self.prohibit(len(missing) > 0, f"Subsonic Inflow (grcbc_in) needs the full inflow state; missing {', '.join(missing)}") if grcbc_out: # Check if EITHER beg OR end is set to -8 self.prohibit(bc_beg != -8 and bc_end != -8, f"Subsonic Outflow (grcbc_out) requires bc_{dir}%beg = -8 or bc_{dir}%end = -8") From 3a48cd10823079a11db193a86d51c5e0893dad1b Mon Sep 17 00:00:00 2001 From: Spencer Bryngelson Date: Sat, 12 Sep 2026 19:20:20 -0500 Subject: [PATCH 2/2] Require the inflow velocity for every active dimension, not just the first --- toolchain/mfc/case_validator.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/toolchain/mfc/case_validator.py b/toolchain/mfc/case_validator.py index e09ad07c2..66e97afe2 100644 --- a/toolchain/mfc/case_validator.py +++ b/toolchain/mfc/case_validator.py @@ -1797,7 +1797,12 @@ def check_grcbc(self): # full. An unset component keeps its default sentinel and the boundary diverges over a few hundred # steps rather than failing outright, which is a hard failure to read backwards from an ICFL abort. num_fluids = self.get("num_fluids", 1) - missing = [n for n in (f"bc_{dir}%pres_in", f"bc_{dir}%vel_in(1)") if self.get(n) is None] + # s_initialize_cbc_module copies vel_in(1..num_dims) and the kernel reads them through + # dir_idx, which is (2,1,3) for a y inflow and (3,1,2) for z -- so requiring only + # component 1 would leave the normal velocity of a y or z inflow unchecked. + num_dims = 3 if (self.get("p", 0) or 0) > 0 else (2 if (self.get("n", 0) or 0) > 0 else 1) + missing = [n for n in (f"bc_{dir}%pres_in",) if self.get(n) is None] + missing += [f"bc_{dir}%vel_in({d})" for d in range(1, num_dims + 1) if self.get(f"bc_{dir}%vel_in({d})") is None] missing += [f"bc_{dir}%alpha_rho_in({i})" for i in range(1, num_fluids + 1) if self.get(f"bc_{dir}%alpha_rho_in({i})") is None] missing += [f"bc_{dir}%alpha_in({i})" for i in range(1, num_fluids + 1) if self.get(f"bc_{dir}%alpha_in({i})") is None] self.prohibit(len(missing) > 0, f"Subsonic Inflow (grcbc_in) needs the full inflow state; missing {', '.join(missing)}")