disdrodb 0.2.0__py3-none-any.whl → 0.3.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 (315) hide show
  1. disdrodb/__init__.py +1 -1
  2. disdrodb/_config.py +1 -3
  3. disdrodb/_version.py +2 -2
  4. disdrodb/accessor/__init__.py +1 -1
  5. disdrodb/accessor/methods.py +18 -11
  6. disdrodb/api/checks.py +2 -4
  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 +15 -9
  11. disdrodb/api/path.py +1 -3
  12. disdrodb/cli/disdrodb_check_metadata_archive.py +2 -2
  13. disdrodb/cli/disdrodb_check_products_options.py +44 -0
  14. disdrodb/cli/disdrodb_create_summary.py +48 -22
  15. disdrodb/cli/disdrodb_create_summary_station.py +39 -18
  16. disdrodb/cli/disdrodb_data_archive_directory.py +1 -3
  17. disdrodb/cli/disdrodb_download_archive.py +45 -24
  18. disdrodb/cli/disdrodb_download_metadata_archive.py +27 -16
  19. disdrodb/cli/disdrodb_download_station.py +56 -26
  20. disdrodb/cli/disdrodb_initialize_station.py +40 -20
  21. disdrodb/cli/disdrodb_metadata_archive_directory.py +1 -3
  22. disdrodb/cli/disdrodb_open_data_archive.py +16 -11
  23. disdrodb/cli/disdrodb_open_logs_directory.py +29 -18
  24. disdrodb/cli/disdrodb_open_metadata_archive.py +25 -11
  25. disdrodb/cli/disdrodb_open_metadata_directory.py +32 -20
  26. disdrodb/cli/disdrodb_open_product_directory.py +38 -21
  27. disdrodb/cli/disdrodb_open_readers_directory.py +1 -3
  28. disdrodb/cli/disdrodb_run.py +189 -0
  29. disdrodb/cli/disdrodb_run_l0.py +55 -64
  30. disdrodb/cli/disdrodb_run_l0_station.py +47 -52
  31. disdrodb/cli/disdrodb_run_l0a.py +47 -45
  32. disdrodb/cli/disdrodb_run_l0a_station.py +38 -37
  33. disdrodb/cli/disdrodb_run_l0b.py +45 -45
  34. disdrodb/cli/disdrodb_run_l0b_station.py +37 -36
  35. disdrodb/cli/disdrodb_run_l0c.py +50 -47
  36. disdrodb/cli/disdrodb_run_l0c_station.py +41 -38
  37. disdrodb/cli/disdrodb_run_l1.py +49 -45
  38. disdrodb/cli/disdrodb_run_l1_station.py +40 -37
  39. disdrodb/cli/disdrodb_run_l2e.py +50 -45
  40. disdrodb/cli/disdrodb_run_l2e_station.py +41 -37
  41. disdrodb/cli/disdrodb_run_l2m.py +49 -45
  42. disdrodb/cli/disdrodb_run_l2m_station.py +40 -37
  43. disdrodb/cli/disdrodb_run_station.py +184 -0
  44. disdrodb/cli/disdrodb_upload_archive.py +45 -35
  45. disdrodb/cli/disdrodb_upload_station.py +39 -32
  46. disdrodb/configs.py +13 -8
  47. disdrodb/constants.py +4 -2
  48. disdrodb/data_transfer/__init__.py +1 -3
  49. disdrodb/data_transfer/download_data.py +38 -54
  50. disdrodb/data_transfer/upload_data.py +1 -3
  51. disdrodb/data_transfer/zenodo.py +1 -3
  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 +1 -14
  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 +17 -3
  74. disdrodb/etc/products/L2M/global.yaml +1 -1
  75. disdrodb/fall_velocity/__init__.py +46 -0
  76. disdrodb/fall_velocity/graupel.py +483 -0
  77. disdrodb/fall_velocity/hail.py +287 -0
  78. disdrodb/{l1/fall_velocity.py → fall_velocity/rain.py} +265 -50
  79. disdrodb/issue/__init__.py +1 -3
  80. disdrodb/issue/checks.py +3 -5
  81. disdrodb/issue/reader.py +1 -3
  82. disdrodb/issue/writer.py +1 -3
  83. disdrodb/l0/__init__.py +1 -1
  84. disdrodb/l0/check_configs.py +26 -17
  85. disdrodb/l0/check_standards.py +1 -3
  86. disdrodb/l0/configs/LPM/l0a_encodings.yml +0 -1
  87. disdrodb/l0/configs/LPM/l0b_cf_attrs.yml +0 -4
  88. disdrodb/l0/configs/LPM/l0b_encodings.yml +9 -9
  89. disdrodb/l0/configs/LPM/raw_data_format.yml +11 -11
  90. disdrodb/l0/configs/LPM_V0/bins_diameter.yml +103 -0
  91. disdrodb/l0/configs/LPM_V0/bins_velocity.yml +103 -0
  92. disdrodb/l0/configs/LPM_V0/l0a_encodings.yml +45 -0
  93. disdrodb/l0/configs/LPM_V0/l0b_cf_attrs.yml +180 -0
  94. disdrodb/l0/configs/LPM_V0/l0b_encodings.yml +410 -0
  95. disdrodb/l0/configs/LPM_V0/raw_data_format.yml +474 -0
  96. disdrodb/l0/configs/ODM470/bins_diameter.yml +643 -0
  97. disdrodb/l0/configs/ODM470/bins_velocity.yml +0 -0
  98. disdrodb/l0/configs/ODM470/l0a_encodings.yml +11 -0
  99. disdrodb/l0/configs/ODM470/l0b_cf_attrs.yml +46 -0
  100. disdrodb/l0/configs/ODM470/l0b_encodings.yml +106 -0
  101. disdrodb/l0/configs/ODM470/raw_data_format.yml +111 -0
  102. disdrodb/l0/configs/PARSIVEL/l0b_cf_attrs.yml +1 -1
  103. disdrodb/l0/configs/PARSIVEL/raw_data_format.yml +8 -8
  104. disdrodb/l0/configs/PARSIVEL2/raw_data_format.yml +9 -9
  105. disdrodb/l0/l0_reader.py +1 -3
  106. disdrodb/l0/l0a_processing.py +7 -5
  107. disdrodb/l0/l0b_nc_processing.py +2 -4
  108. disdrodb/l0/l0b_processing.py +27 -22
  109. disdrodb/l0/l0c_processing.py +37 -11
  110. disdrodb/l0/manuals/LPM_V0.pdf +0 -0
  111. disdrodb/l0/readers/LPM/ARM/ARM_LPM.py +1 -1
  112. disdrodb/l0/readers/LPM/AUSTRALIA/MELBOURNE_2007_LPM.py +1 -1
  113. disdrodb/l0/readers/LPM/BRAZIL/CHUVA_LPM.py +1 -1
  114. disdrodb/l0/readers/LPM/BRAZIL/GOAMAZON_LPM.py +1 -1
  115. disdrodb/l0/readers/LPM/GERMANY/DWD.py +190 -12
  116. disdrodb/l0/readers/LPM/ITALY/GID_LPM.py +63 -14
  117. disdrodb/l0/readers/LPM/ITALY/GID_LPM_PI.py +279 -0
  118. disdrodb/l0/readers/LPM/ITALY/GID_LPM_T.py +279 -0
  119. disdrodb/l0/readers/LPM/ITALY/GID_LPM_W.py +3 -5
  120. disdrodb/l0/readers/LPM/KIT/CHWALA.py +1 -3
  121. disdrodb/l0/readers/LPM/NETHERLANDS/DELFT_LPM_NC.py +1 -1
  122. disdrodb/l0/readers/LPM/NETHERLANDS/DELFT_RWANDA_LPM_NC.py +103 -0
  123. disdrodb/l0/readers/LPM/NORWAY/HAUKELISETER_LPM.py +214 -0
  124. disdrodb/l0/readers/LPM/NORWAY/NMBU_LPM.py +206 -0
  125. disdrodb/l0/readers/LPM/SLOVENIA/ARSO.py +1 -3
  126. disdrodb/l0/readers/LPM/SLOVENIA/UL.py +1 -3
  127. disdrodb/l0/readers/LPM/SWITZERLAND/INNERERIZ_LPM.py +1 -3
  128. disdrodb/l0/readers/LPM/UK/DIVEN.py +1 -1
  129. disdrodb/l0/readers/LPM/UK/WITHWORTH_LPM.py +217 -0
  130. disdrodb/l0/readers/LPM/USA/CHARLESTON.py +227 -0
  131. disdrodb/l0/readers/{LPM → LPM_V0}/BELGIUM/ULIEGE.py +34 -52
  132. disdrodb/l0/readers/LPM_V0/ITALY/GID_LPM_V0.py +240 -0
  133. disdrodb/l0/readers/ODM470/OCEAN/OCEANRAIN.py +123 -0
  134. disdrodb/l0/readers/PARSIVEL/AUSTRALIA/MELBOURNE_2007_PARSIVEL.py +1 -1
  135. disdrodb/l0/readers/PARSIVEL/BASQUECOUNTRY/EUSKALMET_OTT.py +1 -1
  136. disdrodb/l0/readers/PARSIVEL/CHINA/CHONGQING.py +1 -3
  137. disdrodb/l0/readers/PARSIVEL/EPFL/ARCTIC_2021.py +1 -1
  138. disdrodb/l0/readers/PARSIVEL/EPFL/COMMON_2011.py +1 -1
  139. disdrodb/l0/readers/PARSIVEL/EPFL/DAVOS_2009_2011.py +1 -1
  140. disdrodb/l0/readers/PARSIVEL/EPFL/EPFL_2009.py +1 -1
  141. disdrodb/l0/readers/PARSIVEL/EPFL/EPFL_ROOF_2008.py +1 -1
  142. disdrodb/l0/readers/PARSIVEL/EPFL/EPFL_ROOF_2010.py +1 -1
  143. disdrodb/l0/readers/PARSIVEL/EPFL/EPFL_ROOF_2011.py +1 -1
  144. disdrodb/l0/readers/PARSIVEL/EPFL/EPFL_ROOF_2012.py +1 -1
  145. disdrodb/l0/readers/PARSIVEL/EPFL/GENEPI_2007.py +1 -1
  146. disdrodb/l0/readers/PARSIVEL/EPFL/GRAND_ST_BERNARD_2007.py +1 -1
  147. disdrodb/l0/readers/PARSIVEL/EPFL/GRAND_ST_BERNARD_2007_2.py +1 -1
  148. disdrodb/l0/readers/PARSIVEL/EPFL/HPICONET_2010.py +1 -1
  149. disdrodb/l0/readers/PARSIVEL/EPFL/HYMEX_LTE_SOP2.py +1 -1
  150. disdrodb/l0/readers/PARSIVEL/EPFL/HYMEX_LTE_SOP3.py +1 -1
  151. disdrodb/l0/readers/PARSIVEL/EPFL/HYMEX_LTE_SOP4.py +1 -1
  152. disdrodb/l0/readers/PARSIVEL/EPFL/LOCARNO_2018.py +1 -1
  153. disdrodb/l0/readers/PARSIVEL/EPFL/LOCARNO_2019.py +1 -1
  154. disdrodb/l0/readers/PARSIVEL/EPFL/PARADISO_2014.py +1 -1
  155. disdrodb/l0/readers/PARSIVEL/EPFL/PARSIVEL_2007.py +1 -1
  156. disdrodb/l0/readers/PARSIVEL/EPFL/PLATO_2019.py +1 -1
  157. disdrodb/l0/readers/PARSIVEL/EPFL/RACLETS_2019.py +1 -1
  158. disdrodb/l0/readers/PARSIVEL/EPFL/RACLETS_2019_WJF.py +1 -1
  159. disdrodb/l0/readers/PARSIVEL/EPFL/RIETHOLZBACH_2011.py +1 -1
  160. disdrodb/l0/readers/PARSIVEL/EPFL/SAMOYLOV_2017.py +1 -1
  161. disdrodb/l0/readers/PARSIVEL/EPFL/SAMOYLOV_2019.py +1 -1
  162. disdrodb/l0/readers/PARSIVEL/EPFL/UNIL_2022.py +1 -1
  163. disdrodb/l0/readers/PARSIVEL/JAPAN/JMA.py +1 -1
  164. disdrodb/l0/readers/PARSIVEL/KOREA/ICEPOP_MSC.py +159 -0
  165. disdrodb/l0/readers/PARSIVEL/NASA/LPVEX.py +26 -14
  166. disdrodb/l0/readers/PARSIVEL/NASA/MC3E.py +2 -2
  167. disdrodb/l0/readers/PARSIVEL/NCAR/CCOPE_2015.py +1 -1
  168. disdrodb/l0/readers/PARSIVEL/NCAR/OWLES_MIPS.py +1 -1
  169. disdrodb/l0/readers/PARSIVEL/NCAR/PECAN_MOBILE.py +1 -1
  170. disdrodb/l0/readers/PARSIVEL/NCAR/PLOWS_MIPS.py +1 -1
  171. disdrodb/l0/readers/PARSIVEL/NCAR/VORTEX2_2009.py +1 -1
  172. disdrodb/l0/readers/PARSIVEL/NCAR/VORTEX2_2010.py +1 -3
  173. disdrodb/l0/readers/PARSIVEL/NCAR/VORTEX2_2010_UF.py +1 -3
  174. disdrodb/l0/readers/PARSIVEL/SLOVENIA/UL.py +1 -1
  175. disdrodb/l0/readers/PARSIVEL2/ARM/ARM_PARSIVEL2.py +1 -1
  176. disdrodb/l0/readers/PARSIVEL2/BASQUECOUNTRY/EUSKALMET_OTT2.py +2 -2
  177. disdrodb/l0/readers/PARSIVEL2/BELGIUM/ILVO.py +1 -3
  178. disdrodb/l0/readers/PARSIVEL2/BRAZIL/CHUVA_PARSIVEL2.py +1 -1
  179. disdrodb/l0/readers/PARSIVEL2/BRAZIL/GOAMAZON_PARSIVEL2.py +1 -1
  180. disdrodb/l0/readers/PARSIVEL2/CANADA/UQAM_NC.py +1 -1
  181. disdrodb/l0/readers/PARSIVEL2/DENMARK/DTU.py +1 -1
  182. disdrodb/l0/readers/PARSIVEL2/DENMARK/EROSION_nc.py +1 -1
  183. disdrodb/l0/readers/PARSIVEL2/DENMARK/EROSION_raw.py +1 -1
  184. disdrodb/l0/readers/PARSIVEL2/FINLAND/FMI_PARSIVEL2.py +1 -1
  185. disdrodb/l0/readers/PARSIVEL2/FRANCE/ENPC_PARSIVEL2.py +1 -3
  186. disdrodb/l0/readers/PARSIVEL2/FRANCE/OSUG.py +1 -1
  187. disdrodb/l0/readers/PARSIVEL2/FRANCE/SIRTA_PARSIVEL2.py +1 -3
  188. disdrodb/l0/readers/PARSIVEL2/GREECE/NOA.py +4 -3
  189. disdrodb/l0/readers/PARSIVEL2/ITALY/GID_PARSIVEL2.py +1 -3
  190. disdrodb/l0/readers/PARSIVEL2/ITALY/HYDROX.py +5 -3
  191. disdrodb/l0/readers/PARSIVEL2/JAPAN/PRECIP.py +155 -0
  192. disdrodb/l0/readers/PARSIVEL2/KIT/BURKINA_FASO.py +1 -1
  193. disdrodb/l0/readers/PARSIVEL2/KIT/TEAMX.py +1 -1
  194. disdrodb/l0/readers/PARSIVEL2/KOREA/ICEPOP_MSC.py +161 -0
  195. disdrodb/l0/readers/PARSIVEL2/{NASA/GCPEX.py → KOREA/ICEPOP_UCLM.py} +51 -31
  196. disdrodb/l0/readers/PARSIVEL2/MEXICO/OH_IIUNAM_nc.py +1 -1
  197. disdrodb/l0/readers/PARSIVEL2/MPI/BCO_PARSIVEL2.py +15 -8
  198. disdrodb/l0/readers/PARSIVEL2/MPI/BOWTIE.py +9 -4
  199. disdrodb/l0/readers/PARSIVEL2/NASA/APU.py +31 -6
  200. disdrodb/l0/readers/PARSIVEL2/NASA/NSSTC.py +1 -1
  201. disdrodb/l0/readers/PARSIVEL2/NCAR/FARM_PARSIVEL2.py +1 -1
  202. disdrodb/l0/readers/PARSIVEL2/NCAR/PECAN_FP3.py +1 -1
  203. disdrodb/l0/readers/PARSIVEL2/NCAR/PECAN_MIPS.py +1 -1
  204. disdrodb/l0/readers/PARSIVEL2/NCAR/PERILS_MIPS.py +1 -1
  205. disdrodb/l0/readers/PARSIVEL2/NCAR/PERILS_PIPS.py +1 -1
  206. disdrodb/l0/readers/PARSIVEL2/NCAR/RELAMPAGO_PARSIVEL2.py +2 -2
  207. disdrodb/l0/readers/PARSIVEL2/NCAR/SNOWIE_PJ.py +1 -1
  208. disdrodb/l0/readers/PARSIVEL2/NCAR/SNOWIE_SB.py +1 -1
  209. disdrodb/l0/readers/PARSIVEL2/NCAR/VORTEX_SE_2016_P1.py +1 -3
  210. disdrodb/l0/readers/PARSIVEL2/NCAR/VORTEX_SE_2016_P2.py +1 -1
  211. disdrodb/l0/readers/PARSIVEL2/NCAR/VORTEX_SE_2016_PIPS.py +1 -1
  212. disdrodb/l0/readers/PARSIVEL2/NETHERLANDS/DELFT_NC.py +1 -1
  213. disdrodb/l0/readers/{PARSIVEL/NASA/PIERS.py → PARSIVEL2/NORWAY/UIB.py} +65 -31
  214. disdrodb/l0/readers/PARSIVEL2/PHILIPPINES/PAGASA.py +7 -6
  215. disdrodb/l0/readers/PARSIVEL2/SPAIN/CENER.py +1 -1
  216. disdrodb/l0/readers/PARSIVEL2/SPAIN/CR1000DL.py +1 -1
  217. disdrodb/l0/readers/PARSIVEL2/SPAIN/GRANADA.py +1 -3
  218. disdrodb/l0/readers/PARSIVEL2/SPAIN/LIAISE.py +1 -1
  219. disdrodb/l0/readers/PARSIVEL2/SWEDEN/SMHI.py +1 -1
  220. disdrodb/l0/readers/PARSIVEL2/USA/CSU.py +138 -0
  221. disdrodb/l0/readers/PARSIVEL2/USA/CW3E.py +49 -22
  222. disdrodb/l0/readers/PWS100/AUSTRIA/HOAL.py +1 -3
  223. disdrodb/l0/readers/PWS100/FRANCE/ENPC_PWS100.py +1 -3
  224. disdrodb/l0/readers/PWS100/FRANCE/ENPC_PWS100_SIRTA.py +1 -1
  225. disdrodb/l0/readers/{PARSIVEL/NASA/IFLOODS.py → RD80/BRAZIL/ATTO_RD80.py} +50 -36
  226. disdrodb/l0/readers/RD80/BRAZIL/CHUVA_RD80.py +1 -3
  227. disdrodb/l0/readers/RD80/BRAZIL/GOAMAZON_RD80.py +1 -3
  228. disdrodb/l0/readers/RD80/NCAR/CINDY_2011_RD80.py +1 -3
  229. disdrodb/l0/readers/RD80/NCAR/RELAMPAGO_RD80.py +1 -3
  230. disdrodb/l0/readers/RD80/NOAA/PSL_RD80.py +1 -3
  231. disdrodb/l0/readers/{SW250 → SWS250}/BELGIUM/KMI.py +2 -4
  232. disdrodb/l0/readers/template_reader_raw_netcdf_data.py +1 -3
  233. disdrodb/l0/readers/template_reader_raw_text_data.py +1 -3
  234. disdrodb/l0/standards.py +4 -5
  235. disdrodb/l0/template_tools.py +1 -3
  236. disdrodb/l1/__init__.py +1 -1
  237. disdrodb/l1/classification.py +913 -0
  238. disdrodb/l1/processing.py +36 -106
  239. disdrodb/l1/resampling.py +8 -3
  240. disdrodb/l1_env/__init__.py +1 -1
  241. disdrodb/l1_env/routines.py +6 -6
  242. disdrodb/l2/__init__.py +1 -1
  243. disdrodb/l2/empirical_dsd.py +61 -31
  244. disdrodb/l2/processing.py +327 -62
  245. disdrodb/metadata/checks.py +1 -3
  246. disdrodb/metadata/download.py +4 -4
  247. disdrodb/metadata/geolocation.py +1 -3
  248. disdrodb/metadata/info.py +1 -3
  249. disdrodb/metadata/manipulation.py +1 -3
  250. disdrodb/metadata/reader.py +1 -3
  251. disdrodb/metadata/search.py +1 -3
  252. disdrodb/metadata/standards.py +1 -3
  253. disdrodb/metadata/writer.py +1 -3
  254. disdrodb/physics/__init__.py +17 -0
  255. disdrodb/physics/atmosphere.py +272 -0
  256. disdrodb/physics/water.py +130 -0
  257. disdrodb/physics/wrappers.py +62 -0
  258. disdrodb/psd/__init__.py +1 -1
  259. disdrodb/psd/fitting.py +22 -9
  260. disdrodb/psd/models.py +1 -1
  261. disdrodb/routines/__init__.py +5 -1
  262. disdrodb/routines/l0.py +28 -18
  263. disdrodb/routines/l1.py +8 -6
  264. disdrodb/routines/l2.py +8 -4
  265. disdrodb/routines/options.py +116 -71
  266. disdrodb/routines/options_validation.py +728 -0
  267. disdrodb/routines/wrappers.py +431 -11
  268. disdrodb/scattering/__init__.py +1 -1
  269. disdrodb/scattering/axis_ratio.py +9 -6
  270. disdrodb/scattering/permittivity.py +8 -8
  271. disdrodb/scattering/routines.py +32 -14
  272. disdrodb/summary/__init__.py +1 -1
  273. disdrodb/summary/routines.py +146 -86
  274. disdrodb/utils/__init__.py +1 -1
  275. disdrodb/utils/archiving.py +16 -9
  276. disdrodb/utils/attrs.py +4 -3
  277. disdrodb/utils/cli.py +8 -10
  278. disdrodb/utils/compression.py +13 -13
  279. disdrodb/utils/dask.py +33 -14
  280. disdrodb/utils/dataframe.py +1 -3
  281. disdrodb/utils/decorators.py +1 -3
  282. disdrodb/utils/dict.py +1 -1
  283. disdrodb/utils/directories.py +3 -5
  284. disdrodb/utils/encoding.py +2 -4
  285. disdrodb/utils/event.py +1 -1
  286. disdrodb/utils/list.py +1 -3
  287. disdrodb/utils/logger.py +1 -3
  288. disdrodb/utils/manipulations.py +182 -6
  289. disdrodb/utils/pydantic.py +80 -0
  290. disdrodb/utils/routines.py +1 -3
  291. disdrodb/utils/subsetting.py +1 -1
  292. disdrodb/utils/time.py +3 -2
  293. disdrodb/utils/warnings.py +1 -3
  294. disdrodb/utils/writer.py +1 -3
  295. disdrodb/utils/xarray.py +30 -3
  296. disdrodb/utils/yaml.py +1 -3
  297. disdrodb/viz/__init__.py +1 -1
  298. disdrodb/viz/plots.py +197 -21
  299. {disdrodb-0.2.0.dist-info → disdrodb-0.3.0.dist-info}/METADATA +2 -2
  300. disdrodb-0.3.0.dist-info/RECORD +358 -0
  301. {disdrodb-0.2.0.dist-info → disdrodb-0.3.0.dist-info}/entry_points.txt +3 -0
  302. disdrodb/etc/products/L1/1MIN.yaml +0 -13
  303. disdrodb/etc/products/L1/LPM/1MIN.yaml +0 -13
  304. disdrodb/etc/products/L1/PARSIVEL/1MIN.yaml +0 -13
  305. disdrodb/etc/products/L1/PARSIVEL2/1MIN.yaml +0 -13
  306. disdrodb/etc/products/L1/PWS100/1MIN.yaml +0 -13
  307. disdrodb/etc/products/L1/RD80/1MIN.yaml +0 -13
  308. disdrodb/etc/products/L1/SWS250/1MIN.yaml +0 -13
  309. disdrodb/etc/products/L2M/10MIN.yaml +0 -12
  310. disdrodb/l1/beard_model.py +0 -618
  311. disdrodb/l1/filters.py +0 -203
  312. disdrodb-0.2.0.dist-info/RECORD +0 -312
  313. {disdrodb-0.2.0.dist-info → disdrodb-0.3.0.dist-info}/WHEEL +0 -0
  314. {disdrodb-0.2.0.dist-info → disdrodb-0.3.0.dist-info}/licenses/LICENSE +0 -0
  315. {disdrodb-0.2.0.dist-info → disdrodb-0.3.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
  # 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,15 +75,26 @@ 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)):
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):
@@ -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):
@@ -973,7 +991,7 @@ def get_radar_parameters(
973
991
  list_ds = [func(ds_subset, **params) for params in list_params]
974
992
 
975
993
  # Merge into a single dataset
976
- ds_radar = xr.merge(list_ds)
994
+ ds_radar = xr.merge(list_ds, compat="no_conflicts", join="outer")
977
995
 
978
996
  # Order frequency from lowest to highest
979
997
  # --> ['S', 'C', 'X', 'Ku', 'K', 'Ka', 'W']
@@ -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
@@ -223,6 +223,11 @@ def create_table_rain_summary(df, temporal_resolution):
223
223
  table["n_minutes_Dmax_>7"] = np.sum(df["Dmax"] > 7).item() * accumulation_interval_minutes
224
224
  table["n_minutes_Dmax_>8"] = np.sum(df["Dmax"] > 8).item() * accumulation_interval_minutes
225
225
  table["n_minutes_Dmax_>9"] = np.sum(df["Dmax"] > 9).item() * accumulation_interval_minutes
226
+
227
+ # Convert all minutes columns to integer
228
+ for key in table:
229
+ if "minutes" in key:
230
+ table[key] = int(table[key])
226
231
  return table
227
232
 
228
233
 
@@ -233,7 +238,7 @@ def create_table_dsd_summary(df):
233
238
  df["log10(Nt)"] = np.log10(df["Nt"])
234
239
 
235
240
  # List of variables to summarize
236
- variables = ["W", "R", "Z", "D50", "Dm", "sigma_m", "Dmax", "Nw", "log10(Nw)", "Nt", "log10(Nt)"]
241
+ variables = ["LWC", "R", "Z", "D50", "Dm", "sigma_m", "Dmax", "Nw", "log10(Nw)", "Nt", "log10(Nt)"]
237
242
 
238
243
  # Define subset dataframe
239
244
  df_subset = df[variables]
@@ -356,9 +361,9 @@ def create_table_events_summary(df, temporal_resolution):
356
361
  "mean_sigma_m": df_event["sigma_m"].mean(),
357
362
  "median_sigma_m": df_event["sigma_m"].median(),
358
363
  "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(),
364
+ "mean_LWC": df_event["LWC"].mean(),
365
+ "median_LWC": df_event["LWC"].median(),
366
+ "max_LWC": df_event["LWC"].max(),
362
367
  "max_Z": df_event["Z"].max(),
363
368
  "mean_Nbins": int(df_event["Nbins"].mean()),
364
369
  "max_Nbins": int(df_event["Nbins"].max()),
@@ -371,9 +376,22 @@ def create_table_events_summary(df, temporal_resolution):
371
376
 
372
377
  df_events = pd.DataFrame.from_records(events_stats)
373
378
 
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)
379
+ # Round and cast columns
380
+ # - Round to 3 decimals
381
+ df_events["P_total"] = df_events["P_total"].round(decimals=3)
382
+
383
+ lwc_columns = [c for c in df_events.columns if "LWC" in c]
384
+ df_events[lwc_columns] = df_events[lwc_columns].round(decimals=3)
385
+
386
+ # - Cast to integer
387
+ df_events["duration"] = df_events["duration"].astype(int)
388
+ minutes_columns = [c for c in df_events.columns if "minutes" in c]
389
+ df_events[minutes_columns] = df_events[minutes_columns].astype(int)
390
+
391
+ # - Round to 2 decimals
392
+ for var in ["Dmax", "Dm", "sigma_m", "R", "Z"]:
393
+ names = [c for c in df_events.columns if var in c]
394
+ df_events[names] = df_events[names].round(decimals=2)
377
395
  return df_events
378
396
 
379
397
 
@@ -385,7 +403,7 @@ def prepare_latex_table_dsd_summary(df):
385
403
  df[numeric_cols] = df[numeric_cols].astype(str)
386
404
  # Rename
387
405
  rename_dict = {
388
- "W": r"$W\,[\mathrm{g}\,\mathrm{m}^{-3}]$", # [g/m3]
406
+ "LWC": r"$LWC\,[\mathrm{g}\,\mathrm{m}^{-3}]$", # [g/m3]
389
407
  "R": r"$R\,[\mathrm{mm}\,\mathrm{h}^{-1}]$", # [mm/hr]
390
408
  "Z": r"$Z\,[\mathrm{dBZ}]$", # [dBZ]
391
409
  "D50": r"$D_{50}\,[\mathrm{mm}]$", # [mm]
@@ -433,9 +451,9 @@ def prepare_latex_table_events_summary(df):
433
451
  "mean_sigma_m": r"$\sigma_{m,\mathrm{mean}}$",
434
452
  "median_sigma_m": r"$\sigma_{m,\mathrm{median}}$",
435
453
  "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}$",
454
+ "mean_LWC": r"$LWC_{\mathrm{mean}}$",
455
+ "median_LWC": r"$LWC_{\mathrm{median}}$",
456
+ "max_LWC": r"$LWC_{\max}$",
439
457
  "max_Z": r"$Z_{\max}$",
440
458
  "mean_Nbins": r"$N_{\mathrm{bins},\mathrm{mean}}$",
441
459
  "max_Nbins": r"$N_{\mathrm{bins},\max}$",
@@ -716,7 +734,7 @@ def create_nd_dataframe(ds, variables=None):
716
734
  "sample_interval",
717
735
  *RADAR_OPTIONS,
718
736
  ]
719
- df_nd = ds_stack.to_dataframe().drop(columns=coords_to_drop, errors="ignore")
737
+ df_nd = ds_stack.to_dask_dataframe().drop(columns=coords_to_drop, errors="ignore").compute()
720
738
  df_nd["D"] = df_nd["diameter_bin_center"]
721
739
  df_nd["N(D)"] = df_nd["drop_number_concentration"]
722
740
  df_nd = df_nd[df_nd["R"] != 0]
@@ -918,7 +936,7 @@ def plot_dsd_params_relationships(df, add_nt=False, dpi=300):
918
936
  df,
919
937
  x="Dm",
920
938
  y="Nw",
921
- variables=["R", "W", "Nt"],
939
+ variables=["R", "LWC", "Nt"],
922
940
  x_bins=np.arange(0, 8, 0.1),
923
941
  y_bins=log_arange(10, 1_000_000, log_step=0.05, base=10),
924
942
  )
@@ -927,7 +945,7 @@ def plot_dsd_params_relationships(df, add_nt=False, dpi=300):
927
945
  ds_Dm_LWC_stats = compute_2d_histogram(
928
946
  df,
929
947
  x="Dm",
930
- y="W",
948
+ y="LWC",
931
949
  variables=["R", "Nw", "Nt"],
932
950
  x_bins=np.arange(0, 8, 0.1),
933
951
  y_bins=log_arange(0.01, 10, log_step=0.05, base=10),
@@ -938,7 +956,7 @@ def plot_dsd_params_relationships(df, add_nt=False, dpi=300):
938
956
  df,
939
957
  x="Dm",
940
958
  y="R",
941
- variables=["Nw", "W", "Nt"],
959
+ variables=["Nw", "LWC", "Nt"],
942
960
  x_bins=np.arange(0, 8, 0.1),
943
961
  y_bins=log_arange(0.1, 500, log_step=0.05, base=10),
944
962
  )
@@ -948,7 +966,7 @@ def plot_dsd_params_relationships(df, add_nt=False, dpi=300):
948
966
  df,
949
967
  x="Dm",
950
968
  y="Nt",
951
- variables=["R", "W", "Nw"],
969
+ variables=["R", "LWC", "Nw"],
952
970
  x_bins=np.arange(0, 8, 0.1),
953
971
  y_bins=log_arange(1, 100_000, log_step=0.05, base=10),
954
972
  )
@@ -1019,7 +1037,7 @@ def plot_dsd_params_relationships(df, add_nt=False, dpi=300):
1019
1037
  axes[1, 0].set_ylim(nw_lim)
1020
1038
 
1021
1039
  #### - LWC
1022
- im_lwc = ds_Dm_Nw_stats["W_median"].plot.pcolormesh(
1040
+ im_lwc = ds_Dm_Nw_stats["LWC_median"].plot.pcolormesh(
1023
1041
  x="Dm",
1024
1042
  y="Nw",
1025
1043
  cmap=cmap_lwc,
@@ -1067,7 +1085,7 @@ def plot_dsd_params_relationships(df, add_nt=False, dpi=300):
1067
1085
  #### - Counts
1068
1086
  ds_Dm_LWC_stats["count"].plot.pcolormesh(
1069
1087
  x="Dm",
1070
- y="W",
1088
+ y="LWC",
1071
1089
  cmap=cmap_counts,
1072
1090
  norm=norm_counts,
1073
1091
  extend="max",
@@ -1083,7 +1101,7 @@ def plot_dsd_params_relationships(df, add_nt=False, dpi=300):
1083
1101
  # - Empty (diagonal where y-axis is W) - handled above in the loop
1084
1102
  ds_Dm_LWC_stats["R_median"].plot.pcolormesh(
1085
1103
  x="Dm",
1086
- y="W",
1104
+ y="LWC",
1087
1105
  cmap=cmap_r,
1088
1106
  norm=norm_r,
1089
1107
  alpha=0, # fully transparent
@@ -1099,7 +1117,7 @@ def plot_dsd_params_relationships(df, add_nt=False, dpi=300):
1099
1117
  #### - R
1100
1118
  ds_Dm_LWC_stats["R_median"].plot.pcolormesh(
1101
1119
  x="Dm",
1102
- y="W",
1120
+ y="LWC",
1103
1121
  cmap=cmap_r,
1104
1122
  norm=norm_r,
1105
1123
  extend="both",
@@ -1114,7 +1132,7 @@ def plot_dsd_params_relationships(df, add_nt=False, dpi=300):
1114
1132
  #### - Nt
1115
1133
  im_nt = ds_Dm_LWC_stats["Nt_median"].plot.pcolormesh(
1116
1134
  x="Dm",
1117
- y="W",
1135
+ y="LWC",
1118
1136
  cmap=cmap_nt,
1119
1137
  norm=norm_nt,
1120
1138
  extend="both",
@@ -1144,7 +1162,7 @@ def plot_dsd_params_relationships(df, add_nt=False, dpi=300):
1144
1162
  axes[3, 0].set_ylim(r_lim)
1145
1163
 
1146
1164
  #### - LWC
1147
- im_lwc = ds_Dm_R_stats["W_median"].plot.pcolormesh(
1165
+ im_lwc = ds_Dm_R_stats["LWC_median"].plot.pcolormesh(
1148
1166
  x="Dm",
1149
1167
  y="R",
1150
1168
  cmap=cmap_lwc,
@@ -1211,7 +1229,7 @@ def plot_dsd_params_relationships(df, add_nt=False, dpi=300):
1211
1229
  axes[4, 0].set_ylim(nt_lim)
1212
1230
 
1213
1231
  #### - LWC
1214
- ds_Dm_Nt_stats["W_median"].plot.pcolormesh(
1232
+ ds_Dm_Nt_stats["LWC_median"].plot.pcolormesh(
1215
1233
  x="Dm",
1216
1234
  y="Nt",
1217
1235
  cmap=cmap_lwc,
@@ -1336,7 +1354,7 @@ def plot_dsd_params_density(df, log_dm=False, lwc=True, log_normalize=False, fig
1336
1354
  norm = Normalize(0, 1) # Normalized data goes from 0 to 1
1337
1355
 
1338
1356
  # Define the water variable based on lwc flag
1339
- df["LWC"] = df["W"]
1357
+ df["LWC"] = df["LWC"]
1340
1358
  water_var = "LWC" if lwc else "R"
1341
1359
  water_label = "LWC [g/m³]" if lwc else "R [mm/h]"
1342
1360
 
@@ -3742,7 +3760,7 @@ def create_l2_dataframe(ds):
3742
3760
  return df
3743
3761
 
3744
3762
 
3745
- def prepare_summary_dataset(ds, velocity_method="fall_velocity", source="drop_number"):
3763
+ def prepare_summary_dataset(ds, velocity_method="theoretical_velocity", source="drop_number"):
3746
3764
  """Prepare the L2E or L2M dataset to be converted to a dataframe."""
3747
3765
  # Select fall velocity method
3748
3766
  if "velocity_method" in ds.dims:
@@ -3789,70 +3807,72 @@ def generate_station_summary(ds, summary_dir_path, data_source, campaign_name, s
3789
3807
 
3790
3808
  ####---------------------------------------------------------------------.
3791
3809
  #### Create drop spectrum figures and statistics
3792
- # Compute sum of raw and filtered spectrum over time
3793
- raw_drop_number = ds["raw_drop_number"].sum(dim="time")
3794
- drop_number = ds["drop_number"].sum(dim="time")
3795
-
3796
- # Define theoretical and measured average velocity
3797
- theoretical_average_velocity = ds["fall_velocity"].mean(dim="time")
3798
- measured_average_velocity = get_drop_average_velocity(drop_number)
3799
-
3800
- # Save raw and filtered spectrum over time & theoretical and measured average fall velocity
3801
- ds_stats = xr.Dataset()
3802
- ds_stats["raw_drop_number"] = raw_drop_number
3803
- ds_stats["drop_number"] = raw_drop_number
3804
- ds_stats["theoretical_average_velocity"] = theoretical_average_velocity
3805
- ds_stats["measured_average_velocity"] = measured_average_velocity
3806
- filename = define_filename(
3807
- prefix="SpectrumStats",
3808
- extension="nc",
3809
- data_source=data_source,
3810
- campaign_name=campaign_name,
3811
- station_name=station_name,
3812
- temporal_resolution=temporal_resolution,
3813
- )
3814
- ds_stats.to_netcdf(os.path.join(summary_dir_path, filename))
3810
+ if VELOCITY_DIMENSION in ds.dims:
3811
+ # Compute sum of raw and filtered spectrum over time
3812
+ raw_drop_number = ds["raw_drop_number"].sum(dim="time")
3813
+ drop_number = ds["drop_number"].sum(dim="time")
3814
+
3815
+ # Define theoretical and measured average velocity
3816
+ theoretical_average_velocity = ds["fall_velocity"].mean(dim="time")
3817
+ measured_average_velocity = get_drop_average_velocity(drop_number)
3818
+
3819
+ # Save raw and filtered spectrum over time & theoretical and measured average fall velocity
3820
+ ds_stats = xr.Dataset()
3821
+ ds_stats["raw_drop_number"] = raw_drop_number
3822
+ ds_stats["drop_number"] = raw_drop_number
3823
+ ds_stats["theoretical_average_velocity"] = theoretical_average_velocity
3824
+ if measured_average_velocity is not None:
3825
+ ds_stats["measured_average_velocity"] = measured_average_velocity
3826
+ filename = define_filename(
3827
+ prefix="SpectrumStats",
3828
+ extension="nc",
3829
+ data_source=data_source,
3830
+ campaign_name=campaign_name,
3831
+ station_name=station_name,
3832
+ temporal_resolution=temporal_resolution,
3833
+ )
3834
+ ds_stats.to_netcdf(os.path.join(summary_dir_path, filename))
3815
3835
 
3816
- # Create figures with raw and filtered spectrum
3817
- # - Raw
3818
- filename = define_filename(
3819
- prefix="SpectrumRaw",
3820
- extension="png",
3821
- data_source=data_source,
3822
- campaign_name=campaign_name,
3823
- station_name=station_name,
3824
- temporal_resolution=temporal_resolution,
3825
- )
3826
- p = plot_spectrum(raw_drop_number, title="Raw Drop Spectrum")
3827
- p.figure.savefig(os.path.join(summary_dir_path, filename))
3828
- plt.close()
3836
+ # Create figures with raw and filtered spectrum
3837
+ # - Raw
3838
+ filename = define_filename(
3839
+ prefix="SpectrumRaw",
3840
+ extension="png",
3841
+ data_source=data_source,
3842
+ campaign_name=campaign_name,
3843
+ station_name=station_name,
3844
+ temporal_resolution=temporal_resolution,
3845
+ )
3846
+ p = plot_spectrum(raw_drop_number, title="Raw Drop Spectrum")
3847
+ p.figure.savefig(os.path.join(summary_dir_path, filename))
3848
+ plt.close()
3829
3849
 
3830
- # - Filtered
3831
- filename = define_filename(
3832
- prefix="SpectrumFiltered",
3833
- extension="png",
3834
- data_source=data_source,
3835
- campaign_name=campaign_name,
3836
- station_name=station_name,
3837
- temporal_resolution=temporal_resolution,
3838
- )
3839
- p = plot_spectrum(drop_number, title="Filtered Drop Spectrum")
3840
- p.figure.savefig(os.path.join(summary_dir_path, filename))
3841
- plt.close()
3850
+ # - Filtered
3851
+ filename = define_filename(
3852
+ prefix="SpectrumFiltered",
3853
+ extension="png",
3854
+ data_source=data_source,
3855
+ campaign_name=campaign_name,
3856
+ station_name=station_name,
3857
+ temporal_resolution=temporal_resolution,
3858
+ )
3859
+ p = plot_spectrum(drop_number, title="Filtered Drop Spectrum")
3860
+ p.figure.savefig(os.path.join(summary_dir_path, filename))
3861
+ plt.close()
3842
3862
 
3843
- # Create figure comparing raw and filtered spectrum
3844
- filename = define_filename(
3845
- prefix="SpectrumSummary",
3846
- extension="png",
3847
- data_source=data_source,
3848
- campaign_name=campaign_name,
3849
- station_name=station_name,
3850
- temporal_resolution=temporal_resolution,
3851
- )
3863
+ # Create figure comparing raw and filtered spectrum
3864
+ filename = define_filename(
3865
+ prefix="SpectrumSummary",
3866
+ extension="png",
3867
+ data_source=data_source,
3868
+ campaign_name=campaign_name,
3869
+ station_name=station_name,
3870
+ temporal_resolution=temporal_resolution,
3871
+ )
3852
3872
 
3853
- fig = plot_raw_and_filtered_spectra(ds)
3854
- fig.savefig(os.path.join(summary_dir_path, filename))
3855
- plt.close()
3873
+ fig = plot_raw_and_filtered_spectra(ds)
3874
+ fig.savefig(os.path.join(summary_dir_path, filename))
3875
+ plt.close()
3856
3876
 
3857
3877
  ####---------------------------------------------------------------------.
3858
3878
  #### Create L2E dataframe
@@ -3907,6 +3927,7 @@ def generate_station_summary(ds, summary_dir_path, data_source, campaign_name, s
3907
3927
  table_events_summary.to_csv(table_events_summary_csv_filepath)
3908
3928
  # - Save table as pdf
3909
3929
  if is_latex_engine_available():
3930
+ # Sorted by time
3910
3931
  table_events_summary_pdf_filename = table_events_summary_csv_filename.replace(".csv", ".pdf")
3911
3932
  table_events_summary_pdf_filepath = os.path.join(summary_dir_path, table_events_summary_pdf_filename)
3912
3933
  save_table_to_pdf(
@@ -3917,6 +3938,45 @@ def generate_station_summary(ds, summary_dir_path, data_source, campaign_name, s
3917
3938
  orientation="landscape",
3918
3939
  )
3919
3940
 
3941
+ # Sorted by maximum rain intensity
3942
+ table_events_summary = table_events_summary.sort_values(by="max_R", ascending=False)
3943
+ table_events_summary = table_events_summary.reset_index(drop=True)
3944
+ table_events_summary_pdf_filename = define_filename(
3945
+ prefix="Events_Summary_Sorted_By_Rmax",
3946
+ extension="pdf",
3947
+ data_source=data_source,
3948
+ campaign_name=campaign_name,
3949
+ station_name=station_name,
3950
+ temporal_resolution=temporal_resolution,
3951
+ )
3952
+ table_events_summary_pdf_filepath = os.path.join(summary_dir_path, table_events_summary_pdf_filename)
3953
+ save_table_to_pdf(
3954
+ df=prepare_latex_table_events_summary(table_events_summary),
3955
+ filepath=table_events_summary_pdf_filepath,
3956
+ index=True,
3957
+ caption="Events Summary",
3958
+ orientation="landscape",
3959
+ )
3960
+ # Sorted by Ptotal
3961
+ table_events_summary = table_events_summary.sort_values(by="P_total", ascending=False)
3962
+ table_events_summary = table_events_summary.reset_index(drop=True)
3963
+ table_events_summary_pdf_filename = define_filename(
3964
+ prefix="Events_Summary_Sorted_By_Ptot",
3965
+ extension="pdf",
3966
+ data_source=data_source,
3967
+ campaign_name=campaign_name,
3968
+ station_name=station_name,
3969
+ temporal_resolution=temporal_resolution,
3970
+ )
3971
+ table_events_summary_pdf_filepath = os.path.join(summary_dir_path, table_events_summary_pdf_filename)
3972
+ save_table_to_pdf(
3973
+ df=prepare_latex_table_events_summary(table_events_summary),
3974
+ filepath=table_events_summary_pdf_filepath,
3975
+ index=True,
3976
+ caption="Events Summary",
3977
+ orientation="landscape",
3978
+ )
3979
+
3920
3980
  # ---------------------------------------------------------------------.
3921
3981
  #### Create table with integral DSD parameters statistics
3922
3982
  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
@@ -111,17 +111,18 @@ def generate_time_blocks(
111
111
  def identify_events(
112
112
  filepaths,
113
113
  parallel=False,
114
- min_drops=5,
114
+ variable="N",
115
+ detection_threshold=5,
115
116
  neighbor_min_size=2,
116
117
  neighbor_time_interval="5MIN",
117
118
  event_max_time_gap="6H",
118
119
  event_min_duration="5MIN",
119
120
  event_min_size=3,
120
121
  ):
121
- """Return a list of rainy events.
122
+ """Return a list of precipitating events.
122
123
 
123
- Rainy timesteps are defined when N > min_drops.
124
- Any rainy isolated timesteps (based on neighborhood criteria) is removed.
124
+ Precipitating events are defined when 'variable' > detection_threshold.
125
+ Any isolated timesteps with precipitation (based on neighborhood criteria) is removed.
125
126
  Then, consecutive rainy timesteps are grouped into the same event if the time gap between them does not
126
127
  exceed `event_max_time_gap`. Finally, events that do not meet minimum size or duration
127
128
  requirements are filtered out.
@@ -130,6 +131,11 @@ def identify_events(
130
131
  ----------
131
132
  filepaths: list
132
133
  List of L1C file paths.
134
+ variable : str
135
+ Name of the variable to use to apply the event detection.
136
+ The default is "N".
137
+ detection_threshold : int
138
+ Minimum value of 'variable' to consider an event timestep.
133
139
  parallel: bool
134
140
  Whether to load the files in parallel.
135
141
  Set parallel=True only in a multiprocessing environment.
@@ -163,11 +169,11 @@ def identify_events(
163
169
  - "n_timesteps": int, number of valid timesteps in the event
164
170
  """
165
171
  # Open datasets in parallel
166
- ds = open_netcdf_files(filepaths, variables=["time", "N"], parallel=parallel, compute=True)
172
+ ds = open_netcdf_files(filepaths, variables=["time", variable], parallel=parallel, compute=True)
167
173
  # Sort dataset by time
168
174
  ds = ensure_sorted_by_time(ds)
169
175
  # Define candidate timesteps to group into events
170
- idx_valid = ds["N"].to_numpy() > min_drops
176
+ idx_valid = ds[variable].to_numpy() > detection_threshold
171
177
  timesteps = ds["time"].to_numpy()[idx_valid]
172
178
  if "sample_interval" in ds:
173
179
  sample_interval = ds["sample_interval"].compute().item()
@@ -263,8 +269,9 @@ def define_temporal_partitions(filepaths, strategy, parallel, strategy_options):
263
269
  See identify_time_partitions for more information.
264
270
 
265
271
  If ``strategy == 'event'``, supported options are:
266
-
267
- - ``min_drops`` : int
272
+ - ``variable`` : str
273
+ Name of the variable to use to apply the event detection.
274
+ - ``detection_threshold`` : int
268
275
  Minimum number of drops to consider a timestep.
269
276
  - ``neighbor_min_size`` : int
270
277
  Minimum cluster size for merging neighboring events.
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
@@ -95,8 +93,11 @@ def update_disdrodb_attrs(ds, product: str):
95
93
  # ----------------------------------------------
96
94
  # Add time_coverage_start and time_coverage_end
97
95
  if "time" in ds.dims:
96
+ encoding = ds["time"].encoding
98
97
  ds["time"] = ds["time"].dt.floor("s") # ensure no sub-second values
99
98
  ds["time"] = ds["time"].astype("datetime64[s]")
99
+ ds["time"].encoding = encoding # otherwise time encoding get lost !
100
+
100
101
  attrs["time_coverage_start"] = str(ds["time"].data[0])
101
102
  attrs["time_coverage_end"] = str(ds["time"].data[-1])
102
103