BESS-JPL 1.16.0__py3-none-any.whl → 1.18.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 BESS-JPL might be problematic. Click here for more details.
- BESS_JPL/BESS_JPL.py +4 -0
- BESS_JPL/C4_fraction.tif.aux.xml +11 -0
- BESS_JPL/ECOv002-cal-val-BESS-JPL-inputs.csv +1066 -0
- BESS_JPL/ECOv002-cal-val-BESS-JPL-outputs.csv +1066 -0
- BESS_JPL/ECOv002-static-tower-BESS-JPL-inputs.csv +122 -0
- BESS_JPL/ECOv002_calval_BESS_inputs.py +19 -0
- BESS_JPL/ECOv002_static_tower_BESS_inputs.py +19 -0
- BESS_JPL/LAI_from_NDVI.py +0 -1
- BESS_JPL/__init__.py +1 -6
- BESS_JPL/constants.py +4 -1
- BESS_JPL/load_C4_fraction.py +8 -2
- BESS_JPL/model.py +83 -32
- BESS_JPL/process_BESS_table.py +177 -17
- BESS_JPL/verify.py +72 -0
- BESS_JPL/version.py +3 -0
- {bess_jpl-1.16.0.dist-info → bess_jpl-1.18.0.dist-info}/METADATA +9 -6
- {bess_jpl-1.16.0.dist-info → bess_jpl-1.18.0.dist-info}/RECORD +24 -13
- bess_jpl-1.18.0.dist-info/top_level.txt +3 -0
- examples/processing_BESS_with_rasters_and_default_parameters.py +102 -0
- tests/test_import_BESS_JPL.py +2 -0
- tests/test_import_dependencies.py +17 -0
- tests/test_verify.py +5 -0
- BESS_JPL/version.txt +0 -1
- bess_jpl-1.16.0.dist-info/top_level.txt +0 -1
- {bess_jpl-1.16.0.dist-info → bess_jpl-1.18.0.dist-info}/WHEEL +0 -0
- {bess_jpl-1.16.0.dist-info → bess_jpl-1.18.0.dist-info}/licenses/LICENSE +0 -0
BESS_JPL/process_BESS_table.py
CHANGED
|
@@ -5,11 +5,14 @@ import rasters as rt
|
|
|
5
5
|
from dateutil import parser
|
|
6
6
|
from pandas import DataFrame
|
|
7
7
|
|
|
8
|
+
from .constants import *
|
|
8
9
|
from .model import BESS_JPL
|
|
9
10
|
|
|
10
11
|
logger = logging.getLogger(__name__)
|
|
11
12
|
|
|
12
|
-
def process_BESS_table(
|
|
13
|
+
def process_BESS_table(
|
|
14
|
+
input_df: DataFrame,
|
|
15
|
+
C4_fraction_scale_factor: float = C4_FRACTION_SCALE_FACTOR) -> DataFrame:
|
|
13
16
|
ST_C = np.array(input_df.ST_C).astype(np.float64)
|
|
14
17
|
NDVI = np.array(input_df.NDVI).astype(np.float64)
|
|
15
18
|
|
|
@@ -23,28 +26,185 @@ def process_BESS_table(input_df: DataFrame) -> DataFrame:
|
|
|
23
26
|
Ta_C = np.array(input_df.Ta).astype(np.float64)
|
|
24
27
|
|
|
25
28
|
RH = np.array(input_df.RH).astype(np.float64)
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
29
|
+
|
|
30
|
+
if "elevation_km" in input_df:
|
|
31
|
+
elevation_km = np.array(input_df.elevation_km).astype(np.float64)
|
|
32
|
+
else:
|
|
33
|
+
elevation_km = None
|
|
34
|
+
|
|
35
|
+
if "NDVI_minimum" in input_df:
|
|
36
|
+
NDVI_minimum = np.array(input_df.NDVI_minimum).astype(np.float64)
|
|
37
|
+
else:
|
|
38
|
+
NDVI_minimum = None
|
|
39
|
+
|
|
40
|
+
if "NDVI_maximum" in input_df:
|
|
41
|
+
NDVI_maximum = np.array(input_df.NDVI_maximum).astype(np.float64).astype(np.float64)
|
|
42
|
+
else:
|
|
43
|
+
NDVI_maximum = None
|
|
44
|
+
|
|
45
|
+
if "C4_fraction" in input_df:
|
|
46
|
+
C4_fraction = np.array(input_df.C4_fraction).astype(np.float64)
|
|
47
|
+
else:
|
|
48
|
+
C4_fraction = None
|
|
49
|
+
|
|
50
|
+
if "carbon_uptake_efficiency" in input_df:
|
|
51
|
+
carbon_uptake_efficiency = np.array(input_df.carbon_uptake_efficiency).astype(np.float64)
|
|
52
|
+
else:
|
|
53
|
+
carbon_uptake_efficiency = None
|
|
54
|
+
|
|
55
|
+
if "kn" in input_df:
|
|
56
|
+
kn = np.array(input_df.kn).astype(np.float64)
|
|
57
|
+
else:
|
|
58
|
+
kn = None
|
|
59
|
+
|
|
60
|
+
if "peakVCmax_C3" in input_df:
|
|
61
|
+
peakVCmax_C3 = np.array(input_df.peakVCmax_C3).astype(np.float64)
|
|
62
|
+
else:
|
|
63
|
+
peakVCmax_C3 = None
|
|
64
|
+
|
|
65
|
+
if "peakVCmax_C4" in input_df:
|
|
66
|
+
peakVCmax_C4 = np.array(input_df.peakVCmax_C4).astype(np.float64)
|
|
67
|
+
else:
|
|
68
|
+
peakVCmax_C4 = None
|
|
69
|
+
|
|
70
|
+
if "ball_berry_slope_C3" in input_df:
|
|
71
|
+
ball_berry_slope_C3 = np.array(input_df.ball_berry_slope_C3).astype(np.float64)
|
|
72
|
+
else:
|
|
73
|
+
ball_berry_slope_C3 = None
|
|
41
74
|
|
|
75
|
+
if "ball_berry_slope_C4" in input_df:
|
|
76
|
+
ball_berry_slope_C4 = np.array(input_df.ball_berry_slope_C4).astype(np.float64)
|
|
77
|
+
else:
|
|
78
|
+
ball_berry_slope_C4 = None
|
|
79
|
+
|
|
80
|
+
if "ball_berry_intercept_C3" in input_df:
|
|
81
|
+
ball_berry_intercept_C3 = np.array(input_df.ball_berry_intercept_C3).astype(np.float64)
|
|
82
|
+
else:
|
|
83
|
+
ball_berry_intercept_C3 = None
|
|
84
|
+
|
|
85
|
+
if "KG_climate" in input_df:
|
|
86
|
+
KG_climate = np.array(input_df.KG_climate)
|
|
87
|
+
else:
|
|
88
|
+
KG_climate = None
|
|
89
|
+
|
|
90
|
+
if "CI" in input_df:
|
|
91
|
+
CI = np.array(input_df.CI).astype(np.float64)
|
|
92
|
+
else:
|
|
93
|
+
CI = None
|
|
94
|
+
|
|
95
|
+
if "canopy_height_meters" in input_df:
|
|
96
|
+
canopy_height_meters = np.array(input_df.canopy_height_meters).astype(np.float64)
|
|
97
|
+
else:
|
|
98
|
+
canopy_height_meters = None
|
|
99
|
+
|
|
100
|
+
if "COT" in input_df:
|
|
101
|
+
COT = np.array(input_df.COT).astype(np.float64)
|
|
102
|
+
else:
|
|
103
|
+
COT = None
|
|
104
|
+
|
|
105
|
+
if "AOT" in input_df:
|
|
106
|
+
AOT = np.array(input_df.AOT).astype(np.float64)
|
|
107
|
+
else:
|
|
108
|
+
AOT = None
|
|
109
|
+
|
|
110
|
+
if "Ca" in input_df:
|
|
111
|
+
Ca = np.array(input_df.Ca).astype(np.float64)
|
|
112
|
+
else:
|
|
113
|
+
Ca = None
|
|
114
|
+
|
|
115
|
+
if "wind_speed_mps" in input_df:
|
|
116
|
+
wind_speed_mps = np.array(input_df.wind_speed_mps).astype(np.float64)
|
|
117
|
+
else:
|
|
118
|
+
wind_speed_mps = None
|
|
119
|
+
|
|
120
|
+
if "vapor_gccm" in input_df:
|
|
121
|
+
vapor_gccm = np.array(input_df.vapor_gccm).astype(np.float64)
|
|
122
|
+
else:
|
|
123
|
+
vapor_gccm = None
|
|
124
|
+
|
|
125
|
+
if "ozone_cm" in input_df:
|
|
126
|
+
ozone_cm = np.array(input_df.ozone_cm).astype(np.float64)
|
|
127
|
+
else:
|
|
128
|
+
ozone_cm = None
|
|
129
|
+
|
|
130
|
+
# --- Handle geometry and time columns ---
|
|
131
|
+
import pandas as pd
|
|
132
|
+
from rasters import MultiPoint, WGS84
|
|
133
|
+
from shapely.geometry import Point
|
|
134
|
+
|
|
135
|
+
def ensure_geometry(df):
|
|
136
|
+
if "geometry" in df:
|
|
137
|
+
if isinstance(df.geometry.iloc[0], str):
|
|
138
|
+
def parse_geom(s):
|
|
139
|
+
s = s.strip()
|
|
140
|
+
if s.startswith("POINT"):
|
|
141
|
+
coords = s.replace("POINT", "").replace("(", "").replace(")", "").strip().split()
|
|
142
|
+
return Point(float(coords[0]), float(coords[1]))
|
|
143
|
+
elif "," in s:
|
|
144
|
+
coords = [float(c) for c in s.split(",")]
|
|
145
|
+
return Point(coords[0], coords[1])
|
|
146
|
+
else:
|
|
147
|
+
coords = [float(c) for c in s.split()]
|
|
148
|
+
return Point(coords[0], coords[1])
|
|
149
|
+
df = df.copy()
|
|
150
|
+
df['geometry'] = df['geometry'].apply(parse_geom)
|
|
151
|
+
return df
|
|
152
|
+
|
|
153
|
+
input_df = ensure_geometry(input_df)
|
|
154
|
+
|
|
155
|
+
logger.info("started extracting geometry from PT-JPL-SM input table")
|
|
156
|
+
|
|
157
|
+
if "geometry" in input_df:
|
|
158
|
+
# Convert Point objects to coordinate tuples for MultiPoint
|
|
159
|
+
if hasattr(input_df.geometry.iloc[0], "x") and hasattr(input_df.geometry.iloc[0], "y"):
|
|
160
|
+
coords = [(pt.x, pt.y) for pt in input_df.geometry]
|
|
161
|
+
geometry = MultiPoint(coords, crs=WGS84)
|
|
162
|
+
else:
|
|
163
|
+
geometry = MultiPoint(input_df.geometry, crs=WGS84)
|
|
164
|
+
elif "lat" in input_df and "lon" in input_df:
|
|
165
|
+
lat = np.array(input_df.lat).astype(np.float64)
|
|
166
|
+
lon = np.array(input_df.lon).astype(np.float64)
|
|
167
|
+
geometry = MultiPoint(x=lon, y=lat, crs=WGS84)
|
|
168
|
+
else:
|
|
169
|
+
raise KeyError("Input DataFrame must contain either 'geometry' or both 'lat' and 'lon' columns.")
|
|
170
|
+
|
|
171
|
+
logger.info("completed extracting geometry from PT-JPL-SM input table")
|
|
172
|
+
|
|
173
|
+
logger.info("started extracting time from PT-JPL-SM input table")
|
|
174
|
+
time_UTC = pd.to_datetime(input_df.time_UTC).tolist()
|
|
175
|
+
logger.info("completed extracting time from PT-JPL-SM input table")
|
|
176
|
+
|
|
42
177
|
results = BESS_JPL(
|
|
178
|
+
geometry=geometry,
|
|
179
|
+
time_UTC=time_UTC,
|
|
43
180
|
ST_C=ST_C,
|
|
44
181
|
albedo=albedo,
|
|
45
182
|
NDVI=NDVI,
|
|
46
183
|
Ta_C=Ta_C,
|
|
47
|
-
RH=RH
|
|
184
|
+
RH=RH,
|
|
185
|
+
elevation_km=elevation_km,
|
|
186
|
+
NDVI_minimum=NDVI_minimum,
|
|
187
|
+
NDVI_maximum=NDVI_maximum,
|
|
188
|
+
C4_fraction=C4_fraction,
|
|
189
|
+
carbon_uptake_efficiency=carbon_uptake_efficiency,
|
|
190
|
+
kn=kn,
|
|
191
|
+
peakVCmax_C3=peakVCmax_C3,
|
|
192
|
+
peakVCmax_C4=peakVCmax_C4,
|
|
193
|
+
ball_berry_slope_C3=ball_berry_slope_C3,
|
|
194
|
+
ball_berry_slope_C4=ball_berry_slope_C4,
|
|
195
|
+
ball_berry_intercept_C3=ball_berry_intercept_C3,
|
|
196
|
+
KG_climate=KG_climate,
|
|
197
|
+
CI=CI,
|
|
198
|
+
canopy_height_meters=canopy_height_meters,
|
|
199
|
+
COT=COT,
|
|
200
|
+
AOT=AOT,
|
|
201
|
+
Ca=Ca,
|
|
202
|
+
wind_speed_mps=COT * 0 + 7.4,
|
|
203
|
+
vapor_gccm=vapor_gccm,
|
|
204
|
+
ozone_cm=ozone_cm,
|
|
205
|
+
albedo_visible=albedo,
|
|
206
|
+
albedo_NIR=albedo,
|
|
207
|
+
C4_fraction_scale_factor=C4_fraction_scale_factor
|
|
48
208
|
)
|
|
49
209
|
|
|
50
210
|
output_df = input_df.copy()
|
BESS_JPL/verify.py
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
def verify() -> bool:
|
|
2
|
+
"""
|
|
3
|
+
Verifies the correctness of the PT-JPL-SM model implementation by comparing
|
|
4
|
+
its outputs to a reference dataset.
|
|
5
|
+
|
|
6
|
+
This function loads a known input table and the corresponding expected output table.
|
|
7
|
+
It runs the model on the input data, then compares the resulting outputs to the
|
|
8
|
+
reference outputs for key variables using strict numerical tolerances. If all
|
|
9
|
+
outputs match within tolerance, the function returns True. Otherwise, it prints
|
|
10
|
+
which column failed and returns False.
|
|
11
|
+
|
|
12
|
+
Returns:
|
|
13
|
+
bool: True if all model outputs match the reference outputs within tolerance, False otherwise.
|
|
14
|
+
"""
|
|
15
|
+
import pandas as pd
|
|
16
|
+
import numpy as np
|
|
17
|
+
from .ECOv002_calval_BESS_inputs import load_ECOv002_calval_BESS_inputs
|
|
18
|
+
from .process_BESS_table import process_BESS_table
|
|
19
|
+
import os
|
|
20
|
+
|
|
21
|
+
# Load input and output tables
|
|
22
|
+
input_df = load_ECOv002_calval_BESS_inputs()
|
|
23
|
+
module_dir = os.path.dirname(os.path.abspath(__file__))
|
|
24
|
+
output_file_path = os.path.join(module_dir, "ECOv002-cal-val-BESS-JPL-outputs.csv")
|
|
25
|
+
output_df = pd.read_csv(output_file_path)
|
|
26
|
+
|
|
27
|
+
# Run the model on the input table
|
|
28
|
+
model_df = process_BESS_table(input_df)
|
|
29
|
+
|
|
30
|
+
# Columns to compare (model outputs)
|
|
31
|
+
output_columns = [
|
|
32
|
+
"G_Wm2",
|
|
33
|
+
"Rn_Wm2",
|
|
34
|
+
"LE_Wm2"
|
|
35
|
+
]
|
|
36
|
+
|
|
37
|
+
# Compare each output column and collect mismatches
|
|
38
|
+
mismatches = []
|
|
39
|
+
for col in output_columns:
|
|
40
|
+
if col not in model_df or col not in output_df:
|
|
41
|
+
mismatches.append((col, 'missing_column', None))
|
|
42
|
+
continue
|
|
43
|
+
model_vals = model_df[col].values
|
|
44
|
+
ref_vals = output_df[col].values
|
|
45
|
+
# Use numpy allclose for floating point comparison
|
|
46
|
+
if not np.allclose(model_vals, ref_vals, rtol=1e-5, atol=1e-8, equal_nan=True):
|
|
47
|
+
# Find indices where values differ
|
|
48
|
+
diffs = np.abs(model_vals - ref_vals)
|
|
49
|
+
max_diff = np.nanmax(diffs)
|
|
50
|
+
idxs = np.where(~np.isclose(model_vals, ref_vals, rtol=1e-5, atol=1e-8, equal_nan=True))[0]
|
|
51
|
+
mismatch_info = {
|
|
52
|
+
'indices': idxs.tolist(),
|
|
53
|
+
'model_values': model_vals[idxs].tolist(),
|
|
54
|
+
'ref_values': ref_vals[idxs].tolist(),
|
|
55
|
+
'diffs': diffs[idxs].tolist(),
|
|
56
|
+
'max_diff': float(max_diff)
|
|
57
|
+
}
|
|
58
|
+
mismatches.append((col, 'value_mismatch', mismatch_info))
|
|
59
|
+
if mismatches:
|
|
60
|
+
print("Verification failed. Details:")
|
|
61
|
+
for col, reason, info in mismatches:
|
|
62
|
+
if reason == 'missing_column':
|
|
63
|
+
print(f" Missing column: {col}")
|
|
64
|
+
elif reason == 'value_mismatch':
|
|
65
|
+
print(f" Mismatch in column: {col}")
|
|
66
|
+
print(f" Max difference: {info['max_diff']}")
|
|
67
|
+
print(f" Indices off: {info['indices']}")
|
|
68
|
+
print(f" Model values: {info['model_values']}")
|
|
69
|
+
print(f" Reference values: {info['ref_values']}")
|
|
70
|
+
print(f" Differences: {info['diffs']}")
|
|
71
|
+
return False
|
|
72
|
+
return True
|
BESS_JPL/version.py
ADDED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: BESS-JPL
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.18.0
|
|
4
4
|
Summary: Breathing Earth System Simulator (BESS) Gross Primary Production (GPP) and Evapotranspiration (ET) Model Python
|
|
5
5
|
Author-email: Gregory Halverson <gregory.h.halverson@jpl.nasa.gov>
|
|
6
6
|
Project-URL: Homepage, https://github.com/JPL-Evapotranspiration-Algorithms/BESS-JPL
|
|
@@ -10,15 +10,18 @@ Requires-Python: >=3.10
|
|
|
10
10
|
Description-Content-Type: text/markdown
|
|
11
11
|
License-File: LICENSE
|
|
12
12
|
Requires-Dist: check-distribution
|
|
13
|
-
Requires-Dist:
|
|
13
|
+
Requires-Dist: ECOv002-calval-tables>=1.6.0
|
|
14
|
+
Requires-Dist: FLiESANN>=1.6.1
|
|
14
15
|
Requires-Dist: gedi-canopy-height>=1.1.0
|
|
15
16
|
Requires-Dist: GEOS5FP>=1.1.1
|
|
16
|
-
Requires-Dist: koppengeiger>=1.0
|
|
17
|
-
Requires-Dist: MODISCI>=1.
|
|
17
|
+
Requires-Dist: koppengeiger>=1.1.0
|
|
18
|
+
Requires-Dist: MODISCI>=1.4.0
|
|
19
|
+
Requires-Dist: monte-carlo-sensitivity
|
|
18
20
|
Requires-Dist: NASADEM>=1.3.0
|
|
19
21
|
Requires-Dist: numpy
|
|
20
|
-
Requires-Dist: rasters
|
|
21
|
-
Requires-Dist:
|
|
22
|
+
Requires-Dist: rasters>=1.9.0
|
|
23
|
+
Requires-Dist: seaborn
|
|
24
|
+
Requires-Dist: solar-apparent-time>=1.5.3
|
|
22
25
|
Provides-Extra: dev
|
|
23
26
|
Requires-Dist: build; extra == "dev"
|
|
24
27
|
Requires-Dist: pytest>=6.0; extra == "dev"
|
|
@@ -1,15 +1,21 @@
|
|
|
1
|
-
BESS_JPL/BESS_JPL.py,sha256=
|
|
1
|
+
BESS_JPL/BESS_JPL.py,sha256=QfeMnPtlfjgugCYJVhpySP2e4OsD_FClTgS2WactAsA,1582
|
|
2
2
|
BESS_JPL/C3_photosynthesis.py,sha256=-ormDycaWttCOoYJdOoOV_zlM6n0nxkgXxj7fyH_mIs,2760
|
|
3
3
|
BESS_JPL/C4_fraction.jpeg,sha256=ECaEYWA8MnNd5z0Yq3beeUCR93KtTDxM8MrH-YYon3Y,2746
|
|
4
4
|
BESS_JPL/C4_fraction.tif,sha256=DFS-J08JCjnf0hi_T_dFridAegVTiU3FGyMBjS9yc1w,25446
|
|
5
|
+
BESS_JPL/C4_fraction.tif.aux.xml,sha256=5Ytn5UtZdGWQUKNmg_kiOU2zRQsm82sY7bq-j3TS1QY,358
|
|
5
6
|
BESS_JPL/C4_photosynthesis.py,sha256=kITtT2kW1JkYY5v8wpMUhmxfBaJMr_uGk6go5P6w0ag,2029
|
|
7
|
+
BESS_JPL/ECOv002-cal-val-BESS-JPL-inputs.csv,sha256=YwBaHvBXLDhCZySwwfnyhv962j5IH_YxhHex115aVKs,1247281
|
|
8
|
+
BESS_JPL/ECOv002-cal-val-BESS-JPL-outputs.csv,sha256=qxJElgt1PvZYNaQsa1XaeIDcZ-1WtbCXPjblX8-jLFk,1423082
|
|
9
|
+
BESS_JPL/ECOv002-static-tower-BESS-JPL-inputs.csv,sha256=LAVetRyuvyznQXPW7xkzBR0_UC35SCNFg6ukH5016dI,35585
|
|
10
|
+
BESS_JPL/ECOv002_calval_BESS_inputs.py,sha256=UaGhhPQOqly0JuiM86aJAtagNYvovQViKW1tdAv5ElA,606
|
|
11
|
+
BESS_JPL/ECOv002_static_tower_BESS_inputs.py,sha256=pJEindmNfm1wY0Ih-O4WyZtCwWF-NZdh7VK_aE2S-sY,621
|
|
6
12
|
BESS_JPL/FVC_from_NDVI.py,sha256=LYI1ESsrO8UxlPOr_dxJYDeUsrwjVAwrV_OhL-tcAWc,567
|
|
7
|
-
BESS_JPL/LAI_from_NDVI.py,sha256=
|
|
13
|
+
BESS_JPL/LAI_from_NDVI.py,sha256=uwV1voc2q45hmsSHzIhehA3ZHLivzSeoST-ht9ecSIE,783
|
|
8
14
|
BESS_JPL/NDVI_maximum.jpeg,sha256=6kc0-eE_WOU31bUztdjoWsZ3ZmqHAG-ZwS7lMiZyBGA,763946
|
|
9
15
|
BESS_JPL/NDVI_maximum.tif,sha256=yRgdpB-xoVNMveIUapCrnGAwHX7WkH6pVXu4HECuFfc,19664541
|
|
10
16
|
BESS_JPL/NDVI_minimum.jpeg,sha256=AfpRU8PikwExBJ2IdcFKewg6aTcp3gx3y3EQMzeA7vg,644871
|
|
11
17
|
BESS_JPL/NDVI_minimum.tif,sha256=wPV0CFfQSLfiTAEDlwIAI857pA7aw0iqWhVlOAZFsJg,18762242
|
|
12
|
-
BESS_JPL/__init__.py,sha256=
|
|
18
|
+
BESS_JPL/__init__.py,sha256=UaK3mWbc5jNoA4kNzIWF9h7CQs64O_chKrpuxNkH48o,95
|
|
13
19
|
BESS_JPL/ball_berry_intercept_C3.jpeg,sha256=c8jlRD3i8cnWXQNRUfyNTuObEpptcG6p6kQd2RGMK70,634200
|
|
14
20
|
BESS_JPL/ball_berry_intercept_C3.tif,sha256=O7ATUIKtXcIjkUI2lloTiHAgvRk4gWyWjYGh5Xc_CRY,1026642
|
|
15
21
|
BESS_JPL/ball_berry_slope_C3.jpeg,sha256=KdFUYG4h1nRNb_eK7w-M2kqChJnhbcGmal9Z2Jos1nI,225597
|
|
@@ -23,11 +29,11 @@ BESS_JPL/canopy_shortwave_radiation.py,sha256=TzDGFFBVHcZ3s5v-R9pQYeW9PPvYDQ168V
|
|
|
23
29
|
BESS_JPL/carbon_uptake_efficiency.jpeg,sha256=wz2cLk_4-DRdF71xR2c-cx1MsE0CH-EDWjs2pDJcRF0,704540
|
|
24
30
|
BESS_JPL/carbon_uptake_efficiency.tif,sha256=Nnc8h2ImU6_sip0WzDh3q0BRoBe-CfCbwzDtYo5BSog,819269
|
|
25
31
|
BESS_JPL/carbon_water_fluxes.py,sha256=T1E1AHne3lYvkEoasqlM4oLxoSWLWmeJxy1BzrVdPUw,12987
|
|
26
|
-
BESS_JPL/constants.py,sha256=
|
|
32
|
+
BESS_JPL/constants.py,sha256=pkIfSXa8lOpolcjOPXK_NwGcw3IVNgCp9uOmiOT_R3w,203
|
|
27
33
|
BESS_JPL/interpolate_C3_C4.py,sha256=adIyk03Yt6SJ_jFCUm6ivK9QpZYw10C3wJKpx1O56Pk,394
|
|
28
34
|
BESS_JPL/kn.jpeg,sha256=wsI40jabT9_iPpQmOxd3GZzfAN7oZ2DubiARmULFUS0,854097
|
|
29
35
|
BESS_JPL/kn.tif,sha256=nZAIAms7LRDVsadxa4z8yRqOudWu3AjJSm6l1T3ywuY,819988
|
|
30
|
-
BESS_JPL/load_C4_fraction.py,sha256=
|
|
36
|
+
BESS_JPL/load_C4_fraction.py,sha256=qemgzsyDVKvzvql1p_N7g23L8KYvbLw-qxjWlUC3p_Q,624
|
|
31
37
|
BESS_JPL/load_NDVI_maximum.py,sha256=CADnbDULc5qW0oR7UgNN9pM0oplz7QMf8Ki09_fbj-o,401
|
|
32
38
|
BESS_JPL/load_NDVI_minimum.py,sha256=RZaLXKxJe2ViEvj76_l-YSLIMyjo54nP4oAe-NEvACs,401
|
|
33
39
|
BESS_JPL/load_ball_berry_intercept_C3.py,sha256=6auXZHej127rhUCFXe7vdEg9C4CosFSHLTcdqKs06Ls,388
|
|
@@ -38,16 +44,21 @@ BESS_JPL/load_kn.py,sha256=39RkQkkdmey0IPInziJI0kSiI8alRk5Hz42pzm-qihU,346
|
|
|
38
44
|
BESS_JPL/load_peakVCmax_C3.py,sha256=A-Wg4PjPgogfpRsAMo6ZNEXM7G3KbnF7ZRV3k_jTtEA,401
|
|
39
45
|
BESS_JPL/load_peakVCmax_C4.py,sha256=iVmJTitkMkB4AjfjanAi3yv1lWO4sSF6J7cjuRmaCwU,401
|
|
40
46
|
BESS_JPL/meteorology.py,sha256=xIPQnIk9wGJPy8esJyxn35d6c_7UyiNuWTJXDnuSwf8,6995
|
|
41
|
-
BESS_JPL/model.py,sha256=
|
|
47
|
+
BESS_JPL/model.py,sha256=WurAzTeyWhoc_LwCZNqm5iDfkWNVWWlHDp5EveNjE1A,24365
|
|
42
48
|
BESS_JPL/peakVCmax_C3.jpeg,sha256=nVvwLx8JyRhtm5lWRW93HLz0mInshEdOCJ1tAdcFqa8,1006133
|
|
43
49
|
BESS_JPL/peakVCmax_C3.tif,sha256=ax6wCOPc_ovgJJl9YRjPWNY13OCGlzs2djXqwob_U7A,1583598
|
|
44
50
|
BESS_JPL/peakVCmax_C4.jpeg,sha256=s7dhpcD573KW9Se4mejDeSzbSHqPtQY2EL6KJKt7ZIo,961497
|
|
45
51
|
BESS_JPL/peakVCmax_C4.tif,sha256=EST4_yy-HHYmazIv--RePL_bhLejMWql6hoV9EE38ok,1556928
|
|
46
|
-
BESS_JPL/process_BESS_table.py,sha256=
|
|
52
|
+
BESS_JPL/process_BESS_table.py,sha256=CiI_huBJ2R578unMqDMb9dPQUyDuscEd_vqK0-6PHXM,6941
|
|
47
53
|
BESS_JPL/soil_energy_balance.py,sha256=5TKDVkKYJ8jhjuiwbRva_03fi_0gTM0IAKbSm4WhWnY,944
|
|
48
|
-
BESS_JPL/
|
|
49
|
-
|
|
50
|
-
bess_jpl-1.
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
+
BESS_JPL/verify.py,sha256=kNXSsiK1UD_gPRNvb-485q1lpq2wUQ8VEtXJGZRKTL8,3075
|
|
55
|
+
BESS_JPL/version.py,sha256=oPRGJspBmrZU7gLv4L_3WPX3aGwee0inKgfzcyvkXcc,74
|
|
56
|
+
bess_jpl-1.18.0.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
57
|
+
examples/processing_BESS_with_rasters_and_default_parameters.py,sha256=XDlRJMAoQXFSXS0q7z5l_nMeOxFwsLasyJtrNCm-Kak,2600
|
|
58
|
+
tests/test_import_BESS_JPL.py,sha256=7BNKnKdIMbfUb4JVogXCXgiO7XzK9WF54q2aGXWfv3I,62
|
|
59
|
+
tests/test_import_dependencies.py,sha256=sPZY_G7UaENPzTQUgms5TLsQONxtqVlS7QJlTT1izW8,360
|
|
60
|
+
tests/test_verify.py,sha256=T7l9QIpKwon2bdPmfpL2Ac1B8-a9-WcxLGFDdTWnGVk,151
|
|
61
|
+
bess_jpl-1.18.0.dist-info/METADATA,sha256=YBxpMuwrqQc20HYQrIGA9QbO4HCC7yTy7-0raIsY2HY,6460
|
|
62
|
+
bess_jpl-1.18.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
63
|
+
bess_jpl-1.18.0.dist-info/top_level.txt,sha256=NVdh5Igf1HghE2bBB-rc1uYmB5woir8Q-uIjwjjuu2k,24
|
|
64
|
+
bess_jpl-1.18.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# %% [markdown]
|
|
2
|
+
# # Running BESS for an ECOSTRESS Scene
|
|
3
|
+
#
|
|
4
|
+
# This is an example of running the artificial neural network emulator of the Breathing Earth Systems Simulator (BESS) corresponding to an ECOsystem Spaceborne Thermal Radiometer Experiment on Space Station (ECOSTRESS) scene.
|
|
5
|
+
|
|
6
|
+
# %%
|
|
7
|
+
from dateutil import parser
|
|
8
|
+
from matplotlib.colors import LinearSegmentedColormap
|
|
9
|
+
from solar_apparent_time import UTC_to_solar
|
|
10
|
+
import rasters as rt
|
|
11
|
+
from BESS_JPL import BESS_JPL
|
|
12
|
+
import logging
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
# %% [markdown]
|
|
16
|
+
# Here's an example ECOSTRESS surface temperature scene.
|
|
17
|
+
|
|
18
|
+
# %%
|
|
19
|
+
ST_filename = "ECOv002_L2T_LSTE_34366_004_11SPS_20240728T204025_0712_01_LST.tif"
|
|
20
|
+
ST_cmap = "bwr"
|
|
21
|
+
ST_C = rt.Raster.open(ST_filename, cmap=ST_cmap) - 273.15
|
|
22
|
+
ST_C
|
|
23
|
+
|
|
24
|
+
# %% [markdown]
|
|
25
|
+
# Let's get the acquisition time of the scene.
|
|
26
|
+
|
|
27
|
+
# %%
|
|
28
|
+
time_UTC = parser.parse(ST_filename.split("_")[6])
|
|
29
|
+
geometry = ST_C.geometry
|
|
30
|
+
longitude = geometry.centroid_latlon.x
|
|
31
|
+
latitude = geometry.centroid_latlon.y
|
|
32
|
+
time_solar = UTC_to_solar(time_UTC, longitude)
|
|
33
|
+
doy_solar = time_solar.timetuple().tm_yday
|
|
34
|
+
hour_of_day_solar = time_solar.hour + time_solar.minute / 60 + time_solar.second / 3600
|
|
35
|
+
print(f"{time_UTC:%Y-%m-%d %H:%M:%S} UTC")
|
|
36
|
+
print(f"{time_solar:%Y-%m-%d %H:%M:%S} solar apparent time at longitude {longitude}")
|
|
37
|
+
print(f"day of year {doy_solar} at longitude {longitude}")
|
|
38
|
+
print(f"hour of day {hour_of_day_solar} at longitude {longitude}")
|
|
39
|
+
|
|
40
|
+
# %%
|
|
41
|
+
albedo_filename = "ECOv002_L2T_STARS_11SPS_20240728_0712_01_albedo.tif"
|
|
42
|
+
albedo_cmap = LinearSegmentedColormap.from_list(name="albedo", colors=["black", "white"])
|
|
43
|
+
albedo = rt.Raster.open(albedo_filename, cmap=albedo_cmap)
|
|
44
|
+
albedo
|
|
45
|
+
|
|
46
|
+
# %%
|
|
47
|
+
NDVI_filename = "ECOv002_L2T_STARS_11SPS_20240728_0712_01_NDVI.tif"
|
|
48
|
+
NDVI = rt. Raster.open(NDVI_filename)
|
|
49
|
+
|
|
50
|
+
NDVI_COLORMAP_ABSOLUTE = LinearSegmentedColormap.from_list(
|
|
51
|
+
name="NDVI",
|
|
52
|
+
colors=[
|
|
53
|
+
(0, "#0000ff"),
|
|
54
|
+
(0.4, "#000000"),
|
|
55
|
+
(0.5, "#745d1a"),
|
|
56
|
+
(0.6, "#e1dea2"),
|
|
57
|
+
(0.8, "#45ff01"),
|
|
58
|
+
(1, "#325e32")
|
|
59
|
+
]
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
NDVI.cmap = NDVI_COLORMAP_ABSOLUTE
|
|
63
|
+
NDVI
|
|
64
|
+
|
|
65
|
+
# %%
|
|
66
|
+
Ta_filename = "ECOv002_L3T_MET_34366_004_11SPS_20240728T204025_0712_01_Ta.tif"
|
|
67
|
+
Ta_C = rt.Raster.open(Ta_filename)
|
|
68
|
+
Ta_C.cmap = "bwr"
|
|
69
|
+
Ta_C
|
|
70
|
+
|
|
71
|
+
# %%
|
|
72
|
+
RH_filename = "ECOv002_L3T_MET_34366_004_11SPS_20240728T204025_0712_01_RH.tif"
|
|
73
|
+
RH = rt.Raster.open(RH_filename)
|
|
74
|
+
RH.cmap = "bwr_r"
|
|
75
|
+
RH
|
|
76
|
+
|
|
77
|
+
# %%
|
|
78
|
+
BESS_results = BESS_JPL(
|
|
79
|
+
hour_of_day=hour_of_day_solar,
|
|
80
|
+
day_of_year=doy_solar,
|
|
81
|
+
geometry=geometry,
|
|
82
|
+
time_UTC=time_UTC,
|
|
83
|
+
ST_C=ST_C,
|
|
84
|
+
NDVI=NDVI,
|
|
85
|
+
albedo=albedo,
|
|
86
|
+
Ta_C=Ta_C,
|
|
87
|
+
RH=RH
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
# %%
|
|
91
|
+
BESS_results["GPP"]
|
|
92
|
+
|
|
93
|
+
# %%
|
|
94
|
+
BESS_results["Rn"]
|
|
95
|
+
|
|
96
|
+
# %%
|
|
97
|
+
BESS_results["LE"]
|
|
98
|
+
|
|
99
|
+
# %%
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
|
|
3
|
+
# List of dependencies
|
|
4
|
+
dependencies = [
|
|
5
|
+
"check_distribution",
|
|
6
|
+
"FLiESANN",
|
|
7
|
+
"gedi_canopy_height",
|
|
8
|
+
"GEOS5FP",
|
|
9
|
+
"MODISCI",
|
|
10
|
+
"numpy",
|
|
11
|
+
"rasters"
|
|
12
|
+
]
|
|
13
|
+
|
|
14
|
+
# Generate individual test functions for each dependency
|
|
15
|
+
@pytest.mark.parametrize("dependency", dependencies)
|
|
16
|
+
def test_dependency_import(dependency):
|
|
17
|
+
__import__(dependency)
|
tests/test_verify.py
ADDED
BESS_JPL/version.txt
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
1.15.0
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
BESS_JPL
|
|
File without changes
|
|
File without changes
|