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.
- disdrodb/__init__.py +68 -34
- disdrodb/_config.py +5 -4
- disdrodb/_version.py +16 -3
- disdrodb/accessor/__init__.py +20 -0
- disdrodb/accessor/methods.py +125 -0
- disdrodb/api/checks.py +177 -24
- disdrodb/api/configs.py +3 -3
- disdrodb/api/info.py +13 -13
- disdrodb/api/io.py +281 -22
- disdrodb/api/path.py +184 -195
- disdrodb/api/search.py +18 -9
- disdrodb/cli/disdrodb_create_summary.py +103 -0
- disdrodb/cli/disdrodb_create_summary_station.py +91 -0
- disdrodb/cli/disdrodb_run_l0.py +1 -1
- disdrodb/cli/disdrodb_run_l0_station.py +1 -1
- disdrodb/cli/disdrodb_run_l0a_station.py +1 -1
- disdrodb/cli/disdrodb_run_l0b.py +1 -1
- disdrodb/cli/disdrodb_run_l0b_station.py +3 -3
- disdrodb/cli/disdrodb_run_l0c.py +1 -1
- disdrodb/cli/disdrodb_run_l0c_station.py +3 -3
- disdrodb/cli/disdrodb_run_l1_station.py +2 -2
- disdrodb/cli/disdrodb_run_l2e_station.py +2 -2
- disdrodb/cli/disdrodb_run_l2m_station.py +2 -2
- disdrodb/configs.py +149 -4
- disdrodb/constants.py +61 -0
- disdrodb/data_transfer/download_data.py +127 -11
- disdrodb/etc/configs/attributes.yaml +339 -0
- disdrodb/etc/configs/encodings.yaml +473 -0
- disdrodb/etc/products/L1/global.yaml +13 -0
- disdrodb/etc/products/L2E/10MIN.yaml +12 -0
- disdrodb/etc/products/L2E/1MIN.yaml +1 -0
- disdrodb/etc/products/L2E/global.yaml +22 -0
- disdrodb/etc/products/L2M/10MIN.yaml +12 -0
- disdrodb/etc/products/L2M/GAMMA_ML.yaml +8 -0
- disdrodb/etc/products/L2M/NGAMMA_GS_LOG_ND_MAE.yaml +6 -0
- disdrodb/etc/products/L2M/NGAMMA_GS_ND_MAE.yaml +6 -0
- disdrodb/etc/products/L2M/NGAMMA_GS_Z_MAE.yaml +6 -0
- disdrodb/etc/products/L2M/global.yaml +26 -0
- disdrodb/issue/writer.py +2 -0
- disdrodb/l0/__init__.py +13 -0
- disdrodb/l0/configs/LPM/l0b_cf_attrs.yml +4 -4
- disdrodb/l0/configs/PARSIVEL/l0b_cf_attrs.yml +1 -1
- disdrodb/l0/configs/PARSIVEL/l0b_encodings.yml +3 -3
- disdrodb/l0/configs/PARSIVEL/raw_data_format.yml +1 -1
- disdrodb/l0/configs/PARSIVEL2/l0b_cf_attrs.yml +5 -5
- disdrodb/l0/configs/PARSIVEL2/l0b_encodings.yml +3 -3
- disdrodb/l0/configs/PARSIVEL2/raw_data_format.yml +1 -1
- disdrodb/l0/configs/PWS100/l0b_cf_attrs.yml +4 -4
- disdrodb/l0/configs/PWS100/raw_data_format.yml +1 -1
- disdrodb/l0/l0a_processing.py +37 -32
- disdrodb/l0/l0b_nc_processing.py +118 -8
- disdrodb/l0/l0b_processing.py +30 -65
- disdrodb/l0/l0c_processing.py +369 -259
- disdrodb/l0/readers/LPM/ARM/ARM_LPM.py +7 -0
- disdrodb/l0/readers/LPM/NETHERLANDS/DELFT_LPM_NC.py +66 -0
- disdrodb/l0/readers/LPM/SLOVENIA/{CRNI_VRH.py → UL.py} +3 -0
- disdrodb/l0/readers/LPM/SWITZERLAND/INNERERIZ_LPM.py +195 -0
- disdrodb/l0/readers/PARSIVEL/GPM/PIERS.py +0 -2
- disdrodb/l0/readers/PARSIVEL/JAPAN/JMA.py +4 -1
- disdrodb/l0/readers/PARSIVEL/NCAR/PECAN_MOBILE.py +1 -1
- disdrodb/l0/readers/PARSIVEL/NCAR/VORTEX2_2009.py +1 -1
- disdrodb/l0/readers/PARSIVEL2/ARM/ARM_PARSIVEL2.py +4 -0
- disdrodb/l0/readers/PARSIVEL2/BELGIUM/ILVO.py +168 -0
- disdrodb/l0/readers/PARSIVEL2/CANADA/UQAM_NC.py +69 -0
- disdrodb/l0/readers/PARSIVEL2/DENMARK/DTU.py +165 -0
- disdrodb/l0/readers/PARSIVEL2/FINLAND/FMI_PARSIVEL2.py +69 -0
- disdrodb/l0/readers/PARSIVEL2/FRANCE/ENPC_PARSIVEL2.py +255 -134
- disdrodb/l0/readers/PARSIVEL2/FRANCE/OSUG.py +525 -0
- disdrodb/l0/readers/PARSIVEL2/FRANCE/SIRTA_PARSIVEL2.py +1 -1
- disdrodb/l0/readers/PARSIVEL2/GPM/GCPEX.py +9 -7
- disdrodb/l0/readers/PARSIVEL2/KIT/BURKINA_FASO.py +1 -1
- disdrodb/l0/readers/PARSIVEL2/KIT/TEAMX.py +123 -0
- disdrodb/l0/readers/PARSIVEL2/{NETHERLANDS/DELFT.py → MPI/BCO_PARSIVEL2.py} +41 -71
- disdrodb/l0/readers/PARSIVEL2/MPI/BOWTIE.py +220 -0
- disdrodb/l0/readers/PARSIVEL2/NASA/APU.py +120 -0
- disdrodb/l0/readers/PARSIVEL2/NASA/LPVEX.py +109 -0
- disdrodb/l0/readers/PARSIVEL2/NCAR/FARM_PARSIVEL2.py +1 -0
- disdrodb/l0/readers/PARSIVEL2/NCAR/PECAN_FP3.py +1 -1
- disdrodb/l0/readers/PARSIVEL2/NCAR/PERILS_MIPS.py +126 -0
- disdrodb/l0/readers/PARSIVEL2/NCAR/PERILS_PIPS.py +165 -0
- disdrodb/l0/readers/PARSIVEL2/NCAR/VORTEX_SE_2016_P2.py +1 -1
- disdrodb/l0/readers/PARSIVEL2/NCAR/VORTEX_SE_2016_PIPS.py +20 -12
- disdrodb/l0/readers/PARSIVEL2/NETHERLANDS/DELFT_NC.py +5 -0
- disdrodb/l0/readers/PARSIVEL2/SPAIN/CENER.py +144 -0
- disdrodb/l0/readers/PARSIVEL2/SPAIN/CR1000DL.py +201 -0
- disdrodb/l0/readers/PARSIVEL2/SPAIN/LIAISE.py +137 -0
- disdrodb/l0/readers/PARSIVEL2/USA/C3WE.py +146 -0
- disdrodb/l0/readers/PWS100/FRANCE/ENPC_PWS100.py +105 -99
- disdrodb/l0/readers/PWS100/FRANCE/ENPC_PWS100_SIRTA.py +151 -0
- disdrodb/l1/__init__.py +5 -0
- disdrodb/l1/fall_velocity.py +46 -0
- disdrodb/l1/filters.py +34 -20
- disdrodb/l1/processing.py +46 -45
- disdrodb/l1/resampling.py +77 -66
- disdrodb/l1_env/routines.py +18 -3
- disdrodb/l2/__init__.py +7 -0
- disdrodb/l2/empirical_dsd.py +58 -10
- disdrodb/l2/processing.py +268 -117
- disdrodb/metadata/checks.py +132 -125
- disdrodb/metadata/standards.py +3 -1
- disdrodb/psd/fitting.py +631 -345
- disdrodb/psd/models.py +9 -6
- disdrodb/routines/__init__.py +54 -0
- disdrodb/{l0/routines.py → routines/l0.py} +316 -355
- disdrodb/{l1/routines.py → routines/l1.py} +76 -116
- disdrodb/routines/l2.py +1019 -0
- disdrodb/{routines.py → routines/wrappers.py} +98 -10
- disdrodb/scattering/__init__.py +16 -4
- disdrodb/scattering/axis_ratio.py +61 -37
- disdrodb/scattering/permittivity.py +504 -0
- disdrodb/scattering/routines.py +746 -184
- disdrodb/summary/__init__.py +17 -0
- disdrodb/summary/routines.py +4196 -0
- disdrodb/utils/archiving.py +434 -0
- disdrodb/utils/attrs.py +68 -125
- disdrodb/utils/cli.py +5 -5
- disdrodb/utils/compression.py +30 -1
- disdrodb/utils/dask.py +121 -9
- disdrodb/utils/dataframe.py +61 -7
- disdrodb/utils/decorators.py +31 -0
- disdrodb/utils/directories.py +35 -15
- disdrodb/utils/encoding.py +37 -19
- disdrodb/{l2 → utils}/event.py +15 -173
- disdrodb/utils/logger.py +14 -7
- disdrodb/utils/manipulations.py +81 -0
- disdrodb/utils/routines.py +166 -0
- disdrodb/utils/subsetting.py +214 -0
- disdrodb/utils/time.py +35 -177
- disdrodb/utils/writer.py +20 -7
- disdrodb/utils/xarray.py +5 -4
- disdrodb/viz/__init__.py +13 -0
- disdrodb/viz/plots.py +398 -0
- {disdrodb-0.1.2.dist-info → disdrodb-0.1.4.dist-info}/METADATA +4 -3
- {disdrodb-0.1.2.dist-info → disdrodb-0.1.4.dist-info}/RECORD +139 -98
- {disdrodb-0.1.2.dist-info → disdrodb-0.1.4.dist-info}/entry_points.txt +2 -0
- disdrodb/l1/encoding_attrs.py +0 -642
- disdrodb/l2/processing_options.py +0 -213
- disdrodb/l2/routines.py +0 -868
- /disdrodb/l0/readers/PARSIVEL/SLOVENIA/{UL_FGG.py → UL.py} +0 -0
- {disdrodb-0.1.2.dist-info → disdrodb-0.1.4.dist-info}/WHEEL +0 -0
- {disdrodb-0.1.2.dist-info → disdrodb-0.1.4.dist-info}/licenses/LICENSE +0 -0
- {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
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
)
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
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
|
|
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
|
-
#
|
|
172
|
-
if ds["time"].size
|
|
173
|
-
|
|
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
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
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
|
-
|
|
196
|
-
|
|
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
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
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 =
|
|
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
|