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.
Files changed (42) hide show
  1. pyVPRM/VPRM.py +1118 -0
  2. pyVPRM/__init__.py +1 -0
  3. pyVPRM/lib/__init__.py +0 -0
  4. pyVPRM/lib/downmodis.py +1012 -0
  5. pyVPRM/lib/fancy_plot.py +75 -0
  6. pyVPRM/lib/flux_tower_class.py +444 -0
  7. pyVPRM/lib/fluxnet_info/fluxnet_sites.pkl +0 -0
  8. pyVPRM/lib/fluxnet_info/site_infos.txt +218 -0
  9. pyVPRM/lib/functions.py +471 -0
  10. pyVPRM/meteorologies/__init__.py +0 -0
  11. pyVPRM/meteorologies/era5_class_dkrz.py +279 -0
  12. pyVPRM/meteorologies/era5_class_draft.py +60 -0
  13. pyVPRM/meteorologies/era5_monthly_xr.py +149 -0
  14. pyVPRM/meteorologies/met_base_class.py +67 -0
  15. pyVPRM/meteorologies/met_local_measurement.py +56 -0
  16. pyVPRM/sat_managers/__init__.py +0 -0
  17. pyVPRM/sat_managers/base_manager.py +430 -0
  18. pyVPRM/sat_managers/city.py +21 -0
  19. pyVPRM/sat_managers/copernicus.py +29 -0
  20. pyVPRM/sat_managers/esa_world_cover.py +21 -0
  21. pyVPRM/sat_managers/mapbiomas.py +35 -0
  22. pyVPRM/sat_managers/modis.py +266 -0
  23. pyVPRM/sat_managers/proba_v.py +86 -0
  24. pyVPRM/sat_managers/sentinel2.py +192 -0
  25. pyVPRM/sat_managers/synmap.py +21 -0
  26. pyVPRM/sat_managers/viirs.py +232 -0
  27. pyVPRM/sat_managers/viirs09ga.py +173 -0
  28. pyVPRM/vprm_configs/__init__.py +0 -0
  29. pyVPRM/vprm_configs/copernicus_land_cover.yaml +94 -0
  30. pyVPRM/vprm_configs/esa_world_cover.yaml +71 -0
  31. pyVPRM/vprm_configs/synmap.yaml +106 -0
  32. pyVPRM/vprm_models/__init__.py +1 -0
  33. pyVPRM/vprm_models/model_params/__init__.py +0 -0
  34. pyVPRM/vprm_models/vprm_base.py +691 -0
  35. pyVPRM/vprm_models/vprm_base_no_xeric.py +585 -0
  36. pyVPRM/vprm_models/vprm_modified.py +530 -0
  37. pyVPRM/vprm_models/vprm_nn.py +130 -0
  38. pyVPRM-3.0.dist-info/LICENSE +21 -0
  39. pyVPRM-3.0.dist-info/METADATA +40 -0
  40. pyVPRM-3.0.dist-info/RECORD +42 -0
  41. pyVPRM-3.0.dist-info/WHEEL +5 -0
  42. pyVPRM-3.0.dist-info/top_level.txt +1 -0
@@ -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