[Feedback][Tutorial Contents][Welcome Page]
The examples up to now have used the Monte Carlo event information as a basis for analysis. However, to have a full understanding of the capabilities of a proposed detector, one must model and fully simulate the response of a detector design in the presence of all the physics processes. The LCD simulations accomplish this using a program called GISMO, which is an object-oriented program written in C++ offering similar functionality to GEANT. Hits in the sensitive tracking volumes and calorimeters are written out to files with the .sio extension. This tutorial presents an example of a simple reconstruction and analysis of these fully simulated events.
First we show the entire routine, and then follow it with an explanation of different sections.
// // This is an example reconstruction and simple analysis // program for LCD events. // import java.util.*; import hep.lcd.util.driver.Driver; import hep.lcd.util.driver.AbstractProcessor; import hep.lcd.event.LCDEvent; import hep.lcd.mc.smear.SmearDriver; import hep.lcd.recon.tracking.TrackReco; import hep.lcd.event.Track; import hep.lcd.event.TrackList; import hep.lcd.recon.cluster.simple.SimpleClusterBuilder; import hep.lcd.event.Cluster; import hep.lcd.event.ClusterList; import hep.physics.BasicHepLorentzVector; import hep.physics.jets.AbstractJetFinder; import hep.physics.jets.JadeEJetFinder; import hep.physics.jets.DurhamJetFinder; import hep.lcd.geometry.Detector; final public class ExampleReconstruction extends Driver { public ExampleReconstruction() { // Smear Tracker hits with default resolutions add(new SmearDriver()); // Find tracks in combined inner tracker add(new TrackReco()); // Find Clusters using simple clustering algorithm add(new SimpleClusterBuilder()); // Find jets using tracks add(new TrackJetFinder()); // Find jets using clusters add(new ClusterJetFinder()); } } //Find Jets using reconstructed Tracks class TrackJetFinder extends AbstractProcessor { // The jet finder AbstractJetFinder _jetFinder; // Default Constructor public TrackJetFinder() { _jetFinder = new JadeEJetFinder(0.02); } // Fully qualified Constructor public TrackJetFinder( AbstractJetFinder jf) { _jetFinder = jf; } public void process(final LCDEvent event) { // We will use the charged tracks in this example to find jets // Get the list of tracks from the event TrackList tracks = event.getTrackList(); //feed them to the jet finder _jetFinder.setEvent(tracks.getTracks()); // Fill some diagnostic histograms histogram("Tracks Njets").fill(_jetFinder.njets()); // Loop over the found jets double totalJetEnergy = 0; double totalParticleEnergy = 0; for (int ijet =0; ijet<_jetFinder.njets(); ijet++) { totalJetEnergy += _jetFinder.jet(ijet).t(); histogram("Tracks Jet Energy").fill(_jetFinder.jet(ijet).t()); histogram("Number of Tracks in Jet").fill(_jetFinder.nParticlesPerJet(ijet)); // loop over all the tracks in the jet, and add up their energy // (should be the same as the jet energy) double etot = 0; Enumeration e = _jetFinder.particlesInJet(ijet); while (e.hasMoreElements()) etot += ((Track) e.nextElement()).mag(); histogram("Tracks Ptot").fill(etot); totalParticleEnergy += etot; } histogram("Total Track Jet Energy").fill(totalJetEnergy); histogram("Total Track Particle Momentum").fill(totalParticleEnergy); } } // Find Jets using Calorimeter Clusters class ClusterJetFinder extends AbstractProcessor { // the jet finder AbstractJetFinder _jetFinder; // Default Constructor public ClusterJetFinder() { _jetFinder = new DurhamJetFinder(0.02); } // Fully qualified Constructor public ClusterJetFinder( AbstractJetFinder jf) { _jetFinder = jf; } public void process(final LCDEvent event) { // We will use the calorimeter clusters in this example to find jets Vector finals = new Vector(); // Get the EM clusters from the event... ClusterList em = event.getEMClusters(); Enumeration eem = em.getClusters(); // Get the hadronic clusters from the event... ClusterList had = event.getHADClusters(); Enumeration ehad = had.getClusters(); // which detector are we using? Needed to apply sampling fractions. // This will be automatic in the future. Detector det = event.getCurrentDetector(); // defaults... double emscale = 1/.0697; //cng double hadscale = 1/.0189; //cng if(det.toString().equals("ldmar01")) { emscale = 1/.0263; hadscale = 1/.028; } else if(det.toString().equals("sdmar01")) { emscale = 1/.0222; hadscale = 1/.0555; } else if(det.toString().equals("pdmar01")) { emscale = 1/.0697; hadscale = 1/.0189; } double cEn = 0; double pt = 0; double px = 0; double py = 0; double pz = 0; // loop over the EM clusters while (eem.hasMoreElements()) { Cluster c = (Cluster) eem.nextElement(); cEn = emscale*c.getEnergy(); histogram("Total Cluster Energy").fill(cEn); histogram("EM Cluster Energy").fill(cEn); histogram("EM Theta").fill(c.getEnergyTheta()); histogram("EM CosTheta").fill(Math.cos(c.getEnergyTheta())); pt = cEn; px = cEn*Math.sin(c.getEnergyPhi())*Math.sin(c.getEnergyTheta()); py = cEn*Math.cos(c.getEnergyPhi())*Math.sin(c.getEnergyTheta()); pz = cEn*Math.cos(c.getEnergyTheta()); // cut out low energy clusters... if ( cEn > 0.5 ) { finals.addElement(new BasicHepLorentzVector(pt,px,py,pz)); } } // Loop over the hadronic clusters while (ehad.hasMoreElements()) { Cluster c = (Cluster) ehad.nextElement(); // scale the energy cEn = hadscale*c.getEnergy(); histogram("HAD Cluster Energy").fill(cEn); histogram("Total Cluster Energy").fill(cEn); histogram("HAD Theta").fill(c.getEnergyTheta()); histogram("HAD CosTheta").fill(Math.cos(c.getEnergyTheta())); pt = cEn; px = cEn*Math.sin(c.getEnergyPhi())*Math.sin(c.getEnergyTheta()); py = cEn*Math.cos(c.getEnergyPhi())*Math.sin(c.getEnergyTheta()); pz = cEn*Math.cos(c.getEnergyTheta()); // cut out low energy clusters... if ( cEn > 0.5 ) { finals.addElement(new BasicHepLorentzVector(pt + 0.137,px,py,pz)); } } // Send the list of four-vectors to the jet finder... _jetFinder.setEvent(finals.elements()); int njets = _jetFinder.njets(); histogram("Durham clusters Njets").fill(njets); double totalJetEnergy = 0; double totalParticleEnergy = 0; for (int ijet =0; ijet<_jetFinder.njets(); ijet++) { totalJetEnergy += _jetFinder.jet(ijet).t(); histogram("Durham Cluster Jet Energy").fill(_jetFinder.jet(ijet).t()); histogram("Durham Number of Clusters in Jet").fill(_jetFinder.nParticlesPerJet(ijet)); } histogram("Durham Total Jet Energy").fill(totalJetEnergy); } }
To increase the flexibility of the simulations, the hits as recorded by the sensitive volumes in the full simulation are not digitized. Therefore the first step is to smear these "ideal" hits by the detector resolutions. We will use the default settings and simply add a SmearDriver.
Having smeared the hits, we will now find and fit the tracks in the central tracking chambers. To do so, we add a TrackReco Driver. This performs pattern recognition in the sub-detectors, links the track segments and performs a global fit to the hits. The output tracks are then added back to the event.
// Smear Tracker hits with default resolutions add(new SmearDriver()); // Find tracks in combined inner tracker add(new TrackReco());
The tracks will now show up in the LCD Event Display as red tracks.
The Wired event display is also set up to display the reconstructed tracks.
The individual tracks can be toggled on or off by clicking on the boxes. An example of some of the more advanced features of the display can be seen here.
We will cluster the calorimeter cells using a simple clustering algorithm by adding a SimpleClusterBuilder Driver. The resultant clusters found in the electromagnetic and hadronic calorimeters will be added to the event.
// Find Clusters using simple clustering algorithm add(new SimpleClusterBuilder());
That's it for the reconstruction; we've found and fit tracks and clustered the energy depositions in the calorimeter cells.
In the previous tutorial the Monte Carlo particles were used as inputs to the jet finding algorithms. Here we will provide examples for using the reconstructed tracks and the calorimeter clusters as input. (The use of Energy Flow objects, where tracks are used for charged particles and unassociated calorimeter clusters are used for neutrals, is still under development.)
We construct an AbstractProcessor TrackJetFinder to use the reconstructed tracks for jet finding. The default constructor initializes the member jet finder to be a JadeEJetFinder with a ycut of 0.02 just as an example. The user can pass a different jet finder to the fully qualified constructor. The list of tracks is obtained from the LCDEvent via its getTrackList() method. The resulting TrackList is then sent to the jet finder.
// Get the list of tracks from the event TrackList tracks = event.getTrackList(); //feed them to the jet finder _jetFinder.setEvent(tracks.getTracks());Analysis of the found jets proceeds exactly as in the previous tutorial.
We construct an AbstractProcessor ClusterJetFinder to use the reconstructed calorimeter clusters for jet finding. Using the SimpleClusterBuilder results in separate clusters being reconstructed in the EM and hadronic calorimeters. The lists of clusters are obtained from the LCDEvent via its getEMClusters() and getHADClusters() methods. We then extract the Enumeration over which we will loop to access the Clusters.
ClusterList em = event.getEMClusters(); Enumeration eem = em.getClusters(); // Get the hadronic clusters from the event... ClusterList had = event.getHADClusters(); Enumeration ehad = had.getClusters();
As was the case for the tracking hits, the calorimeter deposited energies are written out as measured in the full detector simulation. We need, therefore, to convert the sampled energy into deposited energy. To do so, we need to know which detector is being simulated and then set the EM and hadronic sampling fractions appropriately.
// Which detector are we using? Detector det = event.getCurrentDetector();
The LCDEvent contains the information about the detector which was used to simulate the response. Here we only need to know which detector was used, so we compare against our known detectors. (Of course, in the future this will be done automatically).
We then loop over the Enumeration of clusters and histogram some example quantities and fill a vector of BasicHepLorentzVector objects.
// Creating the vector of final clusters to be sent to the jet finder Vector finals = new Vector();
// EM finals.addElement(new BasicHepLorentzVector(pt,px,py,pz)); // Hadronic finals.addElement(new BasicHepLorentzVector(pt + 0.137,px,py,pz));
EM objects are considered to be massless, whereas we add the pion rest mass to the hadronic clusters when creating the four-vectors. The resulting list is then sent to the jet finder.
// Send the list of four-vectors to the jet finder... _jetFinder.setEvent(finals.elements());
Analysis of the found jets proceeds exactly as in the previous tutorial.