PM-JPL 1.2.2__py3-none-any.whl → 1.3.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.
Potentially problematic release.
This version of PM-JPL might be problematic. Click here for more details.
- PMJPL/PMJPL.py +169 -80
- PMJPL/VPD_factor.py +1 -1
- PMJPL/canopy_aerodynamic_resistance.py +1 -1
- PMJPL/canopy_conductance.py +1 -1
- PMJPL/evapotranspiration_conversion/evapotranspiration_conversion.py +3 -1
- PMJPL/interception.py +1 -3
- PMJPL/parameters.py +1 -1
- PMJPL/penman_monteith/penman_monteith.py +0 -1
- PMJPL/potential_soil_evaporation.py +2 -2
- PMJPL/tmin_factor.py +1 -1
- PMJPL/transpiration.py +4 -4
- PMJPL/version.txt +1 -1
- PMJPL/wet_canopy_resistance.py +1 -0
- PMJPL/wet_soil_evaporation.py +4 -4
- {pm_jpl-1.2.2.dist-info → pm_jpl-1.3.0.dist-info}/METADATA +11 -20
- pm_jpl-1.3.0.dist-info/RECORD +38 -0
- PMJPL/MCD12C1/MCD12C1.py +0 -10
- PMJPL/MCD12C1/__init__.py +0 -1
- PMJPL/SEBAL/SEBAL.py +0 -45
- PMJPL/SEBAL/__init__.py +0 -1
- PMJPL/soil_heat_flux/__init__.py +0 -1
- PMJPL/soil_heat_flux/soil_heat_flux.py +0 -62
- PMJPL/verma_net_radiation/__init__.py +0 -1
- PMJPL/verma_net_radiation/verma_net_radiation.py +0 -108
- pm_jpl-1.2.2.dist-info/RECORD +0 -46
- {pm_jpl-1.2.2.dist-info → pm_jpl-1.3.0.dist-info}/WHEEL +0 -0
- {pm_jpl-1.2.2.dist-info → pm_jpl-1.3.0.dist-info}/licenses/LICENSE +0 -0
- {pm_jpl-1.2.2.dist-info → pm_jpl-1.3.0.dist-info}/top_level.txt +0 -0
PMJPL/PMJPL.py
CHANGED
|
@@ -7,29 +7,28 @@ https://landweb.nascom.nasa.gov/QA_WWW/forPage/user_guide/MOD16UsersGuide2016.pd
|
|
|
7
7
|
Developed by Gregory Halverson in the Jet Propulsion Laboratory Year-Round Internship Program (Columbus Technologies and Services), in coordination with the ECOSTRESS mission and master's thesis studies at California State University, Northridge.
|
|
8
8
|
"""
|
|
9
9
|
import logging
|
|
10
|
-
from typing import
|
|
10
|
+
from typing import Dict, Union
|
|
11
11
|
from datetime import datetime
|
|
12
|
-
from os.path import join, abspath, dirname, expanduser
|
|
13
12
|
|
|
14
13
|
import numpy as np
|
|
15
|
-
import
|
|
16
|
-
from numpy import where, nan, exp, array, isnan, logical_and, clip, float32
|
|
17
|
-
import warnings
|
|
18
|
-
|
|
19
|
-
import rasters as rt
|
|
20
|
-
|
|
14
|
+
import rasters as rt
|
|
21
15
|
from rasters import Raster, RasterGrid, RasterGeometry
|
|
22
16
|
|
|
23
|
-
from
|
|
17
|
+
from check_distribution import check_distribution
|
|
18
|
+
from GEOS5FP import GEOS5FP
|
|
19
|
+
from NASADEM import NASADEM
|
|
20
|
+
from verma_net_radiation import process_verma_net_radiation
|
|
21
|
+
from SEBAL_soil_heat_flux import calculate_SEBAL_soil_heat_flux
|
|
22
|
+
from MCD12C1_2019_v006 import load_MCD12C1_IGBP
|
|
23
|
+
|
|
24
24
|
from .parameters import MOD16_parameter_from_IGBP
|
|
25
25
|
from .evapotranspiration_conversion.evapotranspiration_conversion import lambda_Jkg_from_Ta_C
|
|
26
|
-
from .meteorology_conversion.meteorology_conversion import SVP_Pa_from_Ta_C, calculate_specific_heat,
|
|
26
|
+
from .meteorology_conversion.meteorology_conversion import SVP_Pa_from_Ta_C, calculate_specific_heat, \
|
|
27
|
+
calculate_surface_pressure, celcius_to_kelvin
|
|
27
28
|
from .penman_monteith.penman_monteith import calculate_gamma
|
|
28
|
-
from .priestley_taylor.priestley_taylor import delta_Pa_from_Ta_C
|
|
29
|
+
from .priestley_taylor.priestley_taylor import delta_Pa_from_Ta_C
|
|
29
30
|
|
|
30
|
-
from .
|
|
31
|
-
from .evapotranspiration_conversion import daily_ET_from_daily_LE
|
|
32
|
-
from .meteorology_conversion import kelvin_to_celsius, calculate_specific_humidity, calculate_air_density
|
|
31
|
+
from .meteorology_conversion import calculate_specific_humidity, calculate_air_density
|
|
33
32
|
from .vegetation_conversion.vegetation_conversion import FVC_from_NDVI, LAI_from_NDVI
|
|
34
33
|
|
|
35
34
|
from .constants import *
|
|
@@ -66,24 +65,110 @@ DEFAULT_OUTPUT_VARIABLES = [
|
|
|
66
65
|
'ET_daily_kg'
|
|
67
66
|
]
|
|
68
67
|
|
|
68
|
+
|
|
69
69
|
def PMJPL(
|
|
70
|
-
Rn: Union[Raster, np.ndarray],
|
|
71
|
-
G: Union[Raster, np.ndarray],
|
|
72
70
|
NDVI: Union[Raster, np.ndarray],
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
71
|
+
ST_C: Union[Raster, np.ndarray] = None,
|
|
72
|
+
emissivity: Union[Raster, np.ndarray] = None,
|
|
73
|
+
albedo: Union[Raster, np.ndarray] = None,
|
|
74
|
+
Rn: Union[Raster, np.ndarray] = None,
|
|
75
|
+
G: Union[Raster, np.ndarray] = None,
|
|
76
|
+
Ta_C: Union[Raster, np.ndarray] = None,
|
|
77
|
+
Tmin_C: Union[Raster, np.ndarray] = None,
|
|
78
|
+
RH: Union[Raster, np.ndarray] = None,
|
|
79
|
+
IGBP: Union[Raster, np.ndarray] = None,
|
|
80
|
+
FVC: Union[Raster, np.ndarray] = None,
|
|
81
|
+
geometry: RasterGeometry = None,
|
|
82
|
+
time_UTC: datetime = None,
|
|
83
|
+
GEOS5FP_connection: GEOS5FP = None,
|
|
84
|
+
resampling: str = "nearest",
|
|
77
85
|
Ps_Pa: Union[Raster, np.ndarray] = None,
|
|
78
|
-
|
|
86
|
+
elevation_km: Union[Raster, np.ndarray] = None,
|
|
79
87
|
delta_Pa: Union[Raster, np.ndarray] = None,
|
|
88
|
+
lambda_Jkg: Union[Raster, np.ndarray] = None,
|
|
80
89
|
gamma_Jkg: Union[Raster, np.ndarray, float] = None) -> Dict[str, Raster]:
|
|
81
90
|
results = {}
|
|
82
91
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
92
|
+
if geometry is None and isinstance(NDVI, Raster):
|
|
93
|
+
geometry = NDVI.geometry
|
|
94
|
+
|
|
95
|
+
if GEOS5FP_connection is None:
|
|
96
|
+
GEOS5FP_connection = GEOS5FP()
|
|
97
|
+
|
|
98
|
+
if Ta_C is None and geometry is not None and time_UTC is not None:
|
|
99
|
+
Ta_C = GEOS5FP_connection.Ta_C(
|
|
100
|
+
time_UTC=time_UTC,
|
|
101
|
+
geometry=geometry,
|
|
102
|
+
resampling=resampling
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
if Ta_C is None:
|
|
106
|
+
raise ValueError("air temperature (Ta_C) not given")
|
|
107
|
+
|
|
108
|
+
if Tmin_C is None and geometry is not None and time_UTC is not None:
|
|
109
|
+
Tmin_K = GEOS5FP_connection.Tmin_K(
|
|
110
|
+
time_UTC=time_UTC,
|
|
111
|
+
geometry=geometry,
|
|
112
|
+
resampling=resampling
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
Tmin_C = Tmin_K - 273.15
|
|
116
|
+
|
|
117
|
+
if Tmin_C is None:
|
|
118
|
+
raise ValueError("minimum temperature (Tmin_C) not given")
|
|
119
|
+
|
|
120
|
+
if RH is None and geometry is not None and time_UTC is not None:
|
|
121
|
+
RH = GEOS5FP_connection.RH(
|
|
122
|
+
time_UTC=time_UTC,
|
|
123
|
+
geometry=geometry,
|
|
124
|
+
resampling=resampling
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
if RH is None:
|
|
128
|
+
raise ValueError("relative humidity (RH) not given")
|
|
129
|
+
|
|
130
|
+
if elevation_km is None and geometry is not None:
|
|
131
|
+
elevation_km = NASADEM.elevation_km(geometry=geometry)
|
|
132
|
+
|
|
133
|
+
elevation_m = elevation_km * 1000.0
|
|
134
|
+
|
|
135
|
+
if IGBP is None and geometry is not None:
|
|
136
|
+
IGBP = load_MCD12C1_IGBP(geometry=geometry)
|
|
137
|
+
|
|
138
|
+
if Rn is None and albedo is not None and ST_C is not None and emissivity is not None:
|
|
139
|
+
if SWin is None and geometry is not None and time_UTC is not None:
|
|
140
|
+
SWin = GEOS5FP_connection.SWin(
|
|
141
|
+
time_UTC=time_UTC,
|
|
142
|
+
geometry=geometry,
|
|
143
|
+
resampling=resampling
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
Rn_results = process_verma_net_radiation(
|
|
147
|
+
SWin=SWin,
|
|
148
|
+
albedo=albedo,
|
|
149
|
+
ST_C=ST_C,
|
|
150
|
+
emissivity=emissivity,
|
|
151
|
+
Ta_C=Ta_C,
|
|
152
|
+
RH=RH
|
|
153
|
+
)
|
|
154
|
+
|
|
155
|
+
Rn = Rn_results["Rn"]
|
|
156
|
+
|
|
157
|
+
if Rn is None:
|
|
158
|
+
raise ValueError("net radiation (Rn) not given")
|
|
159
|
+
|
|
160
|
+
if G is None and Rn is not None and ST_C is not None and NDVI is not None and albedo is not None:
|
|
161
|
+
G = calculate_SEBAL_soil_heat_flux(
|
|
162
|
+
Rn=Rn,
|
|
163
|
+
ST_C=ST_C,
|
|
164
|
+
NDVI=NDVI,
|
|
165
|
+
albedo=albedo
|
|
166
|
+
)
|
|
167
|
+
|
|
168
|
+
if G is None:
|
|
169
|
+
raise ValueError("soil heat flux (G) not given")
|
|
170
|
+
|
|
171
|
+
LAI = LAI_from_NDVI(NDVI)
|
|
87
172
|
|
|
88
173
|
# calculate fraction of vegetation cover if it's not given
|
|
89
174
|
if FVC is None:
|
|
@@ -131,7 +216,7 @@ def PMJPL(
|
|
|
131
216
|
# from specific heat of water vapor (CPW)
|
|
132
217
|
# and specific heat of dry air (CPD)
|
|
133
218
|
Cp_Jkg = calculate_specific_heat(specific_humidity)
|
|
134
|
-
results["Cp"] = Cp_Jkg
|
|
219
|
+
results["Cp"] = Cp_Jkg
|
|
135
220
|
|
|
136
221
|
# calculate delta term if it's not given
|
|
137
222
|
if delta_Pa is None:
|
|
@@ -161,7 +246,7 @@ def PMJPL(
|
|
|
161
246
|
|
|
162
247
|
# query leaf conductance to sensible heat (gl_sh) in seconds per meter
|
|
163
248
|
gl_sh = MOD16_parameter_from_IGBP(
|
|
164
|
-
variable="gl_sh",
|
|
249
|
+
variable="gl_sh",
|
|
165
250
|
IGBP=IGBP
|
|
166
251
|
)
|
|
167
252
|
|
|
@@ -173,19 +258,19 @@ def PMJPL(
|
|
|
173
258
|
results['rhc'] = rhc
|
|
174
259
|
|
|
175
260
|
# calculate resistance to radiative heat transfer through air (rrc)
|
|
176
|
-
rrc = float32(rho_kgm3 * Cp_Jkg / (4.0 * SIGMA * Ta_K ** 3.0))
|
|
261
|
+
rrc = np.float32(rho_kgm3 * Cp_Jkg / (4.0 * SIGMA * Ta_K ** 3.0))
|
|
177
262
|
results['rrc'] = rrc
|
|
178
263
|
|
|
179
264
|
# calculate aerodynamic resistance (rhrc)
|
|
180
265
|
# in seconds per meter
|
|
181
266
|
# from wet canopy resistance to sensible heat
|
|
182
267
|
# and resistance to radiative heat transfer through air
|
|
183
|
-
rhrc = float32((rhc * rrc) / (rhc + rrc))
|
|
268
|
+
rhrc = np.float32((rhc * rrc) / (rhc + rrc))
|
|
184
269
|
results['rhrc'] = rhrc
|
|
185
270
|
|
|
186
271
|
# calculate leaf conductance to evaporated water vapor (gl_e_wv)
|
|
187
272
|
gl_e_wv = MOD16_parameter_from_IGBP(
|
|
188
|
-
variable="gl_e_wv",
|
|
273
|
+
variable="gl_e_wv",
|
|
189
274
|
IGBP=IGBP
|
|
190
275
|
)
|
|
191
276
|
|
|
@@ -203,18 +288,18 @@ def PMJPL(
|
|
|
203
288
|
# calculate wet latent heat flux (LEi)
|
|
204
289
|
# in watts per square meter
|
|
205
290
|
LEi = calculate_interception(
|
|
206
|
-
delta_Pa=delta_Pa,
|
|
207
|
-
Ac=Ac,
|
|
208
|
-
rho=rho_kgm3,
|
|
209
|
-
Cp=Cp_Jkg,
|
|
210
|
-
VPD_Pa=VPD_Pa,
|
|
211
|
-
FVC=FVC,
|
|
212
|
-
rhrc=rhrc,
|
|
213
|
-
fwet=fwet,
|
|
291
|
+
delta_Pa=delta_Pa,
|
|
292
|
+
Ac=Ac,
|
|
293
|
+
rho=rho_kgm3,
|
|
294
|
+
Cp=Cp_Jkg,
|
|
295
|
+
VPD_Pa=VPD_Pa,
|
|
296
|
+
FVC=FVC,
|
|
297
|
+
rhrc=rhrc,
|
|
298
|
+
fwet=fwet,
|
|
214
299
|
rvc=rvc,
|
|
215
|
-
gamma_Jkg=gamma_Jkg
|
|
300
|
+
# gamma_Jkg=gamma_Jkg
|
|
216
301
|
)
|
|
217
|
-
|
|
302
|
+
|
|
218
303
|
results['LEi'] = LEi
|
|
219
304
|
|
|
220
305
|
# calculate correctance factor (rcorr)
|
|
@@ -225,7 +310,7 @@ def PMJPL(
|
|
|
225
310
|
|
|
226
311
|
# query biome-specific mean potential stomatal conductance per unit leaf area
|
|
227
312
|
CL = MOD16_parameter_from_IGBP(
|
|
228
|
-
variable="
|
|
313
|
+
variable="cl",
|
|
229
314
|
IGBP=IGBP
|
|
230
315
|
)
|
|
231
316
|
|
|
@@ -233,7 +318,7 @@ def PMJPL(
|
|
|
233
318
|
|
|
234
319
|
# query open minimum temperature by land-cover
|
|
235
320
|
tmin_open = MOD16_parameter_from_IGBP(
|
|
236
|
-
variable="tmin_open",
|
|
321
|
+
variable="tmin_open",
|
|
237
322
|
IGBP=IGBP
|
|
238
323
|
)
|
|
239
324
|
|
|
@@ -241,19 +326,23 @@ def PMJPL(
|
|
|
241
326
|
|
|
242
327
|
# query closed minimum temperature by land-cover
|
|
243
328
|
tmin_close = MOD16_parameter_from_IGBP(
|
|
244
|
-
variable="tmin_close",
|
|
329
|
+
variable="tmin_close",
|
|
245
330
|
IGBP=IGBP
|
|
246
331
|
)
|
|
247
332
|
|
|
248
333
|
results['tmin_close'] = tmin_close
|
|
249
334
|
|
|
335
|
+
check_distribution(Tmin_C, "Tmin_C")
|
|
336
|
+
check_distribution(tmin_open, "tmin_open")
|
|
337
|
+
check_distribution(tmin_close, "tmin_close")
|
|
338
|
+
|
|
250
339
|
# calculate minimum temperature factor for stomatal conductance
|
|
251
|
-
mTmin = calculate_tmin_factor(Tmin_C, tmin_open, tmin_close
|
|
340
|
+
mTmin = calculate_tmin_factor(Tmin_C, tmin_open, tmin_close)
|
|
252
341
|
results['mTmin'] = mTmin
|
|
253
342
|
|
|
254
343
|
# query open vapor pressure deficit by land-cover
|
|
255
344
|
VPD_open = MOD16_parameter_from_IGBP(
|
|
256
|
-
variable="
|
|
345
|
+
variable="vpd_open",
|
|
257
346
|
IGBP=IGBP
|
|
258
347
|
)
|
|
259
348
|
|
|
@@ -261,7 +350,7 @@ def PMJPL(
|
|
|
261
350
|
|
|
262
351
|
# query closed vapor pressure deficit by land-cover
|
|
263
352
|
VPD_close = MOD16_parameter_from_IGBP(
|
|
264
|
-
variable="
|
|
353
|
+
variable="vpd_close",
|
|
265
354
|
IGBP=IGBP
|
|
266
355
|
)
|
|
267
356
|
|
|
@@ -303,32 +392,32 @@ def PMJPL(
|
|
|
303
392
|
|
|
304
393
|
# calculate transpiration
|
|
305
394
|
LEc = calculate_transpiration(
|
|
306
|
-
delta_Pa=delta_Pa,
|
|
307
|
-
Ac=Ac,
|
|
308
|
-
|
|
309
|
-
Cp_Jkg=Cp_Jkg,
|
|
310
|
-
VPD_Pa=VPD_Pa,
|
|
311
|
-
FVC=FVC,
|
|
312
|
-
ra=ra,
|
|
313
|
-
fwet=fwet,
|
|
395
|
+
delta_Pa=delta_Pa,
|
|
396
|
+
Ac=Ac,
|
|
397
|
+
rho_kgm3=rho_kgm3,
|
|
398
|
+
Cp_Jkg=Cp_Jkg,
|
|
399
|
+
VPD_Pa=VPD_Pa,
|
|
400
|
+
FVC=FVC,
|
|
401
|
+
ra=ra,
|
|
402
|
+
fwet=fwet,
|
|
314
403
|
rs=rs,
|
|
315
|
-
gamma_Jkg=gamma_Jkg
|
|
404
|
+
# gamma_Jkg=gamma_Jkg
|
|
316
405
|
)
|
|
317
|
-
|
|
406
|
+
|
|
318
407
|
results['LEc'] = LEc
|
|
319
408
|
|
|
320
409
|
# soil evaporation
|
|
321
410
|
|
|
322
411
|
# query aerodynamic resistant constraints from land-cover
|
|
323
412
|
rbl_max = MOD16_parameter_from_IGBP(
|
|
324
|
-
variable="rbl_max",
|
|
413
|
+
variable="rbl_max",
|
|
325
414
|
IGBP=IGBP
|
|
326
415
|
)
|
|
327
416
|
|
|
328
417
|
results['rbl_max'] = rbl_max
|
|
329
418
|
|
|
330
419
|
rbl_min = MOD16_parameter_from_IGBP(
|
|
331
|
-
variable="rbl_min",
|
|
420
|
+
variable="rbl_min",
|
|
332
421
|
IGBP=IGBP
|
|
333
422
|
)
|
|
334
423
|
|
|
@@ -343,7 +432,7 @@ def PMJPL(
|
|
|
343
432
|
results['rtot'] = rtot
|
|
344
433
|
|
|
345
434
|
# calculate resistance to radiative heat transfer through air
|
|
346
|
-
rrs = float32(rho_kgm3 * Cp_Jkg / (4.0 * SIGMA * Ta_K ** 3))
|
|
435
|
+
rrs = np.float32(rho_kgm3 * Cp_Jkg / (4.0 * SIGMA * Ta_K ** 3))
|
|
347
436
|
results['rrs'] = rrs
|
|
348
437
|
|
|
349
438
|
# calculate aerodynamic resistance at the soil surface
|
|
@@ -358,34 +447,34 @@ def PMJPL(
|
|
|
358
447
|
|
|
359
448
|
# calculate wet soil evaporation
|
|
360
449
|
LE_soil_wet = calculate_wet_soil_evaporation(
|
|
361
|
-
delta_Pa=delta_Pa,
|
|
362
|
-
Asoil=Asoil,
|
|
363
|
-
|
|
364
|
-
Cp_Jkg=Cp_Jkg,
|
|
365
|
-
FVC=FVC,
|
|
366
|
-
VPD_Pa=VPD_Pa,
|
|
367
|
-
ras=ras,
|
|
368
|
-
fwet=fwet,
|
|
450
|
+
delta_Pa=delta_Pa,
|
|
451
|
+
Asoil=Asoil,
|
|
452
|
+
rho_kgm3=rho_kgm3,
|
|
453
|
+
Cp_Jkg=Cp_Jkg,
|
|
454
|
+
FVC=FVC,
|
|
455
|
+
VPD_Pa=VPD_Pa,
|
|
456
|
+
ras=ras,
|
|
457
|
+
fwet=fwet,
|
|
369
458
|
rtot=rtot,
|
|
370
|
-
gamma_Jkg=gamma_Jkg
|
|
459
|
+
# gamma_Jkg=gamma_Jkg
|
|
371
460
|
)
|
|
372
|
-
|
|
461
|
+
|
|
373
462
|
results['LE_soil_wet'] = LE_soil_wet
|
|
374
463
|
|
|
375
464
|
# calculate potential soil evaporation
|
|
376
465
|
LE_soil_pot = calculate_potential_soil_evaporation(
|
|
377
|
-
delta_Pa=delta_Pa,
|
|
378
|
-
Asoil=Asoil,
|
|
379
|
-
rho=rho_kgm3,
|
|
380
|
-
Cp_Jkg=Cp_Jkg,
|
|
381
|
-
FVC=FVC,
|
|
382
|
-
VPD_Pa=VPD_Pa,
|
|
383
|
-
ras=ras,
|
|
384
|
-
fwet=fwet,
|
|
466
|
+
delta_Pa=delta_Pa,
|
|
467
|
+
Asoil=Asoil,
|
|
468
|
+
rho=rho_kgm3,
|
|
469
|
+
Cp_Jkg=Cp_Jkg,
|
|
470
|
+
FVC=FVC,
|
|
471
|
+
VPD_Pa=VPD_Pa,
|
|
472
|
+
ras=ras,
|
|
473
|
+
fwet=fwet,
|
|
385
474
|
rtot=rtot,
|
|
386
|
-
gamma_Jkg=gamma_Jkg
|
|
475
|
+
# gamma_Jkg=gamma_Jkg
|
|
387
476
|
)
|
|
388
|
-
|
|
477
|
+
|
|
389
478
|
results['LE_soil_pot'] = LE_soil_pot
|
|
390
479
|
|
|
391
480
|
# calculate soil moisture constraint
|
|
@@ -396,7 +485,7 @@ def PMJPL(
|
|
|
396
485
|
LEs = rt.clip(LE_soil_wet + LE_soil_pot * fSM, 0.0, None)
|
|
397
486
|
|
|
398
487
|
# fill soil evaporation with zero
|
|
399
|
-
LEs = rt.where(isnan(LEs), 0.0, LEs)
|
|
488
|
+
LEs = rt.where(np.isnan(LEs), 0.0, LEs)
|
|
400
489
|
results['LEs'] = LEs
|
|
401
490
|
|
|
402
491
|
# sum partitions into total latent heat flux
|
PMJPL/VPD_factor.py
CHANGED
|
@@ -20,7 +20,7 @@ def calculate_VPD_factor(
|
|
|
20
20
|
"""
|
|
21
21
|
# calculate VPD factor using queried open and closed VPD
|
|
22
22
|
mVPD = rt.where(VPD <= VPD_open, 1.0, np.nan)
|
|
23
|
-
mVPD = rt.where(
|
|
23
|
+
mVPD = rt.where(np.logical_and(VPD_open < VPD, VPD < VPD_close), (VPD_close - VPD) / (VPD_close - VPD_open), mVPD)
|
|
24
24
|
mVPD = rt.where(VPD >= VPD_close, 0.0, mVPD)
|
|
25
25
|
|
|
26
26
|
return mVPD
|
|
@@ -23,7 +23,7 @@ def calculate_rtotc(
|
|
|
23
23
|
rtotc = rt.where(VPD >= vpd_close, rbl_min, rtotc)
|
|
24
24
|
|
|
25
25
|
rtotc = rt.where(
|
|
26
|
-
|
|
26
|
+
np.logical_and(vpd_open < VPD, VPD < vpd_close),
|
|
27
27
|
rbl_min + (rbl_max - rbl_min) * (vpd_close - VPD) / (vpd_close - vpd_open),
|
|
28
28
|
rtotc
|
|
29
29
|
)
|
PMJPL/canopy_conductance.py
CHANGED
|
@@ -26,7 +26,7 @@ def calculate_canopy_conductance(
|
|
|
26
26
|
"""
|
|
27
27
|
# noinspection PyTypeChecker
|
|
28
28
|
Cc = rt.where(
|
|
29
|
-
|
|
29
|
+
np.logical_and(LAI > 0.0, (1.0 - fwet) > 0.0),
|
|
30
30
|
gl_sh * (gs1 + Gcu) / (gs1 + gl_sh + Gcu) * LAI * (1.0 - fwet),
|
|
31
31
|
0.0
|
|
32
32
|
)
|
|
@@ -6,8 +6,10 @@ from rasters import Raster
|
|
|
6
6
|
import numpy as np
|
|
7
7
|
import pandas as pd
|
|
8
8
|
|
|
9
|
+
from verma_net_radiation import daily_Rn_integration_verma
|
|
10
|
+
|
|
9
11
|
from ..meteorology_conversion.meteorology_conversion import celcius_to_kelvin
|
|
10
|
-
|
|
12
|
+
|
|
11
13
|
|
|
12
14
|
# latent heat of vaporization for water at 20 Celsius in Joules per kilogram
|
|
13
15
|
LAMBDA_JKG_WATER_20C = 2450000.0
|
PMJPL/interception.py
CHANGED
|
@@ -4,7 +4,7 @@ import rasters as rt
|
|
|
4
4
|
from rasters import Raster
|
|
5
5
|
|
|
6
6
|
from .constants import GAMMA_PA
|
|
7
|
-
|
|
7
|
+
|
|
8
8
|
def calculate_interception(
|
|
9
9
|
delta_Pa: Union[Raster, np.ndarray],
|
|
10
10
|
Ac: Union[Raster, np.ndarray],
|
|
@@ -15,7 +15,6 @@ def calculate_interception(
|
|
|
15
15
|
rhrc: Union[Raster, np.ndarray],
|
|
16
16
|
fwet: Union[Raster, np.ndarray],
|
|
17
17
|
rvc: Union[Raster, np.ndarray],
|
|
18
|
-
water: Union[Raster, np.ndarray],
|
|
19
18
|
gamma_Pa: Union[Raster, np.ndarray, float] = GAMMA_PA) -> Union[Raster, np.ndarray]:
|
|
20
19
|
"""
|
|
21
20
|
Calculates the wet evaporation partition of the latent heat flux using the MOD16 method.
|
|
@@ -29,7 +28,6 @@ def calculate_interception(
|
|
|
29
28
|
:param rhrc: aerodynamic resistance in seconds per meter
|
|
30
29
|
:param fwet: relative surface wetness
|
|
31
30
|
:param rvc: wet canopy resistance
|
|
32
|
-
:param water: water content in the canopy
|
|
33
31
|
:param gamma_Pa: psychrometric constant for atmospheric pressure in Pascal (default: GAMMA_PA)
|
|
34
32
|
|
|
35
33
|
:return: wet evaporation in watts per square meter
|
PMJPL/parameters.py
CHANGED
|
@@ -11,7 +11,7 @@ def calculate_potential_soil_evaporation(
|
|
|
11
11
|
rho: float,
|
|
12
12
|
Cp_Jkg: float,
|
|
13
13
|
FVC: float,
|
|
14
|
-
|
|
14
|
+
VPD_Pa: float,
|
|
15
15
|
ras: float,
|
|
16
16
|
fwet: float,
|
|
17
17
|
rtot: float,
|
|
@@ -39,7 +39,7 @@ def calculate_potential_soil_evaporation(
|
|
|
39
39
|
- The Penman-Monteith equation takes into account various factors such as radiation, air density, heat capacity, vegetation cover, vapor pressure deficit, aerodynamic resistance, soil wetness, and total resistance.
|
|
40
40
|
- The function returns the potential soil evaporation as either a Raster object or a NumPy array, depending on the input data type.
|
|
41
41
|
"""
|
|
42
|
-
numerator = (delta_Pa * Asoil + rho * Cp_Jkg * (1.0 - FVC) *
|
|
42
|
+
numerator = (delta_Pa * Asoil + rho * Cp_Jkg * (1.0 - FVC) * VPD_Pa / ras) * (1.0 - fwet)
|
|
43
43
|
denominator = delta_Pa + gamma_Pa * rtot / ras
|
|
44
44
|
LE_soil_pot = numerator / denominator
|
|
45
45
|
|
PMJPL/tmin_factor.py
CHANGED
PMJPL/transpiration.py
CHANGED
|
@@ -8,8 +8,8 @@ from .constants import GAMMA_PA
|
|
|
8
8
|
def calculate_transpiration(
|
|
9
9
|
delta_Pa: Union[Raster, np.ndarray],
|
|
10
10
|
Ac: Union[Raster, np.ndarray],
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
rho_kgm3: Union[Raster, np.ndarray],
|
|
12
|
+
Cp_Jkg: Union[Raster, np.ndarray],
|
|
13
13
|
VPD_Pa: Union[Raster, np.ndarray],
|
|
14
14
|
FVC: Union[Raster, np.ndarray],
|
|
15
15
|
ra: Union[Raster, np.ndarray],
|
|
@@ -34,11 +34,11 @@ def calculate_transpiration(
|
|
|
34
34
|
Returns:
|
|
35
35
|
Union[Raster, np.ndarray]: transpiration (LEc) in mm/day.
|
|
36
36
|
"""
|
|
37
|
-
numerator = (delta_Pa * Ac + (
|
|
37
|
+
numerator = (delta_Pa * Ac + (rho_kgm3 * Cp_Jkg * FVC * VPD_Pa / ra)) * (1.0 - fwet)
|
|
38
38
|
denominator = delta_Pa + gamma_Pa * (1.0 + (rs / ra))
|
|
39
39
|
LEc = numerator / denominator
|
|
40
40
|
|
|
41
41
|
# fill transpiration with zero
|
|
42
|
-
LEc = rt.where(
|
|
42
|
+
LEc = rt.where(np.isnan(LEc), 0.0, LEc)
|
|
43
43
|
|
|
44
44
|
return LEc
|
PMJPL/version.txt
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
1.
|
|
1
|
+
1.3.0
|
PMJPL/wet_canopy_resistance.py
CHANGED
|
@@ -18,4 +18,5 @@ def calculate_wet_canopy_resistance(
|
|
|
18
18
|
:param fwet: relative surface wetness
|
|
19
19
|
:return: wet canopy resistance
|
|
20
20
|
"""
|
|
21
|
+
# print(f"conductance: {conductance.shape}, LAI: {LAI.shape}, fwet: {fwet.shape}")
|
|
21
22
|
return rt.clip(1.0 / rt.clip(conductance * LAI * fwet, 1.0 / max_resistance, None), min_resistance, max_resistance)
|
PMJPL/wet_soil_evaporation.py
CHANGED
|
@@ -7,10 +7,10 @@ from .constants import GAMMA_PA
|
|
|
7
7
|
def calculate_wet_soil_evaporation(
|
|
8
8
|
delta_Pa: Union[Raster, np.ndarray],
|
|
9
9
|
Asoil: Union[Raster, np.ndarray],
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
rho_kgm3: Union[Raster, np.ndarray],
|
|
11
|
+
Cp_Jkg: Union[Raster, np.ndarray],
|
|
12
12
|
FVC: Union[Raster, np.ndarray],
|
|
13
|
-
|
|
13
|
+
VPD_Pa: Union[Raster, np.ndarray],
|
|
14
14
|
ras: Union[Raster, np.ndarray],
|
|
15
15
|
fwet: Union[Raster, np.ndarray],
|
|
16
16
|
rtot: Union[Raster, np.ndarray],
|
|
@@ -29,7 +29,7 @@ def calculate_wet_soil_evaporation(
|
|
|
29
29
|
:param gamme: gamma constant (default: GAMMA)
|
|
30
30
|
:return: wet soil evaporation in watts per square meter
|
|
31
31
|
"""
|
|
32
|
-
numerator = (delta_Pa * Asoil +
|
|
32
|
+
numerator = (delta_Pa * Asoil + rho_kgm3 * Cp_Jkg * (1.0 - FVC) * VPD_Pa / ras) * fwet
|
|
33
33
|
denominator = delta_Pa + gamma_Pa * rtot / ras
|
|
34
34
|
LE_soil_wet = numerator / denominator
|
|
35
35
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: PM-JPL
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.3.0
|
|
4
4
|
Summary: JPL implementation of the MOD16 evapotranspiration algorithm for high resolution instantaneous remote sensing imagery
|
|
5
5
|
Author-email: Gregory Halverson <gregory.h.halverson@jpl.nasa.gov>, Qiaozhen Mu <qiaozhen@ntsg.umt.edu>, Maosheng Zhao <zhao@ntsg.umt.edu>, "Steven W. Running" <swr@ntsg.umt.edu>, "Claire S. Villanueva-Weeks" <claire.s.villanueva-weeks@jpl.gov>
|
|
6
6
|
Project-URL: Homepage, https://github.com/JPL-Evapotranspiration-Algorithms/PM-JPL
|
|
@@ -9,28 +9,19 @@ Classifier: Operating System :: OS Independent
|
|
|
9
9
|
Requires-Python: >=3.10
|
|
10
10
|
Description-Content-Type: text/markdown
|
|
11
11
|
License-File: LICENSE
|
|
12
|
-
Requires-Dist:
|
|
13
|
-
Requires-Dist:
|
|
14
|
-
Requires-Dist:
|
|
15
|
-
Requires-Dist:
|
|
16
|
-
Requires-Dist:
|
|
17
|
-
Requires-Dist:
|
|
12
|
+
Requires-Dist: check-distribution
|
|
13
|
+
Requires-Dist: ECOv002-CMR>=1.0.5
|
|
14
|
+
Requires-Dist: ECOv002-granules>=1.0.3
|
|
15
|
+
Requires-Dist: ECOv003-granules
|
|
16
|
+
Requires-Dist: GEOS5FP>=1.1.1
|
|
17
|
+
Requires-Dist: MCD12C1_2019_v006
|
|
18
|
+
Requires-Dist: NASADEM
|
|
18
19
|
Requires-Dist: numpy
|
|
19
20
|
Requires-Dist: pandas
|
|
20
|
-
Requires-Dist:
|
|
21
|
-
Requires-Dist:
|
|
22
|
-
Requires-Dist: pyproj
|
|
23
|
-
Requires-Dist: pyresample
|
|
24
|
-
Requires-Dist: rasterio
|
|
25
|
-
Requires-Dist: rasters
|
|
26
|
-
Requires-Dist: requests
|
|
27
|
-
Requires-Dist: scikit-image
|
|
28
|
-
Requires-Dist: scipy
|
|
29
|
-
Requires-Dist: shapely
|
|
30
|
-
Requires-Dist: six
|
|
21
|
+
Requires-Dist: rasters>=1.4.6
|
|
22
|
+
Requires-Dist: SEBAL-soil-heat-flux
|
|
31
23
|
Requires-Dist: sun-angles
|
|
32
|
-
Requires-Dist:
|
|
33
|
-
Requires-Dist: urllib3
|
|
24
|
+
Requires-Dist: verma-net-radiation
|
|
34
25
|
Provides-Extra: dev
|
|
35
26
|
Requires-Dist: build; extra == "dev"
|
|
36
27
|
Requires-Dist: pytest>=6.0; extra == "dev"
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
PMJPL/PMJPL.py,sha256=GhybvYW5mw-bh4qIvjMd3h1T4pe2B6KnY_j5KwTmPTw,15491
|
|
2
|
+
PMJPL/VPD_factor.py,sha256=ezHMnnMPGNBt6ZTyiwsTEyMr8fwre6JDsHQea68P7T0,970
|
|
3
|
+
PMJPL/__init__.py,sha256=rqFqtI2rLgIxSN3i2J8wZVoT2EpHYgVizfZt8ctwqsc,213
|
|
4
|
+
PMJPL/canopy_aerodynamic_resistance.py,sha256=lhK1JYGh0J7AiC-fJ-WWrR_nEgH3g5fdJs_BHFee-8o,1217
|
|
5
|
+
PMJPL/canopy_conductance.py,sha256=sSgHJTbyDiqnPrUa6qukvL8Tyfu4c4kBbFbonNTx53o,1367
|
|
6
|
+
PMJPL/constants.py,sha256=Az7hftY_CIibJdvRdQcDisRdKqJYm8khktakCcNZtXU,787
|
|
7
|
+
PMJPL/correctance_factor.py,sha256=V93rZcv5DM3LfujhEK8mRgJ-GHk868hDbTmcg8VoOAo,582
|
|
8
|
+
PMJPL/fwet.py,sha256=-5GEGC1ohKBzsuYGLNiCaVe10DQLm82rsZTZGVxb4WY,616
|
|
9
|
+
PMJPL/interception.py,sha256=2kDqMefH_kzMO9mLVY9BPFSoJE4K0pkQCXwrSi2CR9c,1605
|
|
10
|
+
PMJPL/mod16.csv,sha256=1aVfqLOAJwYuZPaScyqbk4yacObPgp8Q-IPzJm0yReY,847
|
|
11
|
+
PMJPL/parameters.py,sha256=kM26BUDMi-N03Gi2PqQi48kYMKakCB3ReiRMUGrvRQU,1974
|
|
12
|
+
PMJPL/potential_soil_evaporation.py,sha256=O8bHGM4ARqSXJDHu6IWneSEy5qScenotGR3uawijGWg,1829
|
|
13
|
+
PMJPL/soil_moisture_constraint.py,sha256=URUGsE1_p2P1dVQ8qKRcKb93hahYWtAmYqoassRu-PI,667
|
|
14
|
+
PMJPL/tmin_factor.py,sha256=UEeET10ErR2rUr1ViRN8UZmoCACxeeiFAReZXr9Kts4,1595
|
|
15
|
+
PMJPL/transpiration.py,sha256=lhRm2A0yxrlJxDw2he-k3PhE7G-sBsVvAMKo5fmh7wU,1998
|
|
16
|
+
PMJPL/version.txt,sha256=WSltI9YjzgrfdnXSIVboOxJIyFCBNaZd2KnjjEl-lKg,5
|
|
17
|
+
PMJPL/wet_canopy_resistance.py,sha256=Eape5EBJuoP-IRvD0SWHJKCJWhzm03vcG72OZVYqt_Q,879
|
|
18
|
+
PMJPL/wet_soil_evaporation.py,sha256=mw9JG1oXfVdSWnVRLP2SPd53mSRK96b8k3E1zf0ci7A,1440
|
|
19
|
+
PMJPL/downscaling/__init__.py,sha256=xvhP4rHzx-nK_R6HSarJ-WF1bMPXYZGvvr8Hk84-q40,27
|
|
20
|
+
PMJPL/downscaling/downscaling.py,sha256=VuhFbK92llJbtkOtJpah_51sM5ctFJ9oNUaH4aaNO7g,8447
|
|
21
|
+
PMJPL/downscaling/linear_downscale.py,sha256=Yi0d2rb1XVSlBJoL2Arq9RtU5FH1RJ98MHLngJIYUjM,2466
|
|
22
|
+
PMJPL/evapotranspiration_conversion/__init__.py,sha256=21wYXP8FJT63MpUTbHu0wGntyFFeiGDRneGMKCNAu8Q,45
|
|
23
|
+
PMJPL/evapotranspiration_conversion/evapotranspiration_conversion.py,sha256=UYKMv-6kx474_dEMsJnoap21W9CD9Rg1fwcWa1haxLM,2734
|
|
24
|
+
PMJPL/meteorology_conversion/__init__.py,sha256=dLF40imqJCC_l8_QMetbsj1YzkXZuFt9tQ2fsd7Wcdw,38
|
|
25
|
+
PMJPL/meteorology_conversion/meteorology_conversion.py,sha256=8vzx71FLLNhR5v6EQBL8OSgAmupQcgdLX2c9tL9TPxA,4202
|
|
26
|
+
PMJPL/penman_monteith/__init__.py,sha256=vcfkNo6BLDCfSF9HZFDvRMAKCx49F9idN7iNTKQCpcA,31
|
|
27
|
+
PMJPL/penman_monteith/penman_monteith.py,sha256=RiqCgPU_0oYSSLMSVzQnouzJYClNcxtBhk3yEIJEWFU,741
|
|
28
|
+
PMJPL/priestley_taylor/__init__.py,sha256=E0SiG_DNAsMz_8A3342UPwbDyrMOgd35AZ-plaJar5s,32
|
|
29
|
+
PMJPL/priestley_taylor/priestley_taylor.py,sha256=Rj168jfWHSBhGeUkDs6ePrVsHhFbmUujzQaA8z0fCXE,1126
|
|
30
|
+
PMJPL/santanello/__init__.py,sha256=HXZS1p3sp4mDJCXkdq___ZIJ9etu7-B8yauJcFvQFgQ,26
|
|
31
|
+
PMJPL/santanello/santanello.py,sha256=lvgskYrirQz0t1m4XNSj8hLzrESS-oVZzMvAnVPyt3g,1521
|
|
32
|
+
PMJPL/vegetation_conversion/__init__.py,sha256=8gnz0yK_euCV0TtVGDrSGaVfx4g0EJCG2J68ppuA5oc,37
|
|
33
|
+
PMJPL/vegetation_conversion/vegetation_conversion.py,sha256=-K3FLV6pXkpxtRxQvimqqkXAgkn9mUUlHQ8FIscq1Zg,1306
|
|
34
|
+
pm_jpl-1.3.0.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
35
|
+
pm_jpl-1.3.0.dist-info/METADATA,sha256=YIWLcqfoGMKy00_jXjUpXJdlUTQ1-EwddDW6s1AWXo0,4146
|
|
36
|
+
pm_jpl-1.3.0.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
|
|
37
|
+
pm_jpl-1.3.0.dist-info/top_level.txt,sha256=YaAFwdYHUxfUW08hiuFquUEdDGrsYn1duuMMjJKh0Ws,6
|
|
38
|
+
pm_jpl-1.3.0.dist-info/RECORD,,
|
PMJPL/MCD12C1/MCD12C1.py
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
from os.path import join, abspath, dirname
|
|
2
|
-
import numpy as np
|
|
3
|
-
import rasters as rt
|
|
4
|
-
from rasters import Raster, RasterGeometry
|
|
5
|
-
|
|
6
|
-
def load_MCD12C1_IGBP(geometry: RasterGeometry = None) -> Raster:
|
|
7
|
-
filename = join(abspath(dirname(__file__)), "MCD12C1.A2019001.006.2020220162300.tif")
|
|
8
|
-
image = rt.Raster.open(filename, geometry=geometry, resampling="nearest")
|
|
9
|
-
|
|
10
|
-
return image
|
PMJPL/MCD12C1/__init__.py
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
from .MCD12C1 import *
|
PMJPL/SEBAL/SEBAL.py
DELETED
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import numpy as np
|
|
2
|
-
import pandas as pd
|
|
3
|
-
import rasters as rt
|
|
4
|
-
|
|
5
|
-
def calculate_soil_heat_flux(Rn: np.ndarray, ST_C: np.ndarray, NDVI: np.ndarray, albedo: np.ndarray) -> np.ndarray:
|
|
6
|
-
"""
|
|
7
|
-
This function calculates the soil heat flux (G) in the Surface Energy Balance Algorithm for Land (SEBAL) model.
|
|
8
|
-
The formula used in the function is a simplification of the more complex relationship between these variables in the energy balance at the surface.
|
|
9
|
-
|
|
10
|
-
Parameters:
|
|
11
|
-
Rn (np.ndarray): Net radiation at the surface.
|
|
12
|
-
ST_C (np.ndarray): Surface temperature in Celsius.
|
|
13
|
-
NDVI (np.ndarray): Normalized Difference Vegetation Index, indicating the presence and condition of vegetation.
|
|
14
|
-
albedo (np.ndarray): Measure of the diffuse reflection of solar radiation.
|
|
15
|
-
|
|
16
|
-
Returns:
|
|
17
|
-
np.ndarray: The soil heat flux (G), a key component in the energy balance.
|
|
18
|
-
|
|
19
|
-
Reference:
|
|
20
|
-
"Evapotranspiration Estimation Based on Remote Sensing and the SEBAL Model in the Bosten Lake Basin of China" [^1^][1]
|
|
21
|
-
"""
|
|
22
|
-
# Empirical coefficients used in the calculation
|
|
23
|
-
coeff1 = 0.0038
|
|
24
|
-
coeff2 = 0.0074
|
|
25
|
-
|
|
26
|
-
# Vegetation cover correction factor
|
|
27
|
-
NDVI_correction = 1 - 0.98 * NDVI ** 4
|
|
28
|
-
|
|
29
|
-
# Calculation of the soil heat flux (G)
|
|
30
|
-
G = Rn * ST_C * (coeff1 + coeff2 * albedo) * NDVI_correction
|
|
31
|
-
|
|
32
|
-
G = rt.clip(G, 0, None)
|
|
33
|
-
|
|
34
|
-
return G
|
|
35
|
-
|
|
36
|
-
def process_SEBAL_G_table(input_df: pd.DataFrame) -> pd.DataFrame:
|
|
37
|
-
Rn = input_df.Rn
|
|
38
|
-
ST_C = input_df.ST_C
|
|
39
|
-
NDVI = input_df.NDVI
|
|
40
|
-
albedo = input_df.albedo
|
|
41
|
-
G = calculate_soil_heat_flux(Rn=Rn, ST_C=ST_C, NDVI=NDVI, albedo=albedo)
|
|
42
|
-
output_df = input_df.copy()
|
|
43
|
-
output_df["G"] = G
|
|
44
|
-
|
|
45
|
-
return output_df
|
PMJPL/SEBAL/__init__.py
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
from .SEBAL import *
|
PMJPL/soil_heat_flux/__init__.py
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
from .soil_heat_flux import *
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
from typing import Union
|
|
2
|
-
import numpy as np
|
|
3
|
-
|
|
4
|
-
import rasters as rt
|
|
5
|
-
from rasters import Raster
|
|
6
|
-
|
|
7
|
-
from ..santanello import calculate_soil_heat_flux as santanello_G
|
|
8
|
-
from ..SEBAL import calculate_soil_heat_flux as SEBAL_G
|
|
9
|
-
|
|
10
|
-
DEFAULT_G_METHOD = "santanello"
|
|
11
|
-
|
|
12
|
-
def calculate_soil_heat_flux(
|
|
13
|
-
seconds_of_day: Union[Raster, np.ndarray] = None,
|
|
14
|
-
ST_C: Union[Raster, np.ndarray] = None,
|
|
15
|
-
NDVI: Union[Raster, np.ndarray] = None,
|
|
16
|
-
albedo: Union[Raster, np.ndarray] = None,
|
|
17
|
-
Rn: Union[Raster, np.ndarray] = None,
|
|
18
|
-
SM: Union[Raster, np.ndarray] = None,
|
|
19
|
-
method: str = DEFAULT_G_METHOD) -> Union[Raster, np.ndarray]:
|
|
20
|
-
"""
|
|
21
|
-
The method estimates soil heat flux (G) as a function of time of day, net radiation (Rn), soil moisture (SM),
|
|
22
|
-
surface temperature (ST_C), Normalized Difference Vegetation Index (NDVI), and albedo. The method used for
|
|
23
|
-
calculation can be specified.
|
|
24
|
-
|
|
25
|
-
Parameters:
|
|
26
|
-
seconds_of_day (np.ndarray): Time in seconds of the day since midnight.
|
|
27
|
-
ST_C (np.ndarray): Surface temperature in Celsius.
|
|
28
|
-
NDVI (np.ndarray): Normalized Difference Vegetation Index.
|
|
29
|
-
albedo (np.ndarray): Albedo of the surface.
|
|
30
|
-
Rn (np.ndarray): Net radiation in W/m^2.
|
|
31
|
-
SM (np.ndarray): Soil moisture in m^3/m^3.
|
|
32
|
-
method (str, optional): Method to be used for calculation. Defaults to "santanello".
|
|
33
|
-
|
|
34
|
-
Returns:
|
|
35
|
-
G (np.ndarray): Soil heat flux in W/m^2.
|
|
36
|
-
"""
|
|
37
|
-
|
|
38
|
-
# FIXME make sure G doesn't drop to extreme negative values
|
|
39
|
-
|
|
40
|
-
if method == "santanello":
|
|
41
|
-
G = santanello_G(
|
|
42
|
-
seconds_of_day=seconds_of_day,
|
|
43
|
-
Rn=Rn,
|
|
44
|
-
SM=SM
|
|
45
|
-
)
|
|
46
|
-
elif method == "SEBAL":
|
|
47
|
-
G = SEBAL_G(
|
|
48
|
-
Rn=Rn,
|
|
49
|
-
ST_C=ST_C,
|
|
50
|
-
NDVI=NDVI,
|
|
51
|
-
albedo=albedo
|
|
52
|
-
)
|
|
53
|
-
elif method == "MOD16":
|
|
54
|
-
G = (-0.276 * NDVI + 0.35) * Rn
|
|
55
|
-
elif method == "PTJPL":
|
|
56
|
-
G = rt.clip(Rn * (0.05 + (1 - rt.clip(NDVI, 0, 1)) * 0.265), 0, 0.35 * Rn)
|
|
57
|
-
else:
|
|
58
|
-
raise ValueError(f"invalid soil heat flux method: {method}")
|
|
59
|
-
|
|
60
|
-
G = rt.clip(G, 0, None)
|
|
61
|
-
|
|
62
|
-
return G
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
from .verma_net_radiation import *
|
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
from typing import Union, Dict
|
|
2
|
-
import warnings
|
|
3
|
-
import numpy as np
|
|
4
|
-
from sun_angles import daylight_from_SHA
|
|
5
|
-
from sun_angles import sunrise_from_SHA
|
|
6
|
-
from sun_angles import SHA_deg_from_DOY_lat
|
|
7
|
-
from rasters import Raster
|
|
8
|
-
|
|
9
|
-
STEFAN_BOLTZMAN_CONSTANT = 5.67036713e-8 # SI units watts per square meter per kelvin to the fourth
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
def process_verma_net_radiation(
|
|
13
|
-
SWin: np.ndarray,
|
|
14
|
-
albedo: np.ndarray,
|
|
15
|
-
ST_C: np.ndarray,
|
|
16
|
-
emissivity: np.ndarray,
|
|
17
|
-
Ta_C: np.ndarray,
|
|
18
|
-
RH: np.ndarray,
|
|
19
|
-
cloud_mask: np.ndarray = None) -> Dict:
|
|
20
|
-
results = {}
|
|
21
|
-
|
|
22
|
-
# Convert surface temperature from Celsius to Kelvin
|
|
23
|
-
ST_K = ST_C + 273.15
|
|
24
|
-
|
|
25
|
-
# Convert air temperature from Celsius to Kelvin
|
|
26
|
-
Ta_K = Ta_C + 273.15
|
|
27
|
-
|
|
28
|
-
# Calculate water vapor pressure in Pascals using air temperature and relative humidity
|
|
29
|
-
Ea_Pa = (RH * 0.6113 * (10 ** (7.5 * (Ta_K - 273.15) / (Ta_K - 35.85)))) * 1000
|
|
30
|
-
|
|
31
|
-
# constrain albedo between 0 and 1
|
|
32
|
-
albedo = np.clip(albedo, 0, 1)
|
|
33
|
-
|
|
34
|
-
# calculate outgoing shortwave from incoming shortwave and albedo
|
|
35
|
-
SWout = np.clip(SWin * albedo, 0, None)
|
|
36
|
-
results["SWout"] = SWout
|
|
37
|
-
|
|
38
|
-
# calculate instantaneous net radiation from components
|
|
39
|
-
SWnet = np.clip(SWin - SWout, 0, None)
|
|
40
|
-
|
|
41
|
-
# calculate atmospheric emissivity
|
|
42
|
-
eta1 = 0.465 * Ea_Pa / Ta_K
|
|
43
|
-
# atmospheric_emissivity = (1 - (1 + eta1) * np.exp(-(1.2 + 3 * eta1) ** 0.5))
|
|
44
|
-
eta2 = -(1.2 + 3 * eta1) ** 0.5
|
|
45
|
-
eta2 = eta2.astype(float)
|
|
46
|
-
eta3 = np.exp(eta2)
|
|
47
|
-
atmospheric_emissivity = np.where(eta2 != 0, (1 - (1 + eta1) * eta3), np.nan)
|
|
48
|
-
|
|
49
|
-
if cloud_mask is None:
|
|
50
|
-
# calculate incoming longwave for clear sky
|
|
51
|
-
LWin = atmospheric_emissivity * STEFAN_BOLTZMAN_CONSTANT * Ta_K ** 4
|
|
52
|
-
else:
|
|
53
|
-
# calculate incoming longwave for clear sky and cloudy
|
|
54
|
-
LWin = np.where(
|
|
55
|
-
~cloud_mask,
|
|
56
|
-
atmospheric_emissivity * STEFAN_BOLTZMAN_CONSTANT * Ta_K ** 4,
|
|
57
|
-
STEFAN_BOLTZMAN_CONSTANT * Ta_K ** 4
|
|
58
|
-
)
|
|
59
|
-
|
|
60
|
-
results["LWin"] = LWin
|
|
61
|
-
|
|
62
|
-
# constrain emissivity between 0 and 1
|
|
63
|
-
emissivity = np.clip(emissivity, 0, 1)
|
|
64
|
-
|
|
65
|
-
# calculate outgoing longwave from land surface temperature and emissivity
|
|
66
|
-
LWout = emissivity * STEFAN_BOLTZMAN_CONSTANT * ST_K ** 4
|
|
67
|
-
results["LWout"] = LWout
|
|
68
|
-
|
|
69
|
-
# LWnet = np.clip(LWin - LWout, 0, None)
|
|
70
|
-
LWnet = np.clip(LWin - LWout, 0, None)
|
|
71
|
-
|
|
72
|
-
# constrain negative values of instantaneous net radiation
|
|
73
|
-
Rn = np.clip(SWnet + LWnet, 0, None)
|
|
74
|
-
results["Rn"] = Rn
|
|
75
|
-
|
|
76
|
-
return results
|
|
77
|
-
|
|
78
|
-
def daily_Rn_integration_verma(
|
|
79
|
-
Rn: Union[Raster, np.ndarray],
|
|
80
|
-
hour_of_day: Union[Raster, np.ndarray],
|
|
81
|
-
DOY: Union[Raster, np.ndarray] = None,
|
|
82
|
-
lat: Union[Raster, np.ndarray] = None,
|
|
83
|
-
sunrise_hour: Union[Raster, np.ndarray] = None,
|
|
84
|
-
daylight_hours: Union[Raster, np.ndarray] = None) -> Raster:
|
|
85
|
-
"""
|
|
86
|
-
calculate daily net radiation using solar parameters
|
|
87
|
-
this is the average rate of energy transfer from sunrise to sunset
|
|
88
|
-
in watts per square meter
|
|
89
|
-
watts are joules per second
|
|
90
|
-
to get the total amount of energy transferred, factor seconds out of joules
|
|
91
|
-
the number of seconds for which this average is representative is (daylight_hours * 3600)
|
|
92
|
-
documented in verma et al, bisht et al, and lagouARDe et al
|
|
93
|
-
:param Rn:
|
|
94
|
-
:param hour_of_day:
|
|
95
|
-
:param sunrise_hour:
|
|
96
|
-
:param daylight_hours:
|
|
97
|
-
:return:
|
|
98
|
-
"""
|
|
99
|
-
if daylight_hours is None or sunrise_hour is None and DOY is not None and lat is not None:
|
|
100
|
-
sha_deg = SHA_deg_from_DOY_lat(DOY=DOY, latitude=lat)
|
|
101
|
-
daylight_hours = daylight_from_SHA(sha_deg)
|
|
102
|
-
sunrise_hour = sunrise_from_SHA(sha_deg)
|
|
103
|
-
|
|
104
|
-
with warnings.catch_warnings():
|
|
105
|
-
warnings.filterwarnings("ignore")
|
|
106
|
-
Rn_daily = 1.6 * Rn / (np.pi * np.sin(np.pi * (hour_of_day - sunrise_hour) / (daylight_hours)))
|
|
107
|
-
|
|
108
|
-
return Rn_daily
|
pm_jpl-1.2.2.dist-info/RECORD
DELETED
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
PMJPL/PMJPL.py,sha256=QXhLgqeOiLCFjtYHr_01hUfusVL_iOqeK_PXANeKdsU,12819
|
|
2
|
-
PMJPL/VPD_factor.py,sha256=mEi3qXClc07QT2wlfCgzaFkERbm_D8JqWKmB86pJMVk,970
|
|
3
|
-
PMJPL/__init__.py,sha256=rqFqtI2rLgIxSN3i2J8wZVoT2EpHYgVizfZt8ctwqsc,213
|
|
4
|
-
PMJPL/canopy_aerodynamic_resistance.py,sha256=ejcmjGNimv2aja6WFRC_2D_48YD2fVHE3ndWHbGbxfM,1217
|
|
5
|
-
PMJPL/canopy_conductance.py,sha256=1e2KwFGiRrXMJvG0iHwP3cpQ68HFB44eQ0CXsv1mQ-A,1367
|
|
6
|
-
PMJPL/constants.py,sha256=Az7hftY_CIibJdvRdQcDisRdKqJYm8khktakCcNZtXU,787
|
|
7
|
-
PMJPL/correctance_factor.py,sha256=V93rZcv5DM3LfujhEK8mRgJ-GHk868hDbTmcg8VoOAo,582
|
|
8
|
-
PMJPL/fwet.py,sha256=-5GEGC1ohKBzsuYGLNiCaVe10DQLm82rsZTZGVxb4WY,616
|
|
9
|
-
PMJPL/interception.py,sha256=lJ_kAa_Xkr21iWcVtSmLoNPfHEzCuiFSVRxB4-NUs9k,1689
|
|
10
|
-
PMJPL/mod16.csv,sha256=1aVfqLOAJwYuZPaScyqbk4yacObPgp8Q-IPzJm0yReY,847
|
|
11
|
-
PMJPL/parameters.py,sha256=hiMXIafFkS4rqDQVvPhCFuiLc-WXTwlRyS-eIK9vQuk,1973
|
|
12
|
-
PMJPL/potential_soil_evaporation.py,sha256=Xq-cvOqOa9W1FFHMmPKGtZs18tiDRUDOQ86-8rONO_Y,1823
|
|
13
|
-
PMJPL/soil_moisture_constraint.py,sha256=URUGsE1_p2P1dVQ8qKRcKb93hahYWtAmYqoassRu-PI,667
|
|
14
|
-
PMJPL/tmin_factor.py,sha256=BqSPM3Y8eB2fekSxUf9dzmAT_5UPNz0eY_wWnlvn1Xg,1595
|
|
15
|
-
PMJPL/transpiration.py,sha256=8wxCsXURWabn8ARUDnekG3-igdygtlX9SgLrQu_RMaA,1980
|
|
16
|
-
PMJPL/version.txt,sha256=HsT6sNjdXq_vguZ_YaNcA-6ZSYilKT4Xzz0-l8NRGEc,5
|
|
17
|
-
PMJPL/wet_canopy_resistance.py,sha256=q1RBq6SePklb-XLmv3zPbLX5rxtZ4uxvEecB9faJlyE,792
|
|
18
|
-
PMJPL/wet_soil_evaporation.py,sha256=1lZ0qokBffZTCKuuh0M3jYtR2nbJyVLe15gFzXRlBU0,1416
|
|
19
|
-
PMJPL/MCD12C1/MCD12C1.py,sha256=2zq6QW9SJGnADwbExZ7JvAaUcBrHeBSDiRS46RrumAY,378
|
|
20
|
-
PMJPL/MCD12C1/__init__.py,sha256=4_gn1pQK9nuh7ZuUTFpaFhT6ypSvsIxBwIpOYmw5Vfg,23
|
|
21
|
-
PMJPL/SEBAL/SEBAL.py,sha256=IBKKYbZzk0WOND6eRVdgTyqnsLriwOFECGBKIf0nOFk,1688
|
|
22
|
-
PMJPL/SEBAL/__init__.py,sha256=IK_eHynpUb_XvECuLOfE0h3Js-4vdeXqCEe9y5oeKWw,21
|
|
23
|
-
PMJPL/downscaling/__init__.py,sha256=xvhP4rHzx-nK_R6HSarJ-WF1bMPXYZGvvr8Hk84-q40,27
|
|
24
|
-
PMJPL/downscaling/downscaling.py,sha256=VuhFbK92llJbtkOtJpah_51sM5ctFJ9oNUaH4aaNO7g,8447
|
|
25
|
-
PMJPL/downscaling/linear_downscale.py,sha256=Yi0d2rb1XVSlBJoL2Arq9RtU5FH1RJ98MHLngJIYUjM,2466
|
|
26
|
-
PMJPL/evapotranspiration_conversion/__init__.py,sha256=21wYXP8FJT63MpUTbHu0wGntyFFeiGDRneGMKCNAu8Q,45
|
|
27
|
-
PMJPL/evapotranspiration_conversion/evapotranspiration_conversion.py,sha256=kwxLb_Vli_Tfal4lWBHMkEMmpCV7Kha_0wgqk8HjlXs,2754
|
|
28
|
-
PMJPL/meteorology_conversion/__init__.py,sha256=dLF40imqJCC_l8_QMetbsj1YzkXZuFt9tQ2fsd7Wcdw,38
|
|
29
|
-
PMJPL/meteorology_conversion/meteorology_conversion.py,sha256=8vzx71FLLNhR5v6EQBL8OSgAmupQcgdLX2c9tL9TPxA,4202
|
|
30
|
-
PMJPL/penman_monteith/__init__.py,sha256=vcfkNo6BLDCfSF9HZFDvRMAKCx49F9idN7iNTKQCpcA,31
|
|
31
|
-
PMJPL/penman_monteith/penman_monteith.py,sha256=2rSFP9_DBz1vMSbVyBQGhW-VXXb5XT8a7ls8sCstfXU,819
|
|
32
|
-
PMJPL/priestley_taylor/__init__.py,sha256=E0SiG_DNAsMz_8A3342UPwbDyrMOgd35AZ-plaJar5s,32
|
|
33
|
-
PMJPL/priestley_taylor/priestley_taylor.py,sha256=Rj168jfWHSBhGeUkDs6ePrVsHhFbmUujzQaA8z0fCXE,1126
|
|
34
|
-
PMJPL/santanello/__init__.py,sha256=HXZS1p3sp4mDJCXkdq___ZIJ9etu7-B8yauJcFvQFgQ,26
|
|
35
|
-
PMJPL/santanello/santanello.py,sha256=lvgskYrirQz0t1m4XNSj8hLzrESS-oVZzMvAnVPyt3g,1521
|
|
36
|
-
PMJPL/soil_heat_flux/__init__.py,sha256=bES8bWQhwRLmyJPsaFB190yiuz2mHyJM1X8Q1KbwwEE,30
|
|
37
|
-
PMJPL/soil_heat_flux/soil_heat_flux.py,sha256=wg5h6FmIxGFYDFRyQ_0D3GaL5PIiYonuz8u4o8MPaKw,2092
|
|
38
|
-
PMJPL/vegetation_conversion/__init__.py,sha256=8gnz0yK_euCV0TtVGDrSGaVfx4g0EJCG2J68ppuA5oc,37
|
|
39
|
-
PMJPL/vegetation_conversion/vegetation_conversion.py,sha256=-K3FLV6pXkpxtRxQvimqqkXAgkn9mUUlHQ8FIscq1Zg,1306
|
|
40
|
-
PMJPL/verma_net_radiation/__init__.py,sha256=5TzlqNWajiVxbQdUqjWuu17oBrTmjIeaF40nQPnVzWo,35
|
|
41
|
-
PMJPL/verma_net_radiation/verma_net_radiation.py,sha256=Y4OxcuBXTY6IZzZ6cXjxp2xTyeSAfYQ_itws0PcSc-I,3869
|
|
42
|
-
pm_jpl-1.2.2.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
43
|
-
pm_jpl-1.2.2.dist-info/METADATA,sha256=N9Ke0Mpdy46foPoOfBbj5jEvdAQeGN4zIX1iVpgMTGk,4260
|
|
44
|
-
pm_jpl-1.2.2.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
|
|
45
|
-
pm_jpl-1.2.2.dist-info/top_level.txt,sha256=YaAFwdYHUxfUW08hiuFquUEdDGrsYn1duuMMjJKh0Ws,6
|
|
46
|
-
pm_jpl-1.2.2.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|