disdrodb 0.2.0__py3-none-any.whl → 0.3.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (315) hide show
  1. disdrodb/__init__.py +1 -1
  2. disdrodb/_config.py +1 -3
  3. disdrodb/_version.py +2 -2
  4. disdrodb/accessor/__init__.py +1 -1
  5. disdrodb/accessor/methods.py +18 -11
  6. disdrodb/api/checks.py +2 -4
  7. disdrodb/api/configs.py +1 -3
  8. disdrodb/api/create_directories.py +4 -6
  9. disdrodb/api/info.py +1 -3
  10. disdrodb/api/io.py +15 -9
  11. disdrodb/api/path.py +1 -3
  12. disdrodb/cli/disdrodb_check_metadata_archive.py +2 -2
  13. disdrodb/cli/disdrodb_check_products_options.py +44 -0
  14. disdrodb/cli/disdrodb_create_summary.py +48 -22
  15. disdrodb/cli/disdrodb_create_summary_station.py +39 -18
  16. disdrodb/cli/disdrodb_data_archive_directory.py +1 -3
  17. disdrodb/cli/disdrodb_download_archive.py +45 -24
  18. disdrodb/cli/disdrodb_download_metadata_archive.py +27 -16
  19. disdrodb/cli/disdrodb_download_station.py +56 -26
  20. disdrodb/cli/disdrodb_initialize_station.py +40 -20
  21. disdrodb/cli/disdrodb_metadata_archive_directory.py +1 -3
  22. disdrodb/cli/disdrodb_open_data_archive.py +16 -11
  23. disdrodb/cli/disdrodb_open_logs_directory.py +29 -18
  24. disdrodb/cli/disdrodb_open_metadata_archive.py +25 -11
  25. disdrodb/cli/disdrodb_open_metadata_directory.py +32 -20
  26. disdrodb/cli/disdrodb_open_product_directory.py +38 -21
  27. disdrodb/cli/disdrodb_open_readers_directory.py +1 -3
  28. disdrodb/cli/disdrodb_run.py +189 -0
  29. disdrodb/cli/disdrodb_run_l0.py +55 -64
  30. disdrodb/cli/disdrodb_run_l0_station.py +47 -52
  31. disdrodb/cli/disdrodb_run_l0a.py +47 -45
  32. disdrodb/cli/disdrodb_run_l0a_station.py +38 -37
  33. disdrodb/cli/disdrodb_run_l0b.py +45 -45
  34. disdrodb/cli/disdrodb_run_l0b_station.py +37 -36
  35. disdrodb/cli/disdrodb_run_l0c.py +50 -47
  36. disdrodb/cli/disdrodb_run_l0c_station.py +41 -38
  37. disdrodb/cli/disdrodb_run_l1.py +49 -45
  38. disdrodb/cli/disdrodb_run_l1_station.py +40 -37
  39. disdrodb/cli/disdrodb_run_l2e.py +50 -45
  40. disdrodb/cli/disdrodb_run_l2e_station.py +41 -37
  41. disdrodb/cli/disdrodb_run_l2m.py +49 -45
  42. disdrodb/cli/disdrodb_run_l2m_station.py +40 -37
  43. disdrodb/cli/disdrodb_run_station.py +184 -0
  44. disdrodb/cli/disdrodb_upload_archive.py +45 -35
  45. disdrodb/cli/disdrodb_upload_station.py +39 -32
  46. disdrodb/configs.py +13 -8
  47. disdrodb/constants.py +4 -2
  48. disdrodb/data_transfer/__init__.py +1 -3
  49. disdrodb/data_transfer/download_data.py +38 -54
  50. disdrodb/data_transfer/upload_data.py +1 -3
  51. disdrodb/data_transfer/zenodo.py +1 -3
  52. disdrodb/docs.py +1 -3
  53. disdrodb/etc/configs/attributes.yaml +52 -2
  54. disdrodb/etc/configs/encodings.yaml +45 -1
  55. disdrodb/etc/products/L0C/ODM470/global.yaml +5 -0
  56. disdrodb/etc/products/L0C/global.yaml +5 -0
  57. disdrodb/etc/products/L1/ODM470/global.yaml +6 -0
  58. disdrodb/etc/products/L1/global.yaml +1 -14
  59. disdrodb/etc/products/L2E/LPM/1MIN.yaml +1 -0
  60. disdrodb/etc/products/L2E/LPM/global.yaml +36 -0
  61. disdrodb/etc/products/L2E/LPM_V0/1MIN.yaml +1 -0
  62. disdrodb/etc/products/L2E/LPM_V0/global.yaml +36 -0
  63. disdrodb/etc/products/L2E/ODM470/1MIN.yaml +1 -0
  64. disdrodb/etc/products/L2E/ODM470/global.yaml +36 -0
  65. disdrodb/etc/products/L2E/PARSIVEL/1MIN.yaml +1 -0
  66. disdrodb/etc/products/L2E/PARSIVEL/global.yaml +36 -0
  67. disdrodb/etc/products/L2E/PARSIVEL2/1MIN.yaml +1 -0
  68. disdrodb/etc/products/L2E/PARSIVEL2/global.yaml +36 -0
  69. disdrodb/etc/products/L2E/PWS100/1MIN.yaml +1 -0
  70. disdrodb/etc/products/L2E/PWS100/global.yaml +36 -0
  71. disdrodb/etc/products/L2E/RD80/1MIN.yaml +19 -0
  72. disdrodb/etc/products/L2E/SWS250/1MIN.yaml +19 -0
  73. disdrodb/etc/products/L2E/global.yaml +17 -3
  74. disdrodb/etc/products/L2M/global.yaml +1 -1
  75. disdrodb/fall_velocity/__init__.py +46 -0
  76. disdrodb/fall_velocity/graupel.py +483 -0
  77. disdrodb/fall_velocity/hail.py +287 -0
  78. disdrodb/{l1/fall_velocity.py → fall_velocity/rain.py} +265 -50
  79. disdrodb/issue/__init__.py +1 -3
  80. disdrodb/issue/checks.py +3 -5
  81. disdrodb/issue/reader.py +1 -3
  82. disdrodb/issue/writer.py +1 -3
  83. disdrodb/l0/__init__.py +1 -1
  84. disdrodb/l0/check_configs.py +26 -17
  85. disdrodb/l0/check_standards.py +1 -3
  86. disdrodb/l0/configs/LPM/l0a_encodings.yml +0 -1
  87. disdrodb/l0/configs/LPM/l0b_cf_attrs.yml +0 -4
  88. disdrodb/l0/configs/LPM/l0b_encodings.yml +9 -9
  89. disdrodb/l0/configs/LPM/raw_data_format.yml +11 -11
  90. disdrodb/l0/configs/LPM_V0/bins_diameter.yml +103 -0
  91. disdrodb/l0/configs/LPM_V0/bins_velocity.yml +103 -0
  92. disdrodb/l0/configs/LPM_V0/l0a_encodings.yml +45 -0
  93. disdrodb/l0/configs/LPM_V0/l0b_cf_attrs.yml +180 -0
  94. disdrodb/l0/configs/LPM_V0/l0b_encodings.yml +410 -0
  95. disdrodb/l0/configs/LPM_V0/raw_data_format.yml +474 -0
  96. disdrodb/l0/configs/ODM470/bins_diameter.yml +643 -0
  97. disdrodb/l0/configs/ODM470/bins_velocity.yml +0 -0
  98. disdrodb/l0/configs/ODM470/l0a_encodings.yml +11 -0
  99. disdrodb/l0/configs/ODM470/l0b_cf_attrs.yml +46 -0
  100. disdrodb/l0/configs/ODM470/l0b_encodings.yml +106 -0
  101. disdrodb/l0/configs/ODM470/raw_data_format.yml +111 -0
  102. disdrodb/l0/configs/PARSIVEL/l0b_cf_attrs.yml +1 -1
  103. disdrodb/l0/configs/PARSIVEL/raw_data_format.yml +8 -8
  104. disdrodb/l0/configs/PARSIVEL2/raw_data_format.yml +9 -9
  105. disdrodb/l0/l0_reader.py +1 -3
  106. disdrodb/l0/l0a_processing.py +7 -5
  107. disdrodb/l0/l0b_nc_processing.py +2 -4
  108. disdrodb/l0/l0b_processing.py +27 -22
  109. disdrodb/l0/l0c_processing.py +37 -11
  110. disdrodb/l0/manuals/LPM_V0.pdf +0 -0
  111. disdrodb/l0/readers/LPM/ARM/ARM_LPM.py +1 -1
  112. disdrodb/l0/readers/LPM/AUSTRALIA/MELBOURNE_2007_LPM.py +1 -1
  113. disdrodb/l0/readers/LPM/BRAZIL/CHUVA_LPM.py +1 -1
  114. disdrodb/l0/readers/LPM/BRAZIL/GOAMAZON_LPM.py +1 -1
  115. disdrodb/l0/readers/LPM/GERMANY/DWD.py +190 -12
  116. disdrodb/l0/readers/LPM/ITALY/GID_LPM.py +63 -14
  117. disdrodb/l0/readers/LPM/ITALY/GID_LPM_PI.py +279 -0
  118. disdrodb/l0/readers/LPM/ITALY/GID_LPM_T.py +279 -0
  119. disdrodb/l0/readers/LPM/ITALY/GID_LPM_W.py +3 -5
  120. disdrodb/l0/readers/LPM/KIT/CHWALA.py +1 -3
  121. disdrodb/l0/readers/LPM/NETHERLANDS/DELFT_LPM_NC.py +1 -1
  122. disdrodb/l0/readers/LPM/NETHERLANDS/DELFT_RWANDA_LPM_NC.py +103 -0
  123. disdrodb/l0/readers/LPM/NORWAY/HAUKELISETER_LPM.py +214 -0
  124. disdrodb/l0/readers/LPM/NORWAY/NMBU_LPM.py +206 -0
  125. disdrodb/l0/readers/LPM/SLOVENIA/ARSO.py +1 -3
  126. disdrodb/l0/readers/LPM/SLOVENIA/UL.py +1 -3
  127. disdrodb/l0/readers/LPM/SWITZERLAND/INNERERIZ_LPM.py +1 -3
  128. disdrodb/l0/readers/LPM/UK/DIVEN.py +1 -1
  129. disdrodb/l0/readers/LPM/UK/WITHWORTH_LPM.py +217 -0
  130. disdrodb/l0/readers/LPM/USA/CHARLESTON.py +227 -0
  131. disdrodb/l0/readers/{LPM → LPM_V0}/BELGIUM/ULIEGE.py +34 -52
  132. disdrodb/l0/readers/LPM_V0/ITALY/GID_LPM_V0.py +240 -0
  133. disdrodb/l0/readers/ODM470/OCEAN/OCEANRAIN.py +123 -0
  134. disdrodb/l0/readers/PARSIVEL/AUSTRALIA/MELBOURNE_2007_PARSIVEL.py +1 -1
  135. disdrodb/l0/readers/PARSIVEL/BASQUECOUNTRY/EUSKALMET_OTT.py +1 -1
  136. disdrodb/l0/readers/PARSIVEL/CHINA/CHONGQING.py +1 -3
  137. disdrodb/l0/readers/PARSIVEL/EPFL/ARCTIC_2021.py +1 -1
  138. disdrodb/l0/readers/PARSIVEL/EPFL/COMMON_2011.py +1 -1
  139. disdrodb/l0/readers/PARSIVEL/EPFL/DAVOS_2009_2011.py +1 -1
  140. disdrodb/l0/readers/PARSIVEL/EPFL/EPFL_2009.py +1 -1
  141. disdrodb/l0/readers/PARSIVEL/EPFL/EPFL_ROOF_2008.py +1 -1
  142. disdrodb/l0/readers/PARSIVEL/EPFL/EPFL_ROOF_2010.py +1 -1
  143. disdrodb/l0/readers/PARSIVEL/EPFL/EPFL_ROOF_2011.py +1 -1
  144. disdrodb/l0/readers/PARSIVEL/EPFL/EPFL_ROOF_2012.py +1 -1
  145. disdrodb/l0/readers/PARSIVEL/EPFL/GENEPI_2007.py +1 -1
  146. disdrodb/l0/readers/PARSIVEL/EPFL/GRAND_ST_BERNARD_2007.py +1 -1
  147. disdrodb/l0/readers/PARSIVEL/EPFL/GRAND_ST_BERNARD_2007_2.py +1 -1
  148. disdrodb/l0/readers/PARSIVEL/EPFL/HPICONET_2010.py +1 -1
  149. disdrodb/l0/readers/PARSIVEL/EPFL/HYMEX_LTE_SOP2.py +1 -1
  150. disdrodb/l0/readers/PARSIVEL/EPFL/HYMEX_LTE_SOP3.py +1 -1
  151. disdrodb/l0/readers/PARSIVEL/EPFL/HYMEX_LTE_SOP4.py +1 -1
  152. disdrodb/l0/readers/PARSIVEL/EPFL/LOCARNO_2018.py +1 -1
  153. disdrodb/l0/readers/PARSIVEL/EPFL/LOCARNO_2019.py +1 -1
  154. disdrodb/l0/readers/PARSIVEL/EPFL/PARADISO_2014.py +1 -1
  155. disdrodb/l0/readers/PARSIVEL/EPFL/PARSIVEL_2007.py +1 -1
  156. disdrodb/l0/readers/PARSIVEL/EPFL/PLATO_2019.py +1 -1
  157. disdrodb/l0/readers/PARSIVEL/EPFL/RACLETS_2019.py +1 -1
  158. disdrodb/l0/readers/PARSIVEL/EPFL/RACLETS_2019_WJF.py +1 -1
  159. disdrodb/l0/readers/PARSIVEL/EPFL/RIETHOLZBACH_2011.py +1 -1
  160. disdrodb/l0/readers/PARSIVEL/EPFL/SAMOYLOV_2017.py +1 -1
  161. disdrodb/l0/readers/PARSIVEL/EPFL/SAMOYLOV_2019.py +1 -1
  162. disdrodb/l0/readers/PARSIVEL/EPFL/UNIL_2022.py +1 -1
  163. disdrodb/l0/readers/PARSIVEL/JAPAN/JMA.py +1 -1
  164. disdrodb/l0/readers/PARSIVEL/KOREA/ICEPOP_MSC.py +159 -0
  165. disdrodb/l0/readers/PARSIVEL/NASA/LPVEX.py +26 -14
  166. disdrodb/l0/readers/PARSIVEL/NASA/MC3E.py +2 -2
  167. disdrodb/l0/readers/PARSIVEL/NCAR/CCOPE_2015.py +1 -1
  168. disdrodb/l0/readers/PARSIVEL/NCAR/OWLES_MIPS.py +1 -1
  169. disdrodb/l0/readers/PARSIVEL/NCAR/PECAN_MOBILE.py +1 -1
  170. disdrodb/l0/readers/PARSIVEL/NCAR/PLOWS_MIPS.py +1 -1
  171. disdrodb/l0/readers/PARSIVEL/NCAR/VORTEX2_2009.py +1 -1
  172. disdrodb/l0/readers/PARSIVEL/NCAR/VORTEX2_2010.py +1 -3
  173. disdrodb/l0/readers/PARSIVEL/NCAR/VORTEX2_2010_UF.py +1 -3
  174. disdrodb/l0/readers/PARSIVEL/SLOVENIA/UL.py +1 -1
  175. disdrodb/l0/readers/PARSIVEL2/ARM/ARM_PARSIVEL2.py +1 -1
  176. disdrodb/l0/readers/PARSIVEL2/BASQUECOUNTRY/EUSKALMET_OTT2.py +2 -2
  177. disdrodb/l0/readers/PARSIVEL2/BELGIUM/ILVO.py +1 -3
  178. disdrodb/l0/readers/PARSIVEL2/BRAZIL/CHUVA_PARSIVEL2.py +1 -1
  179. disdrodb/l0/readers/PARSIVEL2/BRAZIL/GOAMAZON_PARSIVEL2.py +1 -1
  180. disdrodb/l0/readers/PARSIVEL2/CANADA/UQAM_NC.py +1 -1
  181. disdrodb/l0/readers/PARSIVEL2/DENMARK/DTU.py +1 -1
  182. disdrodb/l0/readers/PARSIVEL2/DENMARK/EROSION_nc.py +1 -1
  183. disdrodb/l0/readers/PARSIVEL2/DENMARK/EROSION_raw.py +1 -1
  184. disdrodb/l0/readers/PARSIVEL2/FINLAND/FMI_PARSIVEL2.py +1 -1
  185. disdrodb/l0/readers/PARSIVEL2/FRANCE/ENPC_PARSIVEL2.py +1 -3
  186. disdrodb/l0/readers/PARSIVEL2/FRANCE/OSUG.py +1 -1
  187. disdrodb/l0/readers/PARSIVEL2/FRANCE/SIRTA_PARSIVEL2.py +1 -3
  188. disdrodb/l0/readers/PARSIVEL2/GREECE/NOA.py +4 -3
  189. disdrodb/l0/readers/PARSIVEL2/ITALY/GID_PARSIVEL2.py +1 -3
  190. disdrodb/l0/readers/PARSIVEL2/ITALY/HYDROX.py +5 -3
  191. disdrodb/l0/readers/PARSIVEL2/JAPAN/PRECIP.py +155 -0
  192. disdrodb/l0/readers/PARSIVEL2/KIT/BURKINA_FASO.py +1 -1
  193. disdrodb/l0/readers/PARSIVEL2/KIT/TEAMX.py +1 -1
  194. disdrodb/l0/readers/PARSIVEL2/KOREA/ICEPOP_MSC.py +161 -0
  195. disdrodb/l0/readers/PARSIVEL2/{NASA/GCPEX.py → KOREA/ICEPOP_UCLM.py} +51 -31
  196. disdrodb/l0/readers/PARSIVEL2/MEXICO/OH_IIUNAM_nc.py +1 -1
  197. disdrodb/l0/readers/PARSIVEL2/MPI/BCO_PARSIVEL2.py +15 -8
  198. disdrodb/l0/readers/PARSIVEL2/MPI/BOWTIE.py +9 -4
  199. disdrodb/l0/readers/PARSIVEL2/NASA/APU.py +31 -6
  200. disdrodb/l0/readers/PARSIVEL2/NASA/NSSTC.py +1 -1
  201. disdrodb/l0/readers/PARSIVEL2/NCAR/FARM_PARSIVEL2.py +1 -1
  202. disdrodb/l0/readers/PARSIVEL2/NCAR/PECAN_FP3.py +1 -1
  203. disdrodb/l0/readers/PARSIVEL2/NCAR/PECAN_MIPS.py +1 -1
  204. disdrodb/l0/readers/PARSIVEL2/NCAR/PERILS_MIPS.py +1 -1
  205. disdrodb/l0/readers/PARSIVEL2/NCAR/PERILS_PIPS.py +1 -1
  206. disdrodb/l0/readers/PARSIVEL2/NCAR/RELAMPAGO_PARSIVEL2.py +2 -2
  207. disdrodb/l0/readers/PARSIVEL2/NCAR/SNOWIE_PJ.py +1 -1
  208. disdrodb/l0/readers/PARSIVEL2/NCAR/SNOWIE_SB.py +1 -1
  209. disdrodb/l0/readers/PARSIVEL2/NCAR/VORTEX_SE_2016_P1.py +1 -3
  210. disdrodb/l0/readers/PARSIVEL2/NCAR/VORTEX_SE_2016_P2.py +1 -1
  211. disdrodb/l0/readers/PARSIVEL2/NCAR/VORTEX_SE_2016_PIPS.py +1 -1
  212. disdrodb/l0/readers/PARSIVEL2/NETHERLANDS/DELFT_NC.py +1 -1
  213. disdrodb/l0/readers/{PARSIVEL/NASA/PIERS.py → PARSIVEL2/NORWAY/UIB.py} +65 -31
  214. disdrodb/l0/readers/PARSIVEL2/PHILIPPINES/PAGASA.py +7 -6
  215. disdrodb/l0/readers/PARSIVEL2/SPAIN/CENER.py +1 -1
  216. disdrodb/l0/readers/PARSIVEL2/SPAIN/CR1000DL.py +1 -1
  217. disdrodb/l0/readers/PARSIVEL2/SPAIN/GRANADA.py +1 -3
  218. disdrodb/l0/readers/PARSIVEL2/SPAIN/LIAISE.py +1 -1
  219. disdrodb/l0/readers/PARSIVEL2/SWEDEN/SMHI.py +1 -1
  220. disdrodb/l0/readers/PARSIVEL2/USA/CSU.py +138 -0
  221. disdrodb/l0/readers/PARSIVEL2/USA/CW3E.py +49 -22
  222. disdrodb/l0/readers/PWS100/AUSTRIA/HOAL.py +1 -3
  223. disdrodb/l0/readers/PWS100/FRANCE/ENPC_PWS100.py +1 -3
  224. disdrodb/l0/readers/PWS100/FRANCE/ENPC_PWS100_SIRTA.py +1 -1
  225. disdrodb/l0/readers/{PARSIVEL/NASA/IFLOODS.py → RD80/BRAZIL/ATTO_RD80.py} +50 -36
  226. disdrodb/l0/readers/RD80/BRAZIL/CHUVA_RD80.py +1 -3
  227. disdrodb/l0/readers/RD80/BRAZIL/GOAMAZON_RD80.py +1 -3
  228. disdrodb/l0/readers/RD80/NCAR/CINDY_2011_RD80.py +1 -3
  229. disdrodb/l0/readers/RD80/NCAR/RELAMPAGO_RD80.py +1 -3
  230. disdrodb/l0/readers/RD80/NOAA/PSL_RD80.py +1 -3
  231. disdrodb/l0/readers/{SW250 → SWS250}/BELGIUM/KMI.py +2 -4
  232. disdrodb/l0/readers/template_reader_raw_netcdf_data.py +1 -3
  233. disdrodb/l0/readers/template_reader_raw_text_data.py +1 -3
  234. disdrodb/l0/standards.py +4 -5
  235. disdrodb/l0/template_tools.py +1 -3
  236. disdrodb/l1/__init__.py +1 -1
  237. disdrodb/l1/classification.py +913 -0
  238. disdrodb/l1/processing.py +36 -106
  239. disdrodb/l1/resampling.py +8 -3
  240. disdrodb/l1_env/__init__.py +1 -1
  241. disdrodb/l1_env/routines.py +6 -6
  242. disdrodb/l2/__init__.py +1 -1
  243. disdrodb/l2/empirical_dsd.py +61 -31
  244. disdrodb/l2/processing.py +327 -62
  245. disdrodb/metadata/checks.py +1 -3
  246. disdrodb/metadata/download.py +4 -4
  247. disdrodb/metadata/geolocation.py +1 -3
  248. disdrodb/metadata/info.py +1 -3
  249. disdrodb/metadata/manipulation.py +1 -3
  250. disdrodb/metadata/reader.py +1 -3
  251. disdrodb/metadata/search.py +1 -3
  252. disdrodb/metadata/standards.py +1 -3
  253. disdrodb/metadata/writer.py +1 -3
  254. disdrodb/physics/__init__.py +17 -0
  255. disdrodb/physics/atmosphere.py +272 -0
  256. disdrodb/physics/water.py +130 -0
  257. disdrodb/physics/wrappers.py +62 -0
  258. disdrodb/psd/__init__.py +1 -1
  259. disdrodb/psd/fitting.py +22 -9
  260. disdrodb/psd/models.py +1 -1
  261. disdrodb/routines/__init__.py +5 -1
  262. disdrodb/routines/l0.py +28 -18
  263. disdrodb/routines/l1.py +8 -6
  264. disdrodb/routines/l2.py +8 -4
  265. disdrodb/routines/options.py +116 -71
  266. disdrodb/routines/options_validation.py +728 -0
  267. disdrodb/routines/wrappers.py +431 -11
  268. disdrodb/scattering/__init__.py +1 -1
  269. disdrodb/scattering/axis_ratio.py +9 -6
  270. disdrodb/scattering/permittivity.py +8 -8
  271. disdrodb/scattering/routines.py +32 -14
  272. disdrodb/summary/__init__.py +1 -1
  273. disdrodb/summary/routines.py +146 -86
  274. disdrodb/utils/__init__.py +1 -1
  275. disdrodb/utils/archiving.py +16 -9
  276. disdrodb/utils/attrs.py +4 -3
  277. disdrodb/utils/cli.py +8 -10
  278. disdrodb/utils/compression.py +13 -13
  279. disdrodb/utils/dask.py +33 -14
  280. disdrodb/utils/dataframe.py +1 -3
  281. disdrodb/utils/decorators.py +1 -3
  282. disdrodb/utils/dict.py +1 -1
  283. disdrodb/utils/directories.py +3 -5
  284. disdrodb/utils/encoding.py +2 -4
  285. disdrodb/utils/event.py +1 -1
  286. disdrodb/utils/list.py +1 -3
  287. disdrodb/utils/logger.py +1 -3
  288. disdrodb/utils/manipulations.py +182 -6
  289. disdrodb/utils/pydantic.py +80 -0
  290. disdrodb/utils/routines.py +1 -3
  291. disdrodb/utils/subsetting.py +1 -1
  292. disdrodb/utils/time.py +3 -2
  293. disdrodb/utils/warnings.py +1 -3
  294. disdrodb/utils/writer.py +1 -3
  295. disdrodb/utils/xarray.py +30 -3
  296. disdrodb/utils/yaml.py +1 -3
  297. disdrodb/viz/__init__.py +1 -1
  298. disdrodb/viz/plots.py +197 -21
  299. {disdrodb-0.2.0.dist-info → disdrodb-0.3.0.dist-info}/METADATA +2 -2
  300. disdrodb-0.3.0.dist-info/RECORD +358 -0
  301. {disdrodb-0.2.0.dist-info → disdrodb-0.3.0.dist-info}/entry_points.txt +3 -0
  302. disdrodb/etc/products/L1/1MIN.yaml +0 -13
  303. disdrodb/etc/products/L1/LPM/1MIN.yaml +0 -13
  304. disdrodb/etc/products/L1/PARSIVEL/1MIN.yaml +0 -13
  305. disdrodb/etc/products/L1/PARSIVEL2/1MIN.yaml +0 -13
  306. disdrodb/etc/products/L1/PWS100/1MIN.yaml +0 -13
  307. disdrodb/etc/products/L1/RD80/1MIN.yaml +0 -13
  308. disdrodb/etc/products/L1/SWS250/1MIN.yaml +0 -13
  309. disdrodb/etc/products/L2M/10MIN.yaml +0 -12
  310. disdrodb/l1/beard_model.py +0 -618
  311. disdrodb/l1/filters.py +0 -203
  312. disdrodb-0.2.0.dist-info/RECORD +0 -312
  313. {disdrodb-0.2.0.dist-info → disdrodb-0.3.0.dist-info}/WHEEL +0 -0
  314. {disdrodb-0.2.0.dist-info → disdrodb-0.3.0.dist-info}/licenses/LICENSE +0 -0
  315. {disdrodb-0.2.0.dist-info → disdrodb-0.3.0.dist-info}/top_level.txt +0 -0
@@ -1,5 +1,5 @@
1
1
  # -----------------------------------------------------------------------------.
2
- # Copyright (c) 2021-2023 DISDRODB developers
2
+ # Copyright (c) 2021-2026 DISDRODB developers
3
3
  #
4
4
  # This program is free software: you can redistribute it and/or modify
5
5
  # it under the terms of the GNU General Public License as published by
@@ -21,6 +21,7 @@ import xarray as xr
21
21
  from disdrodb.constants import DIAMETER_DIMENSION
22
22
  from disdrodb.l0.l0b_processing import ensure_valid_geolocation
23
23
  from disdrodb.l1_env.routines import load_env_dataset
24
+ from disdrodb.physics.wrappers import retrieve_air_density
24
25
  from disdrodb.utils.warnings import suppress_warnings
25
26
 
26
27
 
@@ -45,11 +46,6 @@ def get_fall_velocity_atlas_1973(diameter):
45
46
  Reviews of Geophysics, 11(1), 1-35.
46
47
  https://doi.org/10.1029/RG011i001p00001
47
48
 
48
- Atlas, D., & Ulbrich, C. W. (1977).
49
- Path- and area-integrated rainfall measurement by microwave attenuation in the 1-3 cm band.
50
- Journal of Applied Meteorology, 16(12), 1322-1331.
51
- https://doi.org/10.1175/1520-0450(1977)016<1322:PAAIRM>2.0.CO;2
52
-
53
49
  Gunn, R., & Kinzer, G. D. (1949).
54
50
  The terminal velocity of fall for water droplets in stagnant air.
55
51
  Journal of Meteorology, 6(4), 243-248.
@@ -111,7 +107,7 @@ def get_fall_velocity_uplinger_1981(diameter):
111
107
 
112
108
  """
113
109
  # Valid between 0.1 and 7 mm
114
- fall_velocity = 4.874 * diameter * np.exp(-0.195 * diameter)
110
+ fall_velocity = 4.874 * diameter * np.exp(-0.195 * diameter) # 4.854?
115
111
  fall_velocity = fall_velocity.clip(min=0, max=None)
116
112
  return fall_velocity
117
113
 
@@ -143,8 +139,159 @@ def get_fall_velocity_van_dijk_2002(diameter):
143
139
  return fall_velocity
144
140
 
145
141
 
146
- def get_fall_velocity_beard_1976(diameter, ds_env):
147
- """Calculate the fall velocity of a particle using the Beard (1976) model.
142
+ ####---------------------------------------------------------------------------.
143
+ #### Beard model
144
+
145
+
146
+ def get_raindrop_reynolds_number(diameter, temperature, air_density, water_density, g):
147
+ """Compute raindrop Reynolds number.
148
+
149
+ It quantifies the relative strength of the convective inertia and linear viscous
150
+ forces acting on the drop at terminal velocity.
151
+
152
+ Estimates Reynolds number for drops with diameter between 19 um and 7 mm.
153
+ Coefficients are taken from Table 1 of Beard 1976.
154
+
155
+ Reference: Beard 1976; Pruppacher & Klett 1978
156
+ See also Table A1 in Rahman et al., 2020.
157
+
158
+ Parameters
159
+ ----------
160
+ diameter : float
161
+ Diameter of the raindrop in meters.
162
+ temperature : float
163
+ Temperature in Kelvin.
164
+ air_density : float
165
+ Density of air in kg/m^3.
166
+ water_density : float
167
+ Density of water in kg/m^3.
168
+ g : float
169
+ Gravitational acceleration in m/s^2.
170
+
171
+ Returns
172
+ -------
173
+ float
174
+ Reynolds number for the raindrop.
175
+ """
176
+ from disdrodb.physics.atmosphere import get_air_dynamic_viscosity
177
+ from disdrodb.physics.water import get_pure_water_surface_tension
178
+
179
+ # Define mask for small and large particles
180
+ small_diam_mask = diameter < 1.07e-3 # < 1mm
181
+
182
+ # Compute properties
183
+ pure_water_surface_tension = get_pure_water_surface_tension(temperature) # N/m
184
+ air_viscosity = get_air_dynamic_viscosity(temperature) # kg/(m*s) (aka Pa*s).
185
+ delta_density = water_density - air_density
186
+
187
+ # Compute Davies number for small droplets
188
+ davis_number = 4 * air_density * delta_density * g * diameter**3 / (3 * air_viscosity**2)
189
+
190
+ # Compute the slip correction (is approx 1 and can be discarded)
191
+ # l0 = 6.62*1e-8 # m
192
+ # v0 = 0.01818 # g / m / s
193
+ # p0 = 101_325_25 # Pa
194
+ # t0 = 293.15 # K
195
+ # c_sc = 1 + 2.51*l0*(air_viscosity/v0)*(air_pressure/p0)*((temperature/t0)**3)/diameter
196
+
197
+ # Compute modified Bond and physical property numbers for large droplets
198
+ bond_number = 4 * delta_density * g * diameter**2 / (3 * pure_water_surface_tension)
199
+ property_number = pure_water_surface_tension**3 * air_density**2 / (air_viscosity**4 * delta_density * g)
200
+
201
+ # Compute Reynolds_number_for small particles (diameter < 0.00107) (1 mm)
202
+ b = [-3.18657, 0.992696, -0.00153193, -0.000987059, -0.000578878, 0.0000855176, -0.00000327815]
203
+ x = np.log(davis_number)
204
+ y = b[0] + sum(b * x**i for i, b in enumerate(b[1:], start=1))
205
+ reynolds_number_small = np.exp(y) # TODO: miss C_sc = slip correction factor ?
206
+
207
+ # Compute Reynolds_number_for large particles (diameter >= 0.00107)
208
+ b = [-5.00015, 5.23778, -2.04914, 0.475294, -0.0542819, 0.00238449]
209
+ log_property_number = np.log(property_number) / 6
210
+ x = np.log(bond_number) + log_property_number
211
+ y = b[0] + sum(b * x**i for i, b in enumerate(b[1:], start=1))
212
+ reynolds_number_large = np.exp(log_property_number + y)
213
+
214
+ # Define final reynolds number
215
+ reynolds_number = xr.where(small_diam_mask, reynolds_number_small, reynolds_number_large)
216
+ return reynolds_number
217
+
218
+
219
+ def get_drag_coefficient(diameter, air_density, water_density, fall_velocity, g=9.81):
220
+ """
221
+ Computes the drag coefficient for a raindrop.
222
+
223
+ Parameters
224
+ ----------
225
+ diameter : float
226
+ Diameter of the raindrop in meters.
227
+ air_density : float
228
+ Density of air in kg/m^3.
229
+ water_density : float
230
+ Density of water in kg/m^3.
231
+ fall_velocity : float
232
+ Terminal fall velocity of the raindrop in m/s.
233
+ g : float
234
+ Gravitational acceleration in m/s^2.
235
+
236
+ Returns
237
+ -------
238
+ float
239
+ Drag coefficient of the raindrop.
240
+ """
241
+ delta_density = water_density - air_density
242
+ drag_coefficient = 4 * delta_density * g * diameter / (3 * air_density * fall_velocity**2)
243
+ return drag_coefficient
244
+
245
+
246
+ def get_raindrop_beard1976_fall_velocity(diameter, temperature, air_density, water_density, g):
247
+ """
248
+ Computes the terminal fall velocity of a raindrop in still air.
249
+
250
+ Reference: Beard 1976; Pruppacher & Klett 1978
251
+
252
+ Parameters
253
+ ----------
254
+ diameter : float
255
+ Diameter of the raindrop in millimeters.
256
+ temperature : float
257
+ Temperature in Kelvin.
258
+ air_density : float
259
+ Density of air in kg/m^3.
260
+ water_density : float
261
+ Density of water in kg/m^3.
262
+ g : float
263
+ Gravitational acceleration in m/s^2.
264
+
265
+ Returns
266
+ -------
267
+ float
268
+ Terminal fall velocity of the raindrop in m/s.
269
+ """
270
+ from disdrodb.physics.atmosphere import get_air_dynamic_viscosity
271
+
272
+ # Convert diameter to meter
273
+ diameter = diameter / 1000
274
+
275
+ # Compute air viscotiy and reynolds number
276
+ air_viscosity = get_air_dynamic_viscosity(temperature)
277
+ reynolds_number = get_raindrop_reynolds_number(
278
+ diameter=diameter,
279
+ temperature=temperature,
280
+ air_density=air_density,
281
+ water_density=water_density,
282
+ g=g,
283
+ )
284
+ # Compute fall velocity
285
+ fall_velocity = air_viscosity * reynolds_number / (air_density * diameter)
286
+ return fall_velocity
287
+
288
+
289
+ def retrieve_raindrop_beard_fall_velocity(
290
+ diameter,
291
+ ds_env,
292
+ ):
293
+ """
294
+ Computes the terminal fall velocity for liquid raindrops using the Beard (1976) model.
148
295
 
149
296
  Parameters
150
297
  ----------
@@ -155,56 +302,118 @@ def get_fall_velocity_beard_1976(diameter, ds_env):
155
302
  - 'altitude' : Altitude in meters (m).
156
303
  - 'latitude' : Latitude in degrees.
157
304
  - 'temperature' : Temperature in degrees Kelvin (K).
158
- - 'relative_humidity' : Relative humidity in percentage (%).
159
- - 'sea_level_air_pressure' : Sea level air pressure in Pascals (Pa).
160
- - 'air_pressure': Air pressure in Pascals (Pa).
161
- - 'lapse_rate' : Lapse rate in degrees Celsius per meter (°C/m).
305
+ - 'relative_humidity' : Relative humidity between 0 and 1.
306
+ - 'sea_level_air_pressure' : Standard atmospheric pressure at sea level in Pascals (Pa).
307
+ The default is 101_325 Pa.
308
+ - 'air_pressure': Air pressure in Pascals (Pa). If None, air_pressure at altitude is inferred.
309
+ - 'lapse_rate' : Atmospheric lapse rate in degrees Celsius or Kelvin per meter (°C/m).
310
+ The default is 0.0065 K/m.
311
+ - 'gas_constant_dry_air': Gas constant for dry air in J/(kg*K).
312
+ The default is 287.04 is J/(kg*K).
162
313
 
163
314
  Returns
164
315
  -------
165
316
  fall_velocity : array-like
166
- The calculated fall velocities of the raindrops.
317
+ Terminal fall velocity for liquid raindrops.
167
318
  """
168
- from disdrodb.l1.beard_model import retrieve_fall_velocity
169
-
170
- # Input diameter in mmm
171
- fall_velocity = retrieve_fall_velocity(
172
- diameter=diameter / 1000, # diameter expected in m !!!
173
- altitude=ds_env["altitude"],
174
- latitude=ds_env["latitude"],
175
- temperature=ds_env["temperature"],
176
- relative_humidity=ds_env["relative_humidity"],
177
- air_pressure=ds_env.get("air_pressure", None),
178
- sea_level_air_pressure=ds_env["sea_level_air_pressure"],
179
- lapse_rate=ds_env["lapse_rate"],
319
+ from disdrodb.physics.atmosphere import (
320
+ get_air_density,
321
+ get_air_pressure_at_height,
322
+ get_gravitational_acceleration,
323
+ get_vapor_actual_pressure,
324
+ )
325
+ from disdrodb.physics.water import get_water_density
326
+
327
+ # Retrieve relevant variables from ENV dataset
328
+ altitude = ds_env["altitude"]
329
+ latitude = ds_env["latitude"]
330
+ temperature = ds_env["temperature"]
331
+ relative_humidity = ds_env["relative_humidity"]
332
+ air_pressure = ds_env.get("air_pressure", None)
333
+ sea_level_air_pressure = ds_env.get("sea_level_air_pressure", 101_325)
334
+ gas_constant_dry_air = ds_env.get("gas_constant_dry_air", 287.04)
335
+ lapse_rate = ds_env.get("lapse_rate", 0.0065)
336
+
337
+ # Retrieve air pressure at altitude if not specified
338
+ if air_pressure is None:
339
+ air_pressure = get_air_pressure_at_height(
340
+ altitude=altitude,
341
+ latitude=latitude,
342
+ temperature=temperature,
343
+ sea_level_air_pressure=sea_level_air_pressure,
344
+ lapse_rate=lapse_rate,
345
+ gas_constant_dry_air=gas_constant_dry_air,
346
+ )
347
+
348
+ # Retrieve vapour pressure (from relative humidity)
349
+ vapor_pressure = get_vapor_actual_pressure(
350
+ relative_humidity=relative_humidity,
351
+ temperature=temperature,
180
352
  )
353
+
354
+ # Retrieve air density
355
+ air_density = get_air_density(
356
+ temperature=temperature,
357
+ air_pressure=air_pressure,
358
+ vapor_pressure=vapor_pressure,
359
+ gas_constant_dry_air=gas_constant_dry_air,
360
+ )
361
+
362
+ # Retrieve water density
363
+ water_density = get_water_density(
364
+ temperature=temperature,
365
+ air_pressure=air_pressure,
366
+ sea_level_air_pressure=sea_level_air_pressure,
367
+ )
368
+
369
+ # Retrieve accurate gravitational_acceleration
370
+ g = get_gravitational_acceleration(altitude=altitude, latitude=latitude)
371
+
372
+ # Compute fall velocity
373
+ fall_velocity = get_raindrop_beard1976_fall_velocity(
374
+ diameter=diameter,
375
+ temperature=temperature,
376
+ air_density=air_density,
377
+ water_density=water_density,
378
+ g=g,
379
+ )
380
+
381
+ # drag_coefficient = get_drag_coefficient(diameter=diameter,
382
+ # air_density=air_density,
383
+ # water_density=water_density,
384
+ # g=g.
385
+ # fall_velocity=fall_velocity)
386
+
387
+ # Clip output
181
388
  fall_velocity = fall_velocity.clip(min=0, max=None)
182
389
  return fall_velocity
183
390
 
184
391
 
185
- RAINDROP_FALL_VELOCITY_MODELS = {
392
+ #### --------------------------------------------------------------------------------------
393
+ #### WRAPPERS
394
+ RAIN_FALL_VELOCITY_MODELS = {
186
395
  "Atlas1973": get_fall_velocity_atlas_1973,
187
- "Beard1976": get_fall_velocity_beard_1976,
396
+ "Beard1976": retrieve_raindrop_beard_fall_velocity,
188
397
  "Brandes2002": get_fall_velocity_brandes_2002,
189
398
  "Uplinger1981": get_fall_velocity_uplinger_1981,
190
399
  "VanDijk2002": get_fall_velocity_van_dijk_2002,
191
400
  }
192
401
 
193
402
 
194
- def available_raindrop_fall_velocity_models():
403
+ def available_rain_fall_velocity_models():
195
404
  """Return a list of the available raindrop fall velocity models."""
196
- return list(RAINDROP_FALL_VELOCITY_MODELS)
405
+ return list(RAIN_FALL_VELOCITY_MODELS)
197
406
 
198
407
 
199
- def check_raindrop_fall_velocity_model(model):
408
+ def check_rain_fall_velocity_model(model):
200
409
  """Check validity of the specified raindrop fall velocity model."""
201
- available_models = available_raindrop_fall_velocity_models()
410
+ available_models = available_rain_fall_velocity_models()
202
411
  if model not in available_models:
203
412
  raise ValueError(f"{model} is an invalid raindrop fall velocity model. Valid models: {available_models}.")
204
413
  return model
205
414
 
206
415
 
207
- def get_raindrop_fall_velocity_model(model):
416
+ def get_rain_fall_velocity_model(model):
208
417
  """Return the specified raindrop fall velocity model.
209
418
 
210
419
  Parameters
@@ -224,11 +433,11 @@ def get_raindrop_fall_velocity_model(model):
224
433
  This function serves as a wrapper to various raindrop fall velocity models.
225
434
  It returns the appropriate model based on the `model` parameter.
226
435
  """
227
- model = check_raindrop_fall_velocity_model(model)
228
- return RAINDROP_FALL_VELOCITY_MODELS[model]
436
+ model = check_rain_fall_velocity_model(model)
437
+ return RAIN_FALL_VELOCITY_MODELS[model]
229
438
 
230
439
 
231
- def get_raindrop_fall_velocity(diameter, model, ds_env=None):
440
+ def get_rain_fall_velocity(diameter, model, ds_env=None):
232
441
  """Calculate the fall velocity of raindrops based on their diameter.
233
442
 
234
443
  Parameters
@@ -266,7 +475,7 @@ def get_raindrop_fall_velocity(diameter, model, ds_env=None):
266
475
 
267
476
  """
268
477
  # Check valid method
269
- model = check_raindrop_fall_velocity_model(model)
478
+ model = check_rain_fall_velocity_model(model)
270
479
 
271
480
  # Copy diameter
272
481
  if isinstance(diameter, xr.DataArray):
@@ -275,24 +484,31 @@ def get_raindrop_fall_velocity(diameter, model, ds_env=None):
275
484
  diameter = np.atleast_1d(diameter)
276
485
  diameter = xr.DataArray(diameter, dims=DIAMETER_DIMENSION, coords={DIAMETER_DIMENSION: diameter.copy()})
277
486
 
278
- # Initialize ds_env if None and method == "Beard1976"
279
- if model == "Beard1976":
280
- if ds_env is None:
281
- ds_env = load_env_dataset()
487
+ # Initialize ds_env
488
+ if ds_env is None:
489
+ ds_env = load_env_dataset()
282
490
 
283
- # Ensure valid altitude and geolocation
284
- # - altitude required by Beard
285
- # - latitude required for gravity
286
- for coord in ["altitude", "latitude"]:
287
- ds_env = ensure_valid_geolocation(ds_env, coord=coord, errors="raise")
491
+ # Ensure valid altitude and geolocation
492
+ # - altitude required by Beard
493
+ # - latitude required for gravity
494
+ for coord in ["altitude", "latitude"]:
495
+ ds_env = ensure_valid_geolocation(ds_env, coord=coord, errors="raise")
288
496
 
289
497
  # Retrieve fall velocity
290
- func = get_raindrop_fall_velocity_model(model)
498
+ func = get_rain_fall_velocity_model(model)
291
499
  with suppress_warnings(): # e.g. when diameter = 0 for Beard1976
292
500
  fall_velocity = func(diameter, ds_env=ds_env) if model == "Beard1976" else func(diameter)
293
501
 
502
+ # Correct for altitude
503
+ if model != "Beard1976":
504
+ air_density_height = retrieve_air_density(ds_env)
505
+ air_density_sea_surface = 1.225 # kg/m3 (International Standard Atmosphere air density at sea level)
506
+ correction_factor = (air_density_sea_surface / air_density_height) ** (diameter * 0.025 + 0.375)
507
+ fall_velocity = fall_velocity * correction_factor
508
+
294
509
  # Set to NaN for diameter outside [0, 10)
295
510
  fall_velocity = fall_velocity.where(diameter < 10).where(diameter > 0)
511
+
296
512
  # Ensure fall velocity is > 0 to avoid division by zero
297
513
  # - Some models, at small diameter, can return negative/zero fall velocity
298
514
  fall_velocity = fall_velocity.where(fall_velocity > 0)
@@ -304,7 +520,7 @@ def get_raindrop_fall_velocity(diameter, model, ds_env=None):
304
520
  return fall_velocity.squeeze()
305
521
 
306
522
 
307
- def get_raindrop_fall_velocity_from_ds(ds, ds_env=None, model="Beard1976"):
523
+ def get_rain_fall_velocity_from_ds(ds, ds_env=None, model="Beard1976", diameter="diameter_bin_center"):
308
524
  """Compute the raindrop fall velocity.
309
525
 
310
526
  Parameters
@@ -354,6 +570,5 @@ def get_raindrop_fall_velocity_from_ds(ds, ds_env=None, model="Beard1976"):
354
570
  ds_env = load_env_dataset(ds)
355
571
 
356
572
  # Compute raindrop fall velocity
357
- fall_velocity = get_raindrop_fall_velocity(diameter=ds["diameter_bin_center"], model=model, ds_env=ds_env) # mn
358
-
573
+ fall_velocity = get_rain_fall_velocity(diameter=ds[diameter], model=model, ds_env=ds_env) # mn
359
574
  return fall_velocity
@@ -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/issue/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
@@ -173,7 +171,7 @@ def check_time_periods(time_periods):
173
171
 
174
172
  def _get_issue_timesteps(issue_dict):
175
173
  """Get timesteps from issue dictionary."""
176
- timesteps = issue_dict.get("timesteps", None)
174
+ timesteps = issue_dict.get("timesteps")
177
175
  # Check validity
178
176
  timesteps = check_timesteps(timesteps)
179
177
  # Sort
@@ -183,7 +181,7 @@ def _get_issue_timesteps(issue_dict):
183
181
 
184
182
  def _get_issue_time_periods(issue_dict):
185
183
  """Get time_periods from issue dictionary."""
186
- time_periods = issue_dict.get("time_periods", None)
184
+ time_periods = issue_dict.get("time_periods")
187
185
  time_periods = check_time_periods(time_periods)
188
186
  return time_periods
189
187
 
disdrodb/issue/reader.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/issue/writer.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/l0/__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
@@ -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
@@ -22,7 +20,7 @@ import os
22
20
  from typing import Optional, Union
23
21
 
24
22
  import numpy as np
25
- from pydantic import BaseModel, Field, ValidationError, field_validator, model_validator
23
+ from pydantic import Field, field_validator, model_validator
26
24
 
27
25
  from disdrodb.api.configs import available_sensor_names, get_sensor_configs_dir, read_config_file
28
26
  from disdrodb.l0.standards import (
@@ -36,6 +34,7 @@ from disdrodb.l0.standards import (
36
34
  get_velocity_bin_width,
37
35
  )
38
36
  from disdrodb.utils.directories import list_files
37
+ from disdrodb.utils.pydantic import CustomBaseModel
39
38
 
40
39
  CONFIG_FILES_LIST = [
41
40
  "bins_diameter.yml",
@@ -104,28 +103,24 @@ def check_variable_consistency(sensor_name: str) -> None:
104
103
  raise ValueError(msg)
105
104
 
106
105
 
107
- class SchemaValidationException(Exception):
108
- """Exception raised when schema validation fails."""
109
-
110
-
111
- def _schema_error(object_to_validate: Union[str, list], schema: BaseModel, message) -> bool:
106
+ def _schema_error(object_to_validate: Union[str, list], schema: CustomBaseModel, message) -> bool:
112
107
  """Function that validate the schema of a given object with a given schema.
113
108
 
114
109
  Parameters
115
110
  ----------
116
111
  object_to_validate : Union[str,list]
117
112
  Object to validate.
118
- schema : BaseModel
113
+ schema : CustomBaseModel
119
114
  Base model.
120
115
 
121
116
  """
122
117
  try:
123
118
  schema(**object_to_validate)
124
- except ValidationError as e:
125
- raise SchemaValidationException(f"Schema validation failed. {message} {e}")
119
+ except ValueError as e:
120
+ raise ValueError(f"{message} {e!s}") from None
126
121
 
127
122
 
128
- class L0BEncodingSchema(BaseModel):
123
+ class L0BEncodingSchema(CustomBaseModel):
129
124
  """Pydantic model for DISDRODB netCDF encodings."""
130
125
 
131
126
  contiguous: bool
@@ -136,6 +131,8 @@ class L0BEncodingSchema(BaseModel):
136
131
  fletcher32: bool
137
132
  FillValue: Optional[Union[int, float]] = Field(default=None, alias="_FillValue")
138
133
  chunksizes: Optional[Union[int, list[int]]]
134
+ add_offset: Optional[float] = None
135
+ scale_factor: Optional[float] = None
139
136
 
140
137
  # if contiguous=False, chunksizes specified, otherwise should be not !
141
138
  @model_validator(mode="before")
@@ -200,6 +197,18 @@ class L0BEncodingSchema(BaseModel):
200
197
 
201
198
  return values
202
199
 
200
+ @model_validator(mode="after")
201
+ def remove_offset_and_scale_if_not_int(cls, values):
202
+ """Ensure add_offset and scale_factor only apply to integer/uint dtypes."""
203
+ integer_types = ["int8", "int16", "int32", "int64", "uint8", "uint16", "uint32", "uint64"]
204
+
205
+ if values.dtype not in integer_types:
206
+ # drop those keys to keep model clean
207
+ values.add_offset = None
208
+ values.scale_factor = None
209
+
210
+ return values
211
+
203
212
 
204
213
  def check_l0b_encoding(sensor_name: str) -> None:
205
214
  """Check ``l0b_encodings.yml`` file based on the schema defined in the class ``L0BEncodingSchema``.
@@ -216,7 +225,7 @@ def check_l0b_encoding(sensor_name: str) -> None:
216
225
  _schema_error(
217
226
  object_to_validate=value,
218
227
  schema=L0BEncodingSchema,
219
- message=f"Sensore name : {sensor_name}. Key : {key}.",
228
+ message=f"Invalid {sensor_name} L0B Encoding YAML file '{key}' settings.",
220
229
  )
221
230
 
222
231
 
@@ -243,7 +252,7 @@ def check_l0a_encoding(sensor_name: str) -> None:
243
252
  raise TypeError(f"Expecting a string for {key} in l0a_encodings.yml for sensor {sensor_name}.")
244
253
 
245
254
 
246
- class RawDataFormatSchema(BaseModel):
255
+ class RawDataFormatSchema(CustomBaseModel):
247
256
  """Pydantic model for the DISDRODB RAW Data Format YAML files."""
248
257
 
249
258
  n_digits: Optional[int]
@@ -251,7 +260,7 @@ class RawDataFormatSchema(BaseModel):
251
260
  n_decimals: Optional[int]
252
261
  n_naturals: Optional[int]
253
262
  data_range: Optional[list[float]]
254
- nan_flags: Optional[Union[int, str]] = None
263
+ nan_flags: Optional[Union[int, float, str]] = None
255
264
  valid_values: Optional[list[float]] = None
256
265
  dimension_order: Optional[list[str]] = None
257
266
  n_values: Optional[int] = None
@@ -282,7 +291,7 @@ def check_raw_data_format(sensor_name: str) -> None:
282
291
  _schema_error(
283
292
  object_to_validate=value,
284
293
  schema=RawDataFormatSchema,
285
- message=f"Sensore name : {sensor_name}. Key : {key}.",
294
+ message=f"Invalid {sensor_name} RawDataFormat YAML file '{key}' settings.",
286
295
  )
287
296
 
288
297
 
@@ -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,4 +1,3 @@
1
- device_address: "float32" # 'uint8'
2
1
  weather_code_synop_4677_5min: "float32" # 'uint8'
3
2
  weather_code_synop_4680_5min: "float32" # 'uint8'
4
3
  weather_code_metar_4678_5min: "str"
@@ -1,7 +1,3 @@
1
- device_address:
2
- description: "Device address (factory setting \u201E00\") (NN)"
3
- long_name: Device address
4
- units: ""
5
1
  weather_code_synop_4677_5min:
6
2
  description: 5M SYNOP Tab.4677 (5 minutes mean value) (NN)
7
3
  long_name: 5 min SYNOP Tab.4677
@@ -7,15 +7,15 @@
7
7
  # contiguous: false
8
8
  # chunksizes: 5000
9
9
  # _FillValue: 255
10
- device_address:
11
- dtype: uint8
12
- zlib: true
13
- complevel: 3
14
- shuffle: true
15
- fletcher32: false
16
- contiguous: false
17
- chunksizes: 5000
18
- _FillValue: 255
10
+ # device_address:
11
+ # dtype: uint8
12
+ # zlib: true
13
+ # complevel: 3
14
+ # shuffle: true
15
+ # fletcher32: false
16
+ # contiguous: false
17
+ # chunksizes: 5000
18
+ # _FillValue: 255
19
19
  # sensor_serial_number:
20
20
  # dtype: uint16
21
21
  # zlib: false