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,279 @@
1
+ import xarray as xr
2
+ import glob
3
+ import os
4
+ import time
5
+ import numpy as np
6
+ from dateutil import parser
7
+ from scipy.interpolate import interp2d
8
+ import pygrib
9
+ import copy
10
+ import uuid
11
+ import datetime
12
+ from pyVPRM.meteorologies.met_base_class import met_data_handler_base
13
+ from loguru import logger
14
+
15
+ map_function = lambda lon: (lon - 360) if (lon > 180) else lon
16
+
17
+ bpaths = {
18
+ "sf00": "/pool/data/ERA5/E*/sf/an/{}",
19
+ "sf12": "/pool/data/ERA5/E*/sf/fc/{}",
20
+ "pl00": "/pool/data/ERA5/E*/pl/an/{}",
21
+ "ml00": "/pool/data/ERA5/E*/ml/an/{}",
22
+ }
23
+ # Check documentation under
24
+ # https://confluence.ecmwf.int/display/CKB/ERA5%3A+data+documentation#ERA5:datadocumentation-Spatialgrid
25
+
26
+ keys_dict = {
27
+ "ssrd": [169, "sf12"], # surface solar radiation downwards(J/m**2)
28
+ "t2m": [167, "sf00"], # temperature 2 m
29
+ # 'slt': [43, 'sf00'], #soil type, not sure it's useful...MODIS should do better
30
+ "sp": [134, "sf00"], # surface pressure
31
+ "tcc": [164, "sf00"], # total cloud cover
32
+ "stl1": [139, "sf00"], # soil temperature level1
33
+ "stl2": [170, "sf00"], # soil temperature level2
34
+ "stl3": [183, "sf00"], # soil temperature level3
35
+ "swvl1": [39, "sf00"], # soil water level 1
36
+ "swvl2": [40, "sf00"], # soil water level 2
37
+ "swvl3": [41, "sf00"], # soil water level 3
38
+ "swvl4": [42, "sf00"], # soil water level 3
39
+ "2d": [168, "sf00"], # 2-m dewpoint temperature
40
+ "tp": [228, "sf12"], # total precipitation over given time
41
+ # 'ssr': [176, 'sf12'], #net surface solar radiation (J/m**2)
42
+ # 'str': [177, 'sf12'],#net surface thermal radiation (J/m**2)
43
+ "src": [198, "sf00"],
44
+ "q": [133, "ml00"], # specific humidity (%)
45
+ "e": [182, "sf12"],
46
+ "sst": [34, "sf00"],
47
+ }
48
+
49
+
50
+ class met_data_handler(met_data_handler_base):
51
+ """
52
+ Class for using ERA5 data available on Levante's DKRZ cluster.
53
+ """
54
+
55
+ def __init__(self, year, month, day=None, hour=None, keys=[], timesteps="hourly"):
56
+ super().__init__()
57
+ if timesteps == "hourly":
58
+ self.add_time_str = "1H"
59
+ elif timesteps == "daily":
60
+ self.add_time_str = "1D"
61
+ elif timesteps == "monthly":
62
+ self.add_time_str = "1M"
63
+ self.file_handlers = dict()
64
+ self.in_era5_grid = True
65
+ self.regridder = None
66
+ self.ds_in_t = None
67
+ self.reg_lats = []
68
+ self.reg_lons = []
69
+ if len(keys) == 0:
70
+ self.keys = keys_dict.keys()
71
+ else:
72
+ self.keys = keys
73
+ self.change_date(year, month, day, hour)
74
+
75
+ def _init_data_for_day(self):
76
+ file_dict = dict()
77
+ for c, key in enumerate(self.keys):
78
+ t_dict = dict()
79
+ bpath = bpaths[keys_dict[key][1]].format(self.add_time_str)
80
+ e_id = keys_dict[key][0]
81
+ if self.add_time_str == "1H":
82
+ fname = os.path.join(
83
+ bpath,
84
+ "{:03d}/E*{}_1H_{}-{:02d}-{:02d}_{:03d}.grb".format(
85
+ e_id, keys_dict[key][1], self.year, self.month, self.day, e_id
86
+ ),
87
+ )
88
+ elif self.add_time_str == "1D":
89
+ fname = os.path.join(
90
+ bpath,
91
+ "{:03d}/E*{}_1D_{}-{:02d}_{:03d}.grb".format(
92
+ e_id, keys_dict[key][1], self.year, self.month, e_id
93
+ ),
94
+ )
95
+ elif self.add_time_str == "1M":
96
+ fname = os.path.join(
97
+ bpath,
98
+ "{:03d}/E*{}_1M_{}_{:03d}.grb".format(
99
+ e_id, keys_dict[key][1], self.year, e_id
100
+ ),
101
+ )
102
+ fname = glob.glob(fname)
103
+ fname = [i for i in fname if "EL" not in i]
104
+ if key in self.file_handlers.keys():
105
+ self.file_handlers[key]["current"].close()
106
+ t_dict["current"] = pygrib.open(fname[0])
107
+ t_dict["current_name"] = list(fname)
108
+ t_dict["current_ind"] = 0
109
+ t_dict["type"] = keys_dict[key][1]
110
+ self.file_handlers[key] = t_dict
111
+ if not "sf" in keys_dict[key][1]: # Not a surface value
112
+ self.select_from_pressure_levels(key)
113
+ if self.ds_in_t is None:
114
+ lats, lons = t_dict["current"][1].latlons()
115
+ self.ds_in_t = xr.Dataset(
116
+ {
117
+ "lat": (["lat"], lats[:, 0], {"units": "degrees_north"}),
118
+ "lon": (
119
+ ["lon"],
120
+ [map_function(i) for i in lons[0]],
121
+ {"units": "degrees_east"},
122
+ ),
123
+ }
124
+ )
125
+ self.ds_in_t = self.ds_in_t.set_coords(["lon", "lat"])
126
+
127
+ def _load_data_for_hour(self):
128
+ # Caution: The date as argument corresponds to the END of the ERA5 integration time.
129
+ data_dict = dict()
130
+ if self.add_time_str == "1H":
131
+ for key in self.keys:
132
+ data_dict[key] = (
133
+ ["lat", "lon"],
134
+ self.file_handlers[key]["current"][int(self.hour + 1)].values,
135
+ )
136
+
137
+ elif self.add_time_str == "1D":
138
+ for key in self.keys:
139
+ data_dict[key] = (
140
+ ["lat", "lon"],
141
+ self.file_handlers[key]["current"][int(self.day)].values,
142
+ )
143
+
144
+ elif self.add_time_str == "1M":
145
+ for key in self.keys:
146
+ if self.month not in [
147
+ self.file_handlers[key]["current"][t + 1].month
148
+ for t in range(self.file_handlers[key]["current"].messages)
149
+ ]:
150
+ for i in self.file_handlers[key]["current_name"]:
151
+ tmp = pygrib.open(i)
152
+ if self.month in [
153
+ tmp[t + 1].month for t in range(tmp.messages)
154
+ ]:
155
+ self.file_handlers[key]["current"] = tmp
156
+ break
157
+
158
+ if self.month not in [
159
+ self.file_handlers[key]["current"][t + 1].month
160
+ for t in range(self.file_handlers[key]["current"].messages)
161
+ ]:
162
+ logger.info("No data for given month")
163
+ return
164
+
165
+ for c in range(self.file_handlers[key]["current"].messages):
166
+ if self.file_handlers[key]["current"][c + 1].month == self.month:
167
+ break
168
+ data_dict[key] = (
169
+ ["lat", "lon"],
170
+ self.file_handlers[key]["current"][c + 1].values,
171
+ )
172
+
173
+ self.ds_out = copy.deepcopy(self.ds_in_t)
174
+ self.ds_out = self.ds_out.assign(data_dict)
175
+ self.ds_out = self.ds_out.sortby("lon")
176
+ self.in_era5_grid = True
177
+
178
+ def get_all_interpolators(self, day, hour):
179
+ ret_dict = dict()
180
+ for key in self.keys:
181
+ ret_dict[key] = self.get_interpolator()
182
+ return ret_dict
183
+
184
+ def regrid(
185
+ self,
186
+ lats=None,
187
+ lons=None,
188
+ dataset=None,
189
+ n_cpus=1,
190
+ weights=None,
191
+ overwrite_regridder=False,
192
+ ):
193
+
194
+ import xesmf as xe
195
+
196
+ if self.in_era5_grid is False:
197
+ return
198
+
199
+ if (self.regridder is None) | (overwrite_regridder):
200
+ if (lats is not None) and (lons is not None):
201
+ t_ds_out = xr.Dataset(
202
+ {
203
+ "lat": (["lat"], lats, {"units": "degrees_north"}),
204
+ "lon": (["lon"], lons, {"units": "degrees_east"}),
205
+ }
206
+ )
207
+ t_ds_out = t_ds_out.set_coords(["lon", "lat"])
208
+ self.reg_lats = lats
209
+ self.reg_lons = lons
210
+ else:
211
+ t_ds_out = dataset
212
+
213
+ if (weights is not None) & os.path.exists(str(weights)):
214
+ logger.info("Load weights from {}".format(weights))
215
+ else:
216
+ bfolder = os.path.dirname(weights)
217
+ src_temp_path = os.path.join(bfolder, "{}.nc".format(str(uuid.uuid4())))
218
+ dest_temp_path = os.path.join(
219
+ bfolder, "{}.nc".format(str(uuid.uuid4()))
220
+ )
221
+ self.ds_out.to_netcdf(src_temp_path)
222
+ t_ds_out.to_netcdf(dest_temp_path)
223
+ cmd = "mpirun -np {} ESMF_RegridWeightGen --source {} --destination {} --weight {} -m bilinear --64bit_offset --extrap_method nearestd --no_log".format(
224
+ n_cpus, src_temp_path, dest_temp_path, weights
225
+ )
226
+ logger.info(cmd)
227
+ os.system(cmd)
228
+ os.remove(src_temp_path)
229
+ os.remove(dest_temp_path)
230
+
231
+ self.regridder = xe.Regridder(
232
+ self.ds_in_t, t_ds_out, "bilinear", weights=weights, reuse_weights=True
233
+ )
234
+ self.ds_out = self.regridder(self.ds_out)
235
+ self.in_era5_grid = False
236
+ return
237
+
238
+ def select_from_pressure_levels(self, key):
239
+ selection_args = {}
240
+ if key == "r":
241
+ selection_args["level"] = 975
242
+ selection_args["typeOfLevel"] = "isobaricInhPa"
243
+ elif key == "q":
244
+ selection_args["level"] = 137
245
+ selection_args["typeOfLevel"] = "hybrid"
246
+ try:
247
+ self.file_handlers[key]["current"] = self.file_handlers[key][
248
+ "current"
249
+ ].select(**selection_args)
250
+ except Exception as e:
251
+ logger.info("No era5 data found for {}".format(selection_args))
252
+ return None
253
+
254
+ def get_data(self, lonlat=None, key=None):
255
+ if key is not None:
256
+ tmp = self.ds_out[key]
257
+ else:
258
+ tmp = self.ds_out
259
+ if lonlat is None:
260
+ return tmp
261
+ else:
262
+ lon = lonlat[0]
263
+ if isinstance(lon, list) | isinstance(lon, np.ndarray):
264
+ return tmp.interp(lon=("z", lon), lat=("z", lonlat[1]), method="linear")
265
+ else:
266
+ lon = lonlat[0]
267
+ return tmp.interp(lon=lon, lat=lonlat[1])
268
+
269
+
270
+ if __name__ == "__main__":
271
+ year = "2000"
272
+ month = 2
273
+ day = 20
274
+ hour = 5 # UTC hour
275
+ position = {"lat": 50.30493, "long": 5.99812}
276
+ era5_handler = met_data_handler(year, month, day)
277
+ era5_handler.change_date(hour)
278
+ ret = era5_handler.get_data()
279
+ logger.info(ret)
@@ -0,0 +1,60 @@
1
+ import xarray as xr
2
+ import glob
3
+ import os
4
+ import time
5
+ import numpy as np
6
+ from dateutil import parser
7
+ from scipy.interpolate import interp2d
8
+ import pygrib
9
+ import copy
10
+ import xesmf as xe
11
+ import uuid
12
+ import datetime
13
+ from pyVPRM.meteorologies.met_base_class import met_data_handler_base
14
+ from loguru import logger
15
+
16
+ class met_data_handler(met_data_handler_base):
17
+
18
+ def __init__(self, year, month, day, hour, keys=[]):
19
+ super().__init__()
20
+
21
+ # Init with year, month, day, hour and the required era5 keys as given in the
22
+ # keys_dict above
23
+
24
+ def regrid(
25
+ self,
26
+ lats=None,
27
+ lons=None,
28
+ dataset=None,
29
+ n_cpus=1,
30
+ weights=None,
31
+ overwrite_regridder=False,
32
+ ):
33
+ # Regrid the ERA5 data to given grid with lats and lons or an xarray
34
+ # with given coords alternatively. If regridding weights are given to not recalculate
35
+ # them.
36
+ return
37
+
38
+ def get_data(self, lonlat=None, key=None):
39
+ # Return ERA5 data for lonlat if lonlat is not None else return all data.
40
+ # Pick a specific key if key is not None. Return as xarray dataset
41
+ return
42
+
43
+ def _init_data_for_day(self):
44
+ # If something should be done if a new date is provided
45
+ return
46
+
47
+ def _load_data_for_hour(self):
48
+ # If something should be done if only the hour is changed
49
+ return
50
+
51
+
52
+ if __name__ == "__main__":
53
+ year = "2000"
54
+ month = 2
55
+ day = 20
56
+ hour = 5 # UTC hour
57
+ era5_handler = class_name(year, month, day)
58
+ era5_handler.change_date(hour)
59
+ ret = era5_handler.get_data()
60
+ logger.info(ret)
@@ -0,0 +1,149 @@
1
+ import xarray as xr
2
+ import glob
3
+ import os
4
+ import time
5
+ import numpy as np
6
+ from dateutil import parser
7
+ from scipy.interpolate import interp2d
8
+ import pygrib
9
+ import copy
10
+ import xesmf as xe
11
+ import uuid
12
+ import datetime
13
+ from pyVPRM.meteorologies.met_base_class import met_data_handler_base
14
+ from loguru import logger
15
+
16
+ class met_data_handler(met_data_handler_base):
17
+
18
+ def __init__(self, year, month, day, hour, bpath, mpi=False, keys=[]):
19
+ super().__init__()
20
+ # Init with year, month, day, hour and the required era5 keys as given in the
21
+ # keys_dict above
22
+ self.in_era5_grid = True
23
+ self.this_month = 0
24
+ self.this_year = 0
25
+ self.bpath = bpath
26
+ self.ds_in_t = None
27
+ self.regridder = None
28
+ self.mpi = mpi
29
+ self.change_date(year, month, day, hour)
30
+
31
+ def regrid(
32
+ self,
33
+ lats=None,
34
+ lons=None,
35
+ dataset=None,
36
+ n_cpus=1,
37
+ weights=None,
38
+ overwrite_regridder=False,
39
+ ):
40
+
41
+ import xesmf as xe
42
+
43
+ if self.in_era5_grid is False:
44
+ return
45
+
46
+ if (self.regridder is None) | (overwrite_regridder):
47
+ if (lats is not None) and (lons is not None):
48
+ t_ds_out = xr.Dataset(
49
+ {
50
+ "lat": (["lat"], lats, {"units": "degrees_north"}),
51
+ "lon": (["lon"], lons, {"units": "degrees_east"}),
52
+ }
53
+ )
54
+ t_ds_out = t_ds_out.set_coords(["lon", "lat"])
55
+ self.reg_lats = lats
56
+ self.reg_lons = lons
57
+ else:
58
+ t_ds_out = dataset
59
+
60
+ if (weights is not None) & os.path.exists(str(weights)):
61
+ logger.info("Load weights from {}".format(weights))
62
+ else:
63
+ bfolder = os.path.dirname(weights)
64
+ src_temp_path = os.path.join(bfolder, "{}.nc".format(str(uuid.uuid4())))
65
+ dest_temp_path = os.path.join(
66
+ bfolder, "{}.nc".format(str(uuid.uuid4()))
67
+ )
68
+ self.ds_in_t.to_netcdf(src_temp_path)
69
+ t_ds_out.to_netcdf(dest_temp_path)
70
+ cmd = "ESMF_RegridWeightGen --source {} --destination {} --weight {} -m bilinear --64bit_offset --extrap_method nearestd --no_log".format(
71
+ src_temp_path, dest_temp_path, weights
72
+ )
73
+ if self.mpi:
74
+ cmd = "mpirun -np {} ".format(n_cpus) + cmd
75
+ logger.info(cmd)
76
+ os.system(cmd)
77
+ os.remove(src_temp_path)
78
+ os.remove(dest_temp_path)
79
+
80
+ self.regridder = xe.Regridder(
81
+ self.data, t_ds_out, "bilinear", weights=weights, reuse_weights=True
82
+ )
83
+ self.data = self.regridder(self.data)
84
+ self.in_era5_grid = False
85
+
86
+ def get_data(self, lonlat=None, key=None):
87
+ # Return ERA5 data for lonlat if lonlat is not None else return all data.
88
+ # Pick a specific key if key is not None. Return as xarray dataset
89
+ dt = np.datetime64(
90
+ "{}-{:02d}-{:02d}T{:02d}:00:00.000000".format(
91
+ self.year, self.month, self.day, self.hour
92
+ )
93
+ )
94
+ if key is not None:
95
+ tmp = self.data.sel({"time": dt})[key]
96
+ else:
97
+ tmp = self.data.sel({"time": dt})
98
+ if lonlat is None:
99
+ return tmp
100
+ else:
101
+ lon = lonlat[0]
102
+ if isinstance(lon, list) | isinstance(lon, np.ndarray):
103
+ return tmp.interp(lon=("z", lon), lat=("z", lonlat[1]), method="linear")
104
+ else:
105
+ lon = lonlat[0]
106
+ return tmp.interp(lon=lon, lat=lonlat[1])
107
+ return self.data
108
+
109
+ def _init_data_for_day(self):
110
+ if (self.this_month != self.month) | (self.this_year != self.year):
111
+ self.data = xr.open_dataset(
112
+ os.path.join(self.bpath, "{}_{}.nc".format(self.year, self.month))
113
+ )
114
+ self.this_month = self.month
115
+ self.this_year = self.year
116
+ self.in_era5_grid = True
117
+
118
+ if self.ds_in_t is None:
119
+ self.ds_in_t = xr.Dataset(
120
+ {
121
+ "lat": (
122
+ ["lat"],
123
+ self.data["lat"].values,
124
+ {"units": "degrees_north"},
125
+ ),
126
+ "lon": (
127
+ ["lon"],
128
+ self.data["lon"].values,
129
+ {"units": "degrees_east"},
130
+ ),
131
+ }
132
+ )
133
+ self.ds_in_t = self.ds_in_t.set_coords(["lon", "lat"])
134
+ return
135
+
136
+ def _load_data_for_hour(self):
137
+ # If something should be done if only the hour is changed
138
+ return
139
+
140
+
141
+ if __name__ == "__main__":
142
+ year = "2000"
143
+ month = 2
144
+ day = 20
145
+ hour = 5 # UTC hour
146
+ era5_handler = class_name(year, month, day)
147
+ era5_handler.change_date(hour)
148
+ ret = era5_handler.get_data()
149
+ logger.info(ret)
@@ -0,0 +1,67 @@
1
+ import xarray as xr
2
+ import glob
3
+ import os
4
+ import time
5
+ import numpy as np
6
+ from dateutil import parser
7
+ import pygrib
8
+ import copy
9
+ import uuid
10
+ import datetime
11
+
12
+
13
+ class met_data_handler_base:
14
+ """
15
+ Base class for all meteorologies
16
+ """
17
+
18
+ def __init__(self):
19
+ self.year = None
20
+ self.month = None
21
+ self.day = None
22
+ self.hour = None
23
+ return
24
+
25
+ def change_date(self, year=None, month=None, day=None, hour=None):
26
+ # Caution: The date as argument corresponds to the END of the ERA5 integration time.
27
+
28
+ new_date = False
29
+ if (day != self.day) & (day != None):
30
+ self.day = day
31
+ new_date = True
32
+
33
+ if (month != self.month) & (month != None):
34
+ self.month = month
35
+ new_date = True
36
+
37
+ if (year != self.year) & (year != None):
38
+ self.year = year
39
+ new_date = True
40
+
41
+ if new_date:
42
+ self._init_data_for_day()
43
+
44
+ if (hour != self.hour) & (hour != None):
45
+ self.hour = hour
46
+ new_date = True
47
+
48
+ if new_date:
49
+ self._load_data_for_hour()
50
+ return
51
+
52
+ def _init_data_for_day(self):
53
+ return
54
+
55
+ def _load_data_for_hour(self):
56
+ return
57
+
58
+ def regrid(
59
+ self,
60
+ lats=None,
61
+ lons=None,
62
+ dataset=None,
63
+ n_cpus=1,
64
+ weights=None,
65
+ overwrite_regridder=False,
66
+ ):
67
+ return
@@ -0,0 +1,56 @@
1
+ import xarray as xr
2
+ import glob
3
+ import os
4
+ import time
5
+ import numpy as np
6
+ from dateutil import parser
7
+ import copy
8
+ import datetime
9
+ from pyVPRM.meteorologies.met_base_class import met_data_handler_base
10
+ import pandas as pd
11
+ from loguru import logger
12
+
13
+ key_map = {"time": "TIMESTAMP_START", "ssrd": "SW_IN", "t2m": "TA"}
14
+
15
+
16
+ class met_data_handler(met_data_handler_base):
17
+
18
+ def __init__(self, data_file, names=key_map):
19
+ super().__init__()
20
+ self.names = names
21
+ self.non_time_keys = [
22
+ self.names[i] for i in self.names.keys() if i not in "time"
23
+ ]
24
+ self.data = pd.read_csv(
25
+ data_file, usecols=[self.names[i] for i in self.names.keys()]
26
+ )
27
+ self.data[self.names["time"]] = pd.to_datetime(self.data[self.names["time"]])
28
+ self.data[self.names["t2m"]] = self.data[self.names["t2m"]] + 273.15
29
+ self.data[self.names["ssrd"]] = self.data[self.names["ssrd"]] * 3600
30
+ return
31
+
32
+ def get_data(self, lonlat=None, key=None):
33
+ # Return ERA5 data for lonlat if lonlat is not None else return all data.
34
+ # Pick a specific key if key is not None. Return as xarray dataset
35
+
36
+ date_int = np.datetime64(
37
+ "{}-{:02d}-{:02d} {:02d}:00:00".format(
38
+ self.year, self.month, self.day, self.hour
39
+ )
40
+ )
41
+ row = self.data.loc[self.data[self.names["time"]] == date_int]
42
+ if key is None:
43
+ return row[self.non_time_keys].values
44
+ else:
45
+ return float(row[self.names[key]].values)
46
+
47
+
48
+ if __name__ == "__main__":
49
+ year = "2000"
50
+ month = 2
51
+ day = 20
52
+ hour = 5 # UTC hour
53
+ era5_handler = ERA5(year, month, day)
54
+ era5_handler.change_date(hour)
55
+ ret = era5_handler.get_data()
56
+ logger.info(ret)
File without changes