diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000000000000000000000000000000000000..45f0660c7938d17d16827418ea9bb17aac9d098c --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "mlair/external/toarstats"] + path = mlair/external/toarstats + url = git@gitlab.jsc.fz-juelich.de:esde/toar-public/toarstats.git diff --git a/HPC_setup/requirements_HDFML_additionals.txt b/HPC_setup/requirements_HDFML_additionals.txt index fd22a309913efa6478a4a00f94bac70433e21774..a0bbb3b21daaa5181d5180b22d69c40652e387d7 100644 --- a/HPC_setup/requirements_HDFML_additionals.txt +++ b/HPC_setup/requirements_HDFML_additionals.txt @@ -59,6 +59,7 @@ termcolor==1.1.0 toml==0.10.2 toolz==0.11.1 typing-extensions==3.7.4.3 +tzwhere==3.0.3 urllib3==1.26.3 Werkzeug==1.0.1 wget==3.2 diff --git a/HPC_setup/requirements_JUWELS_additionals.txt b/HPC_setup/requirements_JUWELS_additionals.txt index fd22a309913efa6478a4a00f94bac70433e21774..a0bbb3b21daaa5181d5180b22d69c40652e387d7 100644 --- a/HPC_setup/requirements_JUWELS_additionals.txt +++ b/HPC_setup/requirements_JUWELS_additionals.txt @@ -59,6 +59,7 @@ termcolor==1.1.0 toml==0.10.2 toolz==0.11.1 typing-extensions==3.7.4.3 +tzwhere==3.0.3 urllib3==1.26.3 Werkzeug==1.0.1 wget==3.2 diff --git a/mlair/data_handler/abstract_data_handler.py b/mlair/data_handler/abstract_data_handler.py index 36d6e9ae5394705af4b9fbcfd1d8ff77572642b5..a6f49d2d756200a8a4e5f15c13ecf385ef08dabc 100644 --- a/mlair/data_handler/abstract_data_handler.py +++ b/mlair/data_handler/abstract_data_handler.py @@ -3,8 +3,12 @@ __author__ = 'Lukas Leufen' __date__ = '2020-09-21' import inspect +import logging from typing import Union, Dict +import dask +from dask.diagnostics import ProgressBar + from mlair.helpers import remove_items @@ -84,3 +88,13 @@ class AbstractDataHandler: def _hash_list(self): return [] + + @staticmethod + def _force_dask_computation(data): + try: + with ProgressBar(): + logging.info(f"DefaultDH: _force_dask_computation") + data = dask.compute(data)[0] + except: + logging.info("can't execute dask.compute") + return data diff --git a/mlair/data_handler/data_handler_wrf_chem.py b/mlair/data_handler/data_handler_wrf_chem.py index 8188ddf39e96b769e9d47ada881bfb10ceaff438..f191d6d0d40eea7cd7165f969474da17f910688e 100644 --- a/mlair/data_handler/data_handler_wrf_chem.py +++ b/mlair/data_handler/data_handler_wrf_chem.py @@ -8,6 +8,14 @@ import itertools import glob import matplotlib.pyplot as plt from dask.diagnostics import ProgressBar +from tzwhere import tzwhere +import datetime as dt +from toarstats import toarstats + +import hashlib +from functools import reduce, partial +import dill + import dask import inspect @@ -16,6 +24,7 @@ import gc from mlair.helpers.geofunctions import haversine_dist, bearing_angle, WindSector, VectorRotateLambertConformal2latlon from mlair.helpers.helpers import convert2xrda, remove_items, to_list from mlair.helpers import TimeTrackingWrapper, TimeTracking +from mlair.configuration import check_path_and_create from mlair.data_handler.data_handler_single_station import DataHandlerSingleStation @@ -69,7 +78,6 @@ class BaseWrfChemDataLoader: vars_to_rotate: Tuple[Tuple[Tuple[str, str], Tuple[str, str]]] = DEFAULT_VARS_TO_ROTATE, staged_dimension_mapping=None, stag_ending='_stag', date_format_of_nc_file=None, - ): """ Initialisze data loader @@ -166,7 +174,7 @@ class BaseWrfChemDataLoader: """ if (self.start_time is None) and (self.end_time is None): path_list = os.path.join(self.data_path, self.common_file_starter + '*') - logging.info(f"Reading file(s): {path_list}") + #logging.info(f"Reading file(s): {path_list}") return path_list elif (self.start_time is not None) and (self.end_time is not None): path_list = set() @@ -176,7 +184,7 @@ class BaseWrfChemDataLoader: self.date_format_of_nc_file) + '*' ))[0]) path_list = sorted(list(path_list)) - logging.info(f"Reading file(s): {path_list}") + #logging.info(f"Reading file(s): {path_list}") return path_list else: raise ValueError(f"`start_time' and `end_time' must both be given or None.") @@ -192,10 +200,16 @@ class BaseWrfChemDataLoader: # see also https://github.com/pydata/xarray/issues/1385#issuecomment-438870575 data = xr.open_mfdataset(paths=self.dataset_search_str, combine='nested', concat_dim=self.time_dim_name, parallel=True, decode_cf=False) + data = xr.decode_cf(data) + logging.info(f"Reading file(s): {self.dataset_search_str}") else: data = xr.open_mfdataset(paths=self.dataset_search_str, combine='nested', concat_dim=self.time_dim_name, - parallel=True, decode_cf=False, preprocess=self.preprocess_fkt_for_loader, ) - data = xr.decode_cf(data) + + parallel=True, preprocess=self.preprocess_fkt_for_loader, + #decode_cf=False, + ) + logging.info(f"Reading file(s): {self.dataset_search_str}") + #data = xr.decode_cf(data) self._data = data def preprocess_fkt_for_loader(self, ds): @@ -394,12 +408,20 @@ class SingleGridColumnWrfChemDataLoader(BaseWrfChemDataLoader): DEFAULT_ITER_DIM = "points" DEFAULT_WINDOW_DIM = "window" + _hash = ["data_path", "external_coords_file", "time_dim_name", + "rechunk_values", "variables", "z_coord_selector", "date_format_of_nc_file", + "wind_sectors", "wind_sector_edge_dim_name", "statistics_per_var", + "aggregation_sampling", "time_zone", + ] + def __init__(self, coords: Tuple[float_np_xr, float_np_xr], target_dim=DEFAULT_TARGET_DIM, target_var=DEFAULT_TARGET_VAR, window_history_size=DEFAULT_WINDOW_HISTORY_SIZE, window_lead_time=DEFAULT_WINDOW_LEAD_TIME, external_coords_file: str = None, - wind_sectors=None, wind_sector_edge_dim_name=None, **kwargs): + wind_sectors=None, wind_sector_edge_dim_name=None, statistics_per_var: Dict = None, + aggregation_sampling: str = None, time_zone: str = None, target_time_type: str = None, + station: str = None, lazy_preprocessing: bool = False, **kwargs): """ @@ -417,6 +439,10 @@ class SingleGridColumnWrfChemDataLoader(BaseWrfChemDataLoader): :type external_coords_file: :param wind_sectors: :type wind_sectors: + :param statistics_per_var: Dict containing the (TOAR-) statistics as value for each variable (key) + :param aggregation_sampling: sampling period for statistics (e.g. "daily", "seasonal" etc. See torstats for more details) + :param time_zone: + :param: station :param kwargs: :type kwargs: """ @@ -431,6 +457,18 @@ class SingleGridColumnWrfChemDataLoader(BaseWrfChemDataLoader): self.external_coords_file = external_coords_file self.wind_sectors = wind_sectors self.wind_sector_edge_dim_name = wind_sector_edge_dim_name + self.statistics_per_var = statistics_per_var + self.aggregation_sampling = aggregation_sampling + self.time_zone = time_zone + self.target_time_type = target_time_type + self.station = station + + self.lazy = lazy_preprocessing + self.lazy_path = None + if self.lazy is True: + self.lazy_path = os.path.join(self.data_path, "lazy_data", self.__class__.__name__) + check_path_and_create(self.lazy_path) + logging.debug("SingleGridColumnWrfChemDataLoader Initialised") @@ -450,11 +488,62 @@ class SingleGridColumnWrfChemDataLoader(BaseWrfChemDataLoader): self._set_dims_as_coords() if self.external_coords_file is not None: self._apply_external_coordinates() + self.apply_staged_transormation() - # self.rechunk_data(self.rechunk_values) self._set_geoinfos() + + if self.lazy is False: + self.reset_data_by_other(self.apply_toarstats()) + else: + self.load_lazy() + self.store_lazy() + + # self.rechunk_data(self.rechunk_values) return self + def reset_data_by_other(self, other: xr.Dataset): + attrs = self._data.attrs + self._data = other + # for var in other: + # self._data[var] = other[var] + + def store_lazy(self): + hash = self._get_hash() + filename = os.path.join(self.lazy_path, hash + ".nc") + if not os.path.exists(filename): + self._data.to_netcdf(filename, format="NETCDF4", engine="netcdf4") + logging.info(f"{self.station[0]}: store lazy data: {filename}") + # dill.dump(self._create_lazy_data(), file=open(filename, "wb")) + + # def _create_lazy_data(self): + # return [self._data ]#, self.meta, self.input_data, self.target_data] + + def load_lazy(self): + hash = self._get_hash() + filename = os.path.join(self.lazy_path, hash + ".nc") + try: + self._data = xr.open_mfdataset(filename) + logging.info(f"{self.station[0]}: used lazy data: {filename}") + except FileNotFoundError: + logging.debug(f"{self.station[0]}: could not use lazy data") + self.reset_data_by_other(self.apply_toarstats()) + except OSError: + logging.debug(f"{self.station[0]}: could not use lazy data") + self.reset_data_by_other(self.apply_toarstats()) + + def _extract_lazy(self, lazy_data): + # _data, self.meta, _input_data, _target_data = lazy_data + # f_prep = partial(self._slice_prep, start=self.start, end=self.end) + self._data = lazy_data[0] + # self._data, self.input_data, self.target_data = list(map(f_prep, [_data, _input_data, _target_data])) + + def _hash_list(self): + return sorted(list(set(self._hash))) + + def _get_hash(self): + hash = "".join([str(self.__getattribute__(e)) for e in self._hash_list()]).encode() + return hashlib.md5(hash).hexdigest() + def __exit__(self, exc_type, exc_val, exc_tb): self.data.close() gc.collect() @@ -599,6 +688,121 @@ class SingleGridColumnWrfChemDataLoader(BaseWrfChemDataLoader): else: return {k: list(v.values) for k, v in self._nearest_coords.items()} + def apply_toarstats(self): + dh = self.prepare_and_apply_toarstats(self.data, target_sampling=self.aggregation_sampling) + return dh + + @staticmethod + def _toarstats_wrapper(data, sampling, statistics, metadata, seasons=None, crops=None, + data_capture=None): + + return toarstats(sampling, statistics, data, metadata, seasons, crops, data_capture) + + + @TimeTrackingWrapper + def prepare_and_apply_toarstats(self, data, target_sampling="daily"): + meta = pd.DataFrame({self.physical_x_coord_name: self.get_coordinates()['lon'].tolist(), + self.physical_y_coord_name: self.get_coordinates()['lat'].tolist()}, + index=self.station) + if self.target_time_type is None: + target_time_type_or_zone = self.get_local_time_zone_from_lat_lon(meta=meta) + else: + target_time_type_or_zone = self.target_time_type + collector = [] + for var in self.statistics_per_var.keys(): + collector.append(self.__toarstats_aggregation(data, target_time_type_or_zone, meta, target_sampling, var)) + sampling_data = xr.merge(collector).dropna(self.physical_t_coord_name) + # sampling_data.attrs = data.attrs + missing_squeezed_coords = data.coords._names - sampling_data.coords._names + for coord in missing_squeezed_coords: + sampling_data.coords[coord] = data.coords[coord] + + return sampling_data + + def __toarstats_aggregation(self, data, target_time_type_or_zone, meta, target_sampling, var): + with TimeTracking(name=f"{self.station}: apply toarstats `{self.statistics_per_var[var]}({var})`"): + spatial_dims = list(remove_items(data[var].dims, self.physical_t_coord_name)) + try: + df = data[var].to_dataframe()[[var]].reset_index(level=spatial_dims) + except Exception as e: + logging.info(f"can't reset_index in __toarstats_aggregation: {e}") + df = data[var].to_dataframe()[[var]].reset_index(level=spatial_dims) + + df = df[[var] + spatial_dims] + df = self.set_external_time_zone_and_convert_to_target_time(df, target_time_type_or_zone) + df = df.groupby(spatial_dims) + df = df.apply(self._toarstats_wrapper, sampling=target_sampling, statistics=self.statistics_per_var[var], + metadata=(meta[self.physical_y_coord_name], meta[self.physical_x_coord_name])) + df.columns = [var] + df.index.set_names(df.index.names[:len(spatial_dims)] + [self.physical_t_coord_name], inplace=True) + # df = df.to_xarray().to_array(self.target_dim) + df = df.to_xarray() + df = df.chunk({self.logical_x_coord_name: -1}) + # collector.append(df) + return df + + def set_external_time_zone_and_convert_to_target_time(self, data, target_time_type_or_zone): + """ + + :param data: + :type data: + :param target_time_type_or_zone: + :type target_time_type_or_zone: + :return: + :rtype: + """ + hdata = data + # hdata = data.squeeze().to_pandas() + if target_time_type_or_zone == "solar_time": + lon = self.get_coordinates()['lon'] + toffset = dt.timedelta(hours=np.floor(lon/15.)) + hdata.index = hdata.index + toffset + else: + hdata.index = self.set_time_zone(hdata.index) + hdata.index = hdata.index.tz_convert(target_time_type_or_zone) + logging.debug(f"Set local time zone to: {target_time_type_or_zone}") + return hdata + + def get_local_time_zone_from_lat_lon(self, lat=None, lon=None, meta=None): + """ + Retuns name of time zone for given lat lon coordinates. + + Method also accepts a meta data pd.DataFrame where lat and lon are extracted with the loader's physical x and y + coord names + + :param lat: + :type lat: + :param lon: + :type lon: + :param meta: + :type meta: pd.DataFrame + :return: + :rtype: str + """ + if (lat is None and lon is None) and (meta is not None): + lat = meta[self.physical_y_coord_name] + lon = meta[self.physical_x_coord_name] + + tz_where = tzwhere.tzwhere() + local_time_zone = tz_where.tzNameAt(latitude=lat, longitude=lon) + logging.debug(f"Detect local time zone '{local_time_zone}' based on lat={lat}, lon={lon}") + return local_time_zone + + def set_time_zone(self, time_index): + """ + Sets time zone information on a given index + + :param time_index: + :type time_index: + :return: + :rtype: + """ + + dti = pd.to_datetime(time_index) + dti = dti.tz_localize(self.time_zone) + logging.debug(f"Set external time zone for {self.station} to: {self.time_zone}") + return dti + class DataHandlerSingleGridColumn(DataHandlerSingleStation): _requirements = remove_items(inspect.getfullargspec(DataHandlerSingleStation).args, ["self", "station"]) @@ -609,6 +813,9 @@ class DataHandlerSingleGridColumn(DataHandlerSingleStation): rechunk_values=None, date_format_of_nc_file=None, as_image_like_data_format=True, + time_zone=None, + target_time_type=None, + input_output_sampling4toarstats : tuple = None, **kwargs): self.external_coords_file = external_coords_file self.var_logical_z_coord_selector = self._return_z_coord_select_if_valid(var_logical_z_coord_selector, @@ -622,6 +829,10 @@ class DataHandlerSingleGridColumn(DataHandlerSingleStation): self.rechunk_values = rechunk_values self.date_format_of_nc_file = date_format_of_nc_file self.as_image_like_data_format = as_image_like_data_format + + self.time_zone = time_zone + self.target_time_type = target_time_type + self.input_output_sampling4toarstats = input_output_sampling4toarstats super().__init__(*args, **kwargs) @staticmethod @@ -702,7 +913,13 @@ class DataHandlerSingleGridColumn(DataHandlerSingleStation): # end_time=self.end, date_format_of_nc_file=self.date_format_of_nc_file, wind_sectors=helper_wind_sectors, - wind_sector_edge_dim_name=helper_wind_sector_edge_dim_name , + wind_sector_edge_dim_name=helper_wind_sector_edge_dim_name, + statistics_per_var=self.statistics_per_var, + aggregation_sampling=self.input_output_sampling4toarstats[1], + time_zone=self.time_zone, + target_time_type=self.target_time_type, + station=self.station, + lazy_preprocessing=True, ) self.__loader = loader @@ -722,18 +939,107 @@ class DataHandlerSingleGridColumn(DataHandlerSingleStation): logging.info(f"start compute data for {self.station} in load_data") data = dask.compute(data)[0] + # set time zone to attrs + data.attrs["time_zone"] = self.time_zone + # expand dimesion for iterdim data = data.expand_dims({self.iter_dim: station}).to_array(self.target_dim) # transpose dataarray: set first three fixed and keep remaining as is data = data.transpose(self.iter_dim, self.time_dim, self.target_dim, ...) - data = self._slice_prep(data, start=start, end=end) + + # ToDo add metadata - _meta = {'station_lon': self.loader.get_coordinates()['lon'].tolist(), - 'station_lat': self.loader.get_coordinates()['lat'].tolist()} - meta = pd.DataFrame(_meta, index=station).T + _meta = {self.loader.physical_x_coord_name: self.loader.get_coordinates()['lon'].tolist(), + self.loader.physical_y_coord_name: self.loader.get_coordinates()['lat'].tolist()} + meta = pd.DataFrame(_meta, index=station) + + # if isinstance(self.input_output_sampling4toarstats, tuple) and len(self.input_output_sampling4toarstats) == 2: + # if self.var_logical_z_coord_selector != 0: + # raise NotImplementedError( + # f"Method `apply_toarstats` is not implemented for var_logical_z_coord_selector != 0: " + # f"Is {self.var_logical_z_coord_selector}") + # data = self.prepare_and_apply_toarstats(data, meta, self.input_output_sampling4toarstats[1]) + data = self._slice_prep(data, start=start, end=end) return data, meta + # @TimeTrackingWrapper + # def prepare_and_apply_toarstats(self, data, meta, target_sampling="daily"): + # local_time_zone = self.get_local_time_zone_from_lat_lon(meta=meta) + # hdata = self.set_external_time_zone_and_convert_to_target_time(data, local_time_zone) + # hsampling_data = [] + # for i, var in enumerate(hdata.columns): + # hdf = toarstats(target_sampling, self.statistics_per_var[var], hdata[var], + # (meta[self.loader.physical_y_coord_name], meta[self.loader.physical_x_coord_name])) + # hsampling_data.append(xr.DataArray(hdf, coords=[hdf.index, [var]], + # dims=[self.loader.physical_t_coord_name, self.target_dim])) + # sampling_data = xr.concat(hsampling_data, dim=self.target_dim) + # sampling_data = sampling_data.broadcast_like(data, exclude=self.loader.physical_t_coord_name).dropna( + # self.loader.physical_t_coord_name) + # sampling_data.attrs = data.attrs + # missing_squeezed_coords = data.coords._names - sampling_data.coords._names + # for coord in missing_squeezed_coords: + # sampling_data.coords[coord] = data.coords[coord] + # + # return self._force_dask_computation(sampling_data) + # + # def set_external_time_zone_and_convert_to_target_time(self, data, local_time_zone): + # """ + # + # :param data: + # :type data: + # :param local_time_zone: + # :type local_time_zone: + # :return: + # :rtype: + # """ + # hdata = data.squeeze().to_pandas() + # hdata.index = self.set_time_zone(hdata.index) + # hdata.index = hdata.index.tz_convert(local_time_zone) + # logging.debug(f"Set local time zone for {self.station} to: {local_time_zone}") + # return hdata + # + # def get_local_time_zone_from_lat_lon(self, lat=None, lon=None, meta=None): + # """ + # Retuns name of time zone for given lat lon coordinates. + # + # Method also accepts a meta data pd.DataFrame where lat and lon are extracted with the loader's physical x and y + # coord names + # + # :param lat: + # :type lat: + # :param lon: + # :type lon: + # :param meta: + # :type meta: pd.DataFrame + # :return: + # :rtype: str + # """ + # if (lat is None and lon is None) and (meta is not None): + # lat = meta[self.loader.physical_y_coord_name] + # lon = meta[self.loader.physical_x_coord_name] + # + # + # tz_where = tzwhere.tzwhere() + # local_time_zone = tz_where.tzNameAt(latitude=lat, longitude=lon) + # logging.debug(f"Detect local time zone '{local_time_zone}' based on lat={lat}, lon={lon}") + # return local_time_zone + # + # def set_time_zone(self, time_index): + # """ + # Sets time zone information on a given index + # + # :param time_index: + # :type time_index: + # :return: + # :rtype: + # """ + # + # dti = pd.to_datetime(time_index) + # dti = dti.tz_localize(self.time_zone) + # logging.debug(f"Set external time zone for {self.station} to: {self.time_zone}") + # return dti + @staticmethod def _extract_largest_coord_extractor(var_extarctor, target_extractor) -> Union[List, None]: if var_extarctor is not None and target_extractor is not None: @@ -827,9 +1133,8 @@ class DataHandlerSingleGridColumn(DataHandlerSingleStation): """ return all(self._transformation) - @staticmethod - def interpolate(data, dim: str, method: str = 'linear', limit: int = None, use_coordinate: Union[bool, str] = True, - **kwargs): + def interpolate(self, data, dim: str, method: str = 'linear', limit: int = None, + use_coordinate: Union[bool, str] = True, sampling="daily", **kwargs): """ Interpolate values according to different methods. @@ -866,6 +1171,7 @@ class DataHandlerSingleGridColumn(DataHandlerSingleStation): :return: xarray.DataArray """ + # data = self.create_full_time_dim(data, dim, sampling) return data.interpolate_na(dim=dim, method=method, limit=limit, use_coordinate=use_coordinate, **kwargs) diff --git a/mlair/data_handler/default_data_handler.py b/mlair/data_handler/default_data_handler.py index 188283703cb55481c6e21524077663f8ae2a9f17..1b4715a05d7e072add90137b89f7944299f449f5 100644 --- a/mlair/data_handler/default_data_handler.py +++ b/mlair/data_handler/default_data_handler.py @@ -7,15 +7,12 @@ import inspect import gc import logging import os -import pickle import dill import shutil from functools import reduce from typing import Tuple, Union, List import multiprocessing import psutil -import dask -from dask.diagnostics import ProgressBar import numpy as np import xarray as xr @@ -111,16 +108,6 @@ class DefaultDataHandler(AbstractDataHandler): attr_dict[attr] = val return attr_dict - @staticmethod - def _force_dask_computation(data): - try: - with ProgressBar(): - logging.info(f"DefaultDH: _force_dask_computation") - data = dask.compute(data)[0] - except: - logging.info("can't execute dask.compute") - return data - def _load(self): try: with open(self._save_file, "rb") as f: diff --git a/mlair/external/toarstats b/mlair/external/toarstats new file mode 160000 index 0000000000000000000000000000000000000000..a3c2020686d300db6ca5a1d0b81128f4740e2b16 --- /dev/null +++ b/mlair/external/toarstats @@ -0,0 +1 @@ +Subproject commit a3c2020686d300db6ca5a1d0b81128f4740e2b16 diff --git a/mlair/model_modules/model_class.py b/mlair/model_modules/model_class.py index 8f464b16cbc74a241f70ba1c5bb9f8fe611dba95..fd43674e009631f4fd7f1c5648f500a0eaff2ec1 100644 --- a/mlair/model_modules/model_class.py +++ b/mlair/model_modules/model_class.py @@ -518,7 +518,7 @@ class MyLuongAttentionLSTMModel(AbstractModelClass): self.initial_lr = 0.01 self.clipnorm = 1 - self.n_hidden = 100 + self.n_hidden = 32 # apply to model self.set_model() diff --git a/mlair/run_modules/pre_processing.py b/mlair/run_modules/pre_processing.py index e817d2a16664b751396303f3c95313a85841625c..db9e9e940f7675e618e48f41f0cffb4e4d9ac644 100644 --- a/mlair/run_modules/pre_processing.py +++ b/mlair/run_modules/pre_processing.py @@ -327,8 +327,8 @@ def f_proc(data_handler, station, name_affix, store, **kwargs): except (AttributeError, EmptyQueryResult, KeyError, requests.ConnectionError, ValueError, IndexError) as e: formatted_lines = traceback.format_exc().splitlines() logging.info( - f"remove station {station} because it raised an error: {e} -> {' | '.join(f_inspect_error(formatted_lines))}") - logging.debug(f"detailed information for removal of station {station}: {traceback.format_exc()}") + #f"remove station {station} because it raised an error: {e} -> {' | '.join(f_inspect_error(formatted_lines))}") + f"remove station {station} because it raised an error: {e} -> {' | '.join(formatted_lines)}") res = None return res, station diff --git a/requirements.txt b/requirements.txt index dba565fbb535db7d7782baec8690971d4393b3e0..a2ccc2b04bcde470228bc8684f80f33f6a1945e8 100644 --- a/requirements.txt +++ b/requirements.txt @@ -64,6 +64,7 @@ termcolor==1.1.0 toml==0.10.2 toolz==0.11.1 typing-extensions==3.7.4.3 +tzwhere==3.0.3 urllib3==1.26.3 Werkzeug==1.0.1 wget==3.2 diff --git a/requirements_gpu.txt b/requirements_gpu.txt index f170e1b7b67df7e17a3258ca849b252acaf3e650..be648ff8f7809ba9e80a0adfc356e7091e2415f7 100644 --- a/requirements_gpu.txt +++ b/requirements_gpu.txt @@ -64,6 +64,7 @@ termcolor==1.1.0 toml==0.10.2 toolz==0.11.1 typing-extensions==3.7.4.3 +tzwhere==3.0.3 urllib3==1.26.3 Werkzeug==1.0.1 wget==3.2 diff --git a/run_wrf_dh.py b/run_wrf_dh.py index b9d4cd02a9e103201d98ff629fa5c2de12410e9d..e769338b254a04de8cad50d29e70f2e9d22953a5 100644 --- a/run_wrf_dh.py +++ b/run_wrf_dh.py @@ -8,7 +8,7 @@ from mlair.workflows import DefaultWorkflow from mlair.helpers import remove_items from mlair.configuration.defaults import DEFAULT_PLOT_LIST -from mlair.model_modules.model_class import MyPaperModel, MyLSTMModel, MyCNNModel +from mlair.model_modules.model_class import IntelliO3TsArchitecture, MyLSTMModel, MyCNNModel, MyLuongAttentionLSTMModel import os @@ -33,6 +33,7 @@ def main(parser_args): evaluate_bootstraps=True, number_of_bootstraps=30, create_new_bootstraps=True, # plot_list=plots, model_name_for_plots='SecModel', + time_zone="UTC", # competitors=["test_model", "test_model2"], # competitor_path=os.path.join(os.getcwd(), "data", "comp_test"), competitors=["baseline", "sector_baseline"], @@ -40,10 +41,11 @@ def main(parser_args): train_min_length=1, val_min_length=1, test_min_length=1, # data_handler=DataHandlerSingleStation, # data_handler=DataHandlerSingleGridColumn, - upsampeling=True, + upsampeling=False, epochs=20, - window_lead_time=2, + window_lead_time=4, window_history_size=6, + # ('Germany', (5.98865807458, 47.3024876979, 15.0169958839, 54.983104153)) stations=["coords__48_8479__10_0963", "coords__51_8376__14_1417", # "coords__50_7536__7_0827", "coords__51_4070__6_9656", @@ -65,9 +67,10 @@ def main(parser_args): # data_path='/home/felix/Data/WRF-Chem/upload_aura_2021-02-24/2009/', # data_path='/home/felix/Data/WRF-Chem/test_cut_nc/', # data_path='/home/felix/Data/WRF-Chem/test_cut_nc_joint', - data_path="/home/felix/Data/WRF-Chem/test_cut_nc_joint/short_test", + # data_path="/home/felix/Data/WRF-Chem/test_cut_nc_joint/short_test", + # data_path="/media/felix/INTENSO/WRF_CHEM/hourly/cdo_output_test/jan_test", # data_path = "/p/scratch/deepacf/kleinert1/IASS_proc_monthyl", - # data_path="/media/felix/INTENSO/WRF_CHEM/JFM_2009", + data_path="/media/felix/INTENSO/WRF_CHEM/JFM_2009", # external data coords external_coords_file='/home/felix/Data/WRF-Chem/test_cut_nc/coords.nc', @@ -89,12 +92,18 @@ def main(parser_args): 'no2': {"method": "standardise"}, 'co': {"method": "standardise"}, 'PSFC': {"method": "standardise"}, - 'CLDFRA': {"method": "min_max"}, + # 'CLDFRA': {"method": "min_max", "min": 0., "max": 1.}, }, - variables=['T2', 'o3', 'wdir10ll', 'wspd10ll', 'no', 'no2', 'co', 'PSFC', 'PBLH', 'CLDFRA'], + # variables=['T2', 'o3', 'wdir10ll', 'wspd10ll', 'no', 'no2', 'co', 'PSFC', 'PBLH', 'CLDFRA'], + variables=['T2', 'o3', 'wdir10ll', 'wspd10ll', 'no', 'no2', 'co', 'PSFC', 'PBLH'], target_var='o3', - statistics_per_var={'T2': None, 'o3': None, 'wdir10ll': None, 'wspd10ll': None, - 'no': None, 'no2': None, 'co': None, 'PSFC': None, 'PBLH': None, 'CLDFRA': None, }, + # statistics_per_var={'T2': None, 'o3': None, 'wdir10ll': None, 'wspd10ll': None, + # 'no': None, 'no2': None, 'co': None, 'PSFC': None, 'PBLH': None, 'CLDFRA': None, }, + statistics_per_var={'T2': "average_values", 'o3': "dma8eu", 'wdir10ll': "average_values", + 'wspd10ll': "average_values", 'no': "dma8eu", 'no2': "dma8eu", 'co': "dma8eu", + 'PSFC': "average_values", 'PBLH': "average_values", + # 'CLDFRA': "average_values", + }, # separate_vars=["o3", "o3Sect", "o3SectLeft", "o3SectRight"], separate_vars=["o3", "o3Sect"], # variables=['T2', 'Q2', 'PBLH', 'U10ll', 'V10ll', 'wdir10ll', 'wspd10ll'], @@ -105,46 +114,62 @@ def main(parser_args): var_logical_z_coord_selector=0, targetvar_logical_z_coord_selector=0, aggregation_dim='bottom_top', - radius=100, # km + radius=200, # km start='2009-01-01', - end='2009-01-04', + # end='2009-01-04', + #end='2009-01-31', - # end='2009-03-31', + end='2009-03-31', train_start='2009-01-01', - train_end='2009-01-02', + # train_end='2009-01-02', # train_start='2009-01-01', #train_end='2009-01-15', - # train_end='2009-02-28', + # train_end='2009-02-15', + # train_end="2009-01-31", + train_end='2009-02-28', - val_start='2009-01-02', - val_end='2009-01-03', + # val_start='2009-01-02', + # val_end='2009-01-03', ################################### #val_start='2009-01-15', #val_end='2009-01-22', ################################### - # val_start='2009-03-01', - # val_end='2009-03-14', + val_start='2009-03-01', + val_end='2009-03-14', + ################################### + # val_start='2009-02-15', + # val_end='2009-03-02', + ################################### + # val_start='2009-02-01', + # val_end='2009-02-28', + + # test_start='2009-01-03', + # test_end='2009-01-04', + ################################### + # test_start='2009-01-22', + # test_end='2009-01-31', - test_start='2009-01-03', - test_end='2009-01-04', ################################### - #test_start='2009-01-22', - #test_end='2009-01-31', + test_start='2009-03-15', + test_end='2009-03-31', ################################### - # test_start='2009-03-15', + # test_start='2009-03-02', # test_end='2009-03-31', - sampling='hourly', + # sampling='hourly', + sampling="daily", + input_output_sampling4toarstats=("hourly", "daily"), interpolation_limit=0, - # as_image_like_data_format=False, + as_image_like_data_format=False, # model=MyLSTMModel, + model=MyLuongAttentionLSTMModel, use_multiprocessing=True, # as_image_like_data_format=True, # model=MyLSTMModel, - model=MyCNNModel, + # model=MyCNNModel, **parser_args.__dict__) workflow.run() diff --git a/run_wrf_dh_sector.py b/run_wrf_dh_sector.py index d77bfd74653b0183402dc3d9180badf6548129d7..7c7fd3c8b06f9568b17124252879ee39b80feaeb 100644 --- a/run_wrf_dh_sector.py +++ b/run_wrf_dh_sector.py @@ -7,7 +7,8 @@ from mlair.data_handler.data_handler_wrf_chem import DataHandlerWRF, DataHandler from mlair.workflows import DefaultWorkflow from mlair.helpers import remove_items from mlair.configuration.defaults import DEFAULT_PLOT_LIST -from mlair.model_modules.model_class import MyPaperModel, MyLSTMModel, MyCNNModel, MyCNNModelSect + +from mlair.model_modules.model_class import IntelliO3TsArchitecture, MyLSTMModel, MyCNNModel, MyCNNModelSect import os @@ -37,13 +38,13 @@ def main(parser_args): train_min_length=1, val_min_length=1, test_min_length=1, # data_handler=DataHandlerSingleStation, # data_handler=DataHandlerSingleGridColumn, - epochs=1000, - window_lead_time=2, + epochs=10, + window_lead_time=4, window_history_size=6, stations=["coords__48_8479__10_0963", "coords__51_8376__14_1417", - "coords__50_7536__7_0827", "coords__51_4070__6_9656", - "coords__49_8421__7_8662", "coords__49_7410__7_1935", - "coords__51_1566__11_8182", "coords__51_4065__6_9660", + # "coords__50_7536__7_0827", "coords__51_4070__6_9656", + # "coords__49_8421__7_8662", "coords__49_7410__7_1935", + # "coords__51_1566__11_8182", "coords__51_4065__6_9660", # "coords__50_7333__7_1000", "coords__50_0000__8_0000", # "coords__48_7444__7_6000", "coords__51_0000__11_0000", # "coords__52_7555__8_1000", "coords__50_0000__2_0000", @@ -52,14 +53,16 @@ def main(parser_args): ], # data_handler=DataHandlerWRF, data_handler=DataHandlerMainSectWRF, #, - data_path="/p/scratch/deepacf/kleinert1/IASS_proc_monthyl", + # data_path="/p/scratch/deepacf/kleinert1/IASS_proc_monthyl", #data_path="/p/scratch/deepacf/kleinert1/IASS_proc", #data_path="/p/project/deepacf/intelliaq/kleinert1/DATA/WRF_CHEM_soft_ln_small_test", + data_path="/media/felix/INTENSO/WRF_CHEM/hourly/cdo_output_test/jan_test", common_file_starter="wrfout_d01", date_format_of_nc_file="%Y-%m", time_dim='XTIME', #external_coords_file='/p/project/deepacf/inbound_data/IASS_upload/coords.nc', - external_coords_file="/p/scratch/deepacf/kleinert1/IASS_proc/coords.nc", + # external_coords_file="/p/scratch/deepacf/kleinert1/IASS_proc/coords.nc", + external_coords_file="/media/felix/INTENSO/WRF_CHEM/monthly/coords.nc", transformation={ "T2": {"method": "standardise"}, "Q2": {"method": "standardise"}, @@ -72,12 +75,18 @@ def main(parser_args): 'no2': {"method": "standardise"}, 'co': {"method": "standardise"}, 'PSFC': {"method": "standardise"}, - 'CLDFRA': {"method": "min_max"}, + # 'CLDFRA': {"method": "min_max", "min": 0., "max": 1.}, }, - variables=['T2', 'o3', 'wdir10ll', 'wspd10ll', 'no', 'no2', 'co', 'PSFC', 'PBLH', 'CLDFRA'], + # variables=['T2', 'o3', 'wdir10ll', 'wspd10ll', 'no', 'no2', 'co', 'PSFC', 'PBLH', 'CLDFRA'], + variables=['T2', 'o3', 'wdir10ll', 'wspd10ll', 'no', 'no2', 'co', 'PSFC', 'PBLH'], target_var='o3', - statistics_per_var={'T2': None, 'o3': None, 'wdir10ll': None, 'wspd10ll': None, - 'no': None, 'no2': None, 'co': None, 'PSFC': None, 'PBLH': None, 'CLDFRA': None, }, + # statistics_per_var={'T2': None, 'o3': None, 'wdir10ll': None, 'wspd10ll': None, + # 'no': None, 'no2': None, 'co': None, 'PSFC': None, 'PBLH': None, 'CLDFRA': None, }, + statistics_per_var={'T2': "average_values", 'o3': "dma8eu", 'wdir10ll': "average_values", + 'wspd10ll': "average_values", 'no': "dma8eu", 'no2': "dma8eu", 'co': "dma8eu", + 'PSFC': "average_values", 'PBLH': "average_values", + # 'CLDFRA': "average_values", + }, # variables=['T2', 'Q2', 'PBLH', 'U10ll', 'V10ll', 'wdir10ll', 'wspd10ll'], # target_var=["T2"], # statistics_per_var={'T2': None, 'Q2': None, 'PBLH': None, @@ -87,44 +96,47 @@ def main(parser_args): targetvar_logical_z_coord_selector=0, aggregation_dim='bottom_top', - radius=100, # km + radius=200, # km start='2009-01-01', - #end='2009-01-04', - #end='2009-01-31', - end='2009-03-31', + # end='2009-01-04', + end='2009-01-31', + # end='2009-03-31', #train_start='2009-01-01', #train_end='2009-01-02', train_start='2009-01-01', - #train_end='2009-01-15', - train_end='2009-02-28', + train_end='2009-01-15', + # train_end='2009-02-28', #val_start='2009-01-02', #val_end='2009-01-03', ################################### - #val_start='2009-01-15', - #val_end='2009-01-22', + val_start='2009-01-15', + val_end='2009-01-22', ################################### - val_start='2009-03-01', - val_end='2009-03-14', + # val_start='2009-03-01', + # val_end='2009-03-14', #test_start='2009-01-03', #test_end='2009-01-04', ################################### - #test_start='2009-01-22', - #test_end='2009-01-31', + test_start='2009-01-22', + test_end='2009-01-31', ################################### - test_start='2009-03-15', - test_end='2009-03-31', + # test_start='2009-03-15', + # test_end='2009-03-31', - sampling='hourly', + # sampling='hourly', + sampling="daily", + input_output_sampling4toarstats=("hourly", "daily"), use_multiprocessing=True, interpolation_limit=0, # as_image_like_data_format=False, # model=MyLSTMModel, - model=MyCNNModelSect, +# model=MyCNNModelSect, + model=MyCNNModel, **parser_args.__dict__) workflow.run() diff --git a/supplement/WRF_coord_list_from_IntelliO3.json b/supplement/WRF_coord_list_from_IntelliO3.json new file mode 100644 index 0000000000000000000000000000000000000000..00f83a5a56cf468f82fb21d85d37b33290691e9c --- /dev/null +++ b/supplement/WRF_coord_list_from_IntelliO3.json @@ -0,0 +1 @@ +["coords__52_598476__11_864362", "coords__51_33308__10_867189", "coords__49_515053__8_402374", "coords__53_24696__10_4565", "coords__49_240677__9_446661", "coords__52_489451__13_430844", "coords__49_741035__7_193486", "coords__54_527298__9_549379", "coords__53_715302__7_21398", "coords__48_472086__8_412808", "coords__47_508499__11_142889", "coords__47_84687__11_16085", "coords__54_309673__10_116564", "coords__53_562454__8_569406", "coords__50_791618__11_661233", "coords__49_872299__8_664619", "coords__47_915565__9_754411", "coords__48_972401__13_128934", "coords__52_08918__13_171803", "coords__47_693474__10_034748", "coords__52_362919__9_70612", "coords__51_536911__7_457464", "coords__48_173195__11_648036", "coords__51_83728__11_891525", "coords__53_315823__13_870311", "coords__53_077148__8_815781", "coords__48_001511__7_832122", "coords__51_462734__13_526797", "coords__51_897598__14_057064", "coords__50_497711__9_935862", "coords__50_32061__11_897491", "coords__48_169689__8_619859", "coords__50_10215__8_761242", "coords__52_82943__9_622951", "coords__48_708653__9_414453", "coords__47_777027__9_608422", "coords__51_483192__11_978358", "coords__48_773072__8_220214", "coords__47_518013__10_404233", "coords__51_592201__7_569839", "coords__48_524399__9_058547", "coords__49_632389__7_002141", "coords__54_07312__9_791584", "coords__52_541363__14_057456", "coords__48_663841__10_156297", "coords__52_684196__13_583772", "coords__49_107878__9_733231", "coords__51_182625__6_693875", "coords__48_899233__9_172792", "coords__48_72739__9_334039", "coords__51_103531__6_804103", "coords__51_551067__9_949761", "coords__50_561752__10_3753", "coords__52_348282__13_048529", "coords__48_154533__11_554669", "coords__53_835491__10_695936", "coords__50_587589__8_670028", "coords__51_57066__8_148061", "coords__48_02166__12_538176", "coords__51_855583__13_706503", "coords__54_186714__7_876328", "coords__48_476569__7_937806", "coords__47_898846__11_1112", "coords__51_798626__10_618275", "coords__49_842133__7_866208", "coords__48_710049__8_741153", "coords__51_524265__12_925879", "coords__53_868069__10_901677", "coords__47_58815__7_633272", "coords__51_485287__12_004464", "coords__48_890575__8_705113", "coords__53_630737__10_110595", "coords__51_897018__11_057462", "coords__51_403008__7_208572", "coords__47_985657__8_807748", "coords__52_484165__13_123697", "coords__48_645608__8_904442", "coords__51_453461__6_865108", "coords__53_1413__13_03166", "coords__51_740765__14_322827", "coords__51_406967__6_965641", "coords__51_175671__14_443772", "coords__51_054798__13_728719", "coords__54_43667__12_72528", "coords__53_362347__7_207261", "coords__51_862__6_874553", "coords__51_051247__13_729886", "coords__48_507703__9_051178", "coords__52_339951__14_531917", "coords__50_499954__11_134591", "coords__51_50758__10_238539", "coords__51_183773__7_052633", "coords__48_81707__13_2181", "coords__50_010323__8_451528", "coords__50_754704__6_093923", "coords__52_407719__12_157347", "coords__49_605911__10_963528", "coords__49_4645__8_754019", "coords__50_826__12_542056", "coords__51_156605__11_818216", "coords__50_828465__13_586547", "coords__50_619179__10_787137", "coords__50_017078__8_216497", "coords__52_653269__13_296081", "coords__52_609566__12_876509", "coords__48_562061__7_827066", "coords__51_168083__11_120728", "coords__49_237225__7_036322", "coords__51_657169__11_147792", "coords__53_030094__13_990561", "coords__52_59317__11_17235", "coords__48_345778__9_207639", "coords__53_060043__8_916967", "coords__53_568123__9_786234", "coords__51_448761__7_582294", "coords__52_420444__12_552303", "coords__48_853733__8_225808", "coords__51_547493__7_693836", "coords__50_532963__8_684398", "coords__52_268368__11_864795", "coords__51_93655__7_61158", "coords__51_096863__8_772858", "coords__50_655861__12_2052", "coords__50_933514__11_597061", "coords__51_406544__6_965991", "coords__52_194225__12_561389", "coords__47_723186__12_858856", "coords__51_249214__6_732383", "coords__51_303772__13_009405", "coords__50_89238__14_822847", "coords__51_496189__11_979072", "coords__52_165569__14_455691", "coords__51_67281__6_629575", "coords__48_182835__12_781385", "coords__51_090858__6_976433", "coords__50_889816__6_985164", "coords__49_825165__8_516797", "coords__53_78175__12_175511", "coords__50_424675__7_481394", "coords__50_058193__12_18865", "coords__53_302353__11_362965", "coords__51_054581__12_141314", "coords__50_938503__14_210161", "coords__48_858971__8_152136", "coords__52_255341__8_052861", "coords__54_09323__10_240596", "coords__49_07655__8_40666", "coords__52_127903__11_611456", "coords__54_33268__10_136175", "coords__49_299374__7_061678", "coords__49_589985__10_933278", "coords__47_563141__7_789067", "coords__51_839359__10_790175", "coords__50_653236__6_28107", "coords__51_662453__11_043384", "coords__51_530235__12_337597", "coords__52_447697__13_64705", "coords__52_97347__13_64578", "coords__51_843407__12_251367", "coords__48_573624__13_422039", "coords__51_080399__9_278935", "coords__49_423138__7_293522", "coords__50_930328__8_191934", "coords__48_85321__11_777817", "coords__52_473192__13_225144", "coords__49_869419__9_171545", "coords__49_506504__11_273913", "coords__51_303917__6_819967", "coords__50_221943__8_446078", "coords__51_430901__8_928172", "coords__48_699173__9_6694", "coords__51_447674__7_582803", "coords__51_154842__9_031753", "coords__53_18095__8_625456", "coords__54_16156__12_174106", "coords__50_651184__11_368876", "coords__50_6591__13_465077", "coords__51_830952__8_950597", "coords__53_57058__10_214872", "coords__50_383213__8_060997", "coords__51_593151__7_34867", "coords__52_401352__13_059945", "coords__51_744026__14_640592", "coords__49_672508__9_001981", "coords__48_397079__10_008291", "coords__49_431986__8_525819", "coords__49_416885__6_552036", "coords__51_478413__11_300392", "coords__53_56414__9_967883", "coords__53_638294__9_998009", "coords__52_998749__11_738461", "coords__51_43689__14_254336", "coords__49_233463__6_9876", "coords__51_392868__10_312378", "coords__51_360752__9_271233", "coords__48_274769__8_854501", "coords__51_901581__10_481319", "coords__48_089886__9_800325", "coords__50_416615__9_001078", "coords__52_49855__7_31747", "coords__51_285355__14_749731", "coords__50_959015__13_935698", "coords__48_8088__9_229744", "coords__50_629829__10_708347", "coords__47_650524__11_202008", "coords__50_916302__13_346825", "coords__47_476395__11_063066", "coords__52_121311__12_460597", "coords__52_294636__13_619783", "coords__49_279701__9_693027", "coords__51_314247__9_483397", "coords__49_363819__9_151447", "coords__53_111095__8_755619", "coords__50_164433__9_399442", "coords__52_643525__13_489531", "coords__48_048656__8_463597", "coords__51_642166__11_511397", "coords__49_991516__9_117972", "coords__52_608608__12_885195", "coords__48_086487__9_207036", "coords__50_837135__10_947153", "coords__51_497196__10_791403", "coords__48_847917__10_096292", "coords__51_698963__7_122714", "coords__52_020889__11_728127", "coords__51_119511__13_675006", "coords__50_2665__6_3781", "coords__51_600384__7_125475", "coords__48_326012__10_903049", "coords__51_337666__6_640242", "coords__50_684998__10_916992", "coords__50_979458__11_037926", "coords__53_83017__8_80122", "coords__53_520458__14_257408", "coords__49_357861__6_733539", "coords__53_817772__12_064709", "coords__47_72514__10_306561", "coords__50_759457__9_464639", "coords__49_438465__12_54887", "coords__52_95702__11_16705", "coords__50_570869__12_997278", "coords__52_543007__13_349116", "coords__50_19928__8_437208", "coords__51_291759__9_774589", "coords__51_520836__13_999486", "coords__51_356457__11_988897", "coords__50_753639__7_082675", "coords__47_968754__11_220172", "coords__49_028594__8_355628", "coords__49_54612__8_578803", "coords__47_809892__7_764528", "coords__50_050343__8_24495", "coords__49_270264__7_826522", "coords__52_80077__10_75673", "coords__50_770382__9_459403", "coords__47_664361__9_169289", "coords__50_65389__10_76944", "coords__47_932361__9_237111", "coords__48_678069__9_227769", "coords__51_75975__9_577714", "coords__48_882283__9_569903", "coords__51_200325__12_384813", "coords__48_691139__9_013925", "coords__50_76675__7_9735", "coords__54_171333__12_080003", "coords__50_978294__10_317236", "coords__51_708839__9_55462", "coords__50_354721__12_468952", "coords__51_036102__13_730206", "coords__53_524181__9_685031", "coords__52_292252__13_627789", "coords__49_300731__8_700103", "coords__47_91326__7_90803", "coords__52_99445__11_759531", "coords__53_543687__10_929825", "coords__48_119141__7_848925", "coords__51_622963__12_321664", "coords__51_317902__12_297412", "coords__52_931889__12_809481", "coords__49_634842__9_657919", "coords__49_123222__8_582828", "coords__50_125332__8_746342", "coords__50_970028__9_800261", "coords__50_549297__9_682161", "coords__49_653465__8_81725", "coords__51_837585__14_141703", "coords__50_571507__10_41488", "coords__53_487667__10_083647", "coords__49_718449__8_521947", "coords__49_052322__8_253548", "coords__49_553261__8_655886", "coords__51_318726__12_377628", "coords__53_871307__10_635384", "coords__50_323246__11_721605", "coords__48_832083__9_300811", "coords__49_254345__6_867744", "coords__51_019344__6_884636", "coords__51_870852__12_66369", "coords__51_154613__6_425711", "coords__50_103134__11_442592", "coords__51_758163__10_612481", "coords__51_746346__14_33455", "coords__51_29604__12_0616", "coords__49_804695__9_956419", "coords__48_488888__9_207319", "coords__48_396836__9_979031", "coords__51_207947__10_450997", "coords__53_59617__8_09059", "coords__50_827698__14_78617", "coords__49_446__7_7673", "coords__49_247288__10_584027", "coords__50_4243__7_7299", "coords__50_804256__8_769324", "coords__52_563835__14_015253", "coords__53_396348__12_463929", "coords__49_475758__8_478017", "coords__51_459518__6_648208", "coords__53_734959__14_070766", "coords__52_17017__9_06255", "coords__52_226936__10_473639", "coords__53_48093__9_857223", "coords__52_440811__10_816381", "coords__51_564503__14_3764", "coords__51_326939__6_195867", "coords__51_028877__7_005064", "coords__52_137856__11_642119", "coords__52_02317__8_548389", "coords__54_92497__8_30821", "coords__50_877316__12_074711", "coords__50_653248__10_668642", "coords__52_855244__11_173939", "coords__50_832462__12_917336"] \ No newline at end of file