STIC-JPL 1.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of STIC-JPL might be problematic. Click here for more details.
- STIC_JPL/STIC_JPL.py +370 -0
- STIC_JPL/__init__.py +9 -0
- STIC_JPL/canopy_air_stream.py +37 -0
- STIC_JPL/closure.py +60 -0
- STIC_JPL/constants.py +21 -0
- STIC_JPL/diagnostic.py +70 -0
- STIC_JPL/initialize_with_solar.py +81 -0
- STIC_JPL/initialize_without_solar.py +85 -0
- STIC_JPL/iterate_with_solar.py +144 -0
- STIC_JPL/iterate_without_solar.py +121 -0
- STIC_JPL/meteorology_conversion/__init__.py +1 -0
- STIC_JPL/meteorology_conversion/meteorology_conversion.py +123 -0
- STIC_JPL/net_radiation.py +38 -0
- STIC_JPL/root_zone_initialization.py +36 -0
- STIC_JPL/root_zone_iteration.py +66 -0
- STIC_JPL/soil_heat_flux/__init__.py +1 -0
- STIC_JPL/soil_heat_flux/calculate_SEBAL_soil_heat_flux.py +40 -0
- STIC_JPL/soil_moisture_initialization.py +114 -0
- STIC_JPL/soil_moisture_iteration.py +131 -0
- STIC_JPL/timer/__init__.py +1 -0
- STIC_JPL/timer/timer.py +77 -0
- STIC_JPL/vegetation_conversion/__init__.py +1 -0
- STIC_JPL/vegetation_conversion/vegetation_conversion.py +47 -0
- STIC_JPL/version.txt +1 -0
- stic_jpl-1.1.0.dist-info/METADATA +90 -0
- stic_jpl-1.1.0.dist-info/RECORD +28 -0
- stic_jpl-1.1.0.dist-info/WHEEL +5 -0
- stic_jpl-1.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
from typing import Union, Tuple
|
|
2
|
+
import numpy as np
|
|
3
|
+
|
|
4
|
+
import rasters as rt
|
|
5
|
+
from rasters import Raster
|
|
6
|
+
|
|
7
|
+
from .constants import *
|
|
8
|
+
|
|
9
|
+
def initialize_without_solar(
|
|
10
|
+
ST_C: Union[Raster, np.ndarray], # Surface temperature in Celsius
|
|
11
|
+
Ta_C: Union[Raster, np.ndarray], # Air temperature in Celsius
|
|
12
|
+
dTS: Union[Raster, np.ndarray], # Temperature difference between surface and air in Celsius
|
|
13
|
+
Td_C: Union[Raster, np.ndarray], # Dewpoint temperature in Celsius
|
|
14
|
+
Ea_hPa: Union[Raster, np.ndarray], # Actual vapor pressure in hPa
|
|
15
|
+
Estar_hPa: Union[Raster, np.ndarray], # Saturation vapor pressure at surface temperature in hPa
|
|
16
|
+
SVP_hPa: Union[Raster, np.ndarray], # Saturation vapor pressure at the surface in hPa
|
|
17
|
+
delta_hPa: Union[Raster, np.ndarray], # Slope of the saturation vapor pressure-temperature curve in hPa
|
|
18
|
+
phi_Wm2: Union[Raster, np.ndarray], # Available energy in W/m2
|
|
19
|
+
gamma_hPa: Union[Raster, np.ndarray, float] = GAMMA_HPA, # Psychrometric constant in hPa/°C
|
|
20
|
+
alpha: Union[Raster, np.ndarray, float] = PT_ALPHA # Priestley-Taylor alpha
|
|
21
|
+
) -> Tuple[Union[Raster, np.ndarray]]:
|
|
22
|
+
"""
|
|
23
|
+
Initializes the variables related to moisture and vapor pressure without considering solar radiation.
|
|
24
|
+
|
|
25
|
+
Parameters:
|
|
26
|
+
ST_C (np.ndarray): Surface temperature in Celsius.
|
|
27
|
+
Ta_C (np.ndarray): Air temperature in Celsius.
|
|
28
|
+
dTS (np.ndarray): Temperature difference between surface and air in Celsius.
|
|
29
|
+
Td_C (np.ndarray): Dewpoint temperature in Celsius.
|
|
30
|
+
Ea_hPa (np.ndarray): Actual vapor pressure in hPa.
|
|
31
|
+
Estar (np.ndarray): saturation vapor pressure at surface temperature (hPa/K)
|
|
32
|
+
SVP_hPa (np.ndarray): Saturation vapor pressure at the surface in hPa.
|
|
33
|
+
delta (np.ndarray): Slope of the saturation vapor pressure-temperature curve in hPa/K.
|
|
34
|
+
phi (np.ndarray): available energy in W/m2.
|
|
35
|
+
|
|
36
|
+
Returns:
|
|
37
|
+
Tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray]:
|
|
38
|
+
- SM (np.ndarray): Soil moisture.
|
|
39
|
+
- SMrz (np.ndarray): Rootzone moisture.
|
|
40
|
+
- s1 (np.ndarray): Slope of saturation vapor pressure and dewpoint temperature.
|
|
41
|
+
- s3 (np.ndarray): Slope of saturation vapor pressure and temperature.
|
|
42
|
+
- s33 (np.ndarray): Slope of saturation vapor pressure and surface temperature.
|
|
43
|
+
- s44 (np.ndarray): s44
|
|
44
|
+
- Ms (np.ndarray): Surface moisture.
|
|
45
|
+
- Tsd_C (np.ndarray): Surface dewpoint temperature in Celsius.
|
|
46
|
+
- Es (np.ndarray): Surface vapor pressure in hPa.
|
|
47
|
+
- Ds (np.ndarray): Vapor pressure deficit at the surface.
|
|
48
|
+
"""
|
|
49
|
+
s33 = (45.03 + 3.014 * ST_C + 0.05345 * ST_C ** 2 + 0.00224 * ST_C ** 3) * 1e-2 # hpa/K
|
|
50
|
+
s1 = (45.03 + 3.014 * Td_C + 0.05345 * Td_C ** 2 + 0.00224 * Td_C ** 3) * 1e-2 # hpa/K
|
|
51
|
+
|
|
52
|
+
# Surface dewpoint (Celsius)
|
|
53
|
+
Tsd_C = ((Estar_hPa - Ea_hPa) - (s33 * ST_C) + (s1 * Td_C)) / (s1 - s33)
|
|
54
|
+
|
|
55
|
+
# slope of saturation vapor pressure and temperature
|
|
56
|
+
s3 = rt.where((dTS > -20) & (dTS < 5), (Estar_hPa - Ea_hPa) / (ST_C - Td_C),
|
|
57
|
+
(45.03 + 3.014 * ST_C + 0.05345 * ST_C ** 2 + 0.00224 * ST_C ** 3) * 1e-2) # hpa/K
|
|
58
|
+
|
|
59
|
+
# Surface Moisture (Ms)
|
|
60
|
+
# Surface wetness
|
|
61
|
+
Ms = (s1 / s3) * ((Tsd_C - Td_C) / (ST_C - Td_C))
|
|
62
|
+
Ms = rt.clip(rt.where((dTS < 0) & (Ms < 0) & (phi_Wm2 < 0), np.abs(Ms), Ms), 0, 1)
|
|
63
|
+
|
|
64
|
+
# Rootzone Moisture (Mrz)
|
|
65
|
+
s44 = (SVP_hPa - Ea_hPa) / (Ta_C - Td_C)
|
|
66
|
+
SMrz = (gamma_hPa * s1 * (Tsd_C - Td_C)) / (
|
|
67
|
+
delta_hPa * s3 * (ST_C - Td_C) + gamma_hPa * s44 * (Ta_C - Td_C) - delta_hPa * s1 * (
|
|
68
|
+
Tsd_C - Td_C)) # rootzone wetness
|
|
69
|
+
SMrz = rt.clip(rt.where((dTS < 0) & (SMrz < 0) & (phi_Wm2 < 0), np.abs(SMrz), SMrz), 0, 1)
|
|
70
|
+
|
|
71
|
+
# now the limits of both Ms and Mrz are consistent
|
|
72
|
+
# combine M to account for Hysteresis and initial estimation of surface vapor pressure
|
|
73
|
+
# Potential evaporation (Priestley-Taylor eqn.)
|
|
74
|
+
Ep_PT = (alpha * delta_hPa * phi_Wm2) / (delta_hPa + gamma_hPa)
|
|
75
|
+
Es = rt.where((Ep_PT > phi_Wm2) & (dTS > 0) & (Td_C <= 0), Ea_hPa + SMrz * (Estar_hPa - Ea_hPa),
|
|
76
|
+
Ea_hPa + Ms * (Estar_hPa - Ea_hPa))
|
|
77
|
+
|
|
78
|
+
# soil moisture
|
|
79
|
+
SM = rt.where((Ep_PT > phi_Wm2) & (dTS > 0) & (Td_C <= 0), SMrz, Ms)
|
|
80
|
+
|
|
81
|
+
# hysteresis logic
|
|
82
|
+
# vapor pressure deficit at surface (Ds is later replaced by D0)
|
|
83
|
+
Ds = (Estar_hPa - Es)
|
|
84
|
+
|
|
85
|
+
return SM, SMrz, s1, s3, s33, s44, Ms, Tsd_C, Es, Ds
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
from typing import Union, Tuple
|
|
2
|
+
import numpy as np
|
|
3
|
+
|
|
4
|
+
import rasters as rt
|
|
5
|
+
|
|
6
|
+
from rasters import Raster
|
|
7
|
+
|
|
8
|
+
from .soil_heat_flux import calculate_SEBAL_soil_heat_flux
|
|
9
|
+
|
|
10
|
+
from .constants import *
|
|
11
|
+
from .canopy_air_stream import calculate_canopy_air_stream_vapor_pressure
|
|
12
|
+
from .soil_moisture_iteration import iterate_soil_moisture
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def iterate_with_solar(
|
|
16
|
+
seconds_of_day: Union[Raster, np.ndarray], # Seconds of the day
|
|
17
|
+
ST_C: Union[Raster, np.ndarray], # Soil temperature (°C)
|
|
18
|
+
NDVI: Union[Raster, np.ndarray], # Normalized Difference Vegetation Index
|
|
19
|
+
albedo: Union[Raster, np.ndarray], # Albedo
|
|
20
|
+
gB_ms: Union[Raster, np.ndarray], # boundary layer conductance (m/s)
|
|
21
|
+
gS_ms: Union[Raster, np.ndarray], # stomatal conductance (m/s)
|
|
22
|
+
LE_Wm2: Union[Raster, np.ndarray], # latent heat flux (W/m^2)
|
|
23
|
+
Rg_Wm2: Union[Raster, np.ndarray], # Incoming solar radiation (W/m^2)
|
|
24
|
+
Rn_Wm2: Union[Raster, np.ndarray], # Net radiation (W/m^2)
|
|
25
|
+
LWnet_Wm2: Union[Raster, np.ndarray], # Net longwave radiation (W/m^2)
|
|
26
|
+
Ta_C: Union[Raster, np.ndarray], # Air temperature (°C)
|
|
27
|
+
dTS_C: Union[Raster, np.ndarray], # Change in soil temperature (°C)
|
|
28
|
+
Td_C: Union[Raster, np.ndarray], # Dew point temperature (°C)
|
|
29
|
+
Tsd_C: Union[Raster, np.ndarray], # Soil dew point temperature (°C)
|
|
30
|
+
Ea_hPa: Union[Raster, np.ndarray], # actual vapor pressure (hPa)
|
|
31
|
+
Estar_hPa: Union[Raster, np.ndarray], # saturation vapor pressure at surface temperature (hPa)
|
|
32
|
+
VPD_hPa: Union[Raster, np.ndarray], # Vapor pressure deficit (hPa)
|
|
33
|
+
SVP_hPa: Union[Raster, np.ndarray], # Saturation vapor pressure (hPa)
|
|
34
|
+
delta_hPa: Union[Raster, np.ndarray], # Slope of the saturation vapor pressure-temperature curve (hPa/°C)
|
|
35
|
+
phi_Wm2: Union[Raster, np.ndarray], # Net radiation minus soil heat flux (W/m^2)
|
|
36
|
+
Es_hPa: Union[Raster, np.ndarray], # Saturation vapor pressure (hPa)
|
|
37
|
+
s1: Union[Raster, np.ndarray], # Soil moisture parameter
|
|
38
|
+
s3: Union[Raster, np.ndarray], # Soil moisture parameter
|
|
39
|
+
FVC: Union[Raster, np.ndarray], # Fractional canopy cover
|
|
40
|
+
T0_C: Union[Raster, np.ndarray], # Reference temperature (°C)
|
|
41
|
+
gB_by_gS: Union[Raster, np.ndarray], # Ratio of boundary layer conductance to stomatal conductance
|
|
42
|
+
rho_kgm3: Union[Raster, np.ndarray, float] = RHO_KGM3, # Air density (kg/m^3)
|
|
43
|
+
Cp_Jkg: Union[Raster, np.ndarray, float] = CP_JKG, # Specific heat at constant pressure (J/kg/K)
|
|
44
|
+
gamma_hPa: Union[Raster, np.ndarray, float] = GAMMA_HPA, # Psychrometric constant (hPa/°C)
|
|
45
|
+
G_method: str = "santanello" # Method for calculating soil heat flux
|
|
46
|
+
) -> Tuple[Union[Raster, np.ndarray]]:
|
|
47
|
+
"""
|
|
48
|
+
This function calculates the canopy air stream vapor pressures, vapor pressure deficit at source,
|
|
49
|
+
vapor pressure at the reference height, soil moisture, soil heat flux, and recompute phi.
|
|
50
|
+
|
|
51
|
+
Parameters:
|
|
52
|
+
seconds_of_day (np.ndarray): Seconds of the day
|
|
53
|
+
ST_C (np.ndarray): Soil temperature (°C)
|
|
54
|
+
NDVI (np.ndarray): Normalized Difference Vegetation Index
|
|
55
|
+
albedo (np.ndarray): Albedo
|
|
56
|
+
gB (np.ndarray): Boundary layer conductance (m/s)
|
|
57
|
+
gS (np.ndarray): Stomatal conductance (m/s)
|
|
58
|
+
LE (np.ndarray): Latent heat flux (W/m^2)
|
|
59
|
+
Rg (np.ndarray): Incoming solar radiation (W/m^2)
|
|
60
|
+
Rn (np.ndarray): Net radiation (W/m^2)
|
|
61
|
+
LWnet (np.ndarray): Net longwave radiation (W/m^2)
|
|
62
|
+
Ta_C (np.ndarray): Air temperature (°C)
|
|
63
|
+
dTS (np.ndarray): Change in soil temperature (°C)
|
|
64
|
+
Td_C (np.ndarray): Dew point temperature (°C)
|
|
65
|
+
Tsd_C (np.ndarray): Soil dew point temperature (°C)
|
|
66
|
+
Ea_hPa (np.ndarray): Actual vapor pressure (hPa)
|
|
67
|
+
Estar (np.ndarray): Saturation vapor pressure at surface temperature (hPa)
|
|
68
|
+
VPD_hPa (np.ndarray): Vapor pressure deficit (hPa)
|
|
69
|
+
SVP_hPa (np.ndarray): Saturation vapor pressure (hPa)
|
|
70
|
+
delta (np.ndarray): Slope of the saturation vapor pressure-temperature curve (hPa/°C)
|
|
71
|
+
phi (np.ndarray): Net radiation minus soil heat flux (W/m^2)
|
|
72
|
+
Es (np.ndarray): Saturation vapor pressure (hPa)
|
|
73
|
+
s1 (np.ndarray): Soil moisture parameter
|
|
74
|
+
s3 (np.ndarray): Soil moisture parameter
|
|
75
|
+
fc (np.ndarray): Fractional canopy cover
|
|
76
|
+
T0 (np.ndarray): Reference temperature (°C)
|
|
77
|
+
gB_by_gS (np.ndarray): Ratio of boundary layer conductance to stomatal conductance
|
|
78
|
+
gamma (np.ndarray): Psychrometric constant (hPa/°C)
|
|
79
|
+
rho (np.ndarray): Air density (kg/m^3)
|
|
80
|
+
cp (np.ndarray): Specific heat at constant pressure (J/kg/K)
|
|
81
|
+
G_method (str): Method for calculating soil heat flux (santanello or SEBAL)
|
|
82
|
+
|
|
83
|
+
Returns:
|
|
84
|
+
e0star (np.ndarray): Canopy air stream vapor pressures
|
|
85
|
+
D0 (np.ndarray): Vapor pressure deficit at source
|
|
86
|
+
e0 (np.ndarray): Vapor pressure at the reference height
|
|
87
|
+
SM (np.ndarray): Soil moisture
|
|
88
|
+
G (np.ndarray): Soil heat flux
|
|
89
|
+
"""
|
|
90
|
+
# canopy air stream vapor pressures
|
|
91
|
+
e0star = calculate_canopy_air_stream_vapor_pressure(
|
|
92
|
+
LE=LE_Wm2,
|
|
93
|
+
Ea_hPa=Ea_hPa,
|
|
94
|
+
Estar=Estar_hPa,
|
|
95
|
+
gB=gB_ms,
|
|
96
|
+
gS=gS_ms
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
# vapor pressure deficit at source
|
|
100
|
+
D0 = VPD_hPa + (delta_hPa * phi_Wm2 - (delta_hPa + gamma_hPa) * LE_Wm2) / (rho_kgm3 * Cp_Jkg * gB_ms)
|
|
101
|
+
|
|
102
|
+
# Vapor pressure at the reference height (hPa)
|
|
103
|
+
e0 = e0star - D0
|
|
104
|
+
e0 = rt.where(e0 < 0, Es_hPa, e0)
|
|
105
|
+
e0 = rt.where(e0 > e0star, e0star, e0)
|
|
106
|
+
|
|
107
|
+
# calculate soil moisture
|
|
108
|
+
SM = iterate_soil_moisture(
|
|
109
|
+
delta_hPa=delta_hPa,
|
|
110
|
+
s1=s1,
|
|
111
|
+
s3=s3,
|
|
112
|
+
ST_C=ST_C,
|
|
113
|
+
Ta_C=Ta_C,
|
|
114
|
+
dTS_C=dTS_C,
|
|
115
|
+
Td_C=Td_C,
|
|
116
|
+
Tsd_C=Tsd_C,
|
|
117
|
+
Rg_Wm2=Rg_Wm2,
|
|
118
|
+
Rn_Wm2=Rn_Wm2,
|
|
119
|
+
LWnet_Wm2=LWnet_Wm2,
|
|
120
|
+
FVC=FVC,
|
|
121
|
+
VPD_hPa=VPD_hPa,
|
|
122
|
+
D0_hPa=D0,
|
|
123
|
+
SVP_hPa=SVP_hPa,
|
|
124
|
+
Ea_hPa=Ea_hPa,
|
|
125
|
+
T0=T0_C,
|
|
126
|
+
gamma_hPa=gamma_hPa
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
# calculate soil heat flux
|
|
130
|
+
G = calculate_SEBAL_soil_heat_flux(
|
|
131
|
+
ST_C=ST_C,
|
|
132
|
+
NDVI=NDVI,
|
|
133
|
+
albedo=albedo,
|
|
134
|
+
Rn=Rn_Wm2
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
# recompute phi
|
|
138
|
+
phi_Wm2 = Rn_Wm2 - G
|
|
139
|
+
|
|
140
|
+
#
|
|
141
|
+
alphaN = ((gS_ms * (e0star - Ea_hPa) * (2 * delta_hPa + 2 * gamma_hPa + gamma_hPa * gB_by_gS * (1 + SM))) / (
|
|
142
|
+
2 * delta_hPa * (gamma_hPa * (T0_C - Ta_C) * (gB_ms + gS_ms) + gS_ms * (e0star - Ea_hPa))))
|
|
143
|
+
|
|
144
|
+
return SM, G, e0, e0star, D0, alphaN
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
from typing import Union, Tuple
|
|
2
|
+
import numpy as np
|
|
3
|
+
|
|
4
|
+
import rasters as rt
|
|
5
|
+
from rasters import Raster
|
|
6
|
+
|
|
7
|
+
from .constants import *
|
|
8
|
+
from .canopy_air_stream import calculate_canopy_air_stream_vapor_pressure
|
|
9
|
+
from .root_zone_initialization import calculate_root_zone_moisture
|
|
10
|
+
|
|
11
|
+
def iterate_without_solar(
|
|
12
|
+
LE: Union[Raster, np.ndarray], # Latent heat flux (W/m^2)
|
|
13
|
+
PET: Union[Raster, np.ndarray], # Potential evapotranspiration (W/m^2)
|
|
14
|
+
SM: Union[Raster, np.ndarray],
|
|
15
|
+
ST_C: Union[Raster, np.ndarray], # Surface temperature (°C)
|
|
16
|
+
Ta_C: Union[Raster, np.ndarray], # Air temperature (°C)
|
|
17
|
+
dTS: Union[Raster, np.ndarray], # Surface-air temperature difference (°C)
|
|
18
|
+
T0: Union[Raster, np.ndarray], # Reference temperature (°C)
|
|
19
|
+
gB: Union[Raster, np.ndarray], # Boundary layer conductance (m/s)
|
|
20
|
+
gS: Union[Raster, np.ndarray], # Stomatal conductance (m/s)
|
|
21
|
+
Ea_hPa: Union[Raster, np.ndarray], # Actual vapor pressure (hPa)
|
|
22
|
+
Td_C: Union[Raster, np.ndarray], # Dew point temperature (°C)
|
|
23
|
+
VPD_hPa: Union[Raster, np.ndarray], # Vapor pressure deficit (hPa)
|
|
24
|
+
Estar: Union[Raster, np.ndarray], # Saturation vapor pressure at surface temperature (hPa)
|
|
25
|
+
delta: Union[Raster, np.ndarray], # Slope of the saturation vapor pressure-temperature curve (hPa/°C)
|
|
26
|
+
phi: Union[Raster, np.ndarray], # available energy (W/m^2)
|
|
27
|
+
Ds: Union[Raster, np.ndarray], # Vapor pressure deficit at source (hPa)
|
|
28
|
+
Es: Union[Raster, np.ndarray], # Saturation vapor pressure (hPa)
|
|
29
|
+
s3: Union[Raster, np.ndarray], # Slope of the saturation vapor pressure and temperature
|
|
30
|
+
s4: Union[Raster, np.ndarray], # Slope of the saturation vapor pressure and temperature
|
|
31
|
+
gB_by_gS: Union[Raster, np.ndarray], # Ratio of boundary layer conductance to stomatal conductance
|
|
32
|
+
gamma_hPa: Union[Raster, np.ndarray] = GAMMA_HPA, # Psychrometric constant (hPa/°C)
|
|
33
|
+
rho_kgm3: Union[Raster, np.ndarray] = RHO_KGM3, # Air density (kg/m^3)
|
|
34
|
+
Cp_Jkg: Union[Raster, np.ndarray] = CP_JKG, # Specific heat at constant pressure (J/kg/K)
|
|
35
|
+
) -> Tuple[Union[Raster, np.ndarray]]:
|
|
36
|
+
"""
|
|
37
|
+
Iterate STIC model without knowing solar radiation.
|
|
38
|
+
|
|
39
|
+
Parameters:
|
|
40
|
+
LE (np.ndarray): Latent heat flux (W/m^2)
|
|
41
|
+
PET (np.ndarray): Potential evapotranspiration (W/m^2)
|
|
42
|
+
ST_C (np.ndarray): Surface temperature (°C)
|
|
43
|
+
Ta_C (np.ndarray): Air temperature (°C)
|
|
44
|
+
dTS (np.ndarray): Surface-air temperature difference (°C)
|
|
45
|
+
T0 (np.ndarray): Reference temperature (°C)
|
|
46
|
+
gB (np.ndarray): Boundary layer conductance (m/s)
|
|
47
|
+
gS (np.ndarray): Stomatal conductance (m/s)
|
|
48
|
+
Ea_hPa (np.ndarray): Actual vapor pressure (hPa)
|
|
49
|
+
Td_C (np.ndarray): Dew point temperature (°C)
|
|
50
|
+
VPD_hPa (np.ndarray): Vapor pressure deficit (hPa)
|
|
51
|
+
Estar (np.ndarray): Saturation vapor pressure at surface temperature (hPa)
|
|
52
|
+
delta (np.ndarray): Slope of the saturation vapor pressure-temperature curve (hPa/°C)
|
|
53
|
+
phi (np.ndarray): available energy (W/m^2)
|
|
54
|
+
Ds (np.ndarray): Vapor pressure deficit at source (hPa)
|
|
55
|
+
Es (np.ndarray): Saturation vapor pressure (hPa)
|
|
56
|
+
s3 (np.ndarray): Slope of the saturation vapor pressure and temperature
|
|
57
|
+
s4 (np.ndarray): Soil moisture parameter
|
|
58
|
+
gB_by_gS (np.ndarray): Ratio of boundary layer conductance to stomatal conductance
|
|
59
|
+
gamma (np.ndarray): Psychrometric constant (hPa/°C)
|
|
60
|
+
rho (np.ndarray): Air density (kg/m^3)
|
|
61
|
+
cp (np.ndarray): Specific heat at constant pressure (J/kg/K)
|
|
62
|
+
|
|
63
|
+
Returns:
|
|
64
|
+
SM (np.ndarray): soil moisture (m³/m³)
|
|
65
|
+
SMrz (np.ndarray): Root zone moisture (m³/m³)
|
|
66
|
+
Ms (np.ndarray): Surface Moisture
|
|
67
|
+
s1 (np.ndarray): lope of the saturation vapor pressure and temperature
|
|
68
|
+
e0 (np.ndarray): Vapor pressure at the reference height (hPa)
|
|
69
|
+
e0star (np.ndarray): Canopy air stream vapor pressures (hPa)
|
|
70
|
+
Tsd_C (np.ndarray): Soil dew point temperature (°C)
|
|
71
|
+
D0 (np.ndarray): Vapor pressure deficit at source (hPa)
|
|
72
|
+
alphaN (np.ndarray): Alpha parameter
|
|
73
|
+
"""
|
|
74
|
+
|
|
75
|
+
# canopy air stream vapor pressures
|
|
76
|
+
e0star = calculate_canopy_air_stream_vapor_pressure(
|
|
77
|
+
LE=LE, # latent heat flux (W/m^2)
|
|
78
|
+
Ea_hPa=Ea_hPa, # actual vapor pressure (hPa)
|
|
79
|
+
Estar=Estar, # saturation vapor pressure at surface temperature (hPa)
|
|
80
|
+
gB=gB, # boundary layer conductance (m/s)
|
|
81
|
+
gS=gS # stomatal conductance (m/s),
|
|
82
|
+
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
# vapor pressure deficit at source
|
|
86
|
+
D0 = VPD_hPa + (delta * phi - (delta + gamma_hPa) * LE) / (rho_kgm3 * Cp_Jkg * gB)
|
|
87
|
+
D0 = rt.where(D0 < 0, Ds, D0)
|
|
88
|
+
|
|
89
|
+
# Vapor pressure at the reference height (hPa)
|
|
90
|
+
e0 = rt.clip(e0star - D0, Es, e0star)
|
|
91
|
+
|
|
92
|
+
# re-estimating M (direct LST feedback into M computation)
|
|
93
|
+
s1 = (45.03 + 3.014 * Td_C + 0.05345 * Td_C ** 2 + 0.00224 * Td_C ** 3) * 1e-2 # Soil moisture parameter
|
|
94
|
+
Tsd_C = Td_C + (gamma_hPa * LE) / (rho_kgm3 * Cp_Jkg * gB * s1) # Soil dew point temperature (°C)
|
|
95
|
+
|
|
96
|
+
# Surface Moisture Ms
|
|
97
|
+
Ms = rt.clip(s1 * (Tsd_C - Td_C) / (s3 * (ST_C - Td_C)), 0, 1)
|
|
98
|
+
|
|
99
|
+
# Root zone moisture Mrz
|
|
100
|
+
SMrz = calculate_root_zone_moisture(
|
|
101
|
+
delta_hPa=delta, # Slope of the saturation vapor pressure-temperature curve (hPa/°C)
|
|
102
|
+
ST_C=ST_C, # Surface temperature (°C)
|
|
103
|
+
Ta_C=Ta_C, # Air temperature (°C)
|
|
104
|
+
Td_C=Td_C, # Dew point temperature (°C)
|
|
105
|
+
s11=s1, # Soil moisture parameter
|
|
106
|
+
s33=s3, # Soil moisture parameter
|
|
107
|
+
s44=s4, # Soil moisture parameter
|
|
108
|
+
Tsd_C=Tsd_C # Soil dew point temperature (°C)
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
# combining hysteresis logic to differentiate surface vs. rootzone water control
|
|
112
|
+
SM = rt.where((D0 > VPD_hPa) & (PET > phi) & (dTS > 0), SMrz, SM)
|
|
113
|
+
SM = rt.where((phi > 0) & (dTS > 0) & (Td_C <= 0), SMrz, SM)
|
|
114
|
+
SM = rt.clip(SM, 0, 1)
|
|
115
|
+
|
|
116
|
+
# checking convergence
|
|
117
|
+
# re-estimating alpha
|
|
118
|
+
alphaN = ((gS * (e0star - Ea_hPa) * (2 * delta + 2 * gamma_hPa + gamma_hPa * gB_by_gS * (1 + SM))) / (
|
|
119
|
+
2 * delta * (gamma_hPa * (T0 - Ta_C) * (gB + gS) + gS * (e0star - Ea_hPa))))
|
|
120
|
+
|
|
121
|
+
return SM, SMrz, Ms, s1, e0, e0star, Tsd_C, D0, alphaN
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .meteorology_conversion import *
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
from typing import Union
|
|
2
|
+
import numpy as np
|
|
3
|
+
import rasters as rt
|
|
4
|
+
from rasters import Raster
|
|
5
|
+
|
|
6
|
+
# gas constant for dry air in joules per kilogram per kelvin
|
|
7
|
+
RD = 286.9
|
|
8
|
+
|
|
9
|
+
# gas constant for moist air in joules per kilogram per kelvin
|
|
10
|
+
RW = 461.5
|
|
11
|
+
|
|
12
|
+
# specific heat of water vapor in joules per kilogram per kelvin
|
|
13
|
+
CPW = 1846.0
|
|
14
|
+
|
|
15
|
+
# specific heat of dry air in joules per kilogram per kelvin
|
|
16
|
+
CPD = 1005.0
|
|
17
|
+
|
|
18
|
+
def kelvin_to_celsius(T_K: Union[Raster, np.ndarray]) -> Union[Raster, np.ndarray]:
|
|
19
|
+
"""
|
|
20
|
+
convert temperature in kelvin to celsius.
|
|
21
|
+
:param T_K: temperature in kelvin
|
|
22
|
+
:return: temperature in celsius
|
|
23
|
+
"""
|
|
24
|
+
return T_K - 273.15
|
|
25
|
+
|
|
26
|
+
def celcius_to_kelvin(T_C: Union[Raster, np.ndarray]) -> Union[Raster, np.ndarray]:
|
|
27
|
+
"""
|
|
28
|
+
convert temperature in celsius to kelvin.
|
|
29
|
+
:param T_C: temperature in celsius
|
|
30
|
+
:return: temperature in kelvin
|
|
31
|
+
"""
|
|
32
|
+
return T_C + 273.15
|
|
33
|
+
|
|
34
|
+
def calculate_specific_humidity(
|
|
35
|
+
Ea_Pa: Union[Raster, np.ndarray],
|
|
36
|
+
Ps_Pa: Union[Raster, np.ndarray]) -> Union[Raster, np.ndarray]:
|
|
37
|
+
"""
|
|
38
|
+
Calculate the specific humidity of air as a ratio of kilograms of water to kilograms of air.
|
|
39
|
+
|
|
40
|
+
Args:
|
|
41
|
+
Ea_Pa (Union[Raster, np.ndarray]): Actual water vapor pressure in Pascal.
|
|
42
|
+
surface_pressure_Pa (Union[Raster, np.ndarray]): Surface pressure in Pascal.
|
|
43
|
+
|
|
44
|
+
Returns:
|
|
45
|
+
Union[Raster, np.ndarray]: Specific humidity in kilograms of water per kilograms of air.
|
|
46
|
+
"""
|
|
47
|
+
return ((0.622 * Ea_Pa) / (Ps_Pa - (0.387 * Ea_Pa)))
|
|
48
|
+
|
|
49
|
+
def calculate_specific_heat(specific_humidity: Union[Raster, np.ndarray]):
|
|
50
|
+
# calculate specific heat capacity of the air (Cp)
|
|
51
|
+
# in joules per kilogram per kelvin
|
|
52
|
+
# from specific heat of water vapor (CPW)
|
|
53
|
+
# and specific heat of dry air (CPD)
|
|
54
|
+
Cp_Jkg = specific_humidity * CPW + (1 - specific_humidity) * CPD
|
|
55
|
+
|
|
56
|
+
return Cp_Jkg
|
|
57
|
+
|
|
58
|
+
def calculate_air_density(
|
|
59
|
+
surface_pressure_Pa: Union[Raster, np.ndarray],
|
|
60
|
+
Ta_K: Union[Raster, np.ndarray],
|
|
61
|
+
specific_humidity: Union[Raster, np.ndarray]) -> Union[Raster, np.ndarray]:
|
|
62
|
+
"""
|
|
63
|
+
Calculate air density.
|
|
64
|
+
|
|
65
|
+
Parameters:
|
|
66
|
+
surface_pressure_Pa (Union[Raster, np.ndarray]): Surface pressure in Pascal.
|
|
67
|
+
Ta_K (Union[Raster, np.ndarray]): Air temperature in Kelvin.
|
|
68
|
+
specific_humidity (Union[Raster, np.ndarray]): Specific humidity.
|
|
69
|
+
|
|
70
|
+
Returns:
|
|
71
|
+
Union[Raster, np.ndarray]: Air density in kilograms per cubic meter.
|
|
72
|
+
"""
|
|
73
|
+
# numerator: Pa(N / m ^ 2 = kg * m / s ^ 2); denominator: J / kg / K * K)
|
|
74
|
+
rhoD = surface_pressure_Pa / (RD * Ta_K)
|
|
75
|
+
|
|
76
|
+
# calculate air density (rho) in kilograms per cubic meter
|
|
77
|
+
rho = rhoD * ((1.0 + specific_humidity) / (1.0 + specific_humidity * (RW / RD)))
|
|
78
|
+
|
|
79
|
+
return rho
|
|
80
|
+
|
|
81
|
+
def SVP_kPa_from_Ta_C(Ta_C: Union[Raster, np.ndarray]) -> Union[Raster, np.ndarray]:
|
|
82
|
+
"""
|
|
83
|
+
Calculate the saturation vapor pressure in kiloPascal (kPa) from air temperature in Celsius.
|
|
84
|
+
|
|
85
|
+
Parameters:
|
|
86
|
+
Ta_C (Union[Raster, np.ndarray]): Air temperature in Celsius.
|
|
87
|
+
|
|
88
|
+
Returns:
|
|
89
|
+
Union[Raster, np.ndarray]: Saturation vapor pressure in kPa.
|
|
90
|
+
|
|
91
|
+
"""
|
|
92
|
+
SVP_kPa = np.clip(0.611 * np.exp((Ta_C * 17.27) / (Ta_C + 237.7)), 1, None)
|
|
93
|
+
|
|
94
|
+
return SVP_kPa
|
|
95
|
+
|
|
96
|
+
def SVP_Pa_from_Ta_C(Ta_C: Union[Raster, np.ndarray]) -> Union[Raster, np.ndarray]:
|
|
97
|
+
"""
|
|
98
|
+
Calculate the saturation vapor pressure in Pascal (Pa) from the air temperature in Celsius (Ta_C).
|
|
99
|
+
|
|
100
|
+
Parameters:
|
|
101
|
+
Ta_C (Union[Raster, np.ndarray]): Air temperature in Celsius.
|
|
102
|
+
|
|
103
|
+
Returns:
|
|
104
|
+
Union[Raster, np.ndarray]: Saturation vapor pressure in Pascal (Pa).
|
|
105
|
+
"""
|
|
106
|
+
return SVP_kPa_from_Ta_C(Ta_C) * 1000
|
|
107
|
+
|
|
108
|
+
def calculate_surface_pressure(elevation_m: Union[Raster, np.ndarray], Ta_C: Union[Raster, np.ndarray]) -> Union[Raster, np.ndarray]:
|
|
109
|
+
"""
|
|
110
|
+
Calculate surface pressure using elevation and air temperature.
|
|
111
|
+
|
|
112
|
+
Parameters:
|
|
113
|
+
elevation_m (Union[Raster, np.ndarray]): Elevation in meters.
|
|
114
|
+
Ta_K (Union[Raster, np.ndarray]): Air temperature in Kelvin.
|
|
115
|
+
|
|
116
|
+
Returns:
|
|
117
|
+
Union[Raster, np.ndarray]: Surface pressure in Pascal (Pa).
|
|
118
|
+
"""
|
|
119
|
+
Ta_K = kelvin_to_celsius(Ta_C)
|
|
120
|
+
Ps_Pa = 101325.0 * (1.0 - 0.0065 * elevation_m / Ta_K) ** (9.807 / (0.0065 * 287.0)) # [Pa]
|
|
121
|
+
|
|
122
|
+
return Ps_Pa
|
|
123
|
+
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
from typing import Union
|
|
2
|
+
import numpy as np
|
|
3
|
+
|
|
4
|
+
from rasters import Raster
|
|
5
|
+
|
|
6
|
+
from .constants import SB_SIGMA
|
|
7
|
+
|
|
8
|
+
def calculate_net_longwave_radiation(
|
|
9
|
+
Ta_C: Union[Raster, np.ndarray],
|
|
10
|
+
Ea_hPa: Union[Raster, np.ndarray],
|
|
11
|
+
ST_C: Union[Raster, np.ndarray],
|
|
12
|
+
emissivity: Union[Raster, np.ndarray],
|
|
13
|
+
albedo: Union[Raster, np.ndarray],
|
|
14
|
+
sigma: float = SB_SIGMA) -> Union[Raster, np.ndarray]:
|
|
15
|
+
"""
|
|
16
|
+
Calculate the net radiation.
|
|
17
|
+
|
|
18
|
+
Parameters:
|
|
19
|
+
Ta_C (np.ndarray): Air temperature in Celsius
|
|
20
|
+
Ea_hPa (np.ndarray): Actual vapor pressure at air temperature in hPa
|
|
21
|
+
ST_C (np.ndarray): Surface temperature in Celsius
|
|
22
|
+
emissivity (np.ndarray): Emissivity of the surface
|
|
23
|
+
RG (np.ndarray): Global radiation
|
|
24
|
+
albedo (np.ndarray): Albedo of the surface
|
|
25
|
+
|
|
26
|
+
Returns:
|
|
27
|
+
Lnet (np.ndarray): Net longwave radiation
|
|
28
|
+
"""
|
|
29
|
+
etaa = 1.24 * (Ea_hPa / (Ta_C + 273.15)) ** (1.0 / 7.0) # air emissivity
|
|
30
|
+
LWin = sigma * etaa * (Ta_C + 273.15) ** 4
|
|
31
|
+
LWout = sigma * emissivity * (ST_C + 273.15) ** 4
|
|
32
|
+
|
|
33
|
+
# emissivity was being applied twice here
|
|
34
|
+
# LWnet = emissivity * LWin - LWout
|
|
35
|
+
|
|
36
|
+
LWnet = LWin - LWout
|
|
37
|
+
|
|
38
|
+
return LWnet
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
from typing import Union
|
|
2
|
+
import numpy as np
|
|
3
|
+
|
|
4
|
+
import rasters as rt
|
|
5
|
+
from rasters import Raster
|
|
6
|
+
|
|
7
|
+
from .constants import GAMMA_HPA
|
|
8
|
+
|
|
9
|
+
def calculate_root_zone_moisture(
|
|
10
|
+
delta_hPa: Union[Raster, np.ndarray],
|
|
11
|
+
ST_C: Union[Raster, np.ndarray],
|
|
12
|
+
Ta_C: Union[Raster, np.ndarray],
|
|
13
|
+
Td_C: Union[Raster, np.ndarray],
|
|
14
|
+
s11: Union[Raster, np.ndarray],
|
|
15
|
+
s33: Union[Raster, np.ndarray],
|
|
16
|
+
s44: Union[Raster, np.ndarray],
|
|
17
|
+
Tsd_C: Union[Raster, np.ndarray],
|
|
18
|
+
gamma_hPa: Union[Raster, np.ndarray, float] = GAMMA_HPA) -> Union[Raster, np.ndarray]:
|
|
19
|
+
"""
|
|
20
|
+
This function calculates the rootzone moisture (Mrz) using various parameters.
|
|
21
|
+
|
|
22
|
+
Parameters:
|
|
23
|
+
delta (np.ndarray): Rate of change of saturation vapor pressure with temperature (hPa/°C)
|
|
24
|
+
ST_C (np.ndarray): Surface temperature (°C)
|
|
25
|
+
Ta_C (np.ndarray): Air temperature (°C)
|
|
26
|
+
Td_C (np.ndarray): Dewpoint temperature (°C)
|
|
27
|
+
s11 (np.ndarray): The slope of SVP at dewpoint temperature (hPa/K)
|
|
28
|
+
s33 (np.ndarray): The slope of SVP at surface temperature (hPa/K)
|
|
29
|
+
s44 (np.ndarray): The difference between saturation vapor pressure and actual vapor pressure divided by the difference between air temperature and dewpoint temperature (hPa/K)
|
|
30
|
+
Tsd_C (np.ndarray): The surface dewpoint temperature (°C)
|
|
31
|
+
|
|
32
|
+
Returns:
|
|
33
|
+
SMrz (np.ndarray): The rootzone moisture (m³/m³)
|
|
34
|
+
"""
|
|
35
|
+
return rt.clip((gamma_hPa * s11 * (Tsd_C - Td_C)) / (delta_hPa * s33 * (ST_C - Td_C) + gamma_hPa * s44 * (Ta_C - Td_C) - delta_hPa * s11 * (Tsd_C - Td_C)), 0.0001, 0.999)
|
|
36
|
+
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
from typing import Union
|
|
2
|
+
import numpy as np
|
|
3
|
+
|
|
4
|
+
import rasters as rt
|
|
5
|
+
|
|
6
|
+
from rasters import Raster
|
|
7
|
+
|
|
8
|
+
from .constants import GAMMA_HPA
|
|
9
|
+
|
|
10
|
+
def calculate_rootzone_moisture(
|
|
11
|
+
delta_hPa: Union[Raster, np.ndarray], # Rate of change of saturation vapor pressure with temperature (hPa/°C)
|
|
12
|
+
s1_hPa: Union[Raster, np.ndarray], # The slope of SVP at surface temperature (hPa/K)
|
|
13
|
+
s3_hPa: Union[Raster, np.ndarray], # The slope of SVP at dewpoint temperature (hPa/K)
|
|
14
|
+
ST_C: Union[Raster, np.ndarray], # surface temperature (°C)
|
|
15
|
+
Ta_C: Union[Raster, np.ndarray], # air temperature (°C)
|
|
16
|
+
dTS_C: Union[Raster, np.ndarray], # difference between surface and air temperature (°C)
|
|
17
|
+
Td_C: Union[Raster, np.ndarray], # dewpoint temperature (°C)
|
|
18
|
+
Tsd_C: Union[Raster, np.ndarray], # surface dewpoint temperature (°C)
|
|
19
|
+
Rg_Wm2: Union[Raster, np.ndarray], # Incoming solar radiation (W/m^2)
|
|
20
|
+
Rn_Wm2: Union[Raster, np.ndarray], # Net radiation (W/m^2)
|
|
21
|
+
LWnet_Wm2: Union[Raster, np.ndarray], # Net longwave radiation (W/m^2)
|
|
22
|
+
FVC: Union[Raster, np.ndarray], # Fractional vegetation cover (unitless)
|
|
23
|
+
VPD_hPa: Union[Raster, np.ndarray], # Vapor pressure deficit (hPa)
|
|
24
|
+
D0_hPa: Union[Raster, np.ndarray], # Vapor pressure deficit at source (hPa)
|
|
25
|
+
SVP_hPa: Union[Raster, np.ndarray], # Saturation vapor pressure (hPa)
|
|
26
|
+
Ea_hPa: Union[Raster, np.ndarray], # Actual vapor pressure (hPa)
|
|
27
|
+
gamma_hPa: Union[Raster, np.ndarray, float] = GAMMA_HPA # Psychrometric constant (hPa/°C)
|
|
28
|
+
) -> Union[Raster, np.ndarray]:
|
|
29
|
+
"""
|
|
30
|
+
Calculates the root zone moisture (Mrz) based on thermal IR and meteorological information.
|
|
31
|
+
|
|
32
|
+
Args:
|
|
33
|
+
delta (np.ndarray): Rate of change of saturation vapor pressure with temperature (kPa/°C).
|
|
34
|
+
s1 (np.ndarray): The slope of saturation vapor pressure at surface temperature (hPa/K).
|
|
35
|
+
s3 (np.ndarray): The slope of saturation vapor pressure at dewpoint temperature (hPa/K).
|
|
36
|
+
ST_C (np.ndarray): Surface temperature in degrees Celsius.
|
|
37
|
+
Ta_C (np.ndarray): Air temperature in degrees Celsius.
|
|
38
|
+
dTS (np.ndarray): Difference between surface and air temperature in degrees Celsius.
|
|
39
|
+
Td_C (np.ndarray): Dewpoint temperature in degrees Celsius.
|
|
40
|
+
Tsd_C (np.ndarray): Surface dewpoint temperature in degrees Celsius.
|
|
41
|
+
Rg (np.ndarray): Incoming solar radiation in W/m^2.
|
|
42
|
+
Rn (np.ndarray): Net radiation in W/m^2.
|
|
43
|
+
Lnet (np.ndarray): Net longwave radiation in W/m^2.
|
|
44
|
+
fc (np.ndarray): Fractional vegetation cover (unitless).
|
|
45
|
+
VPD_hPa (np.ndarray): Vapor pressure deficit in hPa.
|
|
46
|
+
D0 (np.ndarray): Vapor pressure deficit at source in hPa.
|
|
47
|
+
SVP_hPa (np.ndarray): Saturation vapor pressure in hPa.
|
|
48
|
+
Ea_hPa (np.ndarray): Actual vapor pressure in hPa.
|
|
49
|
+
|
|
50
|
+
Returns:
|
|
51
|
+
np.ndarray: Root zone moisture (Mrz) (value 0 to 1).
|
|
52
|
+
"""
|
|
53
|
+
s44 = (SVP_hPa - Ea_hPa) / (Ta_C - Td_C)
|
|
54
|
+
kTSTD = (ST_C - Tsd_C) / (Ta_C - Td_C)
|
|
55
|
+
Mrz = (gamma_hPa * s1_hPa * (Tsd_C - Td_C)) / (delta_hPa * s3_hPa * kTSTD * (ST_C - Td_C) + gamma_hPa * s44 * (Ta_C - Td_C) - delta_hPa * s1_hPa * (Tsd_C - Td_C))
|
|
56
|
+
Mrz = rt.where((Rn_Wm2 < 0) & (dTS_C < 0) & (Mrz < 0), np.abs(Mrz), Mrz)
|
|
57
|
+
Mrz = rt.where((Rn_Wm2 < 0) & (dTS_C > 0) & (Mrz < 0), np.abs(Mrz), Mrz)
|
|
58
|
+
Mrz = rt.where((Rn_Wm2 > 0) & (dTS_C < 0) & (Mrz < 0), np.abs(Mrz), Mrz)
|
|
59
|
+
Mrz = rt.where((Rn_Wm2 > 0) & (dTS_C > 0) & (Mrz < 0), np.abs(Mrz), Mrz)
|
|
60
|
+
Mrz = rt.where((Rg_Wm2 > 0) & (Mrz < 0), np.abs(Mrz), Mrz)
|
|
61
|
+
Mrz = rt.where((Rg_Wm2 < 0) & (Mrz < 0), np.abs(Mrz), Mrz)
|
|
62
|
+
Mrz = rt.where((Td_C < 0) & (Mrz < 0), np.abs(Mrz), Mrz)
|
|
63
|
+
Mrz = rt.where(Mrz > 1, 1, Mrz)
|
|
64
|
+
Mrz = rt.where(Mrz < 0, 0.0001, Mrz)
|
|
65
|
+
|
|
66
|
+
return Mrz
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .calculate_SEBAL_soil_heat_flux import calculate_SEBAL_soil_heat_flux
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
from typing import Union
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
import rasters as rt
|
|
5
|
+
from rasters import Raster
|
|
6
|
+
|
|
7
|
+
def calculate_SEBAL_soil_heat_flux(
|
|
8
|
+
Rn: Union[Raster, np.ndarray],
|
|
9
|
+
ST_C: Union[Raster, np.ndarray],
|
|
10
|
+
NDVI: Union[Raster, np.ndarray],
|
|
11
|
+
albedo: Union[Raster, np.ndarray]) -> Union[Raster, np.ndarray]:
|
|
12
|
+
"""
|
|
13
|
+
This function calculates the soil heat flux (G) in the Surface Energy Balance Algorithm for Land (SEBAL) model.
|
|
14
|
+
The formula used in the function is a simplification of the more complex relationship between these variables in the energy balance at the surface.
|
|
15
|
+
|
|
16
|
+
Parameters:
|
|
17
|
+
Rn (np.ndarray): Net radiation at the surface.
|
|
18
|
+
ST_C (np.ndarray): Surface temperature in Celsius.
|
|
19
|
+
NDVI (np.ndarray): Normalized Difference Vegetation Index, indicating the presence and condition of vegetation.
|
|
20
|
+
albedo (np.ndarray): Measure of the diffuse reflection of solar radiation.
|
|
21
|
+
|
|
22
|
+
Returns:
|
|
23
|
+
np.ndarray: The soil heat flux (G), a key component in the energy balance.
|
|
24
|
+
|
|
25
|
+
Reference:
|
|
26
|
+
"Evapotranspiration Estimation Based on Remote Sensing and the SEBAL Model in the Bosten Lake Basin of China" [^1^][1]
|
|
27
|
+
"""
|
|
28
|
+
# Empirical coefficients used in the calculation
|
|
29
|
+
coeff1 = 0.0038
|
|
30
|
+
coeff2 = 0.0074
|
|
31
|
+
|
|
32
|
+
# Vegetation cover correction factor
|
|
33
|
+
NDVI_correction = 1 - 0.98 * NDVI ** 4
|
|
34
|
+
|
|
35
|
+
# Calculation of the soil heat flux (G)
|
|
36
|
+
G = Rn * ST_C * (coeff1 + coeff2 * albedo) * NDVI_correction
|
|
37
|
+
|
|
38
|
+
G = rt.clip(G, 0, None)
|
|
39
|
+
|
|
40
|
+
return G
|