Repository: simpeg/simpeg
Pull request #1679 (2025-06-06 20:49:26)

Fix bug in phase for recursive 1d NSEM simulation
The recursive solution exclusively computes the impedance, apparent resistivity and/or phase of the Zxy impedance at all frequencies. In the convention adopted by SimPEG, Zxy is in the lower-left quadrant of the complex plane. Using np.atan(imag/real) results in phase values between -90 and +90 which is wrong.

Suggest we use ``np.angle`` instead.

![image](https://github.com/user-attachments/assets/d751640b-1d23-419e-abe9-2e29fbb0f1af)

#### PR Checklist
* [ ] If this is a work in progress PR, set as a Draft PR
* [x] Linted my code according to the [style guides](https://docs.simpeg.xyz/latest/content/getting_started/contributing/code-style.html).
* [x] Added [tests](https://docs.simpeg.xyz/latest/content/getting_started/contributing/testing.html) to verify changes to the code.
* [x] Added necessary documentation to any new functions/classes following the
      expect [style](https://docs.simpeg.xyz/latest/content/getting_started/contributing/documentation.html).
* [x] Marked as ready for review (if this is was a draft PR), and converted 
      to a Pull Request
* [x] Tagged ``@simpeg/simpeg-developers`` when ready for review.

codecov[bot]: ## [Codecov](https://app.codecov.io/gh/simpeg/simpeg/pull/1679?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=simpeg) Report
All modified and coverable lines are covered by tests :white_check_mark:
> Project coverage is 85.78%. Comparing base [(`64f7e56`)](https://app.codecov.io/gh/simpeg/simpeg/commit/64f7e569276359ab8e048dbbce49ab74f7e553bb?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=simpeg) to head [(`ca62e8d`)](https://app.codecov.io/gh/simpeg/simpeg/commit/ca62e8db538956699246a69c952e91d5c635d578?dropdown=coverage&el=desc&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    #1679   +/-   ##
=======================================
  Coverage   85.78%   85.78%           
=======================================
  Files         425      425           
  Lines       55480    55480           
  Branches     5187     5187           
=======================================
  Hits        47596    47596           
  Misses       6467     6467           
  Partials     1417     1417           
```

</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/simpeg/simpeg/pull/1679?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).

<details><summary> :rocket: New features to boost your workflow: </summary>

- :snowflake: [Test Analytics](https://docs.codecov.com/docs/test-analytics): Detect flaky tests, report on failures, and find test suite problems.
</details>

Patch:
diff --git a/simpeg/electromagnetics/natural_source/simulation_1d.py b/simpeg/electromagnetics/natural_source/simulation_1d.py
index 424c39c9d..ef0357718 100644
--- a/simpeg/electromagnetics/natural_source/simulation_1d.py
+++ b/simpeg/electromagnetics/natural_source/simulation_1d.py
@@ -248,8 +248,7 @@ class Simulation1DRecursive(BaseSimulation):
                     )
                 elif rx.component == "phase":
                     d.append(
-                        (180.0 / np.pi)
-                        * np.arctan(np.imag(Z[i_freq]) / np.real(Z[i_freq]))
+                        (180.0 / np.pi) * np.arctan2(Z[i_freq].imag, Z[i_freq].real)
                     )
 
         return np.array(d)


Test patch:
diff --git a/tests/em/nsem/forward/test_Recursive1D_VsAnalyticHalfspace.py b/tests/em/nsem/forward/test_Recursive1D_VsAnalyticHalfspace.py
index 3242e6f5a..5d185bc28 100644
--- a/tests/em/nsem/forward/test_Recursive1D_VsAnalyticHalfspace.py
+++ b/tests/em/nsem/forward/test_Recursive1D_VsAnalyticHalfspace.py
@@ -30,7 +30,7 @@ def true_solution(freq, sigma_half):
         -np.sqrt(np.pi * freq * mu_0 / sigma_half),
         -np.sqrt(np.pi * freq * mu_0 / sigma_half),
         1 / sigma_half,
-        45.0,
+        -135.0,
     ]
 
     return soln