Back to home page

sPhenix code displayed by LXR

 
 

    


File indexing completed on 2025-12-16 09:19:54

0001 /*
0002  * Find decay topologies in HepMC
0003  * Cameron Dean
0004  * 04/06/2021
0005  */
0006 
0007 // This is an array of PID's which decay faster than we can see in the detector
0008 // This means if we find them in the HepMC record we need to skip over them
0009 // If your decay descriptor contains one of these IDs then it will be removed from the list before starting the search
0010 
0011 #include "DecayFinder.h"
0012 
0013 #include "DecayFinderContainerBase.h"  // for DecayFinderContainerBase::Iter
0014 #include "DecayFinderContainer_v1.h"   // for DecayFinderContainer_v1
0015 
0016 #include <g4main/PHG4TruthInfoContainer.h>
0017 
0018 #include <phhepmc/PHHepMCGenEvent.h>
0019 #include <phhepmc/PHHepMCGenEventMap.h>
0020 
0021 #include <fun4all/Fun4AllReturnCodes.h>
0022 
0023 #include <phool/PHCompositeNode.h>
0024 #include <phool/PHIODataNode.h>    // for PHIODataNode
0025 #include <phool/PHNodeIterator.h>  // for PHNodeIterator
0026 #include <phool/getClass.h>
0027 
0028 #pragma GCC diagnostic push
0029 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
0030 #include <HepMC/GenEvent.h>
0031 #include <HepMC/GenVertex.h>  // for GenVertex::particle_iterator
0032 #pragma GCC diagnostic pop
0033 
0034 #include <HepMC/GenParticle.h>
0035 #include <HepMC/IteratorRange.h>
0036 #include <HepMC/SimpleVector.h>
0037 
0038 #include <TDatabasePDG.h>
0039 
0040 #include <algorithm>  // for find, for_each, sort, transform
0041 #include <cctype>     // for toupper
0042 #include <cstdlib>    // for abs, size_t
0043 #include <iostream>   // for operator<<, endl, basic_ostream
0044 #include <iterator>   // for end, begin
0045 #include <map>        // for map, map<>::mapped_type, _Rb...
0046 #include <memory>     // for allocator_traits<>::value_type
0047 
0048 int listOfResonantPIDs[] = {111, 113, 213, 333, 310, 311, 313, 323, 413, 423, 513, 523, 441, 443, 100443, 9000111, 9000211, 100111, 100211, 10111,
0049                             10211, 9010111, 9010211, 10113, 10213, 20113, 20213, 9000113, 9000213, 100113, 100213, 9010113, 9010213, 9020113, 9020213,
0050                             30113, 30213, 9030113, 9030213, 9040113, 9040213, 115, 215, 10115, 10215, 9000115, 9000215, 9010115, 9010215, 117, 217,
0051                             9000117, 9000217, 9010117, 9010217, 119, 219, 221, 331, 9000221, 9010221, 100221, 10221, 9020221, 100331, 9030221, 10331,
0052                             9040221, 9050221, 9060221, 9070221, 9080221, 223, 10223, 20223, 10333, 20333, 1000223, 9000223, 9010223, 30223, 100333, 225,
0053                             9000225, 335, 9010225, 9020225, 10225, 9030225, 10335, 9040225, 9050225, 9060225, 9070225, 9080225, 9090225, 227, 337, 229,
0054                             9000229, 9010229, 9000311, 9000321, 10311, 10321, 100311, 100321, 9010311, 9010321, 9020311, 9020321, 10313, 10323, 20313,
0055                             20323, 100313, 100323, 9000313, 9000323, 30313, 30323, 315, 325, 9000315, 9000325, 10315, 10325, 20315, 20325, 9010315,
0056                             9010325, 9020315, 9020325, 317, 327, 9010317, 9010327, 319, 329, 9000319, 9000329, 10411, 10421, 10413, 10423, 20413, 20423,
0057                             415, 425, 431, 10431, 433, 10433, 20433, 435, 10511, 10521, 10513, 10523, 20513, 20523, 515, 525, 10531, 533, 10533, 20533, 535,
0058                             10541, 543, 10543, 20543, 545, 10441, 100441, 10443, 20443, 30443, 9000443, 9010443, 9020443, 445, 100445, 551, 10551, 100551,
0059                             110551, 200551, 210551, 10553, 20553, 30553, 110553, 120553, 130553, 210553, 220553, 9000553, 9010553, 555, 10555, 20555, 100555,
0060                             110555, 120555, 200555, 557, 100557, 2224, 2214, 2114, 1114, 3212, 3224, 3214, 3114, 3324, 3314, 4222, 4212, 4112, 4224, 4214,
0061                             4114, 4232, 4132, 4322, 4312, 4324, 4314, 4332, 4334, 4412, 4422, 4414, 4424, 4432, 4434, 4444};
0062 
0063 DecayFinder::DecayFinder()
0064   : SubsysReco("DECAYFINDER")
0065   , m_save_dst(false)
0066 {
0067 }
0068 
0069 DecayFinder::DecayFinder(const std::string& name)
0070   : SubsysReco(name)
0071   , m_save_dst(false)
0072 {
0073 }
0074 
0075 int DecayFinder::Init(PHCompositeNode* topNode)
0076 {
0077   if (Verbosity() >= VERBOSITY_SOME)
0078   {
0079     std::cout << "DecayFinder name: " << Name() << std::endl;
0080     std::cout << "Decay descriptor: " << m_decayDescriptor << std::endl;
0081   }
0082 
0083   int canSearchDecay = parseDecayDescriptor();
0084 
0085   if (m_save_dst)
0086   {
0087     createDecayNode(topNode);
0088   }
0089 
0090   return canSearchDecay;
0091 }
0092 
0093 int DecayFinder::process_event(PHCompositeNode* topNode)
0094 {
0095   bool decayFound = findDecay(topNode);
0096 
0097   if (decayFound && m_save_dst && Verbosity() >= VERBOSITY_MORE)
0098   {
0099     printNode(topNode);
0100   }
0101 
0102   if (m_triggerOnDecay && !decayFound)
0103   {
0104     if (Verbosity() >= VERBOSITY_MORE)
0105     {
0106       std::cout << "The decay, " << m_decayDescriptor << " was not found or reconstructable in this event, skipping" << std::endl;
0107     }
0108     return Fun4AllReturnCodes::ABORTEVENT;
0109   }
0110   else
0111   {
0112     return Fun4AllReturnCodes::EVENT_OK;
0113   }
0114 }
0115 
0116 int DecayFinder::End(PHCompositeNode* /*topNode*/)
0117 {
0118   if (Verbosity() >= VERBOSITY_SOME)
0119   {
0120     printInfo();
0121   }
0122 
0123   return 0;
0124 }
0125 
0126 /*
0127  *
0128  *This function tries to intepret the string you wrote
0129  *Will be semi-independent of the rest of this class
0130  *(semi- because we need this to set the charges and strings)
0131  *
0132  */
0133 int DecayFinder::parseDecayDescriptor()
0134 {
0135   bool ddCanBeParsed = true;
0136 
0137   size_t daughterLocator;
0138 
0139   std::string mother;
0140   std::string intermediate;
0141   std::string daughter;
0142 
0143   int mother_charge = 0;
0144   std::vector<int> intermediates_charge;
0145   std::vector<int> daughters_charge;
0146 
0147   std::string decayArrow = "->";
0148   std::string chargeIndicator = "^";
0149   std::string startIntermediate = "{";
0150   std::string endIntermediate = "}";
0151 
0152   // These tracks require a + or - after their name for TDatabasePDG
0153   std::string specialTracks[] = {"e", "mu", "pi", "K"};
0154 
0155   std::string manipulateDecayDescriptor = m_decayDescriptor;
0156 
0157   // Remove all white space before we begin
0158   size_t pos;
0159   while ((pos = manipulateDecayDescriptor.find(' ')) != std::string::npos)
0160   {
0161     manipulateDecayDescriptor.replace(pos, 1, "");
0162   }
0163 
0164   // Check for charge conjugate requirement
0165   std::string checkForCC = manipulateDecayDescriptor.substr(0, 1) + manipulateDecayDescriptor.substr(manipulateDecayDescriptor.size() - 3, 3);
0166   std::for_each(checkForCC.begin(), checkForCC.end(), [](char& c)
0167                 { c = ::toupper(c); });
0168 
0169   // Remove the CC check if needed
0170   if (checkForCC == "[]CC")
0171   {
0172     manipulateDecayDescriptor = manipulateDecayDescriptor.substr(1, manipulateDecayDescriptor.size() - 4);
0173     m_getChargeConjugate = true;
0174   }
0175 
0176   // Try and find the initial particle
0177   size_t findMotherEndPoint = manipulateDecayDescriptor.find(decayArrow);
0178   mother = manipulateDecayDescriptor.substr(0, findMotherEndPoint);
0179   if (findParticle(mother))
0180   {
0181     m_mother_ID = abs(get_pdgcode(mother));
0182   }
0183   else
0184   {
0185     ddCanBeParsed = false;
0186   }
0187   manipulateDecayDescriptor.erase(0, findMotherEndPoint + decayArrow.length());
0188 
0189   // Try and find the intermediates
0190   while ((pos = manipulateDecayDescriptor.find(startIntermediate)) != std::string::npos)
0191   {
0192     size_t findIntermediateStartPoint = manipulateDecayDescriptor.find(startIntermediate, pos);
0193     size_t findIntermediateEndPoint = manipulateDecayDescriptor.find(endIntermediate, pos);
0194     std::string intermediateDecay = manipulateDecayDescriptor.substr(pos + 1, findIntermediateEndPoint - (pos + 1));
0195 
0196     intermediate = intermediateDecay.substr(0, intermediateDecay.find(decayArrow));
0197     if (findParticle(intermediate))
0198     {
0199       m_intermediates_ID.push_back(abs(get_pdgcode(intermediate)));
0200     }
0201     else
0202     {
0203       ddCanBeParsed = false;
0204     }
0205 
0206     // Now find the daughters associated to this intermediate
0207     int nDaughters = 0;
0208     intermediateDecay.erase(0, intermediateDecay.find(decayArrow) + decayArrow.length());
0209     while ((daughterLocator = intermediateDecay.find(chargeIndicator)) != std::string::npos)
0210     {
0211       daughter = intermediateDecay.substr(0, daughterLocator);
0212       std::string daughterChargeString = intermediateDecay.substr(daughterLocator + 1, 1);
0213       if (std::find(std::begin(specialTracks), std::end(specialTracks), daughter) != std::end(specialTracks))
0214       {
0215         daughter += daughterChargeString;
0216       }
0217       if (findParticle(daughter))
0218       {
0219         int daughter_ID = abs(get_pdgcode(daughter));
0220         m_daughters_ID.push_back(daughter_ID);
0221         daughters_charge.push_back(get_charge(daughter));
0222 
0223         if (daughter_ID == 22)
0224         {
0225           m_hasPhotonDaughter = m_allowPhotons = true; 
0226         }
0227       }
0228       else
0229       {
0230         ddCanBeParsed = false;
0231       }
0232       intermediateDecay.erase(0, daughterLocator + 2);
0233       ++nDaughters;
0234     }
0235     manipulateDecayDescriptor.erase(findIntermediateStartPoint, findIntermediateEndPoint + 1 - findIntermediateStartPoint);
0236     m_nTracksFromIntermediates.push_back(nDaughters);
0237     m_nTracksFromMother += 1;
0238   }
0239 
0240   // Now find any remaining reconstructable tracks from the mother
0241   while ((daughterLocator = manipulateDecayDescriptor.find(chargeIndicator)) != std::string::npos)
0242   {
0243     daughter = manipulateDecayDescriptor.substr(0, daughterLocator);
0244     std::string daughterChargeString = manipulateDecayDescriptor.substr(daughterLocator + 1, 1);
0245     if (std::find(std::begin(specialTracks), std::end(specialTracks), daughter) != std::end(specialTracks))
0246     {
0247       daughter += daughterChargeString;
0248     }
0249     if (findParticle(daughter))
0250     {
0251       m_daughters_ID.push_back(abs(get_pdgcode(daughter)));
0252       daughters_charge.push_back(get_charge(daughter));
0253     }
0254     else
0255     {
0256       ddCanBeParsed = false;
0257     }
0258     manipulateDecayDescriptor.erase(0, daughterLocator + 2);
0259     m_nTracksFromMother += 1;
0260   }
0261 
0262   unsigned int trackStart = 0;
0263   unsigned int trackEnd = 0;
0264   for (unsigned int i = 0; i < m_intermediates_ID.size(); ++i)
0265   {
0266     trackStart = trackEnd;
0267     trackEnd = m_nTracksFromIntermediates[i] + trackStart;
0268 
0269     int vtxCharge = 0;
0270 
0271     for (unsigned int j = trackStart; j < trackEnd; ++j)
0272     {
0273       vtxCharge += daughters_charge[j];
0274     }
0275 
0276     intermediates_charge.push_back(vtxCharge);
0277   }
0278 
0279   for (unsigned int i = 0; i < m_daughters_ID.size(); ++i)
0280   {
0281     mother_charge += daughters_charge[i];
0282   }
0283 
0284   m_mother_ID = mother_charge == 0 ? m_mother_ID : mother_charge * m_mother_ID;
0285   for (unsigned int i = 0; i < m_intermediates_ID.size(); ++i)
0286   {
0287     m_intermediates_ID[i] = intermediates_charge[i] == 0 ? m_intermediates_ID[i] : intermediates_charge[i] * m_intermediates_ID[i];
0288     m_motherDecayProducts.push_back(m_intermediates_ID[i]);
0289   }
0290   for (unsigned int i = 0; i < m_daughters_ID.size(); ++i)
0291   {
0292     m_daughters_ID[i] = daughters_charge[i] == 0 ? m_daughters_ID[i] : daughters_charge[i] * m_daughters_ID[i];
0293     if (i >= trackEnd)
0294     {
0295       m_motherDecayProducts.push_back(m_daughters_ID[i]);
0296     }
0297   }
0298 
0299   if (ddCanBeParsed)
0300   {
0301     if (Verbosity() >= VERBOSITY_MORE)
0302     {
0303       std::cout << "Your decay descriptor can be parsed" << std::endl;
0304     }
0305     return 0;
0306   }
0307   else
0308   {
0309     if (Verbosity() >= VERBOSITY_SOME)
0310     {
0311       std::cout << "Your decay descriptor cannot be parsed, " << Name() << " will not be registered" << std::endl;
0312     }
0313     return Fun4AllReturnCodes::DONOTREGISTERSUBSYSTEM;
0314   }
0315 }
0316 
0317 /*
0318  * Main body for searching your decay
0319  * Slight issue if you limit the generator decay
0320  * as decays wont enter the HepMC record
0321  * need a switch to go to Geant4 record
0322  */
0323 bool DecayFinder::findDecay(PHCompositeNode* topNode)
0324 {
0325   bool decayWasFound = false;
0326   bool reconstructableDecayWasFound = false;
0327   bool aTrackFailedPT = false;
0328   bool aTrackFailedETA = false;
0329   bool aMotherHasPhoton = false;
0330   bool aMotherHasPi0 = false;
0331   std::vector<int> correctMotherProducts;
0332   std::vector<int> positive_motherDecayProducts;
0333 
0334   int n = sizeof(listOfResonantPIDs) / sizeof(listOfResonantPIDs[0]);
0335   for (int i : m_intermediates_ID)
0336   {
0337     n = deleteElement(listOfResonantPIDs, n, i);
0338   }
0339 
0340   n = deleteElement(listOfResonantPIDs, n, m_mother_ID);
0341 
0342   for (int m_motherDecayProduct : m_motherDecayProducts)
0343   {
0344     positive_motherDecayProducts.push_back(std::abs(m_motherDecayProduct));
0345   }
0346 
0347   m_truthinfo = findNode::getClass<PHG4TruthInfoContainer>(topNode, "G4TruthInfo");
0348   if (!m_truthinfo)
0349   {
0350     std::cout << "DecayFinder: Missing node G4TruthInfo" << std::endl;
0351   }
0352 
0353   m_geneventmap = findNode::getClass<PHHepMCGenEventMap>(topNode, "PHHepMCGenEventMap");
0354   if (!m_geneventmap)
0355   {
0356     std::cout << "DecayFinder: Missing node PHHepMCGenEventMap" << std::endl;
0357   }
0358 
0359   if (!m_truthinfo && !m_geneventmap)
0360   {
0361     std::cout << "You have neither the PHHepMCGenEventMap or G4TruthInfo nodes" << std::endl;
0362     std::cout << "DecayFinder will crash, exiting now!" << std::endl;
0363     exit(1);
0364   }
0365 
0366   if (m_truthinfo && !m_geneventmap)  // This should use the truth info container if we have no HepMC record
0367   {
0368     if (Verbosity() >= VERBOSITY_SOME)
0369     {
0370       std::cout << "You have a valid G4TruthInfo but no PHHepMCGenEventMap container" << std::endl;
0371       std::cout << "You are probably using a particle gun" << std::endl;
0372     }
0373 
0374     PHG4TruthInfoContainer::ConstRange range = m_truthinfo->GetParticleRange();
0375     for (PHG4TruthInfoContainer::ConstIterator iter = range.first; iter != range.second; ++iter)
0376     {
0377       PHG4Particle* g4particle = iter->second;
0378       int this_pid = m_getChargeConjugate ? abs(g4particle->get_pid()) : g4particle->get_pid();
0379       if (this_pid == m_mother_ID)
0380       {
0381         if (Verbosity() >= VERBOSITY_MAX)
0382         {
0383           std::cout << "parent->pdg_id(): " << g4particle->get_pid() << std::endl;
0384         }
0385 
0386         bool breakOut = false;
0387         correctMotherProducts.clear();
0388         decayChain.clear();
0389         decayChain.push_back(std::make_pair(std::make_pair(g4particle->get_primary_id(), g4particle->get_barcode()), g4particle->get_pid()));
0390 
0391         searchGeant4Record(g4particle->get_barcode(), g4particle->get_pid(), positive_motherDecayProducts, breakOut, aMotherHasPhoton, aMotherHasPi0, aTrackFailedPT, aTrackFailedETA, correctMotherProducts);
0392 
0393         if (breakOut)
0394         {
0395           continue;
0396         }
0397 
0398         decayWasFound = compareDecays(m_motherDecayProducts, correctMotherProducts);
0399 
0400         if (decayWasFound)
0401         {
0402           m_counter += 1;
0403           if (aTrackFailedPT && !aTrackFailedETA)
0404           {
0405             m_nCandFail_pT += 1;
0406           }
0407           else if (!aTrackFailedPT && aTrackFailedETA)
0408           {
0409             m_nCandFail_eta += 1;
0410           }
0411           else if (aTrackFailedPT && aTrackFailedETA)
0412           {
0413             m_nCandFail_pT_and_eta += 1;
0414           }
0415           else
0416           {
0417             m_nCandReconstructable += 1;
0418             reconstructableDecayWasFound = true;
0419             if (m_save_dst)
0420             {
0421               fillDecayNode(topNode, decayChain);
0422             }
0423             if (aMotherHasPhoton && !aMotherHasPi0)
0424             {
0425               m_nCandHas_Photon += 1;
0426             }
0427             else if (!aMotherHasPhoton && aMotherHasPi0)
0428             {
0429               m_nCandHas_Pi0 += 1;
0430             }
0431             else if (aMotherHasPhoton && aMotherHasPi0)
0432             {
0433               m_nCandHas_Photon_and_Pi0 += 1;
0434             }
0435             else
0436             {
0437               m_nCandHas_noPhoton_and_noPi0 += 1;
0438             }
0439           }
0440         }
0441       }
0442     }
0443     return reconstructableDecayWasFound;
0444   }
0445 
0446   for (PHHepMCGenEventMap::ConstReverseIter riter = m_geneventmap->rbegin();
0447        riter != m_geneventmap->rend(); ++riter)
0448   {
0449     m_genevt = riter->second;
0450     if (!m_genevt)
0451     {
0452       std::cout << "DecayFinder: Missing node PHHepMCGenEvent" << std::endl;
0453       return false;
0454     }
0455 
0456     HepMC::GenEvent* theEvent = m_genevt->getEvent();
0457 
0458     for (HepMC::GenEvent::particle_const_iterator p = theEvent->particles_begin(); p != theEvent->particles_end(); ++p)
0459     {
0460       int this_pid = m_getChargeConjugate ? abs((*p)->pdg_id()) : (*p)->pdg_id();
0461       if (this_pid == m_mother_ID)
0462       {
0463         if (Verbosity() >= VERBOSITY_MAX)
0464         {
0465           std::cout << "parent->pdg_id(): " << (*p)->pdg_id() << std::endl;
0466         }
0467 
0468         bool breakOut = false;
0469         correctMotherProducts.clear();
0470         decayChain.clear();
0471         decayChain.push_back(std::make_pair(std::make_pair(m_genevt->get_embedding_id(), (*p)->barcode()), (*p)->pdg_id()));
0472 
0473         // Make sure that the mother has a decay in our record
0474         if (!(*p)->end_vertex())  // Mother has no end vertex, decay volume was limited
0475         {
0476           searchGeant4Record((*p)->barcode(), (*p)->pdg_id(), positive_motherDecayProducts, breakOut, aMotherHasPhoton, aMotherHasPi0, aTrackFailedPT, aTrackFailedETA, correctMotherProducts);
0477         }
0478         else
0479         {
0480           searchHepMCRecord((*p), positive_motherDecayProducts, breakOut, aMotherHasPhoton, aMotherHasPi0, aTrackFailedPT, aTrackFailedETA, correctMotherProducts);
0481         }
0482 
0483         if (breakOut)
0484         {
0485           continue;
0486         }
0487 
0488         decayWasFound = compareDecays(m_motherDecayProducts, correctMotherProducts);
0489 
0490         if (decayWasFound)
0491         {
0492           m_counter += 1;
0493           if (aTrackFailedPT && !aTrackFailedETA)
0494           {
0495             m_nCandFail_pT += 1;
0496           }
0497           else if (!aTrackFailedPT && aTrackFailedETA)
0498           {
0499             m_nCandFail_eta += 1;
0500           }
0501           else if (aTrackFailedPT && aTrackFailedETA)
0502           {
0503             m_nCandFail_pT_and_eta += 1;
0504           }
0505           else
0506           {
0507             m_nCandReconstructable += 1;
0508             reconstructableDecayWasFound = true;
0509             if (m_save_dst)
0510             {
0511               fillDecayNode(topNode, decayChain);
0512             }
0513             if (aMotherHasPhoton && !aMotherHasPi0)
0514             {
0515               m_nCandHas_Photon += 1;
0516             }
0517             else if (!aMotherHasPhoton && aMotherHasPi0)
0518             {
0519               m_nCandHas_Pi0 += 1;
0520             }
0521             else if (aMotherHasPhoton && aMotherHasPi0)
0522             {
0523               m_nCandHas_Photon_and_Pi0 += 1;
0524             }
0525             else
0526             {
0527               m_nCandHas_noPhoton_and_noPi0 += 1;
0528             }
0529           }
0530         }
0531       }
0532     }
0533   }
0534 
0535   return reconstructableDecayWasFound;
0536 }
0537 
0538 /*
0539  * Function to search HepMC record
0540  * Can switch to Geant4 search if needed
0541  */
0542 void DecayFinder::searchHepMCRecord(HepMC::GenParticle* particle, std::vector<int> decayProducts,
0543                                     bool& breakLoop, bool& hasPhoton, bool& hasPi0, bool& failedPT, bool& failedETA,
0544                                     std::vector<int>& actualDecayProducts)
0545 {
0546   for (HepMC::GenVertex::particle_iterator children = particle->end_vertex()->particles_begin(HepMC::children);
0547        children != particle->end_vertex()->particles_end(HepMC::children); ++children)
0548   {
0549     if (Verbosity() >= VERBOSITY_MAX)
0550     {
0551       std::cout << "--children->pdg_id(): " << (*children)->pdg_id() << std::endl;
0552     }
0553 
0554     if ((*children)->pdg_id() == 22)
0555     {
0556       hasPhoton = true;
0557     }
0558     if ((*children)->pdg_id() == 111)
0559     {
0560       hasPi0 = true;
0561     }
0562     if ((!m_allowPhotons && (*children)->pdg_id() == 22) || (!m_allowPi0 && (*children)->pdg_id() == 111))
0563     {
0564       breakLoop = true;
0565       break;
0566     }
0567 
0568     // This is one of the children we are looking for
0569     if (std::find(decayProducts.begin(), decayProducts.end(),
0570                   std::abs((*children)->pdg_id())) != decayProducts.end())
0571     {
0572       if (Verbosity() >= VERBOSITY_MAX)
0573       {
0574         std::cout << "This is a child you were looking for" << std::endl;
0575       }
0576       // Check if this is an internediate decay that didnt decay in the generator
0577       std::vector<int> positive_intermediates_ID;
0578       for (int i : m_intermediates_ID)
0579       {
0580         positive_intermediates_ID.push_back(abs(i));
0581       }
0582 
0583       if (!(*children)->end_vertex() && std::find(positive_intermediates_ID.begin(), positive_intermediates_ID.end(),
0584                                                   abs((*children)->pdg_id())) != positive_intermediates_ID.end())
0585       {
0586         std::vector<int> requiredIntermediateDecayProducts;
0587         std::vector<int> positive_requiredIntermediateDecayProducts;
0588         std::vector<int> actualIntermediateDecayProducts;
0589         // Which intermediate decay list to we need
0590         auto it = std::find(positive_intermediates_ID.begin(), positive_intermediates_ID.end(), abs((*children)->pdg_id()));
0591         int index = std::distance(positive_intermediates_ID.begin(), it);
0592 
0593         unsigned int trackStart = 0, trackStop = 0;
0594         if (index == 0)
0595         {
0596           trackStop = m_nTracksFromIntermediates[0];
0597         }
0598         else
0599         {
0600           for (int i = 0; i < index; ++i)
0601           {
0602             trackStart += m_nTracksFromIntermediates[i];
0603           }
0604           trackStop = trackStart + m_nTracksFromIntermediates[index];
0605         }
0606         for (unsigned int i = trackStart; i < trackStop; ++i)
0607         {
0608           requiredIntermediateDecayProducts.push_back(m_daughters_ID[i]);
0609           positive_requiredIntermediateDecayProducts.push_back(abs(m_daughters_ID[i]));
0610         }
0611 
0612         searchGeant4Record((*children)->barcode(), (*children)->pdg_id(), positive_requiredIntermediateDecayProducts,
0613                            breakLoop, hasPhoton, hasPi0, failedPT, failedETA, actualIntermediateDecayProducts);
0614 
0615         bool needThisParticle = compareDecays(requiredIntermediateDecayProducts, actualIntermediateDecayProducts);
0616         if (needThisParticle)
0617         {
0618           actualDecayProducts.push_back((*children)->pdg_id());
0619           decayChain.push_back(std::make_pair(std::make_pair(m_genevt->get_embedding_id(), (*children)->barcode()), (*children)->pdg_id()));
0620         }
0621         else  // Remove what I added to the decayChain
0622         {
0623           decayChain.erase(decayChain.end() - (m_intermediate_product_counter + 1), decayChain.end());
0624           decayChain.pop_back();
0625         }
0626 
0627         m_intermediate_product_counter = 0;
0628       }
0629       else
0630       {
0631         bool needThisParticle = checkIfCorrectHepMCParticle((*children), failedPT, failedETA);
0632         if (needThisParticle)
0633         {
0634           actualDecayProducts.push_back((*children)->pdg_id());
0635           decayChain.push_back(std::make_pair(std::make_pair(m_genevt->get_embedding_id(), (*children)->barcode()), (*children)->pdg_id()));
0636         }
0637       }
0638     }  // Now check if it's part of the resonance list
0639     else if (std::find(std::begin(listOfResonantPIDs), std::end(listOfResonantPIDs),
0640                        std::abs((*children)->pdg_id())) != std::end(listOfResonantPIDs))
0641     {
0642       if (Verbosity() >= VERBOSITY_MAX)
0643       {
0644         std::cout << "This is a resonance to investigate further" << std::endl;
0645       }
0646       if (!(*children)->end_vertex())
0647       {
0648         searchGeant4Record((*children)->barcode(), (*children)->pdg_id(), decayProducts,
0649                            breakLoop, hasPhoton, hasPi0, failedPT, failedETA, actualDecayProducts);
0650       }
0651       else
0652       {
0653         for (HepMC::GenVertex::particle_iterator grandchildren = (*children)->end_vertex()->particles_begin(HepMC::children);
0654              grandchildren != (*children)->end_vertex()->particles_end(HepMC::children); ++grandchildren)
0655         {
0656           bool needThisParticle = checkIfCorrectHepMCParticle((*grandchildren), failedPT, failedETA);
0657           if (needThisParticle)
0658           {
0659             actualDecayProducts.push_back((*grandchildren)->pdg_id());
0660             decayChain.push_back(std::make_pair(std::make_pair(m_genevt->get_embedding_id(), (*grandchildren)->barcode()), (*grandchildren)->pdg_id()));
0661           }
0662         }
0663       }
0664     }
0665     else
0666     {
0667       breakLoop = true;  // This particle is not in the decay descriptor, stop
0668       break;
0669     }
0670   }
0671 }
0672 
0673 /*
0674  *Function to search Geant4 record
0675  * Cannot switch to HepMC search (doesn't make sense to)
0676  */
0677 void DecayFinder::searchGeant4Record(int barcode, int pid, std::vector<int> decayProducts, bool& breakLoop, bool& hasPhoton, bool& hasPi0, bool& failedPT, bool& failedETA, std::vector<int>& actualDecayProducts)
0678 {
0679   PHG4TruthInfoContainer::ConstRange range = m_truthinfo->GetParticleRange();
0680   for (PHG4TruthInfoContainer::ConstIterator iter = range.first; iter != range.second; ++iter)
0681   {
0682     if (decayChain.size() == 100)
0683     {
0684       breakLoop = true;  // Stuck in loop. Sympton not cause!
0685       break;
0686     }
0687 
0688     PHG4Particle* g4particle = iter->second;
0689     PHG4Particle* mother = nullptr;
0690     if (g4particle->get_parent_id() != 0)
0691     {
0692       mother = m_truthinfo->GetParticle(g4particle->get_parent_id());
0693     }
0694     else
0695     {
0696       continue;
0697     }
0698     if (mother->get_barcode() == barcode && abs(mother->get_pid()) == abs(pid))
0699     {
0700       int particleID = g4particle->get_pid();
0701       if (Verbosity() >= VERBOSITY_MAX)
0702       {
0703         std::cout << "--children->pdg_id(): " << particleID << std::endl;
0704       }
0705       if (particleID == 22)
0706       {
0707         hasPhoton = true;
0708       }
0709       if (particleID == 111)
0710       {
0711         hasPi0 = true;
0712       }
0713 
0714       if ((!m_allowPhotons && particleID == 22) || (!m_hasPhotonDaughter && particleID == 22) || (!m_allowPi0 && particleID == 111))
0715       {
0716         breakLoop = true;
0717         break;
0718       }
0719       // This is one of the children we are looking for
0720       if (std::find(decayProducts.begin(), decayProducts.end(),
0721                     std::abs(particleID)) != decayProducts.end())
0722       {
0723         bool needThisParticle = checkIfCorrectGeant4Particle(g4particle, hasPhoton, hasPi0, failedPT, failedETA);
0724         if (needThisParticle)
0725         {
0726           if (Verbosity() >= VERBOSITY_MAX)
0727           {
0728             std::cout << "This is a child you were looking for" << std::endl;
0729           }
0730           actualDecayProducts.push_back(particleID);
0731           int embedding_id = m_geneventmap ? m_genevt->get_embedding_id() : g4particle->get_primary_id();
0732           decayChain.push_back(std::make_pair(std::make_pair(embedding_id, g4particle->get_barcode()), particleID));
0733         }
0734       }  // Now check if it's part of the other resonance list
0735       else if ((m_allowPhotons && !m_hasPhotonDaughter && particleID == 22) || (m_allowPi0 && particleID == 111))
0736       {
0737         continue;
0738       }
0739       else if (std::find(std::begin(listOfResonantPIDs), std::end(listOfResonantPIDs),
0740                          std::abs(particleID)) != std::end(listOfResonantPIDs))
0741       {
0742         if (Verbosity() >= VERBOSITY_MAX)
0743         {
0744           std::cout << "This is a resonance to investigate further" << std::endl;
0745         }
0746         searchGeant4Record(g4particle->get_barcode(), g4particle->get_pid(), decayProducts,
0747                            breakLoop, hasPhoton, hasPi0, failedPT, failedETA, actualDecayProducts);
0748       }
0749       else
0750       {
0751         breakLoop = true;  // This particle is not in the decay descriptor, stop
0752         break;
0753       }
0754     }
0755   }
0756 }
0757 
0758 /*
0759  * Checks if this prticle really matches your request
0760  */
0761 bool DecayFinder::checkIfCorrectHepMCParticle(HepMC::GenParticle* particle, bool& trackFailedPT, bool& trackFailedETA)
0762 {
0763   bool acceptParticle = false;
0764 
0765   std::vector<int> positive_intermediates_ID;
0766   for (int i : m_intermediates_ID)
0767   {
0768     positive_intermediates_ID.push_back(abs(i));
0769   }
0770 
0771   // Check if it is an intermediate or a final track
0772   if (std::find(positive_intermediates_ID.begin(), positive_intermediates_ID.end(),
0773                 abs(particle->pdg_id())) != positive_intermediates_ID.end())
0774   {
0775     std::vector<int> requiredIntermediateDecayProducts;
0776     std::vector<int> actualIntermediateDecayProducts;
0777     // Which intermediate decay list to we need
0778     auto it = std::find(positive_intermediates_ID.begin(), positive_intermediates_ID.end(), abs(particle->pdg_id()));
0779     int index = std::distance(positive_intermediates_ID.begin(), it);
0780 
0781     unsigned int trackStart = 0, trackStop = 0;
0782     if (index == 0)
0783     {
0784       trackStop = m_nTracksFromIntermediates[0];
0785     }
0786     else
0787     {
0788       for (int i = 0; i < index; ++i)
0789       {
0790         trackStart += m_nTracksFromIntermediates[i];
0791       }
0792       trackStop = trackStart + m_nTracksFromIntermediates[index];
0793     }
0794 
0795     for (unsigned int i = trackStart; i < trackStop; ++i)
0796     {
0797       requiredIntermediateDecayProducts.push_back(m_daughters_ID[i]);
0798     }
0799 
0800     for (HepMC::GenVertex::particle_iterator grandchildren = particle->end_vertex()->particles_begin(HepMC::children);
0801          grandchildren != particle->end_vertex()->particles_end(HepMC::children); ++grandchildren)
0802     {
0803       if (Verbosity() >= VERBOSITY_MAX)
0804       {
0805         std::cout << "----grandchildren->pdg_id(): " << (*grandchildren)->pdg_id() << std::endl;
0806       }
0807 
0808       if (std::find(std::begin(listOfResonantPIDs), std::end(listOfResonantPIDs),
0809                     std::abs((*grandchildren)->pdg_id())) != std::end(listOfResonantPIDs))
0810       {
0811         for (HepMC::GenVertex::particle_iterator greatgrandchildren = (*grandchildren)->end_vertex()->particles_begin(HepMC::children);
0812              greatgrandchildren != (*grandchildren)->end_vertex()->particles_end(HepMC::children); ++greatgrandchildren)
0813         {
0814           if (Verbosity() >= VERBOSITY_MAX)
0815           {
0816             std::cout << "--------greatgrandchildren->pdg_id(): " << (*greatgrandchildren)->pdg_id() << std::endl;
0817           }
0818 
0819           if ((m_allowPhotons && !m_hasPhotonDaughter && (*greatgrandchildren)->pdg_id() == 22) || (m_allowPi0 && (*greatgrandchildren)->pdg_id() == 111))
0820           {
0821             continue;
0822           }
0823           else if ((!m_hasPhotonDaughter && (*greatgrandchildren)->pdg_id() == 22) || (!m_allowPhotons && (*greatgrandchildren)->pdg_id() == 22) || (!m_allowPi0 && (*greatgrandchildren)->pdg_id() == 111))
0824           {
0825             break;
0826           }
0827           else
0828           {
0829             actualIntermediateDecayProducts.push_back((*greatgrandchildren)->pdg_id());
0830             decayChain.push_back(std::make_pair(std::make_pair(m_genevt->get_embedding_id(), (*greatgrandchildren)->barcode()), (*greatgrandchildren)->pdg_id()));
0831             ++m_intermediate_product_counter;
0832 
0833             HepMC::FourVector myFourVector = (*greatgrandchildren)->momentum();
0834 
0835             HepMC::GenVertex* thisVtx = (*greatgrandchildren)->production_vertex();
0836             double vtxPos[3] = {thisVtx->point3d().x(), thisVtx->point3d().y(), thisVtx->point3d().z()};
0837             if (m_recalcualteEtaRange)
0838             {
0839               recalculateEta(myFourVector.py(), vtxPos);
0840             }
0841 
0842             if (myFourVector.perp() < m_pt_req)
0843             {
0844               trackFailedPT = true;
0845             }
0846             if (!isInRange(m_eta_low_req, myFourVector.eta(), m_eta_high_req))
0847             {
0848               trackFailedETA = true;
0849             }
0850 
0851             if (Verbosity() >= VERBOSITY_MAX)
0852             {
0853               std::cout << "pT = " << myFourVector.perp() << ", eta = " << myFourVector.eta() << std::endl;
0854               std::cout << "The track " << passOrFail(myFourVector.perp() >= m_pt_req) << " the pT requirement, ";
0855               std::cout << "the track " << passOrFail(isInRange(m_eta_low_req, myFourVector.eta(), m_eta_high_req)) << " the eta requirement." << std::endl;
0856             }
0857           }
0858         }
0859       }
0860       else if ((m_allowPhotons && !m_hasPhotonDaughter && (*grandchildren)->pdg_id() == 22) || (m_allowPi0 && (*grandchildren)->pdg_id() == 111))
0861       {
0862         continue;
0863       }
0864       else if ((!m_hasPhotonDaughter && (*grandchildren)->pdg_id() == 22) || (!m_allowPhotons && (*grandchildren)->pdg_id() == 22) || (!m_allowPi0 && (*grandchildren)->pdg_id() == 111))
0865       {
0866         break;
0867       }
0868       else
0869       {
0870         actualIntermediateDecayProducts.push_back((*grandchildren)->pdg_id());
0871         decayChain.push_back(std::make_pair(std::make_pair(m_genevt->get_embedding_id(), (*grandchildren)->barcode()), (*grandchildren)->pdg_id()));
0872         ++m_intermediate_product_counter;
0873 
0874         HepMC::FourVector myFourVector = (*grandchildren)->momentum();
0875 
0876         HepMC::GenVertex* thisVtx = (*grandchildren)->production_vertex();
0877         double vtxPos[3] = {thisVtx->point3d().x(), thisVtx->point3d().y(), thisVtx->point3d().z()};
0878         if (m_recalcualteEtaRange)
0879         {
0880           recalculateEta(myFourVector.py(), vtxPos);
0881         }
0882 
0883         if (myFourVector.perp() < m_pt_req)
0884         {
0885           trackFailedPT = true;
0886         }
0887         if (!isInRange(m_eta_low_req, myFourVector.eta(), m_eta_high_req))
0888         {
0889           trackFailedETA = true;
0890         }
0891 
0892         if (Verbosity() >= VERBOSITY_MAX)
0893         {
0894           std::cout << "pT = " << myFourVector.perp() << ", eta = " << myFourVector.eta() << std::endl;
0895           std::cout << "The track " << passOrFail(myFourVector.perp() >= m_pt_req) << " the pT requirement, ";
0896           std::cout << "the track " << passOrFail(isInRange(m_eta_low_req, myFourVector.eta(), m_eta_high_req)) << " the eta requirement." << std::endl;
0897         }
0898       }
0899     }
0900 
0901     acceptParticle = compareDecays(requiredIntermediateDecayProducts, actualIntermediateDecayProducts);
0902   }
0903   //else if ((particle->pdg_id() == 22) || (particle->pdg_id() == 111))
0904   //{
0905   //  return false;
0906   //}
0907   else
0908   {
0909     if (Verbosity() >= VERBOSITY_MAX)
0910     {
0911       std::cout << "This is a final state track" << std::endl;
0912     }
0913     const HepMC::FourVector& myFourVector = particle->momentum();
0914 
0915     HepMC::GenVertex* thisVtx = particle->production_vertex();
0916     double vtxPos[3] = {thisVtx->point3d().x(), thisVtx->point3d().y(), thisVtx->point3d().z()};
0917     if (m_recalcualteEtaRange)
0918     {
0919       recalculateEta(myFourVector.py(), vtxPos);
0920     }
0921 
0922     if (myFourVector.perp() < m_pt_req)
0923     {
0924       trackFailedPT = true;
0925     }
0926     if (!isInRange(m_eta_low_req, myFourVector.eta(), m_eta_high_req))
0927     {
0928       trackFailedETA = true;
0929     }
0930 
0931     if (Verbosity() >= VERBOSITY_MAX)
0932     {
0933       std::cout << "pT = " << myFourVector.perp() << ", eta = " << myFourVector.eta() << std::endl;
0934       std::cout << "The track " << passOrFail(myFourVector.perp() >= m_pt_req) << " the pT requirement, ";
0935       std::cout << "the track " << passOrFail(isInRange(m_eta_low_req, myFourVector.eta(), m_eta_high_req)) << " the eta requirement." << std::endl;
0936     }
0937     acceptParticle = true;
0938   }
0939 
0940   return acceptParticle;
0941 }
0942 
0943 /*
0944  * Checks if this prticle really matches your request
0945  */
0946 bool DecayFinder::checkIfCorrectGeant4Particle(PHG4Particle* particle, bool& hasPhoton, bool& hasPi0, bool& trackFailedPT, bool& trackFailedETA)
0947 {
0948   bool acceptParticle = false;
0949 
0950   std::vector<int> positive_intermediates_ID;
0951   for (int i : m_intermediates_ID)
0952   {
0953     positive_intermediates_ID.push_back(abs(i));
0954   }
0955   // Check if it is an intermediate or a final track
0956   if (std::find(positive_intermediates_ID.begin(), positive_intermediates_ID.end(),
0957                 abs(particle->get_pid())) != positive_intermediates_ID.end())
0958   {
0959     std::vector<int> requiredIntermediateDecayProducts;
0960     std::vector<int> actualIntermediateDecayProducts;
0961     // Which intermediate decay list to we need
0962     auto it = std::find(positive_intermediates_ID.begin(), positive_intermediates_ID.end(), abs(particle->get_pid()));
0963     int index = std::distance(positive_intermediates_ID.begin(), it);
0964 
0965     unsigned int trackStart = 0, trackStop = 0;
0966     if (index == 0)
0967     {
0968       trackStop = m_nTracksFromIntermediates[0];
0969     }
0970     else
0971     {
0972       for (int i = 0; i < index; ++i)
0973       {
0974         trackStart += m_nTracksFromIntermediates[i];
0975       }
0976       trackStop = trackStart + m_nTracksFromIntermediates[index];
0977     }
0978 
0979     std::vector<int> positive_intermediateDecayProducts;
0980     for (unsigned int i = trackStart; i < trackStop; ++i)
0981     {
0982       positive_intermediateDecayProducts.push_back(abs(m_daughters_ID[i]));
0983       requiredIntermediateDecayProducts.push_back(m_daughters_ID[i]);
0984     }
0985 
0986     bool fakeBreak = false;
0987     searchGeant4Record(particle->get_barcode(), particle->get_pid(), positive_intermediateDecayProducts, fakeBreak,
0988                        hasPhoton, hasPi0, trackFailedPT, trackFailedETA, actualIntermediateDecayProducts);
0989 
0990     acceptParticle = compareDecays(requiredIntermediateDecayProducts, actualIntermediateDecayProducts);
0991   }
0992   //else if ((particle->get_pid() == 22) || (particle->get_pid() == 111))
0993   //{
0994   //  return false;
0995   //}
0996   else
0997   {
0998     if (Verbosity() >= VERBOSITY_MAX)
0999     {
1000       std::cout << "This is a final state track" << std::endl;
1001     }
1002     double px = particle->get_px();
1003     double py = particle->get_py();
1004     double pz = particle->get_pz();
1005 
1006     double pt = std::sqrt(std::pow(px, 2) + std::pow(py, 2));
1007     double p = std::sqrt(std::pow(px, 2) + std::pow(py, 2) + std::pow(pz, 2));
1008     double eta = 0.5 * std::log((p + pz) / (p - pz));
1009 
1010     PHG4VtxPoint* thisVtx = m_truthinfo->GetVtx(particle->get_vtx_id());
1011     double vtxPos[3] = {thisVtx->get_x(), thisVtx->get_y(), thisVtx->get_z()};
1012     if (m_recalcualteEtaRange)
1013     {
1014       recalculateEta(py, vtxPos);
1015     }
1016 
1017     if (pt < m_pt_req)
1018     {
1019       trackFailedPT = true;
1020     }
1021     if (!isInRange(m_eta_low_req, eta, m_eta_high_req))
1022     {
1023       trackFailedETA = true;
1024     }
1025 
1026     if (Verbosity() >= VERBOSITY_MAX)
1027     {
1028       std::cout << "pT = " << pt << ", eta = " << eta << std::endl;
1029       std::cout << "The track " << passOrFail(pt >= m_pt_req) << " the pT requirement, ";
1030       std::cout << "the track " << passOrFail(isInRange(m_eta_low_req, eta, m_eta_high_req)) << " the eta requirement." << std::endl;
1031     }
1032 
1033     acceptParticle = true;
1034   }
1035 
1036   return acceptParticle;
1037 }
1038 
1039 /*
1040  * Check if the decay matches what we need
1041  */
1042 bool DecayFinder::compareDecays(std::vector<int> required, std::vector<int> actual)
1043 {
1044   bool accept = false;
1045   multiplyVectorByScalarAndSort(required, +1);
1046   multiplyVectorByScalarAndSort(actual, +1);
1047 
1048   if (Verbosity() >= VERBOSITY_MAX)
1049   {
1050     std::cout << "Printing required decay products: ";
1051     for (int i : required)
1052     {
1053       std::cout << i << ", ";
1054     }
1055     std::cout << std::endl;
1056     std::cout << "Printing actual decay products: ";
1057     for (int i : actual)
1058     {
1059       std::cout << i << ", ";
1060     }
1061     std::cout << std::endl;
1062     if (required == actual)
1063     {
1064       std::cout << "*\n* These vectors match\n*\n"
1065                 << std::endl;
1066     }
1067     else
1068     {
1069       std::cout << "*\n* These vectors DONT match\n*\n"
1070                 << std::endl;
1071     }
1072   }
1073 
1074   if (required == actual)
1075   {
1076     accept = true;
1077   }
1078 
1079   if (m_getChargeConjugate && !accept)
1080   {
1081     multiplyVectorByScalarAndSort(required, -1);
1082     if (required == actual)
1083     {
1084       accept = true;
1085     }
1086 
1087     if (Verbosity() >= VERBOSITY_MAX)
1088     {
1089       std::cout << "Checking CC state" << std::endl;
1090       if (required == actual)
1091       {
1092         std::cout << "*\n* These vectors match\n*\n"
1093                   << std::endl;
1094       }
1095       else
1096       {
1097         std::cout << "*\n* These vectors DONT match\n*\n"
1098                   << std::endl;
1099       }
1100     }
1101   }
1102   return accept;
1103 }
1104 
1105 /*
1106  * Everything below this is helper functions
1107  */
1108 int DecayFinder::deleteElement(int arr[], int n, int x)
1109 {
1110   // https://www.geeksforgeeks.org/delete-an-element-from-array-using-two-traversals-and-one-traversal/
1111   // Search x in array
1112   int i;
1113   for (i = 0; i < n; i++)
1114   {
1115     if (arr[i] == x)
1116     {
1117       break;
1118     }
1119   }
1120 
1121   // If x found in array
1122   if (i < n)
1123   {
1124     // reduce size of array and move all
1125     // elements on space ahead
1126     n = n - 1;
1127     for (int j = i; j < n; j++)
1128     {
1129       arr[j] = arr[j + 1];
1130     }
1131   }
1132 
1133   return n;
1134 }
1135 
1136 bool DecayFinder::findParticle(const std::string& particle)
1137 {
1138   bool particleFound = true;
1139   if (!TDatabasePDG::Instance()->GetParticle(particle.c_str()))
1140   {
1141     if (Verbosity() >= VERBOSITY_SOME)
1142     {
1143       std::cout << "The particle, " << particle << " is not in the TDatabasePDG particle list" << std::endl;
1144     }
1145     particleFound = false;
1146   }
1147 
1148   return particleFound;
1149 }
1150 
1151 void DecayFinder::multiplyVectorByScalarAndSort(std::vector<int>& v, int k)
1152 {
1153   // https://slaystudy.com/c-multiply-vector-by-scalar/
1154   std::transform(v.begin(), v.end(), v.begin(), [k](const int& c)
1155   {
1156     int particlesWithNoCC[] = {111, 113, 115, 130, 220, 221, 223, 225, 310, 330, 331, 333, 335, 440, 441, 443, 
1157                                445, 551, 553, 555, 10111, 10113, 10221, 10223, 10331, 10333, 10441, 10443, 
1158                                10551, 10553, 20113, 20223, 20333, 20443, 20553, 100443, 100553};
1159     if (std::find(std::begin(particlesWithNoCC), std::end(particlesWithNoCC), c) != std::end(particlesWithNoCC))
1160     {
1161       return c;
1162     }
1163     else
1164     {
1165       return c * k;
1166     }
1167   });
1168   std::sort(v.begin(), v.end());
1169 }
1170 
1171 int DecayFinder::get_pdgcode(const std::string& name)
1172 {
1173   if (findParticle(name))
1174   {
1175     return TDatabasePDG::Instance()->GetParticle(name.c_str())->PdgCode();
1176   }
1177   else
1178   {
1179     return 0;
1180   }
1181 }
1182 
1183 int DecayFinder::get_charge(const std::string& name)
1184 {
1185   if (findParticle(name))
1186   {
1187     return TDatabasePDG::Instance()->GetParticle(name.c_str())->Charge() / 3;
1188   }
1189   else
1190   {
1191     return -99;
1192   }
1193 }
1194 
1195 bool DecayFinder::isInRange(float min, float value, float max)
1196 {
1197   return min <= value && value <= max;
1198 }
1199 
1200 void DecayFinder::calculateEffectiveTPCradius(double vertex[3], double& effective_top_r, double& effective_bottom_r)
1201 {
1202   double r_sq = std::pow(m_tpc_r, 2);
1203   double x_sq = std::pow(vertex[0], 2);
1204 
1205   effective_top_r = std::sqrt(r_sq - x_sq) - vertex[1];
1206   effective_bottom_r = std::sqrt(r_sq - x_sq) + vertex[1];
1207 }
1208 
1209 void DecayFinder::recalculateEta(double py, double vertex[3])
1210 {
1211   calculateEffectiveTPCradius(vertex, m_effective_top_tpc_r, m_effective_bottom_tpc_r);
1212 
1213   double z_north = m_tpc_z - vertex[2];  // Distance between north end of TPC and vertex z position
1214   double z_south = m_tpc_z + vertex[2];  // Same but for south of TPC
1215 
1216   double top_north_theta = atan(m_effective_top_tpc_r / z_north);
1217   double bottom_north_theta = atan(m_effective_bottom_tpc_r / z_north);
1218   double top_south_theta = atan(m_effective_top_tpc_r / z_south);
1219   double bottom_south_theta = atan(m_effective_bottom_tpc_r / z_south);
1220 
1221   double top_north_eta = -1 * std::log(tan(top_north_theta / 2));
1222   double bottom_north_eta = -1 * std::log(tan(bottom_north_theta / 2));
1223   double top_south_eta = std::log(tan(top_south_theta / 2));
1224   double bottom_south_eta = std::log(tan(bottom_south_theta / 2));
1225 
1226   m_eta_high_req = py < 0 ? bottom_north_eta : top_north_eta;
1227   m_eta_low_req = py < 0 ? bottom_south_eta : top_south_eta;
1228 }
1229 
1230 int DecayFinder::createDecayNode(PHCompositeNode* topNode)
1231 {
1232   PHNodeIterator iter(topNode);
1233 
1234   PHCompositeNode* lowerNode = dynamic_cast<PHCompositeNode*>(iter.findFirst("PHCompositeNode", "DST"));
1235   if (!lowerNode)
1236   {
1237     lowerNode = new PHCompositeNode("DST");
1238     topNode->addNode(lowerNode);
1239     std::cout << "DST node added" << std::endl;
1240   }
1241 
1242   std::string baseName;
1243 
1244   if (m_container_name.empty())
1245   {
1246     // baseName = "decay";
1247     baseName = Name();
1248   }
1249   else
1250   {
1251     baseName = m_container_name;
1252   }
1253 
1254   // Cant have forward slashes in DST or else you make a subdirectory on save!!!
1255   size_t pos;
1256   std::string undrscr = "_";
1257   std::string nothing = "";
1258   std::map<std::string, std::string> forbiddenStrings;
1259   forbiddenStrings["/"] = undrscr;
1260   forbiddenStrings["("] = undrscr;
1261   forbiddenStrings[")"] = nothing;
1262   forbiddenStrings["+"] = "plus";
1263   forbiddenStrings["-"] = "minus";
1264   forbiddenStrings["*"] = "star";
1265   forbiddenStrings[" "] = nothing;
1266   for (auto const& [badString, goodString] : forbiddenStrings)
1267   {
1268     while ((pos = baseName.find(badString)) != std::string::npos)
1269     {
1270       baseName.replace(pos, 1, goodString);
1271     }
1272   }
1273 
1274   m_nodeName = baseName + "_DecayMap";
1275 
1276   m_decayMap = new DecayFinderContainer_v1();
1277   PHIODataNode<PHObject>* decayNode = new PHIODataNode<PHObject>(m_decayMap, m_nodeName.c_str(), "PHObject");
1278   lowerNode->addNode(decayNode);
1279   std::cout << m_nodeName << " node added" << std::endl;
1280 
1281   return Fun4AllReturnCodes::EVENT_OK;
1282 }
1283 
1284 void DecayFinder::fillDecayNode(PHCompositeNode* topNode, Decay& decay)
1285 {
1286   m_decayMap = findNode::getClass<DecayFinderContainer_v1>(topNode, m_nodeName.c_str());
1287   m_decayMap->insert(decay);
1288 }
1289 
1290 void DecayFinder::printInfo()
1291 {
1292   std::cout << "\n---------------DecayFinder information---------------" << std::endl;
1293   std::cout << "Module name: " << Name() << std::endl;
1294   std::cout << "Decay descriptor: " << m_decayDescriptor << std::endl;
1295   std::cout << "Number of generated decays: " << m_counter << std::endl;
1296   std::cout << "  Number of decays that failed pT requirement: " << m_nCandFail_pT << std::endl;
1297   std::cout << "  Number of decays that failed eta requirement: " << m_nCandFail_eta << std::endl;
1298   std::cout << "  Number of decays that failed pT and eta requirements: " << m_nCandFail_pT_and_eta << std::endl;
1299   std::cout << "Number of decays that could be reconstructed: " << m_nCandReconstructable << std::endl;
1300   std::cout << "  Number of reconstructable mothers with associated photon: " << m_nCandHas_Photon << std::endl;
1301   std::cout << "  Number of reconstructable mothers with associated Pi0: " << m_nCandHas_Pi0 << std::endl;
1302   std::cout << "  Number of reconstructable mothers with associated photon and Pi0: " << m_nCandHas_Photon_and_Pi0 << std::endl;
1303   std::cout << "  Number of reconstructable mothers with no associated photons or Pi0s: " << m_nCandHas_noPhoton_and_noPi0 << std::endl;
1304   std::cout << "-----------------------------------------------------\n";
1305   std::cout << std::endl;
1306 }
1307 
1308 void DecayFinder::printNode(PHCompositeNode* topNode)
1309 {
1310   std::cout << "----------------";
1311   std::cout << " DecayFinderNode: " << m_nodeName << " information ";
1312   std::cout << "----------------" << std::endl;
1313   DecayFinderContainer_v1* map = findNode::getClass<DecayFinderContainer_v1>(topNode, m_nodeName.c_str());
1314   for (auto& iter : *map)
1315   {
1316     Decay decay = iter.second;
1317     for (auto& i : decay)
1318     {
1319       std::cout << "Particle embedding ID: " << i.first.first << ", particle barcode: " << i.first.second << ", particle PDG ID: " << i.second << std::endl;
1320     }
1321   }
1322   std::cout << "--------------------------------------------------------------------------------------------------" << std::endl;
1323 }
1324 
1325 std::string DecayFinder::passOrFail(bool condition)
1326 {
1327   return condition ? "passed" : "failed";
1328 }