disdrodb 0.1.2__py3-none-any.whl → 0.1.4__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 (142) hide show
  1. disdrodb/__init__.py +68 -34
  2. disdrodb/_config.py +5 -4
  3. disdrodb/_version.py +16 -3
  4. disdrodb/accessor/__init__.py +20 -0
  5. disdrodb/accessor/methods.py +125 -0
  6. disdrodb/api/checks.py +177 -24
  7. disdrodb/api/configs.py +3 -3
  8. disdrodb/api/info.py +13 -13
  9. disdrodb/api/io.py +281 -22
  10. disdrodb/api/path.py +184 -195
  11. disdrodb/api/search.py +18 -9
  12. disdrodb/cli/disdrodb_create_summary.py +103 -0
  13. disdrodb/cli/disdrodb_create_summary_station.py +91 -0
  14. disdrodb/cli/disdrodb_run_l0.py +1 -1
  15. disdrodb/cli/disdrodb_run_l0_station.py +1 -1
  16. disdrodb/cli/disdrodb_run_l0a_station.py +1 -1
  17. disdrodb/cli/disdrodb_run_l0b.py +1 -1
  18. disdrodb/cli/disdrodb_run_l0b_station.py +3 -3
  19. disdrodb/cli/disdrodb_run_l0c.py +1 -1
  20. disdrodb/cli/disdrodb_run_l0c_station.py +3 -3
  21. disdrodb/cli/disdrodb_run_l1_station.py +2 -2
  22. disdrodb/cli/disdrodb_run_l2e_station.py +2 -2
  23. disdrodb/cli/disdrodb_run_l2m_station.py +2 -2
  24. disdrodb/configs.py +149 -4
  25. disdrodb/constants.py +61 -0
  26. disdrodb/data_transfer/download_data.py +127 -11
  27. disdrodb/etc/configs/attributes.yaml +339 -0
  28. disdrodb/etc/configs/encodings.yaml +473 -0
  29. disdrodb/etc/products/L1/global.yaml +13 -0
  30. disdrodb/etc/products/L2E/10MIN.yaml +12 -0
  31. disdrodb/etc/products/L2E/1MIN.yaml +1 -0
  32. disdrodb/etc/products/L2E/global.yaml +22 -0
  33. disdrodb/etc/products/L2M/10MIN.yaml +12 -0
  34. disdrodb/etc/products/L2M/GAMMA_ML.yaml +8 -0
  35. disdrodb/etc/products/L2M/NGAMMA_GS_LOG_ND_MAE.yaml +6 -0
  36. disdrodb/etc/products/L2M/NGAMMA_GS_ND_MAE.yaml +6 -0
  37. disdrodb/etc/products/L2M/NGAMMA_GS_Z_MAE.yaml +6 -0
  38. disdrodb/etc/products/L2M/global.yaml +26 -0
  39. disdrodb/issue/writer.py +2 -0
  40. disdrodb/l0/__init__.py +13 -0
  41. disdrodb/l0/configs/LPM/l0b_cf_attrs.yml +4 -4
  42. disdrodb/l0/configs/PARSIVEL/l0b_cf_attrs.yml +1 -1
  43. disdrodb/l0/configs/PARSIVEL/l0b_encodings.yml +3 -3
  44. disdrodb/l0/configs/PARSIVEL/raw_data_format.yml +1 -1
  45. disdrodb/l0/configs/PARSIVEL2/l0b_cf_attrs.yml +5 -5
  46. disdrodb/l0/configs/PARSIVEL2/l0b_encodings.yml +3 -3
  47. disdrodb/l0/configs/PARSIVEL2/raw_data_format.yml +1 -1
  48. disdrodb/l0/configs/PWS100/l0b_cf_attrs.yml +4 -4
  49. disdrodb/l0/configs/PWS100/raw_data_format.yml +1 -1
  50. disdrodb/l0/l0a_processing.py +37 -32
  51. disdrodb/l0/l0b_nc_processing.py +118 -8
  52. disdrodb/l0/l0b_processing.py +30 -65
  53. disdrodb/l0/l0c_processing.py +369 -259
  54. disdrodb/l0/readers/LPM/ARM/ARM_LPM.py +7 -0
  55. disdrodb/l0/readers/LPM/NETHERLANDS/DELFT_LPM_NC.py +66 -0
  56. disdrodb/l0/readers/LPM/SLOVENIA/{CRNI_VRH.py → UL.py} +3 -0
  57. disdrodb/l0/readers/LPM/SWITZERLAND/INNERERIZ_LPM.py +195 -0
  58. disdrodb/l0/readers/PARSIVEL/GPM/PIERS.py +0 -2
  59. disdrodb/l0/readers/PARSIVEL/JAPAN/JMA.py +4 -1
  60. disdrodb/l0/readers/PARSIVEL/NCAR/PECAN_MOBILE.py +1 -1
  61. disdrodb/l0/readers/PARSIVEL/NCAR/VORTEX2_2009.py +1 -1
  62. disdrodb/l0/readers/PARSIVEL2/ARM/ARM_PARSIVEL2.py +4 -0
  63. disdrodb/l0/readers/PARSIVEL2/BELGIUM/ILVO.py +168 -0
  64. disdrodb/l0/readers/PARSIVEL2/CANADA/UQAM_NC.py +69 -0
  65. disdrodb/l0/readers/PARSIVEL2/DENMARK/DTU.py +165 -0
  66. disdrodb/l0/readers/PARSIVEL2/FINLAND/FMI_PARSIVEL2.py +69 -0
  67. disdrodb/l0/readers/PARSIVEL2/FRANCE/ENPC_PARSIVEL2.py +255 -134
  68. disdrodb/l0/readers/PARSIVEL2/FRANCE/OSUG.py +525 -0
  69. disdrodb/l0/readers/PARSIVEL2/FRANCE/SIRTA_PARSIVEL2.py +1 -1
  70. disdrodb/l0/readers/PARSIVEL2/GPM/GCPEX.py +9 -7
  71. disdrodb/l0/readers/PARSIVEL2/KIT/BURKINA_FASO.py +1 -1
  72. disdrodb/l0/readers/PARSIVEL2/KIT/TEAMX.py +123 -0
  73. disdrodb/l0/readers/PARSIVEL2/{NETHERLANDS/DELFT.py → MPI/BCO_PARSIVEL2.py} +41 -71
  74. disdrodb/l0/readers/PARSIVEL2/MPI/BOWTIE.py +220 -0
  75. disdrodb/l0/readers/PARSIVEL2/NASA/APU.py +120 -0
  76. disdrodb/l0/readers/PARSIVEL2/NASA/LPVEX.py +109 -0
  77. disdrodb/l0/readers/PARSIVEL2/NCAR/FARM_PARSIVEL2.py +1 -0
  78. disdrodb/l0/readers/PARSIVEL2/NCAR/PECAN_FP3.py +1 -1
  79. disdrodb/l0/readers/PARSIVEL2/NCAR/PERILS_MIPS.py +126 -0
  80. disdrodb/l0/readers/PARSIVEL2/NCAR/PERILS_PIPS.py +165 -0
  81. disdrodb/l0/readers/PARSIVEL2/NCAR/VORTEX_SE_2016_P2.py +1 -1
  82. disdrodb/l0/readers/PARSIVEL2/NCAR/VORTEX_SE_2016_PIPS.py +20 -12
  83. disdrodb/l0/readers/PARSIVEL2/NETHERLANDS/DELFT_NC.py +5 -0
  84. disdrodb/l0/readers/PARSIVEL2/SPAIN/CENER.py +144 -0
  85. disdrodb/l0/readers/PARSIVEL2/SPAIN/CR1000DL.py +201 -0
  86. disdrodb/l0/readers/PARSIVEL2/SPAIN/LIAISE.py +137 -0
  87. disdrodb/l0/readers/PARSIVEL2/USA/C3WE.py +146 -0
  88. disdrodb/l0/readers/PWS100/FRANCE/ENPC_PWS100.py +105 -99
  89. disdrodb/l0/readers/PWS100/FRANCE/ENPC_PWS100_SIRTA.py +151 -0
  90. disdrodb/l1/__init__.py +5 -0
  91. disdrodb/l1/fall_velocity.py +46 -0
  92. disdrodb/l1/filters.py +34 -20
  93. disdrodb/l1/processing.py +46 -45
  94. disdrodb/l1/resampling.py +77 -66
  95. disdrodb/l1_env/routines.py +18 -3
  96. disdrodb/l2/__init__.py +7 -0
  97. disdrodb/l2/empirical_dsd.py +58 -10
  98. disdrodb/l2/processing.py +268 -117
  99. disdrodb/metadata/checks.py +132 -125
  100. disdrodb/metadata/standards.py +3 -1
  101. disdrodb/psd/fitting.py +631 -345
  102. disdrodb/psd/models.py +9 -6
  103. disdrodb/routines/__init__.py +54 -0
  104. disdrodb/{l0/routines.py → routines/l0.py} +316 -355
  105. disdrodb/{l1/routines.py → routines/l1.py} +76 -116
  106. disdrodb/routines/l2.py +1019 -0
  107. disdrodb/{routines.py → routines/wrappers.py} +98 -10
  108. disdrodb/scattering/__init__.py +16 -4
  109. disdrodb/scattering/axis_ratio.py +61 -37
  110. disdrodb/scattering/permittivity.py +504 -0
  111. disdrodb/scattering/routines.py +746 -184
  112. disdrodb/summary/__init__.py +17 -0
  113. disdrodb/summary/routines.py +4196 -0
  114. disdrodb/utils/archiving.py +434 -0
  115. disdrodb/utils/attrs.py +68 -125
  116. disdrodb/utils/cli.py +5 -5
  117. disdrodb/utils/compression.py +30 -1
  118. disdrodb/utils/dask.py +121 -9
  119. disdrodb/utils/dataframe.py +61 -7
  120. disdrodb/utils/decorators.py +31 -0
  121. disdrodb/utils/directories.py +35 -15
  122. disdrodb/utils/encoding.py +37 -19
  123. disdrodb/{l2 → utils}/event.py +15 -173
  124. disdrodb/utils/logger.py +14 -7
  125. disdrodb/utils/manipulations.py +81 -0
  126. disdrodb/utils/routines.py +166 -0
  127. disdrodb/utils/subsetting.py +214 -0
  128. disdrodb/utils/time.py +35 -177
  129. disdrodb/utils/writer.py +20 -7
  130. disdrodb/utils/xarray.py +5 -4
  131. disdrodb/viz/__init__.py +13 -0
  132. disdrodb/viz/plots.py +398 -0
  133. {disdrodb-0.1.2.dist-info → disdrodb-0.1.4.dist-info}/METADATA +4 -3
  134. {disdrodb-0.1.2.dist-info → disdrodb-0.1.4.dist-info}/RECORD +139 -98
  135. {disdrodb-0.1.2.dist-info → disdrodb-0.1.4.dist-info}/entry_points.txt +2 -0
  136. disdrodb/l1/encoding_attrs.py +0 -642
  137. disdrodb/l2/processing_options.py +0 -213
  138. disdrodb/l2/routines.py +0 -868
  139. /disdrodb/l0/readers/PARSIVEL/SLOVENIA/{UL_FGG.py → UL.py} +0 -0
  140. {disdrodb-0.1.2.dist-info → disdrodb-0.1.4.dist-info}/WHEEL +0 -0
  141. {disdrodb-0.1.2.dist-info → disdrodb-0.1.4.dist-info}/licenses/LICENSE +0 -0
  142. {disdrodb-0.1.2.dist-info → disdrodb-0.1.4.dist-info}/top_level.txt +0 -0
@@ -24,79 +24,46 @@ import os
24
24
  import time
25
25
  from typing import Optional
26
26
 
27
- import dask
28
27
  import xarray as xr
29
28
 
30
- # Directory
29
+ from disdrodb.api.checks import check_station_inputs
31
30
  from disdrodb.api.create_directories import (
32
31
  create_logs_directory,
33
32
  create_product_directory,
34
33
  )
35
- from disdrodb.api.io import find_files
36
34
  from disdrodb.api.path import (
37
35
  define_file_folder_path,
38
36
  define_l1_filename,
39
37
  )
40
38
  from disdrodb.api.search import get_required_product
41
- from disdrodb.configs import get_data_archive_dir, get_folder_partitioning, get_metadata_archive_dir
39
+ from disdrodb.configs import (
40
+ get_data_archive_dir,
41
+ get_folder_partitioning,
42
+ get_metadata_archive_dir,
43
+ get_product_options,
44
+ )
42
45
  from disdrodb.l1.processing import generate_l1
46
+ from disdrodb.utils.dask import execute_tasks_safely
43
47
  from disdrodb.utils.decorators import delayed_if_parallel, single_threaded_if_parallel
44
48
 
45
49
  # Logger
46
50
  from disdrodb.utils.logger import (
47
- close_logger,
48
- create_logger_file,
49
51
  create_product_logs,
50
- log_error,
51
52
  log_info,
52
53
  )
54
+ from disdrodb.utils.routines import run_product_generation, try_get_required_filepaths
53
55
  from disdrodb.utils.writer import write_product
54
56
 
55
57
  logger = logging.getLogger(__name__)
56
58
 
57
59
 
58
- def get_l1_options():
59
- """Get L1 options."""
60
- # - TODO: from YAML
61
- # - TODO: as function of sensor name
62
-
63
- # minimum_diameter
64
- # --> PWS100: 0 (0.05)
65
- # --> PARSIVEL: 0.2495 (0.312)
66
- # --> RD80: 0.313 (0.359)
67
- # --> LPM: 0.125 (0.1875) (we currently discard first bin with default settings !)
68
-
69
- # maximum_diameter
70
- # LPM: 9 (10) mm
71
- # RD80: 5.373 (5.6) mm
72
- # OTT: 24.5 (26) mm
73
- # PWS100: 27.2 (28.8) mm
74
-
75
- l1_options = {
76
- # Fall velocity option
77
- "fall_velocity_method": "Beard1976",
78
- # Diameter-Velocity Filtering Options
79
- "minimum_diameter": 0.2495, # OTT PARSIVEL first two bin no data !
80
- "maximum_diameter": 10,
81
- "minimum_velocity": 0,
82
- "maximum_velocity": 12,
83
- "above_velocity_fraction": 0.5,
84
- "above_velocity_tolerance": None,
85
- "below_velocity_fraction": 0.5,
86
- "below_velocity_tolerance": None,
87
- "small_diameter_threshold": 1, # 2
88
- "small_velocity_threshold": 2.5, # 3
89
- "maintain_smallest_drops": True,
90
- }
91
- return l1_options
92
-
93
-
94
60
  @delayed_if_parallel
95
61
  @single_threaded_if_parallel
96
62
  def _generate_l1(
97
63
  filepath,
98
64
  data_dir,
99
65
  logs_dir,
66
+ logs_filename,
100
67
  campaign_name,
101
68
  station_name,
102
69
  # Processing options
@@ -104,7 +71,7 @@ def _generate_l1(
104
71
  verbose,
105
72
  parallel, # this is used only to initialize the correct logger !
106
73
  ):
107
- """Generate the L1 product from the DISRODB L0C netCDF file.
74
+ """Generate the L1 product from the DISDRODB L0C netCDF file.
108
75
 
109
76
  Parameters
110
77
  ----------
@@ -133,68 +100,64 @@ def _generate_l1(
133
100
  If an error occurs during processing, it is caught and logged,
134
101
  but no error is raised to interrupt the execution.
135
102
  """
136
- # -----------------------------------------------------------------.
137
- # Define product name
103
+ # Define product
138
104
  product = "L1"
139
-
140
105
  # Define folder partitioning
141
106
  folder_partitioning = get_folder_partitioning()
142
107
 
143
- # -----------------------------------------------------------------.
144
- # Create file logger
145
- filename = os.path.basename(filepath)
146
- logger, logger_filepath = create_logger_file(
147
- logs_dir=logs_dir,
148
- filename=filename,
149
- parallel=parallel,
150
- )
151
-
152
- ##------------------------------------------------------------------------.
153
- # Log start processing
154
- msg = f"{product} processing of {filename} has started."
155
- log_info(logger=logger, msg=msg, verbose=verbose)
156
-
157
- ##------------------------------------------------------------------------.
158
- # Retrieve L1 configurations
159
- l1_options = get_l1_options()
108
+ # Define product processing function
109
+ def core(
110
+ filepath,
111
+ campaign_name,
112
+ station_name,
113
+ data_dir,
114
+ folder_partitioning,
115
+ ):
116
+ """Define L1 product processing."""
117
+ # Retrieve L1 configurations
118
+ l1_options = get_product_options("L1").get("product_options") # TODO: MOVE OUTSIDE
160
119
 
161
- ##------------------------------------------------------------------------.
162
- ### Core computation
163
- try:
164
120
  # Open the raw netCDF
165
- with xr.open_dataset(filepath, chunks={}, decode_timedelta=False, cache=False) as ds:
121
+ with xr.open_dataset(filepath, chunks=-1, decode_timedelta=False, cache=False) as ds:
166
122
  ds = ds[["raw_drop_number"]].load()
167
123
 
168
124
  # Produce L1 dataset
169
125
  ds = generate_l1(ds=ds, **l1_options)
170
126
 
171
- # Write L1 netCDF4 dataset
172
- if ds["time"].size > 1:
173
- # Define filepath
174
- filename = define_l1_filename(ds, campaign_name=campaign_name, station_name=station_name)
175
- folder_path = define_file_folder_path(ds, data_dir=data_dir, folder_partitioning=folder_partitioning)
176
- filepath = os.path.join(folder_path, filename)
177
- # Write to disk
178
- write_product(ds, product=product, filepath=filepath, force=force)
179
-
180
- ##--------------------------------------------------------------------.
181
- # Clean environment
182
- del ds
183
-
184
- # Log end processing
185
- msg = f"{product} processing of {filename} has ended."
186
- log_info(logger=logger, msg=msg, verbose=verbose)
127
+ # Ensure at least 1 timestep available
128
+ if ds["time"].size <= 1:
129
+ return None
187
130
 
188
- ##--------------------------------------------------------------------.
189
- # Otherwise log the error
190
- except Exception as e:
191
- error_type = str(type(e).__name__)
192
- msg = f"{error_type}: {e}"
193
- log_error(logger, msg, verbose=verbose)
131
+ # Write L1 netCDF4 dataset
132
+ filename = define_l1_filename(ds, campaign_name=campaign_name, station_name=station_name)
133
+ folder_path = define_file_folder_path(ds, dir_path=data_dir, folder_partitioning=folder_partitioning)
134
+ filepath = os.path.join(folder_path, filename)
135
+ write_product(ds, filepath=filepath, force=force)
194
136
 
195
- # Close the file logger
196
- close_logger(logger)
137
+ # Return L1 dataset
138
+ return ds
197
139
 
140
+ # Define product processing function kwargs
141
+ core_func_kwargs = dict( # noqa: C408
142
+ filepath=filepath,
143
+ campaign_name=campaign_name,
144
+ station_name=station_name,
145
+ # Archiving options
146
+ data_dir=data_dir,
147
+ folder_partitioning=folder_partitioning,
148
+ )
149
+ # Run product generation
150
+ logger_filepath = run_product_generation(
151
+ product=product,
152
+ logs_dir=logs_dir,
153
+ logs_filename=logs_filename,
154
+ parallel=parallel,
155
+ verbose=verbose,
156
+ folder_partitioning=folder_partitioning,
157
+ core_func=core,
158
+ core_func_kwargs=core_func_kwargs,
159
+ pass_logger=False,
160
+ )
198
161
  # Return the logger file path
199
162
  return logger_filepath
200
163
 
@@ -260,6 +223,14 @@ def run_l1_station(
260
223
  # Retrieve DISDRODB Metadata Archive directory
261
224
  metadata_archive_dir = get_metadata_archive_dir(metadata_archive_dir)
262
225
 
226
+ # Check valid data_source, campaign_name, and station_name
227
+ check_station_inputs(
228
+ metadata_archive_dir=metadata_archive_dir,
229
+ data_source=data_source,
230
+ campaign_name=campaign_name,
231
+ station_name=station_name,
232
+ )
233
+
263
234
  # Define logs directory
264
235
  logs_dir = create_logs_directory(
265
236
  product=product,
@@ -290,30 +261,18 @@ def run_l1_station(
290
261
 
291
262
  # -------------------------------------------------------------------------.
292
263
  # List files to process
264
+ # - If no data available, print error message and return None
293
265
  required_product = get_required_product(product)
294
- flag_not_available_data = False
295
- try:
296
- filepaths = find_files(
297
- data_archive_dir=data_archive_dir,
298
- data_source=data_source,
299
- campaign_name=campaign_name,
300
- station_name=station_name,
301
- product=required_product,
302
- # Processing options
303
- debugging_mode=debugging_mode,
304
- )
305
- except Exception as e:
306
- print(str(e)) # Case where no file paths available
307
- flag_not_available_data = True
308
-
309
- # -------------------------------------------------------------------------.
310
- # If no data available, print error message and return None
311
- if flag_not_available_data:
312
- msg = (
313
- f"{product} processing of {data_source} {campaign_name} {station_name}"
314
- + f"has not been launched because of missing {required_product} data."
315
- )
316
- print(msg)
266
+ filepaths = try_get_required_filepaths(
267
+ data_archive_dir=data_archive_dir,
268
+ data_source=data_source,
269
+ campaign_name=campaign_name,
270
+ station_name=station_name,
271
+ product=required_product,
272
+ # Processing options
273
+ debugging_mode=debugging_mode,
274
+ )
275
+ if filepaths is None:
317
276
  return
318
277
 
319
278
  # -----------------------------------------------------------------.
@@ -325,6 +284,7 @@ def run_l1_station(
325
284
  filepath=filepath,
326
285
  data_dir=data_dir,
327
286
  logs_dir=logs_dir,
287
+ logs_filename=os.path.basename(filepath),
328
288
  campaign_name=campaign_name,
329
289
  station_name=station_name,
330
290
  # Processing options
@@ -334,7 +294,7 @@ def run_l1_station(
334
294
  )
335
295
  for filepath in filepaths
336
296
  ]
337
- list_logs = dask.compute(*list_tasks) if parallel else list_tasks
297
+ list_logs = execute_tasks_safely(list_tasks=list_tasks, parallel=parallel, logs_dir=logs_dir)
338
298
 
339
299
  # -----------------------------------------------------------------.
340
300
  # Define L1 summary logs