STIC-JPL 1.2.1__tar.gz → 1.2.2__tar.gz
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-1.2.1 → stic_jpl-1.2.2}/PKG-INFO +3 -1
- stic_jpl-1.2.2/STIC_JPL/FVC_from_NDVI.py +49 -0
- stic_jpl-1.2.2/STIC_JPL/LAI_from_NDVI.py +61 -0
- {stic_jpl-1.2.1 → stic_jpl-1.2.2}/STIC_JPL/model.py +12 -9
- stic_jpl-1.2.2/STIC_JPL/version.txt +1 -0
- {stic_jpl-1.2.1 → stic_jpl-1.2.2}/STIC_JPL.egg-info/PKG-INFO +3 -1
- {stic_jpl-1.2.1 → stic_jpl-1.2.2}/STIC_JPL.egg-info/SOURCES.txt +0 -2
- {stic_jpl-1.2.1 → stic_jpl-1.2.2}/STIC_JPL.egg-info/requires.txt +2 -0
- {stic_jpl-1.2.1 → stic_jpl-1.2.2}/pyproject.toml +3 -1
- stic_jpl-1.2.1/STIC_JPL/FVC_from_NDVI.py +0 -26
- stic_jpl-1.2.1/STIC_JPL/LAI_from_NDVI.py +0 -31
- stic_jpl-1.2.1/STIC_JPL/diagnostic.py +0 -70
- stic_jpl-1.2.1/STIC_JPL/timer.py +0 -77
- stic_jpl-1.2.1/STIC_JPL/version.txt +0 -1
- {stic_jpl-1.2.1 → stic_jpl-1.2.2}/README.md +0 -0
- {stic_jpl-1.2.1 → stic_jpl-1.2.2}/STIC_JPL/STIC_JPL.py +0 -0
- {stic_jpl-1.2.1 → stic_jpl-1.2.2}/STIC_JPL/__init__.py +0 -0
- {stic_jpl-1.2.1 → stic_jpl-1.2.2}/STIC_JPL/canopy_air_stream.py +0 -0
- {stic_jpl-1.2.1 → stic_jpl-1.2.2}/STIC_JPL/celcius_to_kelvin.py +0 -0
- {stic_jpl-1.2.1 → stic_jpl-1.2.2}/STIC_JPL/closure.py +0 -0
- {stic_jpl-1.2.1 → stic_jpl-1.2.2}/STIC_JPL/constants.py +0 -0
- {stic_jpl-1.2.1 → stic_jpl-1.2.2}/STIC_JPL/generate_STIC_inputs.py +0 -0
- {stic_jpl-1.2.1 → stic_jpl-1.2.2}/STIC_JPL/initialize_with_solar.py +0 -0
- {stic_jpl-1.2.1 → stic_jpl-1.2.2}/STIC_JPL/initialize_without_solar.py +0 -0
- {stic_jpl-1.2.1 → stic_jpl-1.2.2}/STIC_JPL/iterate_with_solar.py +0 -0
- {stic_jpl-1.2.1 → stic_jpl-1.2.2}/STIC_JPL/iterate_without_solar.py +0 -0
- {stic_jpl-1.2.1 → stic_jpl-1.2.2}/STIC_JPL/net_radiation.py +0 -0
- {stic_jpl-1.2.1 → stic_jpl-1.2.2}/STIC_JPL/process_STIC_table.py +0 -0
- {stic_jpl-1.2.1 → stic_jpl-1.2.2}/STIC_JPL/root_zone_initialization.py +0 -0
- {stic_jpl-1.2.1 → stic_jpl-1.2.2}/STIC_JPL/root_zone_iteration.py +0 -0
- {stic_jpl-1.2.1 → stic_jpl-1.2.2}/STIC_JPL/soil_moisture_initialization.py +0 -0
- {stic_jpl-1.2.1 → stic_jpl-1.2.2}/STIC_JPL/soil_moisture_iteration.py +0 -0
- {stic_jpl-1.2.1 → stic_jpl-1.2.2}/STIC_JPL.egg-info/dependency_links.txt +0 -0
- {stic_jpl-1.2.1 → stic_jpl-1.2.2}/STIC_JPL.egg-info/top_level.txt +0 -0
- {stic_jpl-1.2.1 → stic_jpl-1.2.2}/setup.cfg +0 -0
- {stic_jpl-1.2.1 → stic_jpl-1.2.2}/tests/test_import_STIC.py +0 -0
- {stic_jpl-1.2.1 → stic_jpl-1.2.2}/tests/test_import_dependencies.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: STIC-JPL
|
|
3
|
-
Version: 1.2.
|
|
3
|
+
Version: 1.2.2
|
|
4
4
|
Summary: Surface Temperature Initiated Closure (STIC) Evapotranspiration Model Python Implementation
|
|
5
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
6
|
Project-URL: Homepage, https://github.com/JPL-Evapotranspiration-Algorithms/STIC-JPL
|
|
@@ -8,6 +8,7 @@ Classifier: Programming Language :: Python :: 3
|
|
|
8
8
|
Classifier: Operating System :: OS Independent
|
|
9
9
|
Requires-Python: >=3.10
|
|
10
10
|
Description-Content-Type: text/markdown
|
|
11
|
+
Requires-Dist: check-distribution
|
|
11
12
|
Requires-Dist: colored-logging
|
|
12
13
|
Requires-Dist: ECOv002-CMR>=1.0.5
|
|
13
14
|
Requires-Dist: ECOv002-granules>=1.0.3
|
|
@@ -16,6 +17,7 @@ Requires-Dist: GEOS5FP>=1.1.1
|
|
|
16
17
|
Requires-Dist: monte-carlo-sensitivity
|
|
17
18
|
Requires-Dist: numpy
|
|
18
19
|
Requires-Dist: pandas
|
|
20
|
+
Requires-Dist: pytictoc
|
|
19
21
|
Requires-Dist: rasters>=1.4.6
|
|
20
22
|
Requires-Dist: seaborn
|
|
21
23
|
Requires-Dist: SEBAL-soil-heat-flux
|
|
@@ -0,0 +1,49 @@
|
|
|
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
|
+
Estimate Fractional Vegetation Cover (FVC) from Normalized Difference Vegetation Index (NDVI)
|
|
15
|
+
using a scaled NDVI approach.
|
|
16
|
+
|
|
17
|
+
This method linearly scales NDVI values between two endmembers:
|
|
18
|
+
- NDVIs: NDVI value for bare soil (typically ~0.04 ± 0.03)
|
|
19
|
+
- NDVIv: NDVI value for full vegetation (typically ~0.52 ± 0.03)
|
|
20
|
+
|
|
21
|
+
The resulting Fractional Vegetation Cover (FVC) is calculated as:
|
|
22
|
+
|
|
23
|
+
FVC = clip((NDVI - NDVIs) / (NDVIv - NDVIs), 0.0, 1.0)
|
|
24
|
+
|
|
25
|
+
This approach is based on the assumption that NDVI increases linearly with vegetation cover
|
|
26
|
+
between these two extremes, and is well-supported in the literature.
|
|
27
|
+
|
|
28
|
+
References:
|
|
29
|
+
Carlson, T. N., & Ripley, D. A. (1997). On the relation between NDVI, fractional vegetation cover,
|
|
30
|
+
and leaf area index. Remote Sensing of Environment, 62(3), 241–252.
|
|
31
|
+
https://doi.org/10.1016/S0034-4257(97)00104-1
|
|
32
|
+
|
|
33
|
+
Gutman, G., & Ignatov, A. (1998). The derivation of the green vegetation fraction from NOAA/AVHRR
|
|
34
|
+
data for use in numerical weather prediction models. International Journal of Remote Sensing,
|
|
35
|
+
19(8), 1533–1543. https://doi.org/10.1080/014311698215333
|
|
36
|
+
|
|
37
|
+
Parameters:
|
|
38
|
+
NDVI (Union[Raster, np.ndarray]): Input NDVI data.
|
|
39
|
+
|
|
40
|
+
Returns:
|
|
41
|
+
Union[Raster, np.ndarray]: Estimated Fractional Vegetation Cover (FVC).
|
|
42
|
+
"""
|
|
43
|
+
NDVIv = 0.52 # NDVI for fully vegetated pixel
|
|
44
|
+
NDVIs = 0.04 # NDVI for bare soil pixel
|
|
45
|
+
|
|
46
|
+
# Scale NDVI to FVC using a linear model and clip to [0, 1]
|
|
47
|
+
FVC = rt.clip((NDVI - NDVIs) / (NDVIv - NDVIs), 0.0, 1.0)
|
|
48
|
+
|
|
49
|
+
return FVC
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
from typing import Union
|
|
2
|
+
import numpy as np
|
|
3
|
+
import rasters as rt
|
|
4
|
+
from rasters import Raster
|
|
5
|
+
|
|
6
|
+
# Constants
|
|
7
|
+
KPAR = 0.5 # Extinction coefficient for PAR, assumed average for broadleaf canopies (Weiss & Baret, 2010)
|
|
8
|
+
MIN_FIPAR = 0.0
|
|
9
|
+
MAX_FIPAR = 1.0
|
|
10
|
+
MIN_LAI = 0.0
|
|
11
|
+
MAX_LAI = 10.0
|
|
12
|
+
|
|
13
|
+
def LAI_from_NDVI(
|
|
14
|
+
NDVI: Union[Raster, np.ndarray],
|
|
15
|
+
min_fIPAR: float = MIN_FIPAR,
|
|
16
|
+
max_fIPAR: float = MAX_FIPAR,
|
|
17
|
+
min_LAI: float = MIN_LAI,
|
|
18
|
+
max_LAI: float = MAX_LAI) -> Union[Raster, np.ndarray]:
|
|
19
|
+
"""
|
|
20
|
+
Estimate Leaf Area Index (LAI) from NDVI using a simplified two-step empirical model.
|
|
21
|
+
|
|
22
|
+
This method first approximates the fraction of absorbed photosynthetically active radiation (fIPAR)
|
|
23
|
+
from NDVI, and then estimates LAI using the Beer–Lambert Law. The extinction coefficient for PAR (KPAR)
|
|
24
|
+
is assumed to be 0.5, which is typical for broadleaf canopies under diffuse light conditions.
|
|
25
|
+
|
|
26
|
+
Steps:
|
|
27
|
+
1. fIPAR ≈ NDVI - 0.05 (empirical offset to account for soil background and sensor noise)
|
|
28
|
+
- Based on observed relationships in Myneni & Williams (1994)
|
|
29
|
+
2. LAI = -ln(1 - fIPAR) / KPAR (Beer–Lambert Law)
|
|
30
|
+
- From Sellers (1985)
|
|
31
|
+
|
|
32
|
+
All outputs are clipped to user-defined minimum and maximum thresholds to ensure physical realism.
|
|
33
|
+
|
|
34
|
+
Parameters:
|
|
35
|
+
NDVI (Union[Raster, np.ndarray]): Input NDVI data.
|
|
36
|
+
min_fIPAR (float): Minimum fIPAR value for clipping (default 0.0).
|
|
37
|
+
max_fIPAR (float): Maximum fIPAR value for clipping (default 1.0).
|
|
38
|
+
min_LAI (float): Minimum LAI value for clipping (default 0.0).
|
|
39
|
+
max_LAI (float): Maximum LAI value for clipping (default 10.0).
|
|
40
|
+
|
|
41
|
+
Returns:
|
|
42
|
+
Union[Raster, np.ndarray]: Estimated LAI values.
|
|
43
|
+
|
|
44
|
+
References:
|
|
45
|
+
- Sellers, P. J. (1985). Canopy reflectance, photosynthesis and transpiration.
|
|
46
|
+
*International Journal of Remote Sensing*, 6(8), 1335–1372.
|
|
47
|
+
- Myneni, R. B., & Williams, D. L. (1994). On the relationship between FAPAR and NDVI.
|
|
48
|
+
*Remote Sensing of Environment*, 49(3), 200–211.
|
|
49
|
+
- Weiss, M., & Baret, F. (2010). CAN-EYE V6.1 User Manual. INRA-CSE.
|
|
50
|
+
|
|
51
|
+
"""
|
|
52
|
+
# Empirical conversion from NDVI to fIPAR (adjusted for background noise)
|
|
53
|
+
fIPAR = rt.clip(NDVI - 0.05, min_fIPAR, max_fIPAR)
|
|
54
|
+
|
|
55
|
+
# Avoid division by zero or log of 0 by masking zero fIPAR values
|
|
56
|
+
fIPAR = np.where(fIPAR == 0, np.nan, fIPAR)
|
|
57
|
+
|
|
58
|
+
# Apply Beer–Lambert law to estimate LAI
|
|
59
|
+
LAI = rt.clip(-np.log(1 - fIPAR) * (1 / KPAR), min_LAI, max_LAI)
|
|
60
|
+
|
|
61
|
+
return LAI
|
|
@@ -5,8 +5,11 @@ from os.path import join, abspath, expanduser
|
|
|
5
5
|
from typing import Dict, List
|
|
6
6
|
import numpy as np
|
|
7
7
|
import warnings
|
|
8
|
-
|
|
8
|
+
|
|
9
|
+
from pytictoc import TicToc
|
|
10
|
+
|
|
9
11
|
import colored_logging as cl
|
|
12
|
+
from check_distribution import check_distribution
|
|
10
13
|
import rasters as rt
|
|
11
14
|
from GEOS5FP import GEOS5FP
|
|
12
15
|
from solar_apparent_time import solar_day_of_year_for_area, solar_hour_of_day_for_area
|
|
@@ -29,8 +32,6 @@ from .FVC_from_NDVI import FVC_from_NDVI
|
|
|
29
32
|
from .LAI_from_NDVI import LAI_from_NDVI
|
|
30
33
|
from .celcius_to_kelvin import celcius_to_kelvin
|
|
31
34
|
|
|
32
|
-
from .timer import Timer
|
|
33
|
-
|
|
34
35
|
__author__ = 'Kaniska Mallick, Madeleine Pascolini-Campbell, Gregory Halverson'
|
|
35
36
|
|
|
36
37
|
logger = logging.getLogger(__name__)
|
|
@@ -180,7 +181,7 @@ def STIC_JPL(
|
|
|
180
181
|
G_method = DEFAULT_G_METHOD, # method for calculating soil heat flux
|
|
181
182
|
)
|
|
182
183
|
|
|
183
|
-
|
|
184
|
+
check_distribution(Ms, "Ms")
|
|
184
185
|
|
|
185
186
|
# STIC analytical equations (convergence on LE)
|
|
186
187
|
gB_ms, gS_ms, dT_C, EF = STIC_closure(
|
|
@@ -227,7 +228,9 @@ def STIC_JPL(
|
|
|
227
228
|
PT_Wm2 = None
|
|
228
229
|
iteration = 1
|
|
229
230
|
LE_Wm2_max_change = 0
|
|
230
|
-
|
|
231
|
+
|
|
232
|
+
t = TicToc()
|
|
233
|
+
t.tic()
|
|
231
234
|
|
|
232
235
|
while (np.nanmax(LE_Wm2_change) >= LE_convergence_target and iteration <= max_iterations):
|
|
233
236
|
logger.info(f"running STIC iteration {cl.val(iteration)} / {cl.val(max_iterations)}")
|
|
@@ -330,11 +333,11 @@ def STIC_JPL(
|
|
|
330
333
|
LE_Wm2_old = LE_Wm2_new
|
|
331
334
|
LE_Wm2_max_change = np.nanmax(LE_Wm2_change)
|
|
332
335
|
logger.info(
|
|
333
|
-
f"completed STIC iteration {cl.val(iteration)} / {cl.val(max_iterations)} with max LE change: {cl.val(np.round(LE_Wm2_max_change, 3))} ({t} seconds)")
|
|
336
|
+
f"completed STIC iteration {cl.val(iteration)} / {cl.val(max_iterations)} with max LE change: {cl.val(np.round(LE_Wm2_max_change, 3))} ({t.tocvalue()} seconds)")
|
|
334
337
|
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
+
check_distribution(SM, f"SM_{iteration}")
|
|
339
|
+
check_distribution(G, f"G_{iteration}")
|
|
340
|
+
check_distribution(LE_Wm2_new, f"LE_{iteration}")
|
|
338
341
|
|
|
339
342
|
if LE_Wm2_max_change <= LE_convergence_target:
|
|
340
343
|
logger.info(f"max LE change {cl.val(np.round(LE_Wm2_max_change, 3))} within convergence target {cl.val(np.round(LE_convergence_target, 3))} with {cl.val(iteration)} iteration{'s' if iteration > 1 else ''}")
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
1.2.2
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: STIC-JPL
|
|
3
|
-
Version: 1.2.
|
|
3
|
+
Version: 1.2.2
|
|
4
4
|
Summary: Surface Temperature Initiated Closure (STIC) Evapotranspiration Model Python Implementation
|
|
5
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
6
|
Project-URL: Homepage, https://github.com/JPL-Evapotranspiration-Algorithms/STIC-JPL
|
|
@@ -8,6 +8,7 @@ Classifier: Programming Language :: Python :: 3
|
|
|
8
8
|
Classifier: Operating System :: OS Independent
|
|
9
9
|
Requires-Python: >=3.10
|
|
10
10
|
Description-Content-Type: text/markdown
|
|
11
|
+
Requires-Dist: check-distribution
|
|
11
12
|
Requires-Dist: colored-logging
|
|
12
13
|
Requires-Dist: ECOv002-CMR>=1.0.5
|
|
13
14
|
Requires-Dist: ECOv002-granules>=1.0.3
|
|
@@ -16,6 +17,7 @@ Requires-Dist: GEOS5FP>=1.1.1
|
|
|
16
17
|
Requires-Dist: monte-carlo-sensitivity
|
|
17
18
|
Requires-Dist: numpy
|
|
18
19
|
Requires-Dist: pandas
|
|
20
|
+
Requires-Dist: pytictoc
|
|
19
21
|
Requires-Dist: rasters>=1.4.6
|
|
20
22
|
Requires-Dist: seaborn
|
|
21
23
|
Requires-Dist: SEBAL-soil-heat-flux
|
|
@@ -8,7 +8,6 @@ STIC_JPL/canopy_air_stream.py
|
|
|
8
8
|
STIC_JPL/celcius_to_kelvin.py
|
|
9
9
|
STIC_JPL/closure.py
|
|
10
10
|
STIC_JPL/constants.py
|
|
11
|
-
STIC_JPL/diagnostic.py
|
|
12
11
|
STIC_JPL/generate_STIC_inputs.py
|
|
13
12
|
STIC_JPL/initialize_with_solar.py
|
|
14
13
|
STIC_JPL/initialize_without_solar.py
|
|
@@ -21,7 +20,6 @@ STIC_JPL/root_zone_initialization.py
|
|
|
21
20
|
STIC_JPL/root_zone_iteration.py
|
|
22
21
|
STIC_JPL/soil_moisture_initialization.py
|
|
23
22
|
STIC_JPL/soil_moisture_iteration.py
|
|
24
|
-
STIC_JPL/timer.py
|
|
25
23
|
STIC_JPL/version.txt
|
|
26
24
|
STIC_JPL.egg-info/PKG-INFO
|
|
27
25
|
STIC_JPL.egg-info/SOURCES.txt
|
|
@@ -3,7 +3,7 @@ requires = ["setuptools", "wheel"]
|
|
|
3
3
|
|
|
4
4
|
[project]
|
|
5
5
|
name = "STIC-JPL"
|
|
6
|
-
version = "1.2.
|
|
6
|
+
version = "1.2.2"
|
|
7
7
|
description = "Surface Temperature Initiated Closure (STIC) Evapotranspiration Model Python Implementation"
|
|
8
8
|
readme = "README.md"
|
|
9
9
|
authors = [
|
|
@@ -17,6 +17,7 @@ classifiers = [
|
|
|
17
17
|
"Operating System :: OS Independent",
|
|
18
18
|
]
|
|
19
19
|
dependencies = [
|
|
20
|
+
"check-distribution",
|
|
20
21
|
"colored-logging",
|
|
21
22
|
"ECOv002-CMR>=1.0.5",
|
|
22
23
|
"ECOv002-granules>=1.0.3",
|
|
@@ -25,6 +26,7 @@ dependencies = [
|
|
|
25
26
|
"monte-carlo-sensitivity",
|
|
26
27
|
"numpy",
|
|
27
28
|
"pandas",
|
|
29
|
+
"pytictoc",
|
|
28
30
|
"rasters>=1.4.6",
|
|
29
31
|
"seaborn",
|
|
30
32
|
"SEBAL-soil-heat-flux",
|
|
@@ -1,26 +0,0 @@
|
|
|
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
|
|
@@ -1,31 +0,0 @@
|
|
|
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 LAI_from_NDVI(
|
|
13
|
-
NDVI: Union[Raster, np.ndarray],
|
|
14
|
-
min_fIPAR: float = MIN_FIPAR,
|
|
15
|
-
max_fIPAR: float = MAX_FIPAR,
|
|
16
|
-
min_LAI: float = MIN_LAI,
|
|
17
|
-
max_LAI: float = MAX_LAI) -> Union[Raster, np.ndarray]:
|
|
18
|
-
"""
|
|
19
|
-
Convert Normalized Difference Vegetation Index (NDVI) to Leaf Area Index (LAI).
|
|
20
|
-
|
|
21
|
-
Parameters:
|
|
22
|
-
NDVI (Union[Raster, np.ndarray]): Input NDVI data.
|
|
23
|
-
|
|
24
|
-
Returns:
|
|
25
|
-
Union[Raster, np.ndarray]: Converted LAI data.
|
|
26
|
-
"""
|
|
27
|
-
fIPAR = rt.clip(NDVI - 0.05, min_fIPAR, max_fIPAR)
|
|
28
|
-
fIPAR = np.where(fIPAR == 0, np.nan, fIPAR)
|
|
29
|
-
LAI = rt.clip(-np.log(1 - fIPAR) * (1 / KPAR), min_LAI, max_LAI)
|
|
30
|
-
|
|
31
|
-
return LAI
|
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
from typing import Union
|
|
2
|
-
from os.path import join
|
|
3
|
-
from datetime import date
|
|
4
|
-
import numpy as np
|
|
5
|
-
import logging
|
|
6
|
-
|
|
7
|
-
import colored_logging as cl
|
|
8
|
-
from rasters import Raster
|
|
9
|
-
|
|
10
|
-
logger = logging.getLogger(__name__)
|
|
11
|
-
|
|
12
|
-
def diagnostic(values: Union[Raster, np.ndarray], variable: str, show_distributions: bool = True, output_directory: str = None):
|
|
13
|
-
if isinstance(values, Raster) and output_directory is not None:
|
|
14
|
-
filename = join(output_directory, f"{variable}.tif")
|
|
15
|
-
logger.info(filename)
|
|
16
|
-
values.to_geotiff(filename)
|
|
17
|
-
|
|
18
|
-
if show_distributions:
|
|
19
|
-
unique = np.unique(values)
|
|
20
|
-
nan_proportion = np.count_nonzero(np.isnan(values)) / np.size(values)
|
|
21
|
-
|
|
22
|
-
if len(unique) < 10:
|
|
23
|
-
logger.info(f"variable {cl.name(variable)} ({values.dtype}) has {cl.val(unique)} unique values")
|
|
24
|
-
|
|
25
|
-
for value in unique:
|
|
26
|
-
if np.isnan(value):
|
|
27
|
-
count = np.count_nonzero(np.isnan(values))
|
|
28
|
-
else:
|
|
29
|
-
count = np.count_nonzero(values == value)
|
|
30
|
-
|
|
31
|
-
if value == 0 or np.isnan(value):
|
|
32
|
-
logger.info(f"* {cl.colored(value, 'red')}: {cl.colored(count, 'red')}")
|
|
33
|
-
else:
|
|
34
|
-
logger.info(f"* {cl.val(value)}: {cl.val(count)}")
|
|
35
|
-
else:
|
|
36
|
-
minimum = np.nanmin(values)
|
|
37
|
-
|
|
38
|
-
if minimum < 0:
|
|
39
|
-
minimum_string = cl.colored(f"{minimum:0.3f}", "red")
|
|
40
|
-
else:
|
|
41
|
-
minimum_string = cl.val(f"{minimum:0.3f}")
|
|
42
|
-
|
|
43
|
-
maximum = np.nanmax(values)
|
|
44
|
-
|
|
45
|
-
if maximum <= 0:
|
|
46
|
-
maximum_string = cl.colored(f"{maximum:0.3f}", "red")
|
|
47
|
-
else:
|
|
48
|
-
maximum_string = cl.val(f"{maximum:0.3f}")
|
|
49
|
-
|
|
50
|
-
if nan_proportion > 0.5:
|
|
51
|
-
nan_proportion_string = cl.colored(f"{(nan_proportion * 100):0.2f}%", "yellow")
|
|
52
|
-
elif nan_proportion == 1:
|
|
53
|
-
nan_proportion_string = cl.colored(f"{(nan_proportion * 100):0.2f}%", "red")
|
|
54
|
-
else:
|
|
55
|
-
nan_proportion_string = cl.val(f"{(nan_proportion * 100):0.2f}%")
|
|
56
|
-
|
|
57
|
-
message = "variable " + cl.name(variable) + \
|
|
58
|
-
" min: " + minimum_string + \
|
|
59
|
-
" mean: " + cl.val(f"{np.nanmean(values):0.3f}") + \
|
|
60
|
-
" max: " + maximum_string + \
|
|
61
|
-
" nan: " + nan_proportion_string
|
|
62
|
-
|
|
63
|
-
if np.all(values == 0):
|
|
64
|
-
message += " all zeros"
|
|
65
|
-
logger.warning(message)
|
|
66
|
-
else:
|
|
67
|
-
logger.info(message)
|
|
68
|
-
|
|
69
|
-
if nan_proportion == 1:
|
|
70
|
-
raise ValueError(f"variable {variable} is blank")
|
stic_jpl-1.2.1/STIC_JPL/timer.py
DELETED
|
@@ -1,77 +0,0 @@
|
|
|
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
|
-
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
1.2.1
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|