Back to home page

sPhenix code displayed by LXR

 
 

    


File indexing completed on 2025-12-16 09:21:57

0001 /*!
0002  * \file Fun4AllDstPileupInputMerger.h
0003  * \author Hugo Pereira Da Costa <hugo.pereira-da-costa@cea.fr>
0004  */
0005 
0006 #include "Fun4AllDstPileupMerger.h"
0007 
0008 #include "PHG4Hit.h"  // for PHG4Hit
0009 #include "PHG4HitContainer.h"
0010 #include "PHG4Hitv1.h"
0011 #include "PHG4Particle.h"  // for PHG4Particle
0012 #include "PHG4Particlev3.h"
0013 #include "PHG4TruthInfoContainer.h"
0014 #include "PHG4VtxPoint.h"  // for PHG4VtxPoint
0015 #include "PHG4VtxPointv1.h"
0016 
0017 #include <phhepmc/PHHepMCGenEvent.h>  // for PHHepMCGenEvent
0018 #include <phhepmc/PHHepMCGenEventMap.h>
0019 
0020 #include <phool/PHCompositeNode.h>
0021 #include <phool/PHIODataNode.h>    // for PHIODataNode
0022 #include <phool/PHNode.h>          // for PHNode
0023 #include <phool/PHNodeIterator.h>  // for PHNodeIterator
0024 #include <phool/PHNodeOperation.h>
0025 #include <phool/PHObject.h>  // for PHObject
0026 #include <phool/getClass.h>
0027 
0028 #include <TObject.h>
0029 
0030 #include <HepMC/GenEvent.h>
0031 
0032 #include <iostream>
0033 #include <iterator>
0034 #include <limits>
0035 #include <utility>
0036 
0037 // convenient aliases for deep copying nodes
0038 namespace
0039 {
0040   using PHG4Particle_t = PHG4Particlev3;
0041   using PHG4VtxPoint_t = PHG4VtxPointv1;
0042   using PHG4Hit_t = PHG4Hitv1;
0043 
0044   //! utility class to find all PHG4Hit container nodes from the DST node
0045   class FindG4HitContainer : public PHNodeOperation
0046   {
0047    public:
0048     //! container map alias
0049     using ContainerMap = std::map<std::string, PHG4HitContainer *>;
0050 
0051     //! get container map
0052     const ContainerMap &containers() const
0053     {
0054       return m_containers;
0055     }
0056 
0057    protected:
0058     //! iterator action
0059     void perform(PHNode *node) override
0060     {
0061       // check type name. Only load PHIODataNode
0062       if (node->getType() != "PHIODataNode")
0063       {
0064         return;
0065       }
0066 
0067       // cast to IODataNode and check data
0068       auto *ionode = static_cast<PHIODataNode<TObject> *>(node);
0069       auto *data = dynamic_cast<PHG4HitContainer *>(ionode->getData());
0070       if (data)
0071       {
0072         m_containers.insert(std::make_pair(node->getName(), data));
0073       }
0074     }
0075 
0076    private:
0077     //! container map
0078     ContainerMap m_containers;
0079   };
0080 
0081 }  // namespace
0082 
0083 //_____________________________________________________________________________
0084 void Fun4AllDstPileupMerger::load_nodes(PHCompositeNode *dstNode)
0085 {
0086   // hep mc
0087   m_geneventmap = findNode::getClass<PHHepMCGenEventMap>(dstNode, "PHHepMCGenEventMap");
0088   if (!m_geneventmap)
0089   {
0090     std::cout << "Fun4AllDstPileupMerger::load_nodes - creating PHHepMCGenEventMap" << std::endl;
0091     m_geneventmap = new PHHepMCGenEventMap();
0092     dstNode->addNode(new PHIODataNode<PHObject>(m_geneventmap, "PHHepMCGenEventMap", "PHObject"));
0093   }
0094 
0095   // find all G4Hit containers under dstNode
0096   FindG4HitContainer nodeFinder;
0097   PHNodeIterator(dstNode).forEach(nodeFinder);
0098   m_g4hitscontainers = nodeFinder.containers();
0099 
0100   // g4 truth info
0101   m_g4truthinfo = findNode::getClass<PHG4TruthInfoContainer>(dstNode, "G4TruthInfo");
0102   if (!m_g4truthinfo)
0103   {
0104     std::cout << "Fun4AllDstPileupMerger::load_nodes - creating node G4TruthInfo" << std::endl;
0105     m_g4truthinfo = new PHG4TruthInfoContainer();
0106     dstNode->addNode(new PHIODataNode<PHObject>(m_g4truthinfo, "G4TruthInfo", "PHObject"));
0107   }
0108 }
0109 
0110 //_____________________________________________________________________________
0111 void Fun4AllDstPileupMerger::copy_background_event(PHCompositeNode *dstNode, double delta_t) const
0112 {
0113   // copy PHHepMCGenEventMap
0114   auto *const map = findNode::getClass<PHHepMCGenEventMap>(dstNode, "PHHepMCGenEventMap");
0115 
0116   // keep track of new embed id, after insertion as background event
0117   int new_embed_id = -1;
0118 
0119   if (map && m_geneventmap)
0120   {
0121     if (map->size() != 1)
0122     {
0123       std::cout << "Fun4AllDstPileupMerger::copy_background_event - cannot merge events that contain more than one PHHepMCGenEventMap" << std::endl;
0124       return;
0125     }
0126 
0127     // get event and insert in new map
0128     auto *genevent = map->get_map().begin()->second;
0129     auto *newevent = m_geneventmap->insert_background_event(genevent);
0130 
0131     /*
0132      * this hack prevents a crash when writting out
0133      * it boils down to root trying to write deleted items from the HepMC::GenEvent copy if the source has been deleted
0134      * it does not happen if the source gets written while the copy is deleted
0135      */
0136     newevent->getEvent()->swap(*genevent->getEvent());
0137 
0138     // shift vertex time and store new embed id
0139     newevent->moveVertex(0, 0, 0, delta_t);
0140     new_embed_id = newevent->get_embedding_id();
0141   }
0142 
0143   // copy truth container
0144   // keep track of the correspondance between source index and destination index for vertices, tracks and showers
0145   using ConversionMap = std::map<int, int>;
0146   ConversionMap vtxid_map;
0147   ConversionMap trkid_map;
0148 
0149   auto *const container_truth = findNode::getClass<PHG4TruthInfoContainer>(dstNode, "G4TruthInfo");
0150   if (container_truth && m_g4truthinfo)
0151   {
0152     {
0153       // primary vertices
0154       auto key = m_g4truthinfo->maxvtxindex();
0155       const auto range = container_truth->GetPrimaryVtxRange();
0156       for (auto iter = range.first; iter != range.second; ++iter)
0157       {
0158         // clone vertex, insert in map, and add index conversion
0159         const auto &sourceVertex = iter->second;
0160         auto *newVertex = new PHG4VtxPoint_t(sourceVertex);
0161         newVertex->set_t(sourceVertex->get_t() + delta_t);
0162         m_g4truthinfo->AddVertex(++key, newVertex);
0163         vtxid_map.insert(std::make_pair(sourceVertex->get_id(), key));
0164       }
0165     }
0166 
0167     {
0168       // secondary vertices
0169       auto key = m_g4truthinfo->minvtxindex();
0170       const auto range = container_truth->GetSecondaryVtxRange();
0171 
0172       // loop from last to first to preserve order with respect to the original event
0173       for (
0174           auto iter = std::reverse_iterator<PHG4TruthInfoContainer::ConstVtxIterator>(range.second);
0175           iter != std::reverse_iterator<PHG4TruthInfoContainer::ConstVtxIterator>(range.first);
0176           ++iter)
0177       {
0178         // clone vertex, shift time, insert in map, and add index conversion
0179         const auto &sourceVertex = iter->second;
0180         auto *newVertex = new PHG4VtxPoint_t(sourceVertex);
0181         newVertex->set_t(sourceVertex->get_t() + delta_t);
0182         m_g4truthinfo->AddVertex(--key, newVertex);
0183         vtxid_map.insert(std::make_pair(sourceVertex->get_id(), key));
0184       }
0185     }
0186 
0187     {
0188       // primary particles
0189       auto key = m_g4truthinfo->maxtrkindex();
0190       const auto range = container_truth->GetPrimaryParticleRange();
0191       for (auto iter = range.first; iter != range.second; ++iter)
0192       {
0193         const auto &source = iter->second;
0194         auto *dest = new PHG4Particle_t(source);
0195         m_g4truthinfo->AddParticle(++key, dest);
0196         dest->set_track_id(key);
0197 
0198         // set parent to zero
0199         dest->set_parent_id(0);
0200 
0201         // set primary to itself
0202         dest->set_primary_id(dest->get_track_id());
0203 
0204         // update vertex
0205         const auto keyiter = vtxid_map.find(source->get_vtx_id());
0206         if (keyiter != vtxid_map.end())
0207         {
0208           dest->set_vtx_id(keyiter->second);
0209         }
0210         else
0211         {
0212           std::cout << "Fun4AllDstPileupMerger::copy_background_event - vertex id " << source->get_vtx_id() << " not found in map" << std::endl;
0213         }
0214 
0215         // insert in map
0216         trkid_map.insert(std::make_pair(source->get_track_id(), dest->get_track_id()));
0217       }
0218     }
0219 
0220     {
0221       // secondary particles
0222       auto key = m_g4truthinfo->mintrkindex();
0223       const auto range = container_truth->GetSecondaryParticleRange();
0224 
0225       /*
0226        * loop from last to first to preserve order with respect to the original event
0227        * also this ensures that for a given particle its parent has already been converted and thus found in the map
0228        */
0229       for (
0230           auto iter = std::reverse_iterator<PHG4TruthInfoContainer::ConstIterator>(range.second);
0231           iter != std::reverse_iterator<PHG4TruthInfoContainer::ConstIterator>(range.first);
0232           ++iter)
0233       {
0234         const auto &source = iter->second;
0235         auto *dest = new PHG4Particle_t(source);
0236         m_g4truthinfo->AddParticle(--key, dest);
0237         dest->set_track_id(key);
0238 
0239         // update parent id
0240         auto keyiter = trkid_map.find(source->get_parent_id());
0241         if (keyiter != trkid_map.end())
0242         {
0243           dest->set_parent_id(keyiter->second);
0244         }
0245         else
0246         {
0247           std::cout << "Fun4AllDstPileupMerger::copy_background_event - track id " << source->get_parent_id() << " not found in map" << std::endl;
0248         }
0249 
0250         // update primary id
0251         keyiter = trkid_map.find(source->get_primary_id());
0252         if (keyiter != trkid_map.end())
0253         {
0254           dest->set_primary_id(keyiter->second);
0255         }
0256         else
0257         {
0258           std::cout << "Fun4AllDstPileupMerger::copy_background_event - track id " << source->get_primary_id() << " not found in map" << std::endl;
0259         }
0260 
0261         // update vertex
0262         keyiter = vtxid_map.find(source->get_vtx_id());
0263         if (keyiter != vtxid_map.end())
0264         {
0265           dest->set_vtx_id(keyiter->second);
0266         }
0267         else
0268         {
0269           std::cout << "Fun4AllDstPileupMerger::copy_background_event - vertex id " << source->get_vtx_id() << " not found in map" << std::endl;
0270         }
0271 
0272         // insert in map
0273         trkid_map.insert(std::make_pair(source->get_track_id(), dest->get_track_id()));
0274       }
0275     }
0276 
0277     // vertex embed flags
0278     /* embed flag is stored only for primary vertices, consistently with PHG4TruthEventAction */
0279     for (const auto &pair : vtxid_map)
0280     {
0281       if (pair.first > 0)
0282       {
0283         m_g4truthinfo->AddEmbededVtxId(pair.second, new_embed_id);
0284       }
0285     }
0286 
0287     // track embed flags
0288     /* embed flag is stored only for primary tracks, consistently with PHG4TruthEventAction */
0289     for (const auto &pair : trkid_map)
0290     {
0291       if (pair.first > 0)
0292       {
0293         m_g4truthinfo->AddEmbededTrkId(pair.second, new_embed_id);
0294       }
0295     }
0296   }
0297 
0298   // copy g4hits
0299   // loop over registered maps
0300   for (const auto &pair : m_g4hitscontainers)
0301   {
0302     // check destination node
0303     if (!pair.second)
0304     {
0305       std::cout << "Fun4AllDstPileupMerger::copy_background_event - invalid destination container " << pair.first << std::endl;
0306       continue;
0307     }
0308 
0309     // find source node
0310     auto *container_hit = findNode::getClass<PHG4HitContainer>(dstNode, pair.first);
0311     if (!container_hit)
0312     {
0313       std::cout << "Fun4AllDstPileupMerger::copy_background_event - invalid source container " << pair.first << std::endl;
0314       continue;
0315     }
0316     auto detiter = m_DetectorTiming.find(pair.first);
0317     // apply special  cuts for selected detectors
0318     if (detiter != m_DetectorTiming.end())
0319     {
0320       if (delta_t < detiter->second.first || delta_t > detiter->second.second)
0321       {
0322         continue;
0323       }
0324     }
0325     {
0326       // hits
0327       const auto range = container_hit->getHits();
0328       for (auto iter = range.first; iter != range.second; ++iter)
0329       {
0330         // clone hit
0331         const auto &sourceHit = iter->second;
0332         auto *newHit = new PHG4Hit_t(sourceHit);
0333 
0334         // shift time
0335         newHit->set_t(0, sourceHit->get_t(0) + delta_t);
0336         newHit->set_t(1, sourceHit->get_t(1) + delta_t);
0337 
0338         // update track id
0339         const auto keyiter = trkid_map.find(sourceHit->get_trkid());
0340         if (keyiter != trkid_map.end())
0341         {
0342           newHit->set_trkid(keyiter->second);
0343         }
0344         else
0345         {
0346           std::cout << "Fun4AllDstPileupMerger::copy_background_event - track id " << sourceHit->get_trkid() << " not found in map" << std::endl;
0347         }
0348 
0349         /*
0350          * reset shower ids
0351          * it was decided that showers from the background events will not be copied to the merged event
0352          * as such we just reset the hits shower id
0353          */
0354         newHit->set_shower_id(std::numeric_limits<int>::min());
0355 
0356         /*
0357          * this will generate a new key for the hit and assign it to the hit
0358          * this ensures that there is no conflict with the hits from the 'main' event
0359          */
0360         pair.second->AddHit(newHit->get_detid(), newHit);
0361       }
0362     }
0363 
0364     {
0365       // layers
0366       const auto range = container_hit->getLayers();
0367       for (auto iter = range.first; iter != range.second; ++iter)
0368       {
0369         pair.second->AddLayer(*iter);
0370       }
0371     }
0372   }
0373 }