1
2
3
4
5
6
7
8
9 package org.lcsim.cal.calib;
10
11 import hep.aida.IAnalysisFactory;
12 import hep.aida.ICloud1D;
13 import hep.aida.IDataPoint;
14 import hep.aida.IDataPointSet;
15 import hep.aida.IDataPointSetFactory;
16 import hep.aida.IFitFactory;
17 import hep.aida.IFitResult;
18 import hep.aida.IFitter;
19 import hep.aida.IFunction;
20 import hep.aida.IFunctionFactory;
21 import hep.aida.IHistogram1D;
22 import hep.aida.IPlotter;
23 import hep.aida.IPlotterStyle;
24 import hep.aida.ITree;
25 import hep.physics.vec.Hep3Vector;
26 import java.io.IOException;
27 import java.util.List;
28 import org.lcsim.conditions.ConditionsManager;
29 import org.lcsim.conditions.ConditionsManager.ConditionsSetNotFoundException;
30 import org.lcsim.conditions.ConditionsSet;
31 import org.lcsim.event.CalorimeterHit;
32 import org.lcsim.event.Cluster;
33 import org.lcsim.event.EventHeader;
34 import org.lcsim.geometry.IDDecoder;
35 import org.lcsim.geometry.Subdetector;
36 import org.lcsim.recon.cluster.fixedcone.FixedConeClusterer;
37 import org.lcsim.recon.cluster.fixedcone.FixedConeClusterer.FixedConeDistanceMetric;
38 import org.lcsim.spacegeom.CartesianPoint;
39 import org.lcsim.spacegeom.SpacePoint;
40 import org.lcsim.util.Driver;
41 import org.lcsim.util.aida.AIDA;
42
43 import static java.lang.Math.sin;
44 import static java.lang.Math.PI;
45 import static java.lang.Math.abs;
46 import static java.lang.Math.sqrt;
47 import java.util.Arrays;
48 import java.util.HashMap;
49 import java.util.Map;
50 import java.util.StringTokenizer;
51 import org.lcsim.event.MCParticle;
52
53
54
55
56
57 public class ClusterEnergyAnalysis extends Driver
58 {
59 private ConditionsSet _cond;
60 private FixedConeClusterer _fcc;
61 private CollectionManager _collectionmanager = CollectionManager.defaultInstance();
62
63 private double[] _ecalLayering;
64 boolean _useFirstLayer;
65
66 private double emCalInnerRadius = 0.;
67 private double emCalInnerZ = 0.;
68
69 private Map<String, Double> _fitParameters = new HashMap<String, Double>();
70
71
72 private AIDA aida = AIDA.defaultInstance();
73 private ITree _tree;
74
75 private boolean _initialized;
76
77 public ClusterEnergyAnalysis()
78 {
79 _tree = aida.tree();
80 }
81
82 protected void process(EventHeader event)
83 {
84 if(!_initialized)
85 {
86 ConditionsManager mgr = ConditionsManager.defaultInstance();
87 try
88 {
89 _cond = mgr.getConditions("CalorimeterCalibration");
90 }
91 catch(ConditionsSetNotFoundException e)
92 {
93 System.out.println("ConditionSet CalorimeterCalibration not found for detector "+mgr.getDetector());
94 System.out.println("Please check that this properties file exists for this detector ");
95 }
96 double radius = .5;
97 double seed = 0.;
98 double minE = .05;
99 _fcc = new FixedConeClusterer(radius, seed, minE, FixedConeDistanceMetric.DPHIDTHETA);
100
101 _ecalLayering = _cond.getDoubleArray("ECalLayering");
102 _useFirstLayer = _cond.getDouble("IsFirstEmLayerSampling")==1.;
103
104
105 String photonFitParametersList = _cond.getString("PhotonFitParameters");
106 String[] photonFitParameters = photonFitParametersList.split(",\\s");
107 for(int i=0; i<photonFitParameters.length; ++i)
108 {
109 _fitParameters.put(photonFitParameters[i], _cond.getDouble(photonFitParameters[i]));
110 }
111
112 String hadronFitParametersList = _cond.getString("NeutralHadronFitParameters");
113 String[] hadronFitParameters = hadronFitParametersList.split(",\\s");
114 for(int i=0; i<hadronFitParameters.length; ++i)
115 {
116 _fitParameters.put(hadronFitParameters[i], _cond.getDouble(hadronFitParameters[i]));
117 }
118
119 _initialized = true;
120 }
121
122 if(event.getEventNumber()%1000==0) System.out.println("Event "+event.getEventNumber());
123
124
125
126 List<MCParticle> mcparts = event.getMCParticles();
127 MCParticle mcpart = mcparts.get(mcparts.size()-1);
128 String particleType = mcpart.getType().getName();
129 double mcEnergy = mcpart.getEnergy();
130 long mcIntegerEnergy = Math.round(mcEnergy);
131 boolean meV = false;
132 if(mcEnergy<.99)
133 {
134 mcIntegerEnergy = Math.round(mcEnergy*1000);
135 meV = true;
136 }
137
138
139 String type = "gamma";
140 if(!particleType.equals("gamma")) type = "neutralHadron";
141
142
143
144
145 _tree.mkdirs(type);
146 _tree.cd(type);
147 _tree.mkdirs(mcIntegerEnergy+(meV ? "_MeV": "_GeV"));
148 _tree.cd(mcIntegerEnergy+(meV ? "_MeV": "_GeV"));
149
150
151
152
153
154 Hep3Vector endpoint = mcpart.getEndPoint();
155
156 double radius = sqrt(endpoint.x()*endpoint.x()+endpoint.y()*endpoint.y());
157 double z = endpoint.z();
158
159 boolean doit = true;
160 if(radius<emCalInnerRadius && abs(z) < emCalInnerZ) doit = false;
161 if(doit)
162 {
163 String processedHitsName = _cond.getString("ProcessedHitsCollectionName");
164 List<CalorimeterHit> hitsToCluster = _collectionmanager.getList(processedHitsName);
165
166 List<Cluster> clusters = _fcc.createClusters(hitsToCluster);
167
168
169
170 for(Cluster c : clusters)
171 {
172 aida.cloud1D("uncorrected cluster energy for all clusters").fill(c.getEnergy());
173 double e = correctClusterEnergy(c, type);
174 aida.cloud1D("corrected cluster energy for all clusters").fill(e);
175 }
176
177
178 if(clusters.size()>0)
179 {
180 Cluster c = clusters.get(0);
181 aida.cloud1D("uncorrected cluster energy for highest energy cluster").fill(c.getEnergy());
182 double e = correctClusterEnergy(c, type);
183 aida.cloud1D("corrected cluster energy for highest energy cluster").fill(e);
184
185
186
187
188
189 }
190
191 }
192
193 _tree.cd("/");
194
195 }
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405 private double correctClusterEnergy(Cluster c, String type)
406 {
407 double e = 0.;
408
409
410
411 List<CalorimeterHit> hits = c.getCalorimeterHits();
412 for (CalorimeterHit hit : hits)
413 {
414 Subdetector det = hit.getSubdetector();
415 String detName = det.getName();
416
417 boolean isEM = detName.startsWith("EM");
418 boolean isEndcap = det.isEndcap();
419 IDDecoder decoder = hit.getIDDecoder();
420 decoder.setID(hit.getCellID());
421 int layer = decoder.getLayer();
422 int caltype = 0;
423 if(isEM)
424 {
425 for(int i=1; i<_ecalLayering.length+1; ++i)
426 {
427 if(layer >= _ecalLayering[i-1]) caltype = i-1;
428 }
429 }
430
431 else
432 {
433 caltype = 3;
434 }
435
436 String name = type + "_" +(isEM ? "em"+caltype : "had") + (isEndcap ? "e" : "b");
437
438 SpacePoint p = new CartesianPoint(hit.getPosition());
439 double hitTheta = p.theta();
440 double normalTheta = hitTheta;
441
442 if(isEndcap)
443 {
444 normalTheta -= PI/2.;
445 normalTheta = abs(normalTheta);
446 }
447 else
448 {
449 normalTheta -= PI;
450 }
451 double a = 0.;
452 double b = 0.;
453 if(caltype==0 && !_useFirstLayer)
454 {
455 a = 0.;
456 b = 1.;
457 }
458 else
459 {
460 a = _fitParameters.get(name+"_0");
461 b = _fitParameters.get(name+"_1");
462 }
463
464 double correctionFactor = a + b*sin(normalTheta);
465
466
467
468
469
470
471 e += hit.getRawEnergy()/correctionFactor;
472 }
473 return e;
474 }
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507 protected void endOfData()
508 {
509 boolean showPlots = false;
510 boolean doit = false;
511 if(doit)
512 {
513 String fileType = "png";
514 String[] pars = {"amplitude", "mean","sigma"};
515
516 IAnalysisFactory af = IAnalysisFactory.create();
517 String[] dirs = _tree.listObjectNames(".");
518 for (int ii=0; ii<dirs.length; ++ii)
519 {
520
521 String[] parts = dirs[ii].split("/");
522
523
524
525
526 _tree.cd(dirs[ii]);
527 String[] objects = _tree.listObjectNames(".");
528
529
530
531
532
533
534 sortDirectoriesByEnergy(objects);
535
536 int numberOfPoints = objects.length;
537 double[] energies = new double[objects.length];
538 for(int j=0; j<objects.length; ++j)
539 {
540
541
542 String subDir =parts[1];
543 String[] st = objects[j].split("/")[1].split("_");
544 String e = st[0];
545 String unit = st[1];
546
547 energies[j] = Double.parseDouble(e);
548 if(unit.contains("MeV")) energies[j]/=1000.;
549
550 }
551 IFunctionFactory functionFactory = af.createFunctionFactory(_tree);
552 IFitFactory fitFactory = af.createFitFactory();
553 IFitter jminuit = fitFactory.createFitter("Chi2","jminuit");
554 IFunction gauss = functionFactory.createFunctionByName("gauss","G");
555 IFunction line = functionFactory.createFunctionByName("line","P1");
556 IDataPointSetFactory dpsf = af.createDataPointSetFactory(_tree);
557
558 IPlotter plotter = af.createPlotterFactory().create("sampling fraction plot");
559 plotter.createRegions(3, 4, 0);
560 IPlotterStyle style2 = plotter.region(7).style();
561 style2.legendBoxStyle().setVisible(false);
562 style2.statisticsBoxStyle().setVisible(false);
563
564
565 IPlotterStyle style;
566
567 double[] fitMeans = new double[numberOfPoints];
568 double[] fitSigmas = new double[numberOfPoints];
569 IDataPointSet energyMeans = dpsf.create("energy means vs E",2);
570 IDataPointSet energySigmas = dpsf.create("sigma \\/ E vs E",2);
571 IDataPointSet resolutionFit = dpsf.create("sigma \\/ E vs 1 \\/ \u221a E",2);
572 IDataPointSet energyResiduals = dpsf.create("energy residuals (%) vs E",2);
573 double eMax = 0;
574 for(int i=0; i< numberOfPoints; ++i)
575 {
576 if(energies[i] > .1)
577 {
578 System.out.println("Energy "+energies[i]);
579
580 ICloud1D e = (ICloud1D) _tree.find(objects[i]+"corrected cluster energy for all clusters");
581 if(!e.isConverted()) e.convertToHistogram();
582 IHistogram1D eHist = e.histogram();
583 gauss.setParameter("amplitude",eHist.maxBinHeight());
584 gauss.setParameter("mean",eHist.mean());
585 gauss.setParameter("sigma",eHist.rms());
586 style = plotter.region(i).style();
587 style.legendBoxStyle().setVisible(false);
588 style.statisticsBoxStyle().setVisible(false);
589 double loElimit = energies[i] - .6*sqrt(energies[i]);
590 double hiElimit = energies[i] + .6*sqrt(energies[i]);;
591 plotter.region(i).setXLimits(loElimit, hiElimit);
592 plotter.region(i).plot(eHist);
593 IFitResult jminuitResult = jminuit.fit(eHist,gauss);
594 double[] fitErrors = jminuitResult.errors();
595 IFunction fit = jminuitResult.fittedFunction();
596 for(int j=0; j<pars.length; ++j)
597 {
598 System.out.println(" "+pars[j]+": "+ fit.parameter(pars[j])+" +/- "+fitErrors[j]);
599 }
600 fitMeans[i] = fit.parameter("mean");
601 fitSigmas[i] = fit.parameter("sigma");
602 plotter.region(i).plot(fit);
603
604
605
606 IDataPoint point = energyMeans.addPoint();
607 point.coordinate(0).setValue(energies[i]);
608 point.coordinate(1).setValue(fitMeans[i]);
609 point.coordinate(1).setErrorPlus(fitErrors[1]);
610 point.coordinate(1).setErrorMinus(fitErrors[1]);
611
612
613 IDataPoint point1 = energySigmas.addPoint();
614 point1.coordinate(0).setValue(energies[i]);
615 point1.coordinate(1).setValue(fitSigmas[i]/energies[i]);
616 point1.coordinate(1).setErrorPlus(fitErrors[2]/energies[i]);
617 point1.coordinate(1).setErrorMinus(fitErrors[2]/energies[i]);
618
619
620
621 IDataPoint point3 = resolutionFit.addPoint();
622 point3.coordinate(0).setValue(1./sqrt(energies[i]));
623 point3.coordinate(1).setValue(fitSigmas[i]/energies[i]);
624 point3.coordinate(1).setErrorPlus(fitErrors[2]/energies[i]);
625 point3.coordinate(1).setErrorMinus(fitErrors[2]/energies[i]);
626
627
628 IDataPoint point2 = energyResiduals.addPoint();
629 point2.coordinate(0).setValue(energies[i]);
630 point2.coordinate(1).setValue(100.*(fitMeans[i]-energies[i])/energies[i]);
631
632
633 if(energies[i] > eMax) eMax = energies[i];
634 }
635 }
636
637 IPlotter results = af.createPlotterFactory().create("linearity");
638 style = results.region(0).style();
639 style.xAxisStyle().setLabel("MC Energy [GeV]");
640 style.yAxisStyle().setLabel("Cluster Energy [GeV]");
641 style.titleStyle().setVisible(false);
642 style.statisticsBoxStyle().setVisibileStatistics("011");
643 style.legendBoxStyle().setVisible(true);
644 IFitResult fitLine = jminuit.fit(energyMeans, line);
645 System.out.println(" fit status: "+fitLine.fitStatus());
646 double eMaxBin = eMax+10.;
647 results.region(0).setXLimits(0., eMaxBin);
648 results.region(0).setYLimits(0., eMaxBin);
649 results.region(0).plot(energyMeans);
650 results.region(0).plot(fitLine.fittedFunction());
651
652
653 IPlotter resolution = af.createPlotterFactory().create("resolution");
654 style = resolution.region(0).style();
655 style.xAxisStyle().setLabel("Energy [GeV]");
656 style.yAxisStyle().setLabel("sigma/E");
657 style.titleStyle().setVisible(false);
658 style.statisticsBoxStyle().setVisible(false);
659 style.legendBoxStyle().setVisible(false);
660 resolution.region(0).setXLimits(0., eMaxBin);
661 resolution.region(0).setYLimits(0., .2);
662 resolution.region(0).plot(energySigmas);
663
664
665 IPlotter resolution2 = af.createPlotterFactory().create("sigma/E vs 1/E");
666 style = resolution2.region(0).style();
667 style.xAxisStyle().setLabel("1/ \u221a Energy [1/GeV]");
668 style.yAxisStyle().setLabel("sigma/E");
669
670 style.legendBoxStyle().setVisible(false);
671 IFitResult resFitLine = jminuit.fit(resolutionFit, line);
672 System.out.println(" fit status: "+resFitLine.fitStatus());
673
674
675 resolution2.region(0).plot(resolutionFit);
676 resolution2.region(0).plot(resFitLine.fittedFunction());
677
678 IPlotter residuals = af.createPlotterFactory().create("residuals (%)");
679 style = residuals.region(0).style();
680 style.xAxisStyle().setLabel("Energy [GeV]");
681 style.yAxisStyle().setLabel("Residuals [%]");
682 style.statisticsBoxStyle().setVisible(false);
683 style.titleStyle().setVisible(false);
684
685 residuals.region(0).setXLimits(0., eMaxBin);
686
687 residuals.region(0).plot(energyResiduals);
688
689 if(showPlots)
690 {
691 plotter.show();
692 results.show();
693 resolution.show();
694 resolution2.show();
695 residuals.show();
696 }
697 else
698 {
699 try
700 {
701
702 plotter.writeToFile("energyPlots."+fileType,fileType);
703 results.writeToFile("linearity."+fileType,fileType);
704 resolution.writeToFile("resolution."+fileType,fileType);
705 resolution2.writeToFile("resolutionLinear."+fileType,fileType);
706 residuals.writeToFile("residuals."+fileType,fileType);
707 }
708 catch(IOException e)
709 {
710 System.out.println("problem writing out hardcopy in "+fileType+" format");
711 e.printStackTrace();
712 }
713
714 }
715 }
716 }
717 }
718
719 private static void sortDirectoriesByEnergy(String[] s)
720 {
721 Map<Double, String> map = new HashMap<Double, String>();
722 double[] energies = new double[s.length];
723 for(int j=0; j<s.length; ++j)
724 {
725
726 String subDir = s[j].split("/")[1];
727
728 String[] st = subDir.split("_");
729 String e = st[0];
730 String unit = st[1];
731
732 energies[j] = Double.parseDouble(e);
733 if(unit.contains("MeV")) energies[j]/=1000.;
734 map.put(energies[j], s[j]);
735
736 }
737 Arrays.sort(energies);
738 for(int j=0; j<s.length; ++j)
739 {
740 s[j] = map.get(energies[j]);
741 }
742
743
744
745
746 }
747
748 }