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
@@ -23,34 +23,107 @@ import logging
23
23
  import os
24
24
  import pathlib
25
25
  import shutil
26
+ from typing import Union
27
+
28
+ from disdrodb.utils.list import flatten_list
29
+ from disdrodb.utils.logger import log_info
26
30
 
27
31
  logger = logging.getLogger(__name__)
28
32
 
29
33
 
30
34
  def ensure_string_path(path, msg, accepth_pathlib=False):
31
- if accepth_pathlib:
32
- valid_types = (str, pathlib.PurePath)
33
- else:
34
- valid_types = str
35
+ """Ensure that the path is a string."""
36
+ valid_types = (str, pathlib.PurePath) if accepth_pathlib else str
35
37
  if not isinstance(path, valid_types):
36
38
  raise TypeError(msg)
37
39
  return str(path)
38
40
 
39
41
 
42
+ def contains_netcdf_or_parquet_files(dir_path: str) -> bool:
43
+ """Check (recursively) if a directory has any Parquet or netCDF file.
44
+
45
+ os.walk under the hood uses os.scandir
46
+ os.walk file generator + any() avoid use of while loop
47
+
48
+ The function returns True as soon as one file is found (short-circuit)^; False otherwise.
49
+ """
50
+ suffixes = (".nc", ".parquet")
51
+ return any(fname.endswith(suffixes) for _, _, files in os.walk(dir_path) for fname in files)
52
+
53
+
54
+ def contains_files(dir_path: str) -> bool:
55
+ """Check (recursively) if a directory contains any file.
56
+
57
+ os.walk under the hood uses os.scandir
58
+ os.walk file generator + any() avoid use of while loop
59
+
60
+ The function returns True as soon as one file is found (short-circuit); False otherwise.
61
+ """
62
+ return any(fname for _, _, files in os.walk(dir_path) for fname in files)
63
+
64
+
65
+ def check_glob_pattern(pattern: str) -> None:
66
+ """Check if glob pattern is a string and is a valid pattern.
67
+
68
+ Parameters
69
+ ----------
70
+ pattern : str
71
+ String to be checked.
72
+ """
73
+ if not isinstance(pattern, str):
74
+ raise TypeError("Expect pattern as a string.")
75
+ if pattern[0] == "/":
76
+ raise ValueError("glob_pattern should not start with /")
77
+ if "//" in pattern:
78
+ raise ValueError("glob_pattern expects path with single separators: /, not //")
79
+ if "\\" in pattern:
80
+ raise ValueError("glob_pattern expects path separators to be /, not \\")
81
+ return pattern
82
+
83
+
84
+ def check_glob_patterns(patterns: Union[str, list]) -> list:
85
+ """Check if glob patterns are valids."""
86
+ if not isinstance(patterns, (str, list)):
87
+ raise ValueError("'glob_patterns' must be a str or list of strings.")
88
+ if isinstance(patterns, str):
89
+ patterns = [patterns]
90
+ patterns = [check_glob_pattern(pattern) for pattern in patterns]
91
+ return patterns
92
+
93
+
40
94
  def _recursive_glob(dir_path, glob_pattern):
41
- # ** search for all files recursively
42
- # glob_pattern = os.path.join(base_dir, "**", "metadata", f"{station_name}.yml")
43
- # metadata_filepaths = glob.glob(glob_pattern, recursive=True)
95
+ # ** search for in zero or all subdirectories recursively
44
96
 
45
97
  dir_path = pathlib.Path(dir_path)
46
98
  return [str(path) for path in dir_path.rglob(glob_pattern)]
47
99
 
48
100
 
49
- def list_paths(dir_path, glob_pattern, recursive=False):
101
+ def _list_paths(dir_path, glob_pattern, recursive=False):
102
+ """Return a list of filepaths and directory paths based on a single glob pattern."""
103
+ # If glob pattern has separators, disable recursive option
104
+ if "/" in glob_pattern and "**" not in glob_pattern:
105
+ recursive = False
106
+ # Search paths
50
107
  if not recursive:
51
108
  return glob.glob(os.path.join(dir_path, glob_pattern))
52
- else:
53
- return _recursive_glob(dir_path, glob_pattern)
109
+ return _recursive_glob(dir_path, glob_pattern)
110
+
111
+
112
+ def list_paths(dir_path, glob_pattern, recursive=False):
113
+ """Return a list of filepaths and directory paths.
114
+
115
+ This function accept also a list of glob patterns !
116
+ """
117
+ # Check validity of glob pattern(s)
118
+ glob_patterns = check_glob_patterns(glob_pattern)
119
+ # Search path for specified glob patterns
120
+ paths = flatten_list(
121
+ [
122
+ _list_paths(dir_path=dir_path, glob_pattern=glob_pattern, recursive=recursive)
123
+ for glob_pattern in glob_patterns
124
+ ],
125
+ )
126
+ return paths
54
127
 
55
128
 
56
129
  def list_files(dir_path, glob_pattern, recursive=False):
@@ -78,7 +151,7 @@ def count_directories(dir_path, glob_pattern, recursive=False):
78
151
 
79
152
 
80
153
  def check_directory_exists(dir_path):
81
- """Check if the directory exist."""
154
+ """Check if the directory exists."""
82
155
  if not os.path.exists(dir_path):
83
156
  raise ValueError(f"{dir_path} directory does not exist.")
84
157
  if not os.path.isdir(dir_path):
@@ -90,29 +163,24 @@ def create_directory(path: str, exist_ok=True) -> None:
90
163
  path = ensure_string_path(path, msg="'path' must be a string", accepth_pathlib=True)
91
164
  try:
92
165
  os.makedirs(path, exist_ok=exist_ok)
93
- logger.debug(f"Created directory {path}.")
94
166
  except Exception as e:
167
+ dir_path = os.path.dirname(path)
95
168
  dir_name = os.path.basename(path)
96
- msg = f"Can not create directory {dir_name} inside <path>. Error: {e}"
97
- logger.exception(msg)
169
+ msg = f"Can not create directory {dir_name} inside {dir_path}. Error: {e}"
98
170
  raise FileNotFoundError(msg)
99
171
 
100
172
 
101
- def create_required_directory(dir_path, dir_name):
102
- """Create directory <dir_name> inside the <dir_path> directory."""
103
- try:
104
- new_dir = os.path.join(dir_path, dir_name)
105
- os.makedirs(new_dir, exist_ok=True)
106
- except Exception as e:
107
- msg = f"Can not create directory {dir_name} at {new_dir}. Error: {e}"
108
- logger.exception(msg)
109
- raise FileNotFoundError(msg)
173
+ def create_required_directory(dir_path, dir_name, exist_ok=True):
174
+ """Create directory ``dir_name`` inside the ``dir_path`` directory."""
175
+ dir_path = ensure_string_path(dir_path, msg="'path' must be a string", accepth_pathlib=True)
176
+ new_dir_path = os.path.join(dir_path, dir_name)
177
+ create_directory(path=new_dir_path, exist_ok=exist_ok)
110
178
 
111
179
 
112
180
  def is_empty_directory(path):
113
181
  """Check if a directory path is empty.
114
182
 
115
- Return False if path is a file or non-empty directory.
183
+ Return ``False`` if path is a file or non-empty directory.
116
184
  If the path does not exist, raise an error.
117
185
  """
118
186
  if not os.path.exists(path):
@@ -121,53 +189,47 @@ def is_empty_directory(path):
121
189
  return False
122
190
 
123
191
  paths = os.listdir(path)
124
- if len(paths) == 0:
125
- return True
126
- else:
127
- return False
192
+ return len(paths) == 0
128
193
 
129
194
 
130
- def _remove_file_or_directories(path):
131
- """Return the file/directory or subdirectories tree of 'path'.
195
+ def _remove_file_or_directories(path, logger=None):
196
+ """Return the file/directory or subdirectories tree of ``path``.
132
197
 
133
198
  Use this function with caution.
134
199
  """
135
200
  # If file
136
201
  if os.path.isfile(path):
137
202
  os.remove(path)
138
- logger.info(f"Deleted the file {path}")
203
+ log_info(logger, msg=f"Deleted the file {path}")
139
204
  # If empty directory
140
205
  elif is_empty_directory(path):
141
206
  os.rmdir(path)
142
- logger.info(f"Deleted the empty directory {path}")
207
+ log_info(logger, msg=f"Deleted the empty directory {path}")
143
208
  # If not empty directory
144
209
  else:
145
210
  shutil.rmtree(path)
146
- logger.info(f"Deleted directories within {path}")
147
- return None
211
+ log_info(logger, msg=f"Deleted directories within {path}")
148
212
 
149
213
 
150
- def remove_if_exists(path: str, force: bool = False) -> None:
151
- """Remove file or directory if exists and force=True.
214
+ def remove_if_exists(path: str, force: bool = False, logger=None) -> None:
215
+ """Remove file or directory if exists and ``force=True``.
152
216
 
153
- If force=False --> Raise error
217
+ If ``force=False``, it raises an error.
154
218
  """
155
219
  # If the path does not exist, do nothing
156
220
  if not os.path.exists(path):
157
- return None
221
+ return
158
222
 
159
223
  # If the path exists and force=False, raise Error
160
224
  if not force:
161
225
  msg = f"--force is False and a file already exists at: {path}"
162
- logger.error(msg)
163
226
  raise ValueError(msg)
164
227
 
165
228
  # If force=True, remove the file/directory or subdirectories and files !
166
229
  try:
167
- _remove_file_or_directories(path)
230
+ _remove_file_or_directories(path, logger=logger)
168
231
  except Exception as e:
169
232
  msg = f"Can not delete file(s) at {path}. The error is: {e}"
170
- logger.error(msg)
171
233
  raise ValueError(msg)
172
234
 
173
235
 
@@ -181,18 +243,17 @@ def copy_file(src_filepath, dst_filepath):
181
243
  logger.info(msg)
182
244
  except Exception as e:
183
245
  msg = f"Something went wrong when copying {filename} into {dst_dir}.\n The error is: {e}."
184
- logger.error(msg)
185
246
  raise ValueError(msg)
186
247
 
187
248
 
188
249
  def remove_path_trailing_slash(path: str) -> str:
189
- """
250
+ r"""
190
251
  Removes a trailing slash or backslash from a file path if it exists.
191
252
 
192
253
  This function ensures that the provided file path is normalized by removing
193
- any trailing directory separator characters ('/' or '\\'). This is useful for
194
- maintaining consistency in path strings and for preparing paths for operations
195
- that may not expect a trailing slash.
254
+ any trailing directory separator characters (``'/'`` or ``'\\'``).
255
+ This is useful for maintaining consistency in path strings and for
256
+ preparing paths for operations that may not expect a trailing slash.
196
257
 
197
258
  Parameters
198
259
  ----------
@@ -0,0 +1,127 @@
1
+ #!/usr/bin/env python3
2
+
3
+ # -----------------------------------------------------------------------------.
4
+ # Copyright (c) 2021-2023 DISDRODB developers
5
+ #
6
+ # This program is free software: you can redistribute it and/or modify
7
+ # it under the terms of the GNU General Public License as published by
8
+ # the Free Software Foundation, either version 3 of the License, or
9
+ # (at your option) any later version.
10
+ #
11
+ # This program is distributed in the hope that it will be useful,
12
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ # GNU General Public License for more details.
15
+ #
16
+ # You should have received a copy of the GNU General Public License
17
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
18
+ # -----------------------------------------------------------------------------.
19
+ """DISDRODB netCDF4 encoding utilities."""
20
+ import xarray as xr
21
+
22
+ EPOCH = "seconds since 1970-01-01 00:00:00"
23
+
24
+
25
+ def set_encodings(ds: xr.Dataset, encoding_dict: dict) -> xr.Dataset:
26
+ """Apply the encodings to the xarray Dataset.
27
+
28
+ Parameters
29
+ ----------
30
+ ds : xarray.Dataset
31
+ Input xarray dataset.
32
+ encoding_dict : dict
33
+ Dictionary with encoding specifications.
34
+
35
+ Returns
36
+ -------
37
+ xarray.Dataset
38
+ Output xarray dataset.
39
+ """
40
+ # Subset encoding dictionary
41
+ # - Here below encoding_dict contains only keys (variables) within the dataset
42
+ encoding_dict = {var: encoding_dict[var] for var in ds.data_vars if var in encoding_dict}
43
+
44
+ # Ensure chunksize smaller than the array shape
45
+ encoding_dict = sanitize_encodings_dict(encoding_dict, ds)
46
+
47
+ # Rechunk variables for fast writing !
48
+ # - This pop the chunksize argument from the encoding dict !
49
+ ds = rechunk_dataset(ds, encoding_dict)
50
+
51
+ # Set time encoding
52
+ ds["time"].encoding.update(get_time_encoding())
53
+
54
+ # Set the variable encodings
55
+ for var, encoding in encoding_dict.items():
56
+ ds[var].encoding.update(encoding)
57
+
58
+ # Ensure no deprecated "missing_value" attribute
59
+ # - When source dataset is netcdf (i.e. ARM)
60
+ for var in list(ds.variables):
61
+ _ = ds[var].encoding.pop("missing_value", None)
62
+
63
+ return ds
64
+
65
+
66
+ def sanitize_encodings_dict(encoding_dict: dict, ds: xr.Dataset) -> dict:
67
+ """Ensure chunk size to be smaller than the array shape.
68
+
69
+ Parameters
70
+ ----------
71
+ encoding_dict : dict
72
+ Dictionary containing the variable encodings.
73
+ ds : xarray.Dataset
74
+ Input dataset.
75
+
76
+ Returns
77
+ -------
78
+ dict
79
+ Encoding dictionary.
80
+ """
81
+ for var in ds.data_vars:
82
+ if var in encoding_dict:
83
+ shape = ds[var].shape
84
+ chunks = encoding_dict[var].get("chunksizes", None)
85
+ if chunks is not None:
86
+ chunks = [shape[i] if chunks[i] > shape[i] else chunks[i] for i in range(len(chunks))]
87
+ encoding_dict[var]["chunksizes"] = chunks
88
+ return encoding_dict
89
+
90
+
91
+ def rechunk_dataset(ds: xr.Dataset, encoding_dict: dict) -> xr.Dataset:
92
+ """Coerce the dataset arrays to have the chunk size specified in the encoding dictionary.
93
+
94
+ Parameters
95
+ ----------
96
+ ds : xarray.Dataset
97
+ Input xarray dataset
98
+ encoding_dict : dict
99
+ Dictionary containing the encoding to write the xarray dataset as a netCDF.
100
+
101
+ Returns
102
+ -------
103
+ xarray.Dataset
104
+ Output xarray dataset
105
+ """
106
+ for var in ds.data_vars:
107
+ if var in encoding_dict:
108
+ chunks = encoding_dict[var].pop("chunksizes", None)
109
+ if chunks is not None:
110
+ dims = list(ds[var].dims)
111
+ chunks_dict = dict(zip(dims, chunks))
112
+ ds[var] = ds[var].chunk(chunks_dict)
113
+ return ds
114
+
115
+
116
+ def get_time_encoding() -> dict:
117
+ """Create time encoding.
118
+
119
+ Returns
120
+ -------
121
+ dict
122
+ Time encoding.
123
+ """
124
+ encoding = {}
125
+ encoding["units"] = EPOCH
126
+ encoding["calendar"] = "proleptic_gregorian"
127
+ return encoding
disdrodb/utils/list.py ADDED
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env python3
2
+
3
+ # -----------------------------------------------------------------------------.
4
+ # Copyright (c) 2021-2023 DISDRODB developers
5
+ #
6
+ # This program is free software: you can redistribute it and/or modify
7
+ # it under the terms of the GNU General Public License as published by
8
+ # the Free Software Foundation, either version 3 of the License, or
9
+ # (at your option) any later version.
10
+ #
11
+ # This program is distributed in the hope that it will be useful,
12
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ # GNU General Public License for more details.
15
+ #
16
+ # You should have received a copy of the GNU General Public License
17
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
18
+ # -----------------------------------------------------------------------------.
19
+ """Utilities to work with lists."""
20
+
21
+
22
+ def flatten_list(nested_list):
23
+ """Flatten a nested list into a single-level list."""
24
+ if isinstance(nested_list, list) and len(nested_list) == 0:
25
+ return nested_list
26
+ # If list is already flat, return as is to avoid flattening to chars
27
+ if isinstance(nested_list, list) and not isinstance(nested_list[0], list):
28
+ return nested_list
29
+ return [item for sublist in nested_list for item in sublist] if isinstance(nested_list, list) else [nested_list]