PM-JPL 1.2.1__tar.gz → 1.3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of PM-JPL might be problematic. Click here for more details.

Files changed (54) hide show
  1. {pm_jpl-1.2.1 → pm_jpl-1.3.0}/PKG-INFO +11 -20
  2. {pm_jpl-1.2.1 → pm_jpl-1.3.0}/PMJPL/PMJPL.py +169 -80
  3. {pm_jpl-1.2.1 → pm_jpl-1.3.0}/PMJPL/VPD_factor.py +1 -1
  4. {pm_jpl-1.2.1 → pm_jpl-1.3.0}/PMJPL/canopy_aerodynamic_resistance.py +1 -1
  5. {pm_jpl-1.2.1 → pm_jpl-1.3.0}/PMJPL/canopy_conductance.py +1 -1
  6. {pm_jpl-1.2.1 → pm_jpl-1.3.0}/PMJPL/evapotranspiration_conversion/evapotranspiration_conversion.py +3 -1
  7. {pm_jpl-1.2.1 → pm_jpl-1.3.0}/PMJPL/interception.py +1 -3
  8. pm_jpl-1.3.0/PMJPL/mod16.csv +1 -0
  9. {pm_jpl-1.2.1 → pm_jpl-1.3.0}/PMJPL/parameters.py +1 -1
  10. {pm_jpl-1.2.1 → pm_jpl-1.3.0}/PMJPL/penman_monteith/penman_monteith.py +0 -1
  11. {pm_jpl-1.2.1 → pm_jpl-1.3.0}/PMJPL/potential_soil_evaporation.py +2 -2
  12. {pm_jpl-1.2.1 → pm_jpl-1.3.0}/PMJPL/tmin_factor.py +1 -1
  13. {pm_jpl-1.2.1 → pm_jpl-1.3.0}/PMJPL/transpiration.py +4 -4
  14. pm_jpl-1.3.0/PMJPL/version.txt +1 -0
  15. {pm_jpl-1.2.1 → pm_jpl-1.3.0}/PMJPL/wet_canopy_resistance.py +1 -0
  16. {pm_jpl-1.2.1 → pm_jpl-1.3.0}/PMJPL/wet_soil_evaporation.py +4 -4
  17. {pm_jpl-1.2.1 → pm_jpl-1.3.0}/PM_JPL.egg-info/PKG-INFO +11 -20
  18. {pm_jpl-1.2.1 → pm_jpl-1.3.0}/PM_JPL.egg-info/SOURCES.txt +2 -8
  19. pm_jpl-1.3.0/PM_JPL.egg-info/requires.txt +21 -0
  20. {pm_jpl-1.2.1 → pm_jpl-1.3.0}/pyproject.toml +12 -21
  21. {pm_jpl-1.2.1 → pm_jpl-1.3.0}/tests/test_import_dependencies.py +6 -17
  22. pm_jpl-1.2.1/PMJPL/MCD12C1/MCD12C1.py +0 -10
  23. pm_jpl-1.2.1/PMJPL/MCD12C1/__init__.py +0 -1
  24. pm_jpl-1.2.1/PMJPL/SEBAL/SEBAL.py +0 -45
  25. pm_jpl-1.2.1/PMJPL/SEBAL/__init__.py +0 -1
  26. pm_jpl-1.2.1/PMJPL/soil_heat_flux/__init__.py +0 -1
  27. pm_jpl-1.2.1/PMJPL/soil_heat_flux/soil_heat_flux.py +0 -62
  28. pm_jpl-1.2.1/PMJPL/verma_net_radiation/__init__.py +0 -1
  29. pm_jpl-1.2.1/PMJPL/verma_net_radiation/verma_net_radiation.py +0 -108
  30. pm_jpl-1.2.1/PM_JPL.egg-info/requires.txt +0 -30
  31. {pm_jpl-1.2.1 → pm_jpl-1.3.0}/LICENSE +0 -0
  32. {pm_jpl-1.2.1 → pm_jpl-1.3.0}/PMJPL/__init__.py +0 -0
  33. {pm_jpl-1.2.1 → pm_jpl-1.3.0}/PMJPL/constants.py +0 -0
  34. {pm_jpl-1.2.1 → pm_jpl-1.3.0}/PMJPL/correctance_factor.py +0 -0
  35. {pm_jpl-1.2.1 → pm_jpl-1.3.0}/PMJPL/downscaling/__init__.py +0 -0
  36. {pm_jpl-1.2.1 → pm_jpl-1.3.0}/PMJPL/downscaling/downscaling.py +0 -0
  37. {pm_jpl-1.2.1 → pm_jpl-1.3.0}/PMJPL/downscaling/linear_downscale.py +0 -0
  38. {pm_jpl-1.2.1 → pm_jpl-1.3.0}/PMJPL/evapotranspiration_conversion/__init__.py +0 -0
  39. {pm_jpl-1.2.1 → pm_jpl-1.3.0}/PMJPL/fwet.py +0 -0
  40. {pm_jpl-1.2.1 → pm_jpl-1.3.0}/PMJPL/meteorology_conversion/__init__.py +0 -0
  41. {pm_jpl-1.2.1 → pm_jpl-1.3.0}/PMJPL/meteorology_conversion/meteorology_conversion.py +0 -0
  42. {pm_jpl-1.2.1 → pm_jpl-1.3.0}/PMJPL/penman_monteith/__init__.py +0 -0
  43. {pm_jpl-1.2.1 → pm_jpl-1.3.0}/PMJPL/priestley_taylor/__init__.py +0 -0
  44. {pm_jpl-1.2.1 → pm_jpl-1.3.0}/PMJPL/priestley_taylor/priestley_taylor.py +0 -0
  45. {pm_jpl-1.2.1 → pm_jpl-1.3.0}/PMJPL/santanello/__init__.py +0 -0
  46. {pm_jpl-1.2.1 → pm_jpl-1.3.0}/PMJPL/santanello/santanello.py +0 -0
  47. {pm_jpl-1.2.1 → pm_jpl-1.3.0}/PMJPL/soil_moisture_constraint.py +0 -0
  48. {pm_jpl-1.2.1 → pm_jpl-1.3.0}/PMJPL/vegetation_conversion/__init__.py +0 -0
  49. {pm_jpl-1.2.1 → pm_jpl-1.3.0}/PMJPL/vegetation_conversion/vegetation_conversion.py +0 -0
  50. {pm_jpl-1.2.1 → pm_jpl-1.3.0}/PM_JPL.egg-info/dependency_links.txt +0 -0
  51. {pm_jpl-1.2.1 → pm_jpl-1.3.0}/PM_JPL.egg-info/top_level.txt +0 -0
  52. {pm_jpl-1.2.1 → pm_jpl-1.3.0}/README.md +0 -0
  53. {pm_jpl-1.2.1 → pm_jpl-1.3.0}/setup.cfg +0 -0
  54. {pm_jpl-1.2.1 → pm_jpl-1.3.0}/tests/test_import_PM_JPL.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: PM-JPL
3
- Version: 1.2.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: affine
13
- Requires-Dist: astropy
14
- Requires-Dist: geopandas
15
- Requires-Dist: h5py
16
- Requires-Dist: keras
17
- Requires-Dist: matplotlib
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: pillow
21
- Requires-Dist: pygeos
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: tensorflow
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"
@@ -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 Callable, Dict, Union
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 pandas as pd
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 .MCD12C1.MCD12C1 import load_MCD12C1_IGBP
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, calculate_surface_pressure, celcius_to_kelvin
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, delta_kPa_from_Ta_C
29
+ from .priestley_taylor.priestley_taylor import delta_Pa_from_Ta_C
29
30
 
30
- from .soil_heat_flux import calculate_soil_heat_flux
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
- Ta_C: Union[Raster, np.ndarray],
74
- Tmin_C: Union[Raster, np.ndarray],
75
- RH: Union[Raster, np.ndarray],
76
- IGBP: Union[Raster, np.ndarray],
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
- elevation_m: Union[Raster, np.ndarray] = None,
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
- # calculate leaf area index if it's not given
84
- if LAI is None:
85
- # calculate leaf area index from NDVI
86
- LAI = LAI_from_NDVI(NDVI)
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="CL",
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, IGBP)
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="VPD_open",
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="VPD_close",
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
- rho=rho_kgm3,
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
- rho=rho_kgm3,
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
@@ -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(rt.logical_and(VPD_open < VPD, VPD < VPD_close), (VPD_close - VPD) / (VPD_close - VPD_open), mVPD)
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
- rt.logical_and(vpd_open < VPD, VPD < vpd_close),
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
  )
@@ -26,7 +26,7 @@ def calculate_canopy_conductance(
26
26
  """
27
27
  # noinspection PyTypeChecker
28
28
  Cc = rt.where(
29
- rt.logical_and(LAI > 0.0, (1.0 - fwet) > 0.0),
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
- from ..verma_net_radiation.verma_net_radiation import daily_Rn_integration_verma
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
@@ -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
@@ -0,0 +1 @@
1
+ LC,gl_sh,gl_e_wv,rbl_min,rbl_max,cl,tmin_open,tmin_close,vpd_close,vpd_open
@@ -5,7 +5,7 @@ import pandas as pd
5
5
 
6
6
  from rasters import Raster, RasterGeometry
7
7
 
8
- from .MCD12C1.MCD12C1 import load_MCD12C1_IGBP
8
+ from MCD12C1_2019_v006 import load_MCD12C1_IGBP
9
9
 
10
10
  LUT = pd.read_csv(join(abspath(dirname(__file__)), 'mod16.csv'))
11
11
 
@@ -1,7 +1,6 @@
1
1
  from typing import Union
2
2
  import numpy as np
3
3
  from ..evapotranspiration_conversion.evapotranspiration_conversion import lambda_Jkg_from_Ta_C
4
- from ..meteorology_conversion.meteorology_conversion import celcius_to_kelvin
5
4
 
6
5
  from rasters import Raster
7
6
 
@@ -11,7 +11,7 @@ def calculate_potential_soil_evaporation(
11
11
  rho: float,
12
12
  Cp_Jkg: float,
13
13
  FVC: float,
14
- VPD: float,
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) * VPD / ras) * (1.0 - fwet)
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
 
@@ -32,7 +32,7 @@ def calculate_tmin_factor(
32
32
  mTmin = rt.where(Tmin >= tmin_open, 1.0, np.nan)
33
33
 
34
34
  mTmin = rt.where(
35
- rt.logical_and(
35
+ np.logical_and(
36
36
  tmin_close < Tmin,
37
37
  Tmin < tmin_open
38
38
  ),
@@ -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
- rho: Union[Raster, np.ndarray],
12
- Cp: Union[Raster, np.ndarray],
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 + (rho * Cp * FVC * VPD_Pa / ra)) * (1.0 - fwet)
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(rt.isnan(LEc), 0.0, LEc)
42
+ LEc = rt.where(np.isnan(LEc), 0.0, LEc)
43
43
 
44
44
  return LEc
@@ -0,0 +1 @@
1
+ 1.3.0
@@ -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)
@@ -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
- rho: Union[Raster, np.ndarray],
11
- Cp: Union[Raster, np.ndarray],
10
+ rho_kgm3: Union[Raster, np.ndarray],
11
+ Cp_Jkg: Union[Raster, np.ndarray],
12
12
  FVC: Union[Raster, np.ndarray],
13
- VPD: Union[Raster, np.ndarray],
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 + rho * Cp * (1.0 - FVC) * VPD / ras) * fwet
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.2.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: affine
13
- Requires-Dist: astropy
14
- Requires-Dist: geopandas
15
- Requires-Dist: h5py
16
- Requires-Dist: keras
17
- Requires-Dist: matplotlib
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: pillow
21
- Requires-Dist: pygeos
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: tensorflow
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"
@@ -10,17 +10,15 @@ PMJPL/constants.py
10
10
  PMJPL/correctance_factor.py
11
11
  PMJPL/fwet.py
12
12
  PMJPL/interception.py
13
+ PMJPL/mod16.csv
13
14
  PMJPL/parameters.py
14
15
  PMJPL/potential_soil_evaporation.py
15
16
  PMJPL/soil_moisture_constraint.py
16
17
  PMJPL/tmin_factor.py
17
18
  PMJPL/transpiration.py
19
+ PMJPL/version.txt
18
20
  PMJPL/wet_canopy_resistance.py
19
21
  PMJPL/wet_soil_evaporation.py
20
- PMJPL/MCD12C1/MCD12C1.py
21
- PMJPL/MCD12C1/__init__.py
22
- PMJPL/SEBAL/SEBAL.py
23
- PMJPL/SEBAL/__init__.py
24
22
  PMJPL/downscaling/__init__.py
25
23
  PMJPL/downscaling/downscaling.py
26
24
  PMJPL/downscaling/linear_downscale.py
@@ -34,12 +32,8 @@ PMJPL/priestley_taylor/__init__.py
34
32
  PMJPL/priestley_taylor/priestley_taylor.py
35
33
  PMJPL/santanello/__init__.py
36
34
  PMJPL/santanello/santanello.py
37
- PMJPL/soil_heat_flux/__init__.py
38
- PMJPL/soil_heat_flux/soil_heat_flux.py
39
35
  PMJPL/vegetation_conversion/__init__.py
40
36
  PMJPL/vegetation_conversion/vegetation_conversion.py
41
- PMJPL/verma_net_radiation/__init__.py
42
- PMJPL/verma_net_radiation/verma_net_radiation.py
43
37
  PM_JPL.egg-info/PKG-INFO
44
38
  PM_JPL.egg-info/SOURCES.txt
45
39
  PM_JPL.egg-info/dependency_links.txt
@@ -0,0 +1,21 @@
1
+ check-distribution
2
+ ECOv002-CMR>=1.0.5
3
+ ECOv002-granules>=1.0.3
4
+ ECOv003-granules
5
+ GEOS5FP>=1.1.1
6
+ MCD12C1_2019_v006
7
+ NASADEM
8
+ numpy
9
+ pandas
10
+ rasters>=1.4.6
11
+ SEBAL-soil-heat-flux
12
+ sun-angles
13
+ verma-net-radiation
14
+
15
+ [dev]
16
+ build
17
+ pytest>=6.0
18
+ pytest-cov
19
+ jupyter
20
+ pytest
21
+ twine
@@ -3,7 +3,7 @@ requires = ["setuptools", "wheel"]
3
3
 
4
4
  [project]
5
5
  name = "PM-JPL"
6
- version = "1.2.1"
6
+ version = "1.3.0"
7
7
  description = "JPL implementation of the MOD16 evapotranspiration algorithm for high resolution instantaneous remote sensing imagery"
8
8
  readme = "README.md"
9
9
  authors = [
@@ -18,28 +18,19 @@ classifiers = [
18
18
  "Operating System :: OS Independent",
19
19
  ]
20
20
  dependencies = [
21
- "affine",
22
- "astropy",
23
- "geopandas",
24
- "h5py",
25
- "keras",
26
- "matplotlib",
21
+ "check-distribution",
22
+ "ECOv002-CMR>=1.0.5",
23
+ "ECOv002-granules>=1.0.3",
24
+ "ECOv003-granules",
25
+ "GEOS5FP>=1.1.1",
26
+ "MCD12C1_2019_v006",
27
+ "NASADEM",
27
28
  "numpy",
28
29
  "pandas",
29
- "pillow",
30
- "pygeos",
31
- "pyproj",
32
- "pyresample",
33
- "rasterio",
34
- "rasters",
35
- "requests",
36
- "scikit-image",
37
- "scipy",
38
- "shapely",
39
- "six",
30
+ "rasters>=1.4.6",
31
+ "SEBAL-soil-heat-flux",
40
32
  "sun-angles",
41
- "tensorflow",
42
- "urllib3",
33
+ "verma-net-radiation"
43
34
  ]
44
35
 
45
36
  requires-python = ">=3.10"
@@ -55,7 +46,7 @@ dev = [
55
46
  ]
56
47
 
57
48
  [tool.setuptools.package-data]
58
- PM_JPL = ["*.txt", "*.csv", "*.tif"]
49
+ PMJPL = ["*.txt", "*.csv", "*.tif"]
59
50
 
60
51
  [project.urls]
61
52
  "Homepage" = "https://github.com/JPL-Evapotranspiration-Algorithms/PM-JPL"
@@ -2,26 +2,15 @@ import pytest
2
2
 
3
3
  # List of dependencies
4
4
  dependencies = [
5
- "affine",
6
- "astropy",
7
- "geopandas",
8
- "h5py",
9
- "keras",
10
- "matplotlib",
5
+ "ECOv002_CMR",
6
+ "ECOv002_granules",
7
+ "GEOS5FP",
8
+ "NASADEM",
11
9
  "numpy",
12
- "PIL",
13
10
  "pandas",
14
- "pyproj",
15
- "pyresample",
16
- "rasterio",
17
- "requests",
18
- "scipy",
19
- "shapely",
20
- "six",
21
- "skimage",
11
+ "rasters",
22
12
  "sun_angles",
23
- "tensorflow",
24
- "urllib3"
13
+ "verma_net_radiation"
25
14
  ]
26
15
 
27
16
  # Generate individual test functions for each dependency
@@ -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
@@ -1 +0,0 @@
1
- from .MCD12C1 import *
@@ -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
@@ -1 +0,0 @@
1
- from .SEBAL import *
@@ -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
@@ -1,30 +0,0 @@
1
- affine
2
- astropy
3
- geopandas
4
- h5py
5
- keras
6
- matplotlib
7
- numpy
8
- pandas
9
- pillow
10
- pygeos
11
- pyproj
12
- pyresample
13
- rasterio
14
- rasters
15
- requests
16
- scikit-image
17
- scipy
18
- shapely
19
- six
20
- sun-angles
21
- tensorflow
22
- urllib3
23
-
24
- [dev]
25
- build
26
- pytest>=6.0
27
- pytest-cov
28
- jupyter
29
- pytest
30
- twine
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes