PythonicDISORT 1.2__tar.gz → 1.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: PythonicDISORT
3
- Version: 1.2
3
+ Version: 1.3
4
4
  Summary: Discrete Ordinates Solver for the (1D) Radiative Transfer Equation in a single or multi-layer atmosphere.
5
5
  Author-email: Dion HO Jia Xu <dh3065@columbia.edu>
6
6
  Project-URL: Homepage, https://github.com/LDEO-CREW/Pythonic-DISORT
@@ -8,7 +8,7 @@ dependencies = [
8
8
  "scipy>=1.8.0",
9
9
  ]
10
10
  name = "PythonicDISORT"
11
- version = "1.2"
11
+ version = "1.3"
12
12
  authors = [
13
13
  { name="Dion HO Jia Xu", email="dh3065@columbia.edu" },
14
14
  ]
@@ -9,14 +9,15 @@ def _assemble_intensity_and_fluxes(
9
9
  scaled_omega_arr, # Delta-scaled single-scattering albedos
10
10
  tau_arr, # Lower boundary of layers
11
11
  scaled_tau_arr_with_0, # Delta-scaled lower boundary of layers with 0 inserted in front
12
- mu_arr_pos, mu_arr, # Quadrature nodes for 1) upper 2) both hemispheres
13
- M_inv, W, # 1) 1 / mu; 2) quadrature weights for each hemisphere
12
+ mu_arr_pos, # Upper hemisphere quadrature nodes (cosine polar angles)
13
+ M_inv, W, # 1) 1 / `mu_arr_pos`; 2) quadrature weights for each hemisphere
14
14
  N, NQuad, NLeg, # Number of 1) upper 2) both hemispheres quadrature nodes; 3) phase function Legendre coefficients
15
15
  NFourier, NLayers, NBDRF, # Number of 1) intensity Fourier modes; 2) layers; 3) BDRF Fourier modes
16
16
  is_atmos_multilayered, # Is the atmosphere multilayered?
17
17
  weighted_scaled_Leg_coeffs, # Weighted and delta-scaled Legendre coefficients
18
18
  BDRF_Fourier_modes, # BDRF Fourier modes
19
- mu0, I0, rescale_factor, phi0, # Properties of the direct beam
19
+ mu0, I0, I0_div_4pi, # Primary direct beam parameters
20
+ rescale_factor, phi0, # Secondary direct beam parameters
20
21
  there_is_beam_source, # Is there a beam source?
21
22
  b_pos, b_neg, # Dirichlet BCs
22
23
  b_pos_is_scalar, b_neg_is_scalar, # Is each Dirichlet BCs scalar and so isotropic?
@@ -47,7 +48,6 @@ def _assemble_intensity_and_fluxes(
47
48
  | `tau_arr` | `NLayers` |
48
49
  | `scaled_tau_arr_with_0` | `NLayers + 1` |
49
50
  | `mu_arr_pos` | `NQuad/2` |
50
- | `mu_arr` | `NQuad` |
51
51
  | `M_inv` | `NQuad/2` |
52
52
  | `W` | `NQuad/2` |
53
53
  | `N` | scalar |
@@ -61,6 +61,7 @@ def _assemble_intensity_and_fluxes(
61
61
  | `BDRF_Fourier_modes` | `NBDRF` |
62
62
  | `mu0` | scalar |
63
63
  | `I0` | scalar |
64
+ | `I0_div_4pi` | scalar |
64
65
  | `rescale_factor` | scalar |
65
66
  | `phi0` | scalar |
66
67
  | `there_is_beam_source` | scalar |
@@ -83,7 +84,7 @@ def _assemble_intensity_and_fluxes(
83
84
  | ----------------- | -------------------------------------- |
84
85
  | `G_collect` | `NFourier x NLayers x NQuad x NQuad` |
85
86
  | `G_collect_0` | `NLayers x NQuad x NQuad` |
86
- | `G_inv_collect_0` | `NLayers x NQuad x NQuad` or `None` |
87
+ | `G_inv_mu_inv` | `NLayers x NQuad x NQuad` or `None` |
87
88
  | `K_collect` | `NFourier x NLayers x NQuad` |
88
89
  | `K_collect_0` | `NLayers x NQuad` |
89
90
  | `B_collect` | `NFourier x NLayers x NQuad` or `None` |
@@ -108,45 +109,45 @@ def _assemble_intensity_and_fluxes(
108
109
  outputs = _solve_for_gen_and_part_sols(
109
110
  NFourier,
110
111
  scaled_omega_arr,
111
- mu_arr_pos, mu_arr,
112
+ mu_arr_pos,
112
113
  M_inv, W,
113
114
  N, NQuad, NLeg,
114
115
  NLayers,
115
116
  weighted_scaled_Leg_coeffs,
116
- mu0, I0,
117
+ mu0, I0_div_4pi,
117
118
  there_is_beam_source,
118
- Nscoeffs,
119
119
  there_is_iso_source,
120
120
  )
121
121
  if there_is_beam_source and there_is_iso_source:
122
122
  G_collect, K_collect, B_collect, G_inv_collect_0 = outputs
123
123
  B_collect_0 = B_collect[0, :, :]
124
+ G_inv_mu_inv = G_inv_collect_0 @ np.concatenate([M_inv, -M_inv])
124
125
  elif there_is_beam_source and not there_is_iso_source:
125
126
  G_collect, K_collect, B_collect = outputs
126
127
  B_collect_0 = B_collect[0, :, :]
127
- G_inv_collect_0 = None
128
+ G_inv_mu_inv = None
128
129
  elif not there_is_beam_source and there_is_iso_source:
129
130
  G_collect, K_collect, G_inv_collect_0 = outputs
130
131
  B_collect = None
132
+ G_inv_mu_inv = G_inv_collect_0 @ np.concatenate([M_inv, -M_inv])
131
133
  else:
132
134
  G_collect, K_collect = outputs
133
135
  B_collect = None
134
- G_inv_collect_0 = None
135
-
136
+ G_inv_mu_inv = None
136
137
 
137
138
  GC_collect = _solve_for_coeffs(
138
139
  NFourier,
139
140
  G_collect,
140
141
  K_collect,
141
142
  B_collect,
142
- G_inv_collect_0,
143
+ G_inv_mu_inv,
143
144
  scaled_tau_arr_with_0,
144
- mu_arr, mu_arr_pos, mu_arr_pos * W,
145
+ mu_arr_pos, mu_arr_pos * W,
145
146
  N, NQuad,
146
147
  NLayers, NBDRF,
147
148
  is_atmos_multilayered,
148
149
  BDRF_Fourier_modes,
149
- mu0, I0,
150
+ mu0, I0_div_4pi,
150
151
  there_is_beam_source,
151
152
  b_pos, b_neg,
152
153
  b_pos_is_scalar, b_neg_is_scalar,
@@ -166,7 +167,7 @@ def _assemble_intensity_and_fluxes(
166
167
 
167
168
  # Construct the intensity function (refer to section 3.7 of the Comprehensive Documentation)
168
169
  # --------------------------------------------------------------------------------------------------------------------------
169
- def u(tau, phi, is_antiderivative_wrt_tau=False, return_Fourier_error=False, return_tau_arr=False):
170
+ def u(tau, phi, is_antiderivative_wrt_tau=False, return_Fourier_error=False, return_tau_arr=False, *, _return_l=False):
170
171
  """
171
172
  Intensity function with arguments `(tau, phi)` of types `(array or float, array or float)`.
172
173
  Returns an ndarray with axes corresponding to variation with `mu, tau, phi` respectively.
@@ -182,7 +183,7 @@ def _assemble_intensity_and_fluxes(
182
183
 
183
184
  # Atmospheric layer indices
184
185
  l = np.argmax(tau[:, None] <= tau_arr[None, :], axis=1)
185
- scaled_tau_arr_l = scaled_tau_arr_with_0[l + 1]
186
+ scaled_tau_arr_l = scaled_tau_arr_with_0[1:][l]
186
187
  scaled_tau_arr_lm1 = scaled_tau_arr_with_0[l]
187
188
 
188
189
  # Delta-M scaling
@@ -204,13 +205,13 @@ def _assemble_intensity_and_fluxes(
204
205
  direct_beam_contribution = 0
205
206
  if is_antiderivative_wrt_tau:
206
207
  if there_is_beam_source:
207
- direct_beam_contribution = (B_collect / (-scale_tau / mu0)[None, :, None])[
208
- :, l, :
209
- ] * np.exp(-scaled_tau / mu0)[None, :, None]
208
+ direct_beam_contribution = (
209
+ B_collect.transpose(0, 2, 1) / (-scale_tau / mu0)[None, None, :]
210
+ )[:, :, l] * np.exp(-scaled_tau / mu0)[None, None, :]
210
211
 
211
212
  um = (
212
213
  np.einsum(
213
- "mtij, mtj -> mti",
214
+ "mtij, mtj -> mit",
214
215
  GC_collect[:, l, :, :],
215
216
  np.exp(exponent) / (scale_tau[None, :, None] * K_collect)[:, l, :],
216
217
  optimize=True,
@@ -220,12 +221,13 @@ def _assemble_intensity_and_fluxes(
220
221
  else:
221
222
  if there_is_beam_source:
222
223
  direct_beam_contribution = (
223
- B_collect[:, l, :] * np.exp(-scaled_tau / mu0)[None, :, None]
224
+ B_collect.transpose(0, 2, 1)[:, :, l]
225
+ * np.exp(-scaled_tau / mu0)[None, None, :]
224
226
  )
225
227
 
226
228
  um = (
227
229
  np.einsum(
228
- "mtij, mtj -> mti", GC_collect[:, l, :, :], np.exp(exponent), optimize=True
230
+ "mtij, mtj -> mit", GC_collect[:, l, :, :], np.exp(exponent), optimize=True
229
231
  )
230
232
  + direct_beam_contribution
231
233
  )
@@ -234,32 +236,31 @@ def _assemble_intensity_and_fluxes(
234
236
  if there_is_iso_source:
235
237
  l_uniq, l_inv = np.unique(l, return_inverse=True)
236
238
  _mathscr_v_contribution = _mathscr_v(
237
- scaled_tau, l_inv, Nscoeffs,
239
+ scaled_tau, l_inv,
240
+ Nscoeffs,
238
241
  scaled_s_poly_coeffs[l_uniq],
239
242
  G_collect_0[l_uniq],
240
243
  K_collect_0[l_uniq],
241
- G_inv_collect_0[l_uniq],
242
- mu_arr,
244
+ G_inv_mu_inv[l_uniq],
243
245
  is_antiderivative_wrt_tau,
244
246
  autograd_compatible,
245
247
  )
246
248
 
247
249
  if NFourier == 1:
248
- um = um + _mathscr_v_contribution.T
250
+ um = um + _mathscr_v_contribution
249
251
  elif autograd_compatible:
250
- um = um + np.concatenate((_mathscr_v_contribution.T, np.zeros((NFourier - 1, len(tau), NQuad))))
252
+ um = np.concatenate((um[[0], :, :] + _mathscr_v_contribution, um[1:, :, :]), axis=0)
251
253
  else:
252
- um[0, :, :] += _mathscr_v_contribution.T
254
+ um[0, :, :] += _mathscr_v_contribution
253
255
 
254
- u = np.einsum(
255
- "mti, mp -> itp",
256
- um,
257
- np.cos(np.arange(NFourier)[:, None] * (phi0 - phi)[None, :]),
258
- optimize=True,
256
+ u = np.sum(
257
+ um[:, :, :, None]
258
+ * np.cos(np.arange(NFourier)[:, None] * (phi0 - phi)[None, :])[:, None, None, :],
259
+ axis=0,
259
260
  )
260
261
 
261
262
  outputs = (rescale_factor * np.squeeze(u),)
262
- outputs_len = 1
263
+ output_is_tuple = False
263
264
 
264
265
  if return_Fourier_error:
265
266
  exponent = np.concatenate(
@@ -312,13 +313,20 @@ def _assemble_intensity_and_fluxes(
312
313
  )
313
314
 
314
315
  outputs += (Fourier_error,)
315
- outputs_len += 1
316
+ output_is_tuple = True
316
317
 
317
318
  if return_tau_arr:
318
319
  outputs += (tau_arr,)
319
- outputs_len += 1
320
+ output_is_tuple = True
321
+
322
+ if _return_l: # This indicates to the function that NT corrections are activated
323
+ output_is_tuple = True
324
+ outputs += (l,)
325
+ if there_is_iso_source:
326
+ # The TMS correction will use these
327
+ outputs += (l_uniq, l_inv)
320
328
 
321
- return outputs[0] if outputs_len == 1 else outputs
329
+ return outputs if output_is_tuple else outputs[0]
322
330
  # --------------------------------------------------------------------------------------------------------------------------
323
331
 
324
332
  # Construct u0
@@ -339,7 +347,7 @@ def _assemble_intensity_and_fluxes(
339
347
 
340
348
  # Atmospheric layer indices
341
349
  l = np.argmax(tau[:, None] <= tau_arr[None, :], axis=1)
342
- scaled_tau_arr_l = scaled_tau_arr_with_0[l + 1]
350
+ scaled_tau_arr_l = scaled_tau_arr_with_0[1:][l]
343
351
  scaled_tau_arr_lm1 = scaled_tau_arr_with_0[l]
344
352
 
345
353
  # Delta-M scaling
@@ -403,12 +411,12 @@ def _assemble_intensity_and_fluxes(
403
411
  if there_is_iso_source:
404
412
  l_uniq, l_inv = np.unique(l, return_inverse=True)
405
413
  _mathscr_v_contribution = _mathscr_v(
406
- scaled_tau, l_inv, Nscoeffs,
414
+ scaled_tau, l_inv,
415
+ Nscoeffs,
407
416
  scaled_s_poly_coeffs[l_uniq],
408
417
  G_collect_0[l_uniq],
409
418
  K_collect_0[l_uniq],
410
- G_inv_collect_0[l_uniq],
411
- mu_arr,
419
+ G_inv_mu_inv[l_uniq],
412
420
  is_antiderivative_wrt_tau,
413
421
  autograd_compatible,
414
422
  )
@@ -448,7 +456,7 @@ def _assemble_intensity_and_fluxes(
448
456
 
449
457
  # Atmospheric layer indices
450
458
  l = np.argmax(tau[:, None] <= tau_arr[None, :], axis=1)
451
- scaled_tau_arr_l = scaled_tau_arr_with_0[l + 1]
459
+ scaled_tau_arr_l = scaled_tau_arr_with_0[1:][l]
452
460
  scaled_tau_arr_lm1 = scaled_tau_arr_with_0[l]
453
461
 
454
462
  # Delta-M scaling
@@ -462,12 +470,12 @@ def _assemble_intensity_and_fluxes(
462
470
  if there_is_iso_source:
463
471
  l_uniq, l_inv = np.unique(l, return_inverse=True)
464
472
  _mathscr_v_contribution = _mathscr_v(
465
- scaled_tau, l_inv, Nscoeffs,
473
+ scaled_tau, l_inv,
474
+ Nscoeffs,
466
475
  scaled_s_poly_coeffs[l_uniq],
467
476
  G_collect_0[l_uniq, :N, :],
468
477
  K_collect_0[l_uniq],
469
- G_inv_collect_0[l_uniq],
470
- mu_arr,
478
+ G_inv_mu_inv[l_uniq],
471
479
  is_antiderivative_wrt_tau,
472
480
  autograd_compatible,
473
481
  )
@@ -530,7 +538,7 @@ def _assemble_intensity_and_fluxes(
530
538
 
531
539
  # Atmospheric layer indices
532
540
  l = np.argmax(tau[:, None] <= tau_arr[None, :], axis=1)
533
- scaled_tau_arr_l = scaled_tau_arr_with_0[l + 1]
541
+ scaled_tau_arr_l = scaled_tau_arr_with_0[1:][l]
534
542
  scaled_tau_arr_lm1 = scaled_tau_arr_with_0[l]
535
543
 
536
544
  # Delta-M scaling
@@ -544,12 +552,12 @@ def _assemble_intensity_and_fluxes(
544
552
  if there_is_iso_source:
545
553
  l_uniq, l_inv = np.unique(l, return_inverse=True)
546
554
  _mathscr_v_contribution = _mathscr_v(
547
- scaled_tau, l_inv, Nscoeffs,
555
+ scaled_tau, l_inv,
556
+ Nscoeffs,
548
557
  scaled_s_poly_coeffs[l_uniq],
549
558
  G_collect_0[l_uniq, N:, :],
550
559
  K_collect_0[l_uniq],
551
- G_inv_collect_0[l_uniq],
552
- mu_arr,
560
+ G_inv_mu_inv[l_uniq],
553
561
  is_antiderivative_wrt_tau,
554
562
  autograd_compatible,
555
563
  )