PythonicDISORT 0.6.2__py3-none-any.whl → 0.7.0__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_solution_functions.py → _assemble_intensity_and_fluxes.py} +97 -41
- PythonicDISORT/{_solve_for_coefs.py → _solve_for_coeffs.py} +105 -63
- PythonicDISORT/{_diagonalize.py → _solve_for_gen_and_part_sols.py} +52 -15
- PythonicDISORT/pydisort.py +111 -54
- PythonicDISORT/subroutines.py +49 -9
- {PythonicDISORT-0.6.2.dist-info → PythonicDISORT-0.7.0.dist-info}/METADATA +4 -4
- PythonicDISORT-0.7.0.dist-info/RECORD +11 -0
- PythonicDISORT-0.6.2.dist-info/RECORD +0 -11
- {PythonicDISORT-0.6.2.dist-info → PythonicDISORT-0.7.0.dist-info}/LICENSE.md +0 -0
- {PythonicDISORT-0.6.2.dist-info → PythonicDISORT-0.7.0.dist-info}/WHEEL +0 -0
- {PythonicDISORT-0.6.2.dist-info → PythonicDISORT-0.7.0.dist-info}/top_level.txt +0 -0
|
@@ -1,51 +1,107 @@
|
|
|
1
1
|
from PythonicDISORT.subroutines import _mathscr_v
|
|
2
|
-
from PythonicDISORT.
|
|
3
|
-
from PythonicDISORT.
|
|
2
|
+
from PythonicDISORT._solve_for_gen_and_part_sols import _solve_for_gen_and_part_sols
|
|
3
|
+
from PythonicDISORT._solve_for_coeffs import _solve_for_coeffs
|
|
4
4
|
|
|
5
5
|
import numpy as np
|
|
6
6
|
from math import pi
|
|
7
7
|
|
|
8
|
-
def
|
|
9
|
-
scaled_omega_arr,
|
|
10
|
-
tau_arr,
|
|
11
|
-
scaled_tau_arr_with_0,
|
|
12
|
-
mu_arr_pos, mu_arr,
|
|
13
|
-
M_inv, W,
|
|
14
|
-
N, NQuad, NLeg,
|
|
15
|
-
NLayers, NBDRF,
|
|
16
|
-
|
|
17
|
-
weighted_scaled_Leg_coeffs,
|
|
18
|
-
BDRF_Fourier_modes,
|
|
19
|
-
mu0, I0, I0_orig, phi0,
|
|
20
|
-
there_is_beam_source,
|
|
21
|
-
b_pos, b_neg,
|
|
22
|
-
b_pos_is_scalar, b_neg_is_scalar,
|
|
23
|
-
s_poly_coeffs,
|
|
24
|
-
Nscoeffs,
|
|
25
|
-
there_is_iso_source,
|
|
26
|
-
scale_tau,
|
|
27
|
-
only_flux,
|
|
28
|
-
|
|
29
|
-
|
|
8
|
+
def _assemble_intensity_and_fluxes(
|
|
9
|
+
scaled_omega_arr, # Delta-scaled single-scattering albedos
|
|
10
|
+
tau_arr, # Lower boundary of layers
|
|
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
|
|
14
|
+
N, NQuad, NLeg, # Number of 1) upper 2) both hemispheres quadrature nodes; 3) phase function Legendre coefficients
|
|
15
|
+
NFourier, NLayers, NBDRF, # Number of 1) intensity Fourier modes; 2) layers; 3) BDRF Fourier modes
|
|
16
|
+
is_atmos_multilayered, # Is the atmosphere multilayered?
|
|
17
|
+
weighted_scaled_Leg_coeffs, # Weighted and delta-scaled Legendre coefficients
|
|
18
|
+
BDRF_Fourier_modes, # BDRF Fourier modes
|
|
19
|
+
mu0, I0, I0_orig, phi0, # Properties of direct beam. If I0 was rescaled to 1, I0_orig is the original I0
|
|
20
|
+
there_is_beam_source, # Is there a beam source?
|
|
21
|
+
b_pos, b_neg, # Dirichlet BCs
|
|
22
|
+
b_pos_is_scalar, b_neg_is_scalar, # Is each Dirichlet BCs scalar (isotropic)?
|
|
23
|
+
s_poly_coeffs, # Polynomial coefficients of isotropic source
|
|
24
|
+
Nscoeffs, # Number of isotropic source polynomial coefficients
|
|
25
|
+
there_is_iso_source, # Is there an isotropic source?
|
|
26
|
+
scale_tau, # Delta-scale factor for tau
|
|
27
|
+
only_flux, # Only compute fluxes?
|
|
28
|
+
NLayers_to_use_sparse, # Number of layers above or equal which to use sparse matrices
|
|
29
|
+
_autograd_compatible, # Should the output functions be compatible with autograd?
|
|
30
30
|
):
|
|
31
|
-
"""
|
|
31
|
+
"""In this function the solution functions: intensity `u`, upward flux `flux_up`, downward flux `flux_down`
|
|
32
|
+
are assembled from the eigenpairs and the coefficients which have been solved from the boundary conditions.
|
|
33
|
+
These solution functions are then returned.
|
|
34
|
+
This function is wrapped by the `pydisort` function.
|
|
32
35
|
It should be called through `pydisort` and never directly.
|
|
33
|
-
It has many seemingly redundant arguments
|
|
34
|
-
|
|
36
|
+
It has many seemingly redundant arguments, which are described below,
|
|
37
|
+
to maximize precomputation in `pydisort`
|
|
38
|
+
These arguments are passed on to the `_solve_for_gen_and_part_sols` and `_solve_for_coeffs` functions
|
|
35
39
|
which this function wraps. See the Jupyter Notebook, especially section 3, for
|
|
36
40
|
documentation, explanation and derivation.
|
|
37
41
|
|
|
42
|
+
Arguments of _assemble_intensity_and_fluxes
|
|
43
|
+
| Variable | Type / Shape |
|
|
44
|
+
| ------------------------------ | ---------------------------------- |
|
|
45
|
+
| `scaled_omega_arr` | `NLayers` |
|
|
46
|
+
| `tau_arr` | `NLayers` |
|
|
47
|
+
| `scaled_tau_arr_with_0` | `NLayers + 1` |
|
|
48
|
+
| `mu_arr_pos` | `NQuad/2` |
|
|
49
|
+
| `mu_arr` | `NQuad` |
|
|
50
|
+
| `M_inv` | `NQuad/2` |
|
|
51
|
+
| `W` | `NQuad/2` |
|
|
52
|
+
| `N` | scalar |
|
|
53
|
+
| `NQuad` | scalar |
|
|
54
|
+
| `NLeg` | scalar |
|
|
55
|
+
| `NFourier` | scalar |
|
|
56
|
+
| `NLayers` | scalar |
|
|
57
|
+
| `NBDRF` | scalar |
|
|
58
|
+
| `is_atmos_multilayered` | boolean |
|
|
59
|
+
| `weighted_scaled_Leg_coeffs` | `NLayers x NLeg` |
|
|
60
|
+
| `BDRF_Fourier_modes` | `NBDRF` |
|
|
61
|
+
| `mu0` | scalar |
|
|
62
|
+
| `I0` | scalar |
|
|
63
|
+
| `I0_orig` | scalar |
|
|
64
|
+
| `phi0` | scalar |
|
|
65
|
+
| `there_is_beam_source` | scalar |
|
|
66
|
+
| `b_pos` | `NQuad/2 x NFourier` or scalar |
|
|
67
|
+
| `b_neg` | `NQuad/2 x NFourier` or scalar |
|
|
68
|
+
| `b_pos_is_scalar` | boolean |
|
|
69
|
+
| `b_neg_is_scalar` | boolean |
|
|
70
|
+
| `s_poly_coeffs` | `NLayers x Nscoeffs` or `Nscoeffs` |
|
|
71
|
+
| `Nscoeffs` | scalar |
|
|
72
|
+
| `there_is_iso_source` | boolean |
|
|
73
|
+
| `scale_tau` | `NLayers` |
|
|
74
|
+
| `only_flux` | boolean |
|
|
75
|
+
| `NLayers_to_use_sparse` | scalar |
|
|
76
|
+
| `_autograd_compatible` | boolean |
|
|
77
|
+
|
|
78
|
+
Notable internal variables of _assemble_intensity_and_fluxes
|
|
79
|
+
| Variable | Type / Shape |
|
|
80
|
+
| ----------------- | -------------------------------------- |
|
|
81
|
+
| `G_collect` | `NFourier x NLayers x NQuad x NQuad` |
|
|
82
|
+
| `G_collect_0` | `NLayers x NQuad x NQuad` |
|
|
83
|
+
| `G_inv_collect_0` | `NLayers x NQuad x NQuad` or `None` |
|
|
84
|
+
| `K_collect` | `NFourier x NLayers x NQuad` |
|
|
85
|
+
| `K_collect_0` | `NLayers x NQuad` |
|
|
86
|
+
| `B_collect` | `NFourier x NLayers x NQuad` or `None` |
|
|
87
|
+
| `B_collect_0` | `NLayers x NQuad` or `None` |
|
|
88
|
+
| `B_pos` | `NLayers x NQuad/2` or `None` |
|
|
89
|
+
| `B_neg` | `NLayers x NQuad/2` or `None` |
|
|
90
|
+
| `GC_collect` | `NFourier x NLayers x NQuad x NQuad` |
|
|
91
|
+
| `GC_collect_0` | `NLayers x NQuad x NQuad` |
|
|
92
|
+
| `GC_pos` | `NLayers x NQuad/2 x NQuad` |
|
|
93
|
+
| `GC_neg` | `NLayers x NQuad/2 x NQuad` |
|
|
38
94
|
"""
|
|
39
|
-
if
|
|
95
|
+
if _autograd_compatible:
|
|
40
96
|
import autograd.numpy as np
|
|
41
97
|
else:
|
|
42
98
|
import numpy as np
|
|
43
99
|
|
|
44
|
-
|
|
100
|
+
################################## Assemble uncorrected intensity and flux functions #######################################
|
|
45
101
|
|
|
46
102
|
# Compute all the necessary quantities
|
|
47
103
|
# --------------------------------------------------------------------------------------------------------------------------
|
|
48
|
-
outputs =
|
|
104
|
+
outputs = _solve_for_gen_and_part_sols(
|
|
49
105
|
NFourier,
|
|
50
106
|
scaled_omega_arr,
|
|
51
107
|
mu_arr_pos, mu_arr,
|
|
@@ -73,7 +129,7 @@ def _assemble_solution_functions(
|
|
|
73
129
|
G_inv_collect_0 = None
|
|
74
130
|
B_collect = None
|
|
75
131
|
|
|
76
|
-
GC_collect =
|
|
132
|
+
GC_collect = _solve_for_coeffs(
|
|
77
133
|
NFourier,
|
|
78
134
|
G_collect,
|
|
79
135
|
K_collect,
|
|
@@ -81,10 +137,10 @@ def _assemble_solution_functions(
|
|
|
81
137
|
G_inv_collect_0,
|
|
82
138
|
tau_arr,
|
|
83
139
|
scaled_tau_arr_with_0,
|
|
84
|
-
mu_arr_pos, mu_arr_pos * W,
|
|
140
|
+
mu_arr, mu_arr_pos, mu_arr_pos * W,
|
|
85
141
|
N, NQuad,
|
|
86
142
|
NLayers, NBDRF,
|
|
87
|
-
|
|
143
|
+
is_atmos_multilayered,
|
|
88
144
|
BDRF_Fourier_modes,
|
|
89
145
|
mu0, I0,
|
|
90
146
|
there_is_beam_source,
|
|
@@ -93,7 +149,7 @@ def _assemble_solution_functions(
|
|
|
93
149
|
s_poly_coeffs,
|
|
94
150
|
Nscoeffs,
|
|
95
151
|
there_is_iso_source,
|
|
96
|
-
|
|
152
|
+
NLayers_to_use_sparse,
|
|
97
153
|
)
|
|
98
154
|
|
|
99
155
|
G_collect_0 = G_collect[0, :, :, :]
|
|
@@ -103,7 +159,7 @@ def _assemble_solution_functions(
|
|
|
103
159
|
|
|
104
160
|
if not only_flux:
|
|
105
161
|
|
|
106
|
-
# Construct the intensity function
|
|
162
|
+
# Construct the intensity function (refer to Section 3.7 of the Comprehensive Documentation)
|
|
107
163
|
# --------------------------------------------------------------------------------------------------------------------------
|
|
108
164
|
def u(tau, phi, return_Fourier_error=False):
|
|
109
165
|
tau = np.atleast_1d(tau)
|
|
@@ -150,10 +206,10 @@ def _assemble_solution_functions(
|
|
|
150
206
|
K_collect_0,
|
|
151
207
|
G_inv_collect_0,
|
|
152
208
|
mu_arr,
|
|
153
|
-
|
|
209
|
+
_autograd_compatible,
|
|
154
210
|
)
|
|
155
211
|
|
|
156
|
-
if
|
|
212
|
+
if _autograd_compatible:
|
|
157
213
|
um = um + np.concatenate((_mathscr_v_contribution.T, np.zeros((NFourier - 1, len(tau), NQuad))))
|
|
158
214
|
else:
|
|
159
215
|
um[0, :, :] += _mathscr_v_contribution.T
|
|
@@ -245,7 +301,7 @@ def _assemble_solution_functions(
|
|
|
245
301
|
K_collect_0,
|
|
246
302
|
G_inv_collect_0,
|
|
247
303
|
mu_arr,
|
|
248
|
-
|
|
304
|
+
_autograd_compatible,
|
|
249
305
|
)
|
|
250
306
|
u0 += _mathscr_v_contribution
|
|
251
307
|
|
|
@@ -255,7 +311,7 @@ def _assemble_solution_functions(
|
|
|
255
311
|
return I0_orig * np.squeeze(u0)
|
|
256
312
|
# --------------------------------------------------------------------------------------------------------------------------
|
|
257
313
|
|
|
258
|
-
# Construct the flux functions
|
|
314
|
+
# Construct the flux functions (refer to Section 3.8 of the Comprehensive Documentation)
|
|
259
315
|
# --------------------------------------------------------------------------------------------------------------------------
|
|
260
316
|
GC_pos = GC_collect_0[:, :N, :]
|
|
261
317
|
GC_neg = GC_collect_0[:, N:, :]
|
|
@@ -291,7 +347,7 @@ def _assemble_solution_functions(
|
|
|
291
347
|
K_collect_0,
|
|
292
348
|
G_inv_collect_0,
|
|
293
349
|
mu_arr,
|
|
294
|
-
|
|
350
|
+
_autograd_compatible,
|
|
295
351
|
)[:N, :]
|
|
296
352
|
else:
|
|
297
353
|
_mathscr_v_contribution = 0
|
|
@@ -345,7 +401,7 @@ def _assemble_solution_functions(
|
|
|
345
401
|
K_collect_0,
|
|
346
402
|
G_inv_collect_0,
|
|
347
403
|
mu_arr,
|
|
348
|
-
|
|
404
|
+
_autograd_compatible,
|
|
349
405
|
)[N:, :]
|
|
350
406
|
else:
|
|
351
407
|
_mathscr_v_contribution = 0
|
|
@@ -6,38 +6,79 @@ import scipy as sc
|
|
|
6
6
|
from math import pi
|
|
7
7
|
|
|
8
8
|
|
|
9
|
-
def
|
|
10
|
-
NFourier,
|
|
11
|
-
G_collect,
|
|
12
|
-
K_collect,
|
|
13
|
-
B_collect,
|
|
14
|
-
G_inv_collect_0,
|
|
15
|
-
tau_arr,
|
|
16
|
-
scaled_tau_arr_with_0,
|
|
17
|
-
mu_arr_pos, mu_arr_pos_times_W,
|
|
18
|
-
N, NQuad,
|
|
19
|
-
NLayers, NBDRF,
|
|
20
|
-
|
|
21
|
-
BDRF_Fourier_modes,
|
|
22
|
-
mu0, I0,
|
|
23
|
-
there_is_beam_source,
|
|
24
|
-
b_pos, b_neg,
|
|
25
|
-
b_pos_is_scalar, b_neg_is_scalar,
|
|
26
|
-
s_poly_coeffs,
|
|
27
|
-
Nscoeffs,
|
|
28
|
-
there_is_iso_source,
|
|
29
|
-
|
|
9
|
+
def _solve_for_coeffs(
|
|
10
|
+
NFourier, # Number of intensity Fourier modes
|
|
11
|
+
G_collect, # Eigenvector matrices
|
|
12
|
+
K_collect, # Eigenvalues
|
|
13
|
+
B_collect, # Coefficients vectors for particular solutions
|
|
14
|
+
G_inv_collect_0, # Inverse of eigenvector matrix for the 0th Fourier mode
|
|
15
|
+
tau_arr, # Lower boundary of layers
|
|
16
|
+
scaled_tau_arr_with_0, # Delta-scaled lower boundary of layers with 0 inserted in front
|
|
17
|
+
mu_arr, mu_arr_pos, mu_arr_pos_times_W, # Quadrature nodes for 1) both 2) upper hemispheres; 3) upper hemisphere quadrature nodes times weights
|
|
18
|
+
N, NQuad, # Number of 1) upper 2) both hemispheres quadrature nodes
|
|
19
|
+
NLayers, NBDRF, # Number of 1) intensity Fourier modes; 2) layers
|
|
20
|
+
is_atmos_multilayered, # Is the atmosphere multilayered?
|
|
21
|
+
BDRF_Fourier_modes, # BDRF Fourier modes
|
|
22
|
+
mu0, I0, # Properties of direct beam
|
|
23
|
+
there_is_beam_source, # Is there a beam source?
|
|
24
|
+
b_pos, b_neg, # Dirichlet BCs
|
|
25
|
+
b_pos_is_scalar, b_neg_is_scalar, # Is each Dirichlet BCs scalar (isotropic)?
|
|
26
|
+
s_poly_coeffs, # Polynomial coefficients of isotropic source
|
|
27
|
+
Nscoeffs, # Number of isotropic source polynomial coefficients
|
|
28
|
+
there_is_iso_source, # Is there an isotropic source?
|
|
29
|
+
NLayers_to_use_sparse, # Number of layers above or equal which to use sparse matrices
|
|
30
30
|
):
|
|
31
|
-
"""
|
|
31
|
+
"""
|
|
32
|
+
In this function the unknown coefficients of the general solution to the system
|
|
33
|
+
of ODEs for each Fourier mode is solved using the boundary conditions
|
|
34
|
+
and the product of the coefficients and the eigenvectors is returned.
|
|
35
|
+
This function is wrapped by the `_assemble_intensity_and_fluxes` function.
|
|
32
36
|
It has many seemingly redundant arguments to maximize precomputation in the `pydisort` function.
|
|
33
37
|
See the Jupyter Notebook, especially section 3, for documentation, explanation and derivation.
|
|
34
38
|
The labels in this file reference labels in the Jupyter Notebook, especially sections 3 and 4.
|
|
35
39
|
|
|
40
|
+
Arguments of _solve_for_coeffs
|
|
41
|
+
| Variable | Type / Shape |
|
|
42
|
+
| ------------------------------ | -------------------------------------- |
|
|
43
|
+
| `NFourier` | scalar |
|
|
44
|
+
| `G_collect` | `NFourier x NLayers x NQuad x NQuad` |
|
|
45
|
+
| `K_collect` | `NFourier x NLayers x NQuad` |
|
|
46
|
+
| `B_collect` | `NFourier x NLayers x NQuad` or `None` |
|
|
47
|
+
| `G_inv_collect_0` | `NLayers x NQuad x NQuad` or `None` |
|
|
48
|
+
| `tau_arr` | `NLayers` |
|
|
49
|
+
| `scaled_tau_arr_with_0` | `NLayers + 1` |
|
|
50
|
+
| `mu_arr` | `NQuad` |
|
|
51
|
+
| `mu_arr_pos` | `NQuad/2` |
|
|
52
|
+
| `mu_arr_pos_times_W` | `NQuad/2` |
|
|
53
|
+
| `N` | scalar |
|
|
54
|
+
| `NQuad` | scalar |
|
|
55
|
+
| `NLayers` | scalar |
|
|
56
|
+
| `NBDRF` | scalar |
|
|
57
|
+
| `is_atmos_multilayered` | boolean |
|
|
58
|
+
| `BDRF_Fourier_modes` | `NBDRF` |
|
|
59
|
+
| `mu0` | scalar |
|
|
60
|
+
| `I0` | scalar |
|
|
61
|
+
| `there_is_beam_source` | boolean |
|
|
62
|
+
| `b_pos` | `NQuad/2 x NFourier` or scalar |
|
|
63
|
+
| `b_neg` | `NQuad/2 x NFourier` or scalar |
|
|
64
|
+
| `b_pos_is_scalar` | boolean |
|
|
65
|
+
| `b_neg_is_scalar` | boolean |
|
|
66
|
+
| `s_poly_coeffs` | `NLayers x Nscoeffs` or `Nscoeffs` |
|
|
67
|
+
| `Nscoeffs` | scalar |
|
|
68
|
+
| `there_is_iso_source` | boolean |
|
|
69
|
+
| `NLayers_to_use_sparse` | scalar |
|
|
70
|
+
|
|
71
|
+
Notable internal variables of _solve_for_coeffs
|
|
72
|
+
| Variable | Shape |
|
|
73
|
+
| ------------ | ------------------------------------ |
|
|
74
|
+
| `GC_collect` | `NFourier x NLayers x NQuad x NQuad` |
|
|
75
|
+
|
|
36
76
|
"""
|
|
37
77
|
################################## Solve for coefficients of homogeneous solution ##########################################
|
|
78
|
+
############# Refer to Section 3.6.2 (single-layer) and 4 (multi-layer) of the Comprehensive Documentation #################
|
|
38
79
|
|
|
39
80
|
GC_collect = np.empty((NFourier, NLayers, NQuad, NQuad))
|
|
40
|
-
use_sparse_framework = NLayers >=
|
|
81
|
+
use_sparse_framework = NLayers >= NLayers_to_use_sparse
|
|
41
82
|
|
|
42
83
|
# The following loops can easily be parallelized, but the speed-up is unlikely to be worth the overhead
|
|
43
84
|
for m in range(NFourier):
|
|
@@ -50,6 +91,7 @@ def _solve_for_coefs(
|
|
|
50
91
|
B_collect_m = B_collect[m, :, :]
|
|
51
92
|
|
|
52
93
|
# Generate mathscr_D and mathscr_X (BDRF terms)
|
|
94
|
+
# Just for this part, refer to Section 3.4.2 of the Comprehensive Documentation
|
|
53
95
|
# --------------------------------------------------------------------------------------------------------------------------
|
|
54
96
|
if BDRF_bool:
|
|
55
97
|
mathscr_D_neg = (1 + m_equals_0 * 1) * BDRF_Fourier_modes[m](mu_arr_pos, -mu_arr_pos)
|
|
@@ -92,7 +134,7 @@ def _solve_for_coefs(
|
|
|
92
134
|
).ravel()
|
|
93
135
|
|
|
94
136
|
_mathscr_v_contribution_middle = np.array([])
|
|
95
|
-
if
|
|
137
|
+
if is_atmos_multilayered:
|
|
96
138
|
indices = np.arange(NLayers - 1)
|
|
97
139
|
_mathscr_v_contribution_middle = (
|
|
98
140
|
_mathscr_v(
|
|
@@ -147,7 +189,7 @@ def _solve_for_coefs(
|
|
|
147
189
|
BDRF_RHS_contribution = 0
|
|
148
190
|
|
|
149
191
|
RHS_middle = np.array([])
|
|
150
|
-
if
|
|
192
|
+
if is_atmos_multilayered:
|
|
151
193
|
RHS_middle = np.array(
|
|
152
194
|
[
|
|
153
195
|
(B_collect_m[l + 1, :] - B_collect_m[l, :])
|
|
@@ -173,7 +215,7 @@ def _solve_for_coefs(
|
|
|
173
215
|
RHS = np.concatenate([b_neg_m, RHS_middle, b_pos_m]) + _mathscr_v_contribution
|
|
174
216
|
# --------------------------------------------------------------------------------------------------------------------------
|
|
175
217
|
|
|
176
|
-
# Assemble LHS
|
|
218
|
+
# Assemble LHS (much of this code is replicated in Section 4 of the Comprehensive Documentation)
|
|
177
219
|
dim = NLayers * NQuad
|
|
178
220
|
|
|
179
221
|
G_0_nn = G_collect_m[0, N:, :N]
|
|
@@ -193,8 +235,8 @@ def _solve_for_coefs(
|
|
|
193
235
|
BDRF_LHS_contribution_pos = 0
|
|
194
236
|
|
|
195
237
|
if use_sparse_framework:
|
|
196
|
-
|
|
197
|
-
density = 4 *
|
|
238
|
+
N_sq = N**2
|
|
239
|
+
density = 4 * N_sq * (2 * NLayers - 1)
|
|
198
240
|
row_indices = np.empty(density)
|
|
199
241
|
col_indices = np.empty(density)
|
|
200
242
|
block_rows = np.empty(density)
|
|
@@ -203,35 +245,35 @@ def _solve_for_coefs(
|
|
|
203
245
|
block_row_ind = np.arange(block_row_len).reshape(NQuad, 2 * NQuad)
|
|
204
246
|
block_row_sort = np.empty(block_row_len, dtype='int')
|
|
205
247
|
|
|
206
|
-
block_row_sort[:
|
|
207
|
-
block_row_sort[
|
|
208
|
-
block_row_sort[2 *
|
|
209
|
-
block_row_sort[4 *
|
|
210
|
-
block_row_sort[6 *
|
|
211
|
-
block_row_sort[7 *
|
|
248
|
+
block_row_sort[:N_sq] = block_row_ind[:N, :N].ravel()
|
|
249
|
+
block_row_sort[N_sq : 2 * N_sq] = block_row_ind[N : 2 * N, :N].ravel()
|
|
250
|
+
block_row_sort[2 * N_sq : 4 * N_sq] = block_row_ind[:2 * N, N : 2 * N].ravel()
|
|
251
|
+
block_row_sort[4 * N_sq : 6 * N_sq] = block_row_ind[:2 * N, 2 * N : 3 * N].ravel()
|
|
252
|
+
block_row_sort[6 * N_sq : 7 * N_sq] = block_row_ind[:N, 3 * N : 4 * N].ravel()
|
|
253
|
+
block_row_sort[7 * N_sq : 8 * N_sq] = block_row_ind[N : 2 * N, 3 * N : 4 * N].ravel()
|
|
212
254
|
|
|
213
255
|
# BCs for the entire atmosphere
|
|
214
|
-
row_indices[:
|
|
215
|
-
block_rows[:
|
|
256
|
+
row_indices[:N_sq], col_indices[:N_sq] = _nd_slice_to_indexes(np.s_[:N, :N])
|
|
257
|
+
block_rows[:N_sq] = G_0_nn.ravel()
|
|
216
258
|
(
|
|
217
|
-
row_indices[
|
|
218
|
-
col_indices[
|
|
259
|
+
row_indices[N_sq : 2 * N_sq],
|
|
260
|
+
col_indices[N_sq : 2 * N_sq],
|
|
219
261
|
) = _nd_slice_to_indexes(np.s_[:N, N:NQuad])
|
|
220
|
-
block_rows[
|
|
262
|
+
block_rows[N_sq : 2 * N_sq] = (
|
|
221
263
|
G_0_np * np.exp(K_collect_m[0, :N] * scaled_tau_arr_with_0[1])[None, :]
|
|
222
264
|
).ravel()
|
|
223
265
|
(
|
|
224
|
-
row_indices[2 *
|
|
225
|
-
col_indices[2 *
|
|
266
|
+
row_indices[2 * N_sq : 3 * N_sq],
|
|
267
|
+
col_indices[2 * N_sq : 3 * N_sq],
|
|
226
268
|
) = _nd_slice_to_indexes(np.s_[dim - N : dim, dim - NQuad : dim - N])
|
|
227
|
-
block_rows[2 *
|
|
269
|
+
block_rows[2 * N_sq : 3 * N_sq] = (
|
|
228
270
|
(G_L_pn - BDRF_LHS_contribution_neg) * E_Lm1L[None, :]
|
|
229
271
|
).ravel()
|
|
230
272
|
(
|
|
231
|
-
row_indices[3 *
|
|
232
|
-
col_indices[3 *
|
|
273
|
+
row_indices[3 * N_sq : 4 * N_sq],
|
|
274
|
+
col_indices[3 * N_sq : 4 * N_sq],
|
|
233
275
|
) = _nd_slice_to_indexes(np.s_[dim - N : dim, dim - N : dim])
|
|
234
|
-
block_rows[3 *
|
|
276
|
+
block_rows[3 * N_sq : 4 * N_sq] = (
|
|
235
277
|
G_L_pp - BDRF_LHS_contribution_pos
|
|
236
278
|
).ravel()
|
|
237
279
|
|
|
@@ -256,19 +298,19 @@ def _solve_for_coefs(
|
|
|
256
298
|
np.s_[N + l * NQuad : N + (l + 1) * NQuad, l * NQuad : (l + 2) * NQuad]
|
|
257
299
|
)
|
|
258
300
|
row_indices[
|
|
259
|
-
4 *
|
|
301
|
+
4 * N_sq + l * block_row_len : 4 * N_sq + (l + 1) * block_row_len
|
|
260
302
|
] = row_indices_l[block_row_sort]
|
|
261
303
|
col_indices[
|
|
262
|
-
4 *
|
|
304
|
+
4 * N_sq + l * block_row_len : 4 * N_sq + (l + 1) * block_row_len
|
|
263
305
|
] = col_indices_l[block_row_sort]
|
|
264
306
|
|
|
265
|
-
|
|
266
|
-
block_rows[
|
|
267
|
-
block_rows[
|
|
268
|
-
block_rows[
|
|
269
|
-
block_rows[
|
|
270
|
-
block_rows[
|
|
271
|
-
block_rows[
|
|
307
|
+
start_ind = 4 * N_sq + l * block_row_len
|
|
308
|
+
block_rows[start_ind : N_sq + start_ind] = (G_l_pn * E_lm1l[None, :]).ravel()
|
|
309
|
+
block_rows[start_ind + N_sq : 2 * N_sq + start_ind] = (G_l_nn * E_lm1l[None, :]).ravel()
|
|
310
|
+
block_rows[start_ind + 2 * N_sq : 4 * N_sq + start_ind] = G_l_ap.ravel()
|
|
311
|
+
block_rows[start_ind + 4 * N_sq : 6 * N_sq + start_ind] = -G_lp1_an.ravel()
|
|
312
|
+
block_rows[start_ind + 6 * N_sq : 7 * N_sq + start_ind] = -(G_lp1_pp * E_llp1[None, :]).ravel()
|
|
313
|
+
block_rows[start_ind + 7 * N_sq : 8 * N_sq + start_ind] = -(G_lp1_np * E_llp1[None, :]).ravel()
|
|
272
314
|
|
|
273
315
|
LHS = sc.sparse.coo_matrix(
|
|
274
316
|
(
|
|
@@ -284,7 +326,7 @@ def _solve_for_coefs(
|
|
|
284
326
|
# Solve the system
|
|
285
327
|
C_m = sc.sparse.linalg.spsolve(LHS.tocsr(), RHS).reshape(NLayers, NQuad)
|
|
286
328
|
|
|
287
|
-
else:
|
|
329
|
+
else:
|
|
288
330
|
LHS = np.zeros((dim, dim))
|
|
289
331
|
|
|
290
332
|
# BCs for the entire atmosphere
|
|
@@ -313,14 +355,14 @@ def _solve_for_coefs(
|
|
|
313
355
|
E_lm1l = np.exp(K_l_pos * (scaled_tau_arr_lm1 - scaled_tau_arr_l))
|
|
314
356
|
E_llp1 = np.exp(K_lp1_pos * (scaled_tau_arr_l - scaled_tau_arr_lp1))
|
|
315
357
|
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
LHS[
|
|
319
|
-
LHS[N +
|
|
320
|
-
LHS[
|
|
321
|
-
LHS[
|
|
322
|
-
LHS[
|
|
323
|
-
LHS[N +
|
|
358
|
+
start_row = N + l * NQuad
|
|
359
|
+
start_col = l * NQuad
|
|
360
|
+
LHS[start_row : N + start_row, start_col : N + start_col] = G_l_pn * E_lm1l[None, :]
|
|
361
|
+
LHS[N + start_row : 2 * N + start_row, start_col : N + start_col] = G_l_nn * E_lm1l[None, :]
|
|
362
|
+
LHS[start_row : 2 * N + start_row, N + start_col : 2 * N + start_col] = G_l_ap
|
|
363
|
+
LHS[start_row : 2 * N + start_row, 2 * N + start_col : 3 * N + start_col] = -G_lp1_an
|
|
364
|
+
LHS[start_row : N + start_row, 3 * N + start_col : 4 * N + start_col] = -G_lp1_pp * E_llp1[None, :]
|
|
365
|
+
LHS[N + start_row : 2 * N + start_row, 3 * N + start_col : 4 * N + start_col] = -G_lp1_np * E_llp1[None, :]
|
|
324
366
|
|
|
325
367
|
# Solve the system
|
|
326
368
|
C_m = np.linalg.solve(LHS, RHS).reshape(NLayers, NQuad)
|
|
@@ -3,26 +3,63 @@ import scipy as sc
|
|
|
3
3
|
from math import pi
|
|
4
4
|
|
|
5
5
|
|
|
6
|
-
def
|
|
7
|
-
NFourier,
|
|
8
|
-
scaled_omega_arr,
|
|
9
|
-
mu_arr_pos, mu_arr,
|
|
10
|
-
M_inv, W,
|
|
11
|
-
N, NQuad, NLeg,
|
|
12
|
-
NLayers,
|
|
13
|
-
weighted_scaled_Leg_coeffs,
|
|
14
|
-
mu0, I0,
|
|
15
|
-
there_is_beam_source,
|
|
16
|
-
Nscoeffs,
|
|
17
|
-
there_is_iso_source,
|
|
6
|
+
def _solve_for_gen_and_part_sols(
|
|
7
|
+
NFourier, # Number of intensity Fourier modes
|
|
8
|
+
scaled_omega_arr, # Delta-scaled single-scattering albedos
|
|
9
|
+
mu_arr_pos, mu_arr, # Quadrature nodes for 1) upper 2) both hemispheres
|
|
10
|
+
M_inv, W, # 1) 1 / mu; 2) quadrature weights for each hemisphere
|
|
11
|
+
N, NQuad, NLeg, # Number of 1) upper 2) both hemispheres quadrature nodes; 3) phase function Legendre coefficients
|
|
12
|
+
NLayers, # Number of layers
|
|
13
|
+
weighted_scaled_Leg_coeffs, # Weighted and delta-scaled Legendre coefficients
|
|
14
|
+
mu0, I0, # Properties of direct beam
|
|
15
|
+
there_is_beam_source, # Is there a beam source?
|
|
16
|
+
Nscoeffs, # Number of isotropic source polynomial coefficients
|
|
17
|
+
there_is_iso_source, # Is there an isotropic source?
|
|
18
18
|
):
|
|
19
|
-
"""
|
|
19
|
+
"""
|
|
20
|
+
In this function the coefficient matrix of the system of ODEs for each Fourier mode is diagonalized
|
|
21
|
+
and the eigenpairs are returned; the general solution to each system of ODEs is determined up to unknown coefficients.
|
|
22
|
+
The particular solutions to each system of ODEs is also determined and its coefficient vector is returned.
|
|
23
|
+
This function is wrapped by the `_assemble_intensity_and_fluxes` function.
|
|
20
24
|
It has many seemingly redundant arguments to maximize precomputation in the `pydisort` function.
|
|
21
25
|
See the Jupyter Notebook, especially section 3, for documentation, explanation and derivation.
|
|
22
26
|
The labels in this file reference labels in the Jupyter Notebook, especially sections 3 and 4.
|
|
23
27
|
|
|
28
|
+
Arguments of _solve_for_gen_and_part_sols
|
|
29
|
+
| Variable | Type / Shape |
|
|
30
|
+
| ------------------------------ | ---------------------------------- |
|
|
31
|
+
| `NFourier` | scalar |
|
|
32
|
+
| `scaled_omega_arr` | `NLayers` |
|
|
33
|
+
| `mu_arr_pos` | `NQuad/2` |
|
|
34
|
+
| `mu_arr` | `NQuad` |
|
|
35
|
+
| `M_inv` | `NQuad/2` |
|
|
36
|
+
| `W` | `NQuad/2` |
|
|
37
|
+
| `N` | scalar |
|
|
38
|
+
| `NQuad` | scalar |
|
|
39
|
+
| `NLeg` | scalar |
|
|
40
|
+
| `NLayers` | scalar |
|
|
41
|
+
| `weighted_scaled_Leg_coeffs` | `NLayers x NLeg` |
|
|
42
|
+
| `mu0` | scalar |
|
|
43
|
+
| `I0` | scalar |
|
|
44
|
+
| `there_is_beam_source` | boolean |
|
|
45
|
+
| `Nscoeffs` | scalar |
|
|
46
|
+
| `there_is_iso_source` | boolean |
|
|
47
|
+
|
|
48
|
+
Notable internal variables of _solve_for_gen_and_part_sols
|
|
49
|
+
| Variable | Type / Shape |
|
|
50
|
+
| ----------------- | -------------------------------------- |
|
|
51
|
+
| `ells_all` | `NLeg` |
|
|
52
|
+
| `G_collect` | `NFourier*NLayers x NQuad x NQuad` | Reshaped to NFourier x NLayers x NQuad x NQuad
|
|
53
|
+
| `K_collect` | `NFourier*NLayers x NQuad` | Reshaped to NFourier x NLayers x NQuad
|
|
54
|
+
| `alpha_arr` | `NFourier*NLayers x NQuad/2 x NQuad/2` | Reshaped to NFourier x NLayers x NQuad/2 x NQuad/2
|
|
55
|
+
| `beta_arr` | `NFourier*NLayers x NQuad/2 x NQuad/2` | Reshaped to NFourier x NLayers x NQuad/2 x NQuad/2
|
|
56
|
+
| `X_tilde_arr` | `NFourier*NLayers x NQuad` | Reshaped to NFourier x NLayers x NQuad
|
|
57
|
+
| `B_collect` | `NFourier*NLayers x NQuad` or `None` | Reshaped to NFourier x NLayers x NQuad
|
|
58
|
+
| `G_inv_collect_0` | `NLayers x NQuad x NQuad` or `None` |
|
|
59
|
+
|
|
24
60
|
"""
|
|
25
61
|
############################### Assemble system and diagonalize coefficient matrix #########################################
|
|
62
|
+
########################### Refer to Section 3.4.2 of the Comprehensive Documentation #####################################
|
|
26
63
|
|
|
27
64
|
# Initialization
|
|
28
65
|
# --------------------------------------------------------------------------------------------------------------------------
|
|
@@ -116,7 +153,7 @@ def _diagonalize(
|
|
|
116
153
|
|
|
117
154
|
if len(no_shortcut_indices) > 0:
|
|
118
155
|
|
|
119
|
-
# Diagonalization of coefficient matrix
|
|
156
|
+
# Diagonalization of coefficient matrix (refer to Section 3.4.2 of the Comprehensive Documentation)
|
|
120
157
|
# --------------------------------------------------------------------------------------------------------------------------
|
|
121
158
|
alpha_arr = alpha_arr[: len(no_shortcut_indices), :, :]
|
|
122
159
|
beta_arr = beta_arr[: len(no_shortcut_indices), :, :]
|
|
@@ -153,7 +190,7 @@ def _diagonalize(
|
|
|
153
190
|
G_inv_collect_0[no_shortcut_indices_0, :, :] = G_inv_arr[: len(no_shortcut_indices_0), :, :]
|
|
154
191
|
# --------------------------------------------------------------------------------------------------------------------------
|
|
155
192
|
|
|
156
|
-
# Particular solution for the sunbeam source
|
|
193
|
+
# Particular solution for the sunbeam source (refer to Section 3.6.1 of the Comprehensive Documentation)
|
|
157
194
|
# --------------------------------------------------------------------------------------------------------------------------
|
|
158
195
|
if there_is_beam_source:
|
|
159
196
|
X_tilde_arr = X_tilde_arr[: len(no_shortcut_indices), :]
|
PythonicDISORT/pydisort.py
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
from PythonicDISORT import subroutines
|
|
2
|
-
from PythonicDISORT.
|
|
2
|
+
from PythonicDISORT._assemble_intensity_and_fluxes import _assemble_intensity_and_fluxes
|
|
3
3
|
|
|
4
4
|
import numpy as np
|
|
5
5
|
import scipy as sc
|
|
@@ -22,8 +22,8 @@ def pydisort(
|
|
|
22
22
|
NT_cor=False,
|
|
23
23
|
BDRF_Fourier_modes=[],
|
|
24
24
|
s_poly_coeffs=np.array([[]]),
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
NLayers_to_use_sparse=13,
|
|
26
|
+
_autograd_compatible = False,
|
|
27
27
|
):
|
|
28
28
|
"""Solves the 1D RTE for the fluxes, and optionally intensity,
|
|
29
29
|
of a multi-layer atmosphere with the specified optical properties, boundary conditions
|
|
@@ -37,14 +37,15 @@ def pydisort(
|
|
|
37
37
|
|
|
38
38
|
Parameters
|
|
39
39
|
----------
|
|
40
|
-
tau_arr : array
|
|
40
|
+
tau_arr : array or float
|
|
41
41
|
Optical depth of the lower boundary of each atmospheric layer.
|
|
42
|
-
omega_arr : array
|
|
42
|
+
omega_arr : array or float
|
|
43
43
|
Single-scattering albedo of each atmospheric layer.
|
|
44
44
|
NQuad : int
|
|
45
45
|
Number of `mu` quadrature nodes.
|
|
46
|
-
Leg_coeffs_all :
|
|
47
|
-
All available unweighted phase function Legendre coefficients.
|
|
46
|
+
Leg_coeffs_all : 2darray
|
|
47
|
+
All available unweighted phase function Legendre coefficients.
|
|
48
|
+
Each row of coefficients pertain to an atmospheric layer.
|
|
48
49
|
Each coefficient should be between 0 and 1 inclusive.
|
|
49
50
|
mu0 : float
|
|
50
51
|
Cosine of polar angle of the incident beam.
|
|
@@ -53,9 +54,10 @@ def pydisort(
|
|
|
53
54
|
phi0 : float
|
|
54
55
|
Azimuthal angle of the incident beam.
|
|
55
56
|
NLeg : optional, int
|
|
56
|
-
Number of phase function Legendre coefficients
|
|
57
|
+
Number of phase function Legendre coefficients
|
|
58
|
+
to use in the pre-correction solver.
|
|
57
59
|
NFourier : optional, int
|
|
58
|
-
Number of Fourier modes to use
|
|
60
|
+
Number of Fourier modes to use to construct the intensity function.
|
|
59
61
|
b_pos : optional, 2darray or float
|
|
60
62
|
Dirichlet boundary condition for the upward direction.
|
|
61
63
|
b_neg : optional, 2darray or float
|
|
@@ -72,33 +74,80 @@ def pydisort(
|
|
|
72
74
|
s_poly_coeffs : optional, array
|
|
73
75
|
Polynomial coefficients of isotropic internal sources.
|
|
74
76
|
Arrange coefficients from lowest order term to highest.
|
|
75
|
-
|
|
77
|
+
NLayers_to_use_sparse : optional, int
|
|
76
78
|
At or above how many atmospheric layers should SciPy's sparse matrix framework be used?
|
|
77
79
|
|
|
78
80
|
Returns
|
|
79
81
|
-------
|
|
80
|
-
array
|
|
82
|
+
mu_arr : array
|
|
81
83
|
All `mu` (cosine of polar angle) quadrature nodes.
|
|
82
|
-
function
|
|
84
|
+
Fp(tau) : function, function
|
|
83
85
|
(Energetic) Flux function with argument `tau` (type: array) for positive (upward) `mu` values.
|
|
84
86
|
Returns the diffuse flux magnitudes (type: array).
|
|
85
|
-
function
|
|
87
|
+
Fm(tau) : function
|
|
86
88
|
(Energetic) Flux function with argument `tau` (type: array) for negative (downward) `mu` values.
|
|
87
89
|
Returns a tuple of the diffuse and direct flux magnitudes respectively (type: (array, array)).
|
|
88
|
-
function
|
|
90
|
+
u0(tau) : function
|
|
89
91
|
Zeroth Fourier mode of the intensity with argument `tau` (type: array).
|
|
90
92
|
Returns an ndarray with axes corresponding to variation with `mu` and `tau` respectively.
|
|
91
93
|
This function is useful for calculating actinic fluxes and other quantities of interest,
|
|
92
94
|
but reclassification of delta-scaled flux and other corrections must be done manually
|
|
93
95
|
(for actinic flux `generate_diff_act_flux_funcs` will automatically perform the reclassification).
|
|
94
|
-
function, optional
|
|
96
|
+
u(tau, phi) : function, optional
|
|
95
97
|
Intensity function with arguments `(tau, phi, return_Fourier_error=False)` of types `(array, array, bool)`.
|
|
96
98
|
Returns an ndarray with axes corresponding to variation with `mu, tau, phi` respectively.
|
|
97
99
|
The optional flag `return_Fourier_error` determines whether the function will also return
|
|
98
100
|
the Cauchy / Fourier convergence evaluation (type: float) for the last Fourier term.
|
|
99
101
|
|
|
100
102
|
"""
|
|
101
|
-
|
|
103
|
+
|
|
104
|
+
"""
|
|
105
|
+
Arguments of pydisort
|
|
106
|
+
| Variable | Type / Shape |
|
|
107
|
+
| ----------------------- | ---------------------------------- |
|
|
108
|
+
| `tau_arr` | `NLayers` |
|
|
109
|
+
| `omega_arr` | `NLayers` |
|
|
110
|
+
| `NQuad` | scalar |
|
|
111
|
+
| `Leg_coeffs_all` | `NLeg_all` |
|
|
112
|
+
| `mu0` | scalar |
|
|
113
|
+
| `I0` | scalar |
|
|
114
|
+
| `phi0` | scalar |
|
|
115
|
+
| `NLeg` | scalar |
|
|
116
|
+
| `NFourier` | scalar |
|
|
117
|
+
| `b_pos` | `NQuad/2 x NFourier` or scalar |
|
|
118
|
+
| `b_neg` | `NQuad/2 x NFourier` or scalar |
|
|
119
|
+
| `only_flux` | boolean |
|
|
120
|
+
| `f_arr` | `NLayers` or scalar |
|
|
121
|
+
| `NT_cor` | boolean |
|
|
122
|
+
| `BDRF_Fourier_modes` | `NBDRF` |
|
|
123
|
+
| `s_poly_coeffs` | `NLayers x Nscoeffs` or `Nscoeffs` |
|
|
124
|
+
| `NLayers_to_use_sparse` | scalar |
|
|
125
|
+
|
|
126
|
+
Notable internal variables of pydisort
|
|
127
|
+
| Variable | Type / Shape |
|
|
128
|
+
| ---------------------------- | -------------------- |
|
|
129
|
+
| `I0_orig` | scalar |
|
|
130
|
+
| `thickness_arr` | `NLayers` |
|
|
131
|
+
| `weighted_Leg_coeffs_all` | `NLayers x NLeg_all` |
|
|
132
|
+
| `Leg_coeffs` | `NLayers x NLeg` |
|
|
133
|
+
| `weighted_scaled_Leg_coeffs` | `NLayers x NLeg` |
|
|
134
|
+
| `mu_arr_pos` | `NQuad/2` |
|
|
135
|
+
| `W` | `NQuad/2` |
|
|
136
|
+
| `mu_arr` | `NQuad` |
|
|
137
|
+
| `M_inv` | `NQuad/2` |
|
|
138
|
+
| `scale_tau` | `NLayers` |
|
|
139
|
+
| `scaled_tau_arr_with_0` | `NLayers + 1` |
|
|
140
|
+
| `scaled_omega_arr` | `NLayers` |
|
|
141
|
+
| `sum1` | scalar |
|
|
142
|
+
| `omega_avg` | scalar |
|
|
143
|
+
| `sum2` | scalar |
|
|
144
|
+
| `f_avg` | scalar |
|
|
145
|
+
| `Leg_coeffs_residue` | `NLayers x NLeg_all` |
|
|
146
|
+
| `Leg_coeffs_residue_avg` | `NLeg_all` |
|
|
147
|
+
| `scaled_mu0` | scalar |
|
|
148
|
+
"""
|
|
149
|
+
|
|
150
|
+
if _autograd_compatible:
|
|
102
151
|
import autograd.numpy as np
|
|
103
152
|
else:
|
|
104
153
|
import numpy as np
|
|
@@ -134,10 +183,10 @@ def pydisort(
|
|
|
134
183
|
N = NQuad // 2
|
|
135
184
|
there_is_beam_source = I0 > 0
|
|
136
185
|
there_is_iso_source = Nscoeffs > 0
|
|
137
|
-
|
|
186
|
+
is_atmos_multilayered = NLayers > 1
|
|
138
187
|
# --------------------------------------------------------------------------------------------------------------------------
|
|
139
188
|
|
|
140
|
-
# Input checks
|
|
189
|
+
# Input checks (refer to Section 1 of the Comprehensive Documentation)
|
|
141
190
|
# --------------------------------------------------------------------------------------------------------------------------
|
|
142
191
|
# Optical depths and thickness must be positive
|
|
143
192
|
assert np.all(tau_arr > 0)
|
|
@@ -183,7 +232,7 @@ def pydisort(
|
|
|
183
232
|
# The fractional scattering must be between 0 and 1
|
|
184
233
|
assert np.all(0 <= f_arr) and np.all(f_arr <= 1)
|
|
185
234
|
# The minimum threshold is the minimum numbers of layers: 1
|
|
186
|
-
assert(
|
|
235
|
+
assert(NLayers_to_use_sparse >= 1)
|
|
187
236
|
# --------------------------------------------------------------------------------------------------------------------------
|
|
188
237
|
|
|
189
238
|
# Some more setup
|
|
@@ -191,6 +240,7 @@ def pydisort(
|
|
|
191
240
|
NBDRF = len(BDRF_Fourier_modes)
|
|
192
241
|
weighted_Leg_coeffs_all = (2 * np.arange(NLeg_all) + 1) * Leg_coeffs_all
|
|
193
242
|
Leg_coeffs = Leg_coeffs_all[:, :NLeg]
|
|
243
|
+
# The following is explained in Section 1.4 of the Comprehensive Documentation
|
|
194
244
|
if (b_pos_is_scalar and b_pos == 0) and (b_neg_is_scalar and b_neg == 0) and not there_is_iso_source and there_is_beam_source:
|
|
195
245
|
I0_orig = I0
|
|
196
246
|
I0 = 1
|
|
@@ -198,7 +248,7 @@ def pydisort(
|
|
|
198
248
|
I0_orig = 1
|
|
199
249
|
# --------------------------------------------------------------------------------------------------------------------------
|
|
200
250
|
|
|
201
|
-
# Generation of
|
|
251
|
+
# Generation of "double-Gauss" quadrature weights and points (refer to Section 3.4 of the Comprehensive Documentation)
|
|
202
252
|
# --------------------------------------------------------------------------------------------------------------------------
|
|
203
253
|
# For positive mu values (the weights are identical for both domains)
|
|
204
254
|
mu_arr_pos, W = subroutines.Gauss_Legendre_quad(N) # mu_arr_neg = -mu_arr_pos
|
|
@@ -210,6 +260,7 @@ def pydisort(
|
|
|
210
260
|
# --------------------------------------------------------------------------------------------------------------------------
|
|
211
261
|
|
|
212
262
|
# Delta-M scaling; there is no scaling if f = 0
|
|
263
|
+
# Refer to Sections 1.3.1 and 3.3 of the Comprehensive Documentation
|
|
213
264
|
# --------------------------------------------------------------------------------------------------------------------------
|
|
214
265
|
if np.any(f_arr > 0):
|
|
215
266
|
scale_tau = 1 - omega_arr * f_arr
|
|
@@ -231,18 +282,19 @@ def pydisort(
|
|
|
231
282
|
|
|
232
283
|
if NT_cor and not only_flux and there_is_beam_source and np.any(f_arr > 0) and NLeg < NLeg_all:
|
|
233
284
|
|
|
234
|
-
############################### Perform NT corrections on the intensity but not the flux
|
|
285
|
+
############################### Perform NT corrections on the intensity but not the flux ###############################
|
|
286
|
+
############################### Refer to Section 3.7.2 of the Comprehensive Documentation ##############################
|
|
235
287
|
|
|
236
288
|
# Delta-M scaled solution; no further corrections to the flux
|
|
237
|
-
flux_up, flux_down, u0, u_star =
|
|
289
|
+
flux_up, flux_down, u0, u_star = _assemble_intensity_and_fluxes(
|
|
238
290
|
scaled_omega_arr,
|
|
239
291
|
tau_arr,
|
|
240
292
|
scaled_tau_arr_with_0,
|
|
241
293
|
mu_arr_pos, mu_arr,
|
|
242
294
|
M_inv, W,
|
|
243
|
-
N, NQuad, NLeg,
|
|
244
|
-
NLayers, NBDRF,
|
|
245
|
-
|
|
295
|
+
N, NQuad, NLeg,
|
|
296
|
+
NFourier, NLayers, NBDRF,
|
|
297
|
+
is_atmos_multilayered,
|
|
246
298
|
weighted_scaled_Leg_coeffs,
|
|
247
299
|
BDRF_Fourier_modes,
|
|
248
300
|
mu0, I0, I0_orig, phi0,
|
|
@@ -254,8 +306,8 @@ def pydisort(
|
|
|
254
306
|
there_is_iso_source,
|
|
255
307
|
scale_tau,
|
|
256
308
|
only_flux,
|
|
257
|
-
|
|
258
|
-
|
|
309
|
+
NLayers_to_use_sparse,
|
|
310
|
+
_autograd_compatible,
|
|
259
311
|
)
|
|
260
312
|
|
|
261
313
|
# TMS correction
|
|
@@ -324,16 +376,25 @@ def pydisort(
|
|
|
324
376
|
# TODO: Despite being vectorized and despite many attempts at further optimization,
|
|
325
377
|
# this block of code is slower than desired and is the bottleneck for the TMS correction.
|
|
326
378
|
# --------------------------------------------------------------------------------------------------------------------------
|
|
327
|
-
|
|
379
|
+
solution = (
|
|
380
|
+
mathscr_B[:, l, :] * np.vstack((TMS_correction_pos, TMS_correction_neg))[:, :, None]
|
|
381
|
+
)
|
|
382
|
+
|
|
383
|
+
if is_atmos_multilayered:
|
|
328
384
|
layers_arr = np.arange(NLayers)[:, None]
|
|
329
385
|
pos_contribution_mask = (l[None, :] < layers_arr).ravel()
|
|
330
386
|
neg_contribution_mask = (l[None, :] > layers_arr).ravel()
|
|
387
|
+
any_pos_contribution = np.any(pos_contribution_mask)
|
|
388
|
+
any_neg_contribution = np.any(neg_contribution_mask)
|
|
389
|
+
|
|
390
|
+
if not (any_pos_contribution or any_neg_contribution):
|
|
391
|
+
return solution
|
|
331
392
|
|
|
332
393
|
layers_arr_repeat = np.repeat(layers_arr, Ntau)
|
|
333
394
|
scaled_tau_tile = np.tile(scaled_tau, NLayers)
|
|
334
395
|
scaled_tau_arr_with_0_repeat = np.repeat(scaled_tau_arr_with_0, Ntau)
|
|
335
396
|
|
|
336
|
-
if
|
|
397
|
+
if any_pos_contribution:
|
|
337
398
|
contribution_from_each_other_layer_pos = np.zeros((N, NLayers * Ntau, Nphi))
|
|
338
399
|
scaled_tau_l_tile_pos = scaled_tau_tile[pos_contribution_mask]
|
|
339
400
|
mathscr_B_l_repeat_posmasked = mathscr_B[
|
|
@@ -365,7 +426,7 @@ def pydisort(
|
|
|
365
426
|
contribution_from_each_other_layer_pos.reshape((N, NLayers, Ntau, Nphi)),
|
|
366
427
|
axis=1,
|
|
367
428
|
)
|
|
368
|
-
if
|
|
429
|
+
if any_neg_contribution:
|
|
369
430
|
contribution_from_each_other_layer_neg = np.zeros((N, NLayers * Ntau, Nphi))
|
|
370
431
|
scaled_tau_l_tile_neg = scaled_tau_tile[neg_contribution_mask]
|
|
371
432
|
mathscr_B_l_repeat_negmasked = mathscr_B[
|
|
@@ -398,30 +459,26 @@ def pydisort(
|
|
|
398
459
|
axis=1,
|
|
399
460
|
)
|
|
400
461
|
|
|
401
|
-
if
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
solution
|
|
407
|
-
solution[N:, :, :] += contribution_from_other_layers_neg
|
|
408
|
-
return solution
|
|
409
|
-
|
|
410
|
-
else:
|
|
411
|
-
return mathscr_B[:, l, :] * np.vstack((TMS_correction_pos, TMS_correction_neg))[
|
|
412
|
-
:, :, None
|
|
413
|
-
] + np.concatenate(
|
|
462
|
+
if _autograd_compatible:
|
|
463
|
+
if not any_pos_contribution:
|
|
464
|
+
TMS_correction_pos = np.zeros((N, Ntau, Nphi))
|
|
465
|
+
if not any_neg_contribution:
|
|
466
|
+
TMS_correction_neg = np.zeros((N, Ntau, Nphi))
|
|
467
|
+
return solution + np.concatenate(
|
|
414
468
|
(contribution_from_other_layers_pos, contribution_from_other_layers_neg),
|
|
415
469
|
axis=0,
|
|
416
470
|
)
|
|
471
|
+
else:
|
|
472
|
+
if any_pos_contribution:
|
|
473
|
+
solution[:N, :, :] += contribution_from_other_layers_pos
|
|
474
|
+
if any_neg_contribution:
|
|
475
|
+
solution[N:, :, :] += contribution_from_other_layers_neg
|
|
476
|
+
return solution
|
|
417
477
|
|
|
418
478
|
# --------------------------------------------------------------------------------------------------------------------------
|
|
419
479
|
|
|
420
480
|
else:
|
|
421
|
-
return
|
|
422
|
-
mathscr_B[:, l, :]
|
|
423
|
-
* np.vstack((TMS_correction_pos, TMS_correction_neg))[:, :, None]
|
|
424
|
-
)
|
|
481
|
+
return solution
|
|
425
482
|
# --------------------------------------------------------------------------------------------------------------------------
|
|
426
483
|
|
|
427
484
|
# IMS correction
|
|
@@ -466,7 +523,7 @@ def pydisort(
|
|
|
466
523
|
phi = np.atleast_1d(phi)
|
|
467
524
|
NT_corrections = TMS_correction(tau, phi)
|
|
468
525
|
|
|
469
|
-
if
|
|
526
|
+
if _autograd_compatible:
|
|
470
527
|
NT_corrections = NT_corrections + np.concatenate(
|
|
471
528
|
[np.zeros((N, len(tau), len(phi))), IMS_correction(tau, phi)], axis=0
|
|
472
529
|
)
|
|
@@ -488,15 +545,15 @@ def pydisort(
|
|
|
488
545
|
else:
|
|
489
546
|
if only_flux:
|
|
490
547
|
NFourier = 1 # We only need to solve for the 0th Fourier mode to compute the flux
|
|
491
|
-
return (mu_arr,) +
|
|
548
|
+
return (mu_arr,) + _assemble_intensity_and_fluxes(
|
|
492
549
|
scaled_omega_arr,
|
|
493
550
|
tau_arr,
|
|
494
551
|
scaled_tau_arr_with_0,
|
|
495
552
|
mu_arr_pos, mu_arr,
|
|
496
553
|
M_inv, W,
|
|
497
|
-
N, NQuad, NLeg,
|
|
498
|
-
NLayers, NBDRF,
|
|
499
|
-
|
|
554
|
+
N, NQuad, NLeg,
|
|
555
|
+
NFourier, NLayers, NBDRF,
|
|
556
|
+
is_atmos_multilayered,
|
|
500
557
|
weighted_scaled_Leg_coeffs,
|
|
501
558
|
BDRF_Fourier_modes,
|
|
502
559
|
mu0, I0, I0_orig, phi0,
|
|
@@ -508,6 +565,6 @@ def pydisort(
|
|
|
508
565
|
there_is_iso_source,
|
|
509
566
|
scale_tau,
|
|
510
567
|
only_flux,
|
|
511
|
-
|
|
512
|
-
|
|
568
|
+
NLayers_to_use_sparse,
|
|
569
|
+
_autograd_compatible,
|
|
513
570
|
)
|
PythonicDISORT/subroutines.py
CHANGED
|
@@ -4,7 +4,7 @@ from math import pi
|
|
|
4
4
|
from numpy.polynomial.legendre import leggauss
|
|
5
5
|
|
|
6
6
|
|
|
7
|
-
def transform_interval(arr, c, d, a
|
|
7
|
+
def transform_interval(arr, c, d, a, b):
|
|
8
8
|
"""Affine transformation of an array from interval [a, b] to [c, d].
|
|
9
9
|
|
|
10
10
|
Parameters
|
|
@@ -29,7 +29,7 @@ def transform_interval(arr, c, d, a=-1, b=1):
|
|
|
29
29
|
return (((arr - a) * (d - c)) / (b - a)) + c
|
|
30
30
|
|
|
31
31
|
|
|
32
|
-
def transform_weights(weights, c, d, a
|
|
32
|
+
def transform_weights(weights, c, d, a, b):
|
|
33
33
|
"""Transforms an array of quadrature weights from interval [a, b] to [c, d].
|
|
34
34
|
|
|
35
35
|
Parameters
|
|
@@ -106,7 +106,7 @@ def Gauss_Legendre_quad(N, c=0, d=1):
|
|
|
106
106
|
"""
|
|
107
107
|
mu_arr_pos, W = leggauss(int(N))
|
|
108
108
|
|
|
109
|
-
return transform_interval(mu_arr_pos, c, d), transform_weights(W, c, d)
|
|
109
|
+
return transform_interval(mu_arr_pos, c, d, -1, 1), transform_weights(W, c, d, -1, 1)
|
|
110
110
|
|
|
111
111
|
|
|
112
112
|
def Clenshaw_Curtis_quad(Nphi, c=0, d=(2 * pi)):
|
|
@@ -142,7 +142,7 @@ def Clenshaw_Curtis_quad(Nphi, c=0, d=(2 * pi)):
|
|
|
142
142
|
weights_phi_pos[0] /= 2
|
|
143
143
|
full_weights_phi = np.hstack((weights_phi_pos, np.flip(weights_phi_pos[:-1])))
|
|
144
144
|
|
|
145
|
-
return transform_interval(phi_arr, c, d), transform_weights(full_weights_phi, c, d)
|
|
145
|
+
return transform_interval(phi_arr, c, d, -1, 1), transform_weights(full_weights_phi, c, d, -1, 1)
|
|
146
146
|
|
|
147
147
|
|
|
148
148
|
def generate_FD_mat(Ntau, a, b):
|
|
@@ -256,18 +256,58 @@ def generate_diff_act_flux_funcs(u0):
|
|
|
256
256
|
return flux_act_up, flux_act_down_diffuse
|
|
257
257
|
|
|
258
258
|
|
|
259
|
-
def _mathscr_v(tau,
|
|
259
|
+
def _mathscr_v(tau, # Input optical depths
|
|
260
|
+
l, # Layer index of each input optical depth
|
|
261
|
+
s_poly_coeffs, # Polynomial coefficients of isotropic source
|
|
262
|
+
Nscoeffs, # Number of isotropic source polynomial coefficients
|
|
263
|
+
G, # Eigenvector matrices
|
|
264
|
+
K, # Eigenvalues
|
|
265
|
+
G_inv, # Inverse of eigenvector matrix
|
|
266
|
+
mu_arr, # Quadrature nodes for both hemispheres
|
|
267
|
+
_autograd_compatible=False # Should the output functions be compatible with autograd?
|
|
268
|
+
):
|
|
260
269
|
"""Particular solution for isotropic internal sources.
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
270
|
+
Refer to Section 3.6.1 of the Comprehensive Documentation.
|
|
271
|
+
It has many seemingly redundant arguments to maximize
|
|
272
|
+
precomputation in the `_assemble_intensity_and_fluxes`
|
|
273
|
+
and `_solve_for_coeffs` functions which call it.
|
|
274
|
+
|
|
275
|
+
Arguments of _mathscr_v
|
|
276
|
+
| Variable | Shape |
|
|
277
|
+
| ---------------------- | ------------------------------------- |
|
|
278
|
+
| `tau` | `Ntau` |
|
|
279
|
+
| `l` | `Ntau` |
|
|
280
|
+
| `s_poly_coeffs` | `NLayers x Nscoeffs` or `Nscoeffs` |
|
|
281
|
+
| `G` | `NLayers<= x NQuad x NQuad` |
|
|
282
|
+
| `K` | `NLayers<= x NQuad` |
|
|
283
|
+
| `G_inv` | `NLayers<= x NQuad x NQuad` or `None` |
|
|
284
|
+
| `mu_arr` | `NQuad` |
|
|
285
|
+
| `_autograd_compatible` | boolean |
|
|
286
|
+
|
|
287
|
+
Notable internal variables of _mathscr_v
|
|
288
|
+
| Variable | Shape |
|
|
289
|
+
| ---------------- | ----------------------------------- |
|
|
290
|
+
| i_arr | `Nscoeffs` |
|
|
291
|
+
| i_arr_repeat | `Nscoeffs*(Nscoeffs+1)/2` | Using triangular number formula
|
|
292
|
+
| j_arr | `Nscoeffs*(Nscoeffs+1)/2` | Using triangular number formula
|
|
293
|
+
| s_poly_coeffs_nj | `NLayers x Nscoeffs*(Nscoeffs+1)/2` |
|
|
294
|
+
| OUTPUT | `NQuad x Ntau` |
|
|
264
295
|
"""
|
|
265
296
|
n = Nscoeffs - 1
|
|
266
297
|
|
|
267
|
-
if
|
|
298
|
+
if _autograd_compatible:
|
|
268
299
|
import autograd.numpy as np
|
|
269
300
|
|
|
270
301
|
def mathscr_b(i):
|
|
302
|
+
"""
|
|
303
|
+
Notable internal variables of mathscr_b
|
|
304
|
+
| Variable | Shape |
|
|
305
|
+
| ---------------- | ------------------------------------- |
|
|
306
|
+
| j_arr | `i + 1` |
|
|
307
|
+
| s_poly_coeffs_nj | `i + 1` |
|
|
308
|
+
| OUTPUT | `Nscoeffs x (i + 1) x NQuad` |
|
|
309
|
+
"""
|
|
310
|
+
|
|
271
311
|
j_arr = np.arange(i + 1)
|
|
272
312
|
s_poly_coeffs_nj = s_poly_coeffs[:, n - j_arr]
|
|
273
313
|
return np.sum(
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: PythonicDISORT
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.7.0
|
|
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
|
|
@@ -46,7 +46,7 @@ We highly recommend reading the non-optional parts of sections 1 and 2 before us
|
|
|
46
46
|
|
|
47
47
|
## PyTest and examples of how to use PythonicDISORT
|
|
48
48
|
|
|
49
|
-
Not only do we have verification tests in the Jupyter Notebook, we also
|
|
49
|
+
Not only do we have verification tests in the Jupyter Notebook, we have also recreated most of the test problems in Stamnes' `disotest.f90`;
|
|
50
50
|
`disotest.f90` is included in the `disort4.0.99_f2py` directory of our GitHub repository. In these tests, the solutions from PythonicDISORT are compared
|
|
51
51
|
against solutions from our F2PY-wrapped Stamnes' DISORT (version 4.0.99). With PyTest installed, execute the console command `pytest`
|
|
52
52
|
in the `pydisotest` directory to run these tests. The `pydisotest` directory also contains Jupyter Notebooks, one for each test,
|
|
@@ -56,13 +56,13 @@ to show how the tests were implemented. These notebooks double up as examples of
|
|
|
56
56
|
|
|
57
57
|
* From PyPI: `pip install PythonicDISORT`
|
|
58
58
|
* From Conda-forge: (TODO: we need to first publish on Conda-forge)
|
|
59
|
-
* By cloning repository: `pip install .` in the `Pythonic-DISORT` directory; `pip install -r all_optional_dependencies.txt` to install all optional dependencies
|
|
59
|
+
* By cloning repository: `pip install .` in the `Pythonic-DISORT` directory; `pip install -r all_optional_dependencies.txt` to install all optional dependencies (see *Requirements to run PythonicDISORT*)
|
|
60
60
|
|
|
61
61
|
## Requirements to run PythonicDISORT
|
|
62
62
|
* Python 3.8+
|
|
63
63
|
* `numpy >= 1.8.0`
|
|
64
64
|
* `scipy >= 1.8.0`
|
|
65
|
-
* (OPTIONAL) `pytest >= 6.2.5` (Required
|
|
65
|
+
* (OPTIONAL) `pytest >= 6.2.5` (Required to use the command `pytest`, see *PyTest and examples of how to use PythonicDISORT*)
|
|
66
66
|
|
|
67
67
|
## Additional requirements to run the Jupyter Notebook
|
|
68
68
|
* `autograd >= 1.5`
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
PythonicDISORT/__init__.py,sha256=V1obNzaFgqInxqYJ5h_r6JHbZRxx4VM5VgzCIS6EEzI,84
|
|
2
|
+
PythonicDISORT/_assemble_intensity_and_fluxes.py,sha256=IH1OYHfMLh1LrNiwSCnaJduELvHpStJgXqTycQ869X8,20410
|
|
3
|
+
PythonicDISORT/_solve_for_coeffs.py,sha256=8x7bDARYjS_fnoFGt5LRnm6yUtjyPa_YQ2Mj0LA2AFY,19162
|
|
4
|
+
PythonicDISORT/_solve_for_gen_and_part_sols.py,sha256=okJFq60712DN48-jdodipvP5S11yYK_yobDVpg0kTi8,12841
|
|
5
|
+
PythonicDISORT/pydisort.py,sha256=xjhiRnwmVIPGKJqEuapwLwGLicL3mjizO-w3r5kaP1M,27880
|
|
6
|
+
PythonicDISORT/subroutines.py,sha256=oqPIluJaFF88d7N7iS72wFOKfiYAmT3uA33tpPjuLP0,15857
|
|
7
|
+
PythonicDISORT-0.7.0.dist-info/LICENSE.md,sha256=q1i1QVh0OLzK0fj6kaNRNWsM_KZca66JwWgWwbuCPlA,1092
|
|
8
|
+
PythonicDISORT-0.7.0.dist-info/METADATA,sha256=1V3vyKC8Qa9uEH_WvCfdUnpU28HqOEnb3PdPCIR7Ij4,7230
|
|
9
|
+
PythonicDISORT-0.7.0.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
|
|
10
|
+
PythonicDISORT-0.7.0.dist-info/top_level.txt,sha256=aX6kCeI1E7naZz3xfw4_mIbWh5KBh9dmF3FIvgP5m3Y,15
|
|
11
|
+
PythonicDISORT-0.7.0.dist-info/RECORD,,
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
PythonicDISORT/__init__.py,sha256=V1obNzaFgqInxqYJ5h_r6JHbZRxx4VM5VgzCIS6EEzI,84
|
|
2
|
-
PythonicDISORT/_assemble_solution_functions.py,sha256=_VyCjn6WUXE6thYrf-KoGL0sYZI9dotGtlcaJPWo_fc,14849
|
|
3
|
-
PythonicDISORT/_diagonalize.py,sha256=CT3pG1Hi3-iRJGYoJNiGYey4Mlp0yyGS6qYlUXHYYeA,9147
|
|
4
|
-
PythonicDISORT/_solve_for_coefs.py,sha256=4LEcwveWC70-ALDQjwpnOKxb6yXd5BHqJYdxkkhGtvI,15014
|
|
5
|
-
PythonicDISORT/pydisort.py,sha256=wjiIv0MZZ8QOXyYdZrd86YpzDdmIG12_HXAPNoO0P6s,24295
|
|
6
|
-
PythonicDISORT/subroutines.py,sha256=KXaFUIBdt0o8Ag204oBGObcw1-JYUyxJF3_VX_zNEpI,13295
|
|
7
|
-
PythonicDISORT-0.6.2.dist-info/LICENSE.md,sha256=q1i1QVh0OLzK0fj6kaNRNWsM_KZca66JwWgWwbuCPlA,1092
|
|
8
|
-
PythonicDISORT-0.6.2.dist-info/METADATA,sha256=g6MguV17dX4teiOi0iLYSTq82HuOUwzrERa5jOiacPU,7135
|
|
9
|
-
PythonicDISORT-0.6.2.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
|
|
10
|
-
PythonicDISORT-0.6.2.dist-info/top_level.txt,sha256=aX6kCeI1E7naZz3xfw4_mIbWh5KBh9dmF3FIvgP5m3Y,15
|
|
11
|
-
PythonicDISORT-0.6.2.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|