roc-film 1.13.4__py3-none-any.whl → 1.14.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 (52) hide show
  1. roc/__init__.py +2 -1
  2. roc/film/__init__.py +2 -2
  3. roc/film/commands.py +372 -323
  4. roc/film/config/__init__.py +0 -1
  5. roc/film/constants.py +101 -65
  6. roc/film/descriptor.json +126 -95
  7. roc/film/exceptions.py +28 -27
  8. roc/film/tasks/__init__.py +16 -16
  9. roc/film/tasks/cat_solo_hk.py +86 -74
  10. roc/film/tasks/cdf_postpro.py +438 -309
  11. roc/film/tasks/check_dds.py +39 -45
  12. roc/film/tasks/db_to_anc_bia_sweep_table.py +381 -0
  13. roc/film/tasks/dds_to_l0.py +232 -180
  14. roc/film/tasks/export_solo_coord.py +147 -0
  15. roc/film/tasks/file_handler.py +91 -75
  16. roc/film/tasks/l0_to_hk.py +117 -103
  17. roc/film/tasks/l0_to_l1_bia_current.py +38 -30
  18. roc/film/tasks/l0_to_l1_bia_sweep.py +417 -329
  19. roc/film/tasks/l0_to_l1_sbm.py +250 -208
  20. roc/film/tasks/l0_to_l1_surv.py +185 -130
  21. roc/film/tasks/make_daily_tm.py +40 -37
  22. roc/film/tasks/merge_tcreport.py +77 -71
  23. roc/film/tasks/merge_tmraw.py +102 -89
  24. roc/film/tasks/parse_dds_xml.py +21 -20
  25. roc/film/tasks/set_l0_utc.py +51 -49
  26. roc/film/tests/cdf_compare.py +565 -0
  27. roc/film/tests/hdf5_compare.py +84 -62
  28. roc/film/tests/test_dds_to_l0.py +93 -51
  29. roc/film/tests/test_dds_to_tc.py +8 -11
  30. roc/film/tests/test_dds_to_tm.py +8 -10
  31. roc/film/tests/test_film.py +161 -116
  32. roc/film/tests/test_l0_to_hk.py +64 -36
  33. roc/film/tests/test_l0_to_l1_bia.py +10 -14
  34. roc/film/tests/test_l0_to_l1_sbm.py +14 -19
  35. roc/film/tests/test_l0_to_l1_surv.py +68 -41
  36. roc/film/tests/test_metadata.py +21 -20
  37. roc/film/tests/tests.py +743 -396
  38. roc/film/tools/__init__.py +5 -5
  39. roc/film/tools/dataset_tasks.py +34 -2
  40. roc/film/tools/file_helpers.py +390 -269
  41. roc/film/tools/l0.py +402 -324
  42. roc/film/tools/metadata.py +147 -127
  43. roc/film/tools/skeleton.py +12 -17
  44. roc/film/tools/tools.py +109 -92
  45. roc/film/tools/xlsx2skt.py +161 -139
  46. {roc_film-1.13.4.dist-info → roc_film-1.14.0.dist-info}/LICENSE +127 -125
  47. roc_film-1.14.0.dist-info/METADATA +60 -0
  48. roc_film-1.14.0.dist-info/RECORD +50 -0
  49. {roc_film-1.13.4.dist-info → roc_film-1.14.0.dist-info}/WHEEL +1 -1
  50. roc/film/tasks/l0_to_anc_bia_sweep_table.py +0 -348
  51. roc_film-1.13.4.dist-info/METADATA +0 -120
  52. roc_film-1.13.4.dist-info/RECORD +0 -48
@@ -0,0 +1,565 @@
1
+ #! /usr/bin/env python
2
+ # -*- coding: utf-8 -*-
3
+
4
+ """Maser4py - Compare 2 CDF files module"""
5
+
6
+ import logging
7
+ import os
8
+ import os.path
9
+ import sys
10
+ from pprint import pformat
11
+
12
+ import numpy as np
13
+ from spacepy.pycdf import CDF
14
+
15
+ logger = logging.getLogger(__name__)
16
+
17
+
18
+ # Checking file
19
+ def checking_file_exist(cdf_file):
20
+ if not os.path.isfile(cdf_file):
21
+ raise FileNotFoundError("%s : does not exist !" % cdf_file)
22
+ if not os.access(cdf_file, os.R_OK):
23
+ raise IOError("%s : is not readable !" % cdf_file)
24
+
25
+
26
+ #
27
+ def get_keys_and_attributes(cdf_filepath):
28
+ """
29
+ Get the list data keys (zVars) and global attributes (gAttrs)
30
+
31
+ :param cdf_filepath:
32
+ :return:
33
+ """
34
+ with CDF(cdf_filepath) as cdf_file:
35
+ return list(cdf_file.keys()), cdf_file.attrs.copy()
36
+
37
+
38
+ def list_differences(a, b):
39
+ """
40
+ Find list differences
41
+
42
+ :param a: first list
43
+ :param b: second list
44
+ :return: a tuple containing the differences
45
+ """
46
+ return [x for x in a if x not in b], [x for x in b if x not in a]
47
+
48
+
49
+ # Listing all items
50
+ def list_elements(liste):
51
+ n = len(liste)
52
+ i = 0
53
+ while i < n:
54
+ # logger.debug(" %s", liste[i])
55
+ i += 1
56
+
57
+
58
+ # Deleting a dictionnary's key
59
+ def delete_key(dict, key_to_remove):
60
+ if key_to_remove in dict:
61
+ del dict[key_to_remove]
62
+ else:
63
+ logger.debug("Key to remove '%s' does not exist !", key_to_remove)
64
+ return dict
65
+
66
+
67
+ # Getting a given vAttr's not matched keys
68
+ def get_v_att_keys_diff(field1, field2):
69
+ """
70
+ get the differences between v_att keys of field 1 and field 2
71
+
72
+ :param field1:
73
+ :param field2:
74
+ :return:
75
+ """
76
+
77
+ # convert v_att (class 'spacepy.cdf.zAttrList') of cdf files to sorted
78
+ # lists
79
+
80
+ list_a1 = sorted([attr_key for attr_key in field1.attrs])
81
+
82
+ list_a2 = sorted([attr_key for attr_key in field2.attrs])
83
+ if list_a1 != list_a2:
84
+ result = list_differences(list_a1, list_a2)
85
+ else:
86
+ result = []
87
+
88
+ return result
89
+
90
+
91
+ # Getting a given vAttr's matched keys
92
+ def get_matched_vAttrKey(field1, field2):
93
+ set_a1 = set([attr_key for attr_key in field1.attrs])
94
+
95
+ set_a2 = set([attr_key for attr_key in field2.attrs])
96
+
97
+ return set_a1 & set_a2
98
+
99
+
100
+ def compare_global_attributes(global_att1, global_att2, list_ignore_gatt):
101
+ """
102
+
103
+ Compare global attributes
104
+
105
+ :return: the global attribute differences
106
+ """
107
+
108
+ # initialize the Global Attributes dictionary
109
+ gAttrs = {}
110
+
111
+ list_global_att1 = sorted(list(global_att1.keys()))
112
+ list_global_att2 = sorted(list(global_att2.keys()))
113
+
114
+ if list_ignore_gatt != []:
115
+ list_global_att1 = [n for n in list_global_att1 if n not in list_ignore_gatt]
116
+ list_global_att2 = [n for n in list_global_att2 if n not in list_ignore_gatt]
117
+ not_match_attribute = list_differences(list_global_att1, list_global_att2)
118
+
119
+ l1 = len(not_match_attribute[0])
120
+ l2 = len(not_match_attribute[1])
121
+
122
+ if list_ignore_gatt != []:
123
+ logger.debug(
124
+ "%s Global Attributes to be ignored for comparison : %s",
125
+ len(list_ignore_gatt),
126
+ list_ignore_gatt,
127
+ )
128
+ if l1 != 0 or l2 != 0:
129
+ logger.debug("Global attributes: different")
130
+ logger.debug("File 1 : %s%s", str(len(global_att1)), " global attributes")
131
+ logger.debug("File1's Global Attributes List : %s", list_global_att1)
132
+ logger.debug("File 2 : %s%s", str(len(global_att2)), " global attributes")
133
+ logger.debug("File2's Global Attributes List : %s", list_global_att2)
134
+ logger.debug("Not matched global attributes")
135
+ logger.debug(
136
+ " File1 : %s - %s", len(not_match_attribute[0]), not_match_attribute[0]
137
+ )
138
+ logger.debug(
139
+ " File2 : %s - %s", len(not_match_attribute[1]), not_match_attribute[1]
140
+ )
141
+
142
+ gAttrs["NotMatched"] = not_match_attribute
143
+ # Remove not matched keys from the 2 dictionaries
144
+ not_match1 = not_match_attribute[0]
145
+ not_match2 = not_match_attribute[1]
146
+
147
+ for key_to_remove in not_match1:
148
+ global_att1 = delete_key(global_att1, key_to_remove)
149
+
150
+ for key_to_remove in not_match2:
151
+ global_att2 = delete_key(global_att2, key_to_remove)
152
+
153
+ # Compare Global Attributes's value
154
+ nl1 = len(global_att1)
155
+ nl2 = len(global_att2)
156
+ if nl1 == nl2: # The 2 dictionaries have the same keys
157
+ # Compare 2 dictionaries
158
+ checking = global_att1 == global_att2
159
+ if not checking:
160
+ # Not equal !!
161
+ logger.debug("Global attributes value: different")
162
+ common_att = sorted(list(global_att1.keys()))
163
+
164
+ DiffValueAttr = {}
165
+ for com_att in common_att:
166
+ if com_att not in list_ignore_gatt:
167
+ dd1 = global_att1.get(com_att)
168
+ dd2 = global_att2.get(com_att)
169
+ if dd1 != dd2:
170
+ val1 = dd1[0]
171
+ val2 = dd2[0]
172
+ logger.debug("** %s", com_att)
173
+ logger.debug(" File1 : %s", val1)
174
+ logger.debug(" File2 : %s", val2)
175
+
176
+ DiffValueAttr[com_att] = [val1, val2]
177
+ if DiffValueAttr:
178
+ gAttrs["Value"] = DiffValueAttr
179
+ logger.debug("gAttrs: %s", pformat(DiffValueAttr, width=1000))
180
+
181
+ return gAttrs
182
+
183
+
184
+ def precision_dict_from_list(precision_list):
185
+ precision_dict = {}
186
+ for key_value in precision_list:
187
+ key, value = key_value.split(":")
188
+ precision_dict[key] = float(value)
189
+ return precision_dict
190
+
191
+
192
+ def compare_z_var(
193
+ field1,
194
+ field2,
195
+ key,
196
+ dict_numerical_precision={},
197
+ shape_diff_dict={},
198
+ value_diff_dict={},
199
+ ):
200
+ # check if fields have the same shape
201
+ if field1.shape:
202
+ data1 = field1[...]
203
+ else:
204
+ # Make sure to have numpy ndarray if data1 is a scalar
205
+ data1 = np.atleast_1d(field1[...])
206
+ if field2.shape:
207
+ data2 = field2[...]
208
+ else:
209
+ # Make sure to have numpy ndarray if data2 is a scalar
210
+ data2 = np.atleast_1d(field2[...])
211
+
212
+ res = False
213
+
214
+ if data1.shape != data2.shape:
215
+ logger.debug(
216
+ "%s - array shape is different: %s | %s", key, field1.shape, field2.shape
217
+ )
218
+ shape_diff_dict[key] = [data1.shape, data2.shape]
219
+
220
+ else:
221
+ differences_mask = data1 != data2
222
+ fields_are_different = np.any(differences_mask)
223
+
224
+ # zVariable's key : check for different values
225
+ if fields_are_different:
226
+ if key in dict_numerical_precision.keys():
227
+ tab_diff = np.isclose(data1, data2, atol=dict_numerical_precision[key])
228
+ res = np.all(tab_diff)
229
+ if not res:
230
+ logger.debug(
231
+ "Different values for zVariable '%s' : %s | %s",
232
+ key,
233
+ field1,
234
+ field2,
235
+ )
236
+ value_diff_dict[key] = [
237
+ data1[differences_mask],
238
+ data2[differences_mask],
239
+ ]
240
+
241
+ else:
242
+ logger.debug(
243
+ "Different values for zVariable '%s' : %s | %s", key, field1, field2
244
+ )
245
+ value_diff_dict[key] = [
246
+ data1[differences_mask],
247
+ data2[differences_mask],
248
+ ]
249
+
250
+ return shape_diff_dict, value_diff_dict
251
+
252
+
253
+ def compare_v_att(
254
+ field1, field2, key, key_diff_dict={}, value_diff_dict={}, list_ignore_vatt=[]
255
+ ):
256
+ v_att_keys_diff = list_differences(field1.attrs, field2.attrs)
257
+
258
+ if list_ignore_vatt != []:
259
+ logger.debug(
260
+ "%s Variable Attributes to be ignored for comparison : %s",
261
+ len(list_ignore_vatt),
262
+ list_ignore_vatt,
263
+ )
264
+ for item1 in list_ignore_vatt:
265
+ if item1 in v_att_keys_diff[0]:
266
+ (v_att_keys_diff[0]).remove(item1)
267
+ for item2 in list_ignore_vatt:
268
+ if item2 in v_att_keys_diff[1]:
269
+ (v_att_keys_diff[1]).remove(item2)
270
+
271
+ if len(v_att_keys_diff[0]) != 0 or len(v_att_keys_diff[1]) != 0:
272
+ logger.debug(
273
+ "Different Variable Attribute's keys of the zVariable '%s' : %s",
274
+ key,
275
+ v_att_keys_diff,
276
+ )
277
+ key_diff_dict[key] = v_att_keys_diff
278
+
279
+ common_v_att_keys = get_matched_vAttrKey(field1, field2)
280
+ logger.debug("Identical Variable Attribute's key : %s", common_v_att_keys)
281
+
282
+ vAttrsList1 = field1.attrs
283
+ vAttrsList2 = field2.attrs
284
+
285
+ DiffValue_vAttr = {}
286
+
287
+ for check_item in common_v_att_keys:
288
+ logger.debug(
289
+ "%s : %s | %s",
290
+ check_item,
291
+ vAttrsList1[check_item],
292
+ vAttrsList2[check_item],
293
+ )
294
+
295
+ if vAttrsList1[check_item] == vAttrsList2[check_item]:
296
+ logger.debug("%s : equal", check_item)
297
+ else:
298
+ logger.debug("%s : not equal", check_item)
299
+ DiffValue_vAttr[check_item] = [
300
+ vAttrsList1[check_item],
301
+ vAttrsList2[check_item],
302
+ ]
303
+ value_diff_dict[key] = DiffValue_vAttr
304
+ logger.debug("vAttrs['Value'] : %s", value_diff_dict)
305
+
306
+ return key_diff_dict, value_diff_dict
307
+
308
+
309
+ def compare_data(
310
+ cdf1,
311
+ cdf2,
312
+ cdf_keys1,
313
+ cdf_keys2,
314
+ list_ignore_zvar=[],
315
+ list_ignore_vatt=[],
316
+ list_numerical_precision=[],
317
+ ):
318
+ zVars = {} # store data differences
319
+ vAttrs = {} # store attribute differences
320
+
321
+ # Ignored zVariables for comparison
322
+ if list_ignore_zvar != []:
323
+ logger.debug(
324
+ "%s zVariables to be ignored for comparison : %s",
325
+ len(list_ignore_zvar),
326
+ list_ignore_zvar,
327
+ )
328
+
329
+ if len(cdf_keys1) != len(cdf_keys2):
330
+ logger.debug("Zvariables: different")
331
+
332
+ # ***** Not matched keys *****
333
+ list_diff1, list_diff2 = list_differences(cdf_keys1, cdf_keys2)
334
+
335
+ if cdf_keys1 == cdf_keys2:
336
+ logger.debug("Zvariables keys: identical")
337
+ same_keys = cdf_keys1
338
+ ordered_common_keys = sorted(list(same_keys))
339
+ else:
340
+ if (list_diff1 != []) or (list_diff2 != []):
341
+ zVars["Keys"] = [list_diff1, list_diff2]
342
+
343
+ logger.debug("NOT MATCHED zVARIABLES :")
344
+ for idx, diff_list in enumerate(zVars["Keys"]):
345
+ logger.debug(" File %d : %d - %s", idx + 1, len(diff_list), diff_list)
346
+ # ***** Matched keys *****
347
+ same_keys = set(cdf_keys1) & set(cdf_keys2)
348
+
349
+ # ***** Alphabetical order *****
350
+ ordered_common_keys = sorted(list(same_keys))
351
+
352
+ logger.debug("MATCHED zVARIABLES : %d", len(ordered_common_keys))
353
+ logger.debug(" %s", ordered_common_keys)
354
+
355
+ # prepare the dicts to store z_var and v_att diff
356
+ v_att_key_diff_dict = {}
357
+ v_att_value_diff_dict = {}
358
+ z_var_shape_diff_dict = {}
359
+ z_var_value_diff_dict = {}
360
+
361
+ for key in ordered_common_keys:
362
+ if key in list_ignore_zvar:
363
+ continue
364
+
365
+ # Raw values comparison : It's really necessary for time values like "Epoch"
366
+ # cdf1.raw_var(key) => 549441617029459008
367
+ # cdf1[key] => 2017-05-30 18:39:07.845459
368
+ field1 = cdf1.raw_var(key)
369
+ field2 = cdf2.raw_var(key)
370
+
371
+ dict_numerical_precision = {}
372
+ if len(list_numerical_precision) != 0:
373
+ dict_numerical_precision = precision_dict_from_list(
374
+ list_numerical_precision
375
+ )
376
+
377
+ compare_z_var(
378
+ field1,
379
+ field2,
380
+ key,
381
+ dict_numerical_precision=dict_numerical_precision,
382
+ shape_diff_dict=z_var_shape_diff_dict,
383
+ value_diff_dict=z_var_value_diff_dict,
384
+ )
385
+
386
+ compare_v_att(
387
+ field1,
388
+ field2,
389
+ key,
390
+ list_ignore_vatt=list_ignore_vatt,
391
+ key_diff_dict=v_att_key_diff_dict,
392
+ value_diff_dict=v_att_value_diff_dict,
393
+ )
394
+
395
+ if v_att_value_diff_dict:
396
+ vAttrs["Value"] = v_att_value_diff_dict
397
+ logger.debug("vAttrs['Value'] : %s", vAttrs["Value"])
398
+
399
+ if z_var_shape_diff_dict:
400
+ zVars["Shape"] = z_var_shape_diff_dict
401
+ if z_var_value_diff_dict:
402
+ zVars["Value"] = z_var_value_diff_dict
403
+
404
+ if v_att_key_diff_dict:
405
+ vAttrs["Keys"] = v_att_key_diff_dict
406
+ if v_att_value_diff_dict:
407
+ vAttrs["Value"] = v_att_value_diff_dict
408
+
409
+ return zVars, vAttrs
410
+
411
+
412
+ # Comparing 2 CDF files data
413
+ def cdf_compare(
414
+ cdf_file1,
415
+ cdf_file2,
416
+ list_ignore_gatt=[],
417
+ list_ignore_zvar=[],
418
+ list_ignore_vatt=[],
419
+ list_numerical_precision=[],
420
+ ):
421
+ logger.debug(" CDF file 1 : %s", cdf_file1)
422
+ logger.debug(" CDF file 2 : %s", cdf_file2)
423
+ checking_file_exist(cdf_file1)
424
+ checking_file_exist(cdf_file2)
425
+
426
+ cdf_keys1, global_att1 = get_keys_and_attributes(cdf_file1)
427
+ cdf_keys2, global_att2 = get_keys_and_attributes(cdf_file2)
428
+
429
+ cdf1 = CDF(cdf_file1)
430
+ cdf2 = CDF(cdf_file2)
431
+
432
+ dict_result = {}
433
+
434
+ gAttrs = compare_global_attributes(global_att1, global_att2, list_ignore_gatt)
435
+
436
+ if gAttrs:
437
+ dict_result["gAttrs"] = gAttrs
438
+
439
+ zVars, vAttrs = compare_data(
440
+ cdf1,
441
+ cdf2,
442
+ cdf_keys1,
443
+ cdf_keys2,
444
+ list_ignore_zvar=list_ignore_zvar,
445
+ list_ignore_vatt=list_ignore_vatt,
446
+ list_numerical_precision=list_numerical_precision,
447
+ )
448
+
449
+ if zVars:
450
+ dict_result["zVars"] = zVars
451
+
452
+ if vAttrs:
453
+ dict_result["vAttrs"] = vAttrs
454
+
455
+ cdf1.close()
456
+ cdf2.close()
457
+
458
+ for key, value in dict_result.items():
459
+ logger.debug("*°*°* %s *°*°*", key)
460
+ for key1, value1 in dict_result[key].items():
461
+ logger.debug(" *°* %s : %s", key1, value1)
462
+
463
+ # Case of we need to force to ignore some zVariables
464
+ # if forced_ignored_zvar != []:
465
+ # logger.debug("Forced ignored zVariables (Particular case) : %s", forced_ignored_zvar)
466
+
467
+ logger.debug("Return value: %s", pformat(dict_result, width=1000))
468
+ return dict_result
469
+
470
+
471
+ def main(cdf_file1, cdf_file2):
472
+ if len(sys.argv) >= 3:
473
+ list_argv = sys.argv
474
+ list_ignore_gatt = []
475
+ list_ignore_zvar = []
476
+ list_ignore_vatt = []
477
+ list_numerical_precision = []
478
+
479
+ if "--ignore_gatt" in (list_argv):
480
+ ind_ignore_gatt = (list_argv).index("--ignore_gatt")
481
+ list_ignore_gatt = []
482
+ for item in list_argv[ind_ignore_gatt + 1 :]:
483
+ if not item.startswith("--ignore_") and not item.startswith(
484
+ "--precision"
485
+ ):
486
+ list_ignore_gatt.append(item)
487
+ else:
488
+ break
489
+ logger.warning("Ignored global attributes list : %s", list_ignore_gatt)
490
+ else:
491
+ logger.debug("No global attributes to be ignored")
492
+
493
+ if "--ignore_zvar" in (list_argv):
494
+ ind_ignore_zvar = (list_argv).index("--ignore_zvar")
495
+ list_ignore_zvar = []
496
+ for item in list_argv[ind_ignore_zvar + 1 :]:
497
+ if not item.startswith("--ignore_") and not item.startswith(
498
+ "--precision"
499
+ ):
500
+ list_ignore_zvar.append(item)
501
+ else:
502
+ break
503
+ logger.warning("Ignored zVariables list : %s", list_ignore_zvar)
504
+ else:
505
+ logger.debug("No zVariables to be ignored")
506
+
507
+ if "--ignore_vatt" in (list_argv):
508
+ ind_ignore_vatt = (list_argv).index("--ignore_vatt")
509
+ list_ignore_vatt = []
510
+ for item in list_argv[ind_ignore_vatt + 1 :]:
511
+ if not item.startswith("--ignore_") and not item.startswith(
512
+ "--precision"
513
+ ):
514
+ list_ignore_vatt.append(item)
515
+ else:
516
+ break
517
+ logger.warning("Ignored variable attributes list : %s", list_ignore_vatt)
518
+ else:
519
+ logger.debug("No variable attributes to be ignored")
520
+
521
+ if "--precision" in (list_argv):
522
+ ind_precision_zvar = (list_argv).index("--precision")
523
+ list_numerical_precision = []
524
+ for item in list_argv[ind_precision_zvar + 1 :]:
525
+ if not item.startswith("--ignore_") and not item.startswith(
526
+ "--precision"
527
+ ):
528
+ list_numerical_precision.append(item)
529
+ else:
530
+ break
531
+ logger.warning("Numerical precision list : %s", list_numerical_precision)
532
+ else:
533
+ logger.debug("No zVariable precision set")
534
+
535
+ if "--precision" in (list_argv):
536
+ ind_precision_zvar = (list_argv).index("--precision")
537
+ list_numerical_precision = []
538
+ for item in list_argv[ind_precision_zvar + 1 :]:
539
+ if not item.startswith("--ignore_") and not item.startswith(
540
+ "--precision"
541
+ ):
542
+ list_numerical_precision.append(item)
543
+ else:
544
+ break
545
+ logger.warning("Numerical precision list : %s", list_numerical_precision)
546
+ else:
547
+ logger.debug("No zVariable precision set")
548
+
549
+ result = cdf_compare(
550
+ cdf_file1,
551
+ cdf_file2,
552
+ list_ignore_gatt=list_ignore_gatt,
553
+ list_ignore_zvar=list_ignore_zvar,
554
+ list_ignore_vatt=list_ignore_vatt,
555
+ list_numerical_precision=list_numerical_precision,
556
+ )
557
+ logger.info("Final result : %s", pformat(result, width=1000))
558
+
559
+
560
+ # *°*°*°*°*°*°*°*°
561
+ # Main program
562
+ # *°*°*°*°*°*°*°*°
563
+
564
+ if __name__ == "__main__":
565
+ main(sys.argv[1], sys.argv[2])