PythonicDISORT 1.0.2__py3-none-any.whl → 1.1__py3-none-any.whl
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.
- PythonicDISORT/_assemble_intensity_and_fluxes.py +10 -9
- PythonicDISORT/_solve_for_gen_and_part_sols.py +13 -13
- PythonicDISORT/pydisort.py +26 -23
- PythonicDISORT/subroutines.py +82 -44
- {pythonicdisort-1.0.2.dist-info → pythonicdisort-1.1.dist-info}/METADATA +1 -1
- pythonicdisort-1.1.dist-info/RECORD +11 -0
- pythonicdisort-1.0.2.dist-info/RECORD +0 -11
- {pythonicdisort-1.0.2.dist-info → pythonicdisort-1.1.dist-info}/LICENSE.md +0 -0
- {pythonicdisort-1.0.2.dist-info → pythonicdisort-1.1.dist-info}/WHEEL +0 -0
- {pythonicdisort-1.0.2.dist-info → pythonicdisort-1.1.dist-info}/top_level.txt +0 -0
|
@@ -100,6 +100,7 @@ def _assemble_intensity_and_fluxes(
|
|
|
100
100
|
else:
|
|
101
101
|
import numpy as np
|
|
102
102
|
|
|
103
|
+
|
|
103
104
|
################################## Assemble uncorrected intensity and flux functions #######################################
|
|
104
105
|
|
|
105
106
|
# Compute all the necessary quantities
|
|
@@ -172,7 +173,7 @@ def _assemble_intensity_and_fluxes(
|
|
|
172
173
|
Pass `return_Fourier_error = True` (defaults to `False`) to return the
|
|
173
174
|
Cauchy / Fourier convergence evaluation (type: float) for the last Fourier term.
|
|
174
175
|
Pass `is_antiderivative_wrt_tau = True` (defaults to `False`)
|
|
175
|
-
to switch to an antiderivative of
|
|
176
|
+
to switch to an antiderivative of this function with respect to `tau`.
|
|
176
177
|
"""
|
|
177
178
|
tau = np.atleast_1d(tau)
|
|
178
179
|
phi = np.atleast_1d(phi)
|
|
@@ -238,7 +239,7 @@ def _assemble_intensity_and_fluxes(
|
|
|
238
239
|
G_inv_collect_0[l_uniq],
|
|
239
240
|
mu_arr,
|
|
240
241
|
is_antiderivative_wrt_tau,
|
|
241
|
-
autograd_compatible
|
|
242
|
+
autograd_compatible,
|
|
242
243
|
)
|
|
243
244
|
|
|
244
245
|
if NFourier == 1:
|
|
@@ -323,7 +324,7 @@ def _assemble_intensity_and_fluxes(
|
|
|
323
324
|
but reclassification of delta-scaled flux and other corrections must be done manually
|
|
324
325
|
(for actinic flux `generate_diff_act_flux_funcs` will automatically perform the reclassification).
|
|
325
326
|
Pass `is_antiderivative_wrt_tau = True` (defaults to `False`)
|
|
326
|
-
to switch to an antiderivative of
|
|
327
|
+
to switch to an antiderivative of this function with respect to `tau`.
|
|
327
328
|
"""
|
|
328
329
|
tau = np.atleast_1d(tau)
|
|
329
330
|
if np.any(tau < 0) or np.any(tau > tau_arr[-1]):
|
|
@@ -400,7 +401,7 @@ def _assemble_intensity_and_fluxes(
|
|
|
400
401
|
G_inv_collect_0[l_uniq],
|
|
401
402
|
mu_arr,
|
|
402
403
|
is_antiderivative_wrt_tau,
|
|
403
|
-
autograd_compatible
|
|
404
|
+
autograd_compatible,
|
|
404
405
|
)
|
|
405
406
|
u0 = u0 + _mathscr_v_contribution
|
|
406
407
|
|
|
@@ -428,7 +429,7 @@ def _assemble_intensity_and_fluxes(
|
|
|
428
429
|
(Energetic) Flux function with argument `tau` (type: array or float) for positive (upward) `mu` values.
|
|
429
430
|
Returns the diffuse flux magnitudes (same type and size as `tau`).
|
|
430
431
|
Pass `is_antiderivative_wrt_tau = True` (defaults to `False`)
|
|
431
|
-
to switch to an antiderivative of
|
|
432
|
+
to switch to an antiderivative of this function with respect to `tau`.
|
|
432
433
|
"""
|
|
433
434
|
tau = np.atleast_1d(tau)
|
|
434
435
|
if np.any(tau < 0) or np.any(tau > tau_arr[-1]):
|
|
@@ -457,7 +458,7 @@ def _assemble_intensity_and_fluxes(
|
|
|
457
458
|
G_inv_collect_0[l_uniq],
|
|
458
459
|
mu_arr,
|
|
459
460
|
is_antiderivative_wrt_tau,
|
|
460
|
-
autograd_compatible
|
|
461
|
+
autograd_compatible,
|
|
461
462
|
)
|
|
462
463
|
else:
|
|
463
464
|
_mathscr_v_contribution = 0
|
|
@@ -509,7 +510,7 @@ def _assemble_intensity_and_fluxes(
|
|
|
509
510
|
Returns a tuple of the diffuse and direct flux magnitudes respectively where each entry is of the
|
|
510
511
|
same type and size as `tau`.
|
|
511
512
|
Pass `is_antiderivative_wrt_tau = True` (defaults to `False`)
|
|
512
|
-
to switch to an antiderivative of
|
|
513
|
+
to switch to an antiderivative of this function with respect to `tau`.
|
|
513
514
|
"""
|
|
514
515
|
tau = np.atleast_1d(tau)
|
|
515
516
|
if np.any(tau < 0) or np.any(tau > tau_arr[-1]):
|
|
@@ -538,7 +539,7 @@ def _assemble_intensity_and_fluxes(
|
|
|
538
539
|
G_inv_collect_0[l_uniq],
|
|
539
540
|
mu_arr,
|
|
540
541
|
is_antiderivative_wrt_tau,
|
|
541
|
-
autograd_compatible
|
|
542
|
+
autograd_compatible,
|
|
542
543
|
)
|
|
543
544
|
else:
|
|
544
545
|
_mathscr_v_contribution = 0
|
|
@@ -592,6 +593,6 @@ def _assemble_intensity_and_fluxes(
|
|
|
592
593
|
# --------------------------------------------------------------------------------------------------------------------------
|
|
593
594
|
|
|
594
595
|
if only_flux:
|
|
595
|
-
return flux_up, flux_down, u0#, GC_collect_0, K_collect_0
|
|
596
|
+
return flux_up, flux_down, u0#, GC_collect_0, K_collect_0#, B_collect_0
|
|
596
597
|
else:
|
|
597
598
|
return flux_up, flux_down, u0, u
|
|
@@ -101,16 +101,17 @@ def _solve_for_gen_and_part_sols(
|
|
|
101
101
|
# Loop over NLayers atmospheric layers
|
|
102
102
|
# --------------------------------------------------------------------------------------------------------------------------
|
|
103
103
|
for l in range(NLayers):
|
|
104
|
-
|
|
104
|
+
weighted_scaled_Leg_coeffs_l = weighted_scaled_Leg_coeffs[l, :][ells]
|
|
105
|
+
scaled_omega_l = scaled_omega_arr[l]
|
|
106
|
+
omega_times_Leg_coeffs = (scaled_omega_l / 2) * weighted_scaled_Leg_coeffs_l
|
|
105
107
|
|
|
106
|
-
if np.any(
|
|
107
|
-
scaled_omega_l = scaled_omega_arr[l]
|
|
108
|
+
if np.any(np.abs(omega_times_Leg_coeffs) > 1e-8): # There are shortcuts if multiple scattering is insignificant
|
|
108
109
|
|
|
109
110
|
# Generate D
|
|
110
111
|
# --------------------------------------------------------------------------------------------------------------------------
|
|
111
|
-
D_temp =
|
|
112
|
-
D_pos =
|
|
113
|
-
D_neg =
|
|
112
|
+
D_temp = omega_times_Leg_coeffs[None, :] * (fac[None, :] * asso_leg_term_pos.T)
|
|
113
|
+
D_pos = D_temp @ asso_leg_term_pos
|
|
114
|
+
D_neg = D_temp @ asso_leg_term_neg
|
|
114
115
|
|
|
115
116
|
# --------------------------------------------------------------------------------------------------------------------------
|
|
116
117
|
|
|
@@ -130,8 +131,8 @@ def _solve_for_gen_and_part_sols(
|
|
|
130
131
|
# Generate X
|
|
131
132
|
X_temp = (
|
|
132
133
|
(scaled_omega_l * I0 * (2 - (m == 0)) / (4 * pi))
|
|
133
|
-
*
|
|
134
|
-
* asso_leg_term_mu0
|
|
134
|
+
* weighted_scaled_Leg_coeffs_l
|
|
135
|
+
* (fac * asso_leg_term_mu0)
|
|
135
136
|
)
|
|
136
137
|
X_pos = X_temp @ asso_leg_term_pos
|
|
137
138
|
X_neg = X_temp @ asso_leg_term_neg
|
|
@@ -149,7 +150,6 @@ def _solve_for_gen_and_part_sols(
|
|
|
149
150
|
|
|
150
151
|
# --------------------------------------------------------------------------------------------------------------------------
|
|
151
152
|
|
|
152
|
-
|
|
153
153
|
alpha_arr[ind, :, :] = alpha
|
|
154
154
|
beta_arr[ind, :, :] = beta
|
|
155
155
|
no_shortcut_indices.append(ind)
|
|
@@ -173,15 +173,15 @@ def _solve_for_gen_and_part_sols(
|
|
|
173
173
|
|
|
174
174
|
# Diagonalization of coefficient matrix (refer to section 3.4.2 of the Comprehensive Documentation)
|
|
175
175
|
# --------------------------------------------------------------------------------------------------------------------------
|
|
176
|
-
alpha_arr = alpha_arr[
|
|
177
|
-
beta_arr = beta_arr[
|
|
176
|
+
alpha_arr = alpha_arr[no_shortcut_indices, :, :]
|
|
177
|
+
beta_arr = beta_arr[no_shortcut_indices, :, :]
|
|
178
178
|
|
|
179
179
|
K_squared_arr, eigenvecs_GpG_arr = np.linalg.eig(
|
|
180
180
|
np.einsum(
|
|
181
181
|
"lij, ljk -> lik", alpha_arr - beta_arr, alpha_arr + beta_arr, optimize=True
|
|
182
182
|
),
|
|
183
183
|
)
|
|
184
|
-
|
|
184
|
+
|
|
185
185
|
# Eigenvalues arranged negative then positive, from largest to smallest magnitude
|
|
186
186
|
K_arr = np.concatenate((-np.sqrt(K_squared_arr), np.sqrt(K_squared_arr)), axis=1)
|
|
187
187
|
eigenvecs_GpG_arr = np.concatenate((eigenvecs_GpG_arr, eigenvecs_GpG_arr), axis=2)
|
|
@@ -205,7 +205,7 @@ def _solve_for_gen_and_part_sols(
|
|
|
205
205
|
K_collect[no_shortcut_indices, :] = K_arr
|
|
206
206
|
if len(no_shortcut_indices_0) > 0: # If there is no isotropic source this list will be empty
|
|
207
207
|
G_inv_collect_0[no_shortcut_indices_0, :, :] = np.linalg.inv(
|
|
208
|
-
G_collect[
|
|
208
|
+
G_collect[no_shortcut_indices_0, :, :]
|
|
209
209
|
)
|
|
210
210
|
|
|
211
211
|
# --------------------------------------------------------------------------------------------------------------------------
|
PythonicDISORT/pydisort.py
CHANGED
|
@@ -76,7 +76,7 @@ def pydisort(
|
|
|
76
76
|
NT_cor : optional, bool
|
|
77
77
|
Perform Nakajima-Tanaka intensity corrections?
|
|
78
78
|
BDRF_Fourier_modes : optional, list of functions
|
|
79
|
-
BDRF Fourier modes, each a
|
|
79
|
+
BDRF Fourier modes, each a float, or a function with arguments ``mu, -mu_p`` of type array
|
|
80
80
|
which output has the same dimensions as the outer product of the two arrays.
|
|
81
81
|
s_poly_coeffs : optional, array
|
|
82
82
|
Polynomial coefficients of isotropic internal sources.
|
|
@@ -86,17 +86,17 @@ def pydisort(
|
|
|
86
86
|
At or above how many atmospheric layers should ``scipy.linalg.solve_banded`` be used?
|
|
87
87
|
autograd_compatible : optional, bool
|
|
88
88
|
If ``True``, the autograd package: https://github.com/HIPS/autograd can be used to compute
|
|
89
|
-
the ``tau``-derivatives of the output functions but ``pydisort`` will be less efficient.
|
|
89
|
+
the ``tau``-derivatives of the output functions but ``pydisort`` will be less efficient.
|
|
90
90
|
|
|
91
91
|
Returns
|
|
92
92
|
-------
|
|
93
|
-
mu_arr : array
|
|
93
|
+
mu_arr : array
|
|
94
94
|
All ``mu`` (cosine of polar angle) quadrature nodes.
|
|
95
95
|
Fp(tau) : function
|
|
96
96
|
(Energetic) Flux function with argument ``tau`` (type: array or float) for positive (upward) ``mu`` values.
|
|
97
97
|
Returns the diffuse flux magnitudes (same type and size as ``tau``).
|
|
98
98
|
Pass ``is_antiderivative_wrt_tau = True`` (defaults to ``False``)
|
|
99
|
-
to switch to an antiderivative of
|
|
99
|
+
to switch to an antiderivative of this function with respect to ``tau``.
|
|
100
100
|
For example, ``Fp(tau_arr, is_antiderivative_wrt_tau = True) - Fp(np.insert(tau_arr[:-1] + 1e-15, 0, 0), is_antiderivative_wrt_tau = True)``
|
|
101
101
|
will produce an array of the tau-integral over each layer.
|
|
102
102
|
Pass ``return_tau_arr`` to return ``tau_arr`` (defaults to ``False``).
|
|
@@ -105,7 +105,7 @@ def pydisort(
|
|
|
105
105
|
Returns a tuple of the diffuse and direct flux magnitudes respectively where each entry is of the
|
|
106
106
|
same type and size as ``tau``.
|
|
107
107
|
Pass ``is_antiderivative_wrt_tau = True`` (defaults to ``False``)
|
|
108
|
-
to switch to an antiderivative of
|
|
108
|
+
to switch to an antiderivative of this function with respect to ``tau``.
|
|
109
109
|
Pass ``return_tau_arr`` to return ``tau_arr`` (defaults to ``False``).
|
|
110
110
|
u0(tau) : function
|
|
111
111
|
Zeroth Fourier mode of the intensity with argument ``tau`` (type: array or float).
|
|
@@ -114,13 +114,13 @@ def pydisort(
|
|
|
114
114
|
but reclassification of delta-scaled flux and other corrections must be done manually
|
|
115
115
|
(for actinic flux ``subroutines.generate_diff_act_flux_funcs`` will automatically perform the reclassification).
|
|
116
116
|
Pass ``is_antiderivative_wrt_tau = True`` (defaults to ``False``)
|
|
117
|
-
to switch to an antiderivative of
|
|
117
|
+
to switch to an antiderivative of this function with respect to ``tau``.
|
|
118
118
|
Pass ``return_tau_arr`` to return ``tau_arr`` (defaults to ``False``).
|
|
119
119
|
u(tau, phi) : function, optional
|
|
120
120
|
Intensity function with arguments ``(tau, phi)`` each of type array or float.
|
|
121
121
|
Returns an ndarray with axes corresponding to variation with ``mu, tau, phi`` respectively.
|
|
122
122
|
Pass ``is_antiderivative_wrt_tau = True`` (defaults to ``False``)
|
|
123
|
-
to switch to an antiderivative of
|
|
123
|
+
to switch to an antiderivative of this function with respect to ``tau``.
|
|
124
124
|
Pass ``return_Fourier_error = True`` (defaults to ``False``) to return the
|
|
125
125
|
Cauchy / Fourier convergence evaluation (type: float) for the last Fourier term.
|
|
126
126
|
Pass ``return_tau_arr`` to return ``tau_arr`` (defaults to ``False``).
|
|
@@ -172,13 +172,13 @@ def pydisort(
|
|
|
172
172
|
| `Leg_coeffs_residue_avg` | `NLeg_all` |
|
|
173
173
|
| `scaled_mu0` | scalar |
|
|
174
174
|
"""
|
|
175
|
-
|
|
175
|
+
|
|
176
176
|
if autograd_compatible:
|
|
177
177
|
import autograd.numpy as np
|
|
178
178
|
else:
|
|
179
179
|
import numpy as np
|
|
180
180
|
|
|
181
|
-
# Turn
|
|
181
|
+
# Turn floats into arrays
|
|
182
182
|
# --------------------------------------------------------------------------------------------------------------------------
|
|
183
183
|
tau_arr = np.atleast_1d(tau_arr)
|
|
184
184
|
omega_arr = np.atleast_1d(omega_arr)
|
|
@@ -222,7 +222,7 @@ def pydisort(
|
|
|
222
222
|
if not np.all(tau_arr > 0):
|
|
223
223
|
raise ValueError("tau values cannot be non-positive.")
|
|
224
224
|
if not np.all(thickness_arr > 0):
|
|
225
|
-
raise ValueError("Layer
|
|
225
|
+
raise ValueError("Layer thicknesses cannot be non-positive.")
|
|
226
226
|
# Single-scattering albedo must be between 0 and 1, excluding 1
|
|
227
227
|
if not (np.all(omega_arr >= 0) and np.all(omega_arr < 1)):
|
|
228
228
|
raise ValueError("Single-scattering albedo must be between 0 and 1, excluding 1.")
|
|
@@ -230,21 +230,22 @@ def pydisort(
|
|
|
230
230
|
# The user must supply at least as many phase function Legendre coefficients as intended for use
|
|
231
231
|
if not NLeg > 0:
|
|
232
232
|
raise ValueError("The number of phase function Legendre coefficients must be positive.")
|
|
233
|
-
if not np.all(omega_arr * Leg_coeffs_all[:, 0] == omega_arr):
|
|
234
|
-
raise ValueError("The first phase function Legendre coefficient must equal 1.")
|
|
235
|
-
if not (np.all(-1 <= Leg_coeffs_all) and np.all(Leg_coeffs_all <= 1)):
|
|
236
|
-
raise ValueError("The phase function Legendre coefficients must all be between -1 and 1.")
|
|
237
233
|
if not NLeg <= NLeg_all:
|
|
238
234
|
raise ValueError("`NLeg` cannot be larger than the number of phase function Legendre coefficients provided.")
|
|
239
235
|
# Ensure that the first dimension of the following inputs corresponds to the number of layers
|
|
240
236
|
if not np.shape(Leg_coeffs_all)[0] == NLayers:
|
|
241
|
-
raise ValueError("The zeroth dimension of the shape of `Leg_coeffs_all` does not match the number of layers
|
|
237
|
+
raise ValueError("The zeroth dimension of the shape of `Leg_coeffs_all` does not match the number of layers which is deduced from the length of `tau_arr`.")
|
|
242
238
|
if not len(omega_arr) == NLayers:
|
|
243
|
-
raise ValueError("The zeroth dimension of the shape of `omega_arr` does not match the number of layers
|
|
239
|
+
raise ValueError("The zeroth dimension of the shape of `omega_arr` does not match the number of layers which is deduced from the length of `tau_arr`.")
|
|
244
240
|
if np.any(f_arr != 0) and not len(f_arr) == NLayers:
|
|
245
|
-
raise ValueError("The length of `f_arr` does not match the number of layers
|
|
241
|
+
raise ValueError("The length of `f_arr` does not match the number of layers which is deduced from the length of `tau_arr`.")
|
|
246
242
|
if there_is_iso_source and not np.shape(s_poly_coeffs)[0] == NLayers:
|
|
247
|
-
raise ValueError("The zeroth dimension of the shape of `s_poly_coeffs` does not match the number of layers
|
|
243
|
+
raise ValueError("The zeroth dimension of the shape of `s_poly_coeffs` does not match the number of layers which is deduced from the length of `tau_arr`.")
|
|
244
|
+
# Value checks on the phase function Legendre coefficients
|
|
245
|
+
if not np.all(omega_arr * Leg_coeffs_all[:, 0] == omega_arr):
|
|
246
|
+
raise ValueError("The first phase function Legendre coefficient must equal 1.")
|
|
247
|
+
if not (np.all(-1 <= Leg_coeffs_all) and np.all(Leg_coeffs_all <= 1)):
|
|
248
|
+
raise ValueError("The phase function Legendre coefficients must all be between -1 and 1.")
|
|
248
249
|
# Conditions on the number of quadrature angles (NQuad), Legendre coefficients (NLeg) and loops (NFourier)
|
|
249
250
|
if not NQuad >= 2:
|
|
250
251
|
raise ValueError("There must be at least two streams.")
|
|
@@ -261,7 +262,7 @@ def pydisort(
|
|
|
261
262
|
raise ValueError("There should be more streams than the number of phase function Legendre coefficients used.")
|
|
262
263
|
# We require principal angles and a downward incident beam
|
|
263
264
|
if I0 < 0:
|
|
264
|
-
raise ValueError("The incident beam
|
|
265
|
+
raise ValueError("The intensity of the incident beam cannot be negative.")
|
|
265
266
|
if there_is_beam_source:
|
|
266
267
|
if not (0 < mu0 and mu0 <= 1):
|
|
267
268
|
raise ValueError("The cosine of the polar angle of the incident beam must be between 0 and 1, excluding 0.")
|
|
@@ -345,6 +346,7 @@ def pydisort(
|
|
|
345
346
|
np.max(b_pos),
|
|
346
347
|
np.max(b_neg),
|
|
347
348
|
scaled_s_poly_coeffs[0, 0],
|
|
349
|
+
scaled_s_poly_coeffs[-1, :] @ (scaled_tau_arr_with_0[-1] ** np.arange(Nscoeffs))
|
|
348
350
|
)
|
|
349
351
|
)
|
|
350
352
|
I0 = (I0 / rescale_factor).copy()
|
|
@@ -353,9 +355,10 @@ def pydisort(
|
|
|
353
355
|
scaled_s_poly_coeffs = (scaled_s_poly_coeffs / rescale_factor).copy()
|
|
354
356
|
else:
|
|
355
357
|
rescale_factor = np.max((I0, np.max(b_pos), np.max(b_neg)))
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
358
|
+
if rescale_factor != 0:
|
|
359
|
+
I0 = (I0 / rescale_factor).copy()
|
|
360
|
+
b_pos = (b_pos / rescale_factor).copy()
|
|
361
|
+
b_neg = (b_neg / rescale_factor).copy()
|
|
359
362
|
# --------------------------------------------------------------------------------------------------------------------------
|
|
360
363
|
|
|
361
364
|
if NT_cor and not only_flux and there_is_beam_source and np.any(f_arr > 0) and NLeg < NLeg_all:
|
|
@@ -667,7 +670,7 @@ def pydisort(
|
|
|
667
670
|
tau = np.atleast_1d(tau)
|
|
668
671
|
phi = np.atleast_1d(phi)
|
|
669
672
|
NT_corrections = TMS_correction(tau, phi, is_antiderivative_wrt_tau)
|
|
670
|
-
|
|
673
|
+
|
|
671
674
|
if autograd_compatible:
|
|
672
675
|
NT_corrections = NT_corrections + np.concatenate(
|
|
673
676
|
[np.zeros((N, len(tau), len(phi))), IMS_correction(tau, phi, is_antiderivative_wrt_tau)], axis=0
|
PythonicDISORT/subroutines.py
CHANGED
|
@@ -12,13 +12,13 @@ def transform_interval(arr, c, d, a, b):
|
|
|
12
12
|
arr : array
|
|
13
13
|
The 1D array to transform.
|
|
14
14
|
c : float
|
|
15
|
-
|
|
15
|
+
Lower bound of interval [c, d].
|
|
16
16
|
d : float
|
|
17
|
-
|
|
17
|
+
Upper bound of interval [c, d].
|
|
18
18
|
a : float, optional
|
|
19
|
-
|
|
19
|
+
Lower bound of interval [a, b].
|
|
20
20
|
b : float, optional
|
|
21
|
-
|
|
21
|
+
Upper bound of interval [a, b].
|
|
22
22
|
|
|
23
23
|
Returns
|
|
24
24
|
-------
|
|
@@ -38,13 +38,13 @@ def transform_weights(weights, c, d, a, b):
|
|
|
38
38
|
weights : array
|
|
39
39
|
The weights to transform.
|
|
40
40
|
c : float
|
|
41
|
-
|
|
41
|
+
Lower bound of interval [c, d].
|
|
42
42
|
d : float
|
|
43
|
-
|
|
43
|
+
Upper bound of interval [c, d].
|
|
44
44
|
a : float, optional
|
|
45
|
-
|
|
45
|
+
Lower bound of interval [a, b].
|
|
46
46
|
b : float, optional
|
|
47
|
-
|
|
47
|
+
Upper bound of interval [a, b].
|
|
48
48
|
|
|
49
49
|
Returns
|
|
50
50
|
-------
|
|
@@ -95,9 +95,9 @@ def Gauss_Legendre_quad(N, c=0, d=1):
|
|
|
95
95
|
N : int (will be converted to int)
|
|
96
96
|
Number of quadrature nodes.
|
|
97
97
|
c : float, optional
|
|
98
|
-
|
|
98
|
+
Lower bound of integration interval.
|
|
99
99
|
d : float, optional
|
|
100
|
-
|
|
100
|
+
Upper bound of integration interval.
|
|
101
101
|
|
|
102
102
|
Returns
|
|
103
103
|
-------
|
|
@@ -248,18 +248,18 @@ def generate_diff_act_flux_funcs(u0):
|
|
|
248
248
|
Actinic flux function with argument ``tau`` (type: array) for positive (upward) ``mu`` values.
|
|
249
249
|
Returns the diffuse flux magnitudes (type: array).
|
|
250
250
|
Pass ``is_antiderivative_wrt_tau = True`` (defaults to ``False``)
|
|
251
|
-
to switch to an antiderivative of
|
|
251
|
+
to switch to an antiderivative of this function with respect to ``tau``.
|
|
252
252
|
Pass ``return_tau_arr`` to return ``tau_arr`` (defaults to ``False``).
|
|
253
253
|
Fm_act(tau) : function
|
|
254
254
|
Actinic flux function with argument ``tau`` (type: array) for negative (downward) ``mu`` values.
|
|
255
255
|
Returns the diffuse flux magnitudes (type: array).
|
|
256
256
|
Pass ``is_antiderivative_wrt_tau = True`` (defaults to ``False``)
|
|
257
|
-
to switch to an antiderivative of
|
|
257
|
+
to switch to an antiderivative of this function with respect to ``tau``.
|
|
258
258
|
Pass ``return_tau_arr`` to return ``tau_arr`` (defaults to ``False``).
|
|
259
259
|
|
|
260
260
|
"""
|
|
261
261
|
N = len(u0(0)) // 2
|
|
262
|
-
GL_weights = Gauss_Legendre_quad(N
|
|
262
|
+
GL_weights = Gauss_Legendre_quad(N)[1]
|
|
263
263
|
|
|
264
264
|
# Note that the zeroth axis of the array u0(tau) captures variation with mu
|
|
265
265
|
def flux_act_up(tau, is_antiderivative_wrt_tau=False, return_tau_arr=False):
|
|
@@ -314,11 +314,12 @@ def Planck(T, WVNM):
|
|
|
314
314
|
not_zeros_ind = T != 0
|
|
315
315
|
|
|
316
316
|
results = np.zeros(len(T))
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
317
|
+
if np.sum(not_zeros_ind) > 0:
|
|
318
|
+
results[~not_zeros_ind] = 0
|
|
319
|
+
|
|
320
|
+
# Coded in this way to prevent overflow
|
|
321
|
+
expterm = np.exp(-100 * sc.constants.h * sc.constants.c * WVNM / (sc.constants.k * T[not_zeros_ind]))
|
|
322
|
+
results[not_zeros_ind] = (2e8 * sc.constants.h * sc.constants.c**2 * WVNM**3 * expterm) / (1 - expterm)
|
|
322
323
|
|
|
323
324
|
return np.squeeze(results)[()]
|
|
324
325
|
|
|
@@ -383,11 +384,12 @@ def linear_spline_coefficients(x, y, check_inputs=True):
|
|
|
383
384
|
|
|
384
385
|
|
|
385
386
|
|
|
386
|
-
def generate_s_poly_coeffs(tau_arr, TEMPER, WVNMLO, WVNMHI, **kwargs):
|
|
387
|
+
def generate_s_poly_coeffs(tau_arr, TEMPER, WVNMLO, WVNMHI, omega_arr=None, **kwargs):
|
|
387
388
|
"""Generate DISORT-equivalent ``s_poly_coeffs`` for input into ``pydisort``.
|
|
388
389
|
This convenience function is provided to help match the inputs for Stamnes' DISORT to those for PythonicDISORT.
|
|
389
|
-
|
|
390
|
-
|
|
390
|
+
If ``omega_arr`` is specified, the coefficients will be multiplied by emissivity factors equal to ``1 - omega_arr``
|
|
391
|
+
per Kirchoff's law of thermal radiation, and Kirchoff's law is enforced in Stamnes' DISORT.
|
|
392
|
+
Otherwise, the emissivities will be set to 1 and users can multiply their own emissivity factors.
|
|
391
393
|
|
|
392
394
|
Parameters
|
|
393
395
|
----------
|
|
@@ -400,6 +402,8 @@ def generate_s_poly_coeffs(tau_arr, TEMPER, WVNMLO, WVNMHI, **kwargs):
|
|
|
400
402
|
Lower bound of wavenumber interval with units m^-1. This variable is identically named in Stamnes' DISORT.
|
|
401
403
|
WVNMHI : float
|
|
402
404
|
Upper bound of wavenumber interval with units m^-1. This variable is identically named in Stamnes' DISORT.
|
|
405
|
+
omega_arr : optional, array or float
|
|
406
|
+
Single-scattering albedo of each atmospheric layer which is required to compute the emissivity of each layer.
|
|
403
407
|
**kwargs
|
|
404
408
|
Keyword arguments to pass to ``scipy.integrate.quad_vec``.
|
|
405
409
|
|
|
@@ -413,12 +417,35 @@ def generate_s_poly_coeffs(tau_arr, TEMPER, WVNMLO, WVNMHI, **kwargs):
|
|
|
413
417
|
"""
|
|
414
418
|
tau_arr = np.atleast_1d(tau_arr)
|
|
415
419
|
if not len(TEMPER) == len(tau_arr) + 1:
|
|
416
|
-
raise ValueError(
|
|
417
|
-
|
|
420
|
+
raise ValueError(
|
|
421
|
+
"Missing temperature specification at some boundaries / interfaces."
|
|
422
|
+
)
|
|
423
|
+
|
|
418
424
|
tau_arr_with_0 = np.insert(tau_arr, 0, 0)
|
|
419
|
-
blackbody_emission_at_each_boundary = sc.integrate.quad_vec(
|
|
420
|
-
|
|
421
|
-
|
|
425
|
+
blackbody_emission_at_each_boundary = sc.integrate.quad_vec(
|
|
426
|
+
lambda WVNM: Planck(TEMPER, WVNM), WVNMLO, WVNMHI, **kwargs
|
|
427
|
+
)[0]
|
|
428
|
+
|
|
429
|
+
if omega_arr is None:
|
|
430
|
+
return (
|
|
431
|
+
linear_spline_coefficients(
|
|
432
|
+
tau_arr_with_0, blackbody_emission_at_each_boundary, check_inputs=False
|
|
433
|
+
)
|
|
434
|
+
)
|
|
435
|
+
elif np.isscalar(omega_arr):
|
|
436
|
+
return (
|
|
437
|
+
linear_spline_coefficients(
|
|
438
|
+
tau_arr_with_0, blackbody_emission_at_each_boundary, check_inputs=False
|
|
439
|
+
)
|
|
440
|
+
* (1 - omega_arr)
|
|
441
|
+
)
|
|
442
|
+
else:
|
|
443
|
+
return (
|
|
444
|
+
linear_spline_coefficients(
|
|
445
|
+
tau_arr_with_0, blackbody_emission_at_each_boundary, check_inputs=False
|
|
446
|
+
)
|
|
447
|
+
* (1 - omega_arr)[:, None]
|
|
448
|
+
)
|
|
422
449
|
|
|
423
450
|
|
|
424
451
|
|
|
@@ -432,17 +459,24 @@ def generate_emissivity_from_BDRF(N, zeroth_BDRF_Fourier_mode):
|
|
|
432
459
|
----------
|
|
433
460
|
N : int
|
|
434
461
|
Number of upper hemisphere quadrature nodes. Equal to ``NQuad // 2``.
|
|
435
|
-
zeroth_BDRF_Fourier_mode : function
|
|
462
|
+
zeroth_BDRF_Fourier_mode : function or float
|
|
436
463
|
Zeroth BDRF Fourier mode with arguments ``mu, -mu_p`` of type array
|
|
437
464
|
and which output has the same dimensions as the outer product of the two arrays.
|
|
465
|
+
A scalar input represents a constant function and in that case the output
|
|
466
|
+
is simply one minus the scalar input.
|
|
438
467
|
|
|
439
468
|
Returns
|
|
440
469
|
-------
|
|
441
|
-
array
|
|
470
|
+
array or float
|
|
442
471
|
Emissivity for the blackbody contribution to the lower boundary source ``b_neg``.
|
|
443
472
|
"""
|
|
444
|
-
|
|
445
|
-
|
|
473
|
+
if np.isscalar(zeroth_BDRF_Fourier_mode):
|
|
474
|
+
return 1 - zeroth_BDRF_Fourier_mode
|
|
475
|
+
else:
|
|
476
|
+
mu_arr_pos, W = Gauss_Legendre_quad(N)
|
|
477
|
+
return (
|
|
478
|
+
1 - 2 * zeroth_BDRF_Fourier_mode(mu_arr_pos, mu_arr_pos) * mu_arr_pos[None, :] @ W
|
|
479
|
+
)
|
|
446
480
|
|
|
447
481
|
|
|
448
482
|
|
|
@@ -457,8 +491,9 @@ def cache_BDRF_Fourier_modes(N, mu0, BDRF_Fourier_modes):
|
|
|
457
491
|
Number of upper hemisphere quadrature nodes. Equal to ``NQuad // 2``.
|
|
458
492
|
mu0 : float
|
|
459
493
|
Cosine of polar angle of the incident beam.
|
|
460
|
-
BDRF_Fourier_modes : list of functions
|
|
461
|
-
BDRF Fourier modes, each a scalar
|
|
494
|
+
BDRF_Fourier_modes : list of functions and scalars
|
|
495
|
+
BDRF Fourier modes, each a scalar representing a constant function,
|
|
496
|
+
or a function with arguments ``mu, -mu_p`` of type array
|
|
462
497
|
which output has the same dimensions as the outer product of the two arrays.
|
|
463
498
|
|
|
464
499
|
Returns
|
|
@@ -471,7 +506,7 @@ def cache_BDRF_Fourier_modes(N, mu0, BDRF_Fourier_modes):
|
|
|
471
506
|
NBDRF = len(BDRF_Fourier_modes)
|
|
472
507
|
mu_arr_pos = Gauss_Legendre_quad(N)[0]
|
|
473
508
|
|
|
474
|
-
[
|
|
509
|
+
BDRF_Fourier_modes_evaluated = [
|
|
475
510
|
(
|
|
476
511
|
None
|
|
477
512
|
if np.isscalar(BDRF_Fourier_modes[m])
|
|
@@ -551,15 +586,16 @@ def interpolate(u):
|
|
|
551
586
|
-------
|
|
552
587
|
u_interpol : function
|
|
553
588
|
Intensity function with arguments ``(mu, tau, phi)`` (for ``u``)
|
|
554
|
-
or ``(mu, tau)`` (for ``u0``) each
|
|
589
|
+
or ``(mu, tau)`` (for ``u0``) each an array or scalar.
|
|
555
590
|
Returns an ndarray with axes corresponding to variation with each argument in the same order.
|
|
556
591
|
Pass ``is_antiderivative_wrt_tau = True`` (defaults to ``False``)
|
|
557
|
-
to switch to an antiderivative of
|
|
592
|
+
to switch to an antiderivative of this function with respect to ``tau``.
|
|
558
593
|
Pass ``return_Fourier_error = True`` (defaults to ``False``) to return the
|
|
559
594
|
Cauchy / Fourier convergence evaluation (type: float) for the last Fourier term.
|
|
560
595
|
Pass ``return_tau_arr`` to return ``tau_arr`` (defaults to ``False``).
|
|
561
596
|
|
|
562
597
|
"""
|
|
598
|
+
|
|
563
599
|
N = len(u(0, 0)) // 2
|
|
564
600
|
mu_arr_pos = Gauss_Legendre_quad(N)[0]
|
|
565
601
|
|
|
@@ -774,18 +810,19 @@ def _mathscr_v(tau, # Input optical depths
|
|
|
774
810
|
def _compare(results, mu_to_compare, reorder_mu, flux_up, flux_down, u=None):
|
|
775
811
|
"""Performs pointwise comparisons between results from Stamnes' DISORT,
|
|
776
812
|
which are stored in ``.npz`` files, against results from PythonicDISORT. Used in our PyTests.
|
|
777
|
-
|
|
813
|
+
See the ``*_test`` Jupyter Notebooks to see how this function is used and the arguments that go into it.
|
|
814
|
+
|
|
778
815
|
"""
|
|
779
816
|
# Load saved results from Stamnes' DISORT
|
|
780
817
|
flup = results["flup"]
|
|
781
818
|
rfldn = results["rfldn"]
|
|
782
819
|
rfldir = results["rfldir"]
|
|
783
|
-
if u
|
|
820
|
+
if u is not None:
|
|
784
821
|
uu = results["uu"]
|
|
785
822
|
|
|
786
823
|
# Load comparison points
|
|
787
824
|
tau_test_arr = results["tau_test_arr"]
|
|
788
|
-
if u
|
|
825
|
+
if u is not None:
|
|
789
826
|
phi_arr = results["phi_arr"]
|
|
790
827
|
|
|
791
828
|
# Perform and print the comparisons
|
|
@@ -800,7 +837,7 @@ def _compare(results, mu_to_compare, reorder_mu, flux_up, flux_down, u=None):
|
|
|
800
837
|
diff_flux_up,
|
|
801
838
|
flup,
|
|
802
839
|
out=np.zeros_like(diff_flux_up),
|
|
803
|
-
where=flup
|
|
840
|
+
where=(flup != 0),
|
|
804
841
|
)
|
|
805
842
|
print("Difference =", np.max(diff_flux_up))
|
|
806
843
|
print("Difference ratio =", np.max(ratio_flux_up))
|
|
@@ -813,7 +850,7 @@ def _compare(results, mu_to_compare, reorder_mu, flux_up, flux_down, u=None):
|
|
|
813
850
|
diff_flux_down_diffuse,
|
|
814
851
|
rfldn,
|
|
815
852
|
out=np.zeros_like(diff_flux_down_diffuse),
|
|
816
|
-
where=rfldn
|
|
853
|
+
where=(rfldn != 0),
|
|
817
854
|
)
|
|
818
855
|
print("Difference =", np.max(diff_flux_down_diffuse))
|
|
819
856
|
print(
|
|
@@ -829,7 +866,7 @@ def _compare(results, mu_to_compare, reorder_mu, flux_up, flux_down, u=None):
|
|
|
829
866
|
diff_flux_down_direct,
|
|
830
867
|
rfldir,
|
|
831
868
|
out=np.zeros_like(diff_flux_down_direct),
|
|
832
|
-
where=rfldir
|
|
869
|
+
where=(rfldir != 0),
|
|
833
870
|
)
|
|
834
871
|
print("Difference =", np.max(diff_flux_down_direct))
|
|
835
872
|
print(
|
|
@@ -838,14 +875,15 @@ def _compare(results, mu_to_compare, reorder_mu, flux_up, flux_down, u=None):
|
|
|
838
875
|
)
|
|
839
876
|
print()
|
|
840
877
|
|
|
841
|
-
if u
|
|
878
|
+
if u is not None:
|
|
842
879
|
# Intensity
|
|
843
|
-
|
|
880
|
+
u_cache = u(tau_test_arr, phi_arr)[reorder_mu].reshape(np.shape(uu))
|
|
881
|
+
diff = np.abs(uu - u_cache)[mu_to_compare]
|
|
844
882
|
diff_ratio = np.divide(
|
|
845
883
|
diff,
|
|
846
884
|
uu[mu_to_compare],
|
|
847
885
|
out=np.zeros_like(diff),
|
|
848
|
-
where=uu[mu_to_compare]
|
|
886
|
+
where=(uu[mu_to_compare] != 0),
|
|
849
887
|
)
|
|
850
888
|
max_diff_tau_index = np.argmax(np.max(np.max(diff, axis=0), axis=1))
|
|
851
889
|
max_ratio_tau_index = np.argmax(np.max(np.max(diff_ratio, axis=0), axis=1))
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: PythonicDISORT
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.1
|
|
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
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
PythonicDISORT/__init__.py,sha256=V1obNzaFgqInxqYJ5h_r6JHbZRxx4VM5VgzCIS6EEzI,84
|
|
2
|
+
PythonicDISORT/_assemble_intensity_and_fluxes.py,sha256=H7XxaRBHNIxNZsB49onFcU1hAsBIFWCeTBJ4NhoCT4w,29926
|
|
3
|
+
PythonicDISORT/_solve_for_coeffs.py,sha256=Bb-C5OJt355x8_v8WFB2sJutBtSTAFNIX4OxLQJk9-0,16539
|
|
4
|
+
PythonicDISORT/_solve_for_gen_and_part_sols.py,sha256=NVAFve6FNIEiku4xqaXBAI4G2HYIbhjcLC_B0nhGXXM,13131
|
|
5
|
+
PythonicDISORT/pydisort.py,sha256=jiPMLw-zcwRoZQq2IjZhAxiuHlhC3yY72wvAxAepfgg,39113
|
|
6
|
+
PythonicDISORT/subroutines.py,sha256=rf36t8coXQdnMb0NrEfgrOWDWZHkkH6KDIE3COueEbQ,34034
|
|
7
|
+
pythonicdisort-1.1.dist-info/LICENSE.md,sha256=q1i1QVh0OLzK0fj6kaNRNWsM_KZca66JwWgWwbuCPlA,1092
|
|
8
|
+
pythonicdisort-1.1.dist-info/METADATA,sha256=boJu4nE6zzVbJrwuVJWv2M3PTQhJpoS87XeS9M8ki2U,8308
|
|
9
|
+
pythonicdisort-1.1.dist-info/WHEEL,sha256=iAkIy5fosb7FzIOwONchHf19Qu7_1wCWyFNR5gu9nU0,91
|
|
10
|
+
pythonicdisort-1.1.dist-info/top_level.txt,sha256=aX6kCeI1E7naZz3xfw4_mIbWh5KBh9dmF3FIvgP5m3Y,15
|
|
11
|
+
pythonicdisort-1.1.dist-info/RECORD,,
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
PythonicDISORT/__init__.py,sha256=V1obNzaFgqInxqYJ5h_r6JHbZRxx4VM5VgzCIS6EEzI,84
|
|
2
|
-
PythonicDISORT/_assemble_intensity_and_fluxes.py,sha256=M9mS2tD-GvMgze2MnHZEIarv7bpJsVe32fVPUEn0YpE,29911
|
|
3
|
-
PythonicDISORT/_solve_for_coeffs.py,sha256=Bb-C5OJt355x8_v8WFB2sJutBtSTAFNIX4OxLQJk9-0,16539
|
|
4
|
-
PythonicDISORT/_solve_for_gen_and_part_sols.py,sha256=_sPHgBTn58nOO0u13WCmCiDa6Qbv4HEu-7F_auFUcG4,13089
|
|
5
|
-
PythonicDISORT/pydisort.py,sha256=xeHeW_XcQwSwLYTwYr2tnBUPnu0RqSTrOppO2KEHiT8,38865
|
|
6
|
-
PythonicDISORT/subroutines.py,sha256=BFd0RqtmqzYF8J_ZE8KZB7GE5cl6ARHzbxqy0ewulbg,32517
|
|
7
|
-
pythonicdisort-1.0.2.dist-info/LICENSE.md,sha256=q1i1QVh0OLzK0fj6kaNRNWsM_KZca66JwWgWwbuCPlA,1092
|
|
8
|
-
pythonicdisort-1.0.2.dist-info/METADATA,sha256=-AEj3RRB4SbPh8aydWQtNmBlORzSEhjQ-kEhTjy9WBk,8310
|
|
9
|
-
pythonicdisort-1.0.2.dist-info/WHEEL,sha256=iAkIy5fosb7FzIOwONchHf19Qu7_1wCWyFNR5gu9nU0,91
|
|
10
|
-
pythonicdisort-1.0.2.dist-info/top_level.txt,sha256=aX6kCeI1E7naZz3xfw4_mIbWh5KBh9dmF3FIvgP5m3Y,15
|
|
11
|
-
pythonicdisort-1.0.2.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|