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.
Files changed (313) hide show
  1. disdrodb/__init__.py +3 -1
  2. disdrodb/_config.py +2 -3
  3. disdrodb/_version.py +2 -2
  4. disdrodb/accessor/__init__.py +2 -1
  5. disdrodb/accessor/methods.py +10 -9
  6. disdrodb/api/checks.py +3 -7
  7. disdrodb/api/configs.py +1 -3
  8. disdrodb/api/create_directories.py +4 -6
  9. disdrodb/api/info.py +1 -3
  10. disdrodb/api/io.py +233 -32
  11. disdrodb/api/path.py +3 -7
  12. disdrodb/cli/disdrodb_check_metadata_archive.py +3 -2
  13. disdrodb/cli/disdrodb_check_products_options.py +45 -0
  14. disdrodb/cli/disdrodb_create_summary.py +54 -28
  15. disdrodb/cli/disdrodb_create_summary_station.py +41 -20
  16. disdrodb/cli/disdrodb_data_archive_directory.py +2 -3
  17. disdrodb/cli/disdrodb_download_archive.py +50 -30
  18. disdrodb/cli/disdrodb_download_metadata_archive.py +28 -16
  19. disdrodb/cli/disdrodb_download_station.py +58 -29
  20. disdrodb/cli/disdrodb_initialize_station.py +43 -23
  21. disdrodb/cli/disdrodb_metadata_archive_directory.py +2 -3
  22. disdrodb/cli/disdrodb_open_data_archive.py +17 -13
  23. disdrodb/cli/disdrodb_open_logs_directory.py +31 -21
  24. disdrodb/cli/disdrodb_open_metadata_archive.py +26 -13
  25. disdrodb/cli/disdrodb_open_metadata_directory.py +34 -23
  26. disdrodb/cli/disdrodb_open_product_directory.py +39 -23
  27. disdrodb/cli/disdrodb_open_readers_directory.py +2 -3
  28. disdrodb/cli/disdrodb_run.py +189 -0
  29. disdrodb/cli/disdrodb_run_l0.py +61 -70
  30. disdrodb/cli/disdrodb_run_l0_station.py +50 -55
  31. disdrodb/cli/disdrodb_run_l0a.py +53 -51
  32. disdrodb/cli/disdrodb_run_l0a_station.py +41 -40
  33. disdrodb/cli/disdrodb_run_l0b.py +51 -51
  34. disdrodb/cli/disdrodb_run_l0b_station.py +40 -39
  35. disdrodb/cli/disdrodb_run_l0c.py +56 -53
  36. disdrodb/cli/disdrodb_run_l0c_station.py +44 -41
  37. disdrodb/cli/disdrodb_run_l1.py +55 -51
  38. disdrodb/cli/disdrodb_run_l1_station.py +43 -40
  39. disdrodb/cli/disdrodb_run_l2e.py +56 -51
  40. disdrodb/cli/disdrodb_run_l2e_station.py +44 -40
  41. disdrodb/cli/disdrodb_run_l2m.py +55 -51
  42. disdrodb/cli/disdrodb_run_l2m_station.py +43 -40
  43. disdrodb/cli/disdrodb_run_station.py +184 -0
  44. disdrodb/cli/disdrodb_upload_archive.py +51 -42
  45. disdrodb/cli/disdrodb_upload_station.py +42 -36
  46. disdrodb/configs.py +20 -16
  47. disdrodb/constants.py +5 -2
  48. disdrodb/data_transfer/__init__.py +1 -3
  49. disdrodb/data_transfer/download_data.py +45 -61
  50. disdrodb/data_transfer/upload_data.py +7 -11
  51. disdrodb/data_transfer/zenodo.py +2 -4
  52. disdrodb/docs.py +1 -3
  53. disdrodb/etc/configs/attributes.yaml +52 -2
  54. disdrodb/etc/configs/encodings.yaml +45 -1
  55. disdrodb/etc/products/L0C/ODM470/global.yaml +5 -0
  56. disdrodb/etc/products/L0C/global.yaml +5 -0
  57. disdrodb/etc/products/L1/ODM470/global.yaml +6 -0
  58. disdrodb/etc/products/L1/global.yaml +0 -13
  59. disdrodb/etc/products/L2E/LPM/1MIN.yaml +1 -0
  60. disdrodb/etc/products/L2E/LPM/global.yaml +36 -0
  61. disdrodb/etc/products/L2E/LPM_V0/1MIN.yaml +1 -0
  62. disdrodb/etc/products/L2E/LPM_V0/global.yaml +36 -0
  63. disdrodb/etc/products/L2E/ODM470/1MIN.yaml +1 -0
  64. disdrodb/etc/products/L2E/ODM470/global.yaml +36 -0
  65. disdrodb/etc/products/L2E/PARSIVEL/1MIN.yaml +1 -0
  66. disdrodb/etc/products/L2E/PARSIVEL/global.yaml +36 -0
  67. disdrodb/etc/products/L2E/PARSIVEL2/1MIN.yaml +1 -0
  68. disdrodb/etc/products/L2E/PARSIVEL2/global.yaml +36 -0
  69. disdrodb/etc/products/L2E/PWS100/1MIN.yaml +1 -0
  70. disdrodb/etc/products/L2E/PWS100/global.yaml +36 -0
  71. disdrodb/etc/products/L2E/RD80/1MIN.yaml +19 -0
  72. disdrodb/etc/products/L2E/SWS250/1MIN.yaml +19 -0
  73. disdrodb/etc/products/L2E/global.yaml +16 -2
  74. disdrodb/fall_velocity/__init__.py +47 -0
  75. disdrodb/fall_velocity/graupel.py +484 -0
  76. disdrodb/fall_velocity/hail.py +288 -0
  77. disdrodb/{l1/fall_velocity.py → fall_velocity/rain.py} +265 -44
  78. disdrodb/issue/__init__.py +1 -3
  79. disdrodb/issue/checks.py +2 -3
  80. disdrodb/issue/reader.py +2 -3
  81. disdrodb/issue/writer.py +2 -5
  82. disdrodb/l0/__init__.py +2 -1
  83. disdrodb/l0/check_configs.py +36 -29
  84. disdrodb/l0/check_standards.py +1 -4
  85. disdrodb/l0/configs/LPM/l0a_encodings.yml +17 -17
  86. disdrodb/l0/configs/LPM/l0b_cf_attrs.yml +55 -55
  87. disdrodb/l0/configs/LPM/l0b_encodings.yml +17 -17
  88. disdrodb/l0/configs/LPM/raw_data_format.yml +17 -17
  89. disdrodb/l0/configs/LPM_V0/l0a_encodings.yml +2 -2
  90. disdrodb/l0/configs/LPM_V0/l0b_cf_attrs.yml +2 -2
  91. disdrodb/l0/configs/LPM_V0/l0b_encodings.yml +2 -2
  92. disdrodb/l0/configs/LPM_V0/raw_data_format.yml +2 -2
  93. disdrodb/l0/configs/ODM470/bins_diameter.yml +643 -0
  94. disdrodb/l0/configs/ODM470/bins_velocity.yml +0 -0
  95. disdrodb/l0/configs/ODM470/l0a_encodings.yml +11 -0
  96. disdrodb/l0/configs/ODM470/l0b_cf_attrs.yml +46 -0
  97. disdrodb/l0/configs/ODM470/l0b_encodings.yml +106 -0
  98. disdrodb/l0/configs/ODM470/raw_data_format.yml +111 -0
  99. disdrodb/l0/configs/PARSIVEL/l0b_cf_attrs.yml +1 -1
  100. disdrodb/l0/l0_reader.py +2 -3
  101. disdrodb/l0/l0a_processing.py +6 -8
  102. disdrodb/l0/l0b_nc_processing.py +3 -6
  103. disdrodb/l0/l0b_processing.py +2 -16
  104. disdrodb/l0/l0c_processing.py +29 -12
  105. disdrodb/l0/readers/LPM/ARM/ARM_LPM.py +2 -1
  106. disdrodb/l0/readers/LPM/AUSTRALIA/MELBOURNE_2007_LPM.py +18 -18
  107. disdrodb/l0/readers/LPM/BRAZIL/CHUVA_LPM.py +18 -18
  108. disdrodb/l0/readers/LPM/BRAZIL/GOAMAZON_LPM.py +18 -18
  109. disdrodb/l0/readers/LPM/GERMANY/DWD.py +244 -63
  110. disdrodb/l0/readers/LPM/ITALY/GID_LPM.py +65 -23
  111. disdrodb/l0/readers/LPM/ITALY/GID_LPM_AQ.py +277 -0
  112. disdrodb/l0/readers/LPM/ITALY/GID_LPM_PI.py +19 -18
  113. disdrodb/l0/readers/LPM/ITALY/GID_LPM_T.py +23 -19
  114. disdrodb/l0/readers/LPM/ITALY/GID_LPM_W.py +19 -21
  115. disdrodb/l0/readers/LPM/KIT/CHWALA.py +19 -20
  116. disdrodb/l0/readers/LPM/NETHERLANDS/DELFT_LPM_NC.py +1 -1
  117. disdrodb/l0/readers/LPM/NETHERLANDS/DELFT_RWANDA_LPM_NC.py +18 -18
  118. disdrodb/l0/readers/LPM/NORWAY/HAUKELISETER_LPM.py +19 -20
  119. disdrodb/l0/readers/LPM/NORWAY/NMBU_LPM.py +19 -20
  120. disdrodb/l0/readers/LPM/SLOVENIA/ARSO.py +19 -20
  121. disdrodb/l0/readers/LPM/SLOVENIA/UL.py +19 -20
  122. disdrodb/l0/readers/LPM/SWITZERLAND/INNERERIZ_LPM.py +19 -20
  123. disdrodb/l0/readers/LPM/UK/DIVEN.py +1 -1
  124. disdrodb/l0/readers/LPM/UK/WITHWORTH_LPM.py +19 -20
  125. disdrodb/l0/readers/LPM/USA/CHARLESTON.py +19 -20
  126. disdrodb/l0/readers/LPM/USA/DEVEX.py +255 -0
  127. disdrodb/l0/readers/LPM_V0/BELGIUM/ULIEGE.py +3 -5
  128. disdrodb/l0/readers/LPM_V0/ITALY/GID_LPM_V0.py +4 -3
  129. disdrodb/l0/readers/ODM470/OCEAN/OCEANRAIN.py +124 -0
  130. disdrodb/l0/readers/PARSIVEL/AUSTRALIA/MELBOURNE_2007_PARSIVEL.py +1 -1
  131. disdrodb/l0/readers/PARSIVEL/BASQUECOUNTRY/EUSKALMET_OTT.py +2 -1
  132. disdrodb/l0/readers/PARSIVEL/CHINA/CHONGQING.py +2 -3
  133. disdrodb/l0/readers/PARSIVEL/EPFL/ARCTIC_2021.py +2 -1
  134. disdrodb/l0/readers/PARSIVEL/EPFL/COMMON_2011.py +2 -1
  135. disdrodb/l0/readers/PARSIVEL/EPFL/DAVOS_2009_2011.py +2 -1
  136. disdrodb/l0/readers/PARSIVEL/EPFL/EPFL_2009.py +2 -1
  137. disdrodb/l0/readers/PARSIVEL/EPFL/EPFL_ROOF_2008.py +2 -1
  138. disdrodb/l0/readers/PARSIVEL/EPFL/EPFL_ROOF_2010.py +2 -1
  139. disdrodb/l0/readers/PARSIVEL/EPFL/EPFL_ROOF_2011.py +2 -1
  140. disdrodb/l0/readers/PARSIVEL/EPFL/EPFL_ROOF_2012.py +2 -1
  141. disdrodb/l0/readers/PARSIVEL/EPFL/GENEPI_2007.py +2 -1
  142. disdrodb/l0/readers/PARSIVEL/EPFL/GRAND_ST_BERNARD_2007.py +2 -1
  143. disdrodb/l0/readers/PARSIVEL/EPFL/GRAND_ST_BERNARD_2007_2.py +2 -1
  144. disdrodb/l0/readers/PARSIVEL/EPFL/HPICONET_2010.py +2 -1
  145. disdrodb/l0/readers/PARSIVEL/EPFL/HYMEX_LTE_SOP2.py +2 -1
  146. disdrodb/l0/readers/PARSIVEL/EPFL/HYMEX_LTE_SOP3.py +2 -1
  147. disdrodb/l0/readers/PARSIVEL/EPFL/HYMEX_LTE_SOP4.py +2 -1
  148. disdrodb/l0/readers/PARSIVEL/EPFL/LOCARNO_2018.py +1 -1
  149. disdrodb/l0/readers/PARSIVEL/EPFL/LOCARNO_2019.py +1 -1
  150. disdrodb/l0/readers/PARSIVEL/EPFL/PARADISO_2014.py +2 -1
  151. disdrodb/l0/readers/PARSIVEL/EPFL/PARSIVEL_2007.py +2 -1
  152. disdrodb/l0/readers/PARSIVEL/EPFL/PLATO_2019.py +1 -1
  153. disdrodb/l0/readers/PARSIVEL/EPFL/RACLETS_2019.py +2 -1
  154. disdrodb/l0/readers/PARSIVEL/EPFL/RACLETS_2019_WJF.py +2 -1
  155. disdrodb/l0/readers/PARSIVEL/EPFL/RIETHOLZBACH_2011.py +2 -1
  156. disdrodb/l0/readers/PARSIVEL/EPFL/SAMOYLOV_2017.py +2 -1
  157. disdrodb/l0/readers/PARSIVEL/EPFL/SAMOYLOV_2019.py +2 -1
  158. disdrodb/l0/readers/PARSIVEL/EPFL/UNIL_2022.py +2 -1
  159. disdrodb/l0/readers/PARSIVEL/JAPAN/JMA.py +1 -1
  160. disdrodb/l0/readers/PARSIVEL/KOREA/ICEPOP_MSC.py +159 -0
  161. disdrodb/l0/readers/PARSIVEL/NASA/LPVEX.py +1 -1
  162. disdrodb/l0/readers/PARSIVEL/NASA/MC3E.py +1 -1
  163. disdrodb/l0/readers/PARSIVEL/NCAR/CCOPE_2015.py +1 -1
  164. disdrodb/l0/readers/PARSIVEL/NCAR/OWLES_MIPS.py +1 -1
  165. disdrodb/l0/readers/PARSIVEL/NCAR/PECAN_MOBILE.py +1 -1
  166. disdrodb/l0/readers/PARSIVEL/NCAR/PLOWS_MIPS.py +1 -1
  167. disdrodb/l0/readers/PARSIVEL/NCAR/VORTEX2_2009.py +1 -1
  168. disdrodb/l0/readers/PARSIVEL/NCAR/VORTEX2_2010.py +1 -3
  169. disdrodb/l0/readers/PARSIVEL/NCAR/VORTEX2_2010_UF.py +1 -3
  170. disdrodb/l0/readers/PARSIVEL/SLOVENIA/UL.py +2 -1
  171. disdrodb/l0/readers/PARSIVEL2/ARM/ARM_PARSIVEL2.py +2 -1
  172. disdrodb/l0/readers/PARSIVEL2/BASQUECOUNTRY/EUSKALMET_OTT2.py +2 -1
  173. disdrodb/l0/readers/PARSIVEL2/BELGIUM/ILVO.py +2 -3
  174. disdrodb/l0/readers/PARSIVEL2/BRAZIL/CHUVA_PARSIVEL2.py +1 -1
  175. disdrodb/l0/readers/PARSIVEL2/BRAZIL/GOAMAZON_PARSIVEL2.py +1 -1
  176. disdrodb/l0/readers/PARSIVEL2/CANADA/UQAM_NC.py +1 -1
  177. disdrodb/l0/readers/PARSIVEL2/DENMARK/DTU.py +1 -1
  178. disdrodb/l0/readers/PARSIVEL2/DENMARK/EROSION_nc.py +2 -1
  179. disdrodb/l0/readers/PARSIVEL2/DENMARK/EROSION_raw.py +2 -1
  180. disdrodb/l0/readers/PARSIVEL2/FINLAND/FMI_PARSIVEL2.py +1 -1
  181. disdrodb/l0/readers/PARSIVEL2/FRANCE/ENPC_PARSIVEL2.py +2 -3
  182. disdrodb/l0/readers/PARSIVEL2/FRANCE/OSUG.py +2 -2
  183. disdrodb/l0/readers/PARSIVEL2/FRANCE/SIRTA_PARSIVEL2.py +1 -3
  184. disdrodb/l0/readers/PARSIVEL2/GREECE/NOA.py +4 -3
  185. disdrodb/l0/readers/PARSIVEL2/ITALY/GID_PARSIVEL2.py +1 -3
  186. disdrodb/l0/readers/PARSIVEL2/ITALY/HYDROX.py +6 -3
  187. disdrodb/l0/readers/PARSIVEL2/JAPAN/PRECIP.py +1 -1
  188. disdrodb/l0/readers/PARSIVEL2/KIT/BURKINA_FASO.py +1 -1
  189. disdrodb/l0/readers/PARSIVEL2/KIT/TEAMX.py +1 -1
  190. disdrodb/l0/readers/PARSIVEL2/KOREA/ICEPOP_MSC.py +161 -0
  191. disdrodb/l0/readers/PARSIVEL2/KOREA/ICEPOP_UCLM.py +126 -0
  192. disdrodb/l0/readers/PARSIVEL2/MEXICO/OH_IIUNAM_nc.py +2 -1
  193. disdrodb/l0/readers/PARSIVEL2/MPI/BCO_PARSIVEL2.py +1 -1
  194. disdrodb/l0/readers/PARSIVEL2/MPI/BOWTIE.py +1 -1
  195. disdrodb/l0/readers/PARSIVEL2/NASA/APU.py +3 -1
  196. disdrodb/l0/readers/PARSIVEL2/NASA/NSSTC.py +1 -1
  197. disdrodb/l0/readers/PARSIVEL2/NCAR/FARM_PARSIVEL2.py +2 -1
  198. disdrodb/l0/readers/PARSIVEL2/NCAR/PECAN_FP3.py +1 -1
  199. disdrodb/l0/readers/PARSIVEL2/NCAR/PECAN_MIPS.py +1 -1
  200. disdrodb/l0/readers/PARSIVEL2/NCAR/PERILS_MIPS.py +2 -1
  201. disdrodb/l0/readers/PARSIVEL2/NCAR/PERILS_PIPS.py +2 -1
  202. disdrodb/l0/readers/PARSIVEL2/NCAR/RELAMPAGO_PARSIVEL2.py +1 -1
  203. disdrodb/l0/readers/PARSIVEL2/NCAR/SNOWIE_PJ.py +1 -1
  204. disdrodb/l0/readers/PARSIVEL2/NCAR/SNOWIE_SB.py +1 -1
  205. disdrodb/l0/readers/PARSIVEL2/NCAR/VORTEX_SE_2016_P1.py +2 -3
  206. disdrodb/l0/readers/PARSIVEL2/NCAR/VORTEX_SE_2016_P2.py +1 -1
  207. disdrodb/l0/readers/PARSIVEL2/NCAR/VORTEX_SE_2016_PIPS.py +2 -1
  208. disdrodb/l0/readers/PARSIVEL2/NETHERLANDS/DELFT_NC.py +1 -1
  209. disdrodb/l0/readers/PARSIVEL2/NORWAY/UIB.py +10 -2
  210. disdrodb/l0/readers/PARSIVEL2/PHILIPPINES/PAGASA.py +2 -3
  211. disdrodb/l0/readers/PARSIVEL2/SPAIN/CENER.py +1 -1
  212. disdrodb/l0/readers/PARSIVEL2/SPAIN/CR1000DL.py +1 -1
  213. disdrodb/l0/readers/PARSIVEL2/SPAIN/GRANADA.py +2 -3
  214. disdrodb/l0/readers/PARSIVEL2/SPAIN/LIAISE.py +1 -1
  215. disdrodb/l0/readers/PARSIVEL2/SWEDEN/SMHI.py +2 -1
  216. disdrodb/l0/readers/PARSIVEL2/USA/CSU.py +1 -1
  217. disdrodb/l0/readers/PARSIVEL2/USA/CW3E.py +2 -1
  218. disdrodb/l0/readers/PWS100/AUSTRIA/HOAL.py +2 -3
  219. disdrodb/l0/readers/PWS100/FRANCE/ENPC_PWS100.py +2 -3
  220. disdrodb/l0/readers/PWS100/FRANCE/ENPC_PWS100_SIRTA.py +2 -1
  221. disdrodb/l0/readers/RD80/BRAZIL/ATTO_RD80.py +1 -3
  222. disdrodb/l0/readers/RD80/BRAZIL/CHUVA_RD80.py +1 -3
  223. disdrodb/l0/readers/RD80/BRAZIL/GOAMAZON_RD80.py +1 -3
  224. disdrodb/l0/readers/RD80/NCAR/CINDY_2011_RD80.py +1 -3
  225. disdrodb/l0/readers/RD80/NCAR/RELAMPAGO_RD80.py +1 -3
  226. disdrodb/l0/readers/RD80/NOAA/PSL_RD80.py +2 -3
  227. disdrodb/l0/readers/SWS250/BELGIUM/KMI.py +2 -3
  228. disdrodb/l0/readers/template_reader_raw_netcdf_data.py +2 -3
  229. disdrodb/l0/readers/template_reader_raw_text_data.py +2 -3
  230. disdrodb/l0/standards.py +4 -5
  231. disdrodb/l0/template_tools.py +7 -11
  232. disdrodb/l1/__init__.py +2 -1
  233. disdrodb/l1/classification.py +914 -0
  234. disdrodb/l1/processing.py +36 -106
  235. disdrodb/l1/resampling.py +13 -3
  236. disdrodb/l1_env/__init__.py +1 -1
  237. disdrodb/l1_env/routines.py +7 -6
  238. disdrodb/l2/__init__.py +2 -1
  239. disdrodb/l2/empirical_dsd.py +58 -31
  240. disdrodb/l2/processing.py +327 -61
  241. disdrodb/metadata/checks.py +10 -13
  242. disdrodb/metadata/download.py +5 -4
  243. disdrodb/metadata/geolocation.py +3 -4
  244. disdrodb/metadata/info.py +3 -5
  245. disdrodb/metadata/manipulation.py +1 -3
  246. disdrodb/metadata/reader.py +1 -3
  247. disdrodb/metadata/search.py +1 -4
  248. disdrodb/metadata/standards.py +1 -3
  249. disdrodb/metadata/writer.py +1 -3
  250. disdrodb/physics/__init__.py +17 -0
  251. disdrodb/physics/atmosphere.py +273 -0
  252. disdrodb/physics/water.py +131 -0
  253. disdrodb/physics/wrappers.py +63 -0
  254. disdrodb/psd/__init__.py +1 -2
  255. disdrodb/psd/fitting.py +23 -9
  256. disdrodb/psd/models.py +2 -1
  257. disdrodb/routines/__init__.py +6 -1
  258. disdrodb/routines/l0.py +39 -25
  259. disdrodb/routines/l1.py +23 -16
  260. disdrodb/routines/l2.py +12 -9
  261. disdrodb/routines/options.py +117 -73
  262. disdrodb/routines/options_validation.py +728 -0
  263. disdrodb/routines/wrappers.py +460 -40
  264. disdrodb/scattering/__init__.py +1 -2
  265. disdrodb/scattering/axis_ratio.py +6 -6
  266. disdrodb/scattering/permittivity.py +9 -8
  267. disdrodb/scattering/routines.py +33 -15
  268. disdrodb/summary/__init__.py +1 -1
  269. disdrodb/summary/routines.py +95 -30
  270. disdrodb/utils/__init__.py +1 -1
  271. disdrodb/utils/archiving.py +18 -10
  272. disdrodb/utils/attrs.py +7 -5
  273. disdrodb/utils/cli.py +8 -10
  274. disdrodb/utils/compression.py +10 -13
  275. disdrodb/utils/coords.py +45 -0
  276. disdrodb/utils/dask.py +7 -5
  277. disdrodb/utils/dataframe.py +5 -6
  278. disdrodb/utils/decorators.py +3 -4
  279. disdrodb/utils/dict.py +1 -1
  280. disdrodb/utils/directories.py +5 -7
  281. disdrodb/utils/encoding.py +4 -5
  282. disdrodb/utils/event.py +1 -1
  283. disdrodb/utils/list.py +1 -3
  284. disdrodb/utils/logger.py +1 -3
  285. disdrodb/utils/manipulations.py +175 -4
  286. disdrodb/utils/pydantic.py +81 -0
  287. disdrodb/utils/routines.py +2 -3
  288. disdrodb/utils/subsetting.py +1 -1
  289. disdrodb/utils/time.py +6 -4
  290. disdrodb/utils/warnings.py +2 -3
  291. disdrodb/utils/writer.py +5 -3
  292. disdrodb/utils/xarray.py +31 -3
  293. disdrodb/utils/yaml.py +1 -3
  294. disdrodb/viz/__init__.py +1 -1
  295. disdrodb/viz/plots.py +193 -18
  296. {disdrodb-0.2.1.dist-info → disdrodb-0.4.0.dist-info}/METADATA +5 -4
  297. disdrodb-0.4.0.dist-info/RECORD +361 -0
  298. {disdrodb-0.2.1.dist-info → disdrodb-0.4.0.dist-info}/entry_points.txt +3 -0
  299. disdrodb/etc/products/L1/1MIN.yaml +0 -13
  300. disdrodb/etc/products/L1/LPM/1MIN.yaml +0 -13
  301. disdrodb/etc/products/L1/LPM_V0/1MIN.yaml +0 -13
  302. disdrodb/etc/products/L1/PARSIVEL/1MIN.yaml +0 -13
  303. disdrodb/etc/products/L1/PARSIVEL2/1MIN.yaml +0 -13
  304. disdrodb/etc/products/L1/PWS100/1MIN.yaml +0 -13
  305. disdrodb/etc/products/L1/RD80/1MIN.yaml +0 -13
  306. disdrodb/etc/products/L1/SWS250/1MIN.yaml +0 -13
  307. disdrodb/etc/products/L2M/10MIN.yaml +0 -12
  308. disdrodb/l1/beard_model.py +0 -662
  309. disdrodb/l1/filters.py +0 -205
  310. disdrodb-0.2.1.dist-info/RECORD +0 -329
  311. {disdrodb-0.2.1.dist-info → disdrodb-0.4.0.dist-info}/WHEEL +0 -0
  312. {disdrodb-0.2.1.dist-info → disdrodb-0.4.0.dist-info}/licenses/LICENSE +0 -0
  313. {disdrodb-0.2.1.dist-info → disdrodb-0.4.0.dist-info}/top_level.txt +0 -0
@@ -1,5 +1,5 @@
1
1
  # -----------------------------------------------------------------------------.
2
- # Copyright (c) 2021-2023 DISDRODB developers
2
+ # Copyright (c) 2021-2026 DISDRODB developers
3
3
  #
4
4
  # temperaturehis 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
@@ -15,6 +15,7 @@
15
15
  # along with this program. If not, see <http://www.gnu.org/licenses/>.
16
16
  # -----------------------------------------------------------------------------.
17
17
  """Implement particle permittivity models."""
18
+
18
19
  import numpy as np
19
20
  import xarray as xr
20
21
 
@@ -56,7 +57,7 @@ def get_refractive_index_function(permittivity_model):
56
57
  ----------
57
58
  model : str
58
59
  The model to use for calculating the complex refractive index. Available models are:
59
- 'Liebe1991', 'Liebe1991v2', 'Ellison2005', 'Turner2016', 'Turner2016SLC'.
60
+ 'Liebe1991', 'Liebe1991v2', 'Ellison2007', 'Turner2016', 'Turner2016SLC'.
60
61
 
61
62
  Returns
62
63
  -------
@@ -104,7 +105,7 @@ def get_refractive_index(temperature, frequency, permittivity_model):
104
105
  Frequency in GHz.
105
106
  permittivity_model : str
106
107
  The permittivity model to use for calculating the complex refractive index.
107
- Available models are: 'Liebe1991', 'Liebe1991v2', 'Ellison2005', 'Turner2016', 'Turner2016SLC'.
108
+ Available models are: 'Liebe1991', 'Liebe1991v2', 'Ellison2007', 'Turner2016', 'Turner2016SLC'.
108
109
  See available models with ``disdrodb.scattering.available_permittivity_models()``.
109
110
 
110
111
  Returns
@@ -309,7 +310,7 @@ def get_rain_refractive_index_liebe1991(temperature, frequency):
309
310
  return m
310
311
 
311
312
 
312
- def get_rain_refractive_index_ellison2005(temperature, frequency):
313
+ def get_rain_refractive_index_ellison2007(temperature, frequency):
313
314
  """Compute the complex refractive index according to Ellison (2005) model.
314
315
 
315
316
  Parameters
@@ -343,8 +344,8 @@ def get_rain_refractive_index_ellison2005(temperature, frequency):
343
344
  temperature = ensure_array(temperature)
344
345
 
345
346
  # Check frequency and temperature within validity range
346
- temperature = check_temperature_validity_range(temperature, vmin=0, vmax=100, permittivity_model="Ellison2005")
347
- frequency = check_frequency_validity_range(frequency, vmin=0, vmax=1000, permittivity_model="Ellison2005")
347
+ temperature = check_temperature_validity_range(temperature, vmin=0, vmax=100, permittivity_model="Ellison2007")
348
+ frequency = check_frequency_validity_range(frequency, vmin=0, vmax=1000, permittivity_model="Ellison2007")
348
349
 
349
350
  # Conversion of frequency to Hz
350
351
  frequency = frequency / 1e-9
@@ -479,7 +480,7 @@ def get_rain_refractive_index_turner2016(frequency, temperature):
479
480
  def get_rayleigh_dielectric_factor(m):
480
481
  """Compute the Rayleigh dielectric factor |K|**2 from the complex refractive index.
481
482
 
482
- The magnitude squared of the complex dielectric contrast factor for liquid water,
483
+ The magnitude squared of the complex dielectric constant factor for liquid water,
483
484
  relative to the surrounding medium (typically air).
484
485
 
485
486
  This factor is used to compute the radar reflectivity.
@@ -505,6 +506,6 @@ def get_rayleigh_dielectric_factor(m):
505
506
  REFRACTIVE_INDEX_MODELS = {
506
507
  "Liebe1991": get_rain_refractive_index_liebe1991,
507
508
  "Liebe1991single": get_rain_refractive_index_liebe1991_single,
508
- "Ellison2005": get_rain_refractive_index_ellison2005,
509
+ "Ellison2007": get_rain_refractive_index_ellison2007,
509
510
  "Turner2016": get_rain_refractive_index_turner2016,
510
511
  }
@@ -1,5 +1,5 @@
1
1
  # -----------------------------------------------------------------------------.
2
- # Copyright (c) 2021-2023 DISDRODB developers
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
@@ -26,7 +26,6 @@ import xarray as xr
26
26
 
27
27
  from disdrodb.configs import get_scattering_table_dir
28
28
  from disdrodb.constants import DIAMETER_DIMENSION
29
- from disdrodb.l1.filters import filter_diameter_bins
30
29
  from disdrodb.psd.models import BinnedPSD, create_psd, get_required_parameters
31
30
  from disdrodb.scattering.axis_ratio import check_axis_ratio_model, get_axis_ratio_model
32
31
  from disdrodb.scattering.permittivity import (
@@ -35,7 +34,7 @@ from disdrodb.scattering.permittivity import (
35
34
  get_refractive_index,
36
35
  )
37
36
  from disdrodb.utils.logger import log_info
38
- from disdrodb.utils.manipulations import get_diameter_bin_edges
37
+ from disdrodb.utils.manipulations import filter_diameter_bins, get_diameter_bin_edges
39
38
  from disdrodb.utils.warnings import suppress_warnings
40
39
 
41
40
  logger = logging.getLogger(__name__)
@@ -76,20 +75,31 @@ def check_radar_band(radar_band):
76
75
  return radar_band
77
76
 
78
77
 
78
+ def _is_valid_numeric_frequency(frequency):
79
+ numeric_value = float(frequency)
80
+ if numeric_value <= 0:
81
+ raise ValueError(f"Frequency must be positive, got {numeric_value}")
82
+ return numeric_value
83
+
84
+
79
85
  def _check_frequency(frequency):
80
86
  """Check the validity of the specified frequency."""
81
87
  if isinstance(frequency, str):
82
- frequency = check_radar_band(frequency)
83
- frequency = frequency_dict[frequency]
84
- return frequency
85
- if not isinstance(frequency, (int, float)):
86
- raise TypeError(f"Frequency {frequency} must be a string or a number.")
87
- return frequency
88
+ try:
89
+ frequency = float(frequency)
90
+
91
+ except ValueError:
92
+ # Not numeric, assume radar band name
93
+ frequency = check_radar_band(frequency)
94
+ frequency = frequency_dict[frequency]
95
+ if isinstance(frequency, (int, float, np.integer, np.floating)):
96
+ return _is_valid_numeric_frequency(frequency)
97
+ raise TypeError(f"Frequency {frequency} must be a string or a number.")
88
98
 
89
99
 
90
100
  def ensure_numerical_frequency(frequency):
91
101
  """Ensure that the frequencies are numerical values in GHz."""
92
- if isinstance(frequency, (str, int, float)):
102
+ if isinstance(frequency, (str, int, float, np.integer, np.floating)):
93
103
  frequency = [frequency]
94
104
  frequency = np.array([_check_frequency(f) for f in frequency])
95
105
  return frequency.squeeze()
@@ -476,6 +486,11 @@ def compute_radar_variables(scatterer):
476
486
 
477
487
  To speed up computations, this function should input a scatterer object with
478
488
  a preinitialized scattering table.
489
+
490
+ Note
491
+ ----
492
+ If this function is modified to compute additional radar variables, the global
493
+ variable RADAR_VARIABLES must be updated accordingly !
479
494
  """
480
495
  from pytmatrix import radar
481
496
 
@@ -495,10 +510,13 @@ def compute_radar_variables(scatterer):
495
510
  radar_vars["ZDR"] = 10 * np.log10(radar.Zdr(scatterer)) # dB
496
511
  radar_vars["ZDR"] = np.where(np.isfinite(radar_vars["ZDR"]), radar_vars["ZDR"], np.nan)
497
512
 
498
- radar_vars["LDR"] = 10 * np.log10(radar.ldr(scatterer)) # dBZ
499
- radar_vars["LDR"] = np.where(np.isfinite(radar_vars["LDR"]), radar_vars["LDR"], np.nan)
513
+ radar_vars["LDRH"] = 10 * np.log10(radar.ldr(scatterer, h_pol=True)) # dBZ
514
+ radar_vars["LDRH"] = np.where(np.isfinite(radar_vars["LDRH"]), radar_vars["LDRH"], np.nan)
515
+
516
+ radar_vars["LDRV"] = 10 * np.log10(radar.ldr(scatterer, h_pol=False)) # dBZ
517
+ radar_vars["LDRV"] = np.where(np.isfinite(radar_vars["LDRV"]), radar_vars["LDRV"], np.nan)
500
518
 
501
- radar_vars["RHOHV"] = radar.rho_hv(scatterer) # deg/km
519
+ radar_vars["RHOHV"] = radar.rho_hv(scatterer) # [-]
502
520
  radar_vars["DELTAHV"] = radar.delta_hv(scatterer) * 180.0 / np.pi # [deg]
503
521
 
504
522
  # Set forward scattering for attenuation and phase calculations
@@ -512,7 +530,7 @@ def compute_radar_variables(scatterer):
512
530
 
513
531
  # Radar variables computed by DISDRODB
514
532
  # - Must reflect dictionary order output of compute_radar_variables
515
- RADAR_VARIABLES = ["DBZH", "DBZV", "ZDR", "LDR", "RHOHV", "DELTAHV", "KDP", "AH", "AV", "ADP"]
533
+ RADAR_VARIABLES = ["DBZH", "DBZV", "ZDR", "LDRH", "LDRV", "RHOHV", "DELTAHV", "KDP", "AH", "AV", "ADP"]
516
534
 
517
535
 
518
536
  def _try_compute_radar_variables(scatterer):
@@ -544,7 +562,7 @@ def _estimate_model_radar_parameters(
544
562
  scatterer,
545
563
  ):
546
564
  # Assign PSD model to the scatterer object
547
- parameters = dict(zip(psd_parameters_names, parameters))
565
+ parameters = dict(zip(psd_parameters_names, parameters, strict=True))
548
566
  scatterer.psd = create_psd(psd_model, parameters)
549
567
 
550
568
  # Get radar variables
@@ -1,5 +1,5 @@
1
1
  # -----------------------------------------------------------------------------.
2
- # Copyright (c) 2021-2023 DISDRODB developers
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
@@ -1,5 +1,5 @@
1
1
  # -----------------------------------------------------------------------------.
2
- # Copyright (c) 2021-2023 DISDRODB developers
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
@@ -15,6 +15,7 @@
15
15
  # along with this program. If not, see <http://www.gnu.org/licenses/>.
16
16
  # -----------------------------------------------------------------------------.
17
17
  """Utilities to create summary statistics."""
18
+
18
19
  import gc
19
20
  import importlib
20
21
  import os
@@ -223,6 +224,11 @@ def create_table_rain_summary(df, temporal_resolution):
223
224
  table["n_minutes_Dmax_>7"] = np.sum(df["Dmax"] > 7).item() * accumulation_interval_minutes
224
225
  table["n_minutes_Dmax_>8"] = np.sum(df["Dmax"] > 8).item() * accumulation_interval_minutes
225
226
  table["n_minutes_Dmax_>9"] = np.sum(df["Dmax"] > 9).item() * accumulation_interval_minutes
227
+
228
+ # Convert all minutes columns to integer
229
+ for key in table:
230
+ if "minutes" in key:
231
+ table[key] = int(table[key])
226
232
  return table
227
233
 
228
234
 
@@ -233,7 +239,7 @@ def create_table_dsd_summary(df):
233
239
  df["log10(Nt)"] = np.log10(df["Nt"])
234
240
 
235
241
  # List of variables to summarize
236
- variables = ["W", "R", "Z", "D50", "Dm", "sigma_m", "Dmax", "Nw", "log10(Nw)", "Nt", "log10(Nt)"]
242
+ variables = ["LWC", "R", "Z", "D50", "Dm", "sigma_m", "Dmax", "Nw", "log10(Nw)", "Nt", "log10(Nt)"]
237
243
 
238
244
  # Define subset dataframe
239
245
  df_subset = df[variables]
@@ -356,9 +362,9 @@ def create_table_events_summary(df, temporal_resolution):
356
362
  "mean_sigma_m": df_event["sigma_m"].mean(),
357
363
  "median_sigma_m": df_event["sigma_m"].median(),
358
364
  "max_sigma_m": df_event["sigma_m"].max(),
359
- "mean_W": df_event["W"].mean(),
360
- "median_W": df_event["W"].median(),
361
- "max_W": df_event["W"].max(),
365
+ "mean_LWC": df_event["LWC"].mean(),
366
+ "median_LWC": df_event["LWC"].median(),
367
+ "max_LWC": df_event["LWC"].max(),
362
368
  "max_Z": df_event["Z"].max(),
363
369
  "mean_Nbins": int(df_event["Nbins"].mean()),
364
370
  "max_Nbins": int(df_event["Nbins"].max()),
@@ -371,9 +377,22 @@ def create_table_events_summary(df, temporal_resolution):
371
377
 
372
378
  df_events = pd.DataFrame.from_records(events_stats)
373
379
 
374
- # Round float columns to nearest integer, leave ints unchanged
375
- float_cols = df_events.select_dtypes(include=["float"]).columns
376
- df_events[float_cols] = df_events[float_cols].astype(float).round(decimals=2)
380
+ # Round and cast columns
381
+ # - Round to 3 decimals
382
+ df_events["P_total"] = df_events["P_total"].round(decimals=3)
383
+
384
+ lwc_columns = [c for c in df_events.columns if "LWC" in c]
385
+ df_events[lwc_columns] = df_events[lwc_columns].round(decimals=3)
386
+
387
+ # - Cast to integer
388
+ df_events["duration"] = df_events["duration"].astype(int)
389
+ minutes_columns = [c for c in df_events.columns if "minutes" in c]
390
+ df_events[minutes_columns] = df_events[minutes_columns].astype(int)
391
+
392
+ # - Round to 2 decimals
393
+ for var in ["Dmax", "Dm", "sigma_m", "R", "Z"]:
394
+ names = [c for c in df_events.columns if var in c]
395
+ df_events[names] = df_events[names].round(decimals=2)
377
396
  return df_events
378
397
 
379
398
 
@@ -385,7 +404,7 @@ def prepare_latex_table_dsd_summary(df):
385
404
  df[numeric_cols] = df[numeric_cols].astype(str)
386
405
  # Rename
387
406
  rename_dict = {
388
- "W": r"$W\,[\mathrm{g}\,\mathrm{m}^{-3}]$", # [g/m3]
407
+ "LWC": r"$LWC\,[\mathrm{g}\,\mathrm{m}^{-3}]$", # [g/m3]
389
408
  "R": r"$R\,[\mathrm{mm}\,\mathrm{h}^{-1}]$", # [mm/hr]
390
409
  "Z": r"$Z\,[\mathrm{dBZ}]$", # [dBZ]
391
410
  "D50": r"$D_{50}\,[\mathrm{mm}]$", # [mm]
@@ -433,9 +452,9 @@ def prepare_latex_table_events_summary(df):
433
452
  "mean_sigma_m": r"$\sigma_{m,\mathrm{mean}}$",
434
453
  "median_sigma_m": r"$\sigma_{m,\mathrm{median}}$",
435
454
  "max_sigma_m": r"$\sigma_{m,\max}$",
436
- "mean_W": r"$W_{\mathrm{mean}}$",
437
- "median_W": r"$W_{\mathrm{median}}$",
438
- "max_W": r"$W_{\max}$",
455
+ "mean_LWC": r"$LWC_{\mathrm{mean}}$",
456
+ "median_LWC": r"$LWC_{\mathrm{median}}$",
457
+ "max_LWC": r"$LWC_{\max}$",
439
458
  "max_Z": r"$Z_{\max}$",
440
459
  "mean_Nbins": r"$N_{\mathrm{bins},\mathrm{mean}}$",
441
460
  "max_Nbins": r"$N_{\mathrm{bins},\max}$",
@@ -609,7 +628,7 @@ def fit_powerlaw(x, y, xbins, quantile=0.5, min_counts=10, x_in_db=False, use_ra
609
628
  absolute_sigma=True,
610
629
  maxfev=10_000, # max n iterations
611
630
  )
612
- (a_std, b_std) = np.sqrt(np.diag(pcov))
631
+ a_std, b_std = np.sqrt(np.diag(pcov))
613
632
  a_std = float(a_std)
614
633
  b_std = float(b_std)
615
634
 
@@ -918,7 +937,7 @@ def plot_dsd_params_relationships(df, add_nt=False, dpi=300):
918
937
  df,
919
938
  x="Dm",
920
939
  y="Nw",
921
- variables=["R", "W", "Nt"],
940
+ variables=["R", "LWC", "Nt"],
922
941
  x_bins=np.arange(0, 8, 0.1),
923
942
  y_bins=log_arange(10, 1_000_000, log_step=0.05, base=10),
924
943
  )
@@ -927,7 +946,7 @@ def plot_dsd_params_relationships(df, add_nt=False, dpi=300):
927
946
  ds_Dm_LWC_stats = compute_2d_histogram(
928
947
  df,
929
948
  x="Dm",
930
- y="W",
949
+ y="LWC",
931
950
  variables=["R", "Nw", "Nt"],
932
951
  x_bins=np.arange(0, 8, 0.1),
933
952
  y_bins=log_arange(0.01, 10, log_step=0.05, base=10),
@@ -938,7 +957,7 @@ def plot_dsd_params_relationships(df, add_nt=False, dpi=300):
938
957
  df,
939
958
  x="Dm",
940
959
  y="R",
941
- variables=["Nw", "W", "Nt"],
960
+ variables=["Nw", "LWC", "Nt"],
942
961
  x_bins=np.arange(0, 8, 0.1),
943
962
  y_bins=log_arange(0.1, 500, log_step=0.05, base=10),
944
963
  )
@@ -948,7 +967,7 @@ def plot_dsd_params_relationships(df, add_nt=False, dpi=300):
948
967
  df,
949
968
  x="Dm",
950
969
  y="Nt",
951
- variables=["R", "W", "Nw"],
970
+ variables=["R", "LWC", "Nw"],
952
971
  x_bins=np.arange(0, 8, 0.1),
953
972
  y_bins=log_arange(1, 100_000, log_step=0.05, base=10),
954
973
  )
@@ -1019,7 +1038,7 @@ def plot_dsd_params_relationships(df, add_nt=False, dpi=300):
1019
1038
  axes[1, 0].set_ylim(nw_lim)
1020
1039
 
1021
1040
  #### - LWC
1022
- im_lwc = ds_Dm_Nw_stats["W_median"].plot.pcolormesh(
1041
+ im_lwc = ds_Dm_Nw_stats["LWC_median"].plot.pcolormesh(
1023
1042
  x="Dm",
1024
1043
  y="Nw",
1025
1044
  cmap=cmap_lwc,
@@ -1067,7 +1086,7 @@ def plot_dsd_params_relationships(df, add_nt=False, dpi=300):
1067
1086
  #### - Counts
1068
1087
  ds_Dm_LWC_stats["count"].plot.pcolormesh(
1069
1088
  x="Dm",
1070
- y="W",
1089
+ y="LWC",
1071
1090
  cmap=cmap_counts,
1072
1091
  norm=norm_counts,
1073
1092
  extend="max",
@@ -1083,7 +1102,7 @@ def plot_dsd_params_relationships(df, add_nt=False, dpi=300):
1083
1102
  # - Empty (diagonal where y-axis is W) - handled above in the loop
1084
1103
  ds_Dm_LWC_stats["R_median"].plot.pcolormesh(
1085
1104
  x="Dm",
1086
- y="W",
1105
+ y="LWC",
1087
1106
  cmap=cmap_r,
1088
1107
  norm=norm_r,
1089
1108
  alpha=0, # fully transparent
@@ -1099,7 +1118,7 @@ def plot_dsd_params_relationships(df, add_nt=False, dpi=300):
1099
1118
  #### - R
1100
1119
  ds_Dm_LWC_stats["R_median"].plot.pcolormesh(
1101
1120
  x="Dm",
1102
- y="W",
1121
+ y="LWC",
1103
1122
  cmap=cmap_r,
1104
1123
  norm=norm_r,
1105
1124
  extend="both",
@@ -1114,7 +1133,7 @@ def plot_dsd_params_relationships(df, add_nt=False, dpi=300):
1114
1133
  #### - Nt
1115
1134
  im_nt = ds_Dm_LWC_stats["Nt_median"].plot.pcolormesh(
1116
1135
  x="Dm",
1117
- y="W",
1136
+ y="LWC",
1118
1137
  cmap=cmap_nt,
1119
1138
  norm=norm_nt,
1120
1139
  extend="both",
@@ -1144,7 +1163,7 @@ def plot_dsd_params_relationships(df, add_nt=False, dpi=300):
1144
1163
  axes[3, 0].set_ylim(r_lim)
1145
1164
 
1146
1165
  #### - LWC
1147
- im_lwc = ds_Dm_R_stats["W_median"].plot.pcolormesh(
1166
+ im_lwc = ds_Dm_R_stats["LWC_median"].plot.pcolormesh(
1148
1167
  x="Dm",
1149
1168
  y="R",
1150
1169
  cmap=cmap_lwc,
@@ -1211,7 +1230,7 @@ def plot_dsd_params_relationships(df, add_nt=False, dpi=300):
1211
1230
  axes[4, 0].set_ylim(nt_lim)
1212
1231
 
1213
1232
  #### - LWC
1214
- ds_Dm_Nt_stats["W_median"].plot.pcolormesh(
1233
+ ds_Dm_Nt_stats["LWC_median"].plot.pcolormesh(
1215
1234
  x="Dm",
1216
1235
  y="Nt",
1217
1236
  cmap=cmap_lwc,
@@ -1336,7 +1355,7 @@ def plot_dsd_params_density(df, log_dm=False, lwc=True, log_normalize=False, fig
1336
1355
  norm = Normalize(0, 1) # Normalized data goes from 0 to 1
1337
1356
 
1338
1357
  # Define the water variable based on lwc flag
1339
- df["LWC"] = df["W"]
1358
+ df["LWC"] = df["LWC"]
1340
1359
  water_var = "LWC" if lwc else "R"
1341
1360
  water_label = "LWC [g/m³]" if lwc else "R [mm/h]"
1342
1361
 
@@ -3731,7 +3750,7 @@ def define_filename(prefix, extension, data_source, campaign_name, station_name,
3731
3750
 
3732
3751
  def create_l2_dataframe(ds):
3733
3752
  """Create pandas Dataframe for L2 analysis."""
3734
- dims_to_drop = set(ds.dims).intersection({DIAMETER_DIMENSION, VELOCITY_DIMENSION})
3753
+ dims_to_drop = set(ds.dims).intersection({DIAMETER_DIMENSION, VELOCITY_DIMENSION, "crs"})
3735
3754
  # - Drop array variables and convert to pandas
3736
3755
  df = ds.drop_dims(dims_to_drop).to_pandas()
3737
3756
  # - Drop coordinates
@@ -3742,7 +3761,7 @@ def create_l2_dataframe(ds):
3742
3761
  return df
3743
3762
 
3744
3763
 
3745
- def prepare_summary_dataset(ds, velocity_method="fall_velocity", source="drop_number"):
3764
+ def prepare_summary_dataset(ds, velocity_method="theoretical_velocity", source="drop_number"):
3746
3765
  """Prepare the L2E or L2M dataset to be converted to a dataframe."""
3747
3766
  # Select fall velocity method
3748
3767
  if "velocity_method" in ds.dims:
@@ -3783,8 +3802,11 @@ def generate_station_summary(ds, summary_dir_path, data_source, campaign_name, s
3783
3802
  # Ensure all data are in memory
3784
3803
  ds = ds.compute()
3785
3804
 
3786
- # Keep only timesteps with at least 3 Nbins to remove noise
3787
- valid_idx = np.where(ds["Nbins"] >= 3)[0]
3805
+ # Filter dataset to remove noisy timesteps
3806
+ # - Keep only timesteps with at least 3 Nbins to remove noise
3807
+ # - Keep only timesteps with sigma_m >= 0.2
3808
+ mask = (ds["Nbins"] >= 3) & (ds["sigma_m"] >= 0.2) & (ds["Nbins_missing_fraction"] <= 0.3) & (ds["Dmin"] <= 1)
3809
+ valid_idx = np.where(mask)[0]
3788
3810
  ds = ds.isel(time=valid_idx)
3789
3811
 
3790
3812
  ####---------------------------------------------------------------------.
@@ -3795,7 +3817,10 @@ def generate_station_summary(ds, summary_dir_path, data_source, campaign_name, s
3795
3817
  drop_number = ds["drop_number"].sum(dim="time")
3796
3818
 
3797
3819
  # Define theoretical and measured average velocity
3798
- theoretical_average_velocity = ds["fall_velocity"].mean(dim="time")
3820
+ if "time" in ds["fall_velocity"].dims:
3821
+ theoretical_average_velocity = ds["fall_velocity"].mean(dim="time")
3822
+ else:
3823
+ theoretical_average_velocity = ds["fall_velocity"]
3799
3824
  measured_average_velocity = get_drop_average_velocity(drop_number)
3800
3825
 
3801
3826
  # Save raw and filtered spectrum over time & theoretical and measured average fall velocity
@@ -3909,6 +3934,7 @@ def generate_station_summary(ds, summary_dir_path, data_source, campaign_name, s
3909
3934
  table_events_summary.to_csv(table_events_summary_csv_filepath)
3910
3935
  # - Save table as pdf
3911
3936
  if is_latex_engine_available():
3937
+ # Sorted by time
3912
3938
  table_events_summary_pdf_filename = table_events_summary_csv_filename.replace(".csv", ".pdf")
3913
3939
  table_events_summary_pdf_filepath = os.path.join(summary_dir_path, table_events_summary_pdf_filename)
3914
3940
  save_table_to_pdf(
@@ -3919,6 +3945,45 @@ def generate_station_summary(ds, summary_dir_path, data_source, campaign_name, s
3919
3945
  orientation="landscape",
3920
3946
  )
3921
3947
 
3948
+ # Sorted by maximum rain intensity
3949
+ table_events_summary = table_events_summary.sort_values(by="max_R", ascending=False)
3950
+ table_events_summary = table_events_summary.reset_index(drop=True)
3951
+ table_events_summary_pdf_filename = define_filename(
3952
+ prefix="Events_Summary_Sorted_By_Rmax",
3953
+ extension="pdf",
3954
+ data_source=data_source,
3955
+ campaign_name=campaign_name,
3956
+ station_name=station_name,
3957
+ temporal_resolution=temporal_resolution,
3958
+ )
3959
+ table_events_summary_pdf_filepath = os.path.join(summary_dir_path, table_events_summary_pdf_filename)
3960
+ save_table_to_pdf(
3961
+ df=prepare_latex_table_events_summary(table_events_summary),
3962
+ filepath=table_events_summary_pdf_filepath,
3963
+ index=True,
3964
+ caption="Events Summary",
3965
+ orientation="landscape",
3966
+ )
3967
+ # Sorted by Ptotal
3968
+ table_events_summary = table_events_summary.sort_values(by="P_total", ascending=False)
3969
+ table_events_summary = table_events_summary.reset_index(drop=True)
3970
+ table_events_summary_pdf_filename = define_filename(
3971
+ prefix="Events_Summary_Sorted_By_Ptot",
3972
+ extension="pdf",
3973
+ data_source=data_source,
3974
+ campaign_name=campaign_name,
3975
+ station_name=station_name,
3976
+ temporal_resolution=temporal_resolution,
3977
+ )
3978
+ table_events_summary_pdf_filepath = os.path.join(summary_dir_path, table_events_summary_pdf_filename)
3979
+ save_table_to_pdf(
3980
+ df=prepare_latex_table_events_summary(table_events_summary),
3981
+ filepath=table_events_summary_pdf_filepath,
3982
+ index=True,
3983
+ caption="Events Summary",
3984
+ orientation="landscape",
3985
+ )
3986
+
3922
3987
  # ---------------------------------------------------------------------.
3923
3988
  #### Create table with integral DSD parameters statistics
3924
3989
  table_dsd_summary = create_table_dsd_summary(df)
@@ -1,5 +1,5 @@
1
1
  # -----------------------------------------------------------------------------.
2
- # Copyright (c) 2021-2023 DISDRODB developers
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
@@ -1,5 +1,5 @@
1
1
  # -----------------------------------------------------------------------------.
2
- # Copyright (c) 2021-2023 DISDRODB developers
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
@@ -15,6 +15,7 @@
15
15
  # along with this program. If not, see <http://www.gnu.org/licenses/>.
16
16
  # -----------------------------------------------------------------------------.
17
17
  """Utility function for DISDRODB product archiving."""
18
+
18
19
  import datetime
19
20
 
20
21
  import numpy as np
@@ -111,17 +112,18 @@ def generate_time_blocks(
111
112
  def identify_events(
112
113
  filepaths,
113
114
  parallel=False,
114
- min_drops=5,
115
+ variable="N",
116
+ detection_threshold=5,
115
117
  neighbor_min_size=2,
116
118
  neighbor_time_interval="5MIN",
117
119
  event_max_time_gap="6H",
118
120
  event_min_duration="5MIN",
119
121
  event_min_size=3,
120
122
  ):
121
- """Return a list of rainy events.
123
+ """Return a list of precipitating events.
122
124
 
123
- Rainy timesteps are defined when N > min_drops.
124
- Any rainy isolated timesteps (based on neighborhood criteria) is removed.
125
+ Precipitating events are defined when 'variable' > detection_threshold.
126
+ Any isolated timesteps with precipitation (based on neighborhood criteria) is removed.
125
127
  Then, consecutive rainy timesteps are grouped into the same event if the time gap between them does not
126
128
  exceed `event_max_time_gap`. Finally, events that do not meet minimum size or duration
127
129
  requirements are filtered out.
@@ -130,6 +132,11 @@ def identify_events(
130
132
  ----------
131
133
  filepaths: list
132
134
  List of L1C file paths.
135
+ variable : str
136
+ Name of the variable to use to apply the event detection.
137
+ The default is "N".
138
+ detection_threshold : int
139
+ Minimum value of 'variable' to consider an event timestep.
133
140
  parallel: bool
134
141
  Whether to load the files in parallel.
135
142
  Set parallel=True only in a multiprocessing environment.
@@ -163,11 +170,11 @@ def identify_events(
163
170
  - "n_timesteps": int, number of valid timesteps in the event
164
171
  """
165
172
  # Open datasets in parallel
166
- ds = open_netcdf_files(filepaths, variables=["time", "N"], parallel=parallel, compute=True)
173
+ ds = open_netcdf_files(filepaths, variables=["time", variable], parallel=parallel, compute=True)
167
174
  # Sort dataset by time
168
175
  ds = ensure_sorted_by_time(ds)
169
176
  # Define candidate timesteps to group into events
170
- idx_valid = ds["N"].to_numpy() > min_drops
177
+ idx_valid = ds[variable].to_numpy() > detection_threshold
171
178
  timesteps = ds["time"].to_numpy()[idx_valid]
172
179
  if "sample_interval" in ds:
173
180
  sample_interval = ds["sample_interval"].compute().item()
@@ -263,8 +270,9 @@ def define_temporal_partitions(filepaths, strategy, parallel, strategy_options):
263
270
  See identify_time_partitions for more information.
264
271
 
265
272
  If ``strategy == 'event'``, supported options are:
266
-
267
- - ``min_drops`` : int
273
+ - ``variable`` : str
274
+ Name of the variable to use to apply the event detection.
275
+ - ``detection_threshold`` : int
268
276
  Minimum number of drops to consider a timestep.
269
277
  - ``neighbor_min_size`` : int
270
278
  Minimum cluster size for merging neighboring events.
@@ -317,7 +325,7 @@ def _map_files_to_blocks(files_start_time, files_end_time, filepaths, block_star
317
325
  # Create a list with the a dictionary for each block
318
326
  filepaths = np.array(filepaths)
319
327
  results = []
320
- for i, (start, end) in enumerate(zip(block_starts, block_ends)):
328
+ for i, (start, end) in enumerate(zip(block_starts, block_ends, strict=True)):
321
329
  indices = np.where(mask[:, i])[0]
322
330
  if indices.size > 0:
323
331
  results.append(
disdrodb/utils/attrs.py CHANGED
@@ -1,7 +1,5 @@
1
- #!/usr/bin/env python3
2
-
3
1
  # -----------------------------------------------------------------------------.
4
- # Copyright (c) 2021-2023 DISDRODB developers
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,9 +15,10 @@
17
15
  # along with this program. If not, see <http://www.gnu.org/licenses/>.
18
16
  # -----------------------------------------------------------------------------.
19
17
  """DISDRODB netCDF4 attributes utilities."""
20
- import datetime
18
+
21
19
  import os
22
20
 
21
+ from disdrodb.api.checks import get_current_utc_time
23
22
  from disdrodb.constants import ARCHIVE_VERSION, CONVENTIONS, COORDINATES, SOFTWARE_VERSION
24
23
  from disdrodb.utils.yaml import read_yaml
25
24
 
@@ -95,15 +94,18 @@ def update_disdrodb_attrs(ds, product: str):
95
94
  # ----------------------------------------------
96
95
  # Add time_coverage_start and time_coverage_end
97
96
  if "time" in ds.dims:
97
+ encoding = ds["time"].encoding
98
98
  ds["time"] = ds["time"].dt.floor("s") # ensure no sub-second values
99
99
  ds["time"] = ds["time"].astype("datetime64[s]")
100
+ ds["time"].encoding = encoding # otherwise time encoding get lost !
101
+
100
102
  attrs["time_coverage_start"] = str(ds["time"].data[0])
101
103
  attrs["time_coverage_end"] = str(ds["time"].data[-1])
102
104
 
103
105
  # ----------------------------------------------
104
106
  # Set DISDRODDB attributes
105
107
  # - Add DISDRODB processing info
106
- now = datetime.datetime.utcnow()
108
+ now = get_current_utc_time()
107
109
  current_time = now.strftime("%Y-%m-%d %H:%M:%S")
108
110
  attrs["disdrodb_processing_date"] = current_time
109
111
  # - Add DISDRODB product and version