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
disdrodb/__init__.py CHANGED
@@ -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
@@ -20,6 +20,8 @@ import contextlib
20
20
  import os
21
21
  from importlib.metadata import PackageNotFoundError, version
22
22
 
23
+ os.environ["HDF5_USE_FILE_LOCKING"] = "FALSE"
24
+
23
25
  import disdrodb.accessor # noqa
24
26
  from disdrodb._config import config # noqa
25
27
  from disdrodb.api.configs import available_sensor_names
disdrodb/_config.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
@@ -20,6 +18,7 @@
20
18
 
21
19
  See https://donfig.readthedocs.io/en/latest/configuration.html for more info.
22
20
  """
21
+
23
22
  from donfig import Config
24
23
 
25
24
  from disdrodb.configs import read_configs
disdrodb/_version.py CHANGED
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
28
28
  commit_id: COMMIT_ID
29
29
  __commit_id__: COMMIT_ID
30
30
 
31
- __version__ = version = '0.2.1'
32
- __version_tuple__ = version_tuple = (0, 2, 1)
31
+ __version__ = version = '0.4.0'
32
+ __version_tuple__ = version_tuple = (0, 4, 0)
33
33
 
34
34
  __commit_id__ = commit_id = None
@@ -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
  """This directory defines DISDRODB xarray accessors."""
18
+
18
19
  from .methods import DISDRODB_DataArray_Accessor, DISDRODB_Dataset_Accessor
19
20
 
20
21
  __all__ = ["DISDRODB_DataArray_Accessor", "DISDRODB_Dataset_Accessor"]
@@ -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
  """This module defines DISDRODB xarray accessors."""
18
+
18
19
  import xarray as xr
19
20
 
20
21
 
@@ -32,7 +33,7 @@ class DISDRODB_Base_Accessor:
32
33
  from disdrodb.api.checks import check_time
33
34
 
34
35
  if "time" in self._obj.coords:
35
- start_time = self._obj["time"].to_numpy()[0]
36
+ start_time = self._obj["time"].to_numpy().min()
36
37
  else:
37
38
  raise ValueError("Time coordinate not found")
38
39
  return check_time(start_time)
@@ -43,7 +44,7 @@ class DISDRODB_Base_Accessor:
43
44
  from disdrodb.api.checks import check_time
44
45
 
45
46
  if "time" in self._obj.coords:
46
- end_time = self._obj["time"].to_numpy()[-1]
47
+ end_time = self._obj["time"].to_numpy().max()
47
48
  else:
48
49
  raise ValueError("Time coordinate not found")
49
50
  return check_time(end_time)
@@ -102,6 +103,12 @@ class DISDRODB_Base_Accessor:
102
103
 
103
104
  return plot_spectrum(self._obj, **kwargs)
104
105
 
106
+ def plot_nd(self, **kwargs):
107
+ """Plot drop number concentration N(D) timeseries."""
108
+ from disdrodb.viz.plots import plot_nd
109
+
110
+ return plot_nd(self._obj, **kwargs)
111
+
105
112
 
106
113
  @xr.register_dataset_accessor("disdrodb")
107
114
  class DISDRODB_Dataset_Accessor(DISDRODB_Base_Accessor):
@@ -122,12 +129,6 @@ class DISDRODB_Dataset_Accessor(DISDRODB_Base_Accessor):
122
129
  )
123
130
  return ds
124
131
 
125
- def plot_nd(self, **kwargs):
126
- """Plot drop number concentration N(D) timeseries."""
127
- from disdrodb.viz.plots import plot_nd
128
-
129
- return plot_nd(self._obj, **kwargs)
130
-
131
132
  def plot_raw_and_filtered_spectra(self, **kwargs):
132
133
  """Plot the raw and filtered spectra."""
133
134
  from disdrodb.viz.plots import plot_raw_and_filtered_spectra
disdrodb/api/checks.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,12 +15,12 @@
17
15
  # along with this program. If not, see <http://www.gnu.org/licenses/>.
18
16
  # -----------------------------------------------------------------------------.
19
17
  """DISDRODB Checks Functions."""
18
+
20
19
  import datetime
21
20
  import difflib
22
21
  import logging
23
22
  import os
24
23
  import re
25
- import sys
26
24
  import warnings
27
25
 
28
26
  import numpy as np
@@ -567,9 +565,7 @@ def check_filepaths(filepaths):
567
565
 
568
566
  def get_current_utc_time():
569
567
  """Get current UTC time."""
570
- if sys.version_info >= (3, 11):
571
- return datetime.datetime.now(datetime.UTC).replace(tzinfo=None)
572
- return datetime.datetime.utcnow()
568
+ return datetime.datetime.now(datetime.UTC).replace(tzinfo=None)
573
569
 
574
570
 
575
571
  def check_start_end_time(start_time, end_time):
disdrodb/api/configs.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
@@ -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
@@ -23,7 +21,6 @@
23
21
 
24
22
  import logging
25
23
  import os
26
- import shutil
27
24
 
28
25
  from disdrodb.api.checks import (
29
26
  check_campaign_name,
@@ -46,6 +43,7 @@ from disdrodb.api.path import (
46
43
  from disdrodb.configs import get_data_archive_dir, get_metadata_archive_dir
47
44
  from disdrodb.utils.directories import (
48
45
  create_directory,
46
+ remove_file_or_directories,
49
47
  remove_if_exists,
50
48
  )
51
49
 
@@ -59,7 +57,7 @@ def ensure_empty_data_dir(data_dir, force):
59
57
  """Remove the content of the data_dir directory."""
60
58
  # If force=True, remove all the directory content
61
59
  if force:
62
- shutil.rmtree(data_dir)
60
+ remove_file_or_directories(data_dir)
63
61
  # Recreate the directory
64
62
  create_directory(data_dir)
65
63
  else:
@@ -258,7 +256,7 @@ def create_logs_directory(
258
256
 
259
257
  # Ensure empty log directory
260
258
  if os.path.isdir(logs_dir):
261
- shutil.rmtree(logs_dir)
259
+ remove_file_or_directories(logs_dir)
262
260
 
263
261
  # Create logs directory
264
262
  os.makedirs(logs_dir, exist_ok=True)
disdrodb/api/info.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
disdrodb/api/io.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,22 +15,23 @@
17
15
  # along with this program. If not, see <http://www.gnu.org/licenses/>.
18
16
  # -----------------------------------------------------------------------------.
19
17
  """Routines to list and open DISDRODB products."""
18
+
20
19
  import datetime
20
+ import functools
21
21
  import os
22
- import shutil
23
22
  import subprocess
24
23
  import sys
25
24
  from pathlib import Path
26
- from typing import Optional
27
25
 
28
26
  import numpy as np
29
27
 
30
28
  from disdrodb.api.checks import (
31
29
  check_filepaths,
32
30
  check_start_end_time,
31
+ check_time,
33
32
  get_current_utc_time,
34
33
  )
35
- from disdrodb.api.info import get_start_end_time_from_filepaths
34
+ from disdrodb.api.info import get_start_end_time_from_filepaths, group_filepaths
36
35
  from disdrodb.api.path import (
37
36
  define_campaign_dir,
38
37
  define_data_dir,
@@ -41,7 +40,7 @@ from disdrodb.api.path import (
41
40
  )
42
41
  from disdrodb.l0.l0_reader import define_readers_directory
43
42
  from disdrodb.utils.dict import extract_product_kwargs
44
- from disdrodb.utils.directories import list_files
43
+ from disdrodb.utils.directories import list_files, remove_file_or_directories
45
44
  from disdrodb.utils.logger import (
46
45
  log_info,
47
46
  )
@@ -133,8 +132,8 @@ def find_files(
133
132
  station_name,
134
133
  product,
135
134
  debugging_mode: bool = False,
136
- data_archive_dir: Optional[str] = None,
137
- metadata_archive_dir: Optional[str] = None,
135
+ data_archive_dir: str | None = None,
136
+ metadata_archive_dir: str | None = None,
138
137
  glob_pattern=None,
139
138
  start_time=None,
140
139
  end_time=None,
@@ -292,6 +291,42 @@ def _open_raw_files(filepaths, data_source, campaign_name, station_name, metadat
292
291
  return ds
293
292
 
294
293
 
294
+ def list_coordinates_names(ds):
295
+ """List coordinates of a xarray.Dataset not CF decoded !."""
296
+ coords = set()
297
+ for v in ds.variables:
298
+ attrs = ds[v].attrs
299
+ # auxiliary coordinates
300
+ if "coordinates" in attrs:
301
+ coords |= set(attrs["coordinates"].split())
302
+ # bounds variables
303
+ if "bounds" in attrs:
304
+ coords.add(attrs["bounds"])
305
+ # grid mapping
306
+ if "grid_mapping" in attrs:
307
+ coords.add(attrs["grid_mapping"])
308
+ return coords
309
+
310
+
311
+ def subset_variables(ds, variables):
312
+ """Subset variables while keeping coordinates."""
313
+ # Ensure list
314
+ variables = list(variables)
315
+
316
+ # Always keep dimension variables
317
+ dim_vars = list(ds.dims)
318
+
319
+ # Variables referenced by CF relationships
320
+ coords = list_coordinates_names(ds)
321
+
322
+ # Union of everything we must keep
323
+ keep = set(variables) | set(dim_vars) | coords
324
+
325
+ # Only keep variables that exist
326
+ keep = [v for v in keep if v in list(ds.variables)]
327
+ return ds[keep]
328
+
329
+
295
330
  def filter_dataset_by_time(ds, start_time=None, end_time=None):
296
331
  """Subset an xarray.Dataset by time, robust to duplicated/non-monotonic indices.
297
332
 
@@ -321,6 +356,84 @@ def filter_dataset_by_time(ds, start_time=None, end_time=None):
321
356
  return ds.isel(time=np.where(mask)[0])
322
357
 
323
358
 
359
+ def open_parquet_files(
360
+ filepaths,
361
+ variables=None,
362
+ start_time=None,
363
+ end_time=None,
364
+ time_col="time",
365
+ use_threads=True,
366
+ ):
367
+ """Open Parquet files."""
368
+ import pyarrow.dataset as ds
369
+
370
+ # Open dataset
371
+ dataset = ds.dataset(
372
+ filepaths,
373
+ format="parquet",
374
+ )
375
+
376
+ # Define filters
377
+ filters = []
378
+ if start_time is not None:
379
+ start_time = check_time(start_time)
380
+ filters.append(ds.field(time_col) >= start_time)
381
+
382
+ if end_time is not None:
383
+ end_time = check_time(end_time)
384
+ filters.append(ds.field(time_col) <= end_time)
385
+
386
+ # Combine filters if any exist
387
+ filter_expr = None
388
+ if filters:
389
+ filter_expr = filters[0]
390
+ for f in filters[1:]:
391
+ filter_expr = filter_expr & f
392
+
393
+ # Read table and convert to pandas
394
+ df = dataset.to_table(
395
+ columns=variables,
396
+ filter=filter_expr,
397
+ use_threads=use_threads,
398
+ ).to_pandas()
399
+ return df
400
+
401
+
402
+ def ensure_safe_open_mfdataset(function):
403
+ """Decorator to ensure safe xarray open_mfdataset.
404
+
405
+ parallel argument is changed to False if:
406
+ - dask threading or single-threaded is active
407
+ - distributed multiprocessing with more than 1 thread per process
408
+
409
+ parallel argument is allowed to be True only if:
410
+ - distributed multiprocessing with only 1 thread per process
411
+ """
412
+ import dask
413
+
414
+ from disdrodb.utils.dask import check_parallel_validity
415
+
416
+ @functools.wraps(function)
417
+ def wrapper(*args, **kwargs):
418
+ # Check if it must be a delayed function
419
+ parallel = kwargs.get("parallel", False)
420
+ parallel = check_parallel_validity(parallel)
421
+ kwargs["parallel"] = parallel
422
+
423
+ # If parallel is True at this stage, means being using
424
+ # multiprocessing or dask.distributed with single thread
425
+ if parallel:
426
+ return function(*args, **kwargs)
427
+
428
+ # Call function with single threading
429
+ with dask.config.set(scheduler="single-threaded"): # "synchronous"
430
+ result = function(*args, **kwargs)
431
+ return result
432
+
433
+ return wrapper
434
+
435
+
436
+ @ensure_safe_open_mfdataset
324
437
  def open_netcdf_files(
325
438
  filepaths,
326
439
  chunks=-1,
@@ -329,46 +442,101 @@ def open_netcdf_files(
329
442
  variables=None,
330
443
  parallel=False,
331
444
  compute=True,
445
+ engine="netcdf4",
332
446
  **open_kwargs,
333
447
  ):
334
448
  """Open DISDRODB netCDF files using xarray.
335
449
 
336
- Using combine="nested" and join="outer" ensure that duplicated timesteps are not overwritten!
450
+ Using data_vars="minimal", coords="minimal", compat="override"
451
+ --> will only concatenate those variables with the time dimension,
452
+ --> will skip any checking for variables that don't have a time dimension
453
+ (simply pick the variable from the first file).
454
+ https://github.com/pydata/xarray/issues/1385#issuecomment-1958761334
455
+
456
+ Using combine="nested" and join="outer" ensure that duplicated timesteps
457
+ are not overwritten!
458
+
459
+ When decode_cf=False
460
+ --> lat,lon are data_vars and get concatenated without any checking or reading
461
+ When decode_cf=True
462
+ --> lat, lon are promoted to coords, then get checked for equality across all files
463
+
464
+ For L0B product, if sample_interval variable is present and varies with time,
465
+ this function concatenate the variable over time without problems.
466
+ For L0C product, if sample_interval changes across listed files,
467
+ only sample_interval of first file is reported.
468
+ --> open_dataset take care of just providing filepaths of files with same sample interval.
469
+ In L1 and L2 processing, only filepaths of files with same sample interval
470
+ must be passed to this function.
471
+
337
472
  """
338
473
  import xarray as xr
339
474
 
340
475
  # Ensure variables is a list
341
- if variables is not None and isinstance(variables, str):
342
- variables = [variables]
476
+ if variables is not None:
477
+ if isinstance(variables, str):
478
+ variables = [variables]
479
+ variables = np.unique(variables).tolist()
480
+
343
481
  # Define preprocessing function for parallel opening
344
- preprocess = (lambda ds: ds[variables]) if parallel and variables is not None else None
482
+ if parallel and variables is not None:
483
+
484
+ def preprocess(ds):
485
+ return subset_variables(ds, variables)
486
+
487
+ else:
488
+ preprocess = None
345
489
 
346
490
  # Open netcdf
491
+ xr.set_options(use_new_combine_kwarg_defaults=True)
347
492
  ds = xr.open_mfdataset(
348
493
  filepaths,
349
494
  chunks=chunks,
350
- data_vars="all",
351
495
  combine="nested",
352
- join="outer",
353
496
  concat_dim="time",
354
- engine="netcdf4",
355
- parallel=parallel,
356
- preprocess=preprocess,
357
- compat="no_conflicts",
497
+ data_vars="minimal", # ["sample_interval"], "all" would concat all across time
498
+ coords="minimal",
499
+ join="outer", # "exact"
500
+ compat="override", # "no_conflicts" slows down
358
501
  combine_attrs="override",
359
- coords="different", # maybe minimal? would remove lon/lat/alt?
502
+ preprocess=preprocess, # only if parallel=True
503
+ engine=engine,
504
+ parallel=parallel,
505
+ decode_cf=False, # assume encoding do not vary across files (e.g. "time" units)
506
+ decode_coords=False, # no effect if decode_cf=False
360
507
  decode_timedelta=False,
361
508
  cache=False,
362
509
  autoclose=True,
363
510
  **open_kwargs,
364
511
  )
365
- # - Subset variables
512
+
513
+ # Decode CF
514
+ # - Set to coordinates the variables
515
+ # - latitude/longitude/altitude
516
+ # - sample_interval
517
+ # - diameter/velocity bin width/upper/lower
518
+ ds = xr.decode_cf(ds, decode_times=True, decode_coords=True, decode_timedelta=False)
519
+
520
+ # Subset variables
521
+ # --> After decoding CF, when coordinates are properly set
522
+ # --> Othewerwise, coordinate variables would be removed unless listed in variables
366
523
  if variables is not None and preprocess is None:
524
+ variables = [var for var in variables if var in ds]
367
525
  ds = ds[variables]
368
- # - Subset time
526
+
527
+ # Subset time
369
528
  if start_time is not None or end_time is not None:
370
529
  ds = filter_dataset_by_time(ds, start_time=start_time, end_time=end_time)
371
- # - If compute=True, load in memory and close connections to files
530
+
531
+ # Ensure coordinates are already loaded in memory
532
+ for coord in list(ds.coords):
533
+ ds[coord] = ds[coord].load()
534
+
535
+ # Update time coverage attributes
536
+ ds.attrs["time_coverage_start"] = str(ds.disdrodb.start_time)
537
+ ds.attrs["time_coverage_end"] = str(ds.disdrodb.end_time)
538
+
539
+ # If compute=True, load in memory and close connections to files
372
540
  if compute:
373
541
  dataset = ds.compute()
374
542
  ds.close()
@@ -386,8 +554,8 @@ def open_dataset(
386
554
  product,
387
555
  product_kwargs=None,
388
556
  debugging_mode: bool = False,
389
- data_archive_dir: Optional[str] = None,
390
- metadata_archive_dir: Optional[str] = None,
557
+ data_archive_dir: str | None = None,
558
+ metadata_archive_dir: str | None = None,
391
559
  chunks=-1,
392
560
  parallel=False,
393
561
  compute=False,
@@ -429,7 +597,7 @@ def open_dataset(
429
597
  xarray.Dataset
430
598
 
431
599
  """
432
- from disdrodb.l0.l0a_processing import read_l0a_dataframe
600
+ import xarray as xr
433
601
 
434
602
  # Extract product kwargs from open_kwargs
435
603
  product_kwargs = extract_product_kwargs(open_kwargs, product=product)
@@ -463,9 +631,46 @@ def open_dataset(
463
631
 
464
632
  # Open L0A Parquet files
465
633
  if product == "L0A":
466
- return read_l0a_dataframe(filepaths)
634
+ df = open_parquet_files(
635
+ filepaths=filepaths,
636
+ variables=variables,
637
+ start_time=start_time,
638
+ end_time=end_time,
639
+ use_threads=parallel,
640
+ )
641
+ return df
467
642
 
468
643
  # Open DISDRODB netCDF files using xarray
644
+ # - Special handling for L0C product with possible multiple sample intervals
645
+ if product == "L0C":
646
+ dict_sample_intervals = group_filepaths(filepaths, groups="sample_interval")
647
+ if len(dict_sample_intervals) > 1:
648
+ # Open separately each sample interval
649
+ list_ds = [
650
+ open_netcdf_files(
651
+ filepaths=filepaths,
652
+ chunks=chunks,
653
+ start_time=start_time,
654
+ end_time=end_time,
655
+ variables=variables,
656
+ parallel=parallel,
657
+ compute=compute,
658
+ **open_kwargs,
659
+ )
660
+ for filepaths in dict_sample_intervals.values()
661
+ ]
662
+ # Expand sample_interval coordinate for each dataset
663
+ list_ds = [ds.assign_coords(sample_interval=ds.sample_interval.expand_dims(time=ds.time)) for ds in list_ds]
664
+ # Concatenate along time dimension and sort by time
665
+ ds = xr.concat(list_ds, dim="time")
666
+ ds.attrs["measurement_interval"] = list(dict_sample_intervals)
667
+ ds = ds.sortby("time")
668
+ # Update time coverage attributes
669
+ ds.attrs["time_coverage_start"] = str(ds.disdrodb.start_time)
670
+ ds.attrs["time_coverage_end"] = str(ds.disdrodb.end_time)
671
+ return ds
672
+
673
+ # Otherwise, open all files together
469
674
  ds = open_netcdf_files(
470
675
  filepaths=filepaths,
471
676
  chunks=chunks,
@@ -476,10 +681,6 @@ def open_dataset(
476
681
  compute=compute,
477
682
  **open_kwargs,
478
683
  )
479
-
480
- # Ensure coordinates in memory
481
- # for coord in list(ds.coords):
482
- # ds[coord] = ds[coord].compute()
483
684
  return ds
484
685
 
485
686
 
@@ -509,7 +710,7 @@ def remove_product(
509
710
  **product_kwargs,
510
711
  )
511
712
  log_info(logger=logger, msg="Removal of {product} files started.", verbose=verbose)
512
- shutil.rmtree(data_dir)
713
+ remove_file_or_directories(data_dir)
513
714
  log_info(logger=logger, msg="Removal of {product} files ended.", verbose=verbose)
514
715
 
515
716
 
disdrodb/api/path.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,13 +15,13 @@
17
15
  # along with this program. If not, see <http://www.gnu.org/licenses/>.
18
16
  # -----------------------------------------------------------------------------.
19
17
  """Define paths within the DISDRODB infrastructure."""
18
+
20
19
  import os
21
20
 
22
21
  from disdrodb.configs import get_data_archive_dir, get_metadata_archive_dir
23
22
  from disdrodb.constants import ARCHIVE_VERSION
24
23
  from disdrodb.utils.directories import check_directory_exists
25
24
  from disdrodb.utils.time import (
26
- ensure_sample_interval_in_seconds,
27
25
  get_file_start_end_time,
28
26
  seconds_to_temporal_resolution,
29
27
  )
@@ -805,10 +803,8 @@ def define_l0b_filename(ds, campaign_name: str, station_name: str) -> str:
805
803
  return filename
806
804
 
807
805
 
808
- def define_l0c_filename(ds, campaign_name: str, station_name: str) -> str:
806
+ def define_l0c_filename(ds, campaign_name: str, station_name: str, sample_interval: str) -> str:
809
807
  """Define L0C file name."""
810
- # TODO: add sample_interval as function argument
811
- sample_interval = int(ensure_sample_interval_in_seconds(ds["sample_interval"]).data.item())
812
808
  temporal_resolution = define_temporal_resolution(sample_interval, rolling=False)
813
809
  starting_time, ending_time = get_file_start_end_time(ds)
814
810
  starting_time = starting_time.strftime("%Y%m%d%H%M%S")
@@ -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
  """Wrapper to check DISDRODB Metadata Archive Compliance from terminal."""
18
+
18
19
  import sys
19
20
 
20
21
  import click
@@ -34,7 +35,7 @@ sys.tracebacklimit = 0 # avoid full traceback error if occur
34
35
  help="Whether to raise error of finish the check",
35
36
  )
36
37
  def disdrodb_check_metadata_archive(metadata_archive_dir=None, raise_error=True):
37
- """Run the DISDRODB Metadata Archive Checks."""
38
+ """Validate the DISDRODB Metadata Archive."""
38
39
  from disdrodb.metadata.checks import check_metadata_archive
39
40
 
40
41
  metadata_archive_dir = parse_archive_dir(metadata_archive_dir)