pyVPRM 3.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.
- pyVPRM/VPRM.py +1118 -0
- pyVPRM/__init__.py +1 -0
- pyVPRM/lib/__init__.py +0 -0
- pyVPRM/lib/downmodis.py +1012 -0
- pyVPRM/lib/fancy_plot.py +75 -0
- pyVPRM/lib/flux_tower_class.py +444 -0
- pyVPRM/lib/fluxnet_info/fluxnet_sites.pkl +0 -0
- pyVPRM/lib/fluxnet_info/site_infos.txt +218 -0
- pyVPRM/lib/functions.py +471 -0
- pyVPRM/meteorologies/__init__.py +0 -0
- pyVPRM/meteorologies/era5_class_dkrz.py +279 -0
- pyVPRM/meteorologies/era5_class_draft.py +60 -0
- pyVPRM/meteorologies/era5_monthly_xr.py +149 -0
- pyVPRM/meteorologies/met_base_class.py +67 -0
- pyVPRM/meteorologies/met_local_measurement.py +56 -0
- pyVPRM/sat_managers/__init__.py +0 -0
- pyVPRM/sat_managers/base_manager.py +430 -0
- pyVPRM/sat_managers/city.py +21 -0
- pyVPRM/sat_managers/copernicus.py +29 -0
- pyVPRM/sat_managers/esa_world_cover.py +21 -0
- pyVPRM/sat_managers/mapbiomas.py +35 -0
- pyVPRM/sat_managers/modis.py +266 -0
- pyVPRM/sat_managers/proba_v.py +86 -0
- pyVPRM/sat_managers/sentinel2.py +192 -0
- pyVPRM/sat_managers/synmap.py +21 -0
- pyVPRM/sat_managers/viirs.py +232 -0
- pyVPRM/sat_managers/viirs09ga.py +173 -0
- pyVPRM/vprm_configs/__init__.py +0 -0
- pyVPRM/vprm_configs/copernicus_land_cover.yaml +94 -0
- pyVPRM/vprm_configs/esa_world_cover.yaml +71 -0
- pyVPRM/vprm_configs/synmap.yaml +106 -0
- pyVPRM/vprm_models/__init__.py +1 -0
- pyVPRM/vprm_models/model_params/__init__.py +0 -0
- pyVPRM/vprm_models/vprm_base.py +691 -0
- pyVPRM/vprm_models/vprm_base_no_xeric.py +585 -0
- pyVPRM/vprm_models/vprm_modified.py +530 -0
- pyVPRM/vprm_models/vprm_nn.py +130 -0
- pyVPRM-3.0.dist-info/LICENSE +21 -0
- pyVPRM-3.0.dist-info/METADATA +40 -0
- pyVPRM-3.0.dist-info/RECORD +42 -0
- pyVPRM-3.0.dist-info/WHEEL +5 -0
- pyVPRM-3.0.dist-info/top_level.txt +1 -0
pyVPRM/lib/fancy_plot.py
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# /usr/bin/python
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
import matplotlib as mpl
|
|
5
|
+
import numpy as np
|
|
6
|
+
import scipy as sp
|
|
7
|
+
|
|
8
|
+
mpl.use("pdf")
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def figsize(scale, ratio=(np.sqrt(5.0) - 1.0) / 2.0):
|
|
12
|
+
fig_width_pt = 455.8843 # Get this from LaTeX using \the\textwidth
|
|
13
|
+
inches_per_pt = 1.0 / 72.27 # Convert pt to inch
|
|
14
|
+
fig_width = fig_width_pt * inches_per_pt * scale # width in inches
|
|
15
|
+
fig_height = fig_width * ratio # height in inches
|
|
16
|
+
fig_size = [fig_width, fig_height]
|
|
17
|
+
return fig_size
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
pgf_with_latex = { # setup matplotlib to use latex for output
|
|
21
|
+
# "pgf.texsystem": "pdflatex", # change this if using xetex or lautex
|
|
22
|
+
# "text.usetex": True, # use LaTeX to write all text
|
|
23
|
+
# "font.family": "serif",
|
|
24
|
+
# "font.serif": "Computer Modern", # blank entries should cause plots to inherit fonts from the document
|
|
25
|
+
# "font.sans-serif": [],
|
|
26
|
+
# "font.monospace": [],
|
|
27
|
+
"axes.labelsize": 10, # LaTeX default is 10pt font.
|
|
28
|
+
"legend.fontsize": 10, # Make the legend/label fonts a little smaller
|
|
29
|
+
"xtick.labelsize": 10,
|
|
30
|
+
"ytick.labelsize": 10,
|
|
31
|
+
"figure.figsize": figsize(0.9), # default fig size of 0.9 textwidth
|
|
32
|
+
"xtick.major.pad": 10.0,
|
|
33
|
+
"ytick.major.pad": 10.0,
|
|
34
|
+
"grid.alpha": 0.5,
|
|
35
|
+
"lines.linewidth": 1.0,
|
|
36
|
+
"figure.autolayout": True,
|
|
37
|
+
# "pgf.preamble": [
|
|
38
|
+
# r"\usepackage[utf8x]{inputenc}", # use utf8 fonts becasue your computer can handle it :)
|
|
39
|
+
# r"\usepackage[T1]{fontenc}", # plots will be generated using this preamble
|
|
40
|
+
# r"\usepackage[detect-all]{siunitx}"
|
|
41
|
+
# ]
|
|
42
|
+
}
|
|
43
|
+
mpl.rcParams.update(pgf_with_latex)
|
|
44
|
+
|
|
45
|
+
import matplotlib.pyplot as plt
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def newfig(width, ratio=(np.sqrt(5.0) - 1.0) / 2.0, **pargs):
|
|
49
|
+
fig = plt.figure(figsize=figsize(width, ratio))
|
|
50
|
+
plt.clf()
|
|
51
|
+
ax = fig.add_subplot(111, **pargs)
|
|
52
|
+
return fig, ax
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
colors = [
|
|
56
|
+
"#0065BD",
|
|
57
|
+
"#005293",
|
|
58
|
+
"#003359",
|
|
59
|
+
"#DAD7CB",
|
|
60
|
+
"#E37222",
|
|
61
|
+
"#A2AD00",
|
|
62
|
+
"#98C6EA",
|
|
63
|
+
"#64A0C8",
|
|
64
|
+
"#CCCCC6",
|
|
65
|
+
"#808080",
|
|
66
|
+
"#000000",
|
|
67
|
+
]
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def setNewEdges(edges):
|
|
71
|
+
newEdges = []
|
|
72
|
+
for i in range(0, len(edges) - 1):
|
|
73
|
+
newVal = (edges[i] + edges[i + 1]) * 1.0 / 2
|
|
74
|
+
newEdges.append(newVal)
|
|
75
|
+
return np.array(newEdges)
|
|
@@ -0,0 +1,444 @@
|
|
|
1
|
+
from pyproj import Proj
|
|
2
|
+
import pandas as pd
|
|
3
|
+
import pytz
|
|
4
|
+
from tzwhere import tzwhere
|
|
5
|
+
from dateutil import parser
|
|
6
|
+
import numpy as np
|
|
7
|
+
import os
|
|
8
|
+
from timezonefinder import TimezoneFinder
|
|
9
|
+
from datetime import datetime, timedelta
|
|
10
|
+
import pathlib
|
|
11
|
+
import glob
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class flux_tower_data:
|
|
15
|
+
# Class to store flux tower data in unique format
|
|
16
|
+
|
|
17
|
+
def __init__(self, t_start, t_stop, ssrd_key, t2m_key, site_name):
|
|
18
|
+
self.tstart = t_start
|
|
19
|
+
self.tstop = t_stop
|
|
20
|
+
self.t2m_key = t2m_key
|
|
21
|
+
self.ssrd_key = ssrd_key
|
|
22
|
+
self.len = None
|
|
23
|
+
self.site_dict = None
|
|
24
|
+
self.site_name = site_name
|
|
25
|
+
return
|
|
26
|
+
|
|
27
|
+
def set_land_type(self, lt):
|
|
28
|
+
self.land_cover_type = lt
|
|
29
|
+
return
|
|
30
|
+
|
|
31
|
+
def get_utcs(self):
|
|
32
|
+
return self.site_dict[list(self.site_dict.keys())[0]]["flux_data"][
|
|
33
|
+
"datetime_utc"
|
|
34
|
+
].values
|
|
35
|
+
|
|
36
|
+
def get_lonlat(self):
|
|
37
|
+
return (self.lon, self.lat)
|
|
38
|
+
|
|
39
|
+
def get_site_name(self):
|
|
40
|
+
return self.site_name
|
|
41
|
+
|
|
42
|
+
def get_data(self):
|
|
43
|
+
return self.flux_data
|
|
44
|
+
|
|
45
|
+
def get_len(self):
|
|
46
|
+
return len(self.flux_data)
|
|
47
|
+
|
|
48
|
+
def get_land_type(self):
|
|
49
|
+
return self.land_cover_type
|
|
50
|
+
|
|
51
|
+
def drop_rows_by_index(self, indices):
|
|
52
|
+
self.flux_data = self.flux_data.drop(indices)
|
|
53
|
+
|
|
54
|
+
def add_columns(self, add_dict):
|
|
55
|
+
for i in add_dict.keys():
|
|
56
|
+
self.flux_data[i] = add_dict[i]
|
|
57
|
+
return
|
|
58
|
+
|
|
59
|
+
def cut_to_timewindow(self, tstart, tstop, key="datetime_utc"):
|
|
60
|
+
mask = (self.flux_data[key] >= tstart) & (self.flux_data[key] <= tstop)
|
|
61
|
+
self.flux_data = self.flux_data[mask]
|
|
62
|
+
return
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
class brazil_flux_data(flux_tower_data):
|
|
66
|
+
# https://daac.ornl.gov/cgi-bin/dsviewer.pl?ds_id=1842
|
|
67
|
+
|
|
68
|
+
def __init__(
|
|
69
|
+
self,
|
|
70
|
+
data_path,
|
|
71
|
+
ssrd_key=None,
|
|
72
|
+
t2m_key=None,
|
|
73
|
+
use_vars=None,
|
|
74
|
+
t_start=None,
|
|
75
|
+
t_stop=None,
|
|
76
|
+
):
|
|
77
|
+
|
|
78
|
+
site_name = data_path.split("/")[-1].split("_")[0]
|
|
79
|
+
self.data_path = data_path
|
|
80
|
+
|
|
81
|
+
super().__init__(t_start, t_stop, ssrd_key, t2m_key, site_name)
|
|
82
|
+
|
|
83
|
+
if use_vars is None:
|
|
84
|
+
self.vars = variables = [
|
|
85
|
+
"Year_LBAMIP",
|
|
86
|
+
"DoY_LBAMIP",
|
|
87
|
+
"Hour_LBAMIP",
|
|
88
|
+
"NEE",
|
|
89
|
+
"NEEf",
|
|
90
|
+
"par",
|
|
91
|
+
"mrs",
|
|
92
|
+
"sco2",
|
|
93
|
+
"GEP_model",
|
|
94
|
+
"NEE_model",
|
|
95
|
+
"Re_model",
|
|
96
|
+
"Tair_LBAMIP",
|
|
97
|
+
"Qair_LBAMIP",
|
|
98
|
+
"SWdown_LBAMIP",
|
|
99
|
+
"Wind_LBAMIP",
|
|
100
|
+
"GF_Tair_LBAMIP",
|
|
101
|
+
"tsoil1",
|
|
102
|
+
"tsoil2",
|
|
103
|
+
"par_fill",
|
|
104
|
+
"ust",
|
|
105
|
+
]
|
|
106
|
+
if use_vars is "all":
|
|
107
|
+
self.vars = "all"
|
|
108
|
+
site_info_dict = dict()
|
|
109
|
+
site_info_dict["K67"] = dict(lat=-2.857, lon=-54.959, veg_class="EF")
|
|
110
|
+
site_info_dict["K77"] = dict(lat=-3.0202, lon=-54.8885, veg_class="CRO")
|
|
111
|
+
site_info_dict["K83"] = dict(lat=-3.017, lon=-54.9707, veg_class="EF")
|
|
112
|
+
site_info_dict["K34"] = dict(lat=-2.6091, lon=-60.2093, veg_class="EF")
|
|
113
|
+
site_info_dict["CAX"] = dict(lat=-1.7483, lon=-51.4536, veg_class="EF")
|
|
114
|
+
site_info_dict["FNS"] = dict(lat=-10.7618, lon=-62.3572, veg_class="GRA")
|
|
115
|
+
site_info_dict["RJA"] = dict(lat=-10.078, lon=-61.9331, veg_class="EF")
|
|
116
|
+
site_info_dict["BAN"] = dict(
|
|
117
|
+
lat=-9.824416667, lon=-50.1591111, veg_class="EF"
|
|
118
|
+
) # transitional forest
|
|
119
|
+
site_info_dict["PDG"] = dict(lat=-21.61947222, lon=-47.6498889, veg_class="SH")
|
|
120
|
+
self.lat = site_info_dict[site_name]["lat"]
|
|
121
|
+
self.lon = site_info_dict[site_name]["lon"]
|
|
122
|
+
|
|
123
|
+
def add_tower_data(self):
|
|
124
|
+
if self.vars == "all":
|
|
125
|
+
idata = pd.read_csv(self.data_path, delim_whitespace=True, skiprows=[1])
|
|
126
|
+
else:
|
|
127
|
+
idata = pd.read_csv(
|
|
128
|
+
self.data_path,
|
|
129
|
+
usecols=lambda x: x in self.vars,
|
|
130
|
+
delim_whitespace=True,
|
|
131
|
+
skiprows=[1],
|
|
132
|
+
)
|
|
133
|
+
idata.rename({self.ssrd_key: "ssrd", self.t2m_key: "t2m"}, inplace=True, axis=1)
|
|
134
|
+
tf = TimezoneFinder()
|
|
135
|
+
timezone_str = tf.timezone_at(lng=self.lon, lat=self.lat)
|
|
136
|
+
# tzw = tzwhere.tzwhere()
|
|
137
|
+
# timezone_str = tzw.tzNameAt(self.lat, self.lon)
|
|
138
|
+
timezone = pytz.timezone(timezone_str)
|
|
139
|
+
dt = parser.parse(
|
|
140
|
+
"200001010000"
|
|
141
|
+
) # pick a date that is definitely standard time and not DST
|
|
142
|
+
datetime_u = []
|
|
143
|
+
for i, row in idata.iterrows():
|
|
144
|
+
datetime_u.append(
|
|
145
|
+
datetime(int(row["Year_LBAMIP"]), 1, 1)
|
|
146
|
+
+ timedelta(row["DoY_LBAMIP"] - 1)
|
|
147
|
+
+ timedelta(hours=row["Hour_LBAMIP"])
|
|
148
|
+
- timezone.utcoffset(dt)
|
|
149
|
+
)
|
|
150
|
+
datetime_u = np.array(datetime_u)
|
|
151
|
+
idata["datetime_utc"] = datetime_u
|
|
152
|
+
if (self.tstart is not None) & (self.tstop is not None):
|
|
153
|
+
mask = (datetime_u >= self.tstart) & (datetime_u <= self.tstop)
|
|
154
|
+
flux_data = idata[mask]
|
|
155
|
+
else:
|
|
156
|
+
flux_data = idata
|
|
157
|
+
this_len = len(flux_data)
|
|
158
|
+
if this_len < 2:
|
|
159
|
+
print("No data for {} in given time range".format(self.site_name))
|
|
160
|
+
years = np.unique([t.year for t in datetime_u])
|
|
161
|
+
print("Data only available for the following years {}".format(years))
|
|
162
|
+
return False
|
|
163
|
+
else:
|
|
164
|
+
self.flux_data = flux_data
|
|
165
|
+
if self.t2m_key is not None:
|
|
166
|
+
self.flux_data["t2m"] = self.flux_data["t2m"] - 273.15
|
|
167
|
+
return True
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
class ameri_fluxnet(flux_tower_data):
|
|
171
|
+
|
|
172
|
+
def __init__(
|
|
173
|
+
self,
|
|
174
|
+
data_path,
|
|
175
|
+
ssrd_key=None,
|
|
176
|
+
t2m_key=None,
|
|
177
|
+
use_vars=None,
|
|
178
|
+
t_start=None,
|
|
179
|
+
t_stop=None,
|
|
180
|
+
):
|
|
181
|
+
|
|
182
|
+
site_name = (
|
|
183
|
+
glob.glob(os.path.join(data_path, "*.csv"))[0]
|
|
184
|
+
.split("/")[-1]
|
|
185
|
+
.split("AMF_")[1]
|
|
186
|
+
.split("_")[0]
|
|
187
|
+
)
|
|
188
|
+
self.data_path = data_path
|
|
189
|
+
|
|
190
|
+
super().__init__(t_start, t_stop, ssrd_key, t2m_key, site_name)
|
|
191
|
+
if (use_vars is None) | (use_vars is "all"):
|
|
192
|
+
self.vars = "all"
|
|
193
|
+
else:
|
|
194
|
+
self.vars = use_vars
|
|
195
|
+
idat_info = pd.read_excel(glob.glob(os.path.join(self.data_path, "*.xlsx"))[0])
|
|
196
|
+
self.lat = float(
|
|
197
|
+
idat_info[idat_info["VARIABLE"] == "LOCATION_LAT"]["DATAVALUE"]
|
|
198
|
+
)
|
|
199
|
+
self.lon = float(
|
|
200
|
+
idat_info[idat_info["VARIABLE"] == "LOCATION_LONG"]["DATAVALUE"]
|
|
201
|
+
)
|
|
202
|
+
self.land_cover_type = str(
|
|
203
|
+
idat_info.loc[idat_info["VARIABLE"] == "IGBP"]["DATAVALUE"]
|
|
204
|
+
)
|
|
205
|
+
return
|
|
206
|
+
|
|
207
|
+
def add_tower_data(self):
|
|
208
|
+
if self.vars is "all":
|
|
209
|
+
idata = pd.read_csv(
|
|
210
|
+
glob.glob(os.path.join(self.data_path, "*.csv"))[0], skiprows=2
|
|
211
|
+
)
|
|
212
|
+
else:
|
|
213
|
+
idata = pd.read_csv(
|
|
214
|
+
glob.glob(os.path.join(self.data_path, "*.csv"))[0],
|
|
215
|
+
skiprows=2,
|
|
216
|
+
usecols=lambda x: x in self.vars,
|
|
217
|
+
)
|
|
218
|
+
idata.rename({self.ssrd_key: "ssrd", self.t2m_key: "t2m"}, inplace=True, axis=1)
|
|
219
|
+
tf = TimezoneFinder()
|
|
220
|
+
timezone_str = tf.timezone_at(lng=self.lon, lat=self.lat)
|
|
221
|
+
# tzw = tzwhere.tzwhere()
|
|
222
|
+
# timezone_str = tzw.tzNameAt(self.lat, self.lon)
|
|
223
|
+
timezone = pytz.timezone(timezone_str)
|
|
224
|
+
dt = parser.parse(
|
|
225
|
+
"200001010000"
|
|
226
|
+
) # pick a date that is definitely standard time and not DST
|
|
227
|
+
datetime_u = []
|
|
228
|
+
for i, row in idata.iterrows():
|
|
229
|
+
datetime_u.append(
|
|
230
|
+
parser.parse(str(int(row["TIMESTAMP_END"]))) - timezone.utcoffset(dt)
|
|
231
|
+
)
|
|
232
|
+
datetime_u = np.array(datetime_u)
|
|
233
|
+
idata["datetime_utc"] = datetime_u
|
|
234
|
+
if (self.tstart is not None) & (self.tstop is not None):
|
|
235
|
+
mask = (datetime_u >= self.tstart) & (datetime_u <= self.tstop)
|
|
236
|
+
flux_data = idata[mask]
|
|
237
|
+
else:
|
|
238
|
+
flux_data = idata
|
|
239
|
+
this_len = len(flux_data)
|
|
240
|
+
if this_len < 2:
|
|
241
|
+
print("No data for {} in given time range".format(self.site_name))
|
|
242
|
+
years = np.unique([t.year for t in datetime_u])
|
|
243
|
+
print("Data only available for the following years {}".format(years))
|
|
244
|
+
return False
|
|
245
|
+
else:
|
|
246
|
+
self.flux_data = flux_data
|
|
247
|
+
return True
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
class fluxnet(flux_tower_data):
|
|
251
|
+
|
|
252
|
+
def __init__(
|
|
253
|
+
self,
|
|
254
|
+
data_path,
|
|
255
|
+
ssrd_key=None,
|
|
256
|
+
t2m_key=None,
|
|
257
|
+
use_vars=None,
|
|
258
|
+
t_start=None,
|
|
259
|
+
t_stop=None,
|
|
260
|
+
):
|
|
261
|
+
|
|
262
|
+
site_name = data_path.split("FLX_")[1].split("_")[0]
|
|
263
|
+
self.data_path = data_path
|
|
264
|
+
|
|
265
|
+
super().__init__(t_start, t_stop, ssrd_key, t2m_key, site_name)
|
|
266
|
+
|
|
267
|
+
if use_vars is None:
|
|
268
|
+
self.vars = [
|
|
269
|
+
"NEE_CUT_REF",
|
|
270
|
+
"NEE_VUT_REF",
|
|
271
|
+
"NEE_CUT_REF_QC",
|
|
272
|
+
"NEE_VUT_REF_QC",
|
|
273
|
+
"GPP_NT_VUT_REF",
|
|
274
|
+
"GPP_NT_CUT_REF",
|
|
275
|
+
"GPP_DT_VUT_REF",
|
|
276
|
+
"GPP_DT_CUT_REF",
|
|
277
|
+
"TIMESTAMP_START",
|
|
278
|
+
"TIMESTAMP_END",
|
|
279
|
+
"WD",
|
|
280
|
+
"WS",
|
|
281
|
+
"SW_IN_F",
|
|
282
|
+
"TA_F",
|
|
283
|
+
"USTAR",
|
|
284
|
+
"RECO_NT_VUT_REF",
|
|
285
|
+
"RECO_DT_VUT_REF",
|
|
286
|
+
"TA_F_QC",
|
|
287
|
+
"SW_IN_F_QC",
|
|
288
|
+
]
|
|
289
|
+
elif use_vars is "all":
|
|
290
|
+
self.vars = "all"
|
|
291
|
+
else:
|
|
292
|
+
self.vars = use_vars
|
|
293
|
+
|
|
294
|
+
site_info = pd.read_pickle(
|
|
295
|
+
os.path.join(
|
|
296
|
+
pathlib.Path(__file__).parent.resolve(),
|
|
297
|
+
"fluxnet_info",
|
|
298
|
+
"fluxnet_sites.pkl",
|
|
299
|
+
)
|
|
300
|
+
)
|
|
301
|
+
self.lat = site_info.loc[site_info["SITE_ID"] == site_name]["lat"].values
|
|
302
|
+
self.lon = site_info.loc[site_info["SITE_ID"] == site_name]["long"].values
|
|
303
|
+
self.land_cover_type = site_info.loc[site_info["SITE_ID"] == site_name][
|
|
304
|
+
"IGBP"
|
|
305
|
+
].values
|
|
306
|
+
return
|
|
307
|
+
|
|
308
|
+
def add_tower_data(self):
|
|
309
|
+
if self.vars == "all":
|
|
310
|
+
idata = pd.read_csv(self.data_path)
|
|
311
|
+
else:
|
|
312
|
+
idata = pd.read_csv(self.data_path, usecols=lambda x: x in self.vars)
|
|
313
|
+
idata.rename({self.ssrd_key: "ssrd", self.t2m_key: "t2m"}, inplace=True, axis=1)
|
|
314
|
+
tf = TimezoneFinder()
|
|
315
|
+
timezone_str = tf.timezone_at(lng=self.lon, lat=self.lat)
|
|
316
|
+
# tzw = tzwhere.tzwhere()
|
|
317
|
+
# timezone_str = tzw.tzNameAt(self.lat, self.lon)
|
|
318
|
+
timezone = pytz.timezone(timezone_str)
|
|
319
|
+
dt = parser.parse(
|
|
320
|
+
"200001010000"
|
|
321
|
+
) # pick a date that is definitely standard time and not DST
|
|
322
|
+
datetime_u = []
|
|
323
|
+
for i, row in idata.iterrows():
|
|
324
|
+
datetime_u.append(
|
|
325
|
+
parser.parse(str(int(row["TIMESTAMP_END"]))) - timezone.utcoffset(dt)
|
|
326
|
+
)
|
|
327
|
+
datetime_u = np.array(datetime_u)
|
|
328
|
+
idata["datetime_utc"] = datetime_u
|
|
329
|
+
if (self.tstart is not None) & (self.tstop is not None):
|
|
330
|
+
mask = (datetime_u >= self.tstart) & (datetime_u <= self.tstop)
|
|
331
|
+
flux_data = idata[mask]
|
|
332
|
+
else:
|
|
333
|
+
flux_data = idata
|
|
334
|
+
this_len = len(flux_data)
|
|
335
|
+
if this_len < 2:
|
|
336
|
+
print("No data for {} in given time range".format(self.site_name))
|
|
337
|
+
years = np.unique([t.year for t in datetime_u])
|
|
338
|
+
print("Data only available for the following years {}".format(years))
|
|
339
|
+
return False
|
|
340
|
+
else:
|
|
341
|
+
self.flux_data = flux_data
|
|
342
|
+
return True
|
|
343
|
+
|
|
344
|
+
|
|
345
|
+
class icos(flux_tower_data):
|
|
346
|
+
def __init__(
|
|
347
|
+
self,
|
|
348
|
+
data_path,
|
|
349
|
+
ssrd_key=None,
|
|
350
|
+
t2m_key=None,
|
|
351
|
+
use_vars=None,
|
|
352
|
+
t_start=None,
|
|
353
|
+
t_stop=None,
|
|
354
|
+
):
|
|
355
|
+
|
|
356
|
+
self.data_path = data_path
|
|
357
|
+
site_name = data_path.split("ICOSETC_")[1].split("_")[0]
|
|
358
|
+
|
|
359
|
+
super().__init__(t_start, t_stop, ssrd_key, t2m_key, site_name)
|
|
360
|
+
|
|
361
|
+
if use_vars is None:
|
|
362
|
+
self.vars = variables = [
|
|
363
|
+
"NEE_CUT_REF",
|
|
364
|
+
"NEE_VUT_REF",
|
|
365
|
+
"NEE_CUT_REF_QC",
|
|
366
|
+
"NEE_VUT_REF_QC",
|
|
367
|
+
"GPP_NT_VUT_REF",
|
|
368
|
+
"GPP_NT_CUT_REF",
|
|
369
|
+
"GPP_DT_VUT_REF",
|
|
370
|
+
"GPP_DT_CUT_REF",
|
|
371
|
+
"TIMESTAMP_START",
|
|
372
|
+
"TIMESTAMP_END",
|
|
373
|
+
"WD",
|
|
374
|
+
"WS",
|
|
375
|
+
"SW_IN_F",
|
|
376
|
+
"TA_F",
|
|
377
|
+
"USTAR",
|
|
378
|
+
"RECO_NT_VUT_REF",
|
|
379
|
+
"RECO_DT_VUT_REF",
|
|
380
|
+
"TA_F_QC",
|
|
381
|
+
"SW_IN_F_QC",
|
|
382
|
+
]
|
|
383
|
+
elif use_vars is "all":
|
|
384
|
+
self.vars = "all"
|
|
385
|
+
else:
|
|
386
|
+
self.vars = use_vars
|
|
387
|
+
|
|
388
|
+
site_info = pd.read_csv(
|
|
389
|
+
os.path.join(
|
|
390
|
+
os.path.dirname(self.data_path),
|
|
391
|
+
"ICOSETC_{}_SITEINFO_L2.csv".format(self.site_name),
|
|
392
|
+
),
|
|
393
|
+
on_bad_lines="skip",
|
|
394
|
+
)
|
|
395
|
+
self.land_cover_type = site_info.loc[site_info["VARIABLE"] == "IGBP"][
|
|
396
|
+
"DATAVALUE"
|
|
397
|
+
].values[0]
|
|
398
|
+
self.lat = float(
|
|
399
|
+
site_info.loc[site_info["VARIABLE"] == "LOCATION_LAT"]["DATAVALUE"].values
|
|
400
|
+
)
|
|
401
|
+
self.lon = float(
|
|
402
|
+
site_info.loc[site_info["VARIABLE"] == "LOCATION_LONG"]["DATAVALUE"].values
|
|
403
|
+
)
|
|
404
|
+
|
|
405
|
+
return
|
|
406
|
+
|
|
407
|
+
def add_tower_data(self):
|
|
408
|
+
if self.vars is "all":
|
|
409
|
+
idata = pd.read_csv(self.data_path, on_bad_lines="skip")
|
|
410
|
+
else:
|
|
411
|
+
idata = pd.read_csv(
|
|
412
|
+
self.data_path, usecols=lambda x: x in self.vars, on_bad_lines="skip"
|
|
413
|
+
)
|
|
414
|
+
idata.rename({self.ssrd_key: "ssrd", self.t2m_key: "t2m"}, inplace=True, axis=1)
|
|
415
|
+
tf = TimezoneFinder()
|
|
416
|
+
timezone_str = tf.timezone_at(lng=self.lon, lat=self.lat)
|
|
417
|
+
# tzw = tzwhere.tzwhere()
|
|
418
|
+
# timezone_str = tzw.tzNameAt(self.lat, self.lon)
|
|
419
|
+
timezone = pytz.timezone(timezone_str)
|
|
420
|
+
dt = parser.parse(
|
|
421
|
+
"200001010000"
|
|
422
|
+
) # pick a date that is definitely standard time and not DST
|
|
423
|
+
datetime_u = []
|
|
424
|
+
for i, row in idata.iterrows():
|
|
425
|
+
datetime_u.append(
|
|
426
|
+
parser.parse(str(int(row["TIMESTAMP_END"]))) - timezone.utcoffset(dt)
|
|
427
|
+
)
|
|
428
|
+
datetime_u = np.array(datetime_u)
|
|
429
|
+
idata["datetime_utc"] = datetime_u
|
|
430
|
+
if (self.tstart is not None) & (self.tstop is not None):
|
|
431
|
+
mask = (datetime_u >= self.tstart) & (datetime_u <= self.tstop)
|
|
432
|
+
flux_data = idata[mask]
|
|
433
|
+
else:
|
|
434
|
+
flux_data = idata
|
|
435
|
+
this_len = len(flux_data)
|
|
436
|
+
|
|
437
|
+
if this_len < 2:
|
|
438
|
+
print("No data for {} in given time range".format(self.site_name))
|
|
439
|
+
years = np.unique([t.year for t in datetime_u])
|
|
440
|
+
print("Data only available for the following years {}".format(years))
|
|
441
|
+
return False
|
|
442
|
+
else:
|
|
443
|
+
self.flux_data = flux_data
|
|
444
|
+
return True
|
|
Binary file
|