petal-qc 0.0.10__py3-none-any.whl → 0.0.12__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.

Potentially problematic release.


This version of petal-qc might be problematic. Click here for more details.

@@ -271,12 +271,8 @@ def main():
271
271
 
272
272
  except Exception:
273
273
  # Login with "standard" if the above fails.
274
- client = itkdb.Client()
275
- client.user._access_code1 = getpass.getpass("Access 1: ")
276
- client.user._access_code2 = getpass.getpass("Access 2: ")
277
- client.user.authenticate()
278
- print("Hello {} !".format(client.user.name))
279
-
274
+ client = ITkDButils.create_client()
275
+
280
276
  # Check the Bustape tests
281
277
  try:
282
278
  out = BTreport(client, SN)
petal_qc/__init__.py CHANGED
@@ -1,5 +1,5 @@
1
1
  """petal_qc python module."""
2
- __version__ = "0.0.10"
2
+ __version__ = "0.0.12"
3
3
 
4
4
 
5
5
  def coreMetrology():
@@ -28,6 +28,17 @@ def uploadPetalInformation():
28
28
  from .metrology.uploadPetalInformation import main
29
29
  main()
30
30
 
31
+ def createCoreThermalReport():
32
+ """Create a petal core thermal report."""
33
+ from .thermal.create_core_report import main
34
+ main()
35
+
36
+ def analyzeIRCore():
37
+ """Create a petal core thermal report."""
38
+ from .thermal.analyze_IRCore import main
39
+ main()
40
+
41
+
31
42
  def dashBoard():
32
43
  """Launches the Core thermal analysis ahd PDB script."""
33
44
  from .dashBoard import main
petal_qc/dashBoard.py CHANGED
@@ -87,10 +87,13 @@ class DashWindow(dbGtkUtils.ITkDBWindow):
87
87
 
88
88
  self.mask |= bt
89
89
  opt = IRPetalParam()
90
+ opt.files = []
91
+ opt.golden = None
90
92
  opt.folder = None
91
93
  opt.out = None
92
94
  opt.alias = None
93
95
  opt.SN = None
96
+ opt.desy = False
94
97
  W = CoreThermal(opt, self.session, title="Petal Thermal Test.")
95
98
  W.connect("destroy", self.app_closed, bitn)
96
99
  W.show_all()
@@ -320,11 +320,6 @@ def do_petal_metrology():
320
320
  parser.add_argument("--save", dest='save', action="store_true", default=False)
321
321
  parser.add_argument("--out", dest="out", default="petal_flatness.docx",
322
322
  type=str, help="The output fiel name")
323
- parser.add_argument("--bottom-lp", dest='bLP', action=CommaSeparatedListAction, default=None,
324
- help="Bottom locking point fiducial coordinates")
325
- parser.add_argument("--upper-lp", dest='uLP', action=CommaSeparatedListAction, default=None,
326
- help="upper locking point fiducials coordinates")
327
-
328
323
  parser.add_argument("--title", dest="title", default=None,
329
324
  type=str, help="Document title")
330
325
  parser.add_argument("--nbins", dest="nbins", default=25,
@@ -89,14 +89,11 @@ class CoreMetrology(itkdb_gtk.dbGtkUtils.ITkDBWindow):
89
89
  # The Serial number
90
90
  self.SN = itkdb_gtk.dbGtkUtils.TextEntry()
91
91
  self.SN.connect("text-changed", self.on_SN_changed)
92
- if options.SN:
93
- self.on_SN_changed(self.SN.entry, options.SN)
94
92
 
95
93
  # The prefix
96
94
  self.prefix = Gtk.Entry()
97
- if options.prefix:
98
- self.SN.set_text(options.prefix)
99
95
 
96
+ # The switch
100
97
  self.desy = Gtk.Switch()
101
98
  self.desy.props.halign = Gtk.Align.START
102
99
 
@@ -147,6 +144,22 @@ class CoreMetrology(itkdb_gtk.dbGtkUtils.ITkDBWindow):
147
144
 
148
145
  self.mainBox.pack_start(self.message_panel.frame, True, True, 0)
149
146
 
147
+ if self.options.SN:
148
+ self.on_SN_changed(self.SN.entry, self.options.SN)
149
+
150
+ if self.options.is_front:
151
+ self.back.set_active(True)
152
+
153
+ if self.options.folder:
154
+ the_folder = Gio.File.new_for_path(self.options.folder)
155
+ self.btnFolder.set_file(the_folder)
156
+ self.on_folder_set(None)
157
+
158
+ if len(self.options.files)>0:
159
+ the_file = Gio.File.new_for_path(self.options.files[0])
160
+ self.btnData.set_file(the_file)
161
+ self.on_file_set(None)
162
+
150
163
 
151
164
  def quit(self, *args):
152
165
  """Quits the application."""
@@ -340,6 +353,7 @@ class CoreMetrologyOptions(object):
340
353
  self.files = []
341
354
  self.SN = None
342
355
  self.desy = False
356
+ self.is_front = False
343
357
  self.folder = None
344
358
  self.prefix = None
345
359
  self.locking_points = None
@@ -354,15 +368,12 @@ def main():
354
368
  parser.add_argument('files', nargs='*', help="Input files")
355
369
  parser.add_argument("--prefix", dest='prefix', default=None)
356
370
  parser.add_argument("--SN", dest='SN', default=None)
371
+ parser.add_argument("--front", dest='is_front', action="store_true", default=False)
372
+
357
373
  parser.add_argument("--save", dest='save', action="store_true", default=False)
358
374
  parser.add_argument("--desy", dest='desy', action="store_true", default=False)
359
375
  parser.add_argument("--out", dest="out", default="petal_flatness.docx",
360
376
  type=str, help="The output fiel name")
361
- parser.add_argument("--bottom-lp", dest='bLP', action=CommaSeparatedListAction, default=None,
362
- help="Bottom locking point fiducial coordinates")
363
- parser.add_argument("--upper-lp", dest='uLP', action=CommaSeparatedListAction, default=None,
364
- help="upper locking point fiducials coordinates")
365
-
366
377
  parser.add_argument("--title", dest="title", default=None,
367
378
  type=str, help="Document title")
368
379
  parser.add_argument("--nbins", dest="nbins", default=25,
@@ -96,11 +96,6 @@ def main():
96
96
  parser.add_argument("--desy", dest='desy', action="store_true", default=False, help="True if data is from DESY's SmartScope")
97
97
  parser.add_argument("--out", dest="out", default="petal_flatness.docx",
98
98
  type=str, help="The output file name")
99
- parser.add_argument("--bottom-lp", dest='bLP', action=CommaSeparatedListAction, default=None,
100
- help="Bottom locking point fiducial coordinates")
101
- parser.add_argument("--upper-lp", dest='uLP', action=CommaSeparatedListAction, default=None,
102
- help="upper locking point fiducials coordinates")
103
-
104
99
  parser.add_argument("--title", dest="title", default=None,
105
100
  type=str, help="Report Document title")
106
101
  parser.add_argument("--nbins", dest="nbins", default=25,
@@ -328,10 +328,6 @@ if __name__ == "__main__":
328
328
  parser.add_argument("--save", dest='save', action="store_true", default=False)
329
329
  parser.add_argument("--front", dest='is_front', action="store_true", default=True)
330
330
  parser.add_argument("--back", dest='is_front', action="store_false", default=True)
331
- parser.add_argument("--bottom-lp", dest='bLP', action=CommaSeparatedListAction, default=None,
332
- help="Bottom locking point fiducial coordinates")
333
- parser.add_argument("--upper-lp", dest='uLP', action=CommaSeparatedListAction, default=None,
334
- help="upper locking point fiducials coordinates")
335
331
  parser.add_argument("--out", dest="out", default="petal_flatness.docx",
336
332
  type=str, help="The output fiel name")
337
333
  parser.add_argument("--title", dest="title", default=None,
@@ -2,6 +2,7 @@
2
2
  """Read AVS dats file."""
3
3
  import sys
4
4
  import re
5
+ import numpy as np
5
6
  from argparse import ArgumentParser
6
7
  from pathlib import Path
7
8
 
@@ -243,7 +244,7 @@ def get_float(cell, separator=None, default=0.0):
243
244
  rr = re.findall(r"[-+]?[.]?[\d]+(?:,\d\d\d)*[\.]?\d*(?:[eE][-+]?\d+)?", txt)
244
245
  if len(rr) == 0:
245
246
  return default
246
-
247
+
247
248
  val = float(rr[0])
248
249
  return val
249
250
  except ValueError:
@@ -300,10 +301,10 @@ def get_res_and_accep(sheet, indx):
300
301
  sval = sheet["g{}".format(indx)].value
301
302
  if isinstance(sval, float) or isinstance(sval, int):
302
303
  val = sval
303
-
304
+
304
305
  else:
305
306
  sval = ' '.join(sval.strip().split()).split()
306
-
307
+
307
308
  scale = 1.0
308
309
  try:
309
310
  rr = re.findall(r"[-+]?[.]?[\d]+(?:,\d\d\d)*[\.]?\d*(?:[eE][-+]?\d+)?", sval[0])
@@ -315,19 +316,19 @@ def get_res_and_accep(sheet, indx):
315
316
  U = sval[1].upper()[0]
316
317
  if U=='G':
317
318
  scale = 1000
318
-
319
+
319
320
  except ValueError:
320
321
  val = 0
321
-
322
+
322
323
  val = val * scale
323
324
  #val = get_float(sheet["g{}".format(indx)])
324
325
  pass_val = sheet["h{}".format(indx)]
325
- if pass_val.value is None:
326
+ if pass_val.value is None:
326
327
  # Operator did not set the PASS/FAIL thing
327
328
  accept = True
328
329
  else:
329
330
  accept = get_boolean(pass_val)
330
-
331
+
331
332
  return val, accept
332
333
 
333
334
 
@@ -351,6 +352,70 @@ def cell_value(sheet, coord):
351
352
 
352
353
  return None
353
354
 
355
+ def distance(P1, P2):
356
+ """Distance between 2 points."""
357
+ P = (P2-P1)
358
+ S = np.sum(np.square(P))
359
+ D = np.sqrt(S)
360
+ return D
361
+
362
+ def find_test_indx(tests, val):
363
+ """Apply brute force."""
364
+ try:
365
+ indx = tests.index(val)
366
+
367
+ except ValueError:
368
+ for ix, key in enumerate(tests):
369
+ if key is None:
370
+ continue
371
+
372
+ if val in key:
373
+ indx = ix
374
+ break
375
+
376
+ return indx
377
+
378
+ def fix_commas(P):
379
+ """Fix commas in cells."""
380
+ for i in range(2):
381
+ if P[i] > 1000:
382
+ P[i] /= 1000
383
+
384
+
385
+ def get_locator_distance(sheet, results, tests, nom, result):
386
+ """Compute distance to nominal."""
387
+ Pnom = np.array([
388
+ get_float(sheet['E{}'.format(find_test_indx(tests, "{}_X".format(nom)))]),
389
+ get_float(sheet['E{}'.format(find_test_indx(tests, "{}_Y".format(nom)))])
390
+ ])
391
+ fix_commas(Pnom)
392
+
393
+ P = np.array([results["{}_X".format(result)], results["{}_Y".format(result)]])
394
+ fix_commas(P)
395
+
396
+ D = distance(Pnom, P)
397
+ return D
398
+
399
+
400
+ def check_locator_positions(sheet, the_test, tests):
401
+ """Check position of locators."""
402
+
403
+ defects = []
404
+ locators = [("PL01", "LOCATOR1"), ("PL02", "LOCATOR2"), ("PL03", "LOCATOR3"),
405
+ ("FD01", "FIDUCIAL1"), ("FD02", "FIDUCIAL2")]
406
+
407
+ for nom, val in locators:
408
+ D = get_locator_distance(sheet, the_test["results"], tests, nom, val)
409
+ if D > 0.075:
410
+ defects.append({
411
+ "name": nom,
412
+ "description": "{:.3f} mm out".format(D)
413
+ })
414
+
415
+ if len(defects)>0:
416
+ the_test["passed"] = False
417
+ the_test["defects"].extend(defects)
418
+
354
419
 
355
420
  def check_for_problems(sheet, the_test, row_range):
356
421
  """Finds FAIL massages in the Acceptance column."""
@@ -364,7 +429,8 @@ def check_for_problems(sheet, the_test, row_range):
364
429
  if txt[0] == 'f':
365
430
  nfail += 1
366
431
  hdr = get_text(sheet["d{}".format(row)])
367
- reason = cell_value(sheet, "i{}".format(row))
432
+ result = get_float(sheet["g{}".format(row)])
433
+ reason = "{} [{}]".format(result, cell_value(sheet, "i{}".format(row)))
368
434
 
369
435
  if reason:
370
436
  if len(reason) < 1:
@@ -374,8 +440,8 @@ def check_for_problems(sheet, the_test, row_range):
374
440
  the_test["defects"].append({"name": hdr,
375
441
  "description": reason})
376
442
 
377
- if nfail:
378
- the_test["passed"] = False
443
+ #if nfail:
444
+ # the_test["passed"] = False
379
445
 
380
446
 
381
447
  def get_coreID(bustapeID):
@@ -529,7 +595,8 @@ def readFATfile(session, file_path, SN=None):
529
595
  metrology_test["results"]["PARALLELISM_BACK"] = get_float(sheet["g{}".format(find_idx(tests, "B.PARAL")[0])])
530
596
 
531
597
  # Get defects
532
- check_for_problems(sheet, metrology_test, [tests.index("WEIGH")+1, sheet.max_row])
598
+ check_locator_positions(sheet, metrology_test, tests)
599
+ check_for_problems(sheet, metrology_test, [tests.index("VANGL"), sheet.max_row])
533
600
 
534
601
  return vi_test, delamination_test, grounding_test, metrology_test, batch, petal_weight
535
602
 
@@ -576,8 +643,8 @@ def readProductionSheet(session, file_path, SN):
576
643
 
577
644
  # Assume active sheet is the good one, otherwise will have tofind in wb.sheetnames
578
645
  sheet = wb.active
579
- if sheet.max_row > 30 or sheet.max_column > 8:
580
- raise AVSDataException("Wrong PS file")
646
+ if sheet.max_row > 30 or sheet.max_column > 9:
647
+ raise AVSDataException("Wrong PS file:\nmx row {} mx_col {}".format(sheet.max_row, sheet.max_column))
581
648
 
582
649
  # Find the start
583
650
  indx = find_label(sheet, "PETAL", "A")
@@ -690,6 +757,6 @@ if __name__ == "__main__":
690
757
  sys.exit()
691
758
 
692
759
  fnam = Path(options.files[0]).expanduser().resolve()
693
- readProductionSheet(client, fnam, options.SN)
694
- # readFATfile(client, fnam, options.SN)
760
+ # readProductionSheet(client, fnam, options.SN)
761
+ readFATfile(client, fnam, options.SN)
695
762
  dlg.die()
@@ -56,7 +56,6 @@ def get_type(child):
56
56
 
57
57
  return ctype
58
58
 
59
-
60
59
  class AVSPanel(dbGtkUtils.ITkDBWindow):
61
60
  """Dialog for interaction with DB."""
62
61
 
@@ -270,6 +269,9 @@ class AVSPanel(dbGtkUtils.ITkDBWindow):
270
269
  self.SN.set_text("")
271
270
  self.btnPSF.unselect_all()
272
271
  self.btnFAT.unselect_all()
272
+ self.btn_state.set_label("Undef")
273
+ dbGtkUtils.set_button_color(self.btn_state, "azure", "black")
274
+
273
275
 
274
276
  def create_test_window(self, test_json, test_name, label):
275
277
  """Create the dialog for a DB test and add it to the notebook.
@@ -571,6 +573,15 @@ class AVSPanel(dbGtkUtils.ITkDBWindow):
571
573
  if rc is None:
572
574
  error_txt.append("Problem assembling {} into Petal\n".format(cmp))
573
575
 
576
+ # Check for child stage
577
+ cobj = ITkDButils.get_DB_component(self.session, SN)
578
+ ctype = get_type(cobj)
579
+ cstage = cobj["currentStage"]['code']
580
+ if cstage != final_stage[ctype]:
581
+ rc = ITkDButils.set_object_stage(self.session, SN, final_stage[ctype])
582
+ if rc is None:
583
+ print("Could not set final stage of {} [{}]".format(ctype, SN))
584
+
574
585
  # Check for HonneyComb set
575
586
  for P in self.petal_core["properties"]:
576
587
  if P["code"] == "HC_ID" and P["value"] is None:
@@ -588,17 +599,17 @@ class AVSPanel(dbGtkUtils.ITkDBWindow):
588
599
  break
589
600
 
590
601
  # Check the final stage of the assembled objects
591
- for child in self.petal_core["children"]:
592
- if child["component"]:
593
- cSN = child["component"]["serialNumber"]
594
- ctype = get_type(child)
595
- cobj = ITkDButils.get_DB_component(self.session, cSN)
596
- cstage = cobj["currentStage"]['code']
597
- if cstage != final_stage[ctype]:
598
- rc = ITkDButils.set_object_stage(self.session, cSN, final_stage[ctype])
599
- if rc is None:
600
- print("Could not set final stage of {}".format(cSN))
601
-
602
+ # for child in self.petal_core["children"]:
603
+ # if child["component"]:
604
+ # cSN = child["component"]["serialNumber"]
605
+ # ctype = get_type(child)
606
+ # cobj = ITkDButils.get_DB_component(self.session, cSN)
607
+ # cstage = cobj["currentStage"]['code']
608
+ # if cstage != final_stage[ctype]:
609
+ # rc = ITkDButils.set_object_stage(self.session, cSN, final_stage[ctype])
610
+ # if rc is None:
611
+ # print("Could not set final stage of {}".format(cSN))
612
+ #
602
613
  if len(error_txt)>0:
603
614
  dbGtkUtils.complain("Assembly of {} could not be completeed:".format(this_petal),
604
615
  "\n".join(error_txt))
@@ -0,0 +1,181 @@
1
+ #!/usr/bin/env python3
2
+ """Analize AVS metrology tests."""
3
+ import sys
4
+ from pathlib import Path
5
+ import numpy as np
6
+
7
+ try:
8
+ import itkdb_gtk
9
+
10
+ except ImportError:
11
+ cwd = Path(__file__).parent.parent
12
+ sys.path.append(cwd.as_posix())
13
+
14
+ from itkdb_gtk import ITkDBlogin, ITkDButils
15
+ from petal_qc.metrology.readAVSdata import readFATfile
16
+
17
+
18
+ def set_pos(V, results, obj):
19
+ """Update positions."""
20
+ results["{}_X".format(obj)] = V[0]
21
+ results["{}_Y".format(obj)] = V[1]
22
+
23
+
24
+ def get_pos(results, obj):
25
+ """Return position."""
26
+ try:
27
+ X = results["{}_X".format(obj)]
28
+ Y = results["{}_Y".format(obj)]
29
+
30
+ if abs(X) > 1000:
31
+ X /= 1000
32
+ if abs(Y)>1000:
33
+ Y /= 1000
34
+ except KeyError:
35
+ X = 0.0
36
+ Y = 0.0
37
+
38
+ P = np.array([X, Y], dtype="float64")
39
+ return P
40
+
41
+
42
+ def check_locators(results):
43
+ """Accumulate metrology values."""
44
+ points = ["LOCATOR1", "LOCATOR2", "LOCATOR3", "FIDUCIAL1", "FIDUCIAL2"]
45
+ coord = {}
46
+ for P in points:
47
+ coord[P] = get_pos(results, P)
48
+
49
+ changed = False
50
+ fd1 = np.array(coord["FIDUCIAL1"], dtype="float64")
51
+ if fd1[0]!=0.0 or fd1[1]!=0:
52
+ changed = True
53
+ for V in coord.values():
54
+ V -= fd1
55
+
56
+ for O, P in coord.items():
57
+ set_pos(coord[O], results, O)
58
+
59
+ return changed
60
+
61
+ ROOT_DIR = Path("/Users/lacasta/Nextcloud/ITk/5-Petal_cores")
62
+
63
+
64
+
65
+ def analyze_avs_metrology(session, SN, altid):
66
+ """Regenerate test json from FAT file."""
67
+ P = ROOT_DIR / altid
68
+ files = list(P.glob("AVS.P052.FRT.*.xlsx"))
69
+ if len(files)==0:
70
+ print("Cannot find FAT file for {}".format(altid))
71
+ return None
72
+ elif len(files)>1:
73
+ print("More than one FAT file for {}".format(altid))
74
+ for i, f in enumerate(files):
75
+ print("{} - {}".format(i, Path/f).name)
76
+
77
+ ifile = int(input("Choose file (-1 to discard): "))
78
+ if ifile < 0:
79
+ return None
80
+
81
+ the_file = files[ifile]
82
+
83
+ else:
84
+ the_file = files[0]
85
+
86
+
87
+ tests = readFATfile(session, the_file, SN)
88
+ the_test = tests[3]
89
+ check_locators(the_test["results"])
90
+ the_test["isRetroactive"] = True
91
+ the_test["stage"] = "ASSEMBLY"
92
+
93
+ return the_test
94
+
95
+ def main(session):
96
+ """Entry point"""
97
+ # find all cores
98
+ # Now all the objects
99
+ payload = {
100
+ "filterMap": {
101
+ "componentType": ["CORE_PETAL"],
102
+ "type": ["CORE_AVS"],
103
+ #"currentLocation": ["IFIC"],
104
+ },
105
+ "sorterList": [
106
+ {"key": "alternativeIdentifier", "descending": False }
107
+ ],
108
+ }
109
+
110
+ core_list = session.get("listComponents", json=payload)
111
+ core_tests = ["METROLOGY_AVS"]
112
+
113
+ petal_ids = []
114
+ for core in core_list:
115
+ SN = core["serialNumber"]
116
+ altid = core['alternativeIdentifier']
117
+ if "PPC" not in altid:
118
+ continue
119
+
120
+ petal_ids.append(altid)
121
+
122
+ location = core["currentLocation"]['code']
123
+ coreStage = core["currentStage"]['code']
124
+
125
+ print("\nPetal {} [{}] - {}. {}".format(SN, altid, coreStage, location))
126
+ test_list = session.get("listTestRunsByComponent", json={"filterMap":{"serialNumber": SN, "state": "ready", "testType":core_tests}})
127
+
128
+ good_tests = {}
129
+ for tst in test_list:
130
+ ttype = tst["testType"]["code"]
131
+ if ttype not in core_tests:
132
+ print(ttype)
133
+ continue
134
+
135
+ T = session.get("getTestRun", json={"testRun": tst["id"]})
136
+ if T["state"] != "ready":
137
+ continue
138
+
139
+ if ttype in good_tests:
140
+ if good_tests[ttype]["runNumber"] < T["runNumber"]:
141
+ good_tests[ttype] = T
142
+ else:
143
+ good_tests[ttype] = T
144
+
145
+ for ttype, T in good_tests.items():
146
+ if ttype != "METROLOGY_AVS":
147
+ continue
148
+
149
+ found = False
150
+ for value in T["results"]:
151
+ if value["code"] == "LOCATOR1_X":
152
+ found = True
153
+ break
154
+
155
+ if not found:
156
+ print("LOCATOR1 is not here")
157
+ the_test = analyze_avs_metrology(session, SN, altid)
158
+ if the_test is None:
159
+ continue
160
+
161
+ rc = ITkDButils.upload_test(session, the_test, check_runNumber=True)
162
+ if rc:
163
+ print(rc)
164
+
165
+
166
+ if __name__ == "__main__":
167
+ # ITk_PB authentication
168
+ dlg = ITkDBlogin.ITkDBlogin()
169
+ client = dlg.get_client()
170
+
171
+ try:
172
+ # main(session)
173
+ the_test = analyze_avs_metrology(client, "20USEBC1000124", "PPC.015")
174
+ #rc = ITkDButils.upload_test(client, the_test, check_runNumber=True)
175
+ #if rc:
176
+ # print(rc)
177
+
178
+ except Exception as E:
179
+ print(E)
180
+
181
+ dlg.die()
@@ -0,0 +1,44 @@
1
+ #!/usr/bin/env python3
2
+ """Compara golden files."""
3
+ import json
4
+ import sys
5
+ from pathlib import Path
6
+ from argparse import ArgumentParser
7
+ import numpy as np
8
+ import matplotlib.pyplot as plt
9
+
10
+
11
+ def compare_golden(files):
12
+ """Go through files."""
13
+ fig, ax = plt.subplots(2, 1, tight_layout=True)
14
+ for ff in files:
15
+ ifile = Path(ff).expanduser().resolve()
16
+ if not ifile.exists():
17
+ print("ff does not exist.")
18
+ continue
19
+
20
+ js = None
21
+ with open(ifile, "r", encoding="utf-8") as fp:
22
+ js = json.load(fp)
23
+
24
+ if js is None:
25
+ print("Cannot load {}".format(ff))
26
+ continue
27
+
28
+ for iside in range(2):
29
+ ax[iside].plot(js[iside]["path_length"], js[iside]["path_temp"], '-', label=ifile.name)
30
+
31
+ for iside in range(2):
32
+ ax[iside].legend()
33
+ plt.show()
34
+
35
+ if __name__ == "__main__":
36
+ parser = ArgumentParser()
37
+ parser.add_argument('files', nargs='*', help="Input files")
38
+
39
+ options = parser.parse_args()
40
+ if len(options.files) == 0:
41
+ print("I need an input file")
42
+ sys.exit()
43
+
44
+ compare_golden(options.files)