disdrodb 0.0.21__py3-none-any.whl → 0.1.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 (264) 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 +295 -269
  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 +32 -42
  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 +62 -59
  57. disdrodb/l0/configs/{Thies_LPM → LPM}/l0b_encodings.yml +9 -9
  58. disdrodb/l0/configs/{Thies_LPM → LPM}/raw_data_format.yml +245 -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 +22 -20
  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 +24 -22
  69. disdrodb/l0/configs/{OTT_Parsivel2 → PARSIVEL2}/l0b_encodings.yml +20 -20
  70. disdrodb/l0/configs/{OTT_Parsivel2 → PARSIVEL2}/raw_data_format.yml +98 -98
  71. disdrodb/l0/configs/{RD_80 → RD80}/bins_diameter.yml +40 -40
  72. disdrodb/l0/configs/RD80/l0a_encodings.yml +16 -0
  73. disdrodb/l0/configs/{RD_80 → RD80}/l0b_cf_attrs.yml +3 -3
  74. disdrodb/l0/configs/RD80/l0b_encodings.yml +135 -0
  75. disdrodb/l0/configs/{RD_80 → RD80}/raw_data_format.yml +48 -48
  76. disdrodb/l0/l0_reader.py +216 -340
  77. disdrodb/l0/l0a_processing.py +237 -208
  78. disdrodb/l0/l0b_nc_processing.py +227 -80
  79. disdrodb/l0/l0b_processing.py +93 -173
  80. disdrodb/l0/l0c_processing.py +627 -0
  81. disdrodb/l0/readers/{ARM → LPM/ARM}/ARM_LPM.py +36 -58
  82. disdrodb/l0/readers/LPM/AUSTRALIA/MELBOURNE_2007_LPM.py +226 -0
  83. disdrodb/l0/readers/LPM/BRAZIL/CHUVA_LPM.py +185 -0
  84. disdrodb/l0/readers/LPM/BRAZIL/GOAMAZON_LPM.py +183 -0
  85. disdrodb/l0/readers/LPM/ITALY/GID_LPM.py +179 -0
  86. disdrodb/l0/readers/{UK → LPM/UK}/DIVEN.py +14 -35
  87. disdrodb/l0/readers/PARSIVEL/AUSTRALIA/MELBOURNE_2007_PARSIVEL.py +157 -0
  88. disdrodb/l0/readers/PARSIVEL/CHINA/CHONGQING.py +113 -0
  89. disdrodb/l0/readers/{EPFL → PARSIVEL/EPFL}/ARCTIC_2021.py +40 -57
  90. disdrodb/l0/readers/{EPFL → PARSIVEL/EPFL}/COMMON_2011.py +37 -54
  91. disdrodb/l0/readers/{EPFL → PARSIVEL/EPFL}/DAVOS_2009_2011.py +34 -51
  92. disdrodb/l0/readers/{EPFL → PARSIVEL/EPFL}/EPFL_2009.py +34 -51
  93. disdrodb/l0/readers/{EPFL/PARADISO_2014.py → PARSIVEL/EPFL/EPFL_ROOF_2008.py} +38 -50
  94. disdrodb/l0/readers/PARSIVEL/EPFL/EPFL_ROOF_2010.py +105 -0
  95. disdrodb/l0/readers/{EPFL → PARSIVEL/EPFL}/EPFL_ROOF_2011.py +34 -51
  96. disdrodb/l0/readers/{EPFL → PARSIVEL/EPFL}/EPFL_ROOF_2012.py +33 -51
  97. disdrodb/l0/readers/{EPFL → PARSIVEL/EPFL}/GENEPI_2007.py +25 -44
  98. disdrodb/l0/readers/{EPFL → PARSIVEL/EPFL}/GRAND_ST_BERNARD_2007.py +25 -44
  99. disdrodb/l0/readers/{EPFL → PARSIVEL/EPFL}/GRAND_ST_BERNARD_2007_2.py +25 -44
  100. disdrodb/l0/readers/{EPFL → PARSIVEL/EPFL}/HPICONET_2010.py +34 -51
  101. disdrodb/l0/readers/{EPFL/EPFL_ROOF_2010.py → PARSIVEL/EPFL/HYMEX_LTE_SOP2.py} +37 -50
  102. disdrodb/l0/readers/PARSIVEL/EPFL/HYMEX_LTE_SOP3.py +111 -0
  103. disdrodb/l0/readers/{EPFL → PARSIVEL/EPFL}/HYMEX_LTE_SOP4.py +36 -54
  104. disdrodb/l0/readers/{EPFL → PARSIVEL/EPFL}/LOCARNO_2018.py +34 -52
  105. disdrodb/l0/readers/{EPFL → PARSIVEL/EPFL}/LOCARNO_2019.py +38 -56
  106. disdrodb/l0/readers/PARSIVEL/EPFL/PARADISO_2014.py +105 -0
  107. disdrodb/l0/readers/{EPFL → PARSIVEL/EPFL}/PARSIVEL_2007.py +27 -45
  108. disdrodb/l0/readers/{EPFL → PARSIVEL/EPFL}/PLATO_2019.py +24 -44
  109. disdrodb/l0/readers/PARSIVEL/EPFL/RACLETS_2019.py +140 -0
  110. disdrodb/l0/readers/{EPFL → PARSIVEL/EPFL}/RACLETS_2019_WJF.py +41 -59
  111. disdrodb/l0/readers/{EPFL → PARSIVEL/EPFL}/RIETHOLZBACH_2011.py +34 -51
  112. disdrodb/l0/readers/PARSIVEL/EPFL/SAMOYLOV_2017.py +117 -0
  113. disdrodb/l0/readers/PARSIVEL/EPFL/SAMOYLOV_2019.py +137 -0
  114. disdrodb/l0/readers/{EPFL → PARSIVEL/EPFL}/UNIL_2022.py +42 -55
  115. disdrodb/l0/readers/PARSIVEL/GPM/IFLOODS.py +104 -0
  116. disdrodb/l0/readers/{GPM → PARSIVEL/GPM}/LPVEX.py +29 -48
  117. disdrodb/l0/readers/PARSIVEL/GPM/MC3E.py +184 -0
  118. disdrodb/l0/readers/PARSIVEL/NCAR/CCOPE_2015.py +113 -0
  119. disdrodb/l0/readers/{NCAR/VORTEX_SE_2016_P1.py → PARSIVEL/NCAR/OWLES_MIPS.py} +46 -72
  120. disdrodb/l0/readers/PARSIVEL/NCAR/PECAN_MOBILE.py +125 -0
  121. disdrodb/l0/readers/{NCAR/OWLES_MIPS.py → PARSIVEL/NCAR/PLOWS_MIPS.py} +45 -64
  122. disdrodb/l0/readers/PARSIVEL/NCAR/VORTEX2_2009.py +114 -0
  123. disdrodb/l0/readers/PARSIVEL/NCAR/VORTEX2_2010.py +176 -0
  124. disdrodb/l0/readers/PARSIVEL/NCAR/VORTEX2_2010_UF.py +183 -0
  125. disdrodb/l0/readers/{ARM/ARM_LD.py → PARSIVEL2/ARM/ARM_PARSIVEL2.py} +27 -50
  126. disdrodb/l0/readers/PARSIVEL2/BRAZIL/CHUVA_PARSIVEL2.py +163 -0
  127. disdrodb/l0/readers/PARSIVEL2/BRAZIL/GOAMAZON_PARSIVEL2.py +163 -0
  128. disdrodb/l0/readers/{DENMARK → PARSIVEL2/DENMARK}/EROSION_nc.py +14 -35
  129. disdrodb/l0/readers/PARSIVEL2/FRANCE/SIRTA_PARSIVEL2.py +119 -0
  130. disdrodb/l0/readers/PARSIVEL2/GPM/GCPEX.py +104 -0
  131. disdrodb/l0/readers/PARSIVEL2/GPM/NSSTC.py +176 -0
  132. disdrodb/l0/readers/PARSIVEL2/ITALY/GID_PARSIVEL2.py +32 -0
  133. disdrodb/l0/readers/PARSIVEL2/MEXICO/OH_IIUNAM_nc.py +56 -0
  134. disdrodb/l0/readers/PARSIVEL2/NCAR/PECAN_FP3.py +120 -0
  135. disdrodb/l0/readers/{NCAR → PARSIVEL2/NCAR}/PECAN_MIPS.py +45 -64
  136. disdrodb/l0/readers/PARSIVEL2/NCAR/RELAMPAGO_PARSIVEL2.py +181 -0
  137. disdrodb/l0/readers/PARSIVEL2/NCAR/SNOWIE_PJ.py +160 -0
  138. disdrodb/l0/readers/PARSIVEL2/NCAR/SNOWIE_SB.py +160 -0
  139. disdrodb/l0/readers/{NCAR/PLOWS_MIPS.py → PARSIVEL2/NCAR/VORTEX_SE_2016_P1.py} +49 -66
  140. disdrodb/l0/readers/PARSIVEL2/NCAR/VORTEX_SE_2016_P2.py +118 -0
  141. disdrodb/l0/readers/PARSIVEL2/NCAR/VORTEX_SE_2016_PIPS.py +152 -0
  142. disdrodb/l0/readers/PARSIVEL2/NETHERLANDS/DELFT.py +166 -0
  143. disdrodb/l0/readers/{NCAR/RELAMPAGO_RD80.py → RD80/BRAZIL/CHUVA_RD80.py} +36 -60
  144. disdrodb/l0/readers/{BRAZIL → RD80/BRAZIL}/GOAMAZON_RD80.py +36 -55
  145. disdrodb/l0/readers/{NCAR → RD80/NCAR}/CINDY_2011_RD80.py +35 -54
  146. disdrodb/l0/readers/{BRAZIL/CHUVA_RD80.py → RD80/NCAR/RELAMPAGO_RD80.py} +40 -54
  147. disdrodb/l0/readers/template_reader_raw_netcdf_data.py +62 -0
  148. disdrodb/l0/readers/{reader_template.py → template_reader_raw_text_data.py} +20 -44
  149. disdrodb/l0/routines.py +885 -581
  150. disdrodb/l0/standards.py +72 -236
  151. disdrodb/l0/template_tools.py +104 -109
  152. disdrodb/l1/__init__.py +17 -0
  153. disdrodb/l1/beard_model.py +716 -0
  154. disdrodb/l1/encoding_attrs.py +620 -0
  155. disdrodb/l1/fall_velocity.py +260 -0
  156. disdrodb/l1/filters.py +192 -0
  157. disdrodb/l1/processing.py +200 -0
  158. disdrodb/l1/resampling.py +236 -0
  159. disdrodb/l1/routines.py +357 -0
  160. disdrodb/l1_env/__init__.py +17 -0
  161. disdrodb/l1_env/routines.py +38 -0
  162. disdrodb/l2/__init__.py +17 -0
  163. disdrodb/l2/empirical_dsd.py +1735 -0
  164. disdrodb/l2/event.py +388 -0
  165. disdrodb/l2/processing.py +519 -0
  166. disdrodb/l2/processing_options.py +213 -0
  167. disdrodb/l2/routines.py +868 -0
  168. disdrodb/metadata/__init__.py +9 -2
  169. disdrodb/metadata/checks.py +165 -118
  170. disdrodb/metadata/download.py +81 -0
  171. disdrodb/metadata/geolocation.py +146 -0
  172. disdrodb/metadata/info.py +20 -13
  173. disdrodb/metadata/manipulation.py +1 -1
  174. disdrodb/metadata/reader.py +59 -8
  175. disdrodb/metadata/search.py +77 -144
  176. disdrodb/metadata/standards.py +7 -8
  177. disdrodb/metadata/writer.py +8 -14
  178. disdrodb/psd/__init__.py +38 -0
  179. disdrodb/psd/fitting.py +2146 -0
  180. disdrodb/psd/models.py +774 -0
  181. disdrodb/routines.py +1176 -0
  182. disdrodb/scattering/__init__.py +28 -0
  183. disdrodb/scattering/axis_ratio.py +344 -0
  184. disdrodb/scattering/routines.py +456 -0
  185. disdrodb/utils/__init__.py +17 -0
  186. disdrodb/utils/attrs.py +208 -0
  187. disdrodb/utils/cli.py +269 -0
  188. disdrodb/utils/compression.py +60 -42
  189. disdrodb/utils/dask.py +62 -0
  190. disdrodb/utils/decorators.py +110 -0
  191. disdrodb/utils/directories.py +107 -46
  192. disdrodb/utils/encoding.py +127 -0
  193. disdrodb/utils/list.py +29 -0
  194. disdrodb/utils/logger.py +168 -46
  195. disdrodb/utils/time.py +657 -0
  196. disdrodb/utils/warnings.py +30 -0
  197. disdrodb/utils/writer.py +57 -0
  198. disdrodb/utils/xarray.py +138 -47
  199. disdrodb/utils/yaml.py +0 -1
  200. disdrodb/viz/__init__.py +17 -0
  201. disdrodb/viz/plots.py +17 -0
  202. disdrodb-0.1.0.dist-info/METADATA +321 -0
  203. disdrodb-0.1.0.dist-info/RECORD +216 -0
  204. {disdrodb-0.0.21.dist-info → disdrodb-0.1.0.dist-info}/WHEEL +1 -1
  205. disdrodb-0.1.0.dist-info/entry_points.txt +30 -0
  206. disdrodb/data_transfer/scripts/disdrodb_download_archive.py +0 -53
  207. disdrodb/data_transfer/scripts/disdrodb_upload_archive.py +0 -57
  208. disdrodb/l0/configs/OTT_Parsivel/l0a_encodings.yml +0 -32
  209. disdrodb/l0/configs/OTT_Parsivel2/l0a_encodings.yml +0 -39
  210. disdrodb/l0/configs/RD_80/l0a_encodings.yml +0 -16
  211. disdrodb/l0/configs/RD_80/l0b_encodings.yml +0 -135
  212. disdrodb/l0/configs/Thies_LPM/l0a_encodings.yml +0 -80
  213. disdrodb/l0/io.py +0 -257
  214. disdrodb/l0/l0_processing.py +0 -1091
  215. disdrodb/l0/readers/AUSTRALIA/MELBOURNE_2007_OTT.py +0 -178
  216. disdrodb/l0/readers/AUSTRALIA/MELBOURNE_2007_THIES.py +0 -247
  217. disdrodb/l0/readers/BRAZIL/CHUVA_LPM.py +0 -204
  218. disdrodb/l0/readers/BRAZIL/CHUVA_OTT.py +0 -183
  219. disdrodb/l0/readers/BRAZIL/GOAMAZON_LPM.py +0 -204
  220. disdrodb/l0/readers/BRAZIL/GOAMAZON_OTT.py +0 -183
  221. disdrodb/l0/readers/CHINA/CHONGQING.py +0 -131
  222. disdrodb/l0/readers/EPFL/EPFL_ROOF_2008.py +0 -128
  223. disdrodb/l0/readers/EPFL/HYMEX_LTE_SOP2.py +0 -127
  224. disdrodb/l0/readers/EPFL/HYMEX_LTE_SOP3.py +0 -129
  225. disdrodb/l0/readers/EPFL/RACLETS_2019.py +0 -158
  226. disdrodb/l0/readers/EPFL/SAMOYLOV_2017.py +0 -136
  227. disdrodb/l0/readers/EPFL/SAMOYLOV_2019.py +0 -158
  228. disdrodb/l0/readers/FRANCE/SIRTA_OTT2.py +0 -138
  229. disdrodb/l0/readers/GPM/GCPEX.py +0 -123
  230. disdrodb/l0/readers/GPM/IFLOODS.py +0 -123
  231. disdrodb/l0/readers/GPM/MC3E.py +0 -123
  232. disdrodb/l0/readers/GPM/NSSTC.py +0 -164
  233. disdrodb/l0/readers/ITALY/GID.py +0 -199
  234. disdrodb/l0/readers/MEXICO/OH_IIUNAM_nc.py +0 -92
  235. disdrodb/l0/readers/NCAR/CCOPE_2015.py +0 -133
  236. disdrodb/l0/readers/NCAR/PECAN_FP3.py +0 -137
  237. disdrodb/l0/readers/NCAR/PECAN_MOBILE.py +0 -144
  238. disdrodb/l0/readers/NCAR/RELAMPAGO_OTT.py +0 -195
  239. disdrodb/l0/readers/NCAR/SNOWIE_PJ.py +0 -172
  240. disdrodb/l0/readers/NCAR/SNOWIE_SB.py +0 -179
  241. disdrodb/l0/readers/NCAR/VORTEX2_2009.py +0 -133
  242. disdrodb/l0/readers/NCAR/VORTEX2_2010.py +0 -188
  243. disdrodb/l0/readers/NCAR/VORTEX2_2010_UF.py +0 -191
  244. disdrodb/l0/readers/NCAR/VORTEX_SE_2016_P2.py +0 -135
  245. disdrodb/l0/readers/NCAR/VORTEX_SE_2016_PIPS.py +0 -170
  246. disdrodb/l0/readers/NETHERLANDS/DELFT.py +0 -187
  247. disdrodb/l0/readers/SPAIN/SBEGUERIA.py +0 -179
  248. disdrodb/l0/scripts/disdrodb_run_l0b_concat.py +0 -93
  249. disdrodb/l0/scripts/disdrodb_run_l0b_concat_station.py +0 -85
  250. disdrodb/utils/netcdf.py +0 -452
  251. disdrodb/utils/scripts.py +0 -102
  252. disdrodb-0.0.21.dist-info/AUTHORS.md +0 -18
  253. disdrodb-0.0.21.dist-info/METADATA +0 -186
  254. disdrodb-0.0.21.dist-info/RECORD +0 -168
  255. disdrodb-0.0.21.dist-info/entry_points.txt +0 -15
  256. /disdrodb/l0/configs/{RD_80 → RD80}/bins_velocity.yml +0 -0
  257. /disdrodb/l0/manuals/{Thies_LPM.pdf → LPM.pdf} +0 -0
  258. /disdrodb/l0/manuals/{ODM_470.pdf → ODM470.pdf} +0 -0
  259. /disdrodb/l0/manuals/{OTT_Parsivel.pdf → PARSIVEL.pdf} +0 -0
  260. /disdrodb/l0/manuals/{OTT_Parsivel2.pdf → PARSIVEL2.pdf} +0 -0
  261. /disdrodb/l0/manuals/{PWS_100.pdf → PWS100.pdf} +0 -0
  262. /disdrodb/l0/manuals/{RD_80.pdf → RD80.pdf} +0 -0
  263. {disdrodb-0.0.21.dist-info → disdrodb-0.1.0.dist-info/licenses}/LICENSE +0 -0
  264. {disdrodb-0.0.21.dist-info → disdrodb-0.1.0.dist-info}/top_level.txt +0 -0
disdrodb/api/io.py CHANGED
@@ -16,311 +16,337 @@
16
16
  # You should have received a copy of the GNU General Public License
17
17
  # along with this program. If not, see <http://www.gnu.org/licenses/>.
18
18
  # -----------------------------------------------------------------------------.
19
- """Routines tot extract information from the DISDRODB infrastructure."""
20
-
19
+ """Routines to list and open DISDRODB products."""
21
20
  import os
21
+ import shutil
22
+ import subprocess
23
+ import sys
24
+ from pathlib import Path
25
+ from typing import Optional
26
+
27
+ from disdrodb.api.path import (
28
+ define_campaign_dir,
29
+ define_data_dir,
30
+ define_metadata_dir,
31
+ define_station_dir,
32
+ )
33
+ from disdrodb.l0.l0_reader import define_readers_directory
34
+ from disdrodb.utils.directories import list_files
35
+ from disdrodb.utils.logger import (
36
+ log_info,
37
+ )
38
+
39
+ ####----------------------------------------------------------------------------------
40
+ #### DISDRODB Search Product Files
41
+
42
+
43
+ def filter_filepaths(filepaths, debugging_mode):
44
+ """Filter out filepaths if ``debugging_mode=True``."""
45
+ if debugging_mode:
46
+ max_files = min(3, len(filepaths))
47
+ filepaths = filepaths[0:max_files]
48
+ return filepaths
49
+
50
+
51
+ def find_files(
52
+ data_source,
53
+ campaign_name,
54
+ station_name,
55
+ product,
56
+ debugging_mode: bool = False,
57
+ data_archive_dir: Optional[str] = None,
58
+ glob_pattern="*",
59
+ **product_kwargs,
60
+ ):
61
+ """Retrieve DISDRODB product files for a give station.
62
+
63
+ Parameters
64
+ ----------
65
+ data_source : str
66
+ The name of the institution (for campaigns spanning multiple countries) or
67
+ the name of the country (for campaigns or sensor networks within a single country).
68
+ Must be provided in UPPER CASE.
69
+ campaign_name : str
70
+ The name of the campaign. Must be provided in UPPER CASE.
71
+ station_name : str
72
+ The name of the station.
73
+ product : str
74
+ The name DISDRODB product.
75
+ debugging_mode : bool, optional
76
+ If ``True``, it select maximum 3 files for debugging purposes.
77
+ The default value is ``False``.
78
+ data_archive_dir : str, optional
79
+ The base directory of DISDRODB, expected in the format ``<...>/DISDRODB``.
80
+ If not specified, the path specified in the DISDRODB active configuration will be used.
81
+ glob_pattern: str, optional
82
+ Glob pattern to search for raw data files. The default is "*".
83
+ The argument is used only if product="RAW".
84
+
85
+ Other Parameters
86
+ ----------------
87
+ sample_interval : int, optional
88
+ The sampling interval in seconds of the product.
89
+ It must be specified only for product L2E and L2M !
90
+ rolling : bool, optional
91
+ Whether the dataset has been resampled by aggregating or rolling.
92
+ It must be specified only for product L2E and L2M !
93
+ model_name : str
94
+ The model name of the statistical distribution for the DSD.
95
+ It must be specified only for product L2M !
96
+
97
+ Returns
98
+ -------
99
+ filepaths : list
100
+ List of file paths.
22
101
 
23
- import numpy as np
24
-
25
- from disdrodb.api.checks import check_product
26
- from disdrodb.api.path import get_disdrodb_path
27
- from disdrodb.configs import get_base_dir
28
- from disdrodb.utils.directories import count_files, list_directories, list_files
29
-
30
-
31
- def _get_list_stations_dirs(product, campaign_dir):
32
- # Get directory where data are stored
33
- # - Raw: <campaign>/data/<...>
34
- # - Processed: <campaign>/L0A/L0B>
35
- if product.upper() == "RAW":
36
- product_dir = os.path.join(campaign_dir, "data")
37
- else:
38
- product_dir = os.path.join(campaign_dir, product)
39
- # Check if the data directory exists
40
- # - For a fresh disdrodb-data cloned repo, no "data" directories
41
- if not os.path.exists(product_dir):
42
- return []
43
- # Get list of directories (stations)
44
- stations_names = os.listdir(product_dir)
45
- list_stations_dir = [os.path.join(product_dir, station_name) for station_name in stations_names]
46
- return list_stations_dir
47
-
48
-
49
- def _get_list_stations_with_data(product, campaign_dir):
50
- """Get the list of stations with data inside."""
51
- # Get stations directory
52
- list_stations_dir = _get_list_stations_dirs(product=product, campaign_dir=campaign_dir)
53
- # Count number of files within directory
54
- list_nfiles_per_station = [count_files(station_dir, "*", recursive=True) for station_dir in list_stations_dir]
55
- # Keep only stations with at least one file
56
- stations_names = [os.path.basename(path) for n, path in zip(list_nfiles_per_station, list_stations_dir) if n >= 1]
57
- return stations_names
58
-
59
-
60
- def _get_list_stations_with_metadata(campaign_dir):
61
- # Get directory where metadata are stored
62
- metadata_path = os.path.join(campaign_dir, "metadata")
63
- # List metadata files
64
- metadata_filepaths = list_files(metadata_path, glob_pattern="*.yml", recursive=False)
65
- # Return stations with metadata
66
- stations_names = [os.path.basename(filepath).replace(".yml", "") for filepath in metadata_filepaths]
67
- return stations_names
68
-
69
-
70
- def _get_campaign_stations(base_dir, product, data_source, campaign_name):
71
- # Get campaign directory
72
- campaign_dir = get_disdrodb_path(
73
- base_dir=base_dir,
74
- product=product,
102
+ """
103
+ # Retrieve data directory
104
+ data_dir = define_data_dir(
105
+ data_archive_dir=data_archive_dir,
75
106
  data_source=data_source,
76
107
  campaign_name=campaign_name,
108
+ station_name=station_name,
109
+ product=product,
110
+ # Product options
111
+ **product_kwargs,
77
112
  )
78
113
 
79
- # Get list of stations with data and metadata
80
- list_stations_data = _get_list_stations_with_data(product=product, campaign_dir=campaign_dir)
81
- list_stations_metadata = _get_list_stations_with_metadata(campaign_dir)
82
- # Get list of stations with both data and metadata
83
- stations_names = list(set(list_stations_data).intersection(list_stations_metadata))
114
+ # Define or check the specified glob pattern
115
+ if product != "RAW":
116
+ glob_pattern = "*.parquet" if product == "L0A" else "*.nc"
84
117
 
85
- # Return all available stations for a give campaign
86
- return stations_names
118
+ # Retrieve files
119
+ filepaths = list_files(data_dir, glob_pattern=glob_pattern, recursive=True)
87
120
 
121
+ # Filter out filepaths if debugging_mode=True
122
+ filepaths = filter_filepaths(filepaths, debugging_mode=debugging_mode)
88
123
 
89
- def _get_campaigns_stations(base_dir, product, data_source, campaign_names):
90
- if isinstance(campaign_names, str):
91
- campaign_names = [campaign_names]
92
- list_available_stations = []
93
- for campaign_name in campaign_names:
94
- # Get list of available stations
95
- stations_names = _get_campaign_stations(
96
- base_dir=base_dir,
97
- product=product,
98
- data_source=data_source,
99
- campaign_name=campaign_name,
100
- )
101
- for station_name in stations_names:
102
- list_available_stations.append((data_source, campaign_name, station_name))
124
+ # If no file available, raise error
125
+ if len(filepaths) == 0:
126
+ msg = f"No {product} files are available in {data_dir}. Run {product} processing first."
127
+ raise ValueError(msg)
103
128
 
104
- # Return all available stations for the asked campaigns (and specific data source)
105
- return list_available_stations
129
+ # Sort filepaths
130
+ filepaths = sorted(filepaths)
131
+ return filepaths
106
132
 
107
133
 
108
- def _get_data_source_stations(base_dir, product, data_source):
109
- """Return list of available stations for a specific data source.
134
+ ####----------------------------------------------------------------------------------
135
+ #### DISDRODB Open Product Files
136
+ def open_dataset(
137
+ data_source,
138
+ campaign_name,
139
+ station_name,
140
+ product,
141
+ product_kwargs=None,
142
+ debugging_mode: bool = False,
143
+ data_archive_dir: Optional[str] = None,
144
+ **open_kwargs,
145
+ ):
146
+ """Retrieve DISDRODB product files for a give station.
147
+
148
+ Parameters
149
+ ----------
150
+ data_source : str
151
+ The name of the institution (for campaigns spanning multiple countries) or
152
+ the name of the country (for campaigns or sensor networks within a single country).
153
+ Must be provided in UPPER CASE.
154
+ campaign_name : str
155
+ The name of the campaign. Must be provided in UPPER CASE.
156
+ station_name : str
157
+ The name of the station.
158
+ product : str
159
+ The name DISDRODB product.
160
+ sample_interval : int, optional
161
+ The sampling interval in seconds of the product.
162
+ It must be specified only for product L2E and L2M !
163
+ rolling : bool, optional
164
+ Whether the dataset has been resampled by aggregating or rolling.
165
+ It must be specified only for product L2E and L2M !
166
+ model_name : str
167
+ The model name of the statistical distribution for the DSD.
168
+ It must be specified only for product L2M !
169
+ debugging_mode : bool, optional
170
+ If ``True``, it select maximum 3 files for debugging purposes.
171
+ The default value is ``False``.
172
+ data_archive_dir : str, optional
173
+ The base directory of DISDRODB, expected in the format ``<...>/DISDRODB``.
174
+ If not specified, the path specified in the DISDRODB active configuration will be used.
175
+
176
+ Returns
177
+ -------
178
+ xarray.Dataset
110
179
 
111
- Returns a tuple (<DATA_SOURCE>, <CAMPAIGN_NAME>, <station_name>)
112
180
  """
113
- # Get data source directory
114
- data_source_dir = get_disdrodb_path(
115
- base_dir=base_dir,
116
- product=product,
117
- data_source=data_source,
118
- campaign_name="",
119
- )
120
- # Get possible campaign list
121
- campaign_names = os.listdir(data_source_dir)
181
+ import xarray as xr
122
182
 
123
- # For each campaign, retrieve available stations
124
- list_available_stations = _get_campaigns_stations(
125
- base_dir=base_dir,
126
- product=product,
183
+ from disdrodb.l0.l0a_processing import read_l0a_dataframe
184
+
185
+ # Check product validity
186
+ if product == "RAW":
187
+ raise ValueError("It's not possible to open the raw data with this function.")
188
+ product_kwargs = product_kwargs if product_kwargs else {}
189
+
190
+ # List product files
191
+ filepaths = find_files(
192
+ data_archive_dir=data_archive_dir,
127
193
  data_source=data_source,
128
- campaign_names=campaign_names,
194
+ campaign_name=campaign_name,
195
+ station_name=station_name,
196
+ product=product,
197
+ debugging_mode=debugging_mode,
198
+ **product_kwargs,
129
199
  )
130
200
 
131
- # Return all available stations for a specific data source
132
- return list_available_stations
201
+ # Open L0A Parquet files
202
+ if product == "L0A":
203
+ return read_l0a_dataframe(filepaths)
133
204
 
205
+ # Open DISDRODB netCDF files using xarray
206
+ # - TODO: parallel option and add closers !
207
+ # - decode_timedelta -- > sample_interval not decoded to timedelta !
208
+ list_ds = [xr.open_dataset(fpath, decode_timedelta=False, **open_kwargs) for fpath in filepaths]
209
+ ds = xr.concat(list_ds, dim="time")
210
+ return ds
134
211
 
135
- def _get_data_sources_stations(base_dir, product, data_sources):
136
- if isinstance(data_sources, str):
137
- data_sources = [data_sources]
138
- list_available_stations = []
139
- for data_source in data_sources:
140
- list_available = _get_data_source_stations(
141
- base_dir=base_dir,
142
- product=product,
143
- data_source=data_source,
144
- )
145
- for station_name in list_available:
146
- list_available_stations.append(station_name)
147
212
 
148
- # Return all available stations
149
- return list_available_stations
213
+ ####----------------------------------------------------------------------------------
214
+ #### DISDRODB Remove Product Files
150
215
 
151
216
 
152
- def _get_stations(base_dir, product):
153
- # Get raw or processed directory
154
- level_dir = get_disdrodb_path(
155
- base_dir=base_dir,
217
+ def remove_product(
218
+ data_archive_dir,
219
+ product,
220
+ data_source,
221
+ campaign_name,
222
+ station_name,
223
+ logger=None,
224
+ verbose=True,
225
+ **product_kwargs,
226
+ ):
227
+ """Remove all product files of a specific station."""
228
+ if product.upper() == "RAW":
229
+ raise ValueError("Removal of 'RAW' files is not allowed.")
230
+ data_dir = define_data_dir(
231
+ data_archive_dir=data_archive_dir,
156
232
  product=product,
157
- data_source="",
158
- campaign_name="",
233
+ data_source=data_source,
234
+ campaign_name=campaign_name,
235
+ station_name=station_name,
236
+ **product_kwargs,
159
237
  )
160
- # Get possible data sources
161
- data_sources = os.listdir(level_dir)
238
+ if logger is not None:
239
+ log_info(logger=logger, msg="Removal of {product} files started.", verbose=verbose)
240
+ shutil.rmtree(data_dir)
241
+ if logger is not None:
242
+ log_info(logger=logger, msg="Removal of {product} files ended.", verbose=verbose)
162
243
 
163
- # For each data_source, retrieve available stations
164
- list_available_stations = _get_data_sources_stations(
165
- base_dir=base_dir,
166
- product=product,
167
- data_sources=data_sources,
168
- )
169
- # Return all available stations
170
- return list_available_stations
171
244
 
245
+ ####--------------------------------------------------------------------------.
246
+ #### Open directories
172
247
 
173
- ####---------------------------------------------------------------------------.
174
- #### I/O CHECKS
175
248
 
249
+ def open_file_explorer(path):
250
+ """Open the native file-browser showing 'path'."""
251
+ p = Path(path).resolve()
252
+ if not p.exists():
253
+ raise FileNotFoundError(f"{p} does not exist")
176
254
 
177
- def _check_data_sources(base_dir, product, data_sources):
178
- """Check DISDRODB data source.
255
+ if sys.platform.startswith("win"):
256
+ # Windows
257
+ os.startfile(str(p))
258
+ elif sys.platform == "darwin":
259
+ # macOS
260
+ subprocess.run(["open", str(p)], check=False)
261
+ else:
262
+ # Linux (most desktop environments)
263
+ subprocess.run(["xdg-open", str(p)], check=False)
179
264
 
180
- It checks only if the directory exist.
181
- """
182
- # If data_sources is None, return None
183
- if isinstance(data_sources, type(None)):
184
- return data_sources
185
- # Ensure is a list
186
- if isinstance(data_sources, str):
187
- data_sources = [data_sources]
188
- # Remove duplicates
189
- data_sources = np.unique(np.array(data_sources))
190
- # Get directory
191
- dir_path = get_disdrodb_path(base_dir=base_dir, product=product)
192
- # Get data sources directory
193
- list_dir = os.listdir(dir_path)
194
- # Check if there are invalid data_sources
195
- idx_invalid = np.where(np.isin(data_sources, list_dir, invert=True))[0]
196
- if len(idx_invalid) > 0:
197
- invalid_data_sources = data_sources[idx_invalid].tolist()
198
- raise ValueError(f"These data sources are invalid: {invalid_data_sources}.")
199
- # Return data_sources list
200
- data_sources = data_sources.tolist()
201
- return data_sources
202
-
203
-
204
- def _check_campaign_names(base_dir, product, campaign_names):
205
- """Check DISDRODB campaign_names are valid.
206
-
207
- It checks only if the directory exist within the product.
208
- """
209
- # If campaign_names is None, return None
210
- if isinstance(campaign_names, type(None)):
211
- return campaign_names
212
- # Ensure is a list
213
- if isinstance(campaign_names, str):
214
- campaign_names = [campaign_names]
215
- # Remove duplicates
216
- campaign_names = np.unique(np.array(campaign_names))
217
- # Get product directory path
218
- dir_path = get_disdrodb_path(base_dir=base_dir, product=product)
219
- # Get campaigns directory path
220
- list_campaigns_path = list_directories(dir_path, glob_pattern=os.path.join("*", "*"), recursive=False)
221
- # Get campaigns names
222
- list_campaign_names = [os.path.basename(path) for path in list_campaigns_path]
223
- # Remove duplicates
224
- list_campaign_names = np.unique(list_campaign_names)
225
- # Check if there are invalid campaign_names
226
- idx_invalid = np.where(np.isin(campaign_names, list_campaign_names, invert=True))[0]
227
- if len(idx_invalid) > 0:
228
- invalid_campaign_names = campaign_names[idx_invalid].tolist()
229
- raise ValueError(f"These campaign names are invalid: {invalid_campaign_names}.")
230
- # Return campaign_names list
231
- campaign_names = campaign_names.tolist()
232
- return campaign_names
233
-
234
-
235
- ####---------------------------------------------------------------------------.
236
- #### DISDRODB I/O INTERFACE
237
-
238
-
239
- def available_data_sources(product, base_dir=None):
240
- """Return data sources for which stations data are available."""
241
- base_dir = get_base_dir(base_dir)
242
- product = check_product(product)
243
- # Get available stations
244
- list_available_stations = _get_stations(base_dir=base_dir, product=product)
245
- data_sources = [info[0] for info in list_available_stations]
246
- data_sources = np.unique(data_sources).tolist()
247
- return data_sources
248
-
249
-
250
- def available_campaigns(product, data_sources=None, return_tuple=True, base_dir=None):
251
- """Return campaigns for which stations data are available."""
252
- # Checks
253
- base_dir = get_base_dir(base_dir)
254
- product = check_product(product)
255
- data_sources = _check_data_sources(
256
- base_dir=base_dir,
257
- product=product,
258
- data_sources=data_sources,
265
+
266
+ def open_logs_directory(
267
+ data_source,
268
+ campaign_name,
269
+ station_name=None, # noqa
270
+ data_archive_dir=None,
271
+ ):
272
+ """Open the DISDRODB Data Archive logs directory of a station."""
273
+ from disdrodb.configs import get_data_archive_dir
274
+
275
+ data_archive_dir = get_data_archive_dir(data_archive_dir)
276
+ campaign_dir = define_campaign_dir(
277
+ archive_dir=data_archive_dir,
278
+ product="L0A",
279
+ data_source=data_source,
280
+ campaign_name=campaign_name,
281
+ check_exists=True,
259
282
  )
260
- # Get available stations
261
- if data_sources is None:
262
- list_available_stations = _get_stations(base_dir=base_dir, product=product)
263
- else:
264
- list_available_stations = _get_data_sources_stations(
265
- base_dir=base_dir,
266
- product=product,
267
- data_sources=data_sources,
268
- )
269
- if not return_tuple:
270
- campaigns = [info[1] for info in list_available_stations]
271
- campaigns = np.unique(campaigns).tolist()
272
- return campaigns
273
- else:
274
- data_source_campaigns = [(info[0], info[1]) for info in list_available_stations]
275
- data_source_campaigns = list(set(data_source_campaigns))
276
- return data_source_campaigns
283
+ logs_dir = os.path.join(campaign_dir, "logs")
284
+ open_file_explorer(logs_dir)
277
285
 
278
286
 
279
- def available_stations(
287
+ def open_product_directory(
280
288
  product,
281
- data_sources=None,
282
- campaign_names=None,
283
- return_tuple=True,
284
- base_dir=None,
289
+ data_source,
290
+ campaign_name,
291
+ station_name,
292
+ data_archive_dir=None,
285
293
  ):
286
- """Return stations for which data are available."""
287
- base_dir = get_base_dir(base_dir)
288
- # Checks
289
- product = check_product(product)
290
- data_sources = _check_data_sources(
291
- base_dir=base_dir,
294
+ """Open the DISDRODB Data Archive station product directory."""
295
+ from disdrodb.configs import get_data_archive_dir
296
+
297
+ data_archive_dir = get_data_archive_dir(data_archive_dir)
298
+ station_dir = define_station_dir(
299
+ data_archive_dir=data_archive_dir,
292
300
  product=product,
293
- data_sources=data_sources,
301
+ data_source=data_source,
302
+ campaign_name=campaign_name,
303
+ station_name=station_name,
304
+ check_exists=True,
294
305
  )
295
- campaign_names = _check_campaign_names(
296
- base_dir=base_dir,
297
- product=product,
298
- campaign_names=campaign_names,
306
+ open_file_explorer(station_dir)
307
+
308
+
309
+ def open_metadata_directory(
310
+ data_source,
311
+ campaign_name,
312
+ station_name=None, # noqa
313
+ metadata_archive_dir=None,
314
+ ):
315
+ """Open the DISDRODB Metadata Archive station(s) metadata directory."""
316
+ from disdrodb.configs import get_metadata_archive_dir
317
+
318
+ metadata_archive_dir = get_metadata_archive_dir(metadata_archive_dir)
319
+ metadata_dir = define_metadata_dir(
320
+ metadata_archive_dir=metadata_archive_dir,
321
+ data_source=data_source,
322
+ campaign_name=campaign_name,
323
+ check_exists=True,
299
324
  )
300
- # Format arguments to list
301
- if isinstance(data_sources, str):
302
- data_sources = [data_sources]
303
- if isinstance(campaign_names, str):
304
- campaign_names = [campaign_names]
305
-
306
- # If data_source is None, first retrieve all stations
307
- if data_sources is None:
308
- list_info = _get_stations(base_dir=base_dir, product=product)
309
- # Otherwise retrieve all stations for the specified data sources
310
- else:
311
- list_info = _get_data_sources_stations(
312
- base_dir=base_dir,
313
- data_sources=data_sources,
314
- product=product,
315
- )
316
-
317
- # Then, if campaign_name is not None, subset by campaign_name
318
- if campaign_names is not None:
319
- list_info = [info for info in list_info if info[1] in campaign_names]
320
-
321
- if return_tuple:
322
- return list_info
323
- else:
324
- # TODO: ENSURE THAT NO DUPLICATED STATION NAMES ?
325
- list_stations = [info[2] for info in list_info]
326
- return list_stations
325
+ open_file_explorer(metadata_dir)
326
+
327
+
328
+ def open_readers_directory():
329
+ """Open the disdrodb software readers directory."""
330
+ readers_directory = define_readers_directory()
331
+
332
+ open_file_explorer(readers_directory)
333
+
334
+
335
+ def open_metadata_archive(
336
+ metadata_archive_dir=None,
337
+ ):
338
+ """Open the DISDRODB Metadata Archive."""
339
+ from disdrodb.configs import get_metadata_archive_dir
340
+
341
+ metadata_archive_dir = get_metadata_archive_dir(metadata_archive_dir)
342
+ open_file_explorer(metadata_archive_dir)
343
+
344
+
345
+ def open_data_archive(
346
+ data_archive_dir=None,
347
+ ):
348
+ """Open the DISDRODB Data Archive."""
349
+ from disdrodb.configs import get_data_archive_dir
350
+
351
+ data_archive_dir = get_data_archive_dir(data_archive_dir)
352
+ open_file_explorer(data_archive_dir)