Merge lp:~christopher-hunt08/maus/maus_analysis_devel into lp:maus/merge
- maus_analysis_devel
- Merge into merge
Proposed by
Christopher Hunt
Status: | Merged |
---|---|
Merged at revision: | 740 |
Proposed branch: | lp:~christopher-hunt08/maus/maus_analysis_devel |
Merge into: | lp:maus/merge |
Diff against target: |
917 lines (+750/-20) 7 files modified
bin/scifi/tracker_resolution_plots.py (+45/-0) src/common_py/analysis/__init__.py (+1/-0) src/common_py/analysis/analysis_track.py (+141/-0) src/common_py/analysis/hit_types.py (+217/-5) src/common_py/analysis/inspectors.py (+91/-8) src/common_py/analysis/systematic_error_estimation.py (+247/-0) src/common_py/framework/single_thread.py (+8/-7) |
To merge this branch: | bzr merge lp:~christopher-hunt08/maus/maus_analysis_devel |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
MAUS Maintainers | Pending | ||
Review via email: mp+345284@code.launchpad.net |
Commit message
Description of the change
Some tweaks and additions to the analysis code in src/common_py, plus a bug fix in single_thread.py where using the data object wasn't being correctly deleted at the end of the pipeline.
To post a comment you must log in.
Revision history for this message
Paolo Franchini (p-franchini) wrote : | # |
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'bin/scifi/tracker_resolution_plots.py' | |||
2 | --- bin/scifi/tracker_resolution_plots.py 2017-12-12 10:11:06 +0000 | |||
3 | +++ bin/scifi/tracker_resolution_plots.py 2018-05-09 09:31:35 +0000 | |||
4 | @@ -318,6 +318,11 @@ | |||
5 | 318 | tracker+'_p_residual_p', "p Residuals in p", \ | 318 | tracker+'_p_residual_p', "p Residuals in p", \ |
6 | 319 | PZ_BIN, PZ_MIN, PZ_MAX, 500, -50.0, 50.0 ) | 319 | PZ_BIN, PZ_MIN, PZ_MAX, 500, -50.0, 50.0 ) |
7 | 320 | 320 | ||
8 | 321 | tracker_dict['dpp_residual_p'] = ROOT.TH2F( \ | ||
9 | 322 | tracker+'_dpp_residual_p', "dp/p Residuals in p", \ | ||
10 | 323 | PZ_BIN, PZ_MIN, PZ_MAX, 500, -1.0, 1.0 ) | ||
11 | 324 | |||
12 | 325 | |||
13 | 321 | 326 | ||
14 | 322 | tracker_dict['x_residual_pt'] = ROOT.TH2F( \ | 327 | tracker_dict['x_residual_pt'] = ROOT.TH2F( \ |
15 | 323 | tracker+'_x_residual_pt', "X Residuals in p_{t}", \ | 328 | tracker+'_x_residual_pt', "X Residuals in p_{t}", \ |
16 | @@ -1016,6 +1021,7 @@ | |||
17 | 1016 | tracker_plots['pt_residual_p'].Fill( P_mc, Pt_res ) | 1021 | tracker_plots['pt_residual_p'].Fill( P_mc, Pt_res ) |
18 | 1017 | tracker_plots['pz_residual_p'].Fill( P_mc, res_mom[2] ) | 1022 | tracker_plots['pz_residual_p'].Fill( P_mc, res_mom[2] ) |
19 | 1018 | tracker_plots['p_residual_p'].Fill( P_mc, P_res ) | 1023 | tracker_plots['p_residual_p'].Fill( P_mc, P_res ) |
20 | 1024 | tracker_plots['dpp_residual_p'].Fill( P_mc, P_res/P_mc ) | ||
21 | 1019 | 1025 | ||
22 | 1020 | 1026 | ||
23 | 1021 | tracker_plots['x_residual_pz'].Fill( Pz_mc, res_pos[0] ) | 1027 | tracker_plots['x_residual_pz'].Fill( Pz_mc, res_pos[0] ) |
24 | @@ -1230,6 +1236,45 @@ | |||
25 | 1230 | plot_dict[tracker][component+plot_axis+'_bias'] = bias_graph | 1236 | plot_dict[tracker][component+plot_axis+'_bias'] = bias_graph |
26 | 1231 | 1237 | ||
27 | 1232 | 1238 | ||
28 | 1239 | for tracker in [ "upstream", "downstream" ] : | ||
29 | 1240 | for a_plot in [ "dpp_residual_p" ] : | ||
30 | 1241 | plot = plot_dict[tracker][a_plot] | ||
31 | 1242 | |||
32 | 1243 | rms_error = array.array( 'd' ) | ||
33 | 1244 | bin_size = array.array( 'd' ) | ||
34 | 1245 | bins = array.array( 'd' ) | ||
35 | 1246 | rms = array.array( 'd' ) | ||
36 | 1247 | mean = array.array( 'd' ) | ||
37 | 1248 | mean_error = array.array( 'd' ) | ||
38 | 1249 | |||
39 | 1250 | width = plot.GetXaxis().GetBinWidth(1) | ||
40 | 1251 | for i in range( 0, plot.GetXaxis().GetNbins() ) : | ||
41 | 1252 | projection = plot.ProjectionY( a_plot+'_pro_'+str(i), i, (i+1) ) | ||
42 | 1253 | |||
43 | 1254 | plot_mean = plot.GetXaxis().GetBinCenter( i ) + width | ||
44 | 1255 | pro_mean, pro_mean_err, pro_std, pro_std_err = \ | ||
45 | 1256 | analysis.tools.fit_gaussian(projection) | ||
46 | 1257 | |||
47 | 1258 | bin_size.append( width*0.5 ) | ||
48 | 1259 | bins.append( plot_mean ) | ||
49 | 1260 | rms.append( pro_std ) | ||
50 | 1261 | rms_error.append( pro_std_err ) | ||
51 | 1262 | mean.append( pro_mean ) | ||
52 | 1263 | mean_error.append( pro_mean_err ) | ||
53 | 1264 | |||
54 | 1265 | if len(bins) != 0 : | ||
55 | 1266 | resolution_graph = ROOT.TGraphErrors( len(bins), \ | ||
56 | 1267 | bins, rms, bin_size, rms_error ) | ||
57 | 1268 | bias_graph = ROOT.TGraphErrors( len(bins), \ | ||
58 | 1269 | bins, mean, bin_size, mean_error ) | ||
59 | 1270 | else : | ||
60 | 1271 | resolution_graph = None | ||
61 | 1272 | bias_graph = None | ||
62 | 1273 | |||
63 | 1274 | plot_dict[tracker][a_plot+'_resolution'] = resolution_graph | ||
64 | 1275 | plot_dict[tracker][a_plot+'_bias'] = bias_graph | ||
65 | 1276 | |||
66 | 1277 | |||
67 | 1233 | 1278 | ||
68 | 1234 | for tracker in [ "upstream", "downstream" ] : | 1279 | for tracker in [ "upstream", "downstream" ] : |
69 | 1235 | # for component in [ "pt_", "pz_", ] : | 1280 | # for component in [ "pt_", "pz_", ] : |
70 | 1236 | 1281 | ||
71 | === modified file 'src/common_py/analysis/__init__.py' | |||
72 | --- src/common_py/analysis/__init__.py 2017-02-17 12:38:12 +0000 | |||
73 | +++ src/common_py/analysis/__init__.py 2018-05-09 09:31:35 +0000 | |||
74 | @@ -31,4 +31,5 @@ | |||
75 | 31 | import analysis.hit_types | 31 | import analysis.hit_types |
76 | 32 | import analysis.inspectors | 32 | import analysis.inspectors |
77 | 33 | import analysis.scifitools # pylint: disable = E0401 | 33 | import analysis.scifitools # pylint: disable = E0401 |
78 | 34 | import analysis.systematic_error_estimation | ||
79 | 34 | 35 | ||
80 | 35 | 36 | ||
81 | === added file 'src/common_py/analysis/analysis_track.py' | |||
82 | --- src/common_py/analysis/analysis_track.py 1970-01-01 00:00:00 +0000 | |||
83 | +++ src/common_py/analysis/analysis_track.py 2018-05-09 09:31:35 +0000 | |||
84 | @@ -0,0 +1,141 @@ | |||
85 | 1 | #!/usr/bin/env python | ||
86 | 2 | # This file is part of MAUS: http://micewww.pp.rl.ac.uk/projects/maus | ||
87 | 3 | # | ||
88 | 4 | # MAUS is free software: you can redistribute it and/or modify | ||
89 | 5 | # it under the terms of the GNU General Public License as published by | ||
90 | 6 | # the Free Software Foundation, either version 3 of the License, or | ||
91 | 7 | # (at your option) any later version. | ||
92 | 8 | # | ||
93 | 9 | # MAUS is distributed in the hope that it will be useful, | ||
94 | 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
95 | 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
96 | 12 | # GNU General Public License for more details. | ||
97 | 13 | # | ||
98 | 14 | # You should have received a copy of the GNU General Public License | ||
99 | 15 | # along with MAUS. If not, see <http://www.gnu.org/licenses/>. | ||
100 | 16 | # | ||
101 | 17 | |||
102 | 18 | """ | ||
103 | 19 | Defines the AnalysisTrack class. | ||
104 | 20 | |||
105 | 21 | A generic track class that can be used to simplify the analysis of track data. | ||
106 | 22 | """ | ||
107 | 23 | |||
108 | 24 | # pylint: disable = W0311, R0902, R0904, R0913, C0103, W0102 | ||
109 | 25 | |||
110 | 26 | class AnalysisTrack() : | ||
111 | 27 | """ | ||
112 | 28 | A simple, unified class that holds the essential information, when copied | ||
113 | 29 | from MAUS data types, during various analyses. | ||
114 | 30 | |||
115 | 31 | Some syntax was borrowed from XBoa for simplicity and because I like the | ||
116 | 32 | interface! | ||
117 | 33 | """ | ||
118 | 34 | def __init__( self, trackpoints={}, chisq=0.0, ndf=0, p_value=1.0, status=0 ) : | ||
119 | 35 | """ | ||
120 | 36 | Initialise object. | ||
121 | 37 | """ | ||
122 | 38 | self.__trackpoints = trackpoints | ||
123 | 39 | self.__chisq = chisq | ||
124 | 40 | self.__ndf = ndf | ||
125 | 41 | self.__p_value = p_value | ||
126 | 42 | self.__status = status | ||
127 | 43 | |||
128 | 44 | |||
129 | 45 | def __getitem__(self, index) : | ||
130 | 46 | """ | ||
131 | 47 | Return a trackpoint from the track at index ``index'' | ||
132 | 48 | """ | ||
133 | 49 | return self.__trackpoints[index] | ||
134 | 50 | |||
135 | 51 | |||
136 | 52 | def __setitem__(self, index, item) : | ||
137 | 53 | """ | ||
138 | 54 | Set the value of the trackpoint in the track at index ``index'' | ||
139 | 55 | """ | ||
140 | 56 | self.__trackpoints[index] = item | ||
141 | 57 | |||
142 | 58 | |||
143 | 59 | def __len__(self) : | ||
144 | 60 | """ | ||
145 | 61 | Return the number of trackpoints in the track> | ||
146 | 62 | """ | ||
147 | 63 | return len(self.__trackpoints) | ||
148 | 64 | |||
149 | 65 | |||
150 | 66 | def get_trackpoint( self, index ) : | ||
151 | 67 | """ | ||
152 | 68 | Return a trackpoint from the track at index ``index'' | ||
153 | 69 | """ | ||
154 | 70 | return self.__trackpoints[index] | ||
155 | 71 | |||
156 | 72 | |||
157 | 73 | def set_trackpoint( self, index, item ) : | ||
158 | 74 | """ | ||
159 | 75 | Set the value of the trackpoint in the track at index ``index'' | ||
160 | 76 | """ | ||
161 | 77 | self.__trackpoints[index] = item | ||
162 | 78 | |||
163 | 79 | |||
164 | 80 | def get_p_value( self ) : | ||
165 | 81 | """ | ||
166 | 82 | Return the track p-value | ||
167 | 83 | """ | ||
168 | 84 | return self.__p_value | ||
169 | 85 | |||
170 | 86 | |||
171 | 87 | def set_p_value( self, pvalue ) : | ||
172 | 88 | """ | ||
173 | 89 | Set the track p-value | ||
174 | 90 | """ | ||
175 | 91 | self.__p_value = pvalue | ||
176 | 92 | |||
177 | 93 | |||
178 | 94 | def get_chisq( self ) : | ||
179 | 95 | """ | ||
180 | 96 | Return the track chisq squared | ||
181 | 97 | """ | ||
182 | 98 | return self.__chisq | ||
183 | 99 | |||
184 | 100 | |||
185 | 101 | def set_chisq( self, chisq ) : | ||
186 | 102 | """ | ||
187 | 103 | Set the track chisq squared | ||
188 | 104 | """ | ||
189 | 105 | self.__chisq = chisq | ||
190 | 106 | |||
191 | 107 | |||
192 | 108 | def get_ndf( self ) : | ||
193 | 109 | """ | ||
194 | 110 | Get the track No. Degrees of Freedom | ||
195 | 111 | """ | ||
196 | 112 | return self.__ndf | ||
197 | 113 | |||
198 | 114 | |||
199 | 115 | def set_ndf( self, ndf ) : | ||
200 | 116 | """ | ||
201 | 117 | Set the track No. Degrees of Freedom | ||
202 | 118 | """ | ||
203 | 119 | self.__ndf = ndf | ||
204 | 120 | |||
205 | 121 | |||
206 | 122 | def get_chisq_ndf(self) : | ||
207 | 123 | """ | ||
208 | 124 | Get the track Chisquared / No. Degrees of Freedom | ||
209 | 125 | """ | ||
210 | 126 | return self.__chisq / self.__ndf | ||
211 | 127 | |||
212 | 128 | |||
213 | 129 | def set_status(self, status) : | ||
214 | 130 | """ | ||
215 | 131 | Set a undefined status flag | ||
216 | 132 | """ | ||
217 | 133 | self.__status = status | ||
218 | 134 | |||
219 | 135 | |||
220 | 136 | def get_status(self) : | ||
221 | 137 | """ | ||
222 | 138 | Get the status flag | ||
223 | 139 | """ | ||
224 | 140 | return self.__status | ||
225 | 141 | |||
226 | 0 | 142 | ||
227 | === modified file 'src/common_py/analysis/hit_types.py' | |||
228 | --- src/common_py/analysis/hit_types.py 2017-08-15 16:19:42 +0000 | |||
229 | +++ src/common_py/analysis/hit_types.py 2018-05-09 09:31:35 +0000 | |||
230 | @@ -23,7 +23,7 @@ | |||
231 | 23 | Note that this class is used by the add_hit meth | 23 | Note that this class is used by the add_hit meth |
232 | 24 | """ | 24 | """ |
233 | 25 | 25 | ||
235 | 26 | # pylint: disable = W0311, R0902, R0904, R0913, C0103 | 26 | # pylint: disable = W0311, R0902, R0904, R0913, C0103, R0914, R0915 |
236 | 27 | 27 | ||
237 | 28 | import math | 28 | import math |
238 | 29 | import analysis.tools as tools | 29 | import analysis.tools as tools |
239 | @@ -40,14 +40,15 @@ | |||
240 | 40 | px = 0.0, py = 0.0, pz = 0.0, station = 0, \ | 40 | px = 0.0, py = 0.0, pz = 0.0, station = 0, \ |
241 | 41 | time = 0.0, mass = 105.6583715, p_value = 1.0, pid = 13, \ | 41 | time = 0.0, mass = 105.6583715, p_value = 1.0, pid = 13, \ |
242 | 42 | weight = 1.0, \ | 42 | weight = 1.0, \ |
244 | 43 | scifi_track_point = None, virtual_track_point = None ) : | 43 | scifi_track_point = None, virtual_track_point = None, \ |
245 | 44 | global_track_point = None ) : | ||
246 | 44 | """ | 45 | """ |
247 | 45 | Initialise the object. this can be done in three ways: | 46 | Initialise the object. this can be done in three ways: |
248 | 46 | 1. Specify all components by hand | 47 | 1. Specify all components by hand |
249 | 47 | 2. Build from a sci-fr trackpoint | 48 | 2. Build from a sci-fr trackpoint |
250 | 48 | 3. Build from a virtual trackpoint | 49 | 3. Build from a virtual trackpoint |
251 | 49 | """ | 50 | """ |
253 | 50 | if scifi_track_point is None and virtual_track_point is None : | 51 | if scifi_track_point is None and virtual_track_point is None and global_track_point is None : |
254 | 51 | self.__x = x | 52 | self.__x = x |
255 | 52 | self.__y = y | 53 | self.__y = y |
256 | 53 | self.__z = z | 54 | self.__z = z |
257 | @@ -62,7 +63,7 @@ | |||
258 | 62 | self.__weight = weight | 63 | self.__weight = weight |
259 | 63 | # self.__reference = reference | 64 | # self.__reference = reference |
260 | 64 | 65 | ||
262 | 65 | elif scifi_track_point is not None and virtual_track_point is None : | 66 | elif scifi_track_point is not None and virtual_track_point is None and global_track_point is None : |
263 | 66 | self.__x = scifi_track_point.pos().x() | 67 | self.__x = scifi_track_point.pos().x() |
264 | 67 | self.__y = scifi_track_point.pos().y() | 68 | self.__y = scifi_track_point.pos().y() |
265 | 68 | self.__z = scifi_track_point.pos().z() | 69 | self.__z = scifi_track_point.pos().z() |
266 | @@ -82,7 +83,7 @@ | |||
267 | 82 | # else : | 83 | # else : |
268 | 83 | # self.__reference = reference | 84 | # self.__reference = reference |
269 | 84 | 85 | ||
271 | 85 | elif scifi_track_point is None and virtual_track_point is not None : | 86 | elif scifi_track_point is None and virtual_track_point is not None and global_track_point is None : |
272 | 86 | self.__x = virtual_track_point.GetPosition().x() | 87 | self.__x = virtual_track_point.GetPosition().x() |
273 | 87 | self.__y = virtual_track_point.GetPosition().y() | 88 | self.__y = virtual_track_point.GetPosition().y() |
274 | 88 | self.__z = virtual_track_point.GetPosition().z() | 89 | self.__z = virtual_track_point.GetPosition().z() |
275 | @@ -101,6 +102,20 @@ | |||
276 | 101 | # else : | 102 | # else : |
277 | 102 | # self.__reference = reference | 103 | # self.__reference = reference |
278 | 103 | 104 | ||
279 | 105 | elif scifi_track_point is None and virtual_track_point is None and global_track_point is not None : | ||
280 | 106 | self.__x = global_track_point.get_position().X() | ||
281 | 107 | self.__y = global_track_point.get_position().Y() | ||
282 | 108 | self.__z = global_track_point.get_position().Z() | ||
283 | 109 | self.__px = global_track_point.get_momentum().X() | ||
284 | 110 | self.__py = global_track_point.get_momentum().Y() | ||
285 | 111 | self.__pz = global_track_point.get_momentum().Z() | ||
286 | 112 | self.__time = global_track_point.get_position().T() | ||
287 | 113 | self.__mass = mass | ||
288 | 114 | self.__p_value = p_value | ||
289 | 115 | self.__pid = pid | ||
290 | 116 | self.__station = station | ||
291 | 117 | self.__weight = weight | ||
292 | 118 | |||
293 | 104 | else : | 119 | else : |
294 | 105 | print "WTF!" | 120 | print "WTF!" |
295 | 106 | raise ValueError( 'Please supply precisely one of "virtual_track_point"'+\ | 121 | raise ValueError( 'Please supply precisely one of "virtual_track_point"'+\ |
296 | @@ -388,3 +403,200 @@ | |||
297 | 388 | 403 | ||
298 | 389 | for key, val in __hit_get_variables.iteritems() : | 404 | for key, val in __hit_get_variables.iteritems() : |
299 | 390 | __hit_get_keys.append( key ) | 405 | __hit_get_keys.append( key ) |
300 | 406 | |||
301 | 407 | |||
302 | 408 | ################################################################################ | ||
303 | 409 | |||
304 | 410 | |||
305 | 411 | class AnalysisSpacePoint() : | ||
306 | 412 | """ | ||
307 | 413 | A simple, unified class that holds the essential information, when copied | ||
308 | 414 | from MAUS data types, during various analyses. | ||
309 | 415 | |||
310 | 416 | Some syntax was borrowed from XBoa for simplicity and because I like the | ||
311 | 417 | interface! | ||
312 | 418 | """ | ||
313 | 419 | def __init__( self, x = 0.0, y = 0.0, z = 0.0, station = 0, \ | ||
314 | 420 | time = 0.0, weight = 1.0, tof = None, scifi = None ) : | ||
315 | 421 | """ | ||
316 | 422 | Initialise the object. this can be done in three ways: | ||
317 | 423 | 1. Specify all components by hand | ||
318 | 424 | 2. Build from a sci-fr trackpoint | ||
319 | 425 | 3. Build from a virtual trackpoint | ||
320 | 426 | """ | ||
321 | 427 | if tof is None and scifi is None : | ||
322 | 428 | self.__x = x | ||
323 | 429 | self.__y = y | ||
324 | 430 | self.__z = z | ||
325 | 431 | self.__time = time | ||
326 | 432 | self.__station = station | ||
327 | 433 | self.__weight = weight | ||
328 | 434 | |||
329 | 435 | elif scifi is not None and tof is None : | ||
330 | 436 | self.__x = scifi.pos().x() | ||
331 | 437 | self.__y = scifi.pos().y() | ||
332 | 438 | self.__z = scifi.pos().z() | ||
333 | 439 | self.__time = time | ||
334 | 440 | self.__station = tools.calculate_plane_id(scifi.tracker(), \ | ||
335 | 441 | scifi.station(), 1) | ||
336 | 442 | self.__weight = weight | ||
337 | 443 | |||
338 | 444 | elif scifi is None and tof is not None : | ||
339 | 445 | self.__x = tof.GetGlobalPosX() | ||
340 | 446 | self.__y = tof.GetGlobalPosY() | ||
341 | 447 | self.__z = tof.GetGlobalPosZ() | ||
342 | 448 | self.__time = tof.GetTime() | ||
343 | 449 | self.__station = tof.GetStation() | ||
344 | 450 | self.__weight = weight | ||
345 | 451 | |||
346 | 452 | else : | ||
347 | 453 | print "WTF!" | ||
348 | 454 | raise ValueError( 'Please supply precisely one of "virtual_track_point"'+\ | ||
349 | 455 | ' or "scifi_track_point", or specify all values explicitly.' ) | ||
350 | 456 | |||
351 | 457 | |||
352 | 458 | def __str__( self ) : | ||
353 | 459 | """ | ||
354 | 460 | Return a string of the parameters. | ||
355 | 461 | Mostly useful for debuging. | ||
356 | 462 | """ | ||
357 | 463 | return '(' + str( self.__x ) + ',' +\ | ||
358 | 464 | str( self.__y ) + ',' +\ | ||
359 | 465 | str( self.__z ) + '):[' +\ | ||
360 | 466 | str( self.__time ) +\ | ||
361 | 467 | str( self.__station ) + ']' | ||
362 | 468 | |||
363 | 469 | |||
364 | 470 | def __repr__( self ) : | ||
365 | 471 | """ | ||
366 | 472 | Return a string of the parameters. | ||
367 | 473 | Mostly useful for debuging. | ||
368 | 474 | """ | ||
369 | 475 | return '(' + str( self.__x ) + ',' +\ | ||
370 | 476 | str( self.__y ) + ',' +\ | ||
371 | 477 | str( self.__z ) + '):[' +\ | ||
372 | 478 | str( self.__time ) +\ | ||
373 | 479 | str( self.__station ) + ']' | ||
374 | 480 | |||
375 | 481 | |||
376 | 482 | |||
377 | 483 | def set_x( self, val ) : | ||
378 | 484 | """ | ||
379 | 485 | Set the x position | ||
380 | 486 | """ | ||
381 | 487 | self.__x = val | ||
382 | 488 | |||
383 | 489 | def set_y( self, val ) : | ||
384 | 490 | """ | ||
385 | 491 | Set the y position | ||
386 | 492 | """ | ||
387 | 493 | self.__y = val | ||
388 | 494 | |||
389 | 495 | def set_z( self, val ) : | ||
390 | 496 | """ | ||
391 | 497 | Set the z position | ||
392 | 498 | """ | ||
393 | 499 | self.__z = val | ||
394 | 500 | |||
395 | 501 | def set_time( self, val ) : | ||
396 | 502 | """ | ||
397 | 503 | Set the time | ||
398 | 504 | """ | ||
399 | 505 | self.__time = val | ||
400 | 506 | |||
401 | 507 | def set_station( self, station ) : | ||
402 | 508 | """ | ||
403 | 509 | Set the station ID | ||
404 | 510 | """ | ||
405 | 511 | self.__station = station | ||
406 | 512 | |||
407 | 513 | def set_weight( self, w ) : | ||
408 | 514 | """ | ||
409 | 515 | Set the statistical weight of the hit | ||
410 | 516 | """ | ||
411 | 517 | self.__weight = w | ||
412 | 518 | |||
413 | 519 | |||
414 | 520 | def get_x( self ) : | ||
415 | 521 | """ | ||
416 | 522 | Get the x position | ||
417 | 523 | """ | ||
418 | 524 | return self.__x | ||
419 | 525 | |||
420 | 526 | def get_y( self ) : | ||
421 | 527 | """ | ||
422 | 528 | Get the y position | ||
423 | 529 | """ | ||
424 | 530 | return self.__y | ||
425 | 531 | |||
426 | 532 | def get_z( self ) : | ||
427 | 533 | """ | ||
428 | 534 | Get the z position | ||
429 | 535 | """ | ||
430 | 536 | return self.__z | ||
431 | 537 | |||
432 | 538 | def get_time( self ) : | ||
433 | 539 | """ | ||
434 | 540 | Get the time | ||
435 | 541 | """ | ||
436 | 542 | return self.__time | ||
437 | 543 | |||
438 | 544 | def get_r( self ) : | ||
439 | 545 | """ | ||
440 | 546 | Get the position radius | ||
441 | 547 | """ | ||
442 | 548 | return math.sqrt( self.__x**2 + self.__y**2 ) | ||
443 | 549 | |||
444 | 550 | def get_phi( self ) : | ||
445 | 551 | """ | ||
446 | 552 | Get the Phi angle (Position) | ||
447 | 553 | """ | ||
448 | 554 | return math.atan2( self.__y, self.__x ) | ||
449 | 555 | |||
450 | 556 | def get_station( self ) : | ||
451 | 557 | """ | ||
452 | 558 | Get the particle ID | ||
453 | 559 | """ | ||
454 | 560 | return self.__station | ||
455 | 561 | |||
456 | 562 | |||
457 | 563 | def get_weight( self ) : | ||
458 | 564 | """ | ||
459 | 565 | Return the statistical weight of the hit | ||
460 | 566 | """ | ||
461 | 567 | return self.__weight | ||
462 | 568 | |||
463 | 569 | |||
464 | 570 | def get( self, string ) : | ||
465 | 571 | """ | ||
466 | 572 | Return the value of the variable described in the string | ||
467 | 573 | """ | ||
468 | 574 | if not string in AnalysisSpacePoint.__hit_get_keys : | ||
469 | 575 | return None | ||
470 | 576 | else : | ||
471 | 577 | return AnalysisSpacePoint.__hit_get_variables[ string ]( self ) | ||
472 | 578 | |||
473 | 579 | |||
474 | 580 | def get_as_vector( self ) : | ||
475 | 581 | """ | ||
476 | 582 | Returns the 6D phase-space vector corresponding to the particle. | ||
477 | 583 | [t, x, y, z] | ||
478 | 584 | """ | ||
479 | 585 | return [self.__time, self.__x, self.__y, self.__z] | ||
480 | 586 | |||
481 | 587 | |||
482 | 588 | def get_variable_list() : | ||
483 | 589 | """ | ||
484 | 590 | Return the list of variables that the user can request | ||
485 | 591 | """ | ||
486 | 592 | return AnalysisSpacePoint.__hit_get_keys | ||
487 | 593 | get_variable_list = staticmethod( get_variable_list ) | ||
488 | 594 | |||
489 | 595 | |||
490 | 596 | |||
491 | 597 | __hit_get_keys = [] | ||
492 | 598 | __hit_get_variables = { 'x':get_x, 'y':get_y, 'z':get_z, | ||
493 | 599 | 't':get_time, 'r':get_r, 'station':get_station } | ||
494 | 600 | |||
495 | 601 | for key, val in __hit_get_variables.iteritems() : | ||
496 | 602 | __hit_get_keys.append( key ) | ||
497 | 391 | 603 | ||
498 | === modified file 'src/common_py/analysis/inspectors.py' | |||
499 | --- src/common_py/analysis/inspectors.py 2017-08-15 16:19:42 +0000 | |||
500 | +++ src/common_py/analysis/inspectors.py 2018-05-09 09:31:35 +0000 | |||
501 | @@ -82,13 +82,13 @@ | |||
502 | 82 | 82 | ||
503 | 83 | self.emittance_plot = ROOT.TH1F(\ | 83 | self.emittance_plot = ROOT.TH1F(\ |
504 | 84 | 'inspected_emittance_{0}'.format(self.plane), 'Emittance', \ | 84 | 'inspected_emittance_{0}'.format(self.plane), 'Emittance', \ |
506 | 85 | 1000, 0.0, 20.0) | 85 | 5000, 0.0, 20.0) |
507 | 86 | self.emittance_x_plot = ROOT.TH1F(\ | 86 | self.emittance_x_plot = ROOT.TH1F(\ |
508 | 87 | 'inspected_emittance_x_{0}'.format(self.plane), 'X Emittance', \ | 87 | 'inspected_emittance_x_{0}'.format(self.plane), 'X Emittance', \ |
510 | 88 | 1000, 0.0, 20.0) | 88 | 5000, 0.0, 20.0) |
511 | 89 | self.emittance_y_plot = ROOT.TH1F(\ | 89 | self.emittance_y_plot = ROOT.TH1F(\ |
512 | 90 | 'inspected_emittance_y_{0}'.format(self.plane), 'Y Emittance', \ | 90 | 'inspected_emittance_y_{0}'.format(self.plane), 'Y Emittance', \ |
514 | 91 | 1000, 0.0, 20.0) | 91 | 5000, 0.0, 20.0) |
515 | 92 | self.alpha_plot = ROOT.TH1F(\ | 92 | self.alpha_plot = ROOT.TH1F(\ |
516 | 93 | 'inspected_alpha_{0}'.format(self.plane), 'Alpha Function', \ | 93 | 'inspected_alpha_{0}'.format(self.plane), 'Alpha Function', \ |
517 | 94 | 2000, -5.0, 5.0) | 94 | 2000, -5.0, 5.0) |
518 | @@ -109,11 +109,11 @@ | |||
519 | 109 | 3000, 0.0, 3000.0) | 109 | 3000, 0.0, 3000.0) |
520 | 110 | self.total_momentum_plot = ROOT.TH1F(\ | 110 | self.total_momentum_plot = ROOT.TH1F(\ |
521 | 111 | 'inspected_total_momentum_{0}'.format(self.plane), 'Momentum', \ | 111 | 'inspected_total_momentum_{0}'.format(self.plane), 'Momentum', \ |
523 | 112 | 1000, 0.0, 500.0) | 112 | 2000, 0.0, 500.0) |
524 | 113 | 113 | ||
525 | 114 | self.amplitude_plot = ROOT.TH1F(\ | 114 | self.amplitude_plot = ROOT.TH1F(\ |
526 | 115 | 'single_particle_amplitudes_{0}'.format(self.plane), 'Amplitude', \ | 115 | 'single_particle_amplitudes_{0}'.format(self.plane), 'Amplitude', \ |
528 | 116 | 200, 0.0, 100.0) | 116 | 500, 0.0, 100.0) |
529 | 117 | self.amplitude_momentum_plot = ROOT.TH2F(\ | 117 | self.amplitude_momentum_plot = ROOT.TH2F(\ |
530 | 118 | 'inspected_A_p_phasespace_{0}'.format(self.plane), 'A-p-Phasespace' , \ | 118 | 'inspected_A_p_phasespace_{0}'.format(self.plane), 'A-p-Phasespace' , \ |
531 | 119 | 200, 0.0, 100.0, 260, 130.0, 260.0 ) | 119 | 200, 0.0, 100.0, 260, 130.0, 260.0 ) |
532 | @@ -170,15 +170,15 @@ | |||
533 | 170 | if self.ensemble_size > 1 : | 170 | if self.ensemble_size > 1 : |
534 | 171 | self.ensemble_covariance.add_hit(hit) | 171 | self.ensemble_covariance.add_hit(hit) |
535 | 172 | 172 | ||
537 | 173 | if self.covariance.length() > self.ensemble_size : | 173 | if self.ensemble_covariance.length() > self.ensemble_size : |
538 | 174 | self.fill_plots() | 174 | self.fill_plots() |
539 | 175 | 175 | ||
540 | 176 | 176 | ||
541 | 177 | def fill_plots(self) : | 177 | def fill_plots(self) : |
543 | 178 | if ( self.covariance.length() < (self.ensemble_size / 2) ) or self.ensemble_size < 2 : | 178 | if ( self.ensemble_covariance.length() < (self.ensemble_size / 2) ) or self.ensemble_size < 2 : |
544 | 179 | return | 179 | return |
545 | 180 | 180 | ||
547 | 181 | self.emittance_plot.Fill(self.covariance.get_emittance(\ | 181 | self.emittance_plot.Fill(self.ensemble_covariance.get_emittance(\ |
548 | 182 | ['x','px','y','py'])) | 182 | ['x','px','y','py'])) |
549 | 183 | self.emittance_x_plot.Fill(self.ensemble_covariance.get_emittance(['x','px'])) | 183 | self.emittance_x_plot.Fill(self.ensemble_covariance.get_emittance(['x','px'])) |
550 | 184 | self.emittance_y_plot.Fill(self.ensemble_covariance.get_emittance(['y','py'])) | 184 | self.emittance_y_plot.Fill(self.ensemble_covariance.get_emittance(['y','py'])) |
551 | @@ -446,3 +446,86 @@ | |||
552 | 446 | 446 | ||
553 | 447 | return ins_data | 447 | return ins_data |
554 | 448 | 448 | ||
555 | 449 | |||
556 | 450 | #################################################################################################### | ||
557 | 451 | |||
558 | 452 | |||
559 | 453 | class EmittanceSystematicErrorInspector() : | ||
560 | 454 | |||
561 | 455 | def __init__(self, plane_id, ensemble_size) : | ||
562 | 456 | if ensemble_size < 2 : | ||
563 | 457 | raise ValueError("Ensemble size is too small.") | ||
564 | 458 | |||
565 | 459 | self.plane = plane_id | ||
566 | 460 | self.ensemble_size = ensemble_size | ||
567 | 461 | self.covariance = analysis.covariances.CovarianceMatrix() | ||
568 | 462 | self.true_covariance = analysis.covariances.CovarianceMatrix() | ||
569 | 463 | self.systematic_error_calculator = analysis.systematic_error_estimation.chi_squared_estimator() | ||
570 | 464 | self.true_emittances = [] | ||
571 | 465 | |||
572 | 466 | |||
573 | 467 | def add_hit(self, hit, true_hit) : | ||
574 | 468 | self.covariance.add_hit(hit) | ||
575 | 469 | self.true_covariance.add_hit(true_hit) | ||
576 | 470 | |||
577 | 471 | if self.covariance.length() > self.ensemble_size : | ||
578 | 472 | self.fill_calculator() | ||
579 | 473 | |||
580 | 474 | |||
581 | 475 | def fill_calculator(self) : | ||
582 | 476 | if ( self.covariance.length() < (self.ensemble_size / 2) ) : | ||
583 | 477 | return | ||
584 | 478 | |||
585 | 479 | emittance = self.covariance.get_emittance(['x','px','y','py']) | ||
586 | 480 | true_emittance = self.true_covariance.get_emittance(['x','px','y','py']) | ||
587 | 481 | |||
588 | 482 | self.true_emittances.append( ( true_emittance, true_emittance / math.sqrt( 2.0*(self.true_covariance.length() - 1) ) ) ) | ||
589 | 483 | self.systematic_error_calculator.add_value( emittance, emittance / math.sqrt( 2.0*(self.covariance.length() - 1) ) ) | ||
590 | 484 | |||
591 | 485 | self.covariance.clear() | ||
592 | 486 | self.true_covariance.clear() | ||
593 | 487 | |||
594 | 488 | |||
595 | 489 | def get_current_ensemble_size(self) : | ||
596 | 490 | return self.covariance.length() | ||
597 | 491 | |||
598 | 492 | |||
599 | 493 | def get_systematic_error(self) : | ||
600 | 494 | num_measurements = len(self.systematic_error_calculator) | ||
601 | 495 | |||
602 | 496 | if num_measurements > 0 : | ||
603 | 497 | numer = 0.0 | ||
604 | 498 | denom = 0.0 | ||
605 | 499 | for meas, weight in self.true_emittances : | ||
606 | 500 | numer += meas / (weight**2) | ||
607 | 501 | denom += 1.0 / (weight**2) | ||
608 | 502 | true_emittance = numer / denom | ||
609 | 503 | |||
610 | 504 | bias = self.systematic_error_calculator.calculate_mean() - true_emittance | ||
611 | 505 | error = math.sqrt(self.systematic_error_calculator.calculate_variance()/num_measurements) | ||
612 | 506 | bias_lower = bias - error | ||
613 | 507 | bias_upper = bias + error | ||
614 | 508 | |||
615 | 509 | result = self.systematic_error_calculator.calculate_systematic_error() | ||
616 | 510 | lower, upper = self.systematic_error_calculator.calculate_bounds( result ) | ||
617 | 511 | else : | ||
618 | 512 | bias = 0.0 | ||
619 | 513 | error = 0.0 | ||
620 | 514 | bias_lower = 0.0 | ||
621 | 515 | bias_upper = 0.0 | ||
622 | 516 | |||
623 | 517 | result = 0.0 | ||
624 | 518 | lower = 0.0 | ||
625 | 519 | upper = 0.0 | ||
626 | 520 | |||
627 | 521 | return bias, bias_lower, bias_upper, result, lower, upper | ||
628 | 522 | |||
629 | 523 | |||
630 | 524 | def get_data_dictionary(self) : | ||
631 | 525 | return {} | ||
632 | 526 | |||
633 | 527 | |||
634 | 528 | def get_plot_dictionary(self) : | ||
635 | 529 | return self.systematic_error_calculator.get_plots() | ||
636 | 530 | |||
637 | 531 | |||
638 | 449 | 532 | ||
639 | === added file 'src/common_py/analysis/systematic_error_estimation.py' | |||
640 | --- src/common_py/analysis/systematic_error_estimation.py 1970-01-01 00:00:00 +0000 | |||
641 | +++ src/common_py/analysis/systematic_error_estimation.py 2018-05-09 09:31:35 +0000 | |||
642 | @@ -0,0 +1,247 @@ | |||
643 | 1 | #!/usr/bin/env python | ||
644 | 2 | |||
645 | 3 | # This file is part of MAUS: http://micewww.pp.rl.ac.uk/projects/maus | ||
646 | 4 | # | ||
647 | 5 | # MAUS is free software: you can redistribute it and/or modify | ||
648 | 6 | # it under the terms of the GNU General Public License as published by | ||
649 | 7 | # the Free Software Foundation, either version 3 of the License, or | ||
650 | 8 | # (at your option) any later version. | ||
651 | 9 | # | ||
652 | 10 | # MAUS is distributed in the hope that it will be useful, | ||
653 | 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
654 | 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
655 | 13 | # GNU General Public License for more details. | ||
656 | 14 | # | ||
657 | 15 | # You should have received a copy of the GNU General Public License | ||
658 | 16 | # along with MAUS. If not, see <http://www.gnu.org/licenses/>. | ||
659 | 17 | # | ||
660 | 18 | |||
661 | 19 | """ | ||
662 | 20 | Some classes for the calculation of systematic errors. | ||
663 | 21 | |||
664 | 22 | Inspiration is from: | ||
665 | 23 | L Lyons 1992 J. Phys. A: Math. Gen. 25 1967 | ||
666 | 24 | """ | ||
667 | 25 | |||
668 | 26 | # pylint: disable = W0311, E1101, W0102, R0902, C0103, R0904 | ||
669 | 27 | |||
670 | 28 | import math | ||
671 | 29 | import ROOT | ||
672 | 30 | |||
673 | 31 | import scipy | ||
674 | 32 | import scipy.optimize | ||
675 | 33 | |||
676 | 34 | |||
677 | 35 | class chi_squared_estimator(object) : | ||
678 | 36 | """ | ||
679 | 37 | Performs a chi-squared estiamtion of the systematic error based on pairs of values + errors. | ||
680 | 38 | """ | ||
681 | 39 | |||
682 | 40 | def __init__(self, unique_name="chisq_error_estimation") : | ||
683 | 41 | """ | ||
684 | 42 | Initialise empty object. | ||
685 | 43 | Option to set the convergence criteria for the chisq-minimisation routine | ||
686 | 44 | """ | ||
687 | 45 | self.__unique_name = unique_name | ||
688 | 46 | self.__measurements = [] | ||
689 | 47 | self.__errors = [] | ||
690 | 48 | self.__systematic_error = 0.0 | ||
691 | 49 | self.__mean = 0.0 | ||
692 | 50 | |||
693 | 51 | |||
694 | 52 | def __len__(self) : | ||
695 | 53 | """ | ||
696 | 54 | Return the number of measurements | ||
697 | 55 | """ | ||
698 | 56 | return len(self.__measurements) | ||
699 | 57 | |||
700 | 58 | |||
701 | 59 | def add_value(self, measurement, standard_error) : | ||
702 | 60 | """ | ||
703 | 61 | Add a measurement and its standard error to the object | ||
704 | 62 | """ | ||
705 | 63 | self.__measurements.append(measurement) | ||
706 | 64 | self.__errors.append(standard_error) | ||
707 | 65 | |||
708 | 66 | |||
709 | 67 | def _calculate_chisquared(self) : | ||
710 | 68 | """ | ||
711 | 69 | Private function: calculate the chisquared of the measurements | ||
712 | 70 | """ | ||
713 | 71 | total = 0.0 | ||
714 | 72 | s_sq = self.__systematic_error**2 | ||
715 | 73 | |||
716 | 74 | for meas, error in zip(self.__measurements, self.__errors) : | ||
717 | 75 | total += (meas - self.__mean)**2 / (error*error + s_sq) | ||
718 | 76 | |||
719 | 77 | return total | ||
720 | 78 | |||
721 | 79 | |||
722 | 80 | def _calculate_mean(self) : | ||
723 | 81 | """ | ||
724 | 82 | Private function: calculate the weighted mean of the measurements | ||
725 | 83 | """ | ||
726 | 84 | numerator = 0.0 | ||
727 | 85 | denominator = 0.0 | ||
728 | 86 | # s_sq = self.__systematic_error**2 | ||
729 | 87 | |||
730 | 88 | for meas, error in zip(self.__measurements, self.__errors) : | ||
731 | 89 | numerator += meas / (error*error) | ||
732 | 90 | denominator += 1.0 / (error*error) | ||
733 | 91 | |||
734 | 92 | return numerator / denominator | ||
735 | 93 | |||
736 | 94 | |||
737 | 95 | def calculate_mean(self) : | ||
738 | 96 | """ | ||
739 | 97 | Calculate the weighted mean of the measurements assuming no systematic error. | ||
740 | 98 | """ | ||
741 | 99 | self.__systematic_error = 0.0 | ||
742 | 100 | return self._calculate_mean() | ||
743 | 101 | |||
744 | 102 | |||
745 | 103 | def calculate_variance(self) : | ||
746 | 104 | """ | ||
747 | 105 | Calculate the variance of the measurements assuming no systematic error. | ||
748 | 106 | """ | ||
749 | 107 | mean = self.calculate_mean() | ||
750 | 108 | summation = 0.0 | ||
751 | 109 | for meas in self.__measurements : | ||
752 | 110 | summation += (meas - mean)**2 | ||
753 | 111 | |||
754 | 112 | return summation / len(self.__measurements) | ||
755 | 113 | |||
756 | 114 | |||
757 | 115 | def _constant_error_systematic(self, get_mean, NDOF, stat_error) : | ||
758 | 116 | """ | ||
759 | 117 | Private function: Calculate the systematic error assuming every measurement has the | ||
760 | 118 | same statistical error, and the mean is already assumed. | ||
761 | 119 | |||
762 | 120 | This permits a simpler equation to solve. | ||
763 | 121 | """ | ||
764 | 122 | self.__mean = get_mean() | ||
765 | 123 | total = 0.0 | ||
766 | 124 | |||
767 | 125 | for meas in self.__measurements : | ||
768 | 126 | total += (meas - self.__mean)**2 | ||
769 | 127 | |||
770 | 128 | diff = ( total / NDOF ) - stat_error**2 | ||
771 | 129 | |||
772 | 130 | if diff <= 0.0 : | ||
773 | 131 | return 0.0 | ||
774 | 132 | else : | ||
775 | 133 | return math.sqrt(diff) | ||
776 | 134 | |||
777 | 135 | |||
778 | 136 | def calculate_bounds(self, systematic_estimate, mean=None) : | ||
779 | 137 | """ | ||
780 | 138 | Estimate an asymmetric error bar based on the chisquared distribution. | ||
781 | 139 | |||
782 | 140 | Changes the estimate of the systematic error until the delta chi-squared reaches the | ||
783 | 141 | equivalent of a 1-sigma deviation (central 68%). | ||
784 | 142 | """ | ||
785 | 143 | lower_bar = -1.0e300 # Ridonkulous starting values | ||
786 | 144 | upper_bar = 1.0e300 | ||
787 | 145 | |||
788 | 146 | get_mean = None | ||
789 | 147 | |||
790 | 148 | if mean is None : # Estimate mean from the measurements | ||
791 | 149 | get_mean = self._calculate_mean | ||
792 | 150 | NDOF = len(self.__measurements) - 1 | ||
793 | 151 | |||
794 | 152 | else : # If the mean is specified we gain a degree of freedom. | ||
795 | 153 | get_mean = lambda : mean | ||
796 | 154 | NDOF = len(self.__measurements) | ||
797 | 155 | |||
798 | 156 | |||
799 | 157 | bounds = [(0.0, None)] | ||
800 | 158 | |||
801 | 159 | limit = scipy.stats.chi2.ppf(0.16, NDOF) | ||
802 | 160 | upper_bar = scipy.optimize.minimize(self._minimize_me, [systematic_estimate], args=(limit, get_mean), method="TNC", bounds=bounds) | ||
803 | 161 | |||
804 | 162 | limit = scipy.stats.chi2.ppf(0.84, NDOF) | ||
805 | 163 | lower_bar = scipy.optimize.minimize(self._minimize_me, [systematic_estimate], args=(limit, get_mean), method="TNC", bounds=bounds) | ||
806 | 164 | |||
807 | 165 | return lower_bar.x[0], upper_bar.x[0] | ||
808 | 166 | |||
809 | 167 | |||
810 | 168 | def calculate_systematic_error(self, mean=None, error_assumption=None) : | ||
811 | 169 | """ | ||
812 | 170 | The main function - returns the systematic error given the data and measurements stored in | ||
813 | 171 | the class. | ||
814 | 172 | |||
815 | 173 | Specifying the mean stops the mean from being calculated on the fly from the data, this | ||
816 | 174 | slightly changes th behaviour - the mean is no longer a function of the systematic error and | ||
817 | 175 | the number of degrees of freedom is different. | ||
818 | 176 | |||
819 | 177 | Specifying the error_assumption, assumes that every measurement has the same (specified) | ||
820 | 178 | error. This allows for a faster calculation of the systematic error. | ||
821 | 179 | |||
822 | 180 | Specifying both allows the for systematic error to be calculated trivially. | ||
823 | 181 | """ | ||
824 | 182 | get_mean = None | ||
825 | 183 | NDOF = 0 | ||
826 | 184 | self.__systematic_error = 0.0 | ||
827 | 185 | |||
828 | 186 | if mean is None : # Estimate mean from the measurements | ||
829 | 187 | get_mean = self._calculate_mean | ||
830 | 188 | NDOF = len(self.__measurements) - 1 | ||
831 | 189 | |||
832 | 190 | else : # If the mean is specified we gain a degree of freedom. | ||
833 | 191 | get_mean = lambda : mean | ||
834 | 192 | NDOF = len(self.__measurements) | ||
835 | 193 | |||
836 | 194 | |||
837 | 195 | if error_assumption is not None : # Assume all statistical errors are the | ||
838 | 196 | # same. Shortcut! | ||
839 | 197 | return self._constant_error_systematic(get_mean, NDOF, error_assumption) | ||
840 | 198 | |||
841 | 199 | |||
842 | 200 | bounds = [(0.0, None)] | ||
843 | 201 | estimate = 0.0 | ||
844 | 202 | result = scipy.optimize.minimize(self._minimize_me, [estimate], args=(NDOF, get_mean), method="TNC", bounds=bounds) | ||
845 | 203 | |||
846 | 204 | self.__systematic_error = result.x[0] | ||
847 | 205 | |||
848 | 206 | return self.__systematic_error | ||
849 | 207 | |||
850 | 208 | |||
851 | 209 | def _minimize_me(self, parameters, ndof, get_mean) : | ||
852 | 210 | """ | ||
853 | 211 | Minimize function for SciPy.Optimize. | ||
854 | 212 | |||
855 | 213 | Calculates the squared residual of the Chi-squared value and number of degrees of freedom. | ||
856 | 214 | """ | ||
857 | 215 | self.__systematic_error = parameters[0] | ||
858 | 216 | self.__mean = get_mean() | ||
859 | 217 | chisq = self._calculate_chisquared() | ||
860 | 218 | return (chisq - ndof)**2 | ||
861 | 219 | |||
862 | 220 | |||
863 | 221 | def get_plots(self) : | ||
864 | 222 | """ | ||
865 | 223 | Return a dictionary containing histograms of the data that was stored. | ||
866 | 224 | """ | ||
867 | 225 | if len(self.__measurements) == 0 : | ||
868 | 226 | return {} | ||
869 | 227 | |||
870 | 228 | min_val = min(self.__measurements) | ||
871 | 229 | max_val = max(self.__measurements) | ||
872 | 230 | total_weight = 0.0 | ||
873 | 231 | |||
874 | 232 | for error in self.__errors : | ||
875 | 233 | total_weight += 1.0 / (error**2) | ||
876 | 234 | |||
877 | 235 | hist = ROOT.TH1F(self.__unique_name, "", 100, min_val, max_val) | ||
878 | 236 | weighted_hist = ROOT.TH1F(self.__unique_name+'-weighted', "", 100, min_val, max_val) | ||
879 | 237 | |||
880 | 238 | for value, error in zip( self.__measurements, self.__errors ) : | ||
881 | 239 | hist.Fill(value) | ||
882 | 240 | weighted_hist.Fill(value, (1.0/(error**2))/total_weight) | ||
883 | 241 | |||
884 | 242 | plots = {} | ||
885 | 243 | plots['measurements'] = hist | ||
886 | 244 | plots['weighted_measurements'] = weighted_hist | ||
887 | 245 | |||
888 | 246 | return plots | ||
889 | 247 | |||
890 | 0 | 248 | ||
891 | === modified file 'src/common_py/framework/single_thread.py' | |||
892 | --- src/common_py/framework/single_thread.py 2018-02-14 14:17:17 +0000 | |||
893 | +++ src/common_py/framework/single_thread.py 2018-05-09 09:31:35 +0000 | |||
894 | @@ -201,15 +201,16 @@ | |||
895 | 201 | # done with tranform-merge, now write it out | 201 | # done with tranform-merge, now write it out |
896 | 202 | self.outputer.save(redevent) | 202 | self.outputer.save(redevent) |
897 | 203 | try: | 203 | try: |
898 | 204 | del redevent | ||
899 | 205 | except: | ||
900 | 206 | pass | ||
901 | 207 | # if we converted to a different representation, delete the old one | ||
902 | 208 | try: | ||
903 | 209 | maus_cpp.converter.del_data_repr(event) | 204 | maus_cpp.converter.del_data_repr(event) |
904 | 205 | except TypeError: # pylint: disable = W0702 | ||
905 | 206 | print "Failed to delete MAUS::Data object." | ||
906 | 207 | try: | ||
907 | 210 | maus_cpp.converter.del_data_repr(redevent) | 208 | maus_cpp.converter.del_data_repr(redevent) |
910 | 211 | except: # pylint: disable = W0702 | 209 | except TypeError: # pylint: disable = W0702 |
911 | 212 | pass | 210 | try: # If we returned a different datatype, try to delete it anyway. |
912 | 211 | del redevent | ||
913 | 212 | except: | ||
914 | 213 | print "Failed to delete Reduced Data object." | ||
915 | 213 | 214 | ||
916 | 214 | def start_of_run(self, new_run_number): | 215 | def start_of_run(self, new_run_number): |
917 | 215 | """ | 216 | """ |
Thanks Chris,
I will do it later today,
cheers,
Paolo
On 09/05/18 10:32, Christopher Hunt wrote: /code.launchpad .net/~christoph er-hunt08/ maus/maus_ analysis_ devel/+ merge/345284
> Christopher Hunt has proposed merging lp:~christopher-hunt08/maus/maus_analysis_devel into lp:maus/merge.
>
> Requested reviews:
> MAUS Maintainers (maus-maintainers)
>
> For more details, see:
> https:/
>
> Some tweaks and additions to the analysis code in src/common_py, plus a bug fix in single_thread.py where using the data object wasn't being correctly deleted at the end of the pipeline.
>