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,182 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Read the real pipe and create the pipe contour to compare with.
|
|
3
|
+
|
|
4
|
+
It reads PNG files produced from the petal 3D CAD model and extracts the pipe
|
|
5
|
+
path and the sensor areas. It stores all this information in files that are
|
|
6
|
+
later read by PipeFit.
|
|
7
|
+
|
|
8
|
+
To create the files one needs to run the script twice, one for the front side
|
|
9
|
+
(--front) and anther for the back side (--back).
|
|
10
|
+
|
|
11
|
+
"""
|
|
12
|
+
import random
|
|
13
|
+
import sys
|
|
14
|
+
from argparse import ArgumentParser
|
|
15
|
+
from pathlib import Path
|
|
16
|
+
|
|
17
|
+
import matplotlib.pyplot as plt
|
|
18
|
+
import numpy as np
|
|
19
|
+
import skimage
|
|
20
|
+
|
|
21
|
+
from petal_qc.thermal.contours import adjust_contour
|
|
22
|
+
from petal_qc.thermal.contours import contour_simplify
|
|
23
|
+
from petal_qc.thermal.contours import find_closest
|
|
24
|
+
|
|
25
|
+
script_path = Path(__file__).absolute().parent
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def crange(start, end, modulo):
|
|
29
|
+
"""Circular range.
|
|
30
|
+
|
|
31
|
+
Args:
|
|
32
|
+
----
|
|
33
|
+
start: Start
|
|
34
|
+
end: End
|
|
35
|
+
modulo: Max value
|
|
36
|
+
|
|
37
|
+
Yields
|
|
38
|
+
------
|
|
39
|
+
int: the following value
|
|
40
|
+
|
|
41
|
+
"""
|
|
42
|
+
if start > end:
|
|
43
|
+
while start < modulo:
|
|
44
|
+
yield start
|
|
45
|
+
start += 1
|
|
46
|
+
start = 0
|
|
47
|
+
|
|
48
|
+
while start < end:
|
|
49
|
+
yield start
|
|
50
|
+
start += 1
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def get_pipe_path(im, P1_i, P2_i, debug=False):
|
|
54
|
+
"""Find pipe path and save to file.
|
|
55
|
+
|
|
56
|
+
Given the inlet and outlet point, creates the path of the pipe.
|
|
57
|
+
|
|
58
|
+
Args:
|
|
59
|
+
----
|
|
60
|
+
im: THe image with the pipe
|
|
61
|
+
P1_i: Starting point
|
|
62
|
+
P2_i: End point
|
|
63
|
+
debug: show stuff
|
|
64
|
+
|
|
65
|
+
"""
|
|
66
|
+
contours = skimage.measure.find_contours(im)
|
|
67
|
+
pipe = adjust_contour(np.array(contours[0]))
|
|
68
|
+
|
|
69
|
+
npts = len(pipe)
|
|
70
|
+
i1, P1 = find_closest(P1_i[0], P1_i[1], pipe, True)
|
|
71
|
+
i2, P2 = find_closest(P2_i[0], P2_i[1], pipe, True)
|
|
72
|
+
|
|
73
|
+
indx = list(crange(i1, i2, npts))
|
|
74
|
+
inner = pipe[indx, :]
|
|
75
|
+
linner = len(inner)
|
|
76
|
+
|
|
77
|
+
indx = list(crange(i2, i1, npts))
|
|
78
|
+
outer = np.flipud(pipe[indx, :])
|
|
79
|
+
louter = len(outer)
|
|
80
|
+
|
|
81
|
+
if linner > louter:
|
|
82
|
+
indx = random.sample(range(0, linner), linner - louter)
|
|
83
|
+
inner = np.delete(inner, indx, 0)
|
|
84
|
+
else:
|
|
85
|
+
indx = random.sample(range(0, louter), louter - linner)
|
|
86
|
+
outer = np.delete(outer, indx, 0)
|
|
87
|
+
|
|
88
|
+
center = (inner + outer)/2.0
|
|
89
|
+
|
|
90
|
+
small_center = contour_simplify(center - P1, 0.5)
|
|
91
|
+
print("original len {}, small len {}".format(len(center), len(small_center)))
|
|
92
|
+
|
|
93
|
+
if debug:
|
|
94
|
+
fig, ax = plt.subplots(1, 2, tight_layout=True)
|
|
95
|
+
ax[0].plot(inner[:, 0], inner[:, 1])
|
|
96
|
+
ax[0].plot(outer[:, 0], outer[:, 1])
|
|
97
|
+
ax[0].plot(center[:, 0], center[:, 1])
|
|
98
|
+
ax[1].plot(center[:, 0], center[:, 1])
|
|
99
|
+
ax[1].plot(small_center[:, 0], small_center[:, 1])
|
|
100
|
+
|
|
101
|
+
return small_center, P1
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def get_sensor_area(ims, P1, debug=False):
|
|
105
|
+
"""Find sensor area."""
|
|
106
|
+
if debug:
|
|
107
|
+
fig, ax = plt.subplots(1, 1, tight_layout=True)
|
|
108
|
+
|
|
109
|
+
contours = skimage.measure.find_contours(ims)
|
|
110
|
+
|
|
111
|
+
ncontours = len(contours)
|
|
112
|
+
sensors = []
|
|
113
|
+
for i in range(ncontours):
|
|
114
|
+
sensor = adjust_contour(contours[i]) - P1
|
|
115
|
+
sensor = contour_simplify(sensor, 1)
|
|
116
|
+
sensors.append(sensor)
|
|
117
|
+
if debug:
|
|
118
|
+
ax.plot(sensor[:, 0], sensor[:, 1])
|
|
119
|
+
|
|
120
|
+
return sensors
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def main(opts):
|
|
124
|
+
"""Main entry."""
|
|
125
|
+
global script_path
|
|
126
|
+
front = opts.front
|
|
127
|
+
if opts.folder:
|
|
128
|
+
folder = Path(opts.folder).expanduser().absolute()
|
|
129
|
+
if folder.exists():
|
|
130
|
+
script_path = folder
|
|
131
|
+
else:
|
|
132
|
+
print("Folder {} does not exist.".format(opts.folder))
|
|
133
|
+
sys.exit()
|
|
134
|
+
|
|
135
|
+
if front:
|
|
136
|
+
in_file = "pipe-front.png"
|
|
137
|
+
in_sensors = "pipe-front-sensors-only.png"
|
|
138
|
+
out_file = "pipe_front.npz"
|
|
139
|
+
P1_i = [608, 817] # [602.9, 779.5] # [568.915, 768.52]
|
|
140
|
+
P2_i = [593.5, 818.7] # [588.7, 781.0] # [582.9, 766.7]
|
|
141
|
+
|
|
142
|
+
else:
|
|
143
|
+
in_file = "pipe-back.png"
|
|
144
|
+
in_sensors = "pipe-back-sensors-only.png"
|
|
145
|
+
out_file = "pipe_back.npz"
|
|
146
|
+
P1_i = [251.8, 817.9] # [256.0, 779.0]
|
|
147
|
+
P2_i = [266.1, 818.3] # [270.5, 781.2]
|
|
148
|
+
|
|
149
|
+
# Get the pipe
|
|
150
|
+
im = skimage.io.imread(script_path.joinpath(in_file), as_gray=True)
|
|
151
|
+
im = np.flipud(im)
|
|
152
|
+
|
|
153
|
+
pipe, P1 = get_pipe_path(im, P1_i, P2_i, debug=opts.debug)
|
|
154
|
+
|
|
155
|
+
# Now gethte sensors
|
|
156
|
+
ims = skimage.io.imread(script_path.joinpath(in_sensors), as_gray=True)
|
|
157
|
+
ims = np.flipud(ims)
|
|
158
|
+
|
|
159
|
+
sensors = get_sensor_area(ims, P1, debug=opts.debug)
|
|
160
|
+
|
|
161
|
+
# Save stuff
|
|
162
|
+
np.savez_compressed(out_file, pipe=pipe, *sensors)
|
|
163
|
+
|
|
164
|
+
fig, ax = plt.subplots(1, 1, tight_layout=True)
|
|
165
|
+
ax.plot(pipe[:, 0], pipe[:, 1])
|
|
166
|
+
|
|
167
|
+
for S in sensors:
|
|
168
|
+
ax.plot(S[:, 0], S[:, 1])
|
|
169
|
+
|
|
170
|
+
plt.show()
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
if __name__ == "__main__":
|
|
174
|
+
parser = ArgumentParser(description="PipeContour")
|
|
175
|
+
parser.add_argument("--folder", default=None, help="Folder to find the pictures.")
|
|
176
|
+
parser.add_argument("--front", action="store_true", dest='front', default=True, help="Front side")
|
|
177
|
+
parser.add_argument("--back", action="store_false", dest='front', help="Back side")
|
|
178
|
+
parser.add_argument("--debug", action="store_true", default=False, help="Debug.")
|
|
179
|
+
|
|
180
|
+
opts = parser.parse_args()
|
|
181
|
+
|
|
182
|
+
main(opts)
|
|
@@ -0,0 +1,420 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Do the thermal analysis of the petal core."""
|
|
3
|
+
import os
|
|
4
|
+
import subprocess
|
|
5
|
+
import sys
|
|
6
|
+
import tempfile
|
|
7
|
+
from argparse import Action
|
|
8
|
+
from argparse import ArgumentParser
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
from pathlib import PurePath
|
|
11
|
+
|
|
12
|
+
import matplotlib.pyplot as plt
|
|
13
|
+
import matplotlib.ticker as ticker
|
|
14
|
+
import numpy as np
|
|
15
|
+
from petal_qc.thermal import contours
|
|
16
|
+
from petal_qc.thermal import IRBFile
|
|
17
|
+
from petal_qc.thermal import IRPetal
|
|
18
|
+
from petal_qc.thermal import PipeFit
|
|
19
|
+
from petal_qc.thermal.Petal_IR_Analysis import AnalysisResult
|
|
20
|
+
from petal_qc.thermal.Petal_IR_Analysis import show_2D_image
|
|
21
|
+
from petal_qc.thermal.PetalColorMaps import HighContrast
|
|
22
|
+
|
|
23
|
+
import petal_qc.utils.Progress as Progress
|
|
24
|
+
import petal_qc.utils.utils as utils
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class CommaSeparatedListAction(Action):
|
|
28
|
+
"""Create a list from the comma sepparated numbers at imput."""
|
|
29
|
+
|
|
30
|
+
def __call__(self, parser, namespace, values, option_string=None):
|
|
31
|
+
"""The actual action."""
|
|
32
|
+
setattr(namespace, self.dest, list(map(int, values.split(','))))
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def get_min_max(values, step=1.0):
|
|
36
|
+
"""Return min and max.
|
|
37
|
+
|
|
38
|
+
The values are alined with step.
|
|
39
|
+
|
|
40
|
+
Args:
|
|
41
|
+
----
|
|
42
|
+
values: Array of values
|
|
43
|
+
step (optional): The step_. Defaults to 1.0.
|
|
44
|
+
|
|
45
|
+
Returns
|
|
46
|
+
-------
|
|
47
|
+
min, max.
|
|
48
|
+
|
|
49
|
+
"""
|
|
50
|
+
vmax = np.amax(values)
|
|
51
|
+
vmin = np.amin(values)
|
|
52
|
+
ivmax = round(vmax)
|
|
53
|
+
if ivmax < vmax:
|
|
54
|
+
ivmax += step
|
|
55
|
+
if abs(ivmax-vmax) < 0.25*step:
|
|
56
|
+
ivmax += step
|
|
57
|
+
|
|
58
|
+
ivmin = np.round(vmin)
|
|
59
|
+
if ivmin > vmin:
|
|
60
|
+
ivmin -= step
|
|
61
|
+
if abs(ivmin-vmin) < 0.25*step:
|
|
62
|
+
ivmin -= step
|
|
63
|
+
|
|
64
|
+
return ivmin, ivmax
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def find_ffmpeg():
|
|
68
|
+
"""Returns the path of ffmpeg."""
|
|
69
|
+
folders = os.environ['PATH'].split(':')
|
|
70
|
+
|
|
71
|
+
ffmpeg = None
|
|
72
|
+
for p in folders:
|
|
73
|
+
exe = Path(PurePath(p, "ffmpeg"))
|
|
74
|
+
if exe.exists():
|
|
75
|
+
ffmpeg = exe
|
|
76
|
+
break
|
|
77
|
+
|
|
78
|
+
if not ffmpeg:
|
|
79
|
+
raise Exception("Could not find ffmpeg")
|
|
80
|
+
|
|
81
|
+
return ffmpeg
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def create_movie(template, fout):
|
|
85
|
+
"""Creates a movie frm a set of files.
|
|
86
|
+
|
|
87
|
+
The name of the files should be passed as a template, ej.,
|
|
88
|
+
|
|
89
|
+
<dir_name>/fig%3d.png
|
|
90
|
+
|
|
91
|
+
"""
|
|
92
|
+
pout = utils.find_out_file_name(fout)
|
|
93
|
+
ffmpeg = find_ffmpeg()
|
|
94
|
+
|
|
95
|
+
try:
|
|
96
|
+
out = subprocess.run([ffmpeg, '-r', "10", '-i', template, '-c:v', "libx264", pout],
|
|
97
|
+
capture_output=True,
|
|
98
|
+
text=True,
|
|
99
|
+
timeout=1,
|
|
100
|
+
shell=False)
|
|
101
|
+
print(out)
|
|
102
|
+
print("Movie is ready.")
|
|
103
|
+
|
|
104
|
+
except subprocess.CalledProcessError as xx:
|
|
105
|
+
print("Error")
|
|
106
|
+
print("create_movie: error rc=%d.\n%s" % (xx.returncode, xx.output))
|
|
107
|
+
|
|
108
|
+
except Exception as xx:
|
|
109
|
+
print("Error")
|
|
110
|
+
print("create_movie: error rc=%d.\n%s" % (xx.returncode, xx.output))
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def show_cycle(irbf):
|
|
114
|
+
"""Show thermal cycle.
|
|
115
|
+
|
|
116
|
+
Args:
|
|
117
|
+
----
|
|
118
|
+
irbf: IRB file with sequence.
|
|
119
|
+
|
|
120
|
+
"""
|
|
121
|
+
# Thermal cycle
|
|
122
|
+
T = []
|
|
123
|
+
D = []
|
|
124
|
+
prg = Progress.ShowProgress(irbf.n_images(), width=20)
|
|
125
|
+
prg.start()
|
|
126
|
+
for i, img in enumerate(irbf.images()):
|
|
127
|
+
prg.increase(1, True)
|
|
128
|
+
T.append(np.min(img.image))
|
|
129
|
+
D.append(img.timestamp)
|
|
130
|
+
|
|
131
|
+
prg.stop
|
|
132
|
+
fig, ax = plt.subplots(1, 1)
|
|
133
|
+
ax.plot(D, T, 'o-')
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def save_frame_data(the_frame, path_length, path_temp, sensor_avg, sensor_std):
|
|
137
|
+
"""Save the frame data.
|
|
138
|
+
|
|
139
|
+
The input data are 2D arrays.
|
|
140
|
+
i=0 corresponds to the left image
|
|
141
|
+
i=1 corresponds to the right image
|
|
142
|
+
|
|
143
|
+
Args:
|
|
144
|
+
----
|
|
145
|
+
the_frame: frams index in IRBFile
|
|
146
|
+
path_length: array with positions along the pipe
|
|
147
|
+
path_temp: array with temperatures in path_length positions
|
|
148
|
+
sensor_avg: Average T in sensor areas.
|
|
149
|
+
sensor_std: Temperature std in sensor area.
|
|
150
|
+
|
|
151
|
+
"""
|
|
152
|
+
onam = "pipe_temp_{}.csv".format(the_frame)
|
|
153
|
+
ofile = open(onam, 'w')
|
|
154
|
+
ofile.write("x, T, x, T\n")
|
|
155
|
+
ll = [len(path_length[0]), len(path_length[1])]
|
|
156
|
+
nitems = max(ll[0], ll[1])
|
|
157
|
+
for i in range(nitems):
|
|
158
|
+
for j in range(2):
|
|
159
|
+
if i < ll[j]:
|
|
160
|
+
ofile.write("{:.4f}, {:.4f},".format(path_length[j][i], path_temp[j][i]))
|
|
161
|
+
else:
|
|
162
|
+
ofile.write(",,")
|
|
163
|
+
|
|
164
|
+
ofile.write('\n')
|
|
165
|
+
ofile.close()
|
|
166
|
+
|
|
167
|
+
onam = "sensor_temp_{}.csv".format(the_frame)
|
|
168
|
+
ofile = open(onam, 'w')
|
|
169
|
+
ofile.write("T, std, T, std\n")
|
|
170
|
+
ll = [len(sensor_avg[0]), len(sensor_avg[1])]
|
|
171
|
+
nitems = max(ll[0], ll[1])
|
|
172
|
+
for i in range(nitems):
|
|
173
|
+
for j in range(2):
|
|
174
|
+
if i < ll[j]:
|
|
175
|
+
ofile.write("{:.4f}, {:.4f},".format(sensor_avg[j][i], sensor_std[j][i]))
|
|
176
|
+
else:
|
|
177
|
+
ofile.write(",,")
|
|
178
|
+
|
|
179
|
+
ofile.write('\n')
|
|
180
|
+
ofile.close()
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
def analyze_petal(ifileS, options):
|
|
184
|
+
"""Main entry."""
|
|
185
|
+
from IRDataGetter import IRDataGetter
|
|
186
|
+
# Obtain the Data getter.
|
|
187
|
+
try:
|
|
188
|
+
getter = IRDataGetter.factory(options.institute, options)
|
|
189
|
+
|
|
190
|
+
except NotImplemented:
|
|
191
|
+
print("*** Invalid institute name. ***")
|
|
192
|
+
return
|
|
193
|
+
|
|
194
|
+
# Load parameters from IRPetalParam
|
|
195
|
+
params = IRPetal.IRPetalParam(options)
|
|
196
|
+
params.debug = False
|
|
197
|
+
|
|
198
|
+
# Check if we are going to save the images
|
|
199
|
+
tmp_dir = None
|
|
200
|
+
if options.save_fig:
|
|
201
|
+
tmp_dir = tempfile.TemporaryDirectory()
|
|
202
|
+
|
|
203
|
+
# Open the sequence file
|
|
204
|
+
irbf = IRBFile.open_file(ifileS)
|
|
205
|
+
|
|
206
|
+
# Find first image below the threshold
|
|
207
|
+
# we will use the pipe obtained from here as the reference
|
|
208
|
+
# for the next
|
|
209
|
+
try:
|
|
210
|
+
min_T, i_min, values = getter.find_reference_image(irbf, params.thrs, nframes=2)
|
|
211
|
+
print("Image size: {} x {}".format(values[0].shape[0], values[0].shape[1]))
|
|
212
|
+
|
|
213
|
+
if options.debug:
|
|
214
|
+
show_2D_image(values)
|
|
215
|
+
|
|
216
|
+
except LookupError as e:
|
|
217
|
+
print(e)
|
|
218
|
+
sys.exit()
|
|
219
|
+
|
|
220
|
+
# Get the pipes
|
|
221
|
+
print("Extract pipes.")
|
|
222
|
+
pipes = getter.extract_pipe_path(values, params)
|
|
223
|
+
npipes = len(pipes)
|
|
224
|
+
|
|
225
|
+
# plot pipe paths on top of image
|
|
226
|
+
imgs = IRPetal.get_last_images()
|
|
227
|
+
nimgs = len(imgs)
|
|
228
|
+
if options.debug:
|
|
229
|
+
fig, ax = plt.subplots(1, nimgs, tight_layout=True)
|
|
230
|
+
if nimgs == 1:
|
|
231
|
+
ax = [ax, ]
|
|
232
|
+
|
|
233
|
+
for i, img in enumerate(imgs):
|
|
234
|
+
ax[i].imshow(imgs[i], origin="lower", cmap="jet")
|
|
235
|
+
ax[i].plot(pipes[i][:, 0], pipes[i][:, 1], linewidth=3, color="black")
|
|
236
|
+
|
|
237
|
+
# We now need to fit to the reference pipes to get the proper distance along
|
|
238
|
+
# the pipe.
|
|
239
|
+
transforms = [None, None]
|
|
240
|
+
fitter = [None, None]
|
|
241
|
+
sensors = [None, None]
|
|
242
|
+
ordered_pipes = [None, None]
|
|
243
|
+
|
|
244
|
+
print("Fit pipes and find sensor positions.")
|
|
245
|
+
for i in range(npipes):
|
|
246
|
+
# Fit the points to the "pipes"
|
|
247
|
+
pipe_type = PipeFit.PipeFit.guess_pipe_type(pipes[i])
|
|
248
|
+
|
|
249
|
+
PF = PipeFit.PipeFit(pipe_type)
|
|
250
|
+
R = PF.fit_ex(pipes[i])
|
|
251
|
+
|
|
252
|
+
transforms[pipe_type] = R
|
|
253
|
+
fitter[pipe_type] = PF
|
|
254
|
+
|
|
255
|
+
# Reorder points in pipe contour so that first point corresponds to
|
|
256
|
+
# the U-shape pipe minimum.
|
|
257
|
+
pipes[i] = IRPetal.reorder_pipe_points(pipes[i], pipe_type, R)
|
|
258
|
+
if ordered_pipes[pipe_type] is not None:
|
|
259
|
+
print("### Expect probles. 2 pipes of sme type")
|
|
260
|
+
|
|
261
|
+
ordered_pipes[pipe_type] = pipes[i]
|
|
262
|
+
|
|
263
|
+
# Now make the inverse transform of the area of sernsors and EoS
|
|
264
|
+
S = []
|
|
265
|
+
for s in PF.sensors:
|
|
266
|
+
o = PF.transform_inv(s, R)
|
|
267
|
+
S.append(o)
|
|
268
|
+
sensors[pipe_type] = S
|
|
269
|
+
|
|
270
|
+
pipes = ordered_pipes
|
|
271
|
+
if pipes[0] is None and pipes[1] is not None:
|
|
272
|
+
pipes[0] = pipes[1]
|
|
273
|
+
pipes[1] = None
|
|
274
|
+
|
|
275
|
+
sensors[0] = sensors[1]
|
|
276
|
+
sensors[1] = None
|
|
277
|
+
|
|
278
|
+
fitter[0] = fitter[1]
|
|
279
|
+
fitter[1] = None
|
|
280
|
+
|
|
281
|
+
transforms[0] = transforms[1]
|
|
282
|
+
transforms[1] = None
|
|
283
|
+
|
|
284
|
+
if options.debug:
|
|
285
|
+
fig, ax = plt.subplots(1, npipes, tight_layout=True)
|
|
286
|
+
if npipes == 1:
|
|
287
|
+
if fitter[0]:
|
|
288
|
+
ax = [ax, ]
|
|
289
|
+
else:
|
|
290
|
+
ax = [None, ax]
|
|
291
|
+
|
|
292
|
+
fig.suptitle("Fit result")
|
|
293
|
+
for i, F in enumerate(fitter):
|
|
294
|
+
if F is None:
|
|
295
|
+
continue
|
|
296
|
+
|
|
297
|
+
ax[i].plot(F.pipe[:, 0], F.pipe[:, 1])
|
|
298
|
+
|
|
299
|
+
out = F.transform_data(F.data, transforms[i])
|
|
300
|
+
ax[i].plot(out[:, 0], out[:, 1], 'o')
|
|
301
|
+
|
|
302
|
+
# Now go again through all the sequence and get the temperature along the pipes.
|
|
303
|
+
panels = [['P1', 'P2', 'T1', 'S1', 'SP1'],
|
|
304
|
+
['P1', 'P2', 'T2', 'S2', 'SP2']]
|
|
305
|
+
labels = ["left", "right"]
|
|
306
|
+
tick_labels = ["R0", "R1", "R2", "R3", "R3", "R4", "R4", "R5", "R5", "EoS"]
|
|
307
|
+
fig, ax = plt.subplot_mosaic(panels,
|
|
308
|
+
tight_layout=True,
|
|
309
|
+
figsize=(10, 5),
|
|
310
|
+
gridspec_kw={'width_ratios': (0.25, 0.25, 0.17, 0.16, 0.17)})
|
|
311
|
+
|
|
312
|
+
print("Let's go")
|
|
313
|
+
for j, img in enumerate(irbf.images(options.first_frame, nframes=options.nframe)):
|
|
314
|
+
the_frame = options.first_frame + j
|
|
315
|
+
tmin = np.min(img[0].image)
|
|
316
|
+
|
|
317
|
+
sss = "Image {} - T {:.2f}".format(the_frame, tmin)
|
|
318
|
+
fig.suptitle(sss)
|
|
319
|
+
print(sss)
|
|
320
|
+
values = getter.get_IR_data(img, rotate=True)
|
|
321
|
+
results = getter.analyze_IR_image(values, pipes, sensors, 0, params)
|
|
322
|
+
|
|
323
|
+
# TODO: re-implement this with AnalysisResults
|
|
324
|
+
# if the_frame in options.frames:
|
|
325
|
+
# save_frame_data(the_frame, path_length, path_temp, sensor_avg, sensor_std)
|
|
326
|
+
|
|
327
|
+
ii = 0
|
|
328
|
+
for i in range(2):
|
|
329
|
+
try:
|
|
330
|
+
if results[i] is None:
|
|
331
|
+
continue
|
|
332
|
+
except IndexError:
|
|
333
|
+
continue
|
|
334
|
+
|
|
335
|
+
pmn, pmx = get_min_max(results[i].path_temp)
|
|
336
|
+
spmn, spmx = get_min_max(results[i].path_spread)
|
|
337
|
+
smn, smx = get_min_max(results[i].sensor_avg)
|
|
338
|
+
|
|
339
|
+
pan = "P{}".format(i+1)
|
|
340
|
+
cpan = "T{}".format(i+1)
|
|
341
|
+
span = "S{}".format(i+1)
|
|
342
|
+
sspan = "SP{}".format(i+1)
|
|
343
|
+
ax[pan].clear()
|
|
344
|
+
ax[pan].set_title("Image {}".format(labels[i]))
|
|
345
|
+
ax[pan].imshow(imgs[ii], origin='lower', cmap=HighContrast.reversed()) # , cmap='jet')
|
|
346
|
+
ax[pan].plot(pipes[ii][:, 0], pipes[ii][:, 1], linewidth=2, color="#000000")
|
|
347
|
+
for s in sensors[ii]:
|
|
348
|
+
ax[pan].plot(s[:, 0], s[:, 1], linewidth=2, color="#000000")
|
|
349
|
+
|
|
350
|
+
ax[cpan].clear()
|
|
351
|
+
ax[cpan].yaxis.set_major_locator(ticker.MultipleLocator(1))
|
|
352
|
+
ax[cpan].set_ylim(pmn, pmx)
|
|
353
|
+
ax[cpan].set_title("Pipe {}".format(labels[i]))
|
|
354
|
+
ax[cpan].plot(results[i].path_length, results[i].path_temp)
|
|
355
|
+
|
|
356
|
+
ax[sspan].clear()
|
|
357
|
+
ax[sspan].yaxis.set_major_locator(ticker.MultipleLocator(1))
|
|
358
|
+
ax[sspan].set_ylim(spmn, spmx)
|
|
359
|
+
ax[sspan].set_title("Spread {}".format(labels[i]))
|
|
360
|
+
ax[sspan].plot(results[i].path_length, results[i].path_spread)
|
|
361
|
+
|
|
362
|
+
ax[span].clear()
|
|
363
|
+
ax[span].yaxis.set_major_locator(ticker.MultipleLocator(1))
|
|
364
|
+
ax[span].set_ylim(smn, smx)
|
|
365
|
+
ax[span].set_xticks(range(10), labels=tick_labels)
|
|
366
|
+
|
|
367
|
+
ax[span].set_title("Sensors {}".format(labels[i]))
|
|
368
|
+
ax[span].plot(results[i].sensor_avg, 'o-')
|
|
369
|
+
|
|
370
|
+
ii += 1
|
|
371
|
+
|
|
372
|
+
plt.draw()
|
|
373
|
+
plt.pause(0.0001)
|
|
374
|
+
if the_frame in options.frames:
|
|
375
|
+
ofile = "frame_{:03d}.png".format(the_frame)
|
|
376
|
+
fig.savefig(ofile)
|
|
377
|
+
|
|
378
|
+
if tmp_dir:
|
|
379
|
+
ofile = "{}/fig{:03d}.png".format(tmp_dir.name, j)
|
|
380
|
+
fig.savefig(ofile)
|
|
381
|
+
|
|
382
|
+
if tmp_dir:
|
|
383
|
+
print("Creating movie")
|
|
384
|
+
template = "{}/fig%03d.png".format(tmp_dir.name)
|
|
385
|
+
print("template {}".format(template))
|
|
386
|
+
create_movie(template, options.save_fig)
|
|
387
|
+
|
|
388
|
+
print("Min temperature is {} @ {}".format(min_T, i_min))
|
|
389
|
+
for P in pipes:
|
|
390
|
+
if P is not None:
|
|
391
|
+
print("Pipe shape: {}".format(P.shape))
|
|
392
|
+
|
|
393
|
+
plt.show()
|
|
394
|
+
|
|
395
|
+
|
|
396
|
+
if __name__ == "__main__":
|
|
397
|
+
# This class contains the parameters needed for tha analysis.
|
|
398
|
+
from IRPetalParam import IRPetalParam
|
|
399
|
+
|
|
400
|
+
parser = ArgumentParser()
|
|
401
|
+
parser.add_argument('files', nargs='*', help="Input files")
|
|
402
|
+
parser.add_argument("--save_frames", dest="frames", default=[],
|
|
403
|
+
action=CommaSeparatedListAction,
|
|
404
|
+
help="Frames to save")
|
|
405
|
+
parser.add_argument("--nframe", type=int, default=-1, help="Number of frames. (negative means all.")
|
|
406
|
+
parser.add_argument('--first_frame', type=int, default=0, help="First frame to start.")
|
|
407
|
+
parser.add_argument("--orig", action="store_true", default=False, help="plot the original image")
|
|
408
|
+
parser.add_argument("--save_fig", default=None, help="Save all figures to make a film. Provide output file name")
|
|
409
|
+
parser.add_argument("--show_cycle", action="store_true", default=False, help="Show the thermal cycle.")
|
|
410
|
+
|
|
411
|
+
# Add default parameters to the parser
|
|
412
|
+
IRPetalParam.add_parameters(parser)
|
|
413
|
+
|
|
414
|
+
options = parser.parse_args()
|
|
415
|
+
nfiles = len(options.files)
|
|
416
|
+
if nfiles == 0:
|
|
417
|
+
print("I need an input file")
|
|
418
|
+
sys.exit()
|
|
419
|
+
|
|
420
|
+
analyze_petal(options.files, options)
|