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,157 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
import time
|
|
5
|
+
from scipy.spatial import Delaunay
|
|
6
|
+
from scipy.spatial import ConvexHull
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def flatness_LSPL(M):
|
|
10
|
+
"""Compute flatness according to least squares reference plane method.
|
|
11
|
+
|
|
12
|
+
ISO/TS 12781-1
|
|
13
|
+
|
|
14
|
+
Args:
|
|
15
|
+
M (np.ndarray): The data nx3 array
|
|
16
|
+
|
|
17
|
+
Return
|
|
18
|
+
(float) - the computed flatness
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
# calculate the center of mass and translate all points
|
|
22
|
+
com = np.sum(M, axis=0) / len(M)
|
|
23
|
+
q = M - com
|
|
24
|
+
|
|
25
|
+
# calculate 3x3 matrix. The inner product returns total sum of 3x3 matrix
|
|
26
|
+
Q = np.dot(q.T, q)
|
|
27
|
+
|
|
28
|
+
# Calculate eigenvalues and eigenvectors
|
|
29
|
+
la, vectors = np.linalg.eig(Q)
|
|
30
|
+
|
|
31
|
+
# Extract the eigenvector of the minimum eigenvalue
|
|
32
|
+
n = vectors.T[np.argmin(la)]
|
|
33
|
+
|
|
34
|
+
e = np.dot(q, n)
|
|
35
|
+
|
|
36
|
+
eplus = abs(np.amax(e[np.where(e > 0)]))
|
|
37
|
+
eminus = abs(np.amin(e[np.where(e < 0)]))
|
|
38
|
+
|
|
39
|
+
flatness = eplus + eminus
|
|
40
|
+
return flatness
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def flatness_conhull(M):
|
|
44
|
+
"""Compute (MZPL) flatness by convex hull algorithm.
|
|
45
|
+
|
|
46
|
+
Robust Convex Hull-based Algoritm for Straightness and Flatness
|
|
47
|
+
Determination in Coordinate Measuring (Gyula Hermann)
|
|
48
|
+
|
|
49
|
+
Args:
|
|
50
|
+
M: point array of size (npoints, ndim)
|
|
51
|
+
|
|
52
|
+
Returns
|
|
53
|
+
-------
|
|
54
|
+
flatness - the computed flatness
|
|
55
|
+
|
|
56
|
+
"""
|
|
57
|
+
X = M[:, 0]
|
|
58
|
+
Y = M[:, 1]
|
|
59
|
+
Z = M[:, 2]
|
|
60
|
+
ch = Delaunay(M).convex_hull
|
|
61
|
+
|
|
62
|
+
N = ch.shape[0]
|
|
63
|
+
max_dis_local = np.zeros([N, 1])
|
|
64
|
+
for i in range(0, N):
|
|
65
|
+
P1 = np.array([X[ch[i, 0]], Y[ch[i, 0]], Z[ch[i, 0]]])
|
|
66
|
+
P2 = np.array([X[ch[i, 1]], Y[ch[i, 1]], Z[ch[i, 1]]])
|
|
67
|
+
P3 = np.array([X[ch[i, 2]], Y[ch[i, 2]], Z[ch[i, 2]]])
|
|
68
|
+
|
|
69
|
+
normal = np.cross(P1-P2, P1-P3)
|
|
70
|
+
|
|
71
|
+
D = -normal[0] * P3[0] - normal[1] * P3[1] - normal[2] * P3[2]
|
|
72
|
+
|
|
73
|
+
plane_0 = np.array([normal[0], normal[1], normal[2], D])
|
|
74
|
+
plane = plane_0 / np.sqrt(np.sum(plane_0**2))
|
|
75
|
+
|
|
76
|
+
dis = np.abs(plane[0] * X[:] + plane[1] * Y[:] + plane[2] * Z[:] +
|
|
77
|
+
plane[3]) / np.sqrt(plane[0]**2 + plane[1]**2 + plane[2]**2)
|
|
78
|
+
|
|
79
|
+
max_dis_local[i] = np.max(dis)
|
|
80
|
+
|
|
81
|
+
return np.min(max_dis_local)
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def flatness_conhullN(M):
|
|
85
|
+
"""Compute (MZPL) flatness by convex hull algorithm.
|
|
86
|
+
|
|
87
|
+
Robust Convex Hull-based Algoritm for Straightness and Flatness
|
|
88
|
+
Determination in Coordinate Measuring (Gyula Hermann)
|
|
89
|
+
|
|
90
|
+
Args:
|
|
91
|
+
M: point array of size (npoints, ndim)
|
|
92
|
+
|
|
93
|
+
Returns
|
|
94
|
+
-------
|
|
95
|
+
flatness - the computed flatness
|
|
96
|
+
|
|
97
|
+
"""
|
|
98
|
+
X = M[:, 0]
|
|
99
|
+
Y = M[:, 1]
|
|
100
|
+
Z = M[:, 2]
|
|
101
|
+
max_dis_local = []
|
|
102
|
+
hull = ConvexHull(M, incremental=False, qhull_options=None)
|
|
103
|
+
for plane in hull.equations:
|
|
104
|
+
dis = np.abs(plane[0] * X[:] + plane[1] * Y[:] + plane[2] * Z[:] + plane[3])
|
|
105
|
+
max_dis_local.append(np.max(dis))
|
|
106
|
+
|
|
107
|
+
return np.min(max_dis_local)
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
if __name__ == "__main__":
|
|
111
|
+
import argparse
|
|
112
|
+
import sys
|
|
113
|
+
|
|
114
|
+
parser = argparse.ArgumentParser()
|
|
115
|
+
parser.add_argument('files', nargs='*', help="Input files")
|
|
116
|
+
|
|
117
|
+
options = parser.parse_args()
|
|
118
|
+
if len(options.files) == 0:
|
|
119
|
+
print(sys.argv[0])
|
|
120
|
+
print("I need an input file")
|
|
121
|
+
sys.exit()
|
|
122
|
+
|
|
123
|
+
try:
|
|
124
|
+
data = np.loadtxt(options.files[0], unpack=False, skiprows=1, delimiter=',')
|
|
125
|
+
|
|
126
|
+
except Exception as E:
|
|
127
|
+
print("Could not open input file.")
|
|
128
|
+
print(E)
|
|
129
|
+
sys.exit(1)
|
|
130
|
+
|
|
131
|
+
flatness = flatness_LSPL(data)
|
|
132
|
+
print("LSPL: {:.4f}".format(flatness))
|
|
133
|
+
|
|
134
|
+
flatness = flatness_conhull(data)
|
|
135
|
+
print("convex-hull: {:.4f}".format(flatness))
|
|
136
|
+
|
|
137
|
+
flatness = flatness_conhullN(data)
|
|
138
|
+
print("convex-hullN: {:.4f}".format(flatness))
|
|
139
|
+
|
|
140
|
+
N = 100
|
|
141
|
+
tic = time.perf_counter()
|
|
142
|
+
for i in range(N):
|
|
143
|
+
flatness = flatness_LSPL(data)
|
|
144
|
+
toc = time.perf_counter()
|
|
145
|
+
print("LSPF: {:.4f}".format((toc-tic)/N))
|
|
146
|
+
|
|
147
|
+
tic = time.perf_counter()
|
|
148
|
+
for i in range(N):
|
|
149
|
+
flatness = flatness_conhull(data)
|
|
150
|
+
toc = time.perf_counter()
|
|
151
|
+
print("Delauney: {:.4f}".format((toc-tic)/N))
|
|
152
|
+
|
|
153
|
+
tic = time.perf_counter()
|
|
154
|
+
for i in range(N):
|
|
155
|
+
flatness = flatness_conhullN(data)
|
|
156
|
+
toc = time.perf_counter()
|
|
157
|
+
print("ConHull: {:.4f}".format((toc-tic)/N))
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import time
|
|
2
|
+
import gi
|
|
3
|
+
gi.require_version("Gtk", "3.0")
|
|
4
|
+
from gi.repository import Gtk, GObject, Gio, GLib
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def complain(main_title, second_text="", parent=None):
|
|
9
|
+
"""Open an error dialog.
|
|
10
|
+
|
|
11
|
+
Args:
|
|
12
|
+
main_title: Main text in window
|
|
13
|
+
second_text: Second text
|
|
14
|
+
parent: dialog parent
|
|
15
|
+
|
|
16
|
+
"""
|
|
17
|
+
dialog = Gtk.MessageDialog(
|
|
18
|
+
transient_for=parent,
|
|
19
|
+
flags=0,
|
|
20
|
+
message_type=Gtk.MessageType.ERROR,
|
|
21
|
+
buttons=Gtk.ButtonsType.OK,
|
|
22
|
+
text=main_title,
|
|
23
|
+
)
|
|
24
|
+
dialog.format_secondary_text(second_text)
|
|
25
|
+
dialog.run()
|
|
26
|
+
dialog.destroy()
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def ask_for_confirmation(main_title, second_text, parent=None):
|
|
30
|
+
"""Ask for action cofirmation.
|
|
31
|
+
|
|
32
|
+
Args:
|
|
33
|
+
main_title: Main title in the message window
|
|
34
|
+
second_text: Secondary text in the message widow
|
|
35
|
+
parent (optional): The parent window. Defaults to None.
|
|
36
|
+
|
|
37
|
+
Return:
|
|
38
|
+
OK: True if OK button clicked.
|
|
39
|
+
|
|
40
|
+
"""
|
|
41
|
+
dialog = Gtk.MessageDialog(
|
|
42
|
+
transient_for=parent,
|
|
43
|
+
flags=0,
|
|
44
|
+
message_type=Gtk.MessageType.INFO,
|
|
45
|
+
text=main_title
|
|
46
|
+
)
|
|
47
|
+
dialog.add_buttons(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_OK, Gtk.ResponseType.OK)
|
|
48
|
+
dialog.format_secondary_text(second_text)
|
|
49
|
+
out = dialog.run()
|
|
50
|
+
dialog.destroy()
|
|
51
|
+
return (out == Gtk.ResponseType.OK)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
box.pack_start(btn, True, False, 0)
|
|
55
|
+
|
|
56
|
+
return btn
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
class MessagePanel(object):
|
|
60
|
+
"""Encapsulates a TExtView object to show messages."""
|
|
61
|
+
|
|
62
|
+
def __init__(self, size=100):
|
|
63
|
+
"""Initializarion."""
|
|
64
|
+
self.frame = None
|
|
65
|
+
self.text_view = Gtk.TextView()
|
|
66
|
+
self.textbuffer = self.text_view.get_buffer()
|
|
67
|
+
self.__create_message_panel(size)
|
|
68
|
+
|
|
69
|
+
def __create_message_panel(self, size):
|
|
70
|
+
"""Creates a message panel within a frame.
|
|
71
|
+
|
|
72
|
+
Args:
|
|
73
|
+
size: size of the panel
|
|
74
|
+
|
|
75
|
+
Returns:
|
|
76
|
+
Gtk.TextBuffer, Gtk.Frame
|
|
77
|
+
"""
|
|
78
|
+
frame = Gtk.Frame()
|
|
79
|
+
frame.set_shadow_type(Gtk.ShadowType.IN)
|
|
80
|
+
|
|
81
|
+
box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
|
|
82
|
+
box.set_size_request(-1, size)
|
|
83
|
+
frame.add(box)
|
|
84
|
+
|
|
85
|
+
# The title for the tet view
|
|
86
|
+
box.pack_start(Gtk.Label(label="Messages"), False, True, 0)
|
|
87
|
+
|
|
88
|
+
# A scroll window with the text view
|
|
89
|
+
scrolled = Gtk.ScrolledWindow()
|
|
90
|
+
scrolled.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
|
|
91
|
+
scrolled.add(self.text_view)
|
|
92
|
+
box.pack_start(scrolled, True, True, 0)
|
|
93
|
+
self.frame = frame
|
|
94
|
+
|
|
95
|
+
def scroll_to_end(self):
|
|
96
|
+
"""Scrolls text view to end."""
|
|
97
|
+
end = self.textbuffer.get_end_iter()
|
|
98
|
+
self.text_view.scroll_to_iter(end, 0, False, 0, 0)
|
|
99
|
+
|
|
100
|
+
def write_message(self, text, write_date=True):
|
|
101
|
+
"""Writes text to Text Viewer."""
|
|
102
|
+
nlines = self.textbuffer.get_line_count()
|
|
103
|
+
if nlines > 100:
|
|
104
|
+
start = self.textbuffer.get_iter_at_line(0)
|
|
105
|
+
end = self.textbuffer.get_iter_at_line(75)
|
|
106
|
+
self.textbuffer.delete(start, end)
|
|
107
|
+
|
|
108
|
+
end = self.textbuffer.get_end_iter()
|
|
109
|
+
if write_date:
|
|
110
|
+
msg = "[{}] {}".format(time.strftime("%d/%m/%y %T"), text)
|
|
111
|
+
else:
|
|
112
|
+
msg = text
|
|
113
|
+
|
|
114
|
+
self.textbuffer.insert(end, msg)
|
|
115
|
+
GLib.idle_add(self.scroll_to_end)
|
|
116
|
+
|
|
117
|
+
def write(self, txt):
|
|
118
|
+
"""A write method."""
|
|
119
|
+
self.write_message(txt, write_date=False)
|
|
120
|
+
|
|
@@ -0,0 +1,353 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Petal flatness.
|
|
3
|
+
|
|
4
|
+
This file contains the methods to produce the metrology reports of the petal
|
|
5
|
+
core metrology survey.
|
|
6
|
+
|
|
7
|
+
"""
|
|
8
|
+
import math
|
|
9
|
+
import os
|
|
10
|
+
import sys
|
|
11
|
+
import tempfile
|
|
12
|
+
import traceback
|
|
13
|
+
from argparse import Action
|
|
14
|
+
from argparse import ArgumentParser
|
|
15
|
+
|
|
16
|
+
import petal_qc.utils.docx_utils as docx_utils
|
|
17
|
+
import matplotlib.pyplot as plt
|
|
18
|
+
import numpy as np
|
|
19
|
+
|
|
20
|
+
from petal_qc.metrology import DataFile
|
|
21
|
+
from petal_qc.utils.fit_utils import draw_best_fit
|
|
22
|
+
from petal_qc.utils.fit_utils import fit_gaussian
|
|
23
|
+
from petal_qc.utils.Geometry import fit_plane
|
|
24
|
+
from petal_qc.utils.Geometry import flatness_conhull, flatness_LSPL
|
|
25
|
+
from petal_qc.utils.Geometry import project_to_plane
|
|
26
|
+
|
|
27
|
+
from .analyze_locking_points import analyze_locking_point_data, locking_point_positions
|
|
28
|
+
from .analyze_locking_points import remove_outliers
|
|
29
|
+
from .Cluster import cluster_points
|
|
30
|
+
from .show_data_file import show_data, TOP_VIEW
|
|
31
|
+
|
|
32
|
+
figure_width = 14
|
|
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
|
+
def plot_sensor(Spoints, ax, marker='o', cmap='magma'):
|
|
48
|
+
"""Plot the points given in a scatter plot."""
|
|
49
|
+
ax.scatter(Spoints[:, 0], Spoints[:, 1], Spoints[:, 2],
|
|
50
|
+
c=Spoints[:, 2], cmap=cmap, marker=marker,
|
|
51
|
+
linewidth=0.5)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def sensor_flatness(data, name="Sensor", prefix=None, nbins=50, do_fit=False, do_3d=False, save=False, document=None):
|
|
55
|
+
"""Show Sensor flatness plot.
|
|
56
|
+
|
|
57
|
+
Args:
|
|
58
|
+
----
|
|
59
|
+
data: the data array
|
|
60
|
+
name: name of the sensor
|
|
61
|
+
nbins: number of bins in histogram
|
|
62
|
+
prefix: prefix to be added to the name if not None.
|
|
63
|
+
save: Save plot if True
|
|
64
|
+
document: insert figure in document if not None.
|
|
65
|
+
|
|
66
|
+
"""
|
|
67
|
+
width = 0.0
|
|
68
|
+
ncol = 1
|
|
69
|
+
out, V, M, L = fit_plane(data)
|
|
70
|
+
Z = out[:, 2]
|
|
71
|
+
|
|
72
|
+
fig = plt.figure(figsize=[12, 6])
|
|
73
|
+
fig.suptitle(name)
|
|
74
|
+
fig.subplots_adjust(left=0.05, right=0.95)
|
|
75
|
+
if do_3d:
|
|
76
|
+
ncol = 2
|
|
77
|
+
ax = fig.add_subplot(1, 2, 1, projection='3d')
|
|
78
|
+
# ax.view_init(azim=-90, elev=90)
|
|
79
|
+
ax.set_title("plane of min Z variance")
|
|
80
|
+
surf = ax.scatter(out[:, 0], out[:, 1], Z, c=Z, marker='.', cmap=plt.cm.jet)
|
|
81
|
+
# surf = ax.plot_trisurf(out[:, 0], out[:, 1], Z, cmap=plt.cm.jet, edgecolor="black", linewidths=0.2)
|
|
82
|
+
ax.set_xlabel("X")
|
|
83
|
+
ax.set_ylabel("Y")
|
|
84
|
+
ax.set_zlabel("Z")
|
|
85
|
+
fig.colorbar(surf, shrink=0.5, aspect=5, location='left')
|
|
86
|
+
|
|
87
|
+
ax = fig.add_subplot(1, ncol, ncol)
|
|
88
|
+
n, bins, *_ = ax.hist(Z, bins=nbins)
|
|
89
|
+
if do_fit:
|
|
90
|
+
step = 0.5 * (bins[1] - bins[0])
|
|
91
|
+
X = bins[:-1] + step
|
|
92
|
+
result, legend = fit_gaussian(n, X, np.mean(Z), width=np.std(Z))
|
|
93
|
+
ax.legend([legend], loc=1)
|
|
94
|
+
draw_best_fit(ax, result, bins)
|
|
95
|
+
rms = result.best_values['sigma']
|
|
96
|
+
center = result.best_values['center']
|
|
97
|
+
v1 = center - 3.5*rms
|
|
98
|
+
v2 = center + 3.5*rms
|
|
99
|
+
width = v2 - v1
|
|
100
|
+
ax.axvspan(v1, v2, alpha=0.20, facecolor='g')
|
|
101
|
+
ax.set_title("Z dispersion: {:.3f}".format(width))
|
|
102
|
+
# plt.yscale('log')
|
|
103
|
+
print("{}: rms: {:.3f} 7xRMS {:.3f}".format(name, rms, v2-v1))
|
|
104
|
+
|
|
105
|
+
out_file = None
|
|
106
|
+
if save is True:
|
|
107
|
+
if prefix is None:
|
|
108
|
+
out_file = "{}.png".format(name)
|
|
109
|
+
else:
|
|
110
|
+
out_file = "{}-{}.png".format(prefix, name)
|
|
111
|
+
|
|
112
|
+
plt.savefig(out_file, dpi=300)
|
|
113
|
+
|
|
114
|
+
if document:
|
|
115
|
+
document.add_picture(fig, True, figure_width, caption="{} planarity.".format(name))
|
|
116
|
+
plt.close(fig)
|
|
117
|
+
|
|
118
|
+
return width
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def petal_flatness(orig_data, options, document=None):
|
|
122
|
+
"""Compute the petal flatness in the different sensor areas.
|
|
123
|
+
|
|
124
|
+
Args:
|
|
125
|
+
----
|
|
126
|
+
filename: CSV file with metrology values array([npoints, 3])
|
|
127
|
+
options: parser options (see entry)
|
|
128
|
+
document: docx document.
|
|
129
|
+
|
|
130
|
+
"""
|
|
131
|
+
# SHow raw data
|
|
132
|
+
show_petal_points(orig_data, "Original Input Data")
|
|
133
|
+
|
|
134
|
+
# Try to remove locator points and get the plane
|
|
135
|
+
indx = remove_outliers(orig_data[:, 2])
|
|
136
|
+
M, TM, avg, *_ = fit_plane(orig_data[indx], use_average=7)
|
|
137
|
+
|
|
138
|
+
# project all data to the plane
|
|
139
|
+
M = project_to_plane(orig_data, TM, [0., 0., avg[2]])
|
|
140
|
+
Zmean = np.mean(M[indx, 2])
|
|
141
|
+
M[:, 2] -= Zmean
|
|
142
|
+
Z = M[:, 2]
|
|
143
|
+
|
|
144
|
+
show_petal_points(M, "On Petal plane.")
|
|
145
|
+
|
|
146
|
+
# group points by sensors.
|
|
147
|
+
sensor_dict = {0: "R0", 10: "R1", 20: "R2", 30: "R3_0", 31: "R3_1", 40: "R4_0", 41: "R4_1", 50: "R5_0", 51: "R5_1"}
|
|
148
|
+
sensors, *_ = group_by_sensors(M, options.is_front, False)
|
|
149
|
+
all_data = np.vstack(list(sensors.values()))
|
|
150
|
+
|
|
151
|
+
fig = show_data(all_data, "All points in core", view=TOP_VIEW, surf=False)
|
|
152
|
+
|
|
153
|
+
if document:
|
|
154
|
+
document.add_heading('All points', level=1)
|
|
155
|
+
document.add_picture(fig, True, 14, caption="All points in Petal.")
|
|
156
|
+
plt.close(fig)
|
|
157
|
+
|
|
158
|
+
#
|
|
159
|
+
# Add the tables to the document
|
|
160
|
+
#
|
|
161
|
+
# flatness_func = flatness_conhull
|
|
162
|
+
flatness_func = flatness_LSPL
|
|
163
|
+
F = {}
|
|
164
|
+
for key, val in sensors.items():
|
|
165
|
+
F[key] = flatness_func(val)
|
|
166
|
+
|
|
167
|
+
flatness_all_sensor_area = flatness_func(all_data)
|
|
168
|
+
|
|
169
|
+
outF = [flatness_all_sensor_area, ]
|
|
170
|
+
print("Is front ? {}".format(options.is_front))
|
|
171
|
+
print("Flatness:")
|
|
172
|
+
for i in range(6):
|
|
173
|
+
if i < 3:
|
|
174
|
+
id = 10*i
|
|
175
|
+
lbl = sensor_dict[id]
|
|
176
|
+
print("{}: {:.3f}".format(lbl, F[id]))
|
|
177
|
+
outF.append(F[id])
|
|
178
|
+
else:
|
|
179
|
+
ids = [10*i, 10*i+1]
|
|
180
|
+
lbls = [sensor_dict[i] for i in ids]
|
|
181
|
+
values = [F[id] for id in ids]
|
|
182
|
+
outF.extend(values)
|
|
183
|
+
print("{}: {:.3f} {}: {:.3f}".format(lbls[0], values[0], lbls[1], values[1]))
|
|
184
|
+
|
|
185
|
+
print("All sensor area: {:.3f}".format(flatness_all_sensor_area))
|
|
186
|
+
|
|
187
|
+
# Add table in document
|
|
188
|
+
if document:
|
|
189
|
+
document.add_heading('Petal flatness (LSPL)', level=1)
|
|
190
|
+
table = document.insert_table(rows=1, cols=3, caption="Flatness (LSPL)")
|
|
191
|
+
table.style = document.styles['Table Grid']
|
|
192
|
+
|
|
193
|
+
# populate header row --------
|
|
194
|
+
heading_cells = table.rows[0].cells
|
|
195
|
+
heading_cells[0].text = ""
|
|
196
|
+
heading_cells[1].text = "Flatness (µm)"
|
|
197
|
+
a = table.cell(0, 1)
|
|
198
|
+
b = table.cell(0, 2)
|
|
199
|
+
A = a.merge(b)
|
|
200
|
+
|
|
201
|
+
heading_cells = table.add_row().cells
|
|
202
|
+
heading_cells[0].text = "Area"
|
|
203
|
+
heading_cells[1].text = "S0"
|
|
204
|
+
heading_cells[2].text = "S1"
|
|
205
|
+
|
|
206
|
+
for i in range(6):
|
|
207
|
+
cell = table.add_row().cells
|
|
208
|
+
cell[0].text = "R{}".format(i)
|
|
209
|
+
cell[1].text = "{:.4f}".format(F[10*i]*1000)
|
|
210
|
+
if i > 2:
|
|
211
|
+
cell[2].text = "{:.4f}".format(F[10*i+1]*1000)
|
|
212
|
+
|
|
213
|
+
# add allsensor area
|
|
214
|
+
cell = table.add_row().cells
|
|
215
|
+
cell[0].text = "All sensor area"
|
|
216
|
+
cell[1].text = "{:.4f}".format(flatness_all_sensor_area)
|
|
217
|
+
|
|
218
|
+
return TM, avg, Zmean, outF
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
def show_petal_points(orig_data, title):
|
|
222
|
+
"""Show the given points."""
|
|
223
|
+
fig = plt.figure(figsize=[5, 5])
|
|
224
|
+
fig.suptitle(title)
|
|
225
|
+
ax = fig.add_subplot(2, 1, 1, projection='3d')
|
|
226
|
+
ax.view_init(azim=-90, elev=90)
|
|
227
|
+
Z = orig_data[:, 2]
|
|
228
|
+
ax.scatter(orig_data[:, 0], orig_data[:, 1], Z, c=Z, cmap='viridis', linewidth=0.5)
|
|
229
|
+
ax = fig.add_subplot(2, 1, 2)
|
|
230
|
+
n, bins, *_ = ax.hist(Z, bins=100)
|
|
231
|
+
plt.yscale('log')
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
sensorR = (
|
|
235
|
+
(384.5, 488.423), (489.823, 574.194), (575.594, 637.209),
|
|
236
|
+
(638.609, 755.501), (756.901, 866.062), (867.462, 967.785)
|
|
237
|
+
)
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
def get_iring(P, is_front):
|
|
241
|
+
"""REturn ring number
|
|
242
|
+
|
|
243
|
+
Args:
|
|
244
|
+
----
|
|
245
|
+
P (3D point): A 3D point o nthe petal surface
|
|
246
|
+
is_front: True if front side. Otehrwse false.
|
|
247
|
+
|
|
248
|
+
Returns:
|
|
249
|
+
int: The ring (10*iring + side)
|
|
250
|
+
|
|
251
|
+
"""
|
|
252
|
+
R = np.sqrt(np.sum(P[0:2]**2))
|
|
253
|
+
i = 0
|
|
254
|
+
for ri, ro in sensorR:
|
|
255
|
+
if ri <= R and R <= ro:
|
|
256
|
+
if i < 3:
|
|
257
|
+
side = 0
|
|
258
|
+
else:
|
|
259
|
+
side = 0 if P[0] > 0 else 1
|
|
260
|
+
|
|
261
|
+
return 10*i + side
|
|
262
|
+
|
|
263
|
+
i = i + 1
|
|
264
|
+
|
|
265
|
+
return -1
|
|
266
|
+
|
|
267
|
+
|
|
268
|
+
def group_by_sensors(Min, is_front=True, remove_outliers=False):
|
|
269
|
+
"""Groups data points by sensors."""
|
|
270
|
+
# Now move in Y to be on the ATLAS reference
|
|
271
|
+
M = np.array(Min)
|
|
272
|
+
M[:, 1] = M[:, 1] + 382
|
|
273
|
+
|
|
274
|
+
other = []
|
|
275
|
+
sensors = {}
|
|
276
|
+
|
|
277
|
+
for i in range(0, M.shape[0]):
|
|
278
|
+
P = M[i, :]
|
|
279
|
+
iring = get_iring(P, is_front)
|
|
280
|
+
if iring < 0:
|
|
281
|
+
other.append(P)
|
|
282
|
+
|
|
283
|
+
else:
|
|
284
|
+
sensors.setdefault(iring, []).append(P)
|
|
285
|
+
|
|
286
|
+
if remove_outliers:
|
|
287
|
+
for key, val in sensors.items():
|
|
288
|
+
if remove_outliers:
|
|
289
|
+
sensors[key] = remove_outliers(sensors[key][:, 2], 0.075)
|
|
290
|
+
|
|
291
|
+
return sensors, np.array(other)
|
|
292
|
+
|
|
293
|
+
|
|
294
|
+
def do_petal_flatness(filename, options):
|
|
295
|
+
"""Calls petal_flatness
|
|
296
|
+
|
|
297
|
+
Args:
|
|
298
|
+
----
|
|
299
|
+
filename (): Data file name
|
|
300
|
+
options (): Options
|
|
301
|
+
"""
|
|
302
|
+
orig_data = DataFile.read(filename, label=options.label, type=options.type)
|
|
303
|
+
if orig_data is None:
|
|
304
|
+
print("Input file not found.")
|
|
305
|
+
return
|
|
306
|
+
|
|
307
|
+
# Open the output document if a title is given in the options.
|
|
308
|
+
document = docx_utils.Document()
|
|
309
|
+
document.add_page_numbers()
|
|
310
|
+
document.styles['Normal'].font.name = "Calibri"
|
|
311
|
+
if options.title:
|
|
312
|
+
document.add_heading(options.title, 0)
|
|
313
|
+
|
|
314
|
+
petal_flatness(orig_data, options, document=document)
|
|
315
|
+
|
|
316
|
+
document.save(options.out)
|
|
317
|
+
|
|
318
|
+
|
|
319
|
+
if __name__ == "__main__":
|
|
320
|
+
parser = ArgumentParser()
|
|
321
|
+
parser.add_argument('files', nargs='*', help="Input files")
|
|
322
|
+
parser.add_argument("--prefix", dest='prefix', default=None)
|
|
323
|
+
parser.add_argument("--save", dest='save', action="store_true", default=False)
|
|
324
|
+
parser.add_argument("--front", dest='is_front', action="store_true", default=True)
|
|
325
|
+
parser.add_argument("--back", dest='is_front', action="store_false", default=True)
|
|
326
|
+
parser.add_argument("--bottom-lp", dest='bLP', action=CommaSeparatedListAction, default=None,
|
|
327
|
+
help="Bottom locking point fiducial coordinates")
|
|
328
|
+
parser.add_argument("--upper-lp", dest='uLP', action=CommaSeparatedListAction, default=None,
|
|
329
|
+
help="upper locking point fiducials coordinates")
|
|
330
|
+
parser.add_argument("--out", dest="out", default="petal_flatness.docx",
|
|
331
|
+
type=str, help="The output fiel name")
|
|
332
|
+
parser.add_argument("--title", dest="title", default=None,
|
|
333
|
+
type=str, help="Document title")
|
|
334
|
+
parser.add_argument("--nbins", dest="nbins", default=50,
|
|
335
|
+
type=int, help="Number of bins")
|
|
336
|
+
|
|
337
|
+
# This is to convert a CMM file
|
|
338
|
+
parser.add_argument("--label", default="\\w+", help="The label to select")
|
|
339
|
+
parser.add_argument("--type", default="Punto", help="The class to select")
|
|
340
|
+
|
|
341
|
+
options = parser.parse_args()
|
|
342
|
+
if len(options.files) == 0:
|
|
343
|
+
print(sys.argv[0])
|
|
344
|
+
print("I need an input file")
|
|
345
|
+
sys.exit()
|
|
346
|
+
|
|
347
|
+
try:
|
|
348
|
+
do_petal_flatness(options.files[0], options)
|
|
349
|
+
|
|
350
|
+
except Exception:
|
|
351
|
+
print(traceback.format_exc())
|
|
352
|
+
|
|
353
|
+
plt.show()
|