Repository: simpeg/simpeg
Pull request #1538 (2024-09-20 22:46:18)

Replace `seed` for `random_seed` in directives
#### Summary

Replace `seed` for `random_seed` in directive classes. Replace the `seed` argument for a new `random_seed` argument in `eigenvalue_by_power_iteration`. Update usage of `seed` argument in tests and in codebase. Add tests to check the deprecations.

#### 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/content/getting_started/contributing/code-style.html).
* [ ] Added [tests](https://docs.simpeg.xyz/content/getting_started/practices.html#testing) to verify changes to the code.
* [ ] Added necessary documentation to any new functions/classes following the
      expect [style](https://docs.simpeg.xyz/content/getting_started/practices.html#documentation).
* [ ] 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

Part of #1461

#### 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
-->

#### TODO

- [x] update usage of `seed` in examples and tutorials


codecov[bot]: ## [Codecov](https://app.codecov.io/gh/simpeg/simpeg/pull/1538?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=simpeg) Report
Attention: Patch coverage is `98.40000%` with `2 lines` in your changes missing coverage. Please review.
> Project coverage is 86.30%. Comparing base [(`437fa39`)](https://app.codecov.io/gh/simpeg/simpeg/commit/437fa397952933fae2f8225540bca44dc8250e35?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=simpeg) to head [(`896231d`)](https://app.codecov.io/gh/simpeg/simpeg/commit/896231da35830df2bee036a80d084383aefd5828?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=simpeg).

| [Files with missing lines](https://app.codecov.io/gh/simpeg/simpeg/pull/1538?dropdown=coverage&src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=simpeg) | Patch % | Lines |
|---|---|---|
| [tests/utils/test\_mat\_utils.py](https://app.codecov.io/gh/simpeg/simpeg/pull/1538?src=pr&el=tree&filepath=tests%2Futils%2Ftest_mat_utils.py&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=simpeg#diff-dGVzdHMvdXRpbHMvdGVzdF9tYXRfdXRpbHMucHk=) | 93.33% | [2 Missing :warning: ](https://app.codecov.io/gh/simpeg/simpeg/pull/1538?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=simpeg) |

<details><summary>Additional details and impacted files</summary>


```diff
@@            Coverage Diff             @@
##             main    #1538      +/-   ##
==========================================
+ Coverage   86.28%   86.30%   +0.01%     
==========================================
  Files         397      397              
  Lines       50890    50977      +87     
  Branches     5677     5691      +14     
==========================================
+ Hits        43909    43994      +85     
- Misses       5527     5529       +2     
  Partials     1454     1454              
```

| [Flag](https://app.codecov.io/gh/simpeg/simpeg/pull/1538/flags?src=pr&el=flags&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=simpeg) | Coverage Δ | |
|---|---|---|
| [](https://app.codecov.io/gh/simpeg/simpeg/pull/1538/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=simpeg) | `86.20% <98.40%> (+0.01%)` | :arrow_up: |

Flags with carried forward coverage won't be shown. [Click here](https://docs.codecov.io/docs/carryforward-flags?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=simpeg#carryforward-flags-in-the-pull-request-comment) to find out more.

</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/simpeg/simpeg/pull/1538?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=simpeg).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=simpeg).


Patch:
diff --git a/examples/05-fdem/plot_inv_fdem_loop_loop_2Dinversion.py b/examples/05-fdem/plot_inv_fdem_loop_loop_2Dinversion.py
index 43699d674..e346aa7ac 100644
--- a/examples/05-fdem/plot_inv_fdem_loop_loop_2Dinversion.py
+++ b/examples/05-fdem/plot_inv_fdem_loop_loop_2Dinversion.py
@@ -288,7 +288,7 @@ reg = regularization.WeightedLeastSquares(inversion_mesh)
 opt = optimization.InexactGaussNewton(maxIterCG=10, remember="xc")
 invProb = inverse_problem.BaseInvProblem(dmisfit, reg, opt)
 
-betaest = directives.BetaEstimate_ByEig(beta0_ratio=0.05, n_pw_iter=1, seed=1)
+betaest = directives.BetaEstimate_ByEig(beta0_ratio=0.05, n_pw_iter=1, random_seed=1)
 target = directives.TargetMisfit()
 
 directiveList = [betaest, target]
diff --git a/examples/20-published/plot_heagyetal2017_cyl_inversions.py b/examples/20-published/plot_heagyetal2017_cyl_inversions.py
index 0c72149b2..e41a05f52 100644
--- a/examples/20-published/plot_heagyetal2017_cyl_inversions.py
+++ b/examples/20-published/plot_heagyetal2017_cyl_inversions.py
@@ -155,7 +155,7 @@ def run(plotIt=True, saveFig=False):
 
     # directives
     beta = directives.BetaSchedule(coolingFactor=4, coolingRate=3)
-    betaest = directives.BetaEstimate_ByEig(beta0_ratio=1.0, seed=518936)
+    betaest = directives.BetaEstimate_ByEig(beta0_ratio=1.0, random_seed=518936)
     target = directives.TargetMisfit()
     directiveList = [beta, betaest, target]
 
diff --git a/examples/20-published/plot_laguna_del_maule_inversion.py b/examples/20-published/plot_laguna_del_maule_inversion.py
index a80d5be24..b7f212e1c 100644
--- a/examples/20-published/plot_laguna_del_maule_inversion.py
+++ b/examples/20-published/plot_laguna_del_maule_inversion.py
@@ -121,7 +121,7 @@ def run(plotIt=True, cleanAfterRun=True):
     invProb = inverse_problem.BaseInvProblem(dmis, reg, opt)
 
     # Specify how the initial beta is found
-    betaest = directives.BetaEstimate_ByEig(beta0_ratio=0.5, seed=518936)
+    betaest = directives.BetaEstimate_ByEig(beta0_ratio=0.5, random_seed=518936)
 
     # IRLS sets up the Lp inversion problem
     # Set the eps parameter parameter in Line 11 of the
diff --git a/simpeg/directives/directives.py b/simpeg/directives/directives.py
index 2932de7af..7075dcfd2 100644
--- a/simpeg/directives/directives.py
+++ b/simpeg/directives/directives.py
@@ -354,22 +354,45 @@ class BaseBetaEstimator(InversionDirective):
     ----------
     beta0_ratio : float
         Desired ratio between data misfit and model objective function at initial beta iteration.
-    seed : None or :class:`~simpeg.typing.RandomSeed`, optional
+    random_seed : None or :class:`~simpeg.typing.RandomSeed`, optional
         Random seed used for random sampling. It can either be an int,
         a predefined Numpy random number generator, or any valid input to
         ``numpy.random.default_rng``.
+    seed : None or :class:`~simpeg.typing.RandomSeed`, optional
+
+        .. deprecated:: 0.23.0
+
+           Argument ``seed`` is deprecated in favor of ``random_seed`` and will
+           be removed in SimPEG v0.24.0.
 
     """
 
     def __init__(
         self,
         beta0_ratio=1.0,
+        random_seed: RandomSeed | None = None,
         seed: RandomSeed | None = None,
         **kwargs,
     ):
         super().__init__(**kwargs)
         self.beta0_ratio = beta0_ratio
-        self.seed = seed
+
+        # Deprecate seed argument
+        if seed is not None:
+            if random_seed is not None:
+                raise TypeError(
+                    "Cannot pass both 'random_seed' and 'seed'."
+                    "'seed' has been deprecated and will be removed in "
+                    " SimPEG v0.24.0, please use 'random_seed' instead.",
+                )
+            warnings.warn(
+                "'seed' has been deprecated and will be removed in "
+                " SimPEG v0.24.0, please use 'random_seed' instead.",
+                FutureWarning,
+                stacklevel=2,
+            )
+            random_seed = seed
+        self.random_seed = random_seed
 
     @property
     def beta0_ratio(self):
@@ -388,17 +411,17 @@ class BaseBetaEstimator(InversionDirective):
         )
 
     @property
-    def seed(self):
+    def random_seed(self):
         """Random seed to initialize with.
 
         Returns
         -------
         int, numpy.random.Generator or None
         """
-        return self._seed
+        return self._random_seed
 
-    @seed.setter
-    def seed(self, value):
+    @random_seed.setter
+    def random_seed(self, value):
         try:
             np.random.default_rng(value)
         except TypeError as err:
@@ -407,7 +430,7 @@ class BaseBetaEstimator(InversionDirective):
                 f"a {type(value).__name__}"
             )
             raise TypeError(msg) from err
-        self._seed = value
+        self._random_seed = value
 
     def validate(self, directive_list):
         ind = [isinstance(d, BaseBetaEstimator) for d in directive_list.dList]
@@ -418,6 +441,15 @@ class BaseBetaEstimator(InversionDirective):
 
         return True
 
+    seed = deprecate_property(
+        random_seed,
+        "seed",
+        "random_seed",
+        removal_version="0.24.0",
+        future_warn=True,
+        error=False,
+    )
+
 
 class BetaEstimateMaxDerivative(BaseBetaEstimator):
     r"""Estimate initial trade-off parameter (beta) using largest derivatives.
@@ -433,10 +465,16 @@ class BetaEstimateMaxDerivative(BaseBetaEstimator):
     ----------
     beta0_ratio: float
         Desired ratio between data misfit and model objective function at initial beta iteration.
-    seed : None or :class:`~simpeg.typing.RandomSeed`, optional
+    random_seed : None or :class:`~simpeg.typing.RandomSeed`, optional
         Random seed used for random sampling. It can either be an int,
         a predefined Numpy random number generator, or any valid input to
         ``numpy.random.default_rng``.
+    seed : None or :class:`~simpeg.typing.RandomSeed`, optional
+
+        .. deprecated:: 0.23.0
+
+           Argument ``seed`` is deprecated in favor of ``random_seed`` and will
+           be removed in SimPEG v0.24.0.
 
     Notes
     -----
@@ -466,11 +504,13 @@ class BetaEstimateMaxDerivative(BaseBetaEstimator):
 
     """
 
-    def __init__(self, beta0_ratio=1.0, seed: RandomSeed | None = None, **kwargs):
-        super().__init__(beta0_ratio=beta0_ratio, seed=seed, **kwargs)
+    def __init__(
+        self, beta0_ratio=1.0, random_seed: RandomSeed | None = None, **kwargs
+    ):
+        super().__init__(beta0_ratio=beta0_ratio, random_seed=random_seed, **kwargs)
 
     def initialize(self):
-        rng = np.random.default_rng(seed=self.seed)
+        rng = np.random.default_rng(seed=self.random_seed)
 
         if self.verbose:
             print("Calculating the beta0 parameter.")
@@ -505,10 +545,16 @@ class BetaEstimate_ByEig(BaseBetaEstimator):
         Desired ratio between data misfit and model objective function at initial beta iteration.
     n_pw_iter : int
         Number of power iterations used to estimate largest eigenvalues.
-    seed : None or :class:`~simpeg.typing.RandomSeed`, optional
+    random_seed : None or :class:`~simpeg.typing.RandomSeed`, optional
         Random seed used for random sampling. It can either be an int,
         a predefined Numpy random number generator, or any valid input to
         ``numpy.random.default_rng``.
+    seed : None or :class:`~simpeg.typing.RandomSeed`, optional
+
+        .. deprecated:: 0.23.0
+
+           Argument ``seed`` is deprecated in favor of ``random_seed`` and will
+           be removed in SimPEG v0.24.0.
 
     Notes
     -----
@@ -541,10 +587,13 @@ class BetaEstimate_ByEig(BaseBetaEstimator):
         self,
         beta0_ratio=1.0,
         n_pw_iter=4,
+        random_seed: RandomSeed | None = None,
         seed: RandomSeed | None = None,
         **kwargs,
     ):
-        super().__init__(beta0_ratio=beta0_ratio, seed=seed, **kwargs)
+        super().__init__(
+            beta0_ratio=beta0_ratio, random_seed=random_seed, seed=seed, **kwargs
+        )
         self.n_pw_iter = n_pw_iter
 
     @property
@@ -563,7 +612,7 @@ class BetaEstimate_ByEig(BaseBetaEstimator):
         self._n_pw_iter = validate_integer("n_pw_iter", value, min_val=1)
 
     def initialize(self):
-        rng = np.random.default_rng(seed=self.seed)
+        rng = np.random.default_rng(seed=self.random_seed)
 
         if self.verbose:
             print("Calculating the beta0 parameter.")
@@ -574,13 +623,13 @@ class BetaEstimate_ByEig(BaseBetaEstimator):
             self.dmisfit,
             m,
             n_pw_iter=self.n_pw_iter,
-            seed=rng,
+            random_seed=rng,
         )
         reg_eigenvalue = eigenvalue_by_power_iteration(
             self.reg,
             m,
             n_pw_iter=self.n_pw_iter,
-            seed=rng,
+            random_seed=rng,
         )
 
         self.ratio = np.asarray(dm_eigenvalue / reg_eigenvalue)
@@ -668,13 +717,30 @@ class AlphasSmoothEstimate_ByEig(InversionDirective):
         self,
         alpha0_ratio=1.0,
         n_pw_iter=4,
+        random_seed: RandomSeed | None = None,
         seed: RandomSeed | None = None,
         **kwargs,
     ):
         super().__init__(**kwargs)
         self.alpha0_ratio = alpha0_ratio
         self.n_pw_iter = n_pw_iter
-        self.seed = seed
+
+        # Deprecate seed argument
+        if seed is not None:
+            if random_seed is not None:
+                raise TypeError(
+                    "Cannot pass both 'random_seed' and 'seed'."
+                    "'seed' has been deprecated and will be removed in "
+                    " SimPEG v0.24.0, please use 'random_seed' instead.",
+                )
+            warnings.warn(
+                "'seed' has been deprecated and will be removed in "
+                " SimPEG v0.24.0, please use 'random_seed' instead.",
+                FutureWarning,
+                stacklevel=2,
+            )
+            random_seed = seed
+        self.random_seed = random_seed
 
     @property
     def alpha0_ratio(self):
@@ -707,17 +773,17 @@ class AlphasSmoothEstimate_ByEig(InversionDirective):
         self._n_pw_iter = validate_integer("n_pw_iter", value, min_val=1)
 
     @property
-    def seed(self):
+    def random_seed(self):
         """Random seed to initialize with.
 
         Returns
         -------
         int, numpy.random.Generator or None
         """
-        return self._seed
+        return self._random_seed
 
-    @seed.setter
-    def seed(self, value):
+    @random_seed.setter
+    def random_seed(self, value):
         try:
             np.random.default_rng(value)
         except TypeError as err:
@@ -726,11 +792,20 @@ class AlphasSmoothEstimate_ByEig(InversionDirective):
                 f"a {type(value).__name__}"
             )
             raise TypeError(msg) from err
-        self._seed = value
+        self._random_seed = value
+
+    seed = deprecate_property(
+        random_seed,
+        "seed",
+        "random_seed",
+        removal_version="0.24.0",
+        future_warn=True,
+        error=False,
+    )
 
     def initialize(self):
         """"""
-        rng = np.random.default_rng(seed=self.seed)
+        rng = np.random.default_rng(seed=self.random_seed)
 
         smoothness = []
         smallness = []
@@ -765,7 +840,7 @@ class AlphasSmoothEstimate_ByEig(InversionDirective):
             smallness[0],
             self.invProb.model,
             n_pw_iter=self.n_pw_iter,
-            seed=rng,
+            random_seed=rng,
         )
 
         self.alpha0_ratio = self.alpha0_ratio * np.ones(len(smoothness))
@@ -781,7 +856,7 @@ class AlphasSmoothEstimate_ByEig(InversionDirective):
                 obj,
                 self.invProb.model,
                 n_pw_iter=self.n_pw_iter,
-                seed=rng,
+                random_seed=rng,
             )
             ratio = smallness_eigenvalue / smooth_i_eigenvalue
 
@@ -807,13 +882,30 @@ class ScalingMultipleDataMisfits_ByEig(InversionDirective):
         self,
         chi0_ratio=None,
         n_pw_iter=4,
+        random_seed: RandomSeed | None = None,
         seed: RandomSeed | None = None,
         **kwargs,
     ):
         super().__init__(**kwargs)
         self.chi0_ratio = chi0_ratio
         self.n_pw_iter = n_pw_iter
-        self.seed = seed
+
+        # Deprecate seed argument
+        if seed is not None:
+            if random_seed is not None:
+                raise TypeError(
+                    "Cannot pass both 'random_seed' and 'seed'."
+                    "'seed' has been deprecated and will be removed in "
+                    " SimPEG v0.24.0, please use 'random_seed' instead.",
+                )
+            warnings.warn(
+                "'seed' has been deprecated and will be removed in "
+                " SimPEG v0.24.0, please use 'random_seed' instead.",
+                FutureWarning,
+                stacklevel=2,
+            )
+            random_seed = seed
+        self.random_seed = random_seed
 
     @property
     def chi0_ratio(self):
@@ -846,17 +938,17 @@ class ScalingMultipleDataMisfits_ByEig(InversionDirective):
         self._n_pw_iter = validate_integer("n_pw_iter", value, min_val=1)
 
     @property
-    def seed(self):
+    def random_seed(self):
         """Random seed to initialize with
 
         Returns
         -------
         int, numpy.random.Generator or None
         """
-        return self._seed
+        return self._random_seed
 
-    @seed.setter
-    def seed(self, value):
+    @random_seed.setter
+    def random_seed(self, value):
         try:
             np.random.default_rng(value)
         except TypeError as err:
@@ -865,11 +957,20 @@ class ScalingMultipleDataMisfits_ByEig(InversionDirective):
                 f"a {type(value).__name__}"
             )
             raise TypeError(msg) from err
-        self._seed = value
+        self._random_seed = value
+
+    seed = deprecate_property(
+        random_seed,
+        "seed",
+        "random_seed",
+        removal_version="0.24.0",
+        future_warn=True,
+        error=False,
+    )
 
     def initialize(self):
         """"""
-        rng = np.random.default_rng(seed=self.seed)
+        rng = np.random.default_rng(seed=self.random_seed)
 
         if self.verbose:
             print("Calculating the scaling parameter.")
@@ -892,7 +993,9 @@ class ScalingMultipleDataMisfits_ByEig(InversionDirective):
 
         dm_eigenvalue_list = []
         for dm in self.dmisfit.objfcts:
-            dm_eigenvalue_list += [eigenvalue_by_power_iteration(dm, m, seed=rng)]
+            dm_eigenvalue_list += [
+                eigenvalue_by_power_iteration(dm, m, random_seed=rng)
+            ]
 
         self.chi0 = self.chi0_ratio / np.r_[dm_eigenvalue_list]
         self.chi0 = self.chi0 / np.sum(self.chi0)
diff --git a/simpeg/directives/sim_directives.py b/simpeg/directives/sim_directives.py
index 480cda76e..f40b828c7 100644
--- a/simpeg/directives/sim_directives.py
+++ b/simpeg/directives/sim_directives.py
@@ -270,7 +270,7 @@ class PairedBetaEstimate_ByEig(InversionDirective):
                     dmis,
                     m,
                     n_pw_iter=self.n_pw_iter,
-                    seed=rng,
+                    random_seed=rng,
                 )
             )
 
@@ -279,7 +279,7 @@ class PairedBetaEstimate_ByEig(InversionDirective):
                     reg,
                     m,
                     n_pw_iter=self.n_pw_iter,
-                    seed=rng,
+                    random_seed=rng,
                 )
             )
 
diff --git a/simpeg/utils/mat_utils.py b/simpeg/utils/mat_utils.py
index ee99c4c73..e4c662c05 100644
--- a/simpeg/utils/mat_utils.py
+++ b/simpeg/utils/mat_utils.py
@@ -1,3 +1,4 @@
+import warnings
 import numpy as np
 from .code_utils import deprecate_function
 from ..typing import RandomSeed
@@ -134,6 +135,7 @@ def eigenvalue_by_power_iteration(
     model,
     n_pw_iter=4,
     fields_list=None,
+    random_seed: RandomSeed | None = None,
     seed: RandomSeed | None = None,
 ):
     r"""Estimate largest eigenvalue in absolute value using power iteration.
@@ -155,10 +157,16 @@ def eigenvalue_by_power_iteration(
         they will be evaluated within the function. If combo_objfct mixs data misfit and regularization
         terms, the list should contains simpeg.fields for the data misfit terms and None for the
         regularization term.
-    seed : None or :class:`~simpeg.typing.RandomSeed`, optional
+    random_seed : None or :class:`~simpeg.typing.RandomSeed`, optional
         Random seed for the initial random guess of eigenvector. It can either
         be an int, a predefined Numpy random number generator, or any valid
         input to ``numpy.random.default_rng``.
+    seed : None or :class:`~simpeg.typing.RandomSeed`, optional
+
+        .. deprecated:: 0.23.0
+
+           Argument ``seed`` is deprecated in favor of ``random_seed`` and will
+           be removed in SimPEG v0.24.0.
 
     Returns
     -------
@@ -183,7 +191,22 @@ def eigenvalue_by_power_iteration(
     selected from a uniform distribution.
 
     """
-    rng = np.random.default_rng(seed=seed)
+    # Deprecate seed argument
+    if seed is not None:
+        if random_seed is not None:
+            raise TypeError(
+                "Cannot pass both 'random_seed' and 'seed'."
+                "'seed' has been deprecated and will be removed in "
+                " SimPEG v0.24.0, please use 'random_seed' instead.",
+            )
+        warnings.warn(
+            "'seed' has been deprecated and will be removed in "
+            " SimPEG v0.24.0, please use 'random_seed' instead.",
+            FutureWarning,
+            stacklevel=2,
+        )
+        random_seed = seed
+    rng = np.random.default_rng(seed=random_seed)
 
     # Initial guess for eigen-vector
     x0 = rng.random(size=model.shape)


Test patch:
diff --git a/tests/base/test_directives.py b/tests/base/test_directives.py
index 132cef2e5..65fbb0f7f 100644
--- a/tests/base/test_directives.py
+++ b/tests/base/test_directives.py
@@ -517,9 +517,9 @@ class TestUpdateSensitivityNormalization:
             d_temp.normalization_method = normalization_method
 
 
-class TestSeedProperty:
+class TestRandomSeedProperty:
     """
-    Test ``seed`` setter methods of directives.
+    Test ``random_seed`` setter methods of directives.
     """
 
     directive_classes = (
@@ -531,22 +531,22 @@ class TestSeedProperty:
 
     @pytest.mark.parametrize("directive_class", directive_classes)
     @pytest.mark.parametrize(
-        "seed",
+        "random_seed",
         (42, np.random.default_rng(seed=1), np.array([1, 2])),
         ids=("int", "rng", "array"),
     )
-    def test_valid_seed(self, directive_class, seed):
+    def test_valid_seed(self, directive_class, random_seed):
         "Test if seed setter works as expected on valid seed arguments."
-        directive = directive_class(seed=seed)
-        assert directive.seed is seed
+        directive = directive_class(random_seed=random_seed)
+        assert directive.random_seed is random_seed
 
     @pytest.mark.parametrize("directive_class", directive_classes)
-    @pytest.mark.parametrize("seed", (42.1, np.array([1.0, 2.0])))
-    def test_invalid_seed(self, directive_class, seed):
+    @pytest.mark.parametrize("random_seed", (42.1, np.array([1.0, 2.0])))
+    def test_invalid_seed(self, directive_class, random_seed):
         "Test if seed setter works as expected on valid seed arguments."
         msg = "Unable to initialize the random number generator with "
         with pytest.raises(TypeError, match=msg):
-            directive_class(seed=seed)
+            directive_class(random_seed=random_seed)
 
 
 class TestBetaEstimatorArguments:
@@ -559,23 +559,94 @@ class TestBetaEstimatorArguments:
         """Test on directives.BetaEstimate_ByEig."""
         beta0_ratio = 3.0
         n_pw_iter = 3
-        seed = 42
+        random_seed = 42
         directive = directives.BetaEstimate_ByEig(
-            beta0_ratio=beta0_ratio, n_pw_iter=n_pw_iter, seed=seed
+            beta0_ratio=beta0_ratio, n_pw_iter=n_pw_iter, random_seed=random_seed
         )
         assert directive.beta0_ratio == beta0_ratio
         assert directive.n_pw_iter == n_pw_iter
-        assert directive.seed == seed
+        assert directive.random_seed == random_seed
 
     def test_beta_estimate_max_derivative(self):
         """Test on directives.BetaEstimateMaxDerivative."""
         beta0_ratio = 3.0
-        seed = 42
+        random_seed = 42
         directive = directives.BetaEstimateMaxDerivative(
-            beta0_ratio=beta0_ratio, seed=seed
+            beta0_ratio=beta0_ratio, random_seed=random_seed
         )
         assert directive.beta0_ratio == beta0_ratio
-        assert directive.seed == seed
+        assert directive.random_seed == random_seed
+
+
+class TestDeprecateSeedProperty:
+    """
+    Test deprecation of seed property.
+    """
+
+    CLASSES = (
+        directives.AlphasSmoothEstimate_ByEig,
+        directives.BetaEstimate_ByEig,
+        directives.BetaEstimateMaxDerivative,
+        directives.ScalingMultipleDataMisfits_ByEig,
+    )
+
+    def get_message_duplicated_error(self, old_name, new_name, version="v0.24.0"):
+        msg = (
+            f"Cannot pass both '{new_name}' and '{old_name}'."
+            f"'{old_name}' has been deprecated and will be removed in "
+            f" SimPEG {version}, please use '{new_name}' instead."
+        )
+        return msg
+
+    def get_message_deprecated_warning(self, old_name, new_name, version="v0.24.0"):
+        msg = (
+            f"'{old_name}' has been deprecated and will be removed in "
+            f" SimPEG {version}, please use '{new_name}' instead."
+        )
+        return msg
+
+    @pytest.mark.parametrize("directive", CLASSES)
+    def test_warning_argument(self, directive):
+        """
+        Test if warning is raised after passing ``seed`` to the constructor.
+        """
+        msg = self.get_message_deprecated_warning("seed", "random_seed")
+        seed = 42135
+        with pytest.warns(FutureWarning, match=msg):
+            directive_instance = directive(seed=42135)
+        assert directive_instance.random_seed == seed
+
+    @pytest.mark.parametrize("directive", CLASSES)
+    def test_error_duplicated_argument(self, directive):
+        """
+        Test error after passing ``seed`` and ``random_seed`` to the constructor.
+        """
+        msg = self.get_message_duplicated_error("seed", "random_seed")
+        with pytest.raises(TypeError, match=msg):
+            directive(seed=42, random_seed=42)
+
+    @pytest.mark.parametrize("directive", CLASSES)
+    def test_warning_accessing_property(self, directive):
+        """
+        Test warning when trying to access the ``seed`` property.
+        """
+        directive_obj = directive(random_seed=42)
+        msg = "seed has been deprecated, please use random_seed"
+        with pytest.warns(FutureWarning, match=msg):
+            seed = directive_obj.seed
+        np.testing.assert_allclose(seed, directive_obj.random_seed)
+
+    @pytest.mark.parametrize("directive", CLASSES)
+    def test_warning_setter(self, directive):
+        """
+        Test warning when trying to set the ``seed`` property.
+        """
+        directive_obj = directive(random_seed=42)
+        msg = "seed has been deprecated, please use random_seed"
+        new_seed = 35
+        with pytest.warns(FutureWarning, match=msg):
+            directive_obj.seed = new_seed
+        np.testing.assert_allclose(directive_obj.random_seed, new_seed)
 
 
 class TestUpdateIRLS:
diff --git a/tests/utils/test_mat_utils.py b/tests/utils/test_mat_utils.py
index 9aecd7eee..c194cfc61 100644
--- a/tests/utils/test_mat_utils.py
+++ b/tests/utils/test_mat_utils.py
@@ -1,7 +1,9 @@
+import pytest
 import unittest
 import numpy as np
 from scipy.sparse.linalg import eigsh
 from discretize import TensorMesh
+from simpeg.objective_function import BaseObjectiveFunction
 from simpeg import simulation, data_misfit
 from simpeg.maps import IdentityMap
 from simpeg.regularization import WeightedLeastSquares
@@ -80,7 +82,7 @@ class TestEigenvalues(unittest.TestCase):
         field = self.dmis.simulation.fields(self.true_model)
         max_eigenvalue_numpy, _ = eigsh(dmis_matrix, k=1)
         max_eigenvalue_directive = eigenvalue_by_power_iteration(
-            self.dmis, self.true_model, fields_list=field, n_pw_iter=30, seed=42
+            self.dmis, self.true_model, fields_list=field, n_pw_iter=30, random_seed=42
         )
         passed = np.isclose(max_eigenvalue_numpy, max_eigenvalue_directive, rtol=1e-2)
         self.assertTrue(passed, True)
@@ -93,7 +95,7 @@ class TestEigenvalues(unittest.TestCase):
         dmiscombo_matrix = 2 * self.G.T.dot(WtW.dot(self.G))
         max_eigenvalue_numpy, _ = eigsh(dmiscombo_matrix, k=1)
         max_eigenvalue_directive = eigenvalue_by_power_iteration(
-            self.dmiscombo, self.true_model, n_pw_iter=30, seed=42
+            self.dmiscombo, self.true_model, n_pw_iter=30, random_seed=42
         )
         passed = np.isclose(max_eigenvalue_numpy, max_eigenvalue_directive, rtol=1e-2)
         self.assertTrue(passed, True)
@@ -103,7 +105,7 @@ class TestEigenvalues(unittest.TestCase):
         reg_maxtrix = self.reg.deriv2(self.true_model)
         max_eigenvalue_numpy, _ = eigsh(reg_maxtrix, k=1)
         max_eigenvalue_directive = eigenvalue_by_power_iteration(
-            self.reg, self.true_model, n_pw_iter=100, seed=42
+            self.reg, self.true_model, n_pw_iter=100, random_seed=42
         )
         passed = np.isclose(max_eigenvalue_numpy, max_eigenvalue_directive, rtol=1e-2)
         self.assertTrue(passed, True)
@@ -115,12 +117,72 @@ class TestEigenvalues(unittest.TestCase):
         combo_matrix = dmis_matrix + self.beta * reg_maxtrix
         max_eigenvalue_numpy, _ = eigsh(combo_matrix, k=1)
         max_eigenvalue_directive = eigenvalue_by_power_iteration(
-            self.mixcombo, self.true_model, n_pw_iter=100, seed=42
+            self.mixcombo, self.true_model, n_pw_iter=100, random_seed=42
         )
         passed = np.isclose(max_eigenvalue_numpy, max_eigenvalue_directive, rtol=1e-2)
         self.assertTrue(passed, True)
         print("Eigenvalue Utils for a mixed ComboObjectiveFunction is validated.")
 
 
+class TestDeprecatedSeed:
+    """Test deprecation of ``seed`` argument."""
+
+    @pytest.fixture
+    def mock_objfun(self):
+        """
+        Mock objective function class as child of ``BaseObjectiveFunction``
+        """
+
+        class MockObjectiveFunction(BaseObjectiveFunction):
+
+            def deriv2(self, m, v=None, **kwargs):
+                return np.ones(self.nP)
+
+        return MockObjectiveFunction
+
+    def get_message_duplicated_error(self, old_name, new_name, version="v0.24.0"):
+        msg = (
+            f"Cannot pass both '{new_name}' and '{old_name}'."
+            f"'{old_name}' has been deprecated and will be removed in "
+            f" SimPEG {version}, please use '{new_name}' instead."
+        )
+        return msg
+
+    def get_message_deprecated_warning(self, old_name, new_name, version="v0.24.0"):
+        msg = (
+            f"'{old_name}' has been deprecated and will be removed in "
+            f" SimPEG {version}, please use '{new_name}' instead."
+        )
+        return msg
+
+    def test_warning_argument(self, mock_objfun):
+        """
+        Test if warning is raised after passing ``seed``.
+        """
+        msg = self.get_message_deprecated_warning("seed", "random_seed")
+        n_params = 5
+        combo = mock_objfun(nP=n_params) + 3.0 * mock_objfun(nP=n_params)
+        model = np.ones(n_params)
+        with pytest.warns(FutureWarning, match=msg):
+            result_seed = eigenvalue_by_power_iteration(
+                combo_objfct=combo, model=model, seed=42
+            )
+        # Ensure that using `seed` and `random_seed` generate the same output
+        result_random_seed = eigenvalue_by_power_iteration(
+            combo_objfct=combo, model=model, random_seed=42
+        )
+        np.testing.assert_allclose(result_seed, result_random_seed)
+
+    def test_error_duplicated_argument(self):
+        """
+        Test error after passing ``seed`` and ``random_seed``.
+        """
+        msg = self.get_message_duplicated_error("seed", "random_seed")
+        with pytest.raises(TypeError, match=msg):
+            eigenvalue_by_power_iteration(
+                combo_objfct=None, model=None, random_seed=42, seed=42
+            )
+
+
 if __name__ == "__main__":
     unittest.main()