BESS-JPL 1.6.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.py +468 -0
- BESS_JPL/BESS_JPL.py +23 -0
- BESS_JPL/C3_photosynthesis.py +72 -0
- BESS_JPL/C4_fraction.jpeg +0 -0
- BESS_JPL/C4_fraction.tif +0 -0
- BESS_JPL/C4_photosynthesis.py +56 -0
- BESS_JPL/FVC_from_NDVI.py +22 -0
- BESS_JPL/LAI_from_NDVI.py +29 -0
- BESS_JPL/NDVI_maximum.jpeg +0 -0
- BESS_JPL/NDVI_maximum.tif +0 -0
- BESS_JPL/NDVI_minimum.jpeg +0 -0
- BESS_JPL/NDVI_minimum.tif +0 -0
- BESS_JPL/SZA/__init__.py +1 -0
- BESS_JPL/SZA/daylight_hours.py +74 -0
- BESS_JPL/__init__.py +10 -0
- BESS_JPL/ball_berry_intercept_C3.jpeg +0 -0
- BESS_JPL/ball_berry_intercept_C3.tif +0 -0
- BESS_JPL/ball_berry_slope_C3.jpeg +0 -0
- BESS_JPL/ball_berry_slope_C3.tif +0 -0
- BESS_JPL/ball_berry_slope_C4.jpeg +0 -0
- BESS_JPL/ball_berry_slope_C4.tif +0 -0
- BESS_JPL/calculate_VCmax.py +54 -0
- BESS_JPL/canopy_energy_balance.py +146 -0
- BESS_JPL/canopy_longwave_radiation.py +92 -0
- BESS_JPL/canopy_shortwave_radiation.py +234 -0
- BESS_JPL/carbon_uptake_efficiency.jpeg +0 -0
- BESS_JPL/carbon_uptake_efficiency.tif +0 -0
- BESS_JPL/carbon_water_fluxes.py +277 -0
- BESS_JPL/constants.py +8 -0
- BESS_JPL/interpolate_C3_C4.py +12 -0
- BESS_JPL/kn.jpeg +0 -0
- BESS_JPL/kn.tif +0 -0
- BESS_JPL/load_C4_fraction.py +10 -0
- BESS_JPL/load_NDVI_maximum.py +10 -0
- BESS_JPL/load_NDVI_minimum.py +10 -0
- BESS_JPL/load_ball_berry_intercept_C3.py +10 -0
- BESS_JPL/load_ball_berry_slope_C3.py +10 -0
- BESS_JPL/load_ball_berry_slope_C4.py +10 -0
- BESS_JPL/load_carbon_uptake_efficiency.py +10 -0
- BESS_JPL/load_kn.py +10 -0
- BESS_JPL/load_peakVCmax_C3.py +10 -0
- BESS_JPL/load_peakVCmax_C4.py +10 -0
- BESS_JPL/meteorology.py +204 -0
- BESS_JPL/peakVCmax_C3.jpeg +0 -0
- BESS_JPL/peakVCmax_C3.tif +0 -0
- BESS_JPL/peakVCmax_C4.jpeg +0 -0
- BESS_JPL/peakVCmax_C4.tif +0 -0
- BESS_JPL/soil_energy_balance.py +35 -0
- BESS_JPL/vegetation_conversion/__init__.py +1 -0
- BESS_JPL/vegetation_conversion/vegetation_conversion.py +71 -0
- BESS_JPL/version.txt +1 -0
- bess_jpl-1.6.0.dist-info/METADATA +95 -0
- bess_jpl-1.6.0.dist-info/RECORD +56 -0
- bess_jpl-1.6.0.dist-info/WHEEL +5 -0
- bess_jpl-1.6.0.dist-info/licenses/LICENSE +201 -0
- bess_jpl-1.6.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
from os.path import join, abspath, dirname
|
|
2
|
+
from typing import Union
|
|
3
|
+
|
|
4
|
+
import numpy as np
|
|
5
|
+
import rasters as rt
|
|
6
|
+
from rasters import Raster, RasterGeometry
|
|
7
|
+
from .C3_photosynthesis import calculate_C3_photosynthesis
|
|
8
|
+
from .C4_photosynthesis import calculate_C4_photosynthesis
|
|
9
|
+
from .canopy_longwave_radiation import canopy_longwave_radiation
|
|
10
|
+
from .canopy_energy_balance import canopy_energy_balance
|
|
11
|
+
from .soil_energy_balance import soil_energy_balance
|
|
12
|
+
|
|
13
|
+
PASSES = 1
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def load_ball_berry_intercept_C3(self, geometry: RasterGeometry) -> Raster:
|
|
17
|
+
filename = join(abspath(dirname(__file__)), "ball_berry_intercept_C3.tif")
|
|
18
|
+
image = rt.Raster.open(filename, geometry=geometry, resampling=self.resampling)
|
|
19
|
+
|
|
20
|
+
return image
|
|
21
|
+
|
|
22
|
+
def load_ball_berry_slope_C3(self, geometry: RasterGeometry) -> Raster:
|
|
23
|
+
filename = join(abspath(dirname(__file__)), "ball_berry_slope_C3.tif")
|
|
24
|
+
image = rt.Raster.open(filename, geometry=geometry, resampling=self.resampling)
|
|
25
|
+
|
|
26
|
+
return image
|
|
27
|
+
|
|
28
|
+
def load_ball_berry_slope_C4(self, geometry: RasterGeometry) -> Raster:
|
|
29
|
+
filename = join(abspath(dirname(__file__)), "ball_berry_slope_C4.tif")
|
|
30
|
+
image = rt.Raster.open(filename, geometry=geometry, resampling=self.resampling)
|
|
31
|
+
|
|
32
|
+
return image
|
|
33
|
+
|
|
34
|
+
def carbon_water_fluxes(
|
|
35
|
+
canopy_temperature_K: np.ndarray, # canopy temperature in Kelvin
|
|
36
|
+
soil_temperature_K: np.ndarray, # soil temperature in Kelvin
|
|
37
|
+
LAI: np.ndarray, # leaf area index
|
|
38
|
+
Ta_K: np.ndarray, # air temperature in Kelvin
|
|
39
|
+
APAR_sunlit: np.ndarray, # sunlit leaf absorptance to photosynthetically active radiation [umol m-2 s-1]
|
|
40
|
+
APAR_shaded: np.ndarray, # shaded leaf absorptance to photosynthetically active radiation [umol m-2 s-1]
|
|
41
|
+
ASW_sunlit: np.ndarray, # sunlit absorbed shortwave radiation [W m-2]
|
|
42
|
+
ASW_shaded: np.ndarray, # shaded absorbed shortwave radiation [W m-2]
|
|
43
|
+
ASW_soil: np.ndarray, # absorbed shortwave radiation in soil
|
|
44
|
+
Vcmax25_sunlit: np.ndarray, # sunlit maximum carboxylation rate at 25C
|
|
45
|
+
Vcmax25_shaded: np.ndarray, # shaded maximum carboxylation rate at 25C
|
|
46
|
+
ball_berry_slope: np.ndarray, # Ball-Berry slope
|
|
47
|
+
ball_berry_intercept: Union[np.ndarray, float], # Ball-Berry intercept
|
|
48
|
+
sunlit_fraction: np.ndarray, # sunlit fraction of canopy
|
|
49
|
+
G: np.ndarray, # soil heat flux in W m-2
|
|
50
|
+
SZA: np.ndarray, # solar zenith angle in degrees
|
|
51
|
+
Ca: np.ndarray, # atmospheric CO2 concentration in umol mol-1
|
|
52
|
+
Ps_Pa: np.ndarray, # surface pressure in Pascal
|
|
53
|
+
gamma: np.ndarray, # psychrometric constant in Pa K-1
|
|
54
|
+
Cp: np.ndarray, # specific heat capacity of air in J kg-1 K-1
|
|
55
|
+
rhoa: np.ndarray, # air density in kg m-3
|
|
56
|
+
VPD_Pa: np.ndarray, # vapor pressure deficit in Pascal
|
|
57
|
+
RH: np.ndarray, # relative humidity as a fraction
|
|
58
|
+
desTa: np.ndarray,
|
|
59
|
+
ddesTa: np.ndarray,
|
|
60
|
+
epsa: np.ndarray,
|
|
61
|
+
Rc: np.ndarray,
|
|
62
|
+
Rs: np.ndarray,
|
|
63
|
+
carbon_uptake_efficiency: np.ndarray, # intrinsic quantum efficiency of carbon uptake
|
|
64
|
+
fStress: np.ndarray,
|
|
65
|
+
C4_photosynthesis: bool, # C3 or C4 photosynthesis
|
|
66
|
+
passes: int = PASSES): # number of iterations
|
|
67
|
+
# carbon = 4 if C4_photosynthesis else 3
|
|
68
|
+
GPP_max = 50 if C4_photosynthesis else 40
|
|
69
|
+
|
|
70
|
+
# this model originally initialized soil and canopy temperature to air temperature
|
|
71
|
+
Tf_K_sunlit = canopy_temperature_K
|
|
72
|
+
Tf_K_shaded = canopy_temperature_K
|
|
73
|
+
Tf_K = canopy_temperature_K
|
|
74
|
+
Ts_K = soil_temperature_K
|
|
75
|
+
|
|
76
|
+
# initialize intercellular CO2 concentration to atmospheric CO2 concentration depending on C3 or C4 photosynthesis
|
|
77
|
+
chi = 0.4 if C4_photosynthesis else 0.7
|
|
78
|
+
Ci_sunlit = Ca * chi
|
|
79
|
+
Ci_shaded = Ca * chi
|
|
80
|
+
|
|
81
|
+
ball_berry_intercept = ball_berry_intercept * fStress
|
|
82
|
+
|
|
83
|
+
epsf = 0.98
|
|
84
|
+
epss = 0.96
|
|
85
|
+
|
|
86
|
+
# initialize sunlit partition (overwritten when iterations process)
|
|
87
|
+
|
|
88
|
+
# initialize sunlit net assimilation rate to zero
|
|
89
|
+
An_sunlit = Tf_K_sunlit * 0
|
|
90
|
+
|
|
91
|
+
# initialize sunlit net radiation to zero
|
|
92
|
+
Rn_sunlit = Tf_K_sunlit * 0
|
|
93
|
+
|
|
94
|
+
# initialize sunlit latent heat flux to zero
|
|
95
|
+
LE_sunlit = Tf_K_sunlit * 0
|
|
96
|
+
|
|
97
|
+
# initialize sunlit sensible heat flux to zero
|
|
98
|
+
H_sunlit = Tf_K_sunlit * 0
|
|
99
|
+
|
|
100
|
+
# initialize shaded partition (overwritten when iterations process)
|
|
101
|
+
|
|
102
|
+
# initialize shaded net assimilation rate to zero
|
|
103
|
+
An_shaded = Tf_K_shaded * 0
|
|
104
|
+
|
|
105
|
+
# initialize shaded net radiation to zero
|
|
106
|
+
Rn_shaded = Tf_K_shaded * 0
|
|
107
|
+
|
|
108
|
+
# initialize shaded latent heat flux to zero
|
|
109
|
+
LE_shaded = Tf_K_shaded * 0
|
|
110
|
+
|
|
111
|
+
# initialize shaded sensible heat flux to zero
|
|
112
|
+
H_shaded = Tf_K_shaded * 0
|
|
113
|
+
|
|
114
|
+
# initialize soil partition (overwritten when iterations process)
|
|
115
|
+
|
|
116
|
+
# initialize soil net radiation to zero
|
|
117
|
+
Rn_soil = Ts_K * 0
|
|
118
|
+
|
|
119
|
+
# initialize soil latent heat flux to zero
|
|
120
|
+
LE_soil = Ts_K * 0
|
|
121
|
+
|
|
122
|
+
# Iteration
|
|
123
|
+
for iter in range(1, passes + 1):
|
|
124
|
+
|
|
125
|
+
# Longwave radiation
|
|
126
|
+
# CLR:[ALW_Sun, ALW_shaded, ALW_Soil, Ls, La]
|
|
127
|
+
ALW_sunlit, ALW_shaded, ALW_soil, Ls, La, Lf = canopy_longwave_radiation(
|
|
128
|
+
LAI=LAI, # leaf area index (LAI) [-]
|
|
129
|
+
SZA=SZA, # solar zenith angle (degrees)
|
|
130
|
+
Ts_K=Ts_K, # soil temperature (Ts) [K]
|
|
131
|
+
Tf_K=Tf_K, # foliage temperature (Tf) [K]
|
|
132
|
+
Ta_K=Ta_K, # air temperature (Ta) [K]
|
|
133
|
+
epsa=epsa, # clear-sky emissivity (epsa) [-]
|
|
134
|
+
epsf=epsf, # foliage emissivity (epsf) [-]
|
|
135
|
+
epss=epss # soil emissivity (epss) [-],
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
# calculate sunlit photosynthesis
|
|
139
|
+
if C4_photosynthesis:
|
|
140
|
+
# calculate sunlit photosynthesis for C4 plants
|
|
141
|
+
An_sunlit = calculate_C4_photosynthesis(
|
|
142
|
+
Tf_K=Tf_K_sunlit, # sunlit leaf temperature (Tf) [K]
|
|
143
|
+
Ci=Ci_sunlit, # sunlit intercellular CO2 concentration (Ci) [umol mol-1]
|
|
144
|
+
APAR=APAR_sunlit, # sunlit leaf absorptance to photosynthetically active radiation [umol m-2 s-1]
|
|
145
|
+
Vcmax25=Vcmax25_sunlit # sunlit maximum carboxylation rate at 25C (Vcmax25) [umol m-2 s-1]
|
|
146
|
+
)
|
|
147
|
+
else:
|
|
148
|
+
# calculate sunlit photosynthesis for C3 plants
|
|
149
|
+
An_sunlit = calculate_C3_photosynthesis(
|
|
150
|
+
Tf_K=Tf_K_sunlit, # sunlit leaf temperature (Tf) [K]
|
|
151
|
+
Ci=Ci_sunlit, # sunlit intercellular CO2 concentration (Ci) [umol mol-1]
|
|
152
|
+
APAR=APAR_sunlit, # sunlit leaf absorptance to photosynthetically active radiation [umol m-2 s-1]
|
|
153
|
+
Vcmax25=Vcmax25_sunlit, # sunlit maximum carboxylation rate at 25C (Vcmax25) [umol m-2 s-1]
|
|
154
|
+
Ps_Pa=Ps_Pa, # surface pressure (Ps) [Pa]
|
|
155
|
+
carbon_uptake_efficiency=carbon_uptake_efficiency # intrinsic quantum efficiency for carbon uptake
|
|
156
|
+
)
|
|
157
|
+
|
|
158
|
+
# calculate sunlit energy balance
|
|
159
|
+
Rn_sunlit_new, LE_sunlit_new, H_sunlit_new, Tf_K_sunlit_new, gs2_sunlit_new, Ci_sunlit_new = canopy_energy_balance(
|
|
160
|
+
An=An_sunlit, # net assimulation (An) [umol m-2 s-1]
|
|
161
|
+
ASW=ASW_sunlit, # total absorbed shortwave radiation by sunlit canopy (ASW) [umol m-2 s-1]
|
|
162
|
+
ALW=ALW_sunlit, # total absorbed longwave radiation by sunlit canopy (ALW) [umol m-2 s-1]
|
|
163
|
+
Tf_K=Tf_K_sunlit, # sunlit leaf temperature (Tf) [K]
|
|
164
|
+
Ps_Pa=Ps_Pa, # surface pressure (Ps) [Pa]
|
|
165
|
+
Ca=Ca, # ambient CO2 concentration (Ca) [umol mol-1]
|
|
166
|
+
Ta_K=Ta_K, # air temperature (Ta) [K]
|
|
167
|
+
RH=RH, # relative humidity (RH) [-]
|
|
168
|
+
VPD_Pa=VPD_Pa, # water vapour deficit (VPD) [Pa]
|
|
169
|
+
desTa=desTa, # 1st derivative of saturated vapour pressure (desTa)
|
|
170
|
+
ddesTa=ddesTa, # 2nd derivative of saturated vapour pressure (ddesTa)
|
|
171
|
+
gamma=gamma, # psychrometric constant (gamma) [pa K-1]
|
|
172
|
+
Cp=Cp, # specific heat of air at constant pressure (Cp) [J kg-1 K-1]
|
|
173
|
+
rhoa=rhoa, # air density (rhoa) [kg m-3]
|
|
174
|
+
Rc=Rc, # TODO is this Ra or Rc in Ball-Berry?
|
|
175
|
+
ball_berry_slope=ball_berry_slope, # Ball-Berry slope (m) [-]
|
|
176
|
+
ball_berry_intercept=ball_berry_intercept, # Ball-Berry intercept (b0) [-]
|
|
177
|
+
C4_photosynthesis=C4_photosynthesis # process for C4 plants instead of C3
|
|
178
|
+
)
|
|
179
|
+
|
|
180
|
+
# filter in sunlit energy balance estimates
|
|
181
|
+
Rn_sunlit = np.where(np.isnan(Rn_sunlit_new), Rn_sunlit, Rn_sunlit_new)
|
|
182
|
+
LE_sunlit = np.where(np.isnan(LE_sunlit_new), LE_sunlit, LE_sunlit_new)
|
|
183
|
+
H_sunlit = np.where(np.isnan(H_sunlit_new), H_sunlit, H_sunlit_new)
|
|
184
|
+
Tf_K_sunlit = np.where(np.isnan(Tf_K_sunlit_new), Tf_K_sunlit, Tf_K_sunlit_new)
|
|
185
|
+
Ci_sunlit = np.where(np.isnan(Ci_sunlit_new), Ci_sunlit, Ci_sunlit_new)
|
|
186
|
+
|
|
187
|
+
# Photosynthesis (shade)
|
|
188
|
+
if C4_photosynthesis:
|
|
189
|
+
An_shaded = calculate_C4_photosynthesis(
|
|
190
|
+
Tf_K=Tf_K_shaded, # shaded leaf temperature (Tf) [K]
|
|
191
|
+
Ci=Ci_shaded, # shaded intercellular CO2 concentration (Ci) [umol mol-1]
|
|
192
|
+
APAR=APAR_shaded, # shaded absorbed photosynthetically active radiation (APAR) [umol m-2 s-1]
|
|
193
|
+
Vcmax25=Vcmax25_shaded # shaded maximum carboxylation rate at 25C (Vcmax25) [umol m-2 s-1]
|
|
194
|
+
)
|
|
195
|
+
else:
|
|
196
|
+
An_shaded = calculate_C3_photosynthesis(
|
|
197
|
+
Tf_K=Tf_K_shaded, # shaded leaf temperature (Tf) [K]
|
|
198
|
+
Ci=Ci_shaded, # shaed intercellular CO2 concentration (Ci) [umol mol-1]
|
|
199
|
+
APAR=APAR_shaded, # shaded absorbed photosynthetically active radiation (APAR) [umol m-2 s-1]
|
|
200
|
+
Vcmax25=Vcmax25_shaded, # shaded maximum carboxylation rate at 25C (Vcmax25) [umol m-2 s-1]
|
|
201
|
+
Ps_Pa=Ps_Pa, # surface pressure (Ps) [Pa]
|
|
202
|
+
carbon_uptake_efficiency=carbon_uptake_efficiency # intrinsic quantum efficiency for carbon uptake
|
|
203
|
+
)
|
|
204
|
+
|
|
205
|
+
# calculated shaded energy balance
|
|
206
|
+
Rn_shaded_new, LE_shaded_new, H_shaded_new, Tf_K_shaded_new, gs2_shaded_new, Ci_shaded_new = canopy_energy_balance(
|
|
207
|
+
An=An_shaded, # net assimulation (An) [umol m-2 s-1]
|
|
208
|
+
ASW=ASW_shaded, # total absorbed shortwave radiation by shaded canopy (ASW) [umol m-2 s-1]
|
|
209
|
+
ALW=ALW_shaded, # total absorbed longwave radiation by shaded canopy (ALW) [umol m-2 s-1]
|
|
210
|
+
Tf_K=Tf_K_shaded, # shaded leaf temperature (Tf) [K]
|
|
211
|
+
Ps_Pa=Ps_Pa, # surface pressure (Ps) [Pa]
|
|
212
|
+
Ca=Ca, # ambient CO2 concentration (Ca) [umol mol-1]
|
|
213
|
+
Ta_K=Ta_K, # air temperature (Ta) [K]
|
|
214
|
+
RH=RH, # relative humidity as a fraction
|
|
215
|
+
VPD_Pa=VPD_Pa, # water vapour deficit (VPD) [Pa]
|
|
216
|
+
desTa=desTa, # 1st derivative of saturated vapour pressure (desTa)
|
|
217
|
+
ddesTa=ddesTa, # 2nd derivative of saturated vapour pressure (ddesTa)
|
|
218
|
+
gamma=gamma, # psychrometric constant (gamma) [pa K-1]
|
|
219
|
+
Cp=Cp, # specific heat of air (Cp) [J kg-1 K-1]
|
|
220
|
+
rhoa=rhoa, # air density (rhoa) [kg m-3]
|
|
221
|
+
Rc=Rc,
|
|
222
|
+
ball_berry_slope=ball_berry_slope, # Ball-Berry slope (m) [-]
|
|
223
|
+
ball_berry_intercept=ball_berry_intercept, # Ball-Berry intercept (b0) [-]
|
|
224
|
+
C4_photosynthesis=C4_photosynthesis # process for C4 plants instead of C3
|
|
225
|
+
)
|
|
226
|
+
|
|
227
|
+
# filter in shaded energy balance estimates
|
|
228
|
+
Rn_shaded = np.where(np.isnan(Rn_shaded_new), Rn_shaded, Rn_shaded_new)
|
|
229
|
+
LE_shaded = np.where(np.isnan(LE_shaded_new), LE_shaded, LE_shaded_new)
|
|
230
|
+
H_shaded = np.where(np.isnan(H_shaded_new), H_shaded, H_shaded_new)
|
|
231
|
+
Tf_K_shaded = np.where(np.isnan(Tf_K_shaded_new), Tf_K_shaded, Tf_K_shaded_new)
|
|
232
|
+
Ci_shaded = np.where(np.isnan(Ci_shaded_new), Ci_shaded, Ci_shaded_new)
|
|
233
|
+
|
|
234
|
+
# calculate soil energy balance
|
|
235
|
+
Rn_soil_new, LE_soil_new, Ts_K_soil_new = soil_energy_balance(
|
|
236
|
+
Ts_K=Ts_K, # soil temperature in Kelvin
|
|
237
|
+
Ta_K=Ta_K, # air temperature in Kelvin
|
|
238
|
+
G=G, # soil heat flux (G) [W m-2]
|
|
239
|
+
VPD=VPD_Pa, # water vapour deficit in Pascal
|
|
240
|
+
RH=RH, # relative humidity as a fraction
|
|
241
|
+
gamma=gamma, # psychrometric constant (gamma) [pa K-1]
|
|
242
|
+
Cp=Cp, # specific heat of air (Cp) [J kg-1 K-1]
|
|
243
|
+
rhoa=rhoa, # air density (rhoa) [kg m-3]
|
|
244
|
+
desTa=desTa,
|
|
245
|
+
Rs=Rs,
|
|
246
|
+
ASW_soil=ASW_soil, # total absorbed shortwave radiation by soil (ASW) [umol m-2 s-1]
|
|
247
|
+
ALW_soil=ALW_soil, # total absorbed longwave radiation by soil (ALW) [umol m-2 s-1]
|
|
248
|
+
Ls=Ls,
|
|
249
|
+
epsa=epsa
|
|
250
|
+
)
|
|
251
|
+
|
|
252
|
+
# filter in soil energy balance estimates
|
|
253
|
+
# where new estimates are missing, retain the prior estimates
|
|
254
|
+
Rn_soil = np.where(np.isnan(Rn_soil_new), Rn_soil, Rn_soil_new)
|
|
255
|
+
LE_soil = np.where(np.isnan(LE_soil_new), LE_soil, LE_soil_new)
|
|
256
|
+
Ts_K = np.where(np.isnan(Ts_K_soil_new), Ts_K, Ts_K_soil_new)
|
|
257
|
+
|
|
258
|
+
# combine sunlit and shaded foliage temperatures
|
|
259
|
+
Tf_K_new = (((Tf_K_sunlit ** 4) * sunlit_fraction + (Tf_K_shaded ** 4) * (1 - sunlit_fraction)) ** 0.25)
|
|
260
|
+
Tf_K = np.where(np.isnan(Tf_K_new), Tf_K, Tf_K_new)
|
|
261
|
+
|
|
262
|
+
# calculate canopy latent heat flux
|
|
263
|
+
LE_canopy = np.clip(LE_sunlit + LE_shaded, 0, 1000)
|
|
264
|
+
|
|
265
|
+
# calculate latent heat flux
|
|
266
|
+
LE = np.clip(LE_sunlit + LE_shaded + LE_soil, 0, 1000) # [W m-2]
|
|
267
|
+
|
|
268
|
+
# calculate gross primary productivity
|
|
269
|
+
GPP = np.clip(An_sunlit + An_shaded, 0, GPP_max) # [umol m-2 s-1]
|
|
270
|
+
|
|
271
|
+
# calculate canopy net radiation
|
|
272
|
+
Rn_canopy = np.clip(Rn_sunlit + Rn_shaded, 0, None)
|
|
273
|
+
|
|
274
|
+
# calculate net radiation
|
|
275
|
+
Rn = np.clip(Rn_sunlit + Rn_shaded + Rn_soil, 0, 1000) # [W m-2]
|
|
276
|
+
|
|
277
|
+
return GPP, LE, LE_soil, LE_canopy, Rn, Rn_soil, Rn_canopy
|
BESS_JPL/constants.py
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def interpolate_C3_C4(C3: np.ndarray, C4: np.ndarray, C4_fraction: np.ndarray) -> np.ndarray:
|
|
5
|
+
"""
|
|
6
|
+
Interpolate between C3 and C4 plants based on C4 fraction
|
|
7
|
+
:param C3: value for C3 plants
|
|
8
|
+
:param C4: value for C4 plants
|
|
9
|
+
:param C4_fraction: fraction of C4 plants
|
|
10
|
+
:return: interpolated value
|
|
11
|
+
"""
|
|
12
|
+
return C3 * (1 - C4_fraction) + C4 * C4_fraction
|
BESS_JPL/kn.jpeg
ADDED
|
Binary file
|
BESS_JPL/kn.tif
ADDED
|
Binary file
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
from os.path import join, abspath, dirname
|
|
2
|
+
|
|
3
|
+
import rasters as rt
|
|
4
|
+
from rasters import Raster, RasterGeometry
|
|
5
|
+
|
|
6
|
+
def load_C4_fraction(geometry: RasterGeometry = None, resampling: str = "nearest") -> Raster:
|
|
7
|
+
filename = join(abspath(dirname(__file__)), "C4_fraction.tif")
|
|
8
|
+
image = Raster.open(filename, geometry=geometry, resampling=resampling)
|
|
9
|
+
|
|
10
|
+
return image
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
from os.path import join, abspath, dirname
|
|
2
|
+
|
|
3
|
+
import rasters as rt
|
|
4
|
+
from rasters import Raster, RasterGeometry
|
|
5
|
+
|
|
6
|
+
def load_NDVI_maximum(geometry: RasterGeometry = None, resampling: str = "nearest") -> Raster:
|
|
7
|
+
filename = join(abspath(dirname(__file__)), "NDVI_maximum.tif")
|
|
8
|
+
image = Raster.open(filename, geometry=geometry, resampling=resampling)
|
|
9
|
+
|
|
10
|
+
return image
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
from os.path import join, abspath, dirname
|
|
2
|
+
|
|
3
|
+
import rasters as rt
|
|
4
|
+
from rasters import Raster, RasterGeometry
|
|
5
|
+
|
|
6
|
+
def load_NDVI_minimum(geometry: RasterGeometry = None, resampling: str = "nearest") -> Raster:
|
|
7
|
+
filename = join(abspath(dirname(__file__)), "NDVI_minimum.tif")
|
|
8
|
+
image = Raster.open(filename, geometry=geometry, resampling=resampling)
|
|
9
|
+
|
|
10
|
+
return image
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
from os.path import join, abspath, dirname
|
|
2
|
+
|
|
3
|
+
import rasters as rt
|
|
4
|
+
from rasters import Raster, RasterGeometry
|
|
5
|
+
|
|
6
|
+
def load_ball_berry_intercept_C3(geometry: RasterGeometry = None, resampling: str = "nearest") -> Raster:
|
|
7
|
+
filename = join(abspath(dirname(__file__)), "ball_berry_intercept_C3.tif")
|
|
8
|
+
image = Raster.open(filename, geometry=geometry, resampling=resampling)
|
|
9
|
+
|
|
10
|
+
return image
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
from os.path import join, abspath, dirname
|
|
2
|
+
|
|
3
|
+
import rasters as rt
|
|
4
|
+
from rasters import Raster, RasterGeometry
|
|
5
|
+
|
|
6
|
+
def load_ball_berry_slope_C3(geometry: RasterGeometry = None, resampling: str = "nearest") -> Raster:
|
|
7
|
+
filename = join(abspath(dirname(__file__)), "ball_berry_slope_C3.tif")
|
|
8
|
+
image = Raster.open(filename, geometry=geometry, resampling="nearest")
|
|
9
|
+
|
|
10
|
+
return image
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
from os.path import join, abspath, dirname
|
|
2
|
+
|
|
3
|
+
import rasters as rt
|
|
4
|
+
from rasters import Raster, RasterGeometry
|
|
5
|
+
|
|
6
|
+
def load_ball_berry_slope_C4(geometry: RasterGeometry = None, resampling: str = "nearest") -> Raster:
|
|
7
|
+
filename = join(abspath(dirname(__file__)), "ball_berry_slope_C4.tif")
|
|
8
|
+
image = Raster.open(filename, geometry=geometry, resampling="nearest")
|
|
9
|
+
|
|
10
|
+
return image
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
from os.path import join, abspath, dirname
|
|
2
|
+
|
|
3
|
+
import rasters as rt
|
|
4
|
+
from rasters import Raster, RasterGeometry
|
|
5
|
+
|
|
6
|
+
def load_carbon_uptake_efficiency(geometry: RasterGeometry = None, resampling: str = "nearest") -> Raster:
|
|
7
|
+
filename = join(abspath(dirname(__file__)), "carbon_uptake_efficiency.tif")
|
|
8
|
+
image = Raster.open(filename, geometry=geometry, resampling=resampling)
|
|
9
|
+
|
|
10
|
+
return image
|
BESS_JPL/load_kn.py
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
from os.path import join, abspath, dirname
|
|
2
|
+
|
|
3
|
+
import rasters as rt
|
|
4
|
+
from rasters import Raster, RasterGeometry
|
|
5
|
+
|
|
6
|
+
def load_kn(geometry: RasterGeometry = None, resampling: str = "nearest") -> Raster:
|
|
7
|
+
filename = join(abspath(dirname(__file__)), "kn.tif")
|
|
8
|
+
image = Raster.open(filename, geometry=geometry, resampling="nearest")
|
|
9
|
+
|
|
10
|
+
return image
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
from os.path import join, abspath, dirname
|
|
2
|
+
|
|
3
|
+
import rasters as rt
|
|
4
|
+
from rasters import Raster, RasterGeometry
|
|
5
|
+
|
|
6
|
+
def load_peakVCmax_C3(geometry: RasterGeometry = None, resampling: str = "nearest") -> Raster:
|
|
7
|
+
filename = join(abspath(dirname(__file__)), "peakVCmax_C3.tif")
|
|
8
|
+
image = Raster.open(filename, geometry=geometry, resampling="nearest")
|
|
9
|
+
|
|
10
|
+
return image
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
from os.path import join, abspath, dirname
|
|
2
|
+
|
|
3
|
+
import rasters as rt
|
|
4
|
+
from rasters import Raster, RasterGeometry
|
|
5
|
+
|
|
6
|
+
def load_peakVCmax_C4(geometry: RasterGeometry = None, resampling: str = "nearest") -> Raster:
|
|
7
|
+
filename = join(abspath(dirname(__file__)), "peakVCmax_C4.tif")
|
|
8
|
+
image = Raster.open(filename, geometry=geometry, resampling="nearest")
|
|
9
|
+
|
|
10
|
+
return image
|
BESS_JPL/meteorology.py
ADDED
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
from typing import Tuple
|
|
2
|
+
import numpy as np
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def SVP_kPa_from_Ta_C(Ta_C: np.ndarray) -> np.ndarray:
|
|
6
|
+
"""
|
|
7
|
+
saturation vapor pressure in kPa from air temperature in celsius
|
|
8
|
+
:param Ta_C: air temperature in celsius
|
|
9
|
+
:return: saturation vapor pressure in kiloPascal
|
|
10
|
+
"""
|
|
11
|
+
return 0.611 * np.exp((Ta_C * 17.27) / (Ta_C + 237.7))
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def SVP_Pa_from_Ta_K(Ta_K: np.ndarray) -> np.ndarray:
|
|
15
|
+
"""
|
|
16
|
+
saturation vapor pressure in kPa from air temperature in celsius
|
|
17
|
+
:param Ta_K: air temperature in Kelvin
|
|
18
|
+
:return: saturation vapor pressure in kiloPascal
|
|
19
|
+
"""
|
|
20
|
+
Ta_C = Ta_K - 273.15
|
|
21
|
+
SVP_kPa = SVP_kPa_from_Ta_C(Ta_C)
|
|
22
|
+
SVP_Pa = SVP_kPa * 1000
|
|
23
|
+
|
|
24
|
+
return SVP_Pa
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def meteorology(
|
|
28
|
+
day_of_year: np.ndarray, # day of year
|
|
29
|
+
hour_of_day: np.ndarray, # hour of day
|
|
30
|
+
latitude: np.ndarray, # latitude
|
|
31
|
+
elevation_m: np.ndarray, # elevation in meters
|
|
32
|
+
SZA: np.ndarray, # solar zenith angle in degrees
|
|
33
|
+
Ta_K: np.ndarray, # air temperature in Kelvin
|
|
34
|
+
Ea_Pa: np.ndarray, # vapor pressure in Pascal
|
|
35
|
+
Rg: np.ndarray, # shortwave radiation in W/m2
|
|
36
|
+
wind_speed_mps: np.ndarray, # wind speed in meters per second
|
|
37
|
+
canopy_height_meters: np.ndarray): # canopy height in meters
|
|
38
|
+
"""
|
|
39
|
+
Meteorological calculations for Breathing Earth System Simulator
|
|
40
|
+
Adapted from Youngryel Ryu's MATLAB code by Gregory Halverson and Robert Freepartner
|
|
41
|
+
:param day_of_year: day of year
|
|
42
|
+
:param hour_of_day: hour of day
|
|
43
|
+
:param latitude: latitude
|
|
44
|
+
:param elevation_m: elevation in meters
|
|
45
|
+
:param SZA: solar zenith angle in degrees
|
|
46
|
+
:param Ta_K: air temperature in Kelvin
|
|
47
|
+
:param Ea_Pa: vapor pressure in Pascal
|
|
48
|
+
:param Rg: shortwave radiation in W/m2
|
|
49
|
+
:param wind_speed_mps: wind speed in meters per second
|
|
50
|
+
:param canopy_height_meters: canopy height in meters
|
|
51
|
+
:return:
|
|
52
|
+
Ps_Pa surface pressure in Pascal
|
|
53
|
+
VPD_Pa water vapor deficit in Pascal
|
|
54
|
+
RH relative humidity as a fraction
|
|
55
|
+
desTa 1st derivative of saturated vapor pressure
|
|
56
|
+
ddesTa 2nd derivative of saturated vapor pressure
|
|
57
|
+
gamma psychrometric constant in Pa K-1
|
|
58
|
+
Cp specific heat of air in J kg-1 K-1
|
|
59
|
+
rhoa air density in kg m-3
|
|
60
|
+
epsa all-sky emissivity
|
|
61
|
+
R
|
|
62
|
+
Rc
|
|
63
|
+
Rs
|
|
64
|
+
SFd
|
|
65
|
+
SFd2
|
|
66
|
+
DL
|
|
67
|
+
Ra
|
|
68
|
+
fStress
|
|
69
|
+
"""""
|
|
70
|
+
# Allen et al., 1998 (FAO)
|
|
71
|
+
|
|
72
|
+
# surface pressure
|
|
73
|
+
Ps_Pa = 101325.0 * (1.0 - 0.0065 * elevation_m / Ta_K) ** (9.807 / (0.0065 * 287.0)) # [Pa]
|
|
74
|
+
|
|
75
|
+
# air temperature in Celsius
|
|
76
|
+
Ta_C = Ta_K - 273.16 # [Celsius]
|
|
77
|
+
|
|
78
|
+
# dewpoint temperature in Celsius
|
|
79
|
+
# Td_C = Td_K - 273.16 # [Celsius]
|
|
80
|
+
|
|
81
|
+
# ambient vapour pressure
|
|
82
|
+
# Ea_Pa = 0.6108 * np.exp((17.27 * Td_C) / (Td_C + 237.3)) * 1000 # [Pa]
|
|
83
|
+
|
|
84
|
+
# saturated vapour pressure
|
|
85
|
+
SVP_Pa = 0.6108 * np.exp((17.27 * Ta_C) / (Ta_C + 237.3)) * 1000 # [Pa]
|
|
86
|
+
|
|
87
|
+
# water vapour deficit
|
|
88
|
+
VPD_Pa = np.clip(SVP_Pa - Ea_Pa, 0, None) # [Pa]
|
|
89
|
+
|
|
90
|
+
# relative humidity
|
|
91
|
+
RH = np.clip(Ea_Pa / SVP_Pa, 0, 1) # [-]
|
|
92
|
+
|
|
93
|
+
# 1st derivative of saturated vapour pressure
|
|
94
|
+
desTa = SVP_Pa * 4098.0 * pow((Ta_C + 237.3), (-2)) # [Pa K-1]
|
|
95
|
+
|
|
96
|
+
# 2nd derivative of saturated vapour pressure
|
|
97
|
+
ddesTa = 4098.0 * (desTa * pow((Ta_C + 237.3), (-2)) + (-2) * SVP_Pa * pow((Ta_C + 237.3), (-3))) # [Pa K-2]
|
|
98
|
+
|
|
99
|
+
# latent Heat of Vaporization
|
|
100
|
+
latent_heat = 2.501 - (2.361e-3 * Ta_C) # [J kg-1]
|
|
101
|
+
|
|
102
|
+
# psychrometric constant
|
|
103
|
+
gamma = 0.00163 * Ps_Pa / latent_heat # [Pa K-1]
|
|
104
|
+
|
|
105
|
+
# specific heat
|
|
106
|
+
# this formula for specific heat was generating extreme negative values that threw off the energy balance calculation
|
|
107
|
+
# Cp = 0.24 * 4185.5 * (1.0 + 0.8 * (0.622 * Ea_Pa / (Ps_Pa - Ea_Pa))) # [J kg-1 K-1]
|
|
108
|
+
|
|
109
|
+
# ratio molecular weight of water vapour dry air
|
|
110
|
+
mv_ma = 0.622 # [-] (Wiki)
|
|
111
|
+
|
|
112
|
+
# specific humidity
|
|
113
|
+
q = (mv_ma * Ea_Pa) / (Ps_Pa - 0.378 * Ea_Pa) # 3 [-] (Garratt, 1994)
|
|
114
|
+
|
|
115
|
+
# specific heat of dry air
|
|
116
|
+
Cpd = 1005 + (Ta_K - 250) ** 2 / 3364 # [J kg-1 K-1] (Garratt, 1994)
|
|
117
|
+
|
|
118
|
+
# specific heat of air
|
|
119
|
+
Cp = Cpd * (1 + 0.84 * q) # [J kg-1 K-1] (Garratt, 1994)
|
|
120
|
+
|
|
121
|
+
# virtual temperature
|
|
122
|
+
# Tv_K = Ta_K * 1.0 / (1 - 0.378 * Ea_Pa / Ps_Pa) # [K]
|
|
123
|
+
|
|
124
|
+
# air density
|
|
125
|
+
# rhoa = Ps_Pa / (287.0 * Tv_K) # [kg m-3]
|
|
126
|
+
|
|
127
|
+
# air density
|
|
128
|
+
rhoa = Ps_Pa / (287.05 * Ta_K) # [kg m-3] (Garratt, 1994)
|
|
129
|
+
|
|
130
|
+
# inverse relative distance Earth-Sun
|
|
131
|
+
dr = 1.0 + 0.033 * np.cos(2 * np.pi / 365.0 * day_of_year) # [-]
|
|
132
|
+
|
|
133
|
+
# solar declination
|
|
134
|
+
delta = 0.409 * np.sin(2 * np.pi / 365.0 * day_of_year - 1.39) # [rad]
|
|
135
|
+
|
|
136
|
+
# sunset hour angle
|
|
137
|
+
# Note: the value for arccos may be invalid (< -1.0 or > 1.0).
|
|
138
|
+
# This will result in NaN values in omegaS.
|
|
139
|
+
omegaS = np.arccos(-np.tan(latitude * np.pi / 180.0) * np.tan(delta)) # [rad]
|
|
140
|
+
|
|
141
|
+
# omegaS[np.logical_or(np.isnan(omegaS), np.isinf(omegaS))] = 0.0
|
|
142
|
+
omegaS = np.where(np.isnan(omegaS) | np.isinf(omegaS), 0, omegaS)
|
|
143
|
+
omegaS = np.real(omegaS)
|
|
144
|
+
|
|
145
|
+
# Day length
|
|
146
|
+
DL = 24.0 / np.pi * omegaS
|
|
147
|
+
|
|
148
|
+
# snapshot radiation
|
|
149
|
+
Ra = 1333.6 * dr * np.cos(SZA * np.pi / 180.0)
|
|
150
|
+
|
|
151
|
+
# Daily mean radiation
|
|
152
|
+
RaDaily = 1333.6 / np.pi * dr * (omegaS * np.sin(latitude * np.pi / 180.0) * np.sin(delta)
|
|
153
|
+
+ np.cos(latitude * np.pi / 180.0) * np.cos(delta) * np.sin(omegaS))
|
|
154
|
+
# clear-sky solar radiation
|
|
155
|
+
Rgo = (0.75 + 2e-5 * elevation_m) * Ra # [W m-2]
|
|
156
|
+
|
|
157
|
+
# Choi et al., 2008: The Crawford and Duchon’s cloudiness factor with Brunt equation is recommended.
|
|
158
|
+
|
|
159
|
+
# cloudy index
|
|
160
|
+
cloudy = 1.0 - Rg / Rgo # [-]
|
|
161
|
+
# cloudy[cloudy < 0] = 0
|
|
162
|
+
# cloudy[cloudy > 1] = 1
|
|
163
|
+
cloudy = np.clip(cloudy, 0, 1)
|
|
164
|
+
|
|
165
|
+
# clear-sky emissivity
|
|
166
|
+
epsa0 = 0.605 + 0.048 * (Ea_Pa / 100) ** 0.5 # [-]
|
|
167
|
+
|
|
168
|
+
# all-sky emissivity
|
|
169
|
+
epsa = epsa0 * (1 - cloudy) + cloudy # [-]
|
|
170
|
+
|
|
171
|
+
# Ryu et al. 2008 2012
|
|
172
|
+
|
|
173
|
+
# Upscaling factor
|
|
174
|
+
# non0msk = RaDaily != 0
|
|
175
|
+
# SFd = np.empty(np.shape(RaDaily))
|
|
176
|
+
# SFd[non0msk] = 1800.0 * Ra[non0msk] / (RaDaily[non0msk] * 3600 * 24)
|
|
177
|
+
# SFd[np.logical_not(non0msk)] = 1.0
|
|
178
|
+
SFd = np.where(RaDaily != 0, 1800.0 * Ra / (RaDaily * 3600 * 24), 1)
|
|
179
|
+
# SFd[SZA > 89.0] = 1.0
|
|
180
|
+
SFd = np.where(SZA > 89.0, 1, SFd)
|
|
181
|
+
# SFd[SFd > 1.0] = 1.0
|
|
182
|
+
SFd = np.clip(SFd, None, 1)
|
|
183
|
+
|
|
184
|
+
# bulk aerodynamic resistance
|
|
185
|
+
k = 0.4 # von Karman constant
|
|
186
|
+
z0 = np.clip(canopy_height_meters * 0.05, 0.05, None)
|
|
187
|
+
ustar = wind_speed_mps * k / (np.log(10.0 / z0)) # Stability item ignored
|
|
188
|
+
R = wind_speed_mps / (ustar * ustar) + 2.0 / (k * ustar) # Eq. (2-4) in Ryu et al 2008
|
|
189
|
+
R = np.clip(R, None, 1000)
|
|
190
|
+
Rs = 0.5 * R
|
|
191
|
+
Rc = R # was: Rc = 0.5 * R * 2
|
|
192
|
+
|
|
193
|
+
# Bisht et al., 2005
|
|
194
|
+
DL = DL - 1.5
|
|
195
|
+
|
|
196
|
+
# Time difference between overpass and midday
|
|
197
|
+
dT = np.abs(hour_of_day - 12.0)
|
|
198
|
+
|
|
199
|
+
# Upscaling factor for net radiation
|
|
200
|
+
SFd2 = 1.5 / (np.pi * np.sin((DL - 2.0 * dT) / (2.0 * DL) * np.pi)) * DL / 24.0
|
|
201
|
+
|
|
202
|
+
fStress = RH ** (VPD_Pa / 1000.0)
|
|
203
|
+
|
|
204
|
+
return Ps_Pa, VPD_Pa, RH, desTa, ddesTa, gamma, Cp, rhoa, epsa, R, Rc, Rs, SFd, SFd2, DL, Ra, fStress
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def soil_energy_balance(
|
|
5
|
+
Ts_K: np.ndarray,
|
|
6
|
+
Ta_K: np.ndarray,
|
|
7
|
+
G: np.ndarray,
|
|
8
|
+
VPD: np.ndarray,
|
|
9
|
+
RH: np.ndarray,
|
|
10
|
+
gamma: np.ndarray,
|
|
11
|
+
Cp: np.ndarray,
|
|
12
|
+
rhoa: np.ndarray,
|
|
13
|
+
desTa: np.ndarray,
|
|
14
|
+
Rs: np.ndarray,
|
|
15
|
+
ASW_soil: np.ndarray,
|
|
16
|
+
ALW_soil: np.ndarray,
|
|
17
|
+
Ls: np.ndarray,
|
|
18
|
+
epsa: np.ndarray):
|
|
19
|
+
# Net radiation
|
|
20
|
+
# Rn = Rnet - Rn_Sun - Rn_Sh
|
|
21
|
+
sigma = 5.670373e-8 # [W m-2 K-4] (Wiki)
|
|
22
|
+
Rn = np.clip(ASW_soil + ALW_soil - Ls - 4.0 * epsa * sigma * (Ta_K ** 3) * (Ts_K - Ta_K), 0, None)
|
|
23
|
+
# G = Rn * 0.35
|
|
24
|
+
|
|
25
|
+
# Latent heat
|
|
26
|
+
LE = desTa / (desTa + gamma) * (Rn - G) * (RH ** (VPD / 1000.0)) # (Ryu et al., 2011)
|
|
27
|
+
LE = np.clip(LE, 0, Rn)
|
|
28
|
+
# Sensible heat
|
|
29
|
+
H = np.clip(Rn - G - LE, 0, Rn)
|
|
30
|
+
|
|
31
|
+
# Update temperature
|
|
32
|
+
dT = np.clip(Rs / (rhoa * Cp) * H, -20, 20)
|
|
33
|
+
Ts_K = Ta_K + dT
|
|
34
|
+
|
|
35
|
+
return Rn, LE, Ts_K
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .vegetation_conversion import *
|