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.

@@ -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