CMS 3D CMS Logo

/afs/cern.ch/work/a/aaltunda/public/www/CMSSW_6_2_7/src/SimGeneral/TrackingAnalysis/plugins/TrackingTruthAccumulator.cc

Go to the documentation of this file.
00001 
00023 #include "SimGeneral/TrackingAnalysis/interface/TrackingTruthAccumulator.h"
00024 
00025 #include <SimGeneral/MixingModule/interface/DigiAccumulatorMixModFactory.h>
00026 #include <FWCore/MessageLogger/interface/MessageLogger.h>
00027 #include <FWCore/Framework/interface/Event.h>
00028 #include <FWCore/Framework/interface/EventSetup.h>
00029 #include <FWCore/ParameterSet/interface/ParameterSet.h>
00030 #include <SimGeneral/MixingModule/interface/PileUpEventPrincipal.h>
00031 #include "FWCore/Framework/interface/EDProducer.h"
00032 #include "SimGeneral/TrackingAnalysis/interface/EncodedTruthId.h"
00033 #include "SimDataFormats/GeneratorProducts/interface/HepMCProduct.h"
00034 #include "SimDataFormats/TrackingAnalysis/interface/TrackingParticle.h"
00035 #include "SimDataFormats/TrackingAnalysis/interface/TrackingVertex.h"
00036 #include "SimDataFormats/TrackingHit/interface/PSimHit.h"
00037 #include "FWCore/MessageLogger/interface/MessageLogger.h"
00038 
00039 #include "DataFormats/SiPixelDetId/interface/PixelSubdetector.h"
00040 #include "DataFormats/SiStripDetId/interface/StripSubdetector.h"
00041 #include "DataFormats/SiPixelDetId/interface/PXBDetId.h"
00042 #include "DataFormats/SiPixelDetId/interface/PXFDetId.h"
00043 #include "DataFormats/SiStripDetId/interface/TECDetId.h"
00044 #include "DataFormats/SiStripDetId/interface/TIBDetId.h"
00045 #include "DataFormats/SiStripDetId/interface/TIDDetId.h"
00046 #include "DataFormats/SiStripDetId/interface/TOBDetId.h"
00047 #include "DataFormats/HepMCCandidate/interface/GenParticle.h"
00048 
00049 
00050 
00051 
00052 //---------------------------------------------------------------------------------
00053 //---------------------------------------------------------------------------------
00054 //---------------------------------------------------------------------------------
00055 //------                                                                     ------
00056 //------  Declarations for utility classes and functions in the unnamed      ------
00057 //------  namespace. The definitions are right at the bottom of the file.    ------
00058 //------                                                                     ------
00059 //---------------------------------------------------------------------------------
00060 //---------------------------------------------------------------------------------
00061 //---------------------------------------------------------------------------------
00062 
00063 namespace
00064 {
00069         struct DecayChainTrack
00070         {
00071                 int simTrackIndex;
00072                 struct DecayChainVertex* pParentVertex;
00073                 // Some things have multiple decay vertices. Not sure how that works but it seems to be mostly electrons and some photons.
00074                 std::vector<struct DecayChainVertex*> daughterVertices;
00075                 DecayChainTrack* pMergedBremSource;
00076                 DecayChainTrack() : simTrackIndex(-1), pParentVertex(NULL), pMergedBremSource(NULL) {}
00077                 DecayChainTrack( int newSimTrackIndex ) : simTrackIndex(newSimTrackIndex), pParentVertex(NULL), pMergedBremSource() {}
00078         };
00079 
00084         struct DecayChainVertex
00085         {
00086                 int simVertexIndex;
00087                 DecayChainTrack* pParentTrack;
00088                 std::vector<DecayChainTrack*> daughterTracks;
00089                 DecayChainVertex* pMergedBremSource;
00090                 DecayChainVertex() : simVertexIndex(-1), pParentTrack(NULL), pMergedBremSource(NULL) {}
00091                 DecayChainVertex( int newIndex ) : simVertexIndex(newIndex), pParentTrack(NULL), pMergedBremSource(NULL) {}
00092         };
00093 
00104         struct DecayChain
00105         {
00106         public:
00107                 DecayChain( const std::vector<SimTrack>& trackCollection, const std::vector<SimVertex>& vertexCollection );
00108                 const size_t decayTracksSize;
00109                 const size_t decayVerticesSize;
00110 
00115                 void integrityCheck();
00116                 const SimTrack& getSimTrack( const ::DecayChainTrack* pDecayTrack ) const { return simTrackCollection_.at( pDecayTrack->simTrackIndex ); }
00117                 const SimVertex& getSimVertex( const ::DecayChainVertex* pDecayVertex ) const { return simVertexCollection_.at( pDecayVertex->simVertexIndex ); }
00118         private:
00119                 void findBrem( const std::vector<SimTrack>& trackCollection, const std::vector<SimVertex>& vertexCollection );
00120                 std::unique_ptr< ::DecayChainTrack[]> decayTracks_;
00121                 std::unique_ptr< ::DecayChainVertex[]> decayVertices_;
00122 
00124                 std::vector< ::DecayChainVertex*> rootVertices_;
00125 
00126                 // Keep a record of the constructor parameters
00127                 const std::vector<SimTrack>& simTrackCollection_;
00128                 const std::vector<SimVertex>& simVertexCollection_;
00129         public:
00130                 const std::unique_ptr< ::DecayChainTrack[]>& decayTracks; 
00131                 const std::unique_ptr< ::DecayChainVertex[]>& decayVertices; 
00132                 const std::vector< ::DecayChainVertex*>& rootVertices; 
00133         };
00134 
00139         class TrackingParticleFactory
00140         {
00141         public:
00142                 TrackingParticleFactory( const ::DecayChain& decayChain, const edm::Handle< std::vector<reco::GenParticle> >& hGenParticles,
00143                                 const edm::Handle< std::vector<int> >& hHepMCGenParticleIndices, const std::vector<const PSimHit*>& simHits,
00144                                 double volumeRadius, double volumeZ, bool allowDifferentProcessTypes );
00145                 TrackingParticle createTrackingParticle( const DecayChainTrack* pTrack ) const;
00146                 TrackingVertex createTrackingVertex( const DecayChainVertex* pVertex ) const;
00147                 bool vectorIsInsideVolume( const math::XYZTLorentzVectorD& vector ) const;
00148         private:
00149                 const ::DecayChain& decayChain_;
00150                 const edm::Handle< std::vector<reco::GenParticle> >& hGenParticles_;
00151                 std::vector<int> genParticleIndices_;
00152                 const std::vector<const PSimHit*>& simHits_;
00153                 const double volumeRadius_;
00154                 const double volumeZ_;
00155                 std::multimap<unsigned int, size_t> trackIdToHitIndex_; 
00156                 bool allowDifferentProcessTypeForDifferentDetectors_; 
00157         };
00158 
00163         class OutputCollectionWrapper
00164         {
00165         public:
00166                 OutputCollectionWrapper( const DecayChain& decayChain, TrackingTruthAccumulator::OutputCollections& outputCollections );
00167                 TrackingParticle* addTrackingParticle( const ::DecayChainTrack* pDecayTrack, const TrackingParticle& trackingParticle );
00168                 TrackingVertex* addTrackingVertex( const ::DecayChainVertex* pDecayVertex, const TrackingVertex& trackingVertex );
00169                 TrackingParticle* getTrackingParticle( const ::DecayChainTrack* pDecayTrack );
00171                 void setProxy( const ::DecayChainTrack* pOriginalTrack, const ::DecayChainTrack* pProxyTrack );
00172                 void setProxy( const ::DecayChainVertex* pOriginalVertex, const ::DecayChainVertex* pProxyVertex );
00173                 TrackingVertex* getTrackingVertex( const ::DecayChainVertex* pDecayVertex );
00174                 TrackingParticleRef getRef( const ::DecayChainTrack* pDecayTrack );
00175                 TrackingVertexRef getRef( const ::DecayChainVertex* pDecayVertex );
00176         private:
00177                 void associateToExistingObjects( const ::DecayChainVertex* pChainVertex );
00178                 void associateToExistingObjects( const ::DecayChainTrack* pChainTrack );
00179                 TrackingTruthAccumulator::OutputCollections& output_;
00180                 std::vector<int> trackingParticleIndices_;
00181                 std::vector<int> trackingVertexIndices_;
00182         };
00183 
00186         int LayerFromDetid( const DetId& detid );
00187 
00192         TrackingParticle* addTrackAndParentVertex( ::DecayChainTrack* pDecayTrack, const TrackingParticle& trackingParticle, ::OutputCollectionWrapper* pOutput );
00193 
00198         void addTrack( ::DecayChainTrack* pDecayChainTrack, const TrackingParticleSelector* pSelector, ::OutputCollectionWrapper* pUnmergedOutput, ::OutputCollectionWrapper* pMergedOutput, const ::TrackingParticleFactory& objectFactory, bool addAncestors );
00199 
00200 } // end of the unnamed namespace
00201 
00202 
00203 
00204 
00205 //---------------------------------------------------------------------------------
00206 //---------------------------------------------------------------------------------
00207 //---------------------------------------------------------------------------------
00208 //------                                                                     ------
00209 //------  Definitions for the TrackingTruthAccumulator methods               ------
00210 //------  are below.                                                         ------
00211 //------                                                                     ------
00212 //---------------------------------------------------------------------------------
00213 //---------------------------------------------------------------------------------
00214 //---------------------------------------------------------------------------------
00215 
00216 TrackingTruthAccumulator::TrackingTruthAccumulator( const edm::ParameterSet & config, edm::EDProducer& mixMod ) :
00217                 messageCategory_("TrackingTruthAccumulator"),
00218                 volumeRadius_( config.getParameter<double>("volumeRadius") ),
00219                 volumeZ_( config.getParameter<double>("volumeZ") ),
00220                 ignoreTracksOutsideVolume_( config.getParameter<bool>("ignoreTracksOutsideVolume") ),
00221                 maximumPreviousBunchCrossing_( config.getParameter<unsigned int>("maximumPreviousBunchCrossing") ),
00222                 maximumSubsequentBunchCrossing_( config.getParameter<unsigned int>("maximumSubsequentBunchCrossing") ),
00223                 createUnmergedCollection_( config.getParameter<bool>("createUnmergedCollection") ),
00224                 createMergedCollection_(config.getParameter<bool>("createMergedBremsstrahlung") ),
00225                 addAncestors_( config.getParameter<bool>("alwaysAddAncestors") ),
00226                 removeDeadModules_( config.getParameter<bool>("removeDeadModules") ),
00227                 simTrackLabel_( config.getParameter<edm::InputTag>("simTrackCollection") ),
00228                 simVertexLabel_( config.getParameter<edm::InputTag>("simVertexCollection") ),
00229                 simHitCollectionConfig_( config.getParameter<edm::ParameterSet>("simHitCollections") ),
00230                 genParticleLabel_( config.getParameter<edm::InputTag>("genParticleCollection") ),
00231                 allowDifferentProcessTypeForDifferentDetectors_( config.getParameter<bool>("allowDifferentSimHitProcesses") )
00232 {
00233         //
00234         // Make sure at least one of the merged and unmerged collections have been set
00235         // to be created.
00236         //
00237         if( !createUnmergedCollection_ && !createMergedCollection_ )
00238                 edm::LogError(messageCategory_) << "Both \"createUnmergedCollection\" and \"createMergedBremsstrahlung\" have been"
00239                         << "set to false, which means no collections will be created";
00240 
00241 
00242         //
00243         // Initialize selection for building TrackingParticles
00244         //
00245         if( config.exists( "select" ) )
00246         {
00247                 edm::ParameterSet param=config.getParameter<edm::ParameterSet>("select");
00248                 selector_=TrackingParticleSelector( param.getParameter<double>( "ptMinTP" ),
00249                                 param.getParameter<double>( "minRapidityTP" ),
00250                                 param.getParameter<double>( "maxRapidityTP" ),
00251                                 param.getParameter<double>( "tipTP" ),
00252                                 param.getParameter<double>( "lipTP" ),
00253                                 param.getParameter<int>( "minHitTP" ),
00254                                 param.getParameter<bool>( "signalOnlyTP" ),
00255                                 param.getParameter<bool>( "chargedOnlyTP" ),
00256                                 param.getParameter<bool>( "stableOnlyTP" ),
00257                                 param.getParameter<std::vector<int> >("pdgIdTP") );
00258                 selectorFlag_=true;
00259 
00260                 // Also set these two variables, which are used to drop out early if the SimTrack doesn't conform.
00261                 // The selector_ requires a full TrackingParticle object, but these two variables can veto things early.
00262                 chargedOnly_=param.getParameter<bool>( "chargedOnlyTP" );
00263                 signalOnly_=param.getParameter<bool>( "signalOnlyTP" );
00264         }
00265         else
00266         {
00267                 selectorFlag_=false;
00268                 chargedOnly_=false;
00269                 signalOnly_=false;
00270         }
00271 
00272         //
00273         // Need to state what collections are going to be added to the event. This
00274         // depends on which of the merged and unmerged collections have been configured
00275         // to be created.
00276         //
00277         if( createUnmergedCollection_ )
00278         {
00279                 mixMod.produces<TrackingVertexCollection>();
00280                 mixMod.produces<TrackingParticleCollection>();
00281         }
00282 
00283         if( createMergedCollection_ )
00284         {
00285                 mixMod.produces<TrackingParticleCollection>("MergedTrackTruth");
00286                 mixMod.produces<TrackingVertexCollection>("MergedTrackTruth");
00287         }
00288 }
00289 
00290 void TrackingTruthAccumulator::initializeEvent( edm::Event const& event, edm::EventSetup const& setup )
00291 {
00292         if( createUnmergedCollection_ )
00293         {
00294                 unmergedOutput_.pTrackingParticles.reset( new TrackingParticleCollection );
00295                 unmergedOutput_.pTrackingVertices.reset( new TrackingVertexCollection );
00296                 unmergedOutput_.refTrackingParticles=const_cast<edm::Event&>( event ).getRefBeforePut<TrackingParticleCollection>();
00297                 unmergedOutput_.refTrackingVertexes=const_cast<edm::Event&>( event ).getRefBeforePut<TrackingVertexCollection>();
00298         }
00299 
00300         if( createMergedCollection_ )
00301         {
00302                 mergedOutput_.pTrackingParticles.reset( new TrackingParticleCollection );
00303                 mergedOutput_.pTrackingVertices.reset( new TrackingVertexCollection );
00304                 mergedOutput_.refTrackingParticles=const_cast<edm::Event&>( event ).getRefBeforePut<TrackingParticleCollection>("MergedTrackTruth");
00305                 mergedOutput_.refTrackingVertexes=const_cast<edm::Event&>( event ).getRefBeforePut<TrackingVertexCollection>("MergedTrackTruth");
00306         }
00307 }
00308 
00309 void TrackingTruthAccumulator::accumulate( edm::Event const& event, edm::EventSetup const& setup )
00310 {
00311         // Call the templated version that does the same for both signal and pileup events
00312         accumulateEvent( event, setup );
00313 }
00314 
00315 void TrackingTruthAccumulator::accumulate( PileUpEventPrincipal const& event, edm::EventSetup const& setup )
00316 {
00317         // If this bunch crossing is outside the user configured limit, don't do anything.
00318         if( event.bunchCrossing()>=-static_cast<int>(maximumPreviousBunchCrossing_) && event.bunchCrossing()<=static_cast<int>(maximumSubsequentBunchCrossing_) )
00319         {
00320                 //edm::LogInfo(messageCategory_) << "Analysing pileup event for bunch crossing " << event.bunchCrossing();
00321                 accumulateEvent( event, setup );
00322         }
00323         else edm::LogInfo(messageCategory_) << "Skipping pileup event for bunch crossing " << event.bunchCrossing();
00324 }
00325 
00326 void TrackingTruthAccumulator::finalizeEvent( edm::Event& event, edm::EventSetup const& setup )
00327 {
00328 
00329         if( createUnmergedCollection_ )
00330         {
00331                 edm::LogInfo("TrackingTruthAccumulator") << "Adding " << unmergedOutput_.pTrackingParticles->size() << " TrackingParticles and " << unmergedOutput_.pTrackingVertices->size()
00332                                 << " TrackingVertexs to the event.";
00333 
00334                 event.put( unmergedOutput_.pTrackingParticles );
00335                 event.put( unmergedOutput_.pTrackingVertices );
00336         }
00337 
00338         if( createMergedCollection_ )
00339         {
00340                 edm::LogInfo("TrackingTruthAccumulator") << "Adding " << mergedOutput_.pTrackingParticles->size() << " merged TrackingParticles and " << mergedOutput_.pTrackingVertices->size()
00341                                 << " merged TrackingVertexs to the event.";
00342 
00343                 event.put( mergedOutput_.pTrackingParticles, "MergedTrackTruth" );
00344                 event.put( mergedOutput_.pTrackingVertices, "MergedTrackTruth" );
00345         }
00346 
00347 }
00348 
00349 template<class T> void TrackingTruthAccumulator::accumulateEvent( const T& event, const edm::EventSetup& setup )
00350 {
00351         //
00352         // Get the collections
00353         //
00354         edm::Handle<std::vector<SimTrack> > hSimTracks;
00355         edm::Handle<std::vector<SimVertex> > hSimVertices;
00356         edm::Handle< std::vector<reco::GenParticle> > hGenParticles;
00357         edm::Handle< std::vector<int> > hGenParticleIndices;
00358 
00359         event.getByLabel( simTrackLabel_, hSimTracks );
00360         event.getByLabel( simVertexLabel_, hSimVertices );
00361 
00362         try
00363         {
00364                 event.getByLabel( genParticleLabel_, hGenParticles );
00365                 event.getByLabel( genParticleLabel_, hGenParticleIndices );
00366         }
00367         catch( cms::Exception& exception )
00368         {
00369                 //
00370                 // The Monte Carlo is not always available, e.g. for pileup events. The information
00371                 // is only used if it's available, but for some reason the PileUpEventPrincipal
00372                 // wrapper throws an exception here rather than waiting to see if the handle is
00373                 // used (as is the case for edm::Event). So I just want to catch this exception
00374                 // and use the normal handle checking later on.
00375                 //
00376         }
00377 
00378         // Run through the collections and work out the decay chain of each track/vertex. The
00379         // information in SimTrack and SimVertex only allows traversing upwards, but this will
00380         // allow traversal in both directions. This is required for things like grouping electrons
00381         // that bremsstrahlung as one TrackingParticle if "mergedBremsstrahlung" is set in the
00382         // config file.
00383         DecayChain decayChain( *hSimTracks, *hSimVertices );
00384 
00385         // I only want to create these collections if they're actually required
00386         std::auto_ptr< ::OutputCollectionWrapper> pUnmergedCollectionWrapper;
00387         std::auto_ptr< ::OutputCollectionWrapper> pMergedCollectionWrapper;
00388         if( createUnmergedCollection_ ) pUnmergedCollectionWrapper.reset( new ::OutputCollectionWrapper( decayChain, unmergedOutput_ ) );
00389         if( createMergedCollection_ ) pMergedCollectionWrapper.reset( new ::OutputCollectionWrapper( decayChain, mergedOutput_ ) );
00390 
00391         std::vector<const PSimHit*> simHitPointers;
00392         fillSimHits( simHitPointers, event, setup );
00393         TrackingParticleFactory objectFactory( decayChain, hGenParticles, hGenParticleIndices, simHitPointers, volumeRadius_, volumeZ_, allowDifferentProcessTypeForDifferentDetectors_ );
00394 
00395         // While I'm testing, perform some checks.
00396         // TODO - drop this call once I'm happy it works in all situations.
00397         //decayChain.integrityCheck();
00398 
00399         TrackingParticleSelector* pSelector=NULL;
00400         if( selectorFlag_ ) pSelector=&selector_;
00401 
00402         // Run over all of the SimTracks, but because I'm interested in the decay hierarchy
00403         // do it through the DecayChainTrack objects. These are looped over in sequence here
00404         // but they have the hierarchy information for the functions called to traverse the
00405         // decay chain.
00406 
00407         for( size_t index=0; index<decayChain.decayTracksSize; ++index )
00408         {
00409                 ::DecayChainTrack* pDecayTrack=&decayChain.decayTracks[index];
00410                 const SimTrack& simTrack=hSimTracks->at(pDecayTrack->simTrackIndex);
00411 
00412 
00413                 // Perform some quick checks to see if we can drop out early. Note that these are
00414                 // a subset of the cuts in the selector_ so the created TrackingParticle could still
00415                 // fail. The selector_ requires the full TrackingParticle to be made however, which
00416                 // can be computationally expensive.
00417                 if( chargedOnly_ && simTrack.charge()==0 ) continue;
00418                 if( signalOnly_ && (simTrack.eventId().bunchCrossing()!=0 || simTrack.eventId().event()!=0) ) continue;
00419 
00420                 // Also perform a check to see if the production vertex is inside the tracker volume (if required).
00421                 if( ignoreTracksOutsideVolume_ )
00422                 {
00423                         const SimVertex& simVertex=hSimVertices->at( pDecayTrack->pParentVertex->simVertexIndex );
00424                         if( !objectFactory.vectorIsInsideVolume( simVertex.position() ) ) continue;
00425                 }
00426 
00427 
00428                 // This function creates the TrackinParticle and adds it to the collection if it
00429                 // passes the selection criteria specified in the configuration. If the config
00430                 // specifies adding ancestors, the function is called recursively to do that.
00431                 ::addTrack( pDecayTrack, pSelector, pUnmergedCollectionWrapper.get(), pMergedCollectionWrapper.get(), objectFactory, addAncestors_ );
00432         }
00433 }
00434 
00435 template<class T> void TrackingTruthAccumulator::fillSimHits( std::vector<const PSimHit*>& returnValue, const T& event, const edm::EventSetup& setup )
00436 {
00437         std::vector<std::string> parameterNames=simHitCollectionConfig_.getParameterNames();
00438 
00439         // loop over the different parameter collections. The names of these are unimportant but
00440         // usually set to the sub-detectors, e.g. "muon", "pixel" etcetera.
00441         for( const auto& parameterName : parameterNames )
00442         {
00443                 std::vector<edm::InputTag> collectionTags=simHitCollectionConfig_.getParameter<std::vector<edm::InputTag> >(parameterName);
00444 
00445                 for( const auto& collectionTag : collectionTags )
00446                 {
00447                         edm::Handle< std::vector<PSimHit> > hSimHits;
00448                         event.getByLabel( collectionTag, hSimHits );
00449 
00450                         // TODO - implement removing the dead modules
00451                         for( const auto& simHit : *hSimHits )
00452                         {
00453                                 returnValue.push_back( &simHit );
00454                         }
00455 
00456                 } // end of loop over InputTags
00457         } // end of loop over parameter names. These are arbitrary but usually "muon", "pixel" etcetera.
00458 }
00459 
00460 
00461 //---------------------------------------------------------------------------------
00462 //---------------------------------------------------------------------------------
00463 //---------------------------------------------------------------------------------
00464 //------                                                                     ------
00465 //------  End of the definitions for the TrackingTruthAccumulator methods.   ------
00466 //------  Definitions for the functions and classes declared in the unnamed  ------
00467 //------  namespace are below. Documentation for those is above, where       ------
00468 //------  they're declared.                                                  ------
00469 //------                                                                     ------
00470 //---------------------------------------------------------------------------------
00471 //---------------------------------------------------------------------------------
00472 //---------------------------------------------------------------------------------
00473 
00474 
00475 namespace // Unnamed namespace for things only used in this file
00476 {
00477         //---------------------------------------------------------------------------------
00478         //---------------------------------------------------------------------------------
00479         //----   TrackingParticleFactory methods   ----------------------------------------
00480         //---------------------------------------------------------------------------------
00481         //---------------------------------------------------------------------------------
00482 
00483         ::TrackingParticleFactory::TrackingParticleFactory( const ::DecayChain& decayChain, const edm::Handle< std::vector<reco::GenParticle> >& hGenParticles,
00484                         const edm::Handle< std::vector<int> >& hHepMCGenParticleIndices, const std::vector<const PSimHit*>& simHits,
00485                         double volumeRadius, double volumeZ, bool allowDifferentProcessTypes )
00486                 : decayChain_(decayChain), hGenParticles_(hGenParticles), simHits_(simHits), volumeRadius_(volumeRadius),
00487                   volumeZ_(volumeZ), allowDifferentProcessTypeForDifferentDetectors_(allowDifferentProcessTypes)
00488         {
00489                 // Need to create a multimap to get from a SimTrackId to all of the hits in it. The SimTrackId
00490                 // is an unsigned int.
00491                 for( size_t index=0; index<simHits_.size(); ++index )
00492                 {
00493                         trackIdToHitIndex_.insert( std::make_pair( simHits_[index]->trackId(), index ) );
00494                 }
00495 
00496                 if( hHepMCGenParticleIndices.isValid() ) // Monte Carlo might not be available for the pileup events
00497                 {
00498                         genParticleIndices_.resize( hHepMCGenParticleIndices->size()+1 );
00499 
00500                         // What I need is the reverse mapping of this vector. The sizes are already equivalent because I set
00501                         // the size in the initialiser list.
00502                         for( size_t recoGenParticleIndex=0; recoGenParticleIndex<hHepMCGenParticleIndices->size(); ++recoGenParticleIndex )
00503                         {
00504                                 size_t hepMCGenParticleIndex=(*hHepMCGenParticleIndices)[recoGenParticleIndex];
00505 
00506                                 // They should be the same size, give or take a fencepost error, so this should never happen - but just in case
00507                                 if( genParticleIndices_.size()<hepMCGenParticleIndex ) genParticleIndices_.resize(hepMCGenParticleIndex);
00508 
00509                                 genParticleIndices_[ hepMCGenParticleIndex ]=recoGenParticleIndex;
00510                         }
00511                 }
00512         }
00513 
00514         TrackingParticle TrackingParticleFactory::createTrackingParticle( const ::DecayChainTrack* pChainTrack ) const
00515         {
00516                 typedef math::XYZTLorentzVectorD LorentzVector;
00517                 typedef math::XYZPoint Vector;
00518 
00519                 const SimTrack& simTrack=decayChain_.getSimTrack( pChainTrack );
00520                 const SimVertex& parentSimVertex=decayChain_.getSimVertex( pChainTrack->pParentVertex );
00521 
00522                 LorentzVector position( 0, 0, 0, 0 );
00523                 if( !simTrack.noVertex() ) position=parentSimVertex.position();
00524 
00525                 int pdgId=simTrack.type();
00526 
00527                 TrackingParticle returnValue;
00528                 // N.B. The sim track is added a few lines below, the parent and decay vertices are added in
00529                 // another function later on.
00530 
00531                 //
00532                 // If there is some valid Monte Carlo for this track, take some information from that.
00533                 // Only do so if it is from the signal event however. Not sure why but that's what the
00534                 // old code did.
00535                 //
00536                 if( simTrack.eventId().event()==0 && simTrack.eventId().bunchCrossing()==0 ) // if this is a track in the signal event
00537                 {
00538                         int hepMCGenParticleIndex=simTrack.genpartIndex();
00539                         if( hepMCGenParticleIndex>=0 && hGenParticles_.isValid() )
00540                         {
00541                                 int recoGenParticleIndex=genParticleIndices_[hepMCGenParticleIndex];
00542                                 reco::GenParticleRef generatorParticleRef( hGenParticles_, recoGenParticleIndex );
00543                                 pdgId=generatorParticleRef->pdgId();
00544                                 returnValue.addGenParticle( generatorParticleRef );
00545                         }
00546                 }
00547 
00548                 returnValue.addG4Track( simTrack );
00549 
00550                 // I need to run over the sim hits and count up the different types of hits. To be honest
00551                 // I don't fully understand this next section of code, I copied it from the old TrackingTruthProducer
00552                 // to provide the same results. The different types of hits that I need to count are:
00553                 size_t matchedHits=0; // As far as I can tell, this is the number of tracker layers with hits on them, i.e. taking account of overlaps.
00554                 size_t numberOfHits=0; // The total number of hits not taking account of overlaps.
00555                 size_t numberOfTrackerHits=0; // The number of tracker hits not taking account of overlaps.
00556 
00557                 bool init=true;
00558                 int processType=0;
00559                 int particleType=0;
00560                 int oldLayer = 0;
00561                 int newLayer = 0;
00562                 DetId oldDetector;
00563                 DetId newDetector;
00564 
00565                 for( std::multimap<unsigned int,size_t>::const_iterator iHitIndex=trackIdToHitIndex_.lower_bound( simTrack.trackId() );
00566                                 iHitIndex!=trackIdToHitIndex_.upper_bound( simTrack.trackId() );
00567                                 ++iHitIndex )
00568                 {
00569                         const auto& pSimHit=simHits_[ iHitIndex->second ];
00570 
00571                         // Initial condition for consistent simhit selection
00572                         if( init )
00573                         {
00574                                 processType=pSimHit->processType();
00575                                 particleType=pSimHit->particleType();
00576                                 newDetector=DetId( pSimHit->detUnitId() );
00577                                 init=false;
00578                         }
00579 
00580                         oldDetector=newDetector;
00581                         newDetector=DetId( pSimHit->detUnitId() );
00582 
00583                         // Fast sim seems to have different processType between tracker and muons, so if this flag
00584                         // has been set allow the processType to change if the detector changes.
00585                         if( allowDifferentProcessTypeForDifferentDetectors_ && newDetector.det()!=oldDetector.det() ) processType=pSimHit->processType();
00586 
00587                         // Check for delta and interaction products discards
00588                         if( processType==pSimHit->processType() && particleType==pSimHit->particleType() && pdgId==pSimHit->particleType() )
00589                         {
00590                                 ++numberOfHits;
00591                                 if( newDetector.det() == DetId::Tracker ) ++numberOfTrackerHits;
00592 
00593                                 oldLayer=newLayer;
00594                                 newLayer=LayerFromDetid( newDetector );
00595 
00596                                 // Count hits using layers for glued detectors
00597                                 // newlayer !=0 excludes Muon layers set to 0 by LayerFromDetid
00598                                 if( (oldLayer!=newLayer || (oldLayer==newLayer && oldDetector.subdetId()!=newDetector.subdetId())) && newLayer!=0 ) ++matchedHits;
00599                         }
00600                 } // end of loop over the sim hits for this sim track
00601 
00602                 returnValue.setNumberOfTrackerLayers( matchedHits );
00603                 returnValue.setNumberOfHits( numberOfHits );
00604                 returnValue.setNumberOfTrackerHits( numberOfTrackerHits );
00605 
00606                 return returnValue;
00607         }
00608 
00609         TrackingVertex TrackingParticleFactory::createTrackingVertex( const ::DecayChainVertex* pChainVertex ) const
00610         {
00611                 const SimVertex& simVertex=decayChain_.getSimVertex( pChainVertex );
00612 
00613                 bool isInVolume=this->vectorIsInsideVolume( simVertex.position() );
00614 
00615                 // TODO - Still need to set the truth ID properly. I'm not sure what to set
00616                 // the second parameter of the EncodedTruthId constructor to.
00617                 TrackingVertex returnValue( simVertex.position(), isInVolume, EncodedTruthId( simVertex.eventId(), 0 ) );
00618                 return returnValue;
00619         }
00620 
00621         bool ::TrackingParticleFactory::vectorIsInsideVolume( const math::XYZTLorentzVectorD& vector ) const
00622         {
00623                 return ( vector.Pt()<volumeRadius_ && vector.z()<volumeZ_ );
00624         }
00625 
00626         //---------------------------------------------------------------------------------
00627         //---------------------------------------------------------------------------------
00628         //----   DecayChain methods   -----------------------------------------------------
00629         //---------------------------------------------------------------------------------
00630         //---------------------------------------------------------------------------------
00631 
00632         ::DecayChain::DecayChain( const std::vector<SimTrack>& trackCollection, const std::vector<SimVertex>& vertexCollection )
00633                 : decayTracksSize( trackCollection.size() ),
00634                   decayVerticesSize( vertexCollection.size() ),
00635                   decayTracks_( new DecayChainTrack[decayTracksSize] ),
00636                   decayVertices_( new DecayChainVertex[decayVerticesSize] ),
00637                   simTrackCollection_( trackCollection ),
00638                   simVertexCollection_( vertexCollection ),
00639                   decayTracks( decayTracks_ ), // These const references map onto the actual members for public const access
00640                   decayVertices( decayVertices_ ),
00641                   rootVertices( rootVertices_ )
00642         {
00643                 // I need some maps to be able to get object pointers from the track/vertex ID
00644                 std::map<int,::DecayChainTrack*> trackIdToDecayTrack;
00645                 std::map<int,::DecayChainVertex*> vertexIdToDecayVertex;
00646 
00647                 // First create a DecayChainTrack for every SimTrack and make a note of the
00648                 // trackIds in the map. Also add a pointer to the daughter list of the parent
00649                 // DecayChainVertex, which might include creating the vertex object if it
00650                 // doesn't already exist.
00651                 size_t decayVertexIndex=0; // The index of the next free slot in the DecayChainVertex array.
00652                 for( size_t index=0; index<trackCollection.size(); ++index )
00653                 {
00654                         ::DecayChainTrack* pDecayTrack=&decayTracks_[index]; // Get a pointer for ease of use
00655 
00656                         // This is the array index of the SimTrack that this DecayChainTrack corresponds to. At
00657                         // the moment this is a 1 to 1 relationship with the DecayChainTrack index, but they won't
00658                         // necessarily be accessed through the array later so it's still required to store it.
00659                         pDecayTrack->simTrackIndex=index;
00660 
00661                         trackIdToDecayTrack[ trackCollection[index].trackId() ]=pDecayTrack;
00662 
00663                         int parentVertexIndex=trackCollection[index].vertIndex();
00664                         if( parentVertexIndex>=0 )
00665                         {
00666                                 // Get the DecayChainVertex corresponding to this SimVertex, or initialise it if it hasn't been done already.
00667                                 ::DecayChainVertex*& pParentVertex=vertexIdToDecayVertex[parentVertexIndex];
00668                                 if( pParentVertex==NULL )
00669                                 {
00670                                         // Note that I'm using a reference, so changing pParentVertex will change the entry in the map too.
00671                                         pParentVertex=&decayVertices_[decayVertexIndex];
00672                                         ++decayVertexIndex;
00673                                         pParentVertex->simVertexIndex=parentVertexIndex;
00674                                 }
00675                                 pParentVertex->daughterTracks.push_back(pDecayTrack);
00676                                 pDecayTrack->pParentVertex=pParentVertex;
00677                         }
00678                         else throw std::runtime_error( "TrackingTruthAccumulator: Found a track with an invalid parent vertex index." );
00679                 }
00680 
00681                 // This assert was originally in to check the internal consistency of the decay chain. Fast sim
00682                 // pileup seems to have a load of vertices with no tracks pointing to them though, so fast sim fails
00683                 // this assert if pileup is added. I don't think the problem is vital however, so if the assert is
00684                 // taken out these extra vertices are ignored.
00685                 //assert( vertexIdToDecayVertex.size()==vertexCollection.size() && vertexCollection.size()==decayVertexIndex );
00686 
00687                 // I still need to set DecayChainTrack::daughterVertices and DecayChainVertex::pParentTrack.
00688                 // The information to do this comes from SimVertex::parentIndex. I couldn't do this before
00689                 // because I need all of the DecayChainTracks initialised.
00690                 for( auto& decayVertexMapPair : vertexIdToDecayVertex )
00691                 {
00692                         ::DecayChainVertex* pDecayVertex=decayVertexMapPair.second;
00693                         int parentTrackIndex=vertexCollection[pDecayVertex->simVertexIndex].parentIndex();
00694                         if( parentTrackIndex!=-1 )
00695                         {
00696                                 std::map<int,::DecayChainTrack*>::iterator iParentTrackMapPair=trackIdToDecayTrack.find(parentTrackIndex);
00697                                 if( iParentTrackMapPair==trackIdToDecayTrack.end() )
00698                                 {
00699                                         std::stringstream errorStream;
00700                                         errorStream << "TrackingTruthAccumulator: Something has gone wrong with the indexing. Parent track index is " << parentTrackIndex << ".";
00701                                         throw std::runtime_error( errorStream.str() );
00702                                 }
00703 
00704                                 ::DecayChainTrack* pParentTrackHierarchy=iParentTrackMapPair->second;
00705 
00706                                 pParentTrackHierarchy->daughterVertices.push_back( pDecayVertex );
00707                                 pDecayVertex->pParentTrack=pParentTrackHierarchy;
00708                         }
00709                         else rootVertices_.push_back(pDecayVertex); // Has no parent so is at the top of the decay chain.
00710                 } // end of loop over the vertexIdToDecayVertex map
00711 
00712                 findBrem( trackCollection, vertexCollection );
00713 
00714         } // end of ::DecayChain constructor
00715 
00716         // Function documentation is with the declaration above. This function is only used for testing.
00717         void ::DecayChain::integrityCheck()
00718         {
00719                 //
00720                 // Start off checking the tracks
00721                 //
00722                 for( size_t index=0; index<decayTracksSize; ++index )
00723                 {
00724                         const auto& decayTrack=decayTracks[index];
00725                         //
00726                         // Tracks should always have a production vertex
00727                         //
00728                         if( decayTrack.pParentVertex==NULL ) throw std::runtime_error( "TrackingTruthAccumulator.cc integrityCheck(): Found DecayChainTrack with no parent vertex." );
00729 
00730                         //
00731                         // Make sure the parent has this as a child. Also make sure it's only listed once.
00732                         //
00733                         size_t numberOfTimesListed=0;
00734                         for( const auto pSiblingTrack : decayTrack.pParentVertex->daughterTracks )
00735                         {
00736                                 if( pSiblingTrack==&decayTrack ) ++numberOfTimesListed;
00737                         }
00738                         if( numberOfTimesListed!=1 ) throw std::runtime_error( "TrackingTruthAccumulator.cc integrityCheck(): Found DecayChainTrack whose parent does not have it listed once and only once as a child." );
00739 
00740                         //
00741                         // Make sure all of the children have this listed as a parent.
00742                         //
00743                         for( const auto pDaughterVertex : decayTrack.daughterVertices )
00744                         {
00745                                 if( pDaughterVertex->pParentTrack!=&decayTrack ) throw std::runtime_error( "TrackingTruthAccumulator.cc integrityCheck(): Found DecayChainTrack whose child does not have it listed as the parent." );
00746                         }
00747 
00748                         //
00749                         // Follow the chain up to the root vertex, and make sure that is listed in rootVertices
00750                         //
00751                         const DecayChainVertex* pAncestorVertex=decayTrack.pParentVertex;
00752                         while( pAncestorVertex->pParentTrack!=NULL )
00753                         {
00754                                 if( pAncestorVertex->pParentTrack->pParentVertex==NULL ) throw std::runtime_error( "TrackingTruthAccumulator.cc integrityCheck(): Found DecayChainTrack with no parent vertex higher in the decay chain." );
00755                                 pAncestorVertex=pAncestorVertex->pParentTrack->pParentVertex;
00756                         }
00757                         if( std::find( rootVertices.begin(), rootVertices.end(), pAncestorVertex )==rootVertices.end() )
00758                         {
00759                                 throw std::runtime_error( "TrackingTruthAccumulator.cc integrityCheck(): Found DecayChainTrack whose root vertex is not recorded anywhere." );
00760                         }
00761                 } // end of loop over decayTracks
00762 
00763                 //
00764                 // Now check the vertices
00765                 //
00766                 for( size_t index=0; index<decayVerticesSize; ++index )
00767                 {
00768                         const auto& decayVertex=decayVertices[index];
00769 
00770                         //
00771                         // Make sure this, or a vertex higher in the chain, is in the list of root vertices.
00772                         //
00773                         const DecayChainVertex* pAncestorVertex=&decayVertex;
00774                         while( pAncestorVertex->pParentTrack!=NULL )
00775                         {
00776                                 if( pAncestorVertex->pParentTrack->pParentVertex==NULL ) throw std::runtime_error( "TrackingTruthAccumulator.cc integrityCheck(): Found DecayChainTrack with no parent vertex higher in the vertex decay chain." );
00777                                 pAncestorVertex=pAncestorVertex->pParentTrack->pParentVertex;
00778                         }
00779                         if( std::find( rootVertices.begin(), rootVertices.end(), pAncestorVertex )==rootVertices.end() )
00780                         {
00781                                 throw std::runtime_error( "TrackingTruthAccumulator.cc integrityCheck(): Found DecayChainTrack whose root vertex is not recorded anywhere." );
00782                         }
00783 
00784                         //
00785                         // Make sure the parent has this listed in its daughters once and only once.
00786                         //
00787                         if( decayVertex.pParentTrack!=NULL )
00788                         {
00789                                 size_t numberOfTimesListed=0;
00790                                 for( const auto pSibling : decayVertex.pParentTrack->daughterVertices )
00791                                 {
00792                                         if( pSibling==&decayVertex ) ++numberOfTimesListed;
00793                                 }
00794                                 if( numberOfTimesListed!=1 ) throw std::runtime_error( "TrackingTruthAccumulator.cc integrityCheck(): Found DecayChainVertex whose parent does not have it listed once and only once as a child." );
00795                         }
00796 
00797                         //
00798                         // Make sure all of the children have this listed as the parent
00799                         //
00800                         for( const auto pDaughter : decayVertex.daughterTracks )
00801                         {
00802                                 if( pDaughter->pParentVertex!=&decayVertex ) throw std::runtime_error( "TrackingTruthAccumulator.cc integrityCheck(): Found DecayChainVertex whose child does not have it listed as the parent." );
00803                         }
00804                 } // end of loop over decay vertices
00805 
00806                 std::cout << "TrackingTruthAccumulator.cc integrityCheck() completed successfully" << std::endl;
00807         } // end of ::DecayChain::integrityCheck()
00808 
00809         void ::DecayChain::findBrem( const std::vector<SimTrack>& trackCollection, const std::vector<SimVertex>& vertexCollection )
00810         {
00811                 for( size_t index=0; index<decayVerticesSize; ++index )
00812                 {
00813                         auto& vertex=decayVertices_[index];
00814 
00815                         // Make sure parent is an electron
00816                         if( vertex.pParentTrack==NULL ) continue;
00817                         int parentTrackPDG=trackCollection[vertex.pParentTrack->simTrackIndex].type();
00818                         if( std::abs( parentTrackPDG )!=11 ) continue;
00819 
00820                         size_t numberOfElectrons=0;
00821                         size_t numberOfNonElectronsOrPhotons=0;
00822                         for( auto& pDaughterTrack : vertex.daughterTracks )
00823                         {
00824                                 const auto& simTrack=trackCollection[pDaughterTrack->simTrackIndex];
00825                                 if( simTrack.type()==11 || simTrack.type()==-11 ) ++numberOfElectrons;
00826                                 else if( simTrack.type()!=22 ) ++numberOfNonElectronsOrPhotons;
00827                         }
00828                         if( numberOfElectrons==1 && numberOfNonElectronsOrPhotons==0 )
00829                         {
00830                                 // This is a valid brem, run through and tell all daughters to use the parent
00831                                 // as the brem
00832                                 for( auto& pDaughterTrack : vertex.daughterTracks ) pDaughterTrack->pMergedBremSource=vertex.pParentTrack;
00833                                 vertex.pMergedBremSource=vertex.pParentTrack->pParentVertex;
00834                         }
00835                 }
00836         } // end of ::DecayChain::findBrem()
00837 
00838 
00839         //---------------------------------------------------------------------------------
00840         //---------------------------------------------------------------------------------
00841         //----   OutputCollectionWrapper methods   ----------------------------------------
00842         //---------------------------------------------------------------------------------
00843         //---------------------------------------------------------------------------------
00844 
00845         ::OutputCollectionWrapper::OutputCollectionWrapper( const ::DecayChain& decayChain, TrackingTruthAccumulator::OutputCollections& outputCollections )
00846                 : output_(outputCollections),
00847                   trackingParticleIndices_(decayChain.decayTracksSize,-1),
00848                   trackingVertexIndices_(decayChain.decayVerticesSize,-1)
00849         {
00850                 // No operation besides the initialiser list
00851         }
00852 
00853         TrackingParticle* ::OutputCollectionWrapper::addTrackingParticle( const ::DecayChainTrack* pDecayTrack, const TrackingParticle& trackingParticle )
00854         {
00855                 if( trackingParticleIndices_[pDecayTrack->simTrackIndex]!=-1 ) throw std::runtime_error( "OutputCollectionWrapper::addTrackingParticle - trying to add a particle twice" );
00856 
00857                 trackingParticleIndices_[pDecayTrack->simTrackIndex]=output_.pTrackingParticles->size();
00858                 output_.pTrackingParticles->push_back( trackingParticle );
00859 
00860                 // Clear any associations in case there were any beforehand
00861                 output_.pTrackingParticles->back().clearDecayVertices();
00862                 output_.pTrackingParticles->back().clearParentVertex();
00863 
00864                 // Associate to the objects that are already in the output collections
00865                 associateToExistingObjects( pDecayTrack );
00866 
00867                 return &output_.pTrackingParticles->back();
00868         }
00869 
00870         TrackingVertex* ::OutputCollectionWrapper::addTrackingVertex( const ::DecayChainVertex* pDecayVertex, const TrackingVertex& trackingVertex )
00871         {
00872                 if( trackingVertexIndices_[pDecayVertex->simVertexIndex]!=-1 ) throw std::runtime_error( "OutputCollectionWrapper::addTrackingVertex - trying to add a vertex twice" );
00873 
00874                 trackingVertexIndices_[pDecayVertex->simVertexIndex]=output_.pTrackingVertices->size();
00875                 output_.pTrackingVertices->push_back( trackingVertex );
00876 
00877                 // Associate the new vertex to any parents or children that are already in the output collections
00878                 associateToExistingObjects( pDecayVertex );
00879 
00880                 return &output_.pTrackingVertices->back();
00881         }
00882 
00883         TrackingParticle* ::OutputCollectionWrapper::getTrackingParticle( const ::DecayChainTrack* pDecayTrack )
00884         {
00885                 const int index=trackingParticleIndices_[pDecayTrack->simTrackIndex];
00886                 if( index==-1 ) return NULL;
00887                 else return &(*output_.pTrackingParticles)[index];
00888         }
00889 
00890         TrackingVertex* ::OutputCollectionWrapper::getTrackingVertex( const ::DecayChainVertex* pDecayVertex )
00891         {
00892                 const int index=trackingVertexIndices_[pDecayVertex->simVertexIndex];
00893                 if( index==-1 ) return NULL;
00894                 else return &(*output_.pTrackingVertices)[index];
00895         }
00896 
00897         TrackingParticleRef OutputCollectionWrapper::getRef( const ::DecayChainTrack* pDecayTrack )
00898         {
00899                 const int index=trackingParticleIndices_[pDecayTrack->simTrackIndex];
00900                 if( index==-1 ) throw std::runtime_error( "OutputCollectionWrapper::getRefTrackingParticle - ref requested for a non existent TrackingParticle" );
00901                 else return TrackingParticleRef( output_.refTrackingParticles, index );
00902         }
00903 
00904         TrackingVertexRef OutputCollectionWrapper::getRef( const ::DecayChainVertex* pDecayVertex )
00905         {
00906                 const int index=trackingVertexIndices_[pDecayVertex->simVertexIndex];
00907                 if( index==-1 ) throw std::runtime_error( "OutputCollectionWrapper::getRefTrackingParticle - ref requested for a non existent TrackingVertex" );
00908                 else return TrackingVertexRef( output_.refTrackingVertexes, index );
00909         }
00910 
00911         void ::OutputCollectionWrapper::setProxy( const ::DecayChainTrack* pOriginalTrack, const ::DecayChainTrack* pProxyTrack )
00912         {
00913                 int& index=trackingParticleIndices_[pOriginalTrack->simTrackIndex];
00914                 if( index!=-1 ) throw std::runtime_error( "OutputCollectionWrapper::setProxy() was called for a TrackingParticle that has already been created" );
00915                 // Note that index is a reference so this call changes the value in the vector too
00916                 index=trackingParticleIndices_[pProxyTrack->simTrackIndex];
00917         }
00918 
00919         void ::OutputCollectionWrapper::setProxy( const ::DecayChainVertex* pOriginalVertex, const ::DecayChainVertex* pProxyVertex )
00920         {
00921                 int& index=trackingVertexIndices_[pOriginalVertex->simVertexIndex];
00922                 const int newIndex=trackingVertexIndices_[pProxyVertex->simVertexIndex];
00923 
00924                 if( index!=-1 && index!=newIndex ) throw std::runtime_error( "OutputCollectionWrapper::setProxy() was called for a TrackingVertex that has already been created" );
00925 
00926                 // Note that index is a reference so this call changes the value in the vector too
00927                 index=newIndex;
00928         }
00929 
00930         void ::OutputCollectionWrapper::associateToExistingObjects( const ::DecayChainVertex* pChainVertex )
00931         {
00932                 // First make sure the DecayChainVertex supplied has been turned into a TrackingVertex
00933                 TrackingVertex* pTrackingVertex=getTrackingVertex( pChainVertex );
00934                 if( pTrackingVertex==NULL ) throw std::runtime_error( "associateToExistingObjects was passed a non existent TrackingVertex" );
00935 
00936                 //
00937                 // Associate to the parent track (if there is one)
00938                 //
00939                 ::DecayChainTrack* pParentChainTrack=pChainVertex->pParentTrack;
00940                 if( pParentChainTrack!=NULL ) // Make sure there is a parent track first
00941                 {
00942                         // There is a parent track, but it might not have been turned into a TrackingParticle yet
00943                         TrackingParticle* pParentTrackingParticle=getTrackingParticle(pParentChainTrack);
00944                         if( pParentTrackingParticle!=NULL )
00945                         {
00946                                 pParentTrackingParticle->addDecayVertex( getRef(pChainVertex) );
00947                                 pTrackingVertex->addParentTrack( getRef(pParentChainTrack) );
00948                         }
00949                         // Don't worry about the "else" case - the parent track might not necessarily get added
00950                         // to the output collection at all. A check is done on daughter vertices when tracks
00951                         // are added, so the association will be picked up then.
00952                 }
00953 
00954                 //
00955                 // A parent TrackingVertex is always associated to a daughter TrackingParticle when
00956                 // the TrackingParticle is created. Hence there is no need to check the list of
00957                 // daughter tracks.
00958                 //
00959         }
00960 
00961         void ::OutputCollectionWrapper::associateToExistingObjects( const ::DecayChainTrack* pChainTrack )
00962         {
00963                 //
00964                 // First make sure this DecayChainTrack has been turned into a TrackingParticle
00965                 //
00966                 TrackingParticle* pTrackingParticle=getTrackingParticle( pChainTrack );
00967                 if( pTrackingParticle==NULL ) throw std::runtime_error( "associateToExistingObjects was passed a non existent TrackingParticle" );
00968 
00969                 // Get the parent vertex. This should always already have been turned into a TrackingVertex, and
00970                 // there should always be a parent DecayChainVertex.
00971                 ::DecayChainVertex* pParentChainVertex=pChainTrack->pParentVertex;
00972                 TrackingVertex* pParentTrackingVertex=getTrackingVertex( pParentChainVertex );
00973 
00974                 //
00975                 // First associate to the parent vertex.
00976                 //
00977                 pTrackingParticle->setParentVertex( getRef(pParentChainVertex) );
00978                 pParentTrackingVertex->addDaughterTrack( getRef(pChainTrack) );
00979 
00980                 // If there are any daughter vertices that have already been made into a TrackingVertex
00981                 // make sure they know about each other. If the daughter vertices haven't been made into
00982                 // TrackingVertexs yet, I won't do anything and create the association when the vertex is
00983                 // made.
00984                 for( auto pDaughterChainVertex : pChainTrack->daughterVertices )
00985                 {
00986                         TrackingVertex* pDaughterTrackingVertex=getTrackingVertex( pDaughterChainVertex );
00987                         if( pDaughterTrackingVertex!=NULL )
00988                         {
00989                                 pTrackingParticle->addDecayVertex( getRef(pDaughterChainVertex) );
00990                                 pDaughterTrackingVertex->addParentTrack( getRef(pChainTrack) );
00991                         }
00992                 }
00993         }
00994 
00995 
00996 
00997         //---------------------------------------------------------------------------------
00998         //---------------------------------------------------------------------------------
00999         //----   Functions in the unnamed namespace   -------------------------------------
01000         //---------------------------------------------------------------------------------
01001         //---------------------------------------------------------------------------------
01002 
01003         int LayerFromDetid( const DetId& detId )
01004         {
01005                 if( detId.det()!=DetId::Tracker ) return 0;
01006 
01007                 int layerNumber=0;
01008                 unsigned int subdetId=static_cast<unsigned int>( detId.subdetId() );
01009 
01010                 if( subdetId==StripSubdetector::TIB )
01011                 {
01012                         TIBDetId tibid( detId.rawId() );
01013                         layerNumber=tibid.layer();
01014                 }
01015                 else if( subdetId==StripSubdetector::TOB )
01016                 {
01017                         TOBDetId tobid( detId.rawId() );
01018                         layerNumber=tobid.layer();
01019                 }
01020                 else if( subdetId==StripSubdetector::TID )
01021                 {
01022                         TIDDetId tidid( detId.rawId() );
01023                         layerNumber=tidid.wheel();
01024                 }
01025                 else if( subdetId==StripSubdetector::TEC )
01026                 {
01027                         TECDetId tecid( detId.rawId() );
01028                         layerNumber=tecid.wheel();
01029                 }
01030                 else if( subdetId==PixelSubdetector::PixelBarrel )
01031                 {
01032                         PXBDetId pxbid( detId.rawId() );
01033                         layerNumber=pxbid.layer();
01034                 }
01035                 else if( subdetId==PixelSubdetector::PixelEndcap )
01036                 {
01037                         PXFDetId pxfid( detId.rawId() );
01038                         layerNumber=pxfid.disk();
01039                 }
01040                 else edm::LogVerbatim( "TrackingTruthAccumulator" )<<"Unknown subdetid: "<<subdetId;
01041 
01042                 return layerNumber;
01043         }
01044 
01045         TrackingParticle* addTrackAndParentVertex( ::DecayChainTrack* pDecayTrack, const TrackingParticle& trackingParticle, ::OutputCollectionWrapper* pOutput )
01046         {
01047                 // See if this TrackingParticle has already been created (could be if the DecayChainTracks are
01048                 // looped over in a funny order). If it has then there's no need to do anything.
01049                 TrackingParticle* pTrackingParticle=pOutput->getTrackingParticle( pDecayTrack );
01050                 if( pTrackingParticle==NULL )
01051                 {
01052                         // Need to make sure the production vertex has been created first
01053                         TrackingVertex* pProductionVertex=pOutput->getTrackingVertex( pDecayTrack->pParentVertex );
01054                         if( pProductionVertex==NULL )
01055                         {
01056                                 // TrackingVertex doesn't exist in the output collection yet. However, it's already been
01057                                 // created in the addTrack() function and a temporary reference to it set in the TrackingParticle.
01058                                 // I'll use that reference to create a copy in the output collection. When the TrackingParticle
01059                                 // is added to the output collection a few lines below the temporary reference to the parent
01060                                 // vertex will be cleared, and the correct one referring to the output collection will be set.
01061                                 pProductionVertex=pOutput->addTrackingVertex( pDecayTrack->pParentVertex, *trackingParticle.parentVertex() );
01062                         }
01063 
01064 
01065                         pTrackingParticle=pOutput->addTrackingParticle( pDecayTrack, trackingParticle );
01066                 }
01067 
01068                 return pTrackingParticle;
01069         }
01070 
01071         void addTrack( ::DecayChainTrack* pDecayChainTrack, const TrackingParticleSelector* pSelector, ::OutputCollectionWrapper* pUnmergedOutput, ::OutputCollectionWrapper* pMergedOutput, const ::TrackingParticleFactory& objectFactory, bool addAncestors )
01072         {
01073                 if( pDecayChainTrack==NULL ) return; // This is required for when the addAncestors_ recursive call reaches the top of the chain
01074 
01075                 // Check to see if this particle has already been processed while traversing up the parents
01076                 // of another split in the decay chain. The check in the line above only stops when the top
01077                 // of the chain is reached, whereas this will stop when a previously traversed split is reached.
01078                 { // block to limit the scope of temporary variables
01079                         bool alreadyProcessed=true;
01080                         if( pUnmergedOutput!=NULL )
01081                         {
01082                                 if( pUnmergedOutput->getTrackingParticle( pDecayChainTrack )==NULL ) alreadyProcessed=false;
01083                         }
01084                         if( pMergedOutput!=NULL )
01085                         {
01086                                 if( pMergedOutput->getTrackingParticle( pDecayChainTrack )==NULL ) alreadyProcessed=false;
01087                         }
01088                         if( alreadyProcessed ) return;
01089                 }
01090 
01091                 // Create a TrackingParticle.
01092                 TrackingParticle newTrackingParticle=objectFactory.createTrackingParticle( pDecayChainTrack );
01093 
01094                 // The selector checks the impact parameters from the vertex, so I need to have a valid reference
01095                 // to the parent vertex in the TrackingParticle before that can be called. TrackingParticle needs
01096                 // an edm::Ref for the parent TrackingVertex though. I still don't know if this is going to be
01097                 // added to the collection so I can't take it from there, so I need to create a temporary one.
01098                 // When the addTrackAndParentVertex() is called (assuming it passes selection) it will use the
01099                 // temporary reference to create a copy of the parent vertex, put that in the output collection,
01100                 // and then set the reference in the TrackingParticle properly.
01101                 TrackingVertexCollection dummyCollection; // Only needed to create an edm::Ref
01102                 dummyCollection.push_back( objectFactory.createTrackingVertex( pDecayChainTrack->pParentVertex ) );
01103                 TrackingVertexRef temporaryRef( &dummyCollection, 0 );
01104                 newTrackingParticle.setParentVertex( temporaryRef );
01105 
01106                 // If a selector has been supplied apply it on the new TrackingParticle and return if it fails.
01107                 if( pSelector )
01108                 {
01109                         if( !(*pSelector)( newTrackingParticle ) ) return; // Return if the TrackingParticle fails selection
01110                 }
01111 
01112                 // Add the ancestors first (if required) so that the collection has some kind of chronological
01113                 // order. I don't know how important that is but other code might assume chronological order.
01114                 // If adding ancestors, no selection is applied. Note that I've already checked that all
01115                 // DecayChainTracks have a pParentVertex.
01116                 if( addAncestors ) addTrack( pDecayChainTrack->pParentVertex->pParentTrack, NULL, pUnmergedOutput, pMergedOutput, objectFactory, addAncestors );
01117 
01118                 // If creation of the unmerged collection has been turned off in the config this pointer
01119                 // will be null.
01120                 if( pUnmergedOutput!=NULL ) addTrackAndParentVertex( pDecayChainTrack, newTrackingParticle, pUnmergedOutput );
01121 
01122                 // If creation of the merged collection has been turned off in the config this pointer
01123                 // will be null.
01124                 if( pMergedOutput!=NULL )
01125                 {
01126                         ::DecayChainTrack* pBremParentChainTrack=pDecayChainTrack;
01127                         while( pBremParentChainTrack->pMergedBremSource!=NULL ) pBremParentChainTrack=pBremParentChainTrack->pMergedBremSource;
01128 
01129                         if( pBremParentChainTrack!=pDecayChainTrack )
01130                         {
01131                                 TrackingParticle* pBremParentTrackingParticle=addTrackAndParentVertex( pBremParentChainTrack, newTrackingParticle, pMergedOutput );
01132                                 // The original particle in the bremsstrahlung decay chain has been
01133                                 // created (or retrieved if it already existed), now copy in the
01134                                 // extra information.
01135                                 // TODO - copy extra information.
01136 
01137                                 if( std::abs( newTrackingParticle.pdgId() ) == 22 )
01138                                 {
01139                                         // Photons are added as separate TrackingParticles, but with the production
01140                                         // vertex changed to be the production vertex of the original electron.
01141 
01142                                         // Set up a proxy, so that all requests for the parent TrackingVertex get
01143                                         // redirected to the brem parent's TrackingVertex.
01144                                         pMergedOutput->setProxy( pDecayChainTrack->pParentVertex, pBremParentChainTrack->pParentVertex );
01145 
01146                                         // Now that pMergedOutput thinks the parent vertex is the brem parent's vertex I can
01147                                         // call this and it will set the TrackingParticle parent vertex correctly to the brem
01148                                         // parent vertex.
01149                                         addTrackAndParentVertex( pDecayChainTrack, newTrackingParticle, pMergedOutput );
01150                                 }
01151                                 else if( std::abs( newTrackingParticle.pdgId() ) == 11 )
01152                                 {
01153                                         // Electrons have their G4 tracks and SimHits copied to the parent TrackingParticle.
01154                                         for( const auto& trackSegment : newTrackingParticle.g4Tracks() )
01155                                         {
01156                                                 pBremParentTrackingParticle->addG4Track( trackSegment );
01157                                         }
01158 
01159                                         // Also copy the generator particle references
01160                                         for( const auto& genParticleRef : newTrackingParticle.genParticles() )
01161                                         {
01162                                                 pBremParentTrackingParticle->addGenParticle( genParticleRef );
01163                                         }
01164 
01165                                         pBremParentTrackingParticle->setNumberOfHits(pBremParentTrackingParticle->numberOfHits()+newTrackingParticle.numberOfHits());
01166                                         pBremParentTrackingParticle->setNumberOfTrackerHits(pBremParentTrackingParticle->numberOfTrackerHits()+newTrackingParticle.numberOfTrackerHits());
01167                                         pBremParentTrackingParticle->setNumberOfTrackerLayers(pBremParentTrackingParticle->numberOfTrackerLayers()+newTrackingParticle.numberOfTrackerLayers());
01168 
01169                                         // Set a proxy in the output collection wrapper so that any attempt to get objects for
01170                                         // this DecayChainTrack again get redirected to the brem parent.
01171                                         pMergedOutput->setProxy( pDecayChainTrack, pBremParentChainTrack );
01172                                 }
01173                         }
01174                         else
01175                         {
01176                                 // This is not the result of bremsstrahlung so add to the collection as normal.
01177                                 addTrackAndParentVertex( pDecayChainTrack, newTrackingParticle, pMergedOutput );
01178                         }
01179                 } // end of "if( pMergedOutput!=NULL )", i.e. end of "if bremsstrahlung merging is turned on"
01180 
01181         } // end of addTrack function
01182 
01183 } // end of the unnamed namespace
01184 
01185 // Register with the framework
01186 DEFINE_DIGI_ACCUMULATOR (TrackingTruthAccumulator);