Author: mccaky Date: Wed Oct 29 21:25:20 2014 New Revision: 1336 Log: Added documentation to particle reconstruction drivers and improved code efficiency. Modified: java/trunk/recon/src/main/java/org/hps/recon/particle/HpsReconParticleDriver.java java/trunk/recon/src/main/java/org/hps/recon/particle/ReconParticleDriver.java java/trunk/recon/src/main/java/org/hps/recon/particle/TestRunReconParticleDriver.java Modified: java/trunk/recon/src/main/java/org/hps/recon/particle/HpsReconParticleDriver.java ============================================================================= --- java/trunk/recon/src/main/java/org/hps/recon/particle/HpsReconParticleDriver.java (original) +++ java/trunk/recon/src/main/java/org/hps/recon/particle/HpsReconParticleDriver.java Wed Oct 29 21:25:20 2014 @@ -20,147 +20,188 @@ import org.hps.recon.vertexing.BilliorVertex; import org.hps.recon.vertexing.BilliorVertexer; - /** - * The Main HPS implementation of ReconParticleDriver...makes V0 candidates and does vertex fits + * The main HPS implementation of ReconParticleDriver. Method generates + * V0 candidates and does vertex fits. + * * @author Omar Moreno <[log in to unmask]> * @version $Id$ */ public class HpsReconParticleDriver extends ReconParticleDriver { - - private enum Constraint { - UNCONSTRAINED, - BS_CONSTRAINED, - TARGET_CONSTRAINED - } - - public HpsReconParticleDriver(){} - - @Override - protected void startOfData(){ - -// unconstrainedV0CandidatesColName = "UnconstrainedV0Candidates"; -// beamConV0CandidatesColName = "BeamspotConstrainedV0Candidates"; -// targetConV0CandidatesColName = "TargetConstrainedV0Candidates"; -// unconstrainedV0VerticesColName = "UnconstrainedV0Vertices"; -// beamConV0VerticesColName = "BeamspotConstrainedV0Vertices"; -// targetConV0VerticesColName = "TargetConstrainedV0Vertices"; - } - - /** - * - */ - @Override - void findVertices(List<ReconstructedParticle> electrons, List<ReconstructedParticle> positrons) { - - ReconstructedParticle candidate = null; - BilliorVertex vtxFit = null; - // Loop through both electrons and positrons and try to find a common vertex - for(ReconstructedParticle positron : positrons){ - for(ReconstructedParticle electron : electrons){ - - // Get the tracks associated with the electron and the positron - Track electronTrack = electron.getTracks().get(0); - Track positronTrack = positron.getTracks().get(0); - - // Covert the tracks to BilliorTracks used by the vertexer - BilliorTrack electronBTrack = toBilliorTrack(electronTrack); - BilliorTrack positronBTrack = toBilliorTrack(positronTrack); - - for(Constraint constraint : Constraint.values()){ - - vtxFit = fitVertex(constraint, electronBTrack, positronBTrack); - - candidate = makeReconstructedParticle(electron, positron, vtxFit); - - - switch(constraint){ - case UNCONSTRAINED: - unconstrainedV0Vertices.add(vtxFit); - unconstrainedV0Candidates.add(candidate); - break; - case BS_CONSTRAINED: - beamConV0Vertices.add(vtxFit); - beamConV0Candidates.add(candidate); - break; - case TARGET_CONSTRAINED: - targetConV0Vertices.add(vtxFit); - targetConV0Candidates.add(candidate); - break; - } - } - } - } - } - - /** - * - */ - BilliorVertex fitVertex(Constraint constraint, BilliorTrack electron, BilliorTrack positron){ - - BilliorVertexer vtxFitter = new BilliorVertexer(bField); - // TODO: The beam size should come from the conditions database - vtxFitter.setBeamSize(beamsize); - - switch(constraint){ - case UNCONSTRAINED: - vtxFitter.doBeamSpotConstraint(false); - break; - case BS_CONSTRAINED: - vtxFitter.doBeamSpotConstraint(true); - break; - case TARGET_CONSTRAINED: - vtxFitter.doTargetConstraint(true); - break; - } - - List<BilliorTrack> billiorTracks = new ArrayList<BilliorTrack>(); - billiorTracks.add(electron); - billiorTracks.add(positron); - - return vtxFitter.fitVertex(billiorTracks); - } - - /** - * - */ - ReconstructedParticle makeReconstructedParticle(ReconstructedParticle electron, ReconstructedParticle positron, BilliorVertex vtxFit){ - - ReconstructedParticle candidate = new BaseReconstructedParticle(); - ((BaseReconstructedParticle) candidate).setStartVertex(vtxFit); - candidate.addParticle(electron); - candidate.addParticle(positron); - - // TODO: The calculation of the total fitted momentum should be done within - // BilloirVertex - ((BaseReconstructedParticle) candidate).setMass(vtxFit.getParameters().get("invMass")); - Hep3Vector fittedMomentum = new BasicHep3Vector(vtxFit.getParameters().get("p1X"), - vtxFit.getParameters().get("p1Y"), - vtxFit.getParameters().get("p1Z")); - fittedMomentum = VecOp.add(fittedMomentum, new BasicHep3Vector(vtxFit.getParameters().get("p2X"), - vtxFit.getParameters().get("p2Y"), - vtxFit.getParameters().get("p2Z"))); - this.printDebug("Fitted momentum in tracking frame: " + fittedMomentum.toString()); - fittedMomentum = CoordinateTransformations.transformVectorToDetector(fittedMomentum); - this.printDebug("Fitted momentum in detector frame: " + fittedMomentum.toString()); - HepLorentzVector fourVector = new BasicHepLorentzVector(0, 0, 0, 0); - ((BasicHepLorentzVector) fourVector).setV3(fourVector.t(), fittedMomentum); - ((BaseReconstructedParticle) candidate).set4Vector(fourVector); - - // Add the ReconstructedParticle to the Vertex - vtxFit.setAssociatedParticle(candidate); - - return candidate; - - } - - - /** - * - */ + /** + * Represents a type of constraint for vertex fitting. + * + * @author Omar Moreno <[log in to unmask]> + */ + private enum Constraint { + /** Represents a fit with no constraints. */ + UNCONSTRAINED, + /** Represents a fit with beam spot constraints. */ + BS_CONSTRAINED, + /** Represents a fit with target constraints. */ + TARGET_CONSTRAINED + } + + /** + * Creates reconstructed V0 candidate particles and vertices for + * electron positron pairs using no constraints, beam constraints, + * and target constraints. These are saved to the appropriate lists + * in the super class. + * @param electrons - The list of electrons. + * @param positrons - The list of positrons. + */ + @Override + protected void findVertices(List<ReconstructedParticle> electrons, List<ReconstructedParticle> positrons) { + // Iterate over the positrons and electrons to perform vertexing + // on the pairs. + for(ReconstructedParticle positron : positrons) { + for(ReconstructedParticle electron : electrons) { + // Get the tracks associated with the electron and + // the positron. + Track electronTrack = electron.getTracks().get(0); + Track positronTrack = positron.getTracks().get(0); + + // Covert the tracks to BilliorTracks. + BilliorTrack electronBTrack = toBilliorTrack(electronTrack); + BilliorTrack positronBTrack = toBilliorTrack(positronTrack); + + // Create candidate particles for each constraint. + for(Constraint constraint : Constraint.values()) { + // Generate a candidate vertex and particle. + BilliorVertex vtxFit = fitVertex(constraint, electronBTrack, positronBTrack); + ReconstructedParticle candidate = makeReconstructedParticle(electron, positron, vtxFit); + + // Add the candidate vertex and particle to the + // appropriate LCIO collection. + switch(constraint){ + case UNCONSTRAINED: + unconstrainedV0Vertices.add(vtxFit); + unconstrainedV0Candidates.add(candidate); + break; + case BS_CONSTRAINED: + beamConV0Vertices.add(vtxFit); + beamConV0Candidates.add(candidate); + break; + case TARGET_CONSTRAINED: + targetConV0Vertices.add(vtxFit); + targetConV0Candidates.add(candidate); + break; + } + } + } + } + } + + /** + * Sets the default LCIO collection names if they are not already + * defined previously. + */ + @Override + protected void startOfData(){ + // If the LCIO collection names have not been defined, assign + // them to the default names. + if(unconstrainedV0CandidatesColName == null) { unconstrainedV0CandidatesColName = "UnconstrainedV0Candidates"; } + if(beamConV0CandidatesColName == null) { beamConV0CandidatesColName = "BeamspotConstrainedV0Candidates"; } + if(targetConV0CandidatesColName == null) { targetConV0CandidatesColName = "TargetConstrainedV0Candidates"; } + if(unconstrainedV0VerticesColName == null) { unconstrainedV0VerticesColName = "UnconstrainedV0Vertices"; } + if(beamConV0VerticesColName == null) { beamConV0VerticesColName = "BeamspotConstrainedV0Vertices"; } + if(targetConV0VerticesColName == null) { targetConV0VerticesColName = "TargetConstrainedV0Vertices"; } + } + + /** + * Fits a vertex from an electron/positron track pair using the + * indicated constraint. + * @param constraint - The constraint type to use. + * @param electron - The electron track. + * @param positron - The positron track. + * @return Returns the reconstructed vertex as a <code>BilliorVertex + * </code> object. + */ + private BilliorVertex fitVertex(Constraint constraint, BilliorTrack electron, BilliorTrack positron){ + // Create a vertex fitter from the magnetic field. + BilliorVertexer vtxFitter = new BilliorVertexer(bField); + // TODO: The beam size should come from the conditions database. + vtxFitter.setBeamSize(beamSize); + + // Perform the vertexing based on the specified constraint. + switch(constraint){ + case UNCONSTRAINED: + vtxFitter.doBeamSpotConstraint(false); + break; + case BS_CONSTRAINED: + vtxFitter.doBeamSpotConstraint(true); + break; + case TARGET_CONSTRAINED: + vtxFitter.doTargetConstraint(true); + break; + } + + // Add the electron and positron tracks to a track list for + // the vertex fitter. + List<BilliorTrack> billiorTracks = new ArrayList<BilliorTrack>(); + billiorTracks.add(electron); + billiorTracks.add(positron); + + // Find and return a vertex based on the tracks. + return vtxFitter.fitVertex(billiorTracks); + } + + /** + * Creates a reconstructed V0 candidate particle from an electron, + * positron, and billior vertex. + * @param electron - The electron. + * @param positron - The positron. + * @param vtxFit - The billior vertex. + * @return Returns a reconstructed particle with properties generated + * from the child particles and vertex given as an argument. + */ + private ReconstructedParticle makeReconstructedParticle(ReconstructedParticle electron, ReconstructedParticle positron, BilliorVertex vtxFit){ + // Create a new reconstructed particle to represent the V0 + // candidate and populate it with the electron and positron. + ReconstructedParticle candidate = new BaseReconstructedParticle(); + ((BaseReconstructedParticle) candidate).setStartVertex(vtxFit); + candidate.addParticle(electron); + candidate.addParticle(positron); + + // TODO: The calculation of the total fitted momentum should be + // done within BilloirVertex. + // Calculate the candidate particle momentum and associate it + // with the reconstructed candidate particle. + ((BaseReconstructedParticle) candidate).setMass(vtxFit.getParameters().get("invMass")); + Hep3Vector fittedMomentum = new BasicHep3Vector(vtxFit.getParameters().get("p1X"), + vtxFit.getParameters().get("p1Y"), + vtxFit.getParameters().get("p1Z")); + fittedMomentum = VecOp.add(fittedMomentum, new BasicHep3Vector(vtxFit.getParameters().get("p2X"), + vtxFit.getParameters().get("p2Y"), + vtxFit.getParameters().get("p2Z"))); + fittedMomentum = CoordinateTransformations.transformVectorToDetector(fittedMomentum); + HepLorentzVector fourVector = new BasicHepLorentzVector(0, 0, 0, 0); + ((BasicHepLorentzVector) fourVector).setV3(fourVector.t(), fittedMomentum); + ((BaseReconstructedParticle) candidate).set4Vector(fourVector); + + // VERBOSE :: Output the fitted momentum data. + printDebug("Fitted momentum in tracking frame: " + fittedMomentum.toString()); + printDebug("Fitted momentum in detector frame: " + fittedMomentum.toString()); + + // Add the ReconstructedParticle to the vertex. + vtxFit.setAssociatedParticle(candidate); + + // Return the V0 candidate. + return candidate; + } + + /** + * Converts a <code>Track</code> object to a <code>BilliorTrack + * </code> object. + * @param track - The original track. + * @return Returns the original track as a <code>BilliorTrack + * </code> object. + */ private BilliorTrack toBilliorTrack(Track track) { - - HelicalTrackFit trackFit = ((SeedTrack) track).getSeedCandidate().getHelix(); - return new BilliorTrack(trackFit); + // Convert the track to a helical track fit. + HelicalTrackFit trackFit = ((SeedTrack) track).getSeedCandidate().getHelix(); + + // Generate and return the billior track. + return new BilliorTrack(trackFit); } } Modified: java/trunk/recon/src/main/java/org/hps/recon/particle/ReconParticleDriver.java ============================================================================= --- java/trunk/recon/src/main/java/org/hps/recon/particle/ReconParticleDriver.java (original) +++ java/trunk/recon/src/main/java/org/hps/recon/particle/ReconParticleDriver.java Wed Oct 29 21:25:20 2014 @@ -21,150 +21,318 @@ import org.hps.recon.tracking.TrackUtils; /** - * Driver that matches SVT Tracks and Ecal Clusters and creates - * ReconstructedParticles. + * Driver framework for generating reconstructed particles and matching + * clusters and tracks. * * @author Mathew Graham <[log in to unmask]> * @author Omar Moreno <[log in to unmask]> * @version $Id$ */ public abstract class ReconParticleDriver extends Driver { - - // Flags - boolean debug = false; - - // Reconstructed particle collections - List<ReconstructedParticle> finalStateParticles; - List<ReconstructedParticle> unconstrainedV0Candidates; - List<ReconstructedParticle> beamConV0Candidates; - List<ReconstructedParticle> targetConV0Candidates; - List<ReconstructedParticle> electrons; - List<ReconstructedParticle> positrons; - List<Vertex> unconstrainedV0Vertices; - List<Vertex> beamConV0Vertices; - List<Vertex> targetConV0Vertices; - - // Collections - String ecalClustersCollectionName = "EcalClusters"; - String tracksCollectionName = "MatchedTracks"; - String finalStateParticlesColName = "FinalStateParticles"; - String unconstrainedV0CandidatesColName = "UnconstrainedV0Candidates"; - String beamConV0CandidatesColName = "BeamspotConstrainedV0Candidates"; - String targetConV0CandidatesColName = "TargetConstrainedV0Candidates"; - String unconstrainedV0VerticesColName = "UnconstrainedV0Vertices"; - String beamConV0VerticesColName = "BeamspotConstrainedV0Vertices"; - String targetConV0VerticesColName = "TargetConstrainedV0Vertices"; -// String unconstrainedV0CandidatesColName = null; -// String beamConV0CandidatesColName = null; -// String targetConV0CandidatesColName = null; -// String vertexCandidatesColName = null; -// String vertexBeamConsCandidatesName = null; -// String unconstrainedV0VerticesColName = null; -// String beamConV0VerticesColName = null; -// String targetConV0VerticesColName = null; - - // The beamsize array is in the tracking frame - /* TODO mg-May 14, 2014: the the beam size from the conditions db...also beam position! */ - double[] beamsize = {0.001, 0.2, 0.02}; - double maxTrackClusterDistance = 10000; // [mm] - double bField; - - // flipSign is a kludge... - // HelicalTrackFitter doesn't deal with B-fields in -ive Z correctly - // so we set the B-field in +iveZ and flip signs of fitted tracks - // - // Note: This should be -1 for test run configurations and +1 for - // prop-2014 configurations - int flipSign = 1; - - public ReconParticleDriver() { - } - - public void setDebug(boolean debug) { - this.debug = debug; - } - - public void setMaxTrackClusterDistance(double maxTrackClusterDistance) { - this.maxTrackClusterDistance = maxTrackClusterDistance; - } - - public void setBeamSigmaX(double sigma_x) { - beamsize[1] = sigma_x; - } - - public void setBeamSigmaY(double sigma_y) { - beamsize[2] = sigma_y; - } - + /** + * Sets the name of the LCIO collection for beam spot constrained + * V0 candidate particles. + * @param beamConV0CandidatesColName - The LCIO collection name. + */ + public void setBeamConV0CandidatesColName(String beamConV0CandidatesColName) { + this.beamConV0CandidatesColName = beamConV0CandidatesColName; + } + + /** + * Sets the name of the LCIO collection for beam spot constrained + * V0 candidate vertices. + * @param beamConV0VerticesColName - The LCIO collection name. + */ + public void setBeamConV0VerticesColName(String beamConV0VerticesColName) { + this.beamConV0VerticesColName = beamConV0VerticesColName; + } + + /** + * Sets the beam size sigma in the x-direction. + * @param sigmaX - The standard deviation of the beam width in the + * x-direction. + */ + public void setBeamSigmaX(double sigmaX) { beamSize[1] = sigmaX; } + + /** + * Sets the beam size sigma in the y-direction. + * @param sigmaY - The standard deviation of the beam width in the + * y-direction. + */ + public void setBeamSigmaY(double sigmaY) { beamSize[2] = sigmaY; } + + /** + * Indicates whether verbose debug text should be written out during + * runtime or note. Defaults to <code>false</code>. + * @param debug - <code>true</code> indicates that debug text should + * be written and <code>false</code> that it should be suppressed. + */ + public void setDebug(boolean debug) { this.debug = debug; } + + /** + * Sets the maximum allowed separation distance between a matched + * cluster and track pair. + * @param dxCut - The maximum separation distance in the x-direction. + */ + public void setDxCut(double dxCut) { + this.dxCut = dxCut; + } + + /** + * Sets the maximum allowed separation distance between a matched + * cluster and track pair. + * @param dyCut - The maximum separation distance in the y-direction. + */ + public void setDyCut(double dyCut) { + this.dyCut = dyCut; + } + + /** + * Sets the LCIO collection name for calorimeter cluster data. + * @param ecalClustersCollectionName - The LCIO collection name. + */ public void setEcalClusterCollectionName(String ecalClustersCollectionName) { this.ecalClustersCollectionName = ecalClustersCollectionName; } - + + /** + * Sets the name of the LCIO collection for reconstructed particles. + * @param finalStateParticlesColName - The LCIO collection name. + */ + public void setFinalStateParticlesColName(String finalStateParticlesColName) { + this.finalStateParticlesColName = finalStateParticlesColName; + } + + /** + * Sets the name of the LCIO collection for target constrained V0 + * candidate particles. + * @param targetConV0CandidatesColName - The LCIO collection name. + */ + public void setTargetConV0CandidatesColName(String targetConV0CandidatesColName) { + this.targetConV0CandidatesColName = targetConV0CandidatesColName; + } + + /** + * Sets the name of the LCIO collection for target constrained V0 + * candidate vertices. + * @param targetConV0VerticesColName - The LCIO collection name. + */ + public void setTargetConV0VerticesColName(String targetConV0VerticesColName) { + this.targetConV0VerticesColName = targetConV0VerticesColName; + } + + /** + * Sets the LCIO collection name for particle track data. + * @param tracksCollectionName - The LCIO collection name. + */ public void setTracksCollectionName(String tracksCollectionName) { this.tracksCollectionName = tracksCollectionName; } - public void setFinalStateParticlesColName(String finalStateParticlesColName) { - this.finalStateParticlesColName = finalStateParticlesColName; - } - - + /** + * Sets the name of the LCIO collection for unconstrained V0 + * candidate particles. + * @param unconstrainedV0CandidatesColName - The LCIO collection name. + */ public void setUnconstrainedV0CandidatesColName(String unconstrainedV0CandidatesColName) { this.unconstrainedV0CandidatesColName = unconstrainedV0CandidatesColName; } - - public void setBeamConV0CandidatesColName(String beamConV0CandidatesColName) { - this.beamConV0CandidatesColName = beamConV0CandidatesColName; - } - - - public void setTargetConV0CandidatesColName(String targetV0CandidatesColName) { - this.targetConV0CandidatesColName = targetConV0CandidatesColName; - } - - + /** + * Sets the name of the LCIO collection for unconstrained V0 + * candidate vertices. + * @param unconstrainedV0VerticesColName - The LCIO collection name. + */ public void setUnconstrainedV0VerticesColName(String unconstrainedV0VerticesColName) { this.unconstrainedV0VerticesColName = unconstrainedV0VerticesColName; } - - public void setBeamConV0VerticesColName(String beamConV0VerticesColName) { - this.beamConV0VerticesColName = beamConV0VerticesColName; - } - - - public void setTargetConV0VerticesColName(String targetV0VerticesColName) { - this.targetConV0VerticesColName = targetConV0VerticesColName; - } - + /** + * Updates the magnetic field parameters to match the appropriate + * values for the current detector settings. + */ @Override protected void detectorChanged(Detector detector) { - + // Set the magnetic field parameters to the appropriate values. Hep3Vector ip = new BasicHep3Vector(0., 0., 1.); bField = detector.getFieldMap().getField(ip).y(); - if (bField < 0) - flipSign = -1; - - } - - public void process(EventHeader event) { - - // All events should have a collection of Ecal clusters. If the event - // doesn't have one, skip the event. - if (!event.hasCollection(Cluster.class, ecalClustersCollectionName)) + if (bField < 0) { flipSign = -1; } + } + + /** + * Generates reconstructed V0 candidate particles and vertices from + * sets of positrons and electrons. Implementing methods should + * place the reconstructed vertices and candidate particles into the + * appropriate class variable lists in <code>ReconParticleDriver + * </code>. + * @param electrons - The list of electrons. + * @param positrons - The list of positrons. + */ + protected abstract void findVertices(List<ReconstructedParticle> electrons, List<ReconstructedParticle> positrons); + + /** + * Create the set of final state particles from the event tracks + * and clusters. Clusters will be matched with tracks when this + * is possible. + * @param clusters - The list of event clusters. + * @param tracks - The list of event tracks. + * @return Returns a <code>List</code> collection containing all + * of the <code>ReconstructedParticle</code> objects generated from + * the argument data. + */ + protected List<ReconstructedParticle> makeReconstructedParticles(List<Cluster> clusters, List<Track> tracks) { + // Create a list in which to store reconstructed particles. + List<ReconstructedParticle> particles = new ArrayList<ReconstructedParticle>(); + + // Create a list of unmatched clusters. A cluster should be + // removed from the list if a matching track is found. + //List<Cluster> unmatchedClusters = new ArrayList<Cluster>(clusters); + java.util.Set<Cluster> unmatchedClusters = new java.util.HashSet<Cluster>(clusters); + + // Iterate over all of the tracks and generate reconstructed + // particles for each one. If possible, match a cluster to the + // track as well. + for (Track track : tracks) { + // Create a reconstructed particle to represent the track. + ReconstructedParticle particle = new BaseReconstructedParticle(); + HepLorentzVector fourVector = new BasicHepLorentzVector(0, 0, 0, 0); + + // Store the track in the particle. + particle.addTrack(track); + + // Store the momentum derived from the track in the particle. + Hep3Vector momentum = new BasicHep3Vector(track.getTrackStates().get(0).getMomentum()); + momentum = CoordinateTransformations.transformVectorToDetector(momentum); + ((BasicHepLorentzVector) fourVector).setV3(fourVector.t(), momentum); + + // Derive the charge of the particle from the track. + ((BaseReconstructedParticle) particle).setCharge(track.getCharge() * flipSign); + + // Extrapolate the particle ID from the track. Positively + // charged particles are assumed to be positrons and those + // with negative charges are assumed to be electrons. + if (particle.getCharge() > 0) { + ((BaseReconstructedParticle) particle).setParticleIdUsed(new SimpleParticleID(-11, 0, 0, 0)); + } + else if (particle.getCharge() < 0) { + ((BaseReconstructedParticle) particle).setParticleIdUsed(new SimpleParticleID(11, 0, 0, 0)); + } + + // Track the best matching cluster for the track. A null + // value indicates that no cluster matches the track to + // within the maximum displacement limits. + Cluster matchedCluster = null; + + // Loop through all the unmatched clusters and select the + // cluster, if any, that best fits with the track. + clusterLoop: + for (Cluster cluster : unmatchedClusters) { + // Check if the cluster and track are a valid match. + if (isMatch(cluster, track)) { + // Store the matched cluster. + matchedCluster = cluster; + + // Since a match has been found, the loop can be + // terminated. + break clusterLoop; + } + } + + // If a cluster was found that matches the track... + if (matchedCluster != null) { + // Update the reconstructed particle with the data from + // the cluster. + particle.addCluster(matchedCluster); + ((BasicHepLorentzVector) fourVector).setT(matchedCluster.getEnergy()); + + // Remove the cluster from the set of unmatched clusters. + unmatchedClusters.remove(matchedCluster); + } + + // Store the momentum vector in the reconstructed particle. + ((BaseReconstructedParticle) particle).set4Vector(fourVector); + + // Add the particle to the list of reconstructed particles. + particles.add(particle); + } + + // If any cluster remain unmatched after the tracks are finished, + // they should be processed into additional reconstructed particles. + if (!unmatchedClusters.isEmpty()) + // Iterate over the remaining unmatched clusters. + for (Cluster unmatchedCluster : unmatchedClusters) { + // Create a reconstructed particle to represent the + // unmatched cluster. + ReconstructedParticle particle = new BaseReconstructedParticle(); + HepLorentzVector fourVector = new BasicHepLorentzVector(0, 0, 0, 0); + + // Add the cluster to the particle. + particle.addCluster(unmatchedCluster); + + // Set the reconstructed particle properties based on + // the cluster properties. + ((BasicHepLorentzVector) fourVector).setT(unmatchedCluster.getEnergy()); + ((BaseReconstructedParticle) particle).setCharge(0); + ((BaseReconstructedParticle) particle).set4Vector(fourVector); + + // The particle is assumed to be a photon, since it + // did not leave any track. + ((BaseReconstructedParticle) particle).setParticleIdUsed(new SimpleParticleID(22, 0, 0, 0)); + + // Add the particle to the reconstructed particle list. + particles.add(particle); + } + + // Return the list of reconstructed particles. + return particles; + } + + /** + * Prints a message as per <code>System.out.println</code> to the + * output stream if the verbose debug output option is enabled. + * @param debugMessage - The message to print. + */ + protected void printDebug(String debugMessage) { + // If verbose debug mode is enabled, print out the message. + if(debug) { System.out.printf("%s :: %s%n", simpleName, debugMessage); } + } + + /** + * Processes the track and cluster collections in the event into + * reconstructed particles and V0 candidate particles and vertices. + * These reconstructed particles are then stored in the event. + * @param event - The event to process. + */ + @Override + protected void process(EventHeader event) { + // All events are required to contain calorimeter clusters. If + // the event lacks these, then it should be skipped. + if (!event.hasCollection(Cluster.class, ecalClustersCollectionName)) { return; - - // Get the collection of Ecal clusters from the event. A triggered - // event should have Ecal clusters. If it doesn't, skip the event. + } + + // VERBOSE :: Note that a new event is being read. + printDebug("\nProcessing Event..."); + + // Otherwise, get the list of calorimeter clusters. List<Cluster> clusters = event.get(Cluster.class, ecalClustersCollectionName); - //if(clusters.isEmpty()) return; - this.printDebug("Number of Ecal clusters: " + clusters.size()); - - // Get the collection of tracks from the event - List<Track> tracks = event.get(Track.class, tracksCollectionName); - this.printDebug("Number of Tracks in "+tracksCollectionName+" : " + tracks.size()); - + + // VERBOSE :: Output the number of clusters in the event. + printDebug("Clusters :: " + clusters.size()); + + // Get the set of tracks from the event. If no such collection + // exists, initialize an empty list instead. + List<Track> tracks; + if(event.hasCollection(Track.class, tracksCollectionName)) { + tracks = event.get(Track.class, tracksCollectionName); + } + else { tracks = new ArrayList<Track>(0); } + + // VERBOSE :: Output the number of tracks in the event. + printDebug("Tracks :: " + tracks.size()); + + // Instantiate new lists to store reconstructed particles and + // V0 candidate particles and vertices. finalStateParticles = new ArrayList<ReconstructedParticle>(); electrons = new ArrayList<ReconstructedParticle>(); positrons = new ArrayList<ReconstructedParticle>(); @@ -174,193 +342,227 @@ unconstrainedV0Vertices = new ArrayList<Vertex>(); beamConV0Vertices = new ArrayList<Vertex>(); targetConV0Vertices = new ArrayList<Vertex>(); - - // - finalStateParticles = this.makeReconstructedParticles(clusters, tracks); - this.printDebug("Total number of Final State Particles: " + finalStateParticles.size()); - - // Put all the reconstructed particles in the event + + // Generate the reconstructed particles. + finalStateParticles = makeReconstructedParticles(clusters, tracks); + + // VERBOSE :: Output the number of reconstructed particles. + printDebug("Final State Particles :: " + finalStateParticles.size()); + + // Store the reconstructed particles collection. event.put(finalStateParticlesColName, finalStateParticles, ReconstructedParticle.class, 0); - - // Loop through the list of final state particles and separate the - // charged particles to either electrons or positrons. These lists - // will be used for vertexing purposes. - for (ReconstructedParticle finalStateParticle : finalStateParticles) - if (finalStateParticle.getCharge() > 0) - positrons.add(finalStateParticle); - else if (finalStateParticle.getCharge() < 0) - electrons.add(finalStateParticle); - this.printDebug("Number of Electrons: " + electrons.size()); - this.printDebug("Number of Positrons: " + positrons.size()); - - // Vertex electron and positron candidates + + // Separate the reconstructed particles into electrons and + // positrons so that V0 candidates can be generated from them. + for (ReconstructedParticle finalStateParticle : finalStateParticles) { + // If the charge is positive, assume an electron. + if(finalStateParticle.getCharge() > 0) { positrons.add(finalStateParticle); } + + // Otherwise, assume the particle is a positron. + else if(finalStateParticle.getCharge() < 0) { electrons.add(finalStateParticle); } + } + + // VERBOSE :: Output the number of reconstructed positrons + // and electrons. + printDebug("Number of Electrons: " + electrons.size()); + printDebug("Number of Positrons: " + positrons.size()); + + // Form V0 candidate particles and vertices from the electron + // and positron reconstructed particles. findVertices(electrons, positrons); - - // If the list exist, put the vertexed candidates and vertices into the event + + // Store the V0 candidate particles and vertices for each type + // of constraint in the appropriate collection in the event, + // as long as a collection name is defined. if (unconstrainedV0CandidatesColName != null) { - this.printDebug("Total number of unconstrained V0 candidates: " + unconstrainedV0Candidates.size()); + printDebug("Unconstrained V0 Candidates: " + unconstrainedV0Candidates.size()); event.put(unconstrainedV0CandidatesColName, unconstrainedV0Candidates, ReconstructedParticle.class, 0); } if (beamConV0CandidatesColName != null) { - this.printDebug("Total number of beam constrained V0 candidates: " + unconstrainedV0Candidates.size()); + printDebug("Beam-Constrained V0 Candidates: " + unconstrainedV0Candidates.size()); event.put(beamConV0CandidatesColName, beamConV0Candidates, ReconstructedParticle.class, 0); } if (targetConV0CandidatesColName != null) { - this.printDebug("Total number of target constrained V0 candidates: " + unconstrainedV0Candidates.size()); + printDebug("Target-Constrained V0 Candidates: " + unconstrainedV0Candidates.size()); event.put(targetConV0CandidatesColName, targetConV0Candidates, ReconstructedParticle.class, 0); } if (unconstrainedV0VerticesColName != null) { - this.printDebug("Total number of unconstrained V0 vertices: " + unconstrainedV0Vertices.size()); + printDebug("Unconstrained V0 Vertices: " + unconstrainedV0Vertices.size()); event.put(unconstrainedV0VerticesColName, unconstrainedV0Vertices, Vertex.class, 0); } if (beamConV0VerticesColName != null) { - this.printDebug("Total number of beam constrained V0 vertices: " + beamConV0Vertices.size()); + printDebug("Beam-Constrained V0 Vertices: " + beamConV0Vertices.size()); event.put(beamConV0VerticesColName, beamConV0Vertices, Vertex.class, 0); } if (targetConV0VerticesColName != null) { - this.printDebug("Total number of target constrained V0 vertices: " + beamConV0Vertices.size()); + printDebug("Target-Constrained V0 Vertices: " + beamConV0Vertices.size()); event.put(targetConV0VerticesColName, targetConV0Vertices, Vertex.class, 0); } } - - /** - * - */ - abstract void findVertices(List<ReconstructedParticle> electrons, List<ReconstructedParticle> positrons); - - /** - * make the final state particles from clusters & tracks - * loop over the tracks first and try to match with clusters - */ - protected List<ReconstructedParticle> makeReconstructedParticles(List<Cluster> clusters, List<Track> tracks) { - - // Instantiate the list of reconstructed particles - List<ReconstructedParticle> particles = new ArrayList<ReconstructedParticle>(); - - // Instantiate the list of unmatched clusters. Remove if we find track match - List<Cluster> unmatchedClusters = new ArrayList<Cluster>(clusters); - - for (Track track : tracks) { - - ReconstructedParticle particle = new BaseReconstructedParticle(); - HepLorentzVector fourVector = new BasicHepLorentzVector(0, 0, 0, 0); - - // - // Add all track information to the ReconstructedParticle - // - particle.addTrack(track); - - // Set the momentum of the ReconstructedParticle - Hep3Vector momentum = new BasicHep3Vector(track.getTrackStates().get(0).getMomentum()); - momentum = CoordinateTransformations.transformVectorToDetector(momentum); - ((BasicHepLorentzVector) fourVector).setV3(fourVector.t(), momentum); - // Set the charge of the ReconstructedParticle - ((BaseReconstructedParticle) particle).setCharge(track.getCharge() * flipSign); - // Set the particle ID - if (particle.getCharge() > 0) - ((BaseReconstructedParticle) particle).setParticleIdUsed(new SimpleParticleID(-11, 0, 0, 0)); - else if (particle.getCharge() < 0) - ((BaseReconstructedParticle) particle).setParticleIdUsed(new SimpleParticleID(11, 0, 0, 0)); - - Cluster matchedCluster = null; - // Loop through all of the clusters and find the one that best matches - // the track. - for (Cluster cluster : unmatchedClusters) { - - // Get the position of the Ecal cluster - Hep3Vector clusterPosition = new BasicHep3Vector(cluster.getPosition()); - - // Extrapolate the track to the Ecal cluster position - Hep3Vector trackPosAtEcal = TrackUtils.extrapolateTrack(track, clusterPosition.z()); - this.printDebug("Ecal cluster position: " + clusterPosition.toString()); - - double rMax = Double.MAX_VALUE; - - // Check if any of the extrapolated values are invalid. - // TODO: There are some track whose extrapolated coordinates - // are NaN. The problem seems to be that the y-coordinate - // of the extrapolated helix is found to be non-real. This - // needs to be fixed. - if (Double.isNaN(trackPosAtEcal.x()) || Double.isNaN(trackPosAtEcal.y())) - continue; - this.printDebug("Track position at shower max: " + trackPosAtEcal.toString()); - -// double r = VecOp.sub(trackPosAtEcal, clusterPosition).magnitude(); - // Don't trust extrapolation...just do y-difference for now - double r = Math.abs(clusterPosition.y() - trackPosAtEcal.y()); - this.printDebug("Distance between Ecal cluster and track position: " + r + " mm"); - - // Check if the Ecal cluster and track are within the same - // detector volume i.e. both top or bottom - if (clusterPosition.y() * trackPosAtEcal.y() < 0) { - this.printDebug("Track and Ecal cluster are in opposite volumes. Track Y @ ECAL = " + trackPosAtEcal.z()); - continue; - } - - // TODO: Checking whether r < rMax should be occuring within isMatch. isMatch - // is basically repeating a lot of the same code as above. - if (r < rMax && isMatch(cluster, track)) { - rMax = r; - matchedCluster = cluster; - } - } - - if (matchedCluster != null) { - particle.addCluster(matchedCluster); - ((BasicHepLorentzVector) fourVector).setT(matchedCluster.getEnergy()); - unmatchedClusters.remove(matchedCluster); - } - ((BaseReconstructedParticle) particle).set4Vector(fourVector); - particles.add(particle); - } - - if (!unmatchedClusters.isEmpty()) - for (Cluster unmatchedCluster : unmatchedClusters) { - // Create a reconstructed particle and add it to the - // collection of particles - ReconstructedParticle particle = new BaseReconstructedParticle(); - HepLorentzVector fourVector = new BasicHepLorentzVector(0, 0, 0, 0); - - particle.addCluster(unmatchedCluster); - ((BasicHepLorentzVector) fourVector).setT(unmatchedCluster.getEnergy()); - ((BaseReconstructedParticle) particle).setCharge(0); - ((BaseReconstructedParticle) particle).set4Vector(fourVector); - ((BaseReconstructedParticle) particle).setParticleIdUsed(new SimpleParticleID(22, 0, 0, 0)); - particles.add(particle); - } - - return particles; - } - - /** - * - * @param debugMessage - */ - protected void printDebug(String debugMessage) { - if (debug) - System.out.println(this.getClass().getSimpleName() + ": " + debugMessage); - } - - /** - * - */ - boolean isMatch(Cluster cluster, Track track) { - - // Get the position of the Ecal cluster + + /** + * Sets the LCIO collection names to their default values if they + * are not already defined. + */ + @Override + protected void startOfData() { + // If any of the LCIO collection names are not properly defined, define them now. + if(ecalClustersCollectionName == null) { ecalClustersCollectionName = "EcalClusters"; } + if(tracksCollectionName == null) { tracksCollectionName = "MatchedTracks"; } + if(finalStateParticlesColName == null) { finalStateParticlesColName = "FinalStateParticles"; } + if(unconstrainedV0CandidatesColName == null) { unconstrainedV0CandidatesColName = "UnconstrainedV0Candidates"; } + if(beamConV0CandidatesColName == null) { beamConV0CandidatesColName = "BeamspotConstrainedV0Candidates"; } + if(targetConV0CandidatesColName == null) { targetConV0CandidatesColName = "TargetConstrainedV0Candidates"; } + if(unconstrainedV0VerticesColName == null) { unconstrainedV0VerticesColName = "UnconstrainedV0Vertices"; } + if(beamConV0VerticesColName == null) { beamConV0VerticesColName = "BeamspotConstrainedV0Vertices"; } + if(targetConV0VerticesColName == null) { targetConV0VerticesColName = "TargetConstrainedV0Vertices"; } + } + + /** + * Determines if a cluster is a potential match for a given track. + * If it is, returns the distance between the extrapolation of the + * track to the z-position of the cluster and the cluster position. + * Otherwise, returns <code>null</code> to indicate that the pair + * is not a valid match. + * @param cluster - The cluster to check. + * @param track - The track to check. + * @return Returns the distance between the cluster and extrapolated + * track position in millimeters as a <code>Double</code> if the + * pair is a potential match. Returns <code>null</code> otherwise. + */ + private boolean isMatch(Cluster cluster, Track track) { + // Get the position of the cluster and extrapolate the position + // of the track at the z-position of the cluster. Hep3Vector clusterPosition = new BasicHep3Vector(cluster.getPosition()); - - // Extrapolate the track to the Ecal cluster position Hep3Vector trackPosAtEcal = TrackUtils.extrapolateTrack(track, clusterPosition.z()); - - double dxCut = 20.0; - double dyCut = 20.0; - - if (Math.abs(trackPosAtEcal.x() - clusterPosition.x()) > dxCut) + + // TODO: There are some track whose extrapolated coordinates + // are NaN. The problem seems to be that the y-coordinate + // of the extrapolated helix is found to be non-real. This + // needs to be fixed. + // There is an issue with track extrapolation that sometimes + // yields NaN for extrapolated track parameters. Tracks with + // this issue are not usable and thusly the check should be + // skipped. + if (Double.isNaN(trackPosAtEcal.x()) || Double.isNaN(trackPosAtEcal.y())) { + // VERBOSE :: Indicate the reason for the match failing. + printDebug("\tFailure :: Track extrapolation error."); + + // Return false to indicate that the pair do not match. return false; - - if (Math.abs(trackPosAtEcal.y() - clusterPosition.y()) > dyCut) + } + + // VERBOSE :: Output the position of the extrapolated track + // and the cluster. + printDebug("\tCluster Position :: " + clusterPosition.toString()); + printDebug("\tTrack Position :: " + trackPosAtEcal.toString()); + + // If one of either the cluster or extrapolated track fall on + // one volume of the detector and the other is in the other + // volume, then they can not be a match. (i.e. both parts of + // the pair must be on the top or bottom of the detector.) + if (clusterPosition.y() * trackPosAtEcal.y() < 0) { + // VERBOSE :: Indicate the reason for the match failing. + printDebug("\tFailure :: Cluster/Track pair in opposite volumes."); + + // Return false to indicate that the pair do not match. return false; - + } + + // Check to make sure that the x and y displacements between + // the extrapolated track position and cluster position are + // within the allowed bounds. If they are not, this pair is + // not a match. + if (Math.abs(trackPosAtEcal.x() - clusterPosition.x()) > dxCut) { + // VERBOSE :: Indicate the reason for the match failing. + printDebug("\tFailure :: Pair x-displacement exceeds allowed threshold."); + + // Return false to indicate that the pair do not match. + return false; + } + + if (Math.abs(trackPosAtEcal.y() - clusterPosition.y()) > dyCut) { + // VERBOSE :: Indicate the reason for the match failing. + printDebug("\tFailure :: Pair y-displacement exceeds allowed threshold."); + + // Return false to indicate that the pair do not match. + return false; + } + + // VERBOSE :: Indicate the reason for the match failing. + printDebug("\tSuccess :: Cluster/track pair match!."); + + // A pair that has reached this point is a potential match. + // Return true to indicate a match. return true; } + + // ============================================================== + // ==== Class Variables ========================================= + // ============================================================== + // Local variables. + /** The maximum separation distance in the x-direction beyond which + * a cluster and track will be rejected for pairing. */ + private double dxCut = 20.0; + /** The maximum separation distance in the y-direction beyond which + * a cluster and track will be rejected for pairing. */ + private double dyCut = 20.0; + /** Indicates whether debug text should be output or not. */ + private boolean debug = false; + /** The simple name of the class used for debug print statements. */ + private final String simpleName = getClass().getSimpleName(); + + // Reconstructed Particle Lists + /** Stores reconstructed electron particles. */ + private List<ReconstructedParticle> electrons; + /** Stores reconstructed positron particles. */ + private List<ReconstructedParticle> positrons; + /** Stores particles reconstructed from an event. */ + protected List<ReconstructedParticle> finalStateParticles; + /** Stores reconstructed V0 candidate particles generated without constraints. */ + protected List<ReconstructedParticle> unconstrainedV0Candidates; + /** Stores reconstructed V0 candidate particles generated with beam spot constraints. */ + protected List<ReconstructedParticle> beamConV0Candidates; + /** Stores reconstructed V0 candidate particles generated with target constraints. */ + protected List<ReconstructedParticle> targetConV0Candidates; + /** Stores reconstructed V0 candidate vertices generated without constraints. */ + protected List<Vertex> unconstrainedV0Vertices; + /** Stores reconstructed V0 candidate vertices generated with beam spot constraints. */ + protected List<Vertex> beamConV0Vertices; + /** Stores reconstructed V0 candidate vertices generated with target constraints. */ + protected List<Vertex> targetConV0Vertices; + + // LCIO Collection Names + /** LCIO collection name for calorimeter clusters. */ + private String ecalClustersCollectionName = "EcalClusters"; + /** LCIO collection name for tracks. */ + private String tracksCollectionName = "MatchedTracks"; + /** LCIO collection name for reconstructed particles. */ + private String finalStateParticlesColName = "FinalStateParticles"; + /** LCIO collection name for V0 candidate particles generated without constraints. */ + protected String unconstrainedV0CandidatesColName = null; + /** LCIO collection name for V0 candidate particles generated with beam spot constraints. */ + protected String beamConV0CandidatesColName = null; + /** LCIO collection name for V0 candidate particles generated with target constraints. */ + protected String targetConV0CandidatesColName = null; + /** LCIO collection name for V0 candidate vertices generated without constraints. */ + protected String unconstrainedV0VerticesColName = null; + /** LCIO collection name for V0 candidate vertices generated with beam spot constraints. */ + protected String beamConV0VerticesColName = null; + /** LCIO collection name for V0 candidate vertices generated with target constraints. */ + protected String targetConV0VerticesColName = null; + + // Beam size variables. + // The beamsize array is in the tracking frame + /* TODO mg-May 14, 2014: the the beam size from the conditions db...also beam position! */ + protected double[] beamSize = {0.001, 0.2, 0.02}; + protected double bField; + + // flipSign is a kludge... + // HelicalTrackFitter doesn't deal with B-fields in -ive Z correctly + // so we set the B-field in +iveZ and flip signs of fitted tracks + // + // Note: This should be -1 for test run configurations and +1 for + // prop-2014 configurations + private int flipSign = 1; } Modified: java/trunk/recon/src/main/java/org/hps/recon/particle/TestRunReconParticleDriver.java ============================================================================= --- java/trunk/recon/src/main/java/org/hps/recon/particle/TestRunReconParticleDriver.java (original) +++ java/trunk/recon/src/main/java/org/hps/recon/particle/TestRunReconParticleDriver.java Wed Oct 29 21:25:20 2014 @@ -10,41 +10,59 @@ import org.hps.recon.vertexing.TwoTrackVertexer; /** + * Method creates reconstructed particles from tracks and clusters for + * test run data. Also generates candidate A' reconstructed particles. + * This method does not generate a separate vertex collection. * * @author Omar Moreno <[log in to unmask]> * @version $Id$ */ public class TestRunReconParticleDriver extends ReconParticleDriver { - - public TestRunReconParticleDriver(){}; - - @Override - protected void startOfData(){ - unconstrainedV0CandidatesColName = "V0Candidates"; - } - - @Override - void findVertices(List<ReconstructedParticle> electrons, List<ReconstructedParticle> positrons) { - - TwoTrackVertexer vtxFitter = new TwoTrackVertexer(); - - // Loop through both electrons and positrons and try to vertex them - for(ReconstructedParticle positron : positrons){ - for(ReconstructedParticle electron : electrons){ - - // Get the tracks associated with the electrons and positrons - Track electronTrack = electron.getTracks().get(0); - Track positronTrack = positron.getTracks().get(0); - vtxFitter.setTracks(electronTrack, positronTrack); - vtxFitter.fitVertex(); - Vertex vertex = vtxFitter.getFittedVertex(); - - ReconstructedParticle candidate = new BaseReconstructedParticle(); - ((BaseReconstructedParticle) candidate).setStartVertex(vertex); - candidate.addParticle(electron); - candidate.addParticle(positron); - unconstrainedV0Candidates.add(candidate); - } - } - } + /** + * Generates reconstructed V0 candidate particles from electron + * and positron pairs. + * @param electrons - The list of electrons. + * @param positrons - The list of positrons. + */ + @Override + protected void findVertices(List<ReconstructedParticle> electrons, List<ReconstructedParticle> positrons) { + // Create a vertex fitter. + TwoTrackVertexer vtxFitter = new TwoTrackVertexer(); + + // Iterate over the electrons and positrons and try to generate + // an A' candidate from them. + for(ReconstructedParticle positron : positrons){ + for(ReconstructedParticle electron : electrons){ + // Get the electron and positron tracks. + Track electronTrack = electron.getTracks().get(0); + Track positronTrack = positron.getTracks().get(0); + + // Feed the tracks to the vertex fitter. + vtxFitter.setTracks(electronTrack, positronTrack); + vtxFitter.fitVertex(); + + // Get the reconstructed vertex. + Vertex vertex = vtxFitter.getFittedVertex(); + + // Create a reconstructed particle for the candidate + // particle generated from the electron/positron pair. + ReconstructedParticle candidate = new BaseReconstructedParticle(); + ((BaseReconstructedParticle) candidate).setStartVertex(vertex); + candidate.addParticle(electron); + candidate.addParticle(positron); + + // Add the candidate particle to list. + unconstrainedV0Candidates.add(candidate); + } + } + } + + /** + * Sets the unconstrained A' candidate particle collection name if + * it has not already been defined. + */ + @Override + protected void startOfData(){ + if(unconstrainedV0CandidatesColName == null) { unconstrainedV0CandidatesColName = "V0Candidates"; } + } }