|
31 | 31 |
|
32 | 32 | Key reference for multilayer algorithm is [3]_ |
33 | 33 |
|
| 34 | +Some notes on array dimensions and broadcasting: |
| 35 | +
|
| 36 | +- Nearly all calculations are vectorized. Let "..." denote the dimensions |
| 37 | + corresponding to parameters of the calculations. For example, we might be |
| 38 | + interested in calculating scattering quantities as a function of wavelength |
| 39 | + and volume fraction (volume fraction can enter into a calculation |
| 40 | + indirectly through an effective refractive index). Then "..." might |
| 41 | + represent the volume fraction and wavelength dimensions. |
| 42 | +
|
| 43 | +- m and x must be specified as at least 2D arrays. The shapes are |
| 44 | + m: (..., num_layers) |
| 45 | + x: (..., num_layers) |
| 46 | + where num_layers is the number of layers of a multilayer particle, and |
| 47 | + "..." means at least one other dimension (wavelength). If specified with |
| 48 | + shape (1, 1), the calculation will be done at a single, scalar value of m |
| 49 | + and of x. This situation would correspond to a single wavelength and a |
| 50 | + single, non-layered sphere. |
| 51 | +
|
| 52 | +- Angles (thetas and phis) must be specified with shape |
| 53 | + thetas: ([angle_leading_dims], num_thetas) |
| 54 | + phis: ([angle_leading_dims], num_phis) |
| 55 | + where [angle_leading_dims] is a subset of the leading dimensions of m/x. |
| 56 | +
|
| 57 | +- For example, if m has shape |
| 58 | + m: (num_volume_fractions, num_wavelengths, num_layers), |
| 59 | + then thetas can have shape |
| 60 | + thetas: (num_thetas) or |
| 61 | + thetas: (num_wavelengths, num_thetas) or |
| 62 | + thetas: (num_volume_fractions, num_wavelengths, num_thetas). |
| 63 | + The same is true of phi, but with num_phis instead of num_thetas. |
| 64 | + Therefore, the angles can be a function of wavelength, for example. As |
| 65 | + long as angle_leading_dims are specified in the same order as in "...", |
| 66 | + thetas and phis will broadcast correctly, once the dimensions of other |
| 67 | + quantities have been expanded (see below) |
| 68 | +
|
| 69 | +- Intermediate calculations: quantities to be used in calculations with |
| 70 | + angles have their dimensions expanded to include theta (and phis). For |
| 71 | + example, we might expand x to the following: |
| 72 | + x: (..., 1) |
| 73 | + to broadcast with the thetas array. If phis is specified, we expand x to |
| 74 | + x: (..., 1, 1) |
| 75 | + Other intermediate arrays are expanded to the same dimensions for |
| 76 | + broadcasting -- but not necessarily the same shapes, because we want to |
| 77 | + conserve memory. |
| 78 | +
|
| 79 | +- Intermediate calculations: calculations that involve summing over a series |
| 80 | + will have an "order" dimensions, corresponding to the order of the |
| 81 | + coefficients used in the series. We add this order dimension to the end of |
| 82 | + the array, since we want to remove it after we sum over it. In this case, |
| 83 | + we might expand x as follows: |
| 84 | + x: (..., n_max) |
| 85 | + where n_max is the maximum order. If the calculation also involves the |
| 86 | + angle theta, x would be expanded as |
| 87 | + x: (..., 1, n_max) |
| 88 | + and if phis are involved as well, |
| 89 | + x: (..., 1, 1, n_max) |
| 90 | +
|
| 91 | +- Broadcasting: All functions broadcast over the leading dimensions of m and |
| 92 | + x (the "..." above). Thus, outputs will contain the same dimensions as in |
| 93 | + "..." and possibly others that have been added (like polarization). A |
| 94 | + calculation done for a single value of m and of x -- shape (1, 1) for both |
| 95 | + -- will retain the singlet dimension corresponding to the first 1. This |
| 96 | + dimension can later be removed by ".squeeze()" but we do not squeeze by |
| 97 | + default because doing so would lead to inconsistent numbers of dimensions |
| 98 | + between, for example, single-wavelength and multi-wavelength calculations. |
| 99 | +
|
| 100 | +- Output shapes are as follows. [] indicates optional |
| 101 | + scat. coefficients: (2, ..., n_max) |
| 102 | + diff. cross-secs: (num_polarizations, ..., num_thetas, [num_phis]) |
| 103 | + integrated cross-secs: (...,) |
| 104 | + scat. matrix elements: (..., num_thetas) |
| 105 | +
|
| 106 | +- Outputs generally do not contain a layers dimension because most |
| 107 | + calculations report scattering quantities for the entire sphere, not |
| 108 | + individual layers within it. |
| 109 | +
|
| 110 | +- The broadcasting approach has its limitations, primarily because we choose |
| 111 | + the maximum order (nstop) to calculate the Mie coefficients based on the |
| 112 | + largest value of x in the array of size parameters. Therefore, in |
| 113 | + calculations over a wide range of size parameters, the coefficients |
| 114 | + corresponding to every size parameter are expanded to the same (large) |
| 115 | + order -- which is not only inefficient, but can also lead to numerical |
| 116 | + instabilities for small x's in the size parameter array. One way around |
| 117 | + this limitation would be to use ragged arrays when expanding x to (..., |
| 118 | + n_max), but doing this efficiently would require installing an extension to |
| 119 | + numpy like Awkward Array. |
| 120 | +
|
34 | 121 | References |
35 | 122 | ---------- |
36 | 123 | [1] Bohren, C. F. and Huffman, D. R. "Absorption and Scattering of Light by |
|
0 commit comments