From 051c32ae67770bada9f424aac7b68fccd0b8125d Mon Sep 17 00:00:00 2001 From: NDM14 Date: Wed, 21 Jan 2026 14:38:52 +0100 Subject: [PATCH 1/6] - added method is_mapped_state_valid to state class to check whether the capacity array and its index is set when mapc2p is also set. - added method is_mapped_solution_valid to check whether every state has a valid mapping at runtime. --- src/pyclaw/solution.py | 14 ++++++++++++++ src/pyclaw/state.py | 14 ++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/src/pyclaw/solution.py b/src/pyclaw/solution.py index 6a6c8cdc..aad262e0 100755 --- a/src/pyclaw/solution.py +++ b/src/pyclaw/solution.py @@ -198,6 +198,20 @@ def is_valid(self): - (bool) - True if valid, false otherwise """ return all([state.is_valid() for state in self.states]) + + def is_mapped_solution_valid(self) -> bool: + + r""" Checks to see if this mapped solution is valid + + The Solution checks to make sure it is valid by checking each of its states. + If the mapping and aux is missing, then False is returned. + If the capacity function index is invalid, an ValueError is raised. + If the mapping is present and the capacity array is not set an ValueError is raised. + :Output: + - (bool) - True if valid, false if nothing is set, ValueError otherwise""" + + return all([state.is_mapped_state_valid() for state in self.states]) + def __str__(self): diff --git a/src/pyclaw/state.py b/src/pyclaw/state.py index eff412f7..85f81582 100755 --- a/src/pyclaw/state.py +++ b/src/pyclaw/state.py @@ -188,6 +188,20 @@ def is_valid(self): logger.debug('aux array is not Fortran contiguous.') valid = False return valid + + def is_mapped_state_valid(self) -> bool: + if self.grid.mapc2p is not None and self.aux is None: + if self.grid.mapc2p is not None and self.aux is not None: + if self.index_capa < -1 or self.index_capa >= self.num_aux: + raise ValueError("Capacity function index out of range.") + elif self.index_capa == -1: + raise ValueError("Capacity function index is not set.") + raise ValueError("Mapped grid requires aux array to be set.") + elif self.grid.mapc2p is None and self.aux is not None: + return False + return True + + def set_cparam(self,fortran_module): """ From efde1bc24923370eaa8b09fdc5549e5d44903704 Mon Sep 17 00:00:00 2001 From: NDM14 Date: Wed, 21 Jan 2026 15:41:41 +0100 Subject: [PATCH 2/6] - changed the String of the ValueError for the capacity array --- src/pyclaw/state.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pyclaw/state.py b/src/pyclaw/state.py index 85f81582..5e3709df 100755 --- a/src/pyclaw/state.py +++ b/src/pyclaw/state.py @@ -196,7 +196,7 @@ def is_mapped_state_valid(self) -> bool: raise ValueError("Capacity function index out of range.") elif self.index_capa == -1: raise ValueError("Capacity function index is not set.") - raise ValueError("Mapped grid requires aux array to be set.") + raise ValueError("Mapped grid requires capacity array to be set.") elif self.grid.mapc2p is None and self.aux is not None: return False return True From 0a576b48c72efbe56f56166ff201884e1bdbbacd Mon Sep 17 00:00:00 2001 From: NDM14 Date: Thu, 22 Jan 2026 15:28:38 +0100 Subject: [PATCH 3/6] - removed two unnecassary checks from method is_mapped_state_valid --- src/pyclaw/state.py | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/pyclaw/state.py b/src/pyclaw/state.py index 5e3709df..acba9aa5 100755 --- a/src/pyclaw/state.py +++ b/src/pyclaw/state.py @@ -191,14 +191,11 @@ def is_valid(self): def is_mapped_state_valid(self) -> bool: if self.grid.mapc2p is not None and self.aux is None: - if self.grid.mapc2p is not None and self.aux is not None: - if self.index_capa < -1 or self.index_capa >= self.num_aux: - raise ValueError("Capacity function index out of range.") - elif self.index_capa == -1: - raise ValueError("Capacity function index is not set.") + if self.index_capa < -1 or self.index_capa >= self.num_aux: + raise ValueError("Capacity function index out of range.") + elif self.index_capa == -1: + raise ValueError("Capacity function index is not set.") raise ValueError("Mapped grid requires capacity array to be set.") - elif self.grid.mapc2p is None and self.aux is not None: - return False return True From 66f16619e2488ae52cbba13a979c90fe6f39c704 Mon Sep 17 00:00:00 2001 From: NDM14 Date: Sat, 24 Jan 2026 12:03:00 +0100 Subject: [PATCH 4/6] - removed is_mapped_state_valid method to comply with the present pattern in all objects - implemented the is_mapped_state_valid method from state class to is_valid so only the is_valid function is used to check for validity --- src/pyclaw/solution.py | 16 ---------------- src/pyclaw/state.py | 21 ++++++++++----------- 2 files changed, 10 insertions(+), 27 deletions(-) diff --git a/src/pyclaw/solution.py b/src/pyclaw/solution.py index aad262e0..08d209bd 100755 --- a/src/pyclaw/solution.py +++ b/src/pyclaw/solution.py @@ -198,22 +198,6 @@ def is_valid(self): - (bool) - True if valid, false otherwise """ return all([state.is_valid() for state in self.states]) - - def is_mapped_solution_valid(self) -> bool: - - r""" Checks to see if this mapped solution is valid - - The Solution checks to make sure it is valid by checking each of its states. - If the mapping and aux is missing, then False is returned. - If the capacity function index is invalid, an ValueError is raised. - If the mapping is present and the capacity array is not set an ValueError is raised. - :Output: - - (bool) - True if valid, false if nothing is set, ValueError otherwise""" - - return all([state.is_mapped_state_valid() for state in self.states]) - - - def __str__(self): output = "states:\n" # This is information about each of the states diff --git a/src/pyclaw/state.py b/src/pyclaw/state.py index acba9aa5..005f4ed8 100755 --- a/src/pyclaw/state.py +++ b/src/pyclaw/state.py @@ -187,18 +187,17 @@ def is_valid(self): if not self.aux.flags['F_CONTIGUOUS']: logger.debug('aux array is not Fortran contiguous.') valid = False - return valid - - def is_mapped_state_valid(self) -> bool: if self.grid.mapc2p is not None and self.aux is None: - if self.index_capa < -1 or self.index_capa >= self.num_aux: - raise ValueError("Capacity function index out of range.") - elif self.index_capa == -1: - raise ValueError("Capacity function index is not set.") - raise ValueError("Mapped grid requires capacity array to be set.") - return True - - + raise ValueError("Mapped grid requires capacity array to be set. " \ + "Please set state.aux.") + elif self.grid.mapc2p is not None and self.aux is not None: + if self.index_capa == -1: + raise ValueError("Capacity function index is not set. " \ + "Please set state.index_capa to the appropriate index in the aux array.") + elif self.index_capa < 0 or self.index_capa > self.num_aux -1: + raise ValueError("Capacity function index out of range. " \ + "Please set state.index_capa to the appropriate index in the aux array.") + return valid def set_cparam(self,fortran_module): """ From 1b07b2f86fca6849982aed55b5dffe6b08b52c3f Mon Sep 17 00:00:00 2001 From: NDM14 Date: Tue, 27 Jan 2026 11:46:27 +0100 Subject: [PATCH 5/6] updated error message to tell the user what he needs to do --- src/pyclaw/state.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pyclaw/state.py b/src/pyclaw/state.py index 005f4ed8..ff8b6f56 100755 --- a/src/pyclaw/state.py +++ b/src/pyclaw/state.py @@ -188,8 +188,8 @@ def is_valid(self): logger.debug('aux array is not Fortran contiguous.') valid = False if self.grid.mapc2p is not None and self.aux is None: - raise ValueError("Mapped grid requires capacity array to be set. " \ - "Please set state.aux.") + raise ValueError("Mapped grid requires a capacity function, stored in the aux array, " \ + "but no aux array is present. Please set state.num_aux to a positive value.") elif self.grid.mapc2p is not None and self.aux is not None: if self.index_capa == -1: raise ValueError("Capacity function index is not set. " \ From d34851652a76512bf0ec266e34a1d28dabcf4d38 Mon Sep 17 00:00:00 2001 From: NDM14 Date: Tue, 27 Jan 2026 15:44:38 +0100 Subject: [PATCH 6/6] - Added Testclass and test to check for updated is_valid - the fixture is taken from the example advection_2d_annulus to get a minial setup to test the validity of the state --- src/pyclaw/tests/unittests/test_state.py | 56 ++++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 src/pyclaw/tests/unittests/test_state.py diff --git a/src/pyclaw/tests/unittests/test_state.py b/src/pyclaw/tests/unittests/test_state.py new file mode 100644 index 00000000..cb71693c --- /dev/null +++ b/src/pyclaw/tests/unittests/test_state.py @@ -0,0 +1,56 @@ +import pytest +from pyclaw import State +import pyclaw +from clawpack.pyclaw import Patch +import numpy as np +from examples.advection_2d_annulus import advection_annulus + +class TestState(): + + @pytest.fixture + def state(self) -> State: + r_lower = 0.2 + r_upper = 1.0 + m_r = 40 + + theta_lower = 0.0 + theta_upper = np.pi*2.0 + m_theta = 120 + + r = pyclaw.Dimension(r_lower,r_upper,m_r,name='r') + theta = pyclaw.Dimension(theta_lower,theta_upper,m_theta,name='theta') + + patch = Patch([r, theta]) + patch.grid.mapc2p = advection_annulus.mapc2p_annulus + patch.grid.num_ghost = 2 + num_eqn = 1 + state = State(patch,num_eqn) + + advection_annulus.qinit(state) + + dx, dy = state.grid.delta + p_corners = state.grid.p_nodes + state.aux = advection_annulus.edge_velocities_and_area(p_corners[0],p_corners[1],dx,dy) + state.index_capa = 2 + return state + + + @pytest.mark.parametrize(("raise_error", "aux_none", "invalid_index_capa"), + [(False, False, -1), # Valid state + (True, True, -1), # Invalid state: aux is None + (True, False, -1), # Invalid state: index_capa is -1 + (True, False, -10)]) # Invalid state: index_capa is out of bounds + def test_state_initialization(self, state: State, + raise_error: bool, + aux_none: bool, + invalid_index_capa: int) -> None: + if raise_error: + if aux_none: + state.aux = None + elif state.aux is not None: + state.index_capa = invalid_index_capa + with pytest.raises(ValueError): + assert not state.is_valid() + + else: + assert state.is_valid() \ No newline at end of file