disdrodb 0.0.21__py3-none-any.whl → 0.1.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (279) hide show
  1. disdrodb/__init__.py +132 -15
  2. disdrodb/_config.py +4 -2
  3. disdrodb/_version.py +9 -4
  4. disdrodb/api/checks.py +264 -237
  5. disdrodb/api/configs.py +4 -8
  6. disdrodb/api/create_directories.py +235 -290
  7. disdrodb/api/info.py +217 -26
  8. disdrodb/api/io.py +306 -270
  9. disdrodb/api/path.py +597 -173
  10. disdrodb/api/search.py +486 -0
  11. disdrodb/{metadata/scripts → cli}/disdrodb_check_metadata_archive.py +12 -7
  12. disdrodb/{utils/pandas.py → cli/disdrodb_data_archive_directory.py} +9 -18
  13. disdrodb/cli/disdrodb_download_archive.py +86 -0
  14. disdrodb/cli/disdrodb_download_metadata_archive.py +53 -0
  15. disdrodb/cli/disdrodb_download_station.py +84 -0
  16. disdrodb/{api/scripts → cli}/disdrodb_initialize_station.py +22 -10
  17. disdrodb/cli/disdrodb_metadata_archive_directory.py +32 -0
  18. disdrodb/{data_transfer/scripts/disdrodb_download_station.py → cli/disdrodb_open_data_archive.py} +22 -22
  19. disdrodb/cli/disdrodb_open_logs_directory.py +69 -0
  20. disdrodb/{data_transfer/scripts/disdrodb_upload_station.py → cli/disdrodb_open_metadata_archive.py} +22 -24
  21. disdrodb/cli/disdrodb_open_metadata_directory.py +71 -0
  22. disdrodb/cli/disdrodb_open_product_directory.py +74 -0
  23. disdrodb/cli/disdrodb_open_readers_directory.py +32 -0
  24. disdrodb/{l0/scripts → cli}/disdrodb_run_l0.py +38 -31
  25. disdrodb/{l0/scripts → cli}/disdrodb_run_l0_station.py +32 -30
  26. disdrodb/{l0/scripts → cli}/disdrodb_run_l0a.py +30 -21
  27. disdrodb/{l0/scripts → cli}/disdrodb_run_l0a_station.py +24 -33
  28. disdrodb/{l0/scripts → cli}/disdrodb_run_l0b.py +30 -21
  29. disdrodb/{l0/scripts → cli}/disdrodb_run_l0b_station.py +25 -34
  30. disdrodb/cli/disdrodb_run_l0c.py +130 -0
  31. disdrodb/cli/disdrodb_run_l0c_station.py +129 -0
  32. disdrodb/cli/disdrodb_run_l1.py +122 -0
  33. disdrodb/cli/disdrodb_run_l1_station.py +121 -0
  34. disdrodb/cli/disdrodb_run_l2e.py +122 -0
  35. disdrodb/cli/disdrodb_run_l2e_station.py +122 -0
  36. disdrodb/cli/disdrodb_run_l2m.py +122 -0
  37. disdrodb/cli/disdrodb_run_l2m_station.py +122 -0
  38. disdrodb/cli/disdrodb_upload_archive.py +105 -0
  39. disdrodb/cli/disdrodb_upload_station.py +98 -0
  40. disdrodb/configs.py +90 -25
  41. disdrodb/data_transfer/__init__.py +22 -0
  42. disdrodb/data_transfer/download_data.py +87 -90
  43. disdrodb/data_transfer/upload_data.py +64 -37
  44. disdrodb/data_transfer/zenodo.py +15 -18
  45. disdrodb/docs.py +1 -1
  46. disdrodb/issue/__init__.py +17 -4
  47. disdrodb/issue/checks.py +10 -23
  48. disdrodb/issue/reader.py +9 -12
  49. disdrodb/issue/writer.py +14 -17
  50. disdrodb/l0/__init__.py +17 -26
  51. disdrodb/l0/check_configs.py +35 -23
  52. disdrodb/l0/check_standards.py +46 -51
  53. disdrodb/l0/configs/{Thies_LPM → LPM}/bins_diameter.yml +44 -44
  54. disdrodb/l0/configs/{Thies_LPM → LPM}/bins_velocity.yml +40 -40
  55. disdrodb/l0/configs/LPM/l0a_encodings.yml +80 -0
  56. disdrodb/l0/configs/{Thies_LPM → LPM}/l0b_cf_attrs.yml +84 -65
  57. disdrodb/l0/configs/{Thies_LPM → LPM}/l0b_encodings.yml +50 -9
  58. disdrodb/l0/configs/{Thies_LPM → LPM}/raw_data_format.yml +285 -245
  59. disdrodb/l0/configs/{OTT_Parsivel → PARSIVEL}/bins_diameter.yml +66 -66
  60. disdrodb/l0/configs/{OTT_Parsivel → PARSIVEL}/bins_velocity.yml +64 -64
  61. disdrodb/l0/configs/PARSIVEL/l0a_encodings.yml +32 -0
  62. disdrodb/l0/configs/{OTT_Parsivel → PARSIVEL}/l0b_cf_attrs.yml +23 -21
  63. disdrodb/l0/configs/{OTT_Parsivel → PARSIVEL}/l0b_encodings.yml +17 -17
  64. disdrodb/l0/configs/{OTT_Parsivel → PARSIVEL}/raw_data_format.yml +77 -77
  65. disdrodb/l0/configs/{OTT_Parsivel2 → PARSIVEL2}/bins_diameter.yml +64 -64
  66. disdrodb/l0/configs/{OTT_Parsivel2 → PARSIVEL2}/bins_velocity.yml +64 -64
  67. disdrodb/l0/configs/PARSIVEL2/l0a_encodings.yml +39 -0
  68. disdrodb/l0/configs/{OTT_Parsivel2 → PARSIVEL2}/l0b_cf_attrs.yml +28 -26
  69. disdrodb/l0/configs/{OTT_Parsivel2 → PARSIVEL2}/l0b_encodings.yml +20 -20
  70. disdrodb/l0/configs/{OTT_Parsivel2 → PARSIVEL2}/raw_data_format.yml +107 -107
  71. disdrodb/l0/configs/PWS100/bins_diameter.yml +173 -0
  72. disdrodb/l0/configs/PWS100/bins_velocity.yml +173 -0
  73. disdrodb/l0/configs/PWS100/l0a_encodings.yml +19 -0
  74. disdrodb/l0/configs/PWS100/l0b_cf_attrs.yml +76 -0
  75. disdrodb/l0/configs/PWS100/l0b_encodings.yml +176 -0
  76. disdrodb/l0/configs/PWS100/raw_data_format.yml +182 -0
  77. disdrodb/l0/configs/{RD_80 → RD80}/bins_diameter.yml +40 -40
  78. disdrodb/l0/configs/RD80/l0a_encodings.yml +16 -0
  79. disdrodb/l0/configs/{RD_80 → RD80}/l0b_cf_attrs.yml +3 -3
  80. disdrodb/l0/configs/RD80/l0b_encodings.yml +135 -0
  81. disdrodb/l0/configs/{RD_80 → RD80}/raw_data_format.yml +46 -50
  82. disdrodb/l0/l0_reader.py +216 -340
  83. disdrodb/l0/l0a_processing.py +237 -208
  84. disdrodb/l0/l0b_nc_processing.py +227 -80
  85. disdrodb/l0/l0b_processing.py +96 -174
  86. disdrodb/l0/l0c_processing.py +627 -0
  87. disdrodb/l0/readers/{ARM → LPM/ARM}/ARM_LPM.py +36 -58
  88. disdrodb/l0/readers/LPM/AUSTRALIA/MELBOURNE_2007_LPM.py +236 -0
  89. disdrodb/l0/readers/LPM/BRAZIL/CHUVA_LPM.py +185 -0
  90. disdrodb/l0/readers/LPM/BRAZIL/GOAMAZON_LPM.py +185 -0
  91. disdrodb/l0/readers/LPM/ITALY/GID_LPM.py +195 -0
  92. disdrodb/l0/readers/LPM/ITALY/GID_LPM_W.py +210 -0
  93. disdrodb/l0/readers/{BRAZIL/GOAMAZON_LPM.py → LPM/KIT/CHWALA.py} +97 -76
  94. disdrodb/l0/readers/LPM/SLOVENIA/ARSO.py +197 -0
  95. disdrodb/l0/readers/LPM/SLOVENIA/CRNI_VRH.py +197 -0
  96. disdrodb/l0/readers/{UK → LPM/UK}/DIVEN.py +14 -35
  97. disdrodb/l0/readers/PARSIVEL/AUSTRALIA/MELBOURNE_2007_PARSIVEL.py +157 -0
  98. disdrodb/l0/readers/PARSIVEL/CHINA/CHONGQING.py +113 -0
  99. disdrodb/l0/readers/{EPFL → PARSIVEL/EPFL}/ARCTIC_2021.py +40 -57
  100. disdrodb/l0/readers/{EPFL → PARSIVEL/EPFL}/COMMON_2011.py +37 -54
  101. disdrodb/l0/readers/{EPFL → PARSIVEL/EPFL}/DAVOS_2009_2011.py +34 -51
  102. disdrodb/l0/readers/{EPFL → PARSIVEL/EPFL}/EPFL_2009.py +34 -51
  103. disdrodb/l0/readers/{EPFL/PARADISO_2014.py → PARSIVEL/EPFL/EPFL_ROOF_2008.py} +38 -50
  104. disdrodb/l0/readers/PARSIVEL/EPFL/EPFL_ROOF_2010.py +105 -0
  105. disdrodb/l0/readers/{EPFL → PARSIVEL/EPFL}/EPFL_ROOF_2011.py +34 -51
  106. disdrodb/l0/readers/{EPFL → PARSIVEL/EPFL}/EPFL_ROOF_2012.py +33 -51
  107. disdrodb/l0/readers/{EPFL → PARSIVEL/EPFL}/GENEPI_2007.py +25 -44
  108. disdrodb/l0/readers/{EPFL → PARSIVEL/EPFL}/GRAND_ST_BERNARD_2007.py +25 -44
  109. disdrodb/l0/readers/{EPFL → PARSIVEL/EPFL}/GRAND_ST_BERNARD_2007_2.py +25 -44
  110. disdrodb/l0/readers/{EPFL → PARSIVEL/EPFL}/HPICONET_2010.py +34 -51
  111. disdrodb/l0/readers/{EPFL/EPFL_ROOF_2010.py → PARSIVEL/EPFL/HYMEX_LTE_SOP2.py} +37 -50
  112. disdrodb/l0/readers/PARSIVEL/EPFL/HYMEX_LTE_SOP3.py +111 -0
  113. disdrodb/l0/readers/{EPFL → PARSIVEL/EPFL}/HYMEX_LTE_SOP4.py +36 -54
  114. disdrodb/l0/readers/{EPFL → PARSIVEL/EPFL}/LOCARNO_2018.py +34 -52
  115. disdrodb/l0/readers/{EPFL → PARSIVEL/EPFL}/LOCARNO_2019.py +38 -56
  116. disdrodb/l0/readers/PARSIVEL/EPFL/PARADISO_2014.py +105 -0
  117. disdrodb/l0/readers/{EPFL → PARSIVEL/EPFL}/PARSIVEL_2007.py +27 -45
  118. disdrodb/l0/readers/{EPFL → PARSIVEL/EPFL}/PLATO_2019.py +24 -44
  119. disdrodb/l0/readers/PARSIVEL/EPFL/RACLETS_2019.py +140 -0
  120. disdrodb/l0/readers/{EPFL → PARSIVEL/EPFL}/RACLETS_2019_WJF.py +41 -59
  121. disdrodb/l0/readers/{EPFL → PARSIVEL/EPFL}/RIETHOLZBACH_2011.py +34 -51
  122. disdrodb/l0/readers/PARSIVEL/EPFL/SAMOYLOV_2017.py +117 -0
  123. disdrodb/l0/readers/PARSIVEL/EPFL/SAMOYLOV_2019.py +137 -0
  124. disdrodb/l0/readers/{EPFL → PARSIVEL/EPFL}/UNIL_2022.py +42 -55
  125. disdrodb/l0/readers/PARSIVEL/GPM/IFLOODS.py +104 -0
  126. disdrodb/l0/readers/{GPM → PARSIVEL/GPM}/LPVEX.py +29 -48
  127. disdrodb/l0/readers/PARSIVEL/GPM/MC3E.py +184 -0
  128. disdrodb/l0/readers/PARSIVEL/KIT/BURKINA_FASO.py +133 -0
  129. disdrodb/l0/readers/PARSIVEL/NCAR/CCOPE_2015.py +113 -0
  130. disdrodb/l0/readers/{NCAR/VORTEX_SE_2016_P1.py → PARSIVEL/NCAR/OWLES_MIPS.py} +46 -72
  131. disdrodb/l0/readers/PARSIVEL/NCAR/PECAN_MOBILE.py +125 -0
  132. disdrodb/l0/readers/{NCAR/OWLES_MIPS.py → PARSIVEL/NCAR/PLOWS_MIPS.py} +45 -64
  133. disdrodb/l0/readers/PARSIVEL/NCAR/VORTEX2_2009.py +114 -0
  134. disdrodb/l0/readers/PARSIVEL/NCAR/VORTEX2_2010.py +176 -0
  135. disdrodb/l0/readers/PARSIVEL/NCAR/VORTEX2_2010_UF.py +183 -0
  136. disdrodb/l0/readers/PARSIVEL/SLOVENIA/UL_FGG.py +121 -0
  137. disdrodb/l0/readers/{ARM/ARM_LD.py → PARSIVEL2/ARM/ARM_PARSIVEL2.py} +27 -50
  138. disdrodb/l0/readers/PARSIVEL2/BRAZIL/CHUVA_PARSIVEL2.py +163 -0
  139. disdrodb/l0/readers/PARSIVEL2/BRAZIL/GOAMAZON_PARSIVEL2.py +163 -0
  140. disdrodb/l0/readers/{DENMARK → PARSIVEL2/DENMARK}/EROSION_nc.py +14 -35
  141. disdrodb/l0/readers/PARSIVEL2/FRANCE/ENPC_PARSIVEL2.py +189 -0
  142. disdrodb/l0/readers/PARSIVEL2/FRANCE/SIRTA_PARSIVEL2.py +119 -0
  143. disdrodb/l0/readers/PARSIVEL2/GPM/GCPEX.py +104 -0
  144. disdrodb/l0/readers/PARSIVEL2/GPM/NSSTC.py +176 -0
  145. disdrodb/l0/readers/PARSIVEL2/ITALY/GID_PARSIVEL2.py +32 -0
  146. disdrodb/l0/readers/PARSIVEL2/MEXICO/OH_IIUNAM_nc.py +56 -0
  147. disdrodb/l0/readers/PARSIVEL2/NCAR/PECAN_FP3.py +120 -0
  148. disdrodb/l0/readers/{NCAR → PARSIVEL2/NCAR}/PECAN_MIPS.py +45 -64
  149. disdrodb/l0/readers/PARSIVEL2/NCAR/RELAMPAGO_PARSIVEL2.py +181 -0
  150. disdrodb/l0/readers/PARSIVEL2/NCAR/SNOWIE_PJ.py +160 -0
  151. disdrodb/l0/readers/PARSIVEL2/NCAR/SNOWIE_SB.py +160 -0
  152. disdrodb/l0/readers/{NCAR/PLOWS_MIPS.py → PARSIVEL2/NCAR/VORTEX_SE_2016_P1.py} +49 -66
  153. disdrodb/l0/readers/PARSIVEL2/NCAR/VORTEX_SE_2016_P2.py +118 -0
  154. disdrodb/l0/readers/PARSIVEL2/NCAR/VORTEX_SE_2016_PIPS.py +152 -0
  155. disdrodb/l0/readers/PARSIVEL2/NETHERLANDS/DELFT.py +166 -0
  156. disdrodb/l0/readers/PWS100/FRANCE/ENPC_PWS100.py +150 -0
  157. disdrodb/l0/readers/{NCAR/RELAMPAGO_RD80.py → RD80/BRAZIL/CHUVA_RD80.py} +36 -60
  158. disdrodb/l0/readers/{BRAZIL → RD80/BRAZIL}/GOAMAZON_RD80.py +36 -55
  159. disdrodb/l0/readers/{NCAR → RD80/NCAR}/CINDY_2011_RD80.py +35 -54
  160. disdrodb/l0/readers/{BRAZIL/CHUVA_RD80.py → RD80/NCAR/RELAMPAGO_RD80.py} +40 -54
  161. disdrodb/l0/readers/RD80/NOAA/PSL_RD80.py +274 -0
  162. disdrodb/l0/readers/template_reader_raw_netcdf_data.py +62 -0
  163. disdrodb/l0/readers/{reader_template.py → template_reader_raw_text_data.py} +20 -44
  164. disdrodb/l0/routines.py +885 -581
  165. disdrodb/l0/standards.py +77 -238
  166. disdrodb/l0/template_tools.py +105 -110
  167. disdrodb/l1/__init__.py +17 -0
  168. disdrodb/l1/beard_model.py +716 -0
  169. disdrodb/l1/encoding_attrs.py +635 -0
  170. disdrodb/l1/fall_velocity.py +260 -0
  171. disdrodb/l1/filters.py +192 -0
  172. disdrodb/l1/processing.py +202 -0
  173. disdrodb/l1/resampling.py +236 -0
  174. disdrodb/l1/routines.py +358 -0
  175. disdrodb/l1_env/__init__.py +17 -0
  176. disdrodb/l1_env/routines.py +38 -0
  177. disdrodb/l2/__init__.py +17 -0
  178. disdrodb/l2/empirical_dsd.py +1833 -0
  179. disdrodb/l2/event.py +388 -0
  180. disdrodb/l2/processing.py +528 -0
  181. disdrodb/l2/processing_options.py +213 -0
  182. disdrodb/l2/routines.py +868 -0
  183. disdrodb/metadata/__init__.py +9 -2
  184. disdrodb/metadata/checks.py +180 -124
  185. disdrodb/metadata/download.py +81 -0
  186. disdrodb/metadata/geolocation.py +146 -0
  187. disdrodb/metadata/info.py +20 -13
  188. disdrodb/metadata/manipulation.py +3 -3
  189. disdrodb/metadata/reader.py +59 -8
  190. disdrodb/metadata/search.py +77 -144
  191. disdrodb/metadata/standards.py +83 -80
  192. disdrodb/metadata/writer.py +10 -16
  193. disdrodb/psd/__init__.py +38 -0
  194. disdrodb/psd/fitting.py +2146 -0
  195. disdrodb/psd/models.py +774 -0
  196. disdrodb/routines.py +1412 -0
  197. disdrodb/scattering/__init__.py +28 -0
  198. disdrodb/scattering/axis_ratio.py +344 -0
  199. disdrodb/scattering/routines.py +456 -0
  200. disdrodb/utils/__init__.py +17 -0
  201. disdrodb/utils/attrs.py +208 -0
  202. disdrodb/utils/cli.py +269 -0
  203. disdrodb/utils/compression.py +60 -42
  204. disdrodb/utils/dask.py +62 -0
  205. disdrodb/utils/dataframe.py +342 -0
  206. disdrodb/utils/decorators.py +110 -0
  207. disdrodb/utils/directories.py +107 -46
  208. disdrodb/utils/encoding.py +127 -0
  209. disdrodb/utils/list.py +29 -0
  210. disdrodb/utils/logger.py +168 -46
  211. disdrodb/utils/time.py +657 -0
  212. disdrodb/utils/warnings.py +30 -0
  213. disdrodb/utils/writer.py +57 -0
  214. disdrodb/utils/xarray.py +138 -47
  215. disdrodb/utils/yaml.py +0 -1
  216. disdrodb/viz/__init__.py +17 -0
  217. disdrodb/viz/plots.py +17 -0
  218. disdrodb-0.1.1.dist-info/METADATA +294 -0
  219. disdrodb-0.1.1.dist-info/RECORD +232 -0
  220. {disdrodb-0.0.21.dist-info → disdrodb-0.1.1.dist-info}/WHEEL +1 -1
  221. disdrodb-0.1.1.dist-info/entry_points.txt +30 -0
  222. disdrodb/data_transfer/scripts/disdrodb_download_archive.py +0 -53
  223. disdrodb/data_transfer/scripts/disdrodb_upload_archive.py +0 -57
  224. disdrodb/l0/configs/OTT_Parsivel/l0a_encodings.yml +0 -32
  225. disdrodb/l0/configs/OTT_Parsivel2/l0a_encodings.yml +0 -39
  226. disdrodb/l0/configs/RD_80/l0a_encodings.yml +0 -16
  227. disdrodb/l0/configs/RD_80/l0b_encodings.yml +0 -135
  228. disdrodb/l0/configs/Thies_LPM/l0a_encodings.yml +0 -80
  229. disdrodb/l0/io.py +0 -257
  230. disdrodb/l0/l0_processing.py +0 -1091
  231. disdrodb/l0/readers/AUSTRALIA/MELBOURNE_2007_OTT.py +0 -178
  232. disdrodb/l0/readers/AUSTRALIA/MELBOURNE_2007_THIES.py +0 -247
  233. disdrodb/l0/readers/BRAZIL/CHUVA_LPM.py +0 -204
  234. disdrodb/l0/readers/BRAZIL/CHUVA_OTT.py +0 -183
  235. disdrodb/l0/readers/BRAZIL/GOAMAZON_OTT.py +0 -183
  236. disdrodb/l0/readers/CHINA/CHONGQING.py +0 -131
  237. disdrodb/l0/readers/EPFL/EPFL_ROOF_2008.py +0 -128
  238. disdrodb/l0/readers/EPFL/HYMEX_LTE_SOP2.py +0 -127
  239. disdrodb/l0/readers/EPFL/HYMEX_LTE_SOP3.py +0 -129
  240. disdrodb/l0/readers/EPFL/RACLETS_2019.py +0 -158
  241. disdrodb/l0/readers/EPFL/SAMOYLOV_2017.py +0 -136
  242. disdrodb/l0/readers/EPFL/SAMOYLOV_2019.py +0 -158
  243. disdrodb/l0/readers/FRANCE/SIRTA_OTT2.py +0 -138
  244. disdrodb/l0/readers/GPM/GCPEX.py +0 -123
  245. disdrodb/l0/readers/GPM/IFLOODS.py +0 -123
  246. disdrodb/l0/readers/GPM/MC3E.py +0 -123
  247. disdrodb/l0/readers/GPM/NSSTC.py +0 -164
  248. disdrodb/l0/readers/ITALY/GID.py +0 -199
  249. disdrodb/l0/readers/MEXICO/OH_IIUNAM_nc.py +0 -92
  250. disdrodb/l0/readers/NCAR/CCOPE_2015.py +0 -133
  251. disdrodb/l0/readers/NCAR/PECAN_FP3.py +0 -137
  252. disdrodb/l0/readers/NCAR/PECAN_MOBILE.py +0 -144
  253. disdrodb/l0/readers/NCAR/RELAMPAGO_OTT.py +0 -195
  254. disdrodb/l0/readers/NCAR/SNOWIE_PJ.py +0 -172
  255. disdrodb/l0/readers/NCAR/SNOWIE_SB.py +0 -179
  256. disdrodb/l0/readers/NCAR/VORTEX2_2009.py +0 -133
  257. disdrodb/l0/readers/NCAR/VORTEX2_2010.py +0 -188
  258. disdrodb/l0/readers/NCAR/VORTEX2_2010_UF.py +0 -191
  259. disdrodb/l0/readers/NCAR/VORTEX_SE_2016_P2.py +0 -135
  260. disdrodb/l0/readers/NCAR/VORTEX_SE_2016_PIPS.py +0 -170
  261. disdrodb/l0/readers/NETHERLANDS/DELFT.py +0 -187
  262. disdrodb/l0/readers/SPAIN/SBEGUERIA.py +0 -179
  263. disdrodb/l0/scripts/disdrodb_run_l0b_concat.py +0 -93
  264. disdrodb/l0/scripts/disdrodb_run_l0b_concat_station.py +0 -85
  265. disdrodb/utils/netcdf.py +0 -452
  266. disdrodb/utils/scripts.py +0 -102
  267. disdrodb-0.0.21.dist-info/AUTHORS.md +0 -18
  268. disdrodb-0.0.21.dist-info/METADATA +0 -186
  269. disdrodb-0.0.21.dist-info/RECORD +0 -168
  270. disdrodb-0.0.21.dist-info/entry_points.txt +0 -15
  271. /disdrodb/l0/configs/{RD_80 → RD80}/bins_velocity.yml +0 -0
  272. /disdrodb/l0/manuals/{Thies_LPM.pdf → LPM.pdf} +0 -0
  273. /disdrodb/l0/manuals/{ODM_470.pdf → ODM470.pdf} +0 -0
  274. /disdrodb/l0/manuals/{OTT_Parsivel.pdf → PARSIVEL.pdf} +0 -0
  275. /disdrodb/l0/manuals/{OTT_Parsivel2.pdf → PARSIVEL2.pdf} +0 -0
  276. /disdrodb/l0/manuals/{PWS_100.pdf → PWS100.pdf} +0 -0
  277. /disdrodb/l0/manuals/{RD_80.pdf → RD80.pdf} +0 -0
  278. {disdrodb-0.0.21.dist-info → disdrodb-0.1.1.dist-info/licenses}/LICENSE +0 -0
  279. {disdrodb-0.0.21.dist-info → disdrodb-0.1.1.dist-info}/top_level.txt +0 -0
disdrodb/l0/__init__.py CHANGED
@@ -1,26 +1,17 @@
1
- from disdrodb.l0.l0_processing import (
2
- run_l0a,
3
- run_l0b_from_nc,
4
- )
5
- from disdrodb.l0.l0_reader import available_readers
6
- from disdrodb.l0.routines import (
7
- run_disdrodb_l0,
8
- run_disdrodb_l0_station,
9
- run_disdrodb_l0a,
10
- run_disdrodb_l0a_station,
11
- run_disdrodb_l0b,
12
- run_disdrodb_l0b_station,
13
- )
14
-
15
- __all__ = [
16
- "run_l0a",
17
- "run_l0b_from_nc",
18
- "available_readers",
19
- # Functions invoking the disdrodb_run_* scripts in the terminal
20
- "run_disdrodb_l0a_station",
21
- "run_disdrodb_l0b_station",
22
- "run_disdrodb_l0_station",
23
- "run_disdrodb_l0",
24
- "run_disdrodb_l0a",
25
- "run_disdrodb_l0b",
26
- ]
1
+ # -----------------------------------------------------------------------------.
2
+ # Copyright (c) 2021-2023 DISDRODB developers
3
+ #
4
+ # This program is free software: you can redistribute it and/or modify
5
+ # it under the terms of the GNU General Public License as published by
6
+ # the Free Software Foundation, either version 3 of the License, or
7
+ # (at your option) any later version.
8
+ #
9
+ # This program is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU General Public License
15
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
16
+ # -----------------------------------------------------------------------------.
17
+ """DISDRODB L0 software."""
@@ -19,7 +19,7 @@
19
19
  """Check configuration files."""
20
20
 
21
21
  import os
22
- from typing import List, Optional, Union
22
+ from typing import Optional, Union
23
23
 
24
24
  import numpy as np
25
25
  from pydantic import BaseModel, ValidationError, field_validator, model_validator
@@ -105,7 +105,7 @@ def _check_variable_consistency(sensor_name: str) -> None:
105
105
 
106
106
 
107
107
  class SchemaValidationException(Exception):
108
- """Exception raised when schema validation fails"""
108
+ """Exception raised when schema validation fails."""
109
109
 
110
110
 
111
111
  def _schema_error(object_to_validate: Union[str, list], schema: BaseModel, message) -> bool:
@@ -114,12 +114,11 @@ def _schema_error(object_to_validate: Union[str, list], schema: BaseModel, messa
114
114
  Parameters
115
115
  ----------
116
116
  object_to_validate : Union[str,list]
117
- Object to validate
117
+ Object to validate.
118
118
  schema : BaseModel
119
- Base model
119
+ Base model.
120
120
 
121
121
  """
122
-
123
122
  try:
124
123
  schema(**object_to_validate)
125
124
  except ValidationError as e:
@@ -127,6 +126,8 @@ def _schema_error(object_to_validate: Union[str, list], schema: BaseModel, messa
127
126
 
128
127
 
129
128
  class L0BEncodingSchema(BaseModel):
129
+ """Pydantic model for DISDRODB L0B encodings."""
130
+
130
131
  contiguous: bool
131
132
  dtype: str
132
133
  zlib: bool
@@ -134,11 +135,12 @@ class L0BEncodingSchema(BaseModel):
134
135
  shuffle: bool
135
136
  fletcher32: bool
136
137
  _FillValue: Optional[Union[int, float]]
137
- chunksizes: Optional[Union[int, List[int]]]
138
+ chunksizes: Optional[Union[int, list[int]]]
138
139
 
139
140
  # if contiguous=False, chunksizes specified, otherwise should be not !
140
141
  @model_validator(mode="before")
141
142
  def check_chunksizes_and_zlib(cls, values):
143
+ """Check the chunksizes validity."""
142
144
  contiguous = values.get("contiguous")
143
145
  chunksizes = values.get("chunksizes")
144
146
  if not contiguous and not chunksizes:
@@ -148,6 +150,7 @@ class L0BEncodingSchema(BaseModel):
148
150
  # if contiguous = True, then zlib must be set to False
149
151
  @model_validator(mode="before")
150
152
  def check_contiguous_and_zlib(cls, values):
153
+ """Check the the compression value validity."""
151
154
  contiguous = values.get("contiguous")
152
155
  zlib = values.get("zlib")
153
156
  if contiguous and zlib:
@@ -157,6 +160,7 @@ class L0BEncodingSchema(BaseModel):
157
160
  # if contiguous = True, then fletcher32 must be set to False
158
161
  @model_validator(mode="before")
159
162
  def check_contiguous_and_fletcher32(cls, values):
163
+ """Check the fletcher value validity."""
160
164
  contiguous = values.get("contiguous")
161
165
  fletcher32 = values.get("fletcher32")
162
166
  if contiguous and fletcher32:
@@ -165,14 +169,13 @@ class L0BEncodingSchema(BaseModel):
165
169
 
166
170
 
167
171
  def check_l0b_encoding(sensor_name: str) -> None:
168
- """Check l0b_encodings.yml file based on the schema defined in the class L0BEncodingSchema.
172
+ """Check ``l0b_encodings.yml`` file based on the schema defined in the class ``L0BEncodingSchema``.
169
173
 
170
174
  Parameters
171
175
  ----------
172
176
  sensor_name : str
173
177
  Name of the sensor.
174
178
  """
175
-
176
179
  data = read_config_file(sensor_name, product="L0A", filename="l0b_encodings.yml")
177
180
 
178
181
  # check that the second level of the dictionary match the schema
@@ -185,7 +188,7 @@ def check_l0b_encoding(sensor_name: str) -> None:
185
188
 
186
189
 
187
190
  def check_l0a_encoding(sensor_name: str) -> None:
188
- """Check l0a_encodings.yml file.
191
+ """Check ``l0a_encodings.yml`` file.
189
192
 
190
193
  Parameters
191
194
  ----------
@@ -208,27 +211,31 @@ def check_l0a_encoding(sensor_name: str) -> None:
208
211
 
209
212
 
210
213
  class RawDataFormatSchema(BaseModel):
214
+ """Pydantic model for the DISDRODB RAW Data Format YAML files."""
215
+
211
216
  n_digits: Optional[int]
212
217
  n_characters: Optional[int]
213
218
  n_decimals: Optional[int]
214
219
  n_naturals: Optional[int]
215
- data_range: Optional[List[float]]
220
+ data_range: Optional[list[float]]
216
221
  nan_flags: Optional[Union[int, str]] = None
217
- valid_values: Optional[List[float]] = None
218
- dimension_order: Optional[List[str]] = None
222
+ valid_values: Optional[list[float]] = None
223
+ dimension_order: Optional[list[str]] = None
219
224
  n_values: Optional[int] = None
220
225
  field_number: Optional[str] = None
221
226
 
222
227
  @field_validator("data_range")
223
228
  def check_list_length(cls, value):
229
+ """Check the data_range validity."""
224
230
  if value:
225
231
  if len(value) != 2:
226
232
  raise ValueError(f"data_range must have exactly 2 keys, {len(value)} element have been provided.")
227
233
  return value
234
+ return None
228
235
 
229
236
 
230
237
  def _check_raw_data_format(sensor_name: str) -> None:
231
- """check raw_data_format.yml file based on the schema defined in the class RawDataFormatSchema.
238
+ """Check ``raw_data_format.yml`` file based on the schema defined in the class ``RawDataFormatSchema``.
232
239
 
233
240
  Parameters
234
241
  ----------
@@ -247,7 +254,7 @@ def _check_raw_data_format(sensor_name: str) -> None:
247
254
 
248
255
 
249
256
  def _check_cf_attributes(sensor_name: str) -> None:
250
- """Check that the l0b_cf_attrs.yml description, long_name and units values are strings.
257
+ """Check that the ``l0b_cf_attrs.yml`` description, long_name and units values are strings.
251
258
 
252
259
  Parameters
253
260
  ----------
@@ -271,7 +278,6 @@ def _check_bin_consistency(sensor_name: str) -> None:
271
278
  sensor_name : str
272
279
  Name of the sensor.
273
280
  """
274
-
275
281
  diameter_bin_lower = np.array(get_diameter_bin_lower(sensor_name))
276
282
  diameter_bin_upper = np.array(get_diameter_bin_upper(sensor_name))
277
283
  diameter_bin_center = np.array(get_diameter_bin_center(sensor_name))
@@ -294,10 +300,16 @@ def _check_bin_consistency(sensor_name: str) -> None:
294
300
  if all(arr.size > 1 for arr in [velocity_bin_center, velocity_bin_lower, velocity_bin_upper, velocity_bin_width]):
295
301
  np.testing.assert_allclose(velocity_bin_upper - velocity_bin_lower, velocity_bin_width, atol=1e-3, rtol=1e-4)
296
302
  np.testing.assert_allclose(
297
- velocity_bin_lower + velocity_bin_width / 2, velocity_bin_center, atol=1e-3, rtol=1e-4
303
+ velocity_bin_lower + velocity_bin_width / 2,
304
+ velocity_bin_center,
305
+ atol=1e-3,
306
+ rtol=1e-4,
298
307
  )
299
308
  np.testing.assert_allclose(
300
- velocity_bin_upper - velocity_bin_width / 2, velocity_bin_center, atol=1e-3, rtol=1e-4
309
+ velocity_bin_upper - velocity_bin_width / 2,
310
+ velocity_bin_center,
311
+ atol=1e-3,
312
+ rtol=1e-4,
301
313
  )
302
314
 
303
315
 
@@ -318,7 +330,7 @@ def _check_raw_array(sensor_name: str) -> None:
318
330
 
319
331
  # Get keys in raw_data_format where the value is "dimension_order"
320
332
  dict_keys_with_dimension_order = {
321
- key: value.get("dimension_order") for key, value in raw_data_format.items() if "dimension_order" in value.keys()
333
+ key: value.get("dimension_order") for key, value in raw_data_format.items() if "dimension_order" in value
322
334
  }
323
335
 
324
336
  l0b_encodings = read_config_file(sensor_name, product="L0A", filename="l0b_encodings.yml")
@@ -332,11 +344,11 @@ def _check_raw_array(sensor_name: str) -> None:
332
344
  # Get chunksizes in l0b_encoding.yml and check that if len > 1, has dimension_order key in raw_data_format
333
345
  list_attributes_l0b_encodings = [
334
346
  i
335
- for i in l0b_encodings.keys()
347
+ for i in l0b_encodings
336
348
  if isinstance(l0b_encodings.get(i).get("chunksizes"), list) and len(l0b_encodings.get(i).get("chunksizes")) > 1
337
349
  ]
338
350
  list_attributes_from_raw_data_format = [
339
- i for i in raw_data_format.keys() if raw_data_format.get(i).get("dimension_order") is not None
351
+ i for i in raw_data_format if raw_data_format.get(i).get("dimension_order") is not None
340
352
  ]
341
353
 
342
354
  if not sorted(list_attributes_l0b_encodings) == sorted(list_attributes_from_raw_data_format):
@@ -344,7 +356,7 @@ def _check_raw_array(sensor_name: str) -> None:
344
356
 
345
357
 
346
358
  def check_sensor_configs(sensor_name: str) -> None:
347
- """check sensor configs.
359
+ """Check validity of sensor configuration YAML files.
348
360
 
349
361
  Parameters
350
362
  ----------
@@ -362,6 +374,6 @@ def check_sensor_configs(sensor_name: str) -> None:
362
374
 
363
375
 
364
376
  def check_all_sensors_configs() -> None:
365
- """Check all sensors configs."""
366
- for sensor_name in available_sensor_names(product="L0A"):
377
+ """Check all sensors configuration YAML files."""
378
+ for sensor_name in available_sensor_names():
367
379
  check_sensor_configs(sensor_name=sensor_name)
@@ -25,24 +25,21 @@ import numpy as np
25
25
  import pandas as pd
26
26
 
27
27
  from disdrodb.l0.standards import (
28
+ allowed_l0_variables,
28
29
  get_data_range_dict,
29
- get_l0a_dtype,
30
30
  get_valid_values_dict,
31
31
  )
32
32
 
33
33
  # Logger
34
- from disdrodb.utils.logger import (
35
- log_error,
36
- log_info,
37
- )
34
+ from disdrodb.utils.logger import log_info
38
35
 
39
36
  logger = logging.getLogger(__name__)
40
37
 
41
38
 
42
- def _check_valid_range(df, dict_data_range, verbose=False):
39
+ def _check_valid_range(df, dict_data_range):
43
40
  """Check valid value range of dataframe columns.
44
41
 
45
- It assumes the dict_data_range values are list [min_val, max_val]
42
+ It assumes the ``dict_data_range`` values are list ``[min_val, max_val]``.
46
43
  """
47
44
  list_wrong_columns = []
48
45
  for column in df.columns:
@@ -56,14 +53,13 @@ def _check_valid_range(df, dict_data_range, verbose=False):
56
53
 
57
54
  if len(list_wrong_columns) > 0:
58
55
  msg = f"Columns {list_wrong_columns} has values outside the expected data range."
59
- log_error(logger=logger, msg=msg, verbose=False)
60
56
  raise ValueError(msg)
61
57
 
62
58
 
63
- def _check_valid_values(df, dict_valid_values, verbose=False):
59
+ def _check_valid_values(df, dict_valid_values):
64
60
  """Check valid values of dataframe columns.
65
61
 
66
- It assumes the dict_valid_values values are list [...].
62
+ It assumes the ``dict_valid_values`` values are lists.
67
63
  """
68
64
  list_msg = []
69
65
  list_wrong_columns = []
@@ -81,16 +77,20 @@ def _check_valid_values(df, dict_valid_values, verbose=False):
81
77
 
82
78
  if len(list_wrong_columns) > 0:
83
79
  msg = "\n".join(list_msg)
84
- log_error(logger=logger, msg=msg, verbose=False)
85
80
  raise ValueError(f"Columns {list_wrong_columns} have invalid values.")
86
81
 
87
82
 
88
- def _check_raw_fields_available(df: pd.DataFrame, sensor_name: str, verbose: bool = False) -> None:
83
+ def _check_raw_fields_available(
84
+ df: pd.DataFrame,
85
+ sensor_name: str, # noqa: ARG001
86
+ logger=None, # noqa: ARG001
87
+ verbose: bool = False, # noqa: ARG001
88
+ ) -> None:
89
89
  """Check the presence of the raw spectrum data according to the type of sensor.
90
90
 
91
91
  Parameters
92
92
  ----------
93
- df : pd.DataFrame
93
+ df : pandas.DataFrame
94
94
  Dataframe
95
95
  sensor_name : str
96
96
  Name of the sensor.
@@ -98,26 +98,24 @@ def _check_raw_fields_available(df: pd.DataFrame, sensor_name: str, verbose: boo
98
98
  Raises
99
99
  ------
100
100
  ValueError
101
- Error if the raw_drop_number field is missing.
101
+ Error if the ``raw_drop_number`` field is missing.
102
102
  """
103
- from disdrodb.l0.standards import get_raw_array_nvalues
104
-
105
- # Retrieve raw arrays that could be available (based on sensor_name)
106
- n_bins_dict = get_raw_array_nvalues(sensor_name=sensor_name)
107
- raw_vars = np.array(list(n_bins_dict.keys()))
103
+ # from disdrodb.l0.standards import get_raw_array_nvalues
108
104
 
109
105
  # Check that raw_drop_number is present
110
106
  if "raw_drop_number" not in df.columns:
111
107
  msg = "The 'raw_drop_number' column is not present in the dataframe."
112
- log_error(logger=logger, msg=msg, verbose=False)
113
108
  raise ValueError(msg)
114
109
 
110
+ # Retrieve raw arrays that could be available (based on sensor_name)
111
+ # n_bins_dict = get_raw_array_nvalues(sensor_name=sensor_name)
112
+
115
113
  # Report additional raw arrays that are missing
116
- missing_vars = raw_vars[np.isin(raw_vars, list(df.columns), invert=True)]
117
- if len(missing_vars) > 0:
118
- msg = f"The following raw array variable are missing: {missing_vars}"
119
- log_info(logger=logger, msg=msg, verbose=verbose)
120
- return None
114
+ # raw_vars = np.array(list(n_bins_dict.keys()))
115
+ # missing_vars = raw_vars[np.isin(raw_vars, list(df.columns), invert=True)]
116
+ # if len(missing_vars) > 0:
117
+ # msg = f"The following raw array variable are missing: {missing_vars}"
118
+ # log_info(logger=logger, msg=msg, verbose=verbose)
121
119
 
122
120
 
123
121
  def check_l0a_column_names(df: pd.DataFrame, sensor_name: str) -> None:
@@ -125,7 +123,7 @@ def check_l0a_column_names(df: pd.DataFrame, sensor_name: str) -> None:
125
123
 
126
124
  Parameters
127
125
  ----------
128
- df : pd.DataFrame
126
+ df : pandas.DataFrame
129
127
  Input dataframe.
130
128
  sensor_name : str
131
129
  Name of the sensor.
@@ -133,47 +131,42 @@ def check_l0a_column_names(df: pd.DataFrame, sensor_name: str) -> None:
133
131
  Raises
134
132
  ------
135
133
  ValueError
136
- Error if some columns do not meet the DISDRODB standards or if the 'time' column is missing in the dataframe.
134
+ Error if some columns do not meet the DISDRODB standards or if the ``'time'``
135
+ column is missing in the dataframe.
137
136
 
138
137
  """
139
-
140
138
  # Get valid columns
141
- dtype_dict = get_l0a_dtype(sensor_name)
142
- valid_columns = list(dtype_dict)
143
- valid_columns = valid_columns + ["time", "latitude", "longitude"]
144
- valid_columns = set(valid_columns)
139
+ valid_columns = set(allowed_l0_variables(sensor_name))
140
+
145
141
  # Get dataframe column names
146
- df_columns = list(df.columns)
147
- df_columns = set(df_columns)
148
- # --------------------------------------------
149
- # Check there aren't valid columns
150
- invalid_columns = list(df_columns.difference(valid_columns))
142
+ df_columns = set(df.columns)
143
+
144
+ # Find any columns in df that aren't in the valid list
145
+ invalid_columns = df_columns - valid_columns
146
+
147
+ # Raise error in case
151
148
  if len(invalid_columns) > 0:
152
149
  msg = f"The following columns do no met the DISDRODB standards: {invalid_columns}"
153
- logger.error(msg)
154
150
  raise ValueError(msg)
155
- # --------------------------------------------
151
+
156
152
  # Check time column is present
157
153
  if "time" not in df_columns:
158
154
  msg = "The 'time' column is missing in the dataframe."
159
- log_error(logger=logger, msg=msg, verbose=False)
160
155
  raise ValueError(msg)
161
- # --------------------------------------------
162
- return None
163
156
 
164
157
 
165
- def check_l0a_standards(df: pd.DataFrame, sensor_name: str, verbose: bool = True) -> None:
158
+ def check_l0a_standards(df: pd.DataFrame, sensor_name: str, logger=None, verbose: bool = True) -> None:
166
159
  """Checks that a file respects the DISDRODB L0A standards.
167
160
 
168
161
  Parameters
169
162
  ----------
170
- df : pd.DataFrame
163
+ df : pandas.DataFrame
171
164
  L0A dataframe.
172
165
  sensor_name : str
173
166
  Name of the sensor.
174
167
  verbose : bool, optional
175
168
  Whether to verbose the processing.
176
- The default is True.
169
+ The default value is ``True``.
177
170
 
178
171
  Raises
179
172
  ------
@@ -184,23 +177,24 @@ def check_l0a_standards(df: pd.DataFrame, sensor_name: str, verbose: bool = True
184
177
  # -------------------------------------
185
178
  # Check data range
186
179
  dict_data_range = get_data_range_dict(sensor_name)
187
- _check_valid_range(df=df, dict_data_range=dict_data_range, verbose=verbose)
180
+ _check_valid_range(df=df, dict_data_range=dict_data_range)
188
181
 
189
182
  # -------------------------------------
190
183
  # Check categorical data values
191
184
  dict_valid_values = get_valid_values_dict(sensor_name)
192
- _check_valid_values(df=df, dict_valid_values=dict_valid_values, verbose=verbose)
185
+ _check_valid_values(df=df, dict_valid_values=dict_valid_values)
193
186
 
194
187
  # -------------------------------------
195
188
  # Check if raw spectrum and 1D derivate exists
196
- _check_raw_fields_available(df=df, sensor_name=sensor_name, verbose=verbose)
189
+ _check_raw_fields_available(df=df, sensor_name=sensor_name, logger=logger, verbose=verbose)
197
190
 
198
191
  # -------------------------------------
199
192
  # Check if latitude and longitude are columns of the dataframe
200
193
  # - They should be only provided if the instrument is moving !!!!
194
+ # - TODO: this should be removed and raise error if not platform_type: mobile
201
195
  if "latitude" in df.columns:
202
196
  msg = (
203
- " - The L0A dataframe has column 'latitude'. "
197
+ "The L0A dataframe has column 'latitude'. "
204
198
  + "This should be included only if the sensor is moving. "
205
199
  + "Otherwise, specify the 'latitude' in the metadata !"
206
200
  )
@@ -208,7 +202,7 @@ def check_l0a_standards(df: pd.DataFrame, sensor_name: str, verbose: bool = True
208
202
 
209
203
  if "longitude" in df.columns:
210
204
  msg = (
211
- " - The L0A dataframe has column 'longitude'. "
205
+ "The L0A dataframe has column 'longitude'. "
212
206
  + "This should be included only if the sensor is moving. "
213
207
  + "Otherwise, specify the 'longitude' in the metadata !"
214
208
  )
@@ -218,6 +212,7 @@ def check_l0a_standards(df: pd.DataFrame, sensor_name: str, verbose: bool = True
218
212
 
219
213
 
220
214
  def check_l0b_standards(x: str) -> None:
221
- # TODO:
215
+ """Check L0B standards."""
222
216
  # - Check for realistic values after having removed the flags !!!!
217
+ x = "noqa" # noqa: F841
223
218
  pass
@@ -23,71 +23,71 @@ center:
23
23
  21: 54
24
24
  bounds:
25
25
  0:
26
- - 0.125
27
- - 0.25
26
+ - 0.125
27
+ - 0.25
28
28
  1:
29
- - 0.25
30
- - 0.375
29
+ - 0.25
30
+ - 0.375
31
31
  2:
32
- - 0.375
33
- - 0.5
32
+ - 0.375
33
+ - 0.5
34
34
  3:
35
- - 0.5
36
- - 0.75
35
+ - 0.5
36
+ - 0.75
37
37
  4:
38
- - 0.75
39
- - 1.0
38
+ - 0.75
39
+ - 1.0
40
40
  5:
41
- - 1.0
42
- - 1.25
41
+ - 1.0
42
+ - 1.25
43
43
  6:
44
- - 1.25
45
- - 1.5
44
+ - 1.25
45
+ - 1.5
46
46
  7:
47
- - 1.5
48
- - 1.75
47
+ - 1.5
48
+ - 1.75
49
49
  8:
50
- - 1.75
51
- - 2.0
50
+ - 1.75
51
+ - 2.0
52
52
  9:
53
- - 2.0
54
- - 2.5
53
+ - 2.0
54
+ - 2.5
55
55
  10:
56
- - 2.5
57
- - 3.0
56
+ - 2.5
57
+ - 3.0
58
58
  11:
59
- - 3.0
60
- - 3.5
59
+ - 3.0
60
+ - 3.5
61
61
  12:
62
- - 3.5
63
- - 4.0
62
+ - 3.5
63
+ - 4.0
64
64
  13:
65
- - 4.0
66
- - 4.5
65
+ - 4.0
66
+ - 4.5
67
67
  14:
68
- - 4.5
69
- - 5.0
68
+ - 4.5
69
+ - 5.0
70
70
  15:
71
- - 5.0
72
- - 5.5
71
+ - 5.0
72
+ - 5.5
73
73
  16:
74
- - 5.5
75
- - 6.0
74
+ - 5.5
75
+ - 6.0
76
76
  17:
77
- - 6.0
78
- - 6.5
77
+ - 6.0
78
+ - 6.5
79
79
  18:
80
- - 6.5
81
- - 7.0
80
+ - 6.5
81
+ - 7.0
82
82
  19:
83
- - 7.0
84
- - 7.5
83
+ - 7.0
84
+ - 7.5
85
85
  20:
86
- - 7.5
87
- - 8.0
86
+ - 7.5
87
+ - 8.0
88
88
  21:
89
- - 8.0
90
- - 100
89
+ - 8.0
90
+ - 100
91
91
  width:
92
92
  0: 0.125
93
93
  1: 0.125