petal-qc 0.0.8__py3-none-any.whl → 0.0.10__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 +6 -1
- petal_qc/metrology/PetalMetrology.py +2 -2
- petal_qc/metrology/compare_Cores.py +27 -15
- petal_qc/metrology/coreMetrology.py +1 -1
- petal_qc/metrology/readAVSdata.py +695 -0
- petal_qc/metrology/uploadPetalInformation.py +758 -0
- petal_qc/test/getAVSjson.py +27 -0
- petal_qc/test/getAVStests.py +154 -0
- petal_qc/test/getPetalCoreTestSummary.py +89 -0
- petal_qc/test/prepareDESYfiles.py +25 -8
- petal_qc/thermal/IRCore.py +1 -1
- petal_qc/thermal/IRDataGetter.py +8 -8
- petal_qc/thermal/IRPetal.py +78 -7
- petal_qc/thermal/Petal_IR_Analysis.py +4 -3
- petal_qc/thermal/PipeFit.py +4 -3
- petal_qc/thermal/analyze_IRCore.py +12 -9
- petal_qc/thermal/coreThermal.py +9 -3
- petal_qc/thermal/create_IRCore.py +25 -5
- petal_qc/thermal/create_core_report.py +13 -4
- petal_qc/utils/Geometry.py +2 -2
- {petal_qc-0.0.8.dist-info → petal_qc-0.0.10.dist-info}/METADATA +1 -1
- {petal_qc-0.0.8.dist-info → petal_qc-0.0.10.dist-info}/RECORD +25 -20
- {petal_qc-0.0.8.dist-info → petal_qc-0.0.10.dist-info}/WHEEL +1 -1
- {petal_qc-0.0.8.dist-info → petal_qc-0.0.10.dist-info}/entry_points.txt +1 -0
- {petal_qc-0.0.8.dist-info → petal_qc-0.0.10.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import json
|
|
2
|
+
from itkdb_gtk import ITkDBlogin
|
|
3
|
+
from petal_qc.metrology import readAVSdata
|
|
4
|
+
dlg = ITkDBlogin.ITkDBlogin()
|
|
5
|
+
session = dlg.get_client()
|
|
6
|
+
|
|
7
|
+
ofile = "weights_ppc16.json"
|
|
8
|
+
PSF = "/Users/lacasta/Nextcloud/ITk/5-Petal_cores/PPC.016/AVS.P052.PSH.035 - Petal 016.xlsx"
|
|
9
|
+
|
|
10
|
+
ofile = "weights_ppc17.json"
|
|
11
|
+
ofat = "metrology_test_ppc17.json"
|
|
12
|
+
PSF = "/Users/lacasta/Nextcloud/ITk/5-Petal_cores/PPC.017/AVS.P052.PSH.036 - Petal 017.xlsx"
|
|
13
|
+
FAT = "/Users/lacasta/Nextcloud/ITk/5-Petal_cores/PPC.017/AVS.P052.FRT.036 r0 - FAT_Serie_017.xlsx"
|
|
14
|
+
manuf_json, weights_json, DESY_comp, alias = readAVSdata.readProductionSheet(session, PSF, "SNnnnn")
|
|
15
|
+
|
|
16
|
+
vi_test, delamination_test, grounding_test, metrology_test, batch, petal_weight = readAVSdata.readFATfile(session, FAT, "SNnnn")
|
|
17
|
+
|
|
18
|
+
with open(ofile, "w", encoding="UTF-8") as fin:
|
|
19
|
+
json.dump(weights_json, fin, indent=3)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
with open(ofat, "w", encoding="UTF-8") as fin:
|
|
23
|
+
json.dump(metrology_test, fin, indent=3)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
print("done")
|
|
27
|
+
dlg.die()
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Analize AVS metrology tests."""
|
|
3
|
+
import numpy as np
|
|
4
|
+
import matplotlib.pyplot as plt
|
|
5
|
+
|
|
6
|
+
try:
|
|
7
|
+
import itkdb_gtk
|
|
8
|
+
|
|
9
|
+
except ImportError:
|
|
10
|
+
import sys
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
cwd = Path(__file__).parent.parent
|
|
13
|
+
sys.path.append(cwd.as_posix())
|
|
14
|
+
|
|
15
|
+
from itkdb_gtk import ITkDBlogin, ITkDButils
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def do_metrology(results, M_values):
|
|
19
|
+
pass
|
|
20
|
+
|
|
21
|
+
def do_weighing(results, weights):
|
|
22
|
+
"""Accumulates weighing values to produce stack plot.
|
|
23
|
+
|
|
24
|
+
Args:
|
|
25
|
+
results (): Results from DB
|
|
26
|
+
weights (): Dict with the values.
|
|
27
|
+
"""
|
|
28
|
+
for value in results:
|
|
29
|
+
ipos = value["code"].find("_")
|
|
30
|
+
weights.setdefault(value["code"][ipos+1:], []).append(value["value"])
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def plot_weighing(weights, tick_labels, show_total=False):
|
|
34
|
+
"""Make the plot of weights."""
|
|
35
|
+
labels = ["COOLINGLOOPASSEMBLY", "LOCATOR_A", "LOCATOR_B", "LOCATOR_C",
|
|
36
|
+
"HONEYCOMBSET", "FACING_FRONT", "FACING_BACK",
|
|
37
|
+
"EPOXYADHESIVE", "EPOXYPUTTY", "EPOXYCONDUCTIVE"]
|
|
38
|
+
|
|
39
|
+
fig = plt.figure(tight_layout=True)
|
|
40
|
+
fig.suptitle("Petal Core weight (gr)")
|
|
41
|
+
ax = fig.add_subplot(1, 1, 1)
|
|
42
|
+
ax.set_ylabel("Weight [gr]")
|
|
43
|
+
ax.set_ylim(0, 300)
|
|
44
|
+
npoints = len(weights["CORE"])
|
|
45
|
+
X = np.arange(npoints)
|
|
46
|
+
|
|
47
|
+
values = [ weights[k] for k in labels]
|
|
48
|
+
Y = np.vstack(values)
|
|
49
|
+
ax.stackplot(X, Y, labels=labels)
|
|
50
|
+
ax.set_xticks(range(npoints), labels=tick_labels, rotation="vertical")
|
|
51
|
+
|
|
52
|
+
if not show_total:
|
|
53
|
+
ax.plot(X, [225.0 for x in range(npoints)], linestyle="dashed", color="black", linewidth=1)
|
|
54
|
+
ax.plot(X, [250.0 for x in range(npoints)], '-', color="black", linewidth=1, label="Nominal")
|
|
55
|
+
ax.plot(X, [275.0 for x in range(npoints)], linestyle="dashed", color="black", linewidth=1,)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
ax.legend(loc="upper left", ncol=3, fontsize="x-small")
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def main(session):
|
|
62
|
+
"""Entry point"""
|
|
63
|
+
# find all cores
|
|
64
|
+
# Now all the objects
|
|
65
|
+
payload = {
|
|
66
|
+
"filterMap": {
|
|
67
|
+
"componentType": ["CORE_PETAL"],
|
|
68
|
+
"type": ["CORE_AVS"],
|
|
69
|
+
#"currentLocation": ["IFIC"],
|
|
70
|
+
},
|
|
71
|
+
"sorterList": [
|
|
72
|
+
{"key": "alternativeIdentifier", "descending": False }
|
|
73
|
+
],
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
core_list = session.get("listComponents", json=payload)
|
|
77
|
+
core_tests = ["METROLOGY_AVS", "WEIGHING"]
|
|
78
|
+
|
|
79
|
+
weights = {}
|
|
80
|
+
petal_ids = []
|
|
81
|
+
M_values = []
|
|
82
|
+
for core in core_list:
|
|
83
|
+
SN = core["serialNumber"]
|
|
84
|
+
altid = core['alternativeIdentifier']
|
|
85
|
+
if "PPC" not in altid:
|
|
86
|
+
continue
|
|
87
|
+
|
|
88
|
+
if altid in ["PPC.016", "PPC.017"]:
|
|
89
|
+
pass
|
|
90
|
+
|
|
91
|
+
petal_ids.append(altid)
|
|
92
|
+
|
|
93
|
+
location = core["currentLocation"]['code']
|
|
94
|
+
coreStage = core["currentStage"]['code']
|
|
95
|
+
|
|
96
|
+
print("\nPetal {} [{}] - {}. {}".format(SN, altid, coreStage, location))
|
|
97
|
+
test_list = session.get("listTestRunsByComponent", json={"filterMap":{"serialNumber": SN, "state": "ready", "testType":core_tests}})
|
|
98
|
+
|
|
99
|
+
good_tests = {}
|
|
100
|
+
for tst in test_list:
|
|
101
|
+
ttype = tst["testType"]["code"]
|
|
102
|
+
if ttype not in core_tests:
|
|
103
|
+
print(ttype)
|
|
104
|
+
continue
|
|
105
|
+
|
|
106
|
+
T = session.get("getTestRun", json={"testRun": tst["id"]})
|
|
107
|
+
if T["state"] != "ready":
|
|
108
|
+
continue
|
|
109
|
+
|
|
110
|
+
print("-- {} [{}]".format(T["testType"]["name"], T["runNumber"]))
|
|
111
|
+
if ttype in good_tests:
|
|
112
|
+
if good_tests[ttype]["runNumber"] < T["runNumber"]:
|
|
113
|
+
good_tests[ttype] = T
|
|
114
|
+
else:
|
|
115
|
+
good_tests[ttype] = T
|
|
116
|
+
|
|
117
|
+
for ttype, T in good_tests.items():
|
|
118
|
+
|
|
119
|
+
if ttype == "WEIGHING":
|
|
120
|
+
do_weighing(T["results"], weights)
|
|
121
|
+
|
|
122
|
+
elif ttype == "METROLOGY_AVS":
|
|
123
|
+
do_metrology(T["results"], M_values)
|
|
124
|
+
|
|
125
|
+
else:
|
|
126
|
+
for value in T["results"]:
|
|
127
|
+
print("\t{} - {}".format(value["code"], value["value"]))
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
if not T["passed"]:
|
|
131
|
+
print("\t## test FAILED")
|
|
132
|
+
|
|
133
|
+
print("\t+ Defects:")
|
|
134
|
+
if len(T["defects"]):
|
|
135
|
+
for D in T["defects"]:
|
|
136
|
+
print("\t{} - {}".format(D["name"], D["description"]))
|
|
137
|
+
else:
|
|
138
|
+
print("\nNone")
|
|
139
|
+
|
|
140
|
+
plot_weighing(weights, petal_ids)
|
|
141
|
+
plt.show()
|
|
142
|
+
|
|
143
|
+
if __name__ == "__main__":
|
|
144
|
+
# ITk_PB authentication
|
|
145
|
+
dlg = ITkDBlogin.ITkDBlogin()
|
|
146
|
+
session = dlg.get_client()
|
|
147
|
+
|
|
148
|
+
try:
|
|
149
|
+
main(session)
|
|
150
|
+
|
|
151
|
+
except Exception as E:
|
|
152
|
+
print(E)
|
|
153
|
+
|
|
154
|
+
dlg.die()
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Get a summery of Petal core TEsts."""
|
|
3
|
+
|
|
4
|
+
try:
|
|
5
|
+
import itkdb_gtk
|
|
6
|
+
|
|
7
|
+
except ImportError:
|
|
8
|
+
import sys
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
cwd = Path(__file__).parent.parent
|
|
11
|
+
sys.path.append(cwd.as_posix())
|
|
12
|
+
|
|
13
|
+
from itkdb_gtk import ITkDBlogin, ITkDButils
|
|
14
|
+
from itkdb_gtk.dbGtkUtils import replace_in_container, DictDialog, ask_for_confirmation
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def main(session):
|
|
18
|
+
"""Main entry point."""
|
|
19
|
+
|
|
20
|
+
# find all cores
|
|
21
|
+
# Now all the objects
|
|
22
|
+
payload = {
|
|
23
|
+
"filterMap": {
|
|
24
|
+
#"componentType": ["BT"],
|
|
25
|
+
"componentType": ["CORE_PETAL"],
|
|
26
|
+
"type": ["CORE_AVS"],
|
|
27
|
+
"currentLocation": ["IFIC"],
|
|
28
|
+
},
|
|
29
|
+
"sorterList": [
|
|
30
|
+
{"key": "alternativeIdentifier", "descending": False }
|
|
31
|
+
],
|
|
32
|
+
}
|
|
33
|
+
core_list = session.get("listComponents", json=payload)
|
|
34
|
+
core_tests = ["PETAL_METROLOGY_FRONT", "PETAL_METROLOGY_BACK", "XRAYIMAGING", "THERMAL_EVALUATION", "BTTESTING"]
|
|
35
|
+
|
|
36
|
+
do_check_stage = "AT_QC_SITE"
|
|
37
|
+
#do_check_stage = None
|
|
38
|
+
|
|
39
|
+
for core in core_list:
|
|
40
|
+
SN = core["serialNumber"]
|
|
41
|
+
altid = core['alternativeIdentifier']
|
|
42
|
+
if "PPC" not in altid:
|
|
43
|
+
continue
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
location = core["currentLocation"]['code']
|
|
47
|
+
coreStage = core["currentStage"]['code']
|
|
48
|
+
if do_check_stage:
|
|
49
|
+
if coreStage != do_check_stage:
|
|
50
|
+
rc = ITkDButils.set_object_stage(session, SN, do_check_stage)
|
|
51
|
+
if rc is None:
|
|
52
|
+
print("Could not change stage")
|
|
53
|
+
return False
|
|
54
|
+
|
|
55
|
+
print("Petal {} [{}] - {}. {}".format(SN, id, coreStage, location))
|
|
56
|
+
|
|
57
|
+
test_list = session.get("listTestRunsByComponent", json={"filterMap":{"serialNumber": SN, "state": "ready", "testType":core_tests}})
|
|
58
|
+
|
|
59
|
+
for tst in test_list:
|
|
60
|
+
ttype = tst["testType"]["code"]
|
|
61
|
+
if ttype not in core_tests:
|
|
62
|
+
print(ttype)
|
|
63
|
+
continue
|
|
64
|
+
|
|
65
|
+
T = session.get("getTestRun", json={"testRun": tst["id"]})
|
|
66
|
+
if T["state"] != "ready":
|
|
67
|
+
print(T)
|
|
68
|
+
|
|
69
|
+
print("-- {} [{}]".format(T["testType"]["name"], T["runNumber"]))
|
|
70
|
+
if not T["passed"]:
|
|
71
|
+
print("\t## test FAILED")
|
|
72
|
+
|
|
73
|
+
for D in T["defects"]:
|
|
74
|
+
print("\t{} - {}".format(D["name"], D["description"]))
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
if __name__ == "__main__":
|
|
78
|
+
# ITk_PB authentication
|
|
79
|
+
dlg = ITkDBlogin.ITkDBlogin()
|
|
80
|
+
session = dlg.get_client()
|
|
81
|
+
|
|
82
|
+
try:
|
|
83
|
+
main(session)
|
|
84
|
+
|
|
85
|
+
except Exception as E:
|
|
86
|
+
print(E)
|
|
87
|
+
|
|
88
|
+
dlg.die()
|
|
89
|
+
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
|
-
"""
|
|
2
|
+
"""Prepare raw data input files from DESY so that we can use them with this code."""
|
|
3
3
|
import os
|
|
4
4
|
import fnmatch
|
|
5
5
|
import re
|
|
6
6
|
from pathlib import Path
|
|
7
|
+
import argparse
|
|
7
8
|
|
|
8
9
|
def all_files(root, patterns='*', single_level=False, yield_folders=False):
|
|
9
10
|
"""A generator that reruns all files in the given folder.
|
|
@@ -41,18 +42,26 @@ class PetalCore:
|
|
|
41
42
|
self.back = {}
|
|
42
43
|
|
|
43
44
|
def main(folder, out_folder):
|
|
44
|
-
"""Main entry point.
|
|
45
|
+
"""Main entry point.
|
|
46
|
+
|
|
47
|
+
It takes DESY raw data files and combines them into a single file for front
|
|
48
|
+
and back metrology.
|
|
49
|
+
|
|
50
|
+
Args:
|
|
51
|
+
folder: the input folder where to find the original files.
|
|
52
|
+
out_folder: the folder where the new fiels will be stored.
|
|
53
|
+
"""
|
|
45
54
|
outF = Path(out_folder).expanduser().resolve()
|
|
46
55
|
if not outF.exists():
|
|
47
56
|
os.mkdir(outF)
|
|
48
|
-
|
|
49
|
-
rgx = re.compile(r"Project Name: (\w+)side_.*AlternativeID=PPC-(\d+)", re.MULTILINE|re.DOTALL)
|
|
57
|
+
|
|
58
|
+
rgx = re.compile(r"Project Name: (\w+)side_.*AlternativeID=PPC[-_](\d+)", re.MULTILINE|re.DOTALL)
|
|
50
59
|
petal_cores = {}
|
|
51
60
|
for fnam in all_files(folder, "*.txt"):
|
|
52
61
|
P = Path(fnam).expanduser().resolve()
|
|
53
62
|
with open(fnam, "r", encoding="UTF-8") as ff:
|
|
54
63
|
R = rgx.search(ff.read())
|
|
55
|
-
if R:
|
|
64
|
+
if R:
|
|
56
65
|
petal_id = "PPC.{}".format(R.group(2))
|
|
57
66
|
side = R.group(1).lower()
|
|
58
67
|
if "_2D_" in P.name:
|
|
@@ -75,12 +84,20 @@ def main(folder, out_folder):
|
|
|
75
84
|
list_file.write("{} {}-{} {}\n".format(oname, petal_id, side, petal_id))
|
|
76
85
|
data = ""
|
|
77
86
|
for data_type, fnam in values.items():
|
|
87
|
+
if fnam is None:
|
|
88
|
+
print("This should not happen.")
|
|
89
|
+
|
|
78
90
|
with open(fnam, "r", encoding="UTF-8") as ifile:
|
|
79
91
|
data += ifile.read()
|
|
80
|
-
|
|
92
|
+
|
|
81
93
|
with open(oname, "w", encoding="UTF-8") as ofile:
|
|
82
94
|
ofile.write(data)
|
|
83
|
-
|
|
95
|
+
|
|
84
96
|
list_file.close()
|
|
97
|
+
|
|
85
98
|
if __name__ == "__main__":
|
|
86
|
-
|
|
99
|
+
parser = argparse.ArgumentParser()
|
|
100
|
+
parser.add_argument("--input-folder", default=None, help="Input folder")
|
|
101
|
+
parser.add_argument("--output-folder", help="Outout fodler", default=None)
|
|
102
|
+
|
|
103
|
+
main("/Users/lacasta/Downloads/Report_QC-desy_Sep2024", "/tmp/desy")
|
petal_qc/thermal/IRCore.py
CHANGED
|
@@ -41,7 +41,7 @@ class IRCore(object):
|
|
|
41
41
|
self.files = []
|
|
42
42
|
self.results = [] if results is None else results # list of AnalysisResults. One per side
|
|
43
43
|
self.golden = [] # list of Golden results. One per side.
|
|
44
|
-
self.inlet =
|
|
44
|
+
self.inlet = params.tco2
|
|
45
45
|
|
|
46
46
|
def set_files(self, files):
|
|
47
47
|
"""Set the input files."""
|
petal_qc/thermal/IRDataGetter.py
CHANGED
|
@@ -19,10 +19,10 @@ HAS_GRAPHANA = False
|
|
|
19
19
|
try:
|
|
20
20
|
from petal_qc.utils.readGraphana import ReadGraphana
|
|
21
21
|
HAS_GRAPHANA = True
|
|
22
|
-
|
|
22
|
+
|
|
23
23
|
except ImportError:
|
|
24
24
|
HAS_GRAPHANA = False
|
|
25
|
-
|
|
25
|
+
|
|
26
26
|
|
|
27
27
|
|
|
28
28
|
class IRDataGetter(object):
|
|
@@ -62,7 +62,7 @@ class IRDataGetter(object):
|
|
|
62
62
|
kargs: keyword arguments to pass.
|
|
63
63
|
|
|
64
64
|
"""
|
|
65
|
-
|
|
65
|
+
return
|
|
66
66
|
|
|
67
67
|
def find_reference_image(self, irbf, *args, **kargs):
|
|
68
68
|
"""Find first image in sequence with T < T_min.
|
|
@@ -114,7 +114,7 @@ class IRDataGetter(object):
|
|
|
114
114
|
An array of AnalysisResult objects.
|
|
115
115
|
|
|
116
116
|
"""
|
|
117
|
-
|
|
117
|
+
return
|
|
118
118
|
|
|
119
119
|
def get_analysis_frame(self, irbf):
|
|
120
120
|
"""Get the frame where we want to perform the analysis."""
|
|
@@ -166,12 +166,12 @@ class IRDataIFIC(IRDataGetter):
|
|
|
166
166
|
# T_min = -22.0
|
|
167
167
|
# else:
|
|
168
168
|
# T_min = args[0]
|
|
169
|
-
#
|
|
169
|
+
#
|
|
170
170
|
# irbf.set_concatenate(True)
|
|
171
171
|
# min_T, i_min, ref_img = IRPetal.find_reference_image(irbf, T_min)
|
|
172
172
|
# values = self.get_IR_data(ref_img)
|
|
173
173
|
# self.factor = values.shape[0]/640
|
|
174
|
-
#
|
|
174
|
+
#
|
|
175
175
|
# return min_T, i_min, [values, ]
|
|
176
176
|
|
|
177
177
|
def get_IR_data(self, image, **kargs):
|
|
@@ -281,10 +281,10 @@ class IRDataIFIC(IRDataGetter):
|
|
|
281
281
|
img = self.analysis_frame[0]
|
|
282
282
|
X, T = self.DB.get_temperature(img.timestamp, 1)
|
|
283
283
|
return np.min(T)
|
|
284
|
-
|
|
284
|
+
|
|
285
285
|
else:
|
|
286
286
|
return -9999
|
|
287
|
-
|
|
287
|
+
|
|
288
288
|
|
|
289
289
|
|
|
290
290
|
class IRDataDESY(IRDataGetter):
|
petal_qc/thermal/IRPetal.py
CHANGED
|
@@ -35,7 +35,7 @@ debug_plot = DebugPlot.DebugPlot()
|
|
|
35
35
|
the_segments = None # global variable to store the last segments found.
|
|
36
36
|
the_contours = None # Global variable to store the last contours found
|
|
37
37
|
the_images = None
|
|
38
|
-
|
|
38
|
+
the_3d_points = None
|
|
39
39
|
|
|
40
40
|
class DebugTempProfile(object):
|
|
41
41
|
"""Stores Debug data."""
|
|
@@ -68,6 +68,10 @@ class DebugTempProfile(object):
|
|
|
68
68
|
T_profile = None # Global to store the temp. profile.
|
|
69
69
|
|
|
70
70
|
|
|
71
|
+
def get_all_3d_points():
|
|
72
|
+
"""Return all pipe path 3D points."""
|
|
73
|
+
return the_3d_points
|
|
74
|
+
|
|
71
75
|
def get_last_segments():
|
|
72
76
|
"""Return the last segments found."""
|
|
73
77
|
global the_segments
|
|
@@ -145,6 +149,39 @@ class Segment(object):
|
|
|
145
149
|
|
|
146
150
|
return points
|
|
147
151
|
|
|
152
|
+
@staticmethod
|
|
153
|
+
def get_3d_points_in_list(segments):
|
|
154
|
+
"""Return a list with all the 3D points (x,y,T) in the list of segments.
|
|
155
|
+
|
|
156
|
+
Args:
|
|
157
|
+
----
|
|
158
|
+
segments (list[Segment]): The list of segments
|
|
159
|
+
|
|
160
|
+
Returns
|
|
161
|
+
-------
|
|
162
|
+
np.array: array of points.
|
|
163
|
+
|
|
164
|
+
"""
|
|
165
|
+
# Count the number of points
|
|
166
|
+
npts = 0
|
|
167
|
+
for S in segments:
|
|
168
|
+
if S.Pmin is not None:
|
|
169
|
+
npts += len(S.Pmin)
|
|
170
|
+
|
|
171
|
+
points = np.zeros([npts, 3])
|
|
172
|
+
ipoint = 0
|
|
173
|
+
for S in segments:
|
|
174
|
+
if S.Pmin is None:
|
|
175
|
+
continue
|
|
176
|
+
|
|
177
|
+
for i, Pmin in enumerate(S.Pmin):
|
|
178
|
+
points[ipoint, 0] = Pmin.x
|
|
179
|
+
points[ipoint, 1] = Pmin.y
|
|
180
|
+
points[ipoint, 2] = S.Tmin[i]
|
|
181
|
+
ipoint += 1
|
|
182
|
+
|
|
183
|
+
return points
|
|
184
|
+
|
|
148
185
|
@staticmethod
|
|
149
186
|
def get_spread_in_list(segments):
|
|
150
187
|
"""Return an array with spread values."""
|
|
@@ -323,7 +360,7 @@ def extract_mirrored_pipe_path(values, params):
|
|
|
323
360
|
(left_pipe, right_pipe): The 2 paths.
|
|
324
361
|
|
|
325
362
|
"""
|
|
326
|
-
global the_images
|
|
363
|
+
global the_images, the_3d_points
|
|
327
364
|
if params.rotate:
|
|
328
365
|
rotated = rotate_full_image(values)
|
|
329
366
|
else:
|
|
@@ -331,11 +368,14 @@ def extract_mirrored_pipe_path(values, params):
|
|
|
331
368
|
|
|
332
369
|
imgs = split_IR_image(rotated)
|
|
333
370
|
pipes = []
|
|
371
|
+
points_3d = []
|
|
334
372
|
for img in imgs:
|
|
335
373
|
pipe = extract_pipe_path(img, params)
|
|
336
374
|
pipes.append(pipe)
|
|
375
|
+
points_3d.append(get_all_3d_points())
|
|
337
376
|
|
|
338
377
|
the_images = imgs
|
|
378
|
+
the_3d_points = points_3d
|
|
339
379
|
return list(pipes)
|
|
340
380
|
|
|
341
381
|
|
|
@@ -684,7 +724,7 @@ def get_derivatives(T_min, x_min, x_max, coeff):
|
|
|
684
724
|
return valid_roots, valid_values, valid_curv
|
|
685
725
|
|
|
686
726
|
|
|
687
|
-
def show_profile(debug_plot):
|
|
727
|
+
def show_profile(debug_plot, title=None):
|
|
688
728
|
"""Plot a profile."""
|
|
689
729
|
debug_plot.setup_debug("Slices", is_3d=True)
|
|
690
730
|
if T_profile:
|
|
@@ -693,6 +733,12 @@ def show_profile(debug_plot):
|
|
|
693
733
|
if T_profile._pF is not None:
|
|
694
734
|
debug_plot.plotx("Slices", T_profile._pF[:, 0], T_profile._pF[:, 1], T_profile._Fn, 'b-')
|
|
695
735
|
|
|
736
|
+
if title:
|
|
737
|
+
debug_plot.set_title("Slices", title)
|
|
738
|
+
|
|
739
|
+
|
|
740
|
+
__call_id__ = 0
|
|
741
|
+
__img_num__ = 0
|
|
696
742
|
|
|
697
743
|
def slice_contours(data, inner, outer, distance=50, npoints=15, do_fit=False, show=False) -> list[Segment]:
|
|
698
744
|
"""Make slices between contours.
|
|
@@ -712,8 +758,11 @@ def slice_contours(data, inner, outer, distance=50, npoints=15, do_fit=False, sh
|
|
|
712
758
|
A list of Segments.
|
|
713
759
|
|
|
714
760
|
"""
|
|
715
|
-
global debug_plot
|
|
761
|
+
global debug_plot, __call_id__, __img_num__
|
|
716
762
|
|
|
763
|
+
__call_id__ += 1
|
|
764
|
+
__img_num__ = 0
|
|
765
|
+
#show=True
|
|
717
766
|
segments = []
|
|
718
767
|
dist = 0
|
|
719
768
|
npts = len(outer)
|
|
@@ -726,7 +775,15 @@ def slice_contours(data, inner, outer, distance=50, npoints=15, do_fit=False, sh
|
|
|
726
775
|
U = contours.find_closest(x0, y0, inner)
|
|
727
776
|
Tmin, Pmin, spread = get_T_profile(data, Point(x0, y0), Point(U[0], U[1]), npts=npoints, do_fit=do_fit, debug=False)
|
|
728
777
|
if show:
|
|
729
|
-
show_profile(debug_plot)
|
|
778
|
+
show_profile(debug_plot, "Dist {:.3f}, Tmin {:.2f} ({:.1f}, {:.1f})".format(dist, Tmin[0], Pmin[0].x, Pmin[0].y))
|
|
779
|
+
debug_plot.savefig("Slices", "/tmp/img_{}_{}.png".format(__call_id__, __img_num__))
|
|
780
|
+
__img_num__ += 1
|
|
781
|
+
try:
|
|
782
|
+
ax = debug_plot.get_ax("Contours")
|
|
783
|
+
ax.plot([x0, U[0]], [y0, U[1]], '-')
|
|
784
|
+
ax.plot(Pmin[0].x, Pmin[0].y, 'o')
|
|
785
|
+
except KeyError:
|
|
786
|
+
pass
|
|
730
787
|
|
|
731
788
|
# store results: distance along segment and temperature
|
|
732
789
|
T = []
|
|
@@ -764,7 +821,16 @@ def slice_contours(data, inner, outer, distance=50, npoints=15, do_fit=False, sh
|
|
|
764
821
|
|
|
765
822
|
segments.append(Segment((x0, y0), V, Pmin, path_length, Tmin, spread))
|
|
766
823
|
if show:
|
|
767
|
-
show_profile(debug_plot)
|
|
824
|
+
show_profile(debug_plot, "Dist {:.3f} Tmin {:.2f} ({:.1f}, {:.1f})".format(path_length, Tmin[0], Pmin[0].x, Pmin[0].y))
|
|
825
|
+
debug_plot.savefig("Slices", "/tmp/img_{}_{}.png".format(__call_id__, __img_num__))
|
|
826
|
+
__img_num__ += 1
|
|
827
|
+
|
|
828
|
+
try:
|
|
829
|
+
ax = debug_plot.get_ax("Contours")
|
|
830
|
+
ax.plot([x0, V[0]], [y0, V[1]], '-')
|
|
831
|
+
ax.plot(Pmin[0].x, Pmin[0].y, 'o')
|
|
832
|
+
except KeyError:
|
|
833
|
+
pass
|
|
768
834
|
|
|
769
835
|
dist = 0
|
|
770
836
|
|
|
@@ -772,6 +838,7 @@ def slice_contours(data, inner, outer, distance=50, npoints=15, do_fit=False, sh
|
|
|
772
838
|
if show:
|
|
773
839
|
debug_plot.setup_debug("SlicePipe")
|
|
774
840
|
debug_plot.plot("SlicePipe", D, T, '-o')
|
|
841
|
+
debug_plot.savefig("SlicePipe", "/tmp/slice_pipe_{}.png".format(__call_id__))
|
|
775
842
|
|
|
776
843
|
return segments
|
|
777
844
|
|
|
@@ -829,10 +896,12 @@ def find_image_contours(data, params):
|
|
|
829
896
|
print("contour area: {:.3f}".format(area))
|
|
830
897
|
|
|
831
898
|
if params.debug:
|
|
899
|
+
debug_plot.setup_debug("Contours", 1, 1)
|
|
832
900
|
colors = ["#ff9b54", "#ff7f51"] # ["#540b0e", "#9e2a2b"]
|
|
833
901
|
print("Number of countours:", len(out))
|
|
834
902
|
|
|
835
|
-
|
|
903
|
+
ax = debug_plot.get_ax("Contours")
|
|
904
|
+
ax.clear()
|
|
836
905
|
ax.imshow(data, origin='lower', cmap='jet')
|
|
837
906
|
for i, cnt in enumerate(out):
|
|
838
907
|
ax.plot(cnt[:, 0], cnt[:, 1], linewidth=3, color=colors[i % 2])
|
|
@@ -870,6 +939,7 @@ def get_segments(data, params) -> list[Segment]:
|
|
|
870
939
|
list of segments. See `slice_contours`
|
|
871
940
|
|
|
872
941
|
"""
|
|
942
|
+
global the_3d_points
|
|
873
943
|
cntrs = find_image_contours(data, params)
|
|
874
944
|
if cntrs is None:
|
|
875
945
|
return None
|
|
@@ -881,6 +951,7 @@ def get_segments(data, params) -> list[Segment]:
|
|
|
881
951
|
do_fit=params.do_fit,
|
|
882
952
|
show=params.debug)
|
|
883
953
|
|
|
954
|
+
the_3d_points = Segment.get_3d_points_in_list(the_segments)
|
|
884
955
|
return the_segments
|
|
885
956
|
|
|
886
957
|
|
|
@@ -30,7 +30,7 @@ class AnalysisResult(object):
|
|
|
30
30
|
continue
|
|
31
31
|
|
|
32
32
|
|
|
33
|
-
def show_2D_image(img, title=None):
|
|
33
|
+
def show_2D_image(img, title=None, show_fig=True):
|
|
34
34
|
"""Show a 2D image."""
|
|
35
35
|
if isinstance(img, list):
|
|
36
36
|
fig, ax = plt.subplots(1, len(img))
|
|
@@ -51,8 +51,9 @@ def show_2D_image(img, title=None):
|
|
|
51
51
|
pcm = ax.imshow(img, origin='lower', cmap=HighContrast.reversed()) # cmap="jet")
|
|
52
52
|
fig.colorbar(pcm, ax=ax)
|
|
53
53
|
|
|
54
|
-
|
|
55
|
-
|
|
54
|
+
if show_fig:
|
|
55
|
+
plt.draw()
|
|
56
|
+
plt.pause(0.001)
|
|
56
57
|
|
|
57
58
|
return fig, ax
|
|
58
59
|
|
petal_qc/thermal/PipeFit.py
CHANGED
|
@@ -498,7 +498,7 @@ class PipeFit(object):
|
|
|
498
498
|
|
|
499
499
|
return X, Y
|
|
500
500
|
|
|
501
|
-
def plot(self):
|
|
501
|
+
def plot(self, show_fig=True):
|
|
502
502
|
"""Plot result of fit and data."""
|
|
503
503
|
fig, ax = plt.subplots(1, 1, tight_layout=True)
|
|
504
504
|
ax.plot(self.pipe[:, 0], self.pipe[:, 1], label="Pipe")
|
|
@@ -509,8 +509,9 @@ class PipeFit(object):
|
|
|
509
509
|
|
|
510
510
|
ax.plot(out[:, 0], out[:, 1], 'o', label="Data")
|
|
511
511
|
ax.legend()
|
|
512
|
-
|
|
513
|
-
|
|
512
|
+
if show_fig:
|
|
513
|
+
plt.draw()
|
|
514
|
+
plt.pause(0.0001)
|
|
514
515
|
return fig, ax
|
|
515
516
|
|
|
516
517
|
|