Skip to content

Add scattering after correcting the Rayleigh absorption sign - #35

Merged
scottprahl merged 3 commits into
scottprahl:mainfrom
antonsoo:fix/rayleigh-absorption-sign
Oct 28, 2026
Merged

scottprahl merged 3 commits into
scottprahl:mainfrom
antonsoo:fix/rayleigh-absorption-sign

Conversation

@antonsoo

Copy link
Copy Markdown
Contributor

For a weakly absorbing sphere, the negative-imaginary index convention can give qext < qsca, so the computed absorption is negative:

from miepython import rayleigh

for m in (1.5 - 1e-6j, 1.5 + 1e-6j):
    qext, qsca, _, _ = rayleigh.efficiencies_mx(m, 0.05)
    print(f"{m}: Qabs={qext - qsca:.9e}")

Before:

(1.5-1e-06j): Qabs=-9.979361445e-08
(1.5+1e-06j): Qabs=9.979361445e-08

After, both conventions give Qabs=9.979361445e-08.

Take the absolute value of the absorption contribution before adding scattering: abs(qext.imag) + qsca. The existing expression applies abs after adding scattering, which subtracts scattering when the imaginary part is negative. Add eight weak-absorption regressions for convention agreement, positive absorption and the leading Rayleigh polarizability limit.

Both backend suites pass all 553 tests on Python 3.12 and 3.14. Configured make lint and combined 100% coverage pass. A separate continuation uses the shipped Segelstein water-index table: all 54 absorption/physical-unit configurations pass after, versus none before; 50 previously had negative absorption. Corrected absorption agrees with independent native Scattnlay within 3.4 parts per million for these small particles. All 27 complete positive-index, lossless and full-Mie controls are exactly unchanged, and an installed wheel reproduces the fixed source results. This does not change the scope or accuracy guarantees of the Rayleigh approximation.

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 27, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ⚠️ Failed 2026-10-27T23:53:03.745593Z
We couldn’t complete this review. Comment @codex review to try again.
415f05c PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

scottprahl and others added 2 commits October 28, 2026 10:14
Follow-up to the Rayleigh absorption sign fix:

- conjugate m up front, as core.py does, so absorption is simply
  -Im(...) instead of abs() hiding the sign
- use Bohren & Huffman's Re(ratio**2) for the x**4 extinction term
  rather than |ratio|**2; at m = 1.5 - 1j, x = 0.1 the error against
  Mie falls from 6e-4 to 2e-5, and near resonance (m = 0.05 - 1.43j,
  x = 0.05) from 0.43% to 0.12%
- compare qext tightly against mie.efficiencies_mx for weak, moderate,
  strong and near-resonant absorption; the 1% tolerance of
  test_efficiencies hid both the sign bug and the |ratio|**2 error
- changelog entry crediting @antonsoo

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@scottprahl
scottprahl merged commit 24c3343 into scottprahl:main Oct 28, 2026
10 of 11 checks passed
@scottprahl

Copy link
Copy Markdown
Owner

thanks for your PR! I fixed the problem and used a better approximation from Bohren & Huffman

scottprahl added a commit that referenced this pull request Oct 28, 2026
Builds on the Rayleigh absorption-sign fix (PR #35):

- call core._check_m_x from rayleigh.efficiencies_mx and S1_S2, so the
  Rayleigh functions reject NaN/infinite m or x, negative x and negative
  m.real exactly as the Mie functions do
- add core._check_one_sphere so core and rayleigh S1_S2 (and everything
  built on them) say they take one sphere, instead of numpy's "truth
  value of an array is ambiguous"
- return g with the same shape and type as the other efficiencies
- treat m.real == 0 as a perfect conductor, as the rest of the package
  does: electric plus magnetic dipole (b1 = -a1/2), qext = qsca =
  10/3 x**4, qback = 9 x**4, g = -2/5. The dielectric formulas used
  before gave 3.2x the Mie qext for m = -1j
- rewrite the module docstring: the approximation, which expressions go
  beyond the leading Rayleigh term, accuracy against Mie, conventions,
  conductors, and doctested examples
- tests for all of the above, including the array branch of the
  conjugation that left PR #35's coverage at 99%

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants