From 1c5badb5bffb2008a72820998265e079c8c05f20 Mon Sep 17 00:00:00 2001 From: Jakub Both Date: Tue, 17 Sep 2024 10:55:05 +0200 Subject: [PATCH 1/5] MAINT: Turn off redundant residual computations if tolerance np.inf --- src/porepy/models/solution_strategy.py | 22 ++++++++++++++----- .../numerics/nonlinear/nonlinear_solvers.py | 10 ++++++--- 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/src/porepy/models/solution_strategy.py b/src/porepy/models/solution_strategy.py index d114d7c6c6..79df91c837 100644 --- a/src/porepy/models/solution_strategy.py +++ b/src/porepy/models/solution_strategy.py @@ -511,7 +511,7 @@ def after_simulation(self) -> None: def check_convergence( self, nonlinear_increment: np.ndarray, - residual: np.ndarray, + residual: Optional[np.ndarray], reference_residual: np.ndarray, nl_params: dict[str, Any], ) -> tuple[float, float, bool, bool]: @@ -520,7 +520,7 @@ def check_convergence( Parameters: nonlinear_increment: Newly obtained solution increment vector residual: Residual vector of non-linear system, evaluated at the newly - obtained solution vector. + obtained solution vector. Potentially None, if the residual is not needed reference_residual: Reference residual vector of non-linear system, evaluated for the initial guess at current time step. nl_params: Dictionary of parameters used for the convergence check. @@ -567,8 +567,14 @@ def check_convergence( f"Nonlinear residual norm: {residual_norm:.2e}" ) # Check convergence requiring both the increment and residual to be small. - converged_inc = nonlinear_increment_norm < nl_params["nl_convergence_tol"] - converged_res = residual_norm < nl_params["nl_convergence_tol_res"] + converged_inc = ( + nl_params["nl_convergence_tol"] is np.inf + or nonlinear_increment_norm < nl_params["nl_convergence_tol"] + ) + converged_res = ( + nl_params["nl_convergence_tol_res"] is np.inf + or residual_norm < nl_params["nl_convergence_tol_res"] + ) converged = converged_inc and converged_res diverged = False @@ -580,7 +586,7 @@ def check_convergence( return residual_norm, nonlinear_increment_norm, converged, diverged def compute_residual_norm( - self, residual: np.ndarray, reference_residual: np.ndarray + self, residual: Optional[np.ndarray], reference_residual: np.ndarray ) -> float: """Compute the residual norm for a nonlinear iteration. @@ -593,7 +599,11 @@ def compute_residual_norm( float: Residual norm. """ - residual_norm = np.linalg.norm(residual) / np.sqrt(residual.size) + residual_norm = ( + np.nan + if residual is None + else np.linalg.norm(residual) / np.sqrt(residual.size) + ) return residual_norm def compute_nonlinear_increment_norm( diff --git a/src/porepy/numerics/nonlinear/nonlinear_solvers.py b/src/porepy/numerics/nonlinear/nonlinear_solvers.py index bad8b71262..1f38a0ac91 100644 --- a/src/porepy/numerics/nonlinear/nonlinear_solvers.py +++ b/src/porepy/numerics/nonlinear/nonlinear_solvers.py @@ -70,6 +70,7 @@ def solve(self, model) -> tuple[bool, int]: iteration_counter = 0 residual_norm = np.inf + residual = None nonlinear_increment_norm = np.inf is_converged = False is_diverged = False @@ -87,6 +88,7 @@ def newton_step() -> None: nonlocal nonlinear_increment nonlocal reference_residual nonlocal residual_norm + nonlocal residual nonlocal nonlinear_increment_norm nonlocal is_converged nonlocal is_diverged @@ -103,9 +105,11 @@ def newton_step() -> None: nonlinear_increment = self.iteration(model) model.after_nonlinear_iteration(nonlinear_increment) - # Note: The residual is extracted after the solution has been updated by the - # after_nonlinear_iteration() method. - residual = model.equation_system.assemble(evaluate_jacobian=False) + if self.params["nl_convergence_tol_res"] is not np.inf: + # Note: The residual is extracted after the solution has been updated by the + # after_nonlinear_iteration() method. This is only required if the residual + # is used to check convergence, i.e., the tolerance is not np.inf. + residual = model.equation_system.assemble(evaluate_jacobian=False) residual_norm, nonlinear_increment_norm, is_converged, is_diverged = ( model.check_convergence( From dc831e9560202e2fbe4d0f845bccdb40ede04b55 Mon Sep 17 00:00:00 2001 From: Jakub Both Date: Wed, 18 Sep 2024 08:24:23 +0200 Subject: [PATCH 2/5] STY: indentation --- src/porepy/models/solution_strategy.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/porepy/models/solution_strategy.py b/src/porepy/models/solution_strategy.py index 79df91c837..96def82c4c 100644 --- a/src/porepy/models/solution_strategy.py +++ b/src/porepy/models/solution_strategy.py @@ -520,7 +520,7 @@ def check_convergence( Parameters: nonlinear_increment: Newly obtained solution increment vector residual: Residual vector of non-linear system, evaluated at the newly - obtained solution vector. Potentially None, if the residual is not needed + obtained solution vector. Potentially None, if the residual is not needed. reference_residual: Reference residual vector of non-linear system, evaluated for the initial guess at current time step. nl_params: Dictionary of parameters used for the convergence check. From 2f2b18dc517f461111f4f7009d44155a7087d959 Mon Sep 17 00:00:00 2001 From: "Jakub W. Both" <73653591+jwboth@users.noreply.github.com> Date: Thu, 9 Jan 2025 14:22:22 +0100 Subject: [PATCH 3/5] Apply suggestions from code review Co-authored-by: Ivar Stefansson --- src/porepy/models/solution_strategy.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/porepy/models/solution_strategy.py b/src/porepy/models/solution_strategy.py index 79df91c837..1e0ffa5326 100644 --- a/src/porepy/models/solution_strategy.py +++ b/src/porepy/models/solution_strategy.py @@ -520,7 +520,7 @@ def check_convergence( Parameters: nonlinear_increment: Newly obtained solution increment vector residual: Residual vector of non-linear system, evaluated at the newly - obtained solution vector. Potentially None, if the residual is not needed + obtained solution vector. Potentially None, if the residual is not needed. reference_residual: Reference residual vector of non-linear system, evaluated for the initial guess at current time step. nl_params: Dictionary of parameters used for the convergence check. From d2b291e9e132f3190a5829542bbb3bc232f41637 Mon Sep 17 00:00:00 2001 From: Jakub Both Date: Thu, 9 Jan 2025 14:30:16 +0100 Subject: [PATCH 4/5] MAINT: Adapt style of if-else construct. --- src/porepy/models/solution_strategy.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/porepy/models/solution_strategy.py b/src/porepy/models/solution_strategy.py index 96def82c4c..669b2a1511 100644 --- a/src/porepy/models/solution_strategy.py +++ b/src/porepy/models/solution_strategy.py @@ -596,14 +596,12 @@ def compute_residual_norm( allowing for definiting relative criteria. Returns: - float: Residual norm. + float: Residual norm; np.nan if the residual is None. """ - residual_norm = ( - np.nan - if residual is None - else np.linalg.norm(residual) / np.sqrt(residual.size) - ) + if residual is None: + return np.nan + residual_norm = np.linalg.norm(residual) / np.sqrt(residual.size) return residual_norm def compute_nonlinear_increment_norm( From 34527d72c5ea2e1d4906d3de5673e53913348904 Mon Sep 17 00:00:00 2001 From: Jakub Both Date: Thu, 9 Jan 2025 14:44:57 +0100 Subject: [PATCH 5/5] MAINT: Use explicit/local assignment. --- src/porepy/numerics/nonlinear/nonlinear_solvers.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/porepy/numerics/nonlinear/nonlinear_solvers.py b/src/porepy/numerics/nonlinear/nonlinear_solvers.py index 1f38a0ac91..1467c7d08f 100644 --- a/src/porepy/numerics/nonlinear/nonlinear_solvers.py +++ b/src/porepy/numerics/nonlinear/nonlinear_solvers.py @@ -70,7 +70,6 @@ def solve(self, model) -> tuple[bool, int]: iteration_counter = 0 residual_norm = np.inf - residual = None nonlinear_increment_norm = np.inf is_converged = False is_diverged = False @@ -88,7 +87,6 @@ def newton_step() -> None: nonlocal nonlinear_increment nonlocal reference_residual nonlocal residual_norm - nonlocal residual nonlocal nonlinear_increment_norm nonlocal is_converged nonlocal is_diverged @@ -106,10 +104,13 @@ def newton_step() -> None: model.after_nonlinear_iteration(nonlinear_increment) if self.params["nl_convergence_tol_res"] is not np.inf: - # Note: The residual is extracted after the solution has been updated by the - # after_nonlinear_iteration() method. This is only required if the residual - # is used to check convergence, i.e., the tolerance is not np.inf. + # Note: The residual is extracted after the solution has been updated by + # the after_nonlinear_iteration() method. This is only required if the + # residual is used to check convergence, i.e., the tolerance is not + # np.inf. residual = model.equation_system.assemble(evaluate_jacobian=False) + else: + residual = None residual_norm, nonlinear_increment_norm, is_converged, is_diverged = ( model.check_convergence(