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.

Files changed (51) hide show
  1. petal_qc/BTreport/CheckBTtests.py +321 -0
  2. petal_qc/BTreport/__init__.py +0 -0
  3. petal_qc/BTreport/bustapeReport.py +144 -0
  4. petal_qc/__init__.py +14 -0
  5. petal_qc/metrology/Cluster.py +90 -0
  6. petal_qc/metrology/DataFile.py +47 -0
  7. petal_qc/metrology/PetalMetrology.py +327 -0
  8. petal_qc/metrology/__init__.py +0 -0
  9. petal_qc/metrology/all2csv.py +57 -0
  10. petal_qc/metrology/analyze_locking_points.py +597 -0
  11. petal_qc/metrology/cold_noise.py +106 -0
  12. petal_qc/metrology/comparisonTable.py +59 -0
  13. petal_qc/metrology/convert_mitutoyo.py +175 -0
  14. petal_qc/metrology/convert_smartscope.py +145 -0
  15. petal_qc/metrology/coreMetrology.py +402 -0
  16. petal_qc/metrology/data2csv.py +63 -0
  17. petal_qc/metrology/do_Metrology.py +117 -0
  18. petal_qc/metrology/flatness4nigel.py +157 -0
  19. petal_qc/metrology/gtkutils.py +120 -0
  20. petal_qc/metrology/petal_flatness.py +353 -0
  21. petal_qc/metrology/show_data_file.py +118 -0
  22. petal_qc/metrology/testSummary.py +37 -0
  23. petal_qc/metrology/test_paralelism.py +71 -0
  24. petal_qc/thermal/CSVImage.py +69 -0
  25. petal_qc/thermal/DebugPlot.py +76 -0
  26. petal_qc/thermal/IRBFile.py +768 -0
  27. petal_qc/thermal/IRCore.py +110 -0
  28. petal_qc/thermal/IRDataGetter.py +359 -0
  29. petal_qc/thermal/IRPetal.py +1338 -0
  30. petal_qc/thermal/IRPetalParam.py +71 -0
  31. petal_qc/thermal/PetalColorMaps.py +62 -0
  32. petal_qc/thermal/Petal_IR_Analysis.py +142 -0
  33. petal_qc/thermal/PipeFit.py +598 -0
  34. petal_qc/thermal/__init__.py +0 -0
  35. petal_qc/thermal/analyze_IRCore.py +417 -0
  36. petal_qc/thermal/contours.py +378 -0
  37. petal_qc/thermal/create_IRCore.py +185 -0
  38. petal_qc/thermal/pipe_read.py +182 -0
  39. petal_qc/thermal/show_IR_petal.py +420 -0
  40. petal_qc/utils/Geometry.py +756 -0
  41. petal_qc/utils/Progress.py +182 -0
  42. petal_qc/utils/__init__.py +0 -0
  43. petal_qc/utils/all_files.py +35 -0
  44. petal_qc/utils/docx_utils.py +186 -0
  45. petal_qc/utils/fit_utils.py +188 -0
  46. petal_qc/utils/utils.py +180 -0
  47. petal_qc-0.0.0.dist-info/METADATA +29 -0
  48. petal_qc-0.0.0.dist-info/RECORD +51 -0
  49. petal_qc-0.0.0.dist-info/WHEEL +5 -0
  50. petal_qc-0.0.0.dist-info/entry_points.txt +3 -0
  51. 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()