Giter Club home page Giter Club logo

miepython's Introduction

miepython

by Scott Prahl

pypi github conda doi

License Testing Docs Downloads

miepython is a pure Python module to calculate light scattering for non-absorbing, partially-absorbing, or perfectly-conducting spheres. Mie theory is used, following the procedure described by Wiscombe. This code has been validated against his work.

scattering diagram

This code provides functions for calculating the extinction efficiency, scattering efficiency, backscattering, and scattering asymmetry. Moreover, a set of angles can be given to calculate the scattering at various angles for a sphere.

When comparing different Mie scattering codes, make sure that you're aware of the conventions used by each code. miepython makes the following assumptions

  • the imaginary part of the complex index of refraction for absorbing spheres is negative.
  • the scattering phase function is normalized so it equals the single scattering albedo when integrated over 4ฯ€ steradians by default. This normalization can be changed (see the normalization notebook for details).

This code provides functions for calculating the extinction efficiency, scattering efficiency, backscattering, and scattering asymmetry. Moreover, a set of angles can be given to calculate the scattering for a sphere at each of those angles.

Full documentation at <https://miepython.readthedocs.io>

Pay Attention!

When comparing different Mie scattering codes, make sure that you're aware of the conventions used by each code. miepython makes the following assumptions

  1. the imaginary part of the complex index of refraction for absorbing spheres is negative.
  2. the scattering phase function is normalized so it equals the single scattering albedo when integrated over 4ฯ€ steradians. As of version 2.3, this can be changed.

Installation

Use pip:

pip install miepython

or conda:

conda install -c conda-forge miepython

Or run this code in the cloud using Google Collaboratory by selecting the Jupyter notebook that interests you.

Usage for those that don't do Jupyter

Basic Mie Calculations

from miepython import mie

complex_refractive_index = 1.5-1j # convention is negative imaginary part size_parameter = 1 # 2๐œ‹(radius)/ฮป qext, qsca, qback, g = mie(complex_refractive_index, size_parameter)

print("The extinction efficiency is %.3f" % qext) print("The scattering efficiency is %.3f" % qsca) print("The backscatter efficiency is %.3f" % qback) print("The scattering anisotropy is %.3f" % g)

should produce:

The extinction efficiency  is 2.336
The scattering efficiency  is 0.663
The backscatter efficiency is 0.573
The scattering anisotropy  is 0.192

Simple Dielectric

The script 01_dielectric.py

Glass Spheres

The script 02_glass.py

Water Droplets

The script 03_droplets.py

Small Gold Spheres

The script 04_gold.py

Usage for those that use Jupyter

All the Jupyter notebooks are available in the docs directory and they are all viewable at <https://miepython.readthedocs.io>

Script Examples for those that don't do Jupyter

All the Jupyter notebooks are in the docs directory and shown at <https://miepython.readthedocs.io>

You can also use a Jupyter notebook immediately (well, you do have wait a bit for everything to get uploaded) by clicking the Google Colaboratory button below

Colab

License

miepython is licensed under the terms of the MIT license.

miepython's People

Contributors

actions-user avatar bcbnz avatar jbecca avatar nollety avatar r0oland avatar scottprahl avatar zmoon avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

miepython's Issues

Argument type error for function mie_S1_S2 and functions that calls it

Code

miepython.mie_S1_S2(1.507-0.002j , 0.7086 , -1)

Output

In [8]: miepython.mie_S1_S2(1.507-0.002j , 0.7086 , -1)

TypeError Traceback (most recent call last)
in
----> 1 miepython.mie_S1_S2(1.507-0.002j , 0.7086 , -1)

~/opt/anaconda3/envs/Bo_Chen_Research/lib/python3.8/site-packages/numba/core/dispatcher.py in _explain_matching_error(self, *args, **kws)
654 msg = ("No matching definition for argument type(s) %s"
655 % ', '.join(map(str, args)))
--> 656 raise TypeError(msg)
657
658 def _search_new_conversions(self, *args, **kws):

TypeError: No matching definition for argument type(s) complex128, float64, int64

Example 04_gold

Hello there,
In example 04_gold you name and use the variable radius=0.1. But for the plots, you use the title "Gold Spheres 100nm diameter".
I compared the results of your code to the one nanocomposix uses, and conclude that only the title should be renamed to 100nm radius.

How to get differential cross-sections that really scale with particle size (not normalized)?

I'd like to calculate physical differential cross-sections from the normalized parameters and not sure how. This would have units of area per unit solid angle. https://en.wikipedia.org/wiki/Cross_section_(physics)#Differential_cross_section

I can square the amplitudes Sโ‚ and Sโ‚‚ and see that they give iper and ipar, but I still don't see how to recover actual differential cross-sections; they always integrate to 1.0 for any size particle (any reasonable x and m).

It seems it all boils down to the following sentence in 03_angular_scattering.ipynb:

Now if Pโ‚€ of light is scattered by a sphere then the scattered power on the detector will be...

I can imagine that Pโ‚€ might be the incident power over the geometrical cross-section ฯ€rยฒ but I'm not sure if it's that, or it's related to one of the four values returned from mp.mie().


Example of what a differential cross-section plot with physical units would look like: See Figure 4. http://plaza.ufl.edu/dwhahn/Rayleigh%20and%20Mie%20Light%20Scattering.pdf

screen shot 2019-02-11 at 6 55 08 pm

Difference between your implementation and that of Maetzler

When I use your online calculator or this python module with following settings:

wavelength = 1500e-9
r = 4.710E-07
k = 2*3.14/wavelength
x = k * r             # dimensionless Mie size parameter = 1.9719
m = 1.4100 - 0.0080j  # index of refraction of sphere

qext, qsca, qback, g = miepython.mie(m,x)

print("The qext efficiency  is %.3f" % qext)
print("The scattering efficiency  is %.3f" % qsca)
print("The backscatter efficiency is %.3f" % qback)
print("The scattering anisotropy  is %.3f" % g)

then I get the following results:

The qext efficiency  is 1.155
The scattering efficiency  is 1.090
The backscatter efficiency is 0.097
The scattering anisotropy  is 0.658

With the script of Maetzler (bottom of page https://omlc.org/software/mie/), if I do:

mie(complex(1.410E+00, -8.000E-03), 2*pi/1500e-9*4.710E-01*1e-6).'

I get:

ans =

    1.4100
   -0.0080
    1.9729
    1.0879
    1.1556
   -0.0677
    0.1161
    0.6533
    0.1005

where ans(4) = qext = 1.0879 and ans(5) = qsca = 1.1556.

So it seems that the values of the extinction coefficient and of the scattering coefficent are interchanged.

I digged deeper in your code and found that the Python Mie coefficients an and bn are different to that of Maetzler:

Maezler (an):

  0.310171419307873 - 0.473671739481655i
  0.037432108684527 - 0.200893621373526i
  0.000067151985416 - 0.021297737932288i
 -0.000019924584511 - 0.001285929209167i
 -0.000000825241069 - 0.000050906381267i
 -0.000000022452476 - 0.000001402834546i
 -0.000000000449367 - 0.000000028342714i
 -0.000000000006890 - 0.000000000437321i
 -0.000000000000083 - 0.000000000005320i

Python (an):

  0.317746891588117 + 0.454752059193760i
  0.045298858385873 + 0.197467459081684i
  0.000838661081755 + 0.021263464324966i
  0.000023228420817 + 0.001285707362372i
  0.000000830332704 + 0.000050900760559i
  0.000000022453522 + 0.000001402654704i
  0.000000000449301 + 0.000000028338490i
  0.000000000006889 + 0.000000000437247i
  0.000000000000083 + 0.000000000005319i

Most numbers are equal but the signs are different. Same is true for bn values.

I also tried this Java Applet (http://www.lightscattering.de/MieCalc/eindex.html), which is really hard to get it running and it provides confusing results. Sometimes it provides the same results as the Python script, sometimes it there are clearly wrong values. Therefore I also tried "bhmie Matlab" from this site: http://scatterlib.wikidot.com/mie

With this script, I get the same results as with the script of Maetzler.

This is very confusing. Do you know more about this issue?

Thanks
Apollo3zehn

coefficents calculation at large size parameter gives unexpected results

The following code gives results which I didn't expect:

import numpy as np
import matplotlib.pyplot as plt

# if miepython is missing, do `pip install miepython`
import miepython as mp

m = 1.5 - 0.01j
x = np.logspace(-1, 5, 20)  # also in microns

qext, qsca, qback, g = mp.mie(m,x)
plt.plot(x, qext, 'b+-', label="Q_ext")
plt.plot(x, qsca, 'r+:', label="Q_sca")
plt.plot(x, qback, 'g+:', label="Q_back")
plt.plot(x, g, 'r+-', label="<cos>")
plt.plot(x, qext - g * qsca, 'kx-', label="Q_pr")
plt.xscale('log')
plt.yscale('log')
plt.xlabel("size parameter")
plt.legend()
plt.grid()

The resulting figure:
image

At size parameter larger than ~ 5000, all coefficients except for qext (expected to be ~ 2) deviate largely, and qpr becomes negative.

As I am not so familiar with scattering theory, I couldn't understand/interpret this result. Is this an expected behavior?

getting different results from bhmie implementations

Thanks for your work on miepython. I am seeing different results in this program based off of the bhmie.f program from what I see in miepython.
https://github.com/cfinch/Mie_scattering/blob/master/Mie_scattering_results.txt

For instance,

Case 14
Refractive index = 1.5000-1.0000j
Size parameter = 1.0000

bhmie, Python implementation:
Angle  Cosine              S1                        S2             Intensity         Polzn
0.00   1.0000  -8.38663e-01 -8.64763e-01  -8.38663e-01 -8.64763e-01     TBD             TBD
                (-1.43587)   (-4.53907)    (-1.43587)   (-4.53907)
0.52   0.8660  -8.19225e-01 -8.61719e-01  -7.21779e-01 -7.27856e-01     TBD             TBD
                (-1.44816)   (-4.60321)    (-1.44309)   (-4.99863)
1.05   0.5000  -7.68157e-01 -8.53697e-01  -4.19454e-01 -3.72965e-01     TBD             TBD
                (-1.48429)   (-4.78415)    (-1.45662)   (-9.08475)
1.57   0.0000  -7.03034e-01 -8.43425e-01  -4.44461e-02  6.94424e-02     TBD             TBD
                (-1.54059)   (-5.04542)    (-1.22683)   (-1.12318)
2.09  -0.5000  -6.42983e-01 -8.33904e-01   2.90109e-01  4.67297e-01     TBD             TBD
                (-1.60661)   (-5.32360)    (-1.65895)   (-3.80045)
2.62  -0.8660  -6.02066e-01 -8.27386e-01   5.11402e-01  7.32909e-01     TBD             TBD
                (-1.66244)   (-5.53839)    (-1.67298)   (-5.09510)
3.14  -1.0000  -5.87707e-01 -8.25093e-01   5.87707e-01  8.25093e-01     TBD             TBD
                (-1.68473)   (-5.61943)    (-1.68473)   (-5.61943)

The same angles, refractive index, and size parameter in miepython

import numpy as np
import miepython as mp
import pandas as pd

x=1.0
m=1.5-1.0j
theta=np.array([0.0,0.52,1.05,1.57])
#these are already in radians, just take the cosine
mu = np.cos(theta)
S1, S2 = mp.mie_S1_S2(m,x,mu)
d = {'Radians':theta,'mu':mu,'S1': S1, 'S2': S2}
pd.DataFrame(d)
	Radians	mu			S1											S2
0	0.00	1.000000	(0.21559134761827634+0.07032158696589161j)	(0.21559134761827634+0.07032158696589161j)
1	0.52	0.867819	(0.2088975313282614+0.06911399542780117j)	(0.1850220959903823+0.053959935270422095j)
2	1.05	0.497571	(0.19091059968083227+0.06584447573080125j)	(0.10580127368584931+0.014929002269445686j)
3	1.57	0.000796	(0.1684751305292149+0.06170965784286728j)	(0.013508092940547764-0.02277315059600813j)

I'm probably doing something wrong but if you have any ideas please let me know.

How to obtain a_n and b_n coefficients for whole blood

I am working on a theoretical approach for modelling reflectance spectra in blood.

Using the following parameters:

x(size parameter) = 2pir/lambda

For erythrocytes, r = 2.8 um and lambda = 0.450 um, I obtained x as 39, which was used to compute the a_n and b_n coefficients.

To be exact, I am passing refractive index and x (size parameter) to the "mie_An_Bn" function to obtain a_n and b_n values

I have two questions:

  1. I see that the number of a_n, b_n coefficients varies as a function of size parameter(x). Since I am modelling a spectra(array of wavelengths in the range(450nm - 850nm)), do I need to compute the size parameter and subsequently a_n, and b_n for each of the wavelengths individually. Or Can I use a fixed wavelength (say 450nm).

  2. Is there a way or set of standard values using which I can verify that the computed a_n, b_n coefficients are valid and can be used to model whole blood?

Unit of cross section

Hello, thank you for an excellent Python library!

I noticed that in 02_efficiencies.ipynb, the plot of the absorption, scattering, and extinction cross sections shows a unit of 1/microns^2. However, if I am not mistaken, it should instead be microns^2.

One then gets the absorption coefficient as number_density * cross_section, which is microns^-3 * microns^2 = 1/micron, as it should be.

display of documentation in browser

Hi Scott, thanks for this very helpful tool!

When looking at the introductory documentation page in a browser (Chrome, Internet Explorer), the formulas are displayed in a strange way (see the following snippet).

image

I think this is a bit confusing, as one could read the second line as x = 2 pi r / lambda / n, while it is actually x = 2 pi r / (lambda / n), right?

Scattering phase matrix

Hi @scottprahl and thank you for a very useful Python package!

I noticed a method, mie_S1_S2, to compute the scattering amplitude functions, but no method to compute the scattering phase matrix (perhaps I miss it?) and I was wondering if this would be a feature that you'd be willing to have included in miepython?

In my application (radiative transfer for Earth observation), the knowledge of the scattering phase matrix lets one take polarisation into account, which is a significant improvement compared to unpolarised computations. But I don't know if this is something relevant for your application? From my understanding, deriving the scattering phase matrix from the scattering amplitude funtions is straightforward (e.g. with eqs. 5.2.105-6 in K. N. Liou (2002) - An Introduction to Atmospheric Radiation, Second Edition). If you are interested, I could prepare a pull request. ๐Ÿ˜ƒ

Paper to reference?

Is there a good paper to cite if using miepython in a publication? If so, it might be helpful to include in the README or read-the-docs.

understanding the units of scattering amplitudes from mie_S1_S2()

This seems very easy to use and I can plot stuff, but I'm not sure how to understand and use the Scattering Amplitude outputs. With a plane wave intensity (W/m^2) on a single plarticle I'd like to know for example the scattered intensity at a given angle in W/sr).

help(miepython.mie_S1_S2) returns

...The amplitude functions have been normalized so that when integrated over all 4pi solid angles, the integral will equal the single scattering albedo. The units are weird, sr**(-0.5)

What exactly is the "single scattering albedo" is that the geometrical cross-section? I think I can understand the units (inverse radians) if this is assumed to be integrated over d phi (the azimuthal angle).

Is there a paper or source where I can read further?

Thanks!

update: I've just seen https://github.com/scottprahl/miepython/blob/master/doc/03_angular_scattering.ipynb and will have a look now, and update further, but a published reference would be handy as well.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.