petal-qc 0.0.14.dev1__tar.gz → 0.0.15__tar.gz
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-0.0.14.dev1 → petal_qc-0.0.15}/PKG-INFO +1 -1
- {petal_qc-0.0.14.dev1 → petal_qc-0.0.15}/petal_qc/__init__.py +7 -2
- {petal_qc-0.0.14.dev1 → petal_qc-0.0.15}/petal_qc/metrology/analyze_locking_points.py +4 -4
- {petal_qc-0.0.14.dev1 → petal_qc-0.0.15}/petal_qc/metrology/compare_Cores.py +25 -4
- {petal_qc-0.0.14.dev1 → petal_qc-0.0.15}/petal_qc/metrology/do_Metrology.py +30 -3
- petal_qc-0.0.15/petal_qc/test/createMetrologyFile.py +77 -0
- petal_qc-0.0.15/petal_qc/test/desyModuleBow.py +126 -0
- petal_qc-0.0.15/petal_qc/test/findRawData.py +92 -0
- {petal_qc-0.0.14.dev1 → petal_qc-0.0.15}/petal_qc/test/getPetalCoreTestSummary.py +18 -5
- {petal_qc-0.0.14.dev1 → petal_qc-0.0.15}/petal_qc/test/prepareDESYfiles.py +11 -1
- petal_qc-0.0.15/petal_qc/test/reportFromJSon.py +51 -0
- {petal_qc-0.0.14.dev1 → petal_qc-0.0.15}/petal_qc.egg-info/PKG-INFO +1 -1
- {petal_qc-0.0.14.dev1 → petal_qc-0.0.15}/petal_qc.egg-info/SOURCES.txt +4 -0
- {petal_qc-0.0.14.dev1 → petal_qc-0.0.15}/petal_qc.egg-info/entry_points.txt +1 -0
- {petal_qc-0.0.14.dev1 → petal_qc-0.0.15}/pyproject.toml +2 -1
- {petal_qc-0.0.14.dev1 → petal_qc-0.0.15}/README.md +0 -0
- {petal_qc-0.0.14.dev1 → petal_qc-0.0.15}/petal_qc/BTreport/CheckBTtests.py +0 -0
- {petal_qc-0.0.14.dev1 → petal_qc-0.0.15}/petal_qc/BTreport/__init__.py +0 -0
- {petal_qc-0.0.14.dev1 → petal_qc-0.0.15}/petal_qc/BTreport/bustapeReport.py +0 -0
- {petal_qc-0.0.14.dev1 → petal_qc-0.0.15}/petal_qc/PetalReceptionTests.py +0 -0
- {petal_qc-0.0.14.dev1 → petal_qc-0.0.15}/petal_qc/dashBoard.py +0 -0
- {petal_qc-0.0.14.dev1 → petal_qc-0.0.15}/petal_qc/metrology/Cluster.py +0 -0
- {petal_qc-0.0.14.dev1 → petal_qc-0.0.15}/petal_qc/metrology/DataFile.py +0 -0
- {petal_qc-0.0.14.dev1 → petal_qc-0.0.15}/petal_qc/metrology/PetalMetrology.py +0 -0
- {petal_qc-0.0.14.dev1 → petal_qc-0.0.15}/petal_qc/metrology/__init__.py +0 -0
- {petal_qc-0.0.14.dev1 → petal_qc-0.0.15}/petal_qc/metrology/all2csv.py +0 -0
- {petal_qc-0.0.14.dev1 → petal_qc-0.0.15}/petal_qc/metrology/cold_noise.py +0 -0
- {petal_qc-0.0.14.dev1 → petal_qc-0.0.15}/petal_qc/metrology/comparisonTable.py +0 -0
- {petal_qc-0.0.14.dev1 → petal_qc-0.0.15}/petal_qc/metrology/convert_mitutoyo.py +0 -0
- {petal_qc-0.0.14.dev1 → petal_qc-0.0.15}/petal_qc/metrology/convert_smartscope.py +0 -0
- {petal_qc-0.0.14.dev1 → petal_qc-0.0.15}/petal_qc/metrology/coreMetrology.py +0 -0
- {petal_qc-0.0.14.dev1 → petal_qc-0.0.15}/petal_qc/metrology/data2csv.py +0 -0
- {petal_qc-0.0.14.dev1 → petal_qc-0.0.15}/petal_qc/metrology/flatness4nigel.py +0 -0
- {petal_qc-0.0.14.dev1 → petal_qc-0.0.15}/petal_qc/metrology/gtkutils.py +0 -0
- {petal_qc-0.0.14.dev1 → petal_qc-0.0.15}/petal_qc/metrology/petal_flatness.py +0 -0
- {petal_qc-0.0.14.dev1 → petal_qc-0.0.15}/petal_qc/metrology/readAVSdata.py +0 -0
- {petal_qc-0.0.14.dev1 → petal_qc-0.0.15}/petal_qc/metrology/show_data_file.py +0 -0
- {petal_qc-0.0.14.dev1 → petal_qc-0.0.15}/petal_qc/metrology/testSummary.py +0 -0
- {petal_qc-0.0.14.dev1 → petal_qc-0.0.15}/petal_qc/metrology/test_paralelism.py +0 -0
- {petal_qc-0.0.14.dev1 → petal_qc-0.0.15}/petal_qc/metrology/uploadPetalInformation.py +0 -0
- {petal_qc-0.0.14.dev1 → petal_qc-0.0.15}/petal_qc/test/checkAVStests.py +0 -0
- {petal_qc-0.0.14.dev1 → petal_qc-0.0.15}/petal_qc/test/compare_golden.py +0 -0
- {petal_qc-0.0.14.dev1 → petal_qc-0.0.15}/petal_qc/test/getAVSjson.py +0 -0
- {petal_qc-0.0.14.dev1 → petal_qc-0.0.15}/petal_qc/test/getAVStests.py +0 -0
- {petal_qc-0.0.14.dev1 → petal_qc-0.0.15}/petal_qc/test/listPetalCoreComponents.py +0 -0
- {petal_qc-0.0.14.dev1 → petal_qc-0.0.15}/petal_qc/test/test_Graphana.py +0 -0
- {petal_qc-0.0.14.dev1 → petal_qc-0.0.15}/petal_qc/test/test_coreThermal.py +0 -0
- {petal_qc-0.0.14.dev1 → petal_qc-0.0.15}/petal_qc/thermal/CSVImage.py +0 -0
- {petal_qc-0.0.14.dev1 → petal_qc-0.0.15}/petal_qc/thermal/DESYdata.py +0 -0
- {petal_qc-0.0.14.dev1 → petal_qc-0.0.15}/petal_qc/thermal/DebugPlot.py +0 -0
- {petal_qc-0.0.14.dev1 → petal_qc-0.0.15}/petal_qc/thermal/IRBFile.py +0 -0
- {petal_qc-0.0.14.dev1 → petal_qc-0.0.15}/petal_qc/thermal/IRCore.py +0 -0
- {petal_qc-0.0.14.dev1 → petal_qc-0.0.15}/petal_qc/thermal/IRDataGetter.py +0 -0
- {petal_qc-0.0.14.dev1 → petal_qc-0.0.15}/petal_qc/thermal/IRPetal.py +0 -0
- {petal_qc-0.0.14.dev1 → petal_qc-0.0.15}/petal_qc/thermal/IRPetalParam.py +0 -0
- {petal_qc-0.0.14.dev1 → petal_qc-0.0.15}/petal_qc/thermal/PetalColorMaps.py +0 -0
- {petal_qc-0.0.14.dev1 → petal_qc-0.0.15}/petal_qc/thermal/Petal_IR_Analysis.py +0 -0
- {petal_qc-0.0.14.dev1 → petal_qc-0.0.15}/petal_qc/thermal/PipeFit.py +0 -0
- {petal_qc-0.0.14.dev1 → petal_qc-0.0.15}/petal_qc/thermal/__init__.py +0 -0
- {petal_qc-0.0.14.dev1 → petal_qc-0.0.15}/petal_qc/thermal/analyze_IRCore.py +0 -0
- {petal_qc-0.0.14.dev1 → petal_qc-0.0.15}/petal_qc/thermal/contours.py +0 -0
- {petal_qc-0.0.14.dev1 → petal_qc-0.0.15}/petal_qc/thermal/coreThermal.py +0 -0
- {petal_qc-0.0.14.dev1 → petal_qc-0.0.15}/petal_qc/thermal/create_IRCore.py +0 -0
- {petal_qc-0.0.14.dev1 → petal_qc-0.0.15}/petal_qc/thermal/create_core_report.py +0 -0
- {petal_qc-0.0.14.dev1 → petal_qc-0.0.15}/petal_qc/thermal/pipe_back.npz +0 -0
- {petal_qc-0.0.14.dev1 → petal_qc-0.0.15}/petal_qc/thermal/pipe_front.npz +0 -0
- {petal_qc-0.0.14.dev1 → petal_qc-0.0.15}/petal_qc/thermal/pipe_read.py +0 -0
- {petal_qc-0.0.14.dev1 → petal_qc-0.0.15}/petal_qc/thermal/show_IR_petal.py +0 -0
- {petal_qc-0.0.14.dev1 → petal_qc-0.0.15}/petal_qc/utils/Geometry.py +0 -0
- {petal_qc-0.0.14.dev1 → petal_qc-0.0.15}/petal_qc/utils/Progress.py +0 -0
- {petal_qc-0.0.14.dev1 → petal_qc-0.0.15}/petal_qc/utils/__init__.py +0 -0
- {petal_qc-0.0.14.dev1 → petal_qc-0.0.15}/petal_qc/utils/all_files.py +0 -0
- {petal_qc-0.0.14.dev1 → petal_qc-0.0.15}/petal_qc/utils/docx_utils.py +0 -0
- {petal_qc-0.0.14.dev1 → petal_qc-0.0.15}/petal_qc/utils/fit_utils.py +0 -0
- {petal_qc-0.0.14.dev1 → petal_qc-0.0.15}/petal_qc/utils/readGraphana.py +0 -0
- {petal_qc-0.0.14.dev1 → petal_qc-0.0.15}/petal_qc/utils/utils.py +0 -0
- {petal_qc-0.0.14.dev1 → petal_qc-0.0.15}/petal_qc.egg-info/dependency_links.txt +0 -0
- {petal_qc-0.0.14.dev1 → petal_qc-0.0.15}/petal_qc.egg-info/requires.txt +0 -0
- {petal_qc-0.0.14.dev1 → petal_qc-0.0.15}/petal_qc.egg-info/top_level.txt +0 -0
- {petal_qc-0.0.14.dev1 → petal_qc-0.0.15}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: petal_qc
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.15
|
|
4
4
|
Summary: A collection of scripts for Petal CORE QC.
|
|
5
5
|
Author-email: Carlos Lacasta <carlos.lacasta@cern.ch>
|
|
6
6
|
Project-URL: Homepage, https://gitlab.cern.ch/atlas-itk/sw/db/itk-pdb-gtk-gui-utils
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"""petal_qc python module."""
|
|
2
|
-
__version__ = "0.0.
|
|
2
|
+
__version__ = "0.0.15"
|
|
3
3
|
|
|
4
4
|
|
|
5
5
|
def coreMetrology():
|
|
@@ -9,9 +9,14 @@ def coreMetrology():
|
|
|
9
9
|
|
|
10
10
|
def doMetrology():
|
|
11
11
|
"""Launches the Core metrology analysis in the command line."""
|
|
12
|
-
from .metrology.
|
|
12
|
+
from .metrology.do_Metrology import main
|
|
13
13
|
main()
|
|
14
14
|
|
|
15
|
+
def coreMetrologyTTY():
|
|
16
|
+
"""Launches the Core metrology analysis in the command line."""
|
|
17
|
+
from .metrology.do_Metrology import analyze_core_metrology
|
|
18
|
+
analyze_core_metrology()
|
|
19
|
+
|
|
15
20
|
def coreThermal():
|
|
16
21
|
"""Launches the Core thermal analysis ahd PDB script."""
|
|
17
22
|
from .thermal.coreThermal import main
|
|
@@ -513,12 +513,12 @@ def locking_point_positions(positions, document=None):
|
|
|
513
513
|
dPL2 = np.linalg.norm(positions[1, 0:2] - positions[4, 0:2])
|
|
514
514
|
deltaPL1 = (nPL1-dPL1)
|
|
515
515
|
deltaPL2 = (nPL2-dPL2)
|
|
516
|
-
fPL1 = "PASSED" if abs(deltaPL1) <= 0.
|
|
517
|
-
fPL2 = "PASSED" if abs(deltaPL2) <= 0.
|
|
516
|
+
fPL1 = "PASSED" if abs(deltaPL1) <= 0.075 else "FAILED"
|
|
517
|
+
fPL2 = "PASSED" if abs(deltaPL2) <= 0.075 else "FAILED"
|
|
518
518
|
|
|
519
519
|
for key, val in outDB["REL_POS_DELTA"].items():
|
|
520
520
|
deltaPL = np.linalg.norm(val)
|
|
521
|
-
fPL = "PASSED" if abs(deltaPL) <= 0.
|
|
521
|
+
fPL = "PASSED" if abs(deltaPL) <= 0.075 else "FAILED"
|
|
522
522
|
print("Distance {}: {:.3f} mm ({})".format(key, deltaPL, fPL))
|
|
523
523
|
|
|
524
524
|
if document:
|
|
@@ -559,7 +559,7 @@ def locking_point_positions(positions, document=None):
|
|
|
559
559
|
document.add_paragraph("")
|
|
560
560
|
for key, val in outDB["REL_POS_DELTA"].items():
|
|
561
561
|
deltaPL = np.linalg.norm(val)
|
|
562
|
-
fPL = "PASSED" if abs(deltaPL) <= 0.
|
|
562
|
+
fPL = "PASSED" if abs(deltaPL) <= 0.075 else "FAILED"
|
|
563
563
|
document.add_paragraph("Distance {}: {:.3f} mm ({})".format(key, deltaPL, fPL))
|
|
564
564
|
|
|
565
565
|
return outDB
|
|
@@ -5,6 +5,7 @@ import sys
|
|
|
5
5
|
import argparse
|
|
6
6
|
import glob
|
|
7
7
|
import json
|
|
8
|
+
import math
|
|
8
9
|
from pathlib import Path
|
|
9
10
|
import numpy as np
|
|
10
11
|
import matplotlib.pyplot as plt
|
|
@@ -100,17 +101,22 @@ def draw_deltas(data, keys, fnam=None, title="Front", draw_text=True):
|
|
|
100
101
|
P = [np.zeros([nfiles, 2]),
|
|
101
102
|
np.zeros([nfiles, 2]),
|
|
102
103
|
np.zeros([nfiles, 2])]
|
|
104
|
+
D = [[],[],[]]
|
|
105
|
+
|
|
103
106
|
fig_width = 12.0
|
|
104
107
|
fig_height = 1.2*fig_width/3.0
|
|
105
108
|
fig, ax = plt.subplots(nrows=1, ncols=3, tight_layout=True, figsize=(fig_width, fig_height))
|
|
106
109
|
fig.suptitle(title)
|
|
110
|
+
figb, bx = plt.subplots(nrows=1, ncols=3, tight_layout=True, figsize=(fig_width, fig_height))
|
|
111
|
+
figb.suptitle(title)
|
|
112
|
+
|
|
107
113
|
for i in range(3):
|
|
108
114
|
LBL = [[],[],[]]
|
|
109
115
|
ax[i].set_title(keys[i])
|
|
110
116
|
ax[i].set_aspect('equal', adjustable='box')
|
|
111
|
-
ax[i].set_xlim(-
|
|
112
|
-
ax[i].set_ylim(-
|
|
113
|
-
circle = plt.Circle((0,0),
|
|
117
|
+
ax[i].set_xlim(-150, 150)
|
|
118
|
+
ax[i].set_ylim(-150, 150)
|
|
119
|
+
circle = plt.Circle((0,0), 75, color="red", alpha=0.25)
|
|
114
120
|
ax[i].add_patch(circle)
|
|
115
121
|
circle = plt.Circle((0,0), 25, color="green", alpha=0.25)
|
|
116
122
|
ax[i].add_patch(circle)
|
|
@@ -118,20 +124,34 @@ def draw_deltas(data, keys, fnam=None, title="Front", draw_text=True):
|
|
|
118
124
|
ax[i].set_xlabel("X (µm)")
|
|
119
125
|
ax[i].set_ylabel("Y (µm)")
|
|
120
126
|
ax[i].grid()
|
|
127
|
+
|
|
128
|
+
bx[i].set_title(keys[i])
|
|
129
|
+
bx[i].set_xlabel("Distance (µm)")
|
|
130
|
+
bx[i].grid()
|
|
131
|
+
|
|
121
132
|
|
|
122
133
|
for j, v in enumerate(data.items()):
|
|
123
134
|
label, values = v
|
|
124
135
|
for k in range(3):
|
|
125
136
|
ky = key_table[keys[k]]
|
|
126
|
-
|
|
137
|
+
point = 1000*np.array(values[ky])
|
|
138
|
+
P[k][j, :] = point
|
|
139
|
+
D[k].append(math.sqrt(point[0]**2+point[1]**2))
|
|
127
140
|
LBL[k].append(label.split('.')[1].lstrip('0'))
|
|
128
141
|
|
|
142
|
+
bx[i].hist(D[i], bins=15, range=(0, 150))
|
|
129
143
|
ax[i].scatter(P[i][:,0], P[i][:,1])
|
|
130
144
|
if draw_text:
|
|
131
145
|
for j in range(len(LBL[i])):
|
|
132
146
|
ax[i].text(P[i][j,0], P[i][j,1], LBL[i][j]) #, ha='center', va='top')
|
|
133
147
|
|
|
148
|
+
ofile = Path(fnam).expanduser().resolve()
|
|
149
|
+
print("* parent: ", ofile.parent)
|
|
150
|
+
print("* stem: ", ofile.stem)
|
|
151
|
+
bnam = ofile.parent / "{}-h.png".format(ofile.stem)
|
|
152
|
+
print(bnam.as_posix())
|
|
134
153
|
save_figure(fig, fnam, prefix=title)
|
|
154
|
+
save_figure(figb, bnam, prefix=title)
|
|
135
155
|
|
|
136
156
|
|
|
137
157
|
def show_positions(options):
|
|
@@ -184,6 +204,7 @@ def show_flatness(options):
|
|
|
184
204
|
a.set_ylim(0, 1.2*max(y_lim[0][1], y_lim[1][1]))
|
|
185
205
|
x_lim = a.get_xlim()
|
|
186
206
|
a.fill_between(x_lim, 0, 0.050, facecolor="darkseagreen", alpha=0.1)
|
|
207
|
+
a.fill_between(x_lim, 0.050, 0.100, facecolor="mediumseagreen", alpha=0.1)
|
|
187
208
|
if not options.no_legend:
|
|
188
209
|
a.legend(ncol=3, fontsize="x-small")
|
|
189
210
|
|
|
@@ -68,6 +68,7 @@ def do_analysis(fnam, prefix, SN, options):
|
|
|
68
68
|
|
|
69
69
|
def analyze_files(ifile, options):
|
|
70
70
|
"""Main entry."""
|
|
71
|
+
failed_files = []
|
|
71
72
|
with open(ifile, 'r', encoding='UTF-8') as inp:
|
|
72
73
|
|
|
73
74
|
for line in inp:
|
|
@@ -84,10 +85,26 @@ def analyze_files(ifile, options):
|
|
|
84
85
|
except Exception:
|
|
85
86
|
fnam, prefix, SN, *_ = line.split()
|
|
86
87
|
|
|
87
|
-
|
|
88
|
+
try:
|
|
89
|
+
with open(fnam, "r", encoding="ISO-8859-1") as fin:
|
|
90
|
+
ss = fin.read()
|
|
91
|
+
if ss.find("Punto:")<0:
|
|
92
|
+
options.desy=True
|
|
93
|
+
else:
|
|
94
|
+
options.desy=False
|
|
95
|
+
|
|
96
|
+
do_analysis(fnam, prefix, SN, options)
|
|
97
|
+
print("\n\n")
|
|
98
|
+
except Exception as E:
|
|
99
|
+
failed_files.append([fnam, E])
|
|
100
|
+
continue
|
|
88
101
|
|
|
89
|
-
|
|
90
|
-
|
|
102
|
+
if len(failed_files)>0:
|
|
103
|
+
for fnam, E in failed_files:
|
|
104
|
+
print("### Failed file {}\n{}".format(fnam, E))
|
|
105
|
+
|
|
106
|
+
def parse_options():
|
|
107
|
+
"""Parse command line options."""
|
|
91
108
|
parser = ArgumentParser()
|
|
92
109
|
parser.add_argument('files', nargs='*', help="Input files")
|
|
93
110
|
parser.add_argument("--prefix", dest='prefix', default=None, help="prefix telling if it is front or back.")
|
|
@@ -113,11 +130,21 @@ def main():
|
|
|
113
130
|
print("I need an input file")
|
|
114
131
|
sys.exit()
|
|
115
132
|
|
|
133
|
+
return options
|
|
134
|
+
|
|
135
|
+
def main():
|
|
136
|
+
"Main entry."
|
|
137
|
+
options = parse_options()
|
|
116
138
|
try:
|
|
117
139
|
analyze_files(options.files[0], options)
|
|
118
140
|
|
|
119
141
|
except Exception:
|
|
120
142
|
print(traceback.format_exc())
|
|
121
143
|
|
|
144
|
+
def analyze_core_metrology():
|
|
145
|
+
"""Do a single file analysis."""
|
|
146
|
+
options = parse_options()
|
|
147
|
+
do_analysis(options.files[0], options.prefix, options.SN, options)
|
|
148
|
+
|
|
122
149
|
if __name__ == "__main__":
|
|
123
150
|
main()
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Locates all raw data files."""
|
|
3
|
+
|
|
4
|
+
import os
|
|
5
|
+
import sys
|
|
6
|
+
import fnmatch
|
|
7
|
+
import re
|
|
8
|
+
import shutil
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
import argparse
|
|
11
|
+
|
|
12
|
+
def all_files(root, patterns='*', single_level=False, yield_folders=False):
|
|
13
|
+
"""A generator that reruns all files in the given folder.
|
|
14
|
+
|
|
15
|
+
Args:
|
|
16
|
+
----
|
|
17
|
+
root (file path): The folder
|
|
18
|
+
patterns (str, optional): The pattern of the files. Defaults to '*'.
|
|
19
|
+
single_level (bool, optional): If true, do not go into sub folders. Defaults to False.
|
|
20
|
+
yield_folders (bool, optional): If True, return folders as well. Defaults to False.
|
|
21
|
+
|
|
22
|
+
Yields
|
|
23
|
+
------
|
|
24
|
+
str: file path name
|
|
25
|
+
|
|
26
|
+
"""
|
|
27
|
+
patterns = patterns.split(';')
|
|
28
|
+
for path, subdirs, files in os.walk(root):
|
|
29
|
+
if yield_folders:
|
|
30
|
+
files.extend(subdirs)
|
|
31
|
+
|
|
32
|
+
files.sort()
|
|
33
|
+
for name in files:
|
|
34
|
+
for pattern in patterns:
|
|
35
|
+
if fnmatch.fnmatch(name, pattern):
|
|
36
|
+
yield os.path.join(path, name)
|
|
37
|
+
break
|
|
38
|
+
|
|
39
|
+
if single_level:
|
|
40
|
+
break
|
|
41
|
+
|
|
42
|
+
def main(options):
|
|
43
|
+
"""Locate raw data files in input folder and copies them in out folder
|
|
44
|
+
|
|
45
|
+
Args:
|
|
46
|
+
folder_in (Path): Input folder
|
|
47
|
+
folder_oyt (Path): Output folder
|
|
48
|
+
"""
|
|
49
|
+
reg = re.compile(r"(PPC\.[0-9]+)-(\w+)")
|
|
50
|
+
outF = Path(options.output).expanduser().resolve()
|
|
51
|
+
with open(outF, "w", encoding="utf-8") as fout:
|
|
52
|
+
for folder_in in options.files:
|
|
53
|
+
inF = Path(folder_in).expanduser().resolve()
|
|
54
|
+
if not inF.exists():
|
|
55
|
+
print("Input folder does not exist. {}".format(inF))
|
|
56
|
+
continue
|
|
57
|
+
|
|
58
|
+
for fnam in all_files(inF, "PPC*.txt", yield_folders=False):
|
|
59
|
+
R = reg.search(fnam)
|
|
60
|
+
if R is None:
|
|
61
|
+
continue
|
|
62
|
+
|
|
63
|
+
petal_id = R.group(1)
|
|
64
|
+
side = R.group(2)
|
|
65
|
+
fout.write("{ifile} {pid}-{side} {pid}\n".format(ifile=fnam, side=side, pid=petal_id))
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
if __name__ == "__main__":
|
|
69
|
+
parser = argparse.ArgumentParser()
|
|
70
|
+
parser.add_argument('files', nargs='*', help="Input files")
|
|
71
|
+
parser.add_argument("--output", dest="output", help="Output file", default="out.txt")
|
|
72
|
+
opts = parser.parse_args()
|
|
73
|
+
if len(opts.files)==0:
|
|
74
|
+
print("I need at least one input folder")
|
|
75
|
+
sys.exit(-1)
|
|
76
|
+
|
|
77
|
+
main(opts)
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Get module bow from desy metrology files"""
|
|
3
|
+
import sys
|
|
4
|
+
import re
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
import matplotlib.pyplot as plt
|
|
7
|
+
import numpy as np
|
|
8
|
+
import numpy.linalg as linalg
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
from petal_qc.utils.all_files import all_files
|
|
12
|
+
from petal_qc.metrology import DataFile
|
|
13
|
+
from petal_qc.metrology import DataFile
|
|
14
|
+
from petal_qc.utils.Geometry import fit_plane
|
|
15
|
+
from petal_qc.utils.Geometry import project_to_plane
|
|
16
|
+
from petal_qc.utils.Geometry import remove_outliers_indx
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
rgx = "serialNo =\\s+([A-Z0-9]+)"
|
|
20
|
+
serial_no = re.compile(rgx)
|
|
21
|
+
|
|
22
|
+
mtype = re.compile("Project Name:\\s+([A-Za-z0-9]+)_bow")
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def get_array_range(A):
|
|
26
|
+
"""Gets mean and range of given array."""
|
|
27
|
+
avg = np.mean(A)
|
|
28
|
+
imin = np.argmin(A)
|
|
29
|
+
vmin = A[imin]
|
|
30
|
+
imax = np.argmax(A)
|
|
31
|
+
vmax = A[imax]
|
|
32
|
+
stdv = np.std(A)
|
|
33
|
+
return avg, stdv, [vmin, vmax], [imin, imax]
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def create_bow_figure(SN, mtype, pout, width) -> plt.Figure:
|
|
38
|
+
"""Create the sensor bow figure.
|
|
39
|
+
|
|
40
|
+
Args:
|
|
41
|
+
options: Program options.
|
|
42
|
+
pout: set of points
|
|
43
|
+
width: the actual bow.
|
|
44
|
+
|
|
45
|
+
Returns:
|
|
46
|
+
plt.Figure: The bow figure.
|
|
47
|
+
"""
|
|
48
|
+
fig_bow, ax = plt.subplots(subplot_kw={'projection': '3d'})
|
|
49
|
+
fig_bow.suptitle(r"{}_{} - Sensor bow {:.1f} $\mu$m".format(SN, mtype, width))
|
|
50
|
+
|
|
51
|
+
zplt = 1000*pout[:, 2]
|
|
52
|
+
# surf = ax.plot_trisurf(pout[:, 0], pout[:, 1], zplt, cmap=plt.cm.jet, edgecolor="black", linewidths=0.2)
|
|
53
|
+
surf = ax.scatter(pout[:, 0], pout[:, 1], zplt, c=zplt, marker="o", edgecolor='none')
|
|
54
|
+
ax.set_xlabel("X")
|
|
55
|
+
ax.set_ylabel("Y")
|
|
56
|
+
ax.set_zlabel("Z")
|
|
57
|
+
cbar = fig_bow.colorbar(surf, shrink=0.5, aspect=5, location="left")
|
|
58
|
+
cbar.set_label(r"Z ($\mu$m)")
|
|
59
|
+
return fig_bow
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def module_bow(ifile):
|
|
63
|
+
"""Compute module bow."""
|
|
64
|
+
SN = None
|
|
65
|
+
mod_type = None
|
|
66
|
+
print(Path(ifile).name)
|
|
67
|
+
with open(ifile, "r", encoding="utf-8") as fin:
|
|
68
|
+
ss = fin.read()
|
|
69
|
+
mtx = serial_no.search(ss)
|
|
70
|
+
if mtx:
|
|
71
|
+
SN = mtx.group(1)
|
|
72
|
+
|
|
73
|
+
mtp = mtype.search(ss)
|
|
74
|
+
if mtp:
|
|
75
|
+
mod_type = mtp.group(1)
|
|
76
|
+
|
|
77
|
+
if SN is None:
|
|
78
|
+
return None, None, None
|
|
79
|
+
|
|
80
|
+
print("{} - {}".format(SN, mod_type))
|
|
81
|
+
|
|
82
|
+
data = DataFile.read(ifile, "(Bow|Sensor)")
|
|
83
|
+
if len(data) == 0:
|
|
84
|
+
return None, None, None
|
|
85
|
+
|
|
86
|
+
# Try to remove locator points and get the plane
|
|
87
|
+
indx = remove_outliers_indx(data[:, 2])
|
|
88
|
+
M, TM, *_ = fit_plane(data[indx], use_average=False)
|
|
89
|
+
|
|
90
|
+
# project all data to the plane
|
|
91
|
+
Zmean = np.mean(M[:, 2])
|
|
92
|
+
M[:, 2] -= Zmean
|
|
93
|
+
|
|
94
|
+
mean, stdev, rng, irng = get_array_range(M[:, 2])
|
|
95
|
+
width = 1000*(rng[1]-rng[0])
|
|
96
|
+
|
|
97
|
+
# Check which one is closest to the center
|
|
98
|
+
min2center = linalg.norm(M[irng[0], 0:2])
|
|
99
|
+
max2center = linalg.norm(M[irng[1], 0:2])
|
|
100
|
+
# If center above the top, bow negative
|
|
101
|
+
if max2center < min2center:
|
|
102
|
+
width = -width
|
|
103
|
+
|
|
104
|
+
print("Sensor bow\nAverage: {:.1f} min {:.1f} max {:.1f} rng {:.1f}\n".format(
|
|
105
|
+
mean, 1000*rng[0], 1000*rng[1], width))
|
|
106
|
+
|
|
107
|
+
fig_bow = create_bow_figure(SN, mod_type, M, width)
|
|
108
|
+
fig_bow.savefig("{}-{}-bow.png".format(SN, mod_type), dpi=300)
|
|
109
|
+
plt.close(fig_bow)
|
|
110
|
+
del fig_bow
|
|
111
|
+
return SN, mod_type, width
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def main(folder):
|
|
115
|
+
"""Main entry"""
|
|
116
|
+
fout = open("module-bow.txt", "w", encoding="utf-8")
|
|
117
|
+
for fnam in all_files(folder, "*.txt"):
|
|
118
|
+
SN, mod_type, width = module_bow(fnam)
|
|
119
|
+
if SN:
|
|
120
|
+
fout.write("{}-{} : {:.3f}\n".format(SN, mod_type, width))
|
|
121
|
+
|
|
122
|
+
fout.close()
|
|
123
|
+
|
|
124
|
+
if __name__ == "__main__":
|
|
125
|
+
main("/Users/lacasta/Downloads/InterposerPetal")
|
|
126
|
+
#main("/Users/lacasta/Downloads/kkdvk")
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Locates all raw data files."""
|
|
3
|
+
|
|
4
|
+
import os
|
|
5
|
+
import sys
|
|
6
|
+
import fnmatch
|
|
7
|
+
import re
|
|
8
|
+
import shutil
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
import argparse
|
|
11
|
+
|
|
12
|
+
def all_files(root, patterns='*', single_level=False, yield_folders=False):
|
|
13
|
+
"""A generator that reruns all files in the given folder.
|
|
14
|
+
|
|
15
|
+
Args:
|
|
16
|
+
----
|
|
17
|
+
root (file path): The folder
|
|
18
|
+
patterns (str, optional): The pattern of the files. Defaults to '*'.
|
|
19
|
+
single_level (bool, optional): If true, do not go into sub folders. Defaults to False.
|
|
20
|
+
yield_folders (bool, optional): If True, return folders as well. Defaults to False.
|
|
21
|
+
|
|
22
|
+
Yields
|
|
23
|
+
------
|
|
24
|
+
str: file path name
|
|
25
|
+
|
|
26
|
+
"""
|
|
27
|
+
patterns = patterns.split(';')
|
|
28
|
+
for path, subdirs, files in os.walk(root):
|
|
29
|
+
if yield_folders:
|
|
30
|
+
files.extend(subdirs)
|
|
31
|
+
|
|
32
|
+
files.sort()
|
|
33
|
+
for name in files:
|
|
34
|
+
for pattern in patterns:
|
|
35
|
+
if fnmatch.fnmatch(name, pattern):
|
|
36
|
+
yield os.path.join(path, name)
|
|
37
|
+
break
|
|
38
|
+
|
|
39
|
+
if single_level:
|
|
40
|
+
break
|
|
41
|
+
|
|
42
|
+
def main(folder_in, folder_out):
|
|
43
|
+
"""Locate raw data files in input folder and copies them in out folder
|
|
44
|
+
|
|
45
|
+
Args:
|
|
46
|
+
folder_in (Path): Input folder
|
|
47
|
+
folder_oyt (Path): Output folder
|
|
48
|
+
"""
|
|
49
|
+
inF = Path(folder_in).expanduser().resolve()
|
|
50
|
+
if not inF.exists():
|
|
51
|
+
print("Input folder does not exist. {}".format(inF))
|
|
52
|
+
return
|
|
53
|
+
|
|
54
|
+
reg = re.compile(r"(PPC\.[0-9]+).*metr")
|
|
55
|
+
|
|
56
|
+
outF = Path(folder_out).expanduser().resolve()
|
|
57
|
+
if not outF.exists():
|
|
58
|
+
os.makedirs(outF.as_posix())
|
|
59
|
+
|
|
60
|
+
list_file = open("{}/raw-data-metrology-cores.txt".format(outF.as_posix()), "w", encoding="UTF-8")
|
|
61
|
+
for fnam in all_files(inF, "PPC*.txt", yield_folders=False):
|
|
62
|
+
R = reg.search(fnam)
|
|
63
|
+
if R is None:
|
|
64
|
+
continue
|
|
65
|
+
|
|
66
|
+
petal_id = R.group(1)
|
|
67
|
+
if "back" in fnam:
|
|
68
|
+
side = "{}-back".format(petal_id)
|
|
69
|
+
ofile = "{}-back.txt".format(petal_id)
|
|
70
|
+
elif "front" in fnam:
|
|
71
|
+
side = "{}-front".format(petal_id)
|
|
72
|
+
ofile = "{}-front.txt".format(petal_id)
|
|
73
|
+
else:
|
|
74
|
+
print("Invalid file {}".format(fnam))
|
|
75
|
+
continue
|
|
76
|
+
|
|
77
|
+
out_name = outF / ofile
|
|
78
|
+
list_file.write("{} {} {}\n".format(out_name.as_posix(), side, petal_id))
|
|
79
|
+
shutil.copy(fnam, out_name)
|
|
80
|
+
|
|
81
|
+
list_file.close()
|
|
82
|
+
|
|
83
|
+
if __name__ == "__main__":
|
|
84
|
+
parser = argparse.ArgumentParser()
|
|
85
|
+
parser.add_argument("--input-folder", dest="input", default=None, help="Input folder")
|
|
86
|
+
parser.add_argument("--output-folder", dest="output", help="Outout fodler", default=None)
|
|
87
|
+
opts = parser.parse_args()
|
|
88
|
+
if opts.input is None or opts.output is None:
|
|
89
|
+
print("I need both an input and an output folder.")
|
|
90
|
+
sys.exit(-1)
|
|
91
|
+
|
|
92
|
+
main(opts.input, opts.output)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
2
|
"""Get a summery of Petal core TEsts."""
|
|
3
|
-
|
|
3
|
+
import json
|
|
4
4
|
try:
|
|
5
5
|
import itkdb_gtk
|
|
6
6
|
|
|
@@ -14,7 +14,7 @@ from itkdb_gtk import ITkDBlogin, ITkDButils
|
|
|
14
14
|
from itkdb_gtk.dbGtkUtils import replace_in_container, DictDialog, ask_for_confirmation
|
|
15
15
|
|
|
16
16
|
|
|
17
|
-
def main(session):
|
|
17
|
+
def main(session, options):
|
|
18
18
|
"""Main entry point."""
|
|
19
19
|
|
|
20
20
|
# find all cores
|
|
@@ -24,17 +24,23 @@ def main(session):
|
|
|
24
24
|
#"componentType": ["BT"],
|
|
25
25
|
"componentType": ["CORE_PETAL"],
|
|
26
26
|
"type": ["CORE_AVS"],
|
|
27
|
-
"currentLocation": ["IFIC"],
|
|
27
|
+
# "currentLocation": ["IFIC"],
|
|
28
28
|
},
|
|
29
29
|
"sorterList": [
|
|
30
30
|
{"key": "alternativeIdentifier", "descending": False }
|
|
31
31
|
],
|
|
32
32
|
}
|
|
33
|
+
suff = "ALL"
|
|
34
|
+
if options.institute:
|
|
35
|
+
payload["filterMap"]["currentLocation"] = options.institute
|
|
36
|
+
suff = options.institute
|
|
37
|
+
|
|
33
38
|
core_list = session.get("listComponents", json=payload)
|
|
34
39
|
core_tests = ["PETAL_METROLOGY_FRONT", "PETAL_METROLOGY_BACK", "XRAYIMAGING", "THERMAL_EVALUATION", "BTTESTING"]
|
|
35
40
|
|
|
36
41
|
do_check_stage = "AT_QC_SITE"
|
|
37
42
|
#do_check_stage = None
|
|
43
|
+
petal_id_db = {}
|
|
38
44
|
|
|
39
45
|
for core in core_list:
|
|
40
46
|
SN = core["serialNumber"]
|
|
@@ -42,7 +48,7 @@ def main(session):
|
|
|
42
48
|
if "PPC" not in altid:
|
|
43
49
|
continue
|
|
44
50
|
|
|
45
|
-
|
|
51
|
+
petal_id_db[altid] = SN
|
|
46
52
|
location = core["currentLocation"]['code']
|
|
47
53
|
coreStage = core["currentStage"]['code']
|
|
48
54
|
if do_check_stage:
|
|
@@ -73,14 +79,21 @@ def main(session):
|
|
|
73
79
|
for D in T["defects"]:
|
|
74
80
|
print("\t{} - {}".format(D["name"], D["description"]))
|
|
75
81
|
|
|
82
|
+
with open("petal_ID_db_{}.json".format(suff), "w", encoding="utf-8") as fOut:
|
|
83
|
+
json.dump(petal_id_db, fOut, indent=3)
|
|
76
84
|
|
|
77
85
|
if __name__ == "__main__":
|
|
86
|
+
from argparse import ArgumentParser
|
|
87
|
+
parser = ArgumentParser()
|
|
88
|
+
parser.add_argument("--institute", default=None, help="The petal current location")
|
|
89
|
+
options = parser.parse_args()
|
|
90
|
+
|
|
78
91
|
# ITk_PB authentication
|
|
79
92
|
dlg = ITkDBlogin.ITkDBlogin()
|
|
80
93
|
session = dlg.get_client()
|
|
81
94
|
|
|
82
95
|
try:
|
|
83
|
-
main(session)
|
|
96
|
+
main(session, options)
|
|
84
97
|
|
|
85
98
|
except Exception as E:
|
|
86
99
|
print(E)
|
|
@@ -4,6 +4,7 @@ import os
|
|
|
4
4
|
import sys
|
|
5
5
|
import fnmatch
|
|
6
6
|
import re
|
|
7
|
+
import shutil
|
|
7
8
|
from pathlib import Path
|
|
8
9
|
import argparse
|
|
9
10
|
|
|
@@ -52,14 +53,23 @@ def main(folder, out_folder):
|
|
|
52
53
|
folder: the input folder where to find the original files.
|
|
53
54
|
out_folder: the folder where the new fiels will be stored.
|
|
54
55
|
"""
|
|
56
|
+
inF = Path(folder).expanduser().resolve()
|
|
57
|
+
if not inF.exists():
|
|
58
|
+
print("Input folder does not exist. {}".format(inF))
|
|
59
|
+
return
|
|
60
|
+
|
|
61
|
+
print("Reading folder: {}".format(inF))
|
|
62
|
+
print("output in {}".format(out_folder))
|
|
55
63
|
outF = Path(out_folder).expanduser().resolve()
|
|
56
64
|
if not outF.exists():
|
|
65
|
+
print("creating {}".format(outF))
|
|
57
66
|
os.mkdir(outF)
|
|
58
67
|
|
|
59
68
|
rgx = re.compile(r"Project Name: (\w+)side_.*AlternativeID=PPC[-_](\d+)", re.MULTILINE|re.DOTALL)
|
|
60
69
|
petal_cores = {}
|
|
61
|
-
for fnam in all_files(
|
|
70
|
+
for fnam in all_files(inF, "*.txt"):
|
|
62
71
|
P = Path(fnam).expanduser().resolve()
|
|
72
|
+
print(P.name)
|
|
63
73
|
with open(fnam, "r", encoding="UTF-8") as ff:
|
|
64
74
|
R = rgx.search(ff.read())
|
|
65
75
|
if R:
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""List failing cores from JSon files."""
|
|
3
|
+
import sys
|
|
4
|
+
import argparse
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
import json
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def main(options):
|
|
11
|
+
"""main entry."""
|
|
12
|
+
petal_cores = {}
|
|
13
|
+
for fnam in options.files:
|
|
14
|
+
ifile = Path(fnam).expanduser().resolve()
|
|
15
|
+
with open(ifile, "r", encoding="utf-8") as fin:
|
|
16
|
+
data = json.load(fin)
|
|
17
|
+
|
|
18
|
+
if not data["passed"]:
|
|
19
|
+
petalId = data["component"]
|
|
20
|
+
if petalId not in petal_cores:
|
|
21
|
+
petal_cores[petalId] = {"FRONT": [], "BACK": []}
|
|
22
|
+
|
|
23
|
+
side = "FRONT" if "FRONT" in data["testType"] else "BACK"
|
|
24
|
+
for D in data["defects"]:
|
|
25
|
+
petal_cores[petalId][side].append("{}: {}".format(D["name"], D["description"]))
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
keys = sorted(petal_cores.keys())
|
|
29
|
+
for petalId in keys:
|
|
30
|
+
print(petalId)
|
|
31
|
+
for side in ["FRONT","BACK"]:
|
|
32
|
+
if len(petal_cores[petalId][side])>0:
|
|
33
|
+
print("+-", side)
|
|
34
|
+
for D in petal_cores[petalId][side]:
|
|
35
|
+
print(" ", D)
|
|
36
|
+
|
|
37
|
+
print("\n")
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
if __name__ == "__main__":
|
|
41
|
+
parser = argparse.ArgumentParser()
|
|
42
|
+
parser.add_argument('files', nargs='*', help="Input files")
|
|
43
|
+
opts = parser.parse_args()
|
|
44
|
+
|
|
45
|
+
from petal_qc.utils.all_files import all_files
|
|
46
|
+
|
|
47
|
+
opts.files = []
|
|
48
|
+
for fnam in all_files(Path("~/tmp/petal-metrology/Production/Results").expanduser(), "*.json"):
|
|
49
|
+
opts.files.append(fnam)
|
|
50
|
+
|
|
51
|
+
main(opts)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: petal_qc
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.15
|
|
4
4
|
Summary: A collection of scripts for Petal CORE QC.
|
|
5
5
|
Author-email: Carlos Lacasta <carlos.lacasta@cern.ch>
|
|
6
6
|
Project-URL: Homepage, https://gitlab.cern.ch/atlas-itk/sw/db/itk-pdb-gtk-gui-utils
|
|
@@ -37,11 +37,15 @@ petal_qc/metrology/test_paralelism.py
|
|
|
37
37
|
petal_qc/metrology/uploadPetalInformation.py
|
|
38
38
|
petal_qc/test/checkAVStests.py
|
|
39
39
|
petal_qc/test/compare_golden.py
|
|
40
|
+
petal_qc/test/createMetrologyFile.py
|
|
41
|
+
petal_qc/test/desyModuleBow.py
|
|
42
|
+
petal_qc/test/findRawData.py
|
|
40
43
|
petal_qc/test/getAVSjson.py
|
|
41
44
|
petal_qc/test/getAVStests.py
|
|
42
45
|
petal_qc/test/getPetalCoreTestSummary.py
|
|
43
46
|
petal_qc/test/listPetalCoreComponents.py
|
|
44
47
|
petal_qc/test/prepareDESYfiles.py
|
|
48
|
+
petal_qc/test/reportFromJSon.py
|
|
45
49
|
petal_qc/test/test_Graphana.py
|
|
46
50
|
petal_qc/test/test_coreThermal.py
|
|
47
51
|
petal_qc/thermal/CSVImage.py
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
analyzeIRCore = petal_qc:analyzeIRCore
|
|
3
3
|
bustapeReport = petal_qc:bustapeReport
|
|
4
4
|
coreMetrology = petal_qc:coreMetrology
|
|
5
|
+
coreMetrologyTTY = petal_qc:coreMetrologyTTY
|
|
5
6
|
coreThermal = petal_qc:coreThermal
|
|
6
7
|
createCoreThermalReport = petal_qc:createCoreThermalReport
|
|
7
8
|
doMetrology = petal_qc:doMetrology
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "petal_qc"
|
|
7
|
-
version = "0.0.
|
|
7
|
+
version = "0.0.15"
|
|
8
8
|
authors = [
|
|
9
9
|
{ name="Carlos Lacasta", email="carlos.lacasta@cern.ch" },
|
|
10
10
|
]
|
|
@@ -31,6 +31,7 @@ classifiers = [
|
|
|
31
31
|
|
|
32
32
|
[project.gui-scripts]
|
|
33
33
|
coreMetrology = "petal_qc:coreMetrology"
|
|
34
|
+
coreMetrologyTTY = "petal_qc:coreMetrologyTTY"
|
|
34
35
|
doMetrology = "petal_qc:doMetrology"
|
|
35
36
|
coreThermal = "petal_qc:coreThermal"
|
|
36
37
|
bustapeReport = "petal_qc:bustapeReport"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|