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/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,15 @@ 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(df: pd.DataFrame, sensor_name: str, logger=None, verbose: bool = False) -> None:
89
84
  """Check the presence of the raw spectrum data according to the type of sensor.
90
85
 
91
86
  Parameters
92
87
  ----------
93
- df : pd.DataFrame
88
+ df : pandas.DataFrame
94
89
  Dataframe
95
90
  sensor_name : str
96
91
  Name of the sensor.
@@ -98,7 +93,7 @@ def _check_raw_fields_available(df: pd.DataFrame, sensor_name: str, verbose: boo
98
93
  Raises
99
94
  ------
100
95
  ValueError
101
- Error if the raw_drop_number field is missing.
96
+ Error if the ``raw_drop_number`` field is missing.
102
97
  """
103
98
  from disdrodb.l0.standards import get_raw_array_nvalues
104
99
 
@@ -109,7 +104,6 @@ def _check_raw_fields_available(df: pd.DataFrame, sensor_name: str, verbose: boo
109
104
  # Check that raw_drop_number is present
110
105
  if "raw_drop_number" not in df.columns:
111
106
  msg = "The 'raw_drop_number' column is not present in the dataframe."
112
- log_error(logger=logger, msg=msg, verbose=False)
113
107
  raise ValueError(msg)
114
108
 
115
109
  # Report additional raw arrays that are missing
@@ -117,7 +111,6 @@ def _check_raw_fields_available(df: pd.DataFrame, sensor_name: str, verbose: boo
117
111
  if len(missing_vars) > 0:
118
112
  msg = f"The following raw array variable are missing: {missing_vars}"
119
113
  log_info(logger=logger, msg=msg, verbose=verbose)
120
- return None
121
114
 
122
115
 
123
116
  def check_l0a_column_names(df: pd.DataFrame, sensor_name: str) -> None:
@@ -125,7 +118,7 @@ def check_l0a_column_names(df: pd.DataFrame, sensor_name: str) -> None:
125
118
 
126
119
  Parameters
127
120
  ----------
128
- df : pd.DataFrame
121
+ df : pandas.DataFrame
129
122
  Input dataframe.
130
123
  sensor_name : str
131
124
  Name of the sensor.
@@ -133,47 +126,42 @@ def check_l0a_column_names(df: pd.DataFrame, sensor_name: str) -> None:
133
126
  Raises
134
127
  ------
135
128
  ValueError
136
- Error if some columns do not meet the DISDRODB standards or if the 'time' column is missing in the dataframe.
129
+ Error if some columns do not meet the DISDRODB standards or if the ``'time'``
130
+ column is missing in the dataframe.
137
131
 
138
132
  """
139
-
140
133
  # 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)
134
+ valid_columns = set(allowed_l0_variables(sensor_name))
135
+
145
136
  # 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))
137
+ df_columns = set(df.columns)
138
+
139
+ # Find any columns in df that aren't in the valid list
140
+ invalid_columns = df_columns - valid_columns
141
+
142
+ # Raise error in case
151
143
  if len(invalid_columns) > 0:
152
144
  msg = f"The following columns do no met the DISDRODB standards: {invalid_columns}"
153
- logger.error(msg)
154
145
  raise ValueError(msg)
155
- # --------------------------------------------
146
+
156
147
  # Check time column is present
157
148
  if "time" not in df_columns:
158
149
  msg = "The 'time' column is missing in the dataframe."
159
- log_error(logger=logger, msg=msg, verbose=False)
160
150
  raise ValueError(msg)
161
- # --------------------------------------------
162
- return None
163
151
 
164
152
 
165
- def check_l0a_standards(df: pd.DataFrame, sensor_name: str, verbose: bool = True) -> None:
153
+ def check_l0a_standards(df: pd.DataFrame, sensor_name: str, logger=None, verbose: bool = True) -> None:
166
154
  """Checks that a file respects the DISDRODB L0A standards.
167
155
 
168
156
  Parameters
169
157
  ----------
170
- df : pd.DataFrame
158
+ df : pandas.DataFrame
171
159
  L0A dataframe.
172
160
  sensor_name : str
173
161
  Name of the sensor.
174
162
  verbose : bool, optional
175
163
  Whether to verbose the processing.
176
- The default is True.
164
+ The default value is ``True``.
177
165
 
178
166
  Raises
179
167
  ------
@@ -184,23 +172,24 @@ def check_l0a_standards(df: pd.DataFrame, sensor_name: str, verbose: bool = True
184
172
  # -------------------------------------
185
173
  # Check data range
186
174
  dict_data_range = get_data_range_dict(sensor_name)
187
- _check_valid_range(df=df, dict_data_range=dict_data_range, verbose=verbose)
175
+ _check_valid_range(df=df, dict_data_range=dict_data_range)
188
176
 
189
177
  # -------------------------------------
190
178
  # Check categorical data values
191
179
  dict_valid_values = get_valid_values_dict(sensor_name)
192
- _check_valid_values(df=df, dict_valid_values=dict_valid_values, verbose=verbose)
180
+ _check_valid_values(df=df, dict_valid_values=dict_valid_values)
193
181
 
194
182
  # -------------------------------------
195
183
  # Check if raw spectrum and 1D derivate exists
196
- _check_raw_fields_available(df=df, sensor_name=sensor_name, verbose=verbose)
184
+ _check_raw_fields_available(df=df, sensor_name=sensor_name, logger=logger, verbose=verbose)
197
185
 
198
186
  # -------------------------------------
199
187
  # Check if latitude and longitude are columns of the dataframe
200
188
  # - They should be only provided if the instrument is moving !!!!
189
+ # - TODO: this should be removed and raise error if not platform_type: mobile
201
190
  if "latitude" in df.columns:
202
191
  msg = (
203
- " - The L0A dataframe has column 'latitude'. "
192
+ "The L0A dataframe has column 'latitude'. "
204
193
  + "This should be included only if the sensor is moving. "
205
194
  + "Otherwise, specify the 'latitude' in the metadata !"
206
195
  )
@@ -208,7 +197,7 @@ def check_l0a_standards(df: pd.DataFrame, sensor_name: str, verbose: bool = True
208
197
 
209
198
  if "longitude" in df.columns:
210
199
  msg = (
211
- " - The L0A dataframe has column 'longitude'. "
200
+ "The L0A dataframe has column 'longitude'. "
212
201
  + "This should be included only if the sensor is moving. "
213
202
  + "Otherwise, specify the 'longitude' in the metadata !"
214
203
  )
@@ -218,6 +207,7 @@ def check_l0a_standards(df: pd.DataFrame, sensor_name: str, verbose: bool = True
218
207
 
219
208
 
220
209
  def check_l0b_standards(x: str) -> None:
221
- # TODO:
210
+ """Check L0B standards."""
222
211
  # - Check for realistic values after having removed the flags !!!!
212
+ x = "noqa" # noqa: F841
223
213
  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
@@ -21,65 +21,65 @@ center:
21
21
  19: 15.0
22
22
  bounds:
23
23
  0:
24
- - 0.0
25
- - 0.2
24
+ - 0.0
25
+ - 0.2
26
26
  1:
27
- - 0.2
28
- - 0.4
27
+ - 0.2
28
+ - 0.4
29
29
  2:
30
- - 0.4
31
- - 0.6
30
+ - 0.4
31
+ - 0.6
32
32
  3:
33
- - 0.6
34
- - 0.8
33
+ - 0.6
34
+ - 0.8
35
35
  4:
36
- - 0.8
37
- - 1.0
36
+ - 0.8
37
+ - 1.0
38
38
  5:
39
- - 1.0
40
- - 1.4
39
+ - 1.0
40
+ - 1.4
41
41
  6:
42
- - 1.4
43
- - 1.8
42
+ - 1.4
43
+ - 1.8
44
44
  7:
45
- - 1.8
46
- - 2.2
45
+ - 1.8
46
+ - 2.2
47
47
  8:
48
- - 2.2
49
- - 2.6
48
+ - 2.2
49
+ - 2.6
50
50
  9:
51
- - 2.6
52
- - 3.0
51
+ - 2.6
52
+ - 3.0
53
53
  10:
54
- - 3.0
55
- - 3.4
54
+ - 3.0
55
+ - 3.4
56
56
  11:
57
- - 3.4
58
- - 4.2
57
+ - 3.4
58
+ - 4.2
59
59
  12:
60
- - 4.2
61
- - 5.0
60
+ - 4.2
61
+ - 5.0
62
62
  13:
63
- - 5.0
64
- - 5.8
63
+ - 5.0
64
+ - 5.8
65
65
  14:
66
- - 5.8
67
- - 6.6
66
+ - 5.8
67
+ - 6.6
68
68
  15:
69
- - 6.6
70
- - 7.4
69
+ - 6.6
70
+ - 7.4
71
71
  16:
72
- - 7.4
73
- - 8.2
72
+ - 7.4
73
+ - 8.2
74
74
  17:
75
- - 8.2
76
- - 9.0
75
+ - 8.2
76
+ - 9.0
77
77
  18:
78
- - 9.0
79
- - 10.0
78
+ - 9.0
79
+ - 10.0
80
80
  19:
81
- - 10.0
82
- - 20.0
81
+ - 10.0
82
+ - 20.0
83
83
  width:
84
84
  0: 0.2
85
85
  1: 0.2