petal-qc 0.0.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.
Potentially problematic release.
This version of petal-qc might be problematic. Click here for more details.
- petal_qc/BTreport/CheckBTtests.py +321 -0
- petal_qc/BTreport/__init__.py +0 -0
- petal_qc/BTreport/bustapeReport.py +144 -0
- petal_qc/__init__.py +14 -0
- petal_qc/metrology/Cluster.py +90 -0
- petal_qc/metrology/DataFile.py +47 -0
- petal_qc/metrology/PetalMetrology.py +327 -0
- petal_qc/metrology/__init__.py +0 -0
- petal_qc/metrology/all2csv.py +57 -0
- petal_qc/metrology/analyze_locking_points.py +597 -0
- petal_qc/metrology/cold_noise.py +106 -0
- petal_qc/metrology/comparisonTable.py +59 -0
- petal_qc/metrology/convert_mitutoyo.py +175 -0
- petal_qc/metrology/convert_smartscope.py +145 -0
- petal_qc/metrology/coreMetrology.py +402 -0
- petal_qc/metrology/data2csv.py +63 -0
- petal_qc/metrology/do_Metrology.py +117 -0
- petal_qc/metrology/flatness4nigel.py +157 -0
- petal_qc/metrology/gtkutils.py +120 -0
- petal_qc/metrology/petal_flatness.py +353 -0
- petal_qc/metrology/show_data_file.py +118 -0
- petal_qc/metrology/testSummary.py +37 -0
- petal_qc/metrology/test_paralelism.py +71 -0
- petal_qc/thermal/CSVImage.py +69 -0
- petal_qc/thermal/DebugPlot.py +76 -0
- petal_qc/thermal/IRBFile.py +768 -0
- petal_qc/thermal/IRCore.py +110 -0
- petal_qc/thermal/IRDataGetter.py +359 -0
- petal_qc/thermal/IRPetal.py +1338 -0
- petal_qc/thermal/IRPetalParam.py +71 -0
- petal_qc/thermal/PetalColorMaps.py +62 -0
- petal_qc/thermal/Petal_IR_Analysis.py +142 -0
- petal_qc/thermal/PipeFit.py +598 -0
- petal_qc/thermal/__init__.py +0 -0
- petal_qc/thermal/analyze_IRCore.py +417 -0
- petal_qc/thermal/contours.py +378 -0
- petal_qc/thermal/create_IRCore.py +185 -0
- petal_qc/thermal/pipe_read.py +182 -0
- petal_qc/thermal/show_IR_petal.py +420 -0
- petal_qc/utils/Geometry.py +756 -0
- petal_qc/utils/Progress.py +182 -0
- petal_qc/utils/__init__.py +0 -0
- petal_qc/utils/all_files.py +35 -0
- petal_qc/utils/docx_utils.py +186 -0
- petal_qc/utils/fit_utils.py +188 -0
- petal_qc/utils/utils.py +180 -0
- petal_qc-0.0.0.dist-info/METADATA +29 -0
- petal_qc-0.0.0.dist-info/RECORD +51 -0
- petal_qc-0.0.0.dist-info/WHEEL +5 -0
- petal_qc-0.0.0.dist-info/entry_points.txt +3 -0
- petal_qc-0.0.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,417 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Analyze the JS files generated by create_IRCore."""
|
|
3
|
+
import json
|
|
4
|
+
import os
|
|
5
|
+
import sys
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
import matplotlib.dates as pldates
|
|
9
|
+
import matplotlib.pyplot as plt
|
|
10
|
+
import matplotlib.ticker as ticker
|
|
11
|
+
import numpy as np
|
|
12
|
+
from scipy.interpolate import CubicSpline
|
|
13
|
+
from petal_qc.utils.utils import find_file
|
|
14
|
+
from petal_qc.utils.utils import output_folder
|
|
15
|
+
|
|
16
|
+
from petal_qc.thermal import IRCore
|
|
17
|
+
from petal_qc.thermal import Petal_IR_Analysis
|
|
18
|
+
|
|
19
|
+
CO2_Temp_setting = -35
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def get_acceptance_band():
|
|
23
|
+
"""returns the width of the acceptance band."""
|
|
24
|
+
band = 0.1*CO2_Temp_setting # 10% of setting point
|
|
25
|
+
return abs(band)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def get_names(files):
|
|
29
|
+
"""GEt names from filenames."""
|
|
30
|
+
names = []
|
|
31
|
+
for ifile in files:
|
|
32
|
+
ifile = Path(ifile)
|
|
33
|
+
names.append(ifile.stem)
|
|
34
|
+
return names
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class GoldenAxis(object):
|
|
38
|
+
"""Get best X path."""
|
|
39
|
+
def __init__(self) -> None:
|
|
40
|
+
self.xaxis = [] # Set of coordinates
|
|
41
|
+
self.nitems = [] # number of curves with this axis
|
|
42
|
+
self.index = []
|
|
43
|
+
self.size = []
|
|
44
|
+
self.current = 0
|
|
45
|
+
|
|
46
|
+
@staticmethod
|
|
47
|
+
def round_npts(V):
|
|
48
|
+
"""Return the closest multiple of 10."""
|
|
49
|
+
npts = len(V)
|
|
50
|
+
return int(int(npts/10.0 + 0.5)*10)
|
|
51
|
+
|
|
52
|
+
def check_axis(self, X, indx):
|
|
53
|
+
"""Check in X array is there or not.
|
|
54
|
+
|
|
55
|
+
Args:
|
|
56
|
+
X (np.ndarray): The axis to check.
|
|
57
|
+
i (int): the index in the array of results.
|
|
58
|
+
|
|
59
|
+
"""
|
|
60
|
+
npts = self.round_npts(X)
|
|
61
|
+
for i, v in enumerate(self.xaxis):
|
|
62
|
+
nv = self.size[i]
|
|
63
|
+
if npts == nv:
|
|
64
|
+
self.nitems[i] += 1
|
|
65
|
+
self.index[i].append(indx)
|
|
66
|
+
return
|
|
67
|
+
|
|
68
|
+
self.xaxis.append(X)
|
|
69
|
+
self.size.append(npts)
|
|
70
|
+
self.nitems.append(1)
|
|
71
|
+
self.index.append([indx])
|
|
72
|
+
|
|
73
|
+
def get_axis(self):
|
|
74
|
+
"""Get the actual axis."""
|
|
75
|
+
imax = -1
|
|
76
|
+
indx = -1
|
|
77
|
+
for i, n in enumerate(self.nitems):
|
|
78
|
+
if n > imax:
|
|
79
|
+
imax = n
|
|
80
|
+
indx = i
|
|
81
|
+
|
|
82
|
+
return np.linspace(0., 1.0, num=self.size[indx])
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def compute_average(values):
|
|
86
|
+
"""Compute the mean of arrays in input."""
|
|
87
|
+
data = np.zeros([len(values), len(values[0])])
|
|
88
|
+
for i, V in enumerate(values):
|
|
89
|
+
data[i, :] = V
|
|
90
|
+
|
|
91
|
+
avg = np.mean(data, axis=0)
|
|
92
|
+
return avg
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def create_golden_average(files, options):
|
|
96
|
+
"""Create golden average.
|
|
97
|
+
|
|
98
|
+
Args:
|
|
99
|
+
----
|
|
100
|
+
files (list): List of input files
|
|
101
|
+
options: other options.
|
|
102
|
+
|
|
103
|
+
"""
|
|
104
|
+
names = get_names(files)
|
|
105
|
+
result_list = []
|
|
106
|
+
# Create the axes
|
|
107
|
+
axes = [GoldenAxis() for i in range(2)]
|
|
108
|
+
|
|
109
|
+
# Get the Xaxis.
|
|
110
|
+
# Will be the linspace between 0 and 1 with the most repeated
|
|
111
|
+
# number of points.
|
|
112
|
+
for i, ifile in enumerate(files):
|
|
113
|
+
ifile = find_file(options.folder, ifile)
|
|
114
|
+
if not ifile.exists():
|
|
115
|
+
print("+++ File {} does not exist.".format(ifile))
|
|
116
|
+
continue
|
|
117
|
+
|
|
118
|
+
alias = names[i]
|
|
119
|
+
result = IRCore.IRCore.read_json(ifile)
|
|
120
|
+
if result.aliasID is None or result.aliasID == "":
|
|
121
|
+
result.aliasID = names[i]
|
|
122
|
+
|
|
123
|
+
result_list.append(result)
|
|
124
|
+
|
|
125
|
+
# Loop to get best axis
|
|
126
|
+
R = result.results
|
|
127
|
+
for iside in range(2):
|
|
128
|
+
the_axis = R[iside].path_length
|
|
129
|
+
axes[iside].check_axis(the_axis, i)
|
|
130
|
+
|
|
131
|
+
# Prepare the results for the golden average.
|
|
132
|
+
xvalues = [axes[i].get_axis() for i in range(2)]
|
|
133
|
+
for i, R in enumerate(result_list):
|
|
134
|
+
R.golden = []
|
|
135
|
+
for iside in range(2):
|
|
136
|
+
G = Petal_IR_Analysis.AnalysisResult()
|
|
137
|
+
splnT = CubicSpline(R.results[iside].path_length, R.results[iside].path_temp)
|
|
138
|
+
splnS = CubicSpline(R.results[iside].path_length, R.results[iside].path_spread)
|
|
139
|
+
G.path_length = xvalues[iside]
|
|
140
|
+
G.path_temp = np.array([splnT(x) for x in G.path_length])
|
|
141
|
+
G.path_spread = np.array([splnS(x) for x in G.path_length])
|
|
142
|
+
G.sensor_avg = np.array(R.results[iside].sensor_avg)
|
|
143
|
+
G.sensor_std = np.array(R.results[iside].sensor_std)
|
|
144
|
+
R.golden.append(G)
|
|
145
|
+
|
|
146
|
+
if options.debug:
|
|
147
|
+
fig, ax = plt.subplots(2, 1, tight_layout=True)
|
|
148
|
+
fig.suptitle(R.aliasID)
|
|
149
|
+
for i in range(2):
|
|
150
|
+
ax[i].plot(R.results[i].path_length, R.results[i].path_temp, label="original")
|
|
151
|
+
ax[i].plot(R.golden[i].path_length, R.golden[i].path_temp, label="golden")
|
|
152
|
+
ax[i].legend()
|
|
153
|
+
|
|
154
|
+
# Create the golden object
|
|
155
|
+
golden = [Petal_IR_Analysis.AnalysisResult() for i in range(2)]
|
|
156
|
+
for i, G in enumerate(golden):
|
|
157
|
+
G.path_length = xvalues[i]
|
|
158
|
+
G.path_temp = compute_average([R.golden[i].path_temp for R in result_list])
|
|
159
|
+
G.path_spread = compute_average([R.golden[i].path_spread for R in result_list])
|
|
160
|
+
G.sensor_avg = compute_average([R.golden[i].sensor_avg for R in result_list])
|
|
161
|
+
G.sensor_std = compute_average([R.golden[i].sensor_std for R in result_list])
|
|
162
|
+
|
|
163
|
+
return golden, result_list
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
def show_golden_average(golden, results, value):
|
|
167
|
+
"""Create golden average.
|
|
168
|
+
|
|
169
|
+
Args:
|
|
170
|
+
----
|
|
171
|
+
golden: golden values (from create_golgen_average)
|
|
172
|
+
resuls: results from create_golden_average
|
|
173
|
+
value: value to show, ej path_temp, path_spread, sensor_avg, sensor_std
|
|
174
|
+
|
|
175
|
+
"""
|
|
176
|
+
tick_labels = ["R0", "R1", "R2", "R3", "R3", "R4", "R4", "R5", "R5", "EoS"]
|
|
177
|
+
|
|
178
|
+
factor = 1.0
|
|
179
|
+
if value.find("sensor") >= 0:
|
|
180
|
+
factor = 2.0
|
|
181
|
+
|
|
182
|
+
# Get acceptance band
|
|
183
|
+
band = get_acceptance_band()
|
|
184
|
+
|
|
185
|
+
for iside in range(2):
|
|
186
|
+
fig, ax = plt.subplots(2, 1, tight_layout=True, gridspec_kw={'height_ratios': (0.66, 0.34)}, figsize=(7, 6))
|
|
187
|
+
fig.suptitle("Golden average for {} - side {}.".format(value, iside))
|
|
188
|
+
for a in ax:
|
|
189
|
+
a.grid()
|
|
190
|
+
|
|
191
|
+
if value.find("path") < 0:
|
|
192
|
+
for i in range(2):
|
|
193
|
+
ax[i].set_xticks(range(10), labels=tick_labels)
|
|
194
|
+
|
|
195
|
+
for R in results:
|
|
196
|
+
RS = R.results[iside]
|
|
197
|
+
Y = getattr(RS, value)
|
|
198
|
+
gY = getattr(golden[iside], value)
|
|
199
|
+
O = getattr(R.golden[iside], value) - gY
|
|
200
|
+
if value.find("path") >= 0:
|
|
201
|
+
X = RS.path_length
|
|
202
|
+
gX = golden[iside].path_length
|
|
203
|
+
|
|
204
|
+
else:
|
|
205
|
+
X = np.array([float(x) for x in range(10)])
|
|
206
|
+
gX = X
|
|
207
|
+
|
|
208
|
+
ax[0].plot(X, Y, '-', label=R.aliasID, linewidth=1)
|
|
209
|
+
ax[1].plot(gX, O, '-', label=R.aliasID, linewidth=1)
|
|
210
|
+
|
|
211
|
+
Tmean = np.mean(Y)
|
|
212
|
+
Tband = factor*abs(Tmean)/3
|
|
213
|
+
ax[0].plot(gX, gY, '-', label="Golden", linewidth=4, alpha=0.4, color="black")
|
|
214
|
+
|
|
215
|
+
ax[0].legend(ncol=3, fontsize="x-small")
|
|
216
|
+
ax[0].set_title("T$_{prof}$ values")
|
|
217
|
+
if value.find("temp") >= 0 or value.find("_avg") >= 0:
|
|
218
|
+
ax[0].set_ylim(Tmean-Tband, Tmean+Tband)
|
|
219
|
+
ax[0].fill_between(gX,
|
|
220
|
+
getattr(golden[iside], value) + band,
|
|
221
|
+
getattr(golden[iside], value) - band,
|
|
222
|
+
facecolor="yellow", alpha=0.25,
|
|
223
|
+
label="Acceptance band")
|
|
224
|
+
|
|
225
|
+
ax[1].fill_between(gX, band, -band,
|
|
226
|
+
facecolor="yellow", alpha=0.25,
|
|
227
|
+
label="Acceptance band")
|
|
228
|
+
|
|
229
|
+
ax[1].legend(ncol=4, fontsize="x-small")
|
|
230
|
+
ax[1].set_title("T$_{prof}$ - Golden avg.")
|
|
231
|
+
if value.find("temp") >= 0 or value.find("_avg") >= 0:
|
|
232
|
+
ax[1].set_ylim(-Tband, Tband)
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
def compare_golden(core, golden, value):
|
|
236
|
+
"""Comapres petal core with golden average.
|
|
237
|
+
|
|
238
|
+
Args:
|
|
239
|
+
----
|
|
240
|
+
core (AnalusysResolt): The petal core
|
|
241
|
+
golden (AnalysisResult): The golden avrage
|
|
242
|
+
value (str): The name of the variable to compare
|
|
243
|
+
|
|
244
|
+
"""
|
|
245
|
+
Y = getattr(core, value)
|
|
246
|
+
gY = getattr(golden, value)
|
|
247
|
+
if value.find("path") >= 0:
|
|
248
|
+
X = core.path_length
|
|
249
|
+
gX = golden.path_length
|
|
250
|
+
|
|
251
|
+
else:
|
|
252
|
+
X = np.array([float(x) for x in range(10)])
|
|
253
|
+
gX = X
|
|
254
|
+
|
|
255
|
+
# convert to golden X
|
|
256
|
+
spln = CubicSpline(X, Y)
|
|
257
|
+
gC = np.array([spln(x) for x in gX])
|
|
258
|
+
|
|
259
|
+
# compute difference
|
|
260
|
+
band = get_acceptance_band()
|
|
261
|
+
diff = np.abs(gC-gY)
|
|
262
|
+
outsiders = np.where(diff > band)
|
|
263
|
+
mxval = np.amax(diff)
|
|
264
|
+
|
|
265
|
+
rc = mxval < band
|
|
266
|
+
return rc, mxval, len(outsiders)
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
def analyze_petal_cores(files, golden, options):
|
|
270
|
+
"""Create golden average.
|
|
271
|
+
|
|
272
|
+
Args:
|
|
273
|
+
----
|
|
274
|
+
files (list): List of input files
|
|
275
|
+
golden: the golden object
|
|
276
|
+
options: other options.
|
|
277
|
+
|
|
278
|
+
"""
|
|
279
|
+
names = get_names(files)
|
|
280
|
+
for i, ifile in enumerate(files):
|
|
281
|
+
ifile = find_file(options.folder, ifile)
|
|
282
|
+
if not ifile.exists():
|
|
283
|
+
print("+++ File {} does not exist.".format(ifile))
|
|
284
|
+
continue
|
|
285
|
+
|
|
286
|
+
alias = names[i]
|
|
287
|
+
core = IRCore.IRCore.read_json(ifile)
|
|
288
|
+
if core.aliasID is None or core.aliasID == "":
|
|
289
|
+
core.aliasID = names[i]
|
|
290
|
+
|
|
291
|
+
if core.coreID is None or core.coreID == "":
|
|
292
|
+
print("+++ File {} does not have component serial number.")
|
|
293
|
+
continue
|
|
294
|
+
|
|
295
|
+
out = [{}, {}]
|
|
296
|
+
for iside in range(2):
|
|
297
|
+
for val in ("path_temp", "sensor_avg", "sensor_std"):
|
|
298
|
+
out[iside][val] = compare_golden(core.results[iside], golden[iside], val)
|
|
299
|
+
|
|
300
|
+
dbOut = {
|
|
301
|
+
"component": core.coreID,
|
|
302
|
+
"testType": "THERMAL_EVALUATION",
|
|
303
|
+
"institution": core.institute,
|
|
304
|
+
"runNumber": "1",
|
|
305
|
+
"date": core.date,
|
|
306
|
+
"passed": True,
|
|
307
|
+
"problems": True,
|
|
308
|
+
"comments": [],
|
|
309
|
+
"defects": [],
|
|
310
|
+
"results": {}
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
if options.add_attachments:
|
|
314
|
+
golden_file = Path(options.golden).expanduser().resolve()
|
|
315
|
+
dbOut["attachments"] = [
|
|
316
|
+
{
|
|
317
|
+
"path": ifile.as_posix(),
|
|
318
|
+
"title": "Raw data (IRCore)",
|
|
319
|
+
"description": "Raw Data of the test"
|
|
320
|
+
},
|
|
321
|
+
{
|
|
322
|
+
"path": golden_file.as_posix(),
|
|
323
|
+
"title": "Golden",
|
|
324
|
+
"description": "The golden object used for this test."
|
|
325
|
+
}
|
|
326
|
+
]
|
|
327
|
+
|
|
328
|
+
for iside, side in enumerate(out):
|
|
329
|
+
for key, val in side.items():
|
|
330
|
+
if val[0]:
|
|
331
|
+
continue
|
|
332
|
+
|
|
333
|
+
if val[2] < 2:
|
|
334
|
+
dbOut["comments"].append(
|
|
335
|
+
"{} in side {}: 1 point out of acceptance band.".format(
|
|
336
|
+
key, iside)
|
|
337
|
+
)
|
|
338
|
+
else:
|
|
339
|
+
dbOut["defects"].append(
|
|
340
|
+
{"name": key,
|
|
341
|
+
"description": "{} in side {}: {} points out of acceptance band".format(key, iside, val[2]),
|
|
342
|
+
"properties": "{} > {}".format(val[1], get_acceptance_band())
|
|
343
|
+
}
|
|
344
|
+
)
|
|
345
|
+
dbOut["passed"] = (len(dbOut["defects"]) == 0)
|
|
346
|
+
dbOut["problems"] = (len(dbOut["comments"]) > 0)
|
|
347
|
+
|
|
348
|
+
if options.out is None:
|
|
349
|
+
ofile = "{}-Thermal.json".format(core.coreID)
|
|
350
|
+
else:
|
|
351
|
+
ofile = options.out
|
|
352
|
+
|
|
353
|
+
# Check if we are given an output folder
|
|
354
|
+
ofile = output_folder(options.folder, ofile)
|
|
355
|
+
with open(ofile, 'w') as fp:
|
|
356
|
+
print("writing {}".format(ofile))
|
|
357
|
+
json.dump(dbOut, fp, indent=3, cls=IRCore.NumpyArrayEncoder)
|
|
358
|
+
|
|
359
|
+
|
|
360
|
+
def analyze_IRCore(options):
|
|
361
|
+
"""Main entry."""
|
|
362
|
+
if options.create_golden:
|
|
363
|
+
golden, results = create_golden_average(options.files, options)
|
|
364
|
+
if options.out is None:
|
|
365
|
+
options.out = "out-golden.json"
|
|
366
|
+
|
|
367
|
+
ofile = output_folder(options.folder, options.out)
|
|
368
|
+
with open(ofile, 'w') as fp:
|
|
369
|
+
json.dump(golden, fp, indent=3, cls=IRCore.NumpyArrayEncoder)
|
|
370
|
+
|
|
371
|
+
show_golden_average(golden, results, "path_temp")
|
|
372
|
+
show_golden_average(golden, results, "path_spread")
|
|
373
|
+
show_golden_average(golden, results, "sensor_avg")
|
|
374
|
+
show_golden_average(golden, results, "sensor_std")
|
|
375
|
+
|
|
376
|
+
else:
|
|
377
|
+
if options.golden is None:
|
|
378
|
+
print("I need a golden file to compare with")
|
|
379
|
+
sys.exit(1)
|
|
380
|
+
|
|
381
|
+
golden_file = find_file(options.folder, options.golden)
|
|
382
|
+
if not golden_file.exists():
|
|
383
|
+
print("Golden file does not exist.")
|
|
384
|
+
sys.exit(1)
|
|
385
|
+
|
|
386
|
+
with open(golden_file, 'r') as fp:
|
|
387
|
+
J = json.load(fp)
|
|
388
|
+
|
|
389
|
+
golden = [Petal_IR_Analysis.AnalysisResult() for i in range(2)]
|
|
390
|
+
for i, Jside in enumerate(J):
|
|
391
|
+
golden[i].from_json(Jside)
|
|
392
|
+
|
|
393
|
+
analyze_petal_cores(options.files, golden, options)
|
|
394
|
+
|
|
395
|
+
plt.show()
|
|
396
|
+
|
|
397
|
+
|
|
398
|
+
if __name__ == "__main__":
|
|
399
|
+
from argparse import ArgumentParser
|
|
400
|
+
# Argument parser
|
|
401
|
+
parser = ArgumentParser()
|
|
402
|
+
parser.add_argument('files', nargs='*', help="Input files")
|
|
403
|
+
parser.add_argument("--create-golden", action="store_true", default=False, help="Draw golden average")
|
|
404
|
+
parser.add_argument("--add_attachments", action="store_true", default=False,
|
|
405
|
+
help="If true add the attachments section os DB file.")
|
|
406
|
+
parser.add_argument("--golden", default=None, help="The golden to compare width")
|
|
407
|
+
parser.add_argument("--prefix", default="golden", help="Prefix for figures")
|
|
408
|
+
parser.add_argument("--debug", action="store_true", default=False, help="Set to debug")
|
|
409
|
+
parser.add_argument("--out", default=None, help="File to store Golden.")
|
|
410
|
+
parser.add_argument("--folder", default=None, help="Folder to store output files. Superseeds folder in --out")
|
|
411
|
+
|
|
412
|
+
options = parser.parse_args()
|
|
413
|
+
if len(options.files) == 0:
|
|
414
|
+
print("I need an input file")
|
|
415
|
+
sys.exit()
|
|
416
|
+
|
|
417
|
+
analyze_IRCore(options)
|