disdrodb 0.2.1__py3-none-any.whl → 0.4.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 +3 -1
- disdrodb/_config.py +2 -3
- disdrodb/_version.py +2 -2
- disdrodb/accessor/__init__.py +2 -1
- disdrodb/accessor/methods.py +10 -9
- disdrodb/api/checks.py +3 -7
- disdrodb/api/configs.py +1 -3
- disdrodb/api/create_directories.py +4 -6
- disdrodb/api/info.py +1 -3
- disdrodb/api/io.py +233 -32
- disdrodb/api/path.py +3 -7
- disdrodb/cli/disdrodb_check_metadata_archive.py +3 -2
- disdrodb/cli/disdrodb_check_products_options.py +45 -0
- disdrodb/cli/disdrodb_create_summary.py +54 -28
- disdrodb/cli/disdrodb_create_summary_station.py +41 -20
- disdrodb/cli/disdrodb_data_archive_directory.py +2 -3
- disdrodb/cli/disdrodb_download_archive.py +50 -30
- disdrodb/cli/disdrodb_download_metadata_archive.py +28 -16
- disdrodb/cli/disdrodb_download_station.py +58 -29
- disdrodb/cli/disdrodb_initialize_station.py +43 -23
- disdrodb/cli/disdrodb_metadata_archive_directory.py +2 -3
- disdrodb/cli/disdrodb_open_data_archive.py +17 -13
- disdrodb/cli/disdrodb_open_logs_directory.py +31 -21
- disdrodb/cli/disdrodb_open_metadata_archive.py +26 -13
- disdrodb/cli/disdrodb_open_metadata_directory.py +34 -23
- disdrodb/cli/disdrodb_open_product_directory.py +39 -23
- disdrodb/cli/disdrodb_open_readers_directory.py +2 -3
- disdrodb/cli/disdrodb_run.py +189 -0
- disdrodb/cli/disdrodb_run_l0.py +61 -70
- disdrodb/cli/disdrodb_run_l0_station.py +50 -55
- disdrodb/cli/disdrodb_run_l0a.py +53 -51
- disdrodb/cli/disdrodb_run_l0a_station.py +41 -40
- disdrodb/cli/disdrodb_run_l0b.py +51 -51
- disdrodb/cli/disdrodb_run_l0b_station.py +40 -39
- disdrodb/cli/disdrodb_run_l0c.py +56 -53
- disdrodb/cli/disdrodb_run_l0c_station.py +44 -41
- disdrodb/cli/disdrodb_run_l1.py +55 -51
- disdrodb/cli/disdrodb_run_l1_station.py +43 -40
- disdrodb/cli/disdrodb_run_l2e.py +56 -51
- disdrodb/cli/disdrodb_run_l2e_station.py +44 -40
- disdrodb/cli/disdrodb_run_l2m.py +55 -51
- disdrodb/cli/disdrodb_run_l2m_station.py +43 -40
- disdrodb/cli/disdrodb_run_station.py +184 -0
- disdrodb/cli/disdrodb_upload_archive.py +51 -42
- disdrodb/cli/disdrodb_upload_station.py +42 -36
- disdrodb/configs.py +20 -16
- disdrodb/constants.py +5 -2
- disdrodb/data_transfer/__init__.py +1 -3
- disdrodb/data_transfer/download_data.py +45 -61
- disdrodb/data_transfer/upload_data.py +7 -11
- disdrodb/data_transfer/zenodo.py +2 -4
- disdrodb/docs.py +1 -3
- disdrodb/etc/configs/attributes.yaml +52 -2
- disdrodb/etc/configs/encodings.yaml +45 -1
- disdrodb/etc/products/L0C/ODM470/global.yaml +5 -0
- disdrodb/etc/products/L0C/global.yaml +5 -0
- disdrodb/etc/products/L1/ODM470/global.yaml +6 -0
- disdrodb/etc/products/L1/global.yaml +0 -13
- disdrodb/etc/products/L2E/LPM/1MIN.yaml +1 -0
- disdrodb/etc/products/L2E/LPM/global.yaml +36 -0
- disdrodb/etc/products/L2E/LPM_V0/1MIN.yaml +1 -0
- disdrodb/etc/products/L2E/LPM_V0/global.yaml +36 -0
- disdrodb/etc/products/L2E/ODM470/1MIN.yaml +1 -0
- disdrodb/etc/products/L2E/ODM470/global.yaml +36 -0
- disdrodb/etc/products/L2E/PARSIVEL/1MIN.yaml +1 -0
- disdrodb/etc/products/L2E/PARSIVEL/global.yaml +36 -0
- disdrodb/etc/products/L2E/PARSIVEL2/1MIN.yaml +1 -0
- disdrodb/etc/products/L2E/PARSIVEL2/global.yaml +36 -0
- disdrodb/etc/products/L2E/PWS100/1MIN.yaml +1 -0
- disdrodb/etc/products/L2E/PWS100/global.yaml +36 -0
- disdrodb/etc/products/L2E/RD80/1MIN.yaml +19 -0
- disdrodb/etc/products/L2E/SWS250/1MIN.yaml +19 -0
- disdrodb/etc/products/L2E/global.yaml +16 -2
- disdrodb/fall_velocity/__init__.py +47 -0
- disdrodb/fall_velocity/graupel.py +484 -0
- disdrodb/fall_velocity/hail.py +288 -0
- disdrodb/{l1/fall_velocity.py → fall_velocity/rain.py} +265 -44
- disdrodb/issue/__init__.py +1 -3
- disdrodb/issue/checks.py +2 -3
- disdrodb/issue/reader.py +2 -3
- disdrodb/issue/writer.py +2 -5
- disdrodb/l0/__init__.py +2 -1
- disdrodb/l0/check_configs.py +36 -29
- disdrodb/l0/check_standards.py +1 -4
- disdrodb/l0/configs/LPM/l0a_encodings.yml +17 -17
- disdrodb/l0/configs/LPM/l0b_cf_attrs.yml +55 -55
- disdrodb/l0/configs/LPM/l0b_encodings.yml +17 -17
- disdrodb/l0/configs/LPM/raw_data_format.yml +17 -17
- disdrodb/l0/configs/LPM_V0/l0a_encodings.yml +2 -2
- disdrodb/l0/configs/LPM_V0/l0b_cf_attrs.yml +2 -2
- disdrodb/l0/configs/LPM_V0/l0b_encodings.yml +2 -2
- disdrodb/l0/configs/LPM_V0/raw_data_format.yml +2 -2
- disdrodb/l0/configs/ODM470/bins_diameter.yml +643 -0
- disdrodb/l0/configs/ODM470/bins_velocity.yml +0 -0
- disdrodb/l0/configs/ODM470/l0a_encodings.yml +11 -0
- disdrodb/l0/configs/ODM470/l0b_cf_attrs.yml +46 -0
- disdrodb/l0/configs/ODM470/l0b_encodings.yml +106 -0
- disdrodb/l0/configs/ODM470/raw_data_format.yml +111 -0
- disdrodb/l0/configs/PARSIVEL/l0b_cf_attrs.yml +1 -1
- disdrodb/l0/l0_reader.py +2 -3
- disdrodb/l0/l0a_processing.py +6 -8
- disdrodb/l0/l0b_nc_processing.py +3 -6
- disdrodb/l0/l0b_processing.py +2 -16
- disdrodb/l0/l0c_processing.py +29 -12
- disdrodb/l0/readers/LPM/ARM/ARM_LPM.py +2 -1
- disdrodb/l0/readers/LPM/AUSTRALIA/MELBOURNE_2007_LPM.py +18 -18
- disdrodb/l0/readers/LPM/BRAZIL/CHUVA_LPM.py +18 -18
- disdrodb/l0/readers/LPM/BRAZIL/GOAMAZON_LPM.py +18 -18
- disdrodb/l0/readers/LPM/GERMANY/DWD.py +244 -63
- disdrodb/l0/readers/LPM/ITALY/GID_LPM.py +65 -23
- disdrodb/l0/readers/LPM/ITALY/GID_LPM_AQ.py +277 -0
- disdrodb/l0/readers/LPM/ITALY/GID_LPM_PI.py +19 -18
- disdrodb/l0/readers/LPM/ITALY/GID_LPM_T.py +23 -19
- disdrodb/l0/readers/LPM/ITALY/GID_LPM_W.py +19 -21
- disdrodb/l0/readers/LPM/KIT/CHWALA.py +19 -20
- disdrodb/l0/readers/LPM/NETHERLANDS/DELFT_LPM_NC.py +1 -1
- disdrodb/l0/readers/LPM/NETHERLANDS/DELFT_RWANDA_LPM_NC.py +18 -18
- disdrodb/l0/readers/LPM/NORWAY/HAUKELISETER_LPM.py +19 -20
- disdrodb/l0/readers/LPM/NORWAY/NMBU_LPM.py +19 -20
- disdrodb/l0/readers/LPM/SLOVENIA/ARSO.py +19 -20
- disdrodb/l0/readers/LPM/SLOVENIA/UL.py +19 -20
- disdrodb/l0/readers/LPM/SWITZERLAND/INNERERIZ_LPM.py +19 -20
- disdrodb/l0/readers/LPM/UK/DIVEN.py +1 -1
- disdrodb/l0/readers/LPM/UK/WITHWORTH_LPM.py +19 -20
- disdrodb/l0/readers/LPM/USA/CHARLESTON.py +19 -20
- disdrodb/l0/readers/LPM/USA/DEVEX.py +255 -0
- disdrodb/l0/readers/LPM_V0/BELGIUM/ULIEGE.py +3 -5
- disdrodb/l0/readers/LPM_V0/ITALY/GID_LPM_V0.py +4 -3
- disdrodb/l0/readers/ODM470/OCEAN/OCEANRAIN.py +124 -0
- disdrodb/l0/readers/PARSIVEL/AUSTRALIA/MELBOURNE_2007_PARSIVEL.py +1 -1
- disdrodb/l0/readers/PARSIVEL/BASQUECOUNTRY/EUSKALMET_OTT.py +2 -1
- disdrodb/l0/readers/PARSIVEL/CHINA/CHONGQING.py +2 -3
- disdrodb/l0/readers/PARSIVEL/EPFL/ARCTIC_2021.py +2 -1
- disdrodb/l0/readers/PARSIVEL/EPFL/COMMON_2011.py +2 -1
- disdrodb/l0/readers/PARSIVEL/EPFL/DAVOS_2009_2011.py +2 -1
- disdrodb/l0/readers/PARSIVEL/EPFL/EPFL_2009.py +2 -1
- disdrodb/l0/readers/PARSIVEL/EPFL/EPFL_ROOF_2008.py +2 -1
- disdrodb/l0/readers/PARSIVEL/EPFL/EPFL_ROOF_2010.py +2 -1
- disdrodb/l0/readers/PARSIVEL/EPFL/EPFL_ROOF_2011.py +2 -1
- disdrodb/l0/readers/PARSIVEL/EPFL/EPFL_ROOF_2012.py +2 -1
- disdrodb/l0/readers/PARSIVEL/EPFL/GENEPI_2007.py +2 -1
- disdrodb/l0/readers/PARSIVEL/EPFL/GRAND_ST_BERNARD_2007.py +2 -1
- disdrodb/l0/readers/PARSIVEL/EPFL/GRAND_ST_BERNARD_2007_2.py +2 -1
- disdrodb/l0/readers/PARSIVEL/EPFL/HPICONET_2010.py +2 -1
- disdrodb/l0/readers/PARSIVEL/EPFL/HYMEX_LTE_SOP2.py +2 -1
- disdrodb/l0/readers/PARSIVEL/EPFL/HYMEX_LTE_SOP3.py +2 -1
- disdrodb/l0/readers/PARSIVEL/EPFL/HYMEX_LTE_SOP4.py +2 -1
- disdrodb/l0/readers/PARSIVEL/EPFL/LOCARNO_2018.py +1 -1
- disdrodb/l0/readers/PARSIVEL/EPFL/LOCARNO_2019.py +1 -1
- disdrodb/l0/readers/PARSIVEL/EPFL/PARADISO_2014.py +2 -1
- disdrodb/l0/readers/PARSIVEL/EPFL/PARSIVEL_2007.py +2 -1
- disdrodb/l0/readers/PARSIVEL/EPFL/PLATO_2019.py +1 -1
- disdrodb/l0/readers/PARSIVEL/EPFL/RACLETS_2019.py +2 -1
- disdrodb/l0/readers/PARSIVEL/EPFL/RACLETS_2019_WJF.py +2 -1
- disdrodb/l0/readers/PARSIVEL/EPFL/RIETHOLZBACH_2011.py +2 -1
- disdrodb/l0/readers/PARSIVEL/EPFL/SAMOYLOV_2017.py +2 -1
- disdrodb/l0/readers/PARSIVEL/EPFL/SAMOYLOV_2019.py +2 -1
- disdrodb/l0/readers/PARSIVEL/EPFL/UNIL_2022.py +2 -1
- disdrodb/l0/readers/PARSIVEL/JAPAN/JMA.py +1 -1
- disdrodb/l0/readers/PARSIVEL/KOREA/ICEPOP_MSC.py +159 -0
- disdrodb/l0/readers/PARSIVEL/NASA/LPVEX.py +1 -1
- disdrodb/l0/readers/PARSIVEL/NASA/MC3E.py +1 -1
- disdrodb/l0/readers/PARSIVEL/NCAR/CCOPE_2015.py +1 -1
- disdrodb/l0/readers/PARSIVEL/NCAR/OWLES_MIPS.py +1 -1
- disdrodb/l0/readers/PARSIVEL/NCAR/PECAN_MOBILE.py +1 -1
- disdrodb/l0/readers/PARSIVEL/NCAR/PLOWS_MIPS.py +1 -1
- disdrodb/l0/readers/PARSIVEL/NCAR/VORTEX2_2009.py +1 -1
- disdrodb/l0/readers/PARSIVEL/NCAR/VORTEX2_2010.py +1 -3
- disdrodb/l0/readers/PARSIVEL/NCAR/VORTEX2_2010_UF.py +1 -3
- disdrodb/l0/readers/PARSIVEL/SLOVENIA/UL.py +2 -1
- disdrodb/l0/readers/PARSIVEL2/ARM/ARM_PARSIVEL2.py +2 -1
- disdrodb/l0/readers/PARSIVEL2/BASQUECOUNTRY/EUSKALMET_OTT2.py +2 -1
- disdrodb/l0/readers/PARSIVEL2/BELGIUM/ILVO.py +2 -3
- disdrodb/l0/readers/PARSIVEL2/BRAZIL/CHUVA_PARSIVEL2.py +1 -1
- disdrodb/l0/readers/PARSIVEL2/BRAZIL/GOAMAZON_PARSIVEL2.py +1 -1
- disdrodb/l0/readers/PARSIVEL2/CANADA/UQAM_NC.py +1 -1
- disdrodb/l0/readers/PARSIVEL2/DENMARK/DTU.py +1 -1
- disdrodb/l0/readers/PARSIVEL2/DENMARK/EROSION_nc.py +2 -1
- disdrodb/l0/readers/PARSIVEL2/DENMARK/EROSION_raw.py +2 -1
- disdrodb/l0/readers/PARSIVEL2/FINLAND/FMI_PARSIVEL2.py +1 -1
- disdrodb/l0/readers/PARSIVEL2/FRANCE/ENPC_PARSIVEL2.py +2 -3
- disdrodb/l0/readers/PARSIVEL2/FRANCE/OSUG.py +2 -2
- disdrodb/l0/readers/PARSIVEL2/FRANCE/SIRTA_PARSIVEL2.py +1 -3
- disdrodb/l0/readers/PARSIVEL2/GREECE/NOA.py +4 -3
- disdrodb/l0/readers/PARSIVEL2/ITALY/GID_PARSIVEL2.py +1 -3
- disdrodb/l0/readers/PARSIVEL2/ITALY/HYDROX.py +6 -3
- disdrodb/l0/readers/PARSIVEL2/JAPAN/PRECIP.py +1 -1
- disdrodb/l0/readers/PARSIVEL2/KIT/BURKINA_FASO.py +1 -1
- disdrodb/l0/readers/PARSIVEL2/KIT/TEAMX.py +1 -1
- disdrodb/l0/readers/PARSIVEL2/KOREA/ICEPOP_MSC.py +161 -0
- disdrodb/l0/readers/PARSIVEL2/KOREA/ICEPOP_UCLM.py +126 -0
- disdrodb/l0/readers/PARSIVEL2/MEXICO/OH_IIUNAM_nc.py +2 -1
- disdrodb/l0/readers/PARSIVEL2/MPI/BCO_PARSIVEL2.py +1 -1
- disdrodb/l0/readers/PARSIVEL2/MPI/BOWTIE.py +1 -1
- disdrodb/l0/readers/PARSIVEL2/NASA/APU.py +3 -1
- disdrodb/l0/readers/PARSIVEL2/NASA/NSSTC.py +1 -1
- disdrodb/l0/readers/PARSIVEL2/NCAR/FARM_PARSIVEL2.py +2 -1
- disdrodb/l0/readers/PARSIVEL2/NCAR/PECAN_FP3.py +1 -1
- disdrodb/l0/readers/PARSIVEL2/NCAR/PECAN_MIPS.py +1 -1
- disdrodb/l0/readers/PARSIVEL2/NCAR/PERILS_MIPS.py +2 -1
- disdrodb/l0/readers/PARSIVEL2/NCAR/PERILS_PIPS.py +2 -1
- disdrodb/l0/readers/PARSIVEL2/NCAR/RELAMPAGO_PARSIVEL2.py +1 -1
- disdrodb/l0/readers/PARSIVEL2/NCAR/SNOWIE_PJ.py +1 -1
- disdrodb/l0/readers/PARSIVEL2/NCAR/SNOWIE_SB.py +1 -1
- disdrodb/l0/readers/PARSIVEL2/NCAR/VORTEX_SE_2016_P1.py +2 -3
- disdrodb/l0/readers/PARSIVEL2/NCAR/VORTEX_SE_2016_P2.py +1 -1
- disdrodb/l0/readers/PARSIVEL2/NCAR/VORTEX_SE_2016_PIPS.py +2 -1
- disdrodb/l0/readers/PARSIVEL2/NETHERLANDS/DELFT_NC.py +1 -1
- disdrodb/l0/readers/PARSIVEL2/NORWAY/UIB.py +10 -2
- disdrodb/l0/readers/PARSIVEL2/PHILIPPINES/PAGASA.py +2 -3
- disdrodb/l0/readers/PARSIVEL2/SPAIN/CENER.py +1 -1
- disdrodb/l0/readers/PARSIVEL2/SPAIN/CR1000DL.py +1 -1
- disdrodb/l0/readers/PARSIVEL2/SPAIN/GRANADA.py +2 -3
- disdrodb/l0/readers/PARSIVEL2/SPAIN/LIAISE.py +1 -1
- disdrodb/l0/readers/PARSIVEL2/SWEDEN/SMHI.py +2 -1
- disdrodb/l0/readers/PARSIVEL2/USA/CSU.py +1 -1
- disdrodb/l0/readers/PARSIVEL2/USA/CW3E.py +2 -1
- disdrodb/l0/readers/PWS100/AUSTRIA/HOAL.py +2 -3
- disdrodb/l0/readers/PWS100/FRANCE/ENPC_PWS100.py +2 -3
- disdrodb/l0/readers/PWS100/FRANCE/ENPC_PWS100_SIRTA.py +2 -1
- disdrodb/l0/readers/RD80/BRAZIL/ATTO_RD80.py +1 -3
- disdrodb/l0/readers/RD80/BRAZIL/CHUVA_RD80.py +1 -3
- disdrodb/l0/readers/RD80/BRAZIL/GOAMAZON_RD80.py +1 -3
- disdrodb/l0/readers/RD80/NCAR/CINDY_2011_RD80.py +1 -3
- disdrodb/l0/readers/RD80/NCAR/RELAMPAGO_RD80.py +1 -3
- disdrodb/l0/readers/RD80/NOAA/PSL_RD80.py +2 -3
- disdrodb/l0/readers/SWS250/BELGIUM/KMI.py +2 -3
- disdrodb/l0/readers/template_reader_raw_netcdf_data.py +2 -3
- disdrodb/l0/readers/template_reader_raw_text_data.py +2 -3
- disdrodb/l0/standards.py +4 -5
- disdrodb/l0/template_tools.py +7 -11
- disdrodb/l1/__init__.py +2 -1
- disdrodb/l1/classification.py +914 -0
- disdrodb/l1/processing.py +36 -106
- disdrodb/l1/resampling.py +13 -3
- disdrodb/l1_env/__init__.py +1 -1
- disdrodb/l1_env/routines.py +7 -6
- disdrodb/l2/__init__.py +2 -1
- disdrodb/l2/empirical_dsd.py +58 -31
- disdrodb/l2/processing.py +327 -61
- disdrodb/metadata/checks.py +10 -13
- disdrodb/metadata/download.py +5 -4
- disdrodb/metadata/geolocation.py +3 -4
- disdrodb/metadata/info.py +3 -5
- disdrodb/metadata/manipulation.py +1 -3
- disdrodb/metadata/reader.py +1 -3
- disdrodb/metadata/search.py +1 -4
- disdrodb/metadata/standards.py +1 -3
- disdrodb/metadata/writer.py +1 -3
- disdrodb/physics/__init__.py +17 -0
- disdrodb/physics/atmosphere.py +273 -0
- disdrodb/physics/water.py +131 -0
- disdrodb/physics/wrappers.py +63 -0
- disdrodb/psd/__init__.py +1 -2
- disdrodb/psd/fitting.py +23 -9
- disdrodb/psd/models.py +2 -1
- disdrodb/routines/__init__.py +6 -1
- disdrodb/routines/l0.py +39 -25
- disdrodb/routines/l1.py +23 -16
- disdrodb/routines/l2.py +12 -9
- disdrodb/routines/options.py +117 -73
- disdrodb/routines/options_validation.py +728 -0
- disdrodb/routines/wrappers.py +460 -40
- disdrodb/scattering/__init__.py +1 -2
- disdrodb/scattering/axis_ratio.py +6 -6
- disdrodb/scattering/permittivity.py +9 -8
- disdrodb/scattering/routines.py +33 -15
- disdrodb/summary/__init__.py +1 -1
- disdrodb/summary/routines.py +95 -30
- disdrodb/utils/__init__.py +1 -1
- disdrodb/utils/archiving.py +18 -10
- disdrodb/utils/attrs.py +7 -5
- disdrodb/utils/cli.py +8 -10
- disdrodb/utils/compression.py +10 -13
- disdrodb/utils/coords.py +45 -0
- disdrodb/utils/dask.py +7 -5
- disdrodb/utils/dataframe.py +5 -6
- disdrodb/utils/decorators.py +3 -4
- disdrodb/utils/dict.py +1 -1
- disdrodb/utils/directories.py +5 -7
- disdrodb/utils/encoding.py +4 -5
- disdrodb/utils/event.py +1 -1
- disdrodb/utils/list.py +1 -3
- disdrodb/utils/logger.py +1 -3
- disdrodb/utils/manipulations.py +175 -4
- disdrodb/utils/pydantic.py +81 -0
- disdrodb/utils/routines.py +2 -3
- disdrodb/utils/subsetting.py +1 -1
- disdrodb/utils/time.py +6 -4
- disdrodb/utils/warnings.py +2 -3
- disdrodb/utils/writer.py +5 -3
- disdrodb/utils/xarray.py +31 -3
- disdrodb/utils/yaml.py +1 -3
- disdrodb/viz/__init__.py +1 -1
- disdrodb/viz/plots.py +193 -18
- {disdrodb-0.2.1.dist-info → disdrodb-0.4.0.dist-info}/METADATA +5 -4
- disdrodb-0.4.0.dist-info/RECORD +361 -0
- {disdrodb-0.2.1.dist-info → disdrodb-0.4.0.dist-info}/entry_points.txt +3 -0
- disdrodb/etc/products/L1/1MIN.yaml +0 -13
- disdrodb/etc/products/L1/LPM/1MIN.yaml +0 -13
- disdrodb/etc/products/L1/LPM_V0/1MIN.yaml +0 -13
- disdrodb/etc/products/L1/PARSIVEL/1MIN.yaml +0 -13
- disdrodb/etc/products/L1/PARSIVEL2/1MIN.yaml +0 -13
- disdrodb/etc/products/L1/PWS100/1MIN.yaml +0 -13
- disdrodb/etc/products/L1/RD80/1MIN.yaml +0 -13
- disdrodb/etc/products/L1/SWS250/1MIN.yaml +0 -13
- disdrodb/etc/products/L2M/10MIN.yaml +0 -12
- disdrodb/l1/beard_model.py +0 -662
- disdrodb/l1/filters.py +0 -205
- disdrodb-0.2.1.dist-info/RECORD +0 -329
- {disdrodb-0.2.1.dist-info → disdrodb-0.4.0.dist-info}/WHEEL +0 -0
- {disdrodb-0.2.1.dist-info → disdrodb-0.4.0.dist-info}/licenses/LICENSE +0 -0
- {disdrodb-0.2.1.dist-info → disdrodb-0.4.0.dist-info}/top_level.txt +0 -0
disdrodb/l2/processing.py
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
# -----------------------------------------------------------------------------.
|
|
2
|
-
# Copyright (c) 2021-
|
|
2
|
+
# Copyright (c) 2021-2026 DISDRODB developers
|
|
3
3
|
#
|
|
4
4
|
# This program is free software: you can redistribute it and/or modify
|
|
5
5
|
# it under the terms of the GNU General Public License as published by
|
|
@@ -19,8 +19,8 @@
|
|
|
19
19
|
import numpy as np
|
|
20
20
|
import xarray as xr
|
|
21
21
|
|
|
22
|
-
from disdrodb.constants import DIAMETER_DIMENSION
|
|
23
|
-
from disdrodb.
|
|
22
|
+
from disdrodb.constants import DIAMETER_DIMENSION, METEOROLOGICAL_VARIABLES, VELOCITY_DIMENSION
|
|
23
|
+
from disdrodb.fall_velocity import get_rain_fall_velocity, get_rain_fall_velocity_from_ds
|
|
24
24
|
from disdrodb.l1_env.routines import load_env_dataset
|
|
25
25
|
from disdrodb.l2.empirical_dsd import (
|
|
26
26
|
BINS_METRICS,
|
|
@@ -29,55 +29,23 @@ from disdrodb.l2.empirical_dsd import (
|
|
|
29
29
|
compute_spectrum_parameters,
|
|
30
30
|
get_drop_number_concentration,
|
|
31
31
|
get_effective_sampling_area,
|
|
32
|
+
get_effective_sampling_interval,
|
|
32
33
|
get_kinetic_energy_variables_from_drop_number,
|
|
34
|
+
get_min_max_diameter,
|
|
33
35
|
get_rain_accumulation,
|
|
34
36
|
get_rain_rate_from_drop_number,
|
|
35
37
|
)
|
|
36
38
|
from disdrodb.psd import create_psd, estimate_model_parameters
|
|
37
39
|
from disdrodb.psd.fitting import compute_gof_stats
|
|
38
40
|
from disdrodb.utils.decorators import check_pytmatrix_availability
|
|
39
|
-
from disdrodb.utils.
|
|
41
|
+
from disdrodb.utils.manipulations import (
|
|
42
|
+
define_diameter_array,
|
|
43
|
+
filter_diameter_bins,
|
|
44
|
+
filter_velocity_bins,
|
|
45
|
+
)
|
|
40
46
|
from disdrodb.utils.writer import finalize_product
|
|
41
47
|
|
|
42
48
|
|
|
43
|
-
def define_diameter_array(diameter_min=0, diameter_max=10, diameter_spacing=0.05):
|
|
44
|
-
"""
|
|
45
|
-
Define an array of diameters and their corresponding bin properties.
|
|
46
|
-
|
|
47
|
-
Parameters
|
|
48
|
-
----------
|
|
49
|
-
diameter_min : float, optional
|
|
50
|
-
The minimum diameter value. The default value is 0 mm.
|
|
51
|
-
diameter_max : float, optional
|
|
52
|
-
The maximum diameter value. The default value is 10 mm.
|
|
53
|
-
diameter_spacing : float, optional
|
|
54
|
-
The spacing between diameter values. The default value is 0.05 mm.
|
|
55
|
-
|
|
56
|
-
Returns
|
|
57
|
-
-------
|
|
58
|
-
xr.DataArray
|
|
59
|
-
A DataArray containing the center of each diameter bin, with coordinates for
|
|
60
|
-
the bin width, lower bound, upper bound, and center.
|
|
61
|
-
|
|
62
|
-
"""
|
|
63
|
-
diameters_bounds = np.arange(diameter_min, diameter_max + diameter_spacing / 2, step=diameter_spacing)
|
|
64
|
-
diameters_bin_lower = diameters_bounds[:-1]
|
|
65
|
-
diameters_bin_upper = diameters_bounds[1:]
|
|
66
|
-
diameters_bin_width = diameters_bin_upper - diameters_bin_lower
|
|
67
|
-
diameters_bin_center = diameters_bin_lower + diameters_bin_width / 2
|
|
68
|
-
da = xr.DataArray(
|
|
69
|
-
diameters_bin_center,
|
|
70
|
-
dims="diameter_bin_center",
|
|
71
|
-
coords={
|
|
72
|
-
"diameter_bin_width": ("diameter_bin_center", diameters_bin_width),
|
|
73
|
-
"diameter_bin_lower": ("diameter_bin_center", diameters_bin_lower),
|
|
74
|
-
"diameter_bin_upper": ("diameter_bin_center", diameters_bin_upper),
|
|
75
|
-
"diameter_bin_center": ("diameter_bin_center", diameters_bin_center),
|
|
76
|
-
},
|
|
77
|
-
)
|
|
78
|
-
return da
|
|
79
|
-
|
|
80
|
-
|
|
81
49
|
def define_velocity_array(ds):
|
|
82
50
|
"""
|
|
83
51
|
Create the fall velocity DataArray using various methods.
|
|
@@ -99,7 +67,7 @@ def define_velocity_array(ds):
|
|
|
99
67
|
if "velocity_bin_center" in ds.dims:
|
|
100
68
|
velocity = xr.Dataset(
|
|
101
69
|
{
|
|
102
|
-
"
|
|
70
|
+
"theoretical_velocity": xr.ones_like(drop_number) * ds["fall_velocity"],
|
|
103
71
|
"measured_velocity": xr.ones_like(drop_number) * ds["velocity_bin_center"],
|
|
104
72
|
},
|
|
105
73
|
).to_array(dim="velocity_method")
|
|
@@ -108,12 +76,183 @@ def define_velocity_array(ds):
|
|
|
108
76
|
return velocity
|
|
109
77
|
|
|
110
78
|
|
|
79
|
+
####--------------------------------------------------------------------------
|
|
80
|
+
#### Extract drop spectrum
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def retrieve_drop_spectrum(
|
|
84
|
+
ds,
|
|
85
|
+
ds_env,
|
|
86
|
+
above_velocity_fraction=None,
|
|
87
|
+
above_velocity_tolerance=None,
|
|
88
|
+
below_velocity_fraction=None,
|
|
89
|
+
below_velocity_tolerance=None,
|
|
90
|
+
maintain_drops_smaller_than=1,
|
|
91
|
+
maintain_drops_slower_than=2.5,
|
|
92
|
+
maintain_smallest_drops=False,
|
|
93
|
+
remove_splashing_drops=True,
|
|
94
|
+
fall_velocity_model="Beard1976",
|
|
95
|
+
):
|
|
96
|
+
"""Retrieve the drop spectrum from the DISDRODB L1 product."""
|
|
97
|
+
from disdrodb.fall_velocity.rain import get_rain_fall_velocity
|
|
98
|
+
|
|
99
|
+
# Retrieve spectrum
|
|
100
|
+
raw_spectrum = ds["raw_drop_number"].copy()
|
|
101
|
+
|
|
102
|
+
# Retrieve coordinates
|
|
103
|
+
diameter_upper = raw_spectrum["diameter_bin_upper"]
|
|
104
|
+
diameter_lower = raw_spectrum["diameter_bin_lower"]
|
|
105
|
+
velocity_upper = raw_spectrum["velocity_bin_upper"]
|
|
106
|
+
|
|
107
|
+
# Retrieve rainfall mask
|
|
108
|
+
raindrop_fall_velocity_upper = get_rain_fall_velocity(
|
|
109
|
+
diameter=diameter_upper,
|
|
110
|
+
model=fall_velocity_model,
|
|
111
|
+
ds_env=ds_env,
|
|
112
|
+
)
|
|
113
|
+
raindrop_fall_velocity_lower = get_rain_fall_velocity(
|
|
114
|
+
diameter=diameter_lower,
|
|
115
|
+
model=fall_velocity_model,
|
|
116
|
+
ds_env=ds_env,
|
|
117
|
+
)
|
|
118
|
+
rain_mask = define_rain_spectrum_mask(
|
|
119
|
+
drop_number=raw_spectrum,
|
|
120
|
+
fall_velocity_lower=raindrop_fall_velocity_lower,
|
|
121
|
+
fall_velocity_upper=raindrop_fall_velocity_upper,
|
|
122
|
+
above_velocity_fraction=above_velocity_fraction,
|
|
123
|
+
above_velocity_tolerance=above_velocity_tolerance,
|
|
124
|
+
below_velocity_fraction=below_velocity_fraction,
|
|
125
|
+
below_velocity_tolerance=below_velocity_tolerance,
|
|
126
|
+
maintain_drops_smaller_than=maintain_drops_smaller_than,
|
|
127
|
+
maintain_drops_slower_than=maintain_drops_slower_than,
|
|
128
|
+
maintain_smallest_drops=maintain_smallest_drops,
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
# Set to 0 spectrum not classified as liquid or mixed
|
|
132
|
+
if "precipitation_type" in ds:
|
|
133
|
+
raw_spectrum = xr.where(ds["precipitation_type"].isin([0, 2]), raw_spectrum, 0)
|
|
134
|
+
|
|
135
|
+
# Retrieve drop spectrum
|
|
136
|
+
# - Liquid + Mixed
|
|
137
|
+
drop_spectrum = raw_spectrum.where(rain_mask, 0)
|
|
138
|
+
|
|
139
|
+
# Optionally mask area affected by splashing
|
|
140
|
+
if remove_splashing_drops and "flag_splashing" in ds:
|
|
141
|
+
flag_splashing = ds["flag_splashing"]
|
|
142
|
+
splash_mask = (diameter_lower >= 0.0) & (diameter_upper <= 6) & (velocity_upper <= 0.6)
|
|
143
|
+
|
|
144
|
+
drop_spectrum = xr.where(flag_splashing == 1, drop_spectrum.where(~splash_mask, 0), drop_spectrum)
|
|
145
|
+
return drop_spectrum
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
def define_rain_spectrum_mask(
|
|
149
|
+
drop_number,
|
|
150
|
+
fall_velocity_lower,
|
|
151
|
+
fall_velocity_upper,
|
|
152
|
+
above_velocity_fraction=None,
|
|
153
|
+
above_velocity_tolerance=None,
|
|
154
|
+
below_velocity_fraction=None,
|
|
155
|
+
below_velocity_tolerance=None,
|
|
156
|
+
maintain_drops_smaller_than=1, # 1, # 2
|
|
157
|
+
maintain_drops_slower_than=2.5, # 2.5, # 3
|
|
158
|
+
maintain_smallest_drops=False,
|
|
159
|
+
):
|
|
160
|
+
"""Define a mask for the drop spectrum based on fall velocity thresholds.
|
|
161
|
+
|
|
162
|
+
Parameters
|
|
163
|
+
----------
|
|
164
|
+
drop_number : xarray.DataArray
|
|
165
|
+
Array of drop counts per diameter and velocity bins.
|
|
166
|
+
fall_velocity_lower : array-like
|
|
167
|
+
The expected terminal fall velocities lower bound for rain drops of given size interval.
|
|
168
|
+
fall_velocity_upper : array-like
|
|
169
|
+
The expected terminal fall velocities upper bound for rain drops of given size interval.
|
|
170
|
+
above_velocity_fraction : float, optional
|
|
171
|
+
Fraction of terminal fall velocity above which rain drops are considered too fast.
|
|
172
|
+
Either specify ``above_velocity_fraction`` or ``above_velocity_tolerance``.
|
|
173
|
+
above_velocity_tolerance : float, optional
|
|
174
|
+
Absolute tolerance above which rain drops terminal fall velocities are considered too fast.
|
|
175
|
+
Either specify ``above_velocity_fraction`` or ``above_velocity_tolerance``.
|
|
176
|
+
below_velocity_fraction : float, optional
|
|
177
|
+
Fraction of terminal fall velocity below which rain drops are considered too slow.
|
|
178
|
+
Either specify ``below_velocity_fraction`` or ``below_velocity_tolerance``.
|
|
179
|
+
below_velocity_tolerance : float, optional
|
|
180
|
+
Absolute tolerance below which rain drops terminal fall velocities are considered too slow.
|
|
181
|
+
Either specify ``below_velocity_fraction`` or ``below_velocity_tolerance``.
|
|
182
|
+
maintain_smallest : bool, optional
|
|
183
|
+
If True, ensures that the small rain drops in the spectrum are retained in the mask.
|
|
184
|
+
The smallest rain drops are characterized by ``maintain_drops_smaller_than``
|
|
185
|
+
and ``maintain_drops_slower_than`` arguments.
|
|
186
|
+
Defaults to False.
|
|
187
|
+
maintain_drops_smaller_than : float, optional
|
|
188
|
+
The diameter threshold to use for keeping the smallest rain drop.
|
|
189
|
+
Defaults to 1 mm.
|
|
190
|
+
maintain_drops_slower_than : float, optional
|
|
191
|
+
The fall velocity threshold to use for keeping the smallest rain drops.
|
|
192
|
+
Defaults to 2.5 m/s.
|
|
193
|
+
|
|
194
|
+
Returns
|
|
195
|
+
-------
|
|
196
|
+
xarray.DataArray
|
|
197
|
+
A boolean mask array indicating valid bins according to the specified criteria.
|
|
198
|
+
|
|
199
|
+
"""
|
|
200
|
+
# Ensure it creates a 2D mask if the fall_velocity does not vary over time
|
|
201
|
+
if "time" in drop_number.dims and "time" not in fall_velocity_lower.dims:
|
|
202
|
+
drop_number = drop_number.isel(time=0)
|
|
203
|
+
|
|
204
|
+
# Check arguments
|
|
205
|
+
if above_velocity_fraction is not None and above_velocity_tolerance is not None:
|
|
206
|
+
raise ValueError("Either specify 'above_velocity_fraction' or 'above_velocity_tolerance'.")
|
|
207
|
+
if below_velocity_fraction is not None and below_velocity_tolerance is not None:
|
|
208
|
+
raise ValueError("Either specify 'below_velocity_fraction' or 'below_velocity_tolerance'.")
|
|
209
|
+
|
|
210
|
+
# Define above/below velocity thresholds
|
|
211
|
+
if above_velocity_fraction is not None:
|
|
212
|
+
above_fall_velocity = fall_velocity_upper * (1 + above_velocity_fraction)
|
|
213
|
+
elif above_velocity_tolerance is not None:
|
|
214
|
+
above_fall_velocity = fall_velocity_upper + above_velocity_tolerance
|
|
215
|
+
else:
|
|
216
|
+
above_fall_velocity = np.inf
|
|
217
|
+
|
|
218
|
+
if below_velocity_fraction is not None:
|
|
219
|
+
below_fall_velocity = fall_velocity_lower * (1 - below_velocity_fraction)
|
|
220
|
+
elif below_velocity_tolerance is not None:
|
|
221
|
+
below_fall_velocity = fall_velocity_lower - below_velocity_tolerance
|
|
222
|
+
else:
|
|
223
|
+
below_fall_velocity = 0
|
|
224
|
+
|
|
225
|
+
# Define velocity 2D array
|
|
226
|
+
velocity_lower = xr.ones_like(drop_number) * drop_number["velocity_bin_lower"]
|
|
227
|
+
velocity_upper = xr.ones_like(drop_number) * drop_number["velocity_bin_upper"]
|
|
228
|
+
|
|
229
|
+
# Define mask
|
|
230
|
+
mask = np.logical_and(
|
|
231
|
+
velocity_upper > below_fall_velocity,
|
|
232
|
+
velocity_lower < above_fall_velocity,
|
|
233
|
+
)
|
|
234
|
+
|
|
235
|
+
# Maintant smallest drops
|
|
236
|
+
if maintain_smallest_drops:
|
|
237
|
+
mask_smallest = np.logical_and(
|
|
238
|
+
drop_number["diameter_bin_upper"] <= maintain_drops_smaller_than,
|
|
239
|
+
drop_number["velocity_bin_upper"] <= maintain_drops_slower_than,
|
|
240
|
+
)
|
|
241
|
+
mask = np.logical_or(mask, mask_smallest)
|
|
242
|
+
|
|
243
|
+
return mask
|
|
244
|
+
|
|
245
|
+
|
|
111
246
|
####--------------------------------------------------------------------------
|
|
112
247
|
#### Timesteps filtering functions
|
|
113
248
|
|
|
114
249
|
|
|
115
250
|
def select_timesteps_with_drops(ds, minimum_ndrops=0):
|
|
116
251
|
"""Select timesteps with at least the specified number of drops."""
|
|
252
|
+
# If not a unique time dimension, skip subsetting
|
|
253
|
+
if ds["N"].dims != ("time",):
|
|
254
|
+
return ds
|
|
255
|
+
# Otherwise subset time dimension
|
|
117
256
|
valid_timesteps = ds["N"].to_numpy() >= minimum_ndrops
|
|
118
257
|
if not valid_timesteps.any().item():
|
|
119
258
|
raise ValueError(f"No timesteps with N >= {minimum_ndrops}.")
|
|
@@ -124,6 +263,10 @@ def select_timesteps_with_drops(ds, minimum_ndrops=0):
|
|
|
124
263
|
|
|
125
264
|
def select_timesteps_with_minimum_nbins(ds, minimum_nbins):
|
|
126
265
|
"""Select timesteps with at least the specified number of diameter bins with drops."""
|
|
266
|
+
# If not a unique time dimension, skip subsetting
|
|
267
|
+
if ds["Nbins"].dims != ("time",):
|
|
268
|
+
return ds
|
|
269
|
+
# Otherwise subset time dimension
|
|
127
270
|
if minimum_nbins == 0:
|
|
128
271
|
return ds
|
|
129
272
|
valid_timesteps = ds["Nbins"].to_numpy() >= minimum_nbins
|
|
@@ -167,7 +310,7 @@ def check_l2e_input_dataset(ds):
|
|
|
167
310
|
from disdrodb.scattering import RADAR_OPTIONS
|
|
168
311
|
|
|
169
312
|
# Check minimum required variables, coordinates and dimensions are presents
|
|
170
|
-
required_variables = ["
|
|
313
|
+
required_variables = ["raw_drop_number"]
|
|
171
314
|
required_coords = [
|
|
172
315
|
"diameter_bin_center",
|
|
173
316
|
"diameter_bin_width",
|
|
@@ -194,9 +337,25 @@ def generate_l2e(
|
|
|
194
337
|
ds_env=None,
|
|
195
338
|
compute_spectra=False,
|
|
196
339
|
compute_percentage_contribution=False,
|
|
340
|
+
# Filtering options
|
|
197
341
|
minimum_ndrops=1,
|
|
198
342
|
minimum_nbins=1,
|
|
199
343
|
minimum_rain_rate=0.01,
|
|
344
|
+
minimum_diameter=0,
|
|
345
|
+
maximum_diameter=10,
|
|
346
|
+
minimum_velocity=0,
|
|
347
|
+
maximum_velocity=12,
|
|
348
|
+
keep_mixed_precipitation=False,
|
|
349
|
+
# Spectrum filtering options
|
|
350
|
+
fall_velocity_model="Beard1976",
|
|
351
|
+
above_velocity_fraction=0.5,
|
|
352
|
+
above_velocity_tolerance=None,
|
|
353
|
+
below_velocity_fraction=0.5,
|
|
354
|
+
below_velocity_tolerance=None,
|
|
355
|
+
maintain_drops_smaller_than=1, # 2
|
|
356
|
+
maintain_drops_slower_than=2.5, # 3
|
|
357
|
+
maintain_smallest_drops=True,
|
|
358
|
+
remove_splashing_drops=True,
|
|
200
359
|
):
|
|
201
360
|
"""Generate the DISDRODB L2E dataset from the DISDRODB L1 dataset.
|
|
202
361
|
|
|
@@ -205,15 +364,40 @@ def generate_l2e(
|
|
|
205
364
|
ds : xarray.Dataset
|
|
206
365
|
DISDRODB L1 dataset.
|
|
207
366
|
Alternatively, a xarray dataset with at least:
|
|
208
|
-
|
|
209
|
-
- variables: drop_number, fall_velocity
|
|
367
|
+
- variables: raw_drop_number
|
|
210
368
|
- dimension: DIAMETER_DIMENSION
|
|
211
369
|
- coordinates: diameter_bin_center, diameter_bin_width, sample_interval
|
|
212
370
|
- attributes: sensor_name
|
|
213
|
-
|
|
214
371
|
ds_env : xarray.Dataset, optional
|
|
215
372
|
Environmental dataset used for fall velocity and water density estimates.
|
|
216
373
|
If None, a default environment dataset will be loaded.
|
|
374
|
+
fall_velocity_model : str, optional
|
|
375
|
+
Model name to estimate drop fall velocity.
|
|
376
|
+
The default method is ``"Beard1976"``.
|
|
377
|
+
minimum_diameter : float, optional
|
|
378
|
+
Minimum diameter for filtering. The default value is 0 mm.
|
|
379
|
+
maximum_diameter : float, optional
|
|
380
|
+
Maximum diameter for filtering. The default value is 10 mm.
|
|
381
|
+
minimum_velocity : float, optional
|
|
382
|
+
Minimum velocity for filtering. The default value is 0 m/s.
|
|
383
|
+
maximum_velocity : float, optional
|
|
384
|
+
Maximum velocity for filtering. The default value is 12 m/s.
|
|
385
|
+
above_velocity_fraction : float, optional
|
|
386
|
+
Fraction of drops above velocity threshold. The default value is 0.5.
|
|
387
|
+
above_velocity_tolerance : float or None, optional
|
|
388
|
+
Tolerance for above velocity filtering. The default value is ``None``.
|
|
389
|
+
below_velocity_fraction : float, optional
|
|
390
|
+
Fraction of drops below velocity threshold. The default value is 0.5.
|
|
391
|
+
below_velocity_tolerance : float or None, optional
|
|
392
|
+
Tolerance for below velocity filtering. The default value is ``None``.
|
|
393
|
+
maintain_drops_smaller_than : float, optional
|
|
394
|
+
Threshold for small diameter drops. The default value is 1.
|
|
395
|
+
maintain_drops_slower_than : float, optional
|
|
396
|
+
Threshold for small velocity drops. The default value is 2.5.
|
|
397
|
+
maintain_smallest_drops : bool, optional
|
|
398
|
+
Whether to maintain the smallest drops. The default value is ``True``.
|
|
399
|
+
remove_splashing_drops: bool, optional
|
|
400
|
+
Whether to mask splashing drops. The default value is ``True``.
|
|
217
401
|
|
|
218
402
|
Returns
|
|
219
403
|
-------
|
|
@@ -223,6 +407,67 @@ def generate_l2e(
|
|
|
223
407
|
# Check and prepapre input dataset
|
|
224
408
|
ds = check_l2e_input_dataset(ds)
|
|
225
409
|
|
|
410
|
+
# Select only dry and rainy timesteps
|
|
411
|
+
if "precipitation_type" in ds:
|
|
412
|
+
if keep_mixed_precipitation: # class 4
|
|
413
|
+
ds = ds.isel(time=ds["precipitation_type"].isin([-1, 0, 4]), drop=True)
|
|
414
|
+
else:
|
|
415
|
+
ds = ds.isel(time=ds["precipitation_type"].isin([-1, 0]), drop=True)
|
|
416
|
+
|
|
417
|
+
# Determine if the velocity dimension is available
|
|
418
|
+
has_velocity_dimension = VELOCITY_DIMENSION in ds.dims
|
|
419
|
+
|
|
420
|
+
# - Filter diameter bins
|
|
421
|
+
ds = filter_diameter_bins(ds=ds, minimum_diameter=minimum_diameter, maximum_diameter=maximum_diameter)
|
|
422
|
+
# - Filter velocity bins
|
|
423
|
+
if has_velocity_dimension:
|
|
424
|
+
ds = filter_velocity_bins(ds=ds, minimum_velocity=minimum_velocity, maximum_velocity=maximum_velocity)
|
|
425
|
+
|
|
426
|
+
# -------------------------------------------------------------------------------------------
|
|
427
|
+
# Compute fall velocity
|
|
428
|
+
ds["fall_velocity"] = get_rain_fall_velocity_from_ds(ds=ds, ds_env=ds_env, model=fall_velocity_model)
|
|
429
|
+
|
|
430
|
+
# -------------------------------------------------------
|
|
431
|
+
# Retrieve filtered spectrum and drop counts (summing over velocity dimension if present)
|
|
432
|
+
if has_velocity_dimension:
|
|
433
|
+
drop_number = retrieve_drop_spectrum(
|
|
434
|
+
ds=ds,
|
|
435
|
+
ds_env=ds_env,
|
|
436
|
+
above_velocity_fraction=above_velocity_fraction,
|
|
437
|
+
above_velocity_tolerance=above_velocity_tolerance,
|
|
438
|
+
below_velocity_fraction=below_velocity_fraction,
|
|
439
|
+
below_velocity_tolerance=below_velocity_tolerance,
|
|
440
|
+
maintain_drops_smaller_than=maintain_drops_smaller_than,
|
|
441
|
+
maintain_drops_slower_than=maintain_drops_slower_than,
|
|
442
|
+
maintain_smallest_drops=maintain_smallest_drops,
|
|
443
|
+
remove_splashing_drops=remove_splashing_drops,
|
|
444
|
+
fall_velocity_model=fall_velocity_model,
|
|
445
|
+
)
|
|
446
|
+
drop_counts = drop_number.sum(dim=VELOCITY_DIMENSION) # 1D (diameter)
|
|
447
|
+
drop_counts_raw = ds["raw_drop_number"].sum(dim=VELOCITY_DIMENSION) # 1D (diameter)
|
|
448
|
+
else:
|
|
449
|
+
drop_number = ds["raw_drop_number"] # no filtering applied
|
|
450
|
+
drop_counts = ds["raw_drop_number"] # 1D (diameter)
|
|
451
|
+
drop_counts_raw = ds["raw_drop_number"]
|
|
452
|
+
|
|
453
|
+
ds["drop_number"] = drop_number
|
|
454
|
+
ds["drop_counts"] = drop_counts
|
|
455
|
+
|
|
456
|
+
# -------------------------------------------------------
|
|
457
|
+
# Compute drop statistics
|
|
458
|
+
# - Compute minimum and max drop diameter observed
|
|
459
|
+
min_drop_diameter, max_drop_diameter = get_min_max_diameter(drop_counts)
|
|
460
|
+
|
|
461
|
+
# - Add rain drop statistics
|
|
462
|
+
ds["Dmin"] = min_drop_diameter
|
|
463
|
+
ds["Dmax"] = max_drop_diameter
|
|
464
|
+
ds["N"] = drop_counts.sum(dim=DIAMETER_DIMENSION)
|
|
465
|
+
ds["Nraw"] = drop_counts_raw.sum(dim=DIAMETER_DIMENSION)
|
|
466
|
+
ds["Nremoved"] = ds["Nraw"] - ds["N"]
|
|
467
|
+
|
|
468
|
+
# - Add bins statistics
|
|
469
|
+
ds = add_bins_metrics(ds)
|
|
470
|
+
|
|
226
471
|
# -------------------------------------------------------
|
|
227
472
|
# Initialize L2E dataset
|
|
228
473
|
ds_l2 = xr.Dataset()
|
|
@@ -235,9 +480,6 @@ def generate_l2e(
|
|
|
235
480
|
# Select timesteps with at least the specified number of drops
|
|
236
481
|
ds = select_timesteps_with_drops(ds, minimum_ndrops=minimum_ndrops)
|
|
237
482
|
|
|
238
|
-
# Add bins metrics to resampled data if missing
|
|
239
|
-
ds = add_bins_metrics(ds)
|
|
240
|
-
|
|
241
483
|
# Remove timesteps with not enough bins with drops
|
|
242
484
|
ds = select_timesteps_with_minimum_nbins(ds, minimum_nbins=minimum_nbins)
|
|
243
485
|
|
|
@@ -256,24 +498,41 @@ def generate_l2e(
|
|
|
256
498
|
diameter = ds["diameter_bin_center"] / 1000 # m
|
|
257
499
|
diameter_bin_width = ds["diameter_bin_width"] # mm
|
|
258
500
|
drop_number = ds["drop_number"]
|
|
259
|
-
sample_interval = ensure_sample_interval_in_seconds(ds["sample_interval"]) # s
|
|
260
501
|
|
|
261
|
-
#
|
|
502
|
+
# Retrieve effective sampling interval [s]
|
|
503
|
+
sample_interval = get_effective_sampling_interval(ds, sensor_name=sensor_name) # s
|
|
504
|
+
|
|
505
|
+
# Retrieve effective sampling area [m2]
|
|
262
506
|
sampling_area = get_effective_sampling_area(sensor_name=sensor_name, diameter=diameter) # m2
|
|
263
507
|
|
|
264
508
|
# Copy relevant L1 variables to L2 product
|
|
265
509
|
variables = [
|
|
510
|
+
# L1 inputs
|
|
511
|
+
"sample_interval",
|
|
512
|
+
"fall_velocity",
|
|
266
513
|
"raw_drop_number", # 2D V x D
|
|
267
514
|
"drop_number", # 2D V x D
|
|
515
|
+
# Drop statistics
|
|
268
516
|
"drop_counts", # 1D D
|
|
269
|
-
"sample_interval",
|
|
270
517
|
"N",
|
|
271
518
|
"Nremoved",
|
|
519
|
+
"Nraw",
|
|
272
520
|
"Dmin",
|
|
273
521
|
"Dmax",
|
|
274
|
-
|
|
522
|
+
# L0C QC
|
|
523
|
+
"qc_time",
|
|
524
|
+
# L1 flags and variables
|
|
275
525
|
"qc_resampling",
|
|
276
|
-
"
|
|
526
|
+
"precipitation_type",
|
|
527
|
+
"hydrometeor_type",
|
|
528
|
+
"n_margin_fallers",
|
|
529
|
+
"n_splashing",
|
|
530
|
+
"flag_graupel",
|
|
531
|
+
"flag_hail",
|
|
532
|
+
"flag_spikes",
|
|
533
|
+
"flag_splashing",
|
|
534
|
+
"flag_wind_artefacts",
|
|
535
|
+
*METEOROLOGICAL_VARIABLES,
|
|
277
536
|
]
|
|
278
537
|
|
|
279
538
|
variables = [var for var in variables if var in ds]
|
|
@@ -289,6 +548,7 @@ def generate_l2e(
|
|
|
289
548
|
# -------------------------------------------------------------------------------------------
|
|
290
549
|
# Define velocity array with dimension 'velocity_method'
|
|
291
550
|
velocity = define_velocity_array(ds)
|
|
551
|
+
velocity = velocity.fillna(0)
|
|
292
552
|
|
|
293
553
|
# Compute drop number concentration (Nt) [#/m3/mm]
|
|
294
554
|
drop_number_concentration = get_drop_number_concentration(
|
|
@@ -398,7 +658,7 @@ def check_l2m_input_dataset(ds):
|
|
|
398
658
|
if "drop_number_concentration" not in ds:
|
|
399
659
|
if "drop_number" in ds:
|
|
400
660
|
check_l2e_input_dataset(ds)
|
|
401
|
-
sample_interval =
|
|
661
|
+
sample_interval = get_effective_sampling_interval(ds, sensor_name=ds.attrs["sensor_name"])
|
|
402
662
|
sampling_area = get_effective_sampling_area(
|
|
403
663
|
sensor_name=ds.attrs["sensor_name"],
|
|
404
664
|
diameter=ds["diameter_bin_center"] / 1000,
|
|
@@ -503,7 +763,7 @@ def generate_l2m(
|
|
|
503
763
|
|
|
504
764
|
# Retrieve measurement interval
|
|
505
765
|
# - If dataset is opened with decode_timedelta=False, sample_interval is already in seconds !
|
|
506
|
-
sample_interval =
|
|
766
|
+
sample_interval = get_effective_sampling_interval(ds, sensor_name=ds.attrs["sensor_name"])
|
|
507
767
|
|
|
508
768
|
# Select timesteps with at least the specified number of drops
|
|
509
769
|
ds = select_timesteps_with_drops(ds, minimum_ndrops=minimum_ndrops)
|
|
@@ -549,7 +809,7 @@ def generate_l2m(
|
|
|
549
809
|
drop_number_concentration = psd(diameter)
|
|
550
810
|
|
|
551
811
|
# Retrieve fall velocity for each new diameter bin
|
|
552
|
-
velocity =
|
|
812
|
+
velocity = get_rain_fall_velocity(diameter=diameter, model=fall_velocity_model, ds_env=ds_env) # mm
|
|
553
813
|
|
|
554
814
|
# Compute integral parameters
|
|
555
815
|
ds_params = compute_integral_parameters(
|
|
@@ -576,9 +836,15 @@ def generate_l2m(
|
|
|
576
836
|
|
|
577
837
|
# Add empirical drop_number_concentration and fall velocity
|
|
578
838
|
# - To reuse output dataset to create another L2M dataset or to compute other GOF metrics
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
839
|
+
# Copy relevant L1 variables to L2 product
|
|
840
|
+
variables = [
|
|
841
|
+
"drop_number_concentration",
|
|
842
|
+
"fall_velocity",
|
|
843
|
+
"N",
|
|
844
|
+
*METEOROLOGICAL_VARIABLES,
|
|
845
|
+
]
|
|
846
|
+
variables = [var for var in variables if var in ds]
|
|
847
|
+
ds_params.update(ds[variables])
|
|
582
848
|
ds_params.update(ds[BINS_METRICS])
|
|
583
849
|
|
|
584
850
|
#### ----------------------------------------------------------------------------.
|
disdrodb/metadata/checks.py
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
|
|
3
1
|
# -----------------------------------------------------------------------------.
|
|
4
|
-
# Copyright (c) 2021-
|
|
2
|
+
# Copyright (c) 2021-2026 DISDRODB developers
|
|
5
3
|
#
|
|
6
4
|
# This program is free software: you can redistribute it and/or modify
|
|
7
5
|
# it under the terms of the GNU General Public License as published by
|
|
@@ -19,7 +17,6 @@
|
|
|
19
17
|
"""Check metadata."""
|
|
20
18
|
|
|
21
19
|
import os
|
|
22
|
-
from typing import Optional, Union
|
|
23
20
|
|
|
24
21
|
import numpy as np
|
|
25
22
|
|
|
@@ -192,7 +189,7 @@ def check_station_metadata_geolocation(metadata, raise_error_if_unknown=True) ->
|
|
|
192
189
|
_check_lonlat_validity(longitude=longitude, latitude=latitude, raise_error_if_unknown=raise_error_if_unknown)
|
|
193
190
|
|
|
194
191
|
|
|
195
|
-
def check_metadata_archive_geolocation(metadata_archive_dir:
|
|
192
|
+
def check_metadata_archive_geolocation(metadata_archive_dir: str | None = None, raise_error_if_unknown=True):
|
|
196
193
|
"""Check the metadata files have missing or wrong geolocation..
|
|
197
194
|
|
|
198
195
|
Parameters
|
|
@@ -261,7 +258,7 @@ def check_station_metadata(data_source, campaign_name, station_name, metadata_ar
|
|
|
261
258
|
check_metadata_reader(metadata)
|
|
262
259
|
|
|
263
260
|
|
|
264
|
-
def check_metadata_archive(metadata_archive_dir:
|
|
261
|
+
def check_metadata_archive(metadata_archive_dir: str | None = None, raise_error=False):
|
|
265
262
|
"""Check the archive metadata compliance.
|
|
266
263
|
|
|
267
264
|
Parameters
|
|
@@ -336,7 +333,7 @@ def identify_missing_metadata_coords(metadata_filepaths: str) -> None:
|
|
|
336
333
|
check_station_metadata_geolocation(metadata)
|
|
337
334
|
|
|
338
335
|
|
|
339
|
-
def identify_empty_metadata_keys(metadata_filepaths: list, keys:
|
|
336
|
+
def identify_empty_metadata_keys(metadata_filepaths: list, keys: str | list) -> None:
|
|
340
337
|
"""Identify empty metadata keys.
|
|
341
338
|
|
|
342
339
|
Parameters
|
|
@@ -360,7 +357,7 @@ def identify_empty_metadata_keys(metadata_filepaths: list, keys: Union[str, list
|
|
|
360
357
|
#### Metadata Archive Utilities
|
|
361
358
|
|
|
362
359
|
|
|
363
|
-
def check_metadata_archive_keys(metadata_archive_dir:
|
|
360
|
+
def check_metadata_archive_keys(metadata_archive_dir: str | None = None) -> bool:
|
|
364
361
|
"""Check that all metadata files have valid keys.
|
|
365
362
|
|
|
366
363
|
Parameters
|
|
@@ -407,7 +404,7 @@ def check_metadata_archive_keys(metadata_archive_dir: Optional[str] = None) -> b
|
|
|
407
404
|
return is_valid
|
|
408
405
|
|
|
409
406
|
|
|
410
|
-
def check_metadata_archive_campaign_name(metadata_archive_dir:
|
|
407
|
+
def check_metadata_archive_campaign_name(metadata_archive_dir: str | None = None) -> bool:
|
|
411
408
|
"""Check metadata ``campaign_name``.
|
|
412
409
|
|
|
413
410
|
Parameters
|
|
@@ -453,7 +450,7 @@ def check_metadata_archive_campaign_name(metadata_archive_dir: Optional[str] = N
|
|
|
453
450
|
return is_valid
|
|
454
451
|
|
|
455
452
|
|
|
456
|
-
def check_metadata_archive_data_source(metadata_archive_dir:
|
|
453
|
+
def check_metadata_archive_data_source(metadata_archive_dir: str | None = None) -> bool:
|
|
457
454
|
"""Check metadata ``data_source``.
|
|
458
455
|
|
|
459
456
|
Parameters
|
|
@@ -499,7 +496,7 @@ def check_metadata_archive_data_source(metadata_archive_dir: Optional[str] = Non
|
|
|
499
496
|
return is_valid
|
|
500
497
|
|
|
501
498
|
|
|
502
|
-
def check_metadata_archive_sensor_name(metadata_archive_dir:
|
|
499
|
+
def check_metadata_archive_sensor_name(metadata_archive_dir: str | None = None) -> bool:
|
|
503
500
|
"""Check metadata ``sensor_name``.
|
|
504
501
|
|
|
505
502
|
Parameters
|
|
@@ -545,7 +542,7 @@ def check_metadata_archive_sensor_name(metadata_archive_dir: Optional[str] = Non
|
|
|
545
542
|
return is_valid
|
|
546
543
|
|
|
547
544
|
|
|
548
|
-
def check_metadata_archive_station_name(metadata_archive_dir:
|
|
545
|
+
def check_metadata_archive_station_name(metadata_archive_dir: str | None = None) -> bool:
|
|
549
546
|
"""Check metadata ``station_name``.
|
|
550
547
|
|
|
551
548
|
Parameters
|
|
@@ -591,7 +588,7 @@ def check_metadata_archive_station_name(metadata_archive_dir: Optional[str] = No
|
|
|
591
588
|
return is_valid
|
|
592
589
|
|
|
593
590
|
|
|
594
|
-
def check_metadata_archive_reader(metadata_archive_dir:
|
|
591
|
+
def check_metadata_archive_reader(metadata_archive_dir: str | None = None) -> bool:
|
|
595
592
|
"""Check if the ``reader`` key is available and there is the associated reader.
|
|
596
593
|
|
|
597
594
|
Parameters
|
disdrodb/metadata/download.py
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
|
|
3
1
|
# -----------------------------------------------------------------------------.
|
|
4
|
-
# Copyright (c) 2021-
|
|
2
|
+
# Copyright (c) 2021-2026 DISDRODB developers
|
|
5
3
|
#
|
|
6
4
|
# This program is free software: you can redistribute it and/or modify
|
|
7
5
|
# it under the terms of the GNU General Public License as published by
|
|
@@ -17,12 +15,15 @@
|
|
|
17
15
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
18
16
|
# -----------------------------------------------------------------------------.
|
|
19
17
|
"""Routine to download the DISDRODB Metadata Archive from GitHub."""
|
|
18
|
+
|
|
20
19
|
import io
|
|
21
20
|
import os
|
|
22
21
|
import shutil
|
|
23
22
|
import urllib.request
|
|
24
23
|
import zipfile
|
|
25
24
|
|
|
25
|
+
from disdrodb.utils.directories import remove_file_or_directories
|
|
26
|
+
|
|
26
27
|
|
|
27
28
|
def download_metadata_archive(directory_path, force=False):
|
|
28
29
|
"""Download the DISDRODB Metadata Archive to the specified directory.
|
|
@@ -64,7 +65,7 @@ def download_metadata_archive(directory_path, force=False):
|
|
|
64
65
|
# Handle existing target directory
|
|
65
66
|
if os.path.exists(target_dir):
|
|
66
67
|
if force:
|
|
67
|
-
|
|
68
|
+
remove_file_or_directories(target_dir)
|
|
68
69
|
else:
|
|
69
70
|
raise FileExistsError(
|
|
70
71
|
f"A DISDRODB Metadata Archive already exists at '{target_dir}'. Use force=True to update it.",
|