// File : PandoraPFAProcessor.cc // Title : PandoraPFA cluster and particle flow object reconstruction // Author : M.Thomson // Version : 03-00-02 // Last Update : 23/1/2009 // v03-00-01 : fix bug in AnalyseClusters (hard-coded numbers removed) // : handle new DHCAL // v03-00-01 : Count tail catcher hits separately in cluster energy by // subdetector counts // : Tidy up hit energy correction code and make more flexible // v03-00-00 : New fully ILD compatible version // : Option to use external V0s // : Option to run photon reconstruction phase first // v03-00-alpha : // 30-08-08 : New methods to perfect cluster just photons/neutral hadrons // 28-08-08 : Major improvements to perfect PFA // v02-01-02 // 17/07/2008 : Improve electron fragment removal // 09/07/2008 : Clustering for muon hits can be used as a tail-catcher // v02-01 // 07/07/2008 : minor bug fix + move geometry access to init // 30/06/2008 : Few minor fixes/improvements for 02-01-dev => 02-01 // 06/06/2008 : Remove/disable remaining couts // : inlclude FTD only trachsks // 04/06/2008 : Compatibility with new Mokka LDC models // : bug fix in cone fraction (Protoclusters) // : improved/more robust photon ID // : improved fragment removal // : MUON hits can now be used to tag leaving clusters // : Split track identification // : improved kink/V0 finding for FullLDCTracking // V02-00 : Fix to use 1 or 2 byte Mokka Cell Codings // : Works with digital ECAL // : Improvements to reclustering // : Add PhotonRecovery and FragmentRemoval // : Added extra track killing (helix fit feature) // : Loosened 1 peak photon recovery interesting cut // : Bug fixes from Valgrind checks // : Clone shared photon track hits // : new photon recovery structure // : removed some obsolete and unhelpful code // 20/6/2007 : Add PerfectPFA // CVS1.6 : get B-field from global // : allow possibility of energy-based // tagging a hit as being mip-like // 25/6/2007 : start to use new photon profile information // 3/7/2007 : forced memory management via factory // 3/8/2007 : New: finalFragmentRremoval // 15/9/2007 : TrackCheater Performance ldc00 //rawrms 3.02871 90 % 85.5-95 mean : 91.119 sigma : 22.9+-0.29 //rawrms 5.92266 90 % 190-208 mean : 199.728 sigma : 28.6+-0.58 //rawrms 10.3991 90 % 341-374 mean : 358.221 sigma : 39.7+-0.90 //rawrms 17.3962 90 % 468.5-521 mean : 494.911 sigma : 53.3+-1.04 // 1/10/2007 : Update for new FullLDCTracking // : New V0 tagging // // 28/11/2007 : minor fixes + increased use of Marlin Logging // 9/7/2008 : LDCPrime FullLDCTracking Performance //rawrms 3.3607 90 % 85-95 mean : 90.3094 sigma : 24.8 +- 0.3 //rawrms 6.3182 90 % 188.5-207.5 mean : 198.253 sigma : 30.3 +- 0.4 //rawrms 14.1648 90 % 338-376 mean : 356.339 sigma : 43.5 +- 0.8 //rawrms 19.0566 90 % 464.5-520 mean : 492.967 sigma : 54.3 +- 0.9 // PandoraPFA includes #include "PandoraPFAProcessor.h" #include "MyRecoDisplay.h" #include "MyCaloHitExtended.h" #include #include "ProtoCluster.h" #include "ProtoClusterFactory.h" #include // headers for io,std etc #include // LCIO stuff #include #include #include #include #include "IMPL/ClusterImpl.h" #include "IMPL/LCFlagImpl.h" #include "IMPL/ReconstructedParticleImpl.h" #include #include #include #include #include "UTIL/CellIDDecoder.h" #include "CalorimeterHitType.h" // GEAR include files #include #include #include #include #include #include #include #include const std::string VERSION = "03-00-02"; const std::string DATE = "23/1/2009"; const std::string AUTHOR = "M. Thomson"; const std::string CONTACT = "thomson@hep.phy.cam.ac.uk"; const std::string ILDPERF91 = "rms90 ( 91 GeV) = (24.8 +- 0.3)%/sqrt(E)"; const std::string ILDPERF200 = "rms90 (200 GeV) = (29.3 +- 0.4)%/sqrt(E)"; const std::string ILDPERF360 = "rms90 (360 GeV) = (39.5 +- 0.8)%/sqrt(E)"; const std::string ILDPERF500 = "rms90 (500 GeV) = (49.8 +- 0.9)%/sqrt(E)"; using namespace lcio ; using namespace marlin ; const float pi = acos(-1.0); const float twopi = 2.0*pi; const float massK0S = 0.497648; const float massK = 0.493677; const float massLambda = 1.115683; const float massPion = 0.13957018; const float massElectron = 0.000511; const float massProton = 0.93827203; PandoraPFAProcessor aPandoraPFAProcessor; PandoraPFAProcessor::PandoraPFAProcessor() : Processor("PandoraPFAProcessor") { // modify processor description _description = "PandoraPFAProcessor reconstructs clusters and particle flow objects" ; // FLAG TO SPECIFY USING PERFECT PFA registerProcessorParameter( "PerfectClustering" , "Use MC to cheat clustering" , _perfectClustering, (int)0 ) ; registerProcessorParameter( "PerfectPhotonClustering" , "Use MC to cheat photon clustering only", _perfectPhotonClustering, (int)0 ); registerProcessorParameter( "PerfectMuonClusterMatching" , "Use MC to cheat muon cluster matching only", _perfectMuonClusterMatching, (int)0 ); registerProcessorParameter( "MakePhotonIDLikelihoodHistograms" , "do just that", _makingPhotonIDLikelihoodHistograms, (int)0 ) ; registerProcessorParameter( "UsingLikelihoodPhotonID" , "Use the likelihood function for photonID", _useLikelihoodPhotonID, (int)0 ) ; registerProcessorParameter( "PhotonClustering" , "Cluster photons first", _photonClustering, (int)0 ) ; registerProcessorParameter( "PerfectFragmentRemoval" , "Use MC to cheat fragment removal only", _perfectFragmentRemoval, (int)0 ) ; registerProcessorParameter( "PerfectNeutralHadronClustering" , "Use MC to cheat neutron/KL clustering only", _perfectNeutralHadronClustering, (int)0 ) ; registerProcessorParameter( "PerfectTrackClusterMatching" , "Use MC to cheat track cluster matching" , _perfectTrackClusterMatching, (int)0 ) ; registerProcessorParameter( "PerfectPFA" , "Use MC to cheat all aspects of particle flow ", _perfectPFA, (int)0 ) ; // FLAG TO SPECIFY USING PERFECT LOW E CF REJCTION registerProcessorParameter( "CFCheck" , "Use MC to cheat particle flow" , _cfCheck, (int)0 ) ; // Using cheater tracks ? registerProcessorParameter( "UsingCheatedTracks" , "UsingCheatedTracks ?" , _cheatedTracks, (int)0 ) ; registerProcessorParameter( "CheckForMCBug" , "CheckForMC bug ?" , _checkForMCBug, (int)1 ) ; // Using cheated dedx information () registerProcessorParameter( "UsingCheatedDeDx" , "UsingCheatedDeDx ?" , _cheatedDeDx, (int)0 ) ; //******************************************************************** //********************* Input/Output Collections ********************* //******************************************************************** // Name of CLUSTER collection written by algorithm std::string cellIDCoding; cellIDCoding = "Mokka"; registerProcessorParameter( "CellIDCoding" , "Cluster Collection Name " , _cellIDCoding, cellIDCoding); // Name of CLUSTER collection written by algorithm std::string clusterCollectionName; clusterCollectionName = "PandoraClusters"; // registerProcessorParameter( "ClusterCollectionName" , registerOutputCollection( LCIO::CLUSTER, "ClusterCollectionName" , "Cluster Collection Name " , _clusterCollectionName, clusterCollectionName); // Name of PARTICLE collection written by algorithm std::string particleCollectionName; particleCollectionName = "PandoraPFOs"; registerOutputCollection( LCIO::RECONSTRUCTEDPARTICLE, "ParticleCollectionName" , "Particle Collection Name " , _particleCollectionName, particleCollectionName); // Name of relation between calorimeter hit and sim calorimeter hit std::string caloRel; caloRel = "RelationCaloHit"; registerInputCollection( LCIO::LCRELATION, "RelationCaloString" , "Name of the calo hit <-> sim calo hit relation" , _relationCaloString, caloRel) ; // // Name of relation between calorimeter hit and sim LCAL hit // std::string lcalRel; // lcalRel = "RelationLcalHit"; // registerInputCollection( LCIO::LCRELATION, // "RelationLcalString" , // "Name of the lcal hit <-> sim calo hit relation" , // _relationLcalString, // lcalRel) ; // // Name of relation between calorimeter hit and sim LCAL hit // std::string lcalRel; // lhcalRel = "RelationLhcalHit"; // registerInputCollection( LCIO::LCRELATION, // "RelationLhcalString" , // "Name of the lhcal hit <-> sim calo hit relation" , // _relationLhcalString, // lhcalRel) ; // Name of relation between muon hit and sim hit std::string muonRel; muonRel = "RelationMuonHit"; registerInputCollection( LCIO::LCRELATION, "RelationMuonString" , "Name of the muon hit <-> sim calo hit relation" , _relationMuonString, muonRel) ; // Name of relation between true and MC tracks std::string trackRel; trackRel = "TrueTracksMCP"; registerInputCollection( LCIO::LCRELATION, "RelationTrackString" , "Name of the track hit <-> sim track hit relation" , _relationTrackString, trackRel) ; // Names of Track/ECAL/HCAL Collections to be used in PFA std::vector trackCollections ; trackCollections.push_back(std::string("TrueTracks")); registerInputCollections( LCIO::TRACK, "TrackCollections" , "Name of the Track collection used for clustering" , _trackCollections, trackCollections ) ; // Names of Track/ECAL/HCAL Collections to be used in PFA std::vector tpcHitCollections ; tpcHitCollections.push_back(std::string("UsedTPCTrackerHits")); registerInputCollections( LCIO::TRACKERHIT, "TpcHitCollections" , "Name of the TPC Hit collection used for kink finding" , _tpcHitCollections, tpcHitCollections ) ; // Names of Track/ECAL/HCAL Collections to be used in PFA std::vector curlKilledHitCollections ; curlKilledHitCollections.push_back(std::string("DroppedTPCTrackeHits")); registerInputCollections( LCIO::TRACKERHIT, "CurlKilledTpcHitCollection" , "Name of the Curl Killer TPC Hit collection used for kink finding" , _curlKilledHitCollections, curlKilledHitCollections ) ; std::vector ecalCollections ; ecalCollections.push_back(std::string("ECAL")); registerInputCollections( LCIO::CALORIMETERHIT, "ECALcollections" , "Name of the ECAL collection used to form clusters" , _ecalCollections, ecalCollections ) ; std::vector lcalCollections ; lcalCollections.push_back(std::string("LCAL")); registerInputCollections( LCIO::CALORIMETERHIT, "LCALcollections" , "Name of the LCAL collections" , _lcalCollections, lcalCollections ) ; std::vector lhcalCollections ; lcalCollections.push_back(std::string("LHCAL")); registerInputCollections( LCIO::CALORIMETERHIT, "LHCALcollections" , "Name of the LHCAL collections" , _lhcalCollections, lhcalCollections ) ; std::vector bcalCollections ; lcalCollections.push_back(std::string("BCAL")); registerInputCollections( LCIO::CALORIMETERHIT, "BCALcollections" , "Name of the BCAL collections" , _bcalCollections, bcalCollections ) ; std::vector muonCollections ; muonCollections.push_back(std::string("MUON")); registerInputCollections( LCIO::CALORIMETERHIT, "MUONcollections" , "Name of the MUON collections" , _muonCollections, muonCollections ) ; std::vector hcalCollections ; hcalCollections.push_back(std::string("HCAL")); registerInputCollections( LCIO::CALORIMETERHIT, "HCALcollections" , "Name of the HCAL collection used to form clusters" , _hcalCollections, hcalCollections ) ; std::vector v0VertexCollections; v0VertexCollections.push_back(std::string("V0Vertices")); registerInputCollections( LCIO::VERTEX, "V0VertexCollections" , "Name of external V0 Vertex collections" , _v0VertexCollections, v0VertexCollections ) ; registerProcessorParameter( "RestrictHCALToNLayers" , "Number of HCAL layers used", _maxHCALLayer, (int)9999 ); //******************************************************************** //**************************** Calibration *************************** //******************************************************************** // Calibration constants // NOTE THE CALIBRATION SCHEME USED HERE IS NON-STANDARD // First hits in ECAL/HCAL are converted to normal incident MIP equivalents // Thresholds are applied at the MIP level // MIP equivalent signals are converted to EM or Hadronic energy // i.e. different calibrations for EM and hadronic showers registerProcessorParameter( "ECALMIPcalibration" , "Calibration from deposited ECAL energy to MIP" , _ecalToMIP, (float)200.0 ) ; registerProcessorParameter( "HCALMIPcalibration" , "Calibration from deposited HCAL energy to MIP" , _hcalToMIP, (float)35. ) ; registerProcessorParameter( "MuonHitEnergy" , "Digital energy for muon hit" , _muonHitEnergy, (float)0.5 ) ; registerProcessorParameter( "MuonClusterCoilCorrection" , "Correction for missing part of cluster in coil" , _muonClusterCoilCorrection, (float)10.) ; registerProcessorParameter( "LCALMIPcalibration" , "Calibration from deposited LCAL energy to MIP" , _lcalToMIP, (float)35. ) ; registerProcessorParameter( "ECALThreshold" , "ECAL Threshold in MIPS" , _ecalMIPThreshold, (float)0.5 ) ; registerProcessorParameter( "HCALThreshold" , "HCAL Threshold in MIPS" , _hcalMIPThreshold, (float)0.3 ) ; registerProcessorParameter( "MaxHcalHitEnergy" , "Max energy for a single HCAL hit" , _maxHcalHitEnergy, (float)1. ) ; registerProcessorParameter( "MaxRatioToCutHcalHit" , "Max ratio of surrounding/hit energy to apply a single HCAL hit", _maximumRatioToCutHcalHit, (float)0.5 ) ; registerProcessorParameter( "LCALThreshold" , "LCAL Threshold in MIPS" , _lcalMIPThreshold, (float)0.5 ) ; registerProcessorParameter( "HCALEMMIPToGeV" , "Calibration from deposited HCAL MIP to EM energy" , _hcalEMMIPToGeV, (float)0.0233 ) ; registerProcessorParameter( "LeakageCorrection" , "Apply leakage correction, 0=no, 1=PFO stage, 2=hit energy", _leakageCorrection, (int)0 ) ; registerProcessorParameter( "LeavingHitWeightingFactor" , "Scale leaving hit energies by this factor" , _leavingHitWeightingFactor, (float)1.0 ) ; registerProcessorParameter( "LeavingHitLayersFromEdge" , "Maximum distance for edge of HCAL to be considered leaving" , _leavingHitLayersFromEdge, (int)-999) ; registerProcessorParameter( "HCALHadMIPToGeV" , "Calibration from deposited HCAL MIP to Hadronic energy" , _hcalHadMIPToGeV, (float)0.02 ) ; registerProcessorParameter( "ECALEMMIPToGeV" , "Calibration from deposited ECAL MIP to EM energy" , _ecalEMMIPToGeV, (float)0.005076 ) ; registerProcessorParameter( "LCALEMMIPToGeV" , "Calibration from deposited LCAL MIP to EM energy" , _lcalEMMIPToGeV, (float)0.005076 ) ; registerProcessorParameter( "ECALHadMIPToGeV" , "Calibration from deposited ECAL MIP to Hadronic energy" , _ecalHadMIPToGeV, (float)0.005 ) ; registerProcessorParameter( "HadronicEnergyResolution" , "Hadronic energy resolution for pions" , _hadEnergyRes, (float)0.60 ) ; // FLAG TO SPECIFY DIGITAL HCAL registerProcessorParameter( "DigitalHCAL" , "If set treat HCAL as digital HCAL" , _digitalHCAL, (int)0 ) ; // FLAG TO SPECIFY DIGITAL HCAL registerProcessorParameter( "DigitalECAL" , "If set treat ECAL as digital ECAL" , _digitalECAL, (int)0 ) ; registerProcessorParameter( "ClusterCleaning" , "Cluster Cleaning on/off" , _clusterCleaning, (int)1 ) ; // Magnetic Field need for track extrapolaiton : THIS SHOULD COME FROM GEAR // Removed 20/6/2007 : this now comes from the global parameters //registerProcessorParameter( "BField", // "Magnetic field", // _bField, // (float)4.0); //******************************************************************** //********************* ECAL/HCAL Hit Isolation ********************** //******************************************************************** // Type of isolation algorithm to be used // NONE = use all hits // Look at local density of hits // Look at multiplicity of hits in fixed radius registerProcessorParameter( "IsolationType" , "Type of isolation cut : 0=NONE; 1=DENSITY, 2=MULTIPLICITY", _isolationType, (int)1 ); //*** Multiplicity Algorithm *** // Apply isolation cuts considering hits in +- n layers of layer being considered registerProcessorParameter( "LayersForIsolationECAL" , "Number of ECAL layers for isolation cuts", _layersForIsolationECAL, (int)2 ); registerProcessorParameter( "LayersForIsolationHCAL" , "Number of HCAL layers for isolation cuts", _layersForIsolationHCAL, (int)2 ); // For multiplicity isolation cuts look count hits in 3D radius of registerProcessorParameter( "IsolationDistanceECAL" , "distance (absolute) within layer for ECAL isolation/mm", _distanceForIsolationECAL, (float)50. ); registerProcessorParameter( "IsolationDistanceHCAL" , "distance (absolute) within layer for HCAL isolation /mm", _distanceForIsolationHCAL, (float)250. ); // Number of hits within isolation radius for hit to be considered non-isolated registerProcessorParameter( "SmallestClusterSize" , "number of hits for smallest cluster size when tagging isolated hits", _nSmallestClusterSizeForIsolation, (int)3 ); //*** Density Algorithm *** // cut value - keep hits with density weight > cut registerProcessorParameter( "IsolationDensityWeightCutECAL" , "density weight cut for isolation in ECAL", _densityWeightCutECAL, (float)0.5 ); registerProcessorParameter( "IsolationDensityWeightCutHCAL" , "density weight cut for isolation in HCAL", _densityWeightCutHCAL, (float)0.25 ); // Sum weights over +- N layers of layer being considered registerProcessorParameter( "LayersForDensityWeighting" , "Number of layers (other than current) for density weighting", _layersForDensityWeighting, (int)2 ); // Power for weight - default is weight_i = 1/r_ij^2: i.e. inverse square contributions registerProcessorParameter( "DenistyWeightingPower" , "Power for density weighting assuming 1/r^N weighting e.g. 2 = inverse square", _densityWeightingPower, (int)2 ); // Recombination distance - isolated hits are ignored in the reconstruction but are // added back in if withing this distance of a hit in a cluster registerProcessorParameter( "IsolationDistanceForReCombination" , "sweep up isolated hits within radius", _isolationDistanceForReCombination, (float)200. ); //******************************************************************** //*************** Hits definition for non-isolated hits ************** //******************************************************************** // In clustering algorithm hits in each layer are looped over // the order in which they are stored impacts the seeding of new clusters registerProcessorParameter( "TypeOfOrderingInLayer" , "How hits are ordered within Layer : 0 = PseudoEnergy, 1 = density within layer, 2=local density over layers", _typeOfOrdering, (int)1 ); // Cuts to define a candidate MIP hit // loop over pads with +-n in dphi and +-n in dz registerProcessorParameter( "MipCells" , "Number of pads over which to count for MIP mulitplicity", _mipCells, (int)1 ); // Maximum number of other hits in this nxn square for hit to be tagged as a candidate MIP registerProcessorParameter( "MipMaxCellsHit" , "Maximum Number of mip cells hit for hit to be tagged as candidate MIP", _mipMaxCellsHit, (int)1 ); //Maximum energy deposition for hit to be tagged as mip like wrt expected from MIP", registerProcessorParameter( "MipLikeMipCut" , "Maximum energy (mips) for hit to be tagged as mip like", _mipLikeMipCut, (float)5. ); //******************************************************************** //**************** Cuts on formed ECAL/HCAL clusters ***************** //******************************************************************** // Minimum number of hits in a cluster registerProcessorParameter( "MinimumHitsInCluster" , "minimum number of hits in standalone cluster", _minimumHitsInCluster, (int)5 ); // Minimum cluster energies registerProcessorParameter( "MinimumClusterEnergyEM" , "minimum energy for EM cluster", _minimumClusterEnergyEM, (float)0.1); registerProcessorParameter( "MinimumClusterEnergyHAD" , "minimum energy for HAD cluster", _minimumClusterEnergyHAD, (float)0.5); registerProcessorParameter( "MipsPerHitForHotHadron" , "number of Mips per hit for hadron to be flagged as hot", _mipsPerHitForHotHadron, (float)15.); registerProcessorParameter( "ScaledMipsPerHitForHotHadron" , "number of Mips per hit used to scale hot hadron energies", _scaledMipsPerHitForHotHadron, (float)5.); // Definition of a soft cluster - i.e. candidate hadronic fragment registerProcessorParameter( "MaximumHitsInSoftCluster" , "maximum number of hits for cluster to be considered soft", _maximumHitsInSoftCluster, (int)9 ); registerProcessorParameter( "MaximumDistanceForSoftCluster" , "Distance cuts for joining soft clusters", _maximumDistanceForSoftMerge, (float)500. ); registerProcessorParameter( "SoftClusterEnergyHAD" , "maximum energy for HAD cluster to be considered soft", _softClusterEnergyHAD, (float)2.0); // use track extrapolations from last N points rather than full helix registerProcessorParameter( "UseTrackEndIntersection" , "Use only the end of the track in the main extrap", _usingTrackEndIntersection, (int)0 ); registerProcessorParameter( "UseFTDOnlyTracks" , "Use tracks with only FTD and Si hits", _usingFTDOnlyTracks, (int)1 ); registerProcessorParameter( "FTDOnlyTracksMinimumHits" , "Minimum number of hits for FTD only tracks", _minHitsFTDOnlyTracks, (int)4 ); registerProcessorParameter( "FTDOnlyTracksMatchingCut" , "Track - cluster matching cut for FTD only tracks", _clusterFTDOnlyTrackDistance, (float)10. ); registerProcessorParameter( "TrackClusterAssociationDistance" , "Track - cluster matching cut", _trackClusterAssociationDistance, (float)10. ); registerProcessorParameter( "UseNonVertexTracks" , "Use tracks which don't originate from vertex", _usingNonVertexTracks, (int)1 ); registerProcessorParameter( "UseVertexBackgroundCuts" , "Use cuts to reduce background in VTX", _usingVertexBackgroundCuts, (int)0); registerProcessorParameter( "UseUnmatchedNonVertexTracks" , "Use unmatched tracks which don't originate from vertex", _usingUnmatchedNonVertexTracks, (int)0 ); registerProcessorParameter( "UseUnmatchedVertexTracks" , "Use unmatched vertex/kink tracks", _usingUnmatchedVertexTracks, (int)1 ); registerProcessorParameter( "UnmatchedVertexTrackEnergyCut" , "Maximum energy for unmatched vertex track", _unmatchedVertexTrackMaxEnergy, (float)5.0 ); registerProcessorParameter( "CanUseClusterForExitingTracks" , "Can use cluster energy for PFOs for tracks which exit detector", _canUseClusterForExitingTracks, (int)1 ); registerProcessorParameter( "EnergyCutForVeryLowEnergyTracks" , "Below this enegry tracks are treates as very low enegry", _energyCutForVeryLowEnergyTracks, (float)0.25 ); registerProcessorParameter( "MaxTrackEnergy" , "Ignore tracks above this enegry", _maxTrackEnergy, (float)1600. ); registerProcessorParameter( "IgoreTracks" , "Switch to ignore all tracks", _ignoreTracks, (int)0 ); //******************************************************************** //************** Configuration of Clustering Algorithm *************** //******************************************************************** // Seed clusters with track extrapolations ? registerProcessorParameter( "TrackSeeding" , "Use tracks to seed clusters ? 0=no, 1=only barrel loopers, 2=all loopers, 3=all tracks", _seedClustersWithTracks, (int)3 ); // When trying to associats a hit with previous clusters look at all hits in the // N previous pseudolayers registerProcessorParameter( "LayersToStepBackECAL" , "Maximum Number of layers in ECAL over which cluster associations are made", _layersToStepBackECAL, (int)3 ); registerProcessorParameter( "LayersToStepBackHCAL" , "Maximum Number of layers in HCAL over which cluster associations are made", _layersToStepBackHCAL, (int)3 ); // How to deal with hit assignment to preceding layer compared to assignment in earlier layers registerProcessorParameter( "ClusterFormationStrategy" , "0=Step and make assignment in layer then, if none found, step back, 1=step over iback layers and choose best assignment ", _clusterFormationStrategy, (int)0 ); // Cone half-angle for clustering algorithm registerProcessorParameter( "ClusterFormationAngleECAL" , "tan(angle) used in hit-cluster association", _clusterFormationConeTanECAL, (float)0.3); registerProcessorParameter( "PhotonClusterFormationAngleECAL" , "tan(angle) used in hit-cluster association in photon clustering", _photonClusterFormationConeTanECAL, (float)0.3); registerProcessorParameter( "ClusterFormationAngleHCAL" , "tan(angle) used in hit-cluster association", _clusterFormationConeTanHCAL, (float)0.5); // Number of pads to add to outer circumference of cone registerProcessorParameter( "ClusterFormationPadsECAL" , "number of pads to add to cone in cluster fortmation", _clusterFormationPadsECAL, (float)1.5); registerProcessorParameter( "ClusterFormationPadsHCAL" , "number of pads to add to cone in cluster fortmation", _clusterFormationPadsHCAL, (float)2.5); // Don't associate hits with cone algorithm if they are greater than a certai distance away // from clustered hit being considered registerProcessorParameter( "MaximumDistanceForConeAssociationECAL" , "cut on distance for cone association ECAL", _maximumDistanceForConeAssociationECAL, (float)250.); registerProcessorParameter( "MaximumDistanceForConeAssociationHCAL" , "cut on distance for cone association HCAL", _maximumDistanceForConeAssociationHCAL, (float)500.); // Distance (in pads) for association in the same layer as hits being considered registerProcessorParameter( "SameLayerPadCutECAL" , "distance in number of pads for same layer assoc", _sameLayerPadCutECAL, (float)1.8); registerProcessorParameter( "SameLayerPadCutHCAL" , "distance in number of pads for same layer assoc", _sameLayerPadCutHCAL, (float)1.8); registerProcessorParameter( "TrackingWeight" , "weight given to tracking in protocluster formation", _trackingWeight, (int)2); registerProcessorParameter( "AssociateLoopingTracks" , "Switch on/off matching of looping tracks in CALO", _associateLoopingTracks, (int)1); registerProcessorParameter( "AssociateTrackSegments" , "Switch on/off matching of track segments in CALO", _associateTrackSegments, (int)1); registerProcessorParameter( "AssociateShowersToMips" , "Switch on/off matching of showers to MIP segments", _associateShowersToMips, (int)1); registerProcessorParameter( "AssociateShowersToMipsII" , "Switch on/off matching of showers to MIP segments II", _associateShowersToMipsII, (int)1); registerProcessorParameter( "AssociateBackScatters" , "Switch on/off matching of back-scattered tracks", _associateBackScatters, (int)1); registerProcessorParameter( "AssociateMipStubsToShowers" , "Switch on/off matching of mip track stubs to showers", _associateMipStubsToShowers, (int)1); registerProcessorParameter( "AssociateFromStart" , "Switch on/off matching", _associateFromStart, (int)1); registerProcessorParameter( "AssociateByProximity" , "Switch on/off matching by proximity", _associateByProximity, (int)1); registerProcessorParameter( "AssociateByShowerCone" , "Switch on/off matching by shower cone", _associateByShowerCone, (int)1); registerProcessorParameter( "AssociateSoftClusters" , "Switch on/off matching of soft clusters", _associateSoftClusters, (int)1); registerProcessorParameter( "FragmentRemoval" , "Switch on/off identification and removal of fragment clusters", _fragmentRemoval, (int)1); registerProcessorParameter( "NeutralHadronMerging" , "Switch on/off removal of neutral fragment merging", _neutralHadronMerging, (int)1); registerProcessorParameter( "FragmentRemovalChi2Base", "Base for chi2 requirement", _fragmentRemovalChi2Base, (float)5.0); registerProcessorParameter( "FragmentRemovalGlobalPenalty", "Penalty for using global chi2", _fragmentRemovalGlobalPenalty, (float)5.0); registerProcessorParameter( "FragmentRemovalContactCut" , "Fragment removal contact criterion - cut in pads", _fragmentRemovalContactCut, (float)2.0); registerProcessorParameter( "FragmentRemovalContactWeight" , "Fragment removal: weight for contact evidence", _fragmentRemovalContactWeight, (float)1.0); registerProcessorParameter( "FragmentRemovalConeWeight" , "Fragment removal: weight for cone evidence", _fragmentRemovalConeWeight, (float)1.0); registerProcessorParameter( "FragmentRemovalDistanceWeight" , "Fragment removal: weight for distance evidence", _fragmentRemovalDistanceWeight, (float)1.0); registerProcessorParameter( "FragmentRemovalTrackExtrapolationWeight" , "Fragment removal: weight for track extrapolation evidence", _fragmentRemovalTrackExtrapolationWeight, (float)1.0); registerProcessorParameter( "FragmentRemovalContactLayersCut" , "Fragment removal contact cut criterion - no of layers", _fragmentRemovalContactLayersCut, (int)4); registerProcessorParameter( "FragmentRemovalMaxChi2ForMerge" , "Fragment removal maximum chi2 for merge", _fragmentRemovalMaxChi2ForMerge, (float)9.0); registerProcessorParameter( "UsingMuonHitsToAidClustering" , "Muon hits used to identifying leaving clusters", _usingMuonHitsToAidClustering, (int)1); registerProcessorParameter( "UsingMuonHitsAsTailCatcher" , "Muon hits used as tail catcher", _tailCatcher, (int)1); //******************************************************************** //********************** Clustering Merging Cuts ********************* //******************************************************************** registerProcessorParameter( "CosineConeAngle" , "Cosine of cone half angle for shower cone assoc", _coneAssociationCosine, (float)0.90); registerProcessorParameter( "MergeSoftPhotons" , "Merge soft photon fragments", _mergeSoftPhotons, (int)1); registerProcessorParameter( "SoftPhotonMergingEnergy" , "Energy for cluster to be considered a soft photon fragment", _softPhotonEnergyForMerging, (float)0.2); registerProcessorParameter( "MergeHardPhotons" , "Merge hard photon fragments", _mergeHardPhotons, (int)1); //******************************************************************** //***********Cuts for identifying photons overlaying MIPS************* //******************************************************************** registerProcessorParameter( "AllowPhotonFragmentation" , "Switch on/off code to fragment photons from MIPS", _allowPhotonFragmentation, (int)1 ); registerProcessorParameter( "PhotonFragPhotonDeltaChi2Cut" , "Cut in energy matching for IDed fragmented photons", _photonFragPhotonDeltaChi2Cut, (float)1. ); registerProcessorParameter( "PhotonFragNonPhotonDeltaChi2Cut" , "Cut in energy matching for non-IDed fragmented photons", _photonFragNonPhotonDeltaChi2Cut, (float)0. ); registerProcessorParameter( "UseAdvancedPhotonID" , "Final photon ID based on longitudinal profile", _useAdvancedPhotonID, (int)1 ); //******************************************************************** //*************** Steering of Statistical Reclustering *************** //******************************************************************** // switch it on/off registerProcessorParameter( "AllowReclustering" , "Switch on/off code for statistical reclustering i.e. whether to break up/merge clusters based on track", _allowReclustering, (int)1 ); // photon reconvery : switch it on/off registerProcessorParameter( "PhotonRecovery" , "Switch on/off code for photon recovery", _photonRecovery, (int)1 ); // photon merging registerProcessorParameter( "MergeSplitPhotons" , "Switch on/off photon merging", _mergeSplitPhotons, (int)1 ); // Attempt reclustering if chi between track-cluster energy > cut registerProcessorParameter( "ChiToAttemptReclustering" , "Chi cut for reclustering", _chiToAttemptReclustering, (float)3.0 ); // (float)3.5 ); // Force reclustering if chi between track-cluster energy > cut // has the effect of splitting clusters even if no good solution is found registerProcessorParameter( "ChiToForceReclustering" , "Chi cut for forced reclustering", _chiToForceReclustering, (float)4.0 ); // (float)5.0 ); // The nuclear option - if a track-cluster chi is worse than this cut // remove track registerProcessorParameter( "MatchingChiToKillTrack" , "Chi cut for Killing track", _chiToKillTrack, (float)4.0 ); // registerProcessorParameter( "EnergyDeltaChi2ForCrudeMerging" , "Veto cluster merging based on chi2 difference (Eclust-Etrack)/sigE", _energyDeltaChi2ForCrudeMerging, (float)1.0 ); // registerProcessorParameter( "EnergyChiForCrudeMerging" , "Veto cluster merging based on chi of merged (Eclust-Etrack)/sigE", _energyChiForCrudeMerging, (float)2.5 ); //******************************************************************** //******* Main cuts for finding Looping tracks in Calorimeters ******* //******************************************************************** registerProcessorParameter( "OuterHCAL" , "Region defined as outer HCAL", _outerHcalRegionLayer, (int)10 ); registerProcessorParameter( "LooperClosestApproachCutECAL" , "Maximum distance of closest approach for looping track assoc", _looperClosestApproachCutECAL, (float)50.0 ); registerProcessorParameter( "ProximityCutDistance" , "Distance for proximity association", _proximityClosestApproachCut, (float)50.0 ); registerProcessorParameter( "LooperClosestApproachCutECAL" , "Maximum distance of closest approach for looping track assoc", _looperClosestApproachCutHCAL, (float)200.0 ); registerProcessorParameter( "LooperTrackSeparationCut", "Maximum distance between ends of clusters for looping track assoc", _looperTrackSeparationCut, (float)250.0 ); //******************************************************************** //********************** Tracking/Track Matching ********************* //******************************************************************** // Definition of good tracks to be considered in formation of PFOs registerProcessorParameter( "z0TrackCut" , "cut on z0 to define good tracks", _z0TrackCut, (float)50. ); registerProcessorParameter( "d0TrackCut" , "cut on d0 to define good tracks", _d0TrackCut, (float)50. ); registerProcessorParameter( "MinimumTrackHits" , "minimum number of track hits (applies to Si/FTD)", _minimumTrackHits, (int)5 ); registerProcessorParameter( "SearchForKinks" , "Search for kinks?", _searchForKinks, (int)1 ); registerProcessorParameter( "SearchForSplitTracks" , "Search for split tracks?", _searchForSplitTracks, (int)1 ); registerProcessorParameter( "SearchForProngs" , "Search for prongs?", _searchForProngs, (int)1 ); registerProcessorParameter( "SearchForV0s" , "Search for V0s?", _searchForV0s, (int)1 ); registerProcessorParameter( "V0Finder" , "V0 finder to be used 1=internal, 2=external, 3=both", _v0Finder, (int)2 ); registerProcessorParameter( "SearchForBackScatterss" , "Search for back scatters?", _searchForBackScatters, (int)1 ); registerProcessorParameter( "ExtraLoopingTrackClusterAssociation", "Use additional method to match looping tracks to clusters ? 0=no 1=yes", _extraLooperMatching, (int)1 ); registerProcessorParameter( "piToMuMassWindowWidth" , "width of mass window used to identify pi->mu nu", _piToMuMassWindowWidth, (float)0.03 ); registerProcessorParameter( "kToMuMassWindowWidth" , "width of mass window used to identify K->mu nu", _kToMuMassWindowWidth, (float)0.125 ); //******************************************************************** //******* Main cuts for mathcing tracks Segments in Calorimeters ***** //******************************************************************** registerProcessorParameter( "TrackMergeCutEcal" , "track merging distance in ECAL", _trackMergeCutEcal, (float)25. ); registerProcessorParameter( "TrackMergeCutHcal" , "track merging distance in HCAL", _trackMergeCutHcal, (float)25. ); registerProcessorParameter( "TrackBackMergeCut" , "track merging distance for projecting MIPs back to showers", _trackBackMergeCut, (float)30. ); registerProcessorParameter( "TrackForwardMergeCut" , "track merging distance for projecting MIPs forward to showers", _trackForwardMergeCut, (float)50. ); registerProcessorParameter( "TrackMergePerpCutEcal" , "track merging perp distance in ECAL", _trackMergePerpCutEcal, (float)50. ); registerProcessorParameter( "TrackMergePerpCutHcal" , "track merging perp distance in HCAL", _trackMergePerpCutHcal, (float)75. ); //******************************************************************** //************************ Debug Printing/Display ******************** //******************************************************************** registerProcessorParameter( "RecoDisplay" , "Draw the display", _display, (int)0 ); registerProcessorParameter( "RecoDisplayPlotRange" , "zyz range to be displayed ", _plotRange, (float)4250. ); registerProcessorParameter( "DisplayUnusedTpcHits" , "Display the ununused tpc hits", _displayUnusedTpcHits, (int)0 ); registerProcessorParameter( "ShowProtoClusterFormation" , "Step through cluster formation on display", _showProtoClusterFormation, (int)0 ); registerProcessorParameter( "ShowProtoClusterAssociation" , "Step through cluster association on display", _showProtoClusterAssociation, (int)0 ); registerProcessorParameter( "Printing" , "Debug printing", _printing, (int)1 ); registerProcessorParameter( "AnalyseClusters" , "Turn on internal analysis of clusters", _analyseClusters, (int)0 ); registerProcessorParameter( "FormClusterFromUnusedIsolatedHits" , "Make a dummy cluster from isolated hits", _formClusterFromUnusedIsolatedHits, (int)0 ); std::string rootFile; rootFile = "PandoraPFAAnalysis.root"; registerOptionalParameter( "AnalysisRootFile" , "Name of Root file for PFA Analysis", _rootFile, rootFile); CellIDDecoder::setDefaultEncoding("M:3,S-1:3,I:9,J:9,K-1:6"); } void PandoraPFAProcessor::init() { // Initialisation stage streamlog_out(MESSAGE) << "<-*****************************************************************************************->" << std::endl; streamlog_out(MESSAGE) << "PandoraPFAProcessor::init Welcome to PandoraPFA Version : " << VERSION << std::endl; streamlog_out(MESSAGE) << "PandoraPFAProcessor::init Last updated : " << DATE << std::endl; streamlog_out(MESSAGE) << "PandoraPFAProcessor::init Author : " << AUTHOR << std::endl; streamlog_out(MESSAGE) << "PandoraPFAProcessor::init Email : " << CONTACT << std::endl; streamlog_out(MESSAGE) << "PandoraPFAProcessor::init Z->uds performance for LDCPRIME : " << ILDPERF91 << std::endl; streamlog_out(MESSAGE) << " : " << ILDPERF200 << std::endl; streamlog_out(MESSAGE) << " : " << ILDPERF360 << std::endl; streamlog_out(MESSAGE) << " : " << ILDPERF500 << std::endl; streamlog_out(MESSAGE) << "<-*****************************************************************************************->" << std::endl; // Print algorithm parameters printParameters() ; // zero counters/pointers _nRun = 0 ; _nEvt = 0 ; _recoDisplay = NULL; _mcTree= NULL; _myMcTree= NULL; // if requested - start up internal root-based event display if(_recoDisplay==NULL && _display != 0){ _recoDisplay = new MyRecoDisplay(1); _recoDisplay->SetPlotRange(_plotRange); } // HISTOGRAMS fLong1 = new TH2F("fLong1 ", "long prof <1 ",20, 0., 10., 40, 0., 2.); fLong1_2 = new TH2F("fLong1_2", "long prof 1-2",20, 0., 10., 40, 0., 2.); fLong2_5 = new TH2F("fLong2_5", "long prof 2-5",20, 0., 10., 40, 0., 2.); fLong5 = new TH2F("fLong5 ", "long prof >5 ",20, 0., 10., 40, 0., 2.); Histograms2D.push_back(fLong1); Histograms2D.push_back(fLong1_2); Histograms2D.push_back(fLong2_5); Histograms2D.push_back(fLong5); fLong1H = new TH2F("fLong1H ", "H long prof <1 ",20, 0., 10., 40, 0., 2.); fLong1_2H = new TH2F("fLong1_2H", "H long prof 1-2",20, 0., 10., 40, 0., 2.); fLong2_5H = new TH2F("fLong2_5H", "H long prof 2-5",20, 0., 10., 40, 0., 2.); fLong5H = new TH2F("fLong5H ", "H long prof >5 ",20, 0., 10., 40, 0., 2.); Histograms2D.push_back(fLong1H); Histograms2D.push_back(fLong1_2H); Histograms2D.push_back(fLong2_5H); Histograms2D.push_back(fLong5H); fEhad = new TH1F("fEhad ", "Hadronic E ",100, 0., 10.); fMipFrac = new TH1F("fMipFrac", "mip frac",100, 0., 1.); fMipDcos = new TH2F("fMipDcos ", "mip dcos E<1",41, -0.0125, 1.0125, 40, -1., 1.); Histograms1D.push_back(fEhad); Histograms2D.push_back(fMipDcos); Histograms1D.push_back(fMipFrac); if(_makingPhotonIDLikelihoodHistograms>0){ sighistrms[0] = new TH1F("sighistrms0", " rms ",20, 0., 5.); sighistrms[1] = new TH1F("sighistrms1", " rms ",20, 0., 5.); sighistrms[2] = new TH1F("sighistrms2", " rms ",20, 0., 5.); sighistrms[3] = new TH1F("sighistrms3", " rms ",20, 0., 5.); sighistrms[4] = new TH1F("sighistrms4", " rms ",20, 0., 5.); sighistrms[5] = new TH1F("sighistrms5", " rms ",20, 0., 5.); sighistrms[6] = new TH1F("sighistrms6", " rms ",20, 0., 5.); sighistrms[7] = new TH1F("sighistrms7", " rms ",20, 0., 5.); sighistrms[8] = new TH1F("sighistrms8", " rms ",20, 0., 5.); backhistrms[0] = new TH1F("backhistrms0", " rms ",20, 0., 5.); backhistrms[1] = new TH1F("backhistrms1", " rms ",20, 0., 5.); backhistrms[2] = new TH1F("backhistrms2", " rms ",20, 0., 5.); backhistrms[3] = new TH1F("backhistrms3", " rms ",20, 0., 5.); backhistrms[4] = new TH1F("backhistrms4", " rms ",20, 0., 5.); backhistrms[5] = new TH1F("backhistrms5", " rms ",20, 0., 5.); backhistrms[6] = new TH1F("backhistrms6", " rms ",20, 0., 5.); backhistrms[7] = new TH1F("backhistrms7", " rms ",20, 0., 5.); backhistrms[8] = new TH1F("backhistrms8", " rms ",20, 0., 5.); sighistfrac[0] = new TH1F("sighistfrac0", " frac ",20, 0., 1.); sighistfrac[1] = new TH1F("sighistfrac1", " frac ",20, 0., 1.); sighistfrac[2] = new TH1F("sighistfrac2", " frac ",20, 0., 1.); sighistfrac[3] = new TH1F("sighistfrac3", " frac ",20, 0., 1.); sighistfrac[4] = new TH1F("sighistfrac4", " frac ",20, 0., 1.); sighistfrac[5] = new TH1F("sighistfrac5", " frac ",20, 0., 1.); sighistfrac[6] = new TH1F("sighistfrac6", " frac ",20, 0., 1.); sighistfrac[7] = new TH1F("sighistfrac7", " frac ",20, 0., 1.); sighistfrac[8] = new TH1F("sighistfrac8", " frac ",20, 0., 1.); backhistfrac[0] = new TH1F("backhistfrac0", " frac ",20, 0., 1.); backhistfrac[1] = new TH1F("backhistfrac1", " frac ",20, 0., 1.); backhistfrac[2] = new TH1F("backhistfrac2", " frac ",20, 0., 1.); backhistfrac[3] = new TH1F("backhistfrac3", " frac ",20, 0., 1.); backhistfrac[4] = new TH1F("backhistfrac4", " frac ",20, 0., 1.); backhistfrac[5] = new TH1F("backhistfrac5", " frac ",20, 0., 1.); backhistfrac[6] = new TH1F("backhistfrac6", " frac ",20, 0., 1.); backhistfrac[7] = new TH1F("backhistfrac7", " frac ",20, 0., 1.); backhistfrac[8] = new TH1F("backhistfrac8", " frac ",20, 0., 1.); sighiststart[0] = new TH1F("sighiststart0", " start ",20, 0., 10.); sighiststart[1] = new TH1F("sighiststart1", " start ",20, 0., 10.); sighiststart[2] = new TH1F("sighiststart2", " start ",20, 0., 10.); sighiststart[3] = new TH1F("sighiststart3", " start ",20, 0., 10.); sighiststart[4] = new TH1F("sighiststart4", " start ",20, 0., 10.); sighiststart[5] = new TH1F("sighiststart5", " start ",20, 0., 10.); sighiststart[6] = new TH1F("sighiststart6", " start ",20, 0., 10.); sighiststart[7] = new TH1F("sighiststart7", " start ",20, 0., 10.); sighiststart[8] = new TH1F("sighiststart8", " start ",20, 0., 10.); backhiststart[0] = new TH1F("backhiststart0", " start ",20, 0., 10.); backhiststart[1] = new TH1F("backhiststart1", " start ",20, 0., 10.); backhiststart[2] = new TH1F("backhiststart2", " start ",20, 0., 10.); backhiststart[3] = new TH1F("backhiststart3", " start ",20, 0., 10.); backhiststart[4] = new TH1F("backhiststart4", " start ",20, 0., 10.); backhiststart[5] = new TH1F("backhiststart5", " start ",20, 0., 10.); backhiststart[6] = new TH1F("backhiststart6", " start ",20, 0., 10.); backhiststart[7] = new TH1F("backhiststart7", " start ",20, 0., 10.); backhiststart[8] = new TH1F("backhiststart8", " start ",20, 0., 10.); for(int ihist=0;ihist<9;ihist++){ Histograms1D.push_back(sighistrms[ihist]); Histograms1D.push_back(sighiststart[ihist]); Histograms1D.push_back(sighistfrac[ihist]); Histograms1D.push_back(backhistrms[ihist]); Histograms1D.push_back(backhiststart[ihist]); Histograms1D.push_back(backhistfrac[ihist]); } } fEhadLayerU = new TH2F("fEhadLayerU ", "U Hadronic Layer E",100, 0., 10.,100,0.,100.); fEhadLayer = new TH2F("fEhadLayer ", "Hadronic Layer E",100, 0., 10.,100,0.,100.); fEhadLayerBT = new TH2F("fEhadLayerBT ", "BT Hadronic Layer E",100, 0., 10.,100,0.,100.); eEhadLayerU = new TH2F("eEhadLayerU ", "U Hadronic Layer E",100, 0., 10.,100,0.,100.); eEhadLayer = new TH2F("eEhadLayer ", "Hadronic Layer E",100, 0., 10.,100,0.,100.); eEhadLayerBT = new TH2F("eEhadLayerBT ", "BT Hadronic Layer E",100, 0., 10.,100,0.,100.); bEhadLayerU = new TH2F("bEhadLayerU ", "U Hadronic Layer E",100, 0., 10.,100,0.,100.); bEhadLayer = new TH2F("bEhadLayer ", "Hadronic Layer E",100, 0., 10.,100,0.,100.); bEhadLayerBT = new TH2F("bEhadLayerBT ", "BT Hadronic Layer E",100, 0., 10.,100,0.,100.); fEhadLayersU = new TH2F("fEhadLayersU ", "U Hadronic Layer E",100, 0., 10.,100,0.,100.); fEhadLayers = new TH2F("fEhadLayers ", "Hadronic Layer E",100, 0., 10.,100,0.,100.); fEhadLayersBT = new TH2F("fEhadLayersBT ", "BT Hadronic Layer E",100, 0., 10.,100,0.,100.); eEhadLayersU = new TH2F("eEhadLayersU ", "U Hadronic Layer E",100, 0., 10.,100,0.,100.); eEhadLayers = new TH2F("eEhadLayers ", "Hadronic Layer E",100, 0., 10.,100,0.,100.); eEhadLayersBT = new TH2F("eEhadLayersBT ", "BT Hadronic Layer E",100, 0., 10.,100,0.,100.); bEhadLayersU = new TH2F("bEhadLayersU ", "U Hadronic Layer E",100, 0., 10.,100,0.,100.); bEhadLayers = new TH2F("bEhadLayers ", "Hadronic Layer E",100, 0., 10.,100,0.,100.); bEhadLayersBT = new TH2F("bEhadLayersBT ", "BT Hadronic Layer E",100, 0., 10.,100,0.,100.); fEhadHitsU = new TH2F("fEhadHitsU ", "U Hadronic Layer E",100, 0., 10.,100,0.,100.); fEhadHits = new TH2F("fEhadHits ", "Hadronic Layer E",100, 0., 10.,100,0.,100.); fEhadHitsBT = new TH2F("fEhadHitsBT ", "BT Hadronic Layer E",100, 0., 10.,100,0.,100.); eEhadHitsU = new TH2F("eEhadHitsU ", "U Hadronic Layer E",100, 0., 10.,100,0.,100.); eEhadHits = new TH2F("eEhadHits ", "Hadronic Layer E",100, 0., 10.,100,0.,100.); eEhadHitsBT = new TH2F("eEhadHitsBT ", "BT Hadronic Layer E",100, 0., 10.,100,0.,100.); bEhadHitsU = new TH2F("bEhadHitsU ", "U Hadronic Layer E",100, 0., 10.,100,0.,100.); bEhadHits = new TH2F("bEhadHits ", "Hadronic Layer E",100, 0., 10.,100,0.,100.); bEhadHitsBT = new TH2F("bEhadHitsBT ", "BT Hadronic Layer E",100, 0., 10.,100,0.,100.); Histograms2D.push_back(fEhadLayerU); Histograms2D.push_back(fEhadLayerBT); Histograms2D.push_back(fEhadLayer); Histograms2D.push_back(bEhadLayerU); Histograms2D.push_back(bEhadLayerBT); Histograms2D.push_back(bEhadLayer); Histograms2D.push_back(eEhadLayerU); Histograms2D.push_back(eEhadLayerBT); Histograms2D.push_back(eEhadLayer); Histograms2D.push_back(fEhadLayersU); Histograms2D.push_back(fEhadLayersBT); Histograms2D.push_back(fEhadLayers); Histograms2D.push_back(bEhadLayersU); Histograms2D.push_back(bEhadLayersBT); Histograms2D.push_back(bEhadLayers); Histograms2D.push_back(eEhadLayersU); Histograms2D.push_back(eEhadLayersBT); Histograms2D.push_back(eEhadLayers); Histograms2D.push_back(fEhadHitsU); Histograms2D.push_back(fEhadHitsBT); Histograms2D.push_back(fEhadHits); Histograms2D.push_back(bEhadHitsU); Histograms2D.push_back(bEhadHitsBT); Histograms2D.push_back(bEhadHits); Histograms2D.push_back(eEhadHitsU); Histograms2D.push_back(eEhadHitsBT); Histograms2D.push_back(eEhadHits); fEhadU = new TH1F("fEhadU ", "U Hadronic E",100, 0., 10.); fMipDcosU = new TH2F("fMipDcosU ", "U mip dcos E<1",41, -0.0125, 1.0125, 40, -1., 1.); Histograms1D.push_back(fEhadU); Histograms2D.push_back(fMipDcosU); fEhadBT = new TH1F("fEhadBT ", "BT Hadronic E",100, 0., 10.); fMipDcosBT = new TH2F("fMipDcosBT ", "BT mip dcos E<1",41, -0.0125, 1.0125, 40, -1., 1.); Histograms1D.push_back(fEhadBT); Histograms2D.push_back(fMipDcosBT); fPhotonEP = new TH2F("fPhotonEP", "Photon E vs frac",50, 0., 50., 40, 0., 1.); fPhotonEPU = new TH2F("fPhotonEPU", "Photon E vs frac",50, 0., 50., 40, 0., 1.); Histograms2D.push_back(fPhotonEP); Histograms2D.push_back(fPhotonEPU); fMKink = new TH1F("fMKink", "Kink mass",200, 0., 2.); Histograms1D.push_back(fMKink); fETot = new TH1F("fEtot", "Total ECAL energy",250, 0., 50.); fETotN = new TH1F("fEtotN", "Total non-isolated ECAL energy",250, 0., 50.); fETotI = new TH1F("fEtotI", "Total isolated ECAL energy",250, 0., 50.); fETotL = new TH1F("fEtotL", "Total lost isolated ECAL energy",250, 0., 50.); fETotLC = new TH1F("fEtotLC", "Total lost isolated cluster ECAL energy",250, 0., 50.); Histograms1D.push_back(fETot); Histograms1D.push_back(fETotN); Histograms1D.push_back(fETotI); Histograms1D.push_back(fETotL); Histograms1D.push_back(fETotLC); eLong1 = new TH2F("eLong1 ", "long prof <1 ",20, 0., 10., 40, 0., 2.); eLong1_2 = new TH2F("eLong1_2", "long prof 1-2",20, 0., 10., 40, 0., 2.); eLong2_5 = new TH2F("eLong2_5", "long prof 2-5",20, 0., 10., 40, 0., 2.); eLong5 = new TH2F("eLong5 ", "long prof >5 ",20, 0., 10., 40, 0., 2.); Histograms2D.push_back(eLong1); Histograms2D.push_back(eLong1_2); Histograms2D.push_back(eLong2_5); Histograms2D.push_back(eLong5); eLong1H = new TH2F("eLong1H ", "H long prof <1 ",20, 0., 10., 40, 0., 2.); eLong1_2H = new TH2F("eLong1_2H", "H long prof 1-2",20, 0., 10., 40, 0., 2.); eLong2_5H = new TH2F("eLong2_5H", "H long prof 2-5",20, 0., 10., 40, 0., 2.); eLong5H = new TH2F("eLong5H ", "H long prof >5 ",20, 0., 10., 40, 0., 2.); Histograms2D.push_back(eLong1H); Histograms2D.push_back(eLong1_2H); Histograms2D.push_back(eLong2_5H); Histograms2D.push_back(eLong5H); eEhad = new TH1F("eEhad ", "Hadronic E ",100, 0., 10.); eMipDcos = new TH2F("eMipDcos ", "mip dcos E<1",41, -0.0125, 1.0125, 40, -1., 1.); Histograms1D.push_back(eEhad); Histograms2D.push_back(eMipDcos); eEhadU = new TH1F("eEhadU ", "U Hadronic E",100, 0., 10.); eMipDcosU = new TH2F("eMipDcosU ", "U mip dcos E<1",41, -0.0125, 1.0125, 40, -1., 1.); Histograms1D.push_back(eEhadU); Histograms2D.push_back(eMipDcosU); eEhadBT = new TH1F("eEhadBT ", "BT Hadronic E",100, 0., 10.); eMipDcosBT = new TH2F("eMipDcosBT ", "BT mip dcos E<1",41, -0.0125, 1.0125, 40, -1., 1.); Histograms1D.push_back(eEhadBT); Histograms2D.push_back(eMipDcosBT); ePhotonEP = new TH2F("ePhotonEP", "Photon E vs frac",50, 0., 50., 40, 0., 1.); ePhotonEPU = new TH2F("ePhotonEPU", "Photon E vs frac",50, 0., 50., 40, 0., 1.); Histograms2D.push_back(ePhotonEP); Histograms2D.push_back(ePhotonEPU); eMKink = new TH1F("eMKink", "Kink mass",200, 0., 2.); Histograms1D.push_back(eMKink); eETot = new TH1F("eEtot", "Total ECAL energy",250, 0., 50.); eETotN = new TH1F("eEtotN", "Total non-isolated ECAL energy",250, 0., 50.); eETotI = new TH1F("eEtotI", "Total isolated ECAL energy",250, 0., 50.); eETotL = new TH1F("eEtotL", "Total lost isolated ECAL energy",250, 0., 50.); eETotLC = new TH1F("eEtotLC", "Total lost isolated cluster ECAL energy",250, 0., 50.); Histograms1D.push_back(eETot); Histograms1D.push_back(eETotN); Histograms1D.push_back(eETotI); Histograms1D.push_back(eETotL); Histograms1D.push_back(eETotLC); bLong1 = new TH2F("bLong1 ", "long prof <1 ",20, 0., 10., 40, 0., 2.); bLong1_2 = new TH2F("bLong1_2", "long prof 1-2",20, 0., 10., 40, 0., 2.); bLong2_5 = new TH2F("bLong2_5", "long prof 2-5",20, 0., 10., 40, 0., 2.); bLong5 = new TH2F("bLong5 ", "long prof >5 ",20, 0., 10., 40, 0., 2.); Histograms2D.push_back(bLong1); Histograms2D.push_back(bLong1_2); Histograms2D.push_back(bLong2_5); Histograms2D.push_back(bLong5); bLong1H = new TH2F("bLong1H ", "H long prof <1 ",20, 0., 10., 40, 0., 2.); bLong1_2H = new TH2F("bLong1_2H", "H long prof 1-2",20, 0., 10., 40, 0., 2.); bLong2_5H = new TH2F("bLong2_5H", "H long prof 2-5",20, 0., 10., 40, 0., 2.); bLong5H = new TH2F("bLong5H ", "H long prof >5 ",20, 0., 10., 40, 0., 2.); Histograms2D.push_back(bLong1H); Histograms2D.push_back(bLong1_2H); Histograms2D.push_back(bLong2_5H); Histograms2D.push_back(bLong5H); bEhad = new TH1F("bEhad ", "Hadronic E ",100, 0., 10.); bMipDcos = new TH2F("bMipDcos ", "mip dcos E<1",41, -0.0125, 1.0125, 40, -1., 1.); Histograms1D.push_back(bEhad); Histograms2D.push_back(bMipDcos); bEhadU = new TH1F("bEhadU ", "U Hadronic E",100, 0., 10.); bMipDcosU = new TH2F("bMipDcosU ", "U mip dcos E<1",41, -0.0125, 1.0125, 40, -1., 1.); Histograms1D.push_back(bEhadU); Histograms2D.push_back(bMipDcosU); bEhadBT = new TH1F("bEhadBT ", "BT Hadronic E",100, 0., 10.); bMipDcosBT = new TH2F("bMipDcosBT ", "BT mip dcos E<1",41, -0.0125, 1.0125, 40, -1., 1.); Histograms1D.push_back(bEhadBT); Histograms2D.push_back(bMipDcosBT); bPhotonEP = new TH2F("bPhotonEP", "Photon E vs frac",50, 0., 50., 40, 0., 1.); bPhotonEPU = new TH2F("bPhotonEPU", "Photon E vs frac",50, 0., 50., 40, 0., 1.); Histograms2D.push_back(bPhotonEP); Histograms2D.push_back(bPhotonEPU); bMKink = new TH1F("bMKink", "Kink mass",200, 0., 2.); Histograms1D.push_back(bMKink); bETot = new TH1F("bEtot", "Total ECAL energy",250, 0., 50.); bETotN = new TH1F("bEtotN", "Total non-isolated ECAL energy",250, 0., 50.); bETotI = new TH1F("bEtotI", "Total isolated ECAL energy",250, 0., 50.); bETotL = new TH1F("bEtotL", "Total lost isolated ECAL energy",250, 0., 50.); bETotLC = new TH1F("bEtotLC", "Total lost isolated cluster ECAL energy",250, 0., 50.); Histograms1D.push_back(bETot); Histograms1D.push_back(bETotN); Histograms1D.push_back(bETotI); Histograms1D.push_back(bETotL); Histograms1D.push_back(bETotLC); this->processGearInformation(); } void PandoraPFAProcessor::processRunHeader( LCRunHeader* run) { _nRun++ ; _detectorName = run->getDetectorName(); // determine detector (still some hard-coded parameters) streamlog_out(MESSAGE2) << "processRunHeader Detector Model (from header) : " << _detectorName << std::endl; string::iterator it(_detectorName.begin()); if (it != _detectorName.end())_detectorName[0] = toupper((unsigned char)_detectorName[0]); while(++it != _detectorName.end()){ *it = toupper((unsigned char)*it); } // determine detector (still a few places where code can't be steered from GEAR) streamlog_out(MESSAGE2) << "processRunHeader Detector Model (capitilised) : " << _detectorName << std::endl; _detector = DETECTOR_UNKNOWN; if(_detectorName.find("LDC")!=string::npos){ if(_detectorName.find("00")!=string::npos)_detector = DETECTOR_LDC00; if(_detectorName.find("01")!=string::npos)_detector = DETECTOR_LDC01; if(_detectorName.find("01_05")!=string::npos)_detector = DETECTOR_LDC01_05; if(_detectorName.find("01_06")!=string::npos)_detector = DETECTOR_LDC01_05; if(_detectorName.find("PRIME")!=string::npos)_detector = DETECTOR_LDCPRIME; }else{ if(_detectorName.find("GLD")!=string::npos)_detector = DETECTOR_GLD; if(_detectorName.find("SID")!=string::npos)_detector = DETECTOR_SID; if(_detectorName.find("ILD")!=string::npos)_detector = DETECTOR_ILD; } if(_detector==DETECTOR_ILD)streamlog_out(MESSAGE2) << "processRunHeader Detector Type : ILD " << std::endl; if(_detector==DETECTOR_LDCPRIME)streamlog_out(MESSAGE2) << "processRunHeader Detector Type : LDCPRIME " << std::endl; if(_detector==DETECTOR_LDC00)streamlog_out(MESSAGE2) << "processRunHeader Detector Type : LDC00 " << std::endl; if(_detector==DETECTOR_LDC01)streamlog_out(MESSAGE2) << "processRunHeader Detector Type : LDC01 " << std::endl; if(_detector==DETECTOR_LDC01_05)streamlog_out(MESSAGE2) << "processRunHeader Detector Type : LDC01_05 " << std::endl; if(_detector==DETECTOR_GLD)streamlog_out(WARNING) << "processRunHeader Detector Type : GLD (not fully verified) " << std::endl; if(_detector==DETECTOR_SID)streamlog_out(WARNING) << "processRunHeader Detector Type : SID (not yet supported - some aspects of code may fail) " << std::endl; if(_detector==DETECTOR_UNKNOWN){ streamlog_out(ERROR) << "processRunHeader Don't recognise detector type from header - treat as LDCPRIME" << std::endl; _detector = DETECTOR_LDCPRIME; } } void PandoraPFAProcessor::processGearInformation() { _bField = Global::GEAR->getBField().at(gear::Vector3D(0.,0.,0.)).z(); // TPC Geometry from GEAR const gear::TPCParameters& pTPC = Global::GEAR->getTPCParameters(); const gear::PadRowLayout2D& pTPCpads = pTPC.getPadLayout(); std::vectortpcExtent = pTPCpads.getPlaneExtent(); _tpcInnerR = tpcExtent[0]; _tpcOuterR = tpcExtent[1]; _tpcZmax = pTPC.getMaxDriftLength(); _tpcMaxRow = pTPCpads.getNRows(); _cosTPC = _tpcZmax/sqrt(_tpcZmax*_tpcZmax+(_tpcInnerR+0.)*(_tpcInnerR+0.)); if(_printing>1){ std::cout << " GEAR: tpcExtent " << tpcExtent[0] << std::endl; std::cout << " GEAR: tpcExtent " << tpcExtent[1] << std::endl; } // Calorimeter geometry from GEAR const gear::CalorimeterParameters& pEcalBarrel = Global::GEAR->getEcalBarrelParameters(); const gear::CalorimeterParameters& pEcalEndcap = Global::GEAR->getEcalEndcapParameters(); const gear::CalorimeterParameters& pHcalBarrel = Global::GEAR->getHcalBarrelParameters(); const gear::CalorimeterParameters& pHcalEndcap = Global::GEAR->getHcalEndcapParameters(); const gear::LayerLayout& ecalBarrelLayout = pEcalBarrel.getLayerLayout(); const gear::LayerLayout& ecalEndcapLayout = pEcalEndcap.getLayerLayout(); const gear::LayerLayout& hcalBarrelLayout = pHcalBarrel.getLayerLayout(); const gear::LayerLayout& hcalEndcapLayout = pHcalEndcap.getLayerLayout(); // determine pseudo-geometry of detector (determined by ECAL barrel) // symmetry 0 =cylinder, 1=prorotype, >1 = polygon _ECALsymmetry = pEcalBarrel.getSymmetryOrder(); _HCALInnerSymmetry = pHcalBarrel.getSymmetryOrder(); _symmetry = _ECALsymmetry; std::cout << " GEAR ECAL SYMMETRY : " << _ECALsymmetry << std::endl; // set symmetry of HCALBarrel to be the polygon symmetry of outer edge try { _HCALsymmetry = pHcalBarrel.getIntVal("Hcal_outer_polygon_order"); } catch(gear::UnknownParameterException &e){ if(_HCALInnerSymmetry*2>_symmetry){ _HCALsymmetry = _HCALInnerSymmetry*2; streamlog_out(WARNING) << "processRunHeader Setting HCAL symmetry at outer edge to " << _HCALsymmetry << std::endl; } } // Finally check if cyliderical or polygon bool foundOuterRadius=false; try { double rHcal = pHcalBarrel.getDoubleVal("Hcal_outer_radius"); _outerRadiusOfBarrelHCAL = rHcal; foundOuterRadius=true; _HCALsymmetry = 0; streamlog_out(WARNING) << "processRunHeader found Hcal_outer_radius : treat as DHCAL geometry" << std::endl; } catch(gear::UnknownParameterException &e){ } // set symmetry of HCALEndcap to be the polygon symmetry of outer edge try { _HCALEndcapSymmetry = pHcalEndcap.getIntVal("Hcal_outer_polygon_order"); } catch(gear::UnknownParameterException &e){ _HCALEndcapSymmetry = 8; streamlog_out(WARNING) << "processRunHeader Hcal_outer_polygon_order not found " << std::endl; streamlog_out(WARNING) << "processRunHeader Setting ENDCAP HCAL symmetry at outer edge to " << _HCALEndcapSymmetry << std::endl; } _rOfBarrel = (float)pEcalBarrel.getExtent()[0]; _zOfEndcap = (float)pEcalEndcap.getExtent()[2]; _zOfBarrel = (float)pEcalBarrel.getExtent()[3]; _rInnerEcalEndcap = (float)pEcalEndcap.getExtent()[0]; _zOfHcalEndcap = (float)pHcalEndcap.getExtent()[2]; if(!foundOuterRadius)_outerRadiusOfBarrelHCAL = pHcalBarrel.getExtent()[1]; _outerRadiusOfEndcapHCAL = pHcalEndcap.getExtent()[1]; _rearOfEndcapHCAL = pHcalEndcap.getExtent()[3]; _rOfEndcap = (float)pEcalEndcap.getExtent()[1]; _phiOfBarrel = (float)pEcalBarrel.getPhi0(); _nEcalLayers = ecalBarrelLayout.getNLayers(); _nHcalLayers = hcalBarrelLayout.getNLayers(); _overlapCorrection = _rOfBarrel*(_zOfEndcap/_zOfBarrel-1.0); // Determine ECAL polygon angles // Store radial vectors perpendicular to stave layers in _barrelStaveDir if(_symmetry>1){ float nFoldSymmetry = static_cast(_symmetry); float phi0 = pEcalBarrel.getPhi0(); for(int i=0;i<_symmetry;++i){ float phi = phi0 + i*twopi/nFoldSymmetry; vec3 staveDir = {cos(phi),sin(phi),0.}; _barrelStaveDir.push_back(staveDir); } } // determine HCAL polygon angles // Store radial vectors perpendicular to stave layers in _barrelStaveDirHCAL if(_HCALsymmetry>1){ float nFoldSymmetry = static_cast(_HCALsymmetry); float phi0 = pHcalBarrel.getPhi0(); for(int i=0;i<_HCALsymmetry;++i){ float phi = phi0 + i*twopi/nFoldSymmetry; vec3 staveDir = {cos(phi),sin(phi),0.}; _barrelStaveDirHCAL.push_back(staveDir); } } if(_HCALEndcapSymmetry>1){ float nFoldSymmetry = static_cast(_HCALEndcapSymmetry); float phi0 = pHcalEndcap.getPhi0(); for(int i=0;i<_HCALEndcapSymmetry;++i){ float phi = phi0 + i*twopi/nFoldSymmetry; vec3 staveDir = {cos(phi),sin(phi),0.}; _endcapStaveDirHCAL.push_back(staveDir); } } // Using GEAR information define PSEUDOLAYER in BARREL // Internally PandoraPFA defines pseudolayers starting from 1 // with layer zero is reserved for track projections int layer=1; for(int i=0;i(ecalBarrelLayout.getDistance(i)); _thicknessBarrelLayer[layer] = ecalBarrelLayout.getThickness(i); _absThicknessBarrelLayer[layer] = ecalBarrelLayout.getAbsorberThickness(i); _padSizeEcal[i] = ecalBarrelLayout.getCellSize0(i); // now position the active layer float delta =(_absThicknessBarrelLayer[layer]+_thicknessBarrelLayer[layer])/2.0; _positionBarrelLayer[layer]+= delta; layer++; } for(int i=0;i max layer) // these are only necessary if the number/thickness of barrel and endcap layers are different for(int i=0;i<10;++i){ _positionBarrelLayer[layer+i] = _positionBarrelLayer[layer-1]+_thicknessBarrelLayer[layer-1]; _thicknessBarrelLayer[layer+i] = _thicknessBarrelLayer[layer-1]; _absThicknessBarrelLayer[layer+1] = _absThicknessBarrelLayer[layer-1]; _padSizeHcal[layer+i] = _padSizeHcal[layer-1]; } // define layer zero for track projections _positionBarrelLayer[0] = _positionBarrelLayer[1]-_thicknessBarrelLayer[1]; _thicknessBarrelLayer[0] = _thicknessBarrelLayer[1]; _absThicknessBarrelLayer[0] = _absThicknessBarrelLayer[1]; _padSizeEcal[0] = _padSizeEcal[1]; int nBarrelLayers = layer; _barrelHCALLayerThickness = _thicknessBarrelLayer[layer-1]; // Using GEAR information define PSEUDOLAYERS in ENDCAP // Internally PandoraPFA defines pseudolayers starting from 1 // with layer zero is reserved for track projections layer=1; for(int i=0;i max layer) // these are only necessary if the number/thickness of barrel and endcap layers are different for(int i=0;i<10;++i){ _positionEndcapLayer[layer+i] = _positionEndcapLayer[layer-1]+_thicknessEndcapLayer[layer-1]; _thicknessEndcapLayer[layer+i] = _thicknessEndcapLayer[layer-1]; _absThicknessEndcapLayer[layer+1] = _absThicknessEndcapLayer[layer-1]; } // define layer zero : used to stote track projections _positionEndcapLayer[0] = _positionEndcapLayer[1]-_thicknessEndcapLayer[1]; _thicknessEndcapLayer[0] = _thicknessEndcapLayer[1]; _absThicknessEndcapLayer[0] = _absThicknessEndcapLayer[1]; _padSizeEcal[0] = _padSizeEcal[1]; int nEndcapLayers = layer; if(_printing>3){ for(int i=0;inBarrelLayers)_nPseudoLayers=nEndcapLayers; _nBarrelPseudoLayers = nBarrelLayers; _nEndcapPseudoLayers = nEndcapLayers; // set up correspondance between radius and HCAL barrel layer this->MakeHCALBarrelLookup(); float extentEcalPlug[4]; float extentLcal[4]; float extentLHcal[4]; try { const gear::CalorimeterParameters& pEcalPlug = Global::GEAR->getEcalPlugParameters(); for(int i=0;i<4;i++)extentEcalPlug[i] = pEcalPlug.getExtent()[i]; } catch(gear::UnknownParameterException &e){ for(int i=0;i<4;i++)extentEcalPlug[i] = 0.; } try { const gear::CalorimeterParameters& pLcal = Global::GEAR->getLcalParameters(); for(int i=0;i<4;i++)extentLcal[i] = pLcal.getExtent()[i]; } catch(gear::UnknownParameterException &e){ for(int i=0;i<4;i++)extentLcal[i] = 0.; } try { const gear::CalorimeterParameters& pLHcal = Global::GEAR->getLHcalParameters(); for(int i=0;i<4;i++)extentLHcal[i] = pLHcal.getExtent()[i]; } catch(gear::UnknownParameterException &e){ for(int i=0;i<4;i++)extentLHcal[i] = 0.; } if(_printing>1){ std::cout << " GEAR: ECAL Barrel NLayers : " << ecalBarrelLayout.getNLayers() << std::endl; std::cout << "GEAR : " << (float)pEcalBarrel.getExtent()[0] << std::endl; std::cout << "GEAR : " << (float)pEcalBarrel.getExtent()[1] << std::endl; std::cout << "GEAR : " << (float)pEcalBarrel.getExtent()[2] << std::endl; std::cout << "GEAR : " << (float)pEcalBarrel.getExtent()[3] << std::endl; std::cout << " GEAR: ECAL EndCap NLayers : " << ecalEndcapLayout.getNLayers() << std::endl; std::cout << "GEAR : " << (float)pEcalEndcap.getExtent()[0] << std::endl; std::cout << "GEAR : " << (float)pEcalEndcap.getExtent()[1] << std::endl; std::cout << "GEAR : " << (float)pEcalEndcap.getExtent()[2] << std::endl; std::cout << "GEAR : " << (float)pEcalEndcap.getExtent()[3] << std::endl; std::cout << " GEAR: HCAL Barrel NLayers : " << hcalBarrelLayout.getNLayers() << std::endl; std::cout << "GEAR : " << (float)pHcalBarrel.getExtent()[0] << std::endl; std::cout << "GEAR : " << (float)pHcalBarrel.getExtent()[1] << std::endl; std::cout << "GEAR : " << (float)pHcalBarrel.getExtent()[2] << std::endl; std::cout << "GEAR : " << (float)pHcalBarrel.getExtent()[3] << std::endl; std::cout << " GEAR: HCAL EndCap NLayers : " << hcalEndcapLayout.getNLayers() << std::endl; std::cout << "GEAR : " << (float)pHcalEndcap.getExtent()[0] << std::endl; std::cout << "GEAR : " << (float)pHcalEndcap.getExtent()[1] << std::endl; std::cout << "GEAR : " << (float)pHcalEndcap.getExtent()[2] << std::endl; std::cout << "GEAR : " << (float)pHcalEndcap.getExtent()[3] << std::endl; std::cout << " GEAR: LHCAL " << std::endl; std::cout << "GEAR : " << (float)extentLHcal[0] << std::endl; std::cout << "GEAR : " << (float)extentLHcal[1] << std::endl; std::cout << "GEAR : " << (float)extentLHcal[2] << std::endl; std::cout << "GEAR : " << (float)extentLHcal[3] << std::endl; } // Ultimately the hits passed to the clustering are self-describing // However, a small amount of detector information has to be passed to the clusters // This is done via the factory which is used to create all clusters (ProtoClusterFactory::Instance())->ZOfEndcap(_zOfEndcap); (ProtoClusterFactory::Instance())->ZOfBarrel(_zOfBarrel); // INCLUDING A REALLY UGLY HACK TO SET PHOTON ID CUTS FOR LDC00 with thinner ECAL layers float cut = 0.94; if(_detector=="DETECTOR_LDC00")cut = 0.940; (ProtoClusterFactory::Instance())->SetPhotonIDCuts(cut); } void PandoraPFAProcessor::MakeHCALBarrelLookup() { // Build lookup table for correspondance between perp distance // form origin in HCAL to HCAL layer for(int iradius=0;iradius<10000;iradius++){ float radius = (float)iradius; float barrelLayerDist=999.; int closestLayer=0; for(int ilayer = 0; ilayer <= _nPseudoLayers; ++ilayer){ if(fabs(radius-_positionBarrelLayer[ilayer])processGearInformation(); _nEvt++ ; // clear the old event this->Clear(); // PandoraPFA does not yet work for a digital HCAL // would not be a great deal of work, just hasn't been done yet /// if(_digitalHCAL!=0){ // std::cout << " Digital HCAL option not yet implemented ! "; // std::cout << " to request this feature send email to thomson@hep.phy.cam.ac.uk "; // return; //} // Unpack the MC information for DEBUGGING purposes (ultimately this will be removed) typedef const std::vector StringVec ; StringVec* strVec = evt->getCollectionNames() ; for(StringVec::const_iterator name=strVec->begin(); name!=strVec->end(); name++){ LCCollection* col = evt->getCollection(*name); int nelem = col->getNumberOfElements(); // on the first event print out available collections if(_nEvt==1)streamlog_out(MESSAGE) << "PandoraPFA::processEvent Input Collections : " << *name << " elements : " << nelem << std::endl; if (col->getTypeName() == LCIO::MCPARTICLE ) { _mcTree = new MCTree(col); _myMcTree = new MyMCTree(col); if(_printing>0)_myMcTree->PerfectPFO(1); if(_printing<1)_myMcTree->PerfectPFO(0); _mcPFOs = *(_myMcTree->getMCPFOs()); } } // ************************************************************** // **************** PandoraPFA INITIALIZATION STAGE ************* // ************************************************************** // ReaCALO hits and tracks and store in internal extended objects // the extended hits include information about energy and pseudolayer // the extended tracks include extrapolation information this->initialiseEvent(evt); if(_printing>3)streamlog_out(MESSAGE) << " done initialiseEvent" << std::endl; // Apply isolation cuts the CALO hits this->stripIsolatedHits(); // Apply hit based energy corrections (if any) this->hitEnergyCorrections(); if(_printing>3)std::cout << " done stripIsolatedHits" << std::endl; // Order hits within each pseudolayer either by energy, local denisty,... this->OrderHitsInEachLayer(); if(_printing>3)std::cout << " done OrderHitsInEachLayer" << std::endl; // Could draw hits etc... //_recoDisplay->DrawByMIP(_calHitsByPseudoLayer); //_recoDisplay->DrawByDensity(_calHitsByPseudoLayer); //_recoDisplay->DrawByEnergy(_allCalHitsByPseudoLayer); //_recoDisplay->DrawByEnergy(_calHitsByPseudoLayer); // ***************************************************************** // **************** PandoraPFA CLUSTER FORMATION STAGE ************* // ***************************************************************** // First create the design to which clusters are going to be built // i.e. the basic formation/growth rules // Configure the ProtoCluster factory with the protoClusterDesign protoClusterDesign_t design; design.tanConeAngleECAL = _clusterFormationConeTanECAL; design.tanConeAngleHCAL = _clusterFormationConeTanHCAL; design.additionalPadsECAL = _clusterFormationPadsECAL; design.additionalPadsHCAL = _clusterFormationPadsHCAL; design.sameLayerPadCutECAL = _sameLayerPadCutECAL; design.sameLayerPadCutHCAL = _sameLayerPadCutHCAL; design.maximumDistanceForConeAssociationECAL=_maximumDistanceForConeAssociationECAL; design.maximumDistanceForConeAssociationHCAL=_maximumDistanceForConeAssociationHCAL; design.trackingWeight =_trackingWeight; design.trackingCutOff =_trackingCutOff; design.trackingTube =_trackingTube; // Pass design to factory (ProtoClusterFactory::Instance())->SetDefaultDesign(design); (ProtoClusterFactory::Instance())->SetDesignToDefault(); if(_perfectPFA||_perfectClustering||_perfectPhotonClustering)_photonClustering=0; // Form the protoclusters if(_perfectPFA||_perfectClustering){ // Perform perfect Clustering (and track matching if requested) this->PerfectPFA(evt); }else{ if(_photonClustering && !_perfectPhotonClustering)this->PhotonClustering(); if(_perfectPhotonClustering)this->PerfectPhotonClustering(); if(_perfectNeutralHadronClustering)this->PerfectNeutralHadronClustering(); // Form the protoclusters if(_printing>3)std::cout << " PandoraPFAProcessor: MakeProtoClusters " << std::endl; this->MakeProtoClusters(_tracksAR,_protoClusters); if(_tailCatcher!=0)this->MakeMuonProtoClusters(_tracksAR); if(_printing>3)std::cout << " PandoraPFAProcessor: ProtoClusters : " << _protoClusters.size() << std::endl; // ******************************************************************** // **************** PandoraPFA CLUSTER ASSOCIATION STAGE ************** // ******************************************************************** // associate protoClusters together // NOTE this is one of the main parts of the algorithm! ProtoClusterVec nfinalProtoClusters; if(_protoClusters.size()>0)this->associateProtoClusters(_protoClusters,_tracksAR,nfinalProtoClusters,true); if(_printing>3)std::cout << " PandoraPFAProcessor: assoc : " << nfinalProtoClusters.size() << std::endl; // ******************************************************************** // ************************** PandoraPFA CLEANUP ********************* // ******************************************************************** // cleanup clusters this->finalisePhotons(nfinalProtoClusters); if(_printing>3)std::cout << " PandoraPFAProcessor: finaliseP : " << nfinalProtoClusters.size() << std::endl; ProtoClusterVec vnfinalProtoClusters; if(_fragmentRemoval>0){ this->fragmentRemoval(nfinalProtoClusters,_tracksAR,vnfinalProtoClusters); }else{ this->makeFinalProtoClusters(nfinalProtoClusters,vnfinalProtoClusters); } if(_printing>3)std::cout << " PandoraPFAProcessor: fragRem : " << nfinalProtoClusters.size() << std::endl; this->ExitingTrackReclustering(vnfinalProtoClusters); if(_photonRecovery>0)this->FinalPhotonRecovery(vnfinalProtoClusters, _tracksAR, false); this->makeFinalProtoClusters(vnfinalProtoClusters,_finalProtoClusters); this->findPhotonsIDedAsHadrons(_finalProtoClusters); } // ******************************************************************** // **************** PandoraPFA LCIO Object Creation ******************* // ******************************************************************** if(_printing>3)std::cout << " PandoraPFAProcessor: prepare to create PFOs : " << _finalProtoClusters.size() << std::endl; // create PFO collection if(!_perfectPFA){ this->CreatePFOCollection(evt); } // PFA analysis if(_analyseClusters>0)this->AnalysePFAPerformance(evt); if(1==1){ if(_recoDisplay!=NULL)_recoDisplay->DrawByProtoClusterEnergy(_finalProtoClusters,3,RECO_VIEW_XY); if(_recoDisplay!=NULL)_recoDisplay->DrawByProtoClusterEnergy(_finalProtoClusters,3,RECO_VIEW_XZ); } } void PandoraPFAProcessor::Clear(){ // Clean up after reconstructing an event // Delete all temporary objects // including the protoclusters, the extended hits and tracks if(_printing>3)std::cout << "PandoraPFAProcessor::Clear" << std::endl; // delete navigators if(_caloNavigator!=NULL)delete _caloNavigator; if(_muonNavigator!=NULL)delete _muonNavigator; if(_trackNavigator!=NULL)delete _trackNavigator; _caloNavigator = NULL; _muonNavigator = NULL; _trackNavigator = NULL; // delete the extended hits for(int i=0;iDelete(); _protoClusters.clear(); _photonClusters.clear(); _perfectNeutralHadronClusters.clear(); _muonProtoClusters.clear(); _finalProtoClusters.clear(); // and tell the factory to zero its cluster counter ProtoClusterFactory::Instance()->ResetCounter(); // remove the MC information if(_mcTree!=NULL)delete _mcTree; _mcTree = NULL; if(_myMcTree!=NULL)delete _myMcTree; _myMcTree = NULL; // clear the event display if(_recoDisplay!=NULL){ _recoDisplay->Clear(); _recoDisplay->CleanUp(); } } void PandoraPFAProcessor::PerfectPFA(LCEvent * evt){ if(_caloNavigator==NULL || _trackNavigator==NULL){ streamlog_out(ERROR) << " Can't perform PerfectClustering" << std::endl; if(_caloNavigator==NULL)streamlog_out(ERROR) << " : no calorimeter hit navigator" << std::endl; if(_trackNavigator==NULL)streamlog_out(ERROR) << " :no track navigator" << std::endl; if(_muonNavigator==NULL)streamlog_out(WARNING) << " :no muon hit navigator - won't include muon hits" << std::endl; return; } std::vector mcPFOs = *(_myMcTree->getMCPFOs()); ProtoCluster* protoClusters[mcPFOs.size()]; unsigned int nTracks[mcPFOs.size()]; MyTrackExtended* extendedTracks[mcPFOs.size()][10]; for(unsigned int i =0;i(hiti->getCalorimeterHit()); // use navigator to match hit to simhit LCObjectVec objectVec = _caloNavigator->getRelatedToObjects(calhit); int ibestmc = 0; int ibesttrack = 0; if (objectVec.size() > 0) { SimCalorimeterHit * simhit = dynamic_cast(objectVec[0]); float emax = 0; float emaxtrack = 0; float ehittot = 0; if (simhit->getNMCContributions() > 1){ // find largest contributor to hit for(int i=0;igetNMCContributions();i++){ ehittot+= simhit->getEnergyCont(i); if(simhit->getEnergyCont(i)>emax){ emax = simhit->getEnergyCont(i); ibestmc = i; } } // if significant track contribution use that ? ibesttrack = ibestmc; for(int i=0;igetNMCContributions();i++){ if(simhit->getEnergyCont(i)>0.025*ehittot){ MCParticle * part = simhit->getParticleCont(i); unsigned int jmc = _myMcTree->GetMCPFOIndex(part); if(jmc>=0&&jmcgetPDG()); if( id==211 || id==11 || id==321 || id == 2212){ if(simhit->getEnergyCont(i)>emaxtrack){ emaxtrack = simhit->getEnergyCont(i); ibesttrack = i; } } } } } } if (simhit->getNMCContributions() > 0) { // choose mc particle contributing most to hit // if _perfectClustering==2 preferentially associate to track int iuse = ibestmc; if(_perfectClustering==2)iuse = ibesttrack; MCParticle * part = simhit->getParticleCont(iuse); // use myMcTree to match hit to perfect particle flow object unsigned int jmc = _myMcTree->GetMCPFOIndex(part); if(jmcManufacture(hiti); }else{ protoClusters[jmc]->AddHit(hiti); } } } } } } // update clusters and fill finalProtoCluster collection for(unsigned int i =0;iUpdate(_maxLayer); protoClusters[i]->ClassifyYourself(); _finalProtoClusters.push_back(protoClusters[i]); } } if(_tailCatcher!=0){ this->MakeMuonProtoClusters(_tracksAR); // this->MakePerfectMuonProtoClusters(_tracksAR); } //*********************** Track Matching ********************// // now deal with the tracks for(unsigned int it=0;it<_tracksAR.size();++it){ Track* track = _tracksAR[it]->getTrack(); LCObjectVec objectVec = _trackNavigator->getRelatedToObjects(track); if (objectVec.size() > 0){ bool bs = false; MCParticle* part = dynamic_cast(objectVec[0]); if(part->isBackscatter()){ std::cout << " MC BACKSCATTER FLAG : " << _tracksAR[it]->getEnergy() << std::endl; if( _tracksAR[it]->getEnergy()<2.0)bs = true; } if(!bs){ unsigned int jmc = _myMcTree->GetMCPFOIndex(part); if(jmc>=0&&jmcgetEnergy() << std::endl; } } }else{ std::cout << " ****Unmatched TRACK : " << _tracksAR[it]->getEnergy() << std::endl; } } std::cout << " Done " << std::endl; float totalEnergy = 0.; for(unsigned int i =0; i0){ float trackEnergy = 0; float vetoE = 0.; for(unsigned int it=0;itisBackScatter())veto=true; if(trackAR->isKinkE())veto=true; if(trackAR->isProngE())veto=true; if(trackAR->isSplitE())veto=true; if(!veto)trackEnergy += trackAR->getEnergy(); if(veto){ std::cout << " Vetoing track " << trackAR->getEnergy() << std::endl; vetoE+= trackAR->getEnergy(); } } if(vetoE>0){ MCParticle* mcpart = mcPFOs[i]->getMCParticle(); std::cout << " MCPFO : " << mcpart->getEnergy() << " vetoed track E = " << vetoE << " Left E = " << trackEnergy << std::endl; } totalEnergy+=trackEnergy; } } for(unsigned int i =0;iSetClusterClassification(PC_UNKNOWN); if(mcPFOs[i]->isPhoton())protoClusters[i]->SetClusterClassification(PC_PRIMARY_PHOTON); if(protoClusters[i]->IsPhoton()){ totalEnergy+=protoClusters[i]->EnergyEM(); }else{ totalEnergy+=protoClusters[i]->EnergyHAD(); } } } } if(_printing>0)std::cout << " Total PERFECT ENERGY : " << totalEnergy << std::endl; if(!_perfectTrackClusterMatching)return; // ************* perfect track cluster matching *********************// for(unsigned int i =0; i0){ if(protoClusters[i]!=NULL){ protoClusters[i]->AssociatedTrack(true); for(unsigned int it=0;itaddCluster(protoClusters[i]); protoClusters[i]->AddTrack(trackAR); } } } } if(_printing>1){ for(unsigned int itrack=0;itrack<_tracksAR.size();++itrack){ MyTrackExtended* trackAR = _tracksAR[itrack]; Track* track = trackAR->getTrack(); TrackerHitVec hitvec = track->getTrackerHits(); int nhits = (int)hitvec.size(); float d0 = track->getD0(); float z0 = track->getZ0(); float x =trackAR->getSeedPosition()[0]; float y =trackAR->getSeedPosition()[1]; // float rextrap = sqrt(x*x+y*y); float r = sqrt(x*x+y*y); int nonSiHits = trackAR->nonSiHits(); std::cout << " TRACK : " << itrack << " : " << trackAR->getEnergy() << " r = " << trackAR->getInnerR() << "-" << trackAR->getOuterR() << " d/z0 : " << d0 << "," << z0 << " hits = " << nhits << "(" << nonSiHits<<")"<< " REXTRAP : " << r << " z = " << trackAR->getZMin() << "-" << trackAR->getZMax() << std::endl; } float emcpfo = 0.; float emiss = 0.; for(unsigned int i =0; igetMCParticle(); emcpfo += mcpart->getEnergy(); if(nTracks[i]==1 && (mcPFOs[i]->getPDG()==130 || abs(mcPFOs[i]->getPDG())==2112 || mcPFOs[i]->getPDG()==310 || mcPFOs[i]->getPDG()==22 )){ MyTrackExtended* trackAR = extendedTracks[i][0]; float etrack = trackAR->getEnergy(); if(mcpart->getEnergy() > 1 && fabs(etrack/mcpart->getEnergy()-1) > 0.2 )std::cout << " checking...." <getInnerR() > _tpcInnerR ){ std::cout << " KILL BS TRACK " << etrack << std::endl; trackAR->isBackScatter(true); nTracks[i]=0; } } if(nTracks[i]!=0){ float etrack = 0; for(unsigned int it=0;itgetPDG() << " E= " << mcpart->getEnergy(); std::cout << " Track Match : "; if(trackAR->isProngS())cout << " PS"; if(trackAR->isProngE())cout << " PE"; if(trackAR->isKinkE())cout << " KE"; if(trackAR->isKinkS())cout << " KS"; if(trackAR->isSplitS())cout << " SS"; if(trackAR->isSplitE())cout << " SE"; if(trackAR->isV0())cout << " V0"; if(trackAR->isBackScatter())cout << " BS"; cout << " " << trackAR->getEnergy() << " -> "; bool veto = false; if(trackAR->isBackScatter())veto=true; if(trackAR->isKinkE())veto=true; if(trackAR->isProngE())veto=true; if(!veto)etrack+= trackAR->getEnergy(); if(protoClusters[i]!=NULL){ std::cout << " Cluster : " << protoClusters[i]->EnergyHAD() << std::endl; }else{ cout << std::endl; } } if(mcpart->getEnergy() > 5 && fabs(etrack/mcpart->getEnergy()-1) > 0.2 )std::cout << " ERROR ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ " <getPDG() << " E= " << mcpart->getEnergy(); if(protoClusters[i]==NULL){ std::cout << " Missing McPFO -----------------------: " << std::endl; emiss += mcpart->getEnergy(); }else{ int il = protoClusters[i]->FirstLayer(); float xc = protoClusters[i]->GetCentroid(il)[0]; float yc = protoClusters[i]->GetCentroid(il)[1]; float zc = protoClusters[i]->GetCentroid(il)[2]; float rc = sqrt(xc*xc+yc*yc+zc*zc); float dcos = zc/rc; std::cout << " Cluster : " << protoClusters[i]->EnergyHAD() << " costheta = " << dcos << std::endl; if(mcpart->getEnergy() > 5 && fabs(protoClusters[i]->EnergyHAD()/mcpart->getEnergy()-1) > 0.2 )std::cout << " ERROR ??? ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ " <AddMuonClustersToPFOs(_finalProtoClusters,_tracksAR); // create clusters collection this->CreateClusterCollection(evt); float Etotal = 0; // loop over MC PFOs - look at tracks first for(unsigned int i =0; i0){ std::setaddedClusters; ReconstructedParticleImpl* recoPart = new ReconstructedParticleImpl(); float Mom[3]; float MomC[3]; for(unsigned int ii=0;ii<3;ii++)Mom[ii]=0; for(unsigned int ii=0;ii<3;ii++)MomC[ii]=0; float charge = 0; float Energy=0; float Mass=0.14; float etrack = 0; float eclust = 0; int IDPart=mcPFOs[i]->getPDG(); if(abs(IDPart)==11)Mass = 0.0005; if(abs(IDPart)==321)Mass = 0.49; if(abs(IDPart)==310)Mass = 0.49; if(abs(IDPart)==22)Mass = 0.; for(unsigned int it=0;itgetTrack(); recoPart->addTrack(track); bool veto = false; if(trackAR->isBackScatter())veto=true; if(trackAR->isKinkE())veto=true; if(trackAR->isProngE())veto=true; if(nTracks[i]>1 && trackAR->isSplitE())veto=true; if(veto)std::cout << " veto " << trackAR->getEnergy() << std::endl; if(!veto){ Mom[0] += trackAR->getStartMomentum()[0]; Mom[1] += trackAR->getStartMomentum()[1]; Mom[2] += trackAR->getStartMomentum()[2]; float c = trackAR->getOmega(); c = c/fabs(c); charge += c; etrack += trackAR->getEnergy(); } // now add the clusters ProtoClusterVec clusters = trackAR->getClusterVec(); for(unsigned int ic=0;icGetCluster(); if(cluster!=NULL){ if(addedClusters.count(cluster)==0){ recoPart->addCluster(cluster); addedClusters.insert(cluster); eclust += clusters[ic]->EnergyHAD(); float p[3]; float totGravity = 0.; for (int i=0; i < 3; ++i) { float xgrav = cluster->getPosition()[i]; p[i] = eclust*xgrav; totGravity += xgrav*xgrav; } totGravity = sqrt(totGravity); for (int i=0; i < 3; ++i)MomC[i]+= p[i]/totGravity; } } } } // decaying Lambdas which produce multiple tracks/clusters if(IDPart==3122){ if(eclust>2.0*etrack){ for(unsigned int ii=0;ii<3;ii++)Mom[ii]=MomC[ii]; float En = sqrt(Mom[0]*Mom[0]+Mom[1]*Mom[1]+Mom[2]*Mom[2]+Mass*Mass); std::cout << " Lambda - using cluster energy " << etrack << " -> " << eclust << " " << En << std::endl; } } // decaying Lambdas which produce multiple tracks/clusters if(IDPart==310){ if(eclust>5.0*etrack){ for(unsigned int ii=0;ii<3;ii++)Mom[ii]=MomC[ii]; float En = sqrt(Mom[0]*Mom[0]+Mom[1]*Mom[1]+Mom[2]*Mom[2]+Mass*Mass); std::cout << " KS - using cluster energy " << etrack << " -> " << eclust << " " << En << std::endl; } } if(nTracks[i]>2){ if(eclust>2.0*etrack&&eclust>5.0){ for(unsigned int ii=0;ii<3;ii++)Mom[ii]=MomC[ii]; float En = sqrt(Mom[0]*Mom[0]+Mom[1]*Mom[1]+Mom[2]*Mom[2]+Mass*Mass); std::cout << " Interaction ? - using cluster energy " << etrack << " -> " << eclust << " " << En << std::endl; } } Energy = sqrt(Mom[0]*Mom[0]+Mom[1]*Mom[1]+Mom[2]*Mom[2]+Mass*Mass); recoPart->setMomentum( Mom ); recoPart->setEnergy( Energy ); recoPart->setMass( Mass ); recoPart->setCharge( charge ); recoPart->setType( IDPart ); recparcol->addElement( recoPart ); Etotal+=Energy; } } // loop over MC PFOs - look at clusters for(unsigned int i =0; iGetCluster(); if(cluster!=NULL){ ReconstructedParticleImpl* recoPart = new ReconstructedParticleImpl(); recoPart->addCluster(cluster); float Energy; float Mass=0; float Mom[3]; int IDPart=0; float totGravity = 0.0; if(mcPFOs[i]->isPhoton()){ Energy=protoClusters[i]->EnergyEM(); IDPart = 22; }else{ Energy=protoClusters[i]->EnergyHAD(); IDPart = 2112; } for (int i=0; i < 3; ++i) { float xgrav = cluster->getPosition()[i]; Mom[i] = Energy*xgrav; totGravity += xgrav*xgrav; } totGravity = sqrt(totGravity); for (int i=0; i < 3; ++i)Mom[i] = Mom[i]/totGravity; recoPart->setMomentum( Mom ); recoPart->setEnergy( Energy ); recoPart->setMass( Mass ); recoPart->setCharge( 0. ); recoPart->setType( IDPart ); recparcol->addElement( recoPart ); Etotal+=Energy; } } } } evt->addCollection( recparcol , _particleCollectionName.c_str() ); if(_printing>0)std::cout << " Created Perfect PFO Collection : Etotal = " << Etotal << std::endl; return; } void PandoraPFAProcessor::ExtractMcPfoInfo(){ /////// wibble if(_caloNavigator==NULL || _trackNavigator==NULL){ streamlog_out(ERROR) << " Can't perform ExtractMcPfoInfo" << std::endl; if(_caloNavigator==NULL)streamlog_out(ERROR) << " : no calorimeter hit navigator" << std::endl; if(_trackNavigator==NULL)streamlog_out(ERROR) << " :no track navigator" << std::endl; return; } // veto conversions unsigned int nTracks[_mcPFOs.size()]; for(unsigned int i =0;i<_mcPFOs.size();++i){ nTracks[i]=0; } //*********************** Track Matching ********************// // now deal with the tracks - do not perfect cluster conversions for(unsigned int it=0;it<_tracksAR.size();++it){ Track* track = _tracksAR[it]->getTrack(); LCObjectVec objectVec = _trackNavigator->getRelatedToObjects(track); if (objectVec.size() > 0){ bool bs = false; MCParticle* part = dynamic_cast(objectVec[0]); unsigned int testmc = _myMcTree->GetMCPFOIndex(part); if(testmc<99999){ if(part->isBackscatter()){ if( _tracksAR[it]->getEnergy()<2.0)bs = true; } if(!bs){ unsigned int jmc = _myMcTree->GetMCPFOIndex(part); if(jmc>=0&&jmc<_mcPFOs.size())nTracks[jmc]++; } } } } for(unsigned int ilayer=0;ilayer(hiti->getCalorimeterHit()); // use navigator to match hit to simhit LCObjectVec objectVec = _caloNavigator->getRelatedToObjects(calhit); int ibestmc = 0; if (objectVec.size() > 0) { SimCalorimeterHit * simhit = dynamic_cast(objectVec[0]); float emax = 0; if (simhit->getNMCContributions() > 1){ // find largest contributor to hit for(int i=0;igetNMCContributions();i++){ if(simhit->getEnergyCont(i)>emax){ emax = simhit->getEnergyCont(i); ibestmc = i; } } } if (simhit->getNMCContributions() > 0) { int iuse = ibestmc; MCParticle * part = simhit->getParticleCont(iuse); // use myMcTree to match hit to perfect particle flow object unsigned int jmc = _myMcTree->GetMCPFOIndex(part); if(jmc>=0 && jmc<_mcPFOs.size()){ hiti->setMCPFO(jmc); int IDPart=_mcPFOs[jmc]->getPDG(); if(abs(IDPart)==22 && nTracks[jmc]==0){ hiti->setPhoton(true); } } } } } } return; } void PandoraPFAProcessor::PerfectPhotonClustering(){ if(_caloNavigator==NULL || _trackNavigator==NULL){ streamlog_out(ERROR) << " Can't perform PerfectPhotonClustering" << std::endl; if(_caloNavigator==NULL)streamlog_out(ERROR) << " : no calorimeter hit navigator" << std::endl; if(_trackNavigator==NULL)streamlog_out(ERROR) << " :no track navigator" << std::endl; return; } std::vector mcPFOs = *(_myMcTree->getMCPFOs()); ProtoCluster* protoClusters[mcPFOs.size()]; for(unsigned int i =0;igetTrack(); LCObjectVec objectVec = _trackNavigator->getRelatedToObjects(track); if (objectVec.size() > 0){ bool bs = false; MCParticle* part = dynamic_cast(objectVec[0]); if(part->isBackscatter()){ if( _tracksAR[it]->getEnergy()<2.0)bs = true; } if(!bs){ unsigned int jmc = _myMcTree->GetMCPFOIndex(part); if(jmc>=0&&jmc(hiti->getCalorimeterHit()); // use navigator to match hit to simhit LCObjectVec objectVec = _caloNavigator->getRelatedToObjects(calhit); int ibestmc = 0; if (objectVec.size() > 0) { SimCalorimeterHit * simhit = dynamic_cast(objectVec[0]); float emax = 0; if (simhit->getNMCContributions() > 1){ // find largest contributor to hit for(int i=0;igetNMCContributions();i++){ if(simhit->getEnergyCont(i)>emax){ emax = simhit->getEnergyCont(i); ibestmc = i; } } } if (simhit->getNMCContributions() > 0) { int iuse = ibestmc; MCParticle * part = simhit->getParticleCont(iuse); // use myMcTree to match hit to perfect particle flow object unsigned int jmc = _myMcTree->GetMCPFOIndex(part); if(jmc>=0 && jmcgetPDG(); if(abs(IDPart)==22 && nTracks[jmc]==0){ // add it to the appropriate protocluster _hitsForRemoval.push_back(hiti); if(protoClusters[jmc]==NULL){ protoClusters[jmc] = (ProtoClusterFactory::Instance())->Manufacture(hiti); }else{ protoClusters[jmc]->AddHit(hiti); } } } } } } } // now remove the hits from the list to be clustered this->removeAssociatedHits(); // save the pointers to the created clusters for(unsigned int i =0;iGetDesign(); design.tanConeAngleECAL = _photonClusterFormationConeTanECAL; (ProtoClusterFactory::Instance())->SetDesign(design); for(int i=0;i seedProtoClusters; // step over pseudo-layers working from front to back of the Calorimeters for(unsigned int ilayer=0;ilayer<=(unsigned int)_nEcalLayers;++ilayer){ // loop over hits in layer and try and associate with existing clusters for(unsigned int ihit=0;ihit<_tmpCalHitsByPseudoLayer[ilayer].size();++ihit){ MyCaloHitExtended* hiti = _tmpCalHitsByPseudoLayer[ilayer][ihit]; vectorclustersWantingHit; // allow possible asoscitation to clustered hits in stepBack layers unsigned int stepBack = _layersToStepBackECAL; bool associated = false; float smallestGenericDistance = 9999.; ProtoCluster* bestCluster=NULL; for(unsigned int iback=1; iback<=stepBack&&!associated && iback<=ilayer; ++iback){ unsigned int searchLayer = ilayer - iback; vectorclustersWantingHit; // loop over clusters looking for associations for(unsigned int icluster=0;iclustergenericDistanceToHit(hiti, searchLayer); // generic distance is a measure of goodness of association // anything less than 1.0 indicates a possible association // the details of how this distance could depend on type of cluster if(genericDistance<1.0){ clustersWantingHit.push_back(seedProtoClusters[icluster]); if(genericDistance0){ ProtoCluster* favouredCluster=this->Arbitrate(hiti,clustersWantingHit,searchLayer); favouredCluster->AddHit(hiti); // mark hit for removal from unassociated hits _hitsForRemoval.push_back(hiti); associated = true; } } } if(_clusterFormationStrategy==1 && bestCluster!=NULL){ // check all layers first and and use best cluster bestCluster->AddHit(hiti); // mark hit for removal from unassociated hits _hitsForRemoval.push_back(hiti); } } // remove newly associated hits in layer ilayer from _calHitsByPseudoLayer this->removeTmpAssociatedHits(); // tried to associate hits with previous layers, now check // for associations in current layer while(_tmpCalHitsByPseudoLayer[ilayer].size()>0){ bool found = true; while(found){ found = false; for(unsigned int ihit=0;ihit<_tmpCalHitsByPseudoLayer[ilayer].size();++ihit){ MyCaloHitExtended* hiti = _tmpCalHitsByPseudoLayer[ilayer][ihit]; vectorclustersWantingHit; for(unsigned int icluster=0;iclustergenericDistanceToHit(hiti,ilayer); if(genericDistance<1.0)clustersWantingHit.push_back(seedProtoClusters[icluster]); } // if at least one cluster wants hit - Arbitrate(,,) decides the best if(clustersWantingHit.size()>0){ found = true; ProtoCluster* favouredCluster=this->Arbitrate(hiti,clustersWantingHit,ilayer); favouredCluster->AddHit(hiti); _hitsForRemoval.push_back(hiti); } } this->removeTmpAssociatedHits(); } // BY NOW remaining hits in _calHitsByPseudoLayer[ilayer] have not been associated // The first hit is used to seed a new cluster (first can mean highest energy/density) // Having done this loop over other hits to see if they are associated to the // new cluster - repeat... if(_tmpCalHitsByPseudoLayer[ilayer].size()>0){ MyCaloHitExtended* hiti = _tmpCalHitsByPseudoLayer[ilayer][0]; ProtoCluster* newCluster = (ProtoClusterFactory::Instance())->Manufacture(hiti); seedProtoClusters.push_back(newCluster); _hitsForRemoval.push_back(hiti); this->removeTmpAssociatedHits(); } } // Make sure cluster properties are up to date : this isn't done when new hits are // added as this would be excessively time consuming for(unsigned int icluster=0;iclusterUpdate(ilayer); } // calculate more cluster properties and classify cluster for(unsigned int i=0;iClassifyYourself(); // now perform photon ID for(unsigned int i=0;i peaks; if(seedProtoClusters[i]->EnergyEM()>0.2)seedProtoClusters[i]->TransverseProfile(peaks,_nEcalLayers); bool usedCluster = false; for(unsigned int ipeak=0;ipeakTransverseProfile(ipeak,_nEcalLayers,0); if(photonCand!=NULL){ photonCand=(ProtoClusterFactory::Instance())->CloneAndDelete(photonCand); photonCand->PhotonProfileID(); float showerStart = photonCand->GetLongProfileShowerStart(); float gammaFraction = photonCand->GetLongProfileGammaFraction(); float fraction = photonCand->TruePhotonContribution() / photonCand->EnergyEM(); float closest = 999.; float cclosest = 999.; float c10closest = 999.; float c20closest = 999.; for(unsigned int itrack = 0; itrack < _tracksAR.size();itrack++){ float approach = photonCand->DistanceToTrack(_tracksAR[itrack],10); if(approachCentroidDistanceToTrack(_tracksAR[itrack]); if(cclosest>999)cclosest = 0.; c10closest = photonCand->Centroid10DistanceToTrack(_tracksAR[itrack]); if(c10closest>999)c10closest =0.; c20closest = photonCand->Centroid20DistanceToTrack(_tracksAR[itrack]); if(c20closest>999)c20closest =0.; } } float dist = min(c10closest,c20closest); if(cclosestHits(); float pid = (PhotonIDLikelihoodCalculator::Instance())->PID( peaks[ipeak].energy, peaks[ipeak].rms, gammaFraction,showerStart); bool accept = false; bool useOriginalCluster = false; // cuts for case where there is no pointing track float pidCut = 0.5; //if(closest>10)pidCut=0.45; //if(closest>20)pidCut=0.40; //if(closest>30)pidCut=0.35; //if(closest>40)pidCut=0.30; //if(closest>50)pidCut=0.25; float fracE = photonCand->EnergyEM()/seedProtoClusters[i]->EnergyEM(); if(nhits>=_minimumHitsInCluster && peaks[ipeak].energy>0.2 && pid > pidCut && showerStart<10 && gammaFraction < 1.0 &&peaks[ipeak].rms<5.0 && closest > 2.0){ accept = true; // OK found photon cluster - use this sub-cluster (peak) or the whole thing float diffE = seedProtoClusters[i]->EnergyEM() - photonCand->EnergyEM(); if(fracE>0.95 || peaks.size()==1)useOriginalCluster=true; if(fracE>0.90 && diffE < 2.0)useOriginalCluster=true; if(fracE>0.80 && diffE < 1.0)useOriginalCluster=true; if(fracE>0.5 && diffE<0.5)useOriginalCluster=true; if(ipeak!=0)useOriginalCluster = false; } // cluster which is very close to a nearby track if(nhits>=_minimumHitsInCluster && peaks[ipeak].energy>0.2 && pid > 0.5 && showerStart<10 && gammaFraction < 1.0 &&peaks[ipeak].rms<5.0 && closest <= 2.0){ if(dist > 5.0 && pid > 0.9)accept = true; if(dist > 7.5 && pid > 0.8)accept = true; if(dist > 10.0 && pid > 0.7)accept = true; } if(_printing>0&& peaks[ipeak].energy>1.0){ std::cout << " PEAK " << ipeak << " : " << peaks[ipeak].du << "," << peaks[ipeak].dv << " E = " << peaks[ipeak].energy << " dmin : " << peaks[ipeak].dmin << " d25/d90 : " << peaks[ipeak].showerDepth25 << "/" << peaks[ipeak].showerDepth90 << " start : " << peaks[ipeak].showerStartDepth << " rms = " << peaks[ipeak].rms << " PhotonID : " << showerStart << " " << gammaFraction << " TRUE FRACTION = " << fraction << " pid " << pid << " d = " << closest << " c= " << dist; if(fraction<0.5 && accept)std::cout << " <---A*****************"; if(fraction>0.5 && !accept) std::cout << " <---B*****************"; std::cout << std::endl; } if(accept){ //float fracE = photonCand->EnergyEM()/seedProtoClusters[i]->EnergyEM(); if(useOriginalCluster){ photonCand->IsNowDefunct(); photonCand=(ProtoClusterFactory::Instance())->Clone(seedProtoClusters[i]); usedCluster = true; } _photonClusters.push_back(photonCand); for(int ihit = 0;ihitHits();ihit++){ MyCaloHitExtended* hiti = photonCand->Hit(ihit); _hitsForRemoval.push_back(hiti); } this->removeAssociatedHits(); }else{ photonCand->IsNowDefunct(); } //********** code to make the likelihood histograms ************ if(_makingPhotonIDLikelihoodHistograms){ int ihist = -999; if( peaks[ipeak].energy> 0.2 && peaks[ipeak].energy <= 0.5)ihist=0; if( peaks[ipeak].energy> 0.5 && peaks[ipeak].energy <= 1.0)ihist=1; if( peaks[ipeak].energy> 1.0 && peaks[ipeak].energy <= 1.5)ihist=2; if( peaks[ipeak].energy> 1.5 && peaks[ipeak].energy <= 2.5)ihist=3; if( peaks[ipeak].energy> 2.5 && peaks[ipeak].energy <= 5.0)ihist=4; if( peaks[ipeak].energy> 5.0 && peaks[ipeak].energy <= 10.0)ihist=5; if( peaks[ipeak].energy>10.0 && peaks[ipeak].energy <= 20.0)ihist=6; if( peaks[ipeak].energy>20.0 && peaks[ipeak].energy <= 50.0)ihist=7; if( peaks[ipeak].energy>50.0)ihist=8; if(ihist>=0 && gammaFraction<1.0 && showerStart<10. && peaks[ipeak].rms<5.){ if(fraction>0.5){ sighistrms[ihist]->Fill(peaks[ipeak].rms); sighistfrac[ihist]->Fill(gammaFraction); sighiststart[ihist]->Fill(showerStart); }else{ backhistrms[ihist]->Fill(peaks[ipeak].rms); backhistfrac[ihist]->Fill(gammaFraction); backhiststart[ihist]->Fill(showerStart); } } } } } } // clean up of seed clusters for(unsigned int i=0;iIsNowDefunct(); (ProtoClusterFactory::Instance())->ManageMemory(); // restore clustering algorithm settings (ProtoClusterFactory::Instance())->SetDesignToDefault(); return; } void PandoraPFAProcessor::FinalPhotonExtraction(ProtoClusterVec &protoClusters){ unsigned int nclusters = protoClusters.size(); for(unsigned int jcluster=0;jclusterGetTrackVec(); if(tracks.size()==1){ float clusterE = parentCluster->EnergyHAD(); float trackE = tracks[0]->getEnergy(); float sigE = trackE*_hadEnergyRes/sqrt(trackE); float deltaE = (clusterE-trackE); float chi = deltaE/sigE; if(chi>3.0){ std::vector peaks; parentCluster->TransverseProfile(peaks,_nEcalLayers); bool usedCluster = false; for(unsigned int ipeak=0;ipeakTransverseProfile(ipeak,_nEcalLayers,0); if(photonCand!=NULL){ photonCand=(ProtoClusterFactory::Instance())->CloneAndDelete(photonCand); photonCand->PhotonProfileID(); float showerStart = photonCand->GetLongProfileShowerStart(); float gammaFraction = photonCand->GetLongProfileGammaFraction(); float fraction = photonCand->TruePhotonContribution() / photonCand->EnergyEM(); float cclosest = 999.; float c10closest = 999.; float c20closest = 999.; float closest = photonCand->DistanceToTrack(tracks[0],10); cclosest = photonCand->CentroidDistanceToTrack(tracks[0]); if(cclosest>999)cclosest = 0.; c10closest = photonCand->Centroid10DistanceToTrack(tracks[0]); if(c10closest>999)c10closest =0.; c20closest = photonCand->Centroid20DistanceToTrack(tracks[0]); if(c20closest>999)c20closest =0.; float dist = min(c10closest,c20closest); float pid = (PhotonIDLikelihoodCalculator::Instance())->PID( peaks[ipeak].energy, peaks[ipeak].rms, gammaFraction,showerStart); bool accept = false; if(_printing>0 && peaks[ipeak].energy>1.0){ std::cout << " PEAK " << ipeak << " : " << peaks[ipeak].du << "," << peaks[ipeak].dv << " E = " << peaks[ipeak].energy << " dmin : " << peaks[ipeak].dmin << " d25/d90 : " << peaks[ipeak].showerDepth25 << "/" << peaks[ipeak].showerDepth90 << " start : " << peaks[ipeak].showerStartDepth << " rms = " << peaks[ipeak].rms << " PhotonID : " << showerStart << " " << gammaFraction << " TRUE FRACTION = " << fraction << " pid " << pid << " d = " << closest << " c= " << dist; if(fraction<0.5 && accept)std::cout << " <---A*****************"; if(fraction>0.5 && !accept) std::cout << " <---B*****************"; std::cout << std::endl; } } } } } } return; } void PandoraPFAProcessor::PerfectNeutralHadronClustering(){ if(_caloNavigator==NULL || _trackNavigator==NULL){ streamlog_out(ERROR) << " Can't perform PerfectNeutralHadronClustering" << std::endl; if(_caloNavigator==NULL)streamlog_out(ERROR) << " : no calorimeter hit navigator" << std::endl; if(_trackNavigator==NULL)streamlog_out(ERROR) << " :no track navigator" << std::endl; return; } std::vector mcPFOs = *(_myMcTree->getMCPFOs()); ProtoCluster* protoClusters[mcPFOs.size()]; for(unsigned int i =0;igetTrack(); LCObjectVec objectVec = _trackNavigator->getRelatedToObjects(track); if (objectVec.size() > 0){ bool bs = false; MCParticle* part = dynamic_cast(objectVec[0]); if(part->isBackscatter()){ if(_printing>0)std::cout << " MC BACKSCATTER FLAG : " << _tracksAR[it]->getEnergy() << std::endl; if( _tracksAR[it]->getEnergy()<2.0)bs = true; } if(!bs){ unsigned int jmc = _myMcTree->GetMCPFOIndex(part); if(jmc>=0&&jmc(hiti->getCalorimeterHit()); // use navigator to match hit to simhit LCObjectVec objectVec = _caloNavigator->getRelatedToObjects(calhit); int ibestmc = 0; if (objectVec.size() > 0) { SimCalorimeterHit * simhit = dynamic_cast(objectVec[0]); float emax = 0; if (simhit->getNMCContributions() > 1){ // find largest contributor to hit for(int i=0;igetNMCContributions();i++){ if(simhit->getEnergyCont(i)>emax){ emax = simhit->getEnergyCont(i); ibestmc = i; } } } if (simhit->getNMCContributions() > 0) { int iuse = ibestmc; MCParticle * part = simhit->getParticleCont(iuse); // use myMcTree to match hit to perfect particle flow object unsigned int jmc = _myMcTree->GetMCPFOIndex(part); if(jmc>=0 && jmcgetPDG(); if( ( abs(IDPart)==2112 || abs(IDPart)==130 ) && nTracks[jmc]==0){ // add it to the appropriate protocluster _hitsForRemoval.push_back(hiti); if(protoClusters[jmc]==NULL){ protoClusters[jmc] = (ProtoClusterFactory::Instance())->Manufacture(hiti); }else{ protoClusters[jmc]->AddHit(hiti); } } } } } } } // now remove the hits from the list to be clustered this->removeAssociatedHits(); // save the pointers to the created clusters for(unsigned int i =0;i mcPFOs = *(_myMcTree->getMCPFOs()); unsigned int nTracks[mcPFOs.size()]; MyTrackExtended* mcExtendedTracks[mcPFOs.size()][10]; for(unsigned int i =0;igetTrack(); LCObjectVec objectVec = _trackNavigator->getRelatedToObjects(track); if (objectVec.size() > 0){ bool bs = false; MCParticle* part = dynamic_cast(objectVec[0]); if(part->isBackscatter()){ if(_printing>0)std::cout << " MC BACKSCATTER FLAG : " << _tracksAR[it]->getEnergy() << std::endl; if( _tracksAR[it]->getEnergy()<2.0)bs = true; } if(!bs){ unsigned int jmc = _myMcTree->GetMCPFOIndex(part); if(jmc>=0&&jmcEnergyHAD()>1.0 && !pCi->IsDefunct() )std::cout << "Checking : " << pCi->EnergyHAD() << std::endl; if(!pCi->AssociatedTrack() && !pCi->IsDefunct()){ float mcConts[mcPFOs.size()]; for(unsigned int imc=0;imcEnergyHAD(); int nhits = pCi->Hits(); for(int ihit=0;ihitHit(ihit); CalorimeterHit* calhit = const_cast(hiti->getCalorimeterHit()); // use navigator to match hit to simhit LCObjectVec objectVec = _caloNavigator->getRelatedToObjects(calhit); int ibestmc = 0; if (objectVec.size() > 0) { SimCalorimeterHit * simhit = dynamic_cast(objectVec[0]); float emax = 0; if (simhit->getNMCContributions() > 1){ // find largest contributor to hit for(int i=0;igetNMCContributions();i++){ if(simhit->getEnergyCont(i)>emax){ emax = simhit->getEnergyCont(i); ibestmc = i; } } } if (simhit->getNMCContributions() > 0) { int iuse = ibestmc; MCParticle * part = simhit->getParticleCont(iuse); // use myMcTree to match hit to perfect particle flow object unsigned int jmc = _myMcTree->GetMCPFOIndex(part); if(jmc>=0 && jmcgetEnergyHAD(); } } } } float etot = 0.; float emax = 0.; float efrag = 0.; int ibest = -999; for(unsigned int imc = 0;imc0)efrag+=mcConts[imc]; if(mcConts[imc]>emax){ emax = mcConts[imc]; ibest = imc; } } if(pCi->EnergyHAD()>1.0)std::cout << " best mc : " << emax << "(" << efrag << ") from " << etot << std::endl; if(pCi->EnergyHAD()>1.0 && ibest>=0)std::cout << " best trachs : " << nTracks[ibest] << std::endl; // for now only consider single track perfect PFOs bool foundFragment = false; if(ibest>=0 && etot > 0 && nTracks[ibest]==1 && emax/etot > 0.5)foundFragment = true; if(_perfectFragmentRemoval>1 && ibest>=0 && etot > 0 && nTracks[ibest]==1 && efrag/etot > 0.5)foundFragment = true; if(foundFragment){ // find cluster associated with track ProtoCluster* pCj = NULL; for(unsigned int it=0;itgetClusterVec(); if(clusters.size()>0 && goodTrack){ if(pCi->EnergyHAD()>1.0)std::cout << " FRAGMENT MATCH Eclust : " << E << " best match " << ibest << " " << emax << " / " << etot << " Ntracks : " << nTracks[ibest] << " Track : " << trackAR->getEnergy() <getInnerR(); float chinew = this->ChiClusterTrack(trackAR, pCi->EnergyHAD()); if(pCi->EnergyHAD()>1.0)std::cout << " chi : " << chinew << " Rin " << Rin << std::endl; if(Rin<_tpcInnerR || chinew < 5.0 ){ pCj=clusters[0]; }else{ if(pCi->EnergyHAD()>1.0)std::cout << " VETO: " << std::endl; } } } } if(pCj!=NULL){ if(pCi->EnergyHAD()>1.0)std::cout << " Removing Fragment : " << E << std::endl; pCj->Assimilate(pCi); // Update the properties of the parent pCj->Update(MAX_NUMBER_OF_LAYERS); pCj->ClassifyYourself(); // remove old cluster pCi->IsNowDefunct(); } } } } return; } void PandoraPFAProcessor::associateProtoClusters(ProtoClusterVec &input, MyTrackExtendedVec &tracks, ProtoClusterVec &final, bool firstPass){ // Have initial clustering // Use topological rules to join clusters together // In many ways this is the guts of the algorithm and hides a lot of complexity if(_recoDisplay!=NULL && firstPass && _showProtoClusterAssociation>0)_recoDisplay->DrawByProtoCluster(input,3); // First look for looping tracks (end<->end matching) if(_printing>2)std::cout << "Find and associated looping tracks" << std::endl; if(_associateLoopingTracks>0)this->associateLoopingTracks(input,0); // Look for associated track segements (end<->start matching) if(_printing>2)std::cout << "Match clusters using track segments" << std::endl; if(_associateTrackSegments>0)this->associateTrackSegments(input); // Look for associated track segements (mip end<-> shower start matching) if(_printing>2)std::cout << "Associate showers to mips" << std::endl; if(_associateShowersToMips>0)this->associateShowersToMips(input); if(_associateShowersToMipsII>0)this->associateShowersToMipsII(input); if(_recoDisplay!=NULL && firstPass && _showProtoClusterAssociation>0)_recoDisplay->DrawByProtoCluster(input,3); if(_printing>2)std::cout << "Associate back scatters" << std::endl; if(_associateBackScatters>0)this->associateBackScatters(input); if(_recoDisplay!=NULL && firstPass && _showProtoClusterAssociation>0)_recoDisplay->DrawByProtoCluster(input,3); if(_printing>2)std::cout << "Associate mip stubs" << std::endl; if(_associateMipStubsToShowers>0)this->associateMipStubsToShowers(input); if(_recoDisplay!=NULL && firstPass && _showProtoClusterAssociation>0)_recoDisplay->DrawByProtoCluster(input,3); if(_printing>2)std::cout << "Associate from Start" << std::endl; if(_associateFromStart>0)this->associateFromStart(input); if(_recoDisplay!=NULL && firstPass && _showProtoClusterAssociation>0)_recoDisplay->DrawByProtoCluster(input,3); // now use the cruder methods ProtoClusterVec _joinedProtoClusters; this->combineProtoClusters(input,_joinedProtoClusters); if(_printing>2)std::cout << "Associate clusters by proximity" << std::endl; //if(_recoDisplay!=NULL && firstPass && _showProtoClusterAssociation>0)_recoDisplay->DrawByProtoCluster(_joinedProtoClusters,3); //std::cout << " NOT RUNNING this->associateByProximity " << std::endl; if(_associateByProximity>0)this->associateByProximity(_joinedProtoClusters); if(_recoDisplay!=NULL && firstPass && _showProtoClusterAssociation>0)_recoDisplay->DrawByProtoCluster(_joinedProtoClusters,3); ProtoClusterVec _newJoinedProtoClusters; this->combineProtoClusters(_joinedProtoClusters,_newJoinedProtoClusters); if(_printing>2)std::cout << "Associate by shower cone" << std::endl; if(_associateByShowerCone>0)this->associateByShowerCone(_newJoinedProtoClusters); if(_recoDisplay!=NULL && firstPass && _showProtoClusterAssociation>0)_recoDisplay->DrawByProtoCluster(_newJoinedProtoClusters,3); ProtoClusterVec _combinedProtoClusters; if(_printing>2)std::cout << "Combined Clusters" << std::endl; this->combineProtoClusters(_newJoinedProtoClusters,_combinedProtoClusters); // _recoDisplay->DrawByProtoCluster(_combinedProtoClusters,3); if(_allowPhotonFragmentation==1)this->findPhotonsMergedWithMips(_combinedProtoClusters); if(_printing>2)std::cout << "Assoc soft" << std::endl; if(_associateSoftClusters>0)this->associateSoftClusters(_combinedProtoClusters,firstPass); this->associateIsolatedHits(_combinedProtoClusters,firstPass); //_recoDisplay->DrawByProtoCluster(_combinedProtoClusters,3); ProtoClusterVec _nearFinalProtoClusters; this->makeFinalProtoClusters(_combinedProtoClusters,_nearFinalProtoClusters); // force clean up of defunt clusters // force clean up of defunct clusters if(firstPass)(ProtoClusterFactory::Instance())->ManageMemory(); if(_associateLoopingTracks>1)this->associateLoopingTracks(_nearFinalProtoClusters,1); // the following methods split/merge clusters using tracking information // not used in reclustering if(firstPass && _allowReclustering>0){ this->SplitMultipleTrackAssociations(_nearFinalProtoClusters,tracks,false); for(unsigned int i=0;i<_nearFinalProtoClusters.size();++i){ if(_nearFinalProtoClusters[i]->GetTemporaryReclusteringFlag())streamlog_out(WARNING) << " E BAD RECLUSTER FLAG in temp cluster memory management " << std::endl; } // use tracking information to split if(_photonRecovery>=2)this->PhotonRecovery(_nearFinalProtoClusters,tracks,false ); this->trackDrivenSplitMergedClusters(_nearFinalProtoClusters); (ProtoClusterFactory::Instance())->ManageMemoryDuringReclustering(); for(unsigned int i=0;i<_nearFinalProtoClusters.size();++i){ if(_nearFinalProtoClusters[i]->GetTemporaryReclusteringFlag())streamlog_out(WARNING) << " A BAD RECLUSTER FLAG in temp cluster memory management" << std::endl; } this->trackDrivenAssociation(_nearFinalProtoClusters,0); (ProtoClusterFactory::Instance())->ManageMemoryDuringReclustering(); for(unsigned int i=0;i<_nearFinalProtoClusters.size();++i){ if(_nearFinalProtoClusters[i]->GetTemporaryReclusteringFlag())streamlog_out(WARNING) << " B BAD RECLUSTER FLAG in temp cluster memory management" << std::endl; } this->ResolveTwoTrackAssociations(_nearFinalProtoClusters,tracks,false); // do it again - for(unsigned int i=0;i<_nearFinalProtoClusters.size();++i){ if(_nearFinalProtoClusters[i]->GetTemporaryReclusteringFlag())streamlog_out(WARNING) << " BC BAD RECLUSTER FLAG in temp cluster memory management" << std::endl; } this->trackDrivenAssociation(_nearFinalProtoClusters,1); (ProtoClusterFactory::Instance())->ManageMemoryDuringReclustering(); for(unsigned int i=0;i<_nearFinalProtoClusters.size();++i){ if(_nearFinalProtoClusters[i]->GetTemporaryReclusteringFlag())streamlog_out(WARNING) << " C BAD RECLUSTER FLAG in temp cluster memory management " << std::endl; } this->NewResolveSingleTrackAssociations(_nearFinalProtoClusters,tracks,false); for(unsigned int i=0;i<_nearFinalProtoClusters.size();++i){ if(_nearFinalProtoClusters[i]->GetTemporaryReclusteringFlag())streamlog_out(WARNING) << " D BAD RECLUSTER FLAG in temp cluster memory management " << std::endl; } this->NewResolveTwoTrackAssociations(_nearFinalProtoClusters,tracks,false); for(unsigned int i=0;i<_nearFinalProtoClusters.size();++i){ if(_nearFinalProtoClusters[i]->GetTemporaryReclusteringFlag())streamlog_out(WARNING) << " E BAD RECLUSTER FLAG in temp cluster memory management " << std::endl; } this->NewResolveThreeTrackAssociations(_nearFinalProtoClusters,tracks,false); (ProtoClusterFactory::Instance())->ManageMemoryDuringReclustering(); for(unsigned int i=0;i<_nearFinalProtoClusters.size();++i){ if(_nearFinalProtoClusters[i]->GetTemporaryReclusteringFlag())streamlog_out(WARNING) << " F BAD RECLUSTER FLAG in temp cluster memory management " << std::endl; } this->NewTrackDrivenAssociation(_nearFinalProtoClusters,tracks,false); (ProtoClusterFactory::Instance())->ManageMemoryDuringReclustering(); //this->NewMergedPhotonSearch(_nearFinalProtoClusters,tracks,false ); // force clean up of defunct clusters for(unsigned int i=0;i<_nearFinalProtoClusters.size();++i){ if(_nearFinalProtoClusters[i]->GetTemporaryReclusteringFlag())streamlog_out(WARNING) << " G BAD RECLUSTER FLAG in temp cluster memory management " << std::endl; } if(_photonRecovery==1||_photonRecovery>2)this->PhotonRecovery(_nearFinalProtoClusters,tracks,false ); for(unsigned int i=0;i<_nearFinalProtoClusters.size();++i){ if(_nearFinalProtoClusters[i]->GetTemporaryReclusteringFlag())streamlog_out(WARNING) << " BAD RECLUSTER FLAG in temp cluster memory management " << std::endl; } if(_photonRecovery>0)this->ClusterRecoveryFromMips(_nearFinalProtoClusters,tracks,false ); } if(_printing>2)std::cout << "Get ready to combine" << std::endl; if(_recoDisplay!=NULL && firstPass && _showProtoClusterAssociation>0)_recoDisplay->DrawByProtoCluster(_nearFinalProtoClusters,3); this->combineProtoClusters(_nearFinalProtoClusters,final); if(_printing>2)std::cout << "combined pcs" << final.size() << std::endl; if(_recoDisplay!=NULL && firstPass && _showProtoClusterAssociation>0)_recoDisplay->DrawByProtoCluster(final,3); // force clean up of defunct clusters if(firstPass)(ProtoClusterFactory::Instance())->ManageMemory(); if(_printing>2)std::cout << "cleaned" << final.size() << std::endl; if(_recoDisplay!=NULL && firstPass && _showProtoClusterAssociation>0)_recoDisplay->DrawByProtoCluster(final,3); if(_printing>2)std::cout << "Soft photonID" << final.size() << std::endl; // Soft Photon ID for(unsigned int icluster=0;iclusterSoftPhotonID(); } if(_printing>2)std::cout << "done" << final.size() << std::endl; if(_recoDisplay!=NULL && firstPass && _showProtoClusterAssociation>0)_recoDisplay->DrawByProtoCluster(final,3); if(_printing>2)std::cout << "DDDdone" << final.size() << std::endl; } void PandoraPFAProcessor::mergeSplitPhotons(ProtoClusterVec &pCs){ if(_printing>1)std::cout << " MERGE SPLIT PHOTONS " << pCs.size() << std::endl; int n = static_cast(pCs.size()); for(int icluster=0;iclusterIsPhoton(); int iFirstLayer = pCs[icluster]->FirstLayer(); int iShowerMax = pCs[icluster]->getLayerMax(); float xi = pCs[icluster]->GetCentroid(iShowerMax)[0]; float yi = pCs[icluster]->GetCentroid(iShowerMax)[1]; float zi = pCs[icluster]->GetCentroid(iShowerMax)[2]; float ri = sqrt(xi*xi+yi*yi+zi*zi); if(iFirstLayer<_nEcalLayers && pCs[icluster]->AssociatedTrack()==false && pCs[icluster]->IsDefunct()==false){ for(unsigned int jcluster=icluster+1;jclusterIsPhoton(); int jFirstLayer = pCs[jcluster]->FirstLayer(); int jShowerMax = pCs[jcluster]->getLayerMax(); if(jFirstLayer<_nEcalLayers && pCs[jcluster]->AssociatedTrack()==false&& pCs[jcluster]->IsDefunct()==false){ if(jPhotonID||iPhotonID){ float xj = pCs[jcluster]->GetCentroid(jShowerMax)[0]; float yj = pCs[jcluster]->GetCentroid(jShowerMax)[1]; float zj = pCs[jcluster]->GetCentroid(jShowerMax)[2]; float rj = sqrt(xj*xj+yj*yj+zj*zj); double dcos = 0.; if(ri>0&&rj>0)dcos = (xi*xj+yi*yj+zi*zj)/ri/rj; if(dcos>0.99999999)dcos=0.99999999; if(dcos>0.98){ double theta2 = 2.0*(1.0-dcos); float theta = sqrt(theta2); float padSize = _padSizeEcal[1]; float thetacut = (4.0*padSize)/ri; clusterContact_t contact = pCs[icluster]->ContactLayers(pCs[jcluster],_fragmentRemovalContactCut); bool merge = false; if(theta2 && contact.contactFraction>0.5)merge=true; if(merge){ ProtoCluster* mergedCluster = (ProtoClusterFactory::Instance())->Merge(pCs[icluster],pCs[jcluster]); std::vector peaks; mergedCluster->TransverseProfile(peaks,_nEcalLayers); float peake = 0.; if(peaks.size()>1)peake = peaks[1].energy; if(_printing>1){ std::cout << " Energy : " << pCs[icluster]->EnergyEM() << " - " << pCs[jcluster]->EnergyEM() << std::endl; std::cout << " Contact/Angles " << contact.contactLayers << " f = " << contact.contactFraction << " angles : " << theta << " < " << thetacut << " ?" << std::endl; } float ei = pCs[icluster]->EnergyEM(); float ej = pCs[jcluster]->EnergyEM(); float emin=ei; float emax=ej; int imin = icluster; int imax = jcluster; if(ej0.5){ if(emin<0.2)mergeThem = true; if(emin/emax<0.05 && peake<0.5)mergeThem = true; } if(mergeThem){ if(_printing>1)std::cout << " WILL MERGE " << peake << std::endl; if(_mergeSoftPhotons!=0 && emin<_softPhotonEnergyForMerging){ if(_printing>1)std::cout << " MERGE SOFT !!!!! " << mergedCluster->EnergyEM() << std::endl; pCs[icluster]->IsNowDefunct(); pCs[jcluster]->IsNowDefunct(); pCs[icluster] = mergedCluster; } if(_mergeHardPhotons!=0 && emin>_softPhotonEnergyForMerging){ mergedCluster->PhotonProfileID(); float showerStart = mergedCluster->GetLongProfileShowerStart(); float gammaFraction = mergedCluster->GetLongProfileGammaFraction(); if(_printing>1)std::cout << " L Progfile : " << showerStart << " f = " << gammaFraction << std::endl; if(_printing>1)std::cout << " Cluster RMS : " << mergedCluster->ClusterRMS() << std::endl; std::vector earlyPeaks; mergedCluster->TransverseProfile(earlyPeaks,20); float peakee = 0.; if(earlyPeaks.size()>1)peakee = earlyPeaks[1].energy; if(_printing>1)std::cout << " Early Peaks : " << peakee << std::endl; if(peakee>0.5){ _mergeHardPhotons=false; if(_printing>1)std::cout << " VETO MERGE" << std::endl; } } if(_mergeHardPhotons!=0 && emin>_softPhotonEnergyForMerging){ //if(_recoDisplay!=NULL)_recoDisplay->DrawSingleProtoCluster(mergedCluster,RECO_VIEW_XY); //if(_recoDisplay!=NULL){ // _recoDisplay->DrawTransverseProfile(mergedCluster,40); //} if(_printing>1)std::cout << " MERGE HARD !!!!! " << mergedCluster->EnergyEM() << std::endl; pCs[icluster]->IsNowDefunct(); pCs[jcluster]->IsNowDefunct(); pCs[icluster] = mergedCluster; } } } } } } } } } if(_printing>1)std::cout << " DONE " << std::endl; } void PandoraPFAProcessor::mergeSplitPhotons2(ProtoClusterVec &pCs){ if(_printing>1)std::cout << " MERGE SPLIT PHOTONS 2 " << pCs.size() << std::endl; int n = static_cast(pCs.size()); for(int icluster=0;iclusterIsPhoton(); int iFirstLayer = pCi->FirstLayer(); int iShowerMax = pCi->getLayerMax(); float xi = pCi->GetCentroid(iShowerMax)[0]; float yi = pCi->GetCentroid(iShowerMax)[1]; float zi = pCi->GetCentroid(iShowerMax)[2]; float ri = sqrt(xi*xi+yi*yi+zi*zi); if(iPhotonID && iFirstLayer<_nEcalLayers && pCi->AssociatedTrack()==false && pCi->IsDefunct()==false){ for(unsigned int jcluster=0;jcluster<_photonClusters.size();++jcluster){ ProtoCluster* pCj = _photonClusters[jcluster]; int jShowerMax = pCj->getLayerMax(); float xj = pCj->GetCentroid(jShowerMax)[0]; float yj = pCj->GetCentroid(jShowerMax)[1]; float zj = pCj->GetCentroid(jShowerMax)[2]; float rj = sqrt(xj*xj+yj*yj+zj*zj); double dcos = 0.; if(ri>0&&rj>0)dcos = (xi*xj+yi*yj+zi*zj)/ri/rj; if(dcos>0.99999999)dcos=0.99999999; if(dcos>0.98){ double theta2 = 2.0*(1.0-dcos); float theta = sqrt(theta2); float padSize = _padSizeEcal[1]; float thetacut = (4.0*padSize)/ri; clusterContact_t contact = pCi->ContactLayers(pCj,_fragmentRemovalContactCut); bool merge = false; if(theta2 && contact.contactFraction>0.5)merge=true; if(merge){ // see what merged cluster looks like ProtoCluster* mergedCluster = (ProtoClusterFactory::Instance())->Merge(pCi,pCj); std::vector peaks; mergedCluster->TransverseProfile(peaks,_nEcalLayers); float peake = 0.; if(peaks.size()>1)peake = peaks[1].energy; if(_printing>1){ std::cout << " Energy : " << pCi->EnergyEM() << " - " << pCj->EnergyEM() << std::endl; std::cout << " Contact/Angles " << contact.contactLayers << " f = " << contact.contactFraction << " angles : " << theta << " < " << thetacut << " ?" << std::endl; } float ei = pCi->EnergyEM(); float ej = pCj->EnergyEM(); float emin=ei; float emax=ej; if(ej0.5){ if(emin<0.2)mergeThem = true; if(emin/emax<0.05 && peake<0.5)mergeThem = true; } if(mergeThem){ if(_printing>1)std::cout << " WILL MERGE " << peake << std::endl; if(_mergeSoftPhotons!=0 && emin<_softPhotonEnergyForMerging){ if(_printing>1)std::cout << " MERGE SOFT !!!!! " << mergedCluster->EnergyEM() << std::endl; pCj->Assimilate(pCi); pCi->IsNowDefunct(); } if(_mergeHardPhotons!=0 && emin>_softPhotonEnergyForMerging){ mergedCluster->PhotonProfileID(); float showerStart = mergedCluster->GetLongProfileShowerStart(); float gammaFraction = mergedCluster->GetLongProfileGammaFraction(); if(_printing>1)std::cout << " L Progfile : " << showerStart << " f = " << gammaFraction << std::endl; if(_printing>1)std::cout << " Cluster RMS : " << mergedCluster->ClusterRMS() << std::endl; std::vector earlyPeaks; mergedCluster->TransverseProfile(earlyPeaks,20); float peakee = 0.; if(earlyPeaks.size()>1)peakee = earlyPeaks[1].energy; if(_printing>1)std::cout << " Early Peaks : " << peakee << std::endl; if(peakee>0.5){ _mergeHardPhotons=false; if(_printing>1)std::cout << " VETO MERGE" << std::endl; } } if(_mergeHardPhotons!=0 && emin>_softPhotonEnergyForMerging){ //if(_recoDisplay!=NULL)_recoDisplay->DrawSingleProtoCluster(mergedCluster,RECO_VIEW_XY); //if(_recoDisplay!=NULL){ // _recoDisplay->DrawTransverseProfile(mergedCluster,40); //} if(_printing>1)std::cout << " MERGE HARD !!!!! " << pCj->EnergyEM() << " - " << pCi->EnergyEM() << std::endl; pCj->Assimilate(pCi); pCi->IsNowDefunct(); } } } } } } } if(_printing>1)std::cout << " DONE " << std::endl; } void PandoraPFAProcessor::findPhotonsIDedAsHadrons(ProtoClusterVec & pCs){ if(_printing>1)std::cout << " FIND PHOTONS IDed AS HADRONS " << std::endl; for(unsigned int icluster=0;iclusterAssociatedTrack()==false){ bool photonID = pCs[icluster]->IsPhoton(); if(!photonID){ bool photon = false; float E = pCs[icluster]->EnergyEM(); if(E>1.5 && pCs[icluster]->getLayer90()<_nEcalLayers+5 && pCs[icluster]->FirstLayer()<_nEcalLayers/2){ pCs[icluster]->PhotonProfileID(); float showerStart = pCs[icluster]->GetLongProfileShowerStart(); float gammaFraction = pCs[icluster]->GetLongProfileGammaFraction(); float X0Cut = 4.1; float fractCut = 0.4; if(E>2.5)fractCut = 0.5 - 0.02*showerStart; if(E>5.0)X0Cut = 5.1; if(pCs[icluster]->getLayer90()>_nEcalLayers)X0Cut = 2.0; if(showerStart0.)photon=true; if(gammaFraction>0&&gammaFraction<0.5&&showerStart<2.75)photon = true; // check barrel-endcap overlap if(!photon){ if(pCs[icluster]->BarrelEncapEnergySplit()<0.9){ if( pCs[icluster]->FirstLayer() < 10 && pCs[icluster]->MipFraction() < 0.5&& pCs[icluster]->DCosR() > 0.90)photon = true; } } if(photon){ pCs[icluster]->TagFixedPhoton(); //if(_recoDisplay!=NULL)_recoDisplay->DrawLongitudinalProfile(pCs[icluster]); if(_printing>1)std::cout << " Reclassify hadron as photon " << E << " " << showerStart << " " << gammaFraction << std::endl; if(_printing>1)std::cout << " NEW PHOTON 90 % : " << pCs[icluster]->getLayer90() << std::endl; } } } } } if(_printing>1)std::cout << " DONE FINDING PHOTONS IDed AS HADRONS " << std::endl; } void PandoraPFAProcessor::fragmentRemoval(ProtoClusterVec &protoClusters, MyTrackExtendedVec &extendedTracks, ProtoClusterVec &outputProtoClusters){ // have finished clustering // Look in detail at all hadron clusters and decide // Merge dubious looking clusters this->ClusterTrackAssociation(protoClusters,extendedTracks,false); if(_printing>1){ std::cout << " FRAGMENT REMOVAL *****************" << std::endl; } // The first criterion considered is "contact" // Contact is defined as the number of layers in which a hadron cluster // is in contact (has hits close to) another cluster unsigned int nclusters = protoClusters.size(); for(unsigned int icluster=0;iclusterGetTrackVec(); float chi2best = 9999.; float chibest = 9999.; ProtoCluster* bestParent = NULL; if(tracks.size()==0 && !pCluster->IsPrimaryPhoton()){ float clusterE = pCluster->EnergyHAD(); float contactEnergy = 0.; float contactClusterEnergy = 0.; float contactTrackEnergy = 0.; ProtoClusterVec contacts; int totalContact = 0; for(unsigned int jcluster=0;jclusterGetTrackVec(); if(icluster!=jcluster && xtracks.size()!=0){ float nearTrackE = 0.; float nearClusterE = protoClusters[jcluster]->EnergyHAD(); float fraction = protoClusters[jcluster]->FractionInRadialCone(pCluster,0.90); for(unsigned int it=0;itgetEnergy(); float fractiont = pCluster->FractionInTrackCone(xtracks[it],0.90); if(fractiont>fraction)fraction=fractiont; } clusterContact_t contact = protoClusters[jcluster]->ContactLayers(pCluster,_fragmentRemovalContactCut); float sigE = _hadEnergyRes*sqrt(nearTrackE); float chio = (nearTrackE-nearClusterE)/sigE; float chin = (nearTrackE-nearClusterE-clusterE)/sigE; float chi2o = chio*chio; float chi2n = chin*chin; if(contact.contactLayers>5 || (contact.contactLayers>2 && chio>-1.)){ totalContact+=contact.contactLayers; contactEnergy+= nearTrackE-nearClusterE; contactTrackEnergy+=nearTrackE; contactClusterEnergy+=nearClusterE; contacts.push_back(protoClusters[jcluster]); if(_printing>1)std::cout << " Contact : " << contact.contactLayers << " " << nearTrackE << " " << nearClusterE << std::endl; } if(contact.contactLayers>_fragmentRemovalContactLayersCut){ if(fabs(chi2n)<_fragmentRemovalMaxChi2ForMerge){ if(_printing>1 && pCluster->FirstLayer()>_nEcalLayers-20){ std::cout << " Dodgy cluster " << contact.contactLayers << " : " << pCluster->EnergyHAD() << " : " << chi2o << " : " << chi2n << std::endl; ProtoClusterVec pCs; pCs.push_back(protoClusters[jcluster]); pCs.push_back(protoClusters[icluster]); //if(_recoDisplay!=NULL)_recoDisplay->DrawSingleProtoCluster(pCs,RECO_VIEW_XY); } int layersFromEdge=999; layersFromEdge = this->LayersFromEdge(protoClusters[jcluster]); bool leavingCluster = this->IsClusterLeavingDetector(protoClusters[jcluster]); if(_printing>1 && pCluster->FirstLayer()<=_nEcalLayers-20){ std::cout << " slightly dodgy cluster " << contact.contactLayers << " : " << pCluster->EnergyHAD() << " : " << chi2o << " : " << chi2n << std::endl; if(chio>_chiToAttemptReclustering && chi2n<4.0 && !leavingCluster){ if(_printing>1){ std::cout << "*****WILL REMOVE CLUSTER " << std::endl; std::cout << "layers from edge : " << layersFromEdge << std::endl; std::cout << "PhotonID : " << pCluster->IsPrimaryPhoton() << std::endl; } if(chi2nFirstLayer()>_nEcalLayers-10){ if(chi2n-chi2o<_fragmentRemovalDeltaChi2ForMerge){ if(_printing>1)std::cout << "WILL REMOVE CLUSTER " << std::endl; if(chi2nFirstLayer()-_nEcalLayers)<4){ if(_printing>1)std::cout << "XWILL REMOVE CLUSTER " << std::endl; if(chi2nFirstLayer()>_nEcalLayers){ if(chi2n<4.){ if(_printing>1)std::cout << "YWILL REMOVE CLUSTER " << std::endl; if(chi2n1)std::cout << "REMOVE CLUSTER " << pCluster->EnergyHAD() << std::endl; bool leavingClusteri = this->IsClusterLeavingDetector(pCluster); bool leavingClusterj = this->IsClusterLeavingDetector(bestParent); bool veto = false; if(leavingClusteri||leavingClusterj){ if(chibest<-1.5){ veto = true; if(_printing>1)std::cout<<" Vetoing match : " << chibest << std::endl; } } if(!veto){ // bestParent->Assimilate(pCluster); // pCluster->IsNowDefunct(); } } if(totalContact>10&&bestParent==NULL){ if(_printing>1 && totalContact>0)std::cout << " TOTAL CONTACT " << totalContact << " : " << pCluster->EnergyHAD() << " : " << contactClusterEnergy << " tt : " << contactTrackEnergy << std::endl; // float sigEo = 0.6*sqrt(contactTrackEnergy); // float chio = (contactTrackEnergy-contactClusterEnergy)/sigEo; float de = contactClusterEnergy+pCluster->EnergyHAD()-contactTrackEnergy; float sigE = _hadEnergyRes*sqrt(contactTrackEnergy); float chi = de/sigE; if(_printing>1)std::cout << " CONTACT CHI : " << chi << " " << pCluster->FirstLayer() << std::endl; bool remove = false; if(chi<3 && pCluster->FirstLayer()>20)remove = true; // if(chio>_chiToAttemptReclustering && chi*chi<4.0)remove = true; if(remove){ if(_printing>1)std::cout << "XREMOVE CLUSTER BASED ON CONTACT " << pCluster->EnergyHAD() << std::endl; if(1==2){ int lastlayer = pCluster->LastLayer(); for(int ilayer=1;ilayer<=lastlayer;++ilayer){ int nhits = pCluster->hitsInLayer(ilayer); for(int ihit=0;ihithitInLayer(ilayer,ihit); for(unsigned int icandCluster =0;icandClusterDistanceToHit(hiti); if(dAddHit(hiti); } } // pCluster->IsNowDefunct(); } } } } } // Cone // Look at fraction of cluster within the shower cone of another cluster for(unsigned int icluster=0;iclusterGetTrackVec(); float chi2best = 9999.; ProtoCluster* bestParent = NULL; if(tracks.size()==0 && !pCluster->IsPrimaryPhoton()){ float clusterE = pCluster->EnergyHAD(); for(unsigned int jcluster=0;jclusterGetTrackVec(); if(icluster!=jcluster && xtracks.size()!=0){ float nearTrackE = 0.; float nearClusterE = protoClusters[jcluster]->EnergyHAD(); float fraction = protoClusters[jcluster]->FractionInRadialCone(pCluster,0.90); float fractiont = 0.; for(unsigned int it=0;itgetEnergy(); fractiont = pCluster->FractionInTrackCone(xtracks[it],0.90); if(fractiont>fraction)fraction=fractiont; } clusterContact_t contact = protoClusters[jcluster]->ContactLayers(pCluster,_fragmentRemovalContactCut*2); float sigE = _hadEnergyRes*sqrt(nearTrackE); float chi2o = (nearTrackE-nearClusterE)/sigE; float chi2n = (nearTrackE-nearClusterE-clusterE)/sigE; chi2o = chi2o*chi2o; chi2n = chi2n*chi2n; if(fraction>0.75 && contact.contactLayers>0){ if(fabs(chi2n)<_fragmentRemovalMaxChi2ForMerge){ if(_printing>1 && pCluster->FirstLayer()>_nEcalLayers-20)std::cout << " CONE : Dodgy cluster " << contact.contactLayers << " : " << pCluster->EnergyHAD() << " : " << chi2o << " : " << chi2n << std::endl; if(_printing>1)std::cout << " Fractions : " << fraction << " " << fractiont << std::endl; //if(_printing>1 && pCluster->FirstLayer()<=_nEcalLayers-20)std::cout << " CONE : slightly dodgy cluster " << contact.contactLayers << " : " << pCluster->EnergyHAD() << " : " << chi2o << " : " << chi2n << std::endl; if(pCluster->FirstLayer()>_nEcalLayers-20){ if(chi2n-chi2o<_fragmentRemovalDeltaChi2ForMerge){ if(_printing>1)std::cout << "CONE : WILL REMOVE CLUSTER " << std::endl; if(chi2nFirstLayer()-_nEcalLayers)<4){ if(_printing>1)std::cout << "CONE XWILL REMOVE CLUSTER " << std::endl; if(chi2nFirstLayer()>_nEcalLayers){ if(chi2n<4.){ if(_printing>1)std::cout << "CONE YWILL REMOVE CLUSTER " << std::endl; if(chi2n1)std::cout << "CONE REMOVE CLUSTER " << pCluster->EnergyHAD() << std::endl; //if(_recoDisplay!=NULL){ // _recoDisplay->DrawTransverseProfile(parentCluster,30); //} //ProtoClusterVec pCs; //pCs.push_back(bestParent); //pCs.push_back(pCluster); //if(_recoDisplay!=NULL){ //_recoDisplay->DrawTransverseProfile(pCs,protoClusters[icluster]->FirstLayer()+10); //_recoDisplay->DrawByProtoCluster(pCs,5); //} // bestParent->Assimilate(pCluster); //pCluster->IsNowDefunct(); } } } // Angular separation // Look at angular separation to nearest cluster // look at a) fit to first layers // b) peak position for(unsigned int icluster=0;iclusterGetTrackVec(); float chi2best = 9999.; ProtoCluster* bestParent = NULL; float u0[3]; if(tracks.size()==0 && !pCluster->IsPrimaryPhoton()){ float clusterE = pCluster->EnergyHAD(); fitResult f = pCluster->FitAllHits(); if(f.ok){ u0[0] = f.dir[0]; u0[1] = f.dir[1]; u0[2] = f.dir[2]; } for(unsigned int jcluster=0;jclusterGetTrackVec(); if(icluster!=jcluster && xtracks.size()==1){ float up[3]; up[0] = xtracks[0]->getSeedPosition()[0]; up[1] = xtracks[0]->getSeedPosition()[1]; up[2] = xtracks[0]->getSeedPosition()[2]; float rp = sqrt(up[0]*up[0]+up[1]*up[1]+up[2]*up[2]); up[0] = up[0]/rp; up[1] = up[1]/rp; up[2] = up[2]/rp; float nearTrackE = 0.; float nearClusterE = protoClusters[jcluster]->EnergyHAD(); float fraction = protoClusters[jcluster]->FractionInRadialCone(pCluster,0.9); for(unsigned int it=0;itgetEnergy(); float fractiont = pCluster->FractionInTrackCone(xtracks[it],0.9); if(fractiont>fraction)fraction=fractiont; } clusterContact_t contact = protoClusters[jcluster]->ContactLayers(pCluster,_fragmentRemovalContactCut*2); float sigE = _hadEnergyRes*sqrt(nearTrackE); float chi2o = (nearTrackE-nearClusterE)/sigE; float chi2n = (nearTrackE-nearClusterE-clusterE)/sigE; chi2o = chi2o*chi2o; chi2n = chi2n*chi2n; float dcos = 1.; if(f.ok)dcos = u0[0]*up[0]+u0[1]*up[1]+u0[2]*up[2]; if(dcos>0.98 && contact.contactLayers>0){ if(fabs(chi2n)<_fragmentRemovalMaxChi2ForMerge){ if(_printing>1 && pCluster->FirstLayer()>_nEcalLayers-20)std::cout << " ANGLE : Dodgy cluster " << dcos << " : " << contact.contactLayers << " : " << pCluster->EnergyHAD() << " : " << chi2o << " : " << chi2n << std::endl; //if(_printing>1 && pCluster->FirstLayer()<=_nEcalLayers-20)std::cout << " CONE : slightly dodgy cluster " << contact.contactLayers << " : " << pCluster->EnergyHAD() << " : " << chi2o << " : " << chi2n << std::endl; if(pCluster->FirstLayer()>_nEcalLayers-20+1000){ if(chi2n-chi2o<_fragmentRemovalDeltaChi2ForMerge){ if(_printing>1)std::cout << "ANGLE : WILL REMOVE CLUSTER " << std::endl; if(chi2nFirstLayer()-_nEcalLayers)<4){ if(_printing>1)std::cout << "ANGLE XWILL REMOVE CLUSTER " << std::endl; if(chi2nFirstLayer()>_nEcalLayers+1000){ if(chi2n<4.){ if(_printing>1)std::cout << "ANGLE YWILL REMOVE CLUSTER " << std::endl; if(chi2nEnergyHAD()>0.5 && pCluster->MipFraction()>0.8&&pCluster->FirstLayer()<5){ float uc[3]; float rc[3]; fitResult fiti = pCluster->FitStart(10); if(fiti.ok){ for(unsigned int i=0;i<3;i++){ uc[i] = -fiti.dir[i]; rc[i] = fiti.intercept[i]; } for(unsigned int itrack=0;itrackgetClusterVec(); if(clusters.size()>0){ float ut[3]; float rt[3]; for(unsigned int i=0;i<3;i++){ rt[i] = trackAR->getSeedPosition()[i]; ut[i] = trackAR->getSeedDirection()[i]; } float un[3]; un[0] = ut[1]*uc[2]-ut[2]*uc[1]; un[1] = ut[2]*uc[0]-ut[0]*uc[2]; un[2] = ut[0]*uc[1]-ut[1]*uc[0]; float a = sqrt(un[0]*un[0]+un[1]*un[1]+un[2]*un[2]); if(a>0){ float d = (rt[0]-rc[0])*un[0]/a+ + (rt[1]-rc[1])*un[1]/a+ + (rt[2]-rc[2])*un[2]/a; d = fabs(d); if(_printing>1)std::cout << " distance = " << d << " " << trackAR->getEnergy() << " " << pCluster->EnergyHAD() << std::endl; } } } } } } if(bestParent!=NULL){ if(_printing>1)std::cout << "CONE REMOVE CLUSTER " << pCluster -> EnergyHAD() << std::endl; //bestParent->Assimilate(pCluster); //pCluster->IsNowDefunct(); } } } this->makeFinalProtoClusters(protoClusters,outputProtoClusters); return; } void PandoraPFAProcessor::finalMipFragmentRemoval(ProtoClusterVec &protoClusters, MyTrackExtendedVec &extendedTracks){ // have finished clstering // have final track cluster matching // Look in detail at all hadronic clusters which would pass cuts if(_printing>1){ std::cout << " FINAL MIP FRAGMENT REMOVAL *****************" << std::endl; } vectorendFitResults; vectorstartFitResults; vectorhelices; // fit ends of all ProtoClusters up front - save time for(unsigned int icluster=0;iclusterFitStart(10); startFitResults.push_back(fitS); fitResult fitE = protoClusters[icluster]->FitEnd(10); endFitResults.push_back(fitE); helices.push_back(NULL); } for(unsigned int icluster=0;iclusterAssociatedTrack()){ ProtoCluster* pCi = protoClusters[icluster]; float E = pCi->EnergyHAD(); int nhits = pCi->Hits(); if(!pCi->IsDefunct()&& !pCi->IsPhoton() && E>_minimumClusterEnergyEM&&nhits>=_minimumHitsInCluster){ float closest = 99999.; ProtoCluster* bestParent=NULL; float closestHelix = 99999.; // std::cout << " Ei = " << E << std::endl; for(unsigned int jcluster=0;jcluster < protoClusters.size();++jcluster){ ProtoCluster* pCj = protoClusters[jcluster]; MyTrackExtended* trackAR = NULL; MyTrackExtendedVec tracks = pCj->GetTrackVec(); if(tracks.size()==1){ trackAR = tracks[0]; if(!pCj->IsDefunct() && pCj->EnergyHAD()>0.5 && pCj->MipFraction()>0.5&&pCj->FirstLayer()<5 && endFitResults[jcluster].ok){ float dClosestApproachS =99999.; float dClosestApproachE =99999.; if(startFitResults[icluster].ok){ dClosestApproachS = this->closestApproach(startFitResults[icluster],endFitResults[jcluster]); } if(endFitResults[icluster].ok){ dClosestApproachE = this->closestApproach(endFitResults[icluster],endFitResults[jcluster]); } if(dClosestApproachSEnergyHAD() << " " << pCj->MipFraction() << " clos : " << closest << std::endl; if(!pCj->IsDefunct() && pCj->EnergyHAD()>0.5 && pCj->MipFraction()>0.75&&pCj->FirstLayer()<5){ if(helices[jcluster]==NULL){ int lastLayer = pCj->LastLayer(); int firstLayer = lastLayer-20; if(firstLayer<1)firstLayer=1; vector hits; for(int ilayer = firstLayer;ilayer<=lastLayer;ilayer++){ for(int ihit = 0;ihit< pCj->hitsInLayer(ilayer);ihit++){ hits.push_back(pCj->hitInLayer(ilayer,ihit)); } } if(hits.size()>8){ float ah[hits.size()]; float xh[hits.size()]; float yh[hits.size()]; float zh[hits.size()]; for (unsigned int i=0; igetPosition()[0]); yh[i] = float(hits[i]->getPosition()[1]); zh[i] = float(hits[i]->getPosition()[2]); } ClusterShapes * shapesS = new ClusterShapes(hits.size(),ah,xh,yh,zh); float par[5]; float dpar[5]; float chi2; float distmax; shapesS->FitHelix(500, 0, 1, par, dpar, chi2, distmax); delete shapesS; float x0 = par[0]; float y0 = par[1]; float r0 = par[2]; float bz = par[3]; float phiH = par[4]; HelixClass* helix = new HelixClass(); float signPz = zh[hits.size()-1]-zh[0]; helix->Initialize_BZ(x0, y0, r0, bz, phiH, _bField,signPz,zh[0]); float refs[3]; refs[0] = helix->getReferencePoint()[0]; refs[1] = helix->getReferencePoint()[1]; refs[2] = helix->getReferencePoint()[2]; // now have helix fit to last ten layers.... helices[jcluster] = helix; } } averageE = 0.; countE = 0.; if(helices[jcluster]!=NULL){ for(int ilayer = pCi->LastLayer()-3; ilayer <= pCi->LastLayer();ilayer++){ for(int ihit = 0;ihit< pCi->hitsInLayer(ilayer);ihit++){ float hitxyz[3]; float dist[3]; hitxyz[0] = pCi->hitInLayer(ilayer,ihit)->getPosition()[0]; hitxyz[1] = pCi->hitInLayer(ilayer,ihit)->getPosition()[1]; hitxyz[2] = pCi->hitInLayer(ilayer,ihit)->getPosition()[2]; helices[jcluster]->getDistanceToPoint(hitxyz, dist); averageE+= dist[2]; countE+=1.; if(dist[2]0)averageE = averageE/countE; if(countE<0.5)averageE = 99999.; } averageS = 0.; countS = 0.; if(helices[jcluster]!=NULL){ for(int ilayer = pCi->FirstLayer(); ilayer <= pCi->FirstLayer()+3;ilayer++){ for(int ihit = 0;ihit< pCi->hitsInLayer(ilayer);ihit++){ float hitxyz[3]; float dist[3]; hitxyz[0] = pCi->hitInLayer(ilayer,ihit)->getPosition()[0]; hitxyz[1] = pCi->hitInLayer(ilayer,ihit)->getPosition()[1]; hitxyz[2] = pCi->hitInLayer(ilayer,ihit)->getPosition()[2]; helices[jcluster]->getDistanceToPoint(hitxyz, dist); averageS+= dist[2]; countS+=1.; if(dist[2]0)averageS = averageS/countS; if(countS<0.5)averageS = 99999.; } } // Track pointing to cluster j // compared to trackless cluster i if(helices[jcluster]!=NULL && !pCj->IsDefunct() && pCj->EnergyHAD()>0.5 && pCi->EnergyHAD()>0.5 && pCj->MipFraction()>0.7 &&pCj->FirstLayer()<5){ int layersFromEdge1 = this->LayersFromEdge(pCi); int layersFromEdge2 = this->LayersFromEdge(pCj); bool looper = false; bool mipprojS = false; bool mipprojE = false; bool mipproj = false; fitResult fit1 = startFitResults[icluster]; fitResult fit2 = endFitResults[jcluster]; float trackE = trackAR->getEnergy(); float sigE = _hadEnergyRes*sqrt(trackE); float chi2o = (trackE-pCj->EnergyHAD())/sigE; float chi2n = (trackE-pCj->EnergyHAD()-pCi->EnergyHAD())/sigE; chi2o = chi2o*chi2o; chi2n = chi2n*chi2n; int il = pCi->FirstLayer(); int ll = pCi->LastLayer(); float delta = fabs(pCi->GetCentroid(il)[2])- fabs(pCi->GetCentroid(ll)[2]); bool flipped = false; if(delta < 0 )flipped = true; if(pCi->FirstLayer()LastLayer()){ // if both leave the detector outer edges if(layersFromEdge1<5&&layersFromEdge2<5 && closestHE<250)looper = true; // boundary of ECAL/HCAL if(abs(pCi->LastLayer()-_nEcalLayers)<=5&& abs(pCj->LastLayer()-_nEcalLayers)<=5 && ( (closestHE<100 && pCi->FirstLayer()>10) || closestHE<50))looper = true; // inside ECAL if(pCi->LastLayer()<_nEcalLayers && pCj->LastLayer()<_nEcalLayers && abs(pCi->LastLayer()-pCj->LastLayer())<5&& closestHE<50 && pCi->FirstLayer()>10)looper = true; // inside HCAL if(pCi->LastLayer()>_nEcalLayers&& pCj->LastLayer()>_nEcalLayers&& layersFromEdge2>5 && closestHE<250)looper = true; // inside HCAL if(abs(pCi->LastLayer()-pCj->LastLayer())<10 && layersFromEdge2>5 && pCi->FirstLayer()>10 && closestHE<100)looper = true; // inside HCAL but "wrong way round" if(flipped && abs(pCi->LastLayer()-pCj->LastLayer())<10 && layersFromEdge2>5 && pCi->FirstLayer()>10 && closestHS<100){ if(!looper)closestHE = closestHS; looper = true; } // apply chi2 cut float chi2cut = 0; if(pCi->FirstLayer()>_nEcalLayers && pCi->MipFraction()>0.7)chi2cut += 1; if(pCi->FirstLayer()>_nEcalLayers && pCi->DCosR()<0.5)chi2cut += 1; if(pCi->FirstLayer()>10 && pCi->MipFraction()>0.85)chi2cut += 1; if(_printing>1)std::cout << " looper - now look at chi2 " << chi2n-chi2o << " c.f. " << chi2cut << std::endl; if(chi2n-chi2o>chi2cut || chi2n > 4.0)looper=false; int layersCrossed = 9999; if(looper){ int il = pCi->FirstLayer(); int ll = pCj->LastLayer(); float zs = pCj->GetCentroid(ll)[2]; float ze = pCi->GetCentroid(il)[2]; if(fabs(zs)0)layersCrossed = this->ExpectedLayersCrossed(zs, ze, helices[jcluster]); if(_printing>1)std::cout << " LAYERS CROSS : " << layersCrossed << std::endl; if(layersCrossed>10)looper = false; if(layersFromEdge1<5&&layersFromEdge2<5 && closestHE<250)looper = true; } if(looper&&closestHE1 ){ if(!looper&&_printing>1)std::cout << " ************** Candidate Looper **************" << pCi->EnergyHAD() << std::endl; if(looper&&_printing>1)std::cout << " ************** CANDIDATE Looper **************" << pCi->EnergyHAD() << std::endl; if(_printing>1)std::cout << " LAYERS CROSSED " << layersCrossed << std::endl; if(_printing>1)std::cout << " Best Parent " << bestParent << std::endl; float d = this->closestApproach(fit1,fit2); if(_printing>1){ std::cout << " L fits " << fit1.dir[2] << " <-> " << fit2.dir[2] << " dist = " << d << std::endl; std::cout << " Try " << trackAR->getEnergy() << "<->" << pCj->EnergyHAD() << " chi2 o n : " << chi2o << " -> " << chi2n << std::endl; std::cout << " track start end : " << pCj->FirstLayer() << "-" << pCj->LastLayer() << std::endl; std::cout << " c start end : " << pCi->FirstLayer() << "-" << pCi->LastLayer() << std::endl; std::cout << " c z start end : " << pCi->GetCentroid(pCi->FirstLayer())[2] << "-" <GetCentroid(pCi->LastLayer())[2] << std::endl; std::cout << " Helix Start : " << averageS << " closest = " << closestHS << std::endl; std::cout << " Helix End : " << averageE << " closest = " << closestHE << std::endl; } } } if(bestParent==NULL && pCi->FirstLayer()>=pCj->LastLayer()-5){ bool look = false; if(closestHS<250 || closestHE<250)look = true; // inside HCAL if(pCi->FirstLayer()>_nEcalLayers && closestHS<100 )mipprojS = true; if(pCi->FirstLayer()>_nEcalLayers && closestHE<75 )mipprojE = true; if(pCi->FirstLayer()>_nEcalLayers+20 && closestHS<150 )mipprojS = true; if(pCi->FirstLayer()>_nEcalLayers+20 && closestHE<100 )mipprojE = true; if(pCi->FirstLayer()>_nEcalLayers && pCi->LastLayer()>_nEcalLayers && pCi->DCosR() < 0.5 && closestHS<200 )mipprojS = true; if(pCi->FirstLayer()>_nEcalLayers && pCi->LastLayer()>_nEcalLayers && pCi->DCosR() < 0.5 && closestHE<150 )mipprojE = true; // apply chi2 cut float chi2cut = 0; if(pCi->FirstLayer()>_nEcalLayers && pCi->MipFraction()>0.7)chi2cut = 1; if(pCi->FirstLayer()>_nEcalLayers && pCi->MipFraction()>0.9)chi2cut = 2; if(pCi->FirstLayer()>_nEcalLayers && pCi->MipFraction()>0.9 && pCi->DCosR()<0.7)chi2cut = 3; if(chi2n-chi2o>chi2cut || chi2n>4.0){ mipprojS=false; mipprojE=false; } int layersCrossed = 9999; if(mipprojS&&closestHSFirstLayer(); int ll = pCj->LastLayer(); float zs = pCj->GetCentroid(ll)[2]; float ze = pCi->GetCentroid(il)[2]; if(_printing>1)std::cout << " zs ze : " << zs << " " << ze << std::endl; if(fabs(zs)0)layersCrossed = this->ExpectedLayersCrossed(zs, ze, helices[jcluster]); if(layersCrossed>50)mipprojS = false; } if(mipprojE&&closestHELastLayer(); int ll = pCj->LastLayer(); float zs = pCj->GetCentroid(ll)[2]; float ze = pCi->GetCentroid(il)[2]; if(_printing>1)std::cout << " zs ze : " << zs << " " << ze << std::endl; if(fabs(zs)0)layersCrossed = this->ExpectedLayersCrossed(zs, ze, helices[jcluster]); if(layersCrossed>50)mipprojE = false; } if(mipprojS&&mipprojE){ if(closestHE1 ){ if(!mipproj&&_printing>1)std::cout << " ************** Candidate mip projection **************" << pCi->EnergyHAD() << std::endl; if(mipproj)std::cout << " ************** CANDIDATE MIP PROJECTION **************" << pCi->EnergyHAD() << std::endl; if(_printing>1)std::cout << " LAYERS CROSSED " << layersCrossed << std::endl; float d = this->closestApproach(fit1,fit2); if(_printing>1){ std::cout << " L fits " << fit1.dir[2] << " <-> " << fit2.dir[2] << " dist = " << d << std::endl; std::cout << " Try " << trackAR->getEnergy() << "<->" << pCj->EnergyHAD() << " chi2 o n : " << chi2o << " -> " << chi2n << std::endl; std::cout << " track start end : " << pCj->FirstLayer() << "-" << pCj->LastLayer() << std::endl; std::cout << " c start end : " << pCi->FirstLayer() << "-" << pCi->LastLayer() << std::endl; std::cout << " Helix Start : " << averageS << " closest = " << closestHS << std::endl; std::cout << " Helix End : " << averageE << " closest = " << closestHE << std::endl; } } } } } } if(bestParent!=NULL){ int il = pCi->FirstLayer(); if(_printing>1)std::cout << " ASSOCIATING : " << pCi->EnergyHAD() << " (" << pCi->GetCentroid(il)[0] << "," << pCi->GetCentroid(il)[1] << "," << pCi->GetCentroid(il)[2] << ") " << pCi->Hits() << " " << pCi->FirstLayer() << ":" << pCi->LastLayer() << " d" << pCi->DCosR()<< " " << pCi->ClusterRMS() << " mipf " << pCi->MipFraction() << std::endl; ProtoCluster* pCj = bestParent; il = pCj->FirstLayer(); if(_printing>1)std::cout << " WITH : " << pCj->EnergyHAD() << " (" << pCj->GetCentroid(il)[0] << "," << pCj->GetCentroid(il)[1] << "," << pCj->GetCentroid(il)[2] << ") " << pCj->Hits() << " " << pCj->FirstLayer() << ":" << pCj->LastLayer() << " d" << pCj->DCosR()<< " " << pCj->ClusterRMS() << " mipf " << pCj->MipFraction() << std::endl; //if(_recoDisplay!=NULL){ // ProtoClusterVec temp; // temp.push_back(pCi); // temp.push_back(bestParent); // _recoDisplay->DrawByProtoCluster(temp,3); // } bestParent->Assimilate(pCi); // Update the properties of the parent bestParent->Update(MAX_NUMBER_OF_LAYERS); bestParent->ClassifyYourself(); pCi->IsNowDefunct(); } } } } for(unsigned int icluster=0;iclustergetClusterVec(); bool electron = false; if(clusters.size()==1)electron = this->ElectronID(trackAR,clusters[0]); if(electron){ std::cout<< " Electron energy " << clusters[0]->EnergyHAD() << " -> " << clusters[0]->EnergyEM() << std::endl; clusters[0]->setEnergyHAD(clusters[0]->EnergyEM() ); clusters[0]->IsElectron(true); } } } void PandoraPFAProcessor::finalFragmentRemoval(ProtoClusterVec &protoClusters, MyTrackExtendedVec &extendedTracks){ // first build arrays of potentially associated clusters for each // NEUTRAL HADRON CLUSTER vectorcontacts[protoClusters.size()]; vectortempClusters; int ipass = 0; bool stillGoing = true; bool firstPass = true; const int deepInHcal = min(_nHcalLayers/2,20); const int halfEcal = _nEcalLayers/2; int bestParentCluster = -99999; int bestDaughterCluster = -99999; while(stillGoing){ if(_printing>1)std::cout << " ****** FinalFragmentRemoval ***** Pass " << ipass << std::endl; ipass++; stillGoing = false; for(unsigned int icluster=0;icluster1)std::cout << " Redetermine contacts for " << icluster << std::endl; } } if(determineContacts){ // Calculate everything ProtoCluster* pCi = protoClusters[icluster]; if(!pCi->AssociatedTrack() && !pCi->IsDefunct()){ float E = pCi->EnergyHAD(); int nhits = pCi->Hits(); int firstLayer = pCi->FirstLayer(); // int lastLayer = pCi->LastLayer(); bool photonLike = false; if(firstLayer<10)photonLike = true; pCi->PhotonProfileID(); float showerStart = pCi->GetLongProfileShowerStart(); float gammaFraction = pCi->GetLongProfileGammaFraction(); if(pCi->DCosR()<0.5 || showerStart>4 || gammaFraction>0.75)photonLike = false; if(pCi->IsPrimaryPhoton())photonLike = true; if(showerStart>5 && gammaFraction>0.5)photonLike = false; if(showerStart>8)photonLike = false; if(pCi->getLayer90()>_nEcalLayers)photonLike = false; bool photonVeto = false; if(!photonVeto && E>_minimumClusterEnergyEM&&nhits>=_minimumHitsInCluster){ if(_printing>1)std::cout << "--------------------------------" << E << std::endl; for(unsigned int jcluster=0;jclusterIsDefunct()){ MyTrackExtendedVec tracks = pCj->GetTrackVec(); if( (!pCj->IsPhoton()||tracks.size()>0)){ fragmentContact_t contact = this->CalculateFragmentContactInfo(pCj,pCi); // set flag for this cluster being interesting bool c = false; contact.icluster = jcluster; if(contact.contactLayers>0)c=true; if(contact.trackHelixExtrapolationAverage<250)c = true; if(contact.trackHelixExtrapolationDistance<150)c = true; if(contact.clusterFractionWithin100>0.25)c = true; if(contact.clusterFractionWithin50>0.15)c = true; if(contact.coneFraction25>0.25)c = true; if(contact.minimumDistance<150&&contact.clusterFractionWithin50>0.25)c=true; if(contact.minimumDistance<200&&contact.coneFraction25>0.25)c=true; if(contact.minimumDistance<250&&firstLayer>_nEcalLayers-10)c=true; if(contact.minimumDistance>750.)c = false; if(_printing>1 && contact.projectedDistanceTPCCage<500)std::cout << " TPC CAGE : " << contact.projectedDistanceTPCCage << std::endl; if(pCi->EnergyHAD()>0.6&&pCi->EnergyHAD()<0.5 && _printing>1){ std::cout << " Contact.... " << " cluster = " << contact.icluster << std::endl; std::cout << " Track - Cluster - chi : " << contact.trackEnergy << " " << contact.clusterEnergy << " " << contact.chi << std::endl; std::cout << " Contact Layers/Fraction: " << contact.contactLayers << " " << contact.contactFraction << std::endl; std::cout << " TrackHelix distance/av : " << contact.trackHelixExtrapolationDistance << " " << contact.trackHelixExtrapolationAverage << std::endl; std::cout << " Cone fraction : " << contact.coneFraction25 << " " << contact.coneFraction18 << " " << contact.coneFraction10 << std::endl; std::cout << " closest / fraction : " << contact.minimumDistance << " " << contact.clusterFractionWithin100 << " " << contact.clusterFractionWithin50 << std::endl; } // don't match to clusters leaving detector if(c)contacts[icluster].push_back(contact); } } } } } } } firstPass = false; // Find best fragment cluster bestParentCluster = -99999; bestDaughterCluster = -99999; float mostExcessEvidence = 0.; for(unsigned int icluster=0;iclusterEnergyHAD(); if(contacts[icluster].size()>0 && !pCi->IsDefunct()){ float neutralEnergy = 0.; float trackEnergy = 0.; float clusterEnergy = 0.; // calculate some loose preselection bool possible = false; for(unsigned int ic=0;ic0.001){ trackEnergy+=contacts[icluster][ic].trackEnergy; clusterEnergy += contacts[icluster][ic].clusterEnergy; }else{ neutralEnergy += contacts[icluster][ic].clusterEnergy; } if(contacts[icluster][ic].trackEnergy>0.001){ float oldChi = this->ChiClusterTrack(contacts[icluster][ic].clusterEnergy, contacts[icluster][ic].trackEnergy); float newChi = this->ChiClusterTrack(contacts[icluster][ic].clusterEnergy+pCi->EnergyHAD(), contacts[icluster][ic].trackEnergy); float newChi2 = newChi*newChi; float oldChi2 = oldChi*oldChi; if(E>7.6&&E<7.5&& _printing>1)std::cout << " NEW CHI2 : " << newChi2 << std::endl; if(newChi2<16.0)possible = true; if(newChi2ChiClusterTrack(clusterEnergy, trackEnergy); float newChiTotal = this->ChiClusterTrack(clusterEnergy+pCi->EnergyHAD(), trackEnergy); float oldChi2Total = oldChiTotal*oldChiTotal; float newChi2Total = newChiTotal*newChiTotal; float deltaChi2Total = oldChi2Total- newChi2Total; if(trackEnergy>0.001 && newChi2Total<9.0)possible = true; if(trackEnergy>0.001 && newChi2Total0.001 && possible){ if(_printing>1){ std::cout << " ----------------------------- " << std::endl; std::cout << " Neutral Hadron Cluster " << icluster << " ****ENERGY = " << pCi->EnergyHAD() << " ***** " << pCi->FirstLayer() << " dCosR " << pCi->DCosR() << std::endl; std::cout << " Has " << contacts[icluster].size() << " contacts : " << trackEnergy << " - " << clusterEnergy << " ( " << neutralEnergy << " ) " << oldChi2Total << "->" << newChi2Total << std::endl; } // look in different detector regions int firstLayer = pCi->FirstLayer(); int lastLayer = pCi->LastLayer(); int secondLayer = firstLayer; int thirdLayer = firstLayer; int layer10 = firstLayer; int layer25 = firstLayer; float esum = 0.; for(int ilayer = firstLayer+1; ilayer < pCi->LastLayer(); ilayer++){ if(pCi->hitsInLayer(ilayer)>0){ if(secondLayer==firstLayer)secondLayer = ilayer; if(thirdLayer==secondLayer)thirdLayer = ilayer; if(thirdLayer==firstLayer)thirdLayer = secondLayer; for(int ihit = 0; ihit hitsInLayer(ilayer);++ihit){ const MyCaloHitExtended* hiti = pCi->hitInLayer(ilayer,ihit); esum += hiti->getEnergyHAD(); } if(layer10==firstLayer && esum>0.1*pCi->EnergyHAD())layer10=ilayer; if(layer25==firstLayer && esum>0.25*pCi->EnergyHAD())layer25=ilayer; } } int layerForCorrection = min(thirdLayer,layer25); for(unsigned int ic=0;ic0.001){ float oldChi = this->ChiClusterTrack(contacts[icluster][ic].clusterEnergy, contacts[icluster][ic].trackEnergy); float newChi = this->ChiClusterTrack(contacts[icluster][ic].clusterEnergy+pCi->EnergyHAD(), contacts[icluster][ic].trackEnergy); float newChi2 = newChi*newChi; float oldChi2 = oldChi*oldChi; float deltaChi2 = oldChi2- newChi2; if(_printing>1 && pCi->EnergyHAD()>0.5){ if(contacts[icluster][ic].trackEnergy>0.001)std::cout << " Charged contact........................... " << oldChi2 << "->" << newChi2 << std::endl; if(contacts[icluster][ic].trackEnergy<0.001)std::cout << " Neutral contact........................... " << std::endl; std::cout << " Contact.... " << ic << " cluster = " << contacts[icluster][ic].icluster << std::endl; std::cout << " Track - Cluster - chi : " << contacts[icluster][ic].trackEnergy << " " << contacts[icluster][ic].clusterEnergy << " " << contacts[icluster][ic].chi << std::endl; std::cout << " Contact Layers/Fraction: " << contacts[icluster][ic].contactLayers << " " << contacts[icluster][ic].contactFraction << std::endl; std::cout << " TrackHelix distance/av : " << contacts[icluster][ic].trackHelixExtrapolationDistance << " " << contacts[icluster][ic].trackHelixExtrapolationAverage << std::endl; std::cout << " Cone fraction : " << contacts[icluster][ic].coneFraction25 << " " << contacts[icluster][ic].coneFraction18 << " " << contacts[icluster][ic].coneFraction10 << std::endl; std::cout << " closest / fraction : " << contacts[icluster][ic].minimumDistance << " " << contacts[icluster][ic].clusterFractionWithin100 << " " << contacts[icluster][ic].clusterFractionWithin50 << std::endl; } // Calculate a measure of the evidence that the cluster is a fragment of ic // from layers in contact float contactEvidence = 0.; if(contacts[icluster][ic].contactLayers>1)contactEvidence =0.5; if(contacts[icluster][ic].contactLayers>4)contactEvidence =1.0; if(contacts[icluster][ic].contactLayers>10)contactEvidence =2.0; contactEvidence *= (1.0+contacts[icluster][ic].contactFraction); // from cone extrapolation float coneEvidence = 0.; if(contacts[icluster][ic].coneFraction25>0.5 ){ coneEvidence = contacts[icluster][ic].coneFraction25; coneEvidence += contacts[icluster][ic].coneFraction18; coneEvidence += contacts[icluster][ic].coneFraction10; } if(firstLayer<_nEcalLayers)coneEvidence=coneEvidence/2.0; // from track extrapolation float trackExtrapolationEvidence = 0.; if(contacts[icluster][ic].trackHelixExtrapolationDistance<200){ trackExtrapolationEvidence = (200-contacts[icluster][ic].trackHelixExtrapolationDistance)/100.; if(contacts[icluster][ic].trackHelixExtrapolationDistance<50){ trackExtrapolationEvidence += (50.-contacts[icluster][ic].trackHelixExtrapolationDistance)/20.; } trackExtrapolationEvidence += (200-contacts[icluster][ic].trackHelixExtrapolationAverage)/100.; if(contacts[icluster][ic].trackHelixExtrapolationAverage<50){ trackExtrapolationEvidence += (50.-contacts[icluster][ic].trackHelixExtrapolationDistance)/50.; } } // from distance of closest approach float distanceEvidence = 0.; if(contacts[icluster][ic].minimumDistance<100.){ distanceEvidence = (100.-contacts[icluster][ic].minimumDistance)/100.; distanceEvidence += contacts[icluster][ic].clusterFractionWithin100; distanceEvidence += 2.0*contacts[icluster][ic].clusterFractionWithin50; } // total evidence float evidence = _fragmentRemovalDistanceWeight*distanceEvidence+ _fragmentRemovalConeWeight*coneEvidence+ _fragmentRemovalContactWeight*contactEvidence+ _fragmentRemovalTrackExtrapolationWeight*trackExtrapolationEvidence; if(_printing>1){ std::cout << " Evidence : " << evidence << std::endl; std::cout << " contact : " << contactEvidence << std::endl; std::cout << " track ex : " << trackExtrapolationEvidence << std::endl; std::cout << " cone : " << coneEvidence << std::endl; std::cout << " closeness : " << distanceEvidence << std::endl; } float chi2Evidence = _fragmentRemovalChi2Base - deltaChi2; float globalChi2Evidence = _fragmentRemovalChi2Base + _fragmentRemovalGlobalPenalty - deltaChi2Total; float lcorrection = 0.; // First layers of ECAL if(layerForCorrection<=5)lcorrection = 4.0; // Early part of ECAL if(layerForCorrection<=halfEcal)lcorrection = 2.0; if(layerForCorrection>halfEcal&&layerForCorrection<=_nEcalLayers)lcorrection = 0.0; if(layerForCorrection>_nEcalLayers)lcorrection = -1.0; if(layerForCorrection>_nEcalLayers+deepInHcal)lcorrection = -2.0; if(lastLayer-firstLayer<4 && firstLayer>5)lcorrection = -2.0; if(abs(layerForCorrection-_nEcalLayers)<4)lcorrection = -3.0; float leavingCorrection =0.; if(contacts[icluster][ic].leavingCluster){ leavingCorrection = 5.; if(_usingMuonHitsToAidClustering && contacts[icluster][ic].muonCount>5)leavingCorrection =10.; if(_usingMuonHitsToAidClustering && contacts[icluster][ic].muonCount==0)leavingCorrection = 2.; } float ecorrection = 0.0; if(E<3.0)ecorrection = (E-3); // corrections for low energy fragments float lecorrection = 0.0; if(E<1.5){ if(pCi->HitLayers()<6)lecorrection += -1.0; if(pCi->HitLayers()<4)lecorrection += -1.0; if(layerForCorrection>_nEcalLayers)lecorrection+= -1.0; } float acorrection = 0.0; if(pCi->DCosR()<0.75){ acorrection = -0.5+(pCi->DCosR()-0.75)*2.0; } float pcorrection = 0; if(pCi->IsPrimaryPhoton()){ float showerStart = pCi->GetLongProfileShowerStart(); float gammaFraction = pCi->GetLongProfileGammaFraction(); if(pCi->EnergyHAD()>2.0 && showerStart < 5)pcorrection = 10; if(pCi->EnergyHAD()>2.0 && showerStart < 2.5)pcorrection = 100; if(pCi->EnergyHAD()<2.0 && showerStart < 2.5)pcorrection = 5.; if(pCi->EnergyHAD()<2.0 && showerStart < 2.5 && gammaFraction < 0.8)pcorrection = 10.; if(pCi->EnergyHAD()<2.0 && showerStart > 2.5)pcorrection = 2.; if(pCi->EnergyHAD()<0.5 && (showerStart > 2.5 || gammaFraction > 1))pcorrection = 2.; if(pCi->EnergyHAD()<1.0 && showerStart > 2.5)pcorrection = 0.; } unsigned int jcluster = contacts[icluster][ic].icluster; ProtoCluster* pCj = protoClusters[jcluster]; if(pCj->IsElectron())pcorrection = 0.; // use global chi2 in region of cluster ? bool usingGlobal = false; if(newChi2>oldChi2 && newChi2>9.0)usingGlobal = true; if(globalChi2Evidence1){ std::cout << " Required Evidence : " << requiredEvidence << std::endl; if(!usingGlobal)std::cout << " chi2 evidence : " << chi2Evidence << std::endl; if(usingGlobal)std::cout << " GLOBAL chi2 evid : " << globalChi2Evidence << std::endl; std::cout << " layer correction : " << lcorrection << std::endl; std::cout << " 2nd Layer : " << secondLayer << std::endl; std::cout << " 3rd Layer : " << thirdLayer << std::endl; std::cout << " Layer10 : " << layer10 << std::endl; std::cout << " Layer25 : " << layer25 << std::endl; std::cout << " energy correction : " << ecorrection << std::endl; std::cout << " angle correction : " << acorrection << std::endl; std::cout << " leaving correction : " << leavingCorrection << std::endl; std::cout << " low E correction : " << lecorrection << std::endl; std::cout << " photon correction : " << pcorrection << std::endl; if(leavingCorrection)std::cout << " muon hits : " << contacts[icluster][ic].muonCount << std::endl; } float excessEvidence = evidence - requiredEvidence; if(_printing>0 && pCi->IsPrimaryPhoton() && excessEvidence>0)std::cout << " MATCH PRIMARY PHOTON" << " Eem = " << pCi->EnergyEM() << " ************************************************************************************************" << std::endl; if(excessEvidence>mostExcessEvidence){ bestParentCluster = contacts[icluster][ic].icluster; bestDaughterCluster = icluster; mostExcessEvidence = excessEvidence; if(contacts[icluster][ic].leavingCluster)streamlog_out(WARNING) << " finalFragmentRemoval : beta version - adding neutral fragment to leaving track cluster" << std::endl ; } } } // end of loop over contacts } } // end of if contacts>0 }//end of loop over clusters if(bestParentCluster>=0){ ProtoCluster* pCi = protoClusters[bestDaughterCluster]; ProtoCluster* pCj = protoClusters[bestParentCluster]; if(_printing>1){ std::cout << " ************************************************" << std::endl; std::cout << " Fragment Match " << pCi->EnergyHAD() << " <-> " << pCj->EnergyHAD() << std::endl; std::cout << " ************************************************" << std::endl; } pCj->Assimilate(pCi); // Update the properties of the parent pCj->Update(MAX_NUMBER_OF_LAYERS); pCj->ClassifyYourself(); // remove old cluster pCi->IsNowDefunct(); tempClusters.clear(); for(unsigned int ic=0;icClassifyYourself(); this->findPhotonsIDedAsHadrons(_photonClusters); for(unsigned i=0;i<_photonClusters.size();i++)protoClusters.push_back(_photonClusters[i]); } void PandoraPFAProcessor::AddPhotonClusters(ProtoClusterVec &protoClusters){ // perform photonID for(unsigned i=0;i<_photonClusters.size();i++)_photonClusters[i]->ClassifyYourself(); this->findPhotonsIDedAsHadrons(_photonClusters); for(unsigned i=0;i<_photonClusters.size();i++)protoClusters.push_back(_photonClusters[i]); } void PandoraPFAProcessor::AddPerfectNeutralHadronClusters(ProtoClusterVec &protoClusters){ // perform photonID for(unsigned i=0;i<_perfectNeutralHadronClusters.size();i++)_perfectNeutralHadronClusters[i]->ClassifyYourself(); this->findPhotonsIDedAsHadrons(_perfectNeutralHadronClusters); for(unsigned i=0;i<_perfectNeutralHadronClusters.size();i++){ protoClusters.push_back(_perfectNeutralHadronClusters[i]); std::cout << " Add back PERFECT NEUTRAL HADRON : " << _perfectNeutralHadronClusters[i]->EnergyHAD() << std::endl; } } void PandoraPFAProcessor::AddMuonClustersToPFOs(ProtoClusterVec &protoClusters, MyTrackExtendedVec &extendedTracks){ const float dcosCut = 0.95; if(_maxMuonLayer>_maxLayer)_maxLayer = _maxMuonLayer; std::cout << " MUON CLUSTERS : " << _muonProtoClusters.size() << std::endl; for(unsigned i=0;i<_muonProtoClusters.size();i++){ std::cout << " cluster " << i << " Hits = " << _muonProtoClusters[i]->Hits() << " E = " << _muonProtoClusters[i]->EnergyHAD() << std::endl; if( _muonProtoClusters[i]->Hits()>2){ float estimatedLostEnergy = 0.; int il = _muonProtoClusters[i]->FirstLayer(); int hitsInFirstLayer = _muonProtoClusters[i]->hitsInLayer(il); float xm = _muonProtoClusters[i]->GetCentroid(il)[0]; float ym = _muonProtoClusters[i]->GetCentroid(il)[1]; float zm = _muonProtoClusters[i]->GetCentroid(il)[2]; float rm = sqrt(xm*xm+ym*ym+zm*zm); float rxy = sqrt(xm*xm+ym*ym); if(rxy>4000. && hitsInFirstLayer>2)estimatedLostEnergy+= _muonClusterCoilCorrection; std::cout << " " << xm << "," << ym << "," << zm << " r = " << rxy << std::endl; ProtoClusterVec matchedTracks; ProtoClusterVec matchedHadrons; ProtoClusterVec matchedNonLeavingTracks; ProtoCluster* bestMatchedHadron = NULL; ProtoCluster* bestMatchedTrack = NULL; ProtoCluster* bestMatchedNonLeavingTrack = NULL; float bestDcosTrack = dcosCut; float bestDcosHadron = dcosCut; float bestDcosNonLeavingTrack = dcosCut; for(unsigned icluster=0;iclusterEnergyHAD(); int nhits = protoClusters[icluster]->Hits(); if(E>_minimumClusterEnergyHAD&&nhits>=_minimumHitsInCluster){ bool isLeaving = this->IsClusterLeavingDetector( protoClusters[icluster]); int ll = protoClusters[icluster]->LastLayer(); float xc = protoClusters[icluster]->GetCentroid(ll)[0]; float yc = protoClusters[icluster]->GetCentroid(ll)[1]; float zc = protoClusters[icluster]->GetCentroid(ll)[2]; float rc = sqrt(xc*xc+yc*yc+zc*zc); float dcos = (xc*xm+yc*ym+zc*zm)/rc/rm; if(isLeaving){ if(protoClusters[icluster]->AssociatedTrack()==false){ if(_printing>1)std::cout << " Matched neutral " << dcos << std::endl; if(dcos>bestDcosHadron){ bestDcosHadron = dcos; bestMatchedHadron = protoClusters[icluster]; } if(dcos>dcosCut)matchedHadrons.push_back(protoClusters[icluster]); }else{ float chi = this->ChiClusterTrack(protoClusters[icluster],estimatedLostEnergy); if(_printing>1)std::cout << " Matched track " << dcos << " chi = " << chi << std::endl; if(chi<3.0){ if(dcos>bestDcosTrack){ bestDcosTrack = dcos; bestMatchedTrack = protoClusters[icluster]; } if(dcos>dcosCut)matchedTracks.push_back(protoClusters[icluster]); } } }else{ if(protoClusters[icluster]->AssociatedTrack()==true){ float chiold = this->ChiClusterTrack(protoClusters[icluster]); float chinew = this->ChiClusterTrack(protoClusters[icluster],estimatedLostEnergy); if(chiold<-3.0 && chinew< 3.0){ if(dcos>bestDcosNonLeavingTrack){ bestDcosNonLeavingTrack = dcos; bestMatchedNonLeavingTrack = protoClusters[icluster]; } if(dcos>dcosCut)matchedNonLeavingTracks.push_back(protoClusters[icluster]); } } } } } if(_printing>1)std::cout << " Cluster matches : " << matchedHadrons.size() << " " << matchedTracks.size() << " " << matchedNonLeavingTracks.size() << std::endl; if(bestMatchedTrack==NULL){ if(bestMatchedHadron==NULL && bestMatchedNonLeavingTrack==NULL){ if(_printing>1)std::cout<< " Creating standalone muon cluster " << _muonProtoClusters[i]->EnergyHAD() << std::endl; protoClusters.push_back(_muonProtoClusters[i]); estimatedLostEnergy = hitsInFirstLayer*0.5; float enew = _muonProtoClusters[i]->EnergyHAD() + estimatedLostEnergy; _muonProtoClusters[i]->setEnergyHAD(enew ); if(_printing>1)std::cout << " Would like to add " << estimatedLostEnergy << " --> " << _muonProtoClusters[i]->EnergyHAD() << std::endl; } if(bestMatchedHadron==NULL && bestMatchedNonLeavingTrack!=NULL){ if(_printing>1)std::cout << " Add muon cluster to charged " << bestMatchedNonLeavingTrack->EnergyHAD() << std::endl; bestMatchedNonLeavingTrack->Assimilate(_muonProtoClusters[i]); if(_printing>1)std::cout << bestMatchedNonLeavingTrack->EnergyHAD() << std::endl; float chiold = this->ChiClusterTrack(bestMatchedNonLeavingTrack); float chinew = this->ChiClusterTrack(bestMatchedNonLeavingTrack,estimatedLostEnergy); if(chinew<3.0 && fabs(chinew)EnergyHAD() + estimatedLostEnergy; bestMatchedNonLeavingTrack->setEnergyHAD(enew); if(_printing>1)std::cout << " Added " << estimatedLostEnergy << " --> " << bestMatchedNonLeavingTrack->EnergyHAD() << " " << chiold << "->" << chinew << std::endl; } } if(bestMatchedHadron!=NULL){ if(_printing>1)std::cout << " Add muon cluster to neutral " << bestMatchedHadron->EnergyHAD() << " --> "; bestMatchedHadron->Assimilate(_muonProtoClusters[i]); if(_printing>1)std::cout << bestMatchedHadron->EnergyHAD() << std::endl; if(rxy>4000)estimatedLostEnergy= _muonClusterCoilCorrection; float enew = bestMatchedHadron->EnergyHAD() + estimatedLostEnergy; bestMatchedHadron->setEnergyHAD(enew); if(_printing>1)std::cout << " Would like to add " << estimatedLostEnergy << " --> " << bestMatchedHadron->EnergyHAD() << std::endl; } }else{ if(_printing>1)std::cout << " Add muon cluster to charged " << bestMatchedTrack->EnergyHAD() << " --> "; bestMatchedTrack->Assimilate(_muonProtoClusters[i]); if(_printing>1)std::cout << bestMatchedTrack->EnergyHAD() << std::endl; float chiold = this->ChiClusterTrack(bestMatchedTrack); float chinew = this->ChiClusterTrack(bestMatchedTrack,estimatedLostEnergy); if(chinew<3.0 && fabs(chinew)EnergyHAD() + estimatedLostEnergy; bestMatchedTrack->setEnergyHAD(enew); if(_printing>1)std::cout << " Added " << estimatedLostEnergy << " --> " << bestMatchedTrack->EnergyHAD() << chiold << "->" << chinew << std::endl; } } } } return; } void PandoraPFAProcessor::finalSoftFragmentRemoval(ProtoClusterVec &protoClusters, MyTrackExtendedVec &extendedTracks){ // first build arrays of potentially associated clusters for each // NEUTRAL HADRON CLUSTER vectorcontacts[protoClusters.size()]; vectortempClusters; int ipass = 0; bool stillGoing = true; bool firstPass = true; const int deepInHcal = min(_nHcalLayers/2,20); const int halfEcal = _nEcalLayers/2; int bestParentCluster = -99999; int bestDaughterCluster = -99999; while(stillGoing){ if(_printing>1)std::cout << " ****** FinalSoftFragmentRemoval ***** Pass " << ipass << std::endl; ipass++; stillGoing = false; for(unsigned int icluster=0;icluster1)std::cout << " Redetermine contacts for " << icluster << std::endl; } } if(determineContacts){ // Calculate everything ProtoCluster* pCi = protoClusters[icluster]; if(!pCi->AssociatedTrack() && !pCi->IsDefunct()){ float E = pCi->EnergyHAD(); int nhits = pCi->Hits(); int firstLayer = pCi->FirstLayer(); // int lastLayer = pCi->LastLayer(); bool photonLike = false; if(firstLayer<10)photonLike = true; pCi->PhotonProfileID(); if(E>_minimumClusterEnergyEM&&E<1.5&&nhits>=_minimumHitsInCluster){ if(_printing>1)std::cout << "--------------------------------" << E << std::endl; for(unsigned int jcluster=0;jclusterIsDefunct()){ MyTrackExtendedVec tracks = pCj->GetTrackVec(); if( (!pCj->IsPhoton()||tracks.size()>0)){ fragmentContact_t contact = this->CalculateFragmentContactInfo(pCj,pCi); // set flag for this cluster being interesting bool c = false; contact.icluster = jcluster; if(contact.contactLayers>0)c=true; if(contact.trackHelixExtrapolationAverage<500)c = true; if(contact.trackHelixExtrapolationDistance<300)c = true; if(contact.clusterFractionWithin100>0.125)c = true; if(contact.clusterFractionWithin50>0.1)c = true; if(contact.coneFraction25>0.1)c = true; if(contact.minimumDistance<200&&contact.clusterFractionWithin50>0.1)c=true; if(contact.minimumDistance<250&&contact.coneFraction25>0.1)c=true; if(contact.minimumDistance<300&&firstLayer>_nEcalLayers-10)c=true; if(contact.minimumDistance>1000.)c = false; if(c)contacts[icluster].push_back(contact); } } } } } } } firstPass = false; // Find best fragment cluster bestParentCluster = -99999; bestDaughterCluster = -99999; // float mostExcessEvidence = 0.; for(unsigned int icluster=0;iclusterEnergyHAD(); if(contacts[icluster].size()>0 && !pCi->IsDefunct()){ float neutralEnergy = 0.; float trackEnergy = 0.; float clusterEnergy = 0.; // calculate some loose preselection bool possible = false; for(unsigned int ic=0;ic0.001){ trackEnergy+=contacts[icluster][ic].trackEnergy; clusterEnergy += contacts[icluster][ic].clusterEnergy; }else{ neutralEnergy += contacts[icluster][ic].clusterEnergy; } if(contacts[icluster][ic].trackEnergy>0.001){ float oldChi = this->ChiClusterTrack(contacts[icluster][ic].clusterEnergy, contacts[icluster][ic].trackEnergy); float newChi = this->ChiClusterTrack(contacts[icluster][ic].clusterEnergy+pCi->EnergyHAD(), contacts[icluster][ic].trackEnergy); float newChi2 = newChi*newChi; float oldChi2 = oldChi*oldChi; if(newChi2<16.0)possible = true; if(newChi2ChiClusterTrack(clusterEnergy, trackEnergy); float newChiTotal = this->ChiClusterTrack(clusterEnergy+pCi->EnergyHAD(), trackEnergy); float oldChi2Total = oldChiTotal*oldChiTotal; float newChi2Total = newChiTotal*newChiTotal; float deltaChi2Total = oldChi2Total- newChi2Total; if(trackEnergy>0.001 && newChi2Total<9.0)possible = true; if(trackEnergy>0.001 && newChi2Total0.001 && possible){ if(_printing>1){ std::cout << " ----------------------------- " << std::endl; std::cout << " Neutral Hadron Cluster " << icluster << " ****ENERGY = " << pCi->EnergyHAD() << " ***** " << pCi->FirstLayer() << " dCosR " << pCi->DCosR() << std::endl; std::cout << " Has " << contacts[icluster].size() << " contacts : " << trackEnergy << " - " << clusterEnergy << " ( " << neutralEnergy << " ) " << oldChi2Total << "->" << newChi2Total << std::endl; } // look in different detector regions int firstLayer = pCi->FirstLayer(); int lastLayer = pCi->LastLayer(); int secondLayer = firstLayer; int thirdLayer = firstLayer; int layer10 = firstLayer; int layer25 = firstLayer; float esum = 0.; for(int ilayer = firstLayer+1; ilayer < pCi->LastLayer(); ilayer++){ if(pCi->hitsInLayer(ilayer)>0){ if(secondLayer==firstLayer)secondLayer = ilayer; if(thirdLayer==secondLayer)thirdLayer = ilayer; if(thirdLayer==firstLayer)thirdLayer = secondLayer; for(int ihit = 0; ihit hitsInLayer(ilayer);++ihit){ const MyCaloHitExtended* hiti = pCi->hitInLayer(ilayer,ihit); esum += hiti->getEnergyHAD(); } if(layer10==firstLayer && esum>0.1*pCi->EnergyHAD())layer10=ilayer; if(layer25==firstLayer && esum>0.25*pCi->EnergyHAD())layer25=ilayer; } } int layerForCorrection = min(thirdLayer,layer25); for(unsigned int ic=0;ic0.001){ float oldChi = this->ChiClusterTrack(contacts[icluster][ic].clusterEnergy, contacts[icluster][ic].trackEnergy); float newChi = this->ChiClusterTrack(contacts[icluster][ic].clusterEnergy+pCi->EnergyHAD(), contacts[icluster][ic].trackEnergy); float newChi2 = newChi*newChi; float oldChi2 = oldChi*oldChi; float deltaChi2 = oldChi2- newChi2; if(_printing>1 && pCi->EnergyHAD()>0.5){ if(contacts[icluster][ic].trackEnergy>0.001)std::cout << " Charged contact........................... " << oldChi2 << "->" << newChi2 << std::endl; if(contacts[icluster][ic].trackEnergy<0.001)std::cout << " Neutral contact........................... " << std::endl; std::cout << " Contact.... " << ic << " cluster = " << contacts[icluster][ic].icluster << std::endl; std::cout << " Track - Cluster - chi : " << contacts[icluster][ic].trackEnergy << " " << contacts[icluster][ic].clusterEnergy << " " << contacts[icluster][ic].chi << std::endl; std::cout << " Contact Layers/Fraction: " << contacts[icluster][ic].contactLayers << " " << contacts[icluster][ic].contactFraction << std::endl; std::cout << " TrackHelix distance/av : " << contacts[icluster][ic].trackHelixExtrapolationDistance << " " << contacts[icluster][ic].trackHelixExtrapolationAverage << std::endl; std::cout << " Cone fraction : " << contacts[icluster][ic].coneFraction25 << " " << contacts[icluster][ic].coneFraction18 << " " << contacts[icluster][ic].coneFraction10 << std::endl; std::cout << " closest / fraction : " << contacts[icluster][ic].minimumDistance << " " << contacts[icluster][ic].clusterFractionWithin100 << " " << contacts[icluster][ic].clusterFractionWithin50 << std::endl; } // Calculate a measure of the evidence that the cluster is a fragment of ic // from layers in contact float contactEvidence = 0.; if(contacts[icluster][ic].contactLayers>0)contactEvidence =0.5; if(contacts[icluster][ic].contactLayers>1)contactEvidence =1.0; if(contacts[icluster][ic].contactLayers>4)contactEvidence =1.5; if(contacts[icluster][ic].contactLayers>10)contactEvidence =2.5; contactEvidence *= (1.0+contacts[icluster][ic].contactFraction); // from cone extrapolation float coneEvidence = 0.; if(contacts[icluster][ic].coneFraction25>0.10 ){ coneEvidence = contacts[icluster][ic].coneFraction25; coneEvidence += contacts[icluster][ic].coneFraction18; coneEvidence += contacts[icluster][ic].coneFraction10; } if(firstLayer<_nEcalLayers/2)coneEvidence=coneEvidence/2.0; // from track extrapolation float trackExtrapolationEvidence = 0.; if(contacts[icluster][ic].trackHelixExtrapolationDistance<300){ trackExtrapolationEvidence = (300-contacts[icluster][ic].trackHelixExtrapolationDistance)/100.; if(contacts[icluster][ic].trackHelixExtrapolationDistance<50){ trackExtrapolationEvidence += (50.-contacts[icluster][ic].trackHelixExtrapolationDistance)/20.; } trackExtrapolationEvidence += (300-contacts[icluster][ic].trackHelixExtrapolationAverage)/100.; if(contacts[icluster][ic].trackHelixExtrapolationAverage<100){ trackExtrapolationEvidence += (100.-contacts[icluster][ic].trackHelixExtrapolationDistance)/50.; } } // from distance of closest approach float distanceEvidence = 0.; if(contacts[icluster][ic].minimumDistance<150.){ distanceEvidence = (150.-contacts[icluster][ic].minimumDistance)/100.; distanceEvidence += 1.5*contacts[icluster][ic].clusterFractionWithin100; distanceEvidence += 2.5*contacts[icluster][ic].clusterFractionWithin50; } // total evidence float evidence = _fragmentRemovalDistanceWeight*distanceEvidence+ _fragmentRemovalConeWeight*coneEvidence+ _fragmentRemovalContactWeight*contactEvidence+ _fragmentRemovalTrackExtrapolationWeight*trackExtrapolationEvidence; if(_printing>1){ std::cout << " Evidence : " << evidence << std::endl; std::cout << " contact : " << contactEvidence << std::endl; std::cout << " track ex : " << trackExtrapolationEvidence << std::endl; std::cout << " cone : " << coneEvidence << std::endl; std::cout << " closeness : " << distanceEvidence << std::endl; } float chi2Evidence = _fragmentRemovalChi2Base - deltaChi2; float globalChi2Evidence = _fragmentRemovalChi2Base + _fragmentRemovalGlobalPenalty - deltaChi2Total; float lcorrection = 0.; // First layers of ECAL if(layerForCorrection<=5)lcorrection = 4.0; if(layerForCorrection<=10)lcorrection = 3.0; // Early part of ECAL if(layerForCorrection>10&&layerForCorrection<=halfEcal)lcorrection = 2.0; if(layerForCorrection>halfEcal&&layerForCorrection<=_nEcalLayers)lcorrection = 0.0; if(layerForCorrection>_nEcalLayers)lcorrection = -1.0; if(layerForCorrection>_nEcalLayers+deepInHcal)lcorrection = -2.0; if(lastLayer-firstLayer<4 && firstLayer>5)lcorrection = -2.0; if(abs(layerForCorrection-_nEcalLayers)<4)lcorrection = -3.0; float leavingCorrection =0.; float ecorrection = 0.0; if(E<2.0)ecorrection = 2*(E-2); // corrections for low energy fragments float lecorrection = 0.0; if(E<1.5){ if(pCi->HitLayers()<10)lecorrection += -1.0; if(pCi->HitLayers()<5)lecorrection += -1.0; if(layerForCorrection>_nEcalLayers)lecorrection+= -1.0; } float acorrection = 0.0; if(pCi->DCosR()<0.8)acorrection = -0.5+(pCi->DCosR()-0.8)*2.0; float pcorrection = 0; if(pCi->IsPrimaryPhoton()){ float showerStart = pCi->GetLongProfileShowerStart(); float gammaFraction = pCi->GetLongProfileGammaFraction(); if(pCi->EnergyHAD()>2.0 && showerStart < 5)pcorrection = 10; if(pCi->EnergyHAD()>2.0 && showerStart < 2.5)pcorrection = 100; if(pCi->EnergyHAD()<2.0 && showerStart < 2.5)pcorrection = 5.; if(pCi->EnergyHAD()<2.0 && showerStart < 2.5 && gammaFraction < 0.8)pcorrection = 10.; if(pCi->EnergyHAD()<2.0 && showerStart > 2.5)pcorrection = 2.; if(pCi->EnergyHAD()<0.5 && (showerStart > 2.5 || gammaFraction > 1))pcorrection = 2.; if(pCi->EnergyHAD()<1.0 && showerStart > 2.5)pcorrection = 0.; if(pCi->DCosR()<0.9)pcorrection = 0.; } // use global chi2 in region of cluster ? bool usingGlobal = false; if(newChi2>oldChi2 && newChi2>9.0)usingGlobal = true; if(globalChi2Evidence1){ std::cout << " Required Evidence : " << requiredEvidence << std::endl; if(!usingGlobal)std::cout << " chi2 evidence : " << chi2Evidence << std::endl; if(usingGlobal)std::cout << " GLOBAL chi2 evid : " << globalChi2Evidence << std::endl; std::cout << " layer correction : " << lcorrection << std::endl; std::cout << " 2nd Layer : " << secondLayer << std::endl; std::cout << " 3rd Layer : " << thirdLayer << std::endl; std::cout << " Layer10 : " << layer10 << std::endl; std::cout << " Layer25 : " << layer25 << std::endl; std::cout << " energy correction : " << ecorrection << std::endl; std::cout << " angle correction : " << acorrection << std::endl; std::cout << " leaving correction : " << leavingCorrection << std::endl; std::cout << " low E correction : " << lecorrection << std::endl; std::cout << " photon correction : " << pcorrection << std::endl; if(leavingCorrection)std::cout << " muon hits : " << contacts[icluster][ic].muonCount << std::endl; } float excessEvidence = evidence - requiredEvidence; if(pCi->IsPrimaryPhoton() && excessEvidence>0)std::cout << " MATCH PRIMARY PHOTON" << " Eem = " << pCi->EnergyEM() << std::endl; // if(excessEvidence>mostExcessEvidence && !pCi->IsPrimaryPhoton()){ // bestParentCluster = contacts[icluster][ic].icluster; // /bestDaughterCluster = icluster; // mostExcessEvidence = excessEvidence; // if(contacts[icluster][ic].leavingCluster)streamlog_out(WARNING) << " finalFragmentRemoval : beta version - adding neutral fragment to leaving track cluster" << std::endl ; //} } } // end of loop over contacts } } // end of if contacts>0 }//end of loop over clusters if(bestParentCluster>=0){ ProtoCluster* pCi = protoClusters[bestDaughterCluster]; ProtoCluster* pCj = protoClusters[bestParentCluster]; if(_printing>1){ std::cout << " ************************************************" << std::endl; std::cout << " Fragment Match " << pCi->EnergyHAD() << " <-> " << pCj->EnergyHAD() << std::endl; std::cout << " ************************************************" << std::endl; } pCj->Assimilate(pCi); // Update the properties of the parent pCj->Update(MAX_NUMBER_OF_LAYERS); pCj->ClassifyYourself(); // remove old cluster pCi->IsNowDefunct(); tempClusters.clear(); for(unsigned int ic=0;iccontacts[protoClusters.size()]; vectortempClusters; int ipass = 0; bool stillGoing = true; bool firstPass = true; // const int deepInHcal = min(_nHcalLayers/2,20); // const int halfEcal = _nEcalLayers/2; int bestParentCluster = -99999; int bestDaughterCluster = -99999; while(stillGoing && ipass < 5){ if(_printing>1)std::cout << " ****** NeutralHadronMerging ***** Pass " << ipass << std::endl; ipass++; stillGoing = false; for(unsigned int icluster=0;icluster1)std::cout << " Redetermine contacts for " << icluster << std::endl; } } if(determineContacts){ // Calculate everything ProtoCluster* pCi = protoClusters[icluster]; if(!pCi->AssociatedTrack() && !pCi->IsDefunct()){ float E = pCi->EnergyHAD(); int nhits = pCi->Hits(); int firstLayer = pCi->FirstLayer(); bool photonLike = false; if(firstLayer<10)photonLike = true; pCi->PhotonProfileID(); float showerStart = pCi->GetLongProfileShowerStart(); float gammaFraction = pCi->GetLongProfileGammaFraction(); if(pCi->DCosR()<0.5 || showerStart>5 || gammaFraction>0.75)photonLike = false; if(pCi->IsPhoton())photonLike = true; if(!photonLike && E>_minimumClusterEnergyEM&&nhits>=_minimumHitsInCluster && !pCi->IsDefunct()){ if(_printing>1)std::cout << "--------------------------------" << std::endl; for(unsigned int jcluster=0;jclusterIsDefunct()){ MyTrackExtendedVec tracks = pCj->GetTrackVec(); // don't match to clusters leaving detector if( !pCj->IsPhoton() && !pCj->IsDefunct() && tracks.size()==0){ fragmentContact_t contact = this->CalculateFragmentContactInfo(pCj,pCi); // set flag for this cluster being interesting bool c = false; contact.icluster = jcluster; if(contact.contactLayers>2)c=true; if(contact.clusterFractionWithin100>0.5)c = true; if(contact.clusterFractionWithin50>0.5)c = true; if(contact.minimumDistance<100&&contact.clusterFractionWithin50>0.25)c=true; if(contact.coneFraction25>0.5)c = true; if(contact.minimumDistance>500.)c = false; if(c)contacts[icluster].push_back(contact); } } } } } } } firstPass = false; // Find best fragment cluster bestParentCluster = -99999; bestDaughterCluster = -99999; float mostEvidence = 0.; for(unsigned int icluster=0;iclusterEnergyHAD(); if(contacts[icluster].size()>0){ float neutralEnergy = 0.; float clusterEnergy = 0.; // calculate some loose preselection bool possible = false; for(unsigned int ic=0;ic1){ std::cout << " ----------------------------- " << std::endl; std::cout << " Neutral Hadron Cluster " << icluster << " ****ENERGY = " << pCi->EnergyHAD() << " ***** " << pCi->FirstLayer() << " dCosR " << pCi->DCosR() << std::endl; std::cout << " Has " << contacts[icluster].size() << " contacts : " << " - " << clusterEnergy << " ( " << neutralEnergy << " ) " << std::endl; } // look in different detector regions int firstLayer = pCi->FirstLayer(); for(unsigned int ic=0;ic1 && pCi->EnergyHAD()>0.5){ std::cout << " Neutral contact........................... " << std::endl; std::cout << " Contact.... " << ic << " cluster = " << contacts[icluster][ic].icluster << std::endl; std::cout << " Contact Layers/Fraction: " << contacts[icluster][ic].contactLayers << " " << contacts[icluster][ic].contactFraction << std::endl; std::cout << " Cone fraction : " << contacts[icluster][ic].coneFraction25 << " " << contacts[icluster][ic].coneFraction18 << " " << contacts[icluster][ic].coneFraction10 << std::endl; std::cout << " closest / fraction : " << contacts[icluster][ic].minimumDistance << " " << contacts[icluster][ic].clusterFractionWithin100 << " " << contacts[icluster][ic].clusterFractionWithin50 << std::endl; } // Calculate a measure of the evidence that the cluster is a fragment of ic // from layers in contact float contactEvidence = 0.; if(contacts[icluster][ic].contactLayers>1)contactEvidence =0.5; if(contacts[icluster][ic].contactLayers>4)contactEvidence =1.0; if(contacts[icluster][ic].contactLayers>10)contactEvidence =2.0; contactEvidence *= (1.0+contacts[icluster][ic].contactFraction); // from cone extrapolation float coneEvidence = 0.; if(contacts[icluster][ic].coneFraction25>0.5 ){ coneEvidence = contacts[icluster][ic].coneFraction25; coneEvidence += contacts[icluster][ic].coneFraction18; coneEvidence += contacts[icluster][ic].coneFraction10; } if(firstLayer<_nEcalLayers)coneEvidence=coneEvidence/2.0; // from distance of closest approach float distanceEvidence = 0.; if(contacts[icluster][ic].minimumDistance<100.){ distanceEvidence = (100.-contacts[icluster][ic].minimumDistance)/100.; distanceEvidence += contacts[icluster][ic].clusterFractionWithin100; distanceEvidence += 2.0*contacts[icluster][ic].clusterFractionWithin50; } // total evidence float evidence = _fragmentRemovalDistanceWeight*distanceEvidence+ _fragmentRemovalConeWeight*coneEvidence+ _fragmentRemovalContactWeight*contactEvidence; if(evidence>mostEvidence){ mostEvidence = evidence; bestParentCluster = contacts[icluster][ic].icluster; bestDaughterCluster = icluster; } if(_printing>1){ std::cout << " Evidence : " << evidence << std::endl; std::cout << " contact : " << contactEvidence << std::endl; std::cout << " cone : " << coneEvidence << std::endl; std::cout << " closeness : " << distanceEvidence << std::endl; } } } } } if(bestParentCluster>=0 && mostEvidence > 2.0){ ProtoCluster* pCi = protoClusters[bestDaughterCluster]; ProtoCluster* pCj = protoClusters[bestParentCluster]; streamlog_out(MESSAGE) << "neutralHadronFragmentMerging(beta version) NEUTRAL Fragment Match " << pCi->EnergyHAD() << " will be attached to NEUTRAL CLUSTER " << pCj->EnergyHAD() << std::endl; pCj->Assimilate(pCi); // Update the properties of the parent pCj->Update(MAX_NUMBER_OF_LAYERS); pCj->ClassifyYourself(); // remove old cluster pCi->IsNowDefunct(); tempClusters.clear(); for(unsigned int ic=0;icgetClusterVec(); ProtoClusterVec clustersj = tj->getClusterVec(); if(clustersi.size()>0&&clustersj.size()>0){ contact = this->CalculateFragmentContactInfo(clustersj[0],clustersi[0]); } return contact; } fragmentContact_t PandoraPFAProcessor::CalculateFragmentContactInfo(ProtoCluster* pCj, ProtoCluster* pCi){ // look for layers where clusters are in contact fragmentContact_t contact; contact.candidateDaughterProtoCluster = pCi; contact.candidateParentProtoCluster = pCj; // contact.icluster = jcluster; clusterContact_t ccontact = pCi->ContactLayers(pCj,_fragmentRemovalContactCut); contact.contactLayers = ccontact.contactLayers; contact.contactFraction = ccontact.contactFraction; contact.muonCount = -999; // look at track helix extrapolations float tclosest = 99999.; float taverage = 99999.; float tEnergy = 0.; contact.projectedDistanceTPCCage=999.; MyTrackExtendedVec tracks = pCj->GetTrackVec(); int firstLayer = pCi->FirstLayer(); for(unsigned int itrack=0;itrack < tracks.size();++itrack){ MyTrackExtended* trackAR = tracks[itrack]; HelixClass* helix = trackAR->getHelix(); tEnergy+=trackAR->getEnergy(); if(helix!=NULL){ int layersCrossed = 99999; float zs = trackAR->getSeedPosition()[2]; float ze = pCi->GetCentroid(firstLayer)[2]; float refs[3]; refs[0] = helix->getReferencePoint()[0]; refs[1] = helix->getReferencePoint()[1]; refs[2] = helix->getReferencePoint()[2]; float point[3]; helix->getPointInZ(zs, refs, point); float deltaX = pCi->GetCentroid(firstLayer)[0]-point[0]; float deltaY = pCi->GetCentroid(firstLayer)[1]-point[1]; //float deltaZ = pCi->GetCentroid(firstLayer)[2]-point[2]; float deltaXY = sqrt(deltaX*deltaX+deltaY*deltaY); if(deltaXY<1250.){ if(fabs(zs)<(fabs(ze)+250.) && zs*ze>0)layersCrossed = this->ExpectedLayersCrossed(zs, ze, helix); } // project cluster back to TPC cage - how close to track fitResult mipFit = pCi->MipFit(); if(mipFit.ok){ float tpcx = trackAR->getTpcIntersection()[0]; float tpcy = trackAR->getTpcIntersection()[1]; float tpcz = trackAR->getTpcIntersection()[2]; float deltaX = pCi->GetCentroid(firstLayer)[0]-tpcx; float deltaY = pCi->GetCentroid(firstLayer)[1]-tpcy; float deltaZ = pCi->GetCentroid(firstLayer)[2]-tpcz; float deltar = sqrt(deltaX*deltaX+deltaY*deltaY+deltaZ*deltaZ); float x = mipFit.intercept[0]; float y = mipFit.intercept[1]; float z = mipFit.intercept[2]; float cx = mipFit.dir[0]; float cy = mipFit.dir[1]; float cz = mipFit.dir[2]; // equation of mipfit: r = (x,y,z) + alpha * (cx,cy,cz) if(deltar < 1000.){ if( fabs(pCi->GetCentroid(firstLayer)[2]) > _zOfEndcap && fabs(cz)>0.001){ float alpha; if(pCi->GetCentroid(firstLayer)[2]>0){ alpha = (_tpcZmax - z)/cz; }else{ alpha = (-_tpcZmax - z)/cz; } float xp = x + cx*alpha; float yp = y + cy*alpha; float zp = z + cz*alpha; float delta = sqrt( (xp-tpcx)*(xp-tpcx) + (yp-tpcy)*(yp-tpcy) + (zp-tpcz)*(zp-tpcz) ); if(delta1 && delta<250)std::cout << " PD Endcap : " << xp << "," << yp << "," << zp << " => " << delta << std::endl; } }else{ // solve quadratic to fit intersection with TPC cage (assumed cylidrical) float r0 = sqrt(x*x+y*y); float b = 2*(cx*x+cy*y); float c = r0*r0 - _tpcOuterR*_tpcOuterR; if(b*b-4*c > 0){ float alphap = -b/2. + 0.5*sqrt(b*b-4*c); float xp = x + cx*alphap; float yp = y + cy*alphap; float zp = z + cz*alphap; float delta = sqrt( (xp-tpcx)*(xp-tpcx) + (yp-tpcy)*(yp-tpcy) + (zp-tpcz)*(zp-tpcz) ); if(delta1 && delta<250)std::cout << " PD Barrelp : " << xp << "," << yp << "," << zp << " => " << delta << std::endl; } float alpham = -b/2. - 0.5*sqrt(b*b-4*c); xp = x + cx*alpham; yp = y + cy*alpham; zp = z + cz*alpham; delta = sqrt( (xp-tpcx)*(xp-tpcx) + (yp-tpcy)*(yp-tpcy) + (zp-tpcz)*(zp-tpcz) ); if(delta1 && delta<250)std::cout << " PD Barrelm : " << xp << "," << yp << "," << zp << " => " << delta << std::endl; } } } } } if(layersCrossed<100){ float refs[3]; refs[0] = helix->getReferencePoint()[0]; refs[1] = helix->getReferencePoint()[1]; refs[2] = helix->getReferencePoint()[2]; int lastLayer = firstLayer+20; int layerCount = 0; if(pCj->MipFraction()>0.8){ if(pCj->LastLayer()+10>lastLayer)lastLayer =pCj->LastLayer()+10; layerCount = -999; } if(lastLayer>MAX_NUMBER_OF_LAYERS)lastLayer=MAX_NUMBER_OF_LAYERS-1; float average = 0.; float count = 0.; float closest = 99999.; for(int ilayer = firstLayer;ilayer<=lastLayer;ilayer++){ if(pCi->hitsInLayer(ilayer)>0)layerCount++; for(int ihit = 0; layerCount<10 && ihit< pCi->hitsInLayer(ilayer);ihit++){ float hitxyz[3]; float dist[3]; hitxyz[0] = pCi->hitInLayer(ilayer,ihit)->getPosition()[0]; hitxyz[1] = pCi->hitInLayer(ilayer,ihit)->getPosition()[1]; hitxyz[2] = pCi->hitInLayer(ilayer,ihit)->getPosition()[2]; helix->getDistanceToPoint(hitxyz, dist); average+= dist[2]; count+=1.; if(dist[2]0.5)average = average/count; if(count<0.5)average = 99999.; if(closestEnergyHAD(); contact.chi = this->ChiClusterTrack(pCj); // fraction of hits within 100mm of hit in other cluster contact.clusterFractionWithin100 = pCj->FractionOfCloseHits(pCi,100.); contact.clusterFractionWithin50 = pCj->FractionOfCloseHits(pCi, 50.); // look at separation between closest hits in clusters float distance = pCj->DistanceToClosestHit(pCi); contact.minimumDistance = distance; // look at fraction of pCi in cone of pCj contact.coneFraction25 = pCj->FractionInRadialCone(pCi,0.90); contact.coneFraction18 = pCj->FractionInRadialCone(pCi,0.95); contact.coneFraction10 = pCj->FractionInRadialCone(pCi,0.985); // look at angular separation - NOT YET contact.angularSeparation = 99999.; contact.leavingCluster = this->IsClusterLeavingDetector(pCj); if(contact.leavingCluster && _foundMuonCollection){ int count = 0; int lastLayer = pCj->FirstLayer(); float xc = pCj->GetCentroid(lastLayer)[0]; float yc = pCj->GetCentroid(lastLayer)[1]; float zc = pCj->GetCentroid(lastLayer)[2]; float rc = sqrt(xc*xc+yc*yc+zc*zc); for(unsigned int i=0;i<_muonHits.size();++i){ float x = _muonHits[i]->getPosition()[0]; float y = _muonHits[i]->getPosition()[1]; float z = _muonHits[i]->getPosition()[2]; float r = sqrt(x*x+y*y+z*z); float dcos = (x*xc+y*yc+z*zc)/r/rc; if(dcos>0.8)count++; } contact.muonCount = count; } return contact; } void PandoraPFAProcessor::initialiseEvent( LCEvent * evt ) { // Unpack the calorimeter hits into internal structures typedef const std::vector StringVec ; std::vector caloHitsTemp; LCCollection* _tpcTracks; //************************************************************************** // Track Collections //************************************************************************** // save the pointer to the track collection _tracks = evt->getCollection( _trackCollections[0].c_str() ); if(_tracks==0 && _printing>2)std::cout << " Error : no track collection found " << std::endl; // form extended tracks which include projections to ECAL front face try { _tpcTracks = evt->getCollection("TPCTracks"); } catch(DataNotAvailableException &e){ streamlog_out(WARNING) << " PandoraPFAProcessor::initialiseEvent can't find collection TPCTracks (will not effect performance)" << std::endl; _tpcTracks = NULL; } // **************************** // ************ Vertices ******* // ***************************** _externalV0s.clear(); for (unsigned int i=0; i < _v0VertexCollections.size(); ++i) { try { LCCollection * col = evt->getCollection( _v0VertexCollections.at(i).c_str() ); if (col != 0) { int nelem = col->getNumberOfElements(); for (int j=0; j < nelem; ++j) { Vertex* v = dynamic_cast(col->getElementAt(j)); ReconstructedParticle* part = v->getAssociatedParticle(); TrackVec tracks = part->getTracks(); int goodTracks = 0; for(unsigned int it = 0;itgetTrackerHits(); float nhits = (float)hitvec.size(); for(unsigned int itrack=0;itrack<_tracksAR.size();++itrack){ if(t==_tracksAR[itrack]->getTrack() && _printing>0)std::cout << " VERTEX " << j << " " << _tracksAR[itrack]->getEnergy() << std::endl; if(nhits>=_minimumTrackHits)goodTracks++; } } if(goodTracks>=2)_externalV0s.push_back(v); } } } catch(DataNotAvailableException &e){ streamlog_out(WARNING) << " PandoraPFAProcessor::initialiseEvent no vertex collection " << _v0VertexCollections.at(i).c_str() << std::endl; } } // get track relations _trackNavigator = NULL; _relationTrackCollection = NULL; try { _relationTrackCollection = evt->getCollection(_relationTrackString.c_str()); } catch(DataNotAvailableException &e){ streamlog_out(WARNING) << " PandoraPFAProcessor::initialiseEvent No relation exists between Sim and Track hits" << std::endl; } if(_relationTrackCollection!=NULL)_trackNavigator = new LCRelationNavigator(_relationTrackCollection); std::setusedTrackerHits; std::settpcTrackTrackerHits; std::setallTrackerHits; std::setcurlKilledTrackerHits; if(_tracks!=0 && _ignoreTracks==0){ if(_printing>2)std::cout << "TRACKS " <<_tracks->getNumberOfElements() << std::endl; int nelem = _tracks->getNumberOfElements(); for (int j=0; j < nelem; ++j) { Track* track = dynamic_cast(_tracks->getElementAt(j)); // find corresponding MC particle MCParticle* mcpart = NULL; TrackerHitVec hitvec = track->getTrackerHits(); int nhits = (int)hitvec.size(); for(int i=0;igetRelatedToObjects(track); if (objectVec.size() > 0)mcpart = dynamic_cast(objectVec[0]); } MyTrackExtended * trackAR = new MyTrackExtended(track); trackAR->setMCParticle(mcpart); defineIntersection(trackAR); defineAltIntersection(trackAR); bool goodTrack = false; if(nhits>=_minimumTrackHits)goodTrack = true; // remove VTX background if(_usingVertexBackgroundCuts && goodTrack){ int nonSiHits = trackAR->nonSiHits(); float px = trackAR->getMomentum()[0]; float py = trackAR->getMomentum()[1]; float pz = trackAR->getMomentum()[2]; float p = sqrt(px*px+py*py+pz*pz); float cost = fabs(pz)/p; float pT = sqrt(px*px+py*py); if( cost<0.90 && pT < 1.0 && p < 2.0){ int vtxHits = track->getSubdetectorHitNumbers()[0]; int ftdHits = track->getSubdetectorHitNumbers()[1]; int sitHits = track->getSubdetectorHitNumbers()[2]; int tpcHits = track->getSubdetectorHitNumbers()[3]; if(pT<0.2)goodTrack = false; if( sitHits==0 && tpcHits < 10 && ftdHits== 0)goodTrack = false; if(!goodTrack)std::cout << " Killing background track : " << p << " pt = " << pT << " " << nhits << "(" << nonSiHits << ")" << std::endl; } } if(goodTrack){ _tracksAR.push_back( trackAR ); }else{ delete trackAR; } } } if(_printing>1)std::cout << " USED TRACKER HITS : " << usedTrackerHits.size() << std::endl; // for debugging pass lists of unused TPC hits to event display if(_displayUnusedTpcHits>0){ // get collection of hits killed by curl Killer _curlKilledHits = evt->getCollection( _curlKilledHitCollections[0].c_str() ); nelem = _curlKilledHits->getNumberOfElements(); if(_printing>1)std::cout << " CURL KILLED TRACKER HITS : " << nelem << std::endl; for (int j=0; j < nelem; ++j) { TrackerHit* trackerHit = dynamic_cast(_curlKilledHits->getElementAt(j)); if(usedTrackerHits.count(trackerHit)==0){ curlKilledTrackerHits.insert(trackerHit); _curlKilledTpcTrackerHits.push_back(trackerHit); } } if(_tpcTracks!=0){ if(_printing>2)std::cout << " TPC TRACKS " <<_tpcTracks->getNumberOfElements() << std::endl; int nelem = _tpcTracks->getNumberOfElements(); for (int j=0; j < nelem; ++j) { Track* track = dynamic_cast(_tpcTracks->getElementAt(j)); TrackerHitVec hitvec = track->getTrackerHits(); int nhits = (int)hitvec.size(); for(int i=0;igetCollection( _tpcHitCollections[0].c_str() ); nelem = _tpcTrackerHits->getNumberOfElements(); if(_printing>1)std::cout << " TPC TRACKER HITS : " << nelem << std::endl; int counter = 0; for (int j=0; j < nelem; ++j) { TrackerHit* trackerHit = dynamic_cast(_tpcTrackerHits->getElementAt(j)); if(usedTrackerHits.count(trackerHit)==0 && curlKilledTrackerHits.count(trackerHit)==0){ counter++; // _unusedTpcTrackerHits.push_back(trackerHit); } } if(_printing>1)std::cout << " UNUSED TPC TRACKER HITS : " << counter << std::endl; // tell the display about the unused hits if(_recoDisplay!=NULL)_recoDisplay->SetUnusedTPCHits(_unusedTpcTrackerHits); if(_recoDisplay!=NULL)_recoDisplay->SetCurlKilledTPCHits(_curlKilledTpcTrackerHits); } if(_searchForBackScatters>0)searchForBackScatterTracks(); if(_searchForSplitTracks>0)searchForSplitTracks(); if(_searchForProngs>0)searchForProngs(); if(_searchForKinks>0)searchForKinks(); if(_searchForV0s>0)searchForV0s(); // tell the display about the tracks if(_recoDisplay!=NULL)_recoDisplay->SetTrackAR(_tracksAR); } // get Calorimeter relations _relationCaloCollection = NULL; try { _relationCaloCollection = evt->getCollection(_relationCaloString.c_str()); } catch(DataNotAvailableException &e){ streamlog_out(WARNING) << " PandoraPFAProcessor::initialiseEvent No relation exists between Sim and Calo hits" << std::endl; } if(_relationCaloCollection!=NULL)_caloNavigator = new LCRelationNavigator(_relationCaloCollection); // get muon relations _relationMuonCollection = NULL; try { _relationMuonCollection = evt->getCollection(_relationMuonString.c_str()); } catch(DataNotAvailableException &e){ streamlog_out(WARNING) << " PandoraPFAProcessor::initialiseEvent No relation exists between Sim and Muon hits" << std::endl; } if(_relationMuonCollection!=NULL)_muonNavigator = new LCRelationNavigator(_relationMuonCollection); // First deal with muon chamber hits - these are treated separately from the // calorimeter hits _maxMuonLayer=0; _foundMuonCollection = false; // read MUON hits for (unsigned int i=0; i < _muonCollections.size(); ++i) { try { LCCollection * col = evt->getCollection( _muonCollections.at(i).c_str() ); if (col != 0) { _foundMuonCollection = true; int nelem = col->getNumberOfElements(); string initString = col->getParameters().getStringVal(LCIO::CellIDEncoding); string layerCoding = "K-1"; if(initString.find("K-1")!=string::npos)layerCoding = "K"; if(_printing>1)std::cout << " MUON COLLECTION : " << _muonCollections.at(i).c_str() << " " << nelem << " " << initString << std::endl; CellIDDecoder id( col ) ; for (int j=0; j < nelem; ++j) { CalorimeterHit* hit = dynamic_cast(col->getElementAt(j)); _muonHits.push_back(hit); int trueLayer=-999; int stave=-999; int module=-999; if(_cellIDCoding=="Mokka"){ trueLayer = id( hit )["K-1"]; // + 1; stave = id( hit )["S-1"]; module = id( hit )["M"]; } // make the extended hit MyCaloHitExtended *calohit = new MyCaloHitExtended(hit,CALHITTYPE_MUON); float E = hit->getEnergy(); E= _muonHitEnergy; calohit->setPseudoEnergy(E); calohit->setEnergyInMips(E); calohit->setEnergyEM(E); calohit->setEnergyHAD(E); calohit->setPhysicalLayer(trueLayer); unsigned int pseudoLayer = trueLayer+_nHcalLayers+_nEcalLayers; calohit->setPseudoLayer(pseudoLayer); calohit->setMipCandidateFlag(true); calohit->setModule(module); float padSize = 30.; // _padSizeMuon; calohit->setHitSizeZ(padSize); calohit->setHitSizePhi(padSize); _muonHitsByLayer[pseudoLayer].push_back(calohit); if(pseudoLayer>_maxMuonLayer)_maxMuonLayer = pseudoLayer; } } } catch(DataNotAvailableException &e) {}; } // tell the display about the muon hits if(_recoDisplay!=NULL)_recoDisplay->SetMuon(_muonHits); // read ECAL hits if(_printing>1)std::cout << " READ ECAL HITS " << std::endl; for (unsigned int i=0; i < _ecalCollections.size(); ++i) { try { LCCollection * col = evt->getCollection( _ecalCollections.at(i).c_str() ); if (col != 0) { int nelem = col->getNumberOfElements(); string initString = col->getParameters().getStringVal(LCIO::CellIDEncoding); string layerCoding = "K-1"; if(initString.find("K-1")==string::npos)layerCoding = "K"; if(_printing>1)std::cout << " ECAL COLLECTION : " << _ecalCollections.at(i).c_str() << " " << nelem << " " << initString << std::endl; CellIDDecoder id( col ) ; for (int j=0; j < nelem; ++j) { CalorimeterHit * hit = dynamic_cast(col->getElementAt(j)); int trueLayer=-999; int stave=-999; int module=-999; if(_cellIDCoding=="Mokka"){ trueLayer = id( hit )["K-1"]; // + 1; stave = id( hit )["S-1"]; module = id( hit )["M"]; } if(_cellIDCoding=="Jupiter"){ } float outerScale = 1.0; if(_absThicknessBarrelLayer[1]>0){ outerScale = _absThicknessBarrelLayer[trueLayer]/_absThicknessBarrelLayer[1]; } float energyInMips=1.0; if(_digitalECAL==0){ energyInMips = hit->getEnergy()*_ecalToMIP; energyInMips = energyInMips/outerScale; } float energyEM = energyInMips*_ecalEMMIPToGeV; float energyHAD = energyInMips*_ecalHadMIPToGeV; energyEM = energyEM*outerScale; energyHAD = energyHAD*outerScale; if(energyInMips>_ecalMIPThreshold){ MyCaloHitExtended *calohit = new MyCaloHitExtended(hit,CALHITTYPE_ECAL); calohit->setPseudoEnergy(energyInMips); calohit->setEnergyInMips(energyInMips); calohit->setEnergyEM(energyEM); calohit->setEnergyHAD(energyHAD); calohit->setPhysicalLayer(trueLayer); calohit->setMipCandidateFlag(true); calohit->setModule(module); float x = hit->getPosition()[0]; float y = hit->getPosition()[1]; float z = hit->getPosition()[2]; float r = sqrt(x*x+y*y+z*z); if(_digitalECAL==0){ // check if hit has having too much energy for a single MIP float angularCorrection=1.; if(fabs(z)<_zOfEndcap){ angularCorrection = r/sqrt(x*x+y*y); if(stave>0)_barrelCalHitsByStaveLayer[stave][trueLayer].push_back(calohit); }else{ angularCorrection = r/fabs(z); if(stave>0)_endcapCalHitsByStaveLayer[stave][trueLayer].push_back(calohit); } float mipcut = _mipLikeMipCut*angularCorrection; if(energyInMips>mipcut)calohit->setMipCandidateFlag(false); } caloHitsTemp.push_back(calohit); } } } } catch(DataNotAvailableException &e) {}; } // read hCAL hits for (unsigned int i=0; i < _hcalCollections.size(); ++i) { try { LCCollection * col = evt->getCollection( _hcalCollections.at(i).c_str() ); if (col != 0) { int nelem = col->getNumberOfElements() ; LCFlagImpl flag( col->getFlag() ) ; string initString = col->getParameters().getStringVal(LCIO::CellIDEncoding); string layerCoding = "K-1"; if(initString.find("K-1")==string::npos)layerCoding = "K"; if(_printing>1)std::cout << " HCAL COLLECTION : " << _hcalCollections.at(i).c_str() << " " << nelem << " " << initString << std::endl; CellIDDecoder id( col ) ; for (int j=0; j < nelem; ++j) { CalorimeterHit * hit = dynamic_cast(col->getElementAt(j)); float energyInMips = hit->getEnergy()*_hcalToMIP; float energyEM = energyInMips*_hcalEMMIPToGeV; float energyHAD = energyInMips*_hcalHadMIPToGeV; if(energyInMips>_hcalMIPThreshold){ MyCaloHitExtended *calohit = new MyCaloHitExtended(hit,CALHITTYPE_HCAL); calohit->setPseudoEnergy(energyInMips); calohit->setEnergyInMips(energyInMips); calohit->setEnergyEM(energyEM); calohit->setEnergyHAD(energyHAD); int trueLayer=-999; int stave=-999; int module=-999; if(_cellIDCoding=="Mokka"){ trueLayer = id( hit )["K-1"]; // + 1; stave = id( hit )["S-1"]; module = id( hit )["M"]; } // std::cout << "HCAL : " << stave << " " << module << " " << "l= " << trueLayer << " e= " << energyHAD << std::endl; calohit->setPhysicalLayer(trueLayer); calohit->setMipCandidateFlag(true); if(_digitalHCAL==0){ // check if hit has having too much energy for a single MIP float x = hit->getPosition()[0]; float y = hit->getPosition()[1]; float z = hit->getPosition()[2]; float r = sqrt(x*x+y*y+z*z); float angularCorrection=1.; if(fabs(z)<_zOfEndcap){ angularCorrection = r/sqrt(x*x+y*y); }else{ angularCorrection = r/fabs(z); } float mipcut = _mipLikeMipCut*angularCorrection; if(energyInMips>mipcut)calohit->setMipCandidateFlag(false); } caloHitsTemp.push_back(calohit); } } } } catch(DataNotAvailableException &e) {}; } // read LCAL hits for (unsigned int i=0; i < _lcalCollections.size(); ++i) { try { LCCollection * col = evt->getCollection( _lcalCollections.at(i).c_str() ); if (col != 0) { bool warned = false; int nelem = col->getNumberOfElements() ; if(nelem>0){ string initString = col->getParameters().getStringVal(LCIO::CellIDEncoding); string layerCoding = "K-1"; if(initString.find("K-1")==string::npos)layerCoding = "K"; if(_printing>1)std::cout << " LCAL COLLECTION : " << _lcalCollections.at(i).c_str() << " " << nelem << " " << initString << std::endl; LCFlagImpl flag( col->getFlag() ) ; CellIDDecoder id( col ) ; for (int j=0; j < nelem; ++j) { CalorimeterHit * hit = dynamic_cast(col->getElementAt(j)); float energyInMips =1.0; if(_digitalHCAL==0)energyInMips = hit->getEnergy()*_hcalToMIP; if(_digitalHCAL==1)energyInMips = 1.0; float energyEM = energyInMips*_hcalEMMIPToGeV; float energyHAD = energyInMips*_hcalHadMIPToGeV; if(energyInMips>_hcalMIPThreshold){ MyCaloHitExtended *calohit = new MyCaloHitExtended(hit,CALHITTYPE_LCAL); calohit->setPseudoEnergy(energyInMips); calohit->setEnergyInMips(energyInMips); calohit->setEnergyEM(energyEM); calohit->setEnergyHAD(energyHAD); int trueLayer = id( hit )[layerCoding.c_str()]; if(trueLayer<1){ if(!warned){ streamlog_out(WARNING) << " PandoraPFAProcessor::initialiseEvent couldn't determine BCAL layer : " << trueLayer << " set to 1" << std::endl; warned = true; } trueLayer=1; } calohit->setPhysicalLayer(trueLayer); calohit->setMipCandidateFlag(true); if(_digitalHCAL==0){ // check if hit has having too much energy for a single MIP float mipcut = _mipLikeMipCut; if(energyInMips>mipcut)calohit->setMipCandidateFlag(false); } caloHitsTemp.push_back(calohit); } } } } } catch(DataNotAvailableException &e) {}; } // read BCAL hits for (unsigned int i=0; i < _bcalCollections.size(); ++i) { try { LCCollection * col = evt->getCollection( _bcalCollections.at(i).c_str() ); if (col != 0) { bool warned = false; int nelem = col->getNumberOfElements(); if(nelem>0){ string initString = col->getParameters().getStringVal(LCIO::CellIDEncoding); if(_printing>1)std::cout << " BCAL COLLECTION : " << _bcalCollections.at(i).c_str() << " " << nelem << " " << initString << std::endl; string layerCoding = "K-1"; if(initString.find("K-1")==string::npos)layerCoding = "K"; CellIDDecoder id( col ) ; for (int j=0; j < nelem; ++j) { CalorimeterHit * hit = dynamic_cast(col->getElementAt(j)); float energyInMips =1.0; if(_digitalHCAL==0)energyInMips = hit->getEnergy()*_hcalToMIP; if(_digitalHCAL==1)energyInMips = 1.0; float energyEM = energyInMips*_hcalEMMIPToGeV; float energyHAD = energyInMips*_hcalHadMIPToGeV; if(energyInMips>_hcalMIPThreshold){ MyCaloHitExtended *calohit = new MyCaloHitExtended(hit,CALHITTYPE_BCAL); calohit->setPseudoEnergy(energyInMips); calohit->setEnergyInMips(energyInMips); calohit->setEnergyEM(energyEM); calohit->setEnergyHAD(energyHAD); int trueLayer = id( hit )[layerCoding.c_str()]; if(trueLayer<1){ if(!warned){ streamlog_out(WARNING) << " PandoraPFAProcessor::initialiseEvent couldn't determine BCAL layer : " << trueLayer << " set to 1" << std::endl; warned = true; } trueLayer=1; } calohit->setPhysicalLayer(trueLayer); calohit->setMipCandidateFlag(true); if(_digitalHCAL==0){ // check if hit has having too much energy for a single MIP float mipcut = _mipLikeMipCut; if(energyInMips>mipcut)calohit->setMipCandidateFlag(false); } caloHitsTemp.push_back(calohit); } } } } } catch(DataNotAvailableException &e) {}; } // read LHCAL hits for (unsigned int i=0; i < _lhcalCollections.size(); ++i) { try { LCCollection * col = evt->getCollection( _lhcalCollections.at(i).c_str() ); if (col != 0) { bool warned = false; int nelem = col->getNumberOfElements() ; if(nelem>0){ string initString = col->getParameters().getStringVal(LCIO::CellIDEncoding); if(_printing>1)std::cout << " LHCAL COLLECTION : " << _lhcalCollections.at(i).c_str() << " " << nelem << " " << initString << std::endl; string layerCoding = "K-1"; if(initString.find("K-1")==string::npos)layerCoding = "K"; CellIDDecoder id( col ) ; for (int j=0; j < nelem; ++j) { CalorimeterHit * hit = dynamic_cast(col->getElementAt(j)); float energyInMips =1.0; if(_digitalHCAL==0)energyInMips = hit->getEnergy()*_hcalToMIP; if(_digitalHCAL==1)energyInMips = 1.0; float energyEM = energyInMips*_hcalEMMIPToGeV; float energyHAD = energyInMips*_hcalHadMIPToGeV; if(energyInMips>_hcalMIPThreshold){ MyCaloHitExtended *calohit = new MyCaloHitExtended(hit,CALHITTYPE_LHCAL); calohit->setPseudoEnergy(energyInMips); calohit->setEnergyInMips(energyInMips); calohit->setEnergyEM(energyEM); calohit->setEnergyHAD(energyHAD); int trueLayer = id( hit )[layerCoding.c_str()] + 1; if(trueLayer<1){ if(!warned){ streamlog_out(WARNING) << " PandoraPFAProcessor::initialiseEvent couldn't determine LHCAL layer : " << trueLayer << " set to 1" << std::endl; warned = true; } trueLayer=1; } calohit->setPhysicalLayer(trueLayer); calohit->setMipCandidateFlag(true); if(_digitalHCAL==0){ // check if hit has having too much energy for a single MIP float mipcut = _mipLikeMipCut; if(energyInMips>mipcut)calohit->setMipCandidateFlag(false); } caloHitsTemp.push_back(calohit); } } } } } catch(DataNotAvailableException &e) {}; } if(_printing>3)std::cout << " PandoraPFAProcessor::initialiseEvent now assign hits to pseudolayers " << std::endl; // Arrange hits into pseudolayers int count =0; _maxLayer = 0; for(unsigned int i=0;iCylinderAssignToPseudoLayer(hiti); if(_symmetry==1)this->ProtoAssignToPseudoLayer(hiti); if(_symmetry>=2)this->PolygonAssignToPseudoLayer(hiti); if(_cellIDCoding=="Mokka")trueLayer = hiti->getPhysicalLayer(); unsigned int psLayer = hiti->getPseudoLayer(); if(psLayer>_maxLayer)_maxLayer = psLayer; if(_detector==DETECTOR_GLD){ trueLayer = psLayer; hiti->setPhysicalLayer(trueLayer); if( hiti->getCalorimeterHitType()==CALHITTYPE_HCAL )trueLayer =psLayer-33; } float padSize = _padSizeEcal[1]; if( hiti->getCalorimeterHitType()==CALHITTYPE_ECAL )padSize = _padSizeEcal[trueLayer]; if( hiti->getCalorimeterHitType()==CALHITTYPE_HCAL )padSize = _padSizeHcal[trueLayer]; // for now use coarse clustering for LCAL, LHCAL and MUON if( hiti->getCalorimeterHitType()==CALHITTYPE_BCAL )padSize = _padSizeHcal[1]; if( hiti->getCalorimeterHitType()==CALHITTYPE_LHCAL )padSize = _padSizeHcal[1]; if( hiti->getCalorimeterHitType()==CALHITTYPE_LCAL )padSize = _padSizeHcal[1]; if( hiti->getCalorimeterHitType()==CALHITTYPE_MUON )padSize = _padSizeHcal[1]; hiti->setHitSizeZ(padSize) ; hiti->setHitSizePhi(padSize); if(trueLayer<0){ streamlog_out(ERROR) << " ERROR in determining pad Sizes :" << _detectorName << ": " << trueLayer << std::endl; } bool veto = this->TruncateHCAL(hiti); veto = false; if(!veto)_allCalHitsByPseudoLayer[psLayer].push_back(hiti); if(veto)delete hiti; count++; } // Assign density weights to hits and tag hits as mip-like or not if(_printing>3)std::cout << " PandoraPFAProcessor::initialiseEvent make densitiy weights " << std::endl; this->MakeDensityWeights(); // associate hits and tracks to "true mc pfos" this->ExtractMcPfoInfo(); if(_printing>3)std::cout << " PandoraPFAProcessor::initialiseEvent done" << std::endl; } bool PandoraPFAProcessor::TruncateHCAL(MyCaloHitExtended* hit){ bool veto = false; if(hit->getCalorimeterHitType()==CALHITTYPE_HCAL){ int trueLayer = hit->getPhysicalLayer(); if(trueLayer>_maxHCALLayer-10){ float z = (hit->getCalorimeterHit())->getPosition()[2]; // in barrel may have different ECAL/HCAL geometry if(fabs(z)>_zOfEndcap && trueLayer>=_maxHCALLayer)veto=true; // for barrel and outer extent of endcap HCAL // need to implement precise geometry float x = (hit->getCalorimeterHit())->getPosition()[0]; float y = (hit->getCalorimeterHit())->getPosition()[1]; float prodRadiusMax=0.; for(int istave = 0; istave < _HCALsymmetry; ++istave){ float prodRadius = x*_barrelStaveDirHCAL[istave].x+y*_barrelStaveDirHCAL[istave].y; if(prodRadius>prodRadiusMax)prodRadiusMax=prodRadius; } int iradius = (int)prodRadiusMax; int ll = _hcalLayerForIntRadius[iradius]; if(ll>_maxHCALLayer+_nEcalLayers)veto=true; } } return veto; } void PandoraPFAProcessor::OrderHitsInEachLayer(){ for(unsigned int ilayer=0;ilayer<=_maxLayer;++ilayer){ BubbleSort(_calHitsByPseudoLayer[ilayer]); } } void PandoraPFAProcessor::BubbleSort(MyCaloHitExtendedVec & input) { // ORDER HITS : LOWEST TO HIGHEST GENERIC DISTANCE unsigned int sizeOfVector = input.size(); if(sizeOfVector<2)return; MyCaloHitExtended *one,*two,*Temp; for (unsigned int i = 0 ; i < sizeOfVector-1; i++){ for (unsigned int j = 0; j < sizeOfVector-i-1; j++){ one = input.at(j); two = input.at(j+1); if(one->getGenericDistance() > two->getGenericDistance()){ Temp = input[j]; input[j] = input[j+1]; input[j+1] = Temp; } } } } void PandoraPFAProcessor::Quicksort(MyCaloHitExtendedVec & input, int left, int right) { //more than one element left if(right>left){ int i=left-1, j=right; MyCaloHitExtended * tmp; //infinite loop, stops if i >=j for(;;){ //increm. until larger lelement found while(input[++i]->getGenericDistance()getGenericDistance()); //decrem., until smaller element found while(input[--j]->getGenericDistance()>input[right]->getGenericDistance() && j>i); //kill, if pointers meet if(i>=j) break; //swap elements tmp=input[i]; input[i]=input[j]; input[j]=tmp; } //swap separator tmp=input[i]; input[i]=input[right]; input[right]=tmp; //recursive call for left subsequence Quicksort(input, left, i-1); //recursive call for right subsequence Quicksort(input, i+1, right); } } void PandoraPFAProcessor::combineProtoClusters(ProtoClusterVec &input, ProtoClusterVec &combined){ combined.clear(); for(unsigned int icluster=0;iclusterIsDefunct()==false){ int originatorID = input[icluster]->getEarliestRelationID(); bool found = false; for(unsigned int icombcluster=0;icombclustergetEarliestRelationID(); if(originatorID==combID){ for(int ihit = 0; ihit Hits();++ihit){ MyCaloHitExtended* hiti = input[icluster]->Hit(ihit); combined[icombcluster]->AddHit(hiti); } for(int ihit = 0; ihit IsolatedHits();++ihit){ MyCaloHitExtended* hiti = input[icluster]->IsolatedHit(ihit); combined[icombcluster]->AddIsolatedHit(hiti); } found = true; } } if(!found && input[icluster]->Hits() > 0){ MyCaloHitExtended* hiti = input[icluster]->Hit(0); ProtoCluster* newCluster = (ProtoClusterFactory::Instance())->Manufacture(hiti); for(int ihit = 1; ihit Hits();++ihit){ MyCaloHitExtended* hiti = input[icluster]->Hit(ihit); newCluster->AddHit(hiti); } for(int ihit = 0; ihit IsolatedHits();++ihit){ MyCaloHitExtended* hiti = input[icluster]->IsolatedHit(ihit); newCluster->AddIsolatedHit(hiti); } newCluster->SetID(originatorID); combined.push_back(newCluster); } } } if(_printing>2)std::cout << std::flush; for(unsigned int icluster=0;iclusterUpdate(MAX_NUMBER_OF_LAYERS-1); combined[icluster]->ClassifyYourself(); } for(unsigned int icluster=0;iclusterIsNowDefunct(); } } void PandoraPFAProcessor::makeFinalProtoClusters(ProtoClusterVec &input, ProtoClusterVec &final){ final.erase(final.begin(),final.end()); this->combineProtoClusters(input, final); for(unsigned int icluster=0;iclusterUpdate(MAX_NUMBER_OF_LAYERS-1); final[icluster]->ClassifyYourself(); } } void PandoraPFAProcessor::performPFA(){ float trackE = 0.; float photonE = 0.; float hadronicE = 0.; float lowEM = 0.; float lowHAD = 0.; float lowpt = 0.; float fwdtrack = 0.; // track association if(_printing>1){ std::cout << "************************" << std::endl; std::cout << " PARTICLE FLOW ANALYSIS " << std::endl; std::cout << "************************" << std::endl; } if(_clusterCleaning)this->CleanClusters(_finalProtoClusters); this->ClusterTrackAssociation(_finalProtoClusters,_tracksAR,false); // also try with Alternative track projection this->AltClusterTrackAssociation(_finalProtoClusters,_tracksAR,false); // Soft Photon ID for(unsigned int icluster=0;icluster<_finalProtoClusters.size();++icluster){ _finalProtoClusters[icluster]->SoftPhotonID(); } // Classify tracks this->ClassifyTracks(_finalProtoClusters,_tracksAR,false); // Match looping tracks to endcap clusters if(_extraLooperMatching>0)this->ClusterLoopingTrackAssociation(_finalProtoClusters,_tracksAR,false); // now try with tracks that fail d0/z0 cuts this->ClusterNonVertexTrackAssociation(_finalProtoClusters,_tracksAR,false); // now try with tracks that fail d0/z0 cuts this->FinalTrackRecovery(_finalProtoClusters,_tracksAR,false); this->FinalTrackRecoveryHelix(_finalProtoClusters,_tracksAR,false); this->FinalTrackRecoveryInteractions(_finalProtoClusters,_tracksAR,false); if(_printing>5)std::cout << " Track association done" << std::endl; // MAKE DUMMY CLUSTER OUT OF ISOLATED HITS if(_formClusterFromUnusedIsolatedHits>0){ if(_unusedIsolatedHits.size()>0){ ProtoCluster* pCisol = (ProtoClusterFactory::Instance())->Manufacture(_unusedIsolatedHits[0]); for(unsigned int i=1;i<_unusedIsolatedHits.size();i++){ pCisol->AddHit(_unusedIsolatedHits[i] ); } pCisol->Update(MAX_NUMBER_OF_LAYERS); pCisol->ClassifyYourself(); _finalProtoClusters.push_back(pCisol); } } // look for hadron clusters with anomalous energy for number of hits this->scaleHotHadrons(); if(_printing>5)std::cout << " scale Hot done" << std::endl; // ATTEMPT TO MATCH CLUSTERS AND TRACKS WITH IDEAL PFOs from MC // analyse tracks vector pMcPFOs; if(_myMcTree!=NULL){ pMcPFOs = *(_myMcTree->getMCPFOs()); for(unsigned int imc=0;imcisTrack()){ float pmc[4]; pmc[0] = pMcPFOs[imc]->getMomentum()[0]; pmc[1] = pMcPFOs[imc]->getMomentum()[1]; pmc[2] = pMcPFOs[imc]->getMomentum()[2]; pmc[3] = sqrt(pmc[0]*pmc[0]+pmc[1]*pmc[1]+pmc[2]*pmc[2]); MCParticle* mcpart = pMcPFOs[imc]->getMCParticle(); float pt = sqrt(pmc[0]*pmc[0]+pmc[1]*pmc[1]); if(_trackNavigator!=NULL){ bool found = false; for(unsigned int itrack=0;itrack<_tracksAR.size();++itrack){ MyTrackExtended* trackAR = _tracksAR[itrack]; Track* track = trackAR->getTrack(); LCObjectVec objectVec = _trackNavigator->getRelatedToObjects(track); if (objectVec.size() > 0){ MCParticle* navpart = dynamic_cast(objectVec[0]); if(navpart==mcpart)found=true; } } if (!found){ if(_printing>0)std::cout << " TRACK NAVIGATION Missing Track " << pmc[2]/pmc[3] << " : " << mcpart->getEnergy() << " pt : " << pt << std::endl; if(pt > 0.000001 || mcpart->getEnergy()<100){ if(fabs(pmc[2]/pmc[3])>0.99 || pt <0.15 )fwdtrack+= mcpart->getEnergy(); } } } float dotmax = -1.0; int jbest = -999; for(unsigned int itrack=0;itrack<_tracksAR.size();itrack++){ float p[4]; p[0] = _tracksAR[itrack]->getMomentum()[0]; p[1] = _tracksAR[itrack]->getMomentum()[1]; p[2] = _tracksAR[itrack]->getMomentum()[2]; p[3] = sqrt(p[0]*p[0]+p[1]*p[1]+p[2]*p[2]); float dot = (p[0]*pmc[0]+p[1]*pmc[1]+p[2]*pmc[2])/p[3]/pmc[3]; if(dot>dotmax){ dotmax = dot; jbest = itrack; } } if(jbest>=0){ pMcPFOs[imc]->setTrack(_tracksAR[jbest]); _tracksAR[jbest]->AddMCPFO(pMcPFOs[imc]); } } // Now loop over clusters if(pMcPFOs[imc]->isPhoton() || pMcPFOs[imc]->isNeutralHadron()){ float pmc[4]; pmc[0] = pMcPFOs[imc]->getMomentum()[0]; pmc[1] = pMcPFOs[imc]->getMomentum()[1]; pmc[2] = pMcPFOs[imc]->getMomentum()[2]; pmc[3] = sqrt(pmc[0]*pmc[0]+pmc[1]*pmc[1]+pmc[2]*pmc[2]); MCParticle* mcpart = pMcPFOs[imc]->getMCParticle(); float xe = mcpart->getEndpoint()[0]; float ye = mcpart->getEndpoint()[1]; float ze = mcpart->getEndpoint()[2]; // float re = sqrt(xe*xe+ye*ye+ze*ze); float drmin = 999999.; int imin = -999; int layers = 5; if(pMcPFOs[imc]->isNeutralHadron())layers=100; for(unsigned int icluster=0;icluster<_finalProtoClusters.size();++icluster){ float dr = _finalProtoClusters[icluster]->DistanceToPoint(xe,ye,ze,layers); if(drisPhoton()){ if(drmin<25){ pMcPFOs[imc]->setCluster(_finalProtoClusters[imin]); _finalProtoClusters[imin]->AddMCPFO(pMcPFOs[imc]); } } // Neutral Hadrons if(pMcPFOs[imc]->isNeutralHadron()){ if(drmin<25){ pMcPFOs[imc]->setCluster(_finalProtoClusters[imin]); _finalProtoClusters[imin]->AddMCPFO(pMcPFOs[imc]); } } } } // second pass for clusters for(unsigned int imc=0;imcisPhoton() || pMcPFOs[imc]->isNeutralHadron()){ ProtoCluster* cluster = pMcPFOs[imc]->getCluster(); if(cluster==NULL){ float pmc[4]; pmc[0] = pMcPFOs[imc]->getMomentum()[0]; pmc[1] = pMcPFOs[imc]->getMomentum()[1]; pmc[2] = pMcPFOs[imc]->getMomentum()[2]; pmc[3] = sqrt(pmc[0]*pmc[0]+pmc[1]*pmc[1]+pmc[2]*pmc[2]); MCParticle* mcpart = pMcPFOs[imc]->getMCParticle(); float xe = mcpart->getEndpoint()[0]; float ye = mcpart->getEndpoint()[1]; float ze = mcpart->getEndpoint()[2]; // float re = sqrt(xe*xe+ye*ye+ze*ze); float drmin = 999999.; int imin = -999; int layers = 5; if(pMcPFOs[imc]->isNeutralHadron())layers=20; for(unsigned int icluster=0;icluster<_finalProtoClusters.size();++icluster){ MyMCPFOVec _mcPFOs = _finalProtoClusters[icluster]->GetMCPFOVec(); if(_mcPFOs.size()==0){ float dr = _finalProtoClusters[icluster]->DistanceToLine(xe,ye,ze,pmc[0]/pmc[3],pmc[1]/pmc[3],pmc[2]/pmc[3],layers); if(dr1)cout << " Second Search : " << pmc[3] << " drmin : " << drmin << endl; // Photons if(pMcPFOs[imc]->isPhoton()){ if(drmin<50){ pMcPFOs[imc]->setCluster(_finalProtoClusters[imin]); _finalProtoClusters[imin]->AddMCPFO(pMcPFOs[imc]); } } // Neutral Hadrons if(pMcPFOs[imc]->isNeutralHadron()){ if(drmin<50){ pMcPFOs[imc]->setCluster(_finalProtoClusters[imin]); _finalProtoClusters[imin]->AddMCPFO(pMcPFOs[imc]); } } } } } } if(_printing>5)std::cout << " mc done" << std::endl; this->identifyElectrons(_finalProtoClusters,_tracksAR); if(_photonClustering>0 && _photonClustering<3)this->AddPhotonClusters(_finalProtoClusters); // fragment removal (perfect or not) if(_perfectFragmentRemoval>0){ this->perfectFragmentRemoval(_finalProtoClusters,_tracksAR); //this->neutralHadronFragmentMerging(_finalProtoClusters,_tracksAR); }else{ if(_fragmentRemoval>0 && _perfectClustering ==0){ this->finalMipFragmentRemoval(_finalProtoClusters,_tracksAR); this->finalFragmentRemoval(_finalProtoClusters,_tracksAR); this->neutralHadronFragmentMerging(_finalProtoClusters,_tracksAR); this->FinalPhotonExtraction(_finalProtoClusters); streamlog_out(MESSAGE) << "Finished FinalPhotonExtraction" << std::endl; } } if(_photonClustering>=3)this->AddPhotonClusters(_finalProtoClusters); // do something with muon clusters if(_tailCatcher!=0)this->AddMuonClustersToPFOs(_finalProtoClusters,_tracksAR); // add back photon clusters if perfectPhotonClustering if(_perfectPhotonClustering)this->AddPerfectPhotonClusters(_finalProtoClusters); // add back neutral hadron clusters if perfectNeutralHadronClustering if(_perfectNeutralHadronClustering)this->AddPerfectNeutralHadronClusters(_finalProtoClusters); for(unsigned int itrack=0;itrack<_tracksAR.size();++itrack){ MyTrackExtended* trackAR = _tracksAR[itrack]; Track* track = trackAR->getTrack(); TrackerHitVec hitvec = track->getTrackerHits(); int nhits = (int)hitvec.size(); int nonSiHits = trackAR->nonSiHits(); float d0 = track->getD0(); float z0 = track->getZ0(); float x =trackAR->getSeedPosition()[0]; float y =trackAR->getSeedPosition()[1]; float z =trackAR->getSeedPosition()[2]; float r = sqrt(x*x+y*y); std::cout << " Track " << itrack << " Extrap : " << x << "," << y << "," << z << "," << std::endl; if(nhits >= _minimumTrackHits && fabs(d0)<_d0TrackCut && fabs(z0)<_z0TrackCut && !trackAR->reachedEcal()&&_printing>0)std::cout << " XTRACK : " << itrack << " : " << trackAR->getEnergy() << " r = " << trackAR->getInnerR() << "-" << trackAR->getOuterR() << " d/z0 : " << d0 << "," << z0 << " hits = " << nhits << "(" << nonSiHits<<")"<< " REXTRAP : " << r << std::endl; if(nhits >= _minimumTrackHits && (fabs(d0)>_d0TrackCut|| fabs(z0)>_z0TrackCut)){ if(_printing>0)std::cout << " **TRACK : " << itrack << " : " << trackAR->getEnergy() << " r = " << trackAR->getInnerR() << "-" << trackAR->getOuterR() << " d/z0 : " << d0 << "," << z0 << " hits = " << nhits << "(" << nonSiHits<<")"<< " REXTRAP : " << r << " z = " << trackAR->getZMin() << "-" << trackAR->getZMax() << std::endl; }else{ ProtoClusterVec clusters = trackAR->getClusterVec(); if(clusters.size()==0 && trackAR->trackStatus()!=TRACK_STATUS_LOWPT){ float closest = 999999.; int bestCluster =-1; for(unsigned int icluster=0;icluster<_finalProtoClusters.size();++icluster){ float approach = _finalProtoClusters[icluster]->DistanceToTrack(trackAR,10); if(approach0)std::cout << " *TRACK : " << itrack << " : " << trackAR->getEnergy() << " r = " << trackAR->getInnerR() << "-" << trackAR->getOuterR() << " d/z0 : " << d0 << "," << z0 << " hits = " << nhits << "(" << nonSiHits<<")"<< " REXTRAP : " << r << " closest : " << closest << " z = " << trackAR->getZMin() << "-" << trackAR->getZMax() << std::endl; }else{ if(_printing>0)std::cout << " TRACK : " << itrack << " : " << trackAR->getEnergy() << " r = " << trackAR->getInnerR() << "-" << trackAR->getOuterR() << " d/z0 : " << d0 << "," << z0 << " hits = " << nhits << "(" << nonSiHits<<")"<< " REXTRAP : " << r << " z = " << trackAR->getZMin() << "-" << trackAR->getZMax() << std::endl; } } } for(unsigned int iv=0; iv<_externalV0s.size();iv++){ ReconstructedParticle* part = _externalV0s[iv]->getAssociatedParticle(); TrackVec tracks = part->getTracks(); for(unsigned int it = 0;itgetTrackerHits(); float nhits = (float)hitvec.size(); float nhitsInFit = t->getNdf(); float chi2Fit = t->getChi2(); if(t==_tracksAR[itrack]->getTrack() && _printing>0)std::cout << " VERTEX " << iv << " " << _tracksAR[itrack]->getEnergy() << " hits = " << nhits << " chi2 = " << chi2Fit << "(" << nhitsInFit << ")" << std::endl; } } } streamlog_out(MESSAGE) << "Now have PFOs" << std::endl; if(_printing>0){ cout << endl; cout << " RECONSTRUCTED PARTICLE FLOW OBJECTS " << endl; cout << " ----------------------------------- " << endl; } for(unsigned int itrack=0;itrack<_tracksAR.size();itrack++){ MyTrackExtended* trackAR = _tracksAR[itrack]; if(trackAR->isKinkS()){ MyTrackExtended* daughter = _tracksAR[itrack]->getKinkDaughter(); if(daughter!=NULL){ float missing = _tracksAR[itrack]->getEnergy()-daughter->getEnergy(); ProtoClusterVec dclusters = daughter->getClusterVec(); if(_printing>0)std::cout << "KINKS : " << _tracksAR[itrack]->getEnergy() << " <-> " << daughter->getEnergy() << " " << std::endl; float m1 = this->kinkMass(_tracksAR[itrack],daughter,0.106,0.000); float m2 = this->kinkMass(_tracksAR[itrack],daughter,0.139,0.940); float m3 = this->kinkMass(_tracksAR[itrack],daughter,0.940,0.140); if(dclusters.size()==1 || daughter->getEnergy()<_energyCutForVeryLowEnergyTracks || daughter->trackStatus()==TRACK_STATUS_LOWPT){ float mipf = 1.; if(dclusters.size()==1){ mipf = dclusters[0]->MipFraction(); // if exits detector look at mip fraction in HCAL only int layersFromEdge=999; layersFromEdge = this->LayersFromEdge(dclusters[0]); float mipfHcal = 0.; if(layersFromEdge<5){ mipfHcal = dclusters[0]->MipFraction(_nEcalLayers,_nEcalLayers+_nHcalLayers); } if(_printing>0)std::cout << " KINK K+- -> mu candidate MIPF : " << mipf << " ( " << mipfHcal << ") " << " p : " << _tracksAR[itrack]->getEnergy() << " " <Hits() << " " << dclusters[0]->EnergyEM() << " dCosR " << dclusters[0]->DCosR() << std::endl; if(mipfHcal>mipf){ mipf = mipfHcal; } } float eneutral = 0.; for(unsigned int icluster=0;icluster<_finalProtoClusters.size();++icluster){ if(_finalProtoClusters[icluster]->AssociatedTrack()==false){ float fraction = _finalProtoClusters[icluster]->FractionInTrackCone(_tracksAR[itrack],0.90); // if(fraction>0.25 && _printing>1)std::cout << " KINK K Track Fraction : " << fraction << " E = " << _finalProtoClusters[icluster]->EnergyHAD() << " Photon : " << _finalProtoClusters[icluster]->IsPhoton() <IsPhoton()){ // could check photon points to decay point !!! //} if(fraction>0.25){ eneutral += _finalProtoClusters[icluster]->EnergyHAD(); } } } float chi=9999.; if(eneutral>0.25 && eneutral > 0.25*missing){ float missingEnergy = _tracksAR[itrack]->getEnergy()-daughter->getEnergy(); float dE = missingEnergy - eneutral; float sigE = _hadEnergyRes*sqrt(eneutral); if(missingEnergy>0.)sigE = _hadEnergyRes*sqrt(missingEnergy); chi = dE/sigE; if(_printing>0)std::cout << " KINK neutral : " << eneutral << " chi : " << chi << std::endl; } bool trueMuon = false; MCParticle* mci = _tracksAR[itrack]->getMCParticle(); if(mci!=NULL){ if(_tracksAR[itrack]->getEnergy()>5&& abs(mci->getPDG())==13)trueMuon = true; } if(mipf>0.7 || _tracksAR[itrack]->getEnergy()<1.0 || (mipf>0.5 && dclusters[0]->DCosR()<0.5) || trueMuon){ if(chi>10.0 || trueMuon){ lowpt+=_tracksAR[itrack]->getEnergy()-daughter->getEnergy(); if(_printing>0)std::cout << " KINK KAON - K vs sigma : " << m1 << " " << m2 << "/" << m3 << std::endl; _tracksAR[itrack]->setTrackStatus(TRACK_STATUS_CHARGED_KAON_DECAY); }else{ if(_printing>0)std::cout << " DODGY KINK KAON - K vs sigma : " << m1 << " " << m2 << "/" << m3 << std::endl; //lowpt+=_tracksAR[itrack]->getEnergy()-daughter->getEnergy(); //_tracksAR[itrack]->setTrackStatus(TRACK_STATUS_CHARGED_KAON_DECAY); } }else{ if(_printing>0)std::cout << " IGNORING KINK - K vs sigma : " << m1 << " " << m2 << "/" << m3 << std::endl; } }else{ if(_printing>0)std::cout << " IGNORING KINK - BAD DAUGHTER K vs sigma : " << m1 << " " << m2 << "/" << m3 << " " << dclusters.size() << std::endl; } } } // Track* track = trackAR->getTrack(); ProtoClusterVec clusters = trackAR->getClusterVec(); bool matched = false; MyMCPFOVec mcPFOs = trackAR->GetMCPFOVec(); if(mcPFOs.size()>0)matched=true; float etrue = 0; if(matched){ MCParticle* mcpart = mcPFOs[0]->getMCParticle(); if(mcpart!=NULL)etrue = mcpart->getEnergy(); } if(_usingNonVertexTracks && trackAR->trackStatus()==TRACK_STATUS_NON_VERTEX && trackAR->getInnerR() < _tpcInnerR+25.){ if(clusters.size()==0){ // For LDC square ECAL coverage hole if(_detector==DETECTOR_LDC00||_detector==DETECTOR_LDC01){ float x =trackAR->getSeedPosition()[0]; float y =trackAR->getSeedPosition()[1]; //float rextrap = sqrt(x*x+y*y); bool missedEcal = false; if(fabs(x)<_rInnerEcalEndcap+50. && fabs(y)<_rInnerEcalEndcap+50.)missedEcal = true; if(missedEcal)trackAR->setTrackStatus(TRACK_STATUS_LOWPT); } } } bool goodNonVertexTrack = false; if(_usingNonVertexTracks && trackAR->trackStatus()==TRACK_STATUS_NON_VERTEX && trackAR->getInnerR() < _tpcInnerR+25.)goodNonVertexTrack=true; if(_usingUnmatchedNonVertexTracks==0 && clusters.size()==0){ goodNonVertexTrack = false; } if(trackAR->trackStatus()==TRACK_STATUS_GOOD || goodNonVertexTrack){ trackE += trackAR->getEnergy(); if(_printing>0){ if(trackAR->trackStatus()==TRACK_STATUS_NON_VERTEX)std::cout << "N"; if(trackAR->isKinkE())cout << "KE"; if(trackAR->isProngE())cout << "PE"; if(trackAR->isSplitE())cout << "SE"; if(trackAR->isSplitS())cout << "SS"; if(trackAR->isV0())cout << "V0"; if(!trackAR->reachedEcal())cout << "X"; if(!(trackAR->isKinkE()||trackAR->isV0()))cout << " "; cout << " TRACK : " << trackAR->getEnergy() << " (" << etrue << ") is Matched to "; } float ematched = 0; for(unsigned int i=0;i0)cout << " : " << clusters[i]->EnergyHAD(); ematched+=clusters[i]->EnergyHAD(); float eInMips = clusters[0]->EnergyInMips(); float meanMipsPerHit = eInMips/clusters[0]->Hits(); if(_printing>0)std::cout << " (" << meanMipsPerHit << ")"; } float chi = -999.; chi = this->ChiClusterTrack(trackAR); if(clusters.size()>0){ bool isLeaving = this->IsClusterLeavingDetector(clusters[0]); if(isLeaving){ // int layersFromEdge = this->LayersFromEdge(clusters[0]); // wibble if(_printing>0)std::cout << " L (" << this->EnergyLeavingDetector(clusters[0]) << " ) " ; if(_canUseClusterForExitingTracks!=0){ if(chi>3.0){ bool veto = false; for(unsigned int jtrack=0;jtrack<_tracksAR.size();jtrack++){ float tchi = this->ChiClusterTrack(_tracksAR[jtrack]); if(tchi<-2.0){ fragmentContact_t contact = this->CalculateFragmentContactInfo(trackAR, _tracksAR[jtrack]); ProtoClusterVec clustersj = _tracksAR[jtrack]->getClusterVec(); float E = _tracksAR[jtrack]->getEnergy(); if(clustersj.size()>0)E = E - clustersj[0]->EnergyHAD() ; float newchi = this->ChiClusterTrack(trackAR,-E); veto = false; if(fabs(newchi)2)veto = true; if(contact.trackHelixExtrapolationDistance<100)veto = true; if(contact.clusterFractionWithin100>0.1)veto = true; } } } if(_perfectClustering)veto=true; if(!veto){ if(_printing>0)std::cout << "***"; hadronicE += trackAR->getEnergy()*(EOverP(trackAR)-1.0); if(_printing>0)std::cout << " Added EXCESS : " << trackAR->getEnergy()*(EOverP(trackAR)-1.0) << std::endl; } } } } } //wibble if(_printing>0&&ematched<0.001)std::cout << " UNMATCHED "; Track* track = trackAR->getTrack(); int nonSiHits = trackAR->nonSiHits(); TrackerHitVec hitvec = track->getTrackerHits(); int nhits = (int)hitvec.size(); float px = trackAR->getMomentum()[0]; float py = trackAR->getMomentum()[1]; float pT = sqrt(px*px+py*py); if(_printing>0)std::cout << " fit chi2 : " << track->getChi2() << "/" << track->getNdf() << " hits = " << nhits << "(" << nonSiHits << ") pT = " << pT; if(_printing>0&&ematched>0.001){ cout << " chi = " << chi; if(fabs(chi)>3)std::cout << " <************ "; } if(_printing>0)std::cout << std::endl; if(_printing>0&&ematched<0.001 && nhits < 8){ for(int ih =0;ihgetPosition()[0]; float y = (float)hitvec[ih]->getPosition()[1]; float z = (float)hitvec[ih]->getPosition()[2]; float r2 = x*x+y*y; std::cout << " r = " << sqrt(r2) << " xyz = " << x << "," << y << "," << z << std::endl; } } if(clusters.size()>1000000){ int il = clusters[0]->FirstLayer(); float E = clusters[0]->EnergyHAD(); float eInMips = clusters[0]->EnergyInMips(); float meanMipsPerHit = eInMips/clusters[0]->Hits(); if(_printing>0)std::cout << " HADRON : " << E << " (" << clusters[0]->GetCentroid(il)[0] << "," << clusters[0]->GetCentroid(il)[1] << "," << clusters[0]->GetCentroid(il)[2] << ") " << clusters[0]->Hits() << " " << clusters[0]->FirstLayer() << ":" << clusters[0]->LastLayer() << "+" << clusters[0]->getLayer90() << " " << clusters[0]->getLayerMax() << " d" << clusters[0]->DCosR()<< " " << clusters[0]->ClusterRMS() << " mipf " <MipFraction() << " " << clusters[0]->EnergyEM() << " " << meanMipsPerHit << std::endl; } } if(trackAR->trackStatus()==TRACK_STATUS_NON_VERTEX && trackAR->getInnerR() > _tpcInnerR+25. && clusters.size()>0){ if(_printing>0)std::cout << " NV !!! Track BACK SCATTER ? : " << trackAR->getInnerR() << " - " << trackAR->getOuterR() << " " << _tpcInnerR << " split = " << trackAR->isSplitS() << " " << trackAR->isSplitE() << std::endl; } if(trackAR->trackStatus()==TRACK_STATUS_LOWPT){ lowpt += trackAR->getEnergy(); if(_printing>0)cout << " TRACK : " << trackAR->getEnergy() << " (" << etrue << ") is an unmatched LOWPT track" << endl; } if(trackAR->trackStatus()==TRACK_STATUS_UNASSOC && trackAR->isKinkS()){ if(_printing>0)cout << "KS TRACK : " << trackAR->getEnergy() << " (" << etrue << ") is not used in analysis" << endl; } if(trackAR->trackStatus()==TRACK_STATUS_UNASSOC && trackAR->isKinkE()){ if(_printing>0)cout << "KE TRACK : " << trackAR->getEnergy() << " (" << etrue << ") is not used in analysis (not matched)" << endl; } if(trackAR->trackStatus()==TRACK_STATUS_UNASSOC && trackAR->isProngS()){ if(_printing>0)cout << "PS TRACK : " << trackAR->getEnergy() << " (" << etrue << ") is not used in analysis" << endl; } if(trackAR->trackStatus()==TRACK_STATUS_UNASSOC && trackAR->isProngE()){ if(_printing>0)cout << "PE TRACK : " << trackAR->getEnergy() << " (" << etrue << ") is not used in analysis" << endl; } } if(_analyseClusters!=0)AnalyseClusters(_finalProtoClusters); for(unsigned int icluster=0;icluster<_finalProtoClusters.size();++icluster){ if(_finalProtoClusters[icluster]->AssociatedTrack()==false){ int nhits = _finalProtoClusters[icluster]->Hits(); bool photonID = _finalProtoClusters[icluster]->IsPhoton(); int errorType =_finalProtoClusters[icluster]->GetErrorType(); //if(_digitalECAL==1){ //if(nhits>50&&_recoDisplay!=NULL)_recoDisplay->DrawTransverseProfileFine(_finalProtoClusters[icluster],30); //} if(photonID){ float E = _finalProtoClusters[icluster]->EnergyEM(); if(E>_minimumClusterEnergyEM&&nhits>=_minimumHitsInCluster){ photonE+= E; int il = _finalProtoClusters[icluster]->FirstLayer(); bool photon = false; bool unmatched = false; bool merged = false; bool dodgy = false; //AnalyseCluster(_finalProtoClusters[icluster]); float chargedF = _finalProtoClusters[icluster]->MCChargedFraction(); MyMCPFOVec _mcPFOs = _finalProtoClusters[icluster]->GetMCPFOVec(); if(_mcPFOs.size()==0)unmatched=true; if(_mcPFOs.size()>1)merged=true; for(unsigned int i =0;i<_mcPFOs.size();i++){ if(_mcPFOs[i]->isPhoton())photon=true; } if(_printing>0){ if(chargedF>0.5)cout << "#"; if(!photon && !unmatched && !merged)cout <<"* "; if(merged)cout <<"M "; if(unmatched)cout <<"U "; if(dodgy)cout <<"D "; if(photon&&!merged)cout <<" "; if(unmatched){ if(errorType==1)cout << "BT "; if(errorType==5)cout << "BT1"; if(errorType==2)cout << "CF "; if(errorType==3)cout << "NF "; if(errorType==4)cout << "PF "; if(errorType==999)cout << "DODGY "; } } _finalProtoClusters[icluster]->PhotonProfileID(); float showerStart = _finalProtoClusters[icluster]->GetLongProfileShowerStart(); float gammaFraction = _finalProtoClusters[icluster]->GetLongProfileGammaFraction(); if(!unmatched){ fPhotonEP->Fill(E,gammaFraction,1.); }else{ if(errorType==2||errorType==3)fPhotonEPU->Fill(E,gammaFraction,1.); } if(_printing>0)std::cout << " PHOTON : " << E << " (" << _finalProtoClusters[icluster]->GetCentroid(il)[0] << "," << _finalProtoClusters[icluster]->GetCentroid(il)[1] << "," << _finalProtoClusters[icluster]->GetCentroid(il)[2] << ") mipf " << _finalProtoClusters[icluster]->MipFraction() << " dcosR = " << _finalProtoClusters[icluster]->DCosR() << " layers " << _finalProtoClusters[icluster]->FirstLayer() << ":" << _finalProtoClusters[icluster]->LastLayer() << "+" << _finalProtoClusters[icluster]->getLayer90()<< " LONG : " << showerStart << " " << gammaFraction << std::endl; }else{ lowEM += E; // int il = _finalProtoClusters[icluster]->FirstLayer(); //_finalProtoClusters[icluster]->PhotonProfileID(); //float showerStart = _finalProtoClusters[icluster]->GetLongProfileShowerStart(); //float gammaFraction = _finalProtoClusters[icluster]->GetLongProfileGammaFraction(); if(_printing>0)std::cout << " LOWEM : " << E << std::endl; // if(_printing>0)std::cout << " LOWEM PHOTON : " << E << " (" << _finalProtoClusters[icluster]->GetCentroid(il)[0] << "," << _finalProtoClusters[icluster]->GetCentroid(il)[1] << "," << _finalProtoClusters[icluster]->GetCentroid(il)[2] << ") mipf " << _finalProtoClusters[icluster]->MipFraction() << " " << _finalProtoClusters[icluster]->FirstLayer() << ":" << _finalProtoClusters[icluster]->LastLayer() << "+" << _finalProtoClusters[icluster]->getLayer90()<< " LONG : " << showerStart << " " << gammaFraction << std::endl; } }else{ float E = _finalProtoClusters[icluster]->EnergyHAD(); bool hotHadron = _finalProtoClusters[icluster]->IsHotHadron(); float eInMips = _finalProtoClusters[icluster]->EnergyInMips(); float meanMipsPerHit = eInMips/_finalProtoClusters[icluster]->Hits(); if(E>_minimumClusterEnergyHAD&&nhits>=_minimumHitsInCluster){ int il = _finalProtoClusters[icluster]->FirstLayer(); int ll = _finalProtoClusters[icluster]->LastLayer(); float xl = float(il); float xls = float(ll-il); float xh = float( _finalProtoClusters[icluster]->Hits() ); float etot = E; int layers = ll - il+1; bool dodgy = false; //AnalyseCluster(_finalProtoClusters[icluster]); if(_detector== DETECTOR_GLD)dodgy=false; float chargedF = _finalProtoClusters[icluster]->MCChargedFraction(); if(!dodgy&&layers>1)hadronicE += etot; _finalProtoClusters[icluster]->PhotonProfileID(); float showerStart = _finalProtoClusters[icluster]->GetLongProfileShowerStart(); float gammaFraction = _finalProtoClusters[icluster]->GetLongProfileGammaFraction(); bool photon = false; bool unmatched = false; MyMCPFOVec _mcPFOs = _finalProtoClusters[icluster]->GetMCPFOVec(); if(_mcPFOs.size()==0)unmatched=true; for(unsigned int i =0;i<_mcPFOs.size();i++){ if(_mcPFOs[i]->isPhoton())photon=true; } float z = fabs(_finalProtoClusters[icluster]->GetCentroid(il)[2]); if(!photon&&!dodgy&&layers>1){ if(unmatched){ if(errorType==2){ fEhadU->Fill(E,1.); fEhadLayerU->Fill(E,xl,1.); fEhadLayersU->Fill(E,xls,1.); fEhadHitsU->Fill(E,xh,1.); if(E<1.0){ fMipDcosU->Fill(_finalProtoClusters[icluster]->MipFraction(), _finalProtoClusters[icluster]->DCosR(),1.); } if(z+10<_zOfEndcap){ bEhadU->Fill(E,1.); bEhadLayerU->Fill(E,xl,1.); bEhadLayersU->Fill(E,xls,1.); bEhadHitsU->Fill(E,xh,1.); if(E<1.0){ bMipDcosU->Fill(_finalProtoClusters[icluster]->MipFraction(), _finalProtoClusters[icluster]->DCosR(),1.); } }else{ eEhadU->Fill(E,1.); eEhadLayerU->Fill(E,xl,1.); eEhadLayersU->Fill(E,xls,1.); eEhadHitsU->Fill(E,xh,1.); if(E<1.0){ eMipDcosU->Fill(_finalProtoClusters[icluster]->MipFraction(), _finalProtoClusters[icluster]->DCosR(),1.); } } }else{ fEhad->Fill(E,1.); fEhadLayer->Fill(E,xl,1.); fEhadLayers->Fill(E,xls,1.); fEhadHits->Fill(E,xh,1.); if(E<1.0){ fMipDcos->Fill(_finalProtoClusters[icluster]->MipFraction(), _finalProtoClusters[icluster]->DCosR(),1.); } if(z+10<_zOfEndcap){ bEhad->Fill(E,1.); bEhadLayer->Fill(E,xl,1.); bEhadLayers->Fill(E,xls,1.); bEhadHits->Fill(E,xh,1.); if(E<1.0){ bMipDcos->Fill(_finalProtoClusters[icluster]->MipFraction(), _finalProtoClusters[icluster]->DCosR(),1.); } }else{ eEhad->Fill(E,1.); eEhadLayer->Fill(E,xl,1.); eEhadLayers->Fill(E,xls,1.); eEhadHits->Fill(E,xh,1.); if(E<1.0){ eMipDcos->Fill(_finalProtoClusters[icluster]->MipFraction(), _finalProtoClusters[icluster]->DCosR(),1.); } } } } } if(!photon&&!dodgy&&layers>1&&errorType==1){ fMipDcosBT->Fill(_finalProtoClusters[icluster]->MipFraction(), _finalProtoClusters[icluster]->DCosR(),1.); fEhadBT->Fill(E,1.); fEhadLayerBT->Fill(E,xl,1.); fEhadLayersBT->Fill(E,xls,1.); fEhadHitsBT->Fill(E,xh,1.); if(z+10<_zOfEndcap){ bEhadBT->Fill(E,1.); bEhadLayerBT->Fill(E,xl,1.); bEhadLayersBT->Fill(E,xls,1.); bEhadHitsBT->Fill(E,xh,1.); if(E<1.0){ bMipDcosBT->Fill(_finalProtoClusters[icluster]->MipFraction(), _finalProtoClusters[icluster]->DCosR(),1.); } }else{ eEhadBT->Fill(E,1.); eEhadLayerBT->Fill(E,xl,1.); eEhadLayersBT->Fill(E,xls,1.); eEhadHitsBT->Fill(E,xh,1.); if(E<1.0){ eMipDcosBT->Fill(_finalProtoClusters[icluster]->MipFraction(), _finalProtoClusters[icluster]->DCosR(),1.); } } } if(_useAdvancedPhotonID==1){ if(photon){ if(E<1.5)fLong1->Fill(showerStart,gammaFraction,1.); if(E>1.5&&E<=2.5)fLong1_2->Fill(showerStart,gammaFraction,1.); if(E>2.5&&E<=5)fLong2_5->Fill(showerStart,gammaFraction,1.); if(E>5)fLong5->Fill(showerStart,gammaFraction,1.); }else{ if(E<1.5)fLong1H->Fill(showerStart,gammaFraction,1.); if(E>1.5&&E<=2.5)fLong1_2H->Fill(showerStart,gammaFraction,1.); if(E>2.5&&E<=5)fLong2_5H->Fill(showerStart,gammaFraction,1.); if(E>5)fLong5H->Fill(showerStart,gammaFraction,1.); } if(z+10<_zOfEndcap){ if(photon){ if(E<1.5)bLong1->Fill(showerStart,gammaFraction,1.); if(E>1.5&&E<=2.5)bLong1_2->Fill(showerStart,gammaFraction,1.); if(E>2.5&&E<=5)bLong2_5->Fill(showerStart,gammaFraction,1.); if(E>5)bLong5->Fill(showerStart,gammaFraction,1.); }else{ if(E<1.5)bLong1H->Fill(showerStart,gammaFraction,1.); if(E>1.5&&E<=2.5)bLong1_2H->Fill(showerStart,gammaFraction,1.); if(E>2.5&&E<=5)bLong2_5H->Fill(showerStart,gammaFraction,1.); if(E>5)bLong5H->Fill(showerStart,gammaFraction,1.); } }else{ if(photon){ if(E<1.5)eLong1->Fill(showerStart,gammaFraction,1.); if(E>1.5&&E<=2.5)eLong1_2->Fill(showerStart,gammaFraction,1.); if(E>2.5&&E<=5)eLong2_5->Fill(showerStart,gammaFraction,1.); if(E>5)eLong5->Fill(showerStart,gammaFraction,1.); }else{ if(E<1.5)eLong1H->Fill(showerStart,gammaFraction,1.); if(E>1.5&&E<=2.5)eLong1_2H->Fill(showerStart,gammaFraction,1.); if(E>2.5&&E<=5)eLong2_5H->Fill(showerStart,gammaFraction,1.); if(E>5)eLong5H->Fill(showerStart,gammaFraction,1.); } } } if(_printing>0){ if(chargedF>0.5)cout <<"#"; if(layers<2)cout <<"X"; if(photon)cout <<"* "; if(unmatched&&!dodgy)cout <<"U "; if(unmatched&&dodgy)cout <<"D "; if(!photon && !unmatched)cout <<" "; if(unmatched&&!dodgy){ if(errorType==1)cout << "BT "; if(errorType==2)cout << "CF "; if(errorType==3)cout << "NF "; if(errorType==4)cout << "PF "; } if(hotHadron)std::cout << "HOT"; std::cout << " HADRON : " << E << " (" << _finalProtoClusters[icluster]->GetCentroid(il)[0] << "," << _finalProtoClusters[icluster]->GetCentroid(il)[1] << "," << _finalProtoClusters[icluster]->GetCentroid(il)[2] << ") " << _finalProtoClusters[icluster]->Hits() << " " << _finalProtoClusters[icluster]->FirstLayer() << ":" << _finalProtoClusters[icluster]->LastLayer() << "+" << _finalProtoClusters[icluster]->getLayer90() << " " << _finalProtoClusters[icluster]->getLayerMax() << " d" << _finalProtoClusters[icluster]->DCosR()<< " " << _finalProtoClusters[icluster]->ClusterRMS() << " mipf " << _finalProtoClusters[icluster]->MipFraction() << " " << _finalProtoClusters[icluster]->EnergyEM() << " LONG : " << showerStart << " " << gammaFraction << " " << meanMipsPerHit << " be = " << _finalProtoClusters[icluster]->BarrelEncapEnergySplit() <IsClusterLeavingDetector( _finalProtoClusters[icluster]); float eLeaving = this->EnergyLeavingDetector( _finalProtoClusters[icluster]); if(isLeaving)std::cout << " Cluster Leaving Detector " << eLeaving << std::endl; } }else{ lowHAD += E; // int il = _finalProtoClusters[icluster]->FirstLayer(); //_finalProtoClusters[icluster]->PhotonProfileID(); //float showerStart = _finalProtoClusters[icluster]->GetLongProfileShowerStart(); //float gammaFraction = _finalProtoClusters[icluster]->GetLongProfileGammaFraction(); // std::cout << " LOW HADRON : " << E << " (" << _finalProtoClusters[icluster]->GetCentroid(il)[0] << "," << _finalProtoClusters[icluster]->GetCentroid(il)[1] << "," << _finalProtoClusters[icluster]->GetCentroid(il)[2] << ") " << _finalProtoClusters[icluster]->Hits() << " " << _finalProtoClusters[icluster]->FirstLayer() << ":" << _finalProtoClusters[icluster]->LastLayer() << "+" << _finalProtoClusters[icluster]->getLayer90() << " " << _finalProtoClusters[icluster]->getLayerMax() << " d" << _finalProtoClusters[icluster]->DCosR()<< " " << _finalProtoClusters[icluster]->ClusterRMS() << " mipf " << _finalProtoClusters[icluster]->MipFraction() << " " << _finalProtoClusters[icluster]->EnergyEM() << " LONG : " << showerStart << " " << gammaFraction << " " << meanMipsPerHit << std::endl; } } } } if(_printing>0){ cout << endl; cout << " ERRORS as compared with MC PFOs " << endl; cout << " ----------------------------------- " << endl; } float enu = 0; float efwd = 0; float elow = 0; float eMissingKL = 0; for(unsigned int imc=0;imcgetMCParticle(); if(pMcPFOs[imc]->isNeutrino())enu+= mcpart->getEnergy(); if(mcpart->getPDG()==130){ float xe = mcpart->getEndpoint()[0]; float ye = mcpart->getEndpoint()[1]; float ze = mcpart->getEndpoint()[2]; float re = sqrt(xe*xe+ye*ye); if(re>3000||abs(ze)>4000)eMissingKL+= mcpart->getEnergy(); } if(pMcPFOs[imc]->isTrack()){ MyTrackExtended* track = pMcPFOs[imc]->getTrack(); float p[3]; p[0] = mcpart->getMomentum()[0]; p[1] = mcpart->getMomentum()[1]; p[2] = mcpart->getMomentum()[2]; // float ptot = sqrt(p[0]*p[0]+p[1]*p[1]+p[2]*p[2]); float cost = p[2]/sqrt(p[0]*p[0]+p[1]*p[1]+p[2]*p[2]); float pt = sqrt(p[0]*p[0]+p[1]*p[1]); if(track==NULL){ if(_printing>0)cout << " NO TRACK : " << pMcPFOs[imc]->getName() << " : " << mcpart->getEnergy() << " cost = " << cost << " pt : " << pt << endl; }else{ float x =track->getSeedPosition()[0]; float y =track->getSeedPosition()[1]; // float z =track->getSeedPosition()[2]; float r = sqrt(x*x+y*y); if(track->trackStatus()==TRACK_STATUS_UNKNOWN){ if(_printing>0)cout << " UNK BAD TRACK : " << pMcPFOs[imc]->getName() << " : " << mcpart->getEnergy() << " Etrack " << track->getEnergy() << " pt : " << pt <trackStatus()==TRACK_STATUS_BAD){ if(_printing>0)cout << " BAD BAD TRACK : " << pMcPFOs[imc]->getName() << " : " << mcpart->getEnergy() << " Etrack " << track->getEnergy() << " pt : " << pt << " r : " << r <trackStatus()==TRACK_STATUS_UNASSOC){ float eclosest = 0; float closest = 999999.; int bestCluster =-1; for(unsigned int icluster=0;icluster<_finalProtoClusters.size();++icluster){ float approach = _finalProtoClusters[icluster]->DistanceToAltTrack(track,10); if(approachEnergyHAD(); bestCluster = icluster; } } if(_printing>0)cout << " UNASSOC BAD TRACK : " << pMcPFOs[imc]->getName() << " : " << mcpart->getEnergy() << " Etrack " << track->getEnergy() << " r : " << r << " z int : " << track->getSeedPosition()[2] << " CLOSEST : " << closest << " e " << eclosest << endl; } } } } if(elow>0.1&&_printing>0)cout << " LOW E CLUSTERS : " << elow << endl; if(enu>0.1&&_printing>0)cout << " NEUTRINOS : " << enu << endl; if(efwd>0.1&&_printing>0)cout << " FWD CLUSTERS : " << efwd << endl; if(fwdtrack>0.1&&_printing>0)cout << " FWD TRACK : " << fwdtrack << endl; if(eMissingKL>0.1&&_printing>0)cout << " MISSING KL : " << eMissingKL << endl; if(_printing>0){ std::cout << " Track Energy " << trackE << std::endl; std::cout << " Photon Energy " << photonE << std::endl; std::cout << " Hadronic Energy " << hadronicE << std::endl; std::cout << " Low EM " << lowEM << std::endl; std::cout << " Low Had " << lowHAD << std::endl << std::flush; streamlog_out(MESSAGE) << std::flush; } _etotal = trackE+photonE+hadronicE+lowpt; _etotalnu = trackE+photonE+hadronicE+lowpt+enu; _etotalnufwd= trackE+photonE+hadronicE+lowpt+enu+efwd+fwdtrack; float de = fabs(_etotal-500); if(de>10.)this->setReturnValue(true); if(de<=10.)this->setReturnValue(false); float error = sqrt(0.8*0.8*hadronicE+0.15*0.15*photonE); if(_printing>-1){ streamlog_out(MESSAGE) << "PandoraPFA::performPFA Event : " << _nEvt << std::endl; streamlog_out(MESSAGE) << "PandoraPFA::performPFA PFA Energy : " << _etotal-lowpt << std::endl; streamlog_out(MESSAGE) << "PandoraPFA::performPFA PFA+ Energy : " << _etotal << "+-" << error << std::endl; streamlog_out(MESSAGE) << "PandoraPFA::performPFA PFA+nu+fwd Energy : " << _etotal + enu + efwd + fwdtrack + eMissingKL<< "+-" << error << std::endl; } if(_printing>-1){ std::cout << std::flush; } } void PandoraPFAProcessor::CreateClusterCollection(LCEvent * evt) { int nclust = (int)_finalProtoClusters.size(); LCCollectionVec * clucol = new LCCollectionVec(LCIO::CLUSTER); LCFlagImpl chFlag( clucol->getFlag() ) ; chFlag.setBit( LCIO::CLBIT_HITS ) ; clucol->setFlag( chFlag.getFlag() ) ; //fg:------ use this vector for subdetector names in cluster collection std::vector< std::string > sdNames ; sdNames.push_back("ecal") ; unsigned ecal_Index = 0 ; sdNames.push_back("hcal") ; unsigned hcal_Index = 1 ; sdNames.push_back("yoke") ; unsigned yoke_Index = 2 ; sdNames.push_back("lcal") ; unsigned lcal_Index = 3 ; sdNames.push_back("lhcal"); unsigned lhcal_Index = 4 ; sdNames.push_back("bcal") ; unsigned bcal_Index = 5 ; clucol->parameters().setValues( "ClusterSubdetectorNames" , sdNames ) ; streamlog_out( DEBUG ) << " subdetector energies for : " << " " << sdNames[ ecal_Index ] << " " << sdNames[ hcal_Index ] << " " << sdNames[ yoke_Index ] << " " << sdNames[ lcal_Index ] << " " << sdNames[ lhcal_Index ] << " " << sdNames[ bcal_Index ] << std::endl ; //----------------------------------------------------------------------- for (int icluster=0; icluster < nclust; ++icluster) { ProtoCluster* pCluster = _finalProtoClusters[icluster]; int nhits = pCluster->Hits(); bool passCuts = true; if(nhits <_minimumHitsInCluster)passCuts = false; bool photon = _finalProtoClusters[icluster]->IsPhoton(); if(photon&&pCluster->EnergyEM()<_minimumClusterEnergyEM)passCuts=false; if((!photon)&&pCluster->EnergyHAD()<_minimumClusterEnergyHAD)passCuts=false; if(passCuts){ ClusterImpl * cluster = new ClusterImpl(); // cluster->setTypeBit(LCIO::CLBIT_HITS); float * xhit = new float[nhits]; float * yhit = new float[nhits]; float * zhit = new float[nhits]; float * ahit = new float[nhits]; float totene = 0.0; float totecal = 0.0; float tothcal = 0.0; float tottail = 0.0; for (int ihit=0; ihit < nhits; ++ihit) { MyCaloHitExtended* hiti = pCluster->Hit(ihit); CalorimeterHit * calhit = const_cast(hiti->getCalorimeterHit()); cluster->addHit(calhit,(float)1.0); xhit[ihit] = calhit->getPosition()[0]; yhit[ihit] = calhit->getPosition()[1]; zhit[ihit] = calhit->getPosition()[2]; ahit[ihit] = calhit->getEnergy(); totene += ahit[ihit]; switch(hiti->getCalorimeterHitType()){ case CALHITTYPE_BCAL: case CALHITTYPE_ECAL: case CALHITTYPE_LCAL: totecal += ahit[ihit]; break; case CALHITTYPE_HCAL: case CALHITTYPE_LHCAL: tothcal += ahit[ihit]; break; case CALHITTYPE_MUON: tottail += ahit[ihit]; break; default: totecal += ahit[ihit]; streamlog_out(WARNING) << " CreateClusterCollection unknown hit type " << hiti->getCalorimeterHitType() << std::endl; break; } } int nisohits = pCluster->IsolatedHits(); for (int ihit=0; ihit < nisohits; ++ihit) { MyCaloHitExtended* hiti = pCluster->IsolatedHit(ihit); CalorimeterHit * calhit = const_cast(hiti->getCalorimeterHit()); cluster->addHit(calhit,(float)1.0); totene += calhit->getEnergy(); switch(hiti->getCalorimeterHitType()){ case CALHITTYPE_ECAL: case CALHITTYPE_LCAL: totecal += ahit[ihit]; break; case CALHITTYPE_HCAL: case CALHITTYPE_LHCAL: tothcal += ahit[ihit]; break; case CALHITTYPE_MUON: tottail += ahit[ihit]; break; default: totecal += ahit[ihit]; break; } } // Cluster shapes use only non-isolated hits ClusterShapes * shape = new ClusterShapes(nhits,ahit,xhit,yhit,zhit); cluster->setEnergy(totene); //fg: ----- replace this with energy per subdetector -------- // cluster->subdetectorEnergies().resize(2); // cluster->subdetectorEnergies()[0] = totecal; // cluster->subdetectorEnergies()[1] = tothcal; // cluster->subdetectorEnergies()[2] = tottail; std::vector& sdEnergies = cluster->subdetectorEnergies() ; sdEnergies.resize( sdNames.size() ) ; const CalorimeterHitVec& chits = cluster->getCalorimeterHits() ; for (unsigned ih=0; ih < chits.size() ; ++ih) { switch( CHT( chits[ ih ]->getType() ).caloID() ){ case CHT::ecal: sdEnergies[ ecal_Index ] += chits[ ih ]->getEnergy() ; break; case CHT::hcal: sdEnergies[ hcal_Index ] += chits[ ih ]->getEnergy() ; break; case CHT::yoke: sdEnergies[ yoke_Index ] += chits[ ih ]->getEnergy() ; break; case CHT::lcal: sdEnergies[ lcal_Index ] += chits[ ih ]->getEnergy() ; break; case CHT::lhcal: sdEnergies[ lhcal_Index ] += chits[ ih ]->getEnergy() ; break; case CHT::bcal: sdEnergies[ bcal_Index ] += chits[ ih ]->getEnergy() ; break; default: // streamlog_out( DEBUG ) << " no subdetector found for hit with type : " // << chits[ ih ]->getType() << std::endl ; ; } } //streamlog_out( DEBUG ) << " set cluster subdetector energies to : " // << " " << sdEnergies[ ecal_Index ] // << " " << sdEnergies[ hcal_Index ] // << " " << sdEnergies[ yoke_Index ] // << " " << sdEnergies[ lcal_Index ] // << " " << sdEnergies[ lhcal_Index ] // << " " << sdEnergies[ bcal_Index ] << std::endl ; //fg: ----- end of: replace this with energy per subdetector -------- cluster->setPosition(shape->getCentreOfGravity()); float PhiCluster = atan2(shape->getEigenVecInertia()[1],shape->getEigenVecInertia()[0]); float ThetaCluster = acos(shape->getEigenVecInertia()[2]); cluster->setIPhi(PhiCluster); cluster->setITheta(ThetaCluster); clucol->addElement(cluster); delete shape; delete[] xhit; delete[] yhit; delete[] zhit; delete[] ahit; pCluster->SetCluster(cluster); } } // save the pointers to the hits evt->addCollection(clucol,_clusterCollectionName.c_str()); } void PandoraPFAProcessor::scaleHotHadrons(){ for(unsigned int icluster=0;icluster<_finalProtoClusters.size();++icluster){ bool photonID = _finalProtoClusters[icluster]->IsPhoton(); if( _finalProtoClusters[icluster]->AssociatedTrack())photonID = false; if(!photonID && !_finalProtoClusters[icluster]->IsDefunct()){ float E = _finalProtoClusters[icluster]->EnergyHAD(); bool hotHadron = false; float scale = 1.0; float eInMips = _finalProtoClusters[icluster]->EnergyInMips(); int nhits = _finalProtoClusters[icluster]->Hits(); int firstLayer = _finalProtoClusters[icluster]->FirstLayer(); int lastLayer = _finalProtoClusters[icluster]->LastLayer(); // int layersSpanned = lastLayer-firstLayer; int layersWithHits = 0; for(int il = firstLayer;il<=lastLayer;il++){ if(_finalProtoClusters[icluster]->hitsInLayer(il)>0)layersWithHits++; } float meanMipsPerHit = eInMips/nhits; bool possibleHotHadron = true; if(nhits<_minimumHitsInCluster)possibleHotHadron = false; if(firstLayer<10 && _finalProtoClusters[icluster]->MipFraction()<0.4 && nhits > 50)possibleHotHadron = false; if(nhits>100)possibleHotHadron = false; if(meanMipsPerHit>_mipsPerHitForHotHadron){ if(possibleHotHadron){ hotHadron = true; scale = _scaledMipsPerHitForHotHadron/meanMipsPerHit; }else{ if(_printing>0)std::cout << "HOT Cluster Detected - not TAGGED" << _finalProtoClusters[icluster]->Hits() << " E = " << E << " " << nhits << " " << _finalProtoClusters[icluster]->MipFraction() << " " << layersWithHits << std::endl; } if(hotHadron){ if(_printing>0){ std::cout << "HOT Cluster Detected " << _finalProtoClusters[icluster]->Hits() << " E = " << E << " -> " << E*scale << std::endl; if(_finalProtoClusters[icluster]->AssociatedTrack())std::cout << "*!*!*!*!*!* Matched "; } E=E*scale; _finalProtoClusters[icluster]->setEnergyHAD(E); _finalProtoClusters[icluster]->HotHadron(true); } } } } return; } void PandoraPFAProcessor::CreatePFOCollection(LCEvent * evt){ // Make a new vector of particles LCCollectionVec * recparcol = new LCCollectionVec(LCIO::RECONSTRUCTEDPARTICLE); // perform particle flow analysis this->performPFA(); // create clusters collection this->CreateClusterCollection(evt); // Loop over tracks int IDPart; float Mom[3]; float Energy; float Mass; float Charge; for(unsigned int itrack=0;itrack<_tracksAR.size();itrack++){ IDPart = 0; float mom[3]; float energy; float mass; MyTrackExtended* trackAR = _tracksAR[itrack]; Track* track = trackAR->getTrack(); ProtoClusterVec clusters = trackAR->getClusterVec(); // Single track matched to (at least one) cluster bool goodTrack = GoodPFOTrack(trackAR); if(goodTrack){ bool matchExternalV0 = false; mom[0] = trackAR->getMomentum()[0]; mom[1] = trackAR->getMomentum()[1]; mom[2] = trackAR->getMomentum()[2]; float momentum = sqrt(mom[0]*mom[0]+mom[1]*mom[1]+mom[2]*mom[2]); // assume track is a pion // set particle ID to be either pi+ or pi- IDPart = 211; mass = massPion; Mass = massPion; if((_cheatedDeDx==1) && (_trackNavigator!=NULL)){ LCObjectVec objectVec = _trackNavigator->getRelatedToObjects(track); if (objectVec.size() > 0){ MCParticle* part = dynamic_cast(objectVec[0]); if(abs(part->getPDG())==2212){ if(_printing>0)std::cout << " MC PROTON : " << momentum << std::endl; if(momentum<1.5){ mass = massProton; Mass = massProton; IDPart = 2212; } } } } energy = sqrt(momentum*momentum+mass*mass); Charge = trackAR->getOmega(); Charge = Charge/fabs(Charge); if(Charge<0)IDPart=-211; for(unsigned int i=0;i<3;i++)Mom[i]=mom[i]; Energy = energy; ReconstructedParticleImpl* recoPart = new ReconstructedParticleImpl(); recoPart->addTrack(track); // any back scatters ? unsigned int ndaugthers = trackAR->getNBackScatterDaughters(); for(unsigned int i=0;igetBackScatterDaughter(i); ProtoClusterVec aclusters = d->getClusterVec(); recoPart->addTrack(d->getTrack()); for(unsigned int i=0;iGetCluster(); if(cluster!=NULL)recoPart->addCluster(cluster); } } // get the ProtoClusters associated with track (should be only one) ProtoClusterVec clusters = trackAR->getClusterVec(); float clusterEnergy = 0.0; bool leavingCluster=false; for(unsigned int i=0;iEnergyHAD(); ClusterImpl* cluster = clusters[i]->GetCluster(); if(cluster!=NULL)recoPart->addCluster(cluster); int layersFromEdge = this->LayersFromEdge(clusters[i]); if(layersFromEdge<=3)leavingCluster=true; } // If the cluster energy is larger than reasonable for track // use this rather than the track momentum // Should only happen very rarely // float chi = this->ChiClusterTrack(trackAR); if(fabs(chi)>2.5 && !leavingCluster){ TrackerHitVec hitvec = track->getTrackerHits(); float nhits = (float)hitvec.size(); float nhitsInFit = track->getNdf(); float chi2Fit = track->getChi2(); bool badFit = false; if(nhitsInFit < 0.25*nhits)badFit = true; if(chi2Fit/nhitsInFit > 1.5)badFit = true; if(_cheatedTracks!=0)badFit = false; if(badFit){ streamlog_out(WARNING) << " CreatePFOCollection evidence for a bad track fit - use cluster to define PFO energy " << energy << " -> " << clusterEnergy << std::endl; Energy = trackAR->getEnergy()*this->EOverP(trackAR); Mom[0] = Mom[0]*Energy/energy; Mom[1] = Mom[1]*Energy/energy; Mom[2] = Mom[2]*Energy/energy; } } if(_canUseClusterForExitingTracks!=0 && clusters.size()>0&&leavingCluster &&chi>3.0){ bool veto = false; for(unsigned int jtrack=0;jtrack<_tracksAR.size();jtrack++){ float tchi = this->ChiClusterTrack(_tracksAR[jtrack]); if(tchi<-2.0){ fragmentContact_t contact = this->CalculateFragmentContactInfo(trackAR, _tracksAR[jtrack]); ProtoClusterVec clusters = _tracksAR[jtrack]->getClusterVec(); float E = _tracksAR[jtrack]->getEnergy(); if(clusters.size()>0)E = E - clusters[0]->EnergyHAD() ; float newchi = this->ChiClusterTrack(trackAR,-E); if(fabs(newchi)2)veto = true; if(contact.trackHelixExtrapolationDistance<100)veto = true; if(contact.clusterFractionWithin100>0.1)veto = true; } }//wibble } if(_perfectClustering)veto=true; if(!veto){ if(_printing>0){ std::cout << " ************************************* " << std::endl; std::cout << " PFO LEAVING CLUSTER : " << clusterEnergy << " <-> " << energy << " WILL USE CLUSTER ENERGY : chi = " << chi << std::endl; std::cout << " ************************************* " << std::endl; } Energy = trackAR->getEnergy()*this->EOverP(trackAR); if(_leakageCorrection==1){ ProtoClusterVec clusters = trackAR->getClusterVec(); float eCor = 0; for(unsigned int icluster = 0;iclusterHits();ihit++){ MyCaloHitExtended* hiti = clusters[icluster]->Hit(ihit); if( hiti->getCalorimeterHitType()==CALHITTYPE_HCAL ){ int layersFromEdge = this->LayersFromEdge(hiti); if(layersFromEdge<_leavingHitLayersFromEdge){ eCor += hiti->getEnergyHAD()*(_leavingHitWeightingFactor-1.); } } } } if(eCor>0){ if(_printing>0)std::cout << " Leakage Correction : " << Energy << " --> " << Energy+eCor << std::endl; Energy+=eCor; } } Mom[0] = Mom[0]*Energy/energy; Mom[1] = Mom[1]*Energy/energy; Mom[2] = Mom[2]*Energy/energy; }else{ if(_printing>1)std::cout << " Veto Excess " << std::endl; } } Track* track = trackAR->getTrack(); LCObjectVec objectVec = _trackNavigator->getRelatedToObjects(track); if (objectVec.size() > 0){ MCParticle* part = dynamic_cast(objectVec[0]); unsigned int testmc = _myMcTree->GetMCPFOIndex(part); if(testmc<99999&&abs(part->getPDG())==11){ if(clusters.size()==1){ if(_printing>0)std::cout << "***** true electron track : " << trackAR->getEnergy() << " cluster : " << clusters[0]->EnergyEM() << std::endl; if(_printing>0)std::cout << " electron IsPrimaryPhoton " << clusters[0]->IsPrimaryPhoton() << " first : " << clusters[0]->FirstLayer() << std::endl; clusters[0]->PhotonProfileID(); float showerStart = clusters[0]->GetLongProfileShowerStart(); float gammaFraction = clusters[0]->GetLongProfileGammaFraction(); if(_printing>0)std::cout << " electron start/gfrac : " << showerStart << " " << gammaFraction << std::endl; } if(clusters.size()==0){ if(_printing>0)std::cout << " true electron track : " << trackAR->getEnergy() << " NO matched cluster " << std::endl; } } } // electron ID - still fairly primitive - cuts not tuned if(clusters.size()==1){ bool electron = this->ElectronID(trackAR,clusters[0]); if(electron){ Mass = massElectron; Energy = sqrt(Mom[0]*Mom[0]+Mom[1]*Mom[1]+Mom[2]*Mom[2]+massElectron*massElectron); IDPart = -11; if(Charge<0)IDPart=11; if(_printing>0)std::cout << " TAGGED electron " << IDPart << std::endl; } } // now deal with split tracks if(trackAR->isSplitE()){ MyTrackExtended* parent = _tracksAR[itrack]->getSplitParent(); Charge = parent->getOmega(); Charge = Charge/fabs(Charge); Mom[0] = parent->getStartMomentum()[0]; Mom[1] = parent->getStartMomentum()[1]; Mom[2] = parent->getStartMomentum()[2]; Energy = sqrt(Mom[0]*Mom[0]+Mom[1]*Mom[1]+Mom[2]*Mom[2]+0.14*0.14); recoPart->addTrack(parent->getTrack()); } // now deal with tagged charged kaon->mu nu decays if(trackAR->isKinkE()){ MyTrackExtended* parent = _tracksAR[itrack]->getKinkParent(); if(parent->trackStatus()==TRACK_STATUS_CHARGED_KAON_DECAY){ float mx = this->kinkMass(parent,trackAR,0.106,0.000); if(_printing>0)std::cout << " KINK Parent Mass : " << mx << std::endl; fMKink->Fill(mx,1.); Mass = mx; float deltamPI = _piToMuMassWindowWidth; float deltamK = _kToMuMassWindowWidth; float Emu = trackAR->getEnergy(); if(Emu<1.0){ deltamPI = deltamPI*1.5; deltamK = deltamK*1.5; } if(clusters.size()==1){ if(clusters[0]->MipFraction()>0.9){ deltamPI = deltamPI*1.5; deltamK = deltamK*1.5; } } bool pass = false; if( fabs(mx-0.140) 0.494 - deltamK && mx < 0.494 + deltamK*1.5)pass = true; if(pass){ recoPart->addTrack(parent->getTrack()); // any back scatters ? unsigned int ndaugthers = parent->getNBackScatterDaughters(); for(unsigned int i=0;igetBackScatterDaughter(i); ProtoClusterVec aclusters = d->getClusterVec(); recoPart->addTrack(d->getTrack()); for(unsigned int i=0;iGetCluster(); if(cluster!=NULL)recoPart->addCluster(cluster); } } Charge = parent->getOmega(); Charge = Charge/fabs(Charge); Mom[0] = parent->getStartMomentum()[0]; Mom[1] = parent->getStartMomentum()[1]; Mom[2] = parent->getStartMomentum()[2]; Energy = sqrt(Mom[0]*Mom[0]+Mom[1]*Mom[1]+Mom[2]*Mom[2]+Mass*Mass); if(_printing>0)std::cout << " KINK Parent Energy : " << Energy << std::endl; if( mx > 0.494 - deltamK && mx < 0.494 + deltamK*1.5){ IDPart = 321; if(Charge<0)IDPart=-321; } }else{ if(_printing>0)std::cout << " KINK Parent NOT USED " << std::endl; // nevertheless add the track - but not its energy recoPart->addTrack(parent->getTrack()); } }else{ // not tagged as decay, nevertheless add the track - but not its energy recoPart->addTrack(parent->getTrack()); } } // now deal with prongs if(trackAR->isProngE()){ Mom[0] = trackAR->getStartMomentum()[0]; Mom[1] = trackAR->getStartMomentum()[1]; Mom[2] = trackAR->getStartMomentum()[2]; Energy = trackAR->getEnergy(); MyTrackExtended* parent = _tracksAR[itrack]->getProngParent(); unsigned int ndaugthers = parent->getNProngDaughters(); Charge = parent->getOmega(); Charge = Charge/fabs(Charge); for(unsigned int i=0;igetProngDaughter(i); bool aGoodTrack = GoodPFOTrack(d); if(aGoodTrack && d!=trackAR){ // mark associated track as used in this prong (reuse V0) d->setTrackStatus(TRACK_STATUS_USED_IN_V0); ProtoClusterVec aclusters = d->getClusterVec(); Mom[0] += d->getStartMomentum()[0]; Mom[1] += d->getStartMomentum()[1]; Mom[2] += d->getStartMomentum()[2]; Energy += d->getEnergy(); Mass = (Energy*Energy - Mom[0]*Mom[0]- Mom[1]*Mom[1]- Mom[2]*Mom[2]); if(Mass > 0){ Mass = sqrt(Mass); }else{ Mass = 0.; } recoPart->addTrack(d->getTrack()); // any back scatters ? unsigned int ndaugthers = d->getNBackScatterDaughters(); for(unsigned int i=0;igetBackScatterDaughter(i); ProtoClusterVec aclusters = dd->getClusterVec(); recoPart->addTrack(dd->getTrack()); for(unsigned int i=0;iGetCluster(); if(cluster!=NULL)recoPart->addCluster(cluster); } } for(unsigned int i=0;iGetCluster(); if(cluster!=NULL)recoPart->addCluster(cluster); } } } recoPart->addTrack(parent->getTrack()); // any back scatters ? ndaugthers = parent->getNBackScatterDaughters(); for(unsigned int i=0;igetBackScatterDaughter(i); ProtoClusterVec aclusters = d->getClusterVec(); recoPart->addTrack(d->getTrack()); for(unsigned int i=0;iGetCluster(); if(cluster!=NULL)recoPart->addCluster(cluster); } } if(_printing>0)std::cout << " PRONG : " << Energy << " <-> " << parent->getEnergy() << " mass = " << Mass << std::endl; // K+ -> pi+ pi+ pi- if(fabs(Mass-0.494)<0.03){ IDPart = 321; if(Charge<0)IDPart=-321; // use parent momentum Mom[0] = parent->getMomentum()[0]; Mom[1] = parent->getMomentum()[1]; Mom[2] = parent->getMomentum()[2]; }else{ Mass = 0.140; } Energy = sqrt(Mom[0]*Mom[0]+Mom[1]*Mom[1]+Mom[2]*Mom[2]+Mass*Mass); } // now deal with tagged V0s if(trackAR->isV0()){ int pIDPart = IDPart; // this track is part of V0 initially assume it is a photon conversion IDPart = 22; Charge = 0; // find associated track MyTrackExtended* assocTrack = trackAR->GetMatchedV0Track(); bool aGoodTrack = GoodPFOTrack(assocTrack); if(aGoodTrack){ // mark associated track as used in this V0 assocTrack->setTrackStatus(TRACK_STATUS_USED_IN_V0); // electron ID - still fairly primitive - cuts not tuned ProtoClusterVec aclusters = assocTrack->getClusterVec(); float aCharge = assocTrack->getOmega(); for(unsigned int i=0;iGetCluster(); if(cluster!=NULL)recoPart->addCluster(cluster); } recoPart->addTrack(assocTrack->getTrack()); aCharge = aCharge/fabs(aCharge); int aIDPart = 211; if(aCharge<0)aIDPart=-211; if(aclusters.size()==1){ bool electron = this->ElectronID(assocTrack,aclusters[0]); if(electron){ aIDPart = -11; if(aCharge<0)aIDPart=11; if(_printing>0)std::cout << " TAGGED electron " << aIDPart << std::endl; } } // if using external V0 finder use the vertex information if(_v0Finder==2 || _v0Finder ==3 ){ // loop over the v0s and search for matching tracks for(unsigned int iv=0; iv<_externalV0s.size();iv++){ ReconstructedParticle* part = _externalV0s[iv]->getAssociatedParticle(); TrackVec tracks = part->getTracks(); for(unsigned int it = 0; itgetTrack()){ std::cout << " Found V0 Track " << std::endl; matchExternalV0 = true; Charge = 0; float Mom[3]; Mom[0] = part->getMomentum()[0]; Mom[1] = part->getMomentum()[1]; Mom[2] = part->getMomentum()[2]; float Energy = Mom[0]*Mom[0]+Mom[1]*Mom[1]+Mom[2]*Mom[2]; IDPart = part->getType(); if(IDPart==22)Energy = sqrt(Energy); if(IDPart==310)Energy = sqrt(Energy+massK0S*massK0S); if(abs(IDPart)==3122)Energy = sqrt(Energy+massLambda*massLambda); if(_printing>0 && IDPart==22)std::cout << " Photon Conversion Energy : " << Energy << std::endl; if(_printing>0 && IDPart==310)std::cout << " K0S Energy : " << Energy << std::endl; if(_printing>0 && abs(IDPart)==3122)std::cout << " Lambda Energy : " << Energy << std::endl; recoPart->setMomentum( part->getMomentum() ); recoPart->setEnergy( Energy ); recoPart->setMass( part->getMass() ); recoPart->setCharge( Charge ); recoPart->setType( IDPart ); recoPart->setStartVertex( part->getStartVertex() ); recparcol->addElement( recoPart ); } } } } // KS hypothesis float mom1[4]; float mom2[4]; for(unsigned int i=0;i<3;++i){ mom1[i] = assocTrack->getStartMomentum()[i]; mom2[i] = trackAR->getStartMomentum()[i]; mom[i] = mom1[i]+mom2[i]; } mom1[3] = sqrt(mom1[0]*mom1[0]+mom1[1]*mom1[1]+mom1[2]*mom1[2]+0.14*0.14); mom2[3] = sqrt(mom2[0]*mom2[0]+mom2[1]*mom2[1]+mom2[2]*mom2[2]+0.14*0.14); float mks = sqrt((mom1[3]+mom2[3])*(mom1[3]+mom2[3])-mom[0]*mom[0]-mom[1]*mom[1]-mom[2]*mom[2]); float momKS[4]; for(unsigned int i=0;i<4;++i)momKS[i]=mom1[i]+mom2[i]; if(_printing>0)std::cout << " V0 KS MASS : " << mks << std::endl; // Lambda hypothesis float charge2 = trackAR->getOmega(); charge2 = charge2/fabs(charge2); mom1[3] = sqrt(mom1[0]*mom1[0]+mom1[1]*mom1[1]+mom1[2]*mom1[2]+0.14*0.14); mom2[3] = sqrt(mom2[0]*mom2[0]+mom2[1]*mom2[1]+mom2[2]*mom2[2]+0.938*0.938); float momLambda1[4]; for(unsigned int i=0;i<4;++i)momLambda1[i]=mom1[i]+mom2[i]; float mlambda1 = sqrt((mom1[3]+mom2[3])*(mom1[3]+mom2[3])-mom[0]*mom[0]-mom[1]*mom[1]-mom[2]*mom[2]); if(_printing>0)std::cout << " V0 LAMBDA 1 MASS : " << mlambda1 << std::endl; mom1[3] = sqrt(mom1[0]*mom1[0]+mom1[1]*mom1[1]+mom1[2]*mom1[2]+0.938*0.938); mom2[3] = sqrt(mom2[0]*mom2[0]+mom2[1]*mom2[1]+mom2[2]*mom2[2]+0.14*0.14); float momLambda2[4]; for(unsigned int i=0;i<4;++i)momLambda2[i]=mom1[i]+mom2[i]; float mlambda2 = sqrt((mom1[3]+mom2[3])*(mom1[3]+mom2[3])-mom[0]*mom[0]-mom[1]*mom[1]-mom[2]*mom[2]); if(_printing>0)std::cout << " V0 LAMBDA 2 MASS : " << mlambda2 << std::endl; float dk0 = fabs(mks-0.498); float dlambda1 = fabs(mlambda1-1.116); float dlambda2 = fabs(mlambda2-1.116); float dlambda=dlambda1; int ilambda=1; if(dlambda20)std::cout << " V0 Tagged KS " << Energy << std::endl; } }else{ if(dlambda<0.025){ IDPart = 3122; if(ilambda==1)Energy = momLambda1[3]; if(ilambda==2)Energy = momLambda2[3]; float charge2 = trackAR->getOmega(); charge2 = charge2/fabs(charge2); if(charge2<0 && ilambda==1)IDPart=-IDPart; if(charge2>0 && ilambda==2)IDPart=-IDPart; if(_printing>0)std::cout << " V0 Tagged Lambda " << IDPart << " " << Energy << std::endl; } } if(IDPart==22){ Energy = sqrt(mom1[0]*mom1[0]+mom1[1]*mom1[1]+mom1[2]*mom1[2])+ sqrt(mom2[0]*mom2[0]+mom2[1]*mom2[1]+mom2[2]*mom2[2]); if(_printing>0)std::cout << " V0 conversion ? " << IDPart << " " << Energy << std::endl; // if neither track is identified as an electron. Assume it is // a KS decay if(abs(aIDPart)!=11 && abs(pIDPart)!=11)IDPart = 310; } if(_printing>0)std::cout << " V0 ENERGY OLD : " << trackAR->getEnergy()+assocTrack->getEnergy()<0){ if(clusters.size()>0){ if(clusters[0]->IsPrimaryPhoton())std::cout << " V0 electron? " << energy << " <-> " << clusters[0]->EnergyEM() << endl; std::cout << " V0 mass : " << Mass << std::endl; } } }else{ // other part of V0 is a bad track - add it to PFO but don't add energy // take energy from cluster and assume KS, i.e. possible pi->mu kink recoPart->addTrack(assocTrack->getTrack()); streamlog_out(WARNING) << " PandoraPFAProcessor::CreatePFOCollection adding a bad V0 track (take energy from cluster)" << std::endl; float mom1[4]; mom1[3] = 0; for(unsigned int i=0;i<3;++i){ mom1[i] = assocTrack->getStartMomentum()[i]; mom1[3]+=mom1[i]*mom1[i]; } mom1[3] = sqrt(mom1[3]); float eclust = 0; ProtoClusterVec clusters = assocTrack->getClusterVec(); for(unsigned int i=0;iGetCluster(); if(cluster!=NULL)recoPart->addCluster(cluster); eclust += clusters[i]->EnergyHAD(); } for(unsigned int i=0;i<3;++i)Mom[i]+= mom1[i]*eclust/mom1[3]; Energy = sqrt( Mom[0]*Mom[0]+Mom[1]*Mom[1]+Mom[2]*Mom[2]+0.4498*0.498 ); IDPart = 310; Charge = 0; } } if(matchExternalV0 == false){ recoPart->setMomentum( Mom ); recoPart->setEnergy( Energy ); recoPart->setMass( Mass ); recoPart->setCharge( Charge ); recoPart->setType( IDPart ); recparcol->addElement( recoPart ); } } } for(unsigned int icluster=0;icluster<_finalProtoClusters.size();++icluster){ if(_finalProtoClusters[icluster]->AssociatedTrack()==false){ bool photonID = _finalProtoClusters[icluster]->IsPhoton(); float E = _finalProtoClusters[icluster]->EnergyEM(); if(E>1)fMipFrac->Fill(_finalProtoClusters[icluster]->MipFraction()); if(!photonID){ E = _finalProtoClusters[icluster]->EnergyHAD(); if(_leakageCorrection==1){ float eCor = 0; for(int ihit = 0;ihit< _finalProtoClusters[icluster]->Hits();ihit++){ MyCaloHitExtended* hiti = _finalProtoClusters[icluster]->Hit(ihit); if( hiti->getCalorimeterHitType()==CALHITTYPE_HCAL ){ int layersFromEdge = this->LayersFromEdge(hiti); if(layersFromEdge<_leavingHitLayersFromEdge){ eCor += hiti->getEnergyHAD()*(_leavingHitWeightingFactor-1.); } } } if(eCor>0){ if(_printing>0)std::cout << " Leakage Correction : " << E << " --> " << E+eCor << std::endl; E+=eCor; } } //bool hotHadron = _finalProtoClusters[icluster]->IsHotHadron(); //float eInMips = _finalProtoClusters[icluster]->EnergyInMips(); //float meanMipsPerHit = eInMips/_finalProtoClusters[icluster]->Hits(); } bool dodgy = false; //AnalyseCluster(_finalProtoClusters[icluster]); int il = _finalProtoClusters[icluster]->FirstLayer(); int ll = _finalProtoClusters[icluster]->LastLayer(); int layers = ll - il+1; if(layers<=1)dodgy=true; // if(_finalProtoClusters[icluster]->DCosR()<0.0)dodgy=true; if(photonID || (!dodgy&&E>_minimumClusterEnergyHAD) ){ // get cluster from ProtoCluster - returns NULL if cluster does // not pass minimum his/energy cuts ClusterImpl* cluster = _finalProtoClusters[icluster]->GetCluster(); if(cluster!=NULL){ IDPart = 1; ReconstructedParticleImpl * recoPart = new ReconstructedParticleImpl(); recoPart->addCluster(cluster); Energy = E; float totGravity = 0.0; for (int i=0; i < 3; ++i) { float xgrav = cluster->getPosition()[i]; Mom[i] = Energy*xgrav; totGravity += xgrav*xgrav; } totGravity = sqrt(totGravity); for (int i=0; i < 3; ++i)Mom[i] = Mom[i]/totGravity; Mass = 0.; if(!photonID){ Mass = 0.0; Energy = sqrt(Energy*Energy+Mass*Mass); } IDPart = 2112; if(photonID)IDPart=22; recoPart->setMomentum( Mom ); recoPart->setEnergy( Energy ); recoPart->setMass( Mass ); recoPart->setCharge( 0. ); recoPart->setType( IDPart ); int errorType =_finalProtoClusters[icluster]->GetErrorType(); if(errorType==999)recoPart->setType(999); if(_cfCheck==0 || errorType!=2 || Energy > 2.0){ recparcol->addElement( recoPart ); } if(_recoDisplay!=NULL&&photonID&&Energy>10002.5){ if(_printing>0)std::cout << " PHOTON ENERGY = " << Energy << std::endl; //_recoDisplay->DrawLongitudinalProfile(_finalProtoClusters[icluster]); } } } } } evt->addCollection( recparcol , _particleCollectionName.c_str() ); if(_printing>0)std::cout << " CreatePFOCollection DONE" << std::endl; } bool PandoraPFAProcessor::GoodPFOTrack(MyTrackExtended* trackAR){ bool goodTrack = false; if(trackAR->trackStatus()==TRACK_STATUS_GOOD || trackAR->trackStatus()==TRACK_STATUS_LOWPT)goodTrack = true; // try and make code less senstitive to background (K. Wichmann) if(goodTrack){ int nonSiHits = trackAR->nonSiHits(); float px = trackAR->getMomentum()[0]; float py = trackAR->getMomentum()[1]; float pz = trackAR->getMomentum()[2]; float p = sqrt(px*px+py*py+pz*pz); float cost = fabs(pz)/p; float pT = sqrt(px*px+py*py); if( cost<0.90 && pT < 1.0 && p < 2.0){ Track* track = trackAR->getTrack(); int vtxHits = track->getSubdetectorHitNumbers()[0]; int ftdHits = track->getSubdetectorHitNumbers()[1]; int sitHits = track->getSubdetectorHitNumbers()[2]; int tpcHits = track->getSubdetectorHitNumbers()[3]; if(pT<0.2)goodTrack = false; if( sitHits==0 && tpcHits < 10 && ftdHits== 0)goodTrack = false; } } bool goodNonVertexTrack = false; bool lowptNonVertexTrack = false; ProtoClusterVec clusters = trackAR->getClusterVec(); if(_usingNonVertexTracks && trackAR->trackStatus()==TRACK_STATUS_NON_VERTEX && trackAR->getInnerR() < _tpcInnerR+25.){ goodNonVertexTrack=true; if(_usingUnmatchedNonVertexTracks==0 && clusters.size()==0)goodNonVertexTrack = false; if(_detector==DETECTOR_LDC00 ||_detector==DETECTOR_LDC01){ bool missedEcal = false; // For LDC square ECAL coverage hole float x =trackAR->getSeedPosition()[0]; float y =trackAR->getSeedPosition()[1]; if(fabs(x)<_rInnerEcalEndcap+50. && fabs(y)<_rInnerEcalEndcap+50.)missedEcal = true; if(missedEcal)lowptNonVertexTrack = true; } } bool retVal = goodTrack || goodNonVertexTrack || lowptNonVertexTrack; return retVal; } float PandoraPFAProcessor::kinkMass(MyTrackExtended* parent, MyTrackExtended* daughter, float daughterMass, float neutralMass){ // Calculate the invariant mass for a decaying charged particle float Mom[3]; Mom[0] = parent->getEndMomentum()[0]; Mom[1] = parent->getEndMomentum()[1]; Mom[2] = parent->getEndMomentum()[2]; float pnu[3]; pnu[0] = Mom[0]-daughter->getStartMomentum()[0]; pnu[1] = Mom[1]-daughter->getStartMomentum()[1]; pnu[2] = Mom[2]-daughter->getStartMomentum()[2]; float Edaughter = sqrt(daughter->getStartMomentum()[0]*daughter->getStartMomentum()[0]+ daughter->getStartMomentum()[1]*daughter->getStartMomentum()[1]+ daughter->getStartMomentum()[2]*daughter->getStartMomentum()[2]+ daughterMass*daughterMass); float Enu = sqrt(pnu[0]*pnu[0]+pnu[1]*pnu[1]+pnu[2]*pnu[2]+neutralMass*neutralMass); float mx = sqrt((Edaughter+Enu)*(Edaughter+Enu)-Mom[0]*Mom[0]-Mom[1]*Mom[1]-Mom[2]*Mom[2]); return mx; } bool PandoraPFAProcessor::ElectronID(MyTrackExtended* trackAR, ProtoCluster* pC){ bool id = false; if(pC->IsPrimaryPhoton() || (pC->FirstLayer()<5 && pC->Energy()<5.0)){ pC->PhotonProfileID(); float showerStart = pC->GetLongProfileShowerStart(); float gammaFraction = pC->GetLongProfileGammaFraction(); if(showerStart<2.5&&gammaFraction<0.60){ float mom[3]; mom[0] = trackAR->getMomentum()[0]; mom[1] = trackAR->getMomentum()[1]; mom[2] = trackAR->getMomentum()[2]; float energy = sqrt(mom[0]*mom[0]+mom[1]*mom[1]+mom[2]*mom[2]); float eOverP = pC->EnergyEM()/energy; if(trackAR->isV0()){ if(_printing>0)std::cout << " V0 electron? " << energy << " <-> " << pC->EnergyEM() << endl; }else{ if(_printing>0)std::cout << " electron? " << energy << " <-> " << pC->EnergyEM() << endl; } if(_printing>0)std::cout << " electron? SHOWER START : " << showerStart << std::endl; if(_printing>0)std::cout << " electron? GAMMA FRACT : " << gammaFraction << std::endl; if( (gammaFraction<0.5) || fabs(eOverP-1.0)<0.2){ id = true; } Track* track = trackAR->getTrack(); LCObjectVec objectVec = _trackNavigator->getRelatedToObjects(track); if (objectVec.size() > 0){ MCParticle* part = dynamic_cast(objectVec[0]); if(_printing>0 && id)std::cout << " electron - PDG : " << part->getPDG() << std::endl; } } } return id; } void PandoraPFAProcessor::AnalysePFAPerformance(LCEvent * evt){ // flag mistakes and perform analysis for optimisation studies // off by default - to switch on use config "AnalyseClusters" // the advantage of doing this here is that the results can be // referred back to the ProtoClusters // base the analysis on reconstructed PFOS // reconstructed PFOs std::vector_pfovec; // true PFOs vector _pMcPFOs = *(_myMcTree->getMCPFOs()); if(_printing>1){ std::cout << " ***** ANALYSE PFA PERFORMANCE *****" << std::endl; std::cout << " ***** ANALYSE PFA PERFORMANCE *****" << std::endl; std::cout << " ***** ANALYSE PFA PERFORMANCE *****" << std::endl; std::cout << " ***** ANALYSE PFA PERFORMANCE *****" << std::endl; std::cout << " ***** ANALYSE PFA PERFORMANCE *****" << std::endl; } typedef const std::vector StringVec ; StringVec* strVec = evt->getCollectionNames() ; for(StringVec::const_iterator name=strVec->begin(); name!=strVec->end(); name++){ LCCollection* col = evt->getCollection(*name); int nelem = col->getNumberOfElements(); if (col->getTypeName() == LCIO::RECONSTRUCTEDPARTICLE) { for (int j=0; j < nelem; ++j) { ReconstructedParticle* recoPart = dynamic_cast(col->getElementAt(j)); _pfovec.push_back(recoPart); } } } float totenergy = 0; float totmom[3]={0.,0.,0.}; float tt =0.; float tg =0.; float th =0.; float gt =0.; float gg =0.; float gh =0.; float ht =0.; float hg =0.; float hh =0.; float matches[1000]; float totalmce[1000]; Track* mcpToRecoTrack[1000]; std::mappmcToiMcPFO; // Zero pointers from mcpfo to reconstructed track for(unsigned int imc=0;imc<_pMcPFOs.size();imc++)mcpToRecoTrack[imc]=NULL; // Loop over reconstructed PFOs for(unsigned int i=0;i<_pfovec.size();i++){ totenergy += _pfovec[i]->getEnergy(); totmom[0]+=_pfovec[i]->getMomentum()[0]; totmom[1]+=_pfovec[i]->getMomentum()[1]; totmom[2]+=_pfovec[i]->getMomentum()[2]; TrackVec tracks = _pfovec[i]->getTracks(); ClusterVec clusters = _pfovec[i]->getClusters(); for(unsigned int it=0;itgetRelatedToObjects(tracks[it]); if (objectVec.size() > 0){ MCParticle* navpart = dynamic_cast(objectVec[0]); for(unsigned int imc=0;imc<_pMcPFOs.size();imc++){ MCParticle* mcpart = _pMcPFOs[imc]->getMCParticle(); if(mcpart==navpart)mcpToRecoTrack[imc]=tracks[it]; } } } } // find total recorded energy for MC particles for(unsigned int imc=0;imc<_pMcPFOs.size();imc++)totalmce[imc] = 0.; for(unsigned int i=0;i<_pfovec.size();i++){ ClusterVec clusters = _pfovec[i]->getClusters(); for(unsigned int icluster=0;iclustergetCalorimeterHits(); for(unsigned int ihit=0;ihitgetRelatedToObjects(hits[ihit]); if (objectVec.size() > 0) { SimCalorimeterHit * simhit = dynamic_cast(objectVec[0]); if (simhit->getNMCContributions() > 0) { MCParticle * part = simhit->getParticleCont(0); unsigned int jmc = _myMcTree->GetMCPFOIndex(part); if(jmc<_pMcPFOs.size())totalmce[jmc]+=hits[ihit]->getEnergy(); } } } } } // TRY TO MATCH TRUE PFOs with RECONSTRUCTED PFOs // loop over particles and match CALO hits to MC PFOs for(unsigned int i=0;i<_pfovec.size();i++){ bool isTrack=false; bool isGamma=false; bool isHad=false; float thisgg= 0.; float thishh= 0.; float thistg= 0.; float thisth= 0.; float thistot = 0.; ClusterVec clusters = _pfovec[i]->getClusters(); TrackVec tracks = _pfovec[i]->getTracks(); if(tracks.size()>=1)isTrack=true; if(_pfovec[i]->getType()==22){ isGamma=true; isTrack=false; } if(!isGamma && !isTrack)isHad = true; for(unsigned int imc=0;imc<_pMcPFOs.size();imc++)matches[imc]=0.; if(_printing>2)std::cout << " PFO " << _pfovec[i]->getType() << " " << tracks.size() << " : " << clusters.size() << std::endl; for(unsigned int icluster=0;iclustergetCalorimeterHits(); for(unsigned int ihit=0;ihitgetRelatedToObjects(hits[ihit]); if (objectVec.size() > 0) { SimCalorimeterHit * simhit = dynamic_cast(objectVec[0]); if (simhit->getNMCContributions() > 0) { MCParticle * part = simhit->getParticleCont(0); unsigned int jmc = _myMcTree->GetMCPFOIndex(part); if(jmc<_pMcPFOs.size())matches[jmc]+=hits[ihit]->getEnergy(); } } } } for(unsigned int imc=0;imc<_pMcPFOs.size();imc++){ if(matches[imc]>0.){ thistot +=matches[imc]; MCParticle* mcpart = _pMcPFOs[imc]->getMCParticle(); if(_printing>2)std::cout << " ASSOC : " << imc << _pMcPFOs[imc]->getName() << " e = " << mcpart->getEnergy() << " -> " << matches[imc]<isTrack()){ if(isTrack){ tt+=matches[imc]; }else{ if(mcpToRecoTrack[imc]==NULL){ if(_printing>2)std::cout << " xxx no reco track " << std::endl; if(isGamma)hg+=matches[imc]; if(isHad){ hh+=matches[imc]; } }else{ if(_printing>2)std::cout << " *** reco track " << std::endl; if(isGamma){ tg+=matches[imc]; thistg+=matches[imc]; } if(isHad){ th+=matches[imc]; thisth+=matches[imc]; } } } } if(_pMcPFOs[imc]->isPhoton()){ if(isTrack)gt+=matches[imc]; if(isGamma){ gg+=matches[imc]; thisgg+=matches[imc]; } if(isHad)gh+=matches[imc]; } if(_pMcPFOs[imc]->isNeutralHadron()){ if(isTrack)ht+=matches[imc]; if(isGamma)hg+=matches[imc]; if(isHad){ hh+=matches[imc]; thishh += matches[imc]; } } } } // found a fragment bool badcluster = false; bool goodcluster = false; bool okcluster = false; float completeness = 0.; float purity=0.; if((thisth+thistg>0.5*thistot))badcluster = true; if((thishh>0.9*thistot))goodcluster = true; if((thisgg>0.9*thistot))goodcluster = true; int imost = -1; float most = 0.; float total = 0.; for(unsigned int imc=0;imc<_pMcPFOs.size();imc++){ total += matches[imc]; if(matches[imc]>most){ most = matches[imc]; imost = imc; } } if(imost>-1){ completeness = most/totalmce[imost]; purity = most/total; } if(_printing>0){ std::cout << " purity : " << purity << std::endl; std::cout << " completeness : " << completeness << std::endl; } if(goodcluster){ if(purity > 0.9){ if(completeness<0.75){ goodcluster = false; okcluster = true; } }else{ goodcluster = false; } } if(goodcluster||badcluster||okcluster){ if(_printing>0){ if(badcluster)std::cout << " BAD CLUSTER : " << thisth << " : " << thistg << " c.f. " << thistot << std::endl; if(goodcluster)std::cout << " GOOD CLUSTER : " << thisgg << " : " << thishh << " c.f. " << thistot << std::endl; if(okcluster)std::cout << " OK CLUSTER : " << thisgg << " : " << thishh << " c.f. " << thistot << " completeness : " << completeness << std::endl; } // find proto-cluster if(clusters.size()==1){ for(unsigned int ipcluster=0;ipcluster<_finalProtoClusters.size();++ipcluster){ if(clusters[0]==_finalProtoClusters[ipcluster]->GetCluster()){ _finalProtoClusters[ipcluster]->SetPurity(purity); _finalProtoClusters[ipcluster]->SetCompleteness(completeness); if(goodcluster)_finalProtoClusters[ipcluster]->SetBadness(0); if(okcluster)_finalProtoClusters[ipcluster]->SetBadness(1); if(badcluster)_finalProtoClusters[ipcluster]->SetBadness(2); bool photonID = _finalProtoClusters[ipcluster]->IsPhoton(); float E = _finalProtoClusters[ipcluster]->EnergyEM(); if(!photonID)E = _finalProtoClusters[ipcluster]->EnergyHAD(); int il = _finalProtoClusters[ipcluster]->FirstLayer(); int ll = _finalProtoClusters[ipcluster]->LastLayer(); // int layers = ll - il+1; int ihits = _finalProtoClusters[ipcluster]->Hits(); float dcosr = _finalProtoClusters[ipcluster]->DCosR(); float rms = _finalProtoClusters[ipcluster]->ClusterRMS(); float mipfrac = _finalProtoClusters[ipcluster]->MipFraction(); if(_printing>0){ std::cout << " PROTOCLUSTER : " << E << " layers : " << il << "-" << ll << std::endl; std::cout << " hits : " << ihits << " dcosr " << dcosr << " rms " << rms << " mipf " << mipfrac << std::endl; } } } } } } if(_printing>0){ std::cout << " TRACKS : " << tt << ":" << tg << ":" << th << std::endl; std::cout << " GAMMAS : " << gt << ":" << gg << ":" << gh << std::endl; std::cout << " N HADS : " << ht << ":" << hg << ":" << hh << std::endl; } if(_recoDisplay!=NULL)_recoDisplay->DrawByProtoClusterBadness(_finalProtoClusters,3,RECO_VIEW_XY); } void PandoraPFAProcessor::AnalyseClusters(ProtoClusterVec &pCs){ // TRY TO MATCH TRUE PFOs with RECONSTRUCTED PFOs // loop over particles and match CALO hits to MC PFOs if(_trackNavigator==NULL){ streamlog_out(ERROR) << " PandoraPFAProcessor::AnalyseClusters : track navigator not set - RelationTrackString not specified ?" << std::endl; return; } vector _pMcPFOs = *(_myMcTree->getMCPFOs()); MyTrackExtended* mcpToRecoTrack[_pMcPFOs.size()]; if(_pMcPFOs.size()*pCs.size() > 100000){ streamlog_out(ERROR) << " PandoraPFAProcessor::AnalyseClusters : too many " << std::endl; return; } float emc[_pMcPFOs.size()]; float emcbypc[_pMcPFOs.size()][pCs.size()]; float epc[pCs.size()]; std::mappmcToiMcPFO; // Zero pointers from mcpfo to reconstructed track for(unsigned int imc=0;imc<_pMcPFOs.size();imc++)mcpToRecoTrack[imc]=NULL; for(unsigned int imc=0;imc<_pMcPFOs.size();imc++){ emc[imc]=0.; for(unsigned int i=0;igetTrack(); LCObjectVec objectVec = _trackNavigator->getRelatedToObjects(track); if (objectVec.size() > 0){ MCParticle* navpart = dynamic_cast(objectVec[0]); for(unsigned int imc=0;imc<_pMcPFOs.size();imc++){ MCParticle* mcpart = _pMcPFOs[imc]->getMCParticle(); if(mcpart==navpart)mcpToRecoTrack[imc]=_tracksAR[it]; } } } for(unsigned int i=0;iHits(); for(int ihit=0;ihitHit(ihit); CalorimeterHit* hit = const_cast(hiti->getCalorimeterHit()); LCObjectVec objectVec = _caloNavigator->getRelatedToObjects(hit); if (objectVec.size() > 0) { SimCalorimeterHit * simhit = dynamic_cast(objectVec[0]); if (simhit->getNMCContributions() > 0) { MCParticle * part = simhit->getParticleCont(0); unsigned int jmc = _myMcTree->GetMCPFOIndex(part); if(jmc<_pMcPFOs.size()){ matches[jmc]+=hit->getEnergy(); emc[jmc] += hit->getEnergy(); emcbypc[jmc][i] += hit->getEnergy(); epc[i] += hit->getEnergy(); } } } } for(unsigned int imc=0;imc<_pMcPFOs.size();imc++){ if(matches[imc]>0.){ thistot +=matches[imc]; //MCParticle* mcpart = _pMcPFOs[imc]->getMCParticle(); if(_pMcPFOs[imc]->isTrack()){ if(mcpToRecoTrack[imc]==NULL)tf+=matches[imc]; if(mcpToRecoTrack[imc]!=NULL){ if(mcpToRecoTrack[imc]->trackStatus()==TRACK_STATUS_GOOD || mcpToRecoTrack[imc]->trackStatus()==TRACK_STATUS_LOWPT){ cf+=matches[imc]; }else{ tf1+=matches[imc]; } } } if(_pMcPFOs[imc]->isPhoton()){ pf+=matches[imc]; } if(_pMcPFOs[imc]->isNeutralHadron()){ nf+= matches[imc]; } } } if(thistot>0){ if(tf/thistot>0.5)type =1; if(tf1/thistot>0.5)type =5; if(cf/thistot>0.5)type =2; if(nf/thistot>0.5)type =3; if(pf/thistot>0.5)type =4; } pC->SetErrorType(type); } if(_checkForMCBug){ for(unsigned int imc=0;imc<_pMcPFOs.size();imc++){ float pmc[4]; pmc[0] = _pMcPFOs[imc]->getMomentum()[0]; pmc[1] = _pMcPFOs[imc]->getMomentum()[1]; pmc[2] = _pMcPFOs[imc]->getMomentum()[2]; pmc[3] = sqrt(pmc[0]*pmc[0]+pmc[1]*pmc[1]+pmc[2]*pmc[2]); float sigE = _hadEnergyRes*sqrt(pmc[3]); float sigma = (emc[imc]-pmc[3])/sigE; if(emc[imc]>2.0*pmc[3] && emc[imc]>5. && sigma > 7.5){ if(_printing>0)std::cout << "---> DODGY MC ? : " << emc[imc] << "<->" << pmc[3] << " " << pmc[2]/pmc[3] << " sig = " << sigma << std::endl; // may have a dodgy cluster !!!! for(unsigned int i=0;i0 && ebad/etot>0.5){ if(_printing>0)std::cout << " DODGY CLUSTER " << pCs[i]->EnergyHAD() << " " << pCs[i]->AssociatedTrack() << std::endl; if(_digitalECAL==0 && _digitalHCAL==0)pCs[i]->SetErrorType(999); } } } } } return; } void PandoraPFAProcessor::ClassifyTracks(ProtoClusterVec &protoClusters,MyTrackExtendedVec &extendedTracks, bool print = false ){ // loop over tracks and decide what to do... for(unsigned int itrack=0;itrackgetTrack(); TrackerHitVec hitvec = track->getTrackerHits(); int nhits = (int)hitvec.size(); float d0 = track->getD0(); float z0 = track->getZ0(); float x =trackAR->getSeedPosition()[0]; float y =trackAR->getSeedPosition()[1]; // float rextrap = sqrt(x*x+y*y); bool missedEcal = false; float r = sqrt(x*x+y*y); int nonSiHits = trackAR->nonSiHits(); bool ftdTrack = false; if(r<_tpcInnerR+100 && _usingFTDOnlyTracks!=0 && nonSiHits>=_minHitsFTDOnlyTracks)ftdTrack=true; // old LDC models if(_detector==DETECTOR_LDC00 ||_detector==DETECTOR_LDC01){ // is there a chance that this track would have missed the ECAL ? if(fabs(x)<_rInnerEcalEndcap+100. && fabs(y)<_rInnerEcalEndcap+100.)missedEcal = true; } bool mostlyok = ((nhits >= _minimumTrackHits && trackAR->reachedEcal()) || ftdTrack); if(trackAR->trackStatus()==TRACK_STATUS_KILLED)mostlyok = false; bool ok = (mostlyok &&fabs(d0)<_d0TrackCut&& fabs(z0)<_z0TrackCut); if(mostlyok)ok = (ok || trackAR->isV0() || trackAR->isKinkE() || trackAR->isProngE()); if(ok){ ProtoClusterVec clusters = trackAR->getClusterVec(); if(ftdTrack&&_printing>0)std::cout << " FTD Track " << trackAR->getEnergy() << " " << clusters.size() << std::endl; if(clusters.size()>=1 || trackAR->getEnergy()<_energyCutForVeryLowEnergyTracks){ trackAR->setTrackStatus(TRACK_STATUS_GOOD); }else{ bool islowpt = false; // apply tighter vertex cuts ? // if no Si hits then don't be so harsh with z0 ? int nonSiHits = trackAR->nonSiHits(); float d0Cut = _d0TrackCut/10.; float z0Cut = _z0TrackCut/10.; // if(nonSiHits==0)z0Cut = _z0TrackCut/2.; if(fabs(d0)getInnerR()<100.&& trackAR->getOuterR()>100. &&missedEcal)passed=true; if(trackAR->getInnerR()<100.&&missedEcal&&trackAR->getEnergy()<1.0)passed=true; if(passed){ if(nhits >= _minimumTrackHits && nonSiHits>=0 || trackAR->getEnergy()<1.0){ // now check to see if this track points to a cluster float closest = 99999.; int bestCluster=0; for(unsigned int icluster=0;iclusterDistanceToTrack(trackAR,10); if(approachAssociatedTrack()==false)veto=true; if(veto&&_printing>1)std::cout << " CHECK VETO : " << closest << " " << bestCluster << std::endl; if(!veto)islowpt = true; } } } if(islowpt)trackAR->setTrackStatus(TRACK_STATUS_LOWPT); if(!islowpt)trackAR->setTrackStatus(TRACK_STATUS_UNASSOC); } }else{ if(trackAR->trackStatus()!=TRACK_STATUS_KILLED)trackAR->setTrackStatus(TRACK_STATUS_BAD); if(mostlyok&&_usingNonVertexTracks)trackAR->setTrackStatus(TRACK_STATUS_NON_VERTEX); } } } void PandoraPFAProcessor::ClusterLoopingTrackAssociation(ProtoClusterVec &protoClusters,MyTrackExtendedVec &extendedTracks, bool print = false ){ // already done ? if(_perfectClustering && _perfectTrackClusterMatching)return; // track projection into endcap isn't as precise so try different approach // only applied to as yet unmatched tracks/clusters const float pi = 3.141592654; const float pi2 = pi/2.; for(unsigned int itrack=0;itrackgetClusterVec(); if(clusters.size()==0){ Track* track = trackAR->getTrack(); float d0 = track->getD0(); float z0 = track->getZ0(); float omega = track->getOmega(); float tanLambda = track->getTanLambda(); float phi0 = track->getPhi(); float radius =1.0/omega; float x0 = radius*cos(phi0-pi2); float y0 = radius*sin(phi0-pi2); TrackerHitVec hitvec = track->getTrackerHits(); int nhits = (int)hitvec.size(); float trackEnergy = trackAR->getEnergy(); float seedz = trackAR->getSeedPosition()[2]; float utrack[3]; utrack[2] = tanLambda/sqrt(1.0+tanLambda*tanLambda); bool ok = false; if( fabs(d0)<_d0TrackCut*2. && fabs(z0) <_z0TrackCut*2.)ok = true; if(_usingNonVertexTracks && trackAR->trackStatus() == TRACK_STATUS_NON_VERTEX)ok=true; if(trackAR->trackStatus()==TRACK_STATUS_KILLED)ok=false; if(ok &&nhits > 100 && !trackAR->isKinkS() && !trackAR->isSplitS() && !trackAR->isProngS() && fabs(seedz) > (_zOfEndcap-50.)){ float closest = 999999.; int bestCluster=-1; for(unsigned int icluster=0;iclusterAssociatedTrack()){ int il = pC->FirstLayer(); float zc = pC->GetCentroid(il)[2]; if(fabs(zc)>(_zOfEndcap-50.)&&il<10&& fabs(zc-seedz)<1000){ float ncount=0; float rsum=0; for(int ilayer = il; ilayerhitsInLayer(ilayer);ihit++){ MyCaloHitExtended* hiti = pC->hitInLayer(ilayer,ihit); const float* posi =hiti->getPosition(); float ri = sqrt((posi[0]-x0)*(posi[0]-x0)+(posi[1]-y0)*(posi[1]-y0)); ncount+=1.; rsum+=ri; } } float rmean = 0; if(ncount>0)rmean=rsum/ncount; float xc = pC->GetCentroid(il)[0]; float yc = pC->GetCentroid(il)[1]; float dx = xc - x0; float dy = yc - y0; float dr = sqrt(dx*dx+dy*dy)-fabs(radius); float drmean = rmean-fabs(radius); bool rmatch = false; if(dr<50.&&dr>-100)rmatch=true; if(drmean<50.&&drmean>-100)rmatch=true; if(drmean0){ utrack[0] = (1.0-utrack[2]*utrack[2])/(dx*dx/dy/dy+1.0); if(utrack[0]<0)utrack[0]=0.0; utrack[0]=sqrt(utrack[0]); if(dy>0)utrack[0]=-utrack[0]; if(radius>0)utrack[0] = -utrack[0]; utrack[1]= -dx/dy*utrack[0]; }else{ utrack[0] = 0; utrack[1] = sqrt(1.0-utrack[2]*utrack[2]); if(dx<0)utrack[1]=-utrack[1]; if(radius>0)utrack[1] = -utrack[1]; } fitResult fiti = pC->FitStart(10); if(fiti.ok){ float dcos = utrack[0]*fiti.dir[0]+utrack[1]*fiti.dir[1]+utrack[2]*fiti.dir[2]; float sigE = _hadEnergyRes*sqrt(trackEnergy); float chi = fabs(trackEnergy-pC->EnergyHAD())/sigE; // std::cout << pC->EnergyHAD() << " " << dcos << " " << sigE << " " << chi << " " << pC->MipFraction() << std::endl; if(rmatch&&chi<2.0&& (pC->MipFraction()>0.5||dcos>0.975)){ bool matched = false; if(fabs(dr)<10 && dcos>0.0)matched = true; if(fabs(dr)<25 && dcos>0.75)matched = true; if(fabs(dr)<50 && dcos>0.85)matched = true; if(dcos>0.925)matched = true; if(matched){ if(_printing>2){ std::cout << " xyz : " << xc << "," << yc << "," << zc << std::endl; std::cout << " DR : " << dr << std::endl; std::cout << " TRK : " << dx << "," << dy << "," << tanLambda << std::endl; std::cout << " TRK : " << utrack[0] << "," << utrack[1] << "," << utrack[2] << std::endl; std::cout << " Fit : " << fiti.dir[0] << "," << fiti.dir[1] << "," << fiti.dir[2] << std::endl; std::cout << " DIRECTION COSINE : " << dcos << std::endl; std::cout << " TRACK-CLUSTER : " << trackEnergy << "-" << pC->EnergyHAD() << std::endl; std::cout << " MIP ? " << pC->MipFraction() << std::endl; } if(fabs(dr)=0){ if(_printing>1)std::cout << " Looping cluster match : " << std::cout << " TRACK-CLUSTER : " << trackEnergy << "-" << protoClusters[bestCluster]->EnergyHAD() << std::endl; protoClusters[bestCluster]->AssociatedTrack(true); protoClusters[bestCluster]->AddTrack(trackAR); trackAR->addCluster(protoClusters[bestCluster]); trackAR->setTrackStatus(TRACK_STATUS_GOOD); } } } } } void PandoraPFAProcessor::ClusterTrackAssociation(ProtoClusterVec &protoClusters,MyTrackExtendedVec &extendedTracks, bool print = false ){ // already done ? if(_perfectClustering && _perfectTrackClusterMatching)return; // wibble if(_perfectTrackClusterMatching){ std::vector mcPFOs = *(_myMcTree->getMCPFOs()); // map tracks onto mc pfos unsigned int nTracks[mcPFOs.size()]; MyTrackExtended* mcExtendedTracks[mcPFOs.size()][10]; for(unsigned int i =0;igetTrack(); LCObjectVec objectVec = _trackNavigator->getRelatedToObjects(track); if (objectVec.size() > 0){ bool bs = false; MCParticle* part = dynamic_cast(objectVec[0]); if(part->isBackscatter()){ std::cout << " MC BACKSCATTER FLAG : " << _tracksAR[it]->getEnergy() << std::endl; if( _tracksAR[it]->getEnergy()<2.0)bs = true; } if(!bs){ unsigned int jmc = _myMcTree->GetMCPFOIndex(part); if(jmc>=0&&jmcgetEnergy() << std::endl; } } }else{ std::cout << " ****Unmatched TRACK : " << _tracksAR[it]->getEnergy() << std::endl; } } // end of wibble } // float table[extendedTracks.size()][protoClusters.size()]; //int ttable[extendedTracks.size()]; //int ctable[protoClusters.size()]; // int attable[extendedTracks.size()]; //int actable[protoClusters.size()]; // for(unsigned int ic=0;icClearClusters(); } for(unsigned int icluster=0;iclusterClearTracks(); } if(_printing>1)std::cout << std::flush; // track association for(unsigned int itrack=0;itrackgetTrack(); float d0 = track->getD0(); float z0 = track->getZ0(); TrackerHitVec hitvec = track->getTrackerHits(); int nhits = (int)hitvec.size(); float x =trackAR->getSeedPosition()[0]; float y =trackAR->getSeedPosition()[1]; float r = sqrt(x*x+y*y); int nonSiHits = trackAR->nonSiHits(); bool ftdTrack = false; if(r<_tpcInnerR+100.0 && _usingFTDOnlyTracks!=0 && nonSiHits>=_minHitsFTDOnlyTracks)ftdTrack=true; float trackEnergy = trackAR->getEnergy(); float rinner = trackAR->getInnerR(); // float router = trackAR->getOuterR(); bool ok = (fabs(d0)<_d0TrackCut && fabs(z0) <_z0TrackCut&& nhits >= _minimumTrackHits && trackAR->reachedEcal()); ok = ok || trackAR->isV0() || trackAR->isKinkE() || trackAR->isProngE() || trackAR->isSplitE() || ftdTrack; if(trackAR->trackStatus()==TRACK_STATUS_KILLED)ok=false; if(ok){ float closest = 999999.; int bestCluster=-1; float closestLE = 999999.; int bestClusterLE=-1; for(unsigned int icluster=0;iclusterDistanceToTrack(trackAR,10); //if(approach<_trackClusterAssociationDistance && protoClusters[icluster]->EnergyHAD()>0.2){ // ttable[itrack]++; //ctable[icluster]++; //table[itrack][icluster] = approach; //} if(approachEnergyHAD()>0.2){ closest = approach; bestCluster = icluster; } if(approachEnergyHAD()<=0.2){ closestLE = approach; bestClusterLE = icluster; } } if(trackAR->isKinkS()==false && trackAR->isProngS()==false && trackAR->isSplitS()==false ){ if(rinner<500. || trackAR->isV0() || trackAR->isKinkE()|| trackAR->isProngE()||trackAR->isSplitE()){ int matchedCluster = -999; float matchDistance = _trackClusterAssociationDistance; if(ftdTrack)matchDistance = _clusterFTDOnlyTrackDistance; if(closest=0){ protoClusters[matchedCluster]->AssociatedTrack(true); protoClusters[matchedCluster]->AddTrack(trackAR); trackAR->addCluster(protoClusters[matchedCluster]); } } } if(_printing>1 && print){ float assocE = 0.; if(bestCluster>-1)assocE=protoClusters[bestCluster]->EnergyHAD(); if(trackAR->isV0()){ std::cout << "VTRACK : " << itrack << " Cluster " << bestCluster << " Distance : " << closest << " " << trackEnergy << " " << assocE << std::endl; }else{ if(trackAR->isKinkS()){ std::cout << "KTRACK : " << itrack << " Cluster " << bestCluster << " Distance : " << closest << " " << trackEnergy << " " << assocE << std::endl; }else{ if(trackAR->isProngS()){ std::cout << "PTRACK : " << itrack << " Cluster " << bestCluster << " Distance : " << closest << " " << trackEnergy << " " << assocE << std::endl; }else{ std::cout << " TRACK : " << itrack << " Cluster " << bestCluster << " Distance : " << closest << " " << trackEnergy << " " << assocE << std::endl; } } } } } } //if(_printing>10){ // std::cout << " Track match summary " << std::endl; //for(unsigned int it=0;it1){ //std::cout << " Track " << extendedTracks[it]->getEnergy() << " is matched to : " << std::endl; //for(unsigned int ic=0;icEnergyEM() << " dist = " << table[it][ic] << " c = " << ctable[ic] << std::endl; // } //} //} //} //} } void PandoraPFAProcessor::AltClusterTrackAssociation(ProtoClusterVec &protoClusters,MyTrackExtendedVec &extendedTracks, bool print = false ){ // already done ? if(_perfectClustering && _perfectTrackClusterMatching)return; // try again with loopers using fit to last n hits for(unsigned int itrack=0;itrackgetClusterVec(); // if not previously matched try with Alternative projection if(clusters.size()==0){ Track* track = trackAR->getTrack(); float d0 = track->getD0(); float z0 = track->getZ0(); float rinner = trackAR->getInnerR(); TrackerHitVec hitvec = track->getTrackerHits(); int nhits = (int)hitvec.size(); if( (fabs(d0)<_d0TrackCut && fabs(z0) <_z0TrackCut&& nhits >= _minimumTrackHits && trackAR->reachedEcal()) ){ float closest = 999999.; int bestCluster=-1; for(unsigned int icluster=0;iclusterAssociatedTrack()==false){ float approach = protoClusters[icluster]->DistanceToAltTrack(trackAR,10); if(approachisKinkS()==false && trackAR->isProngS()==false && trackAR->isSplitS()==false && rinner<500.){ if( (closest<50. && trackAR->getEnergy()<5.0) || (closest<20. && trackAR->getEnergy()<25.0)){ float chi = this->ChiClusterTrack(protoClusters[bestCluster]->EnergyHAD(), trackAR->getEnergy()); if(chi<2.0){ protoClusters[bestCluster]->AssociatedTrack(true); protoClusters[bestCluster]->AddTrack(trackAR); trackAR->addCluster(protoClusters[bestCluster]); if(_printing>1)std::cout << " Alt Assoc " << trackAR->getEnergy() << " - " << protoClusters[bestCluster]->EnergyHAD() << " distance : " << closest << std::endl; if(trackAR->getEnergy()>5.0)streamlog_out(WARNING) << " AltClusterTrackAssociation : used for high energy track - may indicate tracking problem " << std::endl ; } } } } } } } void PandoraPFAProcessor::FinalTrackRecovery(ProtoClusterVec &protoClusters,MyTrackExtendedVec &extendedTracks, bool print=false){ // already done ? if(_perfectClustering && _perfectTrackClusterMatching)return; for(unsigned int itrack=0;itrackgetClusterVec(); // if not previously matched if(!trackAR->isKinkS() && !trackAR->isProngS() && !trackAR->isSplitS() && clusters.size()==0 && trackAR->trackStatus()!=TRACK_STATUS_LOWPT){ Track* track = trackAR->getTrack(); // float rinner = trackAR->getInnerR(); TrackerHitVec hitvec = track->getTrackerHits(); int nhits = (int)hitvec.size(); float d0 = track->getD0(); float z0 = track->getZ0(); if( (fabs(d0)<_d0TrackCut&& fabs(z0)<_z0TrackCut) || trackAR->isKinkE() || trackAR->isV0() || trackAR->isProngE() ){ float zmax =-99999.; float zmin =99999.; for(int ih =0;ihgetPosition()[2]; if(fabs(z)zmax)zmax = fabs(z); } float closest = 99999.; ProtoCluster* bestCluster = NULL; for(unsigned int icluster=0;iclusterAssociatedTrack()==false){ float approach = protoClusters[icluster]->DistanceToTrack(trackAR,20); float approachAlt = protoClusters[icluster]->DistanceToAltTrack(trackAR,20); float clusterE = protoClusters[icluster]->EnergyHAD(); float trackE = trackAR->getEnergy(); float sigE = trackE*_hadEnergyRes/sqrt(trackE); float deltaE = (clusterE-trackE); float chi = deltaE/sigE; bool leavingCluster = this->IsClusterLeavingDetector(protoClusters[icluster]); if(fabs(chi)<2. || (leavingCluster && chi <0) ){ if(approach1){ std::cout << " DODGY Track " << trackAR->getEnergy() << " " << trackAR->reachedEcal() << " " << zmin << "-" << zmax << " closest : " << closest << " e = "; if(bestCluster!=NULL)std::cout << bestCluster->EnergyHAD(); std::cout << " " << _tpcZmax << std::endl; } if(zmin<100 || trackAR->isKinkE() || trackAR->isProngE() ||trackAR->isSplitE() ){ if(zmax>_tpcZmax-200.){ // stable particle reached end cap - use it if(closest<100){ bestCluster->AssociatedTrack(true); bestCluster->AddTrack(trackAR); trackAR->addCluster(bestCluster); trackAR->setTrackStatus(TRACK_STATUS_GOOD); if(!trackAR->reachedEcal() && _printing>1)std::cout << " X RECOVERY " << std::endl; }else{ if(closest<250 && bestCluster->EnergyHAD()< trackAR->getEnergy()){ bestCluster->AssociatedTrack(true); bestCluster->AddTrack(trackAR); trackAR->addCluster(bestCluster); trackAR->setTrackStatus(TRACK_STATUS_GOOD); if(!trackAR->reachedEcal() && _printing>1)std::cout << " X X RECOVERY " << std::endl; }else{ if(trackAR->getEnergy()<1.5 &&zmax>_tpcZmax-100.)trackAR->setTrackStatus(TRACK_STATUS_LOWPT); } } }else{ if(closest<10 && trackAR->reachedEcal()){ bestCluster->AssociatedTrack(true); bestCluster->AddTrack(trackAR); trackAR->addCluster(bestCluster); trackAR->setTrackStatus(TRACK_STATUS_GOOD); if(_printing>1)std::cout << " X X X RECOVERY " << std::endl; } } } } } } } void PandoraPFAProcessor::FinalTrackRecoveryInteractions(ProtoClusterVec &protoClusters,MyTrackExtendedVec &extendedTracks, bool print=false){ // already done ? if(_perfectClustering && _perfectTrackClusterMatching)return; for(unsigned int itrack=0;itrackgetClusterVec(); // if not previously matched if(!trackAR->isKinkS() && !trackAR->isProngS() && !trackAR->isSplitS() && clusters.size()==0 && trackAR->trackStatus()==TRACK_STATUS_GOOD){ Track* track = trackAR->getTrack(); float d0 = track->getD0(); float z0 = track->getZ0(); if( (fabs(d0)<_d0TrackCut&& fabs(z0)<_z0TrackCut) || trackAR->isKinkE() || trackAR->isV0() || trackAR->isProngE() ){ float closest = 99999.; ProtoCluster* bestCluster = NULL; for(unsigned int icluster=0;iclusterAssociatedTrack()==false){ float approach = protoClusters[icluster]->DistanceToTrack(trackAR,20); float approachAlt = protoClusters[icluster]->DistanceToAltTrack(trackAR,20); // float clusterE = protoClusters[icluster]->EnergyHAD(); //float trackE = trackAR->getEnergy(); //float chi = this->ChiClusterTrack(clusterE,trackE); //bool leavingCluster = this->IsClusterLeavingDetector(protoClusters[icluster]); if(approach1)std::cout << " UNMATCHED TRACK : " << trackAR->getEnergy() << " closest clust " << bestCluster->EnergyHAD() << " dist = " << closest << std::endl; float seedx = trackAR->getSeedPosition()[0]; float seedy = trackAR->getSeedPosition()[1]; float seedz = trackAR->getSeedPosition()[2]; float tpcx = trackAR->getTpcIntersection()[0]; float tpcy = trackAR->getTpcIntersection()[1]; float tpcz = trackAR->getTpcIntersection()[2]; float tpcproj[3]; tpcproj[0] = (seedx - tpcx); tpcproj[1] = (seedy - tpcy); tpcproj[2] = (seedz - tpcz); float dseedtpc = sqrt(tpcproj[0]*tpcproj[0] + tpcproj[1]*tpcproj[1] + tpcproj[2]*tpcproj[2]); tpcproj[0] = tpcproj[0]/dseedtpc; tpcproj[1] = tpcproj[1]/dseedtpc; tpcproj[2] = tpcproj[2]/dseedtpc; float rseed = sqrt(seedx*seedx+seedy*seedy); int il = bestCluster->FirstLayer(); float xc = bestCluster->GetCentroid(il)[0]; float yc = bestCluster->GetCentroid(il)[1]; float rclust = sqrt(xc*xc+yc*yc); if(_printing>1){ std::cout << " rseed : " << rseed << " rclust " << rclust << std::endl; std::cout << " D(seed-tpc) = " << dseedtpc << std::endl; } if(closest<200){ float delta[3]; int firstLayer = bestCluster->FirstLayer(); delta[0] = bestCluster->GetCentroid(firstLayer)[0] - tpcx; delta[1] = bestCluster->GetCentroid(firstLayer)[1] - tpcy; delta[2] = bestCluster->GetCentroid(firstLayer)[2] - tpcz; float d = sqrt(delta[0]*delta[0]+delta[1]*delta[1]+delta[2]*delta[2]); float dcos = (delta[0]*tpcproj[0]+delta[1]*tpcproj[1]+delta[2]*tpcproj[2])/d; if(_printing>1)std::cout << " DCOS = " << dcos << " ***************************************************************************************************************************************************************************************************** " << std::endl; float clusterE = bestCluster->EnergyHAD(); if(closest<100 || dcos > 0.9 || clusterE < 0.5){ float trackE = trackAR->getEnergy(); float chi = this->ChiClusterTrack(clusterE,trackE); if(_printing>1)std::cout << " CHI = " << chi << std::endl; if(chi<2.0){ bestCluster->AssociatedTrack(true); bestCluster->AddTrack(trackAR); trackAR->addCluster(bestCluster); } } } } if(_printing>1 && bestCluster==NULL)std::cout << " UNMATCHED TRACK : " << trackAR->getEnergy() << " no closest clust " << std::endl; } } } } void PandoraPFAProcessor::FinalTrackRecoveryHelix(ProtoClusterVec &protoClusters,MyTrackExtendedVec &extendedTracks, bool print=false){ // already done ? if(_perfectClustering && _perfectTrackClusterMatching)return; vectorpCs; vectorts; vector cl; vector av; for(unsigned int itrack=0;itrackgetClusterVec(); if( // trackAR->reachedEcal() && !trackAR->isKinkS() && !trackAR->isProngS() && !trackAR->isSplitS() && clusters.size()==0){ Track* track = trackAR->getTrack(); // float rinner = trackAR->getInnerR(); TrackerHitVec hitvec = track->getTrackerHits(); int nhits = (int)hitvec.size(); float d0 = track->getD0(); float z0 = track->getZ0(); if(nhits >= _minimumTrackHits && trackAR->reachedEcal()){ if( (fabs(d0)<_d0TrackCut&& fabs(z0)<_z0TrackCut) || (trackAR->trackStatus()==TRACK_STATUS_NON_VERTEX && trackAR->getInnerR() < _tpcInnerR+25.) || trackAR->isKinkE() || trackAR->isV0() || trackAR->isProngE() || trackAR->isSplitE() ){ float zmax =-99999.; float zmin =99999.; for(int ih =0;ihgetPosition()[2]; if(fabs(z)zmax)zmax = fabs(z); } HelixClass* helix=NULL; for(int i=0;i<2;++i){ if(i==0)helix = trackAR->getHelix(); if(i==1)helix = trackAR->getAltHelix(); if(helix!=NULL){ float refs[3]; refs[0] = helix->getReferencePoint()[0]; refs[1] = helix->getReferencePoint()[1]; refs[2] = helix->getReferencePoint()[2]; int layersCrossed = 99999; float zs = trackAR->getSeedPosition()[2]; for(unsigned int icluster=0;iclusterAssociatedTrack() && !pCi->IsDefunct() && !pCi->IsPhoton()){ int firstLayer = pCi->FirstLayer(); float ze = pCi->GetCentroid(firstLayer)[2]; if(fabs(zs)<(fabs(ze)+250.) && zs*ze>0)layersCrossed = this->ExpectedLayersCrossed(zs, ze, helix); if(layersCrossed<50){ int lastLayer = firstLayer+20; if(lastLayer>MAX_NUMBER_OF_LAYERS)lastLayer=MAX_NUMBER_OF_LAYERS-1; float average = 0.; float count = 0.; float closest = 99999.; int layerCount = 0; for(int ilayer = firstLayer;ilayer<=lastLayer;ilayer++){ if(pCi->hitsInLayer(ilayer)>0)layerCount++; for(int ihit = 0;layerCount<10 && ihit< pCi->hitsInLayer(ilayer);ihit++){ float hitxyz[3]; float dist[3]; hitxyz[0] = pCi->hitInLayer(ilayer,ihit)->getPosition()[0]; hitxyz[1] = pCi->hitInLayer(ilayer,ihit)->getPosition()[1]; hitxyz[2] = pCi->hitInLayer(ilayer,ihit)->getPosition()[2]; helix->getDistanceToPoint(hitxyz, dist); average+= dist[2]; count+=1.; if(dist[2]0)average = average/count; float approach=999; if(i==0)approach = pCi->DistanceToTrack(trackAR,20); if(i==1)approach = pCi->DistanceToAltTrack(trackAR,20); if( (closest<100. && average < 150) || approach <100){ float clusterE = pCi->EnergyHAD(); float trackE = trackAR->getEnergy(); float sigE = trackE*_hadEnergyRes/sqrt(trackE); float deltaE = (clusterE-trackE); float chi = deltaE/sigE; if(fabs(chi)<2.5){ pCs.push_back(pCi); ts.push_back(trackAR); if(closest0){ if(!ts[ibest]->reachedEcal())std::cout << " X "; if(ts[ibest]->trackStatus()==TRACK_STATUS_NON_VERTEX)std::cout << " NonVtx "; if(ts[ibest]->trackStatus()==TRACK_STATUS_LOWPT)std::cout << " LowPt "; std::cout << " Track Recovery Helix : " << ts[ibest]->getEnergy() << " " << pCs[ibest]->EnergyHAD() << " hits = " << pCs[ibest]->Hits() << " close = " << cl[ibest] << " av = " << av[ibest] << std::endl; } stillGoing = true; pCs[ibest]->AssociatedTrack(true); pCs[ibest]->AddTrack(ts[ibest]); ts[ibest]->addCluster(pCs[ibest]); if(ts[ibest]->trackStatus()!=TRACK_STATUS_NON_VERTEX)ts[ibest]->setTrackStatus(TRACK_STATUS_GOOD); for(unsigned int i =0;igetClusterVec(); if(!trackAR->isKinkS() && !trackAR->isProngS() &&!trackAR->isSplitS() && clusters.size()==0 && trackAR->getEnergy() < _unmatchedVertexTrackMaxEnergy){ Track* track = trackAR->getTrack(); float d0 = track->getD0(); float z0 = track->getZ0(); TrackerHitVec hitvec = track->getTrackerHits(); int nhits = (int)hitvec.size(); float rini= trackAR->getInnerR(); if(nhits >= _minimumTrackHits && trackAR->reachedEcal() && trackAR->trackStatus()!=TRACK_STATUS_KILLED){ if( (fabs(d0)<_d0TrackCut/10.&& fabs(z0)<_z0TrackCut/10. && rini < _tpcInnerR+25.) || trackAR->isKinkE() || trackAR->isV0() || trackAR->isProngE() || trackAR->isSplitE() ){ if(trackAR->reachedEcal() && trackAR->trackStatus()!=TRACK_STATUS_LOWPT &&trackAR->trackStatus()!=TRACK_STATUS_NON_VERTEX){ trackAR->setTrackStatus(TRACK_STATUS_GOOD); if(_printing>1)std::cout << "Recovering BAD track : " << trackAR->getEnergy() << std::endl; } } } } } } return; } void PandoraPFAProcessor::ClusterNonVertexTrackAssociation(ProtoClusterVec &protoClusters,MyTrackExtendedVec &extendedTracks, bool print=false){ // already done ? if(_perfectClustering && _perfectTrackClusterMatching)return; // try again with loopers using fit to last n hits for(unsigned int itrack=0;itrackgetClusterVec(); // if not previously matched if(trackAR->trackStatus()==TRACK_STATUS_NON_VERTEX && clusters.size()==0 && trackAR->getInnerR() < _tpcInnerR+25.){ Track* track = trackAR->getTrack(); float rinner = trackAR->getInnerR(); TrackerHitVec hitvec = track->getTrackerHits(); int nhits = (int)hitvec.size(); if(_printing>1)std::cout << "NV track matching : " << trackAR->getEnergy() << " " << trackAR->reachedEcal() << std::endl; if(nhits >= _minimumTrackHits && trackAR->reachedEcal()){ float closest = 999999.; int bestCluster=-1; for(unsigned int icluster=0;iclusterAssociatedTrack()==false){ float approach = protoClusters[icluster]->DistanceToTrack(trackAR,10); float approachA = protoClusters[icluster]->DistanceToAltTrack(trackAR,10); if(approach1)std::cout << " Closest : " << closest << std::endl; if(trackAR->isKinkS()==false && trackAR->isProngS()==false && trackAR->isSplitS()==false) { if(closest< _trackClusterAssociationDistance && rinner<500.){ // check cluster-track energy consistency float clusterE = protoClusters[bestCluster]->EnergyHAD(); float trackE = trackAR->getEnergy(); float sigE = trackE*_hadEnergyRes/sqrt(trackE); float deltaE = (clusterE-trackE); float chi = deltaE/sigE; if(_printing>1)std::cout << " chi = " << chi << std::endl; bool pass = false; if(fabs(chi)<2.5)pass = true; if(closest<10 && fabs(chi)<3.5)pass = true; if(closest<2.5 && protoClusters[bestCluster]->MipFraction() > 0.8 && fabs(chi)<5.)pass = true; if(pass){ protoClusters[bestCluster]->AssociatedTrack(true); protoClusters[bestCluster]->AddTrack(trackAR); trackAR->addCluster(protoClusters[bestCluster]); } } } } } } } void PandoraPFAProcessor::ResolveTwoTrackAssociations(ProtoClusterVec &protoClusters,MyTrackExtendedVec &extendedTracks, bool print = false ){ // set up the cluster designs to be used for the attempted reclustering const int ndesign = 12; float scalei[ndesign] = {0.8,0.6,0.5,0.4,0.3,0.25,0.2,0.15,0.1,1.0,1.0,1.0}; int wgti[ndesign] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 0, 3}; protoClusterDesign_t design[ndesign]; for(int i=0;iClusterTrackAssociation(protoClusters,extendedTracks,false); unsigned int nclusters = protoClusters.size(); for(unsigned int jcluster=0;jclusterGetTrackVec(); if(tracks.size()==2){ float clusterE = parentCluster->EnergyHAD(); float trackE = 0.; for(unsigned int i=0; igetEnergy(); float sigE = trackE*_hadEnergyRes/sqrt(trackE); float deltaE = (clusterE-trackE); float chi = deltaE/sigE; int layersFromEdge=999; bool leavingCluster = false; if(chi<-_chiToAttemptReclustering){ leavingCluster = this->IsClusterLeavingDetector(parentCluster); layersFromEdge = this->LayersFromEdge(parentCluster); if(_printing>1)std::cout << " Layers from edge : " << layersFromEdge << std::endl; } if(chi<_chiToAttemptReclustering && !leavingCluster){ if(_printing>0){ std::cout << "*******RESOLVE TWO TRACK ASSOCIATION******** " << std::endl; } vectorclustersMatchedTo0; vectorclustersMatchedTo1; float et0 = tracks[0]->getEnergy(); float sigE0 = _hadEnergyRes*sqrt(et0); float et1 = tracks[1]->getEnergy(); float sigE1 = _hadEnergyRes*sqrt(et1); for(unsigned int icluster=0;iclusterAssociatedTrack()){ float approach0 = protoClusters[icluster]->DistanceToTrack(tracks[0],10); float approach1 = protoClusters[icluster]->DistanceToTrack(tracks[1],10); if(approach0<50)clustersMatchedTo0.push_back(icluster); if(approach1<50)clustersMatchedTo1.push_back(icluster); } } int ibest0=0; int ibest1=0; float chi2min = 999.; for(unsigned int i0=0;i0EnergyHAD(); float chi0 = (et0-ec0)/sigE0; float ec1 = protoClusters[clustersMatchedTo1[i1]]->EnergyHAD(); float chi1 = (et1-ec1)/sigE1; float chi2 = chi0*chi0+chi1*chi1; if(chi2ClearTracks(); tracks[0]->ClearClusters(); tracks[1]->ClearClusters(); int ic = clustersMatchedTo0[ibest0]; protoClusters[ic]->AssociatedTrack(true); protoClusters[ic]->AddTrack(tracks[0]); tracks[0]->addCluster(protoClusters[ic]); ic =clustersMatchedTo1[ibest1]; protoClusters[ic]->AssociatedTrack(true); protoClusters[ic]->AddTrack(tracks[1]); tracks[1]->addCluster(protoClusters[ic]); } }else{ if(_printing>0)std::cout << " TWO TRACKS RESOLUTION : GOOD CHI2 **************************************************************" << std::endl; // two tracks pointing to same cluster but good energy balance // can we split the cluster appropriately ? ProtoClusterVec finalClusters[ndesign]; // float newchi; float bestchi2 = 99999.; int ibest = -999; int jbest0 = -999; int jbest1 = -999; bool done = false; float et0 = tracks[0]->getEnergy(); float sigE0 = _hadEnergyRes*sqrt(et0); float et1 = tracks[1]->getEnergy(); float sigE1 = _hadEnergyRes*sqrt(et1); for(int i=0;iRecluster(parentCluster,tracks,design[i],finalClusters[i]); // do any of these new clusters satisfy our needs ? vectorclustersMatchedTo0; vectorclustersMatchedTo1; for(unsigned int icluster=0;iclusterDistanceToTrack(tracks[0],10); float approach1 = finalClusters[i][icluster]->DistanceToTrack(tracks[1],10); if(approach0<50)clustersMatchedTo0.push_back(icluster); if(approach1<50)clustersMatchedTo1.push_back(icluster); } bool okmatch=false; int ibest0=0; int ibest1=0; float chi2min = 99999.; for(unsigned int i0=0;i0EnergyHAD(); float chi0 = (et0-ec0)/sigE0; float ec1 = finalClusters[i][clustersMatchedTo1[i1]]->EnergyHAD(); float chi1 = (et1-ec1)/sigE1; float chi2 = chi0*chi0+chi1*chi1; if(_printing>1)std::cout << et0 << " <-> " << ec0 << " and " << et1 << " <-> " << ec1 << " giving chi2 : " << chi2 << std::endl; okmatch = true; if(chi21)std::cout << " BEST : " << ibest << std::endl; parentCluster->IsNowDefunct(); parentCluster->ClearTracks(); for(unsigned int icluster=0;iclusterSetTemporaryReclusteringFlag(false); } tracks[0]->ClearClusters(); tracks[1]->ClearClusters(); finalClusters[ibest][jbest0]->AssociatedTrack(true); finalClusters[ibest][jbest0]->AddTrack(tracks[0]); tracks[0]->addCluster(finalClusters[ibest][jbest0]); finalClusters[ibest][jbest1]->AssociatedTrack(true); finalClusters[ibest][jbest1]->AddTrack(tracks[1]); tracks[1]->addCluster(finalClusters[ibest][jbest1]); } } } } } void PandoraPFAProcessor::SplitMultipleTrackAssociations(ProtoClusterVec &protoClusters,MyTrackExtendedVec &extendedTracks, bool print = false ){ // set up the cluster designs to be used for the attempted reclustering const int ndesign = 12; float scalei[ndesign] = {0.8,0.6,0.5,0.4,0.3,0.25,0.2,0.15,0.1,1.0,1.0, 1.0}; int wgti[ndesign] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 0, 3}; protoClusterDesign_t design[ndesign]; for(int i=0;iClusterTrackAssociation(protoClusters,extendedTracks,false); unsigned int nclusters = protoClusters.size(); for(unsigned int jcluster=0;jclusterGetTrackVec(); if(tracks.size()==2){ float clusterE = parentCluster->EnergyHAD(); float trackE = 0.; for(unsigned int i=0; igetEnergy(); float sigE = trackE*_hadEnergyRes/sqrt(trackE); float deltaE = (clusterE-trackE); float chi = deltaE/sigE; // >one track pointing to the same cluster but with OK chi2 if(chi>-_chiToAttemptReclustering){ if(_printing>1){ std::cout << " ************************************************ " << std::endl; std::cout << " Multiple track association " << chi << std::endl; std::cout << " track 0 : " << tracks[0]->getEnergy() << std::endl; std::cout << " track 1 : " << tracks[1]->getEnergy() << std::endl; std::cout << " cluster : " << parentCluster->EnergyHAD() << std::endl; } ProtoClusterVec clustersToBeReclustered; clustersToBeReclustered.push_back(parentCluster); ProtoClusterVec finalClusters[ndesign]; int ibest = -1; float bestchi2 = 9999.; bool done = false; for(int idesign=0;idesignReclusterMultiple(clustersToBeReclustered,tracks,design[idesign],finalClusters[idesign]); if(_printing>1)std::cout << result.ntrackmatch << std::endl; if(result.ntrackmatch==1){ float newchi2 = result.chi2; if(newchi21.0 && newchi2<9.0){ ibest = idesign; bestchi2 = newchi2; } } // if found a v.good chi2 stop if(bestchi2<1.0)done=true; // if have a good chi2 and things getting worse - stop if(bestchi2<4.0&&newchi2>bestchi2)done=true; } } // Found a good match ? if(_printing>1)std::cout << " Best chi2 " << bestchi2 << " Design " << ibest << std::endl; if(ibest>=0 && bestchi2<_chiToAttemptReclustering*_chiToAttemptReclustering){ if(_printing>1)std::cout << "WILL RECLUSTER !!!! " << std::endl; // recluster for(unsigned int i=0;i1)std::cout << " Removing " << clustersToBeReclustered[i]->EnergyHAD() << std::endl; clustersToBeReclustered[i]->IsNowDefunct(); } for(unsigned int i=0;i1)std::cout << " Adding " << finalClusters[ibest][i]->EnergyHAD() << std::endl; protoClusters.push_back(finalClusters[ibest][i]); finalClusters[ibest][i]->SetTemporaryReclusteringFlag(false); } } } } } } void PandoraPFAProcessor::NewResolveTwoTrackAssociations(ProtoClusterVec &protoClusters,MyTrackExtendedVec &extendedTracks, bool print = false ){ // set up the cluster designs to be used for the attempted reclustering const int ndesign = 12; float scalei[ndesign] = {0.8,0.6,0.5,0.4,0.3,0.25,0.2,0.15,0.1,1.0,1.0, 1.0}; int wgti[ndesign] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 0, 3}; protoClusterDesign_t design[ndesign]; for(int i=0;iClusterTrackAssociation(protoClusters,extendedTracks,false); unsigned int nclusters = protoClusters.size(); for(unsigned int jcluster=0;jclusterGetTrackVec(); if(tracks.size()==2){ float clusterE = parentCluster->EnergyHAD(); float trackE = 0.; for(unsigned int i=0; igetEnergy(); float sigE = trackE*_hadEnergyRes/sqrt(trackE); float deltaE = (clusterE-trackE); float chi = deltaE/sigE; if(chi<-_chiToAttemptReclustering){ if(_printing>1){ std::cout << " ************************************************ " << std::endl; std::cout << " Multiple track problem " << chi << std::endl; std::cout << " track 0 : " << tracks[0]->getEnergy() << std::endl; std::cout << " track 1 : " << tracks[1]->getEnergy() << std::endl; std::cout << " cluster : " << parentCluster->EnergyHAD() << std::endl; } ProtoClusterVec clustersToBeReclustered; clustersToBeReclustered.push_back(parentCluster); vector coneAssocPCs; vector fConeAssocPCs; for(unsigned int icluster=0;iclusterGetTrackVec(); if(icluster!=jcluster && xtracks.size()==0){ float fraction = parentCluster->FractionInRadialCone(protoClusters[icluster],0.90); float fraction0 = protoClusters[icluster]->FractionInTrackCone(tracks[0],0.90); float fraction1 = protoClusters[icluster]->FractionInTrackCone(tracks[1],0.90); if(fraction>0.20){ fConeAssocPCs.push_back(fraction); coneAssocPCs.push_back(protoClusters[icluster]); }else{ if(fraction0>0.05||fraction1>0.05){ if(_printing>1)std::cout << " Good match based on trackCone " << fraction0 << " : " << fraction1 << " Energy " << protoClusters[icluster]->EnergyHAD() << std::endl; // fConeAssocPCs.push_back(0.25); //coneAssocPCs.push_back(protoClusters[icluster]); } clusterContact_t contact = parentCluster->ContactLayers(protoClusters[icluster],2.5); if(contact.contactLayers>4){ if(_printing>1)std::cout << " Contact : " << contact.contactLayers << " Energy " << protoClusters[icluster]->EnergyHAD() << std::endl; //fConeAssocPCs.push_back(0.25); //coneAssocPCs.push_back(protoClusters[icluster]); } } } } if(fConeAssocPCs.size()>0){ // sort in order of decreasing fraction unsigned int sizeOfVector = fConeAssocPCs.size(); if(sizeOfVector>1){ ProtoCluster *tempPC; float tempf; for (unsigned int i = 0 ; i < sizeOfVector-1; i++){ for (unsigned int j = 0; j < sizeOfVector-i-1; j++){ if(fConeAssocPCs[j] < fConeAssocPCs[j+1]){ tempf = fConeAssocPCs[j]; tempPC = coneAssocPCs[j]; fConeAssocPCs[j] = fConeAssocPCs[j+1]; fConeAssocPCs[j+1] = tempf; coneAssocPCs[j] = coneAssocPCs[j+1]; coneAssocPCs[j+1] = tempPC; } } } } } for(unsigned int i=0; i1)std::cout << " Ordered " << i << " Frac " << fConeAssocPCs[i] << " E : " << coneAssocPCs[i]->EnergyHAD() << std::endl; if(fConeAssocPCs[i]>0.20)clustersToBeReclustered.push_back(coneAssocPCs[i]); } ProtoClusterVec finalClusters[ndesign]; int ibest = -1; float bestchi2 = chi*chi; int ibestguess = -1; float bestguesschi = 99999.; bool done = false; for(int idesign=0;idesignReclusterMultiple(clustersToBeReclustered,tracks,design[idesign],finalClusters[idesign]); float newchi2 = result.chi2; if(newchi21.0 && newchi2<9.0){ ibest = idesign; bestchi2 = newchi2; } } // best 2 track match if(result.ntrackmatch==2&&result.chi>0&&result.chi16.0)done=true; } // Found a good match ? if(_printing>1)std::cout << " Best chi2 " << bestchi2 << " Design " << ibest << std::endl; if(ibest>=0 && bestchi2<_chiToAttemptReclustering*_chiToAttemptReclustering){ if(_printing>1)std::cout << "WILL RECLUSTER !!!! " << std::endl; // recluster for(unsigned int i=0;iIsNowDefunct(); } for(unsigned int i=0;iSetTemporaryReclusteringFlag(false); } }else{ if(_printing>1)std::cout << " BEST GUESS DESIGN : " << ibestguess<< std::endl; if(ibestguess>=0){ // not all over yet - this cluster still has too much energy... // try and break it (NOT SURE WHERE THIS SHOULD BE DONE) ProtoClusterVec bestGuessClustersToBeReclustered; for(unsigned int i=0;iGetTrackVec(); if(tracks.size()==2){ if(_printing>1)std::cout << " THIS CLUSTER " << thisCluster->EnergyHAD() << std::endl; bestGuessClustersToBeReclustered.push_back(thisCluster); float clusterE = thisCluster->EnergyHAD(); float trackE = tracks[0]->getEnergy()+tracks[1]->getEnergy(); float sigE = trackE*_hadEnergyRes/sqrt(trackE); float deltaE = (clusterE-trackE); float chi = deltaE/sigE; ProtoClusterVec guessFinalClusters[ndesign]; int newbest = -1; float newbestchi2 = chi*chi; bool done = false; for(int idesign=0;idesign1)std::cout << " Design : " << idesign << std::endl; ReclusterResult_t result = this->ReclusterMultiple(bestGuessClustersToBeReclustered,tracks,design[idesign],guessFinalClusters[idesign]); float newchi2 = result.chi2; if(newchi21.0 && newchi2<_chiToAttemptReclustering*_chiToAttemptReclustering){ newbest = idesign; newbestchi2 = newchi2; } } // if found a v.good chi2 stop if(newbestchi2<1.0)done=true; // if have a good chi2 and things getting worse - stop if(newbestchi2<4.0&&newchi2>16.0)done=true; } // Found a good match ? if(_printing>1)std::cout << " Best chi2 " << newbestchi2 << " Design " << newbest << std::endl; if(newbest>=0 && newbestchi2<_chiToAttemptReclustering*_chiToAttemptReclustering){ if(_printing>1)std::cout << "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWILL RECLUSTER !!!! " << std::endl; // recluster for(unsigned int i=0;iIsNowDefunct(); } for(unsigned int i=0;iGetTrackVec(); if(tracks.size()==0)protoClusters.push_back(thisCluster); thisCluster->SetTemporaryReclusteringFlag(false); } for(unsigned int i=0;iSetTemporaryReclusteringFlag(false); } }else{ if(_printing>1)std::cout << "nothing works " << std::endl; } } } }else{ int ifl = parentCluster->FirstLayer(); if(_printing>1)std::cout << "failed " << parentCluster->GetCentroid(ifl)[0] << "," << parentCluster->GetCentroid(ifl)[1]<ClusterTrackAssociation(protoClusters,extendedTracks,false); unsigned int nclusters = protoClusters.size(); for(unsigned int jcluster=0;jclusterGetTrackVec(); if(tracks.size()==1){ float clusterE = parentCluster->EnergyHAD(); float trackE = tracks[0]->getEnergy(); float sigE = trackE*_hadEnergyRes/sqrt(trackE); float deltaE = (clusterE-trackE); float chi = deltaE/sigE; if(chi>2.0){ if(_printing>1){ std::cout << " ************************************************ " << std::endl; std::cout << " Search for photon " << chi << std::endl; // ProtoCluster* photonCand = parentCluster->AgressiveFragmentPhoton(); ProtoClusterVec clustersToBeReclustered; clustersToBeReclustered.push_back(parentCluster); ProtoClusterVec finalClusters; ReclusterResult_t result = this->ReclusterMultiple(clustersToBeReclustered,tracks,design[12],finalClusters); //if(_recoDisplay!=NULL)_recoDisplay->DrawTransverseProfile(parentCluster,30); //if(_recoDisplay!=NULL)_recoDisplay->DrawSingleProtoCluster(parentCluster,RECO_VIEW_XY); } } } } } void PandoraPFAProcessor::PhotonRecovery(ProtoClusterVec &protoClusters,MyTrackExtendedVec &extendedTracks, bool print = false ){ this->ClusterTrackAssociation(protoClusters,extendedTracks,false); if(_printing>1)cout << " XPHOTON RECOVERY !!!!! " << std::endl; if(_printing>1)cout << " XPHOTON RECOVERY !!!!! " << std::endl; if(_printing>1)cout << " XPHOTON RECOVERY !!!!! " << std::endl; if(_printing>1)cout << " XPHOTON RECOVERY !!!!! " << std::endl; if(_printing>1)cout << " XPHOTON RECOVERY !!!!! " << std::endl; unsigned int nclusters = protoClusters.size(); for(unsigned int jcluster=0;jclusterGetTrackVec(); if(tracks.size()==1){ // bool checkThisCluster = true; int iterations = 0; while(checkThisCluster){ float ePhotons = 0.; float clusterE = parentCluster->EnergyHAD(); float trackE = tracks[0]->getEnergy(); float sigE = trackE*_hadEnergyRes/sqrt(trackE); float deltaE = (clusterE-trackE); float chi = deltaE/sigE; // for the moment don't do anything with exitting tracks std::vector peaks; parentCluster->TransverseProfile(peaks); if(_printing>1){ std::cout << " Track <-> Cluster : " << trackE << "<->" << clusterE << std::endl; for(unsigned int i=0;i0.01){ if(peaks[i].dmin=0)nSignificantPeaks++; // look for peaks other than the closest match to track // require energy of at least 1 GeV for(unsigned int i=0;i1.0){ int ii = i; if(ii != ipeak0){ nSignificantPeaks++; if(peaks[i].energy>e1){ ipeak2 = ipeak1; e2 = e1; ipeak1 = i; e1 = peaks[i].energy; }else if(peaks[i].energy>e2){ ipeak2 = i; e2 = peaks[i].energy; } } } } if(nSignificantPeaks==1 && peaks[ipeak0].dmin<=2){ // only one peak - to which the track points if(peaks[ipeak0].showerStartDepth<15){ bool doit = false; // careful to correct for possible different EM/HAD scale float epeak = peaks[ipeak0].energy*_ecalHadMIPToGeV/_ecalEMMIPToGeV; float xdeltaE = (clusterE-epeak-trackE); float xchi = xdeltaE/sigE; if(fabs(xchi) 2.0)interesting = true; if(chi>-2.0 && peaks[ipeak0].energy>2.5){ parentCluster->PhotonProfileID(true); float showerStart = parentCluster->GetLongProfileShowerStart(); float gammaFraction = parentCluster->GetLongProfileGammaFraction(); if(_printing>1){ std::cout << " chi " << chi << " -> " << xchi << std::endl; std::cout << " Gamma Frac : " << gammaFraction << " " << showerStart << std::endl; } // clear improvement of chi2 + good photonID bool photonID = false; if(gammaFraction<0.5&&showerStart<2.5)photonID = true; if(xchi*xchi+4 < chi*chi && photonID)doit=true; if(epeak/clusterE<0.5 && xchi*xchi2.5 && peaks[ipeak0].showerDepth25<20)recluster[0]= true; if(doit)recluster[0] = true; if(doit)interesting = true; if(_printing>1)std::cout << interesting << " : " << recluster[0]<< std::endl; } } // Criteria for reclustering // first where only a single peak has been identified if(nSignificantPeaks==1 && peaks[ipeak0].dmin>2){ // ipeak1 = ipeak0; // ipeak0 = -999; if(peaks[ipeak0].showerStartDepth<15&&peaks[ipeak0].energy>1.0){ // if(_recoDisplay!=NULL){ //_recoDisplay->DrawTransverseProfile(parentCluster,30); //} float xdeltaE = (clusterE-peaks[ipeak0].energy-trackE); float xchi = xdeltaE/sigE; if(_printing>1)std::cout << " ODD ONE : peak but no pointing track peak" << ipeak0 << " chi " << chi << " -> " << xchi << std::endl; if(fabs(xchi)1){ // recluster[0] = true; interesting = true; } } } if(nSignificantPeaks>1 && peaks[ipeak0].dmin<=2){ // more than one peak - to which the track points if(peaks[ipeak0].showerStartDepth<20){ float xdeltaE = (clusterE-peaks[ipeak0].energy-trackE); float xchi = xdeltaE/sigE; if(fabs(xchi)-2.0){ parentCluster->PhotonProfileID(true); float showerStart = parentCluster->GetLongProfileShowerStart(); float gammaFraction = parentCluster->GetLongProfileGammaFraction(); if(_printing>1)std::cout << " Gamma Frac : " << gammaFraction << std::endl; if(gammaFraction<0.5&&showerStart<2.5)recluster[0] = true; } if(chi>2.0)interesting = true; if(chi>2.0 && fabs(xchi)1 && ipeak0 >=0){ interesting = true; //bool prefer1=true; float xdeltaE1 = (clusterE-peaks[ipeak1].energy-trackE); float xchi1 = xdeltaE1/sigE; float xchi2=-999.; float xchi12=-999.; if(peaks[ipeak1].showerStartDepth<15){ if(xchi1>-2.0)recluster[1] = true; if(chi>2.0 && fabs(xchi1)0 && peaks[ipeak2].showerStartDepth<15){ float xdeltaE2 = (clusterE-peaks[ipeak2].energy-trackE); xchi2 = xdeltaE2/sigE; float xdeltaE12 = (clusterE-peaks[ipeak1].energy-peaks[ipeak2].energy-trackE); xchi12 = xdeltaE12/sigE; if(recluster[1]){ if(xchi12>-2.0){ recluster[1] = true; recluster[2] = true; }else if(fabs(xchi2)-2.0){ recluster[1] = false; recluster[2] = true; } } } } } // if no pointing clusters deal with these first if(recluster[1]||recluster[2])recluster[0]=false; if(interesting){ if(_printing>1){ std::cout << " Checking for photon : " << clusterE << " <-> " << trackE << " chi = " << chi << std::endl; if(ipeak0>=0)std::cout << " PEAK 0 : " << ipeak0 << " : " << peaks[ipeak0].du << "," << peaks[ipeak0].dv << " E = " << peaks[ipeak0].energy << " dmin : " << peaks[ipeak0].dmin << " d25/d90 : " << peaks[ipeak0].showerDepth25 << "/" << peaks[ipeak0].showerDepth90 << " start : " << peaks[ipeak0].showerStartDepth << std::endl; if(ipeak1>=0){ std::cout << " PEAK 1 : " << ipeak1 << " : " << peaks[ipeak1].du << "," << peaks[ipeak1].dv << " E = " << peaks[ipeak1].energy << " dmin : " << peaks[ipeak1].dmin << " d90 : " << peaks[ipeak1].showerDepth90 << " start : " << peaks[ipeak1].showerStartDepth << std::endl; float mipf10 = parentCluster->MipFraction( peaks[ipeak1].showerDepth90,peaks[ipeak1].showerDepth90+10); float mipf20 = parentCluster->MipFraction( peaks[ipeak1].showerDepth90+10,peaks[ipeak1].showerDepth90+20); if(_printing>1)std::cout << " MIPF : " << mipf10 << " " << mipf20 << std::endl; } if(ipeak2>=0)std::cout << " PEAK 2 : " << ipeak2 << " : " << peaks[ipeak2].du << "," << peaks[ipeak2].dv << " E = " << peaks[ipeak2].energy << " dmin : " << peaks[ipeak2].dmin << " d90 : " << peaks[ipeak2].showerDepth90 << " start : " << peaks[ipeak2].showerStartDepth << std::endl; if(recluster[0])std::cout << " WILL RECLUSTER 0 " << std::endl; if(recluster[1])std::cout << " WILL RECLUSTER 1 " << std::endl; if(recluster[2])std::cout << " WILL RECLUSTER 2 " << std::endl; //if(_recoDisplay!=NULL){ // _recoDisplay->DrawTransverseProfile(parentCluster,30); //} //if(recluster[0]||recluster[1]||recluster[2]){ // if(_recoDisplay!=NULL)_recoDisplay->DrawSingleProtoCluster(parentCluster,RECO_VIEW_XY); //} } ProtoCluster* photonCand[3]={NULL,NULL,NULL}; if(recluster[0]){ // Recluster a candidate photon overlapping with track // get default design protoClusterDesign_t design = (ProtoClusterFactory::Instance())->GetDesign(); // set endlayer to 90 % containment region + 5; int endLayer = peaks[ipeak0].showerDepth90+5; // get the clusters corresponding to the peak in this region photonCand[0] = parentCluster->TransverseProfile(ipeak0,30,endLayer-30); if(photonCand[0]==NULL){ if(_printing>1)std::cout << " NO New cluster returned !!!! " << std::endl; } if(photonCand[0]!=NULL){ // clone and delete it - i.e. give factory control over memory management photonCand[0]=(ProtoClusterFactory::Instance())->CloneAndDelete(photonCand[0]); // create empty track vector and recluster without track ProtoClusterVec newFinalClusters; MyTrackExtendedVec nullTracks; photonCand[0]->ClassifyYourself(); if(!photonCand[0]->IsPrimaryPhoton()){ if(_printing>1)std::cout << " New cluster doesn't look like a photon - carry on regardless " << std::endl; } float xdeltaE1 = (clusterE-photonCand[0]->EnergyHAD()-trackE); float xchi1 = xdeltaE1/sigE; if(_printing>1){ std::cout << " PARENT EHAD : " << parentCluster->EnergyHAD() << std::endl; std::cout << " EHAD : " << photonCand[0]->EnergyHAD() << std::endl; std::cout << " EEM : " << photonCand[0]->EnergyEM() << std::endl; std::cout << " New chi : " << xchi1 << std::endl; } if(photonCand[0]->EnergyEM()<1.5*peaks[ipeak0].energy && xchi1 > -2.5){ this->Recluster(photonCand[0],nullTracks,design,newFinalClusters); //if(_recoDisplay!=NULL){ // _recoDisplay->DrawLongitudinalProfile(photonCand[0]); //} photonCand[0]->PhotonProfileID(); float showerStart = photonCand[0]->GetLongProfileShowerStart(); float gammaFraction = photonCand[0]->GetLongProfileGammaFraction(); if(_printing>1)std::cout << " NEW PHOTON 0 SHOWER START : " << showerStart << std::endl; if(_printing>1)std::cout << " NEW PHOTON 0 GAMMA FRACT : " << gammaFraction << std::endl; if(showerStart<5.0 &&gammaFraction<0.75 ){ for(unsigned int i=0;iSetTemporaryReclusteringFlag(false); if(_printing>1)std::cout << " new cluster " << i << " : " << newFinalClusters[i]->EnergyHAD() << std::endl; } ePhotons+= photonCand[0]->EnergyEM(); // remove hits from original cluster // - except those lying on the track which // are added back in with zero energy vectorhitsForRemoval; for(int ilayer=1;ilayer<=endLayer;++ilayer){ int nhits = parentCluster->hitsInLayer(ilayer); float smallestDistance = 999.; MyCaloHitExtended* bestHit =NULL; for(int ihit=0;ihithitInLayer(ilayer,ihit); float distance = 1000.; float genericDistance = parentCluster->genericDistanceToTrackSeed(hiti,distance); if(genericDistanceclone(); _allCalHitsByPseudoLayer[bestHit->getPseudoLayer()].push_back(calohit); float emip = _hcalEMMIPToGeV; if(bestHit->getCalorimeterHitType()==CALHITTYPE_ECAL)emip = _ecalEMMIPToGeV; calohit->setEnergyEM(emip); calohit->setEnergyHAD(emip); calohit->setEnergyInMips(1.); parentCluster->AddHit(calohit); //parentCluster->AddHit(bestHit,0.01); } } for(unsigned int ihit = 0;ihitRemoveHit(hitsForRemoval[ihit]); } // Update the properties of the parent parentCluster->Update(MAX_NUMBER_OF_LAYERS); parentCluster->ClassifyYourself(); }else{ if(_printing>1)std::cout << " Vetoed photon cluster : LONG PROF" << std::endl; } }else{ if(_printing>1)std::cout << " Vetoed photon cluster : ENERGY" << photonCand[0]->EnergyEM() << std::endl; } }else{ streamlog_out(ERROR) << " ERROR - null pointer returned in PhotonRecovery " << std::endl; } } // // Recluster isolated peaks // // remove hits from original cluster // - except those lying on the track which // are added back in with zero energy vectorhitsForRemoval; vectortrackHitsToAddBack; int thePeak=ipeak1; for(int ipeak=1;ipeak<3;ipeak++){ if(recluster[ipeak]){ if(ipeak==1)thePeak=ipeak1; if(ipeak==2)thePeak=ipeak2; photonCand[ipeak] = parentCluster->TransverseProfile(thePeak,30,10); if(photonCand[ipeak]!=NULL){ // this cluster was made by a cluster and not the factory so // clone it and delete original - factory can now deal with memory management photonCand[ipeak]=(ProtoClusterFactory::Instance())->CloneAndDelete(photonCand[ipeak]); // check this makes sense... float xdeltaE = (clusterE-photonCand[ipeak]->EnergyHAD()-trackE); float xchi = xdeltaE/sigE; if(_printing>1)std::cout << trackE << "<->" << clusterE-photonCand[ipeak]->EnergyHAD() << "->" << xchi << std::endl; //if(_recoDisplay!=NULL){ // _recoDisplay->DrawLongitudinalProfile(photonCand[ipeak]); //} photonCand[ipeak]->PhotonProfileID(); float showerStart = photonCand[ipeak]->GetLongProfileShowerStart(); float gammaFraction = photonCand[ipeak]->GetLongProfileGammaFraction(); if(_printing>1)std::cout << " NEW PHOTON i SHOWER START : " << showerStart << std::endl; if(_printing>1)std::cout << " NEW PHOTON i GAMMA FRACT : " << gammaFraction << std::endl; if( (xchi>-2.5) && showerStart<5.0 && gammaFraction < 0.75){ protoClusters.push_back(photonCand[ipeak]); if(_printing>0)std::cout << " New Cluster E : " << photonCand[ipeak]->EnergyEM() << std::endl; ePhotons+= photonCand[ipeak]->EnergyEM(); for(int ilayer=1;ilayer<=30+10;++ilayer){ int nhits = parentCluster->hitsInLayer(ilayer); float smallestDistance = 999.; MyCaloHitExtended* bestHit =NULL; for(int ihit=0;ihithitInLayer(ilayer,ihit); float distance = 1000.; float genericDistance = parentCluster->genericDistanceToTrackSeed(hiti,distance); if(genericDistance1.0)bestHit=NULL; // bestHit is hit in parentCluster on track trajectory // now loop over new cluster int mhits = photonCand[ipeak]->hitsInLayer(ilayer); for(int ihit=0;ihithitInLayer(ilayer,ihit); hitsForRemoval.push_back(hiti); if(hiti==bestHit){ MyCaloHitExtended *calohit= bestHit->clone(); _allCalHitsByPseudoLayer[bestHit->getPseudoLayer()].push_back(calohit); float emip = _hcalEMMIPToGeV; if(bestHit->getCalorimeterHitType()==CALHITTYPE_ECAL)emip = _ecalEMMIPToGeV; calohit->setEnergyEM(emip); calohit->setEnergyHAD(emip); calohit->setEnergyInMips(1.); parentCluster->AddHit(calohit); } } } }else{ if(_printing>0)std::cout << " vetoed photon " << std::endl; } }else{ streamlog_out(ERROR) << " ERROR - null pointer returned in PhotonRecovery " << std::endl; } } } // clean up for(unsigned int ihit = 0;ihitRemoveHit(hitsForRemoval[ihit]); } // Update the properties of the parent parentCluster->Update(MAX_NUMBER_OF_LAYERS); parentCluster->ClassifyYourself(); if(_printing>0)std::cout << " Old Cluster E : " << parentCluster->EnergyHAD() << std::endl; if(hitsForRemoval.size()==0)recluster[1]=false; if(hitsForRemoval.size()==0)recluster[2]=false; } // check the original cluster again ? checkThisCluster = false; iterations++; if(ePhotons>1.0&&(recluster[1]||recluster[2])&&ipeak0>=0)checkThisCluster=true; // trap potential error if(iterations>2){ streamlog_out(WARNING) << " POTENTIAL ERROR IN PhotonReconvery" << std::endl; checkThisCluster = false; } } } } } void PandoraPFAProcessor::FinalPhotonRecovery(ProtoClusterVec &protoClusters,MyTrackExtendedVec &extendedTracks, bool print = false ){ this->ClusterTrackAssociation(protoClusters,extendedTracks,false); if(_printing>1)cout << " FINAL PHOTON RECOVERY !!!!! " << std::endl; unsigned int nclusters = protoClusters.size(); for(unsigned int jcluster=0;jclusterGetTrackVec(); if(tracks.size()==1){ float ePhotons = 0.; float clusterE = parentCluster->EnergyHAD(); float trackE = tracks[0]->getEnergy(); float sigE = trackE*_hadEnergyRes/sqrt(trackE); float deltaE = (clusterE-trackE); float chi = deltaE/sigE; if(chi>2.0){ std::vector peaks; parentCluster->TransverseProfile(peaks); if(_printing>1){ std::cout << " Track <-> Cluster : " << trackE << "<->" << clusterE << std::endl; for(unsigned int i=0;i0.01){ if(peaks[i].dmin=0)nSignificantPeaks++; // look for peaks other than the closest match to track // require energy of at least 1 GeV for(unsigned int i=0;i1.0){ int ii = i; if(ii != ipeak0){ nSignificantPeaks++; if(peaks[i].energy>e1){ ipeak2 = ipeak1; e2 = e1; ipeak1 = i; e1 = peaks[i].energy; }else if(peaks[i].energy>e2){ ipeak2 = i; e2 = peaks[i].energy; } } } } // Criteria for reclustering // first where only a single peak has been identified if(nSignificantPeaks==1 && peaks[ipeak0].dmin>2){ // ipeak1 = ipeak0; // ipeak0 = -999; if(peaks[ipeak0].showerStartDepth<15&&peaks[ipeak0].energy>1.0){ if(_recoDisplay!=NULL){ //_recoDisplay->DrawTransverseProfile(parentCluster,30); } float epeak = peaks[ipeak1].energy*_ecalHadMIPToGeV/_ecalEMMIPToGeV; float xdeltaE = (clusterE-epeak-trackE); float xchi = xdeltaE/sigE; if(_printing>1)std::cout << " ODD ONE : peak but no pointing track peak" << ipeak1 << " chi " << chi << " -> " << xchi << std::endl; if(fabs(xchi)1){ //recluster[0] = true; interesting = true; } } } if(nSignificantPeaks>0 && peaks[ipeak0].dmin<=2){ // more than one peak - to which the track points if(peaks[ipeak0].showerStartDepth<20){ float epeak = peaks[ipeak0].energy*_ecalHadMIPToGeV/_ecalEMMIPToGeV; float xdeltaE = (clusterE-epeak-trackE); float xchi = xdeltaE/sigE; if(fabs(xchi)-2.0){ parentCluster->PhotonProfileID(true); float showerStart = parentCluster->GetLongProfileShowerStart(); float gammaFraction = parentCluster->GetLongProfileGammaFraction(); float mipf10 = parentCluster->MipFraction( peaks[ipeak0].showerDepth90,peaks[ipeak0].showerDepth90+10); float mipf20 = parentCluster->MipFraction( peaks[ipeak0].showerDepth90+10,peaks[ipeak0].showerDepth90+20); if(_printing>1){ std::cout << " chi " << chi << " -> " << xchi << std::endl; std::cout << " Gamma Frac : " << gammaFraction << " " << showerStart << std::endl; std::cout << "MIPF : " << mipf10 << " " << mipf20 << std::endl; } if(gammaFraction<0.5&&showerStart<2.5)recluster[0] = true; } if(chi>2.0)interesting = true; if(chi>2.0 && fabs(xchi)1 && ipeak0 >=0){ interesting = true; //bool prefer1=true; float epeak = peaks[ipeak1].energy*_ecalHadMIPToGeV/_ecalEMMIPToGeV; float xdeltaE1 = (clusterE-epeak-trackE); float xchi1 = xdeltaE1/sigE; float xchi2=-999.; float xchi12=-999.; if(peaks[ipeak1].showerStartDepth<15){ if(xchi1>-2.0)recluster[1] = true; if(chi>2.0 && fabs(xchi1)0 && peaks[ipeak2].showerStartDepth<15){ float xdeltaE2 = (clusterE-peaks[ipeak2].energy-trackE); xchi2 = xdeltaE2/sigE; float xdeltaE12 = (clusterE-peaks[ipeak1].energy-peaks[ipeak2].energy-trackE); xchi12 = xdeltaE12/sigE; if(recluster[1]){ if(xchi12>-2.0){ recluster[1] = true; recluster[2] = true; }else if(fabs(xchi2)-2.0){ recluster[1] = false; recluster[2] = true; } } } } } if(interesting){ if(_printing>1){ std::cout << " Checking for photon : " << clusterE << " <-> " << trackE << " chi = " << chi << std::endl; float mipf10 = parentCluster->MipFraction( peaks[ipeak0].showerDepth90,peaks[ipeak0].showerDepth90+10); float mipf20 = parentCluster->MipFraction( peaks[ipeak0].showerDepth90+10,peaks[ipeak0].showerDepth90+20); std::cout << " MIPF : " << mipf10 << " " << mipf20 << std::endl; //if(_recoDisplay!=NULL){ // _recoDisplay->DrawTransverseProfile(parentCluster,30); //} if(ipeak0>=0)std::cout << " PEAK 0 : " << ipeak0 << " : " << peaks[ipeak0].du << "," << peaks[ipeak0].dv << " E = " << peaks[ipeak0].energy << " dmin : " << peaks[ipeak0].dmin << " d25/d90 : " << peaks[ipeak0].showerDepth25 << "/" << peaks[ipeak0].showerDepth90 << " start : " << peaks[ipeak0].showerStartDepth << std::endl; if(ipeak1>=0)std::cout << " PEAK 1 : " << ipeak1 << " : " << peaks[ipeak1].du << "," << peaks[ipeak1].dv << " E = " << peaks[ipeak1].energy << " dmin : " << peaks[ipeak1].dmin << " d90 : " << peaks[ipeak1].showerDepth90 << " start : " << peaks[ipeak1].showerStartDepth << std::endl; if(ipeak2>=0)std::cout << " PEAK 2 : " << ipeak2 << " : " << peaks[ipeak2].du << "," << peaks[ipeak2].dv << " E = " << peaks[ipeak2].energy << " dmin : " << peaks[ipeak2].dmin << " d90 : " << peaks[ipeak2].showerDepth90 << " start : " << peaks[ipeak2].showerStartDepth << std::endl; if(recluster[0])std::cout << " WILL RECLUSTER 0 " << std::endl; if(recluster[1])std::cout << " WILL RECLUSTER 1 " << std::endl; if(recluster[2])std::cout << " WILL RECLUSTER 2 " << std::endl; //if(_recoDisplay!=NULL){ //_recoDisplay->DrawTransverseProfile(parentCluster,30); //} //if(recluster[0]||recluster[1]||recluster[2]){ //if(_recoDisplay!=NULL)_recoDisplay->DrawSingleProtoCluster(parentCluster,RECO_VIEW_XY); //} } ProtoCluster* photonCand[3]={NULL,NULL,NULL}; if(recluster[0]){ // Recluster a candidate photon overlapping with track // get default design protoClusterDesign_t design = (ProtoClusterFactory::Instance())->GetDesign(); // set endlayer to 90 % containment region + 5; int endLayer = peaks[ipeak0].showerDepth90+5; // get the clusters corresponding to the peak in this region photonCand[0] = parentCluster->TransverseProfile(ipeak0,30,endLayer-30); if(photonCand[0]==NULL){ if(_printing>1)std::cout << " NO New cluster returned !!!! " << std::endl; } if(photonCand[0]!=NULL){ // clone and delete it - i.e. give factory control over memory management photonCand[0]=(ProtoClusterFactory::Instance())->CloneAndDelete(photonCand[0]); // create empty track vector and recluster without track ProtoClusterVec newFinalClusters; MyTrackExtendedVec nullTracks; photonCand[0]->ClassifyYourself(); if(!photonCand[0]->IsPrimaryPhoton()){ if(_printing>1)std::cout << " New cluster doesn't look like a photon - carry on regardless " << std::endl; } float xdeltaE1 = (clusterE-photonCand[0]->EnergyHAD()-trackE); float xchi1 = xdeltaE1/sigE; if(_printing>1)std::cout << " New chi : " << xchi1 << std::endl; if(photonCand[0]->EnergyEM()<1.5*peaks[ipeak0].energy && xchi1 > -2.5){ this->Recluster(photonCand[0],nullTracks,design,newFinalClusters); //if(_recoDisplay!=NULL){ //_recoDisplay->DrawLongitudinalProfile(photonCand[0]); //} photonCand[0]->PhotonProfileID(); float showerStart = photonCand[0]->GetLongProfileShowerStart(); float gammaFraction = photonCand[0]->GetLongProfileGammaFraction(); if(_printing>1)std::cout << " NEW PHOTON 0 SHOWER START : " << showerStart << std::endl; if(_printing>1)std::cout << " NEW PHOTON 0 GAMMA FRACT : " << gammaFraction << std::endl; if(showerStart<5.0 &&gammaFraction<0.75 ){ for(unsigned int i=0;iSetTemporaryReclusteringFlag(false); } ePhotons+= photonCand[0]->EnergyEM(); // remove hits from original cluster // - except those lying on the track which // are added back in with zero energy vectorhitsForRemoval; for(int ilayer=1;ilayer<=endLayer;++ilayer){ int nhits = parentCluster->hitsInLayer(ilayer); float smallestDistance = 999.; MyCaloHitExtended* bestHit =NULL; for(int ihit=0;ihithitInLayer(ilayer,ihit); float distance = 1000.; float genericDistance = parentCluster->genericDistanceToTrackSeed(hiti,distance); if(genericDistanceclone(); _allCalHitsByPseudoLayer[bestHit->getPseudoLayer()].push_back(calohit); float emip = _hcalEMMIPToGeV; if(bestHit->getCalorimeterHitType()==CALHITTYPE_ECAL)emip = _ecalEMMIPToGeV; calohit->setEnergyEM(emip); calohit->setEnergyHAD(emip); calohit->setEnergyInMips(1.); parentCluster->AddHit(calohit); //parentCluster->AddHit(bestHit,0.01); } } for(unsigned int ihit = 0;ihitRemoveHit(hitsForRemoval[ihit]); } // Update the properties of the parent parentCluster->Update(MAX_NUMBER_OF_LAYERS); parentCluster->ClassifyYourself(); }else{ if(_printing>1)std::cout << " Vetoed photon cluster : LONG PROF" << std::endl; } }else{ if(_printing>1)std::cout << " Vetoed photon cluster : ENERGY" << photonCand[0]->EnergyEM() << std::endl; } }else{ streamlog_out(ERROR) << " ERROR - null pointer returned in PhotonRecovery " << std::endl; } } // // Recluster isolated peaks // // remove hits from original cluster // - except those lying on the track which // are added back in with zero energy vectorhitsForRemoval; vectortrackHitsToAddBack; int thePeak=ipeak1; for(int ipeak=1;ipeak<3;ipeak++){ if(recluster[ipeak]){ if(ipeak==1)thePeak=ipeak1; if(ipeak==2)thePeak=ipeak2; photonCand[ipeak] = parentCluster->TransverseProfile(thePeak,30,10); if(photonCand[ipeak]!=NULL){ // this cluster was made by a cluster and not the factor so // clone it and delete original - factory can now deal with memory management photonCand[ipeak]=(ProtoClusterFactory::Instance())->CloneAndDelete(photonCand[ipeak]); // check this makes sense... float xdeltaE = (clusterE-photonCand[ipeak]->EnergyHAD()-trackE); float xchi = xdeltaE/sigE; if(_printing>1)std::cout << trackE << "<->" << clusterE-photonCand[ipeak]->EnergyHAD() << "->" << xchi << std::endl; //if(_recoDisplay!=NULL){ //_recoDisplay->DrawLongitudinalProfile(photonCand[ipeak]); //} photonCand[ipeak]->PhotonProfileID(); float showerStart = photonCand[ipeak]->GetLongProfileShowerStart(); float gammaFraction = photonCand[ipeak]->GetLongProfileGammaFraction(); if(_printing>1)std::cout << " NEW PHOTON i SHOWER START : " << showerStart << std::endl; if(_printing>1)std::cout << " NEW PHOTON i GAMMA FRACT : " << gammaFraction << std::endl; if( (xchi>-2.5) && showerStart<5.0 && gammaFraction < 0.75){ protoClusters.push_back(photonCand[ipeak]); if(_printing>0)std::cout << " New Cluster E : " << photonCand[ipeak]->EnergyEM() << std::endl; ePhotons+= photonCand[ipeak]->EnergyEM(); for(int ilayer=1;ilayer<=30+10;++ilayer){ int nhits = parentCluster->hitsInLayer(ilayer); float smallestDistance = 999.; MyCaloHitExtended* bestHit =NULL; for(int ihit=0;ihithitInLayer(ilayer,ihit); float distance = 1000.; float genericDistance = parentCluster->genericDistanceToTrackSeed(hiti,distance); if(genericDistance1.0)bestHit=NULL; // bestHit is hit in parentCluster on track trajectory // now loop over new cluster int mhits = photonCand[ipeak]->hitsInLayer(ilayer); for(int ihit=0;ihithitInLayer(ilayer,ihit); hitsForRemoval.push_back(hiti); if(hiti==bestHit){ MyCaloHitExtended *calohit= bestHit->clone(); _allCalHitsByPseudoLayer[bestHit->getPseudoLayer()].push_back(calohit); float emip = _hcalEMMIPToGeV; if(bestHit->getCalorimeterHitType()==CALHITTYPE_ECAL)emip = _ecalEMMIPToGeV; calohit->setEnergyEM(emip); calohit->setEnergyHAD(emip); calohit->setEnergyInMips(1.); parentCluster->AddHit(calohit); } } } }else{ if(_printing>0)std::cout << " vetoed photon " << std::endl; } }else{ streamlog_out(ERROR) << " ERROR - null pointer returned in PhotonRecovery " << std::endl; } } } // clean up for(unsigned int ihit = 0;ihitRemoveHit(hitsForRemoval[ihit]); } // Update the properties of the parent parentCluster->Update(MAX_NUMBER_OF_LAYERS); parentCluster->ClassifyYourself(); if(_printing>0)std::cout << " Old Cluster E : " << parentCluster->EnergyHAD() << std::endl; if(hitsForRemoval.size()==0)recluster[1]=false; if(hitsForRemoval.size()==0)recluster[2]=false; } } } } } void PandoraPFAProcessor::ClusterRecoveryFromMips(ProtoClusterVec &protoClusters,MyTrackExtendedVec &extendedTracks, bool print = false ){ this->ClusterTrackAssociation(protoClusters,extendedTracks,false); if(_printing>1)cout << " MIP PHOTON/CLUSTER RECOVERY !!!!! " << std::endl; if(_printing>1)cout << " MIP PHOTON/CLUSTER RECOVERY !!!!! " << std::endl; unsigned int nclusters = protoClusters.size(); for(unsigned int jcluster=0;jclusterGetTrackVec(); if(tracks.size()==1){ // float ePhotons = 0.; float clusterE = parentCluster->EnergyHAD(); float trackE = tracks[0]->getEnergy(); float sigE = trackE*_hadEnergyRes/sqrt(trackE); float deltaE = (clusterE-trackE); float chi = deltaE/sigE; int layersFromEdge=999; layersFromEdge = this->LayersFromEdge(parentCluster); bool leavingCluster = this->IsClusterLeavingDetector(parentCluster); if(leavingCluster){ // exiting track - chi2 no use // dangerous as little protection against mistakes // so check first 10/20 layers in HCAL to see if cluster looks MIP like here // if it does try and extract a possible ECAL photon float hitCount10 = 0.; float mipCount10 = 0.; float hitCount20 = 0.; float mipCount20 = 0.; for(int ilayer = _nEcalLayers;ilayer<_nEcalLayers+20;ilayer++){ for(int ihit = 0;ihit< parentCluster->hitsInLayer(ilayer);ihit++){ MyCaloHitExtended* hit =parentCluster->hitInLayer(ilayer,ihit); if(ilayer<_nEcalLayers+10){ hitCount10+=1.; if(hit->isCandidateMip())mipCount10+=1.; } hitCount20+=1.; if(hit->isCandidateMip())mipCount20+=1.; } } float mipFrac10 = 0.; float mipFrac20 = 0.; if(hitCount10>0)mipFrac10 = mipCount10/hitCount10; if(hitCount20>0)mipFrac20 = mipCount20/hitCount20; std::vector peaks; parentCluster->TransverseProfile(peaks); if(_printing>1){ std::cout << " Track <-> Cluster : " << trackE << "<->" << clusterE << std::endl; for(unsigned int i=0;i0.01){ if(peaks[i].dmin=0)nSignificantPeaks++; // look for peaks other than the closest match to track // require energy of at least 1 GeV for(unsigned int i=0;i1.0){ int ii = i; if(ii != ipeak0){ nSignificantPeaks++; if(peaks[i].energy>e1){ ipeak2 = ipeak1; e2 = e1; ipeak1 = i; e1 = peaks[i].energy; }else if(peaks[i].energy>e2){ ipeak2 = i; e2 = peaks[i].energy; } } } } // Criteria for reclustering // first where only a single peak has been identified if(nSignificantPeaks==1 && (mipFrac10>0.8 || mipFrac20 >0.8)){ if(peaks[ipeak0].dmin>5){ // IGNORE !!! }else{ // only one peak - to which the track points if(peaks[ipeak0].showerStartDepth<15){ //float xdeltaE = (clusterE-peaks[ipeak0].energy-trackE); // float xchi = xdeltaE/sigE; parentCluster->PhotonProfileID(true); // look for a EM shower profile at start of track float showerStart = parentCluster->GetLongProfileShowerStart(); float gammaFraction = parentCluster->GetLongProfileGammaFraction(); if(_printing>1)std::cout << " SS/ Gamma Frac : " << showerStart << " " << gammaFraction << std::endl; if(gammaFraction<0.5&&showerStart<2.5)recluster[0] = true; if(gammaFraction<0.3&&showerStart<6.0)recluster[0] = true; interesting = true; //if(_recoDisplay!=NULL)_recoDisplay->DrawLongitudinalProfile(parentCluster,true); } } } // Mulitiple peaks including one peak matched to the track if(nSignificantPeaks>1000000 && ipeak0 >=0){ interesting = true; //bool prefer1=true; float xdeltaE1 = (clusterE-peaks[ipeak1].energy-trackE); float xchi1 = xdeltaE1/sigE; float xchi2=-999.; float xchi12=-999.; if(peaks[ipeak1].showerStartDepth<15){ if(xchi1>-2.0)recluster[1] = true; if(chi>2.0 && fabs(xchi1)0 && peaks[ipeak2].showerStartDepth<15){ if(leavingCluster)recluster[2]= true; float xdeltaE2 = (clusterE-peaks[ipeak2].energy-trackE); xchi2 = xdeltaE2/sigE; float xdeltaE12 = (clusterE-peaks[ipeak1].energy-peaks[ipeak2].energy-trackE); xchi12 = xdeltaE12/sigE; if(recluster[1]){ if(xchi12>-2.0){ recluster[1] = true; recluster[2] = true; }else if(fabs(xchi2)-2.0){ recluster[1] = false; recluster[2] = true; } } } } } if(interesting){ if(_printing>1){ if(recluster[0])std::cout << " WILL RECLUSTER 0 " << std::endl; if(recluster[1])std::cout << " WILL RECLUSTER 1 " << std::endl; if(recluster[2])std::cout << " WILL RECLUSTER 2 " << std::endl; } ProtoCluster* photonCand[3]={NULL,NULL,NULL}; if(recluster[0]){ // Recluster a candidate photon overlapping with track // get default design protoClusterDesign_t design = (ProtoClusterFactory::Instance())->GetDesign(); // set endlayer to 90 % containment region + 5; int endLayer = peaks[ipeak0].showerDepth90+5; // get the clusters corresponding to the peak in this region photonCand[0] = parentCluster->TransverseProfile(ipeak0,30,endLayer-30); if(photonCand[0]==NULL){ if(_printing>1)std::cout << " NO New cluster returned !!!! " << std::endl; } if(photonCand[0]!=NULL){ // clone and delete it - i.e. give factory control over memory management photonCand[0]=(ProtoClusterFactory::Instance())->CloneAndDelete(photonCand[0]); // create empty track vector and recluster without track ProtoClusterVec newFinalClusters; MyTrackExtendedVec nullTracks; photonCand[0]->ClassifyYourself(); if(!photonCand[0]->IsPrimaryPhoton()){ if(_printing>1)std::cout << " New cluster doesn't look like a photon - carry on regardless " << std::endl; } this->Recluster(photonCand[0],nullTracks,design,newFinalClusters); photonCand[0]->PhotonProfileID(); float showerStart = photonCand[0]->GetLongProfileShowerStart(); float gammaFraction = photonCand[0]->GetLongProfileGammaFraction(); if(_printing>1)std::cout << " NEW PHOTON 0 SHOWER START : " << showerStart << std::endl; if(_printing>1)std::cout << " NEW PHOTON 0 GAMMA FRACT : " << gammaFraction << std::endl; vectorhitsForRemoval; for(unsigned int i=0;iSetTemporaryReclusteringFlag(false); } ePhotons+= photonCand[0]->EnergyEM(); // remove hits from original cluster // - except those lying on the track which // are added back in with zero energy for(int ilayer=1;ilayer<=endLayer;++ilayer){ int nhits = parentCluster->hitsInLayer(ilayer); float smallestDistance = 999.; MyCaloHitExtended* bestHit =NULL; for(int ihit=0;ihithitInLayer(ilayer,ihit); float distance = 1000.; float genericDistance = parentCluster->genericDistanceToTrackSeed(hiti,distance); if(genericDistanceclone(); _allCalHitsByPseudoLayer[bestHit->getPseudoLayer()].push_back(calohit); float emip = _hcalEMMIPToGeV; if(bestHit->getCalorimeterHitType()==CALHITTYPE_ECAL)emip = _ecalEMMIPToGeV; calohit->setEnergyEM(emip); calohit->setEnergyHAD(emip); calohit->setEnergyInMips(1.); parentCluster->AddHit(calohit); //parentCluster->AddHit(bestHit,0.01); } } for(unsigned int ihit = 0;ihitRemoveHit(hitsForRemoval[ihit]); } // Update the properties of the parent parentCluster->Update(MAX_NUMBER_OF_LAYERS); parentCluster->ClassifyYourself(); }else{ if(_printing>1)std::cout << " Vetoed photon cluster : LONG PROF" << std::endl; } } if(1==2){ // // Recluster isolated peaks // // remove hits from original cluster // - except those lying on the track which // are added back in with zero energy vectorhitsForRemoval; vectortrackHitsToAddBack; int thePeak=ipeak1; for(int ipeak=1;ipeak<3;ipeak++){ if(recluster[ipeak]){ if(ipeak==1)thePeak=ipeak1; if(ipeak==2)thePeak=ipeak2; photonCand[ipeak] = parentCluster->TransverseProfile(thePeak,30,10); if(photonCand[ipeak]!=NULL){ // this cluster was made by a cluster and not the factor so // clone it and delete original - factory can now deal with memory management photonCand[ipeak]=(ProtoClusterFactory::Instance())->CloneAndDelete(photonCand[ipeak]); // check this makes sense... float xdeltaE = (clusterE-photonCand[ipeak]->EnergyHAD()-trackE); float xchi = xdeltaE/sigE; if(_printing>1)std::cout << trackE << "<->" << clusterE-photonCand[ipeak]->EnergyHAD() << "->" << xchi << std::endl; if(_recoDisplay!=NULL){ //_recoDisplay->DrawLongitudinalProfile(photonCand[ipeak]); } photonCand[ipeak]->PhotonProfileID(); float showerStart = photonCand[ipeak]->GetLongProfileShowerStart(); float gammaFraction = photonCand[ipeak]->GetLongProfileGammaFraction(); if(_printing>1)std::cout << " NEW PHOTON i SHOWER START : " << showerStart << std::endl; if(_printing>1)std::cout << " NEW PHOTON i GAMMA FRACT : " << gammaFraction << std::endl; if( (xchi>-2.5 || leavingCluster) && showerStart<5.0 && gammaFraction < 0.75){ protoClusters.push_back(photonCand[ipeak]); if(_printing>0)std::cout << " New Cluster E : " << photonCand[ipeak]->EnergyEM() << std::endl; ePhotons+= photonCand[ipeak]->EnergyEM(); for(int ilayer=1;ilayer<=30+10;++ilayer){ int nhits = parentCluster->hitsInLayer(ilayer); float smallestDistance = 999.; MyCaloHitExtended* bestHit =NULL; for(int ihit=0;ihithitInLayer(ilayer,ihit); float distance = 1000.; float genericDistance = parentCluster->genericDistanceToTrackSeed(hiti,distance); if(genericDistance1.0)bestHit=NULL; // bestHit is hit in parentCluster on track trajectory // now loop over new cluster int mhits = photonCand[ipeak]->hitsInLayer(ilayer); for(int ihit=0;ihithitInLayer(ilayer,ihit); hitsForRemoval.push_back(hiti); if(hiti==bestHit){ MyCaloHitExtended *calohit= bestHit->clone(); _allCalHitsByPseudoLayer[bestHit->getPseudoLayer()].push_back(calohit); float emip = _hcalEMMIPToGeV; if(bestHit->getCalorimeterHitType()==CALHITTYPE_ECAL)emip = _ecalEMMIPToGeV; calohit->setEnergyEM(emip); calohit->setEnergyHAD(emip); calohit->setEnergyInMips(1.); parentCluster->AddHit(calohit); } } } }else{ if(_printing>0)std::cout << " vetoed photon " << std::endl; } }else{ streamlog_out(ERROR) << " ERROR - null pointer returned in PhotonRecovery " << std::endl; } } } // clean up for(unsigned int ihit = 0;ihitRemoveHit(hitsForRemoval[ihit]); } // Update the properties of the parent parentCluster->Update(MAX_NUMBER_OF_LAYERS); parentCluster->ClassifyYourself(); if(_printing>0)std::cout << " Old Cluster E : " << parentCluster->EnergyHAD() << std::endl; if(hitsForRemoval.size()==0)recluster[1]=false; if(hitsForRemoval.size()==0)recluster[2]=false; } } } } } } void PandoraPFAProcessor::NewResolveThreeTrackAssociations(ProtoClusterVec &protoClusters,MyTrackExtendedVec &extendedTracks, bool print = false ){ // set up the cluster designs to be used for the attempted reclustering const int ndesign = 12; float scalei[ndesign] = {0.8,0.6,0.5,0.4,0.3,0.25,0.2,0.15,0.1,1.0,1.0, 1.0}; int wgti[ndesign] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 0, 3}; protoClusterDesign_t design[ndesign]; for(int i=0;iClusterTrackAssociation(protoClusters,extendedTracks,false); unsigned int nclusters = protoClusters.size(); for(unsigned int jcluster=0;jclusterGetTrackVec(); if(tracks.size()==3){ float clusterE = parentCluster->EnergyHAD(); float trackE = 0.; for(unsigned int i=0; igetEnergy(); float sigE = trackE*_hadEnergyRes/sqrt(trackE); float deltaE = (clusterE-trackE); float chi = deltaE/sigE; int layersFromEdge=999; bool leavingCluster = false; if(chi<-_chiToAttemptReclustering){ leavingCluster = this->IsClusterLeavingDetector(parentCluster); layersFromEdge = this->LayersFromEdge(parentCluster); if(_printing>1)std::cout << " Layers from edge : " << layersFromEdge << std::endl; } if(chi<-_chiToAttemptReclustering&&!leavingCluster){ if(_printing>1){ std::cout << " ************************************************ " << std::endl; std::cout << " Multiple track problem " << chi << std::endl; std::cout << " track 0 : " << tracks[0]->getEnergy() << std::endl; std::cout << " track 1 : " << tracks[1]->getEnergy() << std::endl; std::cout << " track 2 : " << tracks[2]->getEnergy() << std::endl; std::cout << " cluster : " << parentCluster->EnergyHAD() << std::endl; } ProtoClusterVec clustersToBeReclustered; clustersToBeReclustered.push_back(parentCluster); vector coneAssocPCs; vector fConeAssocPCs; for(unsigned int icluster=0;iclusterGetTrackVec(); if(icluster!=jcluster && xtracks.size()==0){ float fraction = parentCluster->FractionInRadialCone(protoClusters[icluster],0.90); float fraction0 = protoClusters[icluster]->FractionInTrackCone(tracks[0],0.90); float fraction1 = protoClusters[icluster]->FractionInTrackCone(tracks[1],0.90); float fraction2 = protoClusters[icluster]->FractionInTrackCone(tracks[2],0.90); if(fraction>0.25){ fConeAssocPCs.push_back(fraction); coneAssocPCs.push_back(protoClusters[icluster]); }else{ if(fraction0>0.25||fraction1>0.25||fraction2>0.25){ if(_printing>1){ std::cout << " Good match based on trackCone " << std::endl; std::cout << " Energy " << protoClusters[icluster]->EnergyHAD() << std::endl; } } } } } if(fConeAssocPCs.size()>0){ // sort in order of decreasing fraction unsigned int sizeOfVector = fConeAssocPCs.size(); if(sizeOfVector>1){ ProtoCluster *tempPC; float tempf; for (unsigned int i = 0 ; i < sizeOfVector-1; i++){ for (unsigned int j = 0; j < sizeOfVector-i-1; j++){ if(fConeAssocPCs[j] < fConeAssocPCs[j+1]){ tempf = fConeAssocPCs[j]; tempPC = coneAssocPCs[j]; fConeAssocPCs[j] = fConeAssocPCs[j+1]; fConeAssocPCs[j+1] = tempf; coneAssocPCs[j] = coneAssocPCs[j+1]; coneAssocPCs[j+1] = tempPC; } } } } } for(unsigned int i=0; i1)std::cout << " Ordered " << i << " Frac " << fConeAssocPCs[i] << " E : " << coneAssocPCs[i]->EnergyHAD() << std::endl; if(fConeAssocPCs[i]>0.25)clustersToBeReclustered.push_back(coneAssocPCs[i]); } ProtoClusterVec finalClusters[ndesign]; int ibest = -1; float bestchi2 = chi*chi; int ibestguess = -1; float bestguesschi = 99999.; bool done = false; for(int idesign=0;idesignReclusterMultiple(clustersToBeReclustered,tracks,design[idesign],finalClusters[idesign]); float newchi2 = result.chi2; if(newchi21.0 && newchi2<9.0){ ibest = idesign; bestchi2 = newchi2; } } // best 3 track match if(result.ntrackmatch==3&&result.chi>0&&result.chi16.0)done=true; } // Found a good match ? if(_printing>1)std::cout << " Best chi2 " << bestchi2 << " Design " << ibest << std::endl; if(_printing>1)std::cout << " Best chi2 " << bestchi2 << " Design " << ibest << std::endl; if(ibest>=0 && bestchi2<_chiToAttemptReclustering*_chiToAttemptReclustering){ if(_printing>1)std::cout << "WILL RECLUSTER !!!! " << std::endl; // recluster for(unsigned int i=0;iIsNowDefunct(); } for(unsigned int i=0;iSetTemporaryReclusteringFlag(false); } }else{ if(_printing>1)std::cout << " Best guess " << bestguesschi << " Design " << ibestguess << std::endl; if(ibestguess>=0){ // recluster for(unsigned int i=0;iIsNowDefunct(); } int ilast = protoClusters.size(); for(unsigned int i=0;iSetTemporaryReclusteringFlag(false); } // not all over yet - this cluster still has too much energy... // try and break it (NOT SURE WHERE THIS SHOULD BE DONE) clustersToBeReclustered.clear(); unsigned int lastCluster = protoClusters.size(); for(unsigned int i=ilast;iGetTrackVec(); if(tracks.size()==2){ if(_printing>1)std::cout << " THIS CLUSTER " << thisCluster->EnergyHAD() << std::endl; clustersToBeReclustered.push_back(thisCluster); float clusterE = thisCluster->EnergyHAD(); float trackE = tracks[0]->getEnergy()+tracks[1]->getEnergy(); float sigE = trackE*_hadEnergyRes/sqrt(trackE); float deltaE = (clusterE-trackE); float chi = deltaE/sigE; ProtoClusterVec finalClusters[ndesign]; int newbest = -1; float newbestchi2 = chi*chi; bool done = false; for(int idesign=0;idesign1)std::cout << " Design : " << idesign << std::endl; ReclusterResult_t result = this->ReclusterMultiple(clustersToBeReclustered,tracks,design[idesign],finalClusters[idesign]); float newchi2 = result.chi2; if(newchi21.0 && newchi2<9.0){ newbest = idesign; newbestchi2 = newchi2; } } // if found a v.good chi2 stop if(newbestchi2<1.0)done=true; // if have a good chi2 and things getting worse - stop if(newbestchi2<4.0&&newchi2>16.0)done=true; } // Found a good match ? if(_printing>1)std::cout << " Best chi2 " << newbestchi2 << " Design " << newbest << std::endl; if(newbest>=0 && newbestchi2<_chiToAttemptReclustering*_chiToAttemptReclustering){ if(_printing>1)std::cout << "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWILL RECLUSTER !!!! " << std::endl; // recluster for(unsigned int i=0;iIsNowDefunct(); } for(unsigned int i=0;iSetTemporaryReclusteringFlag(false); } }else{ if(_printing>1)std::cout << "nothing works " << std::endl; } } } }else{ int ifl = parentCluster->FirstLayer(); if(_printing>1)std::cout << "failed " << parentCluster->GetCentroid(ifl)[0] << "," << parentCluster->GetCentroid(ifl)[1]<ClusterTrackAssociation(protoClusters,extendedTracks,false); unsigned int nclusters = protoClusters.size(); for(unsigned int jcluster=0;jclusterGetTrackVec(); if(tracks.size()==1 && !parentCluster->IsDefunct() ){ float clusterE = parentCluster->EnergyHAD(); float trackE = 0.; for(unsigned int i=0; igetEnergy(); float sigE = trackE*_hadEnergyRes/sqrt(trackE); float deltaE = (clusterE-trackE); float chi = deltaE/sigE; int layersFromEdge = 999; bool leavingCluster = false; if(chi<-_chiToAttemptReclustering){ leavingCluster = this->IsClusterLeavingDetector(parentCluster); layersFromEdge = this->LayersFromEdge(parentCluster); if(_printing>1)std::cout << " Layers from edge : " << layersFromEdge << std::endl; } if(chi<-_chiToAttemptReclustering&&!leavingCluster){ if(_printing>1){ std::cout << " ************************************************ " << std::endl; std::cout << " Single track problem " << chi << std::endl; std::cout << " track 0 : " << tracks[0]->getEnergy() << std::endl; std::cout << " cluster : " << parentCluster->EnergyHAD() << std::endl; } ProtoClusterVec clustersToBeReclustered; clustersToBeReclustered.push_back(parentCluster); vector coneAssocPCs; vector fConeAssocPCs; for(unsigned int icluster=0;iclusterGetTrackVec(); if(icluster!=jcluster && xtracks.size()==0){ float fraction = parentCluster->FractionInRadialCone(protoClusters[icluster],0.90); float fraction0 = protoClusters[icluster]->FractionInTrackCone(tracks[0],0.90); if(fraction>0.25){ fConeAssocPCs.push_back(fraction); coneAssocPCs.push_back(protoClusters[icluster]); }else{ if(fraction0>0.25){ if(_printing>1){ std::cout << " Good match based on trackCone " << std::endl; std::cout << " Energy " << protoClusters[icluster]->EnergyHAD() << std::endl; } } } } } if(fConeAssocPCs.size()>0){ // sort in order of decreasing fraction unsigned int sizeOfVector = fConeAssocPCs.size(); if(sizeOfVector>1){ ProtoCluster *tempPC; float tempf; for (unsigned int i = 0 ; i < sizeOfVector-1; i++){ for (unsigned int j = 0; j < sizeOfVector-i-1; j++){ if(fConeAssocPCs[j] < fConeAssocPCs[j+1]){ tempf = fConeAssocPCs[j]; tempPC = coneAssocPCs[j]; fConeAssocPCs[j] = fConeAssocPCs[j+1]; fConeAssocPCs[j+1] = tempf; coneAssocPCs[j] = coneAssocPCs[j+1]; coneAssocPCs[j+1] = tempPC; } } } } } for(unsigned int i=0; i1)std::cout << " Ordered " << i << " Frac " << fConeAssocPCs[i] << " E : " << coneAssocPCs[i]->EnergyHAD() << std::endl; if(fConeAssocPCs[i]>0.25)clustersToBeReclustered.push_back(coneAssocPCs[i]); } ProtoClusterVec finalClusters[ndesign]; int ibest = -1; float bestchi2 = chi*chi; int ibestguess = -1; float bestguesschi = 99999.; bool done = false; for(int idesign=0;idesign1)std::cout << " Design : " << idesign << std::endl; ReclusterResult_t result = this->ReclusterMultiple(clustersToBeReclustered,tracks,design[idesign],finalClusters[idesign]); float newchi2 = result.chi2; if(newchi21.0 && newchi2<_chiToAttemptReclustering*_chiToAttemptReclustering){ ibest = idesign; bestchi2 = newchi2; } } if(result.chi>0&&result.chi16.0)done=true; } // Found a good match ? if(_printing>1)std::cout << " Best chi2 " << bestchi2 << " Design " << ibest << std::endl; if(ibest>=0 && bestchi2<_chiToAttemptReclustering*_chiToAttemptReclustering){ if(_printing>1)std::cout << "XWILL RECLUSTER !!!! " << std::endl; // recluster for(unsigned int i=0;iIsNowDefunct(); } for(unsigned int i=0;iSetTemporaryReclusteringFlag(false); } }else{ if(_printing>1)std::cout << " BEST GUESS DESIGN : " << ibestguess<< std::endl; if(ibestguess>=0){ // not all over yet - this cluster still has too much energy... // try and break it (NOT SURE WHERE THIS SHOULD BE DONE) ProtoClusterVec bestGuessClustersToBeReclustered; for(unsigned int i=0;iGetTrackVec(); if(tracks.size()!=0){ if(_printing>1)std::cout << " THIS CLUSTER " << thisCluster->EnergyHAD() << std::endl; bestGuessClustersToBeReclustered.push_back(thisCluster); float clusterE = thisCluster->EnergyHAD(); float trackE = tracks[0]->getEnergy(); float sigE = trackE*_hadEnergyRes/sqrt(trackE); float deltaE = (clusterE-trackE); float chi = deltaE/sigE; ProtoClusterVec guessFinalClusters[ndesign]; int newbest = -1; float newbestchi2 = chi*chi; bool done = false; for(int idesign=0;idesign1)std::cout << " Design : " << idesign << std::endl; ReclusterResult_t result = this->ReclusterMultiple(bestGuessClustersToBeReclustered,tracks,design[idesign],guessFinalClusters[idesign]); float newchi2 = result.chi2; if(newchi21.0 && newchi2<_chiToAttemptReclustering*_chiToAttemptReclustering){ newbest = idesign; newbestchi2 = newchi2; } } // if found a v.good chi2 stop if(newbestchi2<1.0)done=true; // if have a good chi2 and things getting worse - stop if(newbestchi2<4.0&&newchi2>16.0)done=true; } // Found a good match ? if(_printing>1)std::cout << " Best chi2 " << newbestchi2 << " Design " << newbest << std::endl; if(newbest>=0 && newbestchi2<_chiToAttemptReclustering*_chiToAttemptReclustering){ if(_printing>1)std::cout << "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWILL RECLUSTER !!!! " << std::endl; // recluster for(unsigned int i=0;iIsNowDefunct(); } for(unsigned int i=0;iGetTrackVec(); if(tracks.size()==0){ protoClusters.push_back(thisCluster); thisCluster->SetTemporaryReclusteringFlag(false); } } for(unsigned int i=0;iSetTemporaryReclusteringFlag(false); } }else{ if(_printing>1)std::cout << "xxxxx nothing works " << std::endl; } } } }else{ int ifl = parentCluster->FirstLayer(); if(_printing>1)std::cout << "failed " << parentCluster->GetCentroid(ifl)[0] << "," << parentCluster->GetCentroid(ifl)[1]<ClusterTrackAssociation(protoClusters,extendedTracks,false); unsigned int nclusters = protoClusters.size(); for(unsigned int jcluster=0;jclusterGetTrackVec(); if(!parentCluster->IsDefunct() ){ float clusterE = parentCluster->EnergyHAD(); float trackE = 0.; for(unsigned int i=0; igetEnergy(); float sigE = trackE*_hadEnergyRes/sqrt(trackE); float deltaE = (clusterE-trackE); float chi = deltaE/sigE; int layersFromEdge = 999; bool leavingCluster = false; if(chi<-_chiToAttemptReclustering){ leavingCluster = this->IsClusterLeavingDetector(parentCluster); layersFromEdge = this->LayersFromEdge(parentCluster); if(_printing>1)std::cout << " Layers from edge : " << layersFromEdge << std::endl; } // check to see if cluster still has a bad track match if(chi<-_chiToAttemptReclustering && !leavingCluster){ if(_printing>1){ std::cout << " ************************************************ " << std::endl; std::cout << " STILL HAVE A track problem " << chi << std::endl; for(unsigned int it=0;itgetEnergy() << std::endl; } std::cout << " cluster : " << parentCluster->EnergyHAD() << std::endl; } // add the cluster to the list of cluster for reclustering ProtoClusterVec clustersToBeReclustered; clustersToBeReclustered.push_back(parentCluster); // look for clusters with an excess of energy compared to the track in the nearby region vector coneAssocPCs; vector fConeAssocPCs; float excess = 0.; for(unsigned int icluster=0;iclusterGetTrackVec(); float xclusterE = protoClusters[icluster]->EnergyHAD(); float xtrackE = 0.; for(unsigned int i=0; igetEnergy(); if(icluster!=jcluster){ float bestfrac = parentCluster->FractionInRadialCone(protoClusters[icluster],0.90); for(unsigned int it =0;itFractionInTrackCone(tracks[it],0.90); if(fraction>bestfrac)bestfrac=fraction; } if(bestfrac>0.2){ if(xtracks.size()==0){ fConeAssocPCs.push_back(bestfrac); coneAssocPCs.push_back(protoClusters[icluster]); }else{ excess += xclusterE - xtrackE; } }else{ clusterContact_t contact = parentCluster->ContactLayers(protoClusters[icluster],2.5); if(contact.contactLayers>4){ if(_printing>1)std::cout << " Contact : " << contact.contactLayers << " Energy " << protoClusters[icluster]->EnergyHAD() << std::endl; if(xtracks.size()==0){ fConeAssocPCs.push_back(0.5); coneAssocPCs.push_back(protoClusters[icluster]); }else{ excess += xclusterE - xtrackE; } } } } } if(fConeAssocPCs.size()>0){ // sort in order of decreasing fraction unsigned int sizeOfVector = fConeAssocPCs.size(); if(sizeOfVector>1){ ProtoCluster *tempPC; float tempf; for (unsigned int i = 0 ; i < sizeOfVector-1; i++){ for (unsigned int j = 0; j < sizeOfVector-i-1; j++){ if(fConeAssocPCs[j] < fConeAssocPCs[j+1]){ tempf = fConeAssocPCs[j]; tempPC = coneAssocPCs[j]; fConeAssocPCs[j] = fConeAssocPCs[j+1]; fConeAssocPCs[j+1] = tempf; coneAssocPCs[j] = coneAssocPCs[j+1]; coneAssocPCs[j+1] = tempPC; } } } } } if(_printing>1)std::cout << " Excess : " << excess << std::endl; // Add nearby clusters to the list of possible clusters for reclustering for(unsigned int i=0; i1)std::cout << " Ordered " << i << " Frac " << fConeAssocPCs[i] << " E : " << coneAssocPCs[i]->EnergyHAD() << std::endl; if(fConeAssocPCs[i]>0.20)clustersToBeReclustered.push_back(coneAssocPCs[i]); } // Try to recluster ProtoClusterVec finalClusters[ndesign]; int ibest = -1; float bestchi2 = 99999.; int ibestguess = -1; float bestguesschi = 99999.; bool done = false; for(int idesign=0;idesign1)std::cout << " Design : " << idesign << std::endl; ReclusterResult_t result = this->ReclusterMultiple(clustersToBeReclustered,tracks,design[idesign],finalClusters[idesign]); float newchi2 = result.chi2; if(newchi21.0){ ibest = idesign; bestchi2 = newchi2; } } if(result.chi>0&&result.chi16.0)done=true; } // Found a good match ? if(_printing>1)std::cout << " Best chi2 " << bestchi2 << " Design " << ibest << std::endl; bool goodresult = false; if(ibest>=0 && bestchi2<_chiToAttemptReclustering*_chiToAttemptReclustering)goodresult =true; if(ibest>=0 && excess > 0.1 && bestchi2>_chiToAttemptReclustering*_chiToAttemptReclustering){ // on the face of it have a bad match // but some energy could be clustered into adjacent track cluster float eclust =0; for(unsigned int i = 0;iAssociatedTrack())eclust+= finalClusters[ibest][i]->EnergyHAD(); } if(_printing>1){ std::cout << " ECLUST : " << eclust << std::endl; std::cout << " ETRACK : " << trackE << std::endl; std::cout << " EXCESS : " << excess << std::endl; } float alpha = (trackE-eclust)/excess; if(alpha<0.)alpha = 0.; if(alpha>1.)alpha = 1.; float newdeltaE = (eclust+alpha*excess-trackE); float chiWithExcess = newdeltaE/sigE; if(_printing>1)std::cout << " NEW CHI : " << chiWithExcess << std::endl; if(fabs(chiWithExcess)1)std::cout << "XWILL RECLUSTER !!!! " << std::endl; // mark previous clusters as defunct for(unsigned int i=0;iIsNowDefunct(); } // add new clustering to the output for(unsigned int i=0;iSetTemporaryReclusteringFlag(false); } } // What to do if there is no good solution ? if(!goodresult){ if(_printing>1)std::cout << " GIVE UP FOR NOW " << std::endl; } } } } return; } void PandoraPFAProcessor::MakeProtoClusters(MyTrackExtendedVec &tracks, ProtoClusterVec &pClusters){ // Loop over layers in CAL, staring from inner layer // for hit - check if associated with Protocluster hits in previous layer // - then check step back through LAYERSTOSTEPBACKXCAL layers // - then iterate over hits making associations in current layer // - any remaining hit seed new protoclusters // if requested seed protoclusters with tracks if(_printing>3)std::cout << " PandoraPFAProcessor:MakeProtoClusters : SeedWithTracks" << std::endl; if(_seedClustersWithTracks>=1)this->SeedProtoClustersWithTracks(tracks,pClusters); if(_printing>3)std::cout << " PandoraPFAProcessor:MakeProtoClusters : Main Clustering Algorithm" << std::endl; // for strong track-based reclustering if(_trackingWeight==4)this->TrackAsMIPs(tracks,pClusters); // step over pseudo-layers working from front to back of the Calorimeters for(unsigned int ilayer=0;ilayer<=_maxLayer;++ilayer){ if(_printing>5)std::cout << " Ilayer : " << _calHitsByPseudoLayer[ilayer].size() << std::endl; // loop over hits in layer and try and associate with existing clusters for(unsigned int ihit=0;ihit<_calHitsByPseudoLayer[ilayer].size();++ihit){ MyCaloHitExtended* hiti = _calHitsByPseudoLayer[ilayer][ihit]; vectorclustersWantingHit; // allow possible asoscitation to clustered hits in stepBack layers unsigned int stepBack = _layersToStepBackECAL; if(hiti->getCalorimeterHitType()==CALHITTYPE_HCAL)stepBack=_layersToStepBackHCAL; bool associated = false; float smallestGenericDistance = 9999.; ProtoCluster* bestCluster=NULL; for(unsigned int iback=1; iback<=stepBack&&!associated && iback<=ilayer; ++iback){ unsigned int searchLayer = ilayer - iback; vectorclustersWantingHit; // loop over clusters looking for associations for(unsigned int icluster=0;iclustergenericDistanceToHit(hiti, searchLayer); // generic distance is a measure of goodness of association // anything less than 1.0 indicates a possible association // the details of how this distance could depend on type of cluster if(genericDistance<1.0){ clustersWantingHit.push_back(pClusters[icluster]); if(genericDistance0){ ProtoCluster* favouredCluster=this->Arbitrate(hiti,clustersWantingHit,searchLayer); favouredCluster->AddHit(hiti); // mark hit for removal from unassociated hits _hitsForRemoval.push_back(hiti); associated = true; } } } if(_clusterFormationStrategy==1 && bestCluster!=NULL){ // check all layers first and and use best cluster bestCluster->AddHit(hiti); // mark hit for removal from unassociated hits _hitsForRemoval.push_back(hiti); } } // remove newly associated hits in layer ilayer from _calHitsByPseudoLayer this->removeAssociatedHits(); // tried to associate hits with previous layers, now check // for associations in current layer while(_calHitsByPseudoLayer[ilayer].size()>0){ bool found = true; while(found){ found = false; for(unsigned int ihit=0;ihit<_calHitsByPseudoLayer[ilayer].size();++ihit){ MyCaloHitExtended* hiti = _calHitsByPseudoLayer[ilayer][ihit]; vectorclustersWantingHit; for(unsigned int icluster=0;iclustergenericDistanceToHit(hiti,ilayer); if(genericDistance<1.0)clustersWantingHit.push_back(pClusters[icluster]); } // if at least one cluster wants hit - Arbitrate(,,) decides the best if(clustersWantingHit.size()>0){ found = true; ProtoCluster* favouredCluster=this->Arbitrate(hiti,clustersWantingHit,ilayer); favouredCluster->AddHit(hiti); _hitsForRemoval.push_back(hiti); } } this->removeAssociatedHits(); } // BY NOW remaining hits in _calHitsByPseudoLayer[ilayer] have not been associated // The first hit is used to seed a new cluster (first can mean highest energy/density) // Having done this loop over other hits to see if they are associated to the // new cluster - repeat... if(_calHitsByPseudoLayer[ilayer].size()>0){ MyCaloHitExtended* hiti = _calHitsByPseudoLayer[ilayer][0]; ProtoCluster* newCluster = (ProtoClusterFactory::Instance())->Manufacture(hiti); pClusters.push_back(newCluster); _hitsForRemoval.push_back(hiti); this->removeAssociatedHits(); } } // Make sure cluster properties are up to date : this isn't done when new hits are // added as this would be excessively time consuming for(unsigned int icluster=0;iclusterUpdate(ilayer); if(_recoDisplay!=NULL && _showProtoClusterFormation>0)_recoDisplay->DrawByProtoCluster(pClusters); } // calculate more cluster properties and classify cluster for(unsigned int i=0;iClassifyYourself(); if(_printing>3)std::cout << " PandoraPFAProcessor:MakeProtoClusters : Done" << std::endl; return; } void PandoraPFAProcessor::MakePerfectMuonProtoClusters(MyTrackExtendedVec &tracks){ if(_muonNavigator==NULL){ streamlog_out(ERROR) << " Can't perform PerfectMuonClustering" << std::endl; if(_muonNavigator==NULL)streamlog_out(ERROR) << " : no muon hit navigator" << std::endl; return; } std::vector mcPFOs = *(_myMcTree->getMCPFOs()); ProtoCluster* protoClusters[mcPFOs.size()]; for(unsigned int i =0;i(hiti->getCalorimeterHit()); LCObjectVec objectVec = _muonNavigator->getRelatedToObjects(calhit); int ibestmc = 0; if (objectVec.size() > 0) { SimCalorimeterHit * simhit = dynamic_cast(objectVec[0]); float emax = -1.; float ehittot = 0; if (simhit->getNMCContributions() > 0){ // find largest contributor to hit for(int i=0;igetNMCContributions();i++){ ehittot+= simhit->getEnergyCont(i); if(simhit->getEnergyCont(i)>emax){ emax = simhit->getEnergyCont(i); ibestmc = i; } } // choose mc particle contributing most to hit int iuse = ibestmc; MCParticle * part = simhit->getParticleCont(iuse); // use myMcTree to match hit to perfect particle flow object unsigned int jmc = _myMcTree->GetMCPFOIndex(part); if(jmcManufacture(hiti); }else{ protoClusters[jmc]->AddHit(hiti); } } } } } } for(unsigned int i =0;i3)std::cout << " PandoraPFAProcessor:MuonMakeProtoClusters : SeedWithTracks" << std::endl; if(_printing>3)std::cout << " PandoraPFAProcessor:MakeProtoClusters : Main Clustering Algorithm" << std::endl; // load muon hits into _calHitsByPseudoLayer[ilayer][ihit] std::cout << " Max layer " << _maxLayer << " " << _maxMuonLayer << std::endl; unsigned int savedMaxLayer = _maxLayer; if(_maxMuonLayer>_maxLayer)_maxLayer = _maxMuonLayer; for(unsigned int ilayer=0;ilayer<=_maxLayer;++ilayer){ _calHitsByPseudoLayer[ilayer].clear(); // loop over hits in layer and try and associate with existing clusters for(unsigned int ihit=0;ihit<_muonHitsByLayer[ilayer].size();++ihit){ MyCaloHitExtended* hiti = _muonHitsByLayer[ilayer][ihit]; _calHitsByPseudoLayer[ilayer].push_back(hiti); } } MyTrackExtendedVec nullTracks; protoClusterDesign_t design; design.tanConeAngleECAL = _clusterFormationConeTanECAL; design.tanConeAngleHCAL = _clusterFormationConeTanHCAL*1.5; design.additionalPadsECAL = _clusterFormationPadsECAL; design.additionalPadsHCAL = _clusterFormationPadsHCAL*5; design.sameLayerPadCutECAL = _sameLayerPadCutECAL; design.sameLayerPadCutHCAL = _sameLayerPadCutHCAL*25; design.maximumDistanceForConeAssociationECAL=_maximumDistanceForConeAssociationECAL; design.maximumDistanceForConeAssociationHCAL=_maximumDistanceForConeAssociationHCAL*10; design.trackingWeight = 0; design.trackingCutOff = 0; design.trackingTube = 0.0; (ProtoClusterFactory::Instance())->SetDesign(design); this->MakeProtoClusters(nullTracks, _muonProtoClusters); (ProtoClusterFactory::Instance())->SetDesignToDefault(); _maxLayer = savedMaxLayer; return; } void PandoraPFAProcessor::SeedProtoClustersWithTracks(MyTrackExtendedVec &tracks, ProtoClusterVec &pClusters){ // if(_seedClustersWithTracks == 0) NO TRACK SEEDING // if(_seedClustersWithTracks == 1) NON-RADIAL BARREL TRACKS ONLY // if(_seedClustersWithTracks == 2) NON-RADIAL BARREL/ENDCAP TRACKS // if(_seedClustersWithTracks == 3) ALL TRACKS if(_seedClustersWithTracks==0)return; // the intercept with the front first calorimeter layer is treated as // another hit from the purpose of clustering for(unsigned int itrack=0;itrackgetSeedPosition()[i]; d[i] = tracks[itrack]->getSeedDirection()[i]; r2 += r[i]*r[i]; d2 += d[i]*d[i]; cosTheta+=r[i]*d[i]; } cosTheta = cosTheta/sqrt(r2)/sqrt(d2); if(cosTheta<0.7){ if(fabs(tracks[itrack]->getSeedPosition()[2])<_zOfEndcap)use = true; if(_seedClustersWithTracks>=2)use=true; } // if _seedClustersWithTracks>=3 always use if(_seedClustersWithTracks>=3)use=true; if(use){ ProtoCluster* newCluster = (ProtoClusterFactory::Instance())->Manufacture(tracks[itrack]); pClusters.push_back(newCluster); } } } void PandoraPFAProcessor::TrackAsMIPs(MyTrackExtendedVec &tracks, ProtoClusterVec &pClusters){ for(unsigned int icluster=0;iclusterTrackSeeded()){ for(int ilayer=1;ilayer<=_trackingCutOff;++ilayer){ float smallestDistance = 999.; MyCaloHitExtended* bestHit =NULL; for(unsigned int ihit=0;ihit<_calHitsByPseudoLayer[ilayer].size();++ihit){ MyCaloHitExtended* hiti = _calHitsByPseudoLayer[ilayer][ihit]; float genericDistance = pClusters[icluster]->genericDistanceToHit(hiti, ilayer); if(genericDistanceAddHit(bestHit); _hitsForRemoval.push_back(bestHit); } } } this->removeAssociatedHits(); } } void PandoraPFAProcessor::associateLoopingTracks(ProtoClusterVec &pClusters, int pass) { // // * // * * // * * // * * // * * // // look for looping tracks // NOTE:: Ideally this should probably performed using a Kalman Filter // initially apply loose (and therefore efficient preselection) // then apply tight requirements and associate clusters bool debuggingThisCode = false; vectorfitResults; // fit a straight line to the hits in the last 5 planes of all ProtoClusters up front // and store results for(unsigned int icluster=0;iclusterFitEnd(5); fitResults.push_back(fit); } // loop over the clusters for(unsigned int icluster=0;iclusterIsAttachable()){ int lli = pClusters[icluster]->LastLayer(); int fli = pClusters[icluster]->FirstLayer(); // loop over all other clusters jcluster>icluster for(unsigned int jcluster=icluster+1;jclusterIsAttachable()){ int llj = pClusters[jcluster]->LastLayer(); int flj = pClusters[jcluster]->FirstLayer(); float dx = pClusters[icluster]->GetCentroid(lli)[0]-pClusters[jcluster]->GetCentroid(llj)[0]; float dy = pClusters[icluster]->GetCentroid(lli)[1]-pClusters[jcluster]->GetCentroid(llj)[1]; float dz = pClusters[icluster]->GetCentroid(lli)[2]-pClusters[jcluster]->GetCentroid(llj)[2]; float dr = sqrt(dx*dx+dy*dy+dz*dz); float cosTheta = scalarProduct(fiti,fitj); // apply loose cuts before going any further // require ends to be within 2.m and both "tracks" to end within +-6 layers // also require angle between track fits to be greater than 90 degrees if(dr<2000&&abs(lli-llj)<=6&&cosTheta<0.0&&fiti.chi2<100 && fitj.chi2 <100){ // look at closest approach of hits in last layers of two clusters float drmin = 99999.; for(int ihit=0;ihithitsInLayer(lli);ihit++){ MyCaloHitExtended* hiti = pClusters[icluster]->hitInLayer(lli,ihit); for(int jhit=0;jhithitsInLayer(llj);jhit++){ MyCaloHitExtended* hitj = pClusters[jcluster]->hitInLayer(llj,jhit); const float* posi =hiti->getPosition(); const float* posj =hitj->getPosition(); float dxij = (posi[0]-posj[0]); float dyij = (posi[1]-posj[1]); float dzij = (posi[2]-posj[2]); float drij = sqrt(dxij*dxij+dyij*dyij+dzij*dzij); if(drijclosestApproach(fiti,fitj); // is the position of closest approach in sense that tracks are converging float towards = dx*(fitj.dir[0]-fiti.dir[0])+ dy*(fitj.dir[1]-fiti.dir[1])+ dz*(fitj.dir[2]-fiti.dir[2]); float closestApproachCut = _looperClosestApproachCutECAL; // looser requirement in HCAL if(lli>_nEcalLayers&&llj>_nEcalLayers)closestApproachCut=_looperClosestApproachCutHCAL; if(dClosestApproach < closestApproachCut && towards >0.){ // some debug printing if(_printing>2){ std::cout << " Pass************ : " << pass << std::endl; std::cout << " ProtoClusters : " << icluster << ":" << jcluster << std::endl; std::cout << " Closest Approach : " << dClosestApproach << std::endl; std::cout << " CosTheta : " << cosTheta << std::endl; std::cout << " End Layers : " << lli << "," << llj << std::endl; std::cout << " First Layers : " << fli << "," << flj << std::endl; std::cout << " chi2 : " << fiti.chi2 << "," << fitj.chi2 << std::endl; std::cout << " rms : " << fiti.rms << "," << fitj.rms << std::endl; std::cout << " Towards ? : " << towards << std::endl; std::cout << " xy1 : " << pClusters[icluster]->GetCentroid(lli)[0] << "," << pClusters[icluster]->GetCentroid(lli)[1] << std::endl; std::cout << " xy2 : " << pClusters[jcluster]->GetCentroid(llj)[0] << "," << pClusters[jcluster]->GetCentroid(llj)[1] << std::endl; std::cout << " mipf : " << pClusters[icluster]->MipFraction() << "," << pClusters[jcluster]->MipFraction() << std::endl; std::cout << " dr : " << dr << std::endl; std::cout << " drmin : " << drmin << std::endl; std::cout << " diri : " << fiti.dir[0] << "," << fiti.dir[1] << "," << fiti.dir[2] << std::endl; std::cout << " dirj : " << fitj.dir[0] << "," << fitj.dir[1] << "," << fitj.dir[2] << std::endl; std::cout << " inti : " << fiti.intercept[0] << "," << fiti.intercept[1] << "," << fiti.intercept[2] << std::endl; std::cout << " intj : " << fitj.intercept[0] << "," << fitj.intercept[1] << "," << fitj.intercept[2] << std::endl; } // Also want to cut on separation between "tracks" to avoid mathching // clusters from very different regions of detector float drcut = _looperTrackSeparationCut; // on 2nd pass of algorithm (i.e. when looking for fragments) looser cut still if(pass>0)drcut=drcut*2.; // place some cuts on "quality of clusters being matched" bool matched = false; // looser matching in outer part of HCAL if(lli>_nEcalLayers+_outerHcalRegionLayer &&llj>_nEcalLayers+_outerHcalRegionLayer){ // be willing to match most HCAL segments matched = true; drcut=drcut*2; }else{ // look for "good" features - all a bit ad hoc ! int goodFeatures = 0; if(cosTheta<-0.1){ if(cosTheta<-0.5)goodFeatures++; if(dClosestApproach<50.)goodFeatures++; if(abs(lli-llj)<=3)goodFeatures++; if( pClusters[icluster]->MipFraction()>0.9 && pClusters[jcluster]->MipFraction()>0.9)goodFeatures++; if(goodFeatures>1)matched = true; } if(_printing>2)std::cout << " Good features : " << goodFeatures << std::endl; } // If clusters are matched and are within cut distance : join them if(matched && drmin < drcut){ //debuggingThisCode = true; if(_printing>2)std::cout << " MERGING CLUSTERS " << std::endl; if(debuggingThisCode && _recoDisplay!=NULL){ ProtoClusterVec temp; temp.push_back(pClusters[icluster]); temp.push_back(pClusters[jcluster]); _recoDisplay->DrawByProtoCluster(temp,3); } if(pass==0){ pClusters[icluster]->AddDaughter(pClusters[jcluster]); pClusters[jcluster]->AddParent(pClusters[icluster]); }else{ pClusters[icluster]->Assimilate(pClusters[jcluster]); pClusters[jcluster]->IsNowDefunct(); } } } } } } } } if(_printing>2)std::cout << " DONE " << std::endl; } void PandoraPFAProcessor::associateTrackSegments(ProtoClusterVec &pClusters) { // look for broken tracks // ****** // ** // * // * // * // * // // // o // o // o // NOTE:: Ideally this should probably performed using a Kalman Filter // initially apply loose (and therefore efficient preselection) // then apply tight requirements and associate clusters vectorendFitResults; vectorstartFitResults; float cut1; float cut2; bool debuggingThisCode =false; // fit ends of all ProtoClusters up front - save time for(unsigned int icluster=0;iclusterFitStart(5); startFitResults.push_back(fitS); fitResult fitE = pClusters[icluster]->FitEnd(8); endFitResults.push_back(fitE); } for(unsigned int icluster=0;iclusterIsAttachable()){ int fli = pClusters[icluster]->LastLayer(); for(unsigned int jcluster=0;jclusterIsAttachable()){ int flj = pClusters[jcluster]->FirstLayer(); // require first layer of cluster j to be deeper in cal if(flj>fli){ float dx = pClusters[icluster]->GetCentroid(fli)[0]-pClusters[jcluster]->GetCentroid(flj)[0]; float dy = pClusters[icluster]->GetCentroid(fli)[1]-pClusters[jcluster]->GetCentroid(flj)[1]; float dz = pClusters[icluster]->GetCentroid(fli)[2]-pClusters[jcluster]->GetCentroid(flj)[2]; float cosTheta = scalarProduct(fiti,fitj); float dr = sqrt(dx*dx+dy*dy+dz*dz); // loose preselection to save time // require ends to be within 2.0m and tracks to point within 60 degrees if(dr<2000&&cosTheta>0.5){ // find distance of closest approach for track fits float dClosestApproach = this->closestApproach(fiti,fitj); float dr1 = (dx*fiti.dir[0]+ dy*fiti.dir[1]+ dz*fiti.dir[2])/dr; float dr2 = (dx*fitj.dir[0]+ dy*fitj.dir[1]+ dz*fitj.dir[2])/dr; float ddx = fiti.dir[1]*dz - fiti.dir[2]*dy; float ddy = fiti.dir[2]*dx - fiti.dir[0]*dz; float ddz = fiti.dir[0]*dy - fiti.dir[1]*dx; float distSq = ddx*ddx + ddy*ddy+ ddz*ddz; float dPerp1 = sqrt(distSq); ddx = fitj.dir[1]*dz - fitj.dir[2]*dy; ddy = fitj.dir[2]*dx - fitj.dir[0]*dz; ddz = fitj.dir[0]*dy - fitj.dir[1]*dx; distSq = ddx*ddx + ddy*ddy+ ddz*ddz; float dPerp2 = sqrt(distSq); if(flj<=_nEcalLayers){ cut1 = _trackMergeCutEcal; cut2 = _trackMergePerpCutEcal; }else{ cut1 = _trackMergeCutHcal; cut2 = _trackMergePerpCutHcal; } // cut on distance of closest approach of track segments if(dClosestApproach < cut1){ // cut on length of vector between start and end points of the // two tracks and projected perpendicular to the two track directions if(dPerp1ExpectedLayersCrossed(pClusters[icluster]->GetCentroid(fli),pClusters[jcluster]->GetCentroid(flj)); if(_printing>2||debuggingThisCode){ std::cout << " MERGING CLUSTERS " << std::endl; std::cout << " ProtoClusters : " << icluster << ":" << jcluster << std::endl; std::cout << " Closest Approach : " << dClosestApproach << std::endl; std::cout << " CosTheta : " << cosTheta << std::endl; std::cout << " dot/cross 1 : " << dr1 << "," << dPerp1 << std::endl; std::cout << " dot/cross 2 : " << dr2 << "," << dPerp2 << std::endl; std::cout << " End Layers : " << fli << "," << flj << std::endl; std::cout << " Crossed : " << crossed << std::endl; std::cout << " rms : " << fiti.rms << "," << fitj.rms << std::endl; std::cout << " chi2 : " << fiti.chi2 << "," << fitj.chi2 << std::endl; std::cout << " xy1 : " << pClusters[icluster]->GetCentroid(fli)[0] << "," << pClusters[icluster]->GetCentroid(fli)[1] << std::endl; std::cout << " xy2 : " << pClusters[jcluster]->GetCentroid(flj)[0] << "," << pClusters[jcluster]->GetCentroid(flj)[1] << std::endl; std::cout << " dr : " << dr << std::endl; } // require not to many missing clusters and if(fiti.rms<15.&&fitj.rms<15.&&crossed<10){ //pClusters[icluster]->Assimilate(pClusters[jcluster]); //pClusters[jcluster]->IsNowDefunct(); pClusters[icluster]->AddDaughter(pClusters[jcluster]); pClusters[jcluster]->AddParent(pClusters[icluster]); if(debuggingThisCode && _recoDisplay!=NULL){ ProtoClusterVec temp; temp.push_back(pClusters[icluster]); temp.push_back(pClusters[jcluster]); _recoDisplay->DrawByProtoCluster(temp,3); } } } } } } } } } } } } void PandoraPFAProcessor::findPhotonsMergedWithMips(ProtoClusterVec &pClusters) { //* Look for overlapping tracks and photons //* Ask cluster to fragment of a photon from a cluster //* The algorithm parameterises layers as MIP like (if there is a MIP // hit consistent with the track projection) and not much else, // shower like or ambiguous. //* Cuts are placed on any returned cluster (PhotonID and track-cluster energ // matching) to decide whether to use it. //* Performance : for 100 GeV jets this method improves overall performance // reducing the jet energy resolution by about 0.25% if(_printing>2)std::cout << "PandoraPFAProcessor::findPhotonsMergedWithMips()" << std::endl; // associate tracks to clusters (in case it hasn't already been done) this->ClusterTrackAssociation(pClusters,_tracksAR); // loop over clusters unsigned int npc = pClusters.size(); for(unsigned int ipc=0;ipcFragmentPhoton(); // photonCand is a pointer to the newly formed over-lapping photon cluster // (if a candidate has been found) if(photonCand!=NULL){ // clone and delete it - i.e. give factory control over memory management photonCand=(ProtoClusterFactory::Instance())->CloneAndDelete(photonCand); if(_printing>2&&photonCand->IsPrimaryPhoton())std::cout << " IS CLASSIFIED AS A PHOTON " << photonCand->EnergyEM() << " GeV " << std::endl; if(_printing>2&&!photonCand->IsPrimaryPhoton())std::cout << " NOT CLASSIFIED AS A PHOTON " << photonCand->EnergyEM() << " GeV " << std::endl; // Compate track-cluster energy consistency with and without fragmented // photon cluster. Apply looser cuts if new cluster is identified as // a photon. float trackE = 0.; MyTrackExtendedVec tracks =pC->GetTrackVec(); for(unsigned int i=0; igetEnergy(); float sigE = trackE*_hadEnergyRes/sqrt(trackE); float deltaE = (pC->EnergyHAD()-photonCand->EnergyHAD()-trackE); float deltaE0 = (pC->EnergyHAD()-trackE); float chi = deltaE/sigE; float chi0 = deltaE0/sigE; float dchi2 = chi*chi-chi0*chi0; if(_printing>2){ std::cout << " chi0 : " << pC->EnergyHAD() << " - "<< trackE << "->" << chi0 << std::endl; std::cout << " chi : " << pC->EnergyHAD()-photonCand->EnergyHAD() << " - "<< trackE << "->" << chi << std::endl; std::cout << "DCHI2 " << dchi2 << std::endl; } // if(_recoDisplay!=NULL)_recoDisplay->DrawSingleProtoCluster(pC,RECO_VIEW_XY); // The cuts bool pass = false; if(photonCand->IsPrimaryPhoton()&&dchi2<_photonFragPhotonDeltaChi2Cut)pass = true; if(dchi2<_photonFragNonPhotonDeltaChi2Cut)pass=true; if(pass){ // Passed cuts so split of cluster if(_printing>2)std::cout << " SPLITTING OFF PHOTON " << std::endl; // First remove hits from parent for(int ihit = 0;ihitHits();++ihit){ MyCaloHitExtended* hiti = photonCand->Hit(ihit); pC->RemoveHit(hiti); } // Update the properties of the parent pC->Update(MAX_NUMBER_OF_LAYERS); pC->ClassifyYourself(); // Add the new cluster to the list of reconstructed ProtoClusters pClusters.push_back(photonCand); } } } } void PandoraPFAProcessor::finalisePhotons(ProtoClusterVec &pClusters) { // look for broken hadronic clusters if(_printing>3)std::cout << "finalisePhotons 1 " << pClusters.size() << " " << _tracksAR.size() << std::endl; this->ClusterTrackAssociation(pClusters,_tracksAR); if(_printing>3)std::cout << "finalisePhotons 2 " << std::endl; this->findPhotonsIDedAsHadrons(pClusters); if(_printing>3)std::cout << "finalisePhotons 3 " << std::endl; if(_mergeSplitPhotons)this->mergeSplitPhotons(pClusters); if(_printing>3)std::cout << "finalisePhotons 4 " << std::endl; if(_mergeSplitPhotons&&_photonClustering)this->mergeSplitPhotons2(pClusters); if(_printing>3)std::cout << "finalisePhotons 5 " << std::endl; return; } void PandoraPFAProcessor::associateSoftClusters(ProtoClusterVec &pClusters, bool firstPass) { // look for broken hadronic clusters vectortClusters; for(unsigned int icluster=0;iclusterClusterTrackAssociation(pClusters,_tracksAR); for(unsigned int icluster=0;iclusterHits()<=_maximumHitsInSoftCluster)softCluster=true; if(daughterCluster->EnergyHAD()<_softClusterEnergyHAD)softCluster=true; if(daughterCluster->LastLayer()-daughterCluster->FirstLayer()<3)softCluster=true; if(daughterCluster->AssociatedTrack())softCluster=false; if(daughterCluster->EnergyHAD()<_minimumClusterEnergyHAD)softCluster=true;; if(daughterCluster->IsPhoton()&&daughterCluster->EnergyEM()>_minimumClusterEnergyEM)softCluster=false; if(softCluster){ ProtoCluster* bestCandidateParentCluster = NULL; float smallestDistance = 99999.; for(unsigned int jcluster=0;jclusterHits()>_maximumHitsInSoftCluster && parentCluster->EnergyHAD()>_minimumClusterEnergyHAD){ if(parentCluster->getEarliestRelationID()!=daughterCluster->getEarliestRelationID()){ float distance = parentCluster->DistanceToClosestHit(daughterCluster); if(distanceFirstLayer()>20)match=true; if(smallestDistance<250 && daughterCluster->FirstLayer()>40)match=true; if(smallestDistance<_maximumDistanceForSoftMerge && daughterCluster->EnergyHAD()<_minimumClusterEnergyHAD)match=true; if(smallestDistance<_maximumDistanceForSoftMerge && daughterCluster->Hits()<_minimumHitsInCluster)match=true; if(_printing>3){ int il = daughterCluster->FirstLayer(); std::cout << " Soft Match " << daughterCluster->EnergyHAD() << " (" << daughterCluster->GetCentroid(il)[0] << "," << daughterCluster->GetCentroid(il)[1] << "," << daughterCluster->GetCentroid(il)[2] << ") " << il << " dist = " << smallestDistance << std::endl; } if(match){ bestCandidateParentCluster->Assimilate(daughterCluster); daughterCluster->IsNowDefunct(); } } } } } void PandoraPFAProcessor::associateIsolatedHits(ProtoClusterVec &pClusters, bool firstPass) { if(_printing>1)std::cout << " PandoraPFAProcessor::associateIsolatedHits " << firstPass << std::endl; vectortClusters; for(unsigned int icluster=0;iclusterIsDefunct()){ int nhits = pC->Hits(); if(nhits<_minimumHitsInCluster){ for(int i=0;iHit(i); float drmin =99999.; ProtoCluster* bestCluster=NULL; for(unsigned int jcluster=0;jclusterIsDefunct()){ if(pCj->Hits()>=nhits){ float dr = pCj->DistanceToHit(hiti); if(drAddIsolatedHit(hiti); }else{ eLostC+=hiti->getEnergyHAD(); } } } } } if(firstPass)fETotLC->Fill(eLostC,1.); float eLost = 0.; for(int ilayer=0;ilayerIsDefunct()){ float dr = pC->DistanceToHit(hiti); if(drDistanceToIsolatedHit(hiti); if(dri1)std::cout << " Adding isolated hit to cluster - ALREADY THERE ! " << std::endl; }else{ //if(!firstPass&&_printing>1)std::cout << " Adding isolated hit " << std::endl; bestCluster->AddIsolatedHit(hiti); } }else{ if(!firstPass&&_printing>1)std::cout << " Not using isolated hit " << std::endl; _unusedIsolatedHits.push_back(hiti); eLost+=hiti->getEnergyHAD(); } } _isolatedCalHitsByPseudoLayer[ilayer].clear(); } if(firstPass)fETotL->Fill(eLost,1.); } float PandoraPFAProcessor::protoClusterDr(ProtoCluster* p1, ProtoCluster* p2) { float drmin = 99999.; for(int ilayer1=p1->FirstLayer();ilayer1<=p1->LastLayer();++ilayer1){ if(p1->hitsInLayer(ilayer1)>0){ float x1 = p1->GetCentroid(ilayer1)[0]; float y1 = p1->GetCentroid(ilayer1)[1]; float z1 = p1->GetCentroid(ilayer1)[2]; for(int ilayer2=p2->FirstLayer();ilayer2<=p2->LastLayer();++ilayer2){ if(p1->hitsInLayer(ilayer2)>0&&p2->hitsInLayer(ilayer2)>0){ float x2 = p2->GetCentroid(ilayer2)[0]; float y2 = p2->GetCentroid(ilayer2)[1]; float z2 = p2->GetCentroid(ilayer2)[2]; float dx = x1 - x2; float dy = y1 - y2; float dz = z1 - z2; float dr = sqrt(dx*dx+dy*dy+dz*dz); if(drFirstLayer(); float x1 = p1->GetCentroid(ilayer1)[0]; float y1 = p1->GetCentroid(ilayer1)[1]; float z1 = p1->GetCentroid(ilayer1)[2]; int ilayer2=p2->FirstLayer(); float x2 = p2->GetCentroid(ilayer2)[0]; float y2 = p2->GetCentroid(ilayer2)[1]; float z2 = p2->GetCentroid(ilayer2)[2]; float dx = x1 - x2; float dy = y1 - y2; float dz = z1 - z2; float dr = sqrt(dx*dx+dy*dy+dz*dz); return dr; } void PandoraPFAProcessor::associateByShowerCone(ProtoClusterVec &pClusters) { //fg: - if pClusters.size() == 0 the loop code will crash ( as unsigned(-1) == 4294967295 > 0 ) if( pClusters.size() < 1 ) { streamlog_out(WARNING) << " associateByShowerCone : no clusters - return " << std::endl ; return ; } // associate tracks to clusters this->ClusterTrackAssociation(pClusters,_tracksAR); // look for broken hadronic clusters with a simple cone association // order search by tracks then layers std::vector pCs; for(unsigned int icluster=pClusters.size()-1;icluster>0;--icluster){ ProtoCluster* pC = pClusters[icluster]; MyTrackExtendedVec tracks = pC->GetTrackVec(); if(tracks.size()==0 && pC->Hits()>5 ){ pCs.push_back(pC); } } for(unsigned int icluster=0;iclusterIsAttachable()){ for(unsigned int jcluster=0;jclustergetEarliestRelationID()!=daughterCluster->getEarliestRelationID() && parentCluster->IsDefunct()==false ){ if(parentCluster->IsAttachable() && parentCluster->Hits()>5){ float fraction = parentCluster->FractionInCone(daughterCluster,_coneAssociationCosine); if(fraction>highestFraction){ float dr = this->protoClusterDrF(parentCluster,daughterCluster); float drcut = 1000; MyTrackExtendedVec ptracks = parentCluster->GetTrackVec(); if(ptracks.size()==0)drcut = 250.; if(drEnergyHAD()+ daughterCluster->EnergyHAD(); MyTrackExtendedVec tracks = bestCandidateParentCluster->GetTrackVec(); float trackE = 0.; for(unsigned int i=0; igetEnergy(); float sigE = 0.; float chi = 0.; float chi0 = 0.; float dchi2 = 0; if(trackE>0){ sigE = trackE*_hadEnergyRes/sqrt(trackE); float deltaE = (clusterE-trackE); float deltaE0 = (bestCandidateParentCluster->EnergyHAD()-trackE); chi = deltaE/sigE; chi0 = deltaE0/sigE; dchi2 = chi*chi-chi0*chi0; // std::cout << trackE // << " , " // << clusterE // << " : " /// << chi // << " , " /// << chi0 // // << " , " // << dchi2 // << std::endl; } if(tracks.size()==0){ canAssoc = true; }else{ if(dchi2<_energyDeltaChi2ForCrudeMerging && chi<_energyChiForCrudeMerging)canAssoc=true; if(daughterCluster->EnergyHAD()<1.0)canAssoc = true; } if(canAssoc){ float dr = this->protoClusterDrF(bestCandidateParentCluster,daughterCluster); ProtoCluster* p1 = bestCandidateParentCluster; ProtoCluster* p2 = daughterCluster; //daughterCluster->AddParent(bestCandidateParentCluster); //bestCandidateParentCluster->AddDaughter(daughterCluster); if(_printing>2 && daughterCluster->EnergyHAD()>0.0 &&tracks.size()>=0){ std::cout << " DAUGHTER ENERGY : " << daughterCluster->EnergyHAD() << std::endl; std::cout << " PARENT ENERGY : " << bestCandidateParentCluster->EnergyHAD() << std::endl; std::cout << " CONE ASSOC TRACK E : " << trackE << std::endl; std::cout << " DR : " << dr << std::endl; std::cout << " HF : " << highestFraction << std::endl; std::cout << p1->GetCentroid(p1->FirstLayer())[0] << "," << p1->GetCentroid(p1->FirstLayer())[1] << "," << p1->GetCentroid(p1->FirstLayer())[2] << std::endl; std::cout << p2->GetCentroid(p2->FirstLayer())[0] << "," << p2->GetCentroid(p2->FirstLayer())[1] << "," << p2->GetCentroid(p2->FirstLayer())[2] << std::endl; std::cout << "******CONE OLD : (" << trackE << " - " << bestCandidateParentCluster->EnergyHAD() << ")/ " << sigE << " --> " << chi0 << std::endl; std::cout << "******CONE NEW : (" << trackE << " - " << clusterE << ")/ " << sigE << " --> " << chi << std::endl; std::cout << "DELTA CHI2 : " << dchi2 << std::endl; } bestCandidateParentCluster->Assimilate(daughterCluster); daughterCluster->IsNowDefunct(); } } } } } void PandoraPFAProcessor::trackDrivenAssociation(ProtoClusterVec &pClusters, unsigned int ipass) { // associate tracks to clusters this->ClusterTrackAssociation(pClusters,_tracksAR); // look for broken hadronic clusters for(unsigned int icluster=0;iclusterGetTrackVec(); if(tracks.size()==1)this->trackDrivenAssociationSingle(pClusters,icluster,ipass); if(tracks.size()>1)this->trackDrivenAssociationMultiple(pClusters,icluster,ipass); } } void PandoraPFAProcessor::trackDrivenAssociationSingle(ProtoClusterVec &pClusters, unsigned int icluster, unsigned int ipass) { vector coneAssocPCs; vector fConeAssocPCs; ProtoCluster* parentCluster = pClusters[icluster]; float clusterE = parentCluster->EnergyHAD(); MyTrackExtendedVec tracks = parentCluster->GetTrackVec(); float trackE = tracks[0]->getEnergy(); float sigE = trackE*_hadEnergyRes/sqrt(trackE); float deltaE = (clusterE-trackE); float chi = deltaE/sigE; bool badMatch = false; int layersFromEdge = 0; bool leavingCluster = false; if(chi<-2.5){ badMatch = true; leavingCluster = this->IsClusterLeavingDetector(parentCluster); layersFromEdge = this->LayersFromEdge(parentCluster); if(leavingCluster)badMatch=false; } if(badMatch){ if(_printing>1){ std::cout << "*******BAD MATCH************************************ " << std::endl; std::cout << "*******BAD MATCH******* " << trackE << " -> " << clusterE << " : " << chi << " Last layer " << parentCluster->LastLayer() << " form end " << layersFromEdge << " MIPF : " << parentCluster->MipFraction () << std::endl; std::cout << "*******BAD MATCH*********************************** " << std::endl; } bool _matched = false; // check to see if the track makes sense float r2min =999999.; int ist = parentCluster->FirstLayer(); float xc = parentCluster->GetCentroid(ist)[0]; float yc = parentCluster->GetCentroid(ist)[1]; float zc = parentCluster->GetCentroid(ist)[2]; TrackerHitVec hitvec = tracks[0]->getTrack()->getTrackerHits(); int nhits = (int)hitvec.size(); for(int ih =0;ihgetPosition()[0]; float dy = yc-(float)hitvec[ih]->getPosition()[1]; float dz = zc-(float)hitvec[ih]->getPosition()[2]; float r2 = dx*dx+dy*dy+dz*dz; if(r22){ std::cout << " r2min : " << r2min << std::endl; std::cout << " seed : " << tracks[0]->getSeedPosition()[0] << "," << "," << tracks[0]->getSeedPosition()[1] << "," << tracks[0]->getSeedPosition()[2] << std::endl; std::cout << " ist : " << ist << " : " << xc << "," << yc << "," << zc << std::endl; } if(r2min>2000.){ _matched = true; tracks[0]->isKinkS(true); if(_printing>2)std::cout << " TRACK KILLED " << std::endl; tracks[0]->setTrackStatus(TRACK_STATUS_KILLED); return; } float highestHEFraction = 0.; float highestFraction = 0.; // float closestApproach = 99999.; ProtoCluster* bestCandidateDaughter=NULL; ProtoCluster* bestCandidateHEDaughter=NULL; for(unsigned int jcluster=0;jclusterGetTrackVec(); float clusterD = daughterCluster->EnergyHAD(); float newdeltaE = (clusterE+clusterD-trackE); float newchi = newdeltaE/sigE; if(abs(newchi)<200.5 && dtracks.size()==0){ float distance = daughterCluster->DistanceToTrack(tracks[0],10); int dplanes = daughterCluster->FirstLayer() - parentCluster->LastLayer(); float fraction = parentCluster->FractionInRadialCone(daughterCluster,0.90); if(fraction>0.25 && ((ipass == 1) || dplanes < 5) ){ fConeAssocPCs.push_back(fraction); coneAssocPCs.push_back(daughterCluster); } if(_printing>1&&fraction>0.01)std::cout << " Candidate match : " << clusterD << " : " << fraction << "," << distance << " : " << dplanes << std::endl; if(_printing>1&&fraction>0.01)std::cout << parentCluster->FirstLayer() << "-" << parentCluster->LastLayer() << " : " << daughterCluster->FirstLayer() << "-" << daughterCluster->LastLayer() << std::endl; if(abs(newchi)<2.5){ if(fraction>highestFraction){ highestFraction = fraction; bestCandidateDaughter = daughterCluster; } } if(newchi>2.5){ if(fraction>highestHEFraction){ highestHEFraction = fraction; bestCandidateHEDaughter = daughterCluster; } } } } if(fConeAssocPCs.size()>0){ // sort in order of decreasing fraction unsigned int sizeOfVector = fConeAssocPCs.size(); if(sizeOfVector>1){ ProtoCluster *tempPC; float tempf; for (unsigned int i = 0 ; i < sizeOfVector-1; i++){ for (unsigned int j = 0; j < sizeOfVector-i-1; j++){ if(fConeAssocPCs[j] < fConeAssocPCs[j+1]){ tempf = fConeAssocPCs[j]; tempPC = coneAssocPCs[j]; fConeAssocPCs[j] = fConeAssocPCs[j+1]; fConeAssocPCs[j+1] = tempf; coneAssocPCs[j] = coneAssocPCs[j+1]; coneAssocPCs[j+1] = tempPC; } } } } for(unsigned int i=0; i1)std::cout << " Ordered " << i << " Frac " << fConeAssocPCs[i] << " E : " << coneAssocPCs[i]->EnergyHAD() << std::endl; } } // if able to find match to a single cluster do so if(highestFraction>0.50){ // simple match to a single cluster if(_printing>1)std::cout << "BEST MATCH : " << highestFraction << " : " << bestCandidateDaughter->EnergyHAD() <Assimilate(bestCandidateDaughter); bestCandidateDaughter->IsNowDefunct(); return; } // work through ordered (by fraction) list vector clustersToAdd; float clusterSum = 0.; bool ok = false; bool done = false; float lastchi = (clusterE-trackE)/sigE; for(unsigned int i=0; i0.40){ clusterSum += coneAssocPCs[i]->EnergyHAD(); float newdeltaE = (clusterE+clusterSum-trackE); float newchi = newdeltaE/sigE; if(_printing>1)std::cout << " Ordered " << i << " Frac " << fConeAssocPCs[i] << " E : " << coneAssocPCs[i]->EnergyHAD() << " chi : " << newchi << std::endl; if(fabs(newchi)>fabs(lastchi) || newchi > 2.5){ done = true; bestCandidateHEDaughter = coneAssocPCs[i]; highestHEFraction = fConeAssocPCs[i]; } lastchi = newchi; if(abs(newchi)<2.5)ok= true; if(!done)clustersToAdd.push_back(coneAssocPCs[i]); } } if(clustersToAdd.size()>0){ if(ok){ for(unsigned int i=0;i1)std::cout << " Multiple Merge Cluster : " << clustersToAdd[i]->EnergyHAD() << std::endl; parentCluster->Assimilate(clustersToAdd[i]); clustersToAdd[i]->IsNowDefunct(); } return; }else{ float cut = 0.75; if(done)cut = 0.0; for(unsigned int i=0;icut){ if(!done&&_printing>1)std::cout << " Dubious Multiple Merge Cluster : " << clustersToAdd[i]->EnergyHAD() << std::endl; if(done&&_printing>1)std::cout << " Partial Multiple Merge Cluster : " << clustersToAdd[i]->EnergyHAD() << std::endl; parentCluster->Assimilate(clustersToAdd[i]); clustersToAdd[i]->IsNowDefunct(); } if(!done)return; } } } // No single cluster/mulitple clusters are satisfactory // if pointing towards a HE cluster try and split it up ! float clusterE = parentCluster->EnergyHAD(); if(highestHEFraction>0.25){ if(_printing>1)std::cout << "BEST MATCH HIGH ENERGY : " << highestHEFraction << " : " << bestCandidateHEDaughter->EnergyHAD() <Recluster(bestCandidateHEDaughter,tracks,design[i],finalClusters[i]); // do any of these new clusters satisfy our needs ? for(unsigned int kcluster=0;kclusterEnergyHAD(); float newdeltaE = (clusterE+clusterD-trackE); float newchi = newdeltaE/sigE; float fraction = parentCluster->FractionInRadialCone(gDaughterCluster,0.90); if(_printing>1)cout << " design : " << i << " fraction " << fraction << " : chi " << newchi << std::endl; if(fraction>0.5){ float newchi2 = newchi*newchi; if(newchi21.0 && newchi2<9.0){ ibest = i; bestchi2 = newchi2; bestCandidateGrandDaughter = gDaughterCluster; } } // if found a v.good chi2 stop if(bestchi2<1.0)done=true; // if have a good chi2 and things getting worse - stop if(bestchi2<4.0&&newchi2>16.0)done=true; } } } if(bestchi2<9.0){ // simple match to a single cluster if(_printing>1)std::cout << "Choose : " << ibest <1)std::cout << "FRAGMENTED MATCH : " << bestchi2 << " : " << bestCandidateGrandDaughter->EnergyHAD() <Assimilate(bestCandidateGrandDaughter); for(unsigned int i=0;i1)std::cout << " What's left : " << finalClusters[ibest][i] << "(" << bestCandidateGrandDaughter << ")" << finalClusters[ibest][i]->EnergyHAD() << std::endl; if(finalClusters[ibest][i]!=bestCandidateGrandDaughter){ pClusters.push_back(finalClusters[ibest][i]); finalClusters[ibest][i]->SetTemporaryReclusteringFlag(false); } } bestCandidateGrandDaughter->IsNowDefunct(); bestCandidateHEDaughter->IsNowDefunct(); return; }else{ if(tracks.size()==1&&abs(chi)>_chiToKillTrack && ipass>0){ if(_printing>-1)std::cout << " WILL EFFECTIVELY KILL TRACK" << std::endl; //if(_recoDisplay!=NULL)_recoDisplay->DrawTransverseProfile(parentCluster,MAX_NUMBER_OF_LAYERS); //if(_recoDisplay!=NULL)_recoDisplay->DrawSingleProtoCluster(parentCluster,RECO_VIEW_XY); ProtoClusterVec forcedClusters; ProtoCluster* newCluster = this->ReclusterForced(parentCluster,bestCandidateHEDaughter,tracks,forcedClusters); if(_printing>-1)std::cout << " newCluster : " << newCluster << std::endl; if(newCluster!=NULL){ pClusters.push_back(newCluster); newCluster->SetTemporaryReclusteringFlag(false); }else{ if(_printing>-1)std::cout << " No cluster formed .... kill track ? " << std::endl; if(trackE<2.0)tracks[0]->setTrackStatus(TRACK_STATUS_KILLED); } }else{ if(_printing>-1)std::cout << " WILL NOT KILL TRACK " <1){ for(int istave = 0; istave < _HCALsymmetry; ++istave){ float prodRadius = pos[0]*_barrelStaveDirHCAL[istave].x+pos[1]*_barrelStaveDirHCAL[istave].y; if(prodRadius>prodRadiusMax)prodRadiusMax=prodRadius; } }else{ prodRadiusMax = sqrt(pos[0]*pos[0]+pos[1]*pos[1]); } radialDistanceToEdge = (_outerRadiusOfBarrelHCAL-prodRadiusMax)/_barrelHCALLayerThickness; }else{ for(int istave = 0; istave < _HCALEndcapSymmetry; ++istave){ float prodRadius = pos[0]*_endcapStaveDirHCAL[istave].x+pos[1]*_endcapStaveDirHCAL[istave].y; if(prodRadius>prodRadiusMax)prodRadiusMax= prodRadius; } radialDistanceToEdge = (_outerRadiusOfEndcapHCAL-prodRadiusMax)/_endcapHCALLayerThickness; } // distance from back of endcaps outer float rearDistanceToEdge = 99999.; float overlapDistanceToEdge = 99999.; if(fabs(pos[2])>=_zOfEndcap){ rearDistanceToEdge = (_rearOfEndcapHCAL - fabs(pos[2]))/_endcapHCALLayerThickness; }else{ rearDistanceToEdge = (_zOfBarrel - fabs(pos[2]))/_barrelHCALLayerThickness; if(rearDistanceToEdge < 250.){ prodRadiusMax = 0; for(int istave = 0; istave < _HCALEndcapSymmetry; ++istave){ float prodRadius = pos[0]*_endcapStaveDirHCAL[istave].x+pos[1]*_endcapStaveDirHCAL[istave].y; if(prodRadius>prodRadiusMax)prodRadiusMax=prodRadius; } overlapDistanceToEdge = (_outerRadiusOfEndcapHCAL-prodRadiusMax)/_endcapHCALLayerThickness; if(overlapDistanceToEdge>rearDistanceToEdge)rearDistanceToEdge = overlapDistanceToEdge; }else{ rearDistanceToEdge= 99999.; } } int layersFromEdge = static_cast(min(radialDistanceToEdge,rearDistanceToEdge)); int truncation = _nHcalLayers-_maxHCALLayer; if(truncation>0)layersFromEdge = layersFromEdge-truncation; return layersFromEdge; } int PandoraPFAProcessor::LayersFromEdge(ProtoCluster* pCluster) { float pos[3]; int ll = pCluster->LastLayer(); pos[2] = pCluster->GetCentroid(ll)[2]; pos[0] = pCluster->GetCentroid(ll)[0]; pos[1] = pCluster->GetCentroid(ll)[1]; int layersFromEdge = LayersFromEdge(pos); return layersFromEdge; } int PandoraPFAProcessor::LayersFromEdge(MyCaloHitExtended* pHit) { float pos[3]; CalorimeterHit* hit = const_cast(pHit->getCalorimeterHit()); pos[0] = hit->getPosition()[0]; pos[1] = hit->getPosition()[1]; pos[2] = hit->getPosition()[2]; int layersFromEdge = LayersFromEdge(pos); return layersFromEdge; } void PandoraPFAProcessor::trackDrivenAssociationMultiple(ProtoClusterVec &pClusters, unsigned int icluster, unsigned int ipass) { bool _matched = false; ProtoCluster* parentCluster = pClusters[icluster]; float clusterE = parentCluster->EnergyHAD(); MyTrackExtendedVec tracks = parentCluster->GetTrackVec(); float trackE = 0.; for(unsigned int i=0; igetEnergy(); float sigE = trackE*_hadEnergyRes/sqrt(trackE); float deltaE = (clusterE-trackE); float chi = deltaE/sigE; if(chi<-2.5){ if(_printing>2){ std::cout << "*******BAD MATCH (MULTIPLE)************************************ " << std::endl; std::cout << "*******BAD MATCH (MULITPLE)******* " << trackE << " -> " << clusterE << " : " << chi << " Last layer " << parentCluster->LastLayer() << std::endl; std::cout << "*******BAD MATCH (MULTIPLE)*********************************** " << std::endl; } float highestFraction = 0.; float closestApproach = 99999.; ProtoCluster* bestCandidateDaughter=NULL; ProtoCluster* bestCandidateDaughterD=NULL; for(unsigned int jcluster=0;jclusterGetTrackVec(); float clusterD = daughterCluster->EnergyHAD(); float newdeltaE = (clusterE+clusterD-trackE); float newchi = newdeltaE/sigE; if(abs(newchi)<200.5 && dtracks.size()==0){ float distance = daughterCluster->DistanceToTrack(tracks[0],10); //float distance1 = daughterCluster->DistanceToTrack(tracks[1],10); float fraction = parentCluster->FractionInRadialCone(daughterCluster,0.90); float approach = pClusters[icluster]->DistanceToTrack(tracks[0],10); float approach1 = pClusters[icluster]->DistanceToTrack(tracks[0],10); if(_printing>2&&fraction>0.01)std::cout << " Candidate match : " << clusterD << " : " << fraction << "," << approach << " and " << approach1 << std::endl; // first attempt at dealing with > 1 track pointing to same cluster // know something wrong so try looser cut if(abs(newchi)<3.5){ if(fraction>highestFraction){ highestFraction = fraction; bestCandidateDaughter = daughterCluster; } if(distance0.50){ if(_printing>2)std::cout << "BEST MATCH MULTIPLE : " << highestFraction << " : " << bestCandidateDaughter->EnergyHAD() <Assimilate(bestCandidateDaughter); bestCandidateDaughter->IsNowDefunct(); _matched = true; } if(_matched==false){ // so that failed. If two tracks matched to same cluster see if // there is another cluster to which a match can be made // may have two overlapping tracks !!!!! if(tracks.size()==2){ vectorclustersMatchedTo0; vectorclustersMatchedTo1; float et0 = tracks[0]->getEnergy(); float sigE0 = _hadEnergyRes*sqrt(et0); float et1 = tracks[1]->getEnergy(); float sigE1 = _hadEnergyRes*sqrt(et1); for(unsigned int icluster=0;iclusterDistanceToTrack(tracks[0],10); float approach1 = pClusters[icluster]->DistanceToTrack(tracks[1],10); if(approach0<50)clustersMatchedTo0.push_back(icluster); if(approach1<50)clustersMatchedTo1.push_back(icluster); } for(unsigned int i0=0;i0EnergyHAD(); float chi0 = (et0-ec0)/sigE0; float ec1 = pClusters[clustersMatchedTo1[i1]]->EnergyHAD(); float chi1 = (et1-ec1)/sigE1; if(_printing>2)std::cout << et0 << " <-> " << ec0 << " and " << et1 << " <-> " << ec1 << " giving chi2 : " << chi0*chi0+chi1*chi1 << std::endl; }else{ if(_printing>1)std::cout << " THIS ONE IS HARD TO RESOLVE ! " << std::endl; ProtoCluster* bestCandidateDaughter=NULL; float bestchi = chi; for(unsigned int jcluster=0;jclusterGetTrackVec(); float clusterD = daughterCluster->EnergyHAD(); float newdeltaE = (clusterE+clusterD-trackE); float newchi = newdeltaE/sigE; if(newchi<3.0 && dtracks.size()==0){ float fraction = parentCluster->FractionInRadialCone(daughterCluster,0.90); if(fraction>0.75){ if(fabs(newchi)1)std::cout << " Risky Candidate match " << fraction <<" : " << newchi << std::endl; } } } } if(bestCandidateDaughter!=NULL){ parentCluster->Assimilate(bestCandidateDaughter); bestCandidateDaughter->IsNowDefunct(); } } } } } } } } void PandoraPFAProcessor::trackDrivenSplitMergedClusters(ProtoClusterVec &pClusters) { // set up the cluster designs to be used for the attempted reclustering const int ndesign = 13; float scalei[ndesign] = {0.8,0.6,0.5,0.4,0.3,0.25,0.2,0.15,0.1,1.0,1.0,1.0,1.0}; int wgti[ndesign] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 0, 3, 4}; protoClusterDesign_t design[ndesign]; for(int i=0;iClusterTrackAssociation(pClusters,_tracksAR); // look for merged hadronic clusters using track information unsigned int nclusters = pClusters.size(); for(unsigned int icluster=0;iclusterEnergyHAD(); MyTrackExtendedVec tracks = pCluster->GetTrackVec(); if(tracks.size()>0){ float trackE = 0.; for(unsigned int i=0; igetEnergy(); float sigE = trackE*_hadEnergyRes/sqrt(trackE); float deltaE = (clusterE-trackE); float chi = deltaE/sigE; float chi2 = chi*chi; float chi2cut = chi2-1.0; if(chi>_chiToForceReclustering)chi2cut = _chiToForceReclustering*_chiToForceReclustering; if(chi>_chiToAttemptReclustering){ if(_printing>1){ std::cout << "*******BAD MATCH (TRACKD)************************************ " << std::endl; std::cout << "*******BAD MATCH (TRACKD)******* " << trackE << " -> " << clusterE << " : " << chi << " " << std::endl; std::cout << "*******BAD MATCH (TRACKD)*********************************** " << std::endl; } ProtoClusterVec finalClusters[ndesign]; float newchi; float bestchi2 = chi2; float bestchi = 999.; int ibest = -999; bool done = false; for(int i=0;iRecluster(pCluster,tracks,design[i],finalClusters[i]); float newchi2 = newchi*newchi; if(newchi21.0 && newchi216.0)done=true; if(_printing>1)std::cout << " design : " << i << " : " << newchi << std::endl; } if(_printing>1)std::cout << " CHOOSE : " << ibest << std::endl; ProtoCluster* pnew = NULL; if(ibest>=0){ if(_printing>1)std::cout << " WILL RECLUSTER !" << std::endl; pCluster->IsNowDefunct(); pnew = finalClusters[ibest][0]; for(unsigned int i=0;iSetTemporaryReclusteringFlag(false); int il = finalClusters[ibest][i]->FirstLayer(); if(_printing>1)std::cout << " Adding cluster : " << finalClusters[ibest][i]->EnergyHAD() << " (" << finalClusters[ibest][i]->GetCentroid(il)[0] << "," << finalClusters[ibest][i]->GetCentroid(il)[1] << "," << finalClusters[ibest][i]->GetCentroid(il)[2] << ")" << std::endl; } } // Things are desparate. Either not been able to split cluster or // cluster after splitting still has bad chi2. // Still have a cluster with too much energy for the track // Do something - NOT OPTIMAL !!!! if(pnew==NULL || (pnew!=NULL&&bestchi>_chiToKillTrack)){ if(pnew!=NULL)pCluster=pnew; if(_printing>0)std::cout << " NO GOOD RECLUSTERING FOUND" << std::endl; if(tracks.size()==1&& (chi2>_chiToKillTrack*_chiToKillTrack||pnew!=NULL)){ if(_printing>0)std::cout << " WILL EFFECTIVELY KILL TRACK" << std::endl; //if(_recoDisplay!=NULL)_recoDisplay->DrawTransverseProfile(pCluster,MAX_NUMBER_OF_LAYERS); //if(_recoDisplay!=NULL)_recoDisplay->DrawSingleProtoCluster(pCluster,RECO_VIEW_XY); ProtoClusterVec forcedClusters; ProtoCluster* newCluster = this->ReclusterForced(pCluster,tracks,forcedClusters); if(_printing>0)std::cout << " newCluster : " << newCluster << std::endl; if(newCluster!=NULL){ pClusters.push_back(newCluster); newCluster->SetTemporaryReclusteringFlag(false); }else{ if(_printing>0)std::cout << " No cluster formed .... kill track ? " << std::endl; if(trackE<2.0)tracks[0]->setTrackStatus(TRACK_STATUS_KILLED); } } } } } } } void PandoraPFAProcessor::ExitingTrackReclustering(ProtoClusterVec &pClusters) { if(_printing>1)std::cout << " In PandoraPFAProcessor::ExitingTrackReclustering"<< std::endl; // set up the cluster designs to be used for the attempted reclustering const int ndesign = 13; float scalei[ndesign] = {0.8,0.6,0.5,0.4,0.3,0.25,0.2,0.15,0.1,1.0,1.0,1.0,1.0}; int wgti[ndesign] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 0, 3, 4}; protoClusterDesign_t design[ndesign]; for(int i=0;iClusterTrackAssociation(pClusters,_tracksAR); // look for merged hadronic clusters using track information unsigned int nclusters = pClusters.size(); for(unsigned int icluster=0;iclusterEnergyHAD(); MyTrackExtendedVec tracks = pCluster->GetTrackVec(); if(tracks.size()==1){ int layersFromEdge=999; layersFromEdge = this->LayersFromEdge(pCluster); bool leavingCluster = this->IsClusterLeavingDetector(pCluster); if(leavingCluster){ MyTrackExtended* trackAR = tracks[0]; float trackE = trackAR->getEnergy(); float sigE = trackE*_hadEnergyRes/sqrt(trackE); float deltaE = (clusterE-trackE); float chi = deltaE/sigE; float chi2 = chi*chi; int ll = pCluster->LastLayer(); int nhits5=0; int nlayers5=0; float e5=0.; for(int il = ll-4;il<=ll;il++){ int ihits = pCluster->hitsInLayer(il); if(ihits>0)nlayers5++; nhits5+=ihits; for(int ihit=0;ihithitInLayer(il,ihit); e5 += hit->getEnergyHAD(); } } MCParticle* mci = trackAR->getMCParticle(); if(mci!=NULL){ if(_printing>1)std::cout << " LEAVING PARTICLE MC PDG : " << mci->getPDG() << std::endl; } if(chi>2.0){ if(_printing>1){ std::cout << "*******Leaving Track******* " << trackE << " -> " << clusterE << " : " << chi << " chi = " << chi << std::endl; std::cout << " Last layer : " << ll << " from edge " << layersFromEdge << std::endl; std::cout << " In last 5 layers : " << nlayers5 << " hits " << nhits5 << " E5 = " << e5 << std::endl; } ProtoClusterVec finalClusters[ndesign]; float newchi; float bestchi2 = chi2; float bestchi = 999.; int ibest = -999; bool done = false; for(int i=0;iRecluster(pCluster,tracks,design[i],finalClusters[i]); float newchi2 = newchi*newchi; if(newchi21.0 && newchi<1.5)ibest = i; bestchi2 = newchi2; bestchi = newchi; } // if found a v.good chi2 stop if(bestchi2<1.0)done=true; // if have a good chi2 and things getting worse - stop if(bestchi2<4.0&&newchi2>16.0)done=true; if(_printing>1)std::cout << " design : " << i << " : " << newchi << std::endl; } if(_printing>1)std::cout << " CHOOSE : " << ibest << std::endl; bool recluster = true; if(nlayers5<3){ recluster=false; if(_printing>1)std::cout << " won't recluster : less than 3 hit layers" << std::endl; } if(e5<1.0 && nlayers5<4){ recluster=false; if(_printing>1)std::cout << " won't recluster : not enough energy/layers hit in last 5" << std::endl; } if(ibest<0 && chi <2.5){ if(_printing>1)std::cout << " won't recluster : no good reclustering + chi2 too small " << std::endl; recluster = false; } if(recluster && _printing>1)std::cout << " WOULD RECLUSTER " << std::endl; ProtoCluster* pnew = NULL; if(recluster && ibest>=0){ if(_printing>1)std::cout << " RECLUSTERING !" << std::endl; pCluster->IsNowDefunct(); pnew = finalClusters[ibest][0]; for(unsigned int i=0;iSetTemporaryReclusteringFlag(false); int il = finalClusters[ibest][i]->FirstLayer(); if(_printing>1)std::cout << " Adding cluster : " << finalClusters[ibest][i]->EnergyHAD() << " (" << finalClusters[ibest][i]->GetCentroid(il)[0] << "," << finalClusters[ibest][i]->GetCentroid(il)[1] << "," << finalClusters[ibest][i]->GetCentroid(il)[2] << ")" << std::endl; } } } } } } if(_printing>1)std::cout << " Leaving PandoraPFAProcessor::ExitingTrackReclustering"<< std::endl; return; } float PandoraPFAProcessor::Recluster(ProtoCluster* pCluster, MyTrackExtendedVec& tracks, protoClusterDesign_t design, ProtoClusterVec &finalClusters) { (ProtoClusterFactory::Instance())->ReclusteringOn(); float newchi = 99999.; // try and recluster ! for(int ilayer=pCluster->FirstLayer();ilayer<=pCluster->LastLayer();ilayer++){ int nhits = pCluster->hitsInLayer(ilayer); if(_calHitsByPseudoLayer[ilayer].size()>0)cout << " HELPPPPPP ! " << std::endl; for(int ihit=0;ihithitInLayer(ilayer,ihit); _calHitsByPseudoLayer[ilayer].push_back(phit); } } int count = 0; int countI = 0; // now get the isolated hits for(int ilayer=1;ilayerisolatedHitsInLayer(ilayer); for(int ihit=0;ihitisolatedHitInLayer(ilayer,ihit); if(phit->isIsolatedHit()){ _isolatedCalHitsByPseudoLayer[ilayer].push_back(phit); countI++; }else{ _calHitsByPseudoLayer[ilayer].push_back(phit); count++; } } } if(_printing>1)std::cout << "Recluster : " << countI << " " << count << std::endl; // ProtoClusterVec newClusters; if(design.trackingWeight==3&&design.trackingCutOff<=0)design.trackingCutOff=30; (ProtoClusterFactory::Instance())->SetDesign(design); // Form the protoclusters this->MakeProtoClusters(tracks,newClusters); if(newClusters.size()>0)this->associateProtoClusters(newClusters,tracks,finalClusters,false); if(_printing>1)std::cout << " FINAL CLUSTERS : " << finalClusters.size() << std::endl; this->ClusterTrackAssociation(finalClusters,tracks,false); float unassocE = 0.; for(unsigned int jcluster=0;jclusterEnergyHAD(); if(_printing>1)std::cout << " New Cluster : " << clusterE << std::endl; MyTrackExtendedVec xtracks = finalClusters[jcluster]->GetTrackVec(); if(xtracks.size()>0){ float trackE = 0.; for(unsigned int jtrack=0; jtrackgetEnergy(); float sigE = trackE*_hadEnergyRes/sqrt(trackE); float deltaE = (clusterE-trackE); newchi = deltaE/sigE; if(_printing>2)std::cout << " NEW CHI : " << trackE << " - " << clusterE << " -> " << newchi << std::endl; // veto clustering where track is now matched to v. low energy cluster if(clusterE<0.1)newchi=999.; }else{ unassocE+= clusterE; } } if(unassocE<0.25)newchi=999.; // set things back to default values design.tanConeAngleECAL = _clusterFormationConeTanECAL; design.tanConeAngleHCAL = _clusterFormationConeTanHCAL; design.additionalPadsECAL = _clusterFormationPadsECAL; design.additionalPadsHCAL = _clusterFormationPadsHCAL; design.sameLayerPadCutECAL = _sameLayerPadCutECAL; design.sameLayerPadCutHCAL = _sameLayerPadCutHCAL; design.maximumDistanceForConeAssociationECAL=_maximumDistanceForConeAssociationECAL; design.maximumDistanceForConeAssociationHCAL=_maximumDistanceForConeAssociationHCAL; design.trackingWeight =_trackingWeight; design.trackingCutOff = 0; design.trackingTube = 0.0; (ProtoClusterFactory::Instance())->SetDesign(design); (ProtoClusterFactory::Instance())->ReclusteringOff(); return newchi; } ReclusterResult_t PandoraPFAProcessor::ReclusterMultiple(ProtoClusterVec& clusters, MyTrackExtendedVec& tracks, protoClusterDesign_t design, ProtoClusterVec &finalClusters) { (ProtoClusterFactory::Instance())->ReclusteringOn(); ReclusterResult_t result; result.chi2 = 99999.; result.chi = 99999.; result.ntrackmatch = 0; float newchi2 = 99999.; float newchi = 99999.; // try and recluster ! for(unsigned int icluster=0;iclusterFirstLayer();ilayer<=pCluster->LastLayer();ilayer++){ int nhits = pCluster->hitsInLayer(ilayer); for(int ihit=0;ihithitInLayer(ilayer,ihit); _calHitsByPseudoLayer[ilayer].push_back(phit); } } // now get the isolated hits for(int ilayer=1;ilayerisolatedHitsInLayer(ilayer); for(int ihit=0;ihitisolatedHitInLayer(ilayer,ihit); if(phit->isIsolatedHit()){ _isolatedCalHitsByPseudoLayer[ilayer].push_back(phit); }else{ _calHitsByPseudoLayer[ilayer].push_back(phit); } } } } // ProtoClusterVec newClusters; if(_printing>1)std::cout << "Set design " << std::endl; if(design.trackingWeight==3)design.trackingCutOff=30; if(design.trackingWeight==4)design.trackingCutOff=30; (ProtoClusterFactory::Instance())->SetDesign(design); // Form the protoclusters this->MakeProtoClusters(tracks,newClusters); if(newClusters.size()>0)this->associateProtoClusters(newClusters,tracks,finalClusters,false); if(_printing>1)std::cout << " FINAL CLUSTERS : " << finalClusters.size() << std::endl; this->ClusterTrackAssociation(finalClusters,tracks,false); float unassocE = 0.; newchi2 = 0; newchi = 0; float ndof = 0.0; int ccount = 0; result.ntrackmatch=1; for(unsigned int jcluster=0;jclusterEnergyHAD(); if(_printing>1)std::cout << " New Cluster : " << clusterE << std::endl; MyTrackExtendedVec xtracks = finalClusters[jcluster]->GetTrackVec(); if(xtracks.size()>0){ if(xtracks.size()>1)result.ntrackmatch+=xtracks.size()-1; float trackE = 0.; for(unsigned int jtrack=0; jtrackgetEnergy(); float sigE = trackE*_hadEnergyRes/sqrt(trackE); float deltaE = (clusterE-trackE); float chi = deltaE/sigE; if(_printing>1)std::cout << "Tracks : " << xtracks.size() << " CHI : " << trackE << " - " << clusterE << " -> " << chi << std::endl; newchi2 = newchi2 + chi*chi; newchi = newchi + chi; ndof+=1.0; if(xtracks.size()==1){ float sTrackE = xtracks[0]->getEnergy(); float ssigE = sTrackE*_hadEnergyRes/sqrt(sTrackE); float sdeltaE = (clusterE-sTrackE); float schi = sdeltaE/ssigE; if(ccount==0){ result.cluster0 = jcluster; result.chi0 = schi; } if(ccount==1){ result.cluster1 = jcluster; result.chi1 = schi; } } // veto clustering where track is now matched to v. low energy cluster if(clusterE<0.1)newchi2=999.; }else{ unassocE+= clusterE; } } newchi2 = newchi2/ndof; // set things back to default values design.tanConeAngleECAL = _clusterFormationConeTanECAL; design.tanConeAngleHCAL = _clusterFormationConeTanHCAL; design.additionalPadsECAL = _clusterFormationPadsECAL; design.additionalPadsHCAL = _clusterFormationPadsHCAL; design.sameLayerPadCutECAL = _sameLayerPadCutECAL; design.sameLayerPadCutHCAL = _sameLayerPadCutHCAL; design.maximumDistanceForConeAssociationECAL=_maximumDistanceForConeAssociationECAL; design.maximumDistanceForConeAssociationHCAL=_maximumDistanceForConeAssociationHCAL; design.trackingWeight =_trackingWeight; design.trackingCutOff = 0; design.trackingTube = 0.0; (ProtoClusterFactory::Instance())->SetDesign(design); result.chi2 = newchi2; result.chi = newchi; (ProtoClusterFactory::Instance())->ReclusteringOff(); return result; } ProtoCluster* PandoraPFAProcessor::ReclusterForced(ProtoCluster* pCluster, MyTrackExtendedVec& tracks, ProtoClusterVec &finalClusters) { // note no need to deal with delete - factory looks after this ProtoCluster* newCluster = NULL; // try and recluster ! // basically gather up sufficient hits close to track to make up // just enough energy if(tracks.size()>1){ streamlog_out(WARNING) << " PandoraPFAProcessor::ReclusterForced only works for single tracks matched to a cluster" << std::endl; return newCluster; } // get the isolated hits for(int ilayer=1;ilayerisolatedHitsInLayer(ilayer); for(int ihit=0;ihitisolatedHitInLayer(ilayer,ihit); _isolatedCalHitsByPseudoLayer[ilayer].push_back(phit); } } float oldClusterE = pCluster->EnergyHAD(); float trackE = tracks[0]->getEnergy(); float dE = oldClusterE-trackE; float sigE = _hadEnergyRes*sqrt(trackE); float chi2old = (dE/sigE)*(dE/sigE); (ProtoClusterFactory::Instance())->ReclusteringOn(); float clusterE=-999.; float dr = 2500.; bool done=false; int icutmax = 4; for(int icut = 2; icut<=icutmax && !done; icut++){ if(_printing>1)std::cout << " ICUT : " << icut << std::endl; float cut = (float)icut; newCluster = (ProtoClusterFactory::Instance())->Manufacture(tracks[0]); for(int ilayer=pCluster->FirstLayer();ilayer<=pCluster->LastLayer()&&!done;ilayer++){ int nhits = pCluster->hitsInLayer(ilayer); for(int ihit=0;ihithitInLayer(ilayer,ihit); if(newCluster->genericDistanceToTrackSeed(phit, dr)AddHit(phit); } } clusterE = newCluster->EnergyHAD(); float deltaE = clusterE-trackE; float chi2 = (deltaE/sigE)*(deltaE/sigE); if(clusterE>trackE)done=true; if(icut==icutmax&&chi2<_chiToKillTrack*_chiToKillTrack)done=true; } clusterE = newCluster->EnergyHAD(); dE = clusterE-trackE; float chi2 = (dE/sigE)*(dE/sigE); if(_printing>1)std::cout << " SUB-CLUSTER of energy : " << clusterE << " c.f. track : " << trackE << " chi2 = " << chi2 << std::endl; } if(!done){ clusterE = newCluster->EnergyHAD(); dE = clusterE-trackE; float chi2new = (dE/sigE)*(dE/sigE); if(_printing>1)std::cout << " Failed : chi2 " << chi2old << " --> " << chi2new << std::endl; if(chi2old-chi2new>9 && chi2new<36){ if(_printing>1)std::cout << " Signifincant improvement - so recluster " << std::endl; done = true; } } if(done){ // remove hits from old cluster for(int ilayer=newCluster->FirstLayer();ilayer<=newCluster->LastLayer();ilayer++){ int nhits = newCluster->hitsInLayer(ilayer); for(int ihit=0;ihithitInLayer(ilayer,ihit); pCluster->RemoveHit(phit); } } pCluster->Update(pCluster->LastLayer()); newCluster->Update(pCluster->LastLayer()); pCluster->ClassifyYourself(); newCluster->ClassifyYourself(); //add back the isolated hits ProtoClusterVec temp; temp.push_back(pCluster); temp.push_back(newCluster); this->associateIsolatedHits(temp,false); if(_printing>0)std::cout << " ***FORMED NEW SUB-CLUSTER of energy : " << clusterE << " leaving : " << pCluster->EnergyHAD() << std::endl; }else{ newCluster = NULL; } (ProtoClusterFactory::Instance())->ReclusteringOff(); return newCluster; } ProtoCluster* PandoraPFAProcessor::ReclusterForced(ProtoCluster* oldCluster, ProtoCluster* pCluster, MyTrackExtendedVec& tracks, ProtoClusterVec &finalClusters) { // note no need to deal with delete - factory looks after this ProtoCluster* newCluster = NULL; // try and recluster ! // basically gather up sufficient hits close to track to make up // just enough energy if(tracks.size()>1){ streamlog_out(WARNING) << " PandoraPFAProcessor::ReclusterForced only works for single tracks matched to a cluster" << std::endl; return newCluster; } (ProtoClusterFactory::Instance())->ReclusteringOn(); float clusterE=-999.; float trackE = tracks[0]->getEnergy(); float dr = 1000.; bool done=false; bool reclusteringWorked=false; if(_printing>1){ std::cout << " Old Cluster " << oldCluster->EnergyHAD() << std::endl; std::cout << " pCluster " << pCluster->EnergyHAD() << std::endl; } int icutmax = 4; for(int icut = 2; icut<=icutmax && !done; icut++){ if(_printing>2)std::cout << " ICUT : " << icut << std::endl; float cut = (float)icut; newCluster = (ProtoClusterFactory::Instance())->Manufacture(tracks[0]); // newCluster->Assimilate(oldCluster); for(int ilayer=pCluster->FirstLayer();ilayer<=pCluster->LastLayer()&&!done;ilayer++){ int nhits = pCluster->hitsInLayer(ilayer); for(int ihit=0;ihithitInLayer(ilayer,ihit); if(newCluster->genericDistanceToTrackSeed(phit, dr)AddHit(phit); } } clusterE = oldCluster->EnergyHAD()+newCluster->EnergyHAD(); if(clusterE>trackE)done=true; float dE = clusterE-trackE; float sigE = _hadEnergyRes*sqrt(trackE); float chi2 = (dE/sigE)*(dE/sigE); if(icut==icutmax || chi2<_chiToKillTrack*_chiToKillTrack)done=true; if(chi2<_chiToKillTrack*_chiToKillTrack)reclusteringWorked=true; } if(_printing>1)std::cout << " SUB-CLUSTER of energy : " << clusterE << " c.f. track : " << trackE << std::endl; } if(reclusteringWorked){ // remove hits from old cluster for(int ilayer=newCluster->FirstLayer();ilayer<=newCluster->LastLayer();ilayer++){ int nhits = newCluster->hitsInLayer(ilayer); for(int ihit=0;ihithitInLayer(ilayer,ihit); pCluster->RemoveHit(phit); } } newCluster->Assimilate(oldCluster); oldCluster->IsNowDefunct(); pCluster->Update(pCluster->LastLayer()); newCluster->Update(pCluster->LastLayer()); pCluster->ClassifyYourself(); newCluster->ClassifyYourself(); if(_printing>2)std::cout << " ***FORMED NEW SUB-CLUSTER of energy : " << clusterE << " leaving : " << pCluster->EnergyHAD() << std::endl; }else{ newCluster = (ProtoClusterFactory::Instance())->Manufacture(tracks[0]); newCluster->Assimilate(oldCluster); newCluster->Assimilate(pCluster); oldCluster->IsNowDefunct(); pCluster->IsNowDefunct(); newCluster->Update(pCluster->LastLayer()); newCluster->ClassifyYourself(); if(_printing>1)std::cout << " ***FORMED MERGED CLUSTER of energy : " << newCluster->EnergyHAD() << " leaving nothing else " << std::endl; } (ProtoClusterFactory::Instance())->ReclusteringOff(); return newCluster; } void PandoraPFAProcessor::associateBackScatters(ProtoClusterVec &pClusters) { // look for broken hadronic showers due to backscattered track // First look for MIP parent track ending in shower // // PP // PPPP // PPPPPPP // PPPPP // PPPP // P D // P D // P D // P D // // the backscattered MIP is the Daughter for(unsigned int icluster=0;iclusterLastLayer(); int ifirst = daughterCluster->FirstLayer(); float dr=0; if( daughterCluster->IsAttachable() && daughterCluster->Hits()>5 && daughterCluster->getParents()==0 && daughterCluster->getDaughters()==0 && daughterCluster->ClusterRMS()<10.0){ fitResult fiti = daughterCluster->FitLayers(ifirst,ilast-2); if(fiti.ok){ ProtoCluster* bestParent = NULL; float bestApproach = 99999.; for(unsigned int jcluster=0;jclustergetEarliestRelationID()!=daughterCluster->getEarliestRelationID() && parentCluster->getParents()==0){ if(parentCluster->IsAttachable() && daughterCluster->LastLayer() < parentCluster->LastLayer()&& daughterCluster->LastLayer() > parentCluster->FirstLayer() ){ int jfirst = daughterCluster->LastLayer()-2; int jlast = daughterCluster->LastLayer()+2; float closestApproach = parentCluster->DistanceToClosestHit(fiti,jfirst,jlast); if(closestApproach<_trackBackMergeCut){ dr = this->protoClusterDr(parentCluster,daughterCluster); if(dr<100 && closestApproachFitLayers(ifirst,ifirst-8); float genericDistance = bestParent->genericDistance(daughterCluster); if(_printing>2){ std::cout << "____________________________________" << std::endl; std::cout << daughterCluster->getParents() << "," << daughterCluster->getDaughters() << "," << bestParent->getParents() << "," << bestParent->getDaughters() << std::endl; std::cout << " BACK-SCATTER p " << bestParent->GetCentroid(bestParent->FirstLayer())[0] << "," << bestParent->GetCentroid(bestParent->FirstLayer())[1] << std::endl; std::cout << " BACK-SCATTER d " << daughterCluster->GetCentroid(daughterCluster->FirstLayer())[0] << "," << daughterCluster->GetCentroid(daughterCluster->FirstLayer())[1] << std::endl; std::cout << " DAUGHTER APPROACH " << bestApproach << std::endl; std::cout << " associateBackScatter " << dr << std::endl; std::cout << " CHECKING " << fiti.dirDotR << " " << daughterCluster->ClusterRMS() << " ok = " << fiti.ok << std::endl; std::cout << " daugther mip chi2 " << mipfit.chi2 << std::endl; std::cout << " daugther d:s:l " << daughterCluster->FirstLayer() << ":" << daughterCluster->ShowerLayer() << ":" << daughterCluster->LastLayer() << std::endl; std::cout << " GENERIC DISTANCE " << genericDistance << std::endl; } daughterCluster->AddParent(bestParent); bestParent->AddDaughter(daughterCluster); } } } } // look for broken hadronic showers due to backscattered track // now look for MIP parent track ending in shower // // PP // PPPP // PPPPPPP // PPPPP // PPPP // P // P // PD // P DDDD // P DDDDDD // P DDD // P // the backscattered particle is the Daughter of parent MIP section for(unsigned int icluster=0;iclusterFirstLayer(); int ishower = parentCluster->ShowerLayer(); fitResult fiti = parentCluster->FitLayers(ifirst,ishower); if(parentCluster->IsAttachable() && parentCluster->getParents()==0 &&parentCluster->Hits()>5){ for(unsigned int jcluster=0;jclustergetParents()==0)&&(daughterCluster->getDaughters()==0)&& (parentCluster->getEarliestRelationID()!=daughterCluster->getEarliestRelationID())){ if(daughterCluster->IsAttachable() && daughterCluster->LastLayer() < parentCluster->ShowerLayer()&& daughterCluster->LastLayer() > parentCluster->FirstLayer() ){ int jfirst = daughterCluster->LastLayer(); int jlast = daughterCluster->LastLayer()-2; float closestApproach = parentCluster->DistanceToClosestHit(fiti,jfirst,jlast); if(fiti.ok&&closestApproach<_trackBackMergeCut){ if(_printing>2)std::cout << " PARENT APPROACH* " << closestApproach << std::endl; float dr = this->protoClusterDr(parentCluster,daughterCluster); if(_printing>2){ std::cout << "associateBackScatter* " << dr << std::endl; std::cout << " CHECKING " << fiti.dirDotR << " " << fiti.rms << " ok = " << fiti.ok << std::endl; } if(dr<1000 && fiti.rms<15.0){ fitResult mipfit = daughterCluster->FitLayers(ifirst,ifirst-8); if(_printing>2){ std::cout << " daugther mip chi2 " << mipfit.chi2 << std::endl; std::cout << " daugther d:s:l " << daughterCluster->FirstLayer() << ":" << daughterCluster->ShowerLayer() << ":" << daughterCluster->LastLayer() << std::endl; } float genericDistance = parentCluster->genericDistance(daughterCluster); if(_printing>2)std::cout << " GENERIC DISTANCE " << genericDistance << std::endl; daughterCluster->AddParent(parentCluster); parentCluster->AddDaughter(daughterCluster); } } } } } } } } void PandoraPFAProcessor::associateMipStubsToShowers(ProtoClusterVec &pClusters) { // look for broken hadronic showers due to backscattered track // First look for MIP daughter pointing back to shower bool debuggingThisCode = false; for(unsigned int icluster=0;iclusterIsAttachable() && daughterCluster->Hits()>5 && daughterCluster->getParents()==0){ fitResult fiti = daughterCluster->FitStart(10); // the daughter cluster must look MIP like, i.e. be reasonably consistent // with a straight line fit if(fiti.ok==true && fiti.chi2<10.){ ProtoCluster* bestCandidateParentCluster = NULL; float closestApproach = 99999.; for(unsigned int jcluster=0;jclustergetEarliestRelationID()!=daughterCluster->getEarliestRelationID()){ if(parentCluster->Hits()>2 && daughterCluster->FirstLayer() >= parentCluster->LastLayer()){ int jfirst = parentCluster->LastLayer()-4; int jlast = parentCluster->LastLayer(); float approach = parentCluster->DistanceToClosestHit(fiti,jfirst,jlast); float distance = parentCluster->DistanceToClosestHit(daughterCluster); if(distance<250 && approach < closestApproach){ closestApproach = approach; bestCandidateParentCluster = parentCluster; if(approach<100&&_printing>2){ std::cout << "MB : " << daughterCluster->GetCentroid(daughterCluster->FirstLayer())[0] << "," << daughterCluster->GetCentroid(daughterCluster->FirstLayer())[1] << std::endl; std::cout << daughterCluster->FirstLayer() <<":" <ShowerLayer() << std::endl; std::cout << " DISTANCE : " << distance << std::endl; } } } } } if(closestApproach<100&&_printing>2)std::cout << " MIP BACK : " << closestApproach << std::endl; if(closestApproach<_trackBackMergeCut){ if(_printing>2)std::cout << "CHI2 " << fiti.chi2 << std::endl; if(debuggingThisCode && _recoDisplay!=NULL){ ProtoClusterVec temp; temp.push_back(daughterCluster); temp.push_back(bestCandidateParentCluster); _recoDisplay->DrawByProtoCluster(temp,3); } daughterCluster->AddParent(bestCandidateParentCluster); bestCandidateParentCluster->AddDaughter(daughterCluster); } } } } return; } void PandoraPFAProcessor::associateFromStart(ProtoClusterVec &pClusters) { // DD // D D D // DDDDDDDDDDD //DDDDDDDDD | D // | D // | D // PPPPP D // PP|PP // P|P // | // | for(unsigned int icluster=0;iclusterIsAttachable() && daughterCluster->Hits()>5 && daughterCluster->getParents()==0){ ProtoCluster* bestCandidateParentCluster = NULL; float closestApproach = 99999.; for(unsigned int jcluster=0;jclustergetEarliestRelationID()!=daughterCluster->getEarliestRelationID()){ if(parentCluster->Hits()>10 && daughterCluster->FirstLayer() > parentCluster->LastLayer()-5){ float approach = daughterCluster->DistanceFromInitialProjection(parentCluster); if(approach < closestApproach){ closestApproach = approach; bestCandidateParentCluster = parentCluster; } } } } if(closestApproach<_trackForwardMergeCut){ float prox = this->protoClusterDr(bestCandidateParentCluster,daughterCluster); if(_printing>2 && prox < 500){ ProtoCluster* p1 = bestCandidateParentCluster; ProtoCluster* p2 = daughterCluster; std::cout << " FORWARD PROJECTION : " << closestApproach << std::endl; std::cout << p1->GetCentroid(p1->FirstLayer())[0] << "," << p1->GetCentroid(p1->FirstLayer())[1] << "," << p1->GetCentroid(p1->FirstLayer())[2] << std::endl; std::cout << p2->GetCentroid(p2->FirstLayer())[0] << "," << p2->GetCentroid(p2->FirstLayer())[1] << "," << p2->GetCentroid(p2->FirstLayer())[2] << std::endl; } if(prox<500){ daughterCluster->AddParent(bestCandidateParentCluster); bestCandidateParentCluster->AddDaughter(daughterCluster); } } } } return; } void PandoraPFAProcessor::associateShowersToMips(ProtoClusterVec &pClusters) { // look for broken hadronic showers due to backscattered track // First look for MIP daughter pointing back to shower bool debuggingThisCode = false; for(unsigned int icluster=0;iclusterIsAttachable() && parentCluster->Hits()>5 && parentCluster->ClusterRMS()<10.){ fitResult fiti = parentCluster->FitEnd(10); if(fiti.ok){ for(unsigned int jcluster=0;jclustergetEarliestRelationID()!=daughterCluster->getEarliestRelationID()){ if(daughterCluster->IsAttachable() && daughterCluster->Hits()>5 && daughterCluster->FirstLayer() >= parentCluster->FirstLayer()){ int ifirst = daughterCluster->FirstLayer(); int jfirst = parentCluster->LastLayer(); int jlast = parentCluster->LastLayer()+5; float dr=0; for(int i=0;i<3;i++){ float di = (parentCluster->GetCentroid(jfirst)[i]-daughterCluster->GetCentroid(ifirst)[i]); dr += di*di; } dr = sqrt(dr); float approach = daughterCluster->DistanceToClosestHit(fiti,jfirst,jlast); if(approach<100 && dr < 1000){ if(_printing>2||debuggingThisCode){ std::cout << " MIP FORWARD : " << approach << " Photon ? " << parentCluster->IsPrimaryPhoton() << " " << parentCluster->EnergyEM() << " " << parentCluster->MipFraction() << " " << parentCluster->ClusterRMS() << std::endl; std::cout << parentCluster->GetCentroid(jfirst)[0] << "," << parentCluster->GetCentroid(jfirst)[1] << "," << parentCluster->GetCentroid(jfirst)[2] << "," << std::endl; } ProtoCluster* rD = daughterCluster->getEarliestRelation(); float cap = daughterCluster->DistanceToClosestCentroid(fiti,jfirst,jlast); if(rD!=NULL){ int kfirst = rD->FirstLayer(); if(debuggingThisCode||_printing>2)std::cout << " rD " << rD->GetCentroid(kfirst)[0] << "," << rD->GetCentroid(kfirst)[1] << "," << rD->GetCentroid(kfirst)[2] << "," << std::endl; } int crossed = this->ExpectedLayersCrossed( pClusters[icluster]->GetCentroid(pClusters[icluster]->LastLayer()),pClusters[jcluster]->GetCentroid( pClusters[jcluster]->FirstLayer())); if(debuggingThisCode || _printing>2){ std::cout << "CENTROID : " <MipFraction()>0.5 && parentCluster->ClusterRMS() < 10.0 ){ if(debuggingThisCode && _recoDisplay!=NULL){ ProtoClusterVec temp; temp.push_back(daughterCluster); temp.push_back(parentCluster); _recoDisplay->DrawByProtoCluster(temp,3); } daughterCluster->AddParent(parentCluster); parentCluster->AddDaughter(daughterCluster); } } } } } } } } return; } void PandoraPFAProcessor::associateShowersToMipsII(ProtoClusterVec &pClusters) { // look for broken tracks // *** ****** // ** ** // * // * // ** **** // * // // // o // o // o vectorendFitResults; float cut1; float cut2; bool debuggingThisCode =false; // fit ends of all ProtoClusters up front - save time for(unsigned int icluster=0;iclusterFitEnd(8); endFitResults.push_back(fitE); } for(unsigned int icluster=0;iclusterIsAttachable() && fiti.chi2<5. ){ int fli = pClusters[icluster]->LastLayer(); for(unsigned int jcluster=0;jclusterIsAttachable()){ int flj = pClusters[jcluster]->FirstLayer(); if(flj>fli){ int crossed = this->ExpectedLayersCrossed(pClusters[icluster]->GetCentroid(fli),pClusters[jcluster]->GetCentroid(flj)); float dx = pClusters[icluster]->GetCentroid(fli)[0]-pClusters[jcluster]->GetCentroid(flj)[0]; float dy = pClusters[icluster]->GetCentroid(fli)[1]-pClusters[jcluster]->GetCentroid(flj)[1]; float dz = pClusters[icluster]->GetCentroid(fli)[2]-pClusters[jcluster]->GetCentroid(flj)[2]; float dr = sqrt(dx*dx+dy*dy+dz*dz); // loose preselection to save time // require ends to be within 2.0m and tracks to point within 60 degrees if(dr<2000){ // find distance of closest approach for track fits float dr1 = (dx*fiti.dir[0]+ dy*fiti.dir[1]+ dz*fiti.dir[2])/dr; float ddx = fiti.dir[1]*dz - fiti.dir[2]*dy; float ddy = fiti.dir[2]*dx - fiti.dir[0]*dz; float ddz = fiti.dir[0]*dy - fiti.dir[1]*dx; float distSq = ddx*ddx + ddy*ddy+ ddz*ddz; float dPerp1 = sqrt(distSq); if(flj<=_nEcalLayers){ cut1 = _trackMergeCutEcal; cut2 = _trackMergePerpCutEcal; }else{ cut1 = _trackMergeCutHcal; cut2 = _trackMergePerpCutHcal; } if(dPerp12||debuggingThisCode){ std::cout << " MERGING CLUSTERS " << std::endl; std::cout << " ProtoClusters : " << icluster << ":" << jcluster << std::endl; std::cout << " dot/cross 1 : " << dr1 << "," << dPerp1 << std::endl; std::cout << " End Layers : " << fli << "," << flj << std::endl; std::cout << " Crossed : " << crossed << std::endl; std::cout << " rms : " << fiti.rms << std::endl; std::cout << " chi2 : " << fiti.chi2 << std::endl; std::cout << " xy1 : " << pClusters[icluster]->GetCentroid(fli)[0] << "," << pClusters[icluster]->GetCentroid(fli)[1] << std::endl; std::cout << " xy2 : " << pClusters[jcluster]->GetCentroid(flj)[0] << "," << pClusters[jcluster]->GetCentroid(flj)[1] << std::endl; std::cout << " dr : " << dr << std::endl; } // require not to many missing clusters and if(debuggingThisCode && _recoDisplay!=NULL){ ProtoClusterVec temp; temp.push_back(pClusters[icluster]); temp.push_back(pClusters[jcluster]); _recoDisplay->DrawByProtoCluster(temp,1); } pClusters[jcluster]->AddParent(pClusters[icluster]); pClusters[icluster]->AddDaughter(pClusters[jcluster]); } } } } } } } } } void PandoraPFAProcessor::associateByProximity(ProtoClusterVec &pClusters) { // look for broken hadronic clusters by simple proximity // applied late in reconstruction // // P DDDDD // PPPP DD // PPP // P // P // P // P //fg: - if pClusters.size() == 0 the loop code will crash ( as unsigned(-1) == 4294967295 > 0 ) if( pClusters.size() < 1 ) { streamlog_out(WARNING) << " associateByProximity : no clusters - return " << std::endl ; return ; } //associate tracks to clusters this->ClusterTrackAssociation(pClusters,_tracksAR); for(unsigned int icluster=pClusters.size()-1;icluster>0;--icluster){ ProtoCluster* pCd = pClusters[icluster]; if(pCd->IsAttachable() && pCd->IsDefunct()==false && !pCd->AssociatedTrack()){ float closest = 999.; float bestchi =0; float bestchi0 =0; float bestTrackE = 0.; ProtoCluster* bestParent = NULL; for(unsigned int jcluster=0;jclusterIsAttachable()&&pCp->IsDefunct()==false ){ float genericDistance = 999.; int span1 = pCp->LastLayer()-pCd->FirstLayer(); int span2 = pCd->LastLayer()-pCp->FirstLayer(); //check for some near overlap int minspan = min(span1,span2); int dshower = pCd->FirstLayer() - pCp->ShowerLayer(); MyTrackExtendedVec pTracks = pCp->GetTrackVec(); MyTrackExtendedVec dTracks = pCd->GetTrackVec(); float trackE = 0; for(unsigned int i=0; igetEnergy(); for(unsigned int i=0; igetEnergy(); float clusterE = pCp->EnergyHAD()+ pCd->EnergyHAD(); float chi = 0.; float chi0 = 0.; if(trackE>0.){ float sigE = trackE*_hadEnergyRes/sqrt(trackE); float deltaE = (clusterE-trackE); float deltaE0 = (pCp->EnergyHAD()-trackE); chi = deltaE/sigE; chi0 = deltaE0/sigE; } float dchi2 = chi*chi-chi0*chi0; if( (minspan>-3 && dshower>-5) && dchi2<_energyDeltaChi2ForCrudeMerging && chi<_energyChiForCrudeMerging){ if(pCp->FirstLayer()>5||pCd->FirstLayer()>5){ int is = pCd->FirstLayer(); int ie = is+5; genericDistance = pCp->genericDistance(pCd,is,ie); if(genericDistanceprotoClusterDrF(bestParent,pCd); if(prox<500.){ float clusterE = pCd->EnergyHAD()+bestParent->EnergyHAD(); MyTrackExtendedVec pTracks = bestParent->GetTrackVec(); MyTrackExtendedVec dTracks = pCd->GetTrackVec(); fragmentContact_t contact = this->CalculateFragmentContactInfo(bestParent,pCd); if(_printing>2&&pCd->EnergyHAD()>0.5 && (dTracks.size()>0||pTracks.size()>0)){ std::cout << "----Proximity---- ****************************************************************************************************************" << std::endl; int is = pCd->FirstLayer(); std::cout << "p : " << pCd->GetCentroid(is)[0] << "," << pCd->GetCentroid(is)[1] << std::endl; std::cout << " clos/prox " << closest << " " << prox << std::endl; std::cout << " dcos : " << pCd->DCosR() << std::endl; std::cout << " PARENT Energy : " << bestParent->EnergyHAD()<< std::endl; std::cout << " DAUGHTER Energy : " << pCd->EnergyHAD() << std::endl; std::cout << " Track Energy : " << bestTrackE << std::endl; std::cout << " **CHI2 : " << bestchi0 << "->" << bestchi << std::endl; std::cout << " Contact.... " << " cluster = " << contact.icluster << std::endl; std::cout << " Track - Cluster - chi : " << contact.trackEnergy << " " << contact.clusterEnergy << " " << contact.chi << std::endl; std::cout << " Contact Layers/Fraction: " << contact.contactLayers << " " << contact.contactFraction << std::endl; std::cout << " TrackHelix distance/av : " << contact.trackHelixExtrapolationDistance << " " << contact.trackHelixExtrapolationAverage << std::endl; std::cout << " Cone fraction : " << contact.coneFraction25 << " " << contact.coneFraction18 << " " << contact.coneFraction10 << std::endl; std::cout << " closest / fraction : " << contact.minimumDistance << " " << contact.clusterFractionWithin100 << " " << contact.clusterFractionWithin50 << std::endl; } float trackE = 0.; bool canAssoc = false; if(pTracks.size()==0 && dTracks.size()==0)canAssoc= true; if(pTracks.size()>0 && dTracks.size()==0){ canAssoc = true; for(unsigned int i=0; igetEnergy(); for(unsigned int i=0; igetEnergy(); float sigE = trackE*_hadEnergyRes/sqrt(trackE); float deltaE = (clusterE-trackE); float chi = deltaE/sigE; if(chi>3.5){ canAssoc = false; if(_printing>2){ std::cout << "******PROX: " << trackE << " -> " << clusterE << std::endl; std::cout << "******PROX : " << deltaE << " -> " << sigE << " chi = " << chi << std::endl; } } } if(canAssoc){ bool ok = false; // require one piece of further evidence that this is a good associate if(contact.contactFraction>0.3)ok = true; if(contact.trackHelixExtrapolationAverage<50)ok = true; if(contact.clusterFractionWithin50>0.2)ok = true; if(ok){ bestParent->Assimilate(pCd); pCd->IsNowDefunct(); } } } } } } } void PandoraPFAProcessor::removeAssociatedHits() { // std::cout << "in removeAssociatedHits" << _hitsForRemoval.size() << std::endl; if(_hitsForRemoval.size()==0)return; for(unsigned int ihit=0;ihit<_hitsForRemoval.size();++ihit){ MyCaloHitExtended* hiti = _hitsForRemoval[ihit]; int ilayer = hiti->getPseudoLayer(); if(_calHitsByPseudoLayer[ilayer].size()==0)streamlog_out(ERROR) << "PandoraPFA::removeAssociatedHits - no hits in this layer" << std::endl; vector ::iterator literHit; literHit = _calHitsByPseudoLayer[ilayer].begin(); bool notFound = true; while(notFound && literHit != _calHitsByPseudoLayer[ilayer].end()){ if(*literHit==hiti){ notFound = false; _calHitsByPseudoLayer[ilayer].erase(literHit); } literHit++; } if(notFound)streamlog_out(ERROR) << "PandoraPFA::removeAssociatedHits - hit not found" << std::endl; } // clear list of hits to be removed _hitsForRemoval.clear(); } void PandoraPFAProcessor::removeTmpAssociatedHits() { // std::cout << "in removeAssociatedHits" << _hitsForRemoval.size() << std::endl; if(_hitsForRemoval.size()==0)return; for(unsigned int ihit=0;ihit<_hitsForRemoval.size();++ihit){ MyCaloHitExtended* hiti = _hitsForRemoval[ihit]; int ilayer = hiti->getPseudoLayer(); if(_tmpCalHitsByPseudoLayer[ilayer].size()==0)streamlog_out(ERROR) << "PandoraPFA::removeAssociatedHits - no hits in this layer" << std::endl; vector ::iterator literHit; literHit = _tmpCalHitsByPseudoLayer[ilayer].begin(); bool notFound = true; while(notFound && literHit != _tmpCalHitsByPseudoLayer[ilayer].end()){ if(*literHit==hiti){ notFound = false; _tmpCalHitsByPseudoLayer[ilayer].erase(literHit); } literHit++; } if(notFound)streamlog_out(ERROR) << "PandoraPFA::removeTmpAssociatedHits - hit not found" << std::endl; } // clear list of hits to be removed _hitsForRemoval.clear(); } void PandoraPFAProcessor::MakeDensityWeights( ) { // calculate density weighting float rCrossDr[3]; float dr[3]; for(int ilayer=0;ilayer<=(int)_maxLayer;++ilayer){ int jLayerLow = ilayer - _layersForDensityWeighting; int jLayerHigh = ilayer + _layersForDensityWeighting; if(jLayerHigh>=MAX_NUMBER_OF_LAYERS)jLayerHigh=MAX_NUMBER_OF_LAYERS-1; if(jLayerLow<0)jLayerLow=0; for(unsigned int ihit=0;ihit<_allCalHitsByPseudoLayer[ilayer].size();++ihit){ MyCaloHitExtended* hiti = _allCalHitsByPseudoLayer[ilayer][ihit]; float weight = 0; int mipCount = 0; float localWeight = 0; const float* posi = hiti->getPosition(); float ri2 = posi[0]*posi[0]+posi[1]*posi[1]+posi[2]*posi[2]; for(int jlayer = jLayerLow;jlayer<=jLayerHigh;++jlayer){ for(unsigned int jhit=0;jhit<_allCalHitsByPseudoLayer[jlayer].size();++jhit){ MyCaloHitExtended* hitj = _allCalHitsByPseudoLayer[jlayer][jhit]; // skip case when two hits are the same if(hiti!=hitj){ const float* posj = hitj->getPosition(); dr[0] = posj[0]-posi[0]; dr[1] = posj[1]-posi[1]; dr[2] = posj[2]-posi[2]; float dr2 = dr[0]*dr[0]+dr[1]*dr[1]+dr[2]*dr[2]; rCrossDr[0] = posi[1]*dr[2]-posi[2]*dr[1]; rCrossDr[1] = posi[2]*dr[0]-posi[0]*dr[2]; rCrossDr[2] = posi[0]*dr[1]-posi[1]*dr[0]; float deltaR2 = rCrossDr[0]*rCrossDr[0]+rCrossDr[1]*rCrossDr[1]+rCrossDr[2]*rCrossDr[2]; float deltaR2proj = 0.01*deltaR2/ri2; if(dr2<10000){ if(jlayer==ilayer){ if(fabs(posi[2])<_zOfEndcap){ // Barrel float dz = dr[2]; float dphi = sqrt(dr[0]*dr[0]+dr[1]*dr[1]); float padZ = hiti->getHitSizeZ(); float padPhi = hiti->getHitSizePhi(); if(( fabs(dz)<(_mipCells+0.5)*padZ)&&(fabs(dphi)<(_mipCells+0.5)*padPhi))mipCount++; if(( fabs(dz)<1.5*padZ)&&(fabs(dphi)<1.5*padPhi))hiti->addSurroundingEnergy(hitj->getEnergyHAD()); }else{ float dx = fabs(dr[0]); float dy = fabs(dr[1]); float padZ = hiti->getHitSizeZ(); float padPhi = hiti->getHitSizePhi(); if(( fabs(dx)<(_mipCells+0.5)*padZ)&&(fabs(dy)<(_mipCells+0.5)*padPhi))mipCount++; if( (fabs(dx)<1.5*padZ) && (fabs(dy)<1.5*padPhi) )hiti->addSurroundingEnergy(hitj->getEnergyHAD()); } } if(_densityWeightingPower==2){ if(jlayer==ilayer)localWeight+= 1./deltaR2proj; weight += 1./deltaR2proj; }else{ float r = sqrt(deltaR2proj); float rN = 1.; for(int i=0;i<_densityWeightingPower;i++)rN=rN*r; weight += 1./rN; if(jlayer==ilayer)localWeight+= 1./rN; } } } // end of skip if } // end of for-loop over other hits } // end of for-loop over layer of other hits hiti->setDensityWeight(weight); hiti->setLocalDensityWeight(localWeight); bool miplike = (hiti->isCandidateMip() && (mipCount<=_mipMaxCellsHit)); hiti->setMipCandidateFlag(miplike); if(_typeOfOrdering==1)hiti->setGenericDistance(localWeight); if(_typeOfOrdering==2)hiti->setGenericDistance(weight); } // end of for-loop over layer of target hit } // end of for-loop over layer of target pLayer return; } void PandoraPFAProcessor::stripIsolatedHits( ) { // Start with _allCalHitsByPseudoLayer[psLayer] collection // strip out isolated hits to get new collections // _calHitsByPseudoLayer[psLayer] // _isolatedCalHitsByPseudoLayer[psLayer] float dr[3]; float rCrossDr[3]; float cutDistance=0; float cutDistance2=0; int ilow=0; int ihigh=0; switch(_isolationType){ case 0: // NO ISOLATION CUTS for(int ilayer=0;ilayergetDensityWeight(); float cut=0; if(hiti->getCalorimeterHitType()==CALHITTYPE_HCAL)cut = _densityWeightCutHCAL; if(hiti->getCalorimeterHitType()==CALHITTYPE_ECAL)cut = _densityWeightCutECAL; if(w >cut){ _calHitsByPseudoLayer[ilayer].push_back(hiti); }else{ hiti->setIsolatedHitFlag(true); _isolatedCalHitsByPseudoLayer[ilayer].push_back(hiti); } } } break; case 2: // ************************** Muliplicity cuts ****************** for(int ilayer=0;ilayergetCalorimeterHitType()==CALHITTYPE_ECAL){ ilow = ilayer-_layersForIsolationECAL; ihigh = ilayer+_layersForIsolationECAL; cutDistance = _distanceForIsolationECAL; } if(hiti->getCalorimeterHitType()==CALHITTYPE_HCAL){ ilow = ilayer-_layersForIsolationHCAL; ihigh = ilayer+_layersForIsolationHCAL; cutDistance = _distanceForIsolationHCAL; } cutDistance2 = cutDistance*cutDistance; if(ilow<0)ilow=0; if(ihigh>= MAX_NUMBER_OF_LAYERS)ihigh= MAX_NUMBER_OF_LAYERS-1; const float* posi =hiti->getPosition(); float xi = posi[0]; float yi = posi[1]; float zi = posi[2]; float ri2 = xi*xi+yi*yi+zi*zi; bool found = false; int nfound = 0; for(int jlayer=ilow;!found && jlayer<=ihigh;jlayer++){ for(unsigned int jhit= 0; !found && jhit<_allCalHitsByPseudoLayer[jlayer].size();jhit++){ MyCaloHitExtended* hitj = _allCalHitsByPseudoLayer[jlayer][jhit]; const float* posj =hitj->getPosition(); dr[0] = posj[0]-posi[0]; dr[1] = posj[1]-posi[1]; dr[2] = posj[2]-posi[2]; float dr2 = dr[0]*dr[0]+dr[1]*dr[1]+dr[2]*dr[2]; rCrossDr[0] = posi[1]*dr[2]-posi[2]*dr[1]; rCrossDr[1] = posi[2]*dr[0]-posi[0]*dr[2]; rCrossDr[2] = posi[0]*dr[1]-posi[1]*dr[0]; float deltaR2 = rCrossDr[0]*rCrossDr[0]+rCrossDr[1]*rCrossDr[1]+rCrossDr[2]*rCrossDr[2]; float deltaR2proj = deltaR2/ri2; if(deltaR2proj=_nSmallestClusterSizeForIsolation)found = true; } } } if(found)_calHitsByPseudoLayer[ilayer].push_back(hiti); if(!found){ hiti->setIsolatedHitFlag(true); _isolatedCalHitsByPseudoLayer[ilayer].push_back(hiti); } } } break; default: break; } float etot = 0.; for(int ilayer=0;ilayergetEnergyHAD(); } } fETot->Fill(etot,1.); float etotN = 0.; for(int ilayer=0;ilayergetEnergyHAD(); } } fETotN->Fill(etotN,1.); float etotI = 0.; for(int ilayer=0;ilayergetEnergyHAD(); } } fETotI->Fill(etotI,1.); } void PandoraPFAProcessor::hitEnergyCorrections( ) { for(int ilayer=0;ilayergetCalorimeterHitType()==CALHITTYPE_ECAL){ } if(hiti->getCalorimeterHitType()==CALHITTYPE_HCAL){ float energyHAD = hiti->getEnergyHAD(); // Suppress high energy HCAL hits if(energyHAD>_maxHcalHitEnergy){ float es = hiti->getSurroundingEnergy(); float ratio = es/energyHAD; if(ratio<_maximumRatioToCutHcalHit){ energyHAD = _maxHcalHitEnergy; std::cout << " Veto high E HCAL hit " << energyHAD << " se = " << hiti->getSurroundingEnergy() << " ratio = " << ratio << std::endl; } } // Apply correction to account for leakage if(_leakageCorrection==2){ int layersFromEdge = this->LayersFromEdge(hiti); if(layersFromEdge<_leavingHitLayersFromEdge){ energyHAD = energyHAD*_leavingHitWeightingFactor; } } hiti->setEnergyHAD(energyHAD); } } } } void PandoraPFAProcessor::CylinderAssignToPseudoLayer( MyCaloHitExtended* pHit ) { const float* pos =pHit->getPosition(); float radius= pos[0]*pos[0] + pos[1]*pos[1]; radius = sqrt(radius); float zhit = fabs(pos[2]); CalorimeterHitZone zone = CALHITZONE_UNKNOWN; if(radius<_positionBarrelLayer[0])zone = CALHITZONE_ENDCAP; if(zhit<_positionEndcapLayer[0])zone = CALHITZONE_BARREL; if(zone==CALHITZONE_UNKNOWN)zone = CALHITZONE_OVERLAP; int bestLayer=0; int bestBarrelLayer=0; float barrelLayerDist = 9999.; int bestEndcapLayer=0; float endcapLayerDist = 9999.; switch(zone){ case CALHITZONE_BARREL: // use barrel layer for(int ilayer = 0; ilayer <= _nPseudoLayers; ++ilayer){ if(fabs(radius-_positionBarrelLayer[ilayer])setPseudoLayer(bestBarrelLayer); break; case CALHITZONE_ENDCAP: // use end layer for(int ilayer = 0; ilayer <= _nPseudoLayers; ++ilayer){ if(fabs(zhit-_positionEndcapLayer[ilayer])setPseudoLayer(bestEndcapLayer); break; case CALHITZONE_OVERLAP: // check to see whether the equivalent barrel or endcap layer is furthest out for(int ilayer = 0; ilayer <= _nPseudoLayers; ++ilayer){ if(fabs(radius-_positionBarrelLayer[ilayer])bestEndcapLayer)bestLayer =bestBarrelLayer; pHit->setPseudoLayer(bestLayer); break; default: break; } } void PandoraPFAProcessor::ProtoAssignToPseudoLayer( MyCaloHitExtended* pHit ) { std::cout << " PandoraPFAProcessor::ProtoAssignToPseudoLayer NOT YET IMPLEMENTED" << std::endl; } void PandoraPFAProcessor::PolygonAssignToPseudoLayer( MyCaloHitExtended* pHit ) { // assign a hit to a Pseudolayer // a Pseudo layer is a polyhedral surface which accounts for the depth in the // detector in the barrel/endcap overlap region const float* pos =pHit->getPosition(); CalorimeterHitZone zone = CALHITZONE_UNKNOWN; float prodRadiusMax=0.; for(int istave = 0; istave < _symmetry; ++istave){ float prodRadius = pos[0]*_barrelStaveDir[istave].x+pos[1]*_barrelStaveDir[istave].y; if(prodRadius>prodRadiusMax)prodRadiusMax=prodRadius; } float zhit = fabs(pos[2]); if(prodRadiusMax<_positionBarrelLayer[0])zone = CALHITZONE_ENDCAP; if(zhit<_positionEndcapLayer[0])zone = CALHITZONE_BARREL; if(zone==CALHITZONE_UNKNOWN)zone = CALHITZONE_OVERLAP; int bestLayer=0; int bestBarrelLayer=0; float barrelLayerDist = 9999.; int bestEndcapLayer=0; float endcapLayerDist = 9999.; switch(zone){ case CALHITZONE_BARREL: // use barrel layer for(int ilayer = 0; ilayer <= _nPseudoLayers; ++ilayer){ if(fabs(prodRadiusMax-_positionBarrelLayer[ilayer])setPseudoLayer(bestBarrelLayer); if(_printing>8)std::cout << " BARREL " << pHit->getCalorimeterHitType() << " : " << pHit->getPhysicalLayer() << " " << prodRadiusMax << "(" << sqrt(pos[0]*pos[0]+pos[1]*pos[1]) << ") " << pos[0] << "," << pos[1] << "," << pos[2] << " -->" << bestBarrelLayer << " " << barrelLayerDist << std::endl; break; case CALHITZONE_ENDCAP: // use end layer for(int ilayer = 0; ilayer <= _nPseudoLayers; ++ilayer){ if(fabs(zhit-_positionEndcapLayer[ilayer])10)std::cout << " ENDCAP : " << pHit->getCalorimeterHitType() << " " << pHit->getPhysicalLayer() << " " << zhit << "-->" << bestEndcapLayer << " " << endcapLayerDist << std::endl; pHit->setPseudoLayer(bestEndcapLayer); break; case CALHITZONE_OVERLAP: // check to see whether the equivalent barrel or endcap layer is furthest out for(int ilayer = 0; ilayer <= _nPseudoLayers; ++ilayer){ if(fabs(prodRadiusMax-_overlapCorrection-_positionBarrelLayer[ilayer])bestEndcapLayer)bestLayer =bestBarrelLayer; pHit->setPseudoLayer(bestLayer); if(_printing>10){ if(bestBarrelLayer>bestEndcapLayer){ std::cout << " UNKNOWN B " << pHit->getCalorimeterHitType() << " : " << pHit->getPhysicalLayer() << " " << prodRadiusMax << "(" << sqrt(pos[0]*pos[0]+pos[1]*pos[1]) << ") " << pos[0] << "," << pos[1] << "," << pos[2] << " -->" << bestBarrelLayer << " " << barrelLayerDist << " : " << bestEndcapLayer << " " << endcapLayerDist << std::endl; }else{ std::cout << " UNKNOWN E " << pHit->getCalorimeterHitType() << " : " << pHit->getPhysicalLayer() << " " << prodRadiusMax << "(" << sqrt(pos[0]*pos[0]+pos[1]*pos[1]) << ") " << pos[0] << "," << pos[1] << "," << pos[2] << " -->" << bestBarrelLayer << " " << barrelLayerDist << " : " << bestEndcapLayer << " " << endcapLayerDist << std::endl; } } break; default: streamlog_out(ERROR) << " PolygonAssignToPseudoLayer : SHOULD NOT GET HERE " << std::endl; break; } } int PandoraPFAProcessor::GetPseudoLayer( float* pos ) { // assign a hit to a Pseudolayer // a Pseudo layer is a polyhedral surface which accounts for the depth in the // detector in the barrel/endcap overlap region int iplayer = -999; CalorimeterHitZone zone = CALHITZONE_UNKNOWN; float prodRadiusMax=0.; for(int istave = 0; istave < _symmetry; ++istave){ float prodRadius = pos[0]*_barrelStaveDir[istave].x+pos[1]*_barrelStaveDir[istave].y; if(prodRadius>prodRadiusMax)prodRadiusMax=prodRadius; } float zhit = fabs(pos[2]); if(prodRadiusMax<_positionBarrelLayer[0])zone = CALHITZONE_ENDCAP; if(zhit<_positionEndcapLayer[0])zone = CALHITZONE_BARREL; if(zone==CALHITZONE_UNKNOWN)zone = CALHITZONE_OVERLAP; int bestBarrelLayer=0; float barrelLayerDist = 9999.; int bestEndcapLayer=0; float endcapLayerDist = 9999.; switch(zone){ case CALHITZONE_BARREL: // use barrel layer for(int ilayer = 0; ilayer <= _nPseudoLayers; ++ilayer){ if(fabs(prodRadiusMax-_positionBarrelLayer[ilayer])getPhysicalLayer() << " " << prodRadiusMax << "-->" << bestBarrelLayer << " " << barrelLayerDist << std::endl; break; case CALHITZONE_ENDCAP: // use end layer for(int ilayer = 0; ilayer <= _nPseudoLayers; ++ilayer){ if(fabs(zhit-_positionEndcapLayer[ilayer])getPhysicalLayer() << " " << zhit << "-->" << bestEndcapLayer << " " << endcapLayerDist << std::endl; iplayer = bestEndcapLayer; break; case CALHITZONE_OVERLAP: // check to see whether the equivalent barrel or endcap layer is furthest out for(int ilayer = 0; ilayer <= _nPseudoLayers; ++ilayer){ if(fabs(prodRadiusMax-_positionBarrelLayer[ilayer])bestEndcapLayer)iplayer = bestBarrelLayer; break; default: break; } return iplayer; } void PandoraPFAProcessor::searchForV0s() { vectorbackScatter; vectorrin; vectorrout; vectorzin; vectorzout; HelixClass* helixEnd[_tracksAR.size()]; HelixClass* helixStart[_tracksAR.size()]; float zAtEnd[_tracksAR.size()]; float zAtStart[_tracksAR.size()]; if(_printing>0)std::cout << " Search for V0s " << std::endl; if(_v0Finder==2 || _v0Finder ==3 ){ for(unsigned int iv=0; iv<_externalV0s.size();iv++){ ReconstructedParticle* part = _externalV0s[iv]->getAssociatedParticle(); TrackVec tracks = part->getTracks(); if(_printing>0)std::cout << " Extermal vertex with " << tracks.size() << " tracks " << std::endl; if(tracks.size()==2){ MyTrackExtended* et1 = NULL; MyTrackExtended* et2 = NULL; // find extended tracks Track* t1 = tracks[0]; Track* t2 = tracks[1]; for(unsigned int itrack=0;itrack<_tracksAR.size();++itrack){ if(t1==_tracksAR[itrack]->getTrack())et1=_tracksAR[itrack]; if(t2==_tracksAR[itrack]->getTrack())et2=_tracksAR[itrack]; } if(et1!=NULL && et2!=NULL){ if(!et1->isBackScatter() && !et1->isProngE() && !et1->isKinkE() && !et1->isSplitE() && !et2->isBackScatter() && !et2->isProngE() && !et2->isKinkE() && !et2->isSplitE()){ et1->isV0(true); et2->isV0(true); et1->SetMatchedV0Track(et2); et2->SetMatchedV0Track(et1); if(_printing>0)std::cout << " Using extermal vertex : " << et1->getEnergy() << " <-> " << et2->getEnergy() << std::endl; }else{ streamlog_out(WARNING) << "PandoraPFA::searchForV0s external vertex vetoed" << std::endl; } }else{ streamlog_out(WARNING) << "PandoraPFA::searchForV0s unable to match external vertex tracks to extended tracsk" << std::endl; } } } } // use internal V0 finding ? if(_v0Finder!=1 && _v0Finder !=3)return; for(unsigned int itrack=0;itrack< _tracksAR.size();++itrack){ MyTrackExtended * tracki = _tracksAR[itrack]; TrackerHitVec hitvec = tracki->getTrack()->getTrackerHits(); int nhits = (int)hitvec.size(); int outer = 0; float router =-99999.; int inner = 0; float rinner =99999.; int max = 0; int min = 0; float abszmax =-99999.; float abszmin =99999.; float zmax =-99999.; float zmin =99999.; float rAtZMax=99999; float rAtZMin=99999; for(int ih =0;ihgetPosition()[0]; float y = (float)hitvec[ih]->getPosition()[1]; float z = (float)hitvec[ih]->getPosition()[2]; float r2 = x*x+y*y; float r = sqrt(r2); if(zzmax)zmax=z; if(fabs(z)abszmax){ max=ih; abszmax = fabs(z); rAtZMax = r; } if(r_tpcInnerR){ inner=ih; rinner = r; } if(r>router){ outer=ih; router = r; } } vec3 ri; ri.x = (float)hitvec[inner]->getPosition()[0]; ri.y = (float)hitvec[inner]->getPosition()[1]; ri.z = (float)hitvec[inner]->getPosition()[2]; rin.push_back(ri); vec3 ro; ro.x = (float)hitvec[outer]->getPosition()[0]; ro.y = (float)hitvec[outer]->getPosition()[1]; ro.z = (float)hitvec[outer]->getPosition()[2]; rout.push_back(ro); bool bs = false; if( (( fabs(rAtZMax)-_tpcOuterR>-50.) || (fabs(zmax) - _tpcZmax > -50.) ) && (( fabs(rAtZMin)-_tpcOuterR>-50.) || (fabs(zmin) - _tpcZmax > -50.) ) )bs = true; backScatter.push_back(bs); vec3 zi; zi.x = (float)hitvec[min]->getPosition()[0]; zi.y = (float)hitvec[min]->getPosition()[1]; zi.z = (float)hitvec[min]->getPosition()[2]; vec3 zo; zo.x = (float)hitvec[max]->getPosition()[0]; zo.y = (float)hitvec[max]->getPosition()[1]; zo.z = (float)hitvec[max]->getPosition()[2]; zin.push_back(zi); zout.push_back(zo); float d0i = tracki->getD0(); float z0i = tracki->getZ0(); float rini= _tracksAR[itrack]->getInnerR(); if(_printing>1)std::cout << " Track " << itrack << " " << d0i << "," << z0i << " rin = " << rini << " z : " << zi.z << "-" << zo.z << " " << tracki->isBackScatter() << std::endl; float zBegin, zEnd; if (fabs(zmin) _nHitsInFit) { for (int iz = 0 ; iz < nhits-1; iz++) for (int jz = 0; jz < nhits-iz-1; jz++){ TrackerHit * one = hitvec[jz]; TrackerHit * two = hitvec[jz+1]; float dist1 = fabs(float(one->getPosition()[2])-zBegin); float dist2 = fabs(float(two->getPosition()[2])-zBegin); if(dist1 > dist2) { TrackerHit * Temp = hitvec[jz]; hitvec[jz] = hitvec[jz+1]; hitvec[jz+1] = Temp; } } nhitsFit = _nHitsInFit; }else { nhitsFit = nhits; } float * xh = new float[nhitsFit]; float * yh = new float[nhitsFit]; float * zh = new float[nhitsFit]; float * ah = new float[nhitsFit]; for (int i=0; igetPosition()[0]); yh[i] = float(hitvec[i]->getPosition()[1]); zh[i] = float(hitvec[i]->getPosition()[2]); } ClusterShapes * shapesS = new ClusterShapes(nhitsFit,ah,xh,yh,zh); float par[5]; float dpar[5]; float chi2; float distmax; shapesS->FitHelix(500, 0, 1, par, dpar, chi2, distmax); delete shapesS; float x0 = par[0]; float y0 = par[1]; float r0 = par[2]; float bz = par[3]; float phiH = par[4]; helixStart[itrack] = new HelixClass(); helixStart[itrack]->Initialize_BZ(x0, y0, r0, bz, phiH, _bField,signPz, zBegin); float seeds[3]; float refs[3]; refs[0] = helixStart[itrack]->getReferencePoint()[0]; refs[1] = helixStart[itrack]->getReferencePoint()[1]; refs[2] = helixStart[itrack]->getReferencePoint()[2]; helixStart[itrack]->getPointInZ(zAtEnd[itrack], refs, seeds); for (int i=0; igetPosition()[0]); yh[i] = float(hitvec[nhits-1-i]->getPosition()[1]); zh[i] = float(hitvec[nhits-1-i]->getPosition()[2]); } ClusterShapes * shapesE = new ClusterShapes(nhitsFit,ah,xh,yh,zh); shapesE->FitHelix(500, 0, 1, par, dpar, chi2, distmax); delete shapesE; x0 = par[0]; y0 = par[1]; r0 = par[2]; bz = par[3]; phiH = par[4]; helixEnd[itrack] = new HelixClass(); helixEnd[itrack]->Initialize_BZ(x0, y0, r0, bz, phiH, _bField,signPz, zEnd); } // loop over tracks ignoring previously identified v0s for(unsigned int i=0;i< _tracksAR.size();++i){ Track* tracki = _tracksAR[i]->getTrack(); float d0i = tracki->getD0(); float z0i = tracki->getZ0(); float rini= _tracksAR[i]->getInnerR(); if(_tracksAR[i]->hits()>10 && !_tracksAR[i]->isBackScatter() && !_tracksAR[i]->isProngE() && !_tracksAR[i]->isKinkE() && !_tracksAR[i]->isSplitE() && !_tracksAR[i]->isV0() && (rini> _tpcInnerR-10. || fabs(d0i)>_d0TrackCut || fabs(z0i)>_z0TrackCut)){ bool vertexi = (fabs(d0i)<_d0TrackCut) && (fabs(z0i)<_z0TrackCut) && (rini < _tpcInnerR+50.); float drmin = 99999.; float DRmin = 99999.; float rV0min = 99999.; float dr=99999; int jmin=0; for(unsigned int j=i+1;j< _tracksAR.size();++j){ Track* trackj = _tracksAR[j]->getTrack(); float d0j = trackj->getD0(); float z0j = trackj->getZ0(); float rinj= _tracksAR[j]->getInnerR(); if(_tracksAR[j]->hits()>10 && !_tracksAR[j]->isBackScatter() && !_tracksAR[j]->isProngE() && !_tracksAR[j]->isKinkE() &&!_tracksAR[i]->isSplitE() && !_tracksAR[i]->isV0() && ( rinj > _tpcInnerR-10. || fabs(d0j)>_d0TrackCut || fabs(z0j)>_z0TrackCut)){ bool vertexj = (fabs(d0j)<_d0TrackCut) && (fabs(z0j)<_z0TrackCut) && (rinj < _tpcInnerR+50.); // have a pair of candidate V0 tracks // first find track ends for possible V0 float dx = zin[i].x-zin[j].x; float dy = zin[i].y-zin[j].y; float dz = zin[i].z-zin[j].z; float drii = sqrt(dx*dx+dy*dy+dz*dz); dx = zin[i].x-zout[j].x; dy = zin[i].y-zout[j].y; dz = zin[i].z-zout[j].z; float drio = sqrt(dx*dx+dy*dy+dz*dz); dx = zout[i].x-zin[j].x; dy = zout[i].y-zin[j].y; dz = zout[i].z-zin[j].z; float droi = sqrt(dx*dx+dy*dy+dz*dz); dx = zout[i].x-zout[j].x; dy = zout[i].y-zout[j].y; dz = zout[i].z-zout[j].z; float droo = sqrt(dx*dx+dy*dy+dz*dz); float candzi=0; float candzj=0; float canddr = 99999.; if(drii1)std::cout << " NEW V0 candidate " << i << "," << j << " dr = " << canddr << " z z = " << candzi << " " << candzj << std::endl; float refs[3]; float seediAtzi[3]; float seedjAtzi[3]; float seediAtz0[3]; float seedjAtz0[3]; float seediAtzj[3]; float seedjAtzj[3]; float candz0 = (candzi + candzj)/2.0; refs[0] = helixStart[i]->getReferencePoint()[0]; refs[1] = helixStart[i]->getReferencePoint()[1]; refs[2] = helixStart[i]->getReferencePoint()[2]; helixStart[i]->getPointInZ(candzi, refs, seediAtzi); helixStart[i]->getPointInZ(candzj, refs, seediAtzj); helixStart[i]->getPointInZ(candz0, refs, seediAtz0); if(_printing>1)std::cout << " SEED I at zi = " << candzi << " FROM HELIX I : " << seediAtzi[0] << "," << seediAtzi[1] << "," << seediAtzi[2] << std::endl; if(_printing>1)std::cout << " SEED J at zj = " << candzj << " FROM HELIX I : " << seediAtzj[0] << "," << seediAtzj[1] << "," << seediAtzj[2] << std::endl; refs[0] = helixStart[j]->getReferencePoint()[0]; refs[1] = helixStart[j]->getReferencePoint()[1]; refs[2] = helixStart[j]->getReferencePoint()[2]; helixStart[j]->getPointInZ(candzi, refs, seedjAtzi); helixStart[j]->getPointInZ(candzj, refs, seedjAtzj); helixStart[j]->getPointInZ(candz0, refs, seedjAtz0); if(_printing>1)std::cout << " SEED I at zi = " << candzi << " FROM HELIX J : " << seedjAtzi[0] << "," << seedjAtzi[1] << "," << seedjAtzi[2] << std::endl; if(_printing>1)std::cout << " SEED J at zj = " << candzj << " FROM HELIX J : " << seedjAtzj[0] << "," << seedjAtzj[1] << "," << seedjAtzj[2] << std::endl; float dxi = seediAtzi[0]-seedjAtzi[0]; float dyi = seediAtzi[1]-seedjAtzi[1]; float dzi = seediAtzi[2]-seedjAtzi[2]; float dx0 = seediAtz0[0]-seedjAtz0[0]; float dy0 = seediAtz0[1]-seedjAtz0[1]; float dz0 = seediAtz0[2]-seedjAtz0[2]; float dxj = seediAtzj[0]-seedjAtzj[0]; float dyj = seediAtzj[1]-seedjAtzj[1]; float dzj = seediAtzj[2]-seedjAtzj[2]; float dr0 = sqrt(dx0*dx0+dy0*dy0+dz0*dz0); float dri = sqrt(dxi*dxi+dyi*dyi+dzi*dzi); float drj = sqrt(dxj*dxj+dyj*dyj+dzj*dzj); if(_printing>1)std::cout << dri << " " << drj << " " << dr0 << std::endl; float rV0; if(drigetReferencePoint()[0]; refi[1] = helixStart[i]->getReferencePoint()[1]; refi[2] = helixStart[i]->getReferencePoint()[2]; refj[0] = helixStart[j]->getReferencePoint()[0]; refj[1] = helixStart[j]->getReferencePoint()[1]; refj[2] = helixStart[j]->getReferencePoint()[2]; float seedi[3]; float seedj[3]; float zs = candzi; float ze = candzj; if(candzj < candzi){ zs = candzj; ze = candzi; } float zstep = (ze-zs)/10.; if(zstep>0.1){ for(float z = zs; z < ze; z+= zstep){ helixStart[i]->getPointInZ(z, refi, seedi); helixStart[j]->getPointInZ(z, refj, seedj); float dx = seedi[0]-seedj[0]; float dy = seedi[1]-seedj[1]; float dz = seedi[2]-seedj[2]; float newdr = sqrt(dx*dx+dy*dy+dz*dz); if(newdr1)std::cout << " dr : " << dr << " " << canddr << " " << drmin << std::endl; if(dr1)std::cout << " TRACK dr : " << drmin << " " << DRmin << std::endl; Track* trackj = _tracksAR[jmin]->getTrack(); float d0j = trackj->getD0(); float z0j = trackj->getZ0(); bool vertexj = (fabs(d0j)<_d0TrackCut) && (fabs(z0j)<_z0TrackCut); if(drmin<25. || (drmin < 50 && DRmin < 15.0) ){ if(_printing>1)std::cout << " V0 candidate " << i << "," << jmin << " dr = " << drmin << " rV0 = " << rV0min << std::endl; if(backScatter[i]||backScatter[jmin]){ if(_printing>1)std::cout << " Vetoed as Backscatter " << std::endl; }else{ _tracksAR[i]->isV0(true); _tracksAR[jmin]->isV0(true); _tracksAR[i]->SetMatchedV0Track(_tracksAR[jmin]); _tracksAR[jmin]->SetMatchedV0Track(_tracksAR[i]); } }else{ if(drmin<50&&_tracksAR[i]->getInnerR()<_tpcInnerR+50.&&_tracksAR[jmin]->getInnerR()<_tpcInnerR+50. && rV0min < _tpcInnerR+50. && !vertexi && !vertexj){ if(_printing>1)std::cout << " INTERACTION V0 candidate " << i << "," << jmin << " dr = " << drmin << " rV0 = " << rV0min << std::endl; if(backScatter[i]||backScatter[jmin]){ if(_printing>1)std::cout << " Vetoed as Backscatter " << std::endl; }else{ _tracksAR[i]->isV0(true); _tracksAR[jmin]->isV0(true); _tracksAR[i]->SetMatchedV0Track(_tracksAR[jmin]); _tracksAR[jmin]->SetMatchedV0Track(_tracksAR[i]); } } } } } } void PandoraPFAProcessor::searchForKinks() { // 25/7/08 Added improved kink finding in z vectorrin; vectorrout; vectorzin; vectorzout; HelixClass* helixEnd[_tracksAR.size()]; HelixClass* helixStart[_tracksAR.size()]; float zAtEnd[_tracksAR.size()]; float zAtStart[_tracksAR.size()]; if(_printing>1)std::cout << " Search for Kinks " << std::endl; for(unsigned int itrack=0;itrack< _tracksAR.size();++itrack){ MyTrackExtended * tracki = _tracksAR[itrack]; TrackerHitVec hitvec = tracki->getTrack()->getTrackerHits(); int nhits = (int)hitvec.size(); int outer = 0; float router =-99999.; int inner = 0; float rinner =99999.; int max = 0; int min = 0; float abszmax =-99999.; float abszmin =99999.; float zmax =-99999.; float zmin =99999.; for(int ih =0;ihgetPosition()[0]; float y = (float)hitvec[ih]->getPosition()[1]; float z = (float)hitvec[ih]->getPosition()[2]; float r2 = x*x+y*y; float r = sqrt(r2); if(zzmax)zmax=z; if(fabs(z)abszmax){ max=ih; abszmax = fabs(z); } if(r_tpcInnerR){ inner=ih; rinner = r; } if(r>router){ outer=ih; router = r; } } vec3 ri; ri.x = (float)hitvec[inner]->getPosition()[0]; ri.y = (float)hitvec[inner]->getPosition()[1]; ri.z = (float)hitvec[inner]->getPosition()[2]; rin.push_back(ri); vec3 ro; ro.x = (float)hitvec[outer]->getPosition()[0]; ro.y = (float)hitvec[outer]->getPosition()[1]; ro.z = (float)hitvec[outer]->getPosition()[2]; rout.push_back(ro); vec3 zi; zi.x = (float)hitvec[min]->getPosition()[0]; zi.y = (float)hitvec[min]->getPosition()[1]; zi.z = (float)hitvec[min]->getPosition()[2]; vec3 zo; zo.x = (float)hitvec[max]->getPosition()[0]; zo.y = (float)hitvec[max]->getPosition()[1]; zo.z = (float)hitvec[max]->getPosition()[2]; zin.push_back(zi); zout.push_back(zo); float zBegin, zEnd; if (fabs(zmin) _nHitsInFit) { for (int iz = 0 ; iz < nhits-1; iz++) for (int jz = 0; jz < nhits-iz-1; jz++){ TrackerHit * one = hitvec[jz]; TrackerHit * two = hitvec[jz+1]; float dist1 = fabs(float(one->getPosition()[2])-zBegin); float dist2 = fabs(float(two->getPosition()[2])-zBegin); if(dist1 > dist2) { TrackerHit * Temp = hitvec[jz]; hitvec[jz] = hitvec[jz+1]; hitvec[jz+1] = Temp; } } nhitsFit = _nHitsInFit; }else { nhitsFit = nhits; } float * xh = new float[nhitsFit]; float * yh = new float[nhitsFit]; float * zh = new float[nhitsFit]; float * ah = new float[nhitsFit]; for (int i=0; igetPosition()[0]); yh[i] = float(hitvec[i]->getPosition()[1]); zh[i] = float(hitvec[i]->getPosition()[2]); } ClusterShapes * shapesS = new ClusterShapes(nhitsFit,ah,xh,yh,zh); float par[5]; float dpar[5]; float chi2; float distmax; shapesS->FitHelix(500, 0, 1, par, dpar, chi2, distmax); delete shapesS; float x0 = par[0]; float y0 = par[1]; float r0 = par[2]; float bz = par[3]; float phiH = par[4]; helixStart[itrack] = new HelixClass(); helixStart[itrack]->Initialize_BZ(x0, y0, r0, bz, phiH, _bField,signPz, zBegin); float seeds[3]; float refs[3]; refs[0] = helixStart[itrack]->getReferencePoint()[0]; refs[1] = helixStart[itrack]->getReferencePoint()[1]; refs[2] = helixStart[itrack]->getReferencePoint()[2]; helixStart[itrack]->getPointInZ(zAtEnd[itrack], refs, seeds); for (int i=0; igetPosition()[0]); yh[i] = float(hitvec[nhits-1-i]->getPosition()[1]); zh[i] = float(hitvec[nhits-1-i]->getPosition()[2]); } ClusterShapes * shapesE = new ClusterShapes(nhitsFit,ah,xh,yh,zh); shapesE->FitHelix(500, 0, 1, par, dpar, chi2, distmax); delete shapesE; x0 = par[0]; y0 = par[1]; r0 = par[2]; bz = par[3]; phiH = par[4]; helixEnd[itrack] = new HelixClass(); helixEnd[itrack]->Initialize_BZ(x0, y0, r0, bz, phiH, _bField,signPz, zEnd); } if(_printing>1)std::cout << " *******************************NEW KINK/PRONG Finding " << std::endl; MyTrackExtendedVec daughterTracks[_tracksAR.size()]; MyTrackExtendedVec backScatterTracks[_tracksAR.size()]; for(unsigned int i=0;i< _tracksAR.size();++i){ Track* tracki = _tracksAR[i]->getTrack(); float d0i = tracki->getD0(); float z0i = tracki->getZ0(); if(_printing>1)std::cout << _tracksAR[i]->getEnergy() << " " << d0i << " " << z0i << " " << _tracksAR[i]->isProngS() << " " << _tracksAR[i]->isSplitS() << " " << _tracksAR[i]->isBackScatter() << " " << _tracksAR[i]->isV0() << std::endl; if( (_tracksAR[i]->hits()>10 && fabs(d0i)<_d0TrackCut && fabs(z0i)<_z0TrackCut && !_tracksAR[i]->isProngS() && !_tracksAR[i]->isSplitS() && !_tracksAR[i]->isBackScatter() )||_tracksAR[i]->isV0()){ // || _tracksAR[i]->isProngE() ){ float rini= _tracksAR[i]->getInnerR(); float seedi[3]; float refe[3]; float z = zAtEnd[i]; refe[0] = helixEnd[i]->getReferencePoint()[0]; refe[1] = helixEnd[i]->getReferencePoint()[1]; refe[2] = helixEnd[i]->getReferencePoint()[2]; helixEnd[i]->getPointInZ(z, refe, seedi); bool reachedEcali = false; float rendi = sqrt(seedi[0]*seedi[0]+seedi[1]*seedi[1]); if((fabs(rendi-_tpcOuterR)<50.) || ( fabs(z) - _tpcZmax > -50.) )reachedEcali = true; // if(reachedEcali){ seedi[0] = _tracksAR[i]->getSeedPosition()[0]; seedi[1] = _tracksAR[i]->getSeedPosition()[1]; seedi[2] = _tracksAR[i]->getSeedPosition()[2]; z = seedi[2]; } for(unsigned int j=0;j< _tracksAR.size();++j){ if(i!=j){ Track* trackj = _tracksAR[j]->getTrack(); float d0j = trackj->getD0(); float z0j = trackj->getZ0(); float rinj= _tracksAR[j]->getInnerR(); if(_tracksAR[j]->hits()>10 && !_tracksAR[j]->isBackScatter() && !_tracksAR[j]->isProngE() && !_tracksAR[j]->isSplitE() && !_tracksAR[j]->isV0() && ( rinj > _tpcInnerR+50. || (fabs(d0j)>_d0TrackCut || fabs(z0j)>_z0TrackCut))){ float seedj[3]; float refs[3]; float deltaz; float ddx; float ddy; float ddz; float deltar; int ip; int id; float z1; float z2; if(fabs(zAtEnd[i]-zAtStart[j])<=fabs(zAtEnd[i]-zAtEnd[j])){ // normal kink where both tracks propagate outwards ip = i; id = j; refs[0] = helixStart[j]->getReferencePoint()[0]; refs[1] = helixStart[j]->getReferencePoint()[1]; refs[2] = helixStart[j]->getReferencePoint()[2]; helixStart[j]->getPointInZ(z, refs, seedj); deltaz = zAtEnd[i] - zAtStart[j]; ddx = (zout[i].x-zin[j].x); ddy = (zout[i].y-zin[j].y); ddz = (zout[i].z-zin[j].z); deltar = sqrt(ddx*ddx+ddy*ddy+ddz*ddz); z1 = zAtEnd[ip]; z2 = zAtStart[id]; }else{ // kink where daughter track propagates inwards // or a V0 !!! // or a backscattered track ip = j; id = i; refs[0] = helixEnd[j]->getReferencePoint()[0]; refs[1] = helixEnd[j]->getReferencePoint()[1]; refs[2] = helixEnd[j]->getReferencePoint()[2]; helixEnd[j]->getPointInZ(z, refs, seedj); deltaz = zAtEnd[i] - zAtEnd[j]; ddx = (zout[i].x-zout[j].x); ddy = (zout[i].y-zout[j].y); ddz = (zout[i].z-zout[j].z); deltar = sqrt(ddx*ddx+ddy*ddy+ddz*ddz); z1 = zAtEnd[ip]; z2 = zAtEnd[id]; } float dx = seedi[0]-seedj[0]; float dy = seedi[1]-seedj[1]; float dz = seedi[2]-seedj[2]; float dr = sqrt(dx*dx+dy*dy+dz*dz); if(_printing>8)std::cout << " try : " << _tracksAR[i]->getEnergy() << "<->" << _tracksAR[j]->getEnergy() << " --> " << dr << " zs " << z1 << "-" << z2 << std::endl; if(dr>5&&dr<100){ float refsp[3]; float refsd[3]; refsp[0] = helixEnd[ip]->getReferencePoint()[0]; refsp[1] = helixEnd[ip]->getReferencePoint()[1]; refsp[2] = helixEnd[ip]->getReferencePoint()[2]; refsd[0] = helixStart[id]->getReferencePoint()[0]; refsd[1] = helixStart[id]->getReferencePoint()[1]; refsd[2] = helixStart[id]->getReferencePoint()[2]; float seedp[3]; float seedd[3]; float zs = z1; float ze = z2; if(z2 < z1){ zs = z2; ze = z1; } float zstep = (ze-zs)/10.; if(zstep>1.){ for(float z = zs; z < ze; z+= zstep){ helixEnd[ip]->getPointInZ(z, refsp, seedp); helixStart[id]->getPointInZ(z, refsd, seedd); float dx = seedp[0]-seedd[0]; float dy = seedp[1]-seedd[1]; float dz = seedp[2]-seedd[2]; float newdr = sqrt(dx*dx+dy*dy+dz*dz); if(_printing>1)std::cout << z << " " << " newdr = " << newdr << std::endl; if(newdr200)ok=false; if(fabs(deltaz)>100 && dr > 5.0)ok=false; if(rendi>_tpcOuterR)ok=false; //}else{ //if(fabs(deltaz)>25)ok=false; //} if(dr<50){ if(_printing>1){ std::cout << " rendi : " << i << "," << j << " rend " << rendi << " " << _tpcOuterR << " " << _tracksAR[j]->getEnergy() << "," << _tracksAR[i]->getEnergy() << " dr = " << dr << " (deltaR = " << deltar << ")" << std::endl; std::cout << " zi/zj " << zAtStart[i] << " - " << zAtEnd[i] << " " << zAtStart[j] << " - " << zAtEnd[j] << std::endl; } if(_printing>1 && (dr>25 || !ok) ){ std::cout << " XNEW KINK : " << i << " " << j << " z = " << z << " dr = " << dr << std::endl; std::cout << " XNEW KINK : " << _tracksAR[j]->getEnergy() << "," << _tracksAR[i]->getEnergy() << std::endl; std::cout << " XNEW KINK : " << _tracksAR[j]->getInnerR() << "," << _tracksAR[i]->getInnerR() << std::endl; std::cout << " XNEW KINK : " << _tracksAR[j]->getOuterR() << "," << _tracksAR[i]->getOuterR() << std::endl; std::cout << " XNEW KINK : d0/z0s i j : " << d0i << "," << z0i << " " << d0j <<"," << z0j << std::endl; std::cout << " XNEW KINK : ztEnd i j : " << zAtStart[i] << " - " << zAtEnd[i] << " " << zAtStart[j] << " - " << zAtEnd[j] << std::endl; } } if(ok && (dr<25 || deltar < 25)){ if(!reachedEcali){ daughterTracks[i].push_back(_tracksAR[j]); }else{ if(_printing>1){ std::cout << " XNEW KINK : FOUND BACK-SCATTER TRACK " << seedj[0] << "," << seedj[1] << "," << seedj[2] << " " << i << ":" << j << std::endl; std::cout << " INNNER I " << rini << std::endl; } if(rini<_tpcInnerR)backScatterTracks[i].push_back(_tracksAR[j]); } } } } } } } for(unsigned int j=0;j< _tracksAR.size();++j){ if(_printing>1 &&daughterTracks[j].size()>0 )std::cout << " KINK DAUGHTERS : " << daughterTracks[j].size() << std::endl; // tag the KINKED tracks charged -> charged + neutrals if(daughterTracks[j].size()==1){ MCParticle* mci = daughterTracks[j][0]->getMCParticle(); MCParticle* mcj = _tracksAR[j]->getMCParticle(); if(mci!=NULL&&mcj!=NULL){ if(_printing>1)std::cout << " KINK : " << mcj->getPDG() << " -> " << mci->getPDG() << std::endl; } if(_printing>1 &&daughterTracks[j].size()>0 )std::cout << " TAGGED KINK "<< _tracksAR[j]->getEnergy() << " -> " << daughterTracks[j][0]->getEnergy() << std::endl; bool canHandleThisCase = true; if(_tracksAR[j]->isV0()){ if(_printing>1)std::cout << " V0 and KINK - NOT DEALT WITH " << std::endl; canHandleThisCase = false; } if(daughterTracks[j][0]->isSplitS()){ if(_printing>1)std::cout << " Split and KINK - NOT DEALT WITH " << std::endl; canHandleThisCase = false; } if(_printing>1){ std::cout << " KS : " << _tracksAR[j]->isSplitS() << " : " << _tracksAR[j]->isSplitE() << std::endl; std::cout << " KE : " << daughterTracks[j][0]->isSplitS() << " : " << daughterTracks[j][0]->isSplitE() << std::endl; } if(canHandleThisCase){ if(_tracksAR[j]->getInnerR()<_tpcInnerR){ MyTrackExtended* daughter = daughterTracks[j][0]; _tracksAR[j]->isKinkS(true); _tracksAR[j]->setKinkDaughter(daughter); daughter->isKinkE(true); daughter->setKinkParent(_tracksAR[j]); }else{ if(_printing>1)std::cout << " Bad kink - parent starts in TPC " << std::endl; } } } // tag the CHARGED prongs charged -> N charged + neutrals if(daughterTracks[j].size()>1){ if(_printing>1)std::cout << " Should have been tagged by Prong finding " << std::endl; //_tracksAR[j]->isProngS(true); //for(unsigned int i=0;iisV0()){ // if(_printing>1)std::cout << " V0 and a prong - NOT DEALT WITH " << std::endl; //}else{ // _tracksAR[j]->addProngDaughter(daughterTracks[j][i]); // daughterTracks[j][i]->isProngE(true); // daughterTracks[j][i]->isV0(false); // daughterTracks[j][i]->setProngParent(_tracksAR[j]); //} } // tag the back scatters !!!! if(backScatterTracks[j].size()>0){ for(unsigned int i=0;iisV0()){ if(_printing>1)std::cout << " V0 and a backscatter - SHOULD NOT HAPPEN" << std::endl; }else{ if(_printing>1)std::cout << " Potential BS Track : IGNORE " << j << std::endl; //_tracksAR[j]->addBackScatterTrack(backScatterTracks[j][i]); //backScatterTracks[j][i]->isBackScatter(true); //backScatterTracks[j][i]->setBackScatterParent(_tracksAR[j]); } } } } for(unsigned int itrack=0;itrack< _tracksAR.size();++itrack){ delete helixEnd[itrack]; delete helixStart[itrack]; } } void PandoraPFAProcessor::searchForSplitTracks() { // 21/2/08 if(_tracksAR.size()==0)return; if(_printing>1)std::cout << "********************* Search for Split Tracks " << std::endl; for(unsigned int itrack=0;itrack< _tracksAR.size()-1;++itrack){ MyTrackExtended * tracki = _tracksAR[itrack]; for(unsigned int jtrack=itrack+1;jtrack< _tracksAR.size();++jtrack){ MyTrackExtended * trackj = _tracksAR[jtrack]; if(trackj->getEnergy()>0 && tracki->getEnergy()>0){ float dpOverP = fabs(tracki->getEnergy()-trackj->getEnergy()); if(trackj->getEnergy()getEnergy())dpOverP = dpOverP/trackj->getEnergy(); if(tracki->getEnergy()getEnergy())dpOverP = dpOverP/tracki->getEnergy(); if(dpOverP<0.2){ float pi[3]; float pj[3]; pi[0] = tracki->getMomentum()[0]; pi[1] = tracki->getMomentum()[1]; pi[2] = tracki->getMomentum()[2]; pj[0] = trackj->getMomentum()[0]; pj[1] = trackj->getMomentum()[1]; pj[2] = trackj->getMomentum()[2]; float pdot = (pi[0]*pj[0] + pi[1]*pj[1]+ pi[2]*pj[2])/ sqrt(pi[0]*pi[0] + pi[1]*pi[1]+ pi[2]*pi[2])/ sqrt(pj[0]*pj[0] + pj[1]*pj[1]+ pj[2]*pj[2]); if( (pdot>0.99&&dpOverP<0.01) || pdot>0.998){ float mx=0; if( trackj->getEnergy() > tracki->getEnergy())mx = this->kinkMass(trackj,tracki,0.106,0.000); if( tracki->getEnergy() > trackj->getEnergy())mx = this->kinkMass(tracki,trackj,0.106,0.000); if(_printing>1)std::cout << " CAND SPLIT : " << trackj->getEnergy() << "," << tracki->getEnergy() << " pdot " << pdot << " mkink = " << mx << std::endl; TrackerHitVec hitveci= tracki->getTrack()->getTrackerHits(); TrackerHitVec hitvecj= trackj->getTrack()->getTrackerHits(); int nhitsi = (int)hitveci.size(); int nhitsj = (int)hitvecj.size(); int ntpci = 0; int ntpcj = 0; HelixClass* helixi = tracki->getHelix(); HelixClass* helixj = tracki->getHelix(); float hitxyz[3]; float dist[3]; float maxdisti=0; float maxdistj=0; int nclosei = 0; int nclosej = 0; float zmini = 99999; float zminj = 99999; float zmaxi = -99999; float zmaxj = -99999; for(int ih =0;ihgetPosition()[0]; float y = (float)hitveci[ih]->getPosition()[1]; float z = (float)hitveci[ih]->getPosition()[2]; if(fabs(z)zmaxi)zmaxi=fabs(z); float r2 = x*x+y*y; float r = sqrt(r2); if(r>_tpcInnerR)ntpci++; hitxyz[0]=x; hitxyz[1]=y; hitxyz[2]=z; helixj->getDistanceToPoint(hitxyz, dist); if(dist[2]>maxdisti)maxdisti=dist[2]; if(dist[2]<25.)nclosei++; } for(int ih =0;ihgetPosition()[0]; float y = (float)hitvecj[ih]->getPosition()[1]; float z = (float)hitvecj[ih]->getPosition()[2]; if(fabs(z)zmaxj)zmaxj=fabs(z); float r2 = x*x+y*y; float r = sqrt(r2); if(r>_tpcInnerR)ntpcj++; hitxyz[0]=x; hitxyz[1]=y; hitxyz[2]=z; helixi->getDistanceToPoint(hitxyz, dist); if(dist[2]>maxdistj)maxdistj=dist[2]; if(dist[2]<25.)nclosej++; } float fclosei = (float)nclosei/(float)ntpci; float fclosej = (float)nclosej/(float)ntpcj; if(_printing>1)std::cout << " CAND SPLIT I : " << nhitsi << " ntpc " << ntpci << " nclose " << nclosei << " max " << maxdisti << " fclose : " << fclosei << std::endl; if(_printing>1)std::cout << " CAND SPLIT J : " << nhitsj << " ntpc " << ntpcj << " nclose " << nclosej << " max " << maxdistj << " fclose : " << fclosej << std::endl; float split = false; if(maxdistj<50 && maxdisti < 50 && fclosej > 0.95 && fclosei > 0.95 && ntpcj+ntpci < _tpcMaxRow+10.)split = true; if(fabs(mx-massK)<0.03)split=false; if(fabs(mx-massPion)<0.02)split=false; if(split){ if(_printing>1)std::cout << " TAGGED SPLIT TRACK " << _tpcMaxRow << " " << zmaxi << " " << zmaxj << std::endl; if(zmaxi>zmaxj){ tracki->isSplitE(true); tracki->setSplitParent(trackj); if(trackj->reachedEcal())tracki->reachedEcal(true); trackj->isSplitS(true); trackj->setSplitDaughter(tracki); }else{ trackj->isSplitE(true); trackj->setSplitParent(tracki); if(tracki->reachedEcal())trackj->reachedEcal(true); tracki->isSplitS(true); tracki->setSplitDaughter(trackj); } } } } } } } } void PandoraPFAProcessor::searchForBackScatterTracks() { // 20/8/08 New vectorrin; vectorrout; vectorzin; vectorzout; vectorbackScatter; vectorreachedEcal; HelixClass* helixEnd[_tracksAR.size()]; HelixClass* helixStart[_tracksAR.size()]; float zAtEnd[_tracksAR.size()]; float zAtStart[_tracksAR.size()]; if(_printing>2)std::cout << " Search for Backscatters " << std::endl; for(unsigned int itrack=0;itrack< _tracksAR.size();++itrack){ MyTrackExtended * tracki = _tracksAR[itrack]; TrackerHitVec hitvec = tracki->getTrack()->getTrackerHits(); int nhits = (int)hitvec.size(); int outer = 0; float router =-99999.; int inner = 0; float rinner =99999.; float rAtZMin = -99999.; float rAtZMax = -99999.; int max = 0; int min = 0; float abszmax =-99999.; float abszmin =99999.; float zmax =-99999.; float zmin =99999.; for(int ih =0;ihgetPosition()[0]; float y = (float)hitvec[ih]->getPosition()[1]; float z = (float)hitvec[ih]->getPosition()[2]; float r2 = x*x+y*y; float r = sqrt(r2); if(zzmax){ zmax=z; rAtZMax = r; } if(fabs(z)abszmax){ max=ih; abszmax = fabs(z); } if(r_tpcInnerR){ inner=ih; rinner = r; } if(r>router){ outer=ih; router = r; } } vec3 ri; ri.x = (float)hitvec[inner]->getPosition()[0]; ri.y = (float)hitvec[inner]->getPosition()[1]; ri.z = (float)hitvec[inner]->getPosition()[2]; rin.push_back(ri); vec3 ro; ro.x = (float)hitvec[outer]->getPosition()[0]; ro.y = (float)hitvec[outer]->getPosition()[1]; ro.z = (float)hitvec[outer]->getPosition()[2]; rout.push_back(ro); vec3 zi; zi.x = (float)hitvec[min]->getPosition()[0]; zi.y = (float)hitvec[min]->getPosition()[1]; zi.z = (float)hitvec[min]->getPosition()[2]; zin.push_back(zi); vec3 zo; zo.x = (float)hitvec[max]->getPosition()[0]; zo.y = (float)hitvec[max]->getPosition()[1]; zo.z = (float)hitvec[max]->getPosition()[2]; zout.push_back(zo); float zBegin, zEnd; if (fabs(zmin) -50.) ) && (( fabs(rAtZMin-_tpcOuterR)<50.) || (fabs(zmin) -_tpcZmax > -50.) ))bs = true; backScatter.push_back(bs); if(_printing>1&&bs)std::cout << " BS set : " << itrack << " " << zBegin << " - " << zEnd << std::endl; bool re = false; if(( fabs(rAtZMax-_tpcOuterR)<50.) || (fabs(zmax) -_tpcZmax >-50.) )re = true; if(( fabs(rAtZMin-_tpcOuterR)<50.) || (fabs(zmin) -_tpcZmax >-50.))re = true; reachedEcal.push_back(re); int _nHitsInFit = 50; int nhitsFit; if (nhits > _nHitsInFit) { for (int iz = 0 ; iz < nhits-1; iz++) for (int jz = 0; jz < nhits-iz-1; jz++){ TrackerHit * one = hitvec[jz]; TrackerHit * two = hitvec[jz+1]; float dist1 = fabs(float(one->getPosition()[2])-zBegin); float dist2 = fabs(float(two->getPosition()[2])-zBegin); if(dist1 > dist2) { TrackerHit * Temp = hitvec[jz]; hitvec[jz] = hitvec[jz+1]; hitvec[jz+1] = Temp; } } nhitsFit = _nHitsInFit; }else { nhitsFit = nhits; } float * xh = new float[nhitsFit]; float * yh = new float[nhitsFit]; float * zh = new float[nhitsFit]; float * ah = new float[nhitsFit]; for (int i=0; igetPosition()[0]); yh[i] = float(hitvec[i]->getPosition()[1]); zh[i] = float(hitvec[i]->getPosition()[2]); } ClusterShapes * shapesS = new ClusterShapes(nhitsFit,ah,xh,yh,zh); float par[5]; float dpar[5]; float chi2; float distmax; shapesS->FitHelix(500, 0, 1, par, dpar, chi2, distmax); delete shapesS; float x0 = par[0]; float y0 = par[1]; float r0 = par[2]; float bz = par[3]; float phiH = par[4]; helixStart[itrack] = new HelixClass(); helixStart[itrack]->Initialize_BZ(x0, y0, r0, bz, phiH, _bField,signPz, zBegin); float seeds[3]; float refs[3]; refs[0] = helixStart[itrack]->getReferencePoint()[0]; refs[1] = helixStart[itrack]->getReferencePoint()[1]; refs[2] = helixStart[itrack]->getReferencePoint()[2]; helixStart[itrack]->getPointInZ(zAtEnd[itrack], refs, seeds); for (int i=0; igetPosition()[0]); yh[i] = float(hitvec[nhits-1-i]->getPosition()[1]); zh[i] = float(hitvec[nhits-1-i]->getPosition()[2]); } ClusterShapes * shapesE = new ClusterShapes(nhitsFit,ah,xh,yh,zh); shapesE->FitHelix(500, 0, 1, par, dpar, chi2, distmax); delete shapesE; x0 = par[0]; y0 = par[1]; r0 = par[2]; bz = par[3]; phiH = par[4]; helixEnd[itrack] = new HelixClass(); helixEnd[itrack]->Initialize_BZ(x0, y0, r0, bz, phiH, _bField,signPz, zEnd); } if(_printing>1)std::cout << " *******************************NEW backscatter Finding " << std::endl; //MyTrackExtendedVec daughterTracks[_tracksAR.size()]; MyTrackExtendedVec backScatterTracks[_tracksAR.size()]; for(unsigned int i=0;i< _tracksAR.size();++i){ // Track* tracki = _tracksAR[i]->getTrack(); // float d0i = tracki->getD0(); //float rini = _tracksAR[i]->getInnerR(); //float z0i = tracki->getZ0(); float z = zAtEnd[i]; float seedi[3]; seedi[2] = _tracksAR[i]->getSeedPosition()[2]; float rendi = sqrt(seedi[0]*seedi[0]+seedi[1]*seedi[1]); if(reachedEcal[i] && _tracksAR[i]->hits()>10){ seedi[0] = _tracksAR[i]->getSeedPosition()[0]; seedi[1] = _tracksAR[i]->getSeedPosition()[1]; seedi[2] = _tracksAR[i]->getSeedPosition()[2]; z = seedi[2]; for(unsigned int j=0;j< _tracksAR.size();++j){ if(i!=j){ Track* trackj = _tracksAR[j]->getTrack(); float d0j = trackj->getD0(); float z0j = trackj->getZ0(); float rinj= _tracksAR[j]->getInnerR(); if(_tracksAR[j]->hits()>10 && reachedEcal[j] && ( rinj > _tpcInnerR+50. || (fabs(d0j)>_d0TrackCut || fabs(z0j)>_z0TrackCut))){ float seedj[3]; float refs[3]; float deltaz; if(fabs(zAtEnd[i]-zAtStart[j])<=fabs(zAtEnd[i]-zAtEnd[j])){ refs[0] = helixStart[j]->getReferencePoint()[0]; refs[1] = helixStart[j]->getReferencePoint()[1]; refs[2] = helixStart[j]->getReferencePoint()[2]; helixStart[j]->getPointInZ(z, refs, seedj); deltaz = zAtEnd[i] - zAtStart[j]; }else{ refs[0] = helixEnd[j]->getReferencePoint()[0]; refs[1] = helixEnd[j]->getReferencePoint()[1]; refs[2] = helixEnd[j]->getReferencePoint()[2]; helixEnd[j]->getPointInZ(z, refs, seedj); deltaz = zAtEnd[i] - zAtEnd[j]; } float dx = seedi[0]-seedj[0]; float dy = seedi[1]-seedj[1]; float dz = seedi[2]-seedj[2]; float dr = sqrt(dx*dx+dy*dy+dz*dz); bool ok = true; if(backScatter[j]){ if(dr>100)ok=false; }else{ ok = false; } if(ok){ if(_printing>1){ std::cout << " BS rendi : " << i << "," << j << " rend " << rendi << " " << _tpcOuterR << " " << _tracksAR[j]->getEnergy() << "," << _tracksAR[i]->getEnergy() << " dr = " << dr << std::endl; std::cout << " BS zi/zj " << zAtStart[i] << " - " << zAtEnd[i] << " " << zAtStart[j] << " - " << zAtEnd[j] << std::endl; std::cout << " FOUND BACK-SCATTER TRACK " << seedj[0] << "," << seedj[1] << "," << seedj[2] <0){ for(unsigned int i=0;iaddBackScatterTrack(backScatterTracks[j][i]); if(_printing>1)std::cout << " KILL BS TRACK : " << j << std::endl; backScatterTracks[j][i]->isBackScatter(true); backScatterTracks[j][i]->setBackScatterParent(_tracksAR[j]); } } } for(unsigned int itrack=0;itrack< _tracksAR.size();++itrack){ delete helixEnd[itrack]; delete helixStart[itrack]; } } void PandoraPFAProcessor::searchForProngs() { // 20/8/08 New vectorrin; vectorrout; vectorzin; vectorzout; HelixClass* helixEnd[_tracksAR.size()]; HelixClass* helixStart[_tracksAR.size()]; float zAtEnd[_tracksAR.size()]; float zAtStart[_tracksAR.size()]; if(_printing>2)std::cout << " Search for Prongs " << std::endl; for(unsigned int itrack=0;itrack< _tracksAR.size();++itrack){ MyTrackExtended * tracki = _tracksAR[itrack]; TrackerHitVec hitvec = tracki->getTrack()->getTrackerHits(); int nhits = (int)hitvec.size(); int outer = 0; float router =-99999.; int inner = 0; float rinner =99999.; int max = 0; int min = 0; float abszmax =-99999.; float abszmin =99999.; float zmax =-99999.; float zmin =99999.; for(int ih =0;ihgetPosition()[0]; float y = (float)hitvec[ih]->getPosition()[1]; float z = (float)hitvec[ih]->getPosition()[2]; float r2 = x*x+y*y; float r = sqrt(r2); if(zzmax)zmax=z; if(fabs(z)abszmax){ max=ih; abszmax = fabs(z); } if(r_tpcInnerR){ inner=ih; rinner = r; } if(r>router){ outer=ih; router = r; } } vec3 ri; ri.x = (float)hitvec[inner]->getPosition()[0]; ri.y = (float)hitvec[inner]->getPosition()[1]; ri.z = (float)hitvec[inner]->getPosition()[2]; rin.push_back(ri); vec3 ro; ro.x = (float)hitvec[outer]->getPosition()[0]; ro.y = (float)hitvec[outer]->getPosition()[1]; ro.z = (float)hitvec[outer]->getPosition()[2]; rout.push_back(ro); vec3 zi; zi.x = (float)hitvec[min]->getPosition()[0]; zi.y = (float)hitvec[min]->getPosition()[1]; zi.z = (float)hitvec[min]->getPosition()[2]; zin.push_back(zi); vec3 zo; zo.x = (float)hitvec[max]->getPosition()[0]; zo.y = (float)hitvec[max]->getPosition()[1]; zo.z = (float)hitvec[max]->getPosition()[2]; zout.push_back(zo); float zBegin, zEnd; if (fabs(zmin) _nHitsInFit) { for (int iz = 0 ; iz < nhits-1; iz++) for (int jz = 0; jz < nhits-iz-1; jz++){ TrackerHit * one = hitvec[jz]; TrackerHit * two = hitvec[jz+1]; float dist1 = fabs(float(one->getPosition()[2])-zBegin); float dist2 = fabs(float(two->getPosition()[2])-zBegin); if(dist1 > dist2) { TrackerHit * Temp = hitvec[jz]; hitvec[jz] = hitvec[jz+1]; hitvec[jz+1] = Temp; } } nhitsFit = _nHitsInFit; }else { nhitsFit = nhits; } float * xh = new float[nhitsFit]; float * yh = new float[nhitsFit]; float * zh = new float[nhitsFit]; float * ah = new float[nhitsFit]; for (int i=0; igetPosition()[0]); yh[i] = float(hitvec[i]->getPosition()[1]); zh[i] = float(hitvec[i]->getPosition()[2]); } ClusterShapes * shapesS = new ClusterShapes(nhitsFit,ah,xh,yh,zh); float par[5]; float dpar[5]; float chi2; float distmax; shapesS->FitHelix(500, 0, 1, par, dpar, chi2, distmax); delete shapesS; float x0 = par[0]; float y0 = par[1]; float r0 = par[2]; float bz = par[3]; float phiH = par[4]; helixStart[itrack] = new HelixClass(); helixStart[itrack]->Initialize_BZ(x0, y0, r0, bz, phiH, _bField,signPz, zBegin); float seeds[3]; float refs[3]; refs[0] = helixStart[itrack]->getReferencePoint()[0]; refs[1] = helixStart[itrack]->getReferencePoint()[1]; refs[2] = helixStart[itrack]->getReferencePoint()[2]; helixStart[itrack]->getPointInZ(zAtEnd[itrack], refs, seeds); for (int i=0; igetPosition()[0]); yh[i] = float(hitvec[nhits-1-i]->getPosition()[1]); zh[i] = float(hitvec[nhits-1-i]->getPosition()[2]); } ClusterShapes * shapesE = new ClusterShapes(nhitsFit,ah,xh,yh,zh); shapesE->FitHelix(500, 0, 1, par, dpar, chi2, distmax); delete shapesE; x0 = par[0]; y0 = par[1]; r0 = par[2]; bz = par[3]; phiH = par[4]; helixEnd[itrack] = new HelixClass(); helixEnd[itrack]->Initialize_BZ(x0, y0, r0, bz, phiH, _bField,signPz, zEnd); } if(_printing>1)std::cout << " *******************************NEW PRONG Finding " << std::endl; MyTrackExtendedVec daughterTracks[_tracksAR.size()]; MyTrackExtendedVec backScatterTracks[_tracksAR.size()]; for(unsigned int i=0;i< _tracksAR.size();++i){ Track* tracki = _tracksAR[i]->getTrack(); float d0i = tracki->getD0(); float rini = _tracksAR[i]->getInnerR(); float z0i = tracki->getZ0(); if( !_tracksAR[i]->isBackScatter() && !_tracksAR[i]->isSplitS() && !_tracksAR[i]->isSplitE() && _tracksAR[i]->hits()>10 && fabs(d0i)<_d0TrackCut && fabs(z0i)<_z0TrackCut && rini<_tpcInnerR+50.){ float seedi[3]; float refe[3]; float z = zAtEnd[i]; refe[0] = helixEnd[i]->getReferencePoint()[0]; refe[1] = helixEnd[i]->getReferencePoint()[1]; refe[2] = helixEnd[i]->getReferencePoint()[2]; helixEnd[i]->getPointInZ(z, refe, seedi); bool reachedEcali = false; float rendi = sqrt(seedi[0]*seedi[0]+seedi[1]*seedi[1]); if((fabs(rendi-_tpcOuterR)<50.) || (fabs(z) -_tpcZmax >-50.) )reachedEcali = true; // if(reachedEcali){ seedi[0] = _tracksAR[i]->getSeedPosition()[0]; seedi[1] = _tracksAR[i]->getSeedPosition()[1]; seedi[2] = _tracksAR[i]->getSeedPosition()[2]; z = seedi[2]; } for(unsigned int j=0;j< _tracksAR.size();++j){ if(i!=j){ Track* trackj = _tracksAR[j]->getTrack(); float d0j = trackj->getD0(); float z0j = trackj->getZ0(); float rinj= _tracksAR[j]->getInnerR(); if( !_tracksAR[j]->isBackScatter() && _tracksAR[j]->hits()>10 && ( rinj > _tpcInnerR+50. || (fabs(d0j)>_d0TrackCut || fabs(z0j)>_z0TrackCut))){ float seedj[3]; float refs[3]; float deltaz; float ddx; float ddy; float ddz; float deltar; if(fabs(zAtEnd[i]-zAtStart[j])<=fabs(zAtEnd[i]-zAtEnd[j])){ refs[0] = helixStart[j]->getReferencePoint()[0]; refs[1] = helixStart[j]->getReferencePoint()[1]; refs[2] = helixStart[j]->getReferencePoint()[2]; helixStart[j]->getPointInZ(z, refs, seedj); deltaz = zAtEnd[i] - zAtStart[j]; ddx = (zout[i].x-zin[j].x); ddy = (zout[i].y-zin[j].y); ddz = (zout[i].z-zin[j].z); deltar = sqrt(ddx*ddx+ddy*ddy+ddz*ddz); }else{ refs[0] = helixEnd[j]->getReferencePoint()[0]; refs[1] = helixEnd[j]->getReferencePoint()[1]; refs[2] = helixEnd[j]->getReferencePoint()[2]; helixEnd[j]->getPointInZ(z, refs, seedj); deltaz = zAtEnd[i] - zAtEnd[j]; ddx = (zout[i].x-zout[j].x); ddy = (zout[i].y-zout[j].y); ddz = (zout[i].z-zout[j].z); deltar = sqrt(ddx*ddx+ddy*ddy+ddz*ddz); } float dx = seedi[0]-seedj[0]; float dy = seedi[1]-seedj[1]; float dz = seedi[2]-seedj[2]; float dr = sqrt(dx*dx+dy*dy+dz*dz); bool ok = true; if(fabs(d0j)<_d0TrackCut && fabs(z0j)<_z0TrackCut){ if(fabs(deltaz)>100)ok=false; }else{ if(fabs(deltaz)>25)ok=false; } // if(_printing>1)std::cout << " try : " << _tracksAR[i]->getEnergy() << "<->" << _tracksAR[j]->getEnergy() << " --> " << dr << std::endl; if(dr<50){ if(_printing>1){ std::cout << " rendi : " << i << "," << j << " rend " << rendi << " " << _tpcOuterR << " " << _tracksAR[j]->getEnergy() << "," << _tracksAR[i]->getEnergy() << " dr = " << dr << std::endl; std::cout << " zi/zj " << zAtStart[i] << " - " << zAtEnd[i] << " " << zAtStart[j] << " - " << zAtEnd[j] << std::endl; } if(_printing>1 && (dr>25 || !ok) ){ std::cout << " XNEW PRONG : " << i << " " << j << " z = " << z << " dr = " << dr << std::endl; std::cout << " XNEW PRONG : " << _tracksAR[j]->getEnergy() << "," << _tracksAR[i]->getEnergy() << std::endl; std::cout << " XNEW PRONG : " << _tracksAR[j]->getInnerR() << "," << _tracksAR[i]->getInnerR() << std::endl; std::cout << " XNEW PRONG : " << _tracksAR[j]->getOuterR() << "," << _tracksAR[i]->getOuterR() << std::endl; std::cout << " XNEW PRONG : d0/z0s i j : " << d0i << "," << z0i << " " << d0j <<"," << z0j << std::endl; std::cout << " XNEW PRONG : ztEnd i j : " << zAtStart[i] << " - " << zAtEnd[i] << " " << zAtStart[j] << " - " << zAtEnd[j] << std::endl; } } if(ok && (dr<25 ||deltar<25)){ if(!reachedEcali){ daughterTracks[i].push_back(_tracksAR[j]); }else{ if( (fabs(d0j)<_d0TrackCut && fabs(z0j)<_z0TrackCut) || _tracksAR[j]->getEnergy() > 2.5){ if(_printing>1){ std::cout << " XNEW PRONG : FOUND MERGED TRACKs ? " << seedj[0] << "," << seedj[1] << "," << seedj[2] <1){ std::cout << " XNEW PRONG : FOUND BACK-SCATTER TRACK " << seedj[0] << "," << seedj[1] << "," << seedj[2] <1 &&daughterTracks[j].size()>0 )std::cout << " PRONG DAUGHTERS : " << daughterTracks[j].size() << std::endl; // tag the KINKED tracks charged -> charged + neutrals if(daughterTracks[j].size()==1){ MCParticle* mci = daughterTracks[j][0]->getMCParticle(); MCParticle* mcj = _tracksAR[j]->getMCParticle(); if(mci!=NULL&&mcj!=NULL){ if(_printing>1)std::cout << " PRONG??? : " << mcj->getPDG() << " -> " << mci->getPDG() << std::endl; } if(_printing>1 &&daughterTracks[j].size()>0 )std::cout << " TAGGED KINK??? "<< _tracksAR[j]->getEnergy() << " -> " << daughterTracks[j][0]->getEnergy() << std::endl; if(_tracksAR[j]->isV0()){ if(_printing>1)std::cout << " V0 and + KINK - NOT DEALT WITH " << std::endl; }else{ if(_printing>1)std::cout << " KINK found - leave for Kink finder" << std::endl; //_tracksAR[j]->isKinkS(true); //_tracksAR[j]->setKinkDaughter(daughterTracks[j][0]); //daughterTracks[j][0]->isKinkE(true); //daughterTracks[j][0]->setKinkParent(_tracksAR[j]); } } // tag the CHARGED prongs charged -> N charged + neutrals if(daughterTracks[j].size()>1){ if(_printing>1)std::cout << " Prong : " << j << endl; // check energy is sensible as prongs could result from tracking error float ep = _tracksAR[j]->getEnergy(); float ed = 0.; for(unsigned int i=0;iisV0())ed+= daughterTracks[j][i]->getEnergy(); } if(ep+10>ed){ _tracksAR[j]->isProngS(true); for(unsigned int i=0;iisV0()){ if(_printing>1)std::cout << " V0 and a prong - NOT DEALT WITH " << std::endl; }else{ _tracksAR[j]->addProngDaughter(daughterTracks[j][i]); daughterTracks[j][i]->isProngE(true); daughterTracks[j][i]->isV0(false); daughterTracks[j][i]->setProngParent(_tracksAR[j]); } } } } // tag the back scatters !!!! if(backScatterTracks[j].size()>0){ for(unsigned int i=0;iisV0()){ if(_printing>1)std::cout << " V0 and a backscatter - SHOULD NOT HAPPEN" << std::endl; }else{ if(_printing>1)std::cout << " KILL BS TRACK : " << j << std::endl; _tracksAR[j]->addBackScatterTrack(backScatterTracks[j][i]); backScatterTracks[j][i]->isBackScatter(true); backScatterTracks[j][i]->setBackScatterParent(_tracksAR[j]); } } } } for(unsigned int itrack=0;itrack< _tracksAR.size();++itrack){ delete helixEnd[itrack]; delete helixStart[itrack]; } } void PandoraPFAProcessor::defineIntersection( MyTrackExtended * track) { HelixClass * helix = new HelixClass(); TrackerHitVec hitvec = track->getTrack()->getTrackerHits(); int nhits = (int)hitvec.size(); float zmax = -99999.; float zmin = +99999.; float rinner=99999.; float router=-99999.; int nTPC = 0; TrackerHit* lastHit=NULL; // TrackerHit* firstHit=NULL; TrackerHit* outerHit=NULL; TrackerHit* innerHit=NULL; TrackerHit* zmaxHit=NULL; TrackerHit* zminHit=NULL; float xh[nhits]; float yh[nhits]; float zh[nhits]; float ah[nhits]; for(int i =0;igetPosition()[0]; float y = (float)hitvec[i]->getPosition()[1]; float z = (float)hitvec[i]->getPosition()[2]; ah[i] = 0; xh[i] = x; yh[i] = y; zh[i] = z; float r2 = x*x+y*y; float r = sqrt(r2); if(z>zmax){ zmax = z; zmaxHit = hitvec[i]; } if(zrouter){ router=r; outerHit = hitvec[i]; } if(r>_tpcInnerR)nTPC++; } track->setInnerR(rinner); track->setOuterR(router); float zBegin, zEnd; if (fabs(zmin)setZMin(zBegin); track->setZMax(zEnd); ClusterShapes * shapes = new ClusterShapes(nhits,ah,xh,yh,zh); float par[5]; float dpar[5]; float chi2; float distmax; shapes->FitHelix(500, 0, 1, par, dpar, chi2, distmax); delete shapes; float seed[3]; float dir[3]; float Mom[3]; float phi0, z0, d0, omega, tanlambda, signPz; phi0 = track->getTrack()->getPhi(); d0 = track->getTrack()->getD0(); omega = track->getTrack()->getOmega(); z0 = track->getTrack()->getZ0(); tanlambda = track->getTrack()->getTanLambda(); helix->Initialize_Canonical(phi0, d0, z0, omega, tanlambda, _bField); float ref[3]; ref[0] = helix->getReferencePoint()[0]; ref[1] = helix->getReferencePoint()[1]; ref[2] = helix->getReferencePoint()[2]; float momentum=0.; for (int j=0; j < 3; ++j) { Mom[j] = helix->getMomentum()[j]; momentum += Mom[j]*Mom[j]; } float mass = 0.140; momentum = sqrt(momentum); float trackEnergy = sqrt(momentum*momentum+mass*mass); track->setMomentum(Mom); track->setEnergy(trackEnergy); track->setOmega(omega); MCParticle* mcpart = track->getMCParticle(); float etrue = 0.; if(mcpart!=NULL){ etrue = mcpart->getEnergy(); if(fabs(etrue-trackEnergy)/etrue > 0.1){ if(_printing>1)std::cout << " BAD TRACK ENERGY " << etrue << " <-> " << trackEnergy << std::endl; } } // find direction at track start if(innerHit!=NULL){ float zp; float zLine = innerHit->getPosition()[2]; if(zmaxHit!=NULL && zminHit!=NULL){ float z1 = zminHit->getPosition()[2]; float z2 = zmaxHit->getPosition()[2]; if(fabs(z1)>5.0 || fabs(z2)>5.0){ if(fabs(z1)getPointInZ(zLine, ref, seed); track->setTrackStartPosition(seed); if(seed[2]>0.){ zp = seed[2]+0.2; }else{ zp = seed[2]-0.2; } float point[3]; helix->getPointInZ(zp,ref,point); float dx = point[0]-seed[0]; float dy = point[1]-seed[1]; float dz = point[2]-seed[2]; float dr = sqrt(dx*dx+dy*dy+dz*dz); dir[0] = dx/dr; dir[1] = dy/dr; dir[2] = dz/dr; track->setTrackStartDirection(dir); float sMom[3]; sMom[0] = dir[0]*momentum; sMom[1] = dir[1]*momentum; sMom[2] = dir[2]*momentum; track->setStartMomentum(sMom); } // find direction at track end if(outerHit!=NULL){ float zp; float zLine = outerHit->getPosition()[2]; if(zmaxHit!=NULL && zminHit!=NULL){ float z1 = zminHit->getPosition()[2]; float z2 = zmaxHit->getPosition()[2]; if(fabs(z1)>5.0 || fabs(z2)>5.0){ if(fabs(z1)>fabs(z2))zLine = z1; if(fabs(z2)>fabs(z1))zLine = z2; } } helix->getPointInZ(zLine, ref, seed); track->setTrackEndPosition(seed); if(seed[2]>0.){ zp = seed[2]+0.2; }else{ zp = seed[2]-0.2; } float point[3]; helix->getPointInZ(zp,ref,point); float dx = point[0]-seed[0]; float dy = point[1]-seed[1]; float dz = point[2]-seed[2]; float dr = sqrt(dx*dx+dy*dy+dz*dz); dir[0] = dx/dr; dir[1] = dy/dr; dir[2] = dz/dr; track->setTrackEndDirection(dir); float eMom[3]; eMom[0] = dir[0]*momentum; eMom[1] = dir[1]*momentum; eMom[2] = dir[2]*momentum; track->setEndMomentum(eMom); } // Set a flag to indicate whether the track appears to have reached // the ECAL bool outertpc=false; // If there are at least N hits in the TPC hits // then require hits in outer part of TPC if(nTPC>10){ if( (router - _tpcOuterR > -100.) || (fabs(zmax) - _tpcZmax > -50. ) || (fabs(zmin) - _tpcZmax > -50. ) )outertpc=true; } // if lowpt - then may curl up and end inside tpc innerR float pt = sqrt(Mom[0]*Mom[0]+Mom[1]*Mom[1]); float pl = fabs(Mom[2]); float p = sqrt(Mom[0]*Mom[0]+Mom[1]*Mom[1]+Mom[2]*Mom[2]); if(pt<0.3*_bField*_tpcOuterR/2000.)outertpc=true; float cost = pl/p; if(cost>_cosTPC)outertpc = true; track->reachedEcal(outertpc); ref[0] = d0*sin(phi0); ref[1] = -d0*cos(phi0); ref[2] = z0; signPz = tanlambda; float zLine; if (signPz > 0) { zLine = _zOfEndcap; lastHit = zmaxHit; }else{ zLine = -_zOfEndcap; lastHit = zminHit; } if(fabs(zmaxHit->getPosition()[2])<5.0)lastHit = outerHit; float zp; float time_min = helix->getPointInZ(zLine, ref, seed); track->setEndcapSeedPosition(seed); if(seed[2]>0.){ zp = seed[2]+0.2; }else{ zp = seed[2]-0.2; } float point[3]; helix->getPointInZ(zp,ref,point); float dx = point[0]-seed[0]; float dy = point[1]-seed[1]; float dz = point[2]-seed[2]; float dr = sqrt(dx*dx+dy*dy+dz*dz); dir[0] = dx/dr; dir[1] = dy/dr; dir[2] = dz/dr; track->setEndcapSeedDirection(dir); float twopi_n = twopi/((float)_symmetry); if (_symmetry > 0) { for (int i = 0; i < _symmetry; ++i) { float phi = twopi_n*((float)i) + _phiOfBarrel; float xx = _rOfBarrel*cos(phi); float yy = _rOfBarrel*sin(phi); float ax = cos(phi + 0.5*pi); float ay = sin(phi + 0.5*pi); float point[3]; float tt = helix->getPointInXY(xx,yy,ax,ay,ref,point); if (tt < time_min) { time_min = tt; lastHit = outerHit; seed[0] = point[0]; seed[1] = point[1]; seed[2] = point[2]; } } } if(seed[2]>0.){ zp = seed[2]+0.2; }else{ zp = seed[2]-0.2; } helix->getPointInZ(zp,ref,point); dx = point[0]-seed[0]; dy = point[1]-seed[1]; dz = point[2]-seed[2]; dr = sqrt(dx*dx+dy*dy+dz*dz); dir[0] = dx/dr; dir[1] = dy/dr; dir[2] = dz/dr; // now deal with case where not using lumical if(_detector==DETECTOR_LDC00 ||_detector==DETECTOR_LDC01){ float r = sqrt(seed[0]*seed[0]+seed[1]*seed[1]); if(r<_rInnerEcalEndcap){ if (signPz > 0) { zLine = _zOfHcalEndcap; }else{ zLine = -_zOfHcalEndcap; } time_min = helix->getPointInZ(zLine, ref, seed); track->setEndcapSeedPosition(seed); if(seed[2]>0.){ zp = seed[2]+0.2; }else{ zp = seed[2]-0.2; } helix->getPointInZ(zp,ref,point); dx = point[0]-seed[0]; dy = point[1]-seed[1]; dz = point[2]-seed[2]; dr = sqrt(dx*dx+dy*dy+dz*dz); dir[0] = dx/dr; dir[1] = dy/dr; dir[2] = dz/dr; track->setEndcapSeedDirection(dir); } } // projection to TPC outer cage/end plate float pointR[3]; helix->getPointOnCircle(_tpcOuterR,ref,pointR); float pR = sqrt(pointR[0]*pointR[0] + pointR[1]*pointR[1]); if(pR<_tpcOuterR-10.0){ if (signPz > 0) { zLine = _tpcZmax; }else{ zLine = -_tpcZmax; } helix->getPointInZ(zLine,ref,pointR); } track->setTpcIntersection(pointR); float x = lastHit->getPosition()[0]; float y = lastHit->getPosition()[1]; float z = lastHit->getPosition()[2]; if(_printing>3){ std::cout << "Last hit : " << x << "," << y << "," << z << std::endl; std::cout << "Zmin max : " << zminHit->getPosition()[2] << " " << zmaxHit->getPosition()[2] << std::endl; std::cout << "Seed : " << seed[0] << "," << seed[1] << "," << seed[2] << std::endl; } float dright = (x-seed[0])*(x-seed[0])+(y-seed[1])*(y-seed[1])+(z-seed[2])*(z-seed[2]); float dwrong = (x+seed[0])*(x+seed[0])+(y+seed[1])*(y+seed[1])+(z+seed[2])*(z+seed[2]); if(dwrongsetTrackStatus(TRACK_STATUS_KILLED); } } // Kill bad tracks if(nhits >= _minimumTrackHits){ float nhitsInFit = track->getTrack()->getNdf(); float chi2Fit = track->getTrack()->getChi2(); bool badFit = false; if(nhitsInFit < 0.25*nhits)badFit = true; float sigmachi2 = sqrt(2.0*nhitsInFit); float sigchi2 = (chi2Fit - nhitsInFit)/sigmachi2; if(chi2Fit/nhitsInFit > 2.0 && sigchi2 > 5)badFit = true; float etrue = 9999.; if(_cheatedTracks!=0)badFit = false; if(mcpart!=NULL)etrue = mcpart->getEnergy(); if( (badFit && trackEnergy > 100.) || trackEnergy > _maxTrackEnergy ){ streamlog_out(WARNING) << " defineIntersection : Evidence for a bad track fit - kill track " << etrue << " --> " << trackEnergy << " ( " << chi2Fit/nhitsInFit << " " << nhitsInFit << "/" << nhits << " ) " << " sigchi2 " << sigchi2 << std::endl; track->setTrackStatus(TRACK_STATUS_KILLED); }else{ if(mcpart!=NULL){ if(fabs(trackEnergy-etrue)/etrue>0.1){ // streamlog_out(WARNING) << " defineIntersection : Should have killed a bad track ? " << etrue << " --> " << trackEnergy << " ( " << chi2Fit/nhitsInFit << " " << nhitsInFit << "/" << nhits << " ) " << std::endl; } } } } float r2seed = seed[0]*seed[0] + seed[1]*seed[1] + seed[2]*seed[2]; if(r2seed<100.){ track->setTrackStatus(TRACK_STATUS_KILLED); if(_printing>0){ streamlog_out(WARNING) << "PandoraPFA::defineIntersection WARNING KILLED BAD HELIX TRACK " << trackEnergy << " chi2 " << chi2 << std::endl; streamlog_out(WARNING) << " Seed : " << track->getSeedPosition()[0] << "," << track->getSeedPosition()[1] << "," << track->getSeedPosition()[2] << std::endl; streamlog_out(WARNING) << " Dir : " << track->getSeedDirection()[0] << "," << track->getSeedDirection()[1] << "," << track->getSeedDirection()[2] << std::endl; } } if( (rinner>_tpcOuterR-1000) &&(trackEnergy>150.)){ track->setTrackStatus(TRACK_STATUS_KILLED); if(_printing>0){ streamlog_out(WARNING) << "PandoraPFA::defineIntersection WARNING KILLED KINKED HIGH ENERGY TRACK " << trackEnergy << " chi2 " << chi2 << std::endl; streamlog_out(WARNING) << " Seed : " << track->getSeedPosition()[0] << "," << track->getSeedPosition()[1] << "," << track->getSeedPosition()[2] << std::endl; streamlog_out(WARNING) << " Dir : " << track->getSeedDirection()[0] << "," << track->getSeedDirection()[1] << "," << track->getSeedDirection()[2] << std::endl; } } if(_usingTrackEndIntersection==0){ track->setSeedPosition(seed); track->setSeedDirection(dir); track->setHelix(helix); }else{ track->setAltSeedPosition(seed); track->setAltSeedDirection(dir); track->setAltHelix(helix); } } void PandoraPFAProcessor::defineAltIntersection( MyTrackExtended * track) { HelixClass * helix = new HelixClass(); TrackerHitVec hitvec = track->getTrack()->getTrackerHits(); int nhits = (int)hitvec.size(); float zmax = -99999.; float zmin = +99999.; TrackerHit* zmaxHit; TrackerHit* zminHit; for(int i =0;igetPosition()[2]; if(z>zmax){ zmax = z; zmaxHit = hitvec[i]; } if(zgetTrack()->getPhi(); d0 = track->getTrack()->getD0(); omega = track->getTrack()->getOmega(); z0 = track->getTrack()->getZ0(); tanlambda = track->getTrack()->getTanLambda(); helix->Initialize_Canonical(phi0, d0, z0, omega, tanlambda, _bField); int _nHitsInFit = 50; int nhitsFit; if (nhits > _nHitsInFit) { for (int iz = 0 ; iz < nhits-1; iz++) for (int jz = 0; jz < nhits-iz-1; jz++) { TrackerHit * one = hitvec[jz]; TrackerHit * two = hitvec[jz+1]; float dist1 = fabs(float(one->getPosition()[2])-zEnd); float dist2 = fabs(float(two->getPosition()[2])-zEnd); if(dist1 > dist2) { TrackerHit * Temp = hitvec[jz]; hitvec[jz] = hitvec[jz+1]; hitvec[jz+1] = Temp; } } nhitsFit = _nHitsInFit; }else { nhitsFit = nhits; } float * xh = new float[nhitsFit]; float * yh = new float[nhitsFit]; float * zh = new float[nhitsFit]; float * ah = new float[nhitsFit]; for (int i=0; igetPosition()[0]); yh[i] = float(hitvec[i]->getPosition()[1]); zh[i] = float(hitvec[i]->getPosition()[2]); } signPz = zEnd - zBegin; ClusterShapes * shapes = new ClusterShapes(nhitsFit,ah,xh,yh,zh); float par[5]; float dpar[5]; float chi2; float distmax; shapes->FitHelix(500, 0, 1, par, dpar, chi2, distmax); float x0 = par[0]; float y0 = par[1]; float r0 = par[2]; float bz = par[3]; float phiH = par[4]; helix->Initialize_BZ(x0, y0, r0, bz, phiH, _bField,signPz, zBegin); ref[0] = d0*sin(phi0); ref[1] = -d0*cos(phi0); ref[2] = z0; delete shapes; delete[] xh; delete[] yh; delete[] zh; delete[] ah; float zLine; if (signPz > 0) { zLine = _zOfEndcap; }else{ zLine = -_zOfEndcap; } float zp; float time_min = helix->getPointInZ(zLine, ref, seed); if(seed[2]>0.){ zp = seed[2]+0.2; }else{ zp = seed[2]-0.2; } float point[3]; helix->getPointInZ(zp,ref,point); float dx = point[0]-seed[0]; float dy = point[1]-seed[1]; float dz = point[2]-seed[2]; float dr = sqrt(dx*dx+dy*dy+dz*dz); float dir[3]; dir[0] = dx/dr; dir[1] = dy/dr; dir[2] = dz/dr; float twopi_n = twopi/((float)_symmetry); if (_symmetry > 0) { for (int i = 0; i < _symmetry; ++i) { float phi = twopi_n*((float)i) + _phiOfBarrel; float xx = _rOfBarrel*cos(phi); float yy = _rOfBarrel*sin(phi); float ax = cos(phi + 0.5*pi); float ay = sin(phi + 0.5*pi); float point[3]; float tt = helix->getPointInXY(xx,yy,ax,ay,ref,point); if (tt < time_min) { time_min = tt; seed[0] = point[0]; seed[1] = point[1]; seed[2] = point[2]; } } } if(seed[2]>0.){ zp = seed[2]+0.2; }else{ zp = seed[2]-0.2; } helix->getPointInZ(zp,ref,point); dx = point[0]-seed[0]; dy = point[1]-seed[1]; dz = point[2]-seed[2]; dr = sqrt(dx*dx+dy*dy+dz*dz); dir[0] = dx/dr; dir[1] = dy/dr; dir[2] = dz/dr; if(_usingTrackEndIntersection==1){ track->setSeedPosition(seed); track->setSeedDirection(dir); track->setHelix(helix); }else{ track->setAltSeedPosition(seed); track->setAltSeedDirection(dir); track->setAltHelix(helix); } } ProtoCluster* PandoraPFAProcessor::Arbitrate(const MyCaloHitExtended* hit, const vector & clusters, const unsigned int ilayer){ // decide which of the clusters wanting a particular hit should have it // in the simplest form just choose one with smallest genericDistance if(clusters.size()==1)return clusters[0]; ProtoCluster* bestCluster=NULL; float smallestDistance=999.; for(unsigned int icluster=0; iclustergenericDistanceToHit(hit, ilayer); if(genericDistanceWrite(); for(unsigned int i=0;iWrite(); hfile->Close(); } // now tidy up for(unsigned int i=0;iClear(); } float PandoraPFAProcessor::scalarProduct(fitResult fit1, fitResult fit2){ float cost = fit1.dir[0]*fit2.dir[0]+ fit1.dir[1]*fit2.dir[1]+ fit1.dir[2]*fit2.dir[2]; return cost; } float PandoraPFAProcessor::closestApproach(fitResult fit1, fitResult fit2){ // calculates the distance of closest approach between two fit resulrs float retVal = 99999.; if(fit1.ok==false || fit2.ok==false)return retVal; double nxyz[3]; nxyz[0] = fit1.dir[1]*fit2.dir[2]-fit1.dir[2]*fit2.dir[1]; nxyz[1] = fit1.dir[2]*fit2.dir[0]-fit1.dir[0]*fit2.dir[2]; nxyz[2] = fit1.dir[0]*fit2.dir[1]-fit1.dir[1]*fit2.dir[0]; double mag = nxyz[0]*nxyz[0] + nxyz[1]*nxyz[1] + nxyz[2]*nxyz[2]; for(int j =0;j<3;++j)nxyz[j]=nxyz[j]/sqrt(mag); double dxyz[3]; for(int j =0;j<3;++j)dxyz[j] = fit1.intercept[j] - fit2.intercept[j]; double dcloseapproach = 0.0; for(int j =0;j<3;++j)dcloseapproach += dxyz[j]*nxyz[j]; dcloseapproach = fabs(dcloseapproach); return static_cast(dcloseapproach); } int PandoraPFAProcessor::ExpectedLayersCrossed(float* xyzs, float* xyze) { // how many physical layers are crossed in going from point s to point e // assuming straight line float dx = xyze[0]-xyzs[0]; float dy = xyze[1]-xyzs[1]; float dz = xyze[2]-xyzs[2]; if(fabs(dz)==0.0)dz=1.0; float dxdz = dx/dz; float dydz = dy/dz; int islayer = this->GetPseudoLayer(xyzs); int ielayer = this->GetPseudoLayer(xyze); //std::cout << islayer << " " << ielayer << std::endl; int nsteps = 4*(ielayer-islayer); float zstep = dz/nsteps; float point[3]; int icurrent = islayer; int count = 0; for(int i=0;i<=nsteps;i++){ float dzstep = zstep*i; point[0] = xyzs[0]+dzstep*dxdz; point[1] = xyzs[1]+dzstep*dydz; point[2] = xyzs[2]+dzstep; float z = fabs(point[2]); bool gap = false; if(z>_zOfBarrel&&z<_zOfEndcap)gap = true; // in older models with no HCAL ring if(_detector==DETECTOR_LDC00 ||_detector==DETECTOR_LDC01){ if(z>_zOfBarrel&&z<_zOfHcalEndcap){ if(fabs(point[0])>_rOfEndcap)gap = true; if(fabs(point[1])>_rOfEndcap)gap = true; float u = 0.707106*(point[0]+point[1]); float v = 0.707106*(point[0]-point[1]); if(fabs(u)>_rOfEndcap)gap = true; if(fabs(v)>_rOfEndcap)gap = true; } } int ilayer = this->GetPseudoLayer(point); if(ilayer>icurrent){ if(ilayergetReferencePoint()[0]; refs[1] = helix->getReferencePoint()[1]; refs[2] = helix->getReferencePoint()[2]; float point[3]; helix->getPointInZ(zs, refs, point); int islayer = this->GetPseudoLayer(point); int icurrent = islayer; int count = 0; for(float z = zs; fabs(z)getPointInZ(z, refs, point); bool gap = false; if(z>_zOfBarrel&&z<_zOfEndcap)gap = true; // in older models with no HCAL ring if(_detector==DETECTOR_LDC00 ||_detector==DETECTOR_LDC01){ if(z>_zOfBarrel&&z<_zOfHcalEndcap){ if(fabs(point[0])>_rOfEndcap)gap = true; if(fabs(point[1])>_rOfEndcap)gap = true; float u = 0.707106*(point[0]+point[1]); float v = 0.707106*(point[0]-point[1]); if(fabs(u)>_rOfEndcap)gap = true; if(fabs(v)>_rOfEndcap)gap = true; } } int ilayer = this->GetPseudoLayer(point); if(ilayer!=icurrent){ if(!gap)count+=abs(ilayer-icurrent); icurrent=ilayer; } } return count; } float PandoraPFAProcessor::ChiClusterTrack(ProtoCluster* pC){ float chi = 0.; MyTrackExtendedVec asstracks = pC->GetTrackVec(); if(asstracks.size()>0){ float etrack = 0; for(unsigned int it=0;itgetEnergy(); } chi = this->ChiClusterTrack(pC->EnergyHAD(),etrack); } return chi; } float PandoraPFAProcessor::ChiClusterTrack(ProtoCluster* pC, float eExtra){ float chi = 0.; MyTrackExtendedVec asstracks = pC->GetTrackVec(); if(asstracks.size()>0){ float etrack = 0; for(unsigned int it=0;itgetEnergy(); } chi = this->ChiClusterTrack(pC->EnergyHAD()+eExtra,etrack); } return chi; } float PandoraPFAProcessor::ChiClusterTrack(MyTrackExtended* pT){ float chi = 0.; ProtoClusterVec clusters = pT->getClusterVec(); if(clusters.size()==1)chi = this->ChiClusterTrack(clusters[0]); return chi; } float PandoraPFAProcessor::ChiClusterTrack(MyTrackExtended* pT, float extra){ float chi = 0.; ProtoClusterVec clusters = pT->getClusterVec(); if(clusters.size()==1)chi = this->ChiClusterTrack(clusters[0],extra); return chi; } float PandoraPFAProcessor::ChiClusterTrack(float eC, float eT){ float chi = 0.; if(eT>0.001){ float sigE = _hadEnergyRes*sqrt(eT); chi = (eC-eT)/sigE; } return chi; } float PandoraPFAProcessor::EOverP(ProtoCluster* pC){ float eop = 1.; MyTrackExtendedVec asstracks = pC->GetTrackVec(); if(asstracks.size()>0){ float etrack = 0; for(unsigned int it=0;itgetEnergy(); } if(etrack>0.001)eop = pC->EnergyHAD()/etrack; } return eop; } float PandoraPFAProcessor::EOverP(MyTrackExtended* pT){ float eop = 1.; ProtoClusterVec clusters = pT->getClusterVec(); if(clusters.size()==1)eop = this->EOverP(clusters[0]); return eop; } bool PandoraPFAProcessor::IsClusterLeavingDetector(ProtoCluster* pC){ bool leavingCluster =false; int layersFromEdge = this->LayersFromEdge(pC); if(layersFromEdge<=3){ int ll = pC->LastLayer(); int nhits5=0; int nlayers5=0; float e5=0.; for(int il = ll-4;il<=ll;il++){ int ihits = pC->hitsInLayer(il); if(ihits>0)nlayers5++; nhits5+=ihits; for(int ihit=0;ihithitInLayer(il,ihit); e5 += hit->getEnergyHAD(); } } if(nlayers5>=4 || (nlayers5==3&&e5>1.0) )leavingCluster=true; } if(leavingCluster){ int nmuons = this->AssociatedMuonHits(pC); if(nmuons>0&&_printing>1)std::cout << " Leaving cluster muons : " << nmuons << std::endl; } return leavingCluster; } float PandoraPFAProcessor::EnergyLeavingDetector(ProtoCluster* pC){ // get the isolated hits int lastLayer = pC->LastLayer(); int firstLayer = pC->FirstLayer(); bool keepLooking = true; float eLeaving = 0; float eOldLayer = 999; for(int ilayer=lastLayer;ilayer>firstLayer && keepLooking ;ilayer--){ int nhits = pC->hitsInLayer(ilayer); float eLayer = 0; for(int ihit=0;ihithitInLayer(ilayer,ihit); float pos[3]; pos[0] = phit->getPosition()[0]; pos[1] = phit->getPosition()[1]; pos[2] = phit->getPosition()[2]; int layersFromEdge = this->LayersFromEdge(pos); if(layersFromEdge<_leavingHitLayersFromEdge){ eLeaving += phit->getEnergyHAD(); eLayer += phit->getEnergyHAD(); } } if(eLayer ==0 && eOldLayer==0 )keepLooking = false; eOldLayer = eLayer; } return eLeaving; } int PandoraPFAProcessor::AssociatedMuonHits(ProtoCluster* pC){ int muonHits = 0; int lastLayer = pC->FirstLayer(); float xc = pC->GetCentroid(lastLayer)[0]; float yc = pC->GetCentroid(lastLayer)[1]; float zc = pC->GetCentroid(lastLayer)[2]; float rc = sqrt(xc*xc+yc*yc+zc*zc); for(unsigned int i=0;i<_muonHits.size();++i){ float x = _muonHits[i]->getPosition()[0]; float y = _muonHits[i]->getPosition()[1]; float z = _muonHits[i]->getPosition()[2]; float r = sqrt(x*x+y*y+z*z); float dcos = (x*xc+y*yc+z*zc)/r/rc; if(dcos>0.8)muonHits++; } return muonHits; } void PandoraPFAProcessor::CleanClusters(ProtoClusterVec &pCs){ if(_printing>1)std::cout << " CLEAN CLUSTERS " << pCs.size() << std::endl; int n = static_cast(pCs.size()); for(int icluster=0;iclusterEnergyHAD(); for(int ilayer=pCi->FirstLayer();ilayer<=_nEcalLayers;++ilayer){ for(int ihit = 0; ihit hitsInLayer(ilayer);++ihit){ MyCaloHitExtended* hiti = pCi->hitInLayer(ilayer,ihit); float ehit = hiti->getEnergyHAD(); if(ehit>1. && ehit/ecluster>0.2){ if(_printing>1)std::cout << " CLEAN CLUSTERS HIT " << icluster << ":" << ihit << " layer = " << ilayer << " E = " << ehit << " from ECluster = " << ecluster << std::endl; // get new energy from surrounding layers float em =0.; float ep =0.; float e =0.; if(ilayer>1){ for(int i = 0; i hitsInLayer(ilayer-1);++i)em += (pCi->hitInLayer(ilayer-1,i))->getEnergyHAD(); } for(int i = 0; i hitsInLayer(ilayer);++i)e += (pCi->hitInLayer(ilayer,i))->getEnergyHAD(); for(int i = 0; i hitsInLayer(ilayer+1);++i)ep += (pCi->hitInLayer(ilayer+1,i))->getEnergyHAD(); float enew = em+ep; if(ilayer>1)enew=enew/2.; enew = enew - e + ehit; if(enew<0.2)enew=0.2; if(enewRemoveHit(hiti); hiti->setEnergyEM(enew); hiti->setEnergyHAD(enew); pCi->AddHit(hiti); } } } } } if(_printing>5)std::cout << " CLEAN CLUSTERS done " << std::endl; return; }