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.
Files changed (279) hide show
  1. disdrodb/__init__.py +132 -15
  2. disdrodb/_config.py +4 -2
  3. disdrodb/_version.py +9 -4
  4. disdrodb/api/checks.py +264 -237
  5. disdrodb/api/configs.py +4 -8
  6. disdrodb/api/create_directories.py +235 -290
  7. disdrodb/api/info.py +217 -26
  8. disdrodb/api/io.py +306 -270
  9. disdrodb/api/path.py +597 -173
  10. disdrodb/api/search.py +486 -0
  11. disdrodb/{metadata/scripts → cli}/disdrodb_check_metadata_archive.py +12 -7
  12. disdrodb/{utils/pandas.py → cli/disdrodb_data_archive_directory.py} +9 -18
  13. disdrodb/cli/disdrodb_download_archive.py +86 -0
  14. disdrodb/cli/disdrodb_download_metadata_archive.py +53 -0
  15. disdrodb/cli/disdrodb_download_station.py +84 -0
  16. disdrodb/{api/scripts → cli}/disdrodb_initialize_station.py +22 -10
  17. disdrodb/cli/disdrodb_metadata_archive_directory.py +32 -0
  18. disdrodb/{data_transfer/scripts/disdrodb_download_station.py → cli/disdrodb_open_data_archive.py} +22 -22
  19. disdrodb/cli/disdrodb_open_logs_directory.py +69 -0
  20. disdrodb/{data_transfer/scripts/disdrodb_upload_station.py → cli/disdrodb_open_metadata_archive.py} +22 -24
  21. disdrodb/cli/disdrodb_open_metadata_directory.py +71 -0
  22. disdrodb/cli/disdrodb_open_product_directory.py +74 -0
  23. disdrodb/cli/disdrodb_open_readers_directory.py +32 -0
  24. disdrodb/{l0/scripts → cli}/disdrodb_run_l0.py +38 -31
  25. disdrodb/{l0/scripts → cli}/disdrodb_run_l0_station.py +32 -30
  26. disdrodb/{l0/scripts → cli}/disdrodb_run_l0a.py +30 -21
  27. disdrodb/{l0/scripts → cli}/disdrodb_run_l0a_station.py +24 -33
  28. disdrodb/{l0/scripts → cli}/disdrodb_run_l0b.py +30 -21
  29. disdrodb/{l0/scripts → cli}/disdrodb_run_l0b_station.py +25 -34
  30. disdrodb/cli/disdrodb_run_l0c.py +130 -0
  31. disdrodb/cli/disdrodb_run_l0c_station.py +129 -0
  32. disdrodb/cli/disdrodb_run_l1.py +122 -0
  33. disdrodb/cli/disdrodb_run_l1_station.py +121 -0
  34. disdrodb/cli/disdrodb_run_l2e.py +122 -0
  35. disdrodb/cli/disdrodb_run_l2e_station.py +122 -0
  36. disdrodb/cli/disdrodb_run_l2m.py +122 -0
  37. disdrodb/cli/disdrodb_run_l2m_station.py +122 -0
  38. disdrodb/cli/disdrodb_upload_archive.py +105 -0
  39. disdrodb/cli/disdrodb_upload_station.py +98 -0
  40. disdrodb/configs.py +90 -25
  41. disdrodb/data_transfer/__init__.py +22 -0
  42. disdrodb/data_transfer/download_data.py +87 -90
  43. disdrodb/data_transfer/upload_data.py +64 -37
  44. disdrodb/data_transfer/zenodo.py +15 -18
  45. disdrodb/docs.py +1 -1
  46. disdrodb/issue/__init__.py +17 -4
  47. disdrodb/issue/checks.py +10 -23
  48. disdrodb/issue/reader.py +9 -12
  49. disdrodb/issue/writer.py +14 -17
  50. disdrodb/l0/__init__.py +17 -26
  51. disdrodb/l0/check_configs.py +35 -23
  52. disdrodb/l0/check_standards.py +46 -51
  53. disdrodb/l0/configs/{Thies_LPM → LPM}/bins_diameter.yml +44 -44
  54. disdrodb/l0/configs/{Thies_LPM → LPM}/bins_velocity.yml +40 -40
  55. disdrodb/l0/configs/LPM/l0a_encodings.yml +80 -0
  56. disdrodb/l0/configs/{Thies_LPM → LPM}/l0b_cf_attrs.yml +84 -65
  57. disdrodb/l0/configs/{Thies_LPM → LPM}/l0b_encodings.yml +50 -9
  58. disdrodb/l0/configs/{Thies_LPM → LPM}/raw_data_format.yml +285 -245
  59. disdrodb/l0/configs/{OTT_Parsivel → PARSIVEL}/bins_diameter.yml +66 -66
  60. disdrodb/l0/configs/{OTT_Parsivel → PARSIVEL}/bins_velocity.yml +64 -64
  61. disdrodb/l0/configs/PARSIVEL/l0a_encodings.yml +32 -0
  62. disdrodb/l0/configs/{OTT_Parsivel → PARSIVEL}/l0b_cf_attrs.yml +23 -21
  63. disdrodb/l0/configs/{OTT_Parsivel → PARSIVEL}/l0b_encodings.yml +17 -17
  64. disdrodb/l0/configs/{OTT_Parsivel → PARSIVEL}/raw_data_format.yml +77 -77
  65. disdrodb/l0/configs/{OTT_Parsivel2 → PARSIVEL2}/bins_diameter.yml +64 -64
  66. disdrodb/l0/configs/{OTT_Parsivel2 → PARSIVEL2}/bins_velocity.yml +64 -64
  67. disdrodb/l0/configs/PARSIVEL2/l0a_encodings.yml +39 -0
  68. disdrodb/l0/configs/{OTT_Parsivel2 → PARSIVEL2}/l0b_cf_attrs.yml +28 -26
  69. disdrodb/l0/configs/{OTT_Parsivel2 → PARSIVEL2}/l0b_encodings.yml +20 -20
  70. disdrodb/l0/configs/{OTT_Parsivel2 → PARSIVEL2}/raw_data_format.yml +107 -107
  71. disdrodb/l0/configs/PWS100/bins_diameter.yml +173 -0
  72. disdrodb/l0/configs/PWS100/bins_velocity.yml +173 -0
  73. disdrodb/l0/configs/PWS100/l0a_encodings.yml +19 -0
  74. disdrodb/l0/configs/PWS100/l0b_cf_attrs.yml +76 -0
  75. disdrodb/l0/configs/PWS100/l0b_encodings.yml +176 -0
  76. disdrodb/l0/configs/PWS100/raw_data_format.yml +182 -0
  77. disdrodb/l0/configs/{RD_80 → RD80}/bins_diameter.yml +40 -40
  78. disdrodb/l0/configs/RD80/l0a_encodings.yml +16 -0
  79. disdrodb/l0/configs/{RD_80 → RD80}/l0b_cf_attrs.yml +3 -3
  80. disdrodb/l0/configs/RD80/l0b_encodings.yml +135 -0
  81. disdrodb/l0/configs/{RD_80 → RD80}/raw_data_format.yml +46 -50
  82. disdrodb/l0/l0_reader.py +216 -340
  83. disdrodb/l0/l0a_processing.py +237 -208
  84. disdrodb/l0/l0b_nc_processing.py +227 -80
  85. disdrodb/l0/l0b_processing.py +96 -174
  86. disdrodb/l0/l0c_processing.py +627 -0
  87. disdrodb/l0/readers/{ARM → LPM/ARM}/ARM_LPM.py +36 -58
  88. disdrodb/l0/readers/LPM/AUSTRALIA/MELBOURNE_2007_LPM.py +236 -0
  89. disdrodb/l0/readers/LPM/BRAZIL/CHUVA_LPM.py +185 -0
  90. disdrodb/l0/readers/LPM/BRAZIL/GOAMAZON_LPM.py +185 -0
  91. disdrodb/l0/readers/LPM/ITALY/GID_LPM.py +195 -0
  92. disdrodb/l0/readers/LPM/ITALY/GID_LPM_W.py +210 -0
  93. disdrodb/l0/readers/{BRAZIL/GOAMAZON_LPM.py → LPM/KIT/CHWALA.py} +97 -76
  94. disdrodb/l0/readers/LPM/SLOVENIA/ARSO.py +197 -0
  95. disdrodb/l0/readers/LPM/SLOVENIA/CRNI_VRH.py +197 -0
  96. disdrodb/l0/readers/{UK → LPM/UK}/DIVEN.py +14 -35
  97. disdrodb/l0/readers/PARSIVEL/AUSTRALIA/MELBOURNE_2007_PARSIVEL.py +157 -0
  98. disdrodb/l0/readers/PARSIVEL/CHINA/CHONGQING.py +113 -0
  99. disdrodb/l0/readers/{EPFL → PARSIVEL/EPFL}/ARCTIC_2021.py +40 -57
  100. disdrodb/l0/readers/{EPFL → PARSIVEL/EPFL}/COMMON_2011.py +37 -54
  101. disdrodb/l0/readers/{EPFL → PARSIVEL/EPFL}/DAVOS_2009_2011.py +34 -51
  102. disdrodb/l0/readers/{EPFL → PARSIVEL/EPFL}/EPFL_2009.py +34 -51
  103. disdrodb/l0/readers/{EPFL/PARADISO_2014.py → PARSIVEL/EPFL/EPFL_ROOF_2008.py} +38 -50
  104. disdrodb/l0/readers/PARSIVEL/EPFL/EPFL_ROOF_2010.py +105 -0
  105. disdrodb/l0/readers/{EPFL → PARSIVEL/EPFL}/EPFL_ROOF_2011.py +34 -51
  106. disdrodb/l0/readers/{EPFL → PARSIVEL/EPFL}/EPFL_ROOF_2012.py +33 -51
  107. disdrodb/l0/readers/{EPFL → PARSIVEL/EPFL}/GENEPI_2007.py +25 -44
  108. disdrodb/l0/readers/{EPFL → PARSIVEL/EPFL}/GRAND_ST_BERNARD_2007.py +25 -44
  109. disdrodb/l0/readers/{EPFL → PARSIVEL/EPFL}/GRAND_ST_BERNARD_2007_2.py +25 -44
  110. disdrodb/l0/readers/{EPFL → PARSIVEL/EPFL}/HPICONET_2010.py +34 -51
  111. disdrodb/l0/readers/{EPFL/EPFL_ROOF_2010.py → PARSIVEL/EPFL/HYMEX_LTE_SOP2.py} +37 -50
  112. disdrodb/l0/readers/PARSIVEL/EPFL/HYMEX_LTE_SOP3.py +111 -0
  113. disdrodb/l0/readers/{EPFL → PARSIVEL/EPFL}/HYMEX_LTE_SOP4.py +36 -54
  114. disdrodb/l0/readers/{EPFL → PARSIVEL/EPFL}/LOCARNO_2018.py +34 -52
  115. disdrodb/l0/readers/{EPFL → PARSIVEL/EPFL}/LOCARNO_2019.py +38 -56
  116. disdrodb/l0/readers/PARSIVEL/EPFL/PARADISO_2014.py +105 -0
  117. disdrodb/l0/readers/{EPFL → PARSIVEL/EPFL}/PARSIVEL_2007.py +27 -45
  118. disdrodb/l0/readers/{EPFL → PARSIVEL/EPFL}/PLATO_2019.py +24 -44
  119. disdrodb/l0/readers/PARSIVEL/EPFL/RACLETS_2019.py +140 -0
  120. disdrodb/l0/readers/{EPFL → PARSIVEL/EPFL}/RACLETS_2019_WJF.py +41 -59
  121. disdrodb/l0/readers/{EPFL → PARSIVEL/EPFL}/RIETHOLZBACH_2011.py +34 -51
  122. disdrodb/l0/readers/PARSIVEL/EPFL/SAMOYLOV_2017.py +117 -0
  123. disdrodb/l0/readers/PARSIVEL/EPFL/SAMOYLOV_2019.py +137 -0
  124. disdrodb/l0/readers/{EPFL → PARSIVEL/EPFL}/UNIL_2022.py +42 -55
  125. disdrodb/l0/readers/PARSIVEL/GPM/IFLOODS.py +104 -0
  126. disdrodb/l0/readers/{GPM → PARSIVEL/GPM}/LPVEX.py +29 -48
  127. disdrodb/l0/readers/PARSIVEL/GPM/MC3E.py +184 -0
  128. disdrodb/l0/readers/PARSIVEL/KIT/BURKINA_FASO.py +133 -0
  129. disdrodb/l0/readers/PARSIVEL/NCAR/CCOPE_2015.py +113 -0
  130. disdrodb/l0/readers/{NCAR/VORTEX_SE_2016_P1.py → PARSIVEL/NCAR/OWLES_MIPS.py} +46 -72
  131. disdrodb/l0/readers/PARSIVEL/NCAR/PECAN_MOBILE.py +125 -0
  132. disdrodb/l0/readers/{NCAR/OWLES_MIPS.py → PARSIVEL/NCAR/PLOWS_MIPS.py} +45 -64
  133. disdrodb/l0/readers/PARSIVEL/NCAR/VORTEX2_2009.py +114 -0
  134. disdrodb/l0/readers/PARSIVEL/NCAR/VORTEX2_2010.py +176 -0
  135. disdrodb/l0/readers/PARSIVEL/NCAR/VORTEX2_2010_UF.py +183 -0
  136. disdrodb/l0/readers/PARSIVEL/SLOVENIA/UL_FGG.py +121 -0
  137. disdrodb/l0/readers/{ARM/ARM_LD.py → PARSIVEL2/ARM/ARM_PARSIVEL2.py} +27 -50
  138. disdrodb/l0/readers/PARSIVEL2/BRAZIL/CHUVA_PARSIVEL2.py +163 -0
  139. disdrodb/l0/readers/PARSIVEL2/BRAZIL/GOAMAZON_PARSIVEL2.py +163 -0
  140. disdrodb/l0/readers/{DENMARK → PARSIVEL2/DENMARK}/EROSION_nc.py +14 -35
  141. disdrodb/l0/readers/PARSIVEL2/FRANCE/ENPC_PARSIVEL2.py +189 -0
  142. disdrodb/l0/readers/PARSIVEL2/FRANCE/SIRTA_PARSIVEL2.py +119 -0
  143. disdrodb/l0/readers/PARSIVEL2/GPM/GCPEX.py +104 -0
  144. disdrodb/l0/readers/PARSIVEL2/GPM/NSSTC.py +176 -0
  145. disdrodb/l0/readers/PARSIVEL2/ITALY/GID_PARSIVEL2.py +32 -0
  146. disdrodb/l0/readers/PARSIVEL2/MEXICO/OH_IIUNAM_nc.py +56 -0
  147. disdrodb/l0/readers/PARSIVEL2/NCAR/PECAN_FP3.py +120 -0
  148. disdrodb/l0/readers/{NCAR → PARSIVEL2/NCAR}/PECAN_MIPS.py +45 -64
  149. disdrodb/l0/readers/PARSIVEL2/NCAR/RELAMPAGO_PARSIVEL2.py +181 -0
  150. disdrodb/l0/readers/PARSIVEL2/NCAR/SNOWIE_PJ.py +160 -0
  151. disdrodb/l0/readers/PARSIVEL2/NCAR/SNOWIE_SB.py +160 -0
  152. disdrodb/l0/readers/{NCAR/PLOWS_MIPS.py → PARSIVEL2/NCAR/VORTEX_SE_2016_P1.py} +49 -66
  153. disdrodb/l0/readers/PARSIVEL2/NCAR/VORTEX_SE_2016_P2.py +118 -0
  154. disdrodb/l0/readers/PARSIVEL2/NCAR/VORTEX_SE_2016_PIPS.py +152 -0
  155. disdrodb/l0/readers/PARSIVEL2/NETHERLANDS/DELFT.py +166 -0
  156. disdrodb/l0/readers/PWS100/FRANCE/ENPC_PWS100.py +150 -0
  157. disdrodb/l0/readers/{NCAR/RELAMPAGO_RD80.py → RD80/BRAZIL/CHUVA_RD80.py} +36 -60
  158. disdrodb/l0/readers/{BRAZIL → RD80/BRAZIL}/GOAMAZON_RD80.py +36 -55
  159. disdrodb/l0/readers/{NCAR → RD80/NCAR}/CINDY_2011_RD80.py +35 -54
  160. disdrodb/l0/readers/{BRAZIL/CHUVA_RD80.py → RD80/NCAR/RELAMPAGO_RD80.py} +40 -54
  161. disdrodb/l0/readers/RD80/NOAA/PSL_RD80.py +274 -0
  162. disdrodb/l0/readers/template_reader_raw_netcdf_data.py +62 -0
  163. disdrodb/l0/readers/{reader_template.py → template_reader_raw_text_data.py} +20 -44
  164. disdrodb/l0/routines.py +885 -581
  165. disdrodb/l0/standards.py +77 -238
  166. disdrodb/l0/template_tools.py +105 -110
  167. disdrodb/l1/__init__.py +17 -0
  168. disdrodb/l1/beard_model.py +716 -0
  169. disdrodb/l1/encoding_attrs.py +635 -0
  170. disdrodb/l1/fall_velocity.py +260 -0
  171. disdrodb/l1/filters.py +192 -0
  172. disdrodb/l1/processing.py +202 -0
  173. disdrodb/l1/resampling.py +236 -0
  174. disdrodb/l1/routines.py +358 -0
  175. disdrodb/l1_env/__init__.py +17 -0
  176. disdrodb/l1_env/routines.py +38 -0
  177. disdrodb/l2/__init__.py +17 -0
  178. disdrodb/l2/empirical_dsd.py +1833 -0
  179. disdrodb/l2/event.py +388 -0
  180. disdrodb/l2/processing.py +528 -0
  181. disdrodb/l2/processing_options.py +213 -0
  182. disdrodb/l2/routines.py +868 -0
  183. disdrodb/metadata/__init__.py +9 -2
  184. disdrodb/metadata/checks.py +180 -124
  185. disdrodb/metadata/download.py +81 -0
  186. disdrodb/metadata/geolocation.py +146 -0
  187. disdrodb/metadata/info.py +20 -13
  188. disdrodb/metadata/manipulation.py +3 -3
  189. disdrodb/metadata/reader.py +59 -8
  190. disdrodb/metadata/search.py +77 -144
  191. disdrodb/metadata/standards.py +83 -80
  192. disdrodb/metadata/writer.py +10 -16
  193. disdrodb/psd/__init__.py +38 -0
  194. disdrodb/psd/fitting.py +2146 -0
  195. disdrodb/psd/models.py +774 -0
  196. disdrodb/routines.py +1412 -0
  197. disdrodb/scattering/__init__.py +28 -0
  198. disdrodb/scattering/axis_ratio.py +344 -0
  199. disdrodb/scattering/routines.py +456 -0
  200. disdrodb/utils/__init__.py +17 -0
  201. disdrodb/utils/attrs.py +208 -0
  202. disdrodb/utils/cli.py +269 -0
  203. disdrodb/utils/compression.py +60 -42
  204. disdrodb/utils/dask.py +62 -0
  205. disdrodb/utils/dataframe.py +342 -0
  206. disdrodb/utils/decorators.py +110 -0
  207. disdrodb/utils/directories.py +107 -46
  208. disdrodb/utils/encoding.py +127 -0
  209. disdrodb/utils/list.py +29 -0
  210. disdrodb/utils/logger.py +168 -46
  211. disdrodb/utils/time.py +657 -0
  212. disdrodb/utils/warnings.py +30 -0
  213. disdrodb/utils/writer.py +57 -0
  214. disdrodb/utils/xarray.py +138 -47
  215. disdrodb/utils/yaml.py +0 -1
  216. disdrodb/viz/__init__.py +17 -0
  217. disdrodb/viz/plots.py +17 -0
  218. disdrodb-0.1.1.dist-info/METADATA +294 -0
  219. disdrodb-0.1.1.dist-info/RECORD +232 -0
  220. {disdrodb-0.0.21.dist-info → disdrodb-0.1.1.dist-info}/WHEEL +1 -1
  221. disdrodb-0.1.1.dist-info/entry_points.txt +30 -0
  222. disdrodb/data_transfer/scripts/disdrodb_download_archive.py +0 -53
  223. disdrodb/data_transfer/scripts/disdrodb_upload_archive.py +0 -57
  224. disdrodb/l0/configs/OTT_Parsivel/l0a_encodings.yml +0 -32
  225. disdrodb/l0/configs/OTT_Parsivel2/l0a_encodings.yml +0 -39
  226. disdrodb/l0/configs/RD_80/l0a_encodings.yml +0 -16
  227. disdrodb/l0/configs/RD_80/l0b_encodings.yml +0 -135
  228. disdrodb/l0/configs/Thies_LPM/l0a_encodings.yml +0 -80
  229. disdrodb/l0/io.py +0 -257
  230. disdrodb/l0/l0_processing.py +0 -1091
  231. disdrodb/l0/readers/AUSTRALIA/MELBOURNE_2007_OTT.py +0 -178
  232. disdrodb/l0/readers/AUSTRALIA/MELBOURNE_2007_THIES.py +0 -247
  233. disdrodb/l0/readers/BRAZIL/CHUVA_LPM.py +0 -204
  234. disdrodb/l0/readers/BRAZIL/CHUVA_OTT.py +0 -183
  235. disdrodb/l0/readers/BRAZIL/GOAMAZON_OTT.py +0 -183
  236. disdrodb/l0/readers/CHINA/CHONGQING.py +0 -131
  237. disdrodb/l0/readers/EPFL/EPFL_ROOF_2008.py +0 -128
  238. disdrodb/l0/readers/EPFL/HYMEX_LTE_SOP2.py +0 -127
  239. disdrodb/l0/readers/EPFL/HYMEX_LTE_SOP3.py +0 -129
  240. disdrodb/l0/readers/EPFL/RACLETS_2019.py +0 -158
  241. disdrodb/l0/readers/EPFL/SAMOYLOV_2017.py +0 -136
  242. disdrodb/l0/readers/EPFL/SAMOYLOV_2019.py +0 -158
  243. disdrodb/l0/readers/FRANCE/SIRTA_OTT2.py +0 -138
  244. disdrodb/l0/readers/GPM/GCPEX.py +0 -123
  245. disdrodb/l0/readers/GPM/IFLOODS.py +0 -123
  246. disdrodb/l0/readers/GPM/MC3E.py +0 -123
  247. disdrodb/l0/readers/GPM/NSSTC.py +0 -164
  248. disdrodb/l0/readers/ITALY/GID.py +0 -199
  249. disdrodb/l0/readers/MEXICO/OH_IIUNAM_nc.py +0 -92
  250. disdrodb/l0/readers/NCAR/CCOPE_2015.py +0 -133
  251. disdrodb/l0/readers/NCAR/PECAN_FP3.py +0 -137
  252. disdrodb/l0/readers/NCAR/PECAN_MOBILE.py +0 -144
  253. disdrodb/l0/readers/NCAR/RELAMPAGO_OTT.py +0 -195
  254. disdrodb/l0/readers/NCAR/SNOWIE_PJ.py +0 -172
  255. disdrodb/l0/readers/NCAR/SNOWIE_SB.py +0 -179
  256. disdrodb/l0/readers/NCAR/VORTEX2_2009.py +0 -133
  257. disdrodb/l0/readers/NCAR/VORTEX2_2010.py +0 -188
  258. disdrodb/l0/readers/NCAR/VORTEX2_2010_UF.py +0 -191
  259. disdrodb/l0/readers/NCAR/VORTEX_SE_2016_P2.py +0 -135
  260. disdrodb/l0/readers/NCAR/VORTEX_SE_2016_PIPS.py +0 -170
  261. disdrodb/l0/readers/NETHERLANDS/DELFT.py +0 -187
  262. disdrodb/l0/readers/SPAIN/SBEGUERIA.py +0 -179
  263. disdrodb/l0/scripts/disdrodb_run_l0b_concat.py +0 -93
  264. disdrodb/l0/scripts/disdrodb_run_l0b_concat_station.py +0 -85
  265. disdrodb/utils/netcdf.py +0 -452
  266. disdrodb/utils/scripts.py +0 -102
  267. disdrodb-0.0.21.dist-info/AUTHORS.md +0 -18
  268. disdrodb-0.0.21.dist-info/METADATA +0 -186
  269. disdrodb-0.0.21.dist-info/RECORD +0 -168
  270. disdrodb-0.0.21.dist-info/entry_points.txt +0 -15
  271. /disdrodb/l0/configs/{RD_80 → RD80}/bins_velocity.yml +0 -0
  272. /disdrodb/l0/manuals/{Thies_LPM.pdf → LPM.pdf} +0 -0
  273. /disdrodb/l0/manuals/{ODM_470.pdf → ODM470.pdf} +0 -0
  274. /disdrodb/l0/manuals/{OTT_Parsivel.pdf → PARSIVEL.pdf} +0 -0
  275. /disdrodb/l0/manuals/{OTT_Parsivel2.pdf → PARSIVEL2.pdf} +0 -0
  276. /disdrodb/l0/manuals/{PWS_100.pdf → PWS100.pdf} +0 -0
  277. /disdrodb/l0/manuals/{RD_80.pdf → RD80.pdf} +0 -0
  278. {disdrodb-0.0.21.dist-info → disdrodb-0.1.1.dist-info/licenses}/LICENSE +0 -0
  279. {disdrodb-0.0.21.dist-info → disdrodb-0.1.1.dist-info}/top_level.txt +0 -0
disdrodb/l2/event.py ADDED
@@ -0,0 +1,388 @@
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
+ """Functions for event definition."""
18
+ import dask
19
+ import numpy as np
20
+ import pandas as pd
21
+ import xarray as xr
22
+
23
+ from disdrodb.api.info import get_start_end_time_from_filepaths
24
+ from disdrodb.utils.time import acronym_to_seconds, ensure_sorted_by_time
25
+
26
+
27
+ @dask.delayed
28
+ def _delayed_open_dataset(filepath):
29
+ with dask.config.set(scheduler="synchronous"):
30
+ ds = xr.open_dataset(filepath, chunks={}, autoclose=True, decode_timedelta=False, cache=False)
31
+ return ds
32
+
33
+
34
+ def identify_events(
35
+ filepaths,
36
+ parallel=False,
37
+ min_n_drops=5,
38
+ neighbor_min_size=2,
39
+ neighbor_time_interval="5MIN",
40
+ intra_event_max_time_gap="6H",
41
+ event_min_duration="5MIN",
42
+ event_min_size=3,
43
+ ):
44
+ """Return a list of rainy events.
45
+
46
+ Rainy timesteps are defined when N > min_n_drops.
47
+ Any rainy isolated timesteps (based on neighborhood criteria) is removed.
48
+ Then, consecutive rainy timesteps are grouped into the same event if the time gap between them does not
49
+ exceed `intra_event_max_time_gap`. Finally, events that do not meet minimum size or duration
50
+ requirements are filtered out.
51
+
52
+ Parameters
53
+ ----------
54
+ filepaths: list
55
+ List of L1C file paths.
56
+ parallel: bool
57
+ Whether to load the files in parallel.
58
+ Set parallel=True only in a multiprocessing environment.
59
+ The default is False.
60
+ neighbor_time_interval : str
61
+ The time interval around a given a timestep defining the neighborhood.
62
+ Only timesteps that fall within this time interval before or after a timestep are considered neighbors.
63
+ neighbor_min_size : int, optional
64
+ The minimum number of neighboring timesteps required within `neighbor_time_interval` for a
65
+ timestep to be considered non-isolated. Isolated timesteps are removed !
66
+ - If `neighbor_min_size=0, then no timestep is considered isolated and no filtering occurs.
67
+ - If `neighbor_min_size=1`, the timestep must have at least one neighbor within `neighbor_time_interval`.
68
+ - If `neighbor_min_size=2`, the timestep must have at least two timesteps within `neighbor_time_interval`.
69
+ Defaults to 1.
70
+ intra_event_max_time_gap: str
71
+ The maximum time interval between two timesteps to be considered part of the same event.
72
+ This parameters is used to group timesteps into events !
73
+ event_min_duration : str
74
+ The minimum duration an event must span. Events shorter than this duration are discarded.
75
+ event_min_size : int, optional
76
+ The minimum number of valid timesteps required for an event. Defaults to 1.
77
+
78
+ Returns
79
+ -------
80
+ list of dict
81
+ A list of events, where each event is represented as a dictionary with keys:
82
+ - "start_time": np.datetime64, start time of the event
83
+ - "end_time": np.datetime64, end time of the event
84
+ - "duration": np.timedelta64, duration of the event
85
+ - "n_timesteps": int, number of valid timesteps in the event
86
+ """
87
+ # Open datasets in parallel
88
+ if parallel:
89
+ list_ds = dask.compute([_delayed_open_dataset(filepath) for filepath in filepaths])[0]
90
+ else:
91
+ list_ds = [xr.open_dataset(filepath, chunks={}, cache=False, decode_timedelta=False) for filepath in filepaths]
92
+ # Filter dataset for requested variables
93
+ variables = ["time", "N"]
94
+ list_ds = [ds[variables] for ds in list_ds]
95
+ # Concat datasets
96
+ ds = xr.concat(list_ds, dim="time", compat="no_conflicts", combine_attrs="override")
97
+ # Read in memory the variable needed
98
+ ds = ds.compute()
99
+ # Close file on disk
100
+ _ = [ds.close() for ds in list_ds]
101
+ del list_ds
102
+ # Sort dataset by time
103
+ ds = ensure_sorted_by_time(ds)
104
+ # Define candidate timesteps to group into events
105
+ idx_valid = ds["N"].data > min_n_drops
106
+ timesteps = ds["time"].data[idx_valid]
107
+ # Define event list
108
+ event_list = group_timesteps_into_event(
109
+ timesteps=timesteps,
110
+ neighbor_min_size=neighbor_min_size,
111
+ neighbor_time_interval=neighbor_time_interval,
112
+ intra_event_max_time_gap=intra_event_max_time_gap,
113
+ event_min_duration=event_min_duration,
114
+ event_min_size=event_min_size,
115
+ )
116
+ return event_list
117
+
118
+
119
+ def group_timesteps_into_event(
120
+ timesteps,
121
+ intra_event_max_time_gap,
122
+ event_min_size=0,
123
+ event_min_duration="0S",
124
+ neighbor_min_size=0,
125
+ neighbor_time_interval="0S",
126
+ ):
127
+ """
128
+ Group candidate timesteps into events based on temporal criteria.
129
+
130
+ This function groups valid candidate timesteps into events by considering how they cluster
131
+ in time. Any isolated timesteps (based on neighborhood criteria) are first removed. Then,
132
+ consecutive timesteps are grouped into the same event if the time gap between them does not
133
+ exceed `intra_event_max_time_gap`. Finally, events that do not meet minimum size or duration
134
+ requirements are filtered out.
135
+
136
+ Please note that neighbor_min_size and neighbor_time_interval are very sensitive to the
137
+ actual sample interval of the data !
138
+
139
+ Parameters
140
+ ----------
141
+ timesteps: np.ndarray
142
+ Candidate timesteps to be grouped into events.
143
+ neighbor_time_interval : str
144
+ The time interval around a given a timestep defining the neighborhood.
145
+ Only timesteps that fall within this time interval before or after a timestep are considered neighbors.
146
+ neighbor_min_size : int, optional
147
+ The minimum number of neighboring timesteps required within `neighbor_time_interval` for a
148
+ timestep to be considered non-isolated. Isolated timesteps are removed !
149
+ - If `neighbor_min_size=0, then no timestep is considered isolated and no filtering occurs.
150
+ - If `neighbor_min_size=1`, the timestep must have at least one neighbor within `neighbor_time_interval`.
151
+ - If `neighbor_min_size=2`, the timestep must have at least two timesteps within `neighbor_time_interval`.
152
+ Defaults to 1.
153
+ intra_event_max_time_gap: str
154
+ The maximum time interval between two timesteps to be considered part of the same event.
155
+ This parameters is used to group timesteps into events !
156
+ event_min_duration : str
157
+ The minimum duration an event must span. Events shorter than this duration are discarded.
158
+ event_min_size : int, optional
159
+ The minimum number of valid timesteps required for an event. Defaults to 1.
160
+
161
+ Returns
162
+ -------
163
+ list of dict
164
+ A list of events, where each event is represented as a dictionary with keys:
165
+ - "start_time": np.datetime64, start time of the event
166
+ - "end_time": np.datetime64, end time of the event
167
+ - "duration": np.timedelta64, duration of the event
168
+ - "n_timesteps": int, number of valid timesteps in the event
169
+ """
170
+ # Retrieve datetime arguments
171
+ neighbor_time_interval = pd.Timedelta(acronym_to_seconds(neighbor_time_interval), unit="seconds")
172
+ intra_event_max_time_gap = pd.Timedelta(acronym_to_seconds(intra_event_max_time_gap), unit="seconds")
173
+ event_min_duration = pd.Timedelta(acronym_to_seconds(event_min_duration), unit="seconds")
174
+
175
+ # Remove isolated timesteps
176
+ timesteps = remove_isolated_timesteps(
177
+ timesteps,
178
+ neighbor_min_size=neighbor_min_size,
179
+ neighbor_time_interval=neighbor_time_interval,
180
+ )
181
+
182
+ # Group timesteps into events
183
+ # - If two timesteps are separated by less than intra_event_max_time_gap, are considered the same event
184
+ events = group_timesteps_into_events(timesteps, intra_event_max_time_gap)
185
+
186
+ # Define list of event
187
+ event_list = [
188
+ {
189
+ "start_time": event[0],
190
+ "end_time": event[-1],
191
+ "duration": (event[-1] - event[0]).astype("m8[m]"),
192
+ "n_timesteps": len(event),
193
+ }
194
+ for event in events
195
+ ]
196
+
197
+ # Filter event list by duration
198
+ event_list = [event for event in event_list if event["duration"] >= event_min_duration]
199
+
200
+ # Filter event list by duration
201
+ event_list = [event for event in event_list if event["n_timesteps"] >= event_min_size]
202
+
203
+ return event_list
204
+
205
+
206
+ def remove_isolated_timesteps(timesteps, neighbor_min_size, neighbor_time_interval):
207
+ """
208
+ Remove isolated timesteps that do not have enough neighboring timesteps within a specified time gap.
209
+
210
+ A timestep is considered isolated (and thus removed) if it does not have at least `neighbor_min_size` other
211
+ timesteps within the `neighbor_time_interval` before or after it.
212
+ In other words, for each timestep, we look for how many other timesteps fall into the
213
+ time interval [t - neighbor_time_interval, t + neighbor_time_interval], excluding it itself.
214
+ If the count of such neighbors is less than `neighbor_min_size`, that timestep is removed.
215
+
216
+ Parameters
217
+ ----------
218
+ timesteps : array-like of np.datetime64
219
+ Sorted or unsorted array of valid timesteps.
220
+ neighbor_time_interval : np.timedelta64
221
+ The time interval around a given a timestep defining the neighborhood.
222
+ Only timesteps that fall within this time interval before or after a timestep are considered neighbors.
223
+ neighbor_min_size : int, optional
224
+ The minimum number of neighboring timesteps required within `neighbor_time_interval` for a
225
+ timestep to be considered non-isolated.
226
+ - If `neighbor_min_size=0, then no timestep is considered isolated and no filtering occurs.
227
+ - If `neighbor_min_size=1`, the timestep must have at least one neighbor within `neighbor_time_interval`.
228
+ - If `neighbor_min_size=2`, the timestep must have at least two timesteps within `neighbor_time_interval`.
229
+ Defaults to 1.
230
+
231
+ Returns
232
+ -------
233
+ np.ndarray
234
+ Array of timesteps with isolated entries removed.
235
+ """
236
+ # Sort timesteps
237
+ timesteps = np.array(timesteps)
238
+ timesteps.sort()
239
+
240
+ # Do nothing if neighbor_min_size is 0
241
+ if neighbor_min_size == 0:
242
+ return timesteps
243
+
244
+ # Compute the start and end of the interval for each timestep
245
+ t_starts = timesteps - neighbor_time_interval
246
+ t_ends = timesteps + neighbor_time_interval
247
+
248
+ # Use searchsorted to find the positions where these intervals would be inserted
249
+ # to keep the array sorted. This effectively gives us the bounds of timesteps
250
+ # within the neighbor interval.
251
+ left_indices = np.searchsorted(timesteps, t_starts, side="left")
252
+ right_indices = np.searchsorted(timesteps, t_ends, side="right")
253
+
254
+ # The number of neighbors is the difference in indices minus one (to exclude the timestep itself)
255
+ n_neighbors = right_indices - left_indices - 1
256
+ valid_mask = n_neighbors >= neighbor_min_size
257
+
258
+ non_isolated_timesteps = timesteps[valid_mask]
259
+
260
+ # NON VECTORIZED CODE
261
+ # non_isolated_timesteps = []
262
+ # n_neighbours_arr = []
263
+ # for i, t in enumerate(timesteps):
264
+ # n_neighbours = np.sum(np.logical_and(timesteps >= (t - neighbor_time_interval),
265
+ # timesteps <= (t + neighbor_time_interval))) - 1
266
+ # n_neighbours_arr.append(n_neighbours)
267
+ # if n_neighbours > neighbor_min_size:
268
+ # non_isolated_timesteps.append(t)
269
+ # non_isolated_timesteps = np.array(non_isolated_timesteps)
270
+ return non_isolated_timesteps
271
+
272
+
273
+ def group_timesteps_into_events(timesteps, intra_event_max_time_gap):
274
+ """
275
+ Group valid timesteps into events based on a maximum allowed dry interval.
276
+
277
+ Parameters
278
+ ----------
279
+ timesteps : array-like of np.datetime64
280
+ Sorted array of valid timesteps.
281
+ intra_event_max_time_gap : np.timedelta64
282
+ Maximum time interval allowed between consecutive valid timesteps for them
283
+ to be considered part of the same event.
284
+
285
+ Returns
286
+ -------
287
+ list of np.ndarray
288
+ A list of events, where each event is an array of timesteps.
289
+ """
290
+ # Deal with case with no timesteps
291
+ if len(timesteps) == 0:
292
+ return []
293
+
294
+ # Ensure timesteps are sorted
295
+ timesteps.sort()
296
+
297
+ # Compute differences between consecutive timesteps
298
+ diffs = np.diff(timesteps)
299
+
300
+ # Identify the indices where the gap is larger than intra_event_max_time_gap
301
+ # These indices represent boundaries between events
302
+ break_indices = np.where(diffs > intra_event_max_time_gap)[0] + 1
303
+
304
+ # Split the timesteps at the identified break points
305
+ events = np.split(timesteps, break_indices)
306
+
307
+ # NON VECTORIZED CODE
308
+ # events = []
309
+ # current_event = [timesteps[0]]
310
+ # for i in range(1, len(timesteps)):
311
+ # current_t = timesteps[i]
312
+ # previous_t = timesteps[i - 1]
313
+
314
+ # if current_t - previous_t <= intra_event_max_time_gap:
315
+ # current_event.append(current_t)
316
+ # else:
317
+ # events.append(current_event)
318
+ # current_event = [current_t]
319
+
320
+ # events.append(current_event)
321
+ return events
322
+
323
+
324
+ ####-----------------------------------------------------------------------------------.
325
+
326
+
327
+ def get_events_info(list_events, filepaths, accumulation_interval, rolling):
328
+ """
329
+ Provide information about the required files for each event.
330
+
331
+ For each event in `list_events`, this function identifies the file paths from `filepaths` that
332
+ overlap with the event period, adjusted by the `accumulation_interval`. The event period is
333
+ extended backward or forward based on the `rolling` parameter.
334
+
335
+ Parameters
336
+ ----------
337
+ list_events : list of dict
338
+ List of events, where each event is a dictionary containing at least 'start_time' and 'end_time'
339
+ keys with `numpy.datetime64` values.
340
+ filepaths : list of str
341
+ List of file paths corresponding to data files.
342
+ accumulation_interval : numpy.timedelta64 or int
343
+ Time interval to adjust the event period for accumulation. If an integer is provided, it is
344
+ assumed to be in seconds.
345
+ rolling : bool
346
+ If True, adjust the event period backward by `accumulation_interval` (rolling backward).
347
+ If False, adjust forward (aggregate forward).
348
+
349
+ Returns
350
+ -------
351
+ list of dict
352
+ A list where each element is a dictionary containing:
353
+ - 'start_time': Adjusted start time of the event (`numpy.datetime64`).
354
+ - 'end_time': Adjusted end time of the event (`numpy.datetime64`).
355
+ - 'filepaths': List of file paths overlapping with the adjusted event period.
356
+
357
+ """
358
+ # Ensure accumulation_interval is numpy.timedelta64
359
+ if not isinstance(accumulation_interval, np.timedelta64):
360
+ accumulation_interval = np.timedelta64(accumulation_interval, "s")
361
+
362
+ # Retrieve file start_time and end_time
363
+ files_start_time, files_end_time = get_start_end_time_from_filepaths(filepaths)
364
+
365
+ # Retrieve information for each event
366
+ event_info = []
367
+ for event_dict in list_events:
368
+ # Retrieve event time period
369
+ event_start_time = event_dict["start_time"]
370
+ event_end_time = event_dict["end_time"]
371
+
372
+ # Add buffer to account for accumulation interval
373
+ if rolling: # backward
374
+ event_start_time = event_start_time - np.array(accumulation_interval, dtype="m8[s]")
375
+ else: # aggregate forward
376
+ event_end_time = event_end_time + np.array(accumulation_interval, dtype="m8[s]")
377
+
378
+ # Derive event filepaths
379
+ overlaps = (files_start_time <= event_end_time) & (files_end_time >= event_start_time)
380
+ event_filepaths = np.array(filepaths)[overlaps].tolist()
381
+
382
+ # Create dictionary
383
+ if len(event_filepaths) > 0:
384
+ event_info.append(
385
+ {"start_time": event_start_time, "end_time": event_end_time, "filepaths": event_filepaths},
386
+ )
387
+
388
+ return event_info