disdrodb 0.1.3__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 (62) hide show
  1. disdrodb/__init__.py +4 -0
  2. disdrodb/_version.py +2 -2
  3. disdrodb/api/checks.py +70 -47
  4. disdrodb/api/configs.py +0 -2
  5. disdrodb/api/info.py +3 -3
  6. disdrodb/api/io.py +48 -8
  7. disdrodb/api/path.py +116 -133
  8. disdrodb/api/search.py +12 -3
  9. disdrodb/cli/disdrodb_create_summary.py +103 -0
  10. disdrodb/cli/disdrodb_create_summary_station.py +1 -1
  11. disdrodb/cli/disdrodb_run_l0a_station.py +1 -1
  12. disdrodb/cli/disdrodb_run_l0b_station.py +2 -2
  13. disdrodb/cli/disdrodb_run_l0c_station.py +2 -2
  14. disdrodb/cli/disdrodb_run_l1_station.py +2 -2
  15. disdrodb/cli/disdrodb_run_l2e_station.py +2 -2
  16. disdrodb/cli/disdrodb_run_l2m_station.py +2 -2
  17. disdrodb/data_transfer/download_data.py +123 -7
  18. disdrodb/issue/writer.py +2 -0
  19. disdrodb/l0/l0a_processing.py +10 -5
  20. disdrodb/l0/l0b_nc_processing.py +10 -6
  21. disdrodb/l0/l0b_processing.py +26 -61
  22. disdrodb/l0/l0c_processing.py +369 -251
  23. disdrodb/l0/readers/LPM/ARM/ARM_LPM.py +7 -0
  24. disdrodb/l0/readers/PARSIVEL2/ARM/ARM_PARSIVEL2.py +4 -0
  25. disdrodb/l0/readers/PARSIVEL2/CANADA/UQAM_NC.py +69 -0
  26. disdrodb/l0/readers/PARSIVEL2/MPI/BCO_PARSIVEL2.py +136 -0
  27. disdrodb/l0/readers/PARSIVEL2/MPI/BOWTIE.py +220 -0
  28. disdrodb/l0/readers/PARSIVEL2/NASA/LPVEX.py +109 -0
  29. disdrodb/l0/readers/PARSIVEL2/NETHERLANDS/DELFT_NC.py +3 -0
  30. disdrodb/l1/fall_velocity.py +46 -0
  31. disdrodb/l1/processing.py +1 -1
  32. disdrodb/l2/processing.py +1 -1
  33. disdrodb/metadata/checks.py +132 -125
  34. disdrodb/psd/fitting.py +172 -205
  35. disdrodb/psd/models.py +1 -1
  36. disdrodb/routines/__init__.py +54 -0
  37. disdrodb/{l0/routines.py → routines/l0.py} +288 -418
  38. disdrodb/{l1/routines.py → routines/l1.py} +60 -92
  39. disdrodb/{l2/routines.py → routines/l2.py} +249 -462
  40. disdrodb/{routines.py → routines/wrappers.py} +95 -7
  41. disdrodb/scattering/axis_ratio.py +5 -1
  42. disdrodb/scattering/permittivity.py +18 -0
  43. disdrodb/scattering/routines.py +56 -36
  44. disdrodb/summary/routines.py +110 -34
  45. disdrodb/utils/archiving.py +434 -0
  46. disdrodb/utils/cli.py +5 -5
  47. disdrodb/utils/dask.py +62 -1
  48. disdrodb/utils/decorators.py +31 -0
  49. disdrodb/utils/encoding.py +5 -1
  50. disdrodb/{l2 → utils}/event.py +1 -66
  51. disdrodb/utils/logger.py +1 -1
  52. disdrodb/utils/manipulations.py +22 -12
  53. disdrodb/utils/routines.py +166 -0
  54. disdrodb/utils/time.py +3 -291
  55. disdrodb/utils/xarray.py +3 -0
  56. disdrodb/viz/plots.py +85 -14
  57. {disdrodb-0.1.3.dist-info → disdrodb-0.1.4.dist-info}/METADATA +2 -2
  58. {disdrodb-0.1.3.dist-info → disdrodb-0.1.4.dist-info}/RECORD +62 -54
  59. {disdrodb-0.1.3.dist-info → disdrodb-0.1.4.dist-info}/entry_points.txt +1 -0
  60. {disdrodb-0.1.3.dist-info → disdrodb-0.1.4.dist-info}/WHEEL +0 -0
  61. {disdrodb-0.1.3.dist-info → disdrodb-0.1.4.dist-info}/licenses/LICENSE +0 -0
  62. {disdrodb-0.1.3.dist-info → disdrodb-0.1.4.dist-info}/top_level.txt +0 -0
@@ -21,11 +21,9 @@
21
21
  import datetime
22
22
  import logging
23
23
  import os
24
- import shutil
25
24
  import time
26
25
  from typing import Optional
27
26
 
28
- import dask
29
27
  import xarray as xr
30
28
 
31
29
  from disdrodb.api.checks import check_station_inputs
@@ -33,7 +31,6 @@ from disdrodb.api.create_directories import (
33
31
  create_logs_directory,
34
32
  create_product_directory,
35
33
  )
36
- from disdrodb.api.io import find_files
37
34
  from disdrodb.api.path import (
38
35
  define_file_folder_path,
39
36
  define_l1_filename,
@@ -46,16 +43,15 @@ from disdrodb.configs import (
46
43
  get_product_options,
47
44
  )
48
45
  from disdrodb.l1.processing import generate_l1
46
+ from disdrodb.utils.dask import execute_tasks_safely
49
47
  from disdrodb.utils.decorators import delayed_if_parallel, single_threaded_if_parallel
50
48
 
51
49
  # Logger
52
50
  from disdrodb.utils.logger import (
53
- close_logger,
54
- create_logger_file,
55
51
  create_product_logs,
56
- log_error,
57
52
  log_info,
58
53
  )
54
+ from disdrodb.utils.routines import run_product_generation, try_get_required_filepaths
59
55
  from disdrodb.utils.writer import write_product
60
56
 
61
57
  logger = logging.getLogger(__name__)
@@ -67,6 +63,7 @@ def _generate_l1(
67
63
  filepath,
68
64
  data_dir,
69
65
  logs_dir,
66
+ logs_filename,
70
67
  campaign_name,
71
68
  station_name,
72
69
  # Processing options
@@ -74,7 +71,7 @@ def _generate_l1(
74
71
  verbose,
75
72
  parallel, # this is used only to initialize the correct logger !
76
73
  ):
77
- """Generate the L1 product from the DISRODB L0C netCDF file.
74
+ """Generate the L1 product from the DISDRODB L0C netCDF file.
78
75
 
79
76
  Parameters
80
77
  ----------
@@ -103,34 +100,23 @@ def _generate_l1(
103
100
  If an error occurs during processing, it is caught and logged,
104
101
  but no error is raised to interrupt the execution.
105
102
  """
106
- # -----------------------------------------------------------------.
107
- # Define product name
103
+ # Define product
108
104
  product = "L1"
109
-
110
105
  # Define folder partitioning
111
106
  folder_partitioning = get_folder_partitioning()
112
107
 
113
- # -----------------------------------------------------------------.
114
- # Create file logger
115
- filename = os.path.basename(filepath)
116
- logger, logger_filepath = create_logger_file(
117
- logs_dir=logs_dir,
118
- filename=filename,
119
- parallel=parallel,
120
- )
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
121
119
 
122
- ##------------------------------------------------------------------------.
123
- # Log start processing
124
- msg = f"{product} processing of {filename} has started."
125
- log_info(logger=logger, msg=msg, verbose=verbose)
126
- success_flag = False
127
- ##------------------------------------------------------------------------.
128
- # Retrieve L1 configurations
129
- l1_options = get_product_options("L1").get("product_options")
130
-
131
- ##------------------------------------------------------------------------.
132
- ### Core computation
133
- try:
134
120
  # Open the raw netCDF
135
121
  with xr.open_dataset(filepath, chunks=-1, decode_timedelta=False, cache=False) as ds:
136
122
  ds = ds[["raw_drop_number"]].load()
@@ -138,47 +124,40 @@ def _generate_l1(
138
124
  # Produce L1 dataset
139
125
  ds = generate_l1(ds=ds, **l1_options)
140
126
 
141
- # Write L1 netCDF4 dataset
142
- if ds["time"].size > 1:
143
- # Define filepath
144
- filename = define_l1_filename(ds, campaign_name=campaign_name, station_name=station_name)
145
- folder_path = define_file_folder_path(ds, data_dir=data_dir, folder_partitioning=folder_partitioning)
146
- filepath = os.path.join(folder_path, filename)
147
- # Write to disk
148
- write_product(ds, filepath=filepath, force=force)
149
-
150
- ##--------------------------------------------------------------------.
151
- #### - Define logger file final directory
152
- if folder_partitioning != "":
153
- log_dst_dir = define_file_folder_path(ds, data_dir=logs_dir, folder_partitioning=folder_partitioning)
154
- os.makedirs(log_dst_dir, exist_ok=True)
155
-
156
- ##--------------------------------------------------------------------.
157
- # Clean environment
158
- del ds
159
-
160
- # Log end processing
161
- msg = f"{product} processing of {filename} has ended."
162
- log_info(logger=logger, msg=msg, verbose=verbose)
163
- success_flag = True
164
-
165
- ##--------------------------------------------------------------------.
166
- # Otherwise log the error
167
- except Exception as e:
168
- error_type = str(type(e).__name__)
169
- msg = f"{error_type}: {e}"
170
- log_error(logger, msg, verbose=verbose)
127
+ # Ensure at least 1 timestep available
128
+ if ds["time"].size <= 1:
129
+ return None
171
130
 
172
- # Close the file logger
173
- close_logger(logger)
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)
174
136
 
175
- # Move logger file to correct partitioning directory
176
- if success_flag and folder_partitioning != "" and logger_filepath is not None:
177
- # Move logger file to correct partitioning directory
178
- dst_filepath = os.path.join(log_dst_dir, os.path.basename(logger_filepath))
179
- shutil.move(logger_filepath, dst_filepath)
180
- logger_filepath = dst_filepath
137
+ # Return L1 dataset
138
+ return ds
181
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
+ )
182
161
  # Return the logger file path
183
162
  return logger_filepath
184
163
 
@@ -282,30 +261,18 @@ def run_l1_station(
282
261
 
283
262
  # -------------------------------------------------------------------------.
284
263
  # List files to process
264
+ # - If no data available, print error message and return None
285
265
  required_product = get_required_product(product)
286
- flag_not_available_data = False
287
- try:
288
- filepaths = find_files(
289
- data_archive_dir=data_archive_dir,
290
- data_source=data_source,
291
- campaign_name=campaign_name,
292
- station_name=station_name,
293
- product=required_product,
294
- # Processing options
295
- debugging_mode=debugging_mode,
296
- )
297
- except Exception as e:
298
- print(str(e)) # Case where no file paths available
299
- flag_not_available_data = True
300
-
301
- # -------------------------------------------------------------------------.
302
- # If no data available, print error message and return None
303
- if flag_not_available_data:
304
- msg = (
305
- f"{product} processing of {data_source} {campaign_name} {station_name} "
306
- + f"has not been launched because of missing {required_product} data."
307
- )
308
- 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:
309
276
  return
310
277
 
311
278
  # -----------------------------------------------------------------.
@@ -317,6 +284,7 @@ def run_l1_station(
317
284
  filepath=filepath,
318
285
  data_dir=data_dir,
319
286
  logs_dir=logs_dir,
287
+ logs_filename=os.path.basename(filepath),
320
288
  campaign_name=campaign_name,
321
289
  station_name=station_name,
322
290
  # Processing options
@@ -326,7 +294,7 @@ def run_l1_station(
326
294
  )
327
295
  for filepath in filepaths
328
296
  ]
329
- 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)
330
298
 
331
299
  # -----------------------------------------------------------------.
332
300
  # Define L1 summary logs