petal-qc 0.0.14.dev1__py3-none-any.whl → 0.0.16__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/__init__.py +12 -2
- petal_qc/{test/getPetalCoreTestSummary.py → getPetalCoreTestSummary.py} +41 -6
- petal_qc/metrology/PetalMetrology.py +0 -13
- petal_qc/metrology/analyze_locking_points.py +4 -4
- petal_qc/metrology/compare_Cores.py +69 -4
- petal_qc/metrology/coreMetrology.py +0 -12
- petal_qc/metrology/do_Metrology.py +30 -16
- petal_qc/metrology/petal_flatness.py +0 -13
- petal_qc/metrology/readAVSdata.py +2 -0
- petal_qc/metrology/uploadPetalInformation.py +17 -17
- petal_qc/test/analyzeMetrologyTable.py +119 -0
- petal_qc/test/checkAVStests.py +2 -2
- petal_qc/test/createMetrologyFile.py +77 -0
- petal_qc/test/createMetrologyTable.py +87 -0
- petal_qc/test/desyModuleBow.py +126 -0
- petal_qc/test/findRawData.py +92 -0
- petal_qc/test/getAVStests.py +8 -0
- petal_qc/test/prepareDESYfiles.py +13 -2
- petal_qc/test/reportFromJSon.py +51 -0
- petal_qc/thermal/show_IR_petal.py +1 -10
- petal_qc/utils/ArgParserUtils.py +41 -0
- {petal_qc-0.0.14.dev1.dist-info → petal_qc-0.0.16.dist-info}/METADATA +4 -4
- {petal_qc-0.0.14.dev1.dist-info → petal_qc-0.0.16.dist-info}/RECORD +26 -19
- {petal_qc-0.0.14.dev1.dist-info → petal_qc-0.0.16.dist-info}/WHEEL +1 -1
- {petal_qc-0.0.14.dev1.dist-info → petal_qc-0.0.16.dist-info}/entry_points.txt +2 -0
- {petal_qc-0.0.14.dev1.dist-info → petal_qc-0.0.16.dist-info}/top_level.txt +0 -0
petal_qc/__init__.py
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"""petal_qc python module."""
|
|
2
|
-
__version__ = "0.0.
|
|
2
|
+
__version__ = "0.0.16"
|
|
3
3
|
|
|
4
4
|
|
|
5
5
|
def coreMetrology():
|
|
@@ -9,9 +9,14 @@ def coreMetrology():
|
|
|
9
9
|
|
|
10
10
|
def doMetrology():
|
|
11
11
|
"""Launches the Core metrology analysis in the command line."""
|
|
12
|
-
from .metrology.
|
|
12
|
+
from .metrology.do_Metrology import main
|
|
13
13
|
main()
|
|
14
14
|
|
|
15
|
+
def coreMetrologyTTY():
|
|
16
|
+
"""Launches the Core metrology analysis in the command line."""
|
|
17
|
+
from .metrology.do_Metrology import analyze_core_metrology
|
|
18
|
+
analyze_core_metrology()
|
|
19
|
+
|
|
15
20
|
def coreThermal():
|
|
16
21
|
"""Launches the Core thermal analysis ahd PDB script."""
|
|
17
22
|
from .thermal.coreThermal import main
|
|
@@ -43,6 +48,11 @@ def petalReceptionTests():
|
|
|
43
48
|
from .PetalReceptionTests import main
|
|
44
49
|
main()
|
|
45
50
|
|
|
51
|
+
def petalCoreTestSummary():
|
|
52
|
+
"""GND/VI tests."""
|
|
53
|
+
from .getPetalCoreTestSummary import main
|
|
54
|
+
main()
|
|
55
|
+
|
|
46
56
|
def dashBoard():
|
|
47
57
|
"""Launches the Core thermal analysis ahd PDB script."""
|
|
48
58
|
from .dashBoard import main
|
|
@@ -1,20 +1,26 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
2
|
"""Get a summery of Petal core TEsts."""
|
|
3
|
+
import json
|
|
4
|
+
import sys
|
|
5
|
+
import re
|
|
6
|
+
from argparse import ArgumentParser
|
|
3
7
|
|
|
8
|
+
|
|
9
|
+
from pathlib import Path
|
|
4
10
|
try:
|
|
5
11
|
import itkdb_gtk
|
|
6
12
|
|
|
7
13
|
except ImportError:
|
|
8
|
-
import sys
|
|
9
|
-
from pathlib import Path
|
|
10
14
|
cwd = Path(__file__).parent.parent
|
|
11
15
|
sys.path.append(cwd.as_posix())
|
|
12
16
|
|
|
13
17
|
from itkdb_gtk import ITkDBlogin, ITkDButils
|
|
14
18
|
from itkdb_gtk.dbGtkUtils import replace_in_container, DictDialog, ask_for_confirmation
|
|
19
|
+
from petal_qc.utils.ArgParserUtils import RangeListAction
|
|
15
20
|
|
|
21
|
+
r_petal_id = re.compile("PPC.([0-9]*)")
|
|
16
22
|
|
|
17
|
-
def
|
|
23
|
+
def petalCoreTest(session, options):
|
|
18
24
|
"""Main entry point."""
|
|
19
25
|
|
|
20
26
|
# find all cores
|
|
@@ -24,17 +30,25 @@ def main(session):
|
|
|
24
30
|
#"componentType": ["BT"],
|
|
25
31
|
"componentType": ["CORE_PETAL"],
|
|
26
32
|
"type": ["CORE_AVS"],
|
|
27
|
-
"currentLocation": ["IFIC"],
|
|
33
|
+
# "currentLocation": ["IFIC"],
|
|
28
34
|
},
|
|
29
35
|
"sorterList": [
|
|
30
36
|
{"key": "alternativeIdentifier", "descending": False }
|
|
31
37
|
],
|
|
32
38
|
}
|
|
39
|
+
suff = "ALL"
|
|
40
|
+
if options.institute:
|
|
41
|
+
payload["filterMap"]["currentLocation"] = options.institute
|
|
42
|
+
suff = options.institute
|
|
43
|
+
|
|
33
44
|
core_list = session.get("listComponents", json=payload)
|
|
34
45
|
core_tests = ["PETAL_METROLOGY_FRONT", "PETAL_METROLOGY_BACK", "XRAYIMAGING", "THERMAL_EVALUATION", "BTTESTING"]
|
|
35
46
|
|
|
36
47
|
do_check_stage = "AT_QC_SITE"
|
|
37
48
|
#do_check_stage = None
|
|
49
|
+
petal_id_db = {}
|
|
50
|
+
|
|
51
|
+
has_list = len(options.cores) != 0
|
|
38
52
|
|
|
39
53
|
for core in core_list:
|
|
40
54
|
SN = core["serialNumber"]
|
|
@@ -42,7 +56,16 @@ def main(session):
|
|
|
42
56
|
if "PPC" not in altid:
|
|
43
57
|
continue
|
|
44
58
|
|
|
59
|
+
R = r_petal_id.search(altid)
|
|
60
|
+
if R is None:
|
|
61
|
+
continue
|
|
45
62
|
|
|
63
|
+
pid = int(R.group(1))
|
|
64
|
+
|
|
65
|
+
if has_list and pid not in options.cores:
|
|
66
|
+
continue
|
|
67
|
+
|
|
68
|
+
petal_id_db[altid] = SN
|
|
46
69
|
location = core["currentLocation"]['code']
|
|
47
70
|
coreStage = core["currentStage"]['code']
|
|
48
71
|
if do_check_stage:
|
|
@@ -73,17 +96,29 @@ def main(session):
|
|
|
73
96
|
for D in T["defects"]:
|
|
74
97
|
print("\t{} - {}".format(D["name"], D["description"]))
|
|
75
98
|
|
|
99
|
+
with open("petal_ID_db_{}.json".format(suff), "w", encoding="utf-8") as fOut:
|
|
100
|
+
json.dump(petal_id_db, fOut, indent=3)
|
|
76
101
|
|
|
77
|
-
|
|
102
|
+
def main():
|
|
103
|
+
"""Main entry"""
|
|
104
|
+
parser = ArgumentParser()
|
|
105
|
+
parser.add_argument("--institute", default=None, help="The petal current location")
|
|
106
|
+
parser.add_argument("--cores", dest="cores", action=RangeListAction, default=[],
|
|
107
|
+
help="Create list of cores to analyze. The list is made with numbers or ranges (ch1:ch2 or ch1:ch2:step) ")
|
|
108
|
+
options = parser.parse_args()
|
|
109
|
+
|
|
78
110
|
# ITk_PB authentication
|
|
79
111
|
dlg = ITkDBlogin.ITkDBlogin()
|
|
80
112
|
session = dlg.get_client()
|
|
81
113
|
|
|
82
114
|
try:
|
|
83
|
-
|
|
115
|
+
petalCoreTest(session, options)
|
|
84
116
|
|
|
85
117
|
except Exception as E:
|
|
86
118
|
print(E)
|
|
87
119
|
|
|
88
120
|
dlg.die()
|
|
121
|
+
|
|
122
|
+
if __name__ == "__main__":
|
|
123
|
+
main()
|
|
89
124
|
|
|
@@ -45,19 +45,6 @@ def check_spec(val, nom, fraction=0.0):
|
|
|
45
45
|
rc = val <= (1+fraction)*nom
|
|
46
46
|
return rc
|
|
47
47
|
|
|
48
|
-
|
|
49
|
-
class CommaSeparatedListAction(Action):
|
|
50
|
-
"""Create a list from the comma sepparated numbers at imput."""
|
|
51
|
-
|
|
52
|
-
def __call__(self, args_parser, namespace, values, option_string=None):
|
|
53
|
-
"""The actual action."""
|
|
54
|
-
value = np.array(list(map(float, values.split(','))), dtype='float64')
|
|
55
|
-
if value.shape[0] < 3:
|
|
56
|
-
raise ValueError("{} needs a 3D vector".format(self.dest))
|
|
57
|
-
|
|
58
|
-
setattr(namespace, self.dest, value)
|
|
59
|
-
|
|
60
|
-
|
|
61
48
|
def petal_metrology(ifile, options):
|
|
62
49
|
"""Do the analysis of the petal metrology data.
|
|
63
50
|
|
|
@@ -513,12 +513,12 @@ def locking_point_positions(positions, document=None):
|
|
|
513
513
|
dPL2 = np.linalg.norm(positions[1, 0:2] - positions[4, 0:2])
|
|
514
514
|
deltaPL1 = (nPL1-dPL1)
|
|
515
515
|
deltaPL2 = (nPL2-dPL2)
|
|
516
|
-
fPL1 = "PASSED" if abs(deltaPL1) <= 0.
|
|
517
|
-
fPL2 = "PASSED" if abs(deltaPL2) <= 0.
|
|
516
|
+
fPL1 = "PASSED" if abs(deltaPL1) <= 0.075 else "FAILED"
|
|
517
|
+
fPL2 = "PASSED" if abs(deltaPL2) <= 0.075 else "FAILED"
|
|
518
518
|
|
|
519
519
|
for key, val in outDB["REL_POS_DELTA"].items():
|
|
520
520
|
deltaPL = np.linalg.norm(val)
|
|
521
|
-
fPL = "PASSED" if abs(deltaPL) <= 0.
|
|
521
|
+
fPL = "PASSED" if abs(deltaPL) <= 0.075 else "FAILED"
|
|
522
522
|
print("Distance {}: {:.3f} mm ({})".format(key, deltaPL, fPL))
|
|
523
523
|
|
|
524
524
|
if document:
|
|
@@ -559,7 +559,7 @@ def locking_point_positions(positions, document=None):
|
|
|
559
559
|
document.add_paragraph("")
|
|
560
560
|
for key, val in outDB["REL_POS_DELTA"].items():
|
|
561
561
|
deltaPL = np.linalg.norm(val)
|
|
562
|
-
fPL = "PASSED" if abs(deltaPL) <= 0.
|
|
562
|
+
fPL = "PASSED" if abs(deltaPL) <= 0.075 else "FAILED"
|
|
563
563
|
document.add_paragraph("Distance {}: {:.3f} mm ({})".format(key, deltaPL, fPL))
|
|
564
564
|
|
|
565
565
|
return outDB
|
|
@@ -2,13 +2,43 @@
|
|
|
2
2
|
"""Compare quantities."""
|
|
3
3
|
|
|
4
4
|
import sys
|
|
5
|
+
import re
|
|
6
|
+
|
|
5
7
|
import argparse
|
|
6
8
|
import glob
|
|
7
9
|
import json
|
|
10
|
+
import math
|
|
8
11
|
from pathlib import Path
|
|
9
12
|
import numpy as np
|
|
10
13
|
import matplotlib.pyplot as plt
|
|
11
14
|
|
|
15
|
+
r_petal_id = re.compile("PPC.([0-9]*)")
|
|
16
|
+
|
|
17
|
+
class PetalCoreListAction(argparse.Action):
|
|
18
|
+
"""Create a list from the comma sepparated numbers at imput."""
|
|
19
|
+
|
|
20
|
+
def __call__(self, parser, namespace, values, option_string=None):
|
|
21
|
+
"""The actual action."""
|
|
22
|
+
value = []
|
|
23
|
+
for V in values.split(','):
|
|
24
|
+
try:
|
|
25
|
+
value.append(int(V))
|
|
26
|
+
except ValueError:
|
|
27
|
+
if ':' not in V:
|
|
28
|
+
continue
|
|
29
|
+
|
|
30
|
+
items = V.split(':')
|
|
31
|
+
if len(items)==1:
|
|
32
|
+
continue
|
|
33
|
+
|
|
34
|
+
ival = list(map(int, items))
|
|
35
|
+
ival[1] += 1
|
|
36
|
+
for x in range(*ival):
|
|
37
|
+
value.append(int(x))
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
setattr(namespace, self.dest, value)
|
|
41
|
+
|
|
12
42
|
|
|
13
43
|
def get_value(data, value_path):
|
|
14
44
|
"""Get the value from the path given."""
|
|
@@ -58,12 +88,25 @@ def read_data_files(options):
|
|
|
58
88
|
front = {}
|
|
59
89
|
back = {}
|
|
60
90
|
|
|
91
|
+
has_list = len(options.cores) != 0
|
|
92
|
+
|
|
61
93
|
for fnam in options.files:
|
|
62
94
|
ifile = Path(fnam).expanduser().resolve()
|
|
63
95
|
if not ifile.exists():
|
|
64
96
|
print("File does not exist: ", fnam)
|
|
65
97
|
continue
|
|
66
98
|
|
|
99
|
+
R = r_petal_id.search(fnam)
|
|
100
|
+
if R is None:
|
|
101
|
+
continue
|
|
102
|
+
|
|
103
|
+
petal_id = R.group(0)
|
|
104
|
+
pid = int(R.group(1))
|
|
105
|
+
|
|
106
|
+
if has_list and pid not in options.cores:
|
|
107
|
+
continue
|
|
108
|
+
|
|
109
|
+
|
|
67
110
|
data = None
|
|
68
111
|
with open(ifile, 'r', encoding="UTF-8") as fp:
|
|
69
112
|
data = json.load(fp)
|
|
@@ -100,17 +143,22 @@ def draw_deltas(data, keys, fnam=None, title="Front", draw_text=True):
|
|
|
100
143
|
P = [np.zeros([nfiles, 2]),
|
|
101
144
|
np.zeros([nfiles, 2]),
|
|
102
145
|
np.zeros([nfiles, 2])]
|
|
146
|
+
D = [[],[],[]]
|
|
147
|
+
|
|
103
148
|
fig_width = 12.0
|
|
104
149
|
fig_height = 1.2*fig_width/3.0
|
|
105
150
|
fig, ax = plt.subplots(nrows=1, ncols=3, tight_layout=True, figsize=(fig_width, fig_height))
|
|
106
151
|
fig.suptitle(title)
|
|
152
|
+
figb, bx = plt.subplots(nrows=1, ncols=3, tight_layout=True, figsize=(fig_width, fig_height))
|
|
153
|
+
figb.suptitle(title)
|
|
154
|
+
|
|
107
155
|
for i in range(3):
|
|
108
156
|
LBL = [[],[],[]]
|
|
109
157
|
ax[i].set_title(keys[i])
|
|
110
158
|
ax[i].set_aspect('equal', adjustable='box')
|
|
111
|
-
ax[i].set_xlim(-
|
|
112
|
-
ax[i].set_ylim(-
|
|
113
|
-
circle = plt.Circle((0,0),
|
|
159
|
+
ax[i].set_xlim(-150, 150)
|
|
160
|
+
ax[i].set_ylim(-150, 150)
|
|
161
|
+
circle = plt.Circle((0,0), 75, color="red", alpha=0.25)
|
|
114
162
|
ax[i].add_patch(circle)
|
|
115
163
|
circle = plt.Circle((0,0), 25, color="green", alpha=0.25)
|
|
116
164
|
ax[i].add_patch(circle)
|
|
@@ -118,20 +166,34 @@ def draw_deltas(data, keys, fnam=None, title="Front", draw_text=True):
|
|
|
118
166
|
ax[i].set_xlabel("X (µm)")
|
|
119
167
|
ax[i].set_ylabel("Y (µm)")
|
|
120
168
|
ax[i].grid()
|
|
169
|
+
|
|
170
|
+
bx[i].set_title(keys[i])
|
|
171
|
+
bx[i].set_xlabel("Distance (µm)")
|
|
172
|
+
bx[i].grid()
|
|
173
|
+
|
|
121
174
|
|
|
122
175
|
for j, v in enumerate(data.items()):
|
|
123
176
|
label, values = v
|
|
124
177
|
for k in range(3):
|
|
125
178
|
ky = key_table[keys[k]]
|
|
126
|
-
|
|
179
|
+
point = 1000*np.array(values[ky])
|
|
180
|
+
P[k][j, :] = point
|
|
181
|
+
D[k].append(math.sqrt(point[0]**2+point[1]**2))
|
|
127
182
|
LBL[k].append(label.split('.')[1].lstrip('0'))
|
|
128
183
|
|
|
184
|
+
bx[i].hist(D[i], bins=15, range=(0, 150))
|
|
129
185
|
ax[i].scatter(P[i][:,0], P[i][:,1])
|
|
130
186
|
if draw_text:
|
|
131
187
|
for j in range(len(LBL[i])):
|
|
132
188
|
ax[i].text(P[i][j,0], P[i][j,1], LBL[i][j]) #, ha='center', va='top')
|
|
133
189
|
|
|
190
|
+
ofile = Path(fnam).expanduser().resolve()
|
|
191
|
+
print("* parent: ", ofile.parent)
|
|
192
|
+
print("* stem: ", ofile.stem)
|
|
193
|
+
bnam = ofile.parent / "{}-h.png".format(ofile.stem)
|
|
194
|
+
print(bnam.as_posix())
|
|
134
195
|
save_figure(fig, fnam, prefix=title)
|
|
196
|
+
save_figure(figb, bnam, prefix=title)
|
|
135
197
|
|
|
136
198
|
|
|
137
199
|
def show_positions(options):
|
|
@@ -184,6 +246,7 @@ def show_flatness(options):
|
|
|
184
246
|
a.set_ylim(0, 1.2*max(y_lim[0][1], y_lim[1][1]))
|
|
185
247
|
x_lim = a.get_xlim()
|
|
186
248
|
a.fill_between(x_lim, 0, 0.050, facecolor="darkseagreen", alpha=0.1)
|
|
249
|
+
a.fill_between(x_lim, 0.050, 0.100, facecolor="mediumseagreen", alpha=0.1)
|
|
187
250
|
if not options.no_legend:
|
|
188
251
|
a.legend(ncol=3, fontsize="x-small")
|
|
189
252
|
|
|
@@ -230,6 +293,8 @@ if __name__ == "__main__":
|
|
|
230
293
|
parser.add_argument("--out", default=None, help="File to store the figure.")
|
|
231
294
|
parser.add_argument("--no-legend", dest="no_legend", default=False, action="store_true", help="Do not draw the legend")
|
|
232
295
|
parser.add_argument("--no-show", dest="no_show", default=False, action="store_true", help="Do not show the figure")
|
|
296
|
+
parser.add_argument("--cores", dest="cores", action=PetalCoreListAction, default=[],
|
|
297
|
+
help="Create list of cores to analyze. The list is made with numbers or ranges (ch1:ch2 or ch1:ch2:step) ")
|
|
233
298
|
|
|
234
299
|
opts = parser.parse_args()
|
|
235
300
|
if len(opts.files) == 0:
|
|
@@ -18,18 +18,6 @@ from gi.repository import Gtk, GObject, Gio, GLib
|
|
|
18
18
|
|
|
19
19
|
__HELP__ = "https://petal-qc.docs.cern.ch/metrology.html"
|
|
20
20
|
|
|
21
|
-
class CommaSeparatedListAction(Action):
|
|
22
|
-
"""Create a list from the comma sepparated numbers at imput."""
|
|
23
|
-
|
|
24
|
-
def __call__(self, parser, namespace, values, option_string=None):
|
|
25
|
-
"""The actual action."""
|
|
26
|
-
value = np.array(list(map(float, values.split(','))), dtype='float64')
|
|
27
|
-
if value.shape[0] < 3:
|
|
28
|
-
raise ValueError("{} needs a 3D vector".format(self.dest))
|
|
29
|
-
|
|
30
|
-
setattr(namespace, self.dest, value)
|
|
31
|
-
|
|
32
|
-
|
|
33
21
|
class CoreMetrology(itkdb_gtk.dbGtkUtils.ITkDBWindow):
|
|
34
22
|
"""Application window."""
|
|
35
23
|
|
|
@@ -23,21 +23,8 @@ except ImportError:
|
|
|
23
23
|
sys.path.append(cwd.as_posix())
|
|
24
24
|
|
|
25
25
|
from petal_qc.utils.utils import output_folder
|
|
26
|
-
|
|
27
26
|
from petal_qc.metrology.PetalMetrology import petal_metrology
|
|
28
27
|
|
|
29
|
-
|
|
30
|
-
class CommaSeparatedListAction(Action):
|
|
31
|
-
"""Create a list from the comma sepparated numbers at imput."""
|
|
32
|
-
|
|
33
|
-
def __call__(self, parser, namespace, values, option_string=None):
|
|
34
|
-
"""The actual action."""
|
|
35
|
-
value = np.array(list(map(float, values.split(','))), dtype='float64')
|
|
36
|
-
if value.shape[0] < 3:
|
|
37
|
-
raise Exception("{} needs a 3D vector".format(self.dest))
|
|
38
|
-
|
|
39
|
-
setattr(namespace, self.dest, value)
|
|
40
|
-
|
|
41
28
|
def do_analysis(fnam, prefix, SN, options):
|
|
42
29
|
"""Perform analysis of a file.
|
|
43
30
|
|
|
@@ -68,6 +55,7 @@ def do_analysis(fnam, prefix, SN, options):
|
|
|
68
55
|
|
|
69
56
|
def analyze_files(ifile, options):
|
|
70
57
|
"""Main entry."""
|
|
58
|
+
failed_files = []
|
|
71
59
|
with open(ifile, 'r', encoding='UTF-8') as inp:
|
|
72
60
|
|
|
73
61
|
for line in inp:
|
|
@@ -84,10 +72,26 @@ def analyze_files(ifile, options):
|
|
|
84
72
|
except Exception:
|
|
85
73
|
fnam, prefix, SN, *_ = line.split()
|
|
86
74
|
|
|
87
|
-
|
|
75
|
+
try:
|
|
76
|
+
with open(fnam, "r", encoding="ISO-8859-1") as fin:
|
|
77
|
+
ss = fin.read()
|
|
78
|
+
if ss.find("Punto:")<0:
|
|
79
|
+
options.desy=True
|
|
80
|
+
else:
|
|
81
|
+
options.desy=False
|
|
82
|
+
|
|
83
|
+
do_analysis(fnam, prefix, SN, options)
|
|
84
|
+
print("\n\n")
|
|
85
|
+
except Exception as E:
|
|
86
|
+
failed_files.append([fnam, E])
|
|
87
|
+
continue
|
|
88
|
+
|
|
89
|
+
if len(failed_files)>0:
|
|
90
|
+
for fnam, E in failed_files:
|
|
91
|
+
print("### Failed file {}\n{}".format(fnam, E))
|
|
88
92
|
|
|
89
|
-
def
|
|
90
|
-
"
|
|
93
|
+
def parse_options():
|
|
94
|
+
"""Parse command line options."""
|
|
91
95
|
parser = ArgumentParser()
|
|
92
96
|
parser.add_argument('files', nargs='*', help="Input files")
|
|
93
97
|
parser.add_argument("--prefix", dest='prefix', default=None, help="prefix telling if it is front or back.")
|
|
@@ -113,11 +117,21 @@ def main():
|
|
|
113
117
|
print("I need an input file")
|
|
114
118
|
sys.exit()
|
|
115
119
|
|
|
120
|
+
return options
|
|
121
|
+
|
|
122
|
+
def main():
|
|
123
|
+
"Main entry."
|
|
124
|
+
options = parse_options()
|
|
116
125
|
try:
|
|
117
126
|
analyze_files(options.files[0], options)
|
|
118
127
|
|
|
119
128
|
except Exception:
|
|
120
129
|
print(traceback.format_exc())
|
|
121
130
|
|
|
131
|
+
def analyze_core_metrology():
|
|
132
|
+
"""Do a single file analysis."""
|
|
133
|
+
options = parse_options()
|
|
134
|
+
do_analysis(options.files[0], options.prefix, options.SN, options)
|
|
135
|
+
|
|
122
136
|
if __name__ == "__main__":
|
|
123
137
|
main()
|
|
@@ -31,19 +31,6 @@ from .show_data_file import show_data, TOP_VIEW
|
|
|
31
31
|
|
|
32
32
|
figure_width = 14
|
|
33
33
|
|
|
34
|
-
|
|
35
|
-
class CommaSeparatedListAction(Action):
|
|
36
|
-
"""Create a list from the comma sepparated numbers at imput."""
|
|
37
|
-
|
|
38
|
-
def __call__(self, parser, namespace, values, option_string=None):
|
|
39
|
-
"""The actual action."""
|
|
40
|
-
value = np.array(list(map(float, values.split(','))), dtype='float64')
|
|
41
|
-
if value.shape[0] < 3:
|
|
42
|
-
raise Exception("{} needs a 3D vector".format(self.dest))
|
|
43
|
-
|
|
44
|
-
setattr(namespace, self.dest, value)
|
|
45
|
-
|
|
46
|
-
|
|
47
34
|
def plot_sensor(Spoints, ax, marker='o', cmap='magma'):
|
|
48
35
|
"""Plot the points given in a scatter plot."""
|
|
49
36
|
ax.scatter(Spoints[:, 0], Spoints[:, 1], Spoints[:, 2],
|
|
@@ -696,6 +696,8 @@ def readProductionSheet(session, file_path, SN):
|
|
|
696
696
|
manufacturing["results"]["LOCATOR_B"] = sheet["{}{}".format(id_col, i_items+3)].value
|
|
697
697
|
manufacturing["results"]["LOCATOR_C"] = sheet["{}{}".format(id_col, i_items+4)].value
|
|
698
698
|
manufacturing["results"]["HONEYCOMBSET"] = split_comp_list( sheet["{}{}".format(id_col, i_items+5)].value)
|
|
699
|
+
manufacturing["results"]["HONEYCOMBSET"] = [ str(x) for x in manufacturing["results"]["HONEYCOMBSET"]]
|
|
700
|
+
|
|
699
701
|
manufacturing["results"]["EPOXY_ADHESIVE"] = split_comp_list(sheet["{}{}".format(id_col, i_items+8)].value)
|
|
700
702
|
manufacturing["results"]["EPOXY_PUTTY"] = split_comp_list( sheet["{}{}".format(id_col, i_items+9)].value)
|
|
701
703
|
manufacturing["results"]["EPOXY_CONDUCTIVE"] = split_comp_list( sheet["{}{}".format(id_col, i_items+10)].value)
|
|
@@ -537,6 +537,23 @@ class AVSPanel(dbGtkUtils.ITkDBWindow):
|
|
|
537
537
|
if self.petal_core is None:
|
|
538
538
|
return
|
|
539
539
|
|
|
540
|
+
this_petal = self.SN.get_text()
|
|
541
|
+
# Check for HonneyComb set
|
|
542
|
+
for P in self.petal_core["properties"]:
|
|
543
|
+
if P["code"] == "HC_ID" and P["value"] is None:
|
|
544
|
+
if dbGtkUtils.is_iterable(components["HoneyCombSet"]):
|
|
545
|
+
val = ','.join([str(x) for x in components["HoneyCombSet"]])
|
|
546
|
+
else:
|
|
547
|
+
val = str(components["HoneyCombSet"])
|
|
548
|
+
rc = ITkDButils.set_component_property(self.session,
|
|
549
|
+
this_petal,
|
|
550
|
+
"HC_ID",
|
|
551
|
+
val)
|
|
552
|
+
if rc is None:
|
|
553
|
+
error_txt.append("Problems setting HoneyCombSet ID.\n")
|
|
554
|
+
|
|
555
|
+
break
|
|
556
|
+
|
|
540
557
|
comp_map = {
|
|
541
558
|
"BT_PETAL_FRONT": "FacingFront",
|
|
542
559
|
"BT_PETAL_BACK": "FacingBack",
|
|
@@ -565,7 +582,6 @@ class AVSPanel(dbGtkUtils.ITkDBWindow):
|
|
|
565
582
|
error_txt = []
|
|
566
583
|
txt = "Click OK to add\n\t{}".format("\n\t".join(missing))
|
|
567
584
|
if dbGtkUtils.ask_for_confirmation("Missing components", txt, parent=self):
|
|
568
|
-
this_petal = self.SN.get_text()
|
|
569
585
|
for cmp in missing:
|
|
570
586
|
SN = components[comp_map[cmp]]
|
|
571
587
|
if SN[0:5] == "20USE":
|
|
@@ -582,22 +598,6 @@ class AVSPanel(dbGtkUtils.ITkDBWindow):
|
|
|
582
598
|
if rc is None:
|
|
583
599
|
print("Could not set final stage of {} [{}]".format(ctype, SN))
|
|
584
600
|
|
|
585
|
-
# Check for HonneyComb set
|
|
586
|
-
for P in self.petal_core["properties"]:
|
|
587
|
-
if P["code"] == "HC_ID" and P["value"] is None:
|
|
588
|
-
if dbGtkUtils.is_iterable(components["HoneyCombSet"]):
|
|
589
|
-
val = ' '.join(components["HoneyCombSet"])
|
|
590
|
-
else:
|
|
591
|
-
val = str(components["HoneyCombSet"])
|
|
592
|
-
rc = ITkDButils.set_component_property(self.session,
|
|
593
|
-
this_petal,
|
|
594
|
-
"HC_ID",
|
|
595
|
-
val)
|
|
596
|
-
if rc is None:
|
|
597
|
-
error_txt.append("Problems setting HoneyCombSet ID.\n")
|
|
598
|
-
|
|
599
|
-
break
|
|
600
|
-
|
|
601
601
|
# Check the final stage of the assembled objects
|
|
602
602
|
# for child in self.petal_core["children"]:
|
|
603
603
|
# if child["component"]:
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Analyze the table generated by createMetrologyTable."""
|
|
3
|
+
|
|
4
|
+
import sys
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
import math
|
|
7
|
+
import argparse
|
|
8
|
+
import pandas as pd
|
|
9
|
+
import numpy as np
|
|
10
|
+
from numpy.linalg import norm
|
|
11
|
+
import matplotlib.pyplot as plt
|
|
12
|
+
from lmfit.models import LinearModel
|
|
13
|
+
|
|
14
|
+
from petal_qc.utils.fit_utils import draw_best_fit
|
|
15
|
+
|
|
16
|
+
def distance(P1, P2, P3):
|
|
17
|
+
C = np.cross(P2-P1, P3-P1)
|
|
18
|
+
D = C/norm(P2-P1)
|
|
19
|
+
return D
|
|
20
|
+
|
|
21
|
+
def remove_outliers_indx(data, cut=2.0, debug=False):
|
|
22
|
+
"""Remove points far away form the rest.
|
|
23
|
+
|
|
24
|
+
Args:
|
|
25
|
+
----
|
|
26
|
+
data : The data
|
|
27
|
+
cut: max allowed distance
|
|
28
|
+
debug: be verbose if True.
|
|
29
|
+
|
|
30
|
+
Returns
|
|
31
|
+
-------
|
|
32
|
+
index of valid pints in data array.
|
|
33
|
+
|
|
34
|
+
"""
|
|
35
|
+
d = np.abs(data - np.median(data))
|
|
36
|
+
mdev = np.median(d)
|
|
37
|
+
s = d / (mdev if mdev else 1.)
|
|
38
|
+
indx = np.where(s < cut)[0]
|
|
39
|
+
return indx
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def main(options):
|
|
43
|
+
"""main entry."""
|
|
44
|
+
fig_width = 12.0
|
|
45
|
+
fig_height = 1.2*fig_width/3.0
|
|
46
|
+
|
|
47
|
+
T = pd.read_csv(options.files[0])
|
|
48
|
+
|
|
49
|
+
if options.mould > 0:
|
|
50
|
+
x = 1000*T.loc[T['mould'] == options.mould, 'fd_dx'].values
|
|
51
|
+
y = 1000*T.loc[T['mould'] == options.mould, 'fd_dy'].values
|
|
52
|
+
|
|
53
|
+
else:
|
|
54
|
+
x = 1000*T['fd_dx'].values
|
|
55
|
+
y = 1000*T['fd_dy'].values
|
|
56
|
+
|
|
57
|
+
fig, ax = plt.subplots(nrows=1, ncols=3, tight_layout=True, figsize=(fig_width, fig_height))
|
|
58
|
+
fig.suptitle("Relative Position FD01-FD02")
|
|
59
|
+
ax[0].set_title("FD01-FD02")
|
|
60
|
+
ax[0].set_aspect('equal', adjustable='box')
|
|
61
|
+
ax[0].set_xlim(-150, 150)
|
|
62
|
+
ax[0].set_ylim(-150, 150)
|
|
63
|
+
circle = plt.Circle((0,0), 75, color="red", alpha=0.25)
|
|
64
|
+
ax[0].add_patch(circle)
|
|
65
|
+
circle = plt.Circle((0,0), 25, color="green", alpha=0.25)
|
|
66
|
+
ax[0].add_patch(circle)
|
|
67
|
+
|
|
68
|
+
ax[0].set_xlabel("X (µm)")
|
|
69
|
+
ax[0].set_ylabel("Y (µm)")
|
|
70
|
+
ax[0].grid()
|
|
71
|
+
|
|
72
|
+
ax[0].scatter(x, y, marker='.')
|
|
73
|
+
|
|
74
|
+
model = LinearModel()
|
|
75
|
+
params = model.guess(y, x=x)
|
|
76
|
+
result = model.fit(y, params, x=x)
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
P1 = np.array([0, result.eval(x=0)])
|
|
80
|
+
P2 = np.array([1, result.eval(x=1)])
|
|
81
|
+
values = []
|
|
82
|
+
for v, w in zip(x, y):
|
|
83
|
+
P3 = np.array([v, w])
|
|
84
|
+
values.append(distance(P1, P2, P3))
|
|
85
|
+
|
|
86
|
+
indx = remove_outliers_indx(values)
|
|
87
|
+
|
|
88
|
+
xx = x[indx]
|
|
89
|
+
yy = y[indx]
|
|
90
|
+
params = model.guess(yy, xx)
|
|
91
|
+
result = model.fit(yy, params, x=xx)
|
|
92
|
+
result.plot_fit(ax=ax[0])
|
|
93
|
+
print("slope {:.5f}, intercept {:.5f}".format(result.best_values['slope'], result.best_values["intercept"]))
|
|
94
|
+
angle = 180*math.atan( result.best_values['slope'])/math.pi
|
|
95
|
+
print("angle {:.5f} deg.".format(angle))
|
|
96
|
+
|
|
97
|
+
ax[1].set_xlim(-150, 150)
|
|
98
|
+
ax[1].set_xlabel("X (µm)")
|
|
99
|
+
ax[1].grid()
|
|
100
|
+
ax[1].hist(x)
|
|
101
|
+
|
|
102
|
+
ax[2].set_xlim(-150, 150)
|
|
103
|
+
ax[2].set_xlabel("Y (µm)")
|
|
104
|
+
ax[2].grid()
|
|
105
|
+
ax[2].hist(y)
|
|
106
|
+
|
|
107
|
+
plt.show()
|
|
108
|
+
|
|
109
|
+
if __name__ == "__main__":
|
|
110
|
+
parser = argparse.ArgumentParser()
|
|
111
|
+
parser.add_argument('files', nargs='*', help="Input files")
|
|
112
|
+
parser.add_argument('--mould', default=-1, type=int, help="mould index")
|
|
113
|
+
|
|
114
|
+
opts = parser.parse_args()
|
|
115
|
+
if len(opts.files) == 0:
|
|
116
|
+
print("I need at least one input file")
|
|
117
|
+
sys.exit()
|
|
118
|
+
|
|
119
|
+
main(opts)
|
petal_qc/test/checkAVStests.py
CHANGED
|
@@ -169,8 +169,8 @@ if __name__ == "__main__":
|
|
|
169
169
|
client = dlg.get_client()
|
|
170
170
|
|
|
171
171
|
try:
|
|
172
|
-
|
|
173
|
-
the_test = analyze_avs_metrology(client, "20USEBC1000124", "PPC.015")
|
|
172
|
+
main(client)
|
|
173
|
+
# the_test = analyze_avs_metrology(client, "20USEBC1000124", "PPC.015")
|
|
174
174
|
#rc = ITkDButils.upload_test(client, the_test, check_runNumber=True)
|
|
175
175
|
#if rc:
|
|
176
176
|
# print(rc)
|