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,114 @@
|
|
|
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 .vegetation_conversion.vegetation_conversion import FVC_from_NDVI
|
|
8
|
+
|
|
9
|
+
from .constants import GAMMA_HPA
|
|
10
|
+
from .root_zone_initialization import calculate_root_zone_moisture
|
|
11
|
+
|
|
12
|
+
def initialize_soil_moisture(
|
|
13
|
+
delta_hPa: Union[Raster, np.ndarray], # Rate of change of saturation vapor pressure with temperature (hPa/°C)
|
|
14
|
+
ST_C: Union[Raster, np.ndarray], # Surface temperature (°C)
|
|
15
|
+
Ta_C: Union[Raster, np.ndarray], # Air temperature (°C)
|
|
16
|
+
Td_C: Union[Raster, np.ndarray], # Dewpoint temperature (°C)
|
|
17
|
+
dTS: Union[Raster, np.ndarray], # Difference between surface and air temperature (°C)
|
|
18
|
+
Rn_Wm2: Union[Raster, np.ndarray], # Net radiation (W/m²)
|
|
19
|
+
LWnet_Wm2: Union[Raster, np.ndarray], # Net longwave radiation (W/m²)
|
|
20
|
+
FVC: Union[Raster, np.ndarray], # Fractional vegetation cover (unitless)
|
|
21
|
+
VPD_hPa: Union[Raster, np.ndarray], # Vapor pressure deficit (hPa)
|
|
22
|
+
SVP_hPa: Union[Raster, np.ndarray], # Saturation vapor pressure (hPa)
|
|
23
|
+
Ea_hPa: Union[Raster, np.ndarray], # Actual vapor pressure (hPa)
|
|
24
|
+
Estar_hPa: Union[Raster, np.ndarray], # Saturation vapor pressure at surface temperature (hPa)
|
|
25
|
+
gamma_hPa: Union[Raster, np.ndarray, float] = GAMMA_HPA # Psychrometric constant (hPa/°C)
|
|
26
|
+
) -> Tuple[Union[Raster, np.ndarray]]:
|
|
27
|
+
"""
|
|
28
|
+
This function estimates the soil moisture availability (SM) based on thermal IR and meteorological information.
|
|
29
|
+
The estimated SM is treated as initial SM, which will be later estimated through iteration in the actual ET estimation loop to establish feedback between SM and biophysical states.
|
|
30
|
+
|
|
31
|
+
Parameters:
|
|
32
|
+
delta (np.ndarray): Rate of change of saturation vapor pressure with temperature (kPa/°C)
|
|
33
|
+
ST_C (np.ndarray): Surface temperature (°C)
|
|
34
|
+
Ta_C (np.ndarray): Air temperature (°C)
|
|
35
|
+
Td_C (np.ndarray): Dewpoint temperature (°C)
|
|
36
|
+
dTS (np.ndarray): Difference between surface and air temperature (°C)
|
|
37
|
+
Rn (np.ndarray): Net radiation (W/m²)
|
|
38
|
+
LWnet (np.ndarray): Net longwave radiation (W/m²)
|
|
39
|
+
NDVI (np.ndarray): Normalized Difference Vegetation Index (unitless)
|
|
40
|
+
VPD_hPa (np.ndarray): Vapor pressure deficit (hPa)
|
|
41
|
+
SVP_hPa (np.ndarray): Saturation vapor pressure (hPa)
|
|
42
|
+
Ea_hPa (np.ndarray): Actual vapor pressure (hPa)
|
|
43
|
+
Estar (np.ndarray): Saturation vapor pressure at surface temperature (hPa)
|
|
44
|
+
|
|
45
|
+
Returns:
|
|
46
|
+
SM (np.ndarray): soil moisture (m³/m³)
|
|
47
|
+
Mrz (np.ndarray): The rootzone moisture (m³/m³)
|
|
48
|
+
Ms (np.ndarray): The surface moisture (m³/m³)
|
|
49
|
+
Ep_PT (np.ndarray): The potential evaporation (Priestley-Taylor eqn.) (mm/day)
|
|
50
|
+
Ds (np.ndarray): The vapor pressure deficit at surface (hPa)
|
|
51
|
+
s1 (np.ndarray): The slope of SVP at dewpoint temperature (hPa/K)
|
|
52
|
+
s3 (np.ndarray): The slope of SVP at surface temperature (hPa/K)
|
|
53
|
+
Tsd_C (np.ndarray): The surface dewpoint temperature (°C)
|
|
54
|
+
"""
|
|
55
|
+
# Compute the surface dewpoint temperature
|
|
56
|
+
s11 = (45.03 + 3.014 * Td_C + 0.05345 * Td_C ** 2 + 0.00224 * Td_C ** 3) * 1e-2 # slope of SVP at TD (hpa/K)
|
|
57
|
+
s22 = (Estar_hPa - Ea_hPa) / (ST_C - Td_C)
|
|
58
|
+
s33 = (45.03 + 3.014 * ST_C + 0.05345 * ST_C ** 2 + 0.00224 * ST_C ** 3) * 1e-2 # slope of SVP at TS (hpa/K)
|
|
59
|
+
s44 = (SVP_hPa - Ea_hPa) / (Ta_C - Td_C)
|
|
60
|
+
Tsd_C = (Estar_hPa - Ea_hPa - s33 * ST_C + s11 * Td_C) / (s11 - s33) # Surface dewpoint temperature (degC)
|
|
61
|
+
|
|
62
|
+
# Calculate the surface moisture or wetness
|
|
63
|
+
Msurf = (s11 / s22) * ((Tsd_C - Td_C) / (ST_C - Td_C)) # Surface wetness
|
|
64
|
+
Msurf = rt.clip(Msurf, 0.0001, 0.9999)
|
|
65
|
+
|
|
66
|
+
# Calculate the surface vapor pressure and deficit
|
|
67
|
+
esurf = Ea_hPa + Msurf * (Estar_hPa - Ea_hPa)
|
|
68
|
+
Dsurf = esurf - Ea_hPa
|
|
69
|
+
|
|
70
|
+
# Separate the soil and canopy wetness to form a composite surface moisture
|
|
71
|
+
Ms = Msurf
|
|
72
|
+
Mcan = FVC * Msurf
|
|
73
|
+
Msoil = (1 - FVC) * Msurf
|
|
74
|
+
|
|
75
|
+
TdewIndex = (ST_C - Tsd_C) / (Ta_C - Td_C) # % TdewIndex > 1 signifies super dry condition
|
|
76
|
+
Ep_PT = (1.26 * delta_hPa * Rn_Wm2) / (delta_hPa + gamma_hPa) # Potential evaporation (Priestley-Taylor eqn.)
|
|
77
|
+
|
|
78
|
+
# Adjust surface wetness based on certain conditions
|
|
79
|
+
Ms = rt.where((FVC <= 0.25) & (TdewIndex < 1), Msoil, Ms)
|
|
80
|
+
Mcan = rt.where((FVC <= 0.25) & (TdewIndex < 1), 0, Mcan)
|
|
81
|
+
Ms = rt.where((FVC <= 0.25) & (Ta_C > 10) & (Td_C < 0) & (LWnet_Wm2 < -125), Msoil, Ms)
|
|
82
|
+
Mcan = rt.where((FVC <= 0.25) & (Ta_C > 10) & (Td_C < 0) & (LWnet_Wm2 < -125), 0, Mcan)
|
|
83
|
+
|
|
84
|
+
# Calculate the root-zone moisture
|
|
85
|
+
SMrz = calculate_root_zone_moisture(
|
|
86
|
+
delta_hPa=delta_hPa,
|
|
87
|
+
ST_C=ST_C,
|
|
88
|
+
Ta_C=Ta_C,
|
|
89
|
+
Td_C=Td_C,
|
|
90
|
+
s11=s11,
|
|
91
|
+
s33=s33,
|
|
92
|
+
s44=s44,
|
|
93
|
+
Tsd_C=Tsd_C,
|
|
94
|
+
gamma_hPa=gamma_hPa
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
# Combine soil moisture to account for hysteresis and initial estimation of surface vapor pressure
|
|
98
|
+
SM = Ms
|
|
99
|
+
SM = rt.where((Ep_PT > Rn_Wm2) & (dTS > 0), SMrz, SM)
|
|
100
|
+
SM = rt.where((Ep_PT > Rn_Wm2) & (FVC <= 0.25), SMrz, SM)
|
|
101
|
+
SM = rt.where((Ep_PT > Rn_Wm2) & (Dsurf > VPD_hPa), SMrz, SM)
|
|
102
|
+
SM = rt.where((FVC <= 0.25) & (dTS > 0) & (Ta_C > 10) & (Td_C < 0) & (LWnet_Wm2 < -125), SMrz, SM)
|
|
103
|
+
SM = rt.where((FVC <= 0.25) & (dTS > 0) & (Ta_C > 10) & (Td_C < 0) & (Dsurf > VPD_hPa), SMrz, SM)
|
|
104
|
+
SM = rt.where((Ep_PT < Rn_Wm2) & (FVC <= 0.25) & (Dsurf > VPD_hPa), SMrz, SM)
|
|
105
|
+
|
|
106
|
+
es = Ea_hPa + SM * (Estar_hPa - Ea_hPa)
|
|
107
|
+
|
|
108
|
+
# vapor pressure deficit at surface
|
|
109
|
+
Ds = (Estar_hPa - es)
|
|
110
|
+
|
|
111
|
+
s1 = s11
|
|
112
|
+
s3 = s33
|
|
113
|
+
|
|
114
|
+
return SM, SMrz, Ms, Ep_PT, Ds, s1, s3, Tsd_C
|
|
@@ -0,0 +1,131 @@
|
|
|
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
|
+
from .root_zone_iteration import calculate_rootzone_moisture
|
|
10
|
+
|
|
11
|
+
def iterate_soil_moisture(
|
|
12
|
+
delta_hPa: Union[Raster, np.ndarray], # Rate of change of saturation vapor pressure with temperature (hPa/°C)
|
|
13
|
+
s1: Union[Raster, np.ndarray], # The slope of SVP at surface temperature (hPa/K)
|
|
14
|
+
s3: Union[Raster, np.ndarray], # The slope of SVP at dewpoint temperature (hPa/K)
|
|
15
|
+
ST_C: Union[Raster, np.ndarray], # surface temperature (°C)
|
|
16
|
+
Ta_C: Union[Raster, np.ndarray], # air temperature (°C)
|
|
17
|
+
dTS_C: Union[Raster, np.ndarray], # difference between surface and air temperature (°C)
|
|
18
|
+
Td_C: Union[Raster, np.ndarray], # dewpoint temperature (°C)
|
|
19
|
+
Tsd_C: Union[Raster, np.ndarray], # surface dewpoint temperature (°C)
|
|
20
|
+
Rg_Wm2: Union[Raster, np.ndarray], # Incoming solar radiation (W/m^2)
|
|
21
|
+
Rn_Wm2: Union[Raster, np.ndarray], # Net radiation (W/m^2)
|
|
22
|
+
LWnet_Wm2: Union[Raster, np.ndarray], # Net longwave radiation (W/m^2)
|
|
23
|
+
FVC: Union[Raster, np.ndarray], # Fractional vegetation cover (unitless)
|
|
24
|
+
VPD_hPa: Union[Raster, np.ndarray], # Vapor pressure deficit (hPa)
|
|
25
|
+
D0_hPa: Union[Raster, np.ndarray], # Vapor pressure deficit at source (hPa)
|
|
26
|
+
SVP_hPa: Union[Raster, np.ndarray], # Saturation vapor pressure (hPa)
|
|
27
|
+
Ea_hPa: Union[Raster, np.ndarray], # Actual vapor pressure (hPa)
|
|
28
|
+
T0: Union[Raster, np.ndarray], # Temperature at source (°C)
|
|
29
|
+
gamma_hPa: Union[Raster, np.ndarray, float] = GAMMA_HPA # Psychrometric constant (hPa/°C)
|
|
30
|
+
) -> Union[Raster, np.ndarray]:
|
|
31
|
+
"""
|
|
32
|
+
Estimates the soil moisture availability (SM) (or wetness) (value 0 to 1) based on thermal IR and meteorological
|
|
33
|
+
information. However, this M will be treated as initial M, which will be later on estimated through iteration in the
|
|
34
|
+
actual ET estimation loop to establish feedback between M and biophysical states.
|
|
35
|
+
|
|
36
|
+
Args:
|
|
37
|
+
delta (np.ndarray): Rate of change of saturation vapor pressure with temperature (kPa/°C).
|
|
38
|
+
s1 (np.ndarray): The slope of saturation vapor pressure at surface temperature (hPa/K).
|
|
39
|
+
s3 (np.ndarray): The slope of saturation vapor pressure at dewpoint temperature (hPa/K).
|
|
40
|
+
ST_C (np.ndarray): Surface temperature in degrees Celsius.
|
|
41
|
+
Ta_C (np.ndarray): Air temperature in degrees Celsius.
|
|
42
|
+
dTS (np.ndarray): Difference between surface and air temperature in degrees Celsius.
|
|
43
|
+
Td_C (np.ndarray): Dewpoint temperature in degrees Celsius.
|
|
44
|
+
Tsd_C (np.ndarray): Surface dewpoint temperature in degrees Celsius.
|
|
45
|
+
Rg (np.ndarray): Incoming solar radiation in W/m^2.
|
|
46
|
+
Rn (np.ndarray): Net radiation in W/m^2.
|
|
47
|
+
LWnet (np.ndarray): Net longwave radiation in W/m^2.
|
|
48
|
+
FVC (np.ndarray): Fractional vegetation cover (unitless).
|
|
49
|
+
VPD_hPa (np.ndarray): Vapor pressure deficit in hPa.
|
|
50
|
+
D0 (np.ndarray): Vapor pressure deficit at source in hPa.
|
|
51
|
+
SVP_hPa (np.ndarray): Saturation vapor pressure in hPa.
|
|
52
|
+
Ea_hPa (np.ndarray): Actual vapor pressure in hPa.
|
|
53
|
+
T0 (np.ndarray): Temperature at source in degrees Celsius.
|
|
54
|
+
|
|
55
|
+
Returns:
|
|
56
|
+
np.ndarray: Soil moisture availability (SM) (or wetness) (value 0 to 1).
|
|
57
|
+
"""
|
|
58
|
+
# calculate surface wetness (Msurf)
|
|
59
|
+
kTSTD = (T0 - Td_C) / (ST_C - Td_C)
|
|
60
|
+
Msurf = (s1 / s3) * ((Tsd_C - Td_C) / (kTSTD * (ST_C - Td_C))) # Surface wetness
|
|
61
|
+
Msurf = rt.where((Rn_Wm2 < 0) & (dTS_C < 0) & (Msurf < 0), np.abs(Msurf), Msurf)
|
|
62
|
+
Msurf = rt.where((Rn_Wm2 < 0) & (dTS_C > 0) & (Msurf < 0), np.abs(Msurf), Msurf)
|
|
63
|
+
Msurf = rt.where((Rn_Wm2 > 0) & (dTS_C < 0) & (Msurf < 0), np.abs(Msurf), Msurf)
|
|
64
|
+
Msurf = rt.where((Rn_Wm2 > 0) & (dTS_C > 0) & (Msurf < 0), np.abs(Msurf), Msurf)
|
|
65
|
+
|
|
66
|
+
# solar radiation is only used to correct negative values of surface wetness
|
|
67
|
+
Msurf = rt.where((Rg_Wm2 > 0) & (Msurf < 0), np.abs(Msurf), Msurf)
|
|
68
|
+
Msurf = rt.where((Rg_Wm2 < 0) & (Msurf < 0), np.abs(Msurf), Msurf)
|
|
69
|
+
|
|
70
|
+
Msurf = rt.where((Td_C < 0) & (Msurf < 0), np.abs(Msurf), Msurf)
|
|
71
|
+
Msurf = rt.clip(Msurf, 0.0001, 1)
|
|
72
|
+
|
|
73
|
+
# Separating soil and canopy wetness to form a composite surface moisture
|
|
74
|
+
Ms = Msurf
|
|
75
|
+
Mcan = FVC * Msurf
|
|
76
|
+
Msoil = (1 - FVC) * Msurf
|
|
77
|
+
|
|
78
|
+
TdewIndex = (ST_C - Tsd_C) / (Ta_C - Td_C)
|
|
79
|
+
|
|
80
|
+
# Potential evaporation (Priestley-Taylor eqn.)
|
|
81
|
+
Ep_PT = (1.26 * delta_hPa * Rn_Wm2) / (delta_hPa + gamma_hPa)
|
|
82
|
+
|
|
83
|
+
# calculate surface wetness (Ms)
|
|
84
|
+
Ms = rt.where((Ep_PT > Rn_Wm2) & (FVC <= 0.25) & (TdewIndex < 1), Msoil, Ms)
|
|
85
|
+
Ms = rt.where((FVC <= 0.25) & (Ta_C > 10) & (Td_C < 0) & (LWnet_Wm2 < -125), Msoil, Ms)
|
|
86
|
+
Ms = rt.where((Rn_Wm2 > Ep_PT) & (FVC <= 0.25) & (TdewIndex < 1) & (Td_C <= 0), Msoil, Ms)
|
|
87
|
+
Ms = rt.where((Rn_Wm2 > Ep_PT) & (FVC <= 0.25) & (TdewIndex < 1), Msoil, Ms)
|
|
88
|
+
Ms = rt.where((D0_hPa > VPD_hPa) & (FVC <= 0.25) & (TdewIndex < 1), Msoil, Ms)
|
|
89
|
+
|
|
90
|
+
# calculate canopy wetness (Mcan)
|
|
91
|
+
Mcan = rt.where((Ep_PT > Rn_Wm2) & (FVC <= 0.25) & (TdewIndex < 1), 0, Mcan)
|
|
92
|
+
Mcan = rt.where((FVC <= 0.25) & (Ta_C > 10) & (Td_C < 0) & (LWnet_Wm2 < -125), 0, Mcan)
|
|
93
|
+
Mcan = rt.where((Rn_Wm2 > Ep_PT) & (FVC <= 0.25) & (TdewIndex < 1) & (Td_C <= 0), 0, Mcan)
|
|
94
|
+
Mcan = rt.where((Rn_Wm2 > Ep_PT) & (FVC <= 0.25) & (TdewIndex < 1), 0, Mcan)
|
|
95
|
+
Mcan = rt.where((D0_hPa > VPD_hPa) & (FVC <= 0.25) & (TdewIndex < 1), 0, Mcan)
|
|
96
|
+
|
|
97
|
+
# calculate rootzone moisture (Mrz)
|
|
98
|
+
Mrz = calculate_rootzone_moisture(
|
|
99
|
+
delta_hPa=delta_hPa,
|
|
100
|
+
s1_hPa=s1,
|
|
101
|
+
s3_hPa=s3,
|
|
102
|
+
ST_C=ST_C,
|
|
103
|
+
Ta_C=Ta_C,
|
|
104
|
+
dTS_C=dTS_C,
|
|
105
|
+
Td_C=Td_C,
|
|
106
|
+
Tsd_C=Tsd_C,
|
|
107
|
+
Rg_Wm2=Rg_Wm2,
|
|
108
|
+
Rn_Wm2=Rn_Wm2,
|
|
109
|
+
LWnet_Wm2=LWnet_Wm2,
|
|
110
|
+
FVC=FVC,
|
|
111
|
+
VPD_hPa=VPD_hPa,
|
|
112
|
+
D0_hPa=D0_hPa,
|
|
113
|
+
SVP_hPa=SVP_hPa,
|
|
114
|
+
Ea_hPa=Ea_hPa,
|
|
115
|
+
gamma_hPa=gamma_hPa
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
TdewIndex = (ST_C - Tsd_C) / (Ta_C - Td_C)
|
|
119
|
+
|
|
120
|
+
# Potential evaporation (Priestley-Taylor eqn.)
|
|
121
|
+
Ep_PT = (1.26 * delta_hPa * Rn_Wm2) / (delta_hPa + gamma_hPa)
|
|
122
|
+
|
|
123
|
+
# COMBINE M to account for Hysteresis and initial estimation of surface vapor pressure
|
|
124
|
+
SM = Msurf
|
|
125
|
+
SM = rt.where((Ep_PT > Rn_Wm2) & (dTS_C > 0) & (FVC <= 0.25) & (D0_hPa > VPD_hPa) & (TdewIndex < 1), Mrz, SM)
|
|
126
|
+
SM = rt.where((FVC <= 0.25) & (dTS_C > 0) & (Ta_C > 10) & (Td_C < 0) & (LWnet_Wm2 < -125) & (D0_hPa > VPD_hPa), Mrz, SM)
|
|
127
|
+
|
|
128
|
+
return SM
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .timer import *
|
STIC_JPL/timer/timer.py
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"""
|
|
2
|
+
This is a minimalistic performance timer.
|
|
3
|
+
"""
|
|
4
|
+
import time
|
|
5
|
+
|
|
6
|
+
__author__ = "Gregory Halverson"
|
|
7
|
+
|
|
8
|
+
DEFAULT_FORMAT = "0.2f"
|
|
9
|
+
|
|
10
|
+
class Timer(object):
|
|
11
|
+
"""
|
|
12
|
+
This is a minimalistic performance timer.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
def __init__(self):
|
|
16
|
+
self._start_time = None
|
|
17
|
+
self._end_time = None
|
|
18
|
+
self.start()
|
|
19
|
+
|
|
20
|
+
def __enter__(self, *args, **kwargs):
|
|
21
|
+
self.start()
|
|
22
|
+
return self
|
|
23
|
+
|
|
24
|
+
def __exit__(self, *args, **kwargs):
|
|
25
|
+
self.end()
|
|
26
|
+
|
|
27
|
+
def __repr__(self):
|
|
28
|
+
# print("Timer.__repr__")
|
|
29
|
+
return self.__format__(format_string=DEFAULT_FORMAT)
|
|
30
|
+
|
|
31
|
+
def __str__(self):
|
|
32
|
+
# print("Timer.__str__")
|
|
33
|
+
return self.__repr__()
|
|
34
|
+
|
|
35
|
+
def __format__(self, format_string=DEFAULT_FORMAT):
|
|
36
|
+
if format_string is None or format_string == "":
|
|
37
|
+
format_string = DEFAULT_FORMAT
|
|
38
|
+
|
|
39
|
+
return format(self.duration, format_string)
|
|
40
|
+
|
|
41
|
+
@property
|
|
42
|
+
def now(self):
|
|
43
|
+
# return datetime.now()
|
|
44
|
+
return time.perf_counter()
|
|
45
|
+
|
|
46
|
+
def start(self):
|
|
47
|
+
self._start_time = self.now
|
|
48
|
+
|
|
49
|
+
return self.start_time
|
|
50
|
+
|
|
51
|
+
@property
|
|
52
|
+
def start_time(self):
|
|
53
|
+
return self._start_time
|
|
54
|
+
|
|
55
|
+
def end(self):
|
|
56
|
+
self._end_time = self.now
|
|
57
|
+
|
|
58
|
+
return self.end_time
|
|
59
|
+
|
|
60
|
+
@property
|
|
61
|
+
def end_time(self):
|
|
62
|
+
return self._end_time
|
|
63
|
+
|
|
64
|
+
@property
|
|
65
|
+
def duration(self):
|
|
66
|
+
if self.start_time is None:
|
|
67
|
+
raise Exception("timer never started")
|
|
68
|
+
|
|
69
|
+
if self.end_time is None:
|
|
70
|
+
end_time = self.now
|
|
71
|
+
else:
|
|
72
|
+
end_time = self.end_time
|
|
73
|
+
|
|
74
|
+
duration = end_time - self.start_time
|
|
75
|
+
|
|
76
|
+
return duration
|
|
77
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .vegetation_conversion import *
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
from typing import Union
|
|
2
|
+
import numpy as np
|
|
3
|
+
import rasters as rt
|
|
4
|
+
from rasters import Raster
|
|
5
|
+
|
|
6
|
+
KPAR = 0.5
|
|
7
|
+
MIN_FIPAR = 0.0
|
|
8
|
+
MAX_FIPAR = 1.0
|
|
9
|
+
MIN_LAI = 0.0
|
|
10
|
+
MAX_LAI = 10.0
|
|
11
|
+
|
|
12
|
+
def FVC_from_NDVI(NDVI: Union[Raster, np.ndarray]) -> Union[Raster, np.ndarray]:
|
|
13
|
+
"""
|
|
14
|
+
Convert Normalized Difference Vegetation Index (NDVI) to Fractional Vegetation Cover (FVC).
|
|
15
|
+
|
|
16
|
+
Parameters:
|
|
17
|
+
NDVI (Union[Raster, np.ndarray]): Input NDVI data.
|
|
18
|
+
|
|
19
|
+
Returns:
|
|
20
|
+
Union[Raster, np.ndarray]: Converted FVC data.
|
|
21
|
+
"""
|
|
22
|
+
NDVIv = 0.52 # +- 0.03
|
|
23
|
+
NDVIs = 0.04 # +- 0.03
|
|
24
|
+
FVC = rt.clip((NDVI - NDVIs) / (NDVIv - NDVIs), 0.0, 1.0)
|
|
25
|
+
|
|
26
|
+
return FVC
|
|
27
|
+
|
|
28
|
+
def LAI_from_NDVI(
|
|
29
|
+
NDVI: Union[Raster, np.ndarray],
|
|
30
|
+
min_fIPAR: float = MIN_FIPAR,
|
|
31
|
+
max_fIPAR: float = MAX_FIPAR,
|
|
32
|
+
min_LAI: float = MIN_LAI,
|
|
33
|
+
max_LAI: float = MAX_LAI) -> Union[Raster, np.ndarray]:
|
|
34
|
+
"""
|
|
35
|
+
Convert Normalized Difference Vegetation Index (NDVI) to Leaf Area Index (LAI).
|
|
36
|
+
|
|
37
|
+
Parameters:
|
|
38
|
+
NDVI (Union[Raster, np.ndarray]): Input NDVI data.
|
|
39
|
+
|
|
40
|
+
Returns:
|
|
41
|
+
Union[Raster, np.ndarray]: Converted LAI data.
|
|
42
|
+
"""
|
|
43
|
+
fIPAR = rt.clip(NDVI - 0.05, min_fIPAR, max_fIPAR)
|
|
44
|
+
fIPAR = np.where(fIPAR == 0, np.nan, fIPAR)
|
|
45
|
+
LAI = rt.clip(-np.log(1 - fIPAR) * (1 / KPAR), min_LAI, max_LAI)
|
|
46
|
+
|
|
47
|
+
return LAI
|
STIC_JPL/version.txt
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
1.0.4
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: STIC-JPL
|
|
3
|
+
Version: 1.1.0
|
|
4
|
+
Summary: Surface Temperature Initiated Closure (STIC) Evapotranspiration Model Python Implementation
|
|
5
|
+
Author-email: Gregory Halverson <gregory.h.halverson@jpl.nasa.gov>, Kaniska Mallick <kaniska.mallick@list.lu>, Madeleine Pascolini-Campbell <madeleine.a.pascolini-campbell@jpl.nasa.gov>, "Claire S. Villanueva-Weeks" <claire.s.villanueva-weeks@jpl.gov>
|
|
6
|
+
Project-URL: Homepage, https://github.com/JPL-Evapotranspiration-Algorithms/STIC-JPL
|
|
7
|
+
Classifier: Programming Language :: Python :: 3
|
|
8
|
+
Classifier: Operating System :: OS Independent
|
|
9
|
+
Requires-Python: >=3.10
|
|
10
|
+
Description-Content-Type: text/markdown
|
|
11
|
+
Requires-Dist: colored-logging
|
|
12
|
+
Requires-Dist: ECOv002-CMR
|
|
13
|
+
Requires-Dist: ECOv002-granules
|
|
14
|
+
Requires-Dist: GEOS5FP>=1.1.1
|
|
15
|
+
Requires-Dist: numpy
|
|
16
|
+
Requires-Dist: pandas
|
|
17
|
+
Requires-Dist: rasters
|
|
18
|
+
Requires-Dist: solar-apparent-time
|
|
19
|
+
Provides-Extra: dev
|
|
20
|
+
Requires-Dist: build; extra == "dev"
|
|
21
|
+
Requires-Dist: pytest>=6.0; extra == "dev"
|
|
22
|
+
Requires-Dist: pytest-cov; extra == "dev"
|
|
23
|
+
Requires-Dist: jupyter; extra == "dev"
|
|
24
|
+
Requires-Dist: pytest; extra == "dev"
|
|
25
|
+
Requires-Dist: twine; extra == "dev"
|
|
26
|
+
|
|
27
|
+
# Surface Temperature Initiated Closure (STIC) Evapotranspiration Model Python Implementation
|
|
28
|
+
|
|
29
|
+
[](https://github.com/JPL-Evapotranspiration-Algorithms/STIC/actions/workflows/ci.yml)
|
|
30
|
+
|
|
31
|
+
This repository contains the python implementation for the Surface Temperature Initiated Closure (STIC) evapotranspiration model, used by the ECOsystem Spaceborne Thermal Radiometer Experiment on Space Station (ECOSTRESS) and Surface Biology and Geology (SBG) missions.
|
|
32
|
+
|
|
33
|
+
This software package is a Python implementation of the Surface Temperature Initiated Closure (STIC) version 1.3 model designed to implement LST to solve the aerodynamic temperature, which is critical for ET modeling. The original STIC model produced by Kaniska Mallick (Mallick et al. 2015; 2018; 2022) was re-implemented from MATLAB code to Python by Gregory Halverson and Madeleine Pascolini-Campbell. The software was developed under a research grant by the NASA Research Opportunities in Space and Earth Sciences (ROSES) program. It is intended for use by the Hyperspectral Thermal Emission Spectrometer (HyTES), MODIS/ASTER (MASTER) Airborne Simulator, Ecosystem Spaceborne Thermal Radiometer Experiment on Space Station (ECOSTRESS) mission and as a precursor for the Surface Biology and Geology (SBG) mission.
|
|
34
|
+
|
|
35
|
+
The software was developed as part of a research grant by the NASA Research Opportunities in Space and Earth Sciences (ROSES) program. It was designed for use by the Hyperspectral Thermal Emission Spectrometer (HyTES), MODIS/ASTER (MASTER) Airborne Simulator, Ecosystem Spaceborne Thermal Radiometer Experiment on Space Station (ECOSTRESS) mission as a precursor for the Surface Biology and Geology (SBG) mission. It may also be useful for general remote sensing and GIS projects in Python. This package can be utilized for remote sensing research in Jupyter notebooks and deployed for operations in data processing pipelines.
|
|
36
|
+
|
|
37
|
+
The software is being released according to the SPD-41 open-science requirements of NASA-funded ROSES projects.
|
|
38
|
+
|
|
39
|
+
Gregory H. Halverson (they/them)<br>
|
|
40
|
+
[gregory.h.halverson@jpl.nasa.gov](mailto:gregory.h.halverson@jpl.nasa.gov)<br>
|
|
41
|
+
Lead developer<br>
|
|
42
|
+
NASA Jet Propulsion Laboratory 329G
|
|
43
|
+
|
|
44
|
+
Kaniska Mallick (he/him)<br>
|
|
45
|
+
[kaniska.mallick@list.lu](mailto:kaniska.mallick@list.lu)<br>
|
|
46
|
+
Algorithm inventor<br>
|
|
47
|
+
Luxembourg Institute of Science and Technology
|
|
48
|
+
|
|
49
|
+
Tian Hu (he/him)<br>
|
|
50
|
+
[tian.hu@list.lu](mailto:tian.hu@list.lu)<br>
|
|
51
|
+
Algorithm developer<br>
|
|
52
|
+
Luxembourg Institute of Science and Technology
|
|
53
|
+
|
|
54
|
+
Madeleine Pascolini-Campbell (she/her)<br>
|
|
55
|
+
[madeleine.a.pascolini-campbell@jpl.nasa.gov](mailto:madeleine.a.pascolini-campbell@jpl.nasa.gov)<br>
|
|
56
|
+
Algorithm developer<br>
|
|
57
|
+
NASA Jet Propulsion Laboratory 329F
|
|
58
|
+
|
|
59
|
+
Claire Villanueva-Weeks (she/her)<br>
|
|
60
|
+
[claire.s.villanueva-weeks@jpl.nasa.gov](mailto:claire.s.villanueva-weeks@jpl.nasa.gov)<br>
|
|
61
|
+
Code maintenance<br>
|
|
62
|
+
NASA Jet Propulsion Laboratory 329G
|
|
63
|
+
|
|
64
|
+
## Installation
|
|
65
|
+
|
|
66
|
+
Use the pip package manager to install the `STIC` PyPi package.
|
|
67
|
+
|
|
68
|
+
```
|
|
69
|
+
pip install STIC
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Usage
|
|
73
|
+
|
|
74
|
+
Import the `STIC` function from the `STIC` package.
|
|
75
|
+
|
|
76
|
+
```
|
|
77
|
+
from STIC import STIC
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
See the [ECOSTRESS example](ECOSTRESS%20Example.ipynb) for usage.
|
|
81
|
+
|
|
82
|
+
## References
|
|
83
|
+
|
|
84
|
+
Mallick, K., Boegh, E., Trebs, I., Alfieri, J. G., Kustas, W. P., Prueger, J. H., ... & Jarvis, A. J. (2015). Reintroducing radiometric surface temperature into the P enman‐M onteith formulation. Water Resources Research, 51(8), 6214-6243. https://doi.org/10.1002/2014WR016106
|
|
85
|
+
|
|
86
|
+
Mallick, K., Toivonen, E., Trebs, I., Boegh, E., Cleverly, J., Eamus, D., ... & Garcia, M. (2018). Bridging Thermal Infrared Sensing and Physically‐Based Evapotranspiration Modeling: From Theoretical Implementation to Validation Across an Aridity Gradient in Australian Ecosystems. Water Resources Research, 54(5), 3409-3435. https://doi.org/10.1029/2017WR021357
|
|
87
|
+
|
|
88
|
+
Mallick, K., Baldocchi, D., Jarvis, A., Hu, T., Trebs, I., Sulis, M., ... & Kustas, W. P. (2022). Insights Into the Aerodynamic Versus Radiometric Surface Temperature Debate in Thermal‐Based Evaporation Modeling. Geophysical Research Letters, 49(15), e2021GL097568. https://doi.org/10.1029/2021GL097568
|
|
89
|
+
|
|
90
|
+
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
STIC_JPL/STIC_JPL.py,sha256=a0EpRTX6Sd75RPIqAzWckIuj9-KwbCE8T1aSEDpLM-c,17434
|
|
2
|
+
STIC_JPL/__init__.py,sha256=FmTp-Ir0Wbae0SbZgxlNIxq48TDrWCev17Gv1hWskxU,216
|
|
3
|
+
STIC_JPL/canopy_air_stream.py,sha256=UYp3l7mt0XH4SqvCGZhRzCIL-v7-Rvxxfm-C81lheSU,1637
|
|
4
|
+
STIC_JPL/closure.py,sha256=AzWoLnpoZ1MlQAKq0CgpmCMfDGVsp8-hYZ50ry33cic,4031
|
|
5
|
+
STIC_JPL/constants.py,sha256=xIVTsdc3_Rf3EPSgSk1QPjWiojFGn4lf1Swffov3oTM,595
|
|
6
|
+
STIC_JPL/diagnostic.py,sha256=RXjtZbCEJMiTyRuiMGUvekDgO_GcrhXVXvorR0WlAsk,2613
|
|
7
|
+
STIC_JPL/initialize_with_solar.py,sha256=6DUUHdVfeKvDk1pf_bOteSW8qd-n9pU4dowO1sMYOpw,3825
|
|
8
|
+
STIC_JPL/initialize_without_solar.py,sha256=M_7QfP2pr2w5sQO7UOW1GPqxpmQkjmsQ526BgYVVALk,4675
|
|
9
|
+
STIC_JPL/iterate_with_solar.py,sha256=WKySvuIJ4HzcDni0UYafmk5lXex2lJfde82kGnGUDI8,6368
|
|
10
|
+
STIC_JPL/iterate_without_solar.py,sha256=09RERpN6tdZr6ORDhMwEFXwx8941vyn1HMJQ-Q_bY6s,6140
|
|
11
|
+
STIC_JPL/net_radiation.py,sha256=Uwudsazul8V-x5t8KQLi3wpYi-wjMwT__eqZCRV2bIw,1187
|
|
12
|
+
STIC_JPL/root_zone_initialization.py,sha256=3JVKNDt3ebIiGVfuhBawjKs-BicNwkbfMprkzSxd4Cg,1581
|
|
13
|
+
STIC_JPL/root_zone_iteration.py,sha256=1XOMFE3-TdJZzUU5vouflUO4NKaZwAW6s1KJrNez3Es,3787
|
|
14
|
+
STIC_JPL/soil_moisture_initialization.py,sha256=YF0GcHkpH5amABNPpxD8f1lLPRyIAkG2dYJTfEuIX4g,5599
|
|
15
|
+
STIC_JPL/soil_moisture_iteration.py,sha256=QJXOPMxxwIIskpx9zLkXUPfuhWgFPUBcRnGhZo2UjAw,6493
|
|
16
|
+
STIC_JPL/version.txt,sha256=rqWtvvV0eFJzxPOcG3aHz4AZk-DLa_Z4GkFonk7bsgw,5
|
|
17
|
+
STIC_JPL/meteorology_conversion/__init__.py,sha256=dLF40imqJCC_l8_QMetbsj1YzkXZuFt9tQ2fsd7Wcdw,38
|
|
18
|
+
STIC_JPL/meteorology_conversion/meteorology_conversion.py,sha256=8vzx71FLLNhR5v6EQBL8OSgAmupQcgdLX2c9tL9TPxA,4202
|
|
19
|
+
STIC_JPL/soil_heat_flux/__init__.py,sha256=bN0dHUfqR9ob68M1TqdjQTK3kmaL5S4P08yK0Thub6k,74
|
|
20
|
+
STIC_JPL/soil_heat_flux/calculate_SEBAL_soil_heat_flux.py,sha256=PZylUGET5-Uj6BGfhOeqS4tp2pGE__gdc5X1nidLjxw,1516
|
|
21
|
+
STIC_JPL/timer/__init__.py,sha256=I_MQKp_aamBLUzZv0psEbRgs6GZLOJd4mmJ7bli0Ikc,21
|
|
22
|
+
STIC_JPL/timer/timer.py,sha256=tn5e3NQmsh55Jp9Fstjf-8KJW4F8UIJs-d_ZLooFYE8,1610
|
|
23
|
+
STIC_JPL/vegetation_conversion/__init__.py,sha256=8gnz0yK_euCV0TtVGDrSGaVfx4g0EJCG2J68ppuA5oc,37
|
|
24
|
+
STIC_JPL/vegetation_conversion/vegetation_conversion.py,sha256=-K3FLV6pXkpxtRxQvimqqkXAgkn9mUUlHQ8FIscq1Zg,1306
|
|
25
|
+
stic_jpl-1.1.0.dist-info/METADATA,sha256=sDO9vRDdU6d-qTxHfk-0ZoCLX5ZyT1o1F086M0hbqWA,5348
|
|
26
|
+
stic_jpl-1.1.0.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
|
|
27
|
+
stic_jpl-1.1.0.dist-info/top_level.txt,sha256=9NkchxttzACJcGcAaWzMaZarzX40OXQ216hERNA9LIo,9
|
|
28
|
+
stic_jpl-1.1.0.dist-info/RECORD,,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
STIC_JPL
|