View Javadoc
1   package org.hps.recon.particle;
2   
3   import hep.physics.vec.BasicHep3Vector;
4   import hep.physics.vec.BasicHepLorentzVector;
5   import hep.physics.vec.Hep3Vector;
6   import hep.physics.vec.HepLorentzVector;
7   import hep.physics.vec.VecOp;
8   
9   import java.util.ArrayList;
10  import java.util.HashMap;
11  import java.util.HashSet;
12  import java.util.List;
13  import java.util.Set;
14  
15  
16  import org.hps.conditions.beam.BeamEnergy.BeamEnergyCollection;
17  import org.hps.recon.ecal.cluster.ClusterUtilities;
18  import org.hps.recon.tracking.CoordinateTransformations;
19  import org.hps.recon.tracking.TrackUtils;
20  import org.hps.recon.utils.TrackClusterMatcher;
21  import org.hps.record.StandardCuts;
22  import org.lcsim.event.Cluster;
23  import org.lcsim.event.EventHeader;
24  import org.lcsim.event.ReconstructedParticle;
25  import org.lcsim.event.RelationalTable;
26  import org.lcsim.event.Track;
27  import org.lcsim.event.Vertex;
28  import org.lcsim.event.base.BaseCluster;
29  import org.lcsim.event.base.BaseReconstructedParticle;
30  import org.lcsim.geometry.Detector;
31  import org.lcsim.geometry.subdetector.HPSEcal3;
32  import org.lcsim.util.Driver;
33  
34  /**
35   * Driver used to create reconstructed particles and matching clusters and tracks.
36   *
37   * @author <a href="mailto:omoreno@slac.stanford.edu">Omar Moreno</a>
38   * @author Mathew Graham <mgraham@slac.stanford.edu>
39   */
40  public abstract class ReconParticleDriver extends Driver {
41  
42      /**
43       * Utility used to determine if a track and cluster are matched
44       */
45      TrackClusterMatcher matcher = new TrackClusterMatcher();
46  
47      String[] trackCollectionNames = {"GBLTracks"};
48  
49      public static final int ELECTRON = 0;
50      public static final int POSITRON = 1;
51      public static final int MOLLER_TOP = 0;
52      public static final int MOLLER_BOT = 1;
53  
54      // normalized cluster-track distance required for qualifying as a match:
55      private double MAXNSIGMAPOSITIONMATCH=15.0;
56  
57      HPSEcal3 ecal;
58  
59      protected boolean isMC = false;
60      private boolean disablePID = false;
61      protected StandardCuts cuts = new StandardCuts();
62      RelationalTable hitToRotated = null;
63      RelationalTable hitToStrips = null;
64  
65      protected boolean enableTrackClusterMatchPlots = false;
66      
67      public void setTrackClusterMatchPlots(boolean input) {
68          enableTrackClusterMatchPlots = input;
69      }
70  
71     
72      public void setUseCorrectedClusterPositionsForMatching(boolean val){
73          useCorrectedClusterPositionsForMatching = val;
74      }
75      
76      boolean useCorrectedClusterPositionsForMatching = false;
77  
78      // ==============================================================
79      // ==== Class Variables =========================================
80      // ==============================================================
81      // Local variables.
82      /**
83       * Indicates whether debug text should be output or not.
84       */
85      protected boolean debug = false;
86  
87      /**
88       * Indicates whether this is Monte Carlo or data
89       */
90      public boolean isMonteCarlo = false;
91  
92      /**
93       * The simple name of the class used for debug print statements.
94       */
95      private final String simpleName = getClass().getSimpleName();
96  
97      // Reconstructed Particle Lists
98      /**
99       * Stores reconstructed electron particles.
100      */
101     private List<ReconstructedParticle> electrons;
102     /**
103      * Stores reconstructed positron particles.
104      */
105     private List<ReconstructedParticle> positrons;
106     /**
107      * Stores particles reconstructed from an event.
108      */
109     protected List<ReconstructedParticle> finalStateParticles;
110     /**
111      * Stores reconstructed V0 candidate particles generated without constraints.
112      */
113     protected List<ReconstructedParticle> unconstrainedV0Candidates;
114     /**
115      * Stores reconstructed V0 candidate particles generated with beam spot constraints.
116      */
117     protected List<ReconstructedParticle> beamConV0Candidates;
118     /**
119      * Stores reconstructed V0 candidate particles generated with target constraints.
120      */
121     protected List<ReconstructedParticle> targetConV0Candidates;
122     /**
123      * Stores reconstructed V0 candidate vertices generated without constraints.
124      */
125     protected List<Vertex> unconstrainedV0Vertices;
126     /**
127      * Stores reconstructed V0 candidate vertices generated with beam spot constraints.
128      */
129     protected List<Vertex> beamConV0Vertices;
130     /**
131      * Stores reconstructed V0 candidate vertices generated with target constraints.
132      */
133     protected List<Vertex> targetConV0Vertices;
134 
135     // LCIO Collection Names
136     /**
137      * LCIO collection name for calorimeter clusters.
138      */
139     private String ecalClustersCollectionName = "EcalClusters";
140     /**
141      * LCIO collection name for tracks.
142      */
143     private String trackCollectionName = "MatchedTracks";
144     /**
145      * LCIO collection name for reconstructed particles.
146      */
147     private String finalStateParticlesColName = "FinalStateParticles";
148     private String OtherElectronsColName = "OtherElectrons";
149     /**
150      * LCIO collection name for V0 candidate particles generated without constraints.
151      */
152     protected String unconstrainedV0CandidatesColName = null;
153     /**
154      * LCIO collection name for V0 candidate particles generated with beam spot constraints.
155      */
156     protected String beamConV0CandidatesColName = null;
157     /**
158      * LCIO collection name for V0 candidate particles generated with target constraints.
159      */
160     protected String targetConV0CandidatesColName = null;
161     /**
162      * LCIO collection name for V0 candidate vertices generated without constraints.
163      */
164     protected String unconstrainedV0VerticesColName = null;
165     /**
166      * LCIO collection name for V0 candidate vertices generated with beam spot constraints.
167      */
168     protected String beamConV0VerticesColName = null;
169     /**
170      * LCIO collection name for V0 candidate vertices generated with target constraints.
171      */
172     protected String targetConV0VerticesColName = null;
173 
174     // Beam size variables.
175     // The beamsize array is in the tracking frame
176     /* TODO mg-May 14, 2014: the the beam size from the conditions db...also beam position! */
177     protected double[] beamSize = {0.001, 0.130, 0.050}; // rough estimate from harp scans during engineering run
178                                                          // production running
179     // Beam position variables.
180     // The beamPosition array is in the tracking frame
181     /* TODO get the beam position from the conditions db */
182     protected double[] beamPosition = {0.0, 0.0, 0.0}; //
183     protected double bField;
184     protected double beamEnergy = 1.056;
185 
186     // flipSign is a kludge...
187     // HelicalTrackFitter doesn't deal with B-fields in -ive Z correctly
188     // so we set the B-field in +iveZ and flip signs of fitted tracks
189     //
190     // Note: This should be -1 for test run configurations and +1 for
191     // prop-2014 configurations
192     private int flipSign = 1;
193 
194     /**
195      * Sets the condition of whether the data is Monte Carlo or not. This is used to smear the cluster energy
196      * corrections so that the energy resolution is consistent with data. False by default.
197      * 
198      * @param isMC
199      */
200     public void setIsMC(boolean state) {
201         isMC = state;
202     }
203 
204     /**
205      * Sets the name of the LCIO collection for beam spot constrained V0 candidate particles.
206      *
207      * @param beamConV0CandidatesColName - The LCIO collection name.
208      */
209     public void setBeamConV0CandidatesColName(String beamConV0CandidatesColName) {
210         this.beamConV0CandidatesColName = beamConV0CandidatesColName;
211     }
212 
213     /**
214      * Sets the name of the LCIO collection for beam spot constrained V0 candidate vertices.
215      *
216      * @param beamConV0VerticesColName - The LCIO collection name.
217      */
218     public void setBeamConV0VerticesColName(String beamConV0VerticesColName) {
219         this.beamConV0VerticesColName = beamConV0VerticesColName;
220     }
221 
222     /**
223      * Sets the beam position in the x-direction.
224      *
225      * @param X - The beam position at the target in the x-direction in mm.
226      */
227     public void setBeamPositionX(double X) {
228         beamPosition[1] = X; // The beamPosition array is in the tracking frame HPS X => TRACK Y
229     }
230 
231     /**
232      * Sets the beam size sigma in the x-direction.
233      *
234      * @param sigmaX - The standard deviation of the beam width in the x-direction.
235      */
236     public void setBeamSigmaX(double sigmaX) {
237         beamSize[1] = sigmaX; // The beamsize array is in the tracking frame HPS X => TRACK Y
238     }
239 
240     /**
241      * Sets the beam position in the y-direction in mm.
242      *
243      * @param Y - The position of the beam in the y-direction in mm.
244      */
245     public void setBeamPositionY(double Y) {
246         beamPosition[2] = Y; // The beamPosition array is in the tracking frame HPS Y => TRACK Z
247     }
248 
249     /**
250      * Sets the beam size sigma in the y-direction.
251      *
252      * @param sigmaY - The standard deviation of the beam width in the y-direction.
253      */
254     public void setBeamSigmaY(double sigmaY) {
255         beamSize[2] = sigmaY; // The beamsize array is in the tracking frame HPS Y => TRACK Z
256     }
257 
258     /**
259      * Sets the beam position in the z-direction in mm.
260      *
261      * @param Z - The position of the beam in the y-direction in mm.
262      */
263     public void setBeamPositionZ(double Z) {
264         beamPosition[0] = Z; // The beamPosition array is in the tracking frame HPS Z => TRACK X
265     }
266 
267     /**
268      * Indicates whether verbose debug text should be written out during runtime or note. Defaults to <code>false</code>
269      * .
270      *
271      * @param debug - <code>true</code> indicates that debug text should be written and <code>false</code> that it
272      *            should be suppressed.
273      */
274     public void setDebug(boolean debug) {
275         this.debug = debug;
276     }
277 
278     /**
279      * Sets the LCIO collection name for calorimeter cluster data.
280      *
281      * @param ecalClustersCollectionName - The LCIO collection name.
282      */
283     public void setEcalClusterCollectionName(String ecalClustersCollectionName) {
284         this.ecalClustersCollectionName = ecalClustersCollectionName;
285     }
286 
287     /**
288      * Sets the name of the LCIO collection for reconstructed particles.
289      *
290      * @param finalStateParticlesColName - The LCIO collection name.
291      */
292     public void setFinalStateParticlesColName(String finalStateParticlesColName) {
293         this.finalStateParticlesColName = finalStateParticlesColName;
294     }
295 
296     /**
297      * Sets the name of the LCIO collection for target constrained V0 candidate particles.
298      *
299      * @param targetConV0CandidatesColName - The LCIO collection name.
300      */
301     public void setTargetConV0CandidatesColName(String targetConV0CandidatesColName) {
302         this.targetConV0CandidatesColName = targetConV0CandidatesColName;
303     }
304     
305     public void setOtherElectronsColName(String input) {
306         OtherElectronsColName = input;
307     }
308 
309     /**
310      * Sets the name of the LCIO collection for target constrained V0 candidate vertices.
311      *
312      * @param targetConV0VerticesColName - The LCIO collection name.
313      */
314     public void setTargetConV0VerticesColName(String targetConV0VerticesColName) {
315         this.targetConV0VerticesColName = targetConV0VerticesColName;
316     }
317 
318     /**
319      * Sets the LCIO collection name for particle track data.
320      *
321      * @param trackCollectionName - The LCIO collection name.
322      */
323     public void setTrackCollectionName(String trackCollectionName) {
324         this.trackCollectionName = trackCollectionName;
325     }
326 
327     /**
328      * Sets the name of the LCIO collection for unconstrained V0 candidate particles.
329      *
330      * @param unconstrainedV0CandidatesColName - The LCIO collection name.
331      */
332     public void setUnconstrainedV0CandidatesColName(String unconstrainedV0CandidatesColName) {
333         this.unconstrainedV0CandidatesColName = unconstrainedV0CandidatesColName;
334     }
335 
336     /**
337      * Sets the name of the LCIO collection for unconstrained V0 candidate vertices.
338      *
339      * @param unconstrainedV0VerticesColName - The LCIO collection name.
340      */
341     public void setUnconstrainedV0VerticesColName(String unconstrainedV0VerticesColName) {
342         this.unconstrainedV0VerticesColName = unconstrainedV0VerticesColName;
343     }
344 
345     /**
346      * Set the names of the LCIO track collections used as input.
347      *
348      * @param trackCollectionNames Array of collection names. If not set, use all Track collections in the event.
349      */
350     public void setTrackCollectionNames(String[] trackCollectionNames) {
351         this.trackCollectionNames = trackCollectionNames;
352     }
353 
354     /**
355      * Set the requirement on cluster-track position matching in terms of N-sigma.
356      * 
357      * @param nsigma
358      */
359     public void setNSigmaPositionMatch(double nsigma) {
360         MAXNSIGMAPOSITIONMATCH = nsigma;
361     }
362 
363     /** Disable setting the PID of an Ecal cluster. */
364     public void setDisablePID(boolean disablePID) {
365         this.disablePID = disablePID;
366     }
367 
368     /**
369      * Updates the magnetic field parameters to match the appropriate values for the current detector settings.
370      */
371     @Override
372     protected void detectorChanged(Detector detector) {
373         matcher.enablePlots(enableTrackClusterMatchPlots);
374 
375         // Set the magnetic field parameters to the appropriate values.
376         Hep3Vector ip = new BasicHep3Vector(0., 0., 500.0);
377         bField = detector.getFieldMap().getField(ip).y();
378         if (bField < 0) {
379             flipSign = -1;
380         }
381 
382         ecal = (HPSEcal3) detector.getSubdetector("Ecal");
383         matcher.setBFieldMap(detector.getFieldMap());
384         BeamEnergyCollection beamEnergyCollection = 
385                 this.getConditionsManager().getCachedConditions(BeamEnergyCollection.class, "beam_energies").getCachedData();        
386         beamEnergy = beamEnergyCollection.get(0).getBeamEnergy();
387         matcher.setBeamEnergy(beamEnergy); 
388         cuts.changeBeamEnergy(beamEnergy);
389     }
390     
391     public void setMaxMatchChisq(double input) {
392         cuts.setMaxMatchChisq(input);
393     }
394     
395     
396     public void setMaxElectronP(double input) {
397         cuts.setMaxElectronP(input);
398     }
399     
400     public void setMaxMatchDt(double input) {
401         cuts.setMaxMatchDt(input);
402     }
403     
404     public void setTrackClusterTimeOffset(double input) {
405         cuts.setTrackClusterTimeOffset(input);
406     }
407     
408     protected abstract List<ReconstructedParticle> particleCuts(List<ReconstructedParticle> finalStateParticles);
409 
410     /**
411      * Generates reconstructed V0 candidate particles and vertices from sets of positrons and electrons. Implementing
412      * methods should place the reconstructed vertices and candidate particles into the appropriate class variable lists
413      * in <code>ReconParticleDriver
414      * </code>.
415      *
416      * @param electrons - The list of electrons.
417      * @param positrons - The list of positrons.
418      */
419     protected abstract void findVertices(List<ReconstructedParticle> electrons, List<ReconstructedParticle> positrons);
420     
421 
422     /**
423      * Create the set of final state particles from the event tracks and clusters. Clusters will be matched with tracks
424      * when this is possible.
425      *
426      * @param clusters - The list of event clusters.
427      * @param trackCollections - The list of event tracks.
428      * @return Returns a <code>List</code> collection containing all of the <code>ReconstructedParticle</code> objects
429      *         generated from the argument data.
430      */
431     protected List<ReconstructedParticle> makeReconstructedParticles(List<Cluster> clusters,
432             List<List<Track>> trackCollections) {
433 
434         // Create a list in which to store reconstructed particles.
435         List<ReconstructedParticle> particles = new ArrayList<ReconstructedParticle>();
436 
437         // Create a list of unmatched clusters. A cluster should be
438         // removed from the list if a matching track is found.
439         Set<Cluster> unmatchedClusters = new HashSet<Cluster>(clusters);
440 
441         // Create a mapping of matched clusters to corresponding tracks.
442         HashMap<Cluster, Track> clusterToTrack = new HashMap<Cluster, Track>();
443 
444         // Loop through all of the track collections and try to match every
445         // track to a cluster. Allow a cluster to be matched to multiple
446         // tracks and use a probability (to be coded later) to determine what
447         // the best match is.
448         // TODO: At some point, pull this out to it's own method
449         for (List<Track> tracks : trackCollections) {
450 
451             for (Track track : tracks) {
452 
453                 // Create a reconstructed particle to represent the track.
454                 ReconstructedParticle particle = new BaseReconstructedParticle();
455 
456                 // Store the track in the particle.
457                 particle.addTrack(track);
458 
459                 // Set the type of the particle. This is used to identify
460                 // the tracking strategy used in finding the track associated with
461                 // this particle.
462                 ((BaseReconstructedParticle) particle).setType(track.getType());
463 
464                 // Derive the charge of the particle from the track.
465                 int charge = (int) Math.signum(track.getTrackStates().get(0).getOmega());
466                 ((BaseReconstructedParticle) particle).setCharge(charge * flipSign);
467 
468                 // initialize PID quality to a junk value:
469                 ((BaseReconstructedParticle) particle).setGoodnessOfPid(9999);
470 
471                 // Extrapolate the particle ID from the track. Positively
472                 // charged particles are assumed to be positrons and those
473                 // with negative charges are assumed to be electrons.
474                 if (particle.getCharge() > 0) {
475                     ((BaseReconstructedParticle) particle).setParticleIdUsed(new SimpleParticleID(-11, 0, 0, 0));
476                 } else if (particle.getCharge() < 0) {
477                     ((BaseReconstructedParticle) particle).setParticleIdUsed(new SimpleParticleID(11, 0, 0, 0));
478                 }
479 
480                 // normalized distance of the closest match:
481                 double smallestNSigma = Double.MAX_VALUE;
482 
483                 // try to find a matching cluster:
484                 Cluster matchedCluster = null;
485                 for (Cluster cluster : clusters) {
486                     double clusTime = ClusterUtilities.getSeedHitTime(cluster);
487                     double trkT = TrackUtils.getTrackTime(track, hitToStrips, hitToRotated);
488                     
489                     if (Math.abs(clusTime - trkT - cuts.getTrackClusterTimeOffset()) > cuts.getMaxMatchDt()){
490                         if (debug) {
491                             System.out.println("Failed cluster-track deltaT!");
492                             System.out.println(clusTime + "  " + trkT + "  " + cuts.getTrackClusterTimeOffset() + ">" + cuts.getMaxMatchDt());
493                         }
494                         continue;
495                     }
496                     
497                     //if the option to use corrected cluster positions is selected, then
498                     //create a copy of the current cluster, and apply corrections to it
499                     //before calculating nsigma.  Default is don't use corrections.  
500                     Cluster originalCluster = cluster;
501                     if(useCorrectedClusterPositionsForMatching){
502                         cluster = new BaseCluster(cluster);
503                         double ypos = TrackUtils.getTrackStateAtECal(particle.getTracks().get(0)).getReferencePoint()[2];
504                         ClusterUtilities.applyCorrections(ecal, cluster, ypos,isMC);
505                     }
506                     
507                     // normalized distance between this cluster and track:
508                     final double thisNSigma = matcher.getNSigmaPosition(cluster, particle);
509                     if (enableTrackClusterMatchPlots) {
510                         if (TrackUtils.getTrackStateAtECal(track) != null)
511                             matcher.isMatch(cluster, track);
512                     }
513 
514                     // ignore if matching quality doesn't make the cut:
515                     if (thisNSigma > MAXNSIGMAPOSITIONMATCH){
516                         if (debug) {
517                             System.out.println("Failed cluster-track NSigma Cut!");
518                             System.out.println("match NSigma = "+thisNSigma + "; Max NSigma =  " + MAXNSIGMAPOSITIONMATCH );
519                         }
520                         continue;
521                     }
522                         
523 
524                     // ignore if we already found a cluster that's a better match:
525                     if (thisNSigma > smallestNSigma) {
526                         if (debug) {
527                             System.out.println("Already found a better match than this!");
528                             System.out.println("match NSigma = "+thisNSigma + "; smallest NSigma =  " + smallestNSigma );
529                         }
530                         continue;
531                     }
532                     // we found a new best cluster candidate for this track:
533                     smallestNSigma = thisNSigma;
534                     matchedCluster = originalCluster;
535 
536                     // prefer using GBL tracks to correct (later) the clusters, for some consistency:
537                     if (track.getType() >= 32 || !clusterToTrack.containsKey(matchedCluster)) {
538                         clusterToTrack.put(matchedCluster, track);
539                     }
540                 }
541 
542                 // If a cluster was found that matches the track...
543                 if (matchedCluster != null) {
544 
545                     // add cluster to the particle:
546                     particle.addCluster(matchedCluster);
547 
548                     // use pid quality to store track-cluster matching quality:
549                     ((BaseReconstructedParticle) particle).setGoodnessOfPid(smallestNSigma);
550 
551                     // propogate pid to the cluster:
552                     final int pid = particle.getParticleIDUsed().getPDG();
553                     if (Math.abs(pid) == 11) {
554                         if (!disablePID)
555                             ((BaseCluster) matchedCluster).setParticleId(pid);
556                     }
557 
558                     // unmatched clusters will (later) be used to create photon particles:
559                     unmatchedClusters.remove(matchedCluster);
560                 }
561 
562                 // Add the particle to the list of reconstructed particles.
563                 particles.add(particle);
564             }
565         }
566 
567         // Iterate over the remaining unmatched clusters.
568         for (Cluster unmatchedCluster : unmatchedClusters) {
569 
570             // Create a reconstructed particle to represent the unmatched cluster.
571             ReconstructedParticle particle = new BaseReconstructedParticle();
572 
573             // The particle is assumed to be a photon, since it did not leave a track.
574             ((BaseReconstructedParticle) particle).setParticleIdUsed(new SimpleParticleID(22, 0, 0, 0));
575 
576             int pid = particle.getParticleIDUsed().getPDG();
577             if (Math.abs(pid) != 11) {
578                 if (!disablePID)
579                     ((BaseCluster) unmatchedCluster).setParticleId(pid);
580             }
581 
582             // Add the cluster to the particle.
583             particle.addCluster(unmatchedCluster);
584 
585             // Set the reconstructed particle properties based on the cluster properties.
586             ((BaseReconstructedParticle) particle).setCharge(0);
587 
588             // Add the particle to the reconstructed particle list.
589             particles.add(particle);
590         }
591 
592         // Apply the corrections to the Ecal clusters using track information, if available
593         for (Cluster cluster : clusters) {
594             if (cluster.getParticleId() != 0) {
595                 if (clusterToTrack.containsKey(cluster)) {
596                     Track matchedT = clusterToTrack.get(cluster);
597                     double ypos = TrackUtils.getTrackStateAtECal(matchedT).getReferencePoint()[2];
598                     ClusterUtilities.applyCorrections(ecal, cluster, ypos, isMC);
599                 } else {
600                     ClusterUtilities.applyCorrections(ecal, cluster, isMC);
601                 }
602             }
603         }
604 
605         for (ReconstructedParticle particle : particles) {
606             double clusterEnergy = 0;
607             Hep3Vector momentum = null;
608 
609             if (!particle.getClusters().isEmpty()) {
610                 clusterEnergy = particle.getClusters().get(0).getEnergy();
611             }
612 
613             if (!particle.getTracks().isEmpty()) {
614                 momentum = new BasicHep3Vector(particle.getTracks().get(0).getTrackStates().get(0).getMomentum());
615                 momentum = CoordinateTransformations.transformVectorToDetector(momentum);
616             } else if (!particle.getClusters().isEmpty()) {
617                 momentum = new BasicHep3Vector(particle.getClusters().get(0).getPosition());
618                 momentum = VecOp.mult(clusterEnergy, VecOp.unit(momentum));
619             }
620             HepLorentzVector fourVector = new BasicHepLorentzVector(clusterEnergy, momentum);
621             ((BaseReconstructedParticle) particle).set4Vector(fourVector);
622         
623             // recalculate track-cluster matching n_sigma using corrected cluster positions
624             // if that option is selected
625             if(!particle.getClusters().isEmpty() && useCorrectedClusterPositionsForMatching){
626                 double goodnessPID_corrected = matcher.getNSigmaPosition(particle.getClusters().get(0), particle);
627                 ((BaseReconstructedParticle) particle).setGoodnessOfPid(goodnessPID_corrected);
628             }
629             
630         }
631 
632         // Return the list of reconstructed particles.
633         return particles;
634     }
635 
636     /**
637      * Prints a message as per <code>System.out.println</code> to the output stream if the verbose debug output option
638      * is enabled.
639      *
640      * @param debugMessage - The message to print.
641      */
642     protected void printDebug(String debugMessage) {
643         // If verbose debug mode is enabled, print out the message.
644         if (debug) {
645             System.out.printf("%s :: %s%n", simpleName, debugMessage);
646         }
647     }
648 
649     /**
650      * Processes the track and cluster collections in the event into reconstructed particles and V0 candidate particles
651      * and vertices. These reconstructed particles are then stored in the event.
652      *
653      * @param event - The event to process.
654      */
655     @Override
656     protected void process(EventHeader event) {
657 
658         // All events are required to contain Ecal clusters. If
659         // the event lacks these, then it should be skipped.
660         if (!event.hasCollection(Cluster.class, ecalClustersCollectionName)) {
661             return;
662         }
663 
664         // VERBOSE :: Note that a new event is being read.
665         printDebug("\nProcessing Event...");
666 
667         // Get the list of Ecal clusters from an event.
668         List<Cluster> clusters = event.get(Cluster.class, ecalClustersCollectionName);
669 
670         // VERBOSE :: Output the number of clusters in the event.
671         printDebug("Clusters :: " + clusters.size());
672 
673         // Get all collections of the type Track from the event. This is
674         // required in case an event contains different track collection
675         // for each of the different tracking strategies. If the event
676         // doesn't contain any track collections, intialize an empty
677         // collection and add it to the list of collections. This is
678         // needed in order to create final state particles from the the
679         // Ecal clusters in the event.
680         List<List<Track>> trackCollections = new ArrayList<List<Track>>();
681         if (trackCollectionNames != null) {
682             for (String collectionName : trackCollectionNames) {
683                 if (event.hasCollection(Track.class, collectionName)) {
684                          // VERBOSE :: Output the number of clusters in the event.
685                     printDebug("Tracks :: " + event.get(Track.class, collectionName).size());
686                     trackCollections.add(event.get(Track.class, collectionName));
687                 }
688             }
689         } else {
690             if (event.hasCollection(Track.class)) {
691                 trackCollections = event.get(Track.class);
692             } else {
693                 trackCollections.add(new ArrayList<Track>(0));
694             }
695         }
696         
697         hitToRotated = TrackUtils.getHitToRotatedTable(event);
698         hitToStrips = TrackUtils.getHitToStripsTable(event);
699 
700         // Instantiate new lists to store reconstructed particles and
701         // V0 candidate particles and vertices.
702         finalStateParticles = new ArrayList<ReconstructedParticle>();
703         electrons = new ArrayList<ReconstructedParticle>();
704         positrons = new ArrayList<ReconstructedParticle>();
705         unconstrainedV0Candidates = new ArrayList<ReconstructedParticle>();
706         beamConV0Candidates = new ArrayList<ReconstructedParticle>();
707         targetConV0Candidates = new ArrayList<ReconstructedParticle>();
708         unconstrainedV0Vertices = new ArrayList<Vertex>();
709         beamConV0Vertices = new ArrayList<Vertex>();
710         targetConV0Vertices = new ArrayList<Vertex>();
711 
712         // Loop through all of the track collections present in the event and
713         // create final state particles.
714         finalStateParticles.addAll(makeReconstructedParticles(clusters, trackCollections));
715 
716         // Separate the reconstructed particles into electrons and
717         // positrons so that V0 candidates can be generated from them.
718         for (ReconstructedParticle finalStateParticle : finalStateParticles) {
719             // If the charge is positive, assume an electron.
720             if (finalStateParticle.getCharge() > 0) {
721                 positrons.add(finalStateParticle);
722             } // Otherwise, assume the particle is a positron.
723             else if (finalStateParticle.getCharge() < 0) {
724                 electrons.add(finalStateParticle);
725             }
726         }
727 
728         // VERBOSE :: Output the number of reconstructed positrons
729         // and electrons.
730         printDebug("Number of Electrons: " + electrons.size());
731         printDebug("Number of Positrons: " + positrons.size());
732 
733         // Form V0 candidate particles and vertices from the electron
734         // and positron reconstructed particles.
735         findVertices(electrons, positrons);
736         
737         List<ReconstructedParticle> goodFinalStateParticles = particleCuts(finalStateParticles);
738         // VERBOSE :: Output the number of reconstructed particles.
739         printDebug("Final State Particles :: " + goodFinalStateParticles.size());
740         // Add the final state ReconstructedParticles to the event
741         event.put(finalStateParticlesColName, goodFinalStateParticles, ReconstructedParticle.class, 0);
742         for (ReconstructedParticle ele : goodFinalStateParticles) {
743             if (electrons.contains(ele))
744                 electrons.remove(ele);
745         }
746         event.put(OtherElectronsColName, electrons, ReconstructedParticle.class, 0);
747 
748         // Store the V0 candidate particles and vertices for each type
749         // of constraint in the appropriate collection in the event,
750         // as long as a collection name is defined.
751         if (unconstrainedV0CandidatesColName != null) {
752             printDebug("Unconstrained V0 Candidates: " + unconstrainedV0Candidates.size());
753             event.put(unconstrainedV0CandidatesColName, unconstrainedV0Candidates, ReconstructedParticle.class, 0);
754         }
755         if (beamConV0CandidatesColName != null) {
756             printDebug("Beam-Constrained V0 Candidates: " + beamConV0Candidates.size());
757             event.put(beamConV0CandidatesColName, beamConV0Candidates, ReconstructedParticle.class, 0);
758         }
759         if (targetConV0CandidatesColName != null) {
760             printDebug("Target-Constrained V0 Candidates: " + targetConV0Candidates.size());
761             event.put(targetConV0CandidatesColName, targetConV0Candidates, ReconstructedParticle.class, 0);
762         }
763         if (unconstrainedV0VerticesColName != null) {
764             printDebug("Unconstrained V0 Vertices: " + unconstrainedV0Vertices.size());
765             event.put(unconstrainedV0VerticesColName, unconstrainedV0Vertices, Vertex.class, 0);
766         }
767         if (beamConV0VerticesColName != null) {
768             printDebug("Beam-Constrained V0 Vertices: " + beamConV0Vertices.size());
769             event.put(beamConV0VerticesColName, beamConV0Vertices, Vertex.class, 0);
770         }
771         if (targetConV0VerticesColName != null) {
772             printDebug("Target-Constrained V0 Vertices: " + targetConV0Vertices.size());
773             event.put(targetConV0VerticesColName, targetConV0Vertices, Vertex.class, 0);
774         }
775     }
776 
777     /**
778      * Sets the LCIO collection names to their default values if they are not already defined.
779      */
780     @Override
781     protected void startOfData() {
782         // If any of the LCIO collection names are not properly defined, define them now.
783         if (ecalClustersCollectionName == null) {
784             ecalClustersCollectionName = "EcalClusters";
785         }
786         if (trackCollectionName == null) {
787             trackCollectionName = "GBLTracks";
788         }
789         if (finalStateParticlesColName == null) {
790             finalStateParticlesColName = "FinalStateParticles";
791         }
792         if (unconstrainedV0CandidatesColName == null) {
793             unconstrainedV0CandidatesColName = "UnconstrainedV0Candidates";
794         }
795         if (beamConV0CandidatesColName == null) {
796             beamConV0CandidatesColName = "BeamspotConstrainedV0Candidates";
797         }
798         if (targetConV0CandidatesColName == null) {
799             targetConV0CandidatesColName = "TargetConstrainedV0Candidates";
800         }
801         if (unconstrainedV0VerticesColName == null) {
802             unconstrainedV0VerticesColName = "UnconstrainedV0Vertices";
803         }
804         if (beamConV0VerticesColName == null) {
805             beamConV0VerticesColName = "BeamspotConstrainedV0Vertices";
806         }
807         if (targetConV0VerticesColName == null) {
808             targetConV0VerticesColName = "TargetConstrainedV0Vertices";
809         }
810     }
811 
812     @Override
813     protected void endOfData() {
814         if (enableTrackClusterMatchPlots)
815             matcher.saveHistograms();
816     }
817 
818     
819     public void setSnapToEdge(boolean val){
820         this.matcher.setSnapToEdge(val);
821     }
822 }