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.
Files changed (66) hide show
  1. PMJPL/ECOv002-cal-val-PM-JPL-inputs.csv +1048 -0
  2. PMJPL/ECOv002-cal-val-PM-JPL-outputs.csv +1048 -0
  3. PMJPL/ECOv002-static-tower-PM-JPL-inputs.csv +122 -0
  4. PMJPL/ECOv002_calval_PMJPL_inputs.py +19 -0
  5. PMJPL/ECOv002_static_tower_PMJPL_inputs.py +19 -0
  6. PMJPL/PMJPL.py +45 -378
  7. PMJPL/{parameters.py → PMJPL_parameter_from_IGBP.py} +22 -7
  8. PMJPL/VPD_factor.py +1 -1
  9. PMJPL/__init__.py +1 -6
  10. PMJPL/calculate_gamma.py +128 -0
  11. PMJPL/canopy_aerodynamic_resistance.py +151 -18
  12. PMJPL/canopy_conductance.py +71 -15
  13. PMJPL/closed_minimum_temperature.py +11 -0
  14. PMJPL/closed_vapor_pressure_deficit.py +11 -0
  15. PMJPL/constants.py +6 -1
  16. PMJPL/correctance_factor.py +56 -7
  17. PMJPL/generate_PMJPL_inputs.py +263 -0
  18. PMJPL/interception.py +1 -3
  19. PMJPL/leaf_conductance_to_evaporated_water.py +11 -0
  20. PMJPL/leaf_conductance_to_sensible_heat.py +58 -0
  21. PMJPL/maximum_boundary_layer_resistance.py +11 -0
  22. PMJPL/minimum_boundary_layer_resistance.py +11 -0
  23. PMJPL/{tmin_factor.py → minimum_temperature_factor.py} +2 -2
  24. PMJPL/mod16.csv +19 -0
  25. PMJPL/model.py +690 -0
  26. PMJPL/open_minimum_temperature.py +11 -0
  27. PMJPL/open_vapor_pressure_deficit.py +11 -0
  28. PMJPL/potential_soil_evaporation.py +2 -2
  29. PMJPL/potential_stomatal_conductance.py +11 -0
  30. PMJPL/process_PMJPL_table.py +208 -0
  31. PMJPL/process_daily_ET_table.py +40 -0
  32. PMJPL/transpiration.py +4 -4
  33. PMJPL/verify.py +77 -0
  34. PMJPL/version.py +4 -0
  35. PMJPL/wet_canopy_resistance.py +1 -0
  36. PMJPL/wet_soil_evaporation.py +4 -4
  37. {pm_jpl-1.2.1.dist-info → pm_jpl-1.7.0.dist-info}/METADATA +18 -21
  38. pm_jpl-1.7.0.dist-info/RECORD +42 -0
  39. {pm_jpl-1.2.1.dist-info → pm_jpl-1.7.0.dist-info}/WHEEL +1 -1
  40. PMJPL/MCD12C1/MCD12C1.py +0 -10
  41. PMJPL/MCD12C1/__init__.py +0 -1
  42. PMJPL/SEBAL/SEBAL.py +0 -45
  43. PMJPL/SEBAL/__init__.py +0 -1
  44. PMJPL/downscaling/__init__.py +0 -1
  45. PMJPL/downscaling/downscaling.py +0 -271
  46. PMJPL/downscaling/linear_downscale.py +0 -71
  47. PMJPL/evapotranspiration_conversion/__init__.py +0 -1
  48. PMJPL/evapotranspiration_conversion/evapotranspiration_conversion.py +0 -80
  49. PMJPL/fwet.py +0 -21
  50. PMJPL/meteorology_conversion/__init__.py +0 -1
  51. PMJPL/meteorology_conversion/meteorology_conversion.py +0 -123
  52. PMJPL/penman_monteith/__init__.py +0 -1
  53. PMJPL/penman_monteith/penman_monteith.py +0 -20
  54. PMJPL/priestley_taylor/__init__.py +0 -1
  55. PMJPL/priestley_taylor/priestley_taylor.py +0 -27
  56. PMJPL/santanello/__init__.py +0 -1
  57. PMJPL/santanello/santanello.py +0 -46
  58. PMJPL/soil_heat_flux/__init__.py +0 -1
  59. PMJPL/soil_heat_flux/soil_heat_flux.py +0 -62
  60. PMJPL/vegetation_conversion/__init__.py +0 -1
  61. PMJPL/vegetation_conversion/vegetation_conversion.py +0 -47
  62. PMJPL/verma_net_radiation/__init__.py +0 -1
  63. PMJPL/verma_net_radiation/verma_net_radiation.py +0 -108
  64. pm_jpl-1.2.1.dist-info/RECORD +0 -44
  65. {pm_jpl-1.2.1.dist-info → pm_jpl-1.7.0.dist-info}/licenses/LICENSE +0 -0
  66. {pm_jpl-1.2.1.dist-info → pm_jpl-1.7.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,263 @@
1
+ """
2
+ Module: generate_PMJPL_inputs.py
3
+ -------------------------------
4
+ This module provides a function to generate the required input DataFrame for the PM-JPL model. It processes a calibration/validation DataFrame, computes additional variables such as hour of day, day of year (doy), and loads static parameters from the MOD16 lookup table based on IGBP land cover classification. The function is robust to missing or problematic data, logging warnings and filling with NaN as needed.
5
+ """
6
+ import logging
7
+
8
+ import numpy as np
9
+ import pandas as pd
10
+ import rasters as rt
11
+ from dateutil import parser
12
+ from pandas import DataFrame
13
+ from solar_apparent_time import UTC_to_solar
14
+
15
+ from .leaf_conductance_to_sensible_heat import leaf_conductance_to_sensible_heat
16
+ from .leaf_conductance_to_evaporated_water import leaf_conductance_to_evaporated_water
17
+ from .maximum_boundary_layer_resistance import maximum_boundary_layer_resistance
18
+ from .minimum_boundary_layer_resistance import minimum_boundary_layer_resistance
19
+ from .potential_stomatal_conductance import potential_stomatal_conductance
20
+ from .open_minimum_temperature import open_minimum_temperature
21
+ from .closed_minimum_temperature import closed_minimum_temperature
22
+ from .open_vapor_pressure_deficit import open_vapor_pressure_deficit
23
+ from .closed_vapor_pressure_deficit import closed_vapor_pressure_deficit
24
+ from .model import PMJPL
25
+
26
+ logger = logging.getLogger(__name__)
27
+
28
+ # FIXME include additional inputs required by PM-JPL that were not required by previous models
29
+
30
+ def generate_PMJPL_inputs(PMJPL_inputs_from_calval_df: DataFrame) -> DataFrame:
31
+ """
32
+ Generate a DataFrame with all required inputs for the PM-JPL model.
33
+
34
+ Parameters
35
+ ----------
36
+ PMJPL_inputs_from_calval_df : pandas.DataFrame
37
+ DataFrame containing the columns: tower, lat, lon, time_UTC, albedo, elevation_km, IGBP
38
+
39
+ Returns
40
+ -------
41
+ pandas.DataFrame
42
+ DataFrame containing the original columns plus:
43
+ - hour_of_day: int, hour of solar time at the site
44
+ - doy: int, day of year
45
+ - gl_sh: float, leaf conductance to sensible heat per unit LAI (m s-1 LAI-1)
46
+ - gl_e_wv: float, leaf conductance to evaporated water per unit LAI (m s-1 LAI-1)
47
+ - RBL_min: float, minimum atmospheric boundary layer resistance (s m-1)
48
+ - RBL_max: float, maximum atmospheric boundary layer resistance (s m-1)
49
+ - CL: float, mean potential stomatal conductance per unit leaf area (m s-1)
50
+ - Tmin_open: float, temperature at which stomata are completely open (deg C)
51
+ - Tmin_closed: float, temperature at which stomata are almost completely closed (deg C)
52
+ - VPD_closed: float, VPD at which stomata are almost completely closed (Pa)
53
+ - VPD_open: float, VPD at which stomata are completely open (Pa)
54
+
55
+ Notes
56
+ -----
57
+ - This function is robust to missing or problematic data; missing values are filled with np.nan.
58
+ - The function logs progress and warnings for traceability.
59
+ - If columns already exist in the input DataFrame, they are not overwritten.
60
+ - Static parameters are loaded from the MOD16 lookup table based on IGBP land cover classification.
61
+ """
62
+ # Copy input DataFrame to avoid modifying the original
63
+ PMJPL_inputs_df = PMJPL_inputs_from_calval_df.copy()
64
+
65
+ # Prepare lists to collect computed values
66
+ hour_of_day = []
67
+ doy = []
68
+
69
+ # Iterate over each row to compute additional variables
70
+ for i, input_row in PMJPL_inputs_from_calval_df.iterrows():
71
+ tower = input_row.tower
72
+ lat = input_row.lat
73
+ lon = input_row.lon
74
+ time_UTC = input_row.time_UTC
75
+ albedo = input_row.albedo
76
+ elevation_km = input_row.elevation_km
77
+ IGBP = input_row.IGBP if 'IGBP' in input_row else 1 # Default to evergreen needleleaf forest
78
+
79
+ logger.info(f"collecting PMJPL inputs for tower {tower} lat {lat} lon {lon} time {time_UTC} UTC IGBP {IGBP}")
80
+
81
+ # Parse time and convert to solar time
82
+ time_UTC = parser.parse(str(time_UTC))
83
+ time_solar = UTC_to_solar(time_UTC, lon)
84
+ hour_of_day.append(time_solar.hour)
85
+ doy.append(time_UTC.timetuple().tm_yday)
86
+
87
+ # Add computed columns to DataFrame if not already present
88
+ if not "hour_of_day" in PMJPL_inputs_df.columns:
89
+ PMJPL_inputs_df["hour_of_day"] = hour_of_day
90
+
91
+ if not "doy" in PMJPL_inputs_df.columns:
92
+ PMJPL_inputs_df["doy"] = doy
93
+
94
+ # Load static parameters from MOD16 lookup table based on IGBP
95
+ # Use the same parameter query functions as the model code
96
+
97
+ # gl_sh: leaf conductance to sensible heat per unit LAI (m s-1 LAI-1)
98
+ if "gl_sh" not in PMJPL_inputs_df.columns:
99
+ try:
100
+ logger.info("loading static parameter gl_sh from MOD16 lookup table")
101
+ gl_sh_values = []
102
+ for i, input_row in PMJPL_inputs_from_calval_df.iterrows():
103
+ IGBP = input_row.IGBP if 'IGBP' in input_row else 1 # Default to evergreen needleleaf forest
104
+ gl_sh_value = leaf_conductance_to_sensible_heat(IGBP=np.array([IGBP]))
105
+ if hasattr(gl_sh_value, '__iter__'):
106
+ gl_sh_values.append(gl_sh_value[0])
107
+ else:
108
+ gl_sh_values.append(gl_sh_value)
109
+ PMJPL_inputs_df["gl_sh"] = gl_sh_values
110
+ logger.info("successfully loaded gl_sh")
111
+ except Exception as e:
112
+ logger.exception(f"failed to load parameter gl_sh: {e}")
113
+ PMJPL_inputs_df["gl_sh"] = np.nan
114
+
115
+ # gl_e_wv: leaf conductance to evaporated water per unit LAI (m s-1 LAI-1)
116
+ if "gl_e_wv" not in PMJPL_inputs_df.columns:
117
+ try:
118
+ logger.info("loading static parameter gl_e_wv from MOD16 lookup table")
119
+ gl_e_wv_values = []
120
+ for i, input_row in PMJPL_inputs_from_calval_df.iterrows():
121
+ IGBP = input_row.IGBP if 'IGBP' in input_row else 1 # Default to evergreen needleleaf forest
122
+ gl_e_wv_value = leaf_conductance_to_evaporated_water(IGBP=IGBP)
123
+ if hasattr(gl_e_wv_value, '__iter__'):
124
+ gl_e_wv_values.append(gl_e_wv_value[0])
125
+ else:
126
+ gl_e_wv_values.append(gl_e_wv_value)
127
+ PMJPL_inputs_df["gl_e_wv"] = gl_e_wv_values
128
+ logger.info("successfully loaded gl_e_wv")
129
+ except Exception as e:
130
+ logger.exception(f"failed to load parameter gl_e_wv: {e}")
131
+ PMJPL_inputs_df["gl_e_wv"] = np.nan
132
+
133
+ # RBL_min: minimum atmospheric boundary layer resistance (s m-1)
134
+ if "RBL_min" not in PMJPL_inputs_df.columns:
135
+ try:
136
+ logger.info("loading static parameter RBL_min from MOD16 lookup table")
137
+ RBL_min_values = []
138
+ for i, input_row in PMJPL_inputs_from_calval_df.iterrows():
139
+ IGBP = input_row.IGBP if 'IGBP' in input_row else 1 # Default to evergreen needleleaf forest
140
+ RBL_min_value = minimum_boundary_layer_resistance(IGBP=IGBP)
141
+ if hasattr(RBL_min_value, '__iter__'):
142
+ RBL_min_values.append(RBL_min_value[0])
143
+ else:
144
+ RBL_min_values.append(RBL_min_value)
145
+ PMJPL_inputs_df["RBL_min"] = RBL_min_values
146
+ logger.info("successfully loaded RBL_min")
147
+ except Exception as e:
148
+ logger.exception(f"failed to load parameter RBL_min: {e}")
149
+ PMJPL_inputs_df["RBL_min"] = np.nan
150
+
151
+ # RBL_max: maximum atmospheric boundary layer resistance (s m-1)
152
+ if "RBL_max" not in PMJPL_inputs_df.columns:
153
+ try:
154
+ logger.info("loading static parameter RBL_max from MOD16 lookup table")
155
+ RBL_max_values = []
156
+ for i, input_row in PMJPL_inputs_from_calval_df.iterrows():
157
+ IGBP = input_row.IGBP if 'IGBP' in input_row else 1 # Default to evergreen needleleaf forest
158
+ RBL_max_value = maximum_boundary_layer_resistance(IGBP=IGBP)
159
+ if hasattr(RBL_max_value, '__iter__'):
160
+ RBL_max_values.append(RBL_max_value[0])
161
+ else:
162
+ RBL_max_values.append(RBL_max_value)
163
+ PMJPL_inputs_df["RBL_max"] = RBL_max_values
164
+ logger.info("successfully loaded RBL_max")
165
+ except Exception as e:
166
+ logger.exception(f"failed to load parameter RBL_max: {e}")
167
+ PMJPL_inputs_df["RBL_max"] = np.nan
168
+
169
+ # CL: mean potential stomatal conductance per unit leaf area (m s-1)
170
+ if "CL" not in PMJPL_inputs_df.columns:
171
+ try:
172
+ logger.info("loading static parameter CL from MOD16 lookup table")
173
+ CL_values = []
174
+ for i, input_row in PMJPL_inputs_from_calval_df.iterrows():
175
+ IGBP = input_row.IGBP if 'IGBP' in input_row else 1 # Default to evergreen needleleaf forest
176
+ CL_value = potential_stomatal_conductance(IGBP=IGBP)
177
+ if hasattr(CL_value, '__iter__'):
178
+ CL_values.append(CL_value[0])
179
+ else:
180
+ CL_values.append(CL_value)
181
+ PMJPL_inputs_df["CL"] = CL_values
182
+ logger.info("successfully loaded CL")
183
+ except Exception as e:
184
+ logger.exception(f"failed to load parameter CL: {e}")
185
+ PMJPL_inputs_df["CL"] = np.nan
186
+
187
+ # Tmin_open: temperature at which stomata are completely open (deg C)
188
+ if "Tmin_open" not in PMJPL_inputs_df.columns:
189
+ try:
190
+ logger.info("loading static parameter Tmin_open from MOD16 lookup table")
191
+ Tmin_open_values = []
192
+ for i, input_row in PMJPL_inputs_from_calval_df.iterrows():
193
+ IGBP = input_row.IGBP if 'IGBP' in input_row else 1 # Default to evergreen needleleaf forest
194
+ Tmin_open_value = open_minimum_temperature(IGBP=IGBP)
195
+ if hasattr(Tmin_open_value, '__iter__'):
196
+ Tmin_open_values.append(Tmin_open_value[0])
197
+ else:
198
+ Tmin_open_values.append(Tmin_open_value)
199
+ PMJPL_inputs_df["Tmin_open"] = Tmin_open_values
200
+ logger.info("successfully loaded Tmin_open")
201
+ except Exception as e:
202
+ logger.exception(f"failed to load parameter Tmin_open: {e}")
203
+ PMJPL_inputs_df["Tmin_open"] = np.nan
204
+
205
+ # Tmin_closed: temperature at which stomata are almost completely closed (deg C)
206
+ if "Tmin_closed" not in PMJPL_inputs_df.columns:
207
+ try:
208
+ logger.info("loading static parameter Tmin_closed from MOD16 lookup table")
209
+ Tmin_closed_values = []
210
+ for i, input_row in PMJPL_inputs_from_calval_df.iterrows():
211
+ IGBP = input_row.IGBP if 'IGBP' in input_row else 1 # Default to evergreen needleleaf forest
212
+ Tmin_closed_value = closed_minimum_temperature(IGBP=IGBP)
213
+ if hasattr(Tmin_closed_value, '__iter__'):
214
+ Tmin_closed_values.append(Tmin_closed_value[0])
215
+ else:
216
+ Tmin_closed_values.append(Tmin_closed_value)
217
+ PMJPL_inputs_df["Tmin_closed"] = Tmin_closed_values
218
+ logger.info("successfully loaded Tmin_closed")
219
+ except Exception as e:
220
+ logger.exception(f"failed to load parameter Tmin_closed: {e}")
221
+ PMJPL_inputs_df["Tmin_closed"] = np.nan
222
+
223
+ # VPD_closed: VPD at which stomata are almost completely closed (Pa)
224
+ if "VPD_closed" not in PMJPL_inputs_df.columns:
225
+ try:
226
+ logger.info("loading static parameter VPD_closed from MOD16 lookup table")
227
+ VPD_closed_values = []
228
+ for i, input_row in PMJPL_inputs_from_calval_df.iterrows():
229
+ IGBP = input_row.IGBP if 'IGBP' in input_row else 1 # Default to evergreen needleleaf forest
230
+ VPD_closed_value = closed_vapor_pressure_deficit(IGBP=IGBP)
231
+ if hasattr(VPD_closed_value, '__iter__'):
232
+ VPD_closed_values.append(VPD_closed_value[0])
233
+ else:
234
+ VPD_closed_values.append(VPD_closed_value)
235
+ PMJPL_inputs_df["VPD_closed"] = VPD_closed_values
236
+ logger.info("successfully loaded VPD_closed")
237
+ except Exception as e:
238
+ logger.exception(f"failed to load parameter VPD_closed: {e}")
239
+ PMJPL_inputs_df["VPD_closed"] = np.nan
240
+
241
+ # VPD_open: VPD at which stomata are completely open (Pa)
242
+ if "VPD_open" not in PMJPL_inputs_df.columns:
243
+ try:
244
+ logger.info("loading static parameter VPD_open from MOD16 lookup table")
245
+ VPD_open_values = []
246
+ for i, input_row in PMJPL_inputs_from_calval_df.iterrows():
247
+ IGBP = input_row.IGBP if 'IGBP' in input_row else 1 # Default to evergreen needleleaf forest
248
+ VPD_open_value = open_vapor_pressure_deficit(IGBP=IGBP)
249
+ if hasattr(VPD_open_value, '__iter__'):
250
+ VPD_open_values.append(VPD_open_value[0])
251
+ else:
252
+ VPD_open_values.append(VPD_open_value)
253
+ PMJPL_inputs_df["VPD_open"] = VPD_open_values
254
+ logger.info("successfully loaded VPD_open")
255
+ except Exception as e:
256
+ logger.exception(f"failed to load parameter VPD_open: {e}")
257
+ PMJPL_inputs_df["VPD_open"] = np.nan
258
+
259
+ # Rename temperature column if needed for model compatibility
260
+ if "Ta" in PMJPL_inputs_df and "Ta_C" not in PMJPL_inputs_df:
261
+ PMJPL_inputs_df.rename({"Ta": "Ta_C"}, inplace=True)
262
+
263
+ return PMJPL_inputs_df
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
@@ -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 leaf_conductance_to_evaporated_water(IGBP: Union[Raster, int], geometry=None, IGBP_upsampling_resolution_meters=None):
6
+ return PMJPL_parameter_from_IGBP(
7
+ variable="gl_e_wv",
8
+ IGBP=IGBP,
9
+ geometry=geometry,
10
+ IGBP_upsampling_resolution_meters=IGBP_upsampling_resolution_meters
11
+ )
@@ -0,0 +1,58 @@
1
+ """
2
+ leaf_conductance_to_sensible_heat.py
3
+
4
+ Provides a function to query leaf conductance to sensible heat (gl_sh) for a given biome and geometry, as used in the MOD16 evapotranspiration model.
5
+
6
+ Scientific Explanation:
7
+ ----------------------
8
+ Leaf conductance to sensible heat (gl_sh) is a critical parameter in land surface models of evapotranspiration, representing the ability of leaves to transfer heat to the surrounding air via molecular diffusion and turbulent exchange. Sensible heat flux from leaves is governed by both stomatal and boundary layer conductances, which are influenced by leaf morphology, canopy structure, and environmental conditions (Monteith & Unsworth, 2013).
9
+
10
+ In the MOD16 algorithm (Mu et al., 2011), biome-specific values for gl_sh are derived from empirical studies and land cover classifications (IGBP), allowing for spatially explicit modeling of energy partitioning between latent and sensible heat. Accurate estimation of gl_sh is essential for modeling canopy energy balance, as it affects the calculation of wet canopy resistance and ultimately the partitioning of available energy into evapotranspiration components (Running et al., 1999; Mu et al., 2011).
11
+
12
+ References:
13
+ -----------
14
+ - Monteith, J.L., & Unsworth, M.H. (2013). Principles of Environmental Physics (4th Edition). Academic Press.
15
+ - 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
16
+ - Running, S.W., Thornton, P.E., Nemani, R., & Glassy, J.M. (1999). Global terrestrial gross and net primary productivity from the Earth Observing System. In: Methods in Ecosystem Science (pp. 44-57). Springer.
17
+ """
18
+ from .PMJPL_parameter_from_IGBP import PMJPL_parameter_from_IGBP
19
+
20
+ from typing import Optional, Union
21
+ import numpy as np
22
+ from rasters import Raster, RasterGeometry, VectorGeometry
23
+
24
+ from .constants import *
25
+
26
+ def leaf_conductance_to_sensible_heat(
27
+ IGBP: Optional[Union[Raster, np.ndarray]] = None,
28
+ geometry: Optional[Union[RasterGeometry, VectorGeometry]] = None,
29
+ resampling: str = IGBP_PARAMETER_RESAMPLING
30
+ ) -> Optional[Union[Raster, np.ndarray]]:
31
+ """
32
+ Query leaf conductance to sensible heat (gl_sh) for a given biome and geometry.
33
+
34
+ Leaf conductance to sensible heat (gl_sh) is a biome-specific parameter representing the rate at which leaves transfer sensible heat to the atmosphere. It is essential for modeling canopy energy balance and evapotranspiration in land surface models such as MOD16 (Mu et al., 2011).
35
+
36
+ Parameters
37
+ ----------
38
+ IGBP : Raster or np.ndarray
39
+ International Geosphere-Biosphere Programme (IGBP) land cover classification.
40
+ geometry : RasterGeometry or VectorGeometry
41
+ Spatial geometry for the query.
42
+
43
+ Returns
44
+ -------
45
+ gl_sh : Raster or np.ndarray
46
+ Leaf conductance to sensible heat (seconds per meter).
47
+
48
+ References
49
+ ----------
50
+ - Monteith, J.L., & Unsworth, M.H. (2013). Principles of Environmental Physics (4th Edition). Academic Press.
51
+ - Mu, Q., Zhao, M., & Running, S.W. (2011). Improvements to a MODIS global terrestrial evapotranspiration algorithm. Remote Sensing of Environment, 115(8), 1781-1800.
52
+ - Running, S.W., Thornton, P.E., Nemani, R., & Glassy, J.M. (1999). Global terrestrial gross and net primary productivity from the Earth Observing System. In: Methods in Ecosystem Science (pp. 44-57). Springer.
53
+ """
54
+ return PMJPL_parameter_from_IGBP(
55
+ variable="gl_sh",
56
+ IGBP=IGBP,
57
+ geometry=geometry
58
+ )
@@ -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 maximum_boundary_layer_resistance(IGBP: Union[Raster, int], geometry=None, IGBP_upsampling_resolution_meters=None):
6
+ return PMJPL_parameter_from_IGBP(
7
+ variable="RBL_max",
8
+ IGBP=IGBP,
9
+ geometry=geometry,
10
+ IGBP_upsampling_resolution_meters=IGBP_upsampling_resolution_meters
11
+ )
@@ -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 minimum_boundary_layer_resistance(IGBP: Union[Raster, int], geometry=None, IGBP_upsampling_resolution_meters=None):
6
+ return PMJPL_parameter_from_IGBP(
7
+ variable="RBL_min",
8
+ IGBP=IGBP,
9
+ geometry=geometry,
10
+ IGBP_upsampling_resolution_meters=IGBP_upsampling_resolution_meters
11
+ )
@@ -3,7 +3,7 @@ import numpy as np
3
3
  import rasters as rt
4
4
  from rasters import Raster
5
5
 
6
- def calculate_tmin_factor(
6
+ def Tmin_factor(
7
7
  Tmin: Union[Raster, np.ndarray],
8
8
  tmin_open: Union[Raster, np.ndarray],
9
9
  tmin_close: Union[Raster, np.ndarray]) -> Union[Raster, np.ndarray]:
@@ -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
  ),
PMJPL/mod16.csv ADDED
@@ -0,0 +1,19 @@
1
+ LC,gl_sh,gl_e_wv,RBL_min,RBL_max,CL,Tmin_open,Tmin_closed,VPD_closed,VPD_open
2
+ 0,0.02,0.02,20,50,0.007,12.02,-8,4500,650
3
+ 1,0.04,0.04,65,95,0.0032,8.31,-8,3000,650
4
+ 2,0.01,0.01,70,100,0.0025,9.09,-8,4000,1000
5
+ 3,0.04,0.04,65,95,0.0032,10.44,-8,3500,650
6
+ 4,0.01,0.01,65,100,0.0028,9.94,-6,2900,650
7
+ 5,0.04,0.04,65,95,0.0025,9.5,-7,2900,650
8
+ 6,0.04,0.04,20,55,0.0065,8.61,-8,4300,650
9
+ 7,0.04,0.04,20,55,0.0065,8.8,-8,4400,650
10
+ 8,0.08,0.08,25,45,0.0065,11.39,-8,3500,650
11
+ 9,0.08,0.08,25,45,0.0065,11.39,-8,3600,650
12
+ 10,0.02,0.02,20,50,0.007,12.02,-8,4200,650
13
+ 11,0.01,0.01,20,45,0.0065,12.02,-8,4200,650
14
+ 12,0.02,0.02,20,50,0.007,12.02,-8,4500,650
15
+ 13,0.02,0.02,20,50,0.007,12.02,-8,4500,650
16
+ 14,0.02,0.02,20,50,0.007,12.02,-8,4500,650
17
+ 15,0.02,0.02,20,50,0.007,12.02,-8,4500,650
18
+ 16,0.02,0.02,20,50,0.007,12.02,-8,4500,650
19
+ 17,0.02,0.02,20,50,0.007,12.02,-8,4500,650