disdrodb 0.0.21__py3-none-any.whl → 0.1.1__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 +306 -270
- 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 +46 -51
- 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 +84 -65
- disdrodb/l0/configs/{Thies_LPM → LPM}/l0b_encodings.yml +50 -9
- disdrodb/l0/configs/{Thies_LPM → LPM}/raw_data_format.yml +285 -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 +23 -21
- 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 +28 -26
- disdrodb/l0/configs/{OTT_Parsivel2 → PARSIVEL2}/l0b_encodings.yml +20 -20
- disdrodb/l0/configs/{OTT_Parsivel2 → PARSIVEL2}/raw_data_format.yml +107 -107
- disdrodb/l0/configs/PWS100/bins_diameter.yml +173 -0
- disdrodb/l0/configs/PWS100/bins_velocity.yml +173 -0
- disdrodb/l0/configs/PWS100/l0a_encodings.yml +19 -0
- disdrodb/l0/configs/PWS100/l0b_cf_attrs.yml +76 -0
- disdrodb/l0/configs/PWS100/l0b_encodings.yml +176 -0
- disdrodb/l0/configs/PWS100/raw_data_format.yml +182 -0
- 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 +46 -50
- 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 +96 -174
- 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 +236 -0
- disdrodb/l0/readers/LPM/BRAZIL/CHUVA_LPM.py +185 -0
- disdrodb/l0/readers/LPM/BRAZIL/GOAMAZON_LPM.py +185 -0
- disdrodb/l0/readers/LPM/ITALY/GID_LPM.py +195 -0
- disdrodb/l0/readers/LPM/ITALY/GID_LPM_W.py +210 -0
- disdrodb/l0/readers/{BRAZIL/GOAMAZON_LPM.py → LPM/KIT/CHWALA.py} +97 -76
- disdrodb/l0/readers/LPM/SLOVENIA/ARSO.py +197 -0
- disdrodb/l0/readers/LPM/SLOVENIA/CRNI_VRH.py +197 -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/KIT/BURKINA_FASO.py +133 -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/PARSIVEL/SLOVENIA/UL_FGG.py +121 -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/ENPC_PARSIVEL2.py +189 -0
- 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/PWS100/FRANCE/ENPC_PWS100.py +150 -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/RD80/NOAA/PSL_RD80.py +274 -0
- 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 +77 -238
- disdrodb/l0/template_tools.py +105 -110
- disdrodb/l1/__init__.py +17 -0
- disdrodb/l1/beard_model.py +716 -0
- disdrodb/l1/encoding_attrs.py +635 -0
- disdrodb/l1/fall_velocity.py +260 -0
- disdrodb/l1/filters.py +192 -0
- disdrodb/l1/processing.py +202 -0
- disdrodb/l1/resampling.py +236 -0
- disdrodb/l1/routines.py +358 -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 +1833 -0
- disdrodb/l2/event.py +388 -0
- disdrodb/l2/processing.py +528 -0
- disdrodb/l2/processing_options.py +213 -0
- disdrodb/l2/routines.py +868 -0
- disdrodb/metadata/__init__.py +9 -2
- disdrodb/metadata/checks.py +180 -124
- disdrodb/metadata/download.py +81 -0
- disdrodb/metadata/geolocation.py +146 -0
- disdrodb/metadata/info.py +20 -13
- disdrodb/metadata/manipulation.py +3 -3
- disdrodb/metadata/reader.py +59 -8
- disdrodb/metadata/search.py +77 -144
- disdrodb/metadata/standards.py +83 -80
- disdrodb/metadata/writer.py +10 -16
- disdrodb/psd/__init__.py +38 -0
- disdrodb/psd/fitting.py +2146 -0
- disdrodb/psd/models.py +774 -0
- disdrodb/routines.py +1412 -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/dataframe.py +342 -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.1.dist-info/METADATA +294 -0
- disdrodb-0.1.1.dist-info/RECORD +232 -0
- {disdrodb-0.0.21.dist-info → disdrodb-0.1.1.dist-info}/WHEEL +1 -1
- disdrodb-0.1.1.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_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.1.dist-info/licenses}/LICENSE +0 -0
- {disdrodb-0.0.21.dist-info → disdrodb-0.1.1.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,456 @@
|
|
|
1
|
+
# -----------------------------------------------------------------------------.
|
|
2
|
+
# Copyright (c) 2021-2023 DISDRODB developers
|
|
3
|
+
#
|
|
4
|
+
# This program is free software: you can redistribute it and/or modify
|
|
5
|
+
# it under the terms of the GNU General Public License as published by
|
|
6
|
+
# the Free Software Foundation, either version 3 of the License, or
|
|
7
|
+
# (at your option) any later version.
|
|
8
|
+
#
|
|
9
|
+
# This program is distributed in the hope that it will be useful,
|
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
12
|
+
# GNU General Public License for more details.
|
|
13
|
+
#
|
|
14
|
+
# You should have received a copy of the GNU General Public License
|
|
15
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
16
|
+
# -----------------------------------------------------------------------------.
|
|
17
|
+
"""Implement PSD scattering routines."""
|
|
18
|
+
|
|
19
|
+
import itertools
|
|
20
|
+
|
|
21
|
+
import dask
|
|
22
|
+
import numpy as np
|
|
23
|
+
import xarray as xr
|
|
24
|
+
from pytmatrix import orientation, radar, refractive, tmatrix_aux
|
|
25
|
+
from pytmatrix.psd import BinnedPSD, PSDIntegrator
|
|
26
|
+
from pytmatrix.tmatrix import Scatterer
|
|
27
|
+
|
|
28
|
+
from disdrodb.psd.models import create_psd, get_required_parameters
|
|
29
|
+
from disdrodb.scattering.axis_ratio import check_axis_ratio, get_axis_ratio_method
|
|
30
|
+
from disdrodb.utils.warnings import suppress_warnings
|
|
31
|
+
|
|
32
|
+
# Wavelengths for which the refractive index is defined in pytmatrix (in mm)
|
|
33
|
+
wavelength_dict = {
|
|
34
|
+
"S": tmatrix_aux.wl_S,
|
|
35
|
+
"C": tmatrix_aux.wl_C,
|
|
36
|
+
"X": tmatrix_aux.wl_X,
|
|
37
|
+
"Ku": tmatrix_aux.wl_Ku,
|
|
38
|
+
"Ka": tmatrix_aux.wl_Ka,
|
|
39
|
+
"W": tmatrix_aux.wl_W,
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def available_radar_bands():
|
|
44
|
+
"""Return a list of the available radar bands."""
|
|
45
|
+
return list(wavelength_dict)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def check_radar_band(radar_band):
|
|
49
|
+
"""Check the validity of the specified radar band."""
|
|
50
|
+
available_bands = available_radar_bands()
|
|
51
|
+
if radar_band not in available_bands:
|
|
52
|
+
raise ValueError(f"{radar_band} is an invalid radar band. Valid radar bands: {available_bands}.")
|
|
53
|
+
return radar_band
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def get_radar_wavelength(radar_band):
|
|
57
|
+
"""Get the wavelength of a radar band."""
|
|
58
|
+
wavelength = wavelength_dict[radar_band]
|
|
59
|
+
return wavelength
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def initialize_scatterer(wavelength, canting_angle_std=7, D_max=8, axis_ratio="Thurai2007"):
|
|
63
|
+
"""Initialize T-matrix scatterer object for a given wavelength."""
|
|
64
|
+
# Retrieve custom axis ratio function
|
|
65
|
+
axis_ratio_func = get_axis_ratio_method(axis_ratio)
|
|
66
|
+
|
|
67
|
+
# Retrieve water complex refractive index
|
|
68
|
+
# - Here we currently assume 10 °C
|
|
69
|
+
# - m_w_0C and m_w_20C are also available
|
|
70
|
+
# TODO: should be another dimension ? Or use scatterer.psd_integrator.m_func?
|
|
71
|
+
water_refractive_index = refractive.m_w_10C[wavelength]
|
|
72
|
+
|
|
73
|
+
# ---------------------------------------------------------------.
|
|
74
|
+
# Initialize Scatterer class
|
|
75
|
+
scatterer = Scatterer(wavelength=wavelength, m=water_refractive_index)
|
|
76
|
+
# - Define particle orientation PDF for orientational averaging
|
|
77
|
+
# --> The standard deviation of the angle with respect to vertical orientation (the canting angle).
|
|
78
|
+
scatterer.or_pdf = orientation.gaussian_pdf(std=canting_angle_std)
|
|
79
|
+
# - Define orientation methods
|
|
80
|
+
# --> Alternatives: orient_averaged_fixed, orient_single
|
|
81
|
+
scatterer.orient = orientation.orient_averaged_fixed
|
|
82
|
+
|
|
83
|
+
# ---------------------------------------------------------------.
|
|
84
|
+
# Initialize PSDIntegrator
|
|
85
|
+
scatterer.psd_integrator = PSDIntegrator()
|
|
86
|
+
# - Define axis_ratio_func
|
|
87
|
+
# --> The Scatterer class expects horizontal to vertical
|
|
88
|
+
scatterer.psd_integrator.axis_ratio_func = lambda D: 1.0 / axis_ratio_func(D)
|
|
89
|
+
# - Define function to compute refrative index (as function of D)
|
|
90
|
+
# scatterer.psd_integrator.m_func = None # Use constant value of scatterer.m
|
|
91
|
+
# - Define number of points over which to integrate
|
|
92
|
+
scatterer.psd_integrator.num_points = 1024
|
|
93
|
+
# - Define maximum drop diameter
|
|
94
|
+
scatterer.psd_integrator.D_max = D_max
|
|
95
|
+
# - Define geometries
|
|
96
|
+
scatterer.psd_integrator.geometries = (tmatrix_aux.geom_horiz_back, tmatrix_aux.geom_horiz_forw)
|
|
97
|
+
# ---------------------------------------------------------------.
|
|
98
|
+
# Initialize scattering table
|
|
99
|
+
scatterer.psd_integrator.init_scatter_table(scatterer)
|
|
100
|
+
return scatterer
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def compute_radar_variables(scatterer):
|
|
104
|
+
"""Compute radar variables for a given scatter object with a specified PSD.
|
|
105
|
+
|
|
106
|
+
To speed up computations, this function should input a scatterer object with
|
|
107
|
+
a preinitialized scattering table.
|
|
108
|
+
"""
|
|
109
|
+
# Compute radar parameters
|
|
110
|
+
radar_vars = {}
|
|
111
|
+
scatterer.set_geometry(tmatrix_aux.geom_horiz_back)
|
|
112
|
+
radar_vars["Zh"] = 10 * np.log10(radar.refl(scatterer, h_pol=True)) # dBZ
|
|
113
|
+
radar_vars["Zdr"] = 10 * np.log10(radar.Zdr(scatterer)) # dB
|
|
114
|
+
radar_vars["rho_hv"] = radar.rho_hv(scatterer)
|
|
115
|
+
radar_vars["ldr"] = radar.ldr(scatterer)
|
|
116
|
+
scatterer.set_geometry(tmatrix_aux.geom_horiz_forw)
|
|
117
|
+
radar_vars["Kdp"] = radar.Kdp(scatterer)
|
|
118
|
+
radar_vars["Ai"] = radar.Ai(scatterer)
|
|
119
|
+
return radar_vars
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def _estimate_empirical_radar_parameters(
|
|
123
|
+
drop_number_concentration,
|
|
124
|
+
bin_edges,
|
|
125
|
+
scatterer,
|
|
126
|
+
output_dictionary,
|
|
127
|
+
):
|
|
128
|
+
# Initialize bad results
|
|
129
|
+
if output_dictionary:
|
|
130
|
+
null_output = {"Zh": np.nan, "Zdr": np.nan, "rho_hv": np.nan, "ldr": np.nan, "Kdp": np.nan, "Ai": np.nan}
|
|
131
|
+
else:
|
|
132
|
+
null_output = np.array([np.nan, np.nan, np.nan, np.nan, np.nan, np.nan])
|
|
133
|
+
|
|
134
|
+
# Assign PSD model to the scatterer object
|
|
135
|
+
scatterer.psd = BinnedPSD(bin_edges, drop_number_concentration)
|
|
136
|
+
|
|
137
|
+
# Get radar variables
|
|
138
|
+
with suppress_warnings():
|
|
139
|
+
try:
|
|
140
|
+
radar_vars = compute_radar_variables(scatterer)
|
|
141
|
+
output = radar_vars if output_dictionary else np.array(list(radar_vars.values()))
|
|
142
|
+
except Exception:
|
|
143
|
+
output = null_output
|
|
144
|
+
return output
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
def _estimate_model_radar_parameters(
|
|
148
|
+
parameters,
|
|
149
|
+
psd_model,
|
|
150
|
+
psd_parameters_names,
|
|
151
|
+
scatterer,
|
|
152
|
+
output_dictionary,
|
|
153
|
+
):
|
|
154
|
+
# Initialize bad results
|
|
155
|
+
if output_dictionary:
|
|
156
|
+
null_output = {"Zh": np.nan, "Zdr": np.nan, "rho_hv": np.nan, "ldr": np.nan, "Kdp": np.nan, "Ai": np.nan}
|
|
157
|
+
else:
|
|
158
|
+
null_output = np.array([np.nan, np.nan, np.nan, np.nan, np.nan, np.nan])
|
|
159
|
+
|
|
160
|
+
# Assign PSD model to the scatterer object
|
|
161
|
+
parameters = dict(zip(psd_parameters_names, parameters))
|
|
162
|
+
scatterer.psd = create_psd(psd_model, parameters)
|
|
163
|
+
|
|
164
|
+
# Get radar variables
|
|
165
|
+
with suppress_warnings():
|
|
166
|
+
radar_vars = compute_radar_variables(scatterer)
|
|
167
|
+
try:
|
|
168
|
+
radar_vars = compute_radar_variables(scatterer)
|
|
169
|
+
output = radar_vars if output_dictionary else np.array(list(radar_vars.values()))
|
|
170
|
+
except Exception:
|
|
171
|
+
output = null_output
|
|
172
|
+
return output
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
def get_psd_parameters(ds):
|
|
176
|
+
"""Return a xr.Dataset with only the PSD parameters as variable."""
|
|
177
|
+
psd_model = ds.attrs["disdrodb_psd_model"]
|
|
178
|
+
required_parameters = get_required_parameters(psd_model)
|
|
179
|
+
missing_parameters = [param for param in required_parameters if param not in ds]
|
|
180
|
+
if len(missing_parameters) > 0:
|
|
181
|
+
raise ValueError(f"The {psd_model} parameters {missing_parameters} are not present in the dataset.")
|
|
182
|
+
return ds[required_parameters]
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
def get_model_radar_parameters(
|
|
186
|
+
ds,
|
|
187
|
+
radar_band,
|
|
188
|
+
canting_angle_std=7,
|
|
189
|
+
diameter_max=10,
|
|
190
|
+
axis_ratio="Thurai2007",
|
|
191
|
+
):
|
|
192
|
+
"""Compute radar parameters from a PSD model.
|
|
193
|
+
|
|
194
|
+
Parameters
|
|
195
|
+
----------
|
|
196
|
+
ds : xarray.Dataset
|
|
197
|
+
Dataset containing the parameters of the PSD model.
|
|
198
|
+
The dataset attribute disdrodb_psd_model specifies the PSD model to use.
|
|
199
|
+
radar_band : str
|
|
200
|
+
Radar band to be used.
|
|
201
|
+
canting_angle_std : float, optional
|
|
202
|
+
Standard deviation of the canting angle. The default value is 7.
|
|
203
|
+
diameter_max : float, optional
|
|
204
|
+
Maximum diameter. The default value is 8 mm.
|
|
205
|
+
axis_ratio : str, optional
|
|
206
|
+
Method to compute the axis ratio. The default method is ``Thurai2007``.
|
|
207
|
+
|
|
208
|
+
Returns
|
|
209
|
+
-------
|
|
210
|
+
xarray.Dataset
|
|
211
|
+
Dataset containing the computed radar parameters.
|
|
212
|
+
"""
|
|
213
|
+
# Retrieve psd model and parameters.
|
|
214
|
+
psd_model = ds.attrs["disdrodb_psd_model"]
|
|
215
|
+
required_parameters = get_required_parameters(psd_model)
|
|
216
|
+
ds_parameters = get_psd_parameters(ds)
|
|
217
|
+
|
|
218
|
+
# Check argument validity
|
|
219
|
+
axis_ratio = check_axis_ratio(axis_ratio)
|
|
220
|
+
radar_band = check_radar_band(radar_band)
|
|
221
|
+
|
|
222
|
+
# Retrieve wavelengths in mm
|
|
223
|
+
wavelength = get_radar_wavelength(radar_band)
|
|
224
|
+
|
|
225
|
+
# Create DataArray with PSD parameters
|
|
226
|
+
da_parameters = ds_parameters.to_array(dim="psd_parameters").compute()
|
|
227
|
+
|
|
228
|
+
# Initialize scattering table
|
|
229
|
+
scatterer = initialize_scatterer(
|
|
230
|
+
wavelength=wavelength,
|
|
231
|
+
canting_angle_std=canting_angle_std,
|
|
232
|
+
D_max=diameter_max,
|
|
233
|
+
axis_ratio=axis_ratio,
|
|
234
|
+
)
|
|
235
|
+
|
|
236
|
+
# Define kwargs
|
|
237
|
+
kwargs = {
|
|
238
|
+
"output_dictionary": False,
|
|
239
|
+
"psd_model": psd_model,
|
|
240
|
+
"psd_parameters_names": required_parameters,
|
|
241
|
+
"scatterer": scatterer,
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
# Loop over each PSD (not in parallel --> dask="forbidden")
|
|
245
|
+
# - It costs much more to initiate the scatterer rather than looping over timesteps !
|
|
246
|
+
da_radar = xr.apply_ufunc(
|
|
247
|
+
_estimate_model_radar_parameters,
|
|
248
|
+
da_parameters,
|
|
249
|
+
kwargs=kwargs,
|
|
250
|
+
input_core_dims=[["psd_parameters"]],
|
|
251
|
+
output_core_dims=[["radar_variables"]],
|
|
252
|
+
vectorize=True,
|
|
253
|
+
dask="forbidden",
|
|
254
|
+
dask_gufunc_kwargs={"output_sizes": {"radar_variables": 5}}, # lengths of the new output_core_dims dimensions.
|
|
255
|
+
output_dtypes=["float64"],
|
|
256
|
+
)
|
|
257
|
+
|
|
258
|
+
# Add parameters coordinates
|
|
259
|
+
da_radar = da_radar.assign_coords({"radar_variables": ["Zh", "Zdr", "rho_hv", "ldr", "Kdp", "Ai"]})
|
|
260
|
+
|
|
261
|
+
# Create parameters dataset
|
|
262
|
+
ds_radar = da_radar.to_dataset(dim="radar_variables")
|
|
263
|
+
|
|
264
|
+
# Expand dimensions for later merging
|
|
265
|
+
dims_dict = {
|
|
266
|
+
"radar_band": [radar_band],
|
|
267
|
+
"axis_ratio": [axis_ratio],
|
|
268
|
+
"canting_angle_std": [canting_angle_std],
|
|
269
|
+
"diameter_max": [diameter_max],
|
|
270
|
+
}
|
|
271
|
+
ds_radar = ds_radar.expand_dims(dim=dims_dict)
|
|
272
|
+
return ds_radar
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
def get_empirical_radar_parameters(
|
|
276
|
+
ds,
|
|
277
|
+
radar_band=None,
|
|
278
|
+
canting_angle_std=7,
|
|
279
|
+
diameter_max=8,
|
|
280
|
+
axis_ratio="Thurai2007",
|
|
281
|
+
):
|
|
282
|
+
"""Compute radar parameters from empirical drop number concentration.
|
|
283
|
+
|
|
284
|
+
Parameters
|
|
285
|
+
----------
|
|
286
|
+
ds : xarray.Dataset
|
|
287
|
+
Dataset containing the drop number concentration variable.
|
|
288
|
+
radar_band : str
|
|
289
|
+
Radar band to be used.
|
|
290
|
+
canting_angle_std : float, optional
|
|
291
|
+
Standard deviation of the canting angle. The default value is 7.
|
|
292
|
+
diameter_max : float, optional
|
|
293
|
+
Maximum diameter. The default value is 8 mm.
|
|
294
|
+
axis_ratio : str, optional
|
|
295
|
+
Method to compute the axis ratio. The default method is ``Thurai2007``.
|
|
296
|
+
|
|
297
|
+
Returns
|
|
298
|
+
-------
|
|
299
|
+
xarray.Dataset
|
|
300
|
+
Dataset containing the computed radar parameters.
|
|
301
|
+
"""
|
|
302
|
+
# Define inputs
|
|
303
|
+
da_drop_number_concentration = ds["drop_number_concentration"].compute()
|
|
304
|
+
|
|
305
|
+
# Define bin edges
|
|
306
|
+
bin_edges = np.append(ds["diameter_bin_lower"].compute().data, ds["diameter_bin_upper"].compute().data[-1])
|
|
307
|
+
|
|
308
|
+
# Check argument validity
|
|
309
|
+
axis_ratio = check_axis_ratio(axis_ratio)
|
|
310
|
+
radar_band = check_radar_band(radar_band)
|
|
311
|
+
|
|
312
|
+
# Retrieve wavelengths in mm
|
|
313
|
+
wavelength = get_radar_wavelength(radar_band)
|
|
314
|
+
|
|
315
|
+
# Initialize scattering table
|
|
316
|
+
scatterer = initialize_scatterer(
|
|
317
|
+
wavelength=wavelength,
|
|
318
|
+
canting_angle_std=canting_angle_std,
|
|
319
|
+
D_max=diameter_max,
|
|
320
|
+
axis_ratio=axis_ratio,
|
|
321
|
+
)
|
|
322
|
+
|
|
323
|
+
# Define kwargs
|
|
324
|
+
kwargs = {
|
|
325
|
+
"output_dictionary": False,
|
|
326
|
+
"bin_edges": bin_edges,
|
|
327
|
+
"scatterer": scatterer,
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
# Loop over each PSD (not in parallel --> dask="forbidden")
|
|
331
|
+
# - It costs much more to initiate the scatterer rather than looping over timesteps !
|
|
332
|
+
da_radar = xr.apply_ufunc(
|
|
333
|
+
_estimate_empirical_radar_parameters,
|
|
334
|
+
da_drop_number_concentration,
|
|
335
|
+
kwargs=kwargs,
|
|
336
|
+
input_core_dims=[["diameter_bin_center"]],
|
|
337
|
+
output_core_dims=[["radar_variables"]],
|
|
338
|
+
vectorize=True,
|
|
339
|
+
dask="forbidden",
|
|
340
|
+
dask_gufunc_kwargs={"output_sizes": {"radar_variables": 5}}, # lengths of the new output_core_dims dimensions.
|
|
341
|
+
output_dtypes=["float64"],
|
|
342
|
+
)
|
|
343
|
+
|
|
344
|
+
# Add parameters coordinates
|
|
345
|
+
da_radar = da_radar.assign_coords({"radar_variables": ["Zh", "Zdr", "rho_hv", "ldr", "Kdp", "Ai"]})
|
|
346
|
+
|
|
347
|
+
# Create parameters dataset
|
|
348
|
+
ds_radar = da_radar.to_dataset(dim="radar_variables")
|
|
349
|
+
|
|
350
|
+
# Expand dimensions for later merging
|
|
351
|
+
dims_dict = {
|
|
352
|
+
"radar_band": [radar_band],
|
|
353
|
+
"axis_ratio": [axis_ratio],
|
|
354
|
+
"canting_angle_std": [canting_angle_std],
|
|
355
|
+
"diameter_max": [diameter_max],
|
|
356
|
+
}
|
|
357
|
+
ds_radar = ds_radar.expand_dims(dim=dims_dict)
|
|
358
|
+
return ds_radar
|
|
359
|
+
|
|
360
|
+
|
|
361
|
+
def get_radar_parameters(
|
|
362
|
+
ds,
|
|
363
|
+
radar_band=None,
|
|
364
|
+
canting_angle_std=7,
|
|
365
|
+
diameter_max=8,
|
|
366
|
+
axis_ratio="Thurai2007",
|
|
367
|
+
parallel=True,
|
|
368
|
+
):
|
|
369
|
+
"""Compute radar parameters from empirical drop number concentration or PSD model.
|
|
370
|
+
|
|
371
|
+
Parameters
|
|
372
|
+
----------
|
|
373
|
+
ds : xarray.Dataset
|
|
374
|
+
Dataset containing the drop number concentration variable.
|
|
375
|
+
radar_band : str or list of str, optional
|
|
376
|
+
Radar band(s) to be used.
|
|
377
|
+
If ``None`` (the default), all available radar bands are used.
|
|
378
|
+
canting_angle_std : float or list of float, optional
|
|
379
|
+
Standard deviation of the canting angle. The default value is 7.
|
|
380
|
+
diameter_max : float or list of float, optional
|
|
381
|
+
Maximum diameter. The default value is 8 mm.
|
|
382
|
+
axis_ratio : str or list of str, optional
|
|
383
|
+
Method to compute the axis ratio. The default method is ``Thurai2007``.
|
|
384
|
+
parallel : bool, optional
|
|
385
|
+
Whether to compute radar variables in parallel.
|
|
386
|
+
The default value is ``True``.
|
|
387
|
+
|
|
388
|
+
Returns
|
|
389
|
+
-------
|
|
390
|
+
xarray.Dataset
|
|
391
|
+
Dataset containing the computed radar parameters.
|
|
392
|
+
"""
|
|
393
|
+
# Decide whether to simulate radar parameters based on empirical PSD or model PSD
|
|
394
|
+
if "disdrodb_psd_model" not in ds.attrs and "drop_number_concentration" not in ds:
|
|
395
|
+
raise ValueError("The input dataset is not a DISDRODB L2E or L2M product.")
|
|
396
|
+
# Model-based simulation
|
|
397
|
+
if "disdrodb_psd_model" in ds.attrs:
|
|
398
|
+
func = get_model_radar_parameters
|
|
399
|
+
ds_subset = get_psd_parameters(ds).compute()
|
|
400
|
+
# Empirical PSD simulation
|
|
401
|
+
else:
|
|
402
|
+
func = get_empirical_radar_parameters
|
|
403
|
+
ds_subset = ds[["drop_number_concentration"]].compute()
|
|
404
|
+
|
|
405
|
+
# Initialize radar band if not provided
|
|
406
|
+
if radar_band is None:
|
|
407
|
+
radar_band = available_radar_bands()
|
|
408
|
+
|
|
409
|
+
# Ensure parameters are list
|
|
410
|
+
diameter_max = np.atleast_1d(diameter_max)
|
|
411
|
+
canting_angle_std = np.atleast_1d(canting_angle_std)
|
|
412
|
+
axis_ratio = np.atleast_1d(axis_ratio)
|
|
413
|
+
radar_band = np.atleast_1d(radar_band)
|
|
414
|
+
|
|
415
|
+
# Check parameters validity
|
|
416
|
+
axis_ratio = [check_axis_ratio(method) for method in axis_ratio]
|
|
417
|
+
radar_band = [check_radar_band(band) for band in radar_band]
|
|
418
|
+
|
|
419
|
+
# Order radar band from longest to shortest wavelength
|
|
420
|
+
# - ["S", "C", "X", "Ku", "Ka", "W"]
|
|
421
|
+
radar_band = sorted(radar_band, key=lambda x: wavelength_dict[x])[::-1]
|
|
422
|
+
|
|
423
|
+
# Retrieve combination of parameters
|
|
424
|
+
list_params = [
|
|
425
|
+
{
|
|
426
|
+
"radar_band": rb.item(),
|
|
427
|
+
"canting_angle_std": cas.item(),
|
|
428
|
+
"axis_ratio": ar.item(),
|
|
429
|
+
"diameter_max": d_max.item(),
|
|
430
|
+
}
|
|
431
|
+
for rb, cas, ar, d_max in itertools.product(radar_band, canting_angle_std, axis_ratio, diameter_max)
|
|
432
|
+
]
|
|
433
|
+
|
|
434
|
+
# Compute radar variables for each configuration in parallel
|
|
435
|
+
# - The function expects the data into memory (no dask arrays !)
|
|
436
|
+
if parallel:
|
|
437
|
+
list_ds = [dask.delayed(func)(ds_subset, **params) for params in list_params]
|
|
438
|
+
list_ds = dask.compute(*list_ds)
|
|
439
|
+
else:
|
|
440
|
+
list_ds = [func(ds_subset, **params) for params in list_params]
|
|
441
|
+
|
|
442
|
+
# Merge into a single dataset
|
|
443
|
+
# - Order radar bands from longest to shortest wavelength
|
|
444
|
+
ds_radar = xr.merge(list_ds)
|
|
445
|
+
ds_radar = ds_radar.sel(radar_band=radar_band)
|
|
446
|
+
|
|
447
|
+
# Copy global attributes from input dataset
|
|
448
|
+
ds_radar.attrs = ds.attrs.copy()
|
|
449
|
+
|
|
450
|
+
# Remove single dimensions (add info to attributes)
|
|
451
|
+
parameters = ["radar_band", "canting_angle_std", "axis_ratio", "diameter_max"]
|
|
452
|
+
for param in parameters:
|
|
453
|
+
if ds_radar.sizes[param] == 1:
|
|
454
|
+
ds_radar.attrs[f"disdrodb_scattering_{param}"] = ds_radar[param].item()
|
|
455
|
+
ds_radar = ds_radar.squeeze()
|
|
456
|
+
return ds_radar
|
disdrodb/utils/__init__.py
CHANGED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# -----------------------------------------------------------------------------.
|
|
2
|
+
# Copyright (c) 2021-2023 DISDRODB developers
|
|
3
|
+
#
|
|
4
|
+
# This program is free software: you can redistribute it and/or modify
|
|
5
|
+
# it under the terms of the GNU General Public License as published by
|
|
6
|
+
# the Free Software Foundation, either version 3 of the License, or
|
|
7
|
+
# (at your option) any later version.
|
|
8
|
+
#
|
|
9
|
+
# This program is distributed in the hope that it will be useful,
|
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
12
|
+
# GNU General Public License for more details.
|
|
13
|
+
#
|
|
14
|
+
# You should have received a copy of the GNU General Public License
|
|
15
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
16
|
+
# -----------------------------------------------------------------------------.
|
|
17
|
+
"""DISDRODB Utils Module."""
|
disdrodb/utils/attrs.py
ADDED
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
|
|
3
|
+
# -----------------------------------------------------------------------------.
|
|
4
|
+
# Copyright (c) 2021-2023 DISDRODB developers
|
|
5
|
+
#
|
|
6
|
+
# This program is free software: you can redistribute it and/or modify
|
|
7
|
+
# it under the terms of the GNU General Public License as published by
|
|
8
|
+
# the Free Software Foundation, either version 3 of the License, or
|
|
9
|
+
# (at your option) any later version.
|
|
10
|
+
#
|
|
11
|
+
# This program is distributed in the hope that it will be useful,
|
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
14
|
+
# GNU General Public License for more details.
|
|
15
|
+
#
|
|
16
|
+
# You should have received a copy of the GNU General Public License
|
|
17
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
18
|
+
# -----------------------------------------------------------------------------.
|
|
19
|
+
"""DISDRODB netCDF4 attributes utilities."""
|
|
20
|
+
import datetime
|
|
21
|
+
|
|
22
|
+
from disdrodb import ARCHIVE_VERSION, CONVENTIONS, SOFTWARE_VERSION
|
|
23
|
+
|
|
24
|
+
####---------------------------------------------------------------------.
|
|
25
|
+
#### Variable attributes
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def set_attrs(ds, attrs_dict):
|
|
29
|
+
"""Set attributes to the variables of the xr.Dataset."""
|
|
30
|
+
for var in attrs_dict:
|
|
31
|
+
if var in ds:
|
|
32
|
+
ds[var].attrs.update(attrs_dict[var])
|
|
33
|
+
return ds
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
####---------------------------------------------------------------------.
|
|
37
|
+
#### Coordinates attributes
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def get_coords_attrs_dict():
|
|
41
|
+
"""Return dictionary with DISDRODB coordinates attributes."""
|
|
42
|
+
attrs_dict = {}
|
|
43
|
+
# Define diameter attributes
|
|
44
|
+
attrs_dict["diameter_bin_center"] = {
|
|
45
|
+
"name": "diameter_bin_center",
|
|
46
|
+
"standard_name": "diameter_bin_center",
|
|
47
|
+
"long_name": "diameter_bin_center",
|
|
48
|
+
"units": "mm",
|
|
49
|
+
"description": "Bin center drop diameter value",
|
|
50
|
+
}
|
|
51
|
+
attrs_dict["diameter_bin_width"] = {
|
|
52
|
+
"name": "diameter_bin_width",
|
|
53
|
+
"standard_name": "diameter_bin_width",
|
|
54
|
+
"long_name": "diameter_bin_width",
|
|
55
|
+
"units": "mm",
|
|
56
|
+
"description": "Drop diameter bin width",
|
|
57
|
+
}
|
|
58
|
+
attrs_dict["diameter_bin_upper"] = {
|
|
59
|
+
"name": "diameter_bin_upper",
|
|
60
|
+
"standard_name": "diameter_bin_upper",
|
|
61
|
+
"long_name": "diameter_bin_upper",
|
|
62
|
+
"units": "mm",
|
|
63
|
+
"description": "Bin upper bound drop diameter value",
|
|
64
|
+
}
|
|
65
|
+
attrs_dict["velocity_bin_lower"] = {
|
|
66
|
+
"name": "velocity_bin_lower",
|
|
67
|
+
"standard_name": "velocity_bin_lower",
|
|
68
|
+
"long_name": "velocity_bin_lower",
|
|
69
|
+
"units": "mm",
|
|
70
|
+
"description": "Bin lower bound drop diameter value",
|
|
71
|
+
}
|
|
72
|
+
# Define velocity attributes
|
|
73
|
+
attrs_dict["velocity_bin_center"] = {
|
|
74
|
+
"name": "velocity_bin_center",
|
|
75
|
+
"standard_name": "velocity_bin_center",
|
|
76
|
+
"long_name": "velocity_bin_center",
|
|
77
|
+
"units": "m/s",
|
|
78
|
+
"description": "Bin center drop fall velocity value",
|
|
79
|
+
}
|
|
80
|
+
attrs_dict["velocity_bin_width"] = {
|
|
81
|
+
"name": "velocity_bin_width",
|
|
82
|
+
"standard_name": "velocity_bin_width",
|
|
83
|
+
"long_name": "velocity_bin_width",
|
|
84
|
+
"units": "m/s",
|
|
85
|
+
"description": "Drop fall velocity bin width",
|
|
86
|
+
}
|
|
87
|
+
attrs_dict["velocity_bin_upper"] = {
|
|
88
|
+
"name": "velocity_bin_upper",
|
|
89
|
+
"standard_name": "velocity_bin_upper",
|
|
90
|
+
"long_name": "velocity_bin_upper",
|
|
91
|
+
"units": "m/s",
|
|
92
|
+
"description": "Bin upper bound drop fall velocity value",
|
|
93
|
+
}
|
|
94
|
+
attrs_dict["velocity_bin_lower"] = {
|
|
95
|
+
"name": "velocity_bin_lower",
|
|
96
|
+
"standard_name": "velocity_bin_lower",
|
|
97
|
+
"long_name": "velocity_bin_lower",
|
|
98
|
+
"units": "m/s",
|
|
99
|
+
"description": "Bin lower bound drop fall velocity value",
|
|
100
|
+
}
|
|
101
|
+
# Define geolocation attributes
|
|
102
|
+
attrs_dict["latitude"] = {
|
|
103
|
+
"name": "latitude",
|
|
104
|
+
"standard_name": "latitude",
|
|
105
|
+
"long_name": "Latitude",
|
|
106
|
+
"units": "degrees_north",
|
|
107
|
+
}
|
|
108
|
+
attrs_dict["longitude"] = {
|
|
109
|
+
"name": "longitude",
|
|
110
|
+
"standard_name": "longitude",
|
|
111
|
+
"long_name": "Longitude",
|
|
112
|
+
"units": "degrees_east",
|
|
113
|
+
}
|
|
114
|
+
attrs_dict["altitude"] = {
|
|
115
|
+
"name": "altitude",
|
|
116
|
+
"standard_name": "altitude",
|
|
117
|
+
"long_name": "Altitude",
|
|
118
|
+
"units": "m",
|
|
119
|
+
"description": "Elevation above sea level",
|
|
120
|
+
}
|
|
121
|
+
# Define time attributes
|
|
122
|
+
attrs_dict["time"] = {
|
|
123
|
+
"name": "time",
|
|
124
|
+
"standard_name": "time",
|
|
125
|
+
"long_name": "time",
|
|
126
|
+
"description": "UTC Time",
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return attrs_dict
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def set_coordinate_attributes(ds):
|
|
133
|
+
"""Set coordinates attributes."""
|
|
134
|
+
# Get attributes dictionary
|
|
135
|
+
attrs_dict = get_coords_attrs_dict()
|
|
136
|
+
# Set attributes
|
|
137
|
+
ds = set_attrs(ds, attrs_dict)
|
|
138
|
+
return ds
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
####-------------------------------------------------------------------------.
|
|
142
|
+
#### DISDRODB Global Attributes
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
def set_disdrodb_attrs(ds, product: str):
|
|
146
|
+
"""Add DISDRODB processing information to the netCDF global attributes.
|
|
147
|
+
|
|
148
|
+
It assumes stations metadata are already added the dataset.
|
|
149
|
+
|
|
150
|
+
Parameters
|
|
151
|
+
----------
|
|
152
|
+
ds : xarray.Dataset
|
|
153
|
+
Dataset
|
|
154
|
+
product: str
|
|
155
|
+
DISDRODB product.
|
|
156
|
+
|
|
157
|
+
Returns
|
|
158
|
+
-------
|
|
159
|
+
xarray dataset
|
|
160
|
+
Dataset.
|
|
161
|
+
"""
|
|
162
|
+
# Add dataset conventions
|
|
163
|
+
ds.attrs["Conventions"] = CONVENTIONS
|
|
164
|
+
|
|
165
|
+
# Add featureType
|
|
166
|
+
if "platform_type" in ds.attrs:
|
|
167
|
+
platform_type = ds.attrs["platform_type"]
|
|
168
|
+
if platform_type == "fixed":
|
|
169
|
+
ds.attrs["featureType"] = "timeSeries"
|
|
170
|
+
else:
|
|
171
|
+
ds.attrs["featureType"] = "trajectory"
|
|
172
|
+
|
|
173
|
+
# Update DISDRODDB attributes
|
|
174
|
+
ds = update_disdrodb_attrs(ds=ds, product=product)
|
|
175
|
+
return ds
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
def update_disdrodb_attrs(ds, product: str):
|
|
179
|
+
"""Add DISDRODB processing information to the netCDF global attributes.
|
|
180
|
+
|
|
181
|
+
It assumes stations metadata are already added the dataset.
|
|
182
|
+
|
|
183
|
+
Parameters
|
|
184
|
+
----------
|
|
185
|
+
ds : xarray dataset.
|
|
186
|
+
Dataset
|
|
187
|
+
product: str
|
|
188
|
+
DISDRODB product.
|
|
189
|
+
|
|
190
|
+
Returns
|
|
191
|
+
-------
|
|
192
|
+
xarray dataset
|
|
193
|
+
Dataset.
|
|
194
|
+
"""
|
|
195
|
+
# Add time_coverage_start and time_coverage_end
|
|
196
|
+
ds.attrs["time_coverage_start"] = str(ds["time"].data[0])
|
|
197
|
+
ds.attrs["time_coverage_end"] = str(ds["time"].data[-1])
|
|
198
|
+
|
|
199
|
+
# DISDRODDB attributes
|
|
200
|
+
# - Add DISDRODB processing info
|
|
201
|
+
now = datetime.datetime.utcnow()
|
|
202
|
+
current_time = now.strftime("%Y-%m-%d %H:%M:%S")
|
|
203
|
+
ds.attrs["disdrodb_processing_date"] = current_time
|
|
204
|
+
# - Add DISDRODB product and version
|
|
205
|
+
ds.attrs["disdrodb_product_version"] = ARCHIVE_VERSION
|
|
206
|
+
ds.attrs["disdrodb_software_version"] = SOFTWARE_VERSION
|
|
207
|
+
ds.attrs["disdrodb_product"] = product
|
|
208
|
+
return ds
|