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,182 @@
1
+ #!/usr/bin/env python3
2
+ """An object usefull to show the progress of a process."""
3
+ import sys
4
+ import time
5
+
6
+
7
+ class GTimer(object):
8
+ """A timer."""
9
+
10
+ def __init__(self, do_start=False):
11
+ """Initialization.
12
+
13
+ Args:
14
+ ----
15
+ do_start: If True, start the timer. Defaults to False.
16
+
17
+ """
18
+ self._start = time.time()
19
+ self._running = True
20
+ self._end = self._start
21
+ self._mark = self._start
22
+ if do_start:
23
+ self.start()
24
+
25
+ def mark(self):
26
+ """Time since last mark."""
27
+ return time.time() - self._mark
28
+
29
+ def set_mark(self):
30
+ """Sets a time mark."""
31
+ self._mark = time.time()
32
+
33
+ def start(self):
34
+ """Start the timer."""
35
+ self._running = True
36
+ self._start = time.time()
37
+
38
+ def stop(self):
39
+ """Stop the timer."""
40
+ self._end = time.time()
41
+ self._running = False
42
+ return self._end - self._start
43
+
44
+ def reset(self):
45
+ """Reset the timer."""
46
+ self._start = time.time()
47
+
48
+ def __call__(self):
49
+ """Get elapsed time since start."""
50
+ if self._running:
51
+ return time.time() - self._start
52
+ else:
53
+ return self._end - self._start
54
+
55
+
56
+ def rate_units(r):
57
+ """Return the rate as a string with proper unitns."""
58
+ units = "Hz"
59
+ if r > 1.0e6:
60
+ r /= 1.0e6
61
+ units = "MHz"
62
+
63
+ elif r > 1.0e3:
64
+ r /= 1.0e3
65
+ units = "kHz"
66
+
67
+ elif r > 1.0:
68
+ pass
69
+
70
+ elif r > 1e-3:
71
+ r /= 1.0e-3
72
+ units = "mHz"
73
+
74
+ else:
75
+ r /= 1.0e-6
76
+ units = "uHz"
77
+
78
+ return r, units
79
+
80
+
81
+ def time_units(t):
82
+ """Return time as string with proper units."""
83
+ units = "s"
84
+ if t > 86400.0:
85
+ t /= 86400.0
86
+ units = "d "
87
+
88
+ elif t > 3600.0:
89
+ t /= 3600.0
90
+ units = "h "
91
+
92
+ elif t > 60.0:
93
+ t /= 60.0
94
+ units = "m "
95
+
96
+ elif t > 1.0:
97
+ units = "s "
98
+
99
+ elif t > 1.0e-3:
100
+ t /= 1.0e-3
101
+ units = "ms"
102
+
103
+ elif t > 1.0e-6:
104
+ t /= 1.0e-6
105
+ units = "us"
106
+
107
+ else:
108
+ t /= 1.0e-9
109
+ units = "ns"
110
+
111
+ return t, units
112
+
113
+
114
+ class ShowProgress(object):
115
+ """Shows the program status based on a counter."""
116
+
117
+ def __init__(self, max_val, width=40):
118
+ """Initialization.
119
+
120
+ Args:
121
+ ----
122
+ max_val: Max value
123
+ width (optional): The width of the message string.
124
+
125
+ """
126
+ self.width = width-2
127
+ self.timer = GTimer()
128
+ self.counter = 0.0
129
+ self.max_val = float(max_val)
130
+ self.prg = 0.0
131
+
132
+ def start(self):
133
+ """Start the process monitor."""
134
+ self.counter = 0
135
+ self.timer.start()
136
+
137
+ def stop(self):
138
+ """Stop th eprocess monitor."""
139
+ self.timer.stop()
140
+
141
+ def increase(self, val=1.0, show=False, interval=0.1):
142
+ """Increase the counter and show message if requested.
143
+
144
+ Args:
145
+ ----
146
+ val: Value of increment.
147
+ show: True to show the message. Defaults to False.
148
+ interval: Inerval to update message.
149
+
150
+ """
151
+ self.counter += val
152
+ self.prg = self.counter/self.max_val
153
+ if show:
154
+ if self.timer.mark() > interval:
155
+ self.timer.set_mark()
156
+ self.show()
157
+
158
+ def show(self):
159
+ """Shows message."""
160
+ self.show_stat(self.prg)
161
+
162
+ def show_stat(self, x):
163
+ """Show status of input value."""
164
+ n21 = int(x*self.width)
165
+ n22 = int(self.width-n21-1)
166
+
167
+ c21 = n21*'='
168
+ c22 = n22*' '
169
+ if self.prg > 0.0:
170
+ tt = self.timer()*(1.0/self.prg-1.0)
171
+ else:
172
+ tt = 0.0
173
+
174
+ rate = self.counter/self.timer()
175
+ rv, ru = rate_units(rate)
176
+ te, teu = time_units(self.timer())
177
+ tr, tru = time_units(tt)
178
+
179
+ # ss = '\r[%s>%s] %5.1f%% %8d' % (c21 , c22, 100.*x, self.counter)
180
+ ss = '\rElapsed %4.1f %s %5.1f %s [%s>%s] %5.1f%% ERT %5.1f %s' % (te, teu, rv, ru, c21, c22, 100.*x, tr, tru)
181
+ print(ss, end='')
182
+ sys.stdout.flush()
File without changes
@@ -0,0 +1,35 @@
1
+ """method to get all files in a folder matching the given name."""
2
+ import os
3
+ import fnmatch
4
+ from pathlib import Path
5
+
6
+
7
+ def all_files(root, patterns='*', single_level=False, yield_folders=False):
8
+ """A generator that reruns all files in the given folder.
9
+
10
+ Args:
11
+ ----
12
+ root (file path): The folder
13
+ patterns (str, optional): The pattern of the files. Defaults to '*'.
14
+ single_level (bool, optional): If true, do not go into sub folders. Defaults to False.
15
+ yield_folders (bool, optional): If True, return folders as well. Defaults to False.
16
+
17
+ Yields
18
+ ------
19
+ str: file path name
20
+
21
+ """
22
+ patterns = patterns.split(';')
23
+ for path, subdirs, files in os.walk(root):
24
+ if yield_folders:
25
+ files.extend(subdirs)
26
+
27
+ files.sort()
28
+ for name in files:
29
+ for pattern in patterns:
30
+ if fnmatch.fnmatch(name, pattern):
31
+ yield Path(os.path.join(path, name))
32
+ break
33
+
34
+ if single_level:
35
+ break
@@ -0,0 +1,186 @@
1
+ #!/usr/bin/env python3
2
+ """Set of utilities to use wit hpython-docx."""
3
+ import os
4
+ import tempfile
5
+
6
+ import docx
7
+ from docx.enum.text import WD_ALIGN_PARAGRAPH
8
+ from docx.enum.text import WD_PARAGRAPH_ALIGNMENT
9
+ from docx.oxml import ns
10
+ from docx.oxml import OxmlElement
11
+ from docx.oxml import parse_xml
12
+ from docx.shared import Cm
13
+
14
+
15
+ def create_element(name):
16
+ """Create a new XML element."""
17
+ return OxmlElement(name)
18
+
19
+
20
+ def create_attribute(element, name, value):
21
+ """Create an attribute."""
22
+ element.set(ns.qn(name), value)
23
+
24
+
25
+ def add_page_number(paragraph):
26
+ """Add page number."""
27
+ paragraph.alignment = WD_PARAGRAPH_ALIGNMENT.CENTER
28
+
29
+ page_run = paragraph.add_run()
30
+ t1 = create_element('w:t')
31
+ create_attribute(t1, 'xml:space', 'preserve')
32
+ t1.text = 'Page '
33
+ page_run._r.append(t1)
34
+
35
+ page_num_run = paragraph.add_run()
36
+
37
+ fldChar1 = create_element('w:fldChar')
38
+ create_attribute(fldChar1, 'w:fldCharType', 'begin')
39
+
40
+ instrText = create_element('w:instrText')
41
+ create_attribute(instrText, 'xml:space', 'preserve')
42
+ instrText.text = "PAGE"
43
+
44
+ fldChar2 = create_element('w:fldChar')
45
+ create_attribute(fldChar2, 'w:fldCharType', 'end')
46
+
47
+ page_num_run._r.append(fldChar1)
48
+ page_num_run._r.append(instrText)
49
+ page_num_run._r.append(fldChar2)
50
+
51
+ of_run = paragraph.add_run()
52
+ t2 = create_element('w:t')
53
+ create_attribute(t2, 'xml:space', 'preserve')
54
+ t2.text = ' of '
55
+ of_run._r.append(t2)
56
+
57
+ fldChar3 = create_element('w:fldChar')
58
+ create_attribute(fldChar3, 'w:fldCharType', 'begin')
59
+
60
+ instrText2 = create_element('w:instrText')
61
+ create_attribute(instrText2, 'xml:space', 'preserve')
62
+ instrText2.text = "NUMPAGES"
63
+
64
+ fldChar4 = create_element('w:fldChar')
65
+ create_attribute(fldChar4, 'w:fldCharType', 'end')
66
+
67
+ num_pages_run = paragraph.add_run()
68
+ num_pages_run._r.append(fldChar3)
69
+ num_pages_run._r.append(instrText2)
70
+ num_pages_run._r.append(fldChar4)
71
+
72
+
73
+ def paragraph_align_center():
74
+ """Align center."""
75
+ return WD_ALIGN_PARAGRAPH.CENTER
76
+
77
+
78
+ class Document(object):
79
+ """Create a document."""
80
+
81
+ def __init__(self):
82
+ """Initialize."""
83
+ self.doc = docx.Document()
84
+ self.doc_fign = 1
85
+ self.doc_tbln = 1
86
+
87
+ def __getattr__(self, __name):
88
+ """Call docx.document.Document stuff."""
89
+ try:
90
+ return getattr(self.doc, __name)
91
+
92
+ except Exception:
93
+ return object.__getattribute__(self, __name)
94
+
95
+ def add_page_numbers(self):
96
+ """Add page numbers."""
97
+ add_page_number(self.doc.sections[0].footer.paragraphs[0])
98
+
99
+ def add_picture(self, fig, center=True, size=10, caption=None):
100
+ """Add a picture in the document.
101
+
102
+ Args:
103
+ ----
104
+ doc: the document
105
+ fig : The matplotlib figure
106
+ center (bool, optional): If picture will be centerd. Defaults to True.
107
+ size (int, optional): Size of picture in cm. Defaults to 10.
108
+ caption (str, optional): The text of the caption. Defaults to None.
109
+
110
+ Returns
111
+ -------
112
+ Index of Figure if caption is True, otherwise -1.
113
+
114
+ """
115
+ png_file = tempfile.NamedTemporaryFile(suffix=".png", delete=False)
116
+ fig.savefig(png_file, dpi=300)
117
+ png_file.close()
118
+ P = self.add_paragraph()
119
+ if center:
120
+ P.alignment = WD_ALIGN_PARAGRAPH.CENTER
121
+
122
+ P.add_run().add_picture(png_file.name, width=Cm(size))
123
+ rc = -1
124
+ if caption:
125
+ P = self.add_paragraph()
126
+ R = P.add_run("Figure ")
127
+
128
+ p = R.element # this is the actual lxml element for a paragraph
129
+ fld_xml = r"""<w:fldSimple %s w:instr="SEQ Figure \* ARABIC ">
130
+ <w:r><w:rPr>
131
+ <w:noProof/>
132
+ </w:rPr>
133
+ <w:t>%d</w:t>
134
+ </w:r></w:fldSimple>""" % (ns.nsdecls('w'), self.doc_fign)
135
+ rc = self.doc_fign
136
+ self.doc_fign += 1
137
+
138
+ # fld_xml = '<w:fldSimple %s w:instr=" SEQ Figure \* ARABIC "/>' % nsdecls('w')
139
+ fldSimple = parse_xml(fld_xml)
140
+ p.addnext(fldSimple)
141
+ P.add_run(". {}".format(caption))
142
+ P.style = self.styles['Caption']
143
+ if center:
144
+ P.alignment = paragraph_align_center()
145
+
146
+ os.remove(png_file.name)
147
+ return rc
148
+
149
+ def insert_table(self, rows=1, cols=1, caption=None, center=False):
150
+ """Adds a table to the document.
151
+
152
+ Args:
153
+ ----
154
+ nrow: The number of rows in the table
155
+ ncol: The number of columns in the table
156
+ caption: The caption if not NOne. Defaults to None.
157
+ center: wheter to center the table and caption or not.
158
+
159
+ Returns
160
+ -------
161
+ The table object.
162
+
163
+ """
164
+ if caption:
165
+ P = self.add_paragraph()
166
+ R = P.add_run("Table ")
167
+
168
+ p = R.element # this is the actual lxml element for a paragraph
169
+ fld_xml = r"""<w:fldSimple %s w:instr="SEQ Table \* ARABIC ">
170
+ <w:r><w:rPr>
171
+ <w:noProof/>
172
+ </w:rPr>
173
+ <w:t>%d</w:t>
174
+ </w:r></w:fldSimple>""" % (ns.nsdecls('w'), self.doc_tbln)
175
+ self.doc_tbln += 1
176
+
177
+ # fld_xml = '<w:fldSimple %s w:instr=" SEQ Figure \* ARABIC "/>' % nsdecls('w')
178
+ fldSimple = parse_xml(fld_xml)
179
+ p.addnext(fldSimple)
180
+ P.add_run(". {}".format(caption))
181
+ P.style = self.styles['Caption']
182
+ if center:
183
+ P.alignment = paragraph_align_center()
184
+
185
+ table = self.add_table(rows=rows, cols=cols)
186
+ return table
@@ -0,0 +1,188 @@
1
+ #!/usr/bin/env python3
2
+ """A number of utils to make fits with numpy."""
3
+ import matplotlib.pyplot as plt
4
+ import numpy as np
5
+ from lmfit.models import GaussianModel
6
+ from scipy.signal import find_peaks
7
+ # from scipy.stats import moyal as landau
8
+
9
+ log2 = np.log(2)
10
+ s2pi = np.sqrt(2*np.pi)
11
+ spi = np.sqrt(np.pi)
12
+ s2 = np.sqrt(2.0)
13
+ tiny = np.finfo(np.float64).eps
14
+
15
+
16
+ def fit_gaussian(n, X, center, width=5.0, amplitude=1):
17
+ """Fit a gaussion.
18
+
19
+ Args:
20
+ ----
21
+ n: The bins
22
+ X: the bin edges
23
+ center: The center (or mean) of the gaussian.
24
+ width: the sigma estimate of the gaussion. Defaults to 5.0.
25
+ amplitude: the estimae of the amplitude. Defaults to 1.
26
+
27
+ Returns
28
+ -------
29
+ the fit result and a legend
30
+
31
+ """
32
+ model = GaussianModel()
33
+ params = model.make_params(amplitude=amplitude, center=center, sigma=width)
34
+ result = model.fit(n, params, x=X)
35
+ legend = r'$\mu$=%.3f $\sigma$=%.3f' % (result.best_values['center'], result.best_values['sigma'])
36
+ return result, legend
37
+
38
+
39
+ def create_multi_peak(peaks):
40
+ """Create a multi gaussan model.
41
+
42
+ input is an array of (amplitude, center, width) tuples
43
+ """
44
+ def create_single_peak(ipeak, center, width=5.0, amplitude=1):
45
+ """Create a single gaussian with initial values as given.
46
+
47
+ Parameter:
48
+ ipeak - label for hte peak (a decimal number)
49
+ center - center of hte peak
50
+ width - width of the peak
51
+ amplitude - amplitude of the peak
52
+
53
+ """
54
+ pref = "f{0}_".format(ipeak)
55
+ model = GaussianModel(prefix=pref)
56
+ model.set_param_hint(pref+'amplitude', value=amplitude)
57
+ model.set_param_hint(pref+'center', value=center)
58
+ model.set_param_hint(pref+'sigma', value=width)
59
+ return model
60
+
61
+ ipeak = 0
62
+ mod = None
63
+ for ampl, center, sigma in peaks:
64
+ this_mod = create_single_peak(ipeak, center, sigma, ampl)
65
+ if mod is None:
66
+ mod = this_mod
67
+ else:
68
+ mod = mod + this_mod
69
+
70
+ ipeak += 1
71
+
72
+ return mod
73
+
74
+
75
+ def fit_multi_gaus(hints, n, bins):
76
+ """Fit a a number of gaussians as defined by the hints.
77
+
78
+ Parameter:
79
+ hints: an array of (ampl, mean, sigma)
80
+ n: histogram bin contents
81
+ bins: bin limits
82
+
83
+ Returns
84
+ -------
85
+ result: The fit result object
86
+ out: an array of (mean, std) tuples, one per peak
87
+ legend: a lengend.
88
+
89
+ """
90
+ width = (bins[1] - bins[0])
91
+ X = bins[:-1] + (0.5*width)
92
+
93
+ model = create_multi_peak(hints)
94
+ if model is None:
95
+ return None, None, None
96
+
97
+ # do the fit
98
+ result = model.fit(n, x=X)
99
+ legend = r""
100
+ out = []
101
+ for i in range(len(hints)):
102
+ pref = "f{0}_".format(i)
103
+ if i:
104
+ legend += '\n'
105
+ legend += r"$\mu$={:.3f} $\sigma$={:.3f}".format(result.best_values[pref + 'center'],
106
+ result.best_values[pref + 'sigma'])
107
+
108
+ out.append((result.best_values[pref + 'center'], result.best_values[pref + 'sigma']))
109
+
110
+ return result, out, legend
111
+
112
+
113
+ def fit_peak_model(n, bins, distance=None, height=None, debug=None):
114
+ """Fit a multigaussian model from the number of peaks found.
115
+
116
+ TODO: need to compute the distance from the noise and step
117
+
118
+ Parameter:
119
+ ---------
120
+ n: histogram bin contents
121
+ bins: bin limits
122
+ distance: distance parameter find_peak
123
+ height: the cut on the peak height
124
+ debug: set to true to see extra information
125
+
126
+ Returns
127
+ -------
128
+ result: The fit result object
129
+ out: an array of (mean, std) tuples, one per peak
130
+ legend: a lengend
131
+
132
+ """
133
+ width = (bins[1] - bins[0])
134
+ ntot = np.sum(n)
135
+ thrs = 0.01*ntot
136
+ if height is not None:
137
+ thrs = height
138
+
139
+ if debug:
140
+ print("ntot:", ntot)
141
+ print("thrs:", thrs)
142
+ print("width:", width)
143
+
144
+ peaks, prop = find_peaks(n, thrs, distance=distance)
145
+ if debug:
146
+ print("== Peaks")
147
+ for peak, ampl in zip(peaks, prop['peak_heights']):
148
+ print("\t height {:.3f} peak {:.3f} width {:.3f}".format(ampl, bins[peak], width))
149
+
150
+ hints = []
151
+ for peak, ampl in zip(peaks, prop['peak_heights']):
152
+ hints.append((ampl, bins[peak], width))
153
+
154
+ return fit_multi_gaus(hints, n, bins)
155
+
156
+
157
+ def draw_best_fit_orig(ax, result, bins, legend=None):
158
+ """Draw the best fit."""
159
+ step = 0.5 * (bins[1] - bins[0])
160
+ X = bins[:-1] + step
161
+ ax.plot(X, result.best_fit)
162
+ if legend is not None:
163
+ ax.legend([legend], loc=1)
164
+
165
+
166
+ def draw_best_fit(ax, result, bins, npts=100, legend=None, color="#fa6e1e"):
167
+ """Draw the best fit."""
168
+ X = np.linspace(bins[0], bins[:-1], num=npts)
169
+ Y = result.eval(param=result.params, x=X)
170
+ ax.plot(X, Y, color=color)
171
+ if legend is not None:
172
+ ax.legend([legend], loc=1)
173
+
174
+
175
+ if __name__ == "__main__":
176
+ nevts = 10000
177
+ fig, ax = plt.subplots(nrows=1, ncols=2)
178
+
179
+ # Double peak gauss
180
+ peak1 = np.random.default_rng().normal(10.0, 0.5, nevts)
181
+ values = np.append(peak1, np.random.default_rng().normal(7.5, 0.75, int(0.75*nevts)))
182
+
183
+ count, bins, ignored = ax[0].hist(values, 50)
184
+ result, out, legend = fit_peak_model(count, bins, debug=True)
185
+ ax[0].legend([legend], loc=1)
186
+ draw_best_fit(ax[0], result, bins)
187
+
188
+ plt.show()