View Javadoc

1   /*
2    * PandoraPfoSamplingFractionAnalysislDriver
3    *
4    * $Id: PandoraPfoSamplingFractionAnalysislDriver.java,v 1.3 2012/02/10 15:26:26 grefe Exp $
5    */
6   package org.lcsim.cal.calib;
7   
8   import static java.lang.Math.sqrt;
9   import hep.aida.ITree;
10  
11  import java.util.List;
12  
13  import org.lcsim.conditions.ConditionsManager;
14  import org.lcsim.conditions.ConditionsSet;
15  import org.lcsim.conditions.ConditionsManager.ConditionsSetNotFoundException;
16  import org.lcsim.event.CalorimeterHit;
17  import org.lcsim.event.Cluster;
18  import org.lcsim.event.EventHeader;
19  import org.lcsim.event.MCParticle;
20  import org.lcsim.geometry.IDDecoder;
21  import org.lcsim.recon.cluster.fixedcone.FixedConeClusterer;
22  import org.lcsim.util.Driver;
23  import org.lcsim.util.aida.AIDA;
24  
25  import Jama.Matrix;
26  import java.util.HashMap;
27  import java.util.Map;
28  import org.lcsim.event.ReconstructedParticle;
29  import org.lcsim.event.SimCalorimeterHit;
30  
31  /**
32   *
33   * @author Norman Graf
34   */
35  public class PandoraPfoSamplingFractionAnalysislDriver extends Driver
36  {
37  
38      private ConditionsSet _cond;
39      private CollectionManager _collectionmanager = CollectionManager.defaultInstance();
40      // we will accumulate the raw energy values in three depths:
41      // 1. Layers (0)1 through (20)21 of the EM calorimeter (note that if layer 0 is massless, SF==1.)
42      // 2. last ten layers of the EM calorimeter
43      // 3. the hadron calorimeter
44      //
45      private double[][] _acc = new double[3][3];
46      private double[] _vec = new double[3];
47      // let's use a clusterer to remove effects of calorimeter cells hit far, far away.
48      // use the only cross-detector clusterer we have:
49      private FixedConeClusterer _fcc;
50      private AIDA aida = AIDA.defaultInstance();
51      private ITree _tree;
52      private boolean _initialized = false;
53      private boolean _debug = false;
54      private double[] _ecalLayering;
55      boolean _useFirstLayer;
56  
57      boolean _isHcalDigital = false;
58  
59      /**
60       * Creates a new instance of SamplingFractionAnalysisDriver
61       */
62      public PandoraPfoSamplingFractionAnalysislDriver()
63      {
64          _tree = aida.tree();
65      }
66  
67      protected void process(EventHeader event)
68      {
69  
70          if (!_initialized) {
71              ConditionsManager mgr = ConditionsManager.defaultInstance();
72              try {
73                  _cond = mgr.getConditions("CalorimeterCalibration");
74              } catch (ConditionsSetNotFoundException e) {
75                  System.out.println("ConditionSet CalorimeterCalibration not found for detector " + mgr.getDetector());
76                  System.out.println("Please check that this properties file exists for this detector ");
77              }
78  
79              _ecalLayering = _cond.getDoubleArray("ECalLayering");
80              _useFirstLayer = _cond.getDouble("IsFirstEmLayerSampling") == 1.;
81  
82              ConditionsSet hcalProperties = mgr.getConditions("SamplingFractions/HcalBarrel");
83  
84              _isHcalDigital = hcalProperties.getBoolean("digital");
85              System.out.println("HCal is " + (_isHcalDigital == true ? "" : "not") + " read out digitally");
86  
87              System.out.println("initialized...");
88  
89              _initialized = true;
90          }
91  
92          // organize the histogram tree by species and energy
93          List<MCParticle> mcparts = event.getMCParticles();
94          //MCParticle mcpart = mcparts.get(mcparts.size() - 1); // this only works if particle was generated by stdhep, does not work with GEANT gps
95          MCParticle mcpart = null;
96          // Look for the most energetic final state particle
97          for (MCParticle myMCP : mcparts) {
98              if (myMCP.getGeneratorStatus() == MCParticle.FINAL_STATE) {
99                  if (mcpart == null) {
100                     mcpart = myMCP;
101                 } else if (mcpart.getEnergy() < myMCP.getEnergy()) {
102                     mcpart = myMCP;
103                 }
104             }
105         }
106         if (mcpart != null) {
107             String particleType = mcpart.getType().getName();
108             double mcEnergy = mcpart.getEnergy();
109             long mcIntegerEnergy = Math.round(mcEnergy);
110             boolean meV = false;
111             if (mcEnergy < .99) {
112                 mcIntegerEnergy = Math.round(mcEnergy * 1000);
113                 meV = true;
114             }
115 
116         // to derive the sampling fractions, want access to the raw energies
117             // create a map keyed on ID for the SimCalorimeterHits
118             // use the ID of the CalorimeterHits in the clusters to fetch them back
119             Map<Long, SimCalorimeterHit> simCalHitMap = new HashMap<Long, SimCalorimeterHit>();
120 
121             List<List<SimCalorimeterHit>> collections = event.get(SimCalorimeterHit.class);
122             for (List<SimCalorimeterHit> collection : collections) {
123                 for (SimCalorimeterHit hit : collection) {
124                     simCalHitMap.put(hit.getCellID(), hit);
125                 }
126             }
127 
128             _tree.mkdirs(particleType);
129             _tree.cd(particleType);
130             _tree.mkdirs(mcIntegerEnergy + (meV ? "_MeV" : "_GeV"));
131             _tree.cd(mcIntegerEnergy + (meV ? "_MeV" : "_GeV"));
132 
133             if (mcpart.getSimulatorStatus().isDecayedInCalorimeter()) {
134                 List<ReconstructedParticle> rpCollection = event.get(ReconstructedParticle.class, "PandoraPFOCollection");
135                 if (_debug) {
136                     System.out.println("found " + rpCollection.size() + " ReconstructedParticles");
137                 }
138                 // System.out.println("Found "+rpCollection.size()+" ReconstructedParticles");
139 //            aida.cloud1D("Number of ReconstructedParticles found").fill(rpCollection.size());
140                 if (rpCollection.size() == 1) {
141 
142                     for (ReconstructedParticle p : rpCollection) {
143                         if (_debug) {
144                             System.out.println("  energy " + p.getEnergy());
145                         }
146                     }
147                     // fetch the highest energy RP (usually the first)
148                     ReconstructedParticle p = rpCollection.get(0);
149                     List<Cluster> clusters = p.getClusters();
150                     if (_debug) {
151                         System.out.println("found " + clusters.size() + " clusters");
152                     }
153                     aida.histogram1D("number of found clusters", 10, -0.5, 9.5).fill(clusters.size());
154                     // proceed only if we found a single cluster above threshold
155                     if (clusters.size() > 0) {
156                         int nHCalHits = 0;
157                         for (Cluster c : clusters) {
158                             aida.cloud1D("Highest energy cluster energy").fill(c.getEnergy());
159                             aida.cloud1D("Highest energy cluster number of cells").fill(c.getCalorimeterHits().size());
160 
161                             double clusterEnergy = c.getEnergy();
162                             double mcMass = mcpart.getType().getMass();
163                             // subtract the mass to get kinetic energy...
164                             double expectedEnergy = mcEnergy;
165                             // In case of protons and neutrons we expect only the kinetic energy in the shower
166                             if (mcpart.getPDGID() == 2212 || mcpart.getPDGID() == 2112) {
167                                 expectedEnergy = mcEnergy - mcMass;
168                             }
169 //                System.out.println(mcpart.getType().getName()+" "+expectedEnergy);
170                             aida.cloud1D("measured - predicted energy").fill(clusterEnergy - expectedEnergy);
171 
172                         // let's now break down the cluster by component.
173                             // this analysis uses:
174                             // 1.) first 20 EM layers
175                             // 2.) next 10 EM layers
176                             // 3.) Had layers
177                             List<CalorimeterHit> hits = c.getCalorimeterHits();
178                             double[] vals = new double[4];
179                             double clusterEnergySum = 0.;
180                             double rawEnergySum = 0.;
181                             for (CalorimeterHit hit : hits) {
182                                 long id = hit.getCellID();
183                                 IDDecoder decoder = hit.getIDDecoder();
184                                 decoder.setID(id);
185                                 SimCalorimeterHit simHit = simCalHitMap.get(id);
186                                 double rawEnergy = simHit.getRawEnergy();
187                                 double correctedEnergy = hit.getCorrectedEnergy();
188                                 int layer = decoder.getLayer();
189                                 String detectorName = decoder.getSubdetector().getName();
190 //                        System.out.println(detectorName);
191                                 int caltype = 0;
192                                 // FIXME Hard-coded name.
193                                 if (detectorName.toUpperCase().startsWith("ECAL")) {
194                                     for (int i = 1; i < _ecalLayering.length + 1; ++i) {
195                                         if (layer >= _ecalLayering[i - 1]) {
196                                             caltype = i - 1;
197                                         }
198                                     }
199                                 }
200                                 // FIXME Hard-coded name.
201                                 if (detectorName.toUpperCase().startsWith("HCAL")) {
202                                     caltype = 3;
203                                     nHCalHits += 1;
204                                 }
205 //                        System.out.println("layer "+layer+" caltype "+caltype);
206                                 clusterEnergy += hit.getCorrectedEnergy();
207 //                            vals[caltype] += hit.getCorrectedEnergy();
208                                 vals[caltype] += rawEnergy;
209                             } // end of loop over hits in cluster
210                             if (_isHcalDigital == true) {
211                                 vals[3] = nHCalHits;
212                             }
213                             if (_debug) {
214                                 System.out.println("vals: " + vals[0] + " " + vals[1] + " " + vals[2] + " " + vals[3]);
215                             }
216                         // set up linear least squares:
217                             // expectedEnergy = a*E1 + b*E2 +c*E3
218                             for (int j = 0; j < 3; ++j) {
219                                 _vec[j] += expectedEnergy * vals[j + 1];
220                                 for (int k = 0; k < 3; ++k) {
221                                     _acc[j][k] += vals[j + 1] * vals[k + 1];
222                                 }
223                             }
224                         }
225                     } // end of cluster loop
226                 } // end of one RP cut
227 //
228 ////            event.put("All Calorimeter Hits",allHits);
229 ////            event.put("Hits To Cluster",hitsToCluster);
230 //            event.put("Found Clusters", clusters);
231 //            } // end of ReconstructedParticle loop
232             }// end of check on decays outside tracker volume
233         }
234         _tree.cd("/");
235     }
236 
237     protected void endOfData()
238     {
239         System.out.println("done! endOfData.");
240         // calculate the sampling fractions...
241         Matrix A = new Matrix(_acc, 3, 3);
242         A.print(6, 4);
243         Matrix b = new Matrix(3, 1);
244         for (int i = 0; i < 3; ++i) {
245             b.set(i, 0, _vec[i]);
246         }
247         b.print(6, 4);
248         try {
249             Matrix x = A.solve(b);
250             x.print(6, 4);
251             System.out.println("SamplingFractions: " + 1. / x.get(0, 0) + ", " + 1. / x.get(1, 0) + ", " + 1. / x.get(2, 0));//+ ", " + 1. / x.get(3, 0));
252         } catch (Exception e) {
253             e.printStackTrace();
254 //            System.out.println("try reducing dimensionality...");
255 //            Matrix Ap = new Matrix(_acc, 2, 2);
256 //            Ap.print(6, 4);
257 //            Matrix bp = new Matrix(2, 1);
258 //            for (int i = 0; i < 2; ++i)
259 //            {
260 //                bp.set(i, 0, _vec[i]);
261 //            }
262 //            bp.print(6, 4);
263 //            try
264 //            {
265 //                Matrix x = Ap.solve(bp);
266 //                x.print(6, 4);
267 //            } catch (Exception e2)
268 //            {
269 //                e2.printStackTrace();
270 //            }
271         }
272     }
273 
274     public void setDebug(boolean debug)
275     {
276         _debug = debug;
277     }
278 }