Repository: simpeg/simpeg (python)

Issue:
warning with default solver 
I appreciate the idea of wanting to alert users that a default solver is being used, but it is odd that if I am writing a tutorial or example and want to explicitly set the default solver, that I get a warning (e.g. in the following figure). A warning usually implies that I should change my code, but here, it is just information. For the purposes of a tutorial, I then opt not to use the handy functionality of getting a default solver because having a warning message pop up is distracting (and I don't want to be promoting that users should suppress all warnings). 

![image](https://github.com/user-attachments/assets/6f558e37-60c1-42a4-ada8-6222fc8a73ca)

So, then the question is what to do. I would suggest that we remove the warning and instead include a statement in the inversion log about what solver is being used (we could also add this as a statement that is printed out when running a "verbose" simulation, but I know that we don't have that option implemented uniformly across all simulations at the moment). Totally open to other suggestions too, but I think that when a user explicitly calls `get_default_solver` that we shouldn't throw a warning at them. 




Pull request:
Only warn about default solver when set in simulations
#### Summary

Add a `warn=False` argument to the `get_default_solver()` function. Only when `warn=True`, the warning about the setting of the default solver is raised. This makes the function not to raise a warning when called with the default arguments. When default solvers are being used within simulations, call the function with `warn=True` to let users know about the solver being automatically selected. Update tests accordingly.

#### PR Checklist
* [ ] If this is a work in progress PR, set as a Draft PR
* [ ] Linted my code according to the [style guides](https://docs.simpeg.xyz/latest/content/getting_started/contributing/code-style.html).
* [ ] Added [tests](https://docs.simpeg.xyz/latest/content/getting_started/contributing/testing.html) to verify changes to the code.
* [ ] Added necessary documentation to any new functions/classes following the
      expect [style](https://docs.simpeg.xyz/latest/content/getting_started/contributing/documentation.html).
* [ ] Marked as ready for review (if this is was a draft PR), and converted
      to a Pull Request
* [ ] Tagged ``@simpeg/simpeg-developers`` when ready for review.

#### Reference issue

Fix #1563

#### What does this implement/fix?
<!--Please explain your changes.-->

#### Additional information
<!--Any additional information you think is important.-->


<!--
Once all tests pass and the code has been reviewed and approved, it will be merged into main
-->


Patch:
diff --git a/simpeg/potential_fields/magnetics/simulation.py b/simpeg/potential_fields/magnetics/simulation.py
index 55db09e54..a40a28bb9 100644
--- a/simpeg/potential_fields/magnetics/simulation.py
+++ b/simpeg/potential_fields/magnetics/simulation.py
@@ -1612,7 +1612,7 @@ def MagneticsDiffSecondaryInv(mesh, model, data, **kwargs):
 
     # Create an optimization program
     opt = optimization.InexactGaussNewton(maxIter=miter)
-    opt.bfgsH0 = get_default_solver()(sp.identity(model.nP), flag="D")
+    opt.bfgsH0 = get_default_solver(warn=True)(sp.identity(model.nP), flag="D")
     # Create a regularization program
     reg = regularization.WeightedLeastSquares(model)
     # Create an objective function
diff --git a/simpeg/simulation.py b/simpeg/simulation.py
index de6ec1264..aa0237f0f 100644
--- a/simpeg/simulation.py
+++ b/simpeg/simulation.py
@@ -194,7 +194,7 @@ class BaseSimulation(props.HasModel):
         if self._solver is None:
             # do not cache this, in case the user wants to
             # change it after the first time it is requested.
-            return get_default_solver()
+            return get_default_solver(warn=True)
         return self._solver
 
     @solver.setter
diff --git a/simpeg/utils/solver_utils.py b/simpeg/utils/solver_utils.py
index bca12303f..55ffab0f1 100644
--- a/simpeg/utils/solver_utils.py
+++ b/simpeg/utils/solver_utils.py
@@ -49,22 +49,30 @@ class DefaultSolverWarning(UserWarning):
     pass
 
 
-def get_default_solver() -> Type[Base]:
+def get_default_solver(warn=False) -> Type[Base]:
     """Return the default solver used by simpeg.
 
+    Parameters
+    ----------
+    warn : bool, optional
+        If True, a warning will be raised to let users know that the default
+        solver is being chosen depending on their system.
+
     Returns
     -------
     solver
         The default solver class used by simpeg's simulations.
     """
-    warnings.warn(
-        f"Using the default solver: {_DEFAULT_SOLVER.__name__}. \n\n"
-        f"If you would like to suppress this notification, add \n"
-        f"warnings.filterwarnings('ignore', simpeg.utils.solver_utils.DefaultSolverWarning)\n"
-        f" to your script.",
-        DefaultSolverWarning,
-        stacklevel=2,
-    )
+    if warn:
+        warnings.warn(
+            f"Using the default solver: {_DEFAULT_SOLVER.__name__}. \n\n"
+            f"If you would like to suppress this notification, add \n"
+            f"warnings.filterwarnings("
+            "'ignore', simpeg.utils.solver_utils.DefaultSolverWarning)\n"
+            f" to your script.",
+            DefaultSolverWarning,
+            stacklevel=2,
+        )
     return _DEFAULT_SOLVER
 
 


Test patch:
diff --git a/tests/utils/test_default_solver.py b/tests/utils/test_default_solver.py
index f95a3cf4d..e8e2fc3ba 100644
--- a/tests/utils/test_default_solver.py
+++ b/tests/utils/test_default_solver.py
@@ -1,3 +1,4 @@
+import warnings
 import pytest
 from pymatsolver import SolverCG
 
@@ -11,18 +12,14 @@ from simpeg.utils.solver_utils import (
 @pytest.fixture(autouse=True)
 def reset_default_solver():
     # This should get automatically used
-    with pytest.warns(DefaultSolverWarning):
-        initial_default = get_default_solver()
+    initial_default = get_default_solver()
     yield
     set_default_solver(initial_default)
 
 
 def test_default_setting():
     set_default_solver(SolverCG)
-
-    with pytest.warns(DefaultSolverWarning, match="Using the default solver: SolverCG"):
-        new_default = get_default_solver()
-
+    new_default = get_default_solver()
     assert new_default == SolverCG
 
 
@@ -31,7 +28,7 @@ def test_default_error():
         pass
 
     with pytest.warns(DefaultSolverWarning):
-        initial_default = get_default_solver()
+        initial_default = get_default_solver(warn=True)
 
     with pytest.raises(
         TypeError,
@@ -40,7 +37,20 @@ def test_default_error():
         set_default_solver(Temp)
 
     with pytest.warns(DefaultSolverWarning):
-        after_default = get_default_solver()
+        after_default = get_default_solver(warn=True)
 
     # make sure we didn't accidentally set the default.
     assert initial_default == after_default
+
+
+def test_warning():
+    """Test if warning is raised when warn=True."""
+    with pytest.warns(DefaultSolverWarning, match="Using the default solver"):
+        get_default_solver(warn=True)
+
+
+def test_no_warning():
+    """Test if no warning is issued with default parameters."""
+    with warnings.catch_warnings():
+        warnings.simplefilter("error")  # raise error if warning was raised
+        get_default_solver()