disdrodb 0.0.21__py3-none-any.whl → 0.1.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.
- disdrodb/__init__.py +132 -15
- disdrodb/_config.py +4 -2
- disdrodb/_version.py +9 -4
- disdrodb/api/checks.py +264 -237
- disdrodb/api/configs.py +4 -8
- disdrodb/api/create_directories.py +235 -290
- disdrodb/api/info.py +217 -26
- disdrodb/api/io.py +295 -269
- disdrodb/api/path.py +597 -173
- disdrodb/api/search.py +486 -0
- disdrodb/{metadata/scripts → cli}/disdrodb_check_metadata_archive.py +12 -7
- disdrodb/{utils/pandas.py → cli/disdrodb_data_archive_directory.py} +9 -18
- disdrodb/cli/disdrodb_download_archive.py +86 -0
- disdrodb/cli/disdrodb_download_metadata_archive.py +53 -0
- disdrodb/cli/disdrodb_download_station.py +84 -0
- disdrodb/{api/scripts → cli}/disdrodb_initialize_station.py +22 -10
- disdrodb/cli/disdrodb_metadata_archive_directory.py +32 -0
- disdrodb/{data_transfer/scripts/disdrodb_download_station.py → cli/disdrodb_open_data_archive.py} +22 -22
- disdrodb/cli/disdrodb_open_logs_directory.py +69 -0
- disdrodb/{data_transfer/scripts/disdrodb_upload_station.py → cli/disdrodb_open_metadata_archive.py} +22 -24
- disdrodb/cli/disdrodb_open_metadata_directory.py +71 -0
- disdrodb/cli/disdrodb_open_product_directory.py +74 -0
- disdrodb/cli/disdrodb_open_readers_directory.py +32 -0
- disdrodb/{l0/scripts → cli}/disdrodb_run_l0.py +38 -31
- disdrodb/{l0/scripts → cli}/disdrodb_run_l0_station.py +32 -30
- disdrodb/{l0/scripts → cli}/disdrodb_run_l0a.py +30 -21
- disdrodb/{l0/scripts → cli}/disdrodb_run_l0a_station.py +24 -33
- disdrodb/{l0/scripts → cli}/disdrodb_run_l0b.py +30 -21
- disdrodb/{l0/scripts → cli}/disdrodb_run_l0b_station.py +25 -34
- disdrodb/cli/disdrodb_run_l0c.py +130 -0
- disdrodb/cli/disdrodb_run_l0c_station.py +129 -0
- disdrodb/cli/disdrodb_run_l1.py +122 -0
- disdrodb/cli/disdrodb_run_l1_station.py +121 -0
- disdrodb/cli/disdrodb_run_l2e.py +122 -0
- disdrodb/cli/disdrodb_run_l2e_station.py +122 -0
- disdrodb/cli/disdrodb_run_l2m.py +122 -0
- disdrodb/cli/disdrodb_run_l2m_station.py +122 -0
- disdrodb/cli/disdrodb_upload_archive.py +105 -0
- disdrodb/cli/disdrodb_upload_station.py +98 -0
- disdrodb/configs.py +90 -25
- disdrodb/data_transfer/__init__.py +22 -0
- disdrodb/data_transfer/download_data.py +87 -90
- disdrodb/data_transfer/upload_data.py +64 -37
- disdrodb/data_transfer/zenodo.py +15 -18
- disdrodb/docs.py +1 -1
- disdrodb/issue/__init__.py +17 -4
- disdrodb/issue/checks.py +10 -23
- disdrodb/issue/reader.py +9 -12
- disdrodb/issue/writer.py +14 -17
- disdrodb/l0/__init__.py +17 -26
- disdrodb/l0/check_configs.py +35 -23
- disdrodb/l0/check_standards.py +32 -42
- disdrodb/l0/configs/{Thies_LPM → LPM}/bins_diameter.yml +44 -44
- disdrodb/l0/configs/{Thies_LPM → LPM}/bins_velocity.yml +40 -40
- disdrodb/l0/configs/LPM/l0a_encodings.yml +80 -0
- disdrodb/l0/configs/{Thies_LPM → LPM}/l0b_cf_attrs.yml +62 -59
- disdrodb/l0/configs/{Thies_LPM → LPM}/l0b_encodings.yml +9 -9
- disdrodb/l0/configs/{Thies_LPM → LPM}/raw_data_format.yml +245 -245
- disdrodb/l0/configs/{OTT_Parsivel → PARSIVEL}/bins_diameter.yml +66 -66
- disdrodb/l0/configs/{OTT_Parsivel → PARSIVEL}/bins_velocity.yml +64 -64
- disdrodb/l0/configs/PARSIVEL/l0a_encodings.yml +32 -0
- disdrodb/l0/configs/{OTT_Parsivel → PARSIVEL}/l0b_cf_attrs.yml +22 -20
- disdrodb/l0/configs/{OTT_Parsivel → PARSIVEL}/l0b_encodings.yml +17 -17
- disdrodb/l0/configs/{OTT_Parsivel → PARSIVEL}/raw_data_format.yml +77 -77
- disdrodb/l0/configs/{OTT_Parsivel2 → PARSIVEL2}/bins_diameter.yml +64 -64
- disdrodb/l0/configs/{OTT_Parsivel2 → PARSIVEL2}/bins_velocity.yml +64 -64
- disdrodb/l0/configs/PARSIVEL2/l0a_encodings.yml +39 -0
- disdrodb/l0/configs/{OTT_Parsivel2 → PARSIVEL2}/l0b_cf_attrs.yml +24 -22
- disdrodb/l0/configs/{OTT_Parsivel2 → PARSIVEL2}/l0b_encodings.yml +20 -20
- disdrodb/l0/configs/{OTT_Parsivel2 → PARSIVEL2}/raw_data_format.yml +98 -98
- disdrodb/l0/configs/{RD_80 → RD80}/bins_diameter.yml +40 -40
- disdrodb/l0/configs/RD80/l0a_encodings.yml +16 -0
- disdrodb/l0/configs/{RD_80 → RD80}/l0b_cf_attrs.yml +3 -3
- disdrodb/l0/configs/RD80/l0b_encodings.yml +135 -0
- disdrodb/l0/configs/{RD_80 → RD80}/raw_data_format.yml +48 -48
- disdrodb/l0/l0_reader.py +216 -340
- disdrodb/l0/l0a_processing.py +237 -208
- disdrodb/l0/l0b_nc_processing.py +227 -80
- disdrodb/l0/l0b_processing.py +93 -173
- disdrodb/l0/l0c_processing.py +627 -0
- disdrodb/l0/readers/{ARM → LPM/ARM}/ARM_LPM.py +36 -58
- disdrodb/l0/readers/LPM/AUSTRALIA/MELBOURNE_2007_LPM.py +226 -0
- disdrodb/l0/readers/LPM/BRAZIL/CHUVA_LPM.py +185 -0
- disdrodb/l0/readers/LPM/BRAZIL/GOAMAZON_LPM.py +183 -0
- disdrodb/l0/readers/LPM/ITALY/GID_LPM.py +179 -0
- disdrodb/l0/readers/{UK → LPM/UK}/DIVEN.py +14 -35
- disdrodb/l0/readers/PARSIVEL/AUSTRALIA/MELBOURNE_2007_PARSIVEL.py +157 -0
- disdrodb/l0/readers/PARSIVEL/CHINA/CHONGQING.py +113 -0
- disdrodb/l0/readers/{EPFL → PARSIVEL/EPFL}/ARCTIC_2021.py +40 -57
- disdrodb/l0/readers/{EPFL → PARSIVEL/EPFL}/COMMON_2011.py +37 -54
- disdrodb/l0/readers/{EPFL → PARSIVEL/EPFL}/DAVOS_2009_2011.py +34 -51
- disdrodb/l0/readers/{EPFL → PARSIVEL/EPFL}/EPFL_2009.py +34 -51
- disdrodb/l0/readers/{EPFL/PARADISO_2014.py → PARSIVEL/EPFL/EPFL_ROOF_2008.py} +38 -50
- disdrodb/l0/readers/PARSIVEL/EPFL/EPFL_ROOF_2010.py +105 -0
- disdrodb/l0/readers/{EPFL → PARSIVEL/EPFL}/EPFL_ROOF_2011.py +34 -51
- disdrodb/l0/readers/{EPFL → PARSIVEL/EPFL}/EPFL_ROOF_2012.py +33 -51
- disdrodb/l0/readers/{EPFL → PARSIVEL/EPFL}/GENEPI_2007.py +25 -44
- disdrodb/l0/readers/{EPFL → PARSIVEL/EPFL}/GRAND_ST_BERNARD_2007.py +25 -44
- disdrodb/l0/readers/{EPFL → PARSIVEL/EPFL}/GRAND_ST_BERNARD_2007_2.py +25 -44
- disdrodb/l0/readers/{EPFL → PARSIVEL/EPFL}/HPICONET_2010.py +34 -51
- disdrodb/l0/readers/{EPFL/EPFL_ROOF_2010.py → PARSIVEL/EPFL/HYMEX_LTE_SOP2.py} +37 -50
- disdrodb/l0/readers/PARSIVEL/EPFL/HYMEX_LTE_SOP3.py +111 -0
- disdrodb/l0/readers/{EPFL → PARSIVEL/EPFL}/HYMEX_LTE_SOP4.py +36 -54
- disdrodb/l0/readers/{EPFL → PARSIVEL/EPFL}/LOCARNO_2018.py +34 -52
- disdrodb/l0/readers/{EPFL → PARSIVEL/EPFL}/LOCARNO_2019.py +38 -56
- disdrodb/l0/readers/PARSIVEL/EPFL/PARADISO_2014.py +105 -0
- disdrodb/l0/readers/{EPFL → PARSIVEL/EPFL}/PARSIVEL_2007.py +27 -45
- disdrodb/l0/readers/{EPFL → PARSIVEL/EPFL}/PLATO_2019.py +24 -44
- disdrodb/l0/readers/PARSIVEL/EPFL/RACLETS_2019.py +140 -0
- disdrodb/l0/readers/{EPFL → PARSIVEL/EPFL}/RACLETS_2019_WJF.py +41 -59
- disdrodb/l0/readers/{EPFL → PARSIVEL/EPFL}/RIETHOLZBACH_2011.py +34 -51
- disdrodb/l0/readers/PARSIVEL/EPFL/SAMOYLOV_2017.py +117 -0
- disdrodb/l0/readers/PARSIVEL/EPFL/SAMOYLOV_2019.py +137 -0
- disdrodb/l0/readers/{EPFL → PARSIVEL/EPFL}/UNIL_2022.py +42 -55
- disdrodb/l0/readers/PARSIVEL/GPM/IFLOODS.py +104 -0
- disdrodb/l0/readers/{GPM → PARSIVEL/GPM}/LPVEX.py +29 -48
- disdrodb/l0/readers/PARSIVEL/GPM/MC3E.py +184 -0
- disdrodb/l0/readers/PARSIVEL/NCAR/CCOPE_2015.py +113 -0
- disdrodb/l0/readers/{NCAR/VORTEX_SE_2016_P1.py → PARSIVEL/NCAR/OWLES_MIPS.py} +46 -72
- disdrodb/l0/readers/PARSIVEL/NCAR/PECAN_MOBILE.py +125 -0
- disdrodb/l0/readers/{NCAR/OWLES_MIPS.py → PARSIVEL/NCAR/PLOWS_MIPS.py} +45 -64
- disdrodb/l0/readers/PARSIVEL/NCAR/VORTEX2_2009.py +114 -0
- disdrodb/l0/readers/PARSIVEL/NCAR/VORTEX2_2010.py +176 -0
- disdrodb/l0/readers/PARSIVEL/NCAR/VORTEX2_2010_UF.py +183 -0
- disdrodb/l0/readers/{ARM/ARM_LD.py → PARSIVEL2/ARM/ARM_PARSIVEL2.py} +27 -50
- disdrodb/l0/readers/PARSIVEL2/BRAZIL/CHUVA_PARSIVEL2.py +163 -0
- disdrodb/l0/readers/PARSIVEL2/BRAZIL/GOAMAZON_PARSIVEL2.py +163 -0
- disdrodb/l0/readers/{DENMARK → PARSIVEL2/DENMARK}/EROSION_nc.py +14 -35
- disdrodb/l0/readers/PARSIVEL2/FRANCE/SIRTA_PARSIVEL2.py +119 -0
- disdrodb/l0/readers/PARSIVEL2/GPM/GCPEX.py +104 -0
- disdrodb/l0/readers/PARSIVEL2/GPM/NSSTC.py +176 -0
- disdrodb/l0/readers/PARSIVEL2/ITALY/GID_PARSIVEL2.py +32 -0
- disdrodb/l0/readers/PARSIVEL2/MEXICO/OH_IIUNAM_nc.py +56 -0
- disdrodb/l0/readers/PARSIVEL2/NCAR/PECAN_FP3.py +120 -0
- disdrodb/l0/readers/{NCAR → PARSIVEL2/NCAR}/PECAN_MIPS.py +45 -64
- disdrodb/l0/readers/PARSIVEL2/NCAR/RELAMPAGO_PARSIVEL2.py +181 -0
- disdrodb/l0/readers/PARSIVEL2/NCAR/SNOWIE_PJ.py +160 -0
- disdrodb/l0/readers/PARSIVEL2/NCAR/SNOWIE_SB.py +160 -0
- disdrodb/l0/readers/{NCAR/PLOWS_MIPS.py → PARSIVEL2/NCAR/VORTEX_SE_2016_P1.py} +49 -66
- disdrodb/l0/readers/PARSIVEL2/NCAR/VORTEX_SE_2016_P2.py +118 -0
- disdrodb/l0/readers/PARSIVEL2/NCAR/VORTEX_SE_2016_PIPS.py +152 -0
- disdrodb/l0/readers/PARSIVEL2/NETHERLANDS/DELFT.py +166 -0
- disdrodb/l0/readers/{NCAR/RELAMPAGO_RD80.py → RD80/BRAZIL/CHUVA_RD80.py} +36 -60
- disdrodb/l0/readers/{BRAZIL → RD80/BRAZIL}/GOAMAZON_RD80.py +36 -55
- disdrodb/l0/readers/{NCAR → RD80/NCAR}/CINDY_2011_RD80.py +35 -54
- disdrodb/l0/readers/{BRAZIL/CHUVA_RD80.py → RD80/NCAR/RELAMPAGO_RD80.py} +40 -54
- disdrodb/l0/readers/template_reader_raw_netcdf_data.py +62 -0
- disdrodb/l0/readers/{reader_template.py → template_reader_raw_text_data.py} +20 -44
- disdrodb/l0/routines.py +885 -581
- disdrodb/l0/standards.py +72 -236
- disdrodb/l0/template_tools.py +104 -109
- disdrodb/l1/__init__.py +17 -0
- disdrodb/l1/beard_model.py +716 -0
- disdrodb/l1/encoding_attrs.py +620 -0
- disdrodb/l1/fall_velocity.py +260 -0
- disdrodb/l1/filters.py +192 -0
- disdrodb/l1/processing.py +200 -0
- disdrodb/l1/resampling.py +236 -0
- disdrodb/l1/routines.py +357 -0
- disdrodb/l1_env/__init__.py +17 -0
- disdrodb/l1_env/routines.py +38 -0
- disdrodb/l2/__init__.py +17 -0
- disdrodb/l2/empirical_dsd.py +1735 -0
- disdrodb/l2/event.py +388 -0
- disdrodb/l2/processing.py +519 -0
- disdrodb/l2/processing_options.py +213 -0
- disdrodb/l2/routines.py +868 -0
- disdrodb/metadata/__init__.py +9 -2
- disdrodb/metadata/checks.py +165 -118
- disdrodb/metadata/download.py +81 -0
- disdrodb/metadata/geolocation.py +146 -0
- disdrodb/metadata/info.py +20 -13
- disdrodb/metadata/manipulation.py +1 -1
- disdrodb/metadata/reader.py +59 -8
- disdrodb/metadata/search.py +77 -144
- disdrodb/metadata/standards.py +7 -8
- disdrodb/metadata/writer.py +8 -14
- disdrodb/psd/__init__.py +38 -0
- disdrodb/psd/fitting.py +2146 -0
- disdrodb/psd/models.py +774 -0
- disdrodb/routines.py +1176 -0
- disdrodb/scattering/__init__.py +28 -0
- disdrodb/scattering/axis_ratio.py +344 -0
- disdrodb/scattering/routines.py +456 -0
- disdrodb/utils/__init__.py +17 -0
- disdrodb/utils/attrs.py +208 -0
- disdrodb/utils/cli.py +269 -0
- disdrodb/utils/compression.py +60 -42
- disdrodb/utils/dask.py +62 -0
- disdrodb/utils/decorators.py +110 -0
- disdrodb/utils/directories.py +107 -46
- disdrodb/utils/encoding.py +127 -0
- disdrodb/utils/list.py +29 -0
- disdrodb/utils/logger.py +168 -46
- disdrodb/utils/time.py +657 -0
- disdrodb/utils/warnings.py +30 -0
- disdrodb/utils/writer.py +57 -0
- disdrodb/utils/xarray.py +138 -47
- disdrodb/utils/yaml.py +0 -1
- disdrodb/viz/__init__.py +17 -0
- disdrodb/viz/plots.py +17 -0
- disdrodb-0.1.0.dist-info/METADATA +321 -0
- disdrodb-0.1.0.dist-info/RECORD +216 -0
- {disdrodb-0.0.21.dist-info → disdrodb-0.1.0.dist-info}/WHEEL +1 -1
- disdrodb-0.1.0.dist-info/entry_points.txt +30 -0
- disdrodb/data_transfer/scripts/disdrodb_download_archive.py +0 -53
- disdrodb/data_transfer/scripts/disdrodb_upload_archive.py +0 -57
- disdrodb/l0/configs/OTT_Parsivel/l0a_encodings.yml +0 -32
- disdrodb/l0/configs/OTT_Parsivel2/l0a_encodings.yml +0 -39
- disdrodb/l0/configs/RD_80/l0a_encodings.yml +0 -16
- disdrodb/l0/configs/RD_80/l0b_encodings.yml +0 -135
- disdrodb/l0/configs/Thies_LPM/l0a_encodings.yml +0 -80
- disdrodb/l0/io.py +0 -257
- disdrodb/l0/l0_processing.py +0 -1091
- disdrodb/l0/readers/AUSTRALIA/MELBOURNE_2007_OTT.py +0 -178
- disdrodb/l0/readers/AUSTRALIA/MELBOURNE_2007_THIES.py +0 -247
- disdrodb/l0/readers/BRAZIL/CHUVA_LPM.py +0 -204
- disdrodb/l0/readers/BRAZIL/CHUVA_OTT.py +0 -183
- disdrodb/l0/readers/BRAZIL/GOAMAZON_LPM.py +0 -204
- disdrodb/l0/readers/BRAZIL/GOAMAZON_OTT.py +0 -183
- disdrodb/l0/readers/CHINA/CHONGQING.py +0 -131
- disdrodb/l0/readers/EPFL/EPFL_ROOF_2008.py +0 -128
- disdrodb/l0/readers/EPFL/HYMEX_LTE_SOP2.py +0 -127
- disdrodb/l0/readers/EPFL/HYMEX_LTE_SOP3.py +0 -129
- disdrodb/l0/readers/EPFL/RACLETS_2019.py +0 -158
- disdrodb/l0/readers/EPFL/SAMOYLOV_2017.py +0 -136
- disdrodb/l0/readers/EPFL/SAMOYLOV_2019.py +0 -158
- disdrodb/l0/readers/FRANCE/SIRTA_OTT2.py +0 -138
- disdrodb/l0/readers/GPM/GCPEX.py +0 -123
- disdrodb/l0/readers/GPM/IFLOODS.py +0 -123
- disdrodb/l0/readers/GPM/MC3E.py +0 -123
- disdrodb/l0/readers/GPM/NSSTC.py +0 -164
- disdrodb/l0/readers/ITALY/GID.py +0 -199
- disdrodb/l0/readers/MEXICO/OH_IIUNAM_nc.py +0 -92
- disdrodb/l0/readers/NCAR/CCOPE_2015.py +0 -133
- disdrodb/l0/readers/NCAR/PECAN_FP3.py +0 -137
- disdrodb/l0/readers/NCAR/PECAN_MOBILE.py +0 -144
- disdrodb/l0/readers/NCAR/RELAMPAGO_OTT.py +0 -195
- disdrodb/l0/readers/NCAR/SNOWIE_PJ.py +0 -172
- disdrodb/l0/readers/NCAR/SNOWIE_SB.py +0 -179
- disdrodb/l0/readers/NCAR/VORTEX2_2009.py +0 -133
- disdrodb/l0/readers/NCAR/VORTEX2_2010.py +0 -188
- disdrodb/l0/readers/NCAR/VORTEX2_2010_UF.py +0 -191
- disdrodb/l0/readers/NCAR/VORTEX_SE_2016_P2.py +0 -135
- disdrodb/l0/readers/NCAR/VORTEX_SE_2016_PIPS.py +0 -170
- disdrodb/l0/readers/NETHERLANDS/DELFT.py +0 -187
- disdrodb/l0/readers/SPAIN/SBEGUERIA.py +0 -179
- disdrodb/l0/scripts/disdrodb_run_l0b_concat.py +0 -93
- disdrodb/l0/scripts/disdrodb_run_l0b_concat_station.py +0 -85
- disdrodb/utils/netcdf.py +0 -452
- disdrodb/utils/scripts.py +0 -102
- disdrodb-0.0.21.dist-info/AUTHORS.md +0 -18
- disdrodb-0.0.21.dist-info/METADATA +0 -186
- disdrodb-0.0.21.dist-info/RECORD +0 -168
- disdrodb-0.0.21.dist-info/entry_points.txt +0 -15
- /disdrodb/l0/configs/{RD_80 → RD80}/bins_velocity.yml +0 -0
- /disdrodb/l0/manuals/{Thies_LPM.pdf → LPM.pdf} +0 -0
- /disdrodb/l0/manuals/{ODM_470.pdf → ODM470.pdf} +0 -0
- /disdrodb/l0/manuals/{OTT_Parsivel.pdf → PARSIVEL.pdf} +0 -0
- /disdrodb/l0/manuals/{OTT_Parsivel2.pdf → PARSIVEL2.pdf} +0 -0
- /disdrodb/l0/manuals/{PWS_100.pdf → PWS100.pdf} +0 -0
- /disdrodb/l0/manuals/{RD_80.pdf → RD80.pdf} +0 -0
- {disdrodb-0.0.21.dist-info → disdrodb-0.1.0.dist-info/licenses}/LICENSE +0 -0
- {disdrodb-0.0.21.dist-info → disdrodb-0.1.0.dist-info}/top_level.txt +0 -0
disdrodb/l0/l0b_nc_processing.py
CHANGED
|
@@ -18,12 +18,11 @@
|
|
|
18
18
|
# -----------------------------------------------------------------------------.
|
|
19
19
|
"""Functions to process DISDRODB raw netCDF files into DISDRODB L0B netCDF files."""
|
|
20
20
|
|
|
21
|
-
import copy
|
|
22
21
|
import logging
|
|
23
22
|
|
|
24
23
|
import numpy as np
|
|
25
|
-
import xarray as xr
|
|
26
24
|
|
|
25
|
+
from disdrodb.api.checks import check_sensor_name
|
|
27
26
|
from disdrodb.l0.l0b_processing import finalize_dataset
|
|
28
27
|
from disdrodb.l0.standards import (
|
|
29
28
|
get_bin_coords_dict,
|
|
@@ -36,7 +35,6 @@ from disdrodb.l0.standards import (
|
|
|
36
35
|
from disdrodb.utils.logger import (
|
|
37
36
|
# log_warning,
|
|
38
37
|
# log_debug,
|
|
39
|
-
log_error,
|
|
40
38
|
log_info,
|
|
41
39
|
)
|
|
42
40
|
|
|
@@ -46,7 +44,7 @@ logger = logging.getLogger(__name__)
|
|
|
46
44
|
|
|
47
45
|
|
|
48
46
|
def _check_dict_names_validity(dict_names, sensor_name):
|
|
49
|
-
"""Check dict_names dictionary values validity."""
|
|
47
|
+
"""Check ``dict_names`` dictionary values validity."""
|
|
50
48
|
valid_names = get_valid_names(sensor_name)
|
|
51
49
|
keys = np.array(list(dict_names.keys()))
|
|
52
50
|
values = np.array(list(dict_names.values()))
|
|
@@ -56,13 +54,11 @@ def _check_dict_names_validity(dict_names, sensor_name):
|
|
|
56
54
|
# Report invalid keys and raise error
|
|
57
55
|
invalid_dict = {k: dict_names[k] for k in invalid_keys}
|
|
58
56
|
msg = f"The following dict_names values are not valid: {invalid_dict}"
|
|
59
|
-
log_error(logger=logger, msg=msg, verbose=False)
|
|
60
57
|
raise ValueError(msg)
|
|
61
|
-
return None
|
|
62
58
|
|
|
63
59
|
|
|
64
60
|
def _get_dict_names_variables(dict_names, sensor_name):
|
|
65
|
-
"""Get DISDRODB variables specified in dict_names
|
|
61
|
+
"""Get DISDRODB variables specified in ``dict_names``."""
|
|
66
62
|
possible_variables = get_valid_variable_names(sensor_name)
|
|
67
63
|
dictionary_names = list(dict_names.values())
|
|
68
64
|
variables = [name for name in dictionary_names if name in possible_variables]
|
|
@@ -78,7 +74,7 @@ def _get_missing_variables(ds, dict_names, sensor_name):
|
|
|
78
74
|
|
|
79
75
|
|
|
80
76
|
def rename_dataset(ds, dict_names):
|
|
81
|
-
"""Rename Dataset variables, coordinates and dimensions."""
|
|
77
|
+
"""Rename xr.Dataset variables, coordinates and dimensions."""
|
|
82
78
|
# Get dataset variables, coordinates and dimensions of the dataset
|
|
83
79
|
ds_vars = list(ds.data_vars)
|
|
84
80
|
ds_dims = list(ds.dims)
|
|
@@ -101,24 +97,23 @@ def rename_dataset(ds, dict_names):
|
|
|
101
97
|
|
|
102
98
|
|
|
103
99
|
def subset_dataset(ds, dict_names, sensor_name):
|
|
104
|
-
"""Subset Dataset with expected variables."""
|
|
100
|
+
"""Subset xr.Dataset with expected variables."""
|
|
105
101
|
# Get valid variable names
|
|
106
102
|
possible_variables = get_valid_variable_names(sensor_name)
|
|
107
103
|
# Get variables availables in the dict_names and dataset
|
|
108
104
|
dataset_variables = list(ds.data_vars)
|
|
109
105
|
dictionary_names = list(dict_names.values())
|
|
110
106
|
# Get subset variables
|
|
111
|
-
subset_variables = []
|
|
112
|
-
for var in dataset_variables:
|
|
113
|
-
if var in dictionary_names and var in possible_variables:
|
|
114
|
-
subset_variables.append(var)
|
|
107
|
+
subset_variables = [var for var in dataset_variables if var in dictionary_names and var in possible_variables]
|
|
115
108
|
# Subset the dataset
|
|
116
109
|
ds = ds[subset_variables]
|
|
117
110
|
return ds
|
|
118
111
|
|
|
119
112
|
|
|
120
113
|
def add_dataset_missing_variables(ds, missing_vars, sensor_name):
|
|
121
|
-
"""Add missing Dataset variables as nan DataArrays."""
|
|
114
|
+
"""Add missing xr.Dataset variables as ``np.nan`` xr.DataArrays."""
|
|
115
|
+
import xarray as xr
|
|
116
|
+
|
|
122
117
|
from disdrodb.l0.standards import get_variables_dimension
|
|
123
118
|
|
|
124
119
|
# Get dimension of each variables
|
|
@@ -128,7 +123,7 @@ def add_dataset_missing_variables(ds, missing_vars, sensor_name):
|
|
|
128
123
|
# Get variable dimension
|
|
129
124
|
dims = var_dims_dict[var]
|
|
130
125
|
# Retrieve expected shape
|
|
131
|
-
expected_shape = [ds.
|
|
126
|
+
expected_shape = [ds.sizes[dim] for dim in dims]
|
|
132
127
|
# Create DataArray
|
|
133
128
|
arr = np.zeros(expected_shape) * np.nan
|
|
134
129
|
da = xr.DataArray(arr, dims=dims)
|
|
@@ -137,15 +132,15 @@ def add_dataset_missing_variables(ds, missing_vars, sensor_name):
|
|
|
137
132
|
return ds
|
|
138
133
|
|
|
139
134
|
|
|
140
|
-
def
|
|
135
|
+
def standardize_raw_dataset(ds, dict_names, sensor_name):
|
|
141
136
|
"""This function preprocess raw netCDF to improve compatibility with DISDRODB standards.
|
|
142
137
|
|
|
143
|
-
This function checks validity of the dict_names
|
|
144
|
-
If some variables specified in the dict_names are missing, it adds a
|
|
138
|
+
This function checks validity of the ``dict_names``, rename and subset the data accordingly.
|
|
139
|
+
If some variables specified in the ``dict_names`` are missing, it adds a ``np.nan`` xr.DataArray !
|
|
145
140
|
|
|
146
141
|
Parameters
|
|
147
142
|
----------
|
|
148
|
-
ds
|
|
143
|
+
ds : xarray.Dataset
|
|
149
144
|
Raw netCDF to be converted to DISDRODB standards.
|
|
150
145
|
dict_names : dict
|
|
151
146
|
Dictionary mapping raw netCDF variables/coordinates/dimension names
|
|
@@ -155,10 +150,13 @@ def preprocess_raw_netcdf(ds, dict_names, sensor_name):
|
|
|
155
150
|
|
|
156
151
|
Returns
|
|
157
152
|
-------
|
|
158
|
-
ds
|
|
159
|
-
xarray Dataset with
|
|
153
|
+
ds : xarray.Dataset
|
|
154
|
+
xarray Dataset with variables compliant with DISDRODB conventions.
|
|
160
155
|
|
|
161
156
|
"""
|
|
157
|
+
# Check if the sensor name is valid
|
|
158
|
+
check_sensor_name(sensor_name)
|
|
159
|
+
|
|
162
160
|
# Check variable_dict has valid values
|
|
163
161
|
# - Check valid DISDRODB variables + dimensions + coords
|
|
164
162
|
_check_dict_names_validity(dict_names=dict_names, sensor_name=sensor_name)
|
|
@@ -175,32 +173,35 @@ def preprocess_raw_netcdf(ds, dict_names, sensor_name):
|
|
|
175
173
|
ds = add_dataset_missing_variables(ds=ds, missing_vars=missing_vars, sensor_name=sensor_name)
|
|
176
174
|
|
|
177
175
|
# Update the coordinates for (diameter and velocity)
|
|
178
|
-
|
|
179
|
-
ds = ds.assign_coords(coords)
|
|
176
|
+
ds = ds.assign_coords(get_bin_coords_dict(sensor_name))
|
|
180
177
|
|
|
181
178
|
# Return dataset
|
|
182
179
|
return ds
|
|
183
180
|
|
|
184
181
|
|
|
185
|
-
def replace_custom_nan_flags(ds, dict_nan_flags, verbose=False):
|
|
186
|
-
"""Set values corresponding to nan_flags to np.nan
|
|
182
|
+
def replace_custom_nan_flags(ds, dict_nan_flags, logger=None, verbose=False):
|
|
183
|
+
"""Set values corresponding to ``nan_flags`` to ``np.nan``.
|
|
187
184
|
|
|
188
185
|
This function must be used in a reader, if necessary.
|
|
189
186
|
|
|
190
187
|
Parameters
|
|
191
188
|
----------
|
|
192
|
-
df
|
|
189
|
+
df : xarray.Dataset
|
|
193
190
|
Input xarray dataset
|
|
194
191
|
dict_nan_flags : dict
|
|
195
|
-
Dictionary with nan flags value to set as np.nan
|
|
192
|
+
Dictionary with nan flags value to set as ``np.nan``.
|
|
193
|
+
verbose : bool
|
|
194
|
+
Whether to verbose the processing. The default value is ``False``.
|
|
196
195
|
|
|
197
196
|
Returns
|
|
198
197
|
-------
|
|
199
|
-
|
|
200
|
-
Dataset without nan_flags values.
|
|
198
|
+
xarray.Dataset
|
|
199
|
+
Dataset without ``nan_flags`` values.
|
|
201
200
|
"""
|
|
202
201
|
# Loop over the needed variable, and replace nan_flags values with np.nan
|
|
203
202
|
for var, nan_flags in dict_nan_flags.items():
|
|
203
|
+
# Ensure nan_flags is a list
|
|
204
|
+
nan_flags = [nan_flags] if not isinstance(nan_flags, list) else nan_flags
|
|
204
205
|
# If the variable is in the dataframe
|
|
205
206
|
if var in ds:
|
|
206
207
|
# Get occurrence of nan_flags
|
|
@@ -215,12 +216,12 @@ def replace_custom_nan_flags(ds, dict_nan_flags, verbose=False):
|
|
|
215
216
|
return ds
|
|
216
217
|
|
|
217
218
|
|
|
218
|
-
def replace_nan_flags(ds, sensor_name, verbose):
|
|
219
|
-
"""Set values corresponding to nan_flags to np.nan
|
|
219
|
+
def replace_nan_flags(ds, sensor_name, verbose, logger=None):
|
|
220
|
+
"""Set values corresponding to ``nan_flags`` to ``np.nan``.
|
|
220
221
|
|
|
221
222
|
Parameters
|
|
222
223
|
----------
|
|
223
|
-
ds
|
|
224
|
+
ds : xarray.Dataset
|
|
224
225
|
Input xarray dataset
|
|
225
226
|
dict_nan_flags : dict
|
|
226
227
|
Dictionary with nan flags value to set as np.nan
|
|
@@ -229,22 +230,22 @@ def replace_nan_flags(ds, sensor_name, verbose):
|
|
|
229
230
|
|
|
230
231
|
Returns
|
|
231
232
|
-------
|
|
232
|
-
|
|
233
|
-
Dataset without nan_flags values.
|
|
233
|
+
xarray.Dataset
|
|
234
|
+
Dataset without ``nan_flags`` values.
|
|
234
235
|
"""
|
|
235
236
|
# Get dictionary of nan flags
|
|
236
237
|
dict_nan_flags = get_nan_flags_dict(sensor_name)
|
|
237
238
|
# Replace nan flags with nan
|
|
238
|
-
ds = replace_custom_nan_flags(ds, dict_nan_flags, verbose=verbose)
|
|
239
|
+
ds = replace_custom_nan_flags(ds, dict_nan_flags=dict_nan_flags, logger=logger, verbose=verbose)
|
|
239
240
|
return ds
|
|
240
241
|
|
|
241
242
|
|
|
242
|
-
def set_nan_outside_data_range(ds, sensor_name, verbose):
|
|
243
|
-
"""Set values outside the data range as np.nan
|
|
243
|
+
def set_nan_outside_data_range(ds, sensor_name, verbose, logger=None):
|
|
244
|
+
"""Set values outside the data range as ``np.nan``.
|
|
244
245
|
|
|
245
246
|
Parameters
|
|
246
247
|
----------
|
|
247
|
-
ds
|
|
248
|
+
ds : xarray.Dataset
|
|
248
249
|
Input xarray dataset
|
|
249
250
|
sensor_name : str
|
|
250
251
|
Name of the sensor.
|
|
@@ -253,7 +254,7 @@ def set_nan_outside_data_range(ds, sensor_name, verbose):
|
|
|
253
254
|
|
|
254
255
|
Returns
|
|
255
256
|
-------
|
|
256
|
-
|
|
257
|
+
xarray.Dataset
|
|
257
258
|
Dataset without values outside the expected data range.
|
|
258
259
|
"""
|
|
259
260
|
# Get dictionary of data_range
|
|
@@ -277,12 +278,12 @@ def set_nan_outside_data_range(ds, sensor_name, verbose):
|
|
|
277
278
|
return ds
|
|
278
279
|
|
|
279
280
|
|
|
280
|
-
def set_nan_invalid_values(ds, sensor_name, verbose):
|
|
281
|
-
"""Set invalid (class) values to np.nan
|
|
281
|
+
def set_nan_invalid_values(ds, sensor_name, verbose, logger=None):
|
|
282
|
+
"""Set invalid (class) values to ``np.nan``.
|
|
282
283
|
|
|
283
284
|
Parameters
|
|
284
285
|
----------
|
|
285
|
-
ds
|
|
286
|
+
ds : xarray.Dataset
|
|
286
287
|
Input xarray dataset
|
|
287
288
|
sensor_name : str
|
|
288
289
|
Name of the sensor.
|
|
@@ -291,7 +292,7 @@ def set_nan_invalid_values(ds, sensor_name, verbose):
|
|
|
291
292
|
|
|
292
293
|
Returns
|
|
293
294
|
-------
|
|
294
|
-
|
|
295
|
+
xarray.Dataset
|
|
295
296
|
Dataset without invalid values.
|
|
296
297
|
"""
|
|
297
298
|
# Get dictionary of valid values
|
|
@@ -313,25 +314,146 @@ def set_nan_invalid_values(ds, sensor_name, verbose):
|
|
|
313
314
|
return ds
|
|
314
315
|
|
|
315
316
|
|
|
316
|
-
def
|
|
317
|
+
def drop_timesteps(ds, timesteps: list):
|
|
318
|
+
"""
|
|
319
|
+
Drop specific time steps from a Dataset.
|
|
320
|
+
|
|
321
|
+
Parameters
|
|
322
|
+
----------
|
|
323
|
+
ds : xarray.Dataset
|
|
324
|
+
Input dataset with a 'time' dimension.
|
|
325
|
+
timesteps : list
|
|
326
|
+
List of datetime-like values to remove.
|
|
327
|
+
|
|
328
|
+
Returns
|
|
329
|
+
-------
|
|
330
|
+
xarray.Dataset
|
|
331
|
+
Dataset with specified timesteps removed.
|
|
332
|
+
|
|
333
|
+
Raises
|
|
334
|
+
------
|
|
335
|
+
ValueError
|
|
336
|
+
If no timesteps remain after removal.
|
|
337
|
+
"""
|
|
338
|
+
# Create a boolean mask of valid timesteps
|
|
339
|
+
times = ds["time"].to_numpy()
|
|
340
|
+
mask = ~np.isin(times, np.array(timesteps, dtype=times.dtype))
|
|
341
|
+
ds_filtered = ds.isel(time=mask)
|
|
342
|
+
|
|
343
|
+
# Ensure there's at least one timestep left
|
|
344
|
+
if ds_filtered.sizes.get("time", 0) == 0:
|
|
345
|
+
raise ValueError(
|
|
346
|
+
"No timesteps left after removing problematic timesteps. " "Maybe you need to adjust the issue YAML file.",
|
|
347
|
+
)
|
|
348
|
+
return ds_filtered
|
|
349
|
+
|
|
350
|
+
|
|
351
|
+
def drop_time_periods(ds, time_periods: list):
|
|
352
|
+
"""
|
|
353
|
+
Drop all time steps within any of the specified time intervals.
|
|
354
|
+
|
|
355
|
+
Parameters
|
|
356
|
+
----------
|
|
357
|
+
ds : xarray.Dataset
|
|
358
|
+
Input dataset with a 'time' dimension.
|
|
359
|
+
time_periods : list of tuple
|
|
360
|
+
Each tuple is (start_time, end_time), datetime-like, inclusive.
|
|
361
|
+
|
|
362
|
+
Returns
|
|
363
|
+
-------
|
|
364
|
+
xarray.Dataset
|
|
365
|
+
Dataset with all times within the given periods removed.
|
|
366
|
+
|
|
367
|
+
Raises
|
|
368
|
+
------
|
|
369
|
+
ValueError
|
|
370
|
+
If no timesteps remain after removal.
|
|
371
|
+
"""
|
|
372
|
+
times = ds["time"].to_numpy()
|
|
373
|
+
mask = np.ones_like(times, dtype=bool)
|
|
374
|
+
|
|
375
|
+
for start, end in time_periods:
|
|
376
|
+
start_np = np.datetime64(start)
|
|
377
|
+
end_np = np.datetime64(end)
|
|
378
|
+
# exclude times in the inclusive interval [start, end]
|
|
379
|
+
mask &= ~((times >= start_np) & (times <= end_np))
|
|
380
|
+
|
|
381
|
+
ds_filtered = ds.isel(time=mask)
|
|
382
|
+
|
|
383
|
+
if ds_filtered.sizes.get("time", 0) == 0:
|
|
384
|
+
raise ValueError(
|
|
385
|
+
"No timesteps left after removing problematic time_periods. "
|
|
386
|
+
"Maybe you need to adjust the issue YAML file.",
|
|
387
|
+
)
|
|
388
|
+
return ds_filtered
|
|
389
|
+
|
|
390
|
+
|
|
391
|
+
def remove_issue_timesteps(
|
|
392
|
+
ds,
|
|
393
|
+
issue_dict: dict,
|
|
394
|
+
logger=None,
|
|
395
|
+
verbose: bool = False,
|
|
396
|
+
):
|
|
397
|
+
"""
|
|
398
|
+
Remove bad timesteps and time periods from an xarray Dataset according to issue definitions.
|
|
399
|
+
|
|
400
|
+
Parameters
|
|
401
|
+
----------
|
|
402
|
+
ds : xarray.Dataset
|
|
403
|
+
Input dataset with a 'time' dimension.
|
|
404
|
+
issue_dict : dict
|
|
405
|
+
Dictionary with optional keys 'timesteps' (list of datetimes) and
|
|
406
|
+
'time_periods' (list of (start, end) tuples).
|
|
407
|
+
logger : any, optional
|
|
408
|
+
Logger instance to record dropped steps, by default None.
|
|
409
|
+
verbose : bool, optional
|
|
410
|
+
Whether to log informational messages, by default False.
|
|
411
|
+
|
|
412
|
+
Returns
|
|
413
|
+
-------
|
|
414
|
+
xarray.Dataset
|
|
415
|
+
Cleaned dataset.
|
|
416
|
+
|
|
417
|
+
Raises
|
|
418
|
+
------
|
|
419
|
+
ValueError
|
|
420
|
+
If after removing specified timesteps/periods no data remains.
|
|
421
|
+
"""
|
|
422
|
+
n_initial = ds.sizes.get("time", 0)
|
|
423
|
+
timesteps = issue_dict.get("timesteps", []) or []
|
|
424
|
+
time_periods = issue_dict.get("time_periods", []) or []
|
|
425
|
+
|
|
426
|
+
# Drop individual timesteps
|
|
427
|
+
if timesteps:
|
|
428
|
+
ds = drop_timesteps(ds, timesteps)
|
|
429
|
+
|
|
430
|
+
# Drop intervals of time
|
|
431
|
+
if time_periods:
|
|
432
|
+
ds = drop_time_periods(ds, time_periods)
|
|
433
|
+
|
|
434
|
+
# Report number dropped
|
|
435
|
+
n_remaining = ds.sizes.get("time", 0)
|
|
436
|
+
dropped = n_initial - n_remaining
|
|
437
|
+
if dropped > 0:
|
|
438
|
+
msg = f"{dropped} timesteps were dropped according to the issue YAML file content."
|
|
439
|
+
log_info(logger=logger, msg=msg, verbose=verbose)
|
|
440
|
+
return ds
|
|
441
|
+
|
|
442
|
+
|
|
443
|
+
def sanitize_ds(
|
|
317
444
|
ds,
|
|
318
|
-
dict_names,
|
|
319
|
-
ds_sanitizer_fun,
|
|
320
445
|
sensor_name,
|
|
321
|
-
|
|
322
|
-
|
|
446
|
+
metadata,
|
|
447
|
+
issue_dict=None,
|
|
448
|
+
verbose=False,
|
|
449
|
+
logger=None,
|
|
323
450
|
):
|
|
324
|
-
"""Convert a raw xr.Dataset into a DISDRODB L0B netCDF.
|
|
451
|
+
"""Convert a raw ``xr.Dataset`` into a DISDRODB L0B netCDF.
|
|
325
452
|
|
|
326
453
|
Parameters
|
|
327
454
|
----------
|
|
328
|
-
ds :
|
|
329
|
-
|
|
330
|
-
dict_names : dict
|
|
331
|
-
Dictionary mapping raw netCDF variables/coordinates/dimension names
|
|
332
|
-
to DISDRODB standards.
|
|
333
|
-
ds_sanitizer_fun : function
|
|
334
|
-
Sanitizer function to do ad-hoc processing of the xr.Dataset.
|
|
455
|
+
ds : xarray.Dataset
|
|
456
|
+
Raw xarray dataset
|
|
335
457
|
attrs: dict
|
|
336
458
|
Global metadata to attach as global attributes to the xr.Dataset.
|
|
337
459
|
sensor_name : str
|
|
@@ -342,39 +464,64 @@ def create_l0b_from_raw_nc(
|
|
|
342
464
|
|
|
343
465
|
Returns
|
|
344
466
|
-------
|
|
345
|
-
|
|
467
|
+
xarray.Dataset
|
|
346
468
|
L0B xr.Dataset
|
|
347
469
|
"""
|
|
348
|
-
# Preprocess netcdf
|
|
349
|
-
ds = preprocess_raw_netcdf(ds=ds, dict_names=dict_names, sensor_name=sensor_name)
|
|
350
|
-
|
|
351
|
-
# Add CRS and geolocation information
|
|
352
|
-
attrs = copy.deepcopy(attrs)
|
|
353
|
-
coords = {}
|
|
354
|
-
geolocation_vars = ["latitude", "longitude", "altitude"]
|
|
355
|
-
for var in geolocation_vars:
|
|
356
|
-
if var not in ds:
|
|
357
|
-
coords[var] = attrs[var]
|
|
358
|
-
_ = attrs.pop(var)
|
|
359
|
-
ds = ds.assign_coords(coords)
|
|
360
|
-
|
|
361
|
-
# Add global attributes
|
|
362
|
-
ds.attrs = attrs
|
|
363
|
-
|
|
364
|
-
# Apply dataset sanitizer function
|
|
365
|
-
ds = ds_sanitizer_fun(ds)
|
|
366
|
-
|
|
367
470
|
# Replace nan flags values with np.nans
|
|
368
|
-
ds = replace_nan_flags(ds, sensor_name=sensor_name, verbose=verbose)
|
|
471
|
+
ds = replace_nan_flags(ds, sensor_name=sensor_name, logger=logger, verbose=verbose)
|
|
472
|
+
|
|
473
|
+
# Filter out problematic tiemsteps reported in the issue YAML file
|
|
474
|
+
ds = remove_issue_timesteps(ds, issue_dict=issue_dict, logger=logger, verbose=verbose)
|
|
369
475
|
|
|
370
476
|
# Set values outside the data range to np.nan
|
|
371
|
-
ds = set_nan_outside_data_range(ds, sensor_name=sensor_name, verbose=verbose)
|
|
477
|
+
ds = set_nan_outside_data_range(ds, sensor_name=sensor_name, logger=logger, verbose=verbose)
|
|
372
478
|
|
|
373
479
|
# Replace invalid values with np.nan
|
|
374
|
-
ds = set_nan_invalid_values(ds, sensor_name=sensor_name, verbose=verbose)
|
|
480
|
+
ds = set_nan_invalid_values(ds, sensor_name=sensor_name, logger=logger, verbose=verbose)
|
|
375
481
|
|
|
376
482
|
# Finalize dataset
|
|
377
|
-
ds = finalize_dataset(ds, sensor_name=sensor_name)
|
|
483
|
+
ds = finalize_dataset(ds, sensor_name=sensor_name, attrs=metadata)
|
|
378
484
|
|
|
379
485
|
# Return dataset
|
|
380
486
|
return ds
|
|
487
|
+
|
|
488
|
+
|
|
489
|
+
def open_raw_netcdf_file(
|
|
490
|
+
filepath,
|
|
491
|
+
logger=None,
|
|
492
|
+
engine="netcdf4",
|
|
493
|
+
cache=False,
|
|
494
|
+
chunks=None,
|
|
495
|
+
decode_timedelta=False,
|
|
496
|
+
**kwargs,
|
|
497
|
+
):
|
|
498
|
+
"""Open a raw netCDF file.
|
|
499
|
+
|
|
500
|
+
Parameters
|
|
501
|
+
----------
|
|
502
|
+
filepath : str
|
|
503
|
+
Path to the raw netCDF file.
|
|
504
|
+
|
|
505
|
+
Returns
|
|
506
|
+
-------
|
|
507
|
+
xarray.Dataset
|
|
508
|
+
Raw netCDF file as an xarray Dataset.
|
|
509
|
+
"""
|
|
510
|
+
import xarray as xr
|
|
511
|
+
|
|
512
|
+
# Note: chunks=None avoid usage of Dask
|
|
513
|
+
|
|
514
|
+
# Open the raw netCDF
|
|
515
|
+
with xr.open_dataset(
|
|
516
|
+
filepath,
|
|
517
|
+
decode_timedelta=decode_timedelta,
|
|
518
|
+
cache=cache,
|
|
519
|
+
engine=engine,
|
|
520
|
+
chunks=chunks,
|
|
521
|
+
**kwargs,
|
|
522
|
+
) as data:
|
|
523
|
+
ds = data.load()
|
|
524
|
+
|
|
525
|
+
# Log information
|
|
526
|
+
log_info(logger=logger, msg=f"netCDF file {filepath} has been loaded successively into xarray.", verbose=False)
|
|
527
|
+
return ds
|