PM-JPL 1.2.1__py3-none-any.whl → 1.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.
- PMJPL/ECOv002-cal-val-PM-JPL-inputs.csv +1048 -0
- PMJPL/ECOv002-cal-val-PM-JPL-outputs.csv +1048 -0
- PMJPL/ECOv002-static-tower-PM-JPL-inputs.csv +122 -0
- PMJPL/ECOv002_calval_PMJPL_inputs.py +19 -0
- PMJPL/ECOv002_static_tower_PMJPL_inputs.py +19 -0
- PMJPL/PMJPL.py +45 -378
- PMJPL/{parameters.py → PMJPL_parameter_from_IGBP.py} +22 -7
- PMJPL/VPD_factor.py +1 -1
- PMJPL/__init__.py +1 -6
- PMJPL/calculate_gamma.py +128 -0
- PMJPL/canopy_aerodynamic_resistance.py +151 -18
- PMJPL/canopy_conductance.py +71 -15
- PMJPL/closed_minimum_temperature.py +11 -0
- PMJPL/closed_vapor_pressure_deficit.py +11 -0
- PMJPL/constants.py +6 -1
- PMJPL/correctance_factor.py +56 -7
- PMJPL/generate_PMJPL_inputs.py +263 -0
- PMJPL/interception.py +1 -3
- PMJPL/leaf_conductance_to_evaporated_water.py +11 -0
- PMJPL/leaf_conductance_to_sensible_heat.py +58 -0
- PMJPL/maximum_boundary_layer_resistance.py +11 -0
- PMJPL/minimum_boundary_layer_resistance.py +11 -0
- PMJPL/{tmin_factor.py → minimum_temperature_factor.py} +2 -2
- PMJPL/mod16.csv +19 -0
- PMJPL/model.py +690 -0
- PMJPL/open_minimum_temperature.py +11 -0
- PMJPL/open_vapor_pressure_deficit.py +11 -0
- PMJPL/potential_soil_evaporation.py +2 -2
- PMJPL/potential_stomatal_conductance.py +11 -0
- PMJPL/process_PMJPL_table.py +208 -0
- PMJPL/process_daily_ET_table.py +40 -0
- PMJPL/transpiration.py +4 -4
- PMJPL/verify.py +77 -0
- PMJPL/version.py +4 -0
- PMJPL/wet_canopy_resistance.py +1 -0
- PMJPL/wet_soil_evaporation.py +4 -4
- {pm_jpl-1.2.1.dist-info → pm_jpl-1.7.0.dist-info}/METADATA +18 -21
- pm_jpl-1.7.0.dist-info/RECORD +42 -0
- {pm_jpl-1.2.1.dist-info → pm_jpl-1.7.0.dist-info}/WHEEL +1 -1
- 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/downscaling/__init__.py +0 -1
- PMJPL/downscaling/downscaling.py +0 -271
- PMJPL/downscaling/linear_downscale.py +0 -71
- PMJPL/evapotranspiration_conversion/__init__.py +0 -1
- PMJPL/evapotranspiration_conversion/evapotranspiration_conversion.py +0 -80
- PMJPL/fwet.py +0 -21
- PMJPL/meteorology_conversion/__init__.py +0 -1
- PMJPL/meteorology_conversion/meteorology_conversion.py +0 -123
- PMJPL/penman_monteith/__init__.py +0 -1
- PMJPL/penman_monteith/penman_monteith.py +0 -20
- PMJPL/priestley_taylor/__init__.py +0 -1
- PMJPL/priestley_taylor/priestley_taylor.py +0 -27
- PMJPL/santanello/__init__.py +0 -1
- PMJPL/santanello/santanello.py +0 -46
- PMJPL/soil_heat_flux/__init__.py +0 -1
- PMJPL/soil_heat_flux/soil_heat_flux.py +0 -62
- PMJPL/vegetation_conversion/__init__.py +0 -1
- PMJPL/vegetation_conversion/vegetation_conversion.py +0 -47
- PMJPL/verma_net_radiation/__init__.py +0 -1
- PMJPL/verma_net_radiation/verma_net_radiation.py +0 -108
- pm_jpl-1.2.1.dist-info/RECORD +0 -44
- {pm_jpl-1.2.1.dist-info → pm_jpl-1.7.0.dist-info}/licenses/LICENSE +0 -0
- {pm_jpl-1.2.1.dist-info → pm_jpl-1.7.0.dist-info}/top_level.txt +0 -0
PMJPL/model.py
ADDED
|
@@ -0,0 +1,690 @@
|
|
|
1
|
+
|
|
2
|
+
"""
|
|
3
|
+
MOD16 model of evapotranspiration
|
|
4
|
+
|
|
5
|
+
This implementation follows the MOD16 Version 1.5 Collection 6 algorithm described in the MOD16 user's guide.
|
|
6
|
+
https://landweb.nascom.nasa.gov/QA_WWW/forPage/user_guide/MOD16UsersGuide2016.pdf
|
|
7
|
+
|
|
8
|
+
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.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
# All imports moved to the top
|
|
12
|
+
import logging
|
|
13
|
+
from typing import Dict, Union
|
|
14
|
+
from datetime import datetime
|
|
15
|
+
|
|
16
|
+
import numpy as np
|
|
17
|
+
import rasters as rt
|
|
18
|
+
from rasters import Raster, RasterGrid, RasterGeometry, VectorGeometry
|
|
19
|
+
|
|
20
|
+
from check_distribution import check_distribution
|
|
21
|
+
from GEOS5FP import GEOS5FP
|
|
22
|
+
from NASADEM import NASADEM
|
|
23
|
+
from verma_net_radiation import verma_net_radiation
|
|
24
|
+
from SEBAL_soil_heat_flux import calculate_SEBAL_soil_heat_flux
|
|
25
|
+
from MCD12C1_2019_v006 import load_MCD12C1_IGBP
|
|
26
|
+
|
|
27
|
+
from carlson_leaf_area_index import carlson_leaf_area_index
|
|
28
|
+
from carlson_fractional_vegetation_cover import carlson_fractional_vegetation_cover
|
|
29
|
+
from carlson_leaf_area_index import carlson_leaf_area_index
|
|
30
|
+
|
|
31
|
+
from daylight_evapotranspiration import lambda_Jkg_from_Ta_C, daylight_ET_from_instantaneous_LE
|
|
32
|
+
|
|
33
|
+
from meteorology_conversion import SVP_Pa_from_Ta_C
|
|
34
|
+
from meteorology_conversion import calculate_air_density
|
|
35
|
+
from meteorology_conversion import calculate_specific_heat
|
|
36
|
+
from meteorology_conversion import calculate_specific_humidity
|
|
37
|
+
from meteorology_conversion import calculate_surface_pressure
|
|
38
|
+
from meteorology_conversion import celcius_to_kelvin
|
|
39
|
+
|
|
40
|
+
from priestley_taylor import delta_Pa_from_Ta_C
|
|
41
|
+
from PTJPL import calculate_relative_surface_wetness
|
|
42
|
+
from PTJPL import RH_THRESHOLD, MIN_FWET
|
|
43
|
+
|
|
44
|
+
from .constants import *
|
|
45
|
+
from .PMJPL_parameter_from_IGBP import PMJPL_parameter_from_IGBP
|
|
46
|
+
from .calculate_gamma import calculate_gamma
|
|
47
|
+
from .soil_moisture_constraint import calculate_fSM
|
|
48
|
+
from .minimum_temperature_factor import Tmin_factor
|
|
49
|
+
from .correctance_factor import calculate_correctance_factor
|
|
50
|
+
from .VPD_factor import calculate_VPD_factor
|
|
51
|
+
from .canopy_conductance import calculate_canopy_conductance
|
|
52
|
+
from .wet_canopy_resistance import calculate_wet_canopy_resistance
|
|
53
|
+
from .canopy_aerodynamic_resistance import calculate_canopy_aerodynamic_resistance
|
|
54
|
+
from .wet_soil_evaporation import calculate_wet_soil_evaporation
|
|
55
|
+
from .potential_soil_evaporation import calculate_potential_soil_evaporation
|
|
56
|
+
from .interception import calculate_interception
|
|
57
|
+
from .transpiration import calculate_transpiration
|
|
58
|
+
from .leaf_conductance_to_sensible_heat import leaf_conductance_to_sensible_heat
|
|
59
|
+
from .potential_stomatal_conductance import potential_stomatal_conductance
|
|
60
|
+
from .open_minimum_temperature import open_minimum_temperature
|
|
61
|
+
from .closed_minimum_temperature import closed_minimum_temperature
|
|
62
|
+
from .open_vapor_pressure_deficit import open_vapor_pressure_deficit
|
|
63
|
+
from .closed_vapor_pressure_deficit import closed_vapor_pressure_deficit
|
|
64
|
+
from .leaf_conductance_to_evaporated_water import leaf_conductance_to_evaporated_water
|
|
65
|
+
from .maximum_boundary_layer_resistance import maximum_boundary_layer_resistance
|
|
66
|
+
from .minimum_boundary_layer_resistance import minimum_boundary_layer_resistance
|
|
67
|
+
|
|
68
|
+
__author__ = 'Qiaozhen Mu, Maosheng Zhao, Steven W. Running, Gregory Halverson'
|
|
69
|
+
|
|
70
|
+
logger = logging.getLogger(__name__)
|
|
71
|
+
|
|
72
|
+
def PMJPL(
|
|
73
|
+
NDVI: Union[Raster, np.ndarray],
|
|
74
|
+
ST_C: Union[Raster, np.ndarray] = None,
|
|
75
|
+
emissivity: Union[Raster, np.ndarray] = None,
|
|
76
|
+
albedo: Union[Raster, np.ndarray] = None,
|
|
77
|
+
Rn_Wm2: Union[Raster, np.ndarray] = None,
|
|
78
|
+
G_Wm2: Union[Raster, np.ndarray] = None,
|
|
79
|
+
SWin_Wm2: Union[Raster, np.ndarray] = None,
|
|
80
|
+
Ta_C: Union[Raster, np.ndarray] = None,
|
|
81
|
+
Tmin_C: Union[Raster, np.ndarray] = None,
|
|
82
|
+
RH: Union[Raster, np.ndarray] = None,
|
|
83
|
+
IGBP: Union[Raster, np.ndarray] = None,
|
|
84
|
+
FVC: Union[Raster, np.ndarray] = None,
|
|
85
|
+
geometry: RasterGeometry = None,
|
|
86
|
+
time_UTC: datetime = None,
|
|
87
|
+
GEOS5FP_connection: GEOS5FP = None,
|
|
88
|
+
resampling: str = "nearest",
|
|
89
|
+
Ps_Pa: Union[Raster, np.ndarray] = None,
|
|
90
|
+
elevation_km: Union[Raster, np.ndarray] = None,
|
|
91
|
+
delta_Pa: Union[Raster, np.ndarray] = None,
|
|
92
|
+
lambda_Jkg: Union[Raster, np.ndarray] = None,
|
|
93
|
+
gamma_Jkg: Union[Raster, np.ndarray, float] = None,
|
|
94
|
+
gl_sh: Union[Raster, np.ndarray] = None,
|
|
95
|
+
CL: Union[Raster, np.ndarray] = None,
|
|
96
|
+
Tmin_open: Union[Raster, np.ndarray] = None,
|
|
97
|
+
Tmin_closed: Union[Raster, np.ndarray] = None,
|
|
98
|
+
VPD_open: Union[Raster, np.ndarray] = None,
|
|
99
|
+
VPD_closed: Union[Raster, np.ndarray] = None,
|
|
100
|
+
gl_e_wv: Union[Raster, np.ndarray] = None,
|
|
101
|
+
RBL_max: Union[Raster, np.ndarray] = None,
|
|
102
|
+
RBL_min: Union[Raster, np.ndarray] = None,
|
|
103
|
+
RH_threshold: float = RH_THRESHOLD,
|
|
104
|
+
min_fwet: float = MIN_FWET,
|
|
105
|
+
IGBP_upsampling_resolution_meters: float = IGBP_UPSAMPLING_RESOLUTION_METERS,
|
|
106
|
+
upscale_to_daylight: bool = False,
|
|
107
|
+
Rn_daylight_Wm2: Union[Raster, np.ndarray] = None,
|
|
108
|
+
day_of_year: np.ndarray = None,
|
|
109
|
+
regenerate_net_radiation: bool = False
|
|
110
|
+
) -> Dict[str, Raster]:
|
|
111
|
+
"""
|
|
112
|
+
MOD16 Penman-Monteith Evapotranspiration Model (Version 1.5, Collection 6)
|
|
113
|
+
|
|
114
|
+
Implements the MOD16 algorithm for partitioning daylight latent heat flux (LE) into canopy transpiration, soil evaporation, and wet canopy evaporation, following Mu et al. (2011) and the MOD16 User Guide (2016).
|
|
115
|
+
|
|
116
|
+
Scientific Overview:
|
|
117
|
+
-------------------
|
|
118
|
+
This function estimates daylight evapotranspiration (ET) and its components using satellite-derived vegetation indices, land cover, and meteorological data. It applies the Penman-Monteith equation, partitioning energy and resistances according to biophysical and meteorological constraints. The model is designed for gridded raster inputs but supports numpy arrays for flexibility.
|
|
119
|
+
|
|
120
|
+
Key Steps:
|
|
121
|
+
- Retrieves or computes all necessary meteorological and surface variables (temperature, humidity, pressure, radiation, NDVI, LAI, FVC, etc.).
|
|
122
|
+
- Calculates net radiation (Verma et al., 1989), soil heat flux (SEBAL; Bastiaanssen et al., 1998), and meteorological properties (Allen et al., 1998).
|
|
123
|
+
- Computes resistances and conductances for canopy and soil evaporation, including biome-specific and environmental constraints (Mu et al., 2011; Monteith, 1965).
|
|
124
|
+
- Partitions LE into wet canopy evaporation, transpiration, and soil evaporation, applying soil moisture and surface wetness constraints.
|
|
125
|
+
|
|
126
|
+
Parameters
|
|
127
|
+
----------
|
|
128
|
+
NDVI : Raster or np.ndarray
|
|
129
|
+
Normalized Difference Vegetation Index.
|
|
130
|
+
ST_C : Raster or np.ndarray, optional
|
|
131
|
+
Surface temperature (Celsius).
|
|
132
|
+
emissivity : Raster or np.ndarray, optional
|
|
133
|
+
Surface emissivity.
|
|
134
|
+
albedo : Raster or np.ndarray, optional
|
|
135
|
+
Surface albedo.
|
|
136
|
+
Rn_Wm2 : Raster or np.ndarray, optional
|
|
137
|
+
Net radiation (W/m^2).
|
|
138
|
+
G_Wm2 : Raster or np.ndarray, optional
|
|
139
|
+
Soil heat flux (W/m^2).
|
|
140
|
+
SWin_Wm2 : Raster or np.ndarray, optional
|
|
141
|
+
Incoming shortwave radiation (W/m^2).
|
|
142
|
+
Ta_C : Raster or np.ndarray, optional
|
|
143
|
+
Air temperature (Celsius).
|
|
144
|
+
Tmin_C : Raster or np.ndarray, optional
|
|
145
|
+
Minimum air temperature (Celsius).
|
|
146
|
+
RH : Raster or np.ndarray, optional
|
|
147
|
+
Relative humidity (fraction).
|
|
148
|
+
IGBP : Raster or np.ndarray, optional
|
|
149
|
+
Land cover classification (IGBP).
|
|
150
|
+
FVC : Raster or np.ndarray, optional
|
|
151
|
+
Fractional vegetation cover.
|
|
152
|
+
geometry : RasterGeometry, optional
|
|
153
|
+
Spatial geometry for raster data.
|
|
154
|
+
time_UTC : datetime, optional
|
|
155
|
+
Timestamp for meteorological data.
|
|
156
|
+
GEOS5FP_connection : GEOS5FP, optional
|
|
157
|
+
Meteorological data source.
|
|
158
|
+
resampling : str, optional
|
|
159
|
+
Resampling method for raster data.
|
|
160
|
+
Ps_Pa : Raster or np.ndarray, optional
|
|
161
|
+
Surface pressure (Pa).
|
|
162
|
+
elevation_km : Raster or np.ndarray, optional
|
|
163
|
+
Elevation (km).
|
|
164
|
+
delta_Pa : Raster or np.ndarray, optional
|
|
165
|
+
Slope of saturation vapor pressure curve (Pa/°C).
|
|
166
|
+
lambda_Jkg : Raster or np.ndarray, optional
|
|
167
|
+
Latent heat of vaporization (J/kg).
|
|
168
|
+
gamma_Jkg : Raster, np.ndarray, or float, optional
|
|
169
|
+
Psychrometric constant (J/kg).
|
|
170
|
+
gl_sh : Raster or np.ndarray, optional
|
|
171
|
+
Leaf conductance to sensible heat.
|
|
172
|
+
CL : Raster or np.ndarray, optional
|
|
173
|
+
Potential stomatal conductance.
|
|
174
|
+
Tmin_open, Tmin_closed : Raster or np.ndarray, optional
|
|
175
|
+
Open/closed minimum temperature by land cover.
|
|
176
|
+
VPD_open, VPD_closed : Raster or np.ndarray, optional
|
|
177
|
+
Open/closed vapor pressure deficit by land cover.
|
|
178
|
+
gl_e_wv : Raster or np.ndarray, optional
|
|
179
|
+
Leaf conductance to evaporated water vapor.
|
|
180
|
+
RBL_max, RBL_min : Raster or np.ndarray, optional
|
|
181
|
+
Maximum/minimum boundary layer resistance.
|
|
182
|
+
RH_threshold : float, optional
|
|
183
|
+
RH threshold for surface wetness.
|
|
184
|
+
min_fwet : float, optional
|
|
185
|
+
Minimum surface wetness.
|
|
186
|
+
IGBP_upsampling_resolution_meters : float, optional
|
|
187
|
+
Resolution for upsampling IGBP data.
|
|
188
|
+
upscale_to_daylight : bool, optional
|
|
189
|
+
Whether to upscale instantaneous values to daylight estimates.
|
|
190
|
+
regenerate_net_radiation : bool, optional
|
|
191
|
+
Whether to regenerate net radiation from surface components even if Rn_Wm2 is provided.
|
|
192
|
+
|
|
193
|
+
Returns
|
|
194
|
+
-------
|
|
195
|
+
Dict[str, Raster]
|
|
196
|
+
Dictionary of output rasters, including:
|
|
197
|
+
- 'LEi_Wm2': Wet canopy evaporation (W/m^2)
|
|
198
|
+
- 'LEc_Wm2': Canopy transpiration (W/m^2)
|
|
199
|
+
- 'LEs': Soil evaporation (W/m^2)
|
|
200
|
+
- 'LE_Wm2': Total latent heat flux (W/m^2)
|
|
201
|
+
- Additional intermediate variables (e.g., resistances, conductances, meteorological properties)
|
|
202
|
+
|
|
203
|
+
References
|
|
204
|
+
----------
|
|
205
|
+
Mu, Q., Zhao, M., & Running, S. W. (2011). Improvements to a MODIS global terrestrial evapotranspiration algorithm. Remote Sensing of Environment, 115(8), 1781-1800. https://doi.org/10.1016/j.rse.2011.02.019
|
|
206
|
+
MOD16 User Guide (2016): https://landweb.nascom.nasa.gov/QA_WWW/forPage/user_guide/MOD16UsersGuide2016.pdf
|
|
207
|
+
Allen, R. G., Pereira, L. S., Raes, D., & Smith, M. (1998). Crop evapotranspiration—Guidelines for computing crop water requirements—FAO Irrigation and drainage paper 56.
|
|
208
|
+
Monteith, J. L. (1965). Evaporation and environment. Symposia of the Society for Experimental Biology, 19, 205-234.
|
|
209
|
+
Carlson, T. N., & Ripley, D. A. (1997). On the relation between NDVI, fractional vegetation cover, and leaf area index. Remote Sensing of Environment, 62(3), 241-252.
|
|
210
|
+
Bastiaanssen, W. G. M., et al. (1998). A remote sensing surface energy balance algorithm for land (SEBAL). Journal of Hydrology, 212-213, 198-212.
|
|
211
|
+
Verma, S. B., Rosenberg, N. J., & Blad, B. L. (1989). Microclimate, evapotranspiration, and water status of maize under shelterbelt and non-shelterbelt conditions. Agricultural and Forest Meteorology, 46(1), 21-34.
|
|
212
|
+
"""
|
|
213
|
+
results = {}
|
|
214
|
+
|
|
215
|
+
if geometry is None and isinstance(NDVI, Raster):
|
|
216
|
+
geometry = NDVI.geometry
|
|
217
|
+
|
|
218
|
+
if GEOS5FP_connection is None:
|
|
219
|
+
GEOS5FP_connection = GEOS5FP()
|
|
220
|
+
|
|
221
|
+
if Ta_C is None and geometry is not None and time_UTC is not None:
|
|
222
|
+
Ta_C = GEOS5FP_connection.Ta_C(
|
|
223
|
+
time_UTC=time_UTC,
|
|
224
|
+
geometry=geometry,
|
|
225
|
+
resampling=resampling
|
|
226
|
+
)
|
|
227
|
+
|
|
228
|
+
if Ta_C is None:
|
|
229
|
+
raise ValueError("air temperature (Ta_C) not given")
|
|
230
|
+
|
|
231
|
+
check_distribution(Ta_C, "Ta_C")
|
|
232
|
+
|
|
233
|
+
if Tmin_C is None and geometry is not None and time_UTC is not None:
|
|
234
|
+
Tmin_K = GEOS5FP_connection.Tmin_K(
|
|
235
|
+
time_UTC=time_UTC,
|
|
236
|
+
geometry=geometry,
|
|
237
|
+
resampling=resampling
|
|
238
|
+
)
|
|
239
|
+
|
|
240
|
+
Tmin_C = Tmin_K - 273.15
|
|
241
|
+
|
|
242
|
+
if Tmin_C is None:
|
|
243
|
+
raise ValueError("minimum temperature (Tmin_C) not given")
|
|
244
|
+
|
|
245
|
+
check_distribution(Tmin_C, "Tmin_C")
|
|
246
|
+
|
|
247
|
+
if RH is None and geometry is not None and time_UTC is not None:
|
|
248
|
+
RH = GEOS5FP_connection.RH(
|
|
249
|
+
time_UTC=time_UTC,
|
|
250
|
+
geometry=geometry,
|
|
251
|
+
resampling=resampling
|
|
252
|
+
)
|
|
253
|
+
|
|
254
|
+
if RH is None:
|
|
255
|
+
raise ValueError("relative humidity (RH) not given")
|
|
256
|
+
|
|
257
|
+
check_distribution(RH, "RH")
|
|
258
|
+
|
|
259
|
+
if elevation_km is None and geometry is not None:
|
|
260
|
+
elevation_km = NASADEM.elevation_km(geometry=geometry)
|
|
261
|
+
|
|
262
|
+
check_distribution(elevation_km, "elevation_km")
|
|
263
|
+
|
|
264
|
+
elevation_m = elevation_km * 1000.0
|
|
265
|
+
|
|
266
|
+
if IGBP is None and geometry is not None:
|
|
267
|
+
if isinstance(geometry, VectorGeometry):
|
|
268
|
+
IGBP_geometry = geometry
|
|
269
|
+
elif isinstance(geometry, RasterGeometry):
|
|
270
|
+
IGBP_geometry = geometry.UTM(IGBP_upsampling_resolution_meters)
|
|
271
|
+
else:
|
|
272
|
+
raise ValueError(f"invalid geometry type for IGBP retrieval: {type(geometry)}")
|
|
273
|
+
|
|
274
|
+
IGBP = load_MCD12C1_IGBP(geometry=IGBP_geometry)
|
|
275
|
+
|
|
276
|
+
check_distribution(np.float32(IGBP), "IGBP")
|
|
277
|
+
|
|
278
|
+
if regenerate_net_radiation or (Rn_Wm2 is None and albedo is not None and ST_C is not None and emissivity is not None):
|
|
279
|
+
if SWin_Wm2 is None and geometry is not None and time_UTC is not None:
|
|
280
|
+
logger.info("retrieving shortwave radiation (SWin_Wm2) from GEOS-5 FP")
|
|
281
|
+
SWin_Wm2 = GEOS5FP_connection.SWin(
|
|
282
|
+
time_UTC=time_UTC,
|
|
283
|
+
geometry=geometry,
|
|
284
|
+
resampling=resampling
|
|
285
|
+
)
|
|
286
|
+
elif SWin_Wm2 is not None:
|
|
287
|
+
logger.info("using given shortwave radiation (SWin_Wm2)")
|
|
288
|
+
|
|
289
|
+
if upscale_to_daylight:
|
|
290
|
+
logger.info("running Verma net radiation with daylight upscaling")
|
|
291
|
+
else:
|
|
292
|
+
logger.info("running instantaneous Verma net radiation")
|
|
293
|
+
|
|
294
|
+
Rn_results = verma_net_radiation(
|
|
295
|
+
SWin_Wm2=SWin_Wm2,
|
|
296
|
+
albedo=albedo,
|
|
297
|
+
ST_C=ST_C,
|
|
298
|
+
emissivity=emissivity,
|
|
299
|
+
Ta_C=Ta_C,
|
|
300
|
+
RH=RH,
|
|
301
|
+
upscale_to_daylight=upscale_to_daylight,
|
|
302
|
+
)
|
|
303
|
+
|
|
304
|
+
Rn_Wm2 = Rn_results["Rn_Wm2"]
|
|
305
|
+
|
|
306
|
+
if "Rn_daylight_Wm2" in Rn_results:
|
|
307
|
+
Rn_daylight_Wm2 = Rn_results["Rn_daylight_Wm2"]
|
|
308
|
+
|
|
309
|
+
elif Rn_Wm2 is not None:
|
|
310
|
+
logger.info("using given net radiation (Rn_Wm2) for PM-JPL processing")
|
|
311
|
+
|
|
312
|
+
if Rn_Wm2 is None:
|
|
313
|
+
missing_vars = []
|
|
314
|
+
if albedo is None:
|
|
315
|
+
missing_vars.append('albedo')
|
|
316
|
+
if ST_C is None:
|
|
317
|
+
missing_vars.append('ST_C')
|
|
318
|
+
if emissivity is None:
|
|
319
|
+
missing_vars.append('emissivity')
|
|
320
|
+
if missing_vars:
|
|
321
|
+
raise ValueError(f"net radiation (Rn_Wm2) not given, and missing required variables to calculate: {', '.join(missing_vars)}")
|
|
322
|
+
else:
|
|
323
|
+
raise ValueError("net radiation (Rn_Wm2) not given and cannot be calculated")
|
|
324
|
+
|
|
325
|
+
check_distribution(Rn_Wm2, "Rn_Wm2")
|
|
326
|
+
|
|
327
|
+
if G_Wm2 is None and Rn_Wm2 is not None and ST_C is not None and NDVI is not None and albedo is not None:
|
|
328
|
+
G_Wm2 = calculate_SEBAL_soil_heat_flux(
|
|
329
|
+
Rn=Rn_Wm2,
|
|
330
|
+
ST_C=ST_C,
|
|
331
|
+
NDVI=NDVI,
|
|
332
|
+
albedo=albedo
|
|
333
|
+
)
|
|
334
|
+
|
|
335
|
+
if G_Wm2 is None:
|
|
336
|
+
raise ValueError("soil heat flux (G) not given")
|
|
337
|
+
|
|
338
|
+
check_distribution(G_Wm2, "G_Wm2")
|
|
339
|
+
results["G_Wm2"] = G_Wm2
|
|
340
|
+
|
|
341
|
+
LAI = carlson_leaf_area_index(NDVI)
|
|
342
|
+
|
|
343
|
+
# calculate fraction of vegetation cover if it's not given
|
|
344
|
+
if FVC is None:
|
|
345
|
+
# calculate fraction of vegetation cover from NDVI
|
|
346
|
+
FVC = carlson_fractional_vegetation_cover(NDVI)
|
|
347
|
+
|
|
348
|
+
# calculate surface air pressure if it's not given
|
|
349
|
+
if Ps_Pa is None:
|
|
350
|
+
# calculate surface air pressure is Pascal
|
|
351
|
+
Ps_Pa = calculate_surface_pressure(elevation_m=elevation_m, Ta_C=Ta_C)
|
|
352
|
+
|
|
353
|
+
# calculate Penman-Monteith/Priestley-Taylor delta term if it's not given
|
|
354
|
+
if delta_Pa is None:
|
|
355
|
+
# calculate Penman-Monteith/Priestley-Taylor delta term in Pascal per degree Celsius
|
|
356
|
+
delta_Pa = delta_Pa_from_Ta_C(Ta_C)
|
|
357
|
+
|
|
358
|
+
# calculate latent heat of vaporization if it's not given
|
|
359
|
+
if lambda_Jkg is None:
|
|
360
|
+
# calculate latent heat of vaporization in Joules per kilogram
|
|
361
|
+
lambda_Jkg = lambda_Jkg_from_Ta_C(Ta_C)
|
|
362
|
+
|
|
363
|
+
logger.info("calculating PM-MOD meteorology")
|
|
364
|
+
|
|
365
|
+
# calculate air temperature in Kelvin
|
|
366
|
+
Ta_K = celcius_to_kelvin(Ta_C)
|
|
367
|
+
|
|
368
|
+
# calculate saturation vapor pressure in Pascal from air temperature in Celsius
|
|
369
|
+
SVP_Pa = SVP_Pa_from_Ta_C(Ta_C)
|
|
370
|
+
|
|
371
|
+
# calculate vapor pressure in Pascal from releative humidity and saturation vapor pressure
|
|
372
|
+
Ea_Pa = RH * SVP_Pa
|
|
373
|
+
|
|
374
|
+
# specific humidity of air
|
|
375
|
+
# as a ratio of kilograms of water to kilograms of air and water
|
|
376
|
+
# from surface pressure and actual water vapor pressure
|
|
377
|
+
specific_humidity = calculate_specific_humidity(Ea_Pa, Ps_Pa)
|
|
378
|
+
check_distribution(specific_humidity, "specific_humidity")
|
|
379
|
+
results['specific_humidity'] = specific_humidity
|
|
380
|
+
|
|
381
|
+
# calculate air density (rho) in kilograms per cubic meter
|
|
382
|
+
rho_kgm3 = calculate_air_density(Ps_Pa, Ta_K, specific_humidity)
|
|
383
|
+
check_distribution(rho_kgm3, "rho_kgm3")
|
|
384
|
+
results["rho_kgm3"] = rho_kgm3
|
|
385
|
+
|
|
386
|
+
# calculate specific heat capacity of the air (Cp)
|
|
387
|
+
# in joules per kilogram per kelvin
|
|
388
|
+
# from specific heat of water vapor (CPW)
|
|
389
|
+
# and specific heat of dry air (CPD)
|
|
390
|
+
Cp_Jkg = calculate_specific_heat(specific_humidity)
|
|
391
|
+
check_distribution(Cp_Jkg, "Cp_Jkg")
|
|
392
|
+
results["Cp"] = Cp_Jkg
|
|
393
|
+
|
|
394
|
+
# calculate delta term if it's not given
|
|
395
|
+
if delta_Pa is None:
|
|
396
|
+
# slope of saturation vapor pressure curve in Pascal per degree
|
|
397
|
+
delta_Pa = delta_Pa_from_Ta_C(Ta_C)
|
|
398
|
+
|
|
399
|
+
check_distribution(delta_Pa, "delta_Pa")
|
|
400
|
+
results["delta_Pa"] = delta_Pa
|
|
401
|
+
|
|
402
|
+
# calculate gamma term if it's not given
|
|
403
|
+
if gamma_Jkg is None:
|
|
404
|
+
# calculate psychrometric gamma in Joules per kilogram
|
|
405
|
+
gamma_Jkg = calculate_gamma(
|
|
406
|
+
Ta_C=Ta_C,
|
|
407
|
+
Ps_Pa=Ps_Pa,
|
|
408
|
+
Cp_Jkg=Cp_Jkg
|
|
409
|
+
)
|
|
410
|
+
|
|
411
|
+
# vapor pressure deficit in Pascal
|
|
412
|
+
VPD_Pa = rt.clip(SVP_Pa - Ea_Pa, 0.0, None)
|
|
413
|
+
|
|
414
|
+
# calculate relative surface wetness (fwet)
|
|
415
|
+
# from relative humidity
|
|
416
|
+
fwet = calculate_relative_surface_wetness(
|
|
417
|
+
RH=RH,
|
|
418
|
+
RH_threshold=RH_threshold,
|
|
419
|
+
min_fwet=min_fwet
|
|
420
|
+
)
|
|
421
|
+
|
|
422
|
+
check_distribution(fwet, "fwet")
|
|
423
|
+
results['fwet'] = fwet
|
|
424
|
+
|
|
425
|
+
logger.info("calculating PM-MOD resistances")
|
|
426
|
+
|
|
427
|
+
# query leaf conductance to sensible heat (gl_sh) in seconds per meter
|
|
428
|
+
if gl_sh is None:
|
|
429
|
+
gl_sh = leaf_conductance_to_sensible_heat(IGBP, geometry)
|
|
430
|
+
|
|
431
|
+
check_distribution(gl_sh, "gl_sh")
|
|
432
|
+
results['gl_sh'] = gl_sh
|
|
433
|
+
|
|
434
|
+
# calculate wet canopy resistance to sensible heat (rhc) in seconds per meter
|
|
435
|
+
rhc = calculate_wet_canopy_resistance(gl_sh, LAI, fwet)
|
|
436
|
+
check_distribution(rhc, "rhc")
|
|
437
|
+
results['rhc'] = rhc
|
|
438
|
+
|
|
439
|
+
# calculate resistance to radiative heat transfer through air (rrc)
|
|
440
|
+
rrc = np.float32(rho_kgm3 * Cp_Jkg / (4.0 * SIGMA * Ta_K ** 3.0))
|
|
441
|
+
check_distribution(rrc, "rrc")
|
|
442
|
+
results['rrc'] = rrc
|
|
443
|
+
|
|
444
|
+
# calculate aerodynamic resistance (rhrc)
|
|
445
|
+
rhrc = np.float32((rhc * rrc) / (rhc + rrc))
|
|
446
|
+
check_distribution(rhrc, "rhrc")
|
|
447
|
+
results['rhrc'] = rhrc
|
|
448
|
+
|
|
449
|
+
# calculate leaf conductance to evaporated water vapor (gl_e_wv)
|
|
450
|
+
if gl_e_wv is None:
|
|
451
|
+
gl_e_wv = leaf_conductance_to_evaporated_water(IGBP, geometry, IGBP_upsampling_resolution_meters)
|
|
452
|
+
|
|
453
|
+
check_distribution(gl_e_wv, "gl_e_wv")
|
|
454
|
+
results['gl_e_wv'] = gl_e_wv
|
|
455
|
+
|
|
456
|
+
rvc = calculate_wet_canopy_resistance(gl_e_wv, LAI, fwet)
|
|
457
|
+
check_distribution(rvc, "rvc")
|
|
458
|
+
results['rvc'] = rvc
|
|
459
|
+
|
|
460
|
+
# caluclate available radiation to the canopy (Ac)
|
|
461
|
+
Ac = Rn_Wm2 * FVC
|
|
462
|
+
check_distribution(Ac, "Ac")
|
|
463
|
+
results['Ac'] = Ac
|
|
464
|
+
|
|
465
|
+
# calculate wet latent heat flux (LEi)
|
|
466
|
+
LE_interception_Wm2 = calculate_interception(
|
|
467
|
+
delta_Pa=delta_Pa,
|
|
468
|
+
Ac=Ac,
|
|
469
|
+
rho=rho_kgm3,
|
|
470
|
+
Cp=Cp_Jkg,
|
|
471
|
+
VPD_Pa=VPD_Pa,
|
|
472
|
+
FVC=FVC,
|
|
473
|
+
rhrc=rhrc,
|
|
474
|
+
fwet=fwet,
|
|
475
|
+
rvc=rvc,
|
|
476
|
+
)
|
|
477
|
+
|
|
478
|
+
check_distribution(LE_interception_Wm2, "LE_interception_Wm2")
|
|
479
|
+
results['LE_interception_Wm2'] = LE_interception_Wm2
|
|
480
|
+
|
|
481
|
+
# calculate correctance factor (rcorr)
|
|
482
|
+
rcorr = calculate_correctance_factor(Ps_Pa, Ta_K)
|
|
483
|
+
check_distribution(rcorr, "rcorr")
|
|
484
|
+
results['rcorr'] = rcorr
|
|
485
|
+
|
|
486
|
+
# biome-specific mean potential stomatal conductance per unit leaf area
|
|
487
|
+
if CL is None:
|
|
488
|
+
CL = potential_stomatal_conductance(IGBP, geometry, IGBP_upsampling_resolution_meters)
|
|
489
|
+
|
|
490
|
+
check_distribution(CL, "CL")
|
|
491
|
+
results['CL'] = CL
|
|
492
|
+
|
|
493
|
+
# open minimum temperature by land-cover
|
|
494
|
+
if Tmin_open is None:
|
|
495
|
+
Tmin_open = open_minimum_temperature(IGBP, geometry, IGBP_upsampling_resolution_meters)
|
|
496
|
+
|
|
497
|
+
check_distribution(Tmin_open, "Tmin_open")
|
|
498
|
+
results['Tmin_open'] = Tmin_open
|
|
499
|
+
|
|
500
|
+
# closed minimum temperature by land-cover
|
|
501
|
+
if Tmin_closed is None:
|
|
502
|
+
Tmin_closed = closed_minimum_temperature(IGBP, geometry, IGBP_upsampling_resolution_meters)
|
|
503
|
+
|
|
504
|
+
check_distribution(Tmin_closed, "Tmin_closed")
|
|
505
|
+
results['Tmin_closed'] = Tmin_closed
|
|
506
|
+
|
|
507
|
+
check_distribution(Tmin_C, "Tmin_C")
|
|
508
|
+
|
|
509
|
+
# minimum temperature factor for stomatal conductance
|
|
510
|
+
mTmin = Tmin_factor(Tmin_C, Tmin_open, Tmin_closed)
|
|
511
|
+
check_distribution(mTmin, "mTmin")
|
|
512
|
+
results['mTmin'] = mTmin
|
|
513
|
+
|
|
514
|
+
# open vapor pressure deficit by land-cover
|
|
515
|
+
if VPD_open is None:
|
|
516
|
+
VPD_open = open_vapor_pressure_deficit(IGBP, geometry, IGBP_upsampling_resolution_meters)
|
|
517
|
+
|
|
518
|
+
check_distribution(VPD_open, "VPD_open")
|
|
519
|
+
results['VPD_open'] = VPD_open
|
|
520
|
+
|
|
521
|
+
# closed vapor pressure deficit by land-cover
|
|
522
|
+
if VPD_closed is None:
|
|
523
|
+
VPD_closed = closed_vapor_pressure_deficit(IGBP, geometry, IGBP_upsampling_resolution_meters)
|
|
524
|
+
|
|
525
|
+
check_distribution(VPD_closed, "VPD_closed")
|
|
526
|
+
results['VPD_closed'] = VPD_closed
|
|
527
|
+
|
|
528
|
+
# vapor pressure deficit factor for stomatal conductance
|
|
529
|
+
mVPD = calculate_VPD_factor(VPD_open, VPD_closed, VPD_Pa)
|
|
530
|
+
check_distribution(mVPD, "mVPD")
|
|
531
|
+
results['mVPD'] = mVPD
|
|
532
|
+
|
|
533
|
+
# stomatal conductance (gs1)
|
|
534
|
+
gs1 = CL * mTmin * mVPD * rcorr
|
|
535
|
+
check_distribution(gs1, "gs1")
|
|
536
|
+
results['gs1'] = gs1
|
|
537
|
+
|
|
538
|
+
# correct cuticular conductance constant to leaf cuticular conductance (Gcu) using correction factor (rcorr)
|
|
539
|
+
Gcu = CUTICULAR_CONDUCTANCE * rcorr
|
|
540
|
+
check_distribution(Gcu, "Gcu")
|
|
541
|
+
results['Gcu'] = Gcu
|
|
542
|
+
|
|
543
|
+
# canopy conductance
|
|
544
|
+
Cc = calculate_canopy_conductance(LAI, fwet, gl_sh, gs1, Gcu)
|
|
545
|
+
check_distribution(Cc, "Cc")
|
|
546
|
+
results['Cc'] = Cc
|
|
547
|
+
|
|
548
|
+
# surface resistance to evapotranspiration as inverse of canopy conductance (Cc)
|
|
549
|
+
rs = rt.clip(1.0 / Cc, 0.0, MAX_RESISTANCE)
|
|
550
|
+
check_distribution(rs, "rs")
|
|
551
|
+
results['rs'] = rs
|
|
552
|
+
|
|
553
|
+
# convective heat transfer as inverse of leaf conductance to sensible heat (gl_sh)
|
|
554
|
+
rh = 1.0 / gl_sh
|
|
555
|
+
check_distribution(rs, "rh")
|
|
556
|
+
results['rh'] = rs
|
|
557
|
+
|
|
558
|
+
# radiative heat transfer (rr)
|
|
559
|
+
rr = rho_kgm3 * Cp_Jkg / (4.0 * SIGMA * Ta_K ** 3)
|
|
560
|
+
check_distribution(rr, "rr")
|
|
561
|
+
results['rr'] = rr
|
|
562
|
+
|
|
563
|
+
# parallel resistance (ra)
|
|
564
|
+
ra = (rh * rr) / (rh + rr)
|
|
565
|
+
check_distribution(ra, "ra")
|
|
566
|
+
results["ra"] = ra
|
|
567
|
+
|
|
568
|
+
# transpiration
|
|
569
|
+
LE_canopy_Wm2 = calculate_transpiration(
|
|
570
|
+
delta_Pa=delta_Pa,
|
|
571
|
+
Ac=Ac,
|
|
572
|
+
rho_kgm3=rho_kgm3,
|
|
573
|
+
Cp_Jkg=Cp_Jkg,
|
|
574
|
+
VPD_Pa=VPD_Pa,
|
|
575
|
+
FVC=FVC,
|
|
576
|
+
ra=ra,
|
|
577
|
+
fwet=fwet,
|
|
578
|
+
rs=rs,
|
|
579
|
+
)
|
|
580
|
+
|
|
581
|
+
check_distribution(LE_canopy_Wm2, "LE_canopy_Wm2")
|
|
582
|
+
results['LE_canopy_Wm2'] = LE_canopy_Wm2
|
|
583
|
+
|
|
584
|
+
# soil evaporation
|
|
585
|
+
# aerodynamic resistant constraints from land-cover
|
|
586
|
+
if RBL_max is None:
|
|
587
|
+
RBL_max = maximum_boundary_layer_resistance(IGBP, geometry, IGBP_upsampling_resolution_meters)
|
|
588
|
+
|
|
589
|
+
check_distribution(RBL_max, "RBL_max")
|
|
590
|
+
results['RBL_max'] = RBL_max
|
|
591
|
+
|
|
592
|
+
if RBL_min is None:
|
|
593
|
+
RBL_min = minimum_boundary_layer_resistance(IGBP, geometry, IGBP_upsampling_resolution_meters)
|
|
594
|
+
|
|
595
|
+
check_distribution(RBL_min, "RBL_min")
|
|
596
|
+
results['RBL_min'] = RBL_min
|
|
597
|
+
|
|
598
|
+
# canopy aerodynamic resistance in seconds per meter
|
|
599
|
+
rtotc = calculate_canopy_aerodynamic_resistance(VPD_Pa, VPD_open, VPD_closed, RBL_max, RBL_min)
|
|
600
|
+
check_distribution(rtotc, "rtotc")
|
|
601
|
+
results['rtotc'] = rtotc
|
|
602
|
+
|
|
603
|
+
# total aerodynamic resistance
|
|
604
|
+
rtot = rcorr * rtotc
|
|
605
|
+
check_distribution(rtot, "rtot")
|
|
606
|
+
results['rtot'] = rtot
|
|
607
|
+
|
|
608
|
+
# resistance to radiative heat transfer through air
|
|
609
|
+
rrs = np.float32(rho_kgm3 * Cp_Jkg / (4.0 * SIGMA * Ta_K ** 3))
|
|
610
|
+
check_distribution(rrs, "rrs")
|
|
611
|
+
results['rrs'] = rrs
|
|
612
|
+
|
|
613
|
+
# aerodynamic resistance at the soil surface
|
|
614
|
+
ras = (rtot * rrs) / (rtot + rrs)
|
|
615
|
+
check_distribution(ras, "ras")
|
|
616
|
+
results['ras'] = ras
|
|
617
|
+
|
|
618
|
+
# available radiation at the soil
|
|
619
|
+
Asoil = rt.clip((1.0 - FVC) * Rn_Wm2 - G_Wm2, 0.0, None)
|
|
620
|
+
check_distribution(Asoil, "Asoil")
|
|
621
|
+
results['Asoil'] = Asoil
|
|
622
|
+
|
|
623
|
+
# separate wet soil evaporation and potential soil evaporation
|
|
624
|
+
# wet soil evaporation
|
|
625
|
+
wet_soil_evaporation_Wm2 = calculate_wet_soil_evaporation(
|
|
626
|
+
delta_Pa=delta_Pa,
|
|
627
|
+
Asoil=Asoil,
|
|
628
|
+
rho_kgm3=rho_kgm3,
|
|
629
|
+
Cp_Jkg=Cp_Jkg,
|
|
630
|
+
FVC=FVC,
|
|
631
|
+
VPD_Pa=VPD_Pa,
|
|
632
|
+
ras=ras,
|
|
633
|
+
fwet=fwet,
|
|
634
|
+
rtot=rtot,
|
|
635
|
+
)
|
|
636
|
+
|
|
637
|
+
check_distribution(wet_soil_evaporation_Wm2, "wet_soil_evaporation_Wm2")
|
|
638
|
+
results['wet_soil_evaporation_Wm2'] = wet_soil_evaporation_Wm2
|
|
639
|
+
|
|
640
|
+
# potential soil evaporation
|
|
641
|
+
potential_soil_evaporation_Wm2 = calculate_potential_soil_evaporation(
|
|
642
|
+
delta_Pa=delta_Pa,
|
|
643
|
+
Asoil=Asoil,
|
|
644
|
+
rho=rho_kgm3,
|
|
645
|
+
Cp_Jkg=Cp_Jkg,
|
|
646
|
+
FVC=FVC,
|
|
647
|
+
VPD_Pa=VPD_Pa,
|
|
648
|
+
ras=ras,
|
|
649
|
+
fwet=fwet,
|
|
650
|
+
rtot=rtot,
|
|
651
|
+
)
|
|
652
|
+
|
|
653
|
+
check_distribution(potential_soil_evaporation_Wm2, "potential_soil_evaporation_Wm2")
|
|
654
|
+
results['potential_soil_evaporation_Wm2'] = potential_soil_evaporation_Wm2
|
|
655
|
+
|
|
656
|
+
# soil moisture constraint
|
|
657
|
+
fSM = calculate_fSM(RH, VPD_Pa)
|
|
658
|
+
check_distribution(fSM, "fSM")
|
|
659
|
+
results['fSM'] = fSM
|
|
660
|
+
|
|
661
|
+
# soil evaporation
|
|
662
|
+
LE_soil_Wm2 = rt.clip(wet_soil_evaporation_Wm2 + potential_soil_evaporation_Wm2 * fSM, 0.0, None)
|
|
663
|
+
LE_soil_Wm2 = rt.where(np.isnan(LE_soil_Wm2), 0.0, LE_soil_Wm2)
|
|
664
|
+
check_distribution(LE_soil_Wm2, "LE_soil_Wm2")
|
|
665
|
+
results['LE_soil_Wm2'] = LE_soil_Wm2
|
|
666
|
+
|
|
667
|
+
# sum partitions into total latent heat flux
|
|
668
|
+
LE_Wm2 = rt.clip(LE_interception_Wm2 + LE_canopy_Wm2 + LE_soil_Wm2, 0.0, Rn_Wm2)
|
|
669
|
+
check_distribution(LE_Wm2, "LE_Wm2")
|
|
670
|
+
results['LE_Wm2'] = LE_Wm2
|
|
671
|
+
|
|
672
|
+
# --- daylight Upscaling Option ---
|
|
673
|
+
if upscale_to_daylight and time_UTC is not None:
|
|
674
|
+
logger.info("started daylight ET upscaling (PMJPL)")
|
|
675
|
+
|
|
676
|
+
# Use new upscaling function from daylight_evapotranspiration
|
|
677
|
+
daylight_results = daylight_ET_from_instantaneous_LE(
|
|
678
|
+
LE_instantaneous_Wm2=LE_Wm2,
|
|
679
|
+
Rn_instantaneous_Wm2=Rn_Wm2,
|
|
680
|
+
G_instantaneous_Wm2=G_Wm2,
|
|
681
|
+
day_of_year=day_of_year,
|
|
682
|
+
time_UTC=time_UTC,
|
|
683
|
+
geometry=geometry
|
|
684
|
+
)
|
|
685
|
+
# Add all returned daylight results to output
|
|
686
|
+
results.update(daylight_results)
|
|
687
|
+
|
|
688
|
+
logger.info("completed daylight ET upscaling (PMJPL)")
|
|
689
|
+
|
|
690
|
+
return results
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
from .PMJPL_parameter_from_IGBP import PMJPL_parameter_from_IGBP
|
|
2
|
+
from rasters import Raster, RasterGeometry, VectorGeometry
|
|
3
|
+
from typing import Union
|
|
4
|
+
|
|
5
|
+
def open_minimum_temperature(IGBP: Union[Raster, int], geometry=None, IGBP_upsampling_resolution_meters=None):
|
|
6
|
+
return PMJPL_parameter_from_IGBP(
|
|
7
|
+
variable="Tmin_open",
|
|
8
|
+
IGBP=IGBP,
|
|
9
|
+
geometry=geometry,
|
|
10
|
+
IGBP_upsampling_resolution_meters=IGBP_upsampling_resolution_meters
|
|
11
|
+
)
|