Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 34 additions & 6 deletions toolchain/mfc/case_validator.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,14 @@
"math": r"m > 0, \quad n \geq 0, \quad p \geq 0",
"explanation": ("The x-direction must have cells. Cannot have z without y. Cylindrical coordinates require odd p."),
},
"check_domain_extents": {
"title": "Domain Extents Specified",
"category": "Domain and Geometry",
"math": r"m > 0 \Rightarrow x_{\mathrm{beg}}, x_{\mathrm{end}} \ \mathrm{set}",
"explanation": (
"Every dimension that has cells needs its physical extents so that the grid can be generated. Skipped on restarts (old_grid = T), where the mesh is read from the existing grid files."
),
},
"check_patch_within_domain": {
"title": "Patch Within Domain",
"category": "Domain and Geometry",
Expand Down Expand Up @@ -330,12 +338,6 @@ def check_parameter_types(self):
f"recon_type must be one of {_recon_shown}",
)

# Required domain parameters when m > 0
m = self.get("m")
if m is not None and m > 0:
self.prohibit(not self.is_set("x_domain%beg"), "x_domain%beg must be set when m > 0")
self.prohibit(not self.is_set("x_domain%end"), "x_domain%end must be set when m > 0")

# Common Checks (All Stages)

def check_simulation_domain(self):
Expand Down Expand Up @@ -1508,6 +1510,31 @@ def check_restart(self):
f"num_patches must be <= {num_patches_max} (num_patches_max in m_constants.fpp)",
)

def check_domain_extents(self):
"""Checks that the physical extents of every active dimension are set (pre-process)

The grid generator needs (xyz)_domain%beg and (xyz)_domain%end for each
dimension that has cells. On a restart (old_grid = T) the mesh is read
from the existing grid files, so the extents are neither needed nor read.
"""
if self.get("old_grid", "F") == "T":
return

m = self.get("m", 0)
if self._is_numeric(m) and m > 0:
self.prohibit(not self.is_set("x_domain%beg"), "x_domain%beg must be set when m > 0")
self.prohibit(not self.is_set("x_domain%end"), "x_domain%end must be set when m > 0")

n = self.get("n", 0)
if self._is_numeric(n) and n > 0:
self.prohibit(not self.is_set("y_domain%beg"), "y_domain%beg must be set when n > 0")
self.prohibit(not self.is_set("y_domain%end"), "y_domain%end must be set when n > 0")

p = self.get("p", 0)
if self._is_numeric(p) and p > 0:
self.prohibit(not self.is_set("z_domain%beg"), "z_domain%beg must be set when p > 0")
self.prohibit(not self.is_set("z_domain%end"), "z_domain%end must be set when p > 0")

def check_qbmm_pre_process(self):
"""Checks QBMM constraints for pre-process"""
qbmm = self.get("qbmm", "F") == "T"
Expand Down Expand Up @@ -2499,6 +2526,7 @@ def validate_pre_process(self):
"""Validate pre-process-specific parameters"""
self.validate_common()
self.check_restart()
self.check_domain_extents()
self.check_qbmm_pre_process()
self.check_parallel_io_pre_process()
self.check_grid_stretching()
Expand Down
35 changes: 35 additions & 0 deletions toolchain/mfc/params_tests/test_integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -263,5 +263,40 @@ def test_validator_log_params_match_registry(self):
self.assertEqual(validator_log_params, registry_log_params)


class TestDomainExtents(unittest.TestCase):
"""Tests for the pre-process domain extent requirement."""

# 2D case with no (xyz)_domain entries
BASE = {"m": 100, "n": 50, "num_patches": 1}

def _errors(self, params, stage):
from ..case_validator import CaseConstraintError, CaseValidator

validator = CaseValidator(params)
try:
validator.validate(stage)
except CaseConstraintError:
pass
return [e for e in validator.errors if "domain%" in e and "must be set" in e]

def test_missing_extents_rejected(self):
"""Every dimension with cells needs its extents when generating a grid."""
self.assertEqual(len(self._errors(self.BASE, "pre_process")), 4)

def test_restart_does_not_need_extents(self):
"""old_grid = T reads the mesh from the grid files, so the extents are not needed."""
params = {**self.BASE, "old_grid": "T", "old_ic": "T", "t_step_old": 7000, "num_patches": 0}

for stage in ("pre_process", "simulation", "post_process"):
with self.subTest(stage=stage):
self.assertEqual(self._errors(params, stage), [])

def test_extents_not_required_outside_pre_process(self):
"""(xyz)_domain is a pre-process parameter only."""
for stage in ("simulation", "post_process"):
with self.subTest(stage=stage):
self.assertEqual(self._errors(self.BASE, stage), [])


if __name__ == "__main__":
unittest.main()
Loading