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/api/info.py
CHANGED
|
@@ -19,19 +19,31 @@
|
|
|
19
19
|
"""Retrieve file information from DISDRODB products file names and filepaths."""
|
|
20
20
|
|
|
21
21
|
import os
|
|
22
|
+
from collections import defaultdict
|
|
22
23
|
from pathlib import Path
|
|
23
24
|
|
|
24
25
|
import numpy as np
|
|
25
26
|
from trollsift import Parser
|
|
26
27
|
|
|
28
|
+
from disdrodb.utils.time import acronym_to_seconds
|
|
29
|
+
|
|
27
30
|
####---------------------------------------------------------------------------
|
|
28
31
|
########################
|
|
29
32
|
#### FNAME PATTERNS ####
|
|
30
33
|
########################
|
|
31
|
-
|
|
34
|
+
DISDRODB_FNAME_L0_PATTERN = (
|
|
32
35
|
"{product:s}.{campaign_name:s}.{station_name:s}.s{start_time:%Y%m%d%H%M%S}.e{end_time:%Y%m%d%H%M%S}"
|
|
33
36
|
".{version:s}.{data_format:s}"
|
|
34
37
|
)
|
|
38
|
+
DISDRODB_FNAME_L2E_PATTERN = ( # also L0C and L1 --> accumulation_acronym = sample_interval
|
|
39
|
+
"{product:s}.{accumulation_acronym}.{campaign_name:s}.{station_name:s}.s{start_time:%Y%m%d%H%M%S}.e{end_time:%Y%m%d%H%M%S}"
|
|
40
|
+
".{version:s}.{data_format:s}"
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
DISDRODB_FNAME_L2M_PATTERN = (
|
|
44
|
+
"{product:s}_{subproduct:s}.{accumulation_acronym}.{campaign_name:s}.{station_name:s}.s{start_time:%Y%m%d%H%M%S}.e{end_time:%Y%m%d%H%M%S}"
|
|
45
|
+
".{version:s}.{data_format:s}"
|
|
46
|
+
)
|
|
35
47
|
|
|
36
48
|
####---------------------------------------------------------------------------.
|
|
37
49
|
##########################
|
|
@@ -41,9 +53,17 @@ DISDRODB_FNAME_PATTERN = (
|
|
|
41
53
|
|
|
42
54
|
def _parse_filename(filename):
|
|
43
55
|
"""Parse the filename with trollsift."""
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
56
|
+
if filename.startswith("L0A") or filename.startswith("L0B"):
|
|
57
|
+
p = Parser(DISDRODB_FNAME_L0_PATTERN)
|
|
58
|
+
info_dict = p.parse(filename)
|
|
59
|
+
elif filename.startswith("L2E") or filename.startswith("L1") or filename.startswith("L0C"):
|
|
60
|
+
p = Parser(DISDRODB_FNAME_L2E_PATTERN)
|
|
61
|
+
info_dict = p.parse(filename)
|
|
62
|
+
elif filename.startswith("L2M"):
|
|
63
|
+
p = Parser(DISDRODB_FNAME_L2M_PATTERN)
|
|
64
|
+
info_dict = p.parse(filename)
|
|
65
|
+
else:
|
|
66
|
+
raise ValueError("Not a DISDRODB product file.")
|
|
47
67
|
return info_dict
|
|
48
68
|
|
|
49
69
|
|
|
@@ -54,6 +74,11 @@ def _get_info_from_filename(filename):
|
|
|
54
74
|
info_dict = _parse_filename(filename)
|
|
55
75
|
except ValueError:
|
|
56
76
|
raise ValueError(f"{filename} can not be parsed. Report the issue.")
|
|
77
|
+
|
|
78
|
+
# Add additional information to info dictionary
|
|
79
|
+
if "accumulation_acronym" in info_dict:
|
|
80
|
+
info_dict["sample_interval"] = acronym_to_seconds(info_dict["accumulation_acronym"])
|
|
81
|
+
|
|
57
82
|
# Return info dictionary
|
|
58
83
|
return info_dict
|
|
59
84
|
|
|
@@ -91,6 +116,7 @@ def _get_version_from_filepath(filepath):
|
|
|
91
116
|
|
|
92
117
|
|
|
93
118
|
def get_version_from_filepaths(filepaths):
|
|
119
|
+
"""Return the DISDROB product version of the specified files."""
|
|
94
120
|
if isinstance(filepaths, str):
|
|
95
121
|
filepaths = [filepaths]
|
|
96
122
|
list_version = [_get_version_from_filepath(filepath) for filepath in filepaths]
|
|
@@ -98,34 +124,47 @@ def get_version_from_filepaths(filepaths):
|
|
|
98
124
|
|
|
99
125
|
|
|
100
126
|
def get_campaign_name_from_filepaths(filepaths):
|
|
127
|
+
"""Return the DISDROB campaign name of the specified files."""
|
|
101
128
|
list_id = get_key_from_filepaths(filepaths, key="campaign_name")
|
|
102
129
|
return list_id
|
|
103
130
|
|
|
104
131
|
|
|
105
132
|
def get_station_name_from_filepaths(filepaths):
|
|
133
|
+
"""Return the DISDROB station name of the specified files."""
|
|
106
134
|
list_id = get_key_from_filepaths(filepaths, key="station_name")
|
|
107
135
|
return list_id
|
|
108
136
|
|
|
109
137
|
|
|
110
138
|
def get_product_from_filepaths(filepaths):
|
|
139
|
+
"""Return the DISDROB product name of the specified files."""
|
|
111
140
|
list_id = get_key_from_filepaths(filepaths, key="product")
|
|
112
141
|
return list_id
|
|
113
142
|
|
|
114
143
|
|
|
115
144
|
def get_start_time_from_filepaths(filepaths):
|
|
145
|
+
"""Return the start time of the specified files."""
|
|
116
146
|
list_start_time = get_key_from_filepaths(filepaths, key="start_time")
|
|
117
147
|
return list_start_time
|
|
118
148
|
|
|
119
149
|
|
|
120
150
|
def get_end_time_from_filepaths(filepaths):
|
|
151
|
+
"""Return the end time of the specified files."""
|
|
121
152
|
list_end_time = get_key_from_filepaths(filepaths, key="end_time")
|
|
122
153
|
return list_end_time
|
|
123
154
|
|
|
124
155
|
|
|
125
156
|
def get_start_end_time_from_filepaths(filepaths):
|
|
157
|
+
"""Return the start and end time of the specified files."""
|
|
126
158
|
list_start_time = get_key_from_filepaths(filepaths, key="start_time")
|
|
127
159
|
list_end_time = get_key_from_filepaths(filepaths, key="end_time")
|
|
128
|
-
return np.array(list_start_time), np.array(list_end_time)
|
|
160
|
+
return np.array(list_start_time).astype("M8[s]"), np.array(list_end_time).astype("M8[s]")
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
def get_sample_interval_from_filepaths(filepaths):
|
|
164
|
+
"""Return the sample interval of the specified files."""
|
|
165
|
+
list_accumulation_acronym = get_key_from_filepaths(filepaths, key="accumulation_acronym")
|
|
166
|
+
list_sample_interval = [acronym_to_seconds(s) for s in list_accumulation_acronym]
|
|
167
|
+
return list_sample_interval
|
|
129
168
|
|
|
130
169
|
|
|
131
170
|
####--------------------------------------------------------------------------.
|
|
@@ -135,18 +174,18 @@ def get_start_end_time_from_filepaths(filepaths):
|
|
|
135
174
|
|
|
136
175
|
|
|
137
176
|
def infer_disdrodb_tree_path_components(path: str) -> list:
|
|
138
|
-
"""Return a list with the component of
|
|
177
|
+
"""Return a list with the component of a DISDRODB path ``disdrodb_path``.
|
|
139
178
|
|
|
140
179
|
Parameters
|
|
141
180
|
----------
|
|
142
181
|
path : str
|
|
143
|
-
|
|
182
|
+
Directory or file path within the DISDRODB archive.
|
|
144
183
|
|
|
145
184
|
Returns
|
|
146
185
|
-------
|
|
147
186
|
list
|
|
148
187
|
Path element of the DISDRODB archive.
|
|
149
|
-
Format: [
|
|
188
|
+
Format: [``data_archive_dir``, ``product_version``, ``data_source`, ``campaign_name``, ...]
|
|
150
189
|
"""
|
|
151
190
|
# Retrieve path elements (os-specific)
|
|
152
191
|
p = Path(path)
|
|
@@ -158,60 +197,79 @@ def infer_disdrodb_tree_path_components(path: str) -> list:
|
|
|
158
197
|
raise ValueError(f"The DISDRODB directory is not present in the path '{path}'")
|
|
159
198
|
# Find the rightermost occurrence
|
|
160
199
|
right_most_occurrence = max(idx_occurrence)
|
|
161
|
-
# Define
|
|
162
|
-
|
|
200
|
+
# Define archive_dir and tree components
|
|
201
|
+
archive_dir = os.path.join(*list_path_elements[: right_most_occurrence + 1])
|
|
163
202
|
tree_components = list_path_elements[right_most_occurrence + 1 :]
|
|
164
203
|
# Return components
|
|
165
|
-
components = [
|
|
204
|
+
components = [archive_dir, *tree_components]
|
|
166
205
|
return components
|
|
167
206
|
|
|
168
207
|
|
|
169
208
|
def infer_path_info_dict(path: str) -> dict:
|
|
170
|
-
"""Return a dictionary with the
|
|
209
|
+
"""Return a dictionary with the ``data_archive_dir``, ``data_source`` and ``campaign_name`` of the disdrodb_path.
|
|
171
210
|
|
|
172
211
|
Parameters
|
|
173
212
|
----------
|
|
174
213
|
path : str
|
|
175
|
-
|
|
214
|
+
Directory or file path within the DISDRODB archive.
|
|
176
215
|
|
|
177
216
|
Returns
|
|
178
217
|
-------
|
|
179
|
-
|
|
218
|
+
dict
|
|
180
219
|
Dictionary with the path element of the DISDRODB archive.
|
|
181
|
-
Valid keys: "
|
|
220
|
+
Valid keys: ``"data_archive_dir"``, ``"data_source"``, ``"campaign_name"``
|
|
182
221
|
"""
|
|
183
222
|
components = infer_disdrodb_tree_path_components(path=path)
|
|
184
223
|
if len(components) <= 3:
|
|
185
224
|
raise ValueError(f"Impossible to determine data_source and campaign_name from {path}")
|
|
186
225
|
path_dict = {}
|
|
187
|
-
path_dict["
|
|
226
|
+
path_dict["data_archive_dir"] = components[0]
|
|
188
227
|
path_dict["data_source"] = components[2]
|
|
189
228
|
path_dict["campaign_name"] = components[3]
|
|
190
229
|
return path_dict
|
|
191
230
|
|
|
192
231
|
|
|
232
|
+
def infer_path_info_tuple(path: str) -> tuple:
|
|
233
|
+
"""Return a tuple with the ``data_archive_dir``, ``data_source`` and ``campaign_name`` of the disdrodb_path.
|
|
234
|
+
|
|
235
|
+
Parameters
|
|
236
|
+
----------
|
|
237
|
+
path : str
|
|
238
|
+
Directory or file path within the DISDRODB archive.
|
|
239
|
+
|
|
240
|
+
Returns
|
|
241
|
+
-------
|
|
242
|
+
tuple
|
|
243
|
+
Dictionary with the path element of the DISDRODB archive.
|
|
244
|
+
Valid keys: ``"data_archive_dir"``, ``"data_source"``, ``"campaign_name"``
|
|
245
|
+
"""
|
|
246
|
+
path_dict = infer_path_info_dict(path)
|
|
247
|
+
return path_dict["data_archive_dir"], path_dict["data_source"], path_dict["campaign_name"]
|
|
248
|
+
|
|
249
|
+
|
|
193
250
|
def infer_disdrodb_tree_path(path: str) -> str:
|
|
194
|
-
"""Return the directory tree path from the
|
|
251
|
+
"""Return the directory tree path from the archive directory.
|
|
195
252
|
|
|
196
|
-
Current assumption: no data_source
|
|
253
|
+
Current assumption: no ``data_source``, ``campaign_name``, ``station_name`` or file contain the word DISDRODB!
|
|
197
254
|
|
|
198
255
|
Parameters
|
|
199
256
|
----------
|
|
200
257
|
path : str
|
|
201
|
-
|
|
258
|
+
Directory or file path within the DISDRODB archive.
|
|
202
259
|
|
|
203
260
|
Returns
|
|
204
261
|
-------
|
|
205
262
|
str
|
|
206
263
|
Path inside the DISDRODB archive.
|
|
207
|
-
Format: DISDRODB/<
|
|
264
|
+
Format: ``DISDRODB/RAW/<DATA_SOURCE>/<CAMPAIGN_NAME>/...``
|
|
265
|
+
Format: ``DISDRODB/<ARCHIVE_VERSION>/<DATA_SOURCE>/<CAMPAIGN_NAME>/...``
|
|
208
266
|
"""
|
|
209
267
|
components = infer_disdrodb_tree_path_components(path=path)
|
|
210
268
|
tree_filepath = os.path.join("DISDRODB", *components[1:])
|
|
211
269
|
return tree_filepath
|
|
212
270
|
|
|
213
271
|
|
|
214
|
-
def
|
|
272
|
+
def infer_archive_dir_from_path(path: str) -> str:
|
|
215
273
|
"""Return the disdrodb base directory from a file or directory path.
|
|
216
274
|
|
|
217
275
|
Assumption: no data_source, campaign_name, station_name or file contain the word DISDRODB!
|
|
@@ -219,7 +277,7 @@ def infer_base_dir_from_path(path: str) -> str:
|
|
|
219
277
|
Parameters
|
|
220
278
|
----------
|
|
221
279
|
path : str
|
|
222
|
-
|
|
280
|
+
Directory or file path within the DISDRODB archive.
|
|
223
281
|
|
|
224
282
|
Returns
|
|
225
283
|
-------
|
|
@@ -232,12 +290,12 @@ def infer_base_dir_from_path(path: str) -> str:
|
|
|
232
290
|
def infer_campaign_name_from_path(path: str) -> str:
|
|
233
291
|
"""Return the campaign name from a file or directory path.
|
|
234
292
|
|
|
235
|
-
Assumption: no data_source
|
|
293
|
+
Assumption: no ``data_source``, ``campaign_name``, ``station_name`` or file contain the word DISDRODB!
|
|
236
294
|
|
|
237
295
|
Parameters
|
|
238
296
|
----------
|
|
239
297
|
path : str
|
|
240
|
-
|
|
298
|
+
Directory or file path within the DISDRODB archive.
|
|
241
299
|
|
|
242
300
|
Returns
|
|
243
301
|
-------
|
|
@@ -254,12 +312,12 @@ def infer_campaign_name_from_path(path: str) -> str:
|
|
|
254
312
|
def infer_data_source_from_path(path: str) -> str:
|
|
255
313
|
"""Return the data_source from a file or directory path.
|
|
256
314
|
|
|
257
|
-
Assumption: no data_source
|
|
315
|
+
Assumption: no ``data_source``, ``campaign_name``, ``station_name`` or file contain the word DISDRODB!
|
|
258
316
|
|
|
259
317
|
Parameters
|
|
260
318
|
----------
|
|
261
319
|
path : str
|
|
262
|
-
|
|
320
|
+
Directory or file path within the DISDRODB archive.
|
|
263
321
|
|
|
264
322
|
Returns
|
|
265
323
|
-------
|
|
@@ -274,3 +332,136 @@ def infer_data_source_from_path(path: str) -> str:
|
|
|
274
332
|
|
|
275
333
|
|
|
276
334
|
####--------------------------------------------------------------------------.
|
|
335
|
+
#######################
|
|
336
|
+
#### Group utility ####
|
|
337
|
+
#######################
|
|
338
|
+
|
|
339
|
+
|
|
340
|
+
FILE_KEYS = [
|
|
341
|
+
"product",
|
|
342
|
+
"subproduct",
|
|
343
|
+
"campaign_name",
|
|
344
|
+
"station_name",
|
|
345
|
+
"start_time",
|
|
346
|
+
"end_time",
|
|
347
|
+
"data_format",
|
|
348
|
+
"accumulation_acronym",
|
|
349
|
+
"sample_interval",
|
|
350
|
+
]
|
|
351
|
+
|
|
352
|
+
|
|
353
|
+
TIME_KEYS = [
|
|
354
|
+
"year",
|
|
355
|
+
"month",
|
|
356
|
+
"month_name",
|
|
357
|
+
"quarter",
|
|
358
|
+
"season",
|
|
359
|
+
"day",
|
|
360
|
+
"doy",
|
|
361
|
+
"dow",
|
|
362
|
+
"hour",
|
|
363
|
+
"minute",
|
|
364
|
+
"second",
|
|
365
|
+
]
|
|
366
|
+
|
|
367
|
+
|
|
368
|
+
def check_groups(groups):
|
|
369
|
+
"""Check groups validity."""
|
|
370
|
+
if not isinstance(groups, (str, list)):
|
|
371
|
+
raise TypeError("'groups' must be a list (or a string if a single group is specified.")
|
|
372
|
+
if isinstance(groups, str):
|
|
373
|
+
groups = [groups]
|
|
374
|
+
groups = np.array(groups)
|
|
375
|
+
valid_keys = FILE_KEYS + TIME_KEYS
|
|
376
|
+
invalid_keys = groups[np.isin(groups, valid_keys, invert=True)]
|
|
377
|
+
if len(invalid_keys) > 0:
|
|
378
|
+
raise ValueError(f"The following group keys are invalid: {invalid_keys}. Valid values are {valid_keys}.")
|
|
379
|
+
return groups.tolist()
|
|
380
|
+
|
|
381
|
+
|
|
382
|
+
def get_season(time):
|
|
383
|
+
"""Get season from `datetime.datetime` or `datetime.date` object."""
|
|
384
|
+
month = time.month
|
|
385
|
+
if month in [12, 1, 2]:
|
|
386
|
+
return "DJF" # Winter (December, January, February)
|
|
387
|
+
if month in [3, 4, 5]:
|
|
388
|
+
return "MAM" # Spring (March, April, May)
|
|
389
|
+
if month in [6, 7, 8]:
|
|
390
|
+
return "JJA" # Summer (June, July, August)
|
|
391
|
+
return "SON" # Autumn (September, October, November)
|
|
392
|
+
|
|
393
|
+
|
|
394
|
+
def get_time_component(time, component):
|
|
395
|
+
"""Get time component from `datetime.datetime` object."""
|
|
396
|
+
func_dict = {
|
|
397
|
+
"year": lambda time: time.year,
|
|
398
|
+
"month": lambda time: time.month,
|
|
399
|
+
"day": lambda time: time.day,
|
|
400
|
+
"doy": lambda time: time.timetuple().tm_yday, # Day of year
|
|
401
|
+
"dow": lambda time: time.weekday(), # Day of week (0=Monday, 6=Sunday)
|
|
402
|
+
"hour": lambda time: time.hour,
|
|
403
|
+
"minute": lambda time: time.minute,
|
|
404
|
+
"second": lambda time: time.second,
|
|
405
|
+
# Additional
|
|
406
|
+
"month_name": lambda time: time.strftime("%B"), # Full month name
|
|
407
|
+
"quarter": lambda time: (time.month - 1) // 3 + 1, # Quarter (1-4)
|
|
408
|
+
"season": lambda time: get_season(time), # Season (DJF, MAM, JJA, SON)
|
|
409
|
+
}
|
|
410
|
+
return str(func_dict[component](time))
|
|
411
|
+
|
|
412
|
+
|
|
413
|
+
def _get_groups_value(groups, filepath):
|
|
414
|
+
"""Return the value associated to the groups keys.
|
|
415
|
+
|
|
416
|
+
If multiple keys are specified, the value returned is a string of format: ``<group_value_1>/<group_value_2>/...``
|
|
417
|
+
|
|
418
|
+
If a single key is specified and is ``start_time`` or ``end_time``, the function
|
|
419
|
+
returns a :py:class:`datetime.datetime` object.
|
|
420
|
+
"""
|
|
421
|
+
single_key = len(groups) == 1
|
|
422
|
+
info_dict = get_info_from_filepath(filepath)
|
|
423
|
+
start_time = info_dict["start_time"]
|
|
424
|
+
list_key_values = []
|
|
425
|
+
for key in groups:
|
|
426
|
+
if key in TIME_KEYS:
|
|
427
|
+
list_key_values.append(get_time_component(start_time, component=key))
|
|
428
|
+
else:
|
|
429
|
+
value = info_dict.get(key, f"{key}=None")
|
|
430
|
+
list_key_values.append(value if single_key else str(value))
|
|
431
|
+
if single_key:
|
|
432
|
+
return list_key_values[0]
|
|
433
|
+
return "/".join(list_key_values)
|
|
434
|
+
|
|
435
|
+
|
|
436
|
+
def group_filepaths(filepaths, groups=None):
|
|
437
|
+
"""
|
|
438
|
+
Group filepaths in a dictionary if groups are specified.
|
|
439
|
+
|
|
440
|
+
Parameters
|
|
441
|
+
----------
|
|
442
|
+
filepaths : list
|
|
443
|
+
List of filepaths.
|
|
444
|
+
groups: list or str
|
|
445
|
+
The group keys by which to group the filepaths.
|
|
446
|
+
Valid group keys are ``product``, ``subproduct``, ``campaign_name``, ``station_name``,
|
|
447
|
+
``start_time``, ``end_time``,``accumulation_acronym``,``sample_interval``,
|
|
448
|
+
``data_format``,
|
|
449
|
+
``year``, ``month``, ``day``, ``doy``, ``dow``, ``hour``, ``minute``, ``second``,
|
|
450
|
+
``month_name``, ``quarter``, ``season``.
|
|
451
|
+
The time components are extracted from ``start_time`` !
|
|
452
|
+
If groups is ``None`` returns the input filepaths list.
|
|
453
|
+
The default value is ``None``.
|
|
454
|
+
|
|
455
|
+
Returns
|
|
456
|
+
-------
|
|
457
|
+
dict or list
|
|
458
|
+
Either a dictionary of format ``{<group_value>: <list_filepaths>}``.
|
|
459
|
+
or the original input filepaths (if ``groups=None``)
|
|
460
|
+
|
|
461
|
+
"""
|
|
462
|
+
if groups is None:
|
|
463
|
+
return filepaths
|
|
464
|
+
groups = check_groups(groups)
|
|
465
|
+
filepaths_dict = defaultdict(list)
|
|
466
|
+
_ = [filepaths_dict[_get_groups_value(groups, filepath)].append(filepath) for filepath in filepaths]
|
|
467
|
+
return dict(filepaths_dict)
|