File indexing completed on 2025-12-16 09:22:01
0001 #include "PHG4TruthEventAction.h"
0002
0003 #include "PHG4Hit.h"
0004 #include "PHG4HitContainer.h"
0005 #include "PHG4HitDefs.h" // for keytype
0006 #include "PHG4Particle.h" // for PHG4Particle
0007 #include "PHG4Shower.h"
0008 #include "PHG4TruthInfoContainer.h"
0009 #include "PHG4UserPrimaryParticleInformation.h"
0010
0011 #include <phool/PHCompositeNode.h>
0012 #include <phool/PHIODataNode.h> // for PHIODataNode
0013 #include <phool/PHNode.h>
0014 #include <phool/PHNodeIterator.h> // for PHNodeIterator
0015 #include <phool/PHPointerListIterator.h>
0016 #include <phool/getClass.h>
0017 #include <phool/phool.h> // for PHWHERE
0018
0019 #include <Geant4/G4Event.hh>
0020 #include <Geant4/G4PrimaryParticle.hh> // for G4PrimaryPart...
0021 #include <Geant4/G4PrimaryVertex.hh> // for G4PrimaryVertex
0022 #include <Geant4/G4VUserPrimaryParticleInformation.hh> // for G4VUserPrimar...
0023
0024 #include <Eigen/Dense>
0025
0026 #include <cmath> // for isnan
0027 #include <cstdlib> // for abs
0028 #include <iostream> // for operator<<, endl
0029 #include <iterator> // for reverse_iterator
0030 #include <map>
0031 #include <string> // for operator==
0032 #include <utility> // for swap, pair
0033 #include <vector> // for vector, vecto...
0034
0035 class PHG4VtxPoint;
0036
0037
0038 void PHG4TruthEventAction::BeginOfEventAction(const G4Event* )
0039 {
0040
0041 if (!m_TruthInfoContainer)
0042 {
0043 std::cout << "PHG4TruthEventAction::EndOfEventAction - unable to find G4TruthInfo node" << std::endl;
0044 return;
0045 }
0046
0047 const PHG4TruthInfoContainer::Map& map = m_TruthInfoContainer->GetMap();
0048 if (!map.empty())
0049 {
0050 m_LowerKeyPrevExist = map.begin()->first;
0051 m_UpperKeyPrevExist = map.rbegin()->first;
0052 }
0053 }
0054
0055
0056 void PHG4TruthEventAction::EndOfEventAction(const G4Event* evt)
0057 {
0058
0059 if (!m_TruthInfoContainer)
0060 {
0061 std::cout << "PHG4TruthEventAction::EndOfEventAction - unable to find G4TruthInfo node" << std::endl;
0062 return;
0063 }
0064
0065
0066
0067 PruneShowers();
0068 ProcessShowers();
0069
0070
0071
0072 std::set<int> savelist;
0073 std::set<int> savevtxlist;
0074
0075 for (int mytrkid : m_WriteSet)
0076 {
0077 std::vector<int> wrttracks;
0078 std::vector<int> wrtvtx;
0079
0080
0081 PHG4Particle* particle = m_TruthInfoContainer->GetParticle(mytrkid);
0082
0083
0084 if (savelist.contains(mytrkid))
0085 {
0086 continue;
0087 }
0088
0089 wrttracks.push_back(mytrkid);
0090 wrtvtx.push_back(particle->get_vtx_id());
0091
0092
0093
0094 int parentid = particle->get_parent_id();
0095 while (!savelist.contains(parentid) && parentid != 0)
0096 {
0097 particle = m_TruthInfoContainer->GetParticle(parentid);
0098 wrttracks.push_back(parentid);
0099 wrtvtx.push_back(particle->get_vtx_id());
0100 parentid = particle->get_parent_id();
0101 }
0102
0103
0104
0105 while (wrttracks.begin() != wrttracks.end())
0106 {
0107 savelist.insert(wrttracks.back());
0108 wrttracks.pop_back();
0109 }
0110
0111 while (wrtvtx.begin() != wrtvtx.end())
0112 {
0113 savevtxlist.insert(wrtvtx.back());
0114 wrtvtx.pop_back();
0115 }
0116 }
0117
0118
0119
0120
0121
0122
0123
0124 int removed[4] = {0};
0125 PHG4TruthInfoContainer::Range truth_range = m_TruthInfoContainer->GetParticleRange();
0126 PHG4TruthInfoContainer::Iterator truthiter = truth_range.first;
0127 while (truthiter != truth_range.second)
0128 {
0129 removed[0]++;
0130 int trackid = truthiter->first;
0131 if (!savelist.contains(trackid))
0132 {
0133
0134
0135
0136
0137
0138
0139
0140
0141 if (((trackid < m_LowerKeyPrevExist) || (trackid > m_UpperKeyPrevExist)) && ((truthiter->second)->get_parent_id() != 0))
0142 {
0143 m_TruthInfoContainer->delete_particle(truthiter++);
0144 removed[1]++;
0145 }
0146 else
0147 {
0148
0149
0150 savevtxlist.insert((truthiter->second)->get_vtx_id());
0151 ++truthiter;
0152 }
0153 }
0154 else
0155 {
0156
0157 ++truthiter;
0158 }
0159 }
0160
0161 PHG4TruthInfoContainer::VtxRange vtxrange = m_TruthInfoContainer->GetVtxRange();
0162 PHG4TruthInfoContainer::VtxIterator vtxiter = vtxrange.first;
0163 while (vtxiter != vtxrange.second)
0164 {
0165 removed[2]++;
0166 if (!savevtxlist.contains(vtxiter->first))
0167 {
0168 m_TruthInfoContainer->delete_vtx(vtxiter++);
0169 removed[3]++;
0170 }
0171 else
0172 {
0173 ++vtxiter;
0174 }
0175 }
0176
0177
0178
0179 G4PrimaryVertex* pvtx = evt->GetPrimaryVertex();
0180 while (pvtx)
0181 {
0182 G4PrimaryParticle* part = pvtx->GetPrimary();
0183 while (part)
0184 {
0185 PHG4UserPrimaryParticleInformation* userdata = dynamic_cast<PHG4UserPrimaryParticleInformation*>(part->GetUserInformation());
0186 if (userdata)
0187 {
0188 if (userdata->get_embed())
0189 {
0190 m_TruthInfoContainer->AddEmbededTrkId(userdata->get_user_track_id(), userdata->get_embed());
0191 m_TruthInfoContainer->AddEmbededVtxId(userdata->get_user_vtx_id(), userdata->get_embed());
0192 }
0193 }
0194 part = part->GetNext();
0195 }
0196 pvtx = pvtx->GetNext();
0197 }
0198
0199 return;
0200 }
0201
0202
0203 void PHG4TruthEventAction::AddTrackidToWritelist(const int trackid)
0204 {
0205 m_WriteSet.insert(trackid);
0206 }
0207
0208
0209 void PHG4TruthEventAction::SetInterfacePointers(PHCompositeNode* topNode)
0210 {
0211
0212 m_TruthInfoContainer = findNode::getClass<PHG4TruthInfoContainer>(topNode, "G4TruthInfo");
0213
0214
0215 if (!m_TruthInfoContainer)
0216 {
0217 std::cout << "PHG4TruthEventAction::SetInterfacePointers - unable to find G4TruthInfo" << std::endl;
0218 }
0219
0220 SearchNode(topNode);
0221 }
0222
0223
0224 void PHG4TruthEventAction::SearchNode(PHCompositeNode* top)
0225 {
0226
0227
0228
0229
0230 PHNodeIterator nodeiter(top);
0231 PHPointerListIterator<PHNode> iter(nodeiter.ls());
0232 PHNode* thisNode;
0233 while ((thisNode = iter()))
0234 {
0235 if (thisNode->getType() == "PHCompositeNode")
0236 {
0237 SearchNode(static_cast<PHCompositeNode*>(thisNode));
0238 }
0239 else if (thisNode->getType() == "PHIODataNode")
0240 {
0241 if (thisNode->getName().find("G4HIT_") == 0)
0242 {
0243 PHIODataNode<PHG4HitContainer>* DNode = static_cast<PHIODataNode<PHG4HitContainer>*>(thisNode);
0244 if (DNode)
0245 {
0246 PHG4HitContainer* object = dynamic_cast<PHG4HitContainer*>(DNode->getData());
0247 if (object)
0248 {
0249 m_HitContainerMap[object->GetID()] = object;
0250 }
0251 }
0252 }
0253 }
0254 }
0255 }
0256
0257 int PHG4TruthEventAction::ResetEvent(PHCompositeNode* )
0258 {
0259 m_WriteSet.clear();
0260 return 0;
0261 }
0262
0263 void PHG4TruthEventAction::PruneShowers()
0264 {
0265 PHG4TruthInfoContainer::ShowerRange range = m_TruthInfoContainer->GetShowerRange();
0266 for (PHG4TruthInfoContainer::ShowerIterator iter = range.first;
0267 iter != range.second;
0268 ++iter)
0269 {
0270 PHG4Shower* shower = iter->second;
0271
0272 std::set<int> remove_ids;
0273 for (PHG4Shower::ParticleIdIter jter = shower->begin_g4particle_id();
0274 jter != shower->end_g4particle_id();
0275 ++jter)
0276 {
0277 int g4particle_id = *jter;
0278 PHG4Particle* particle = m_TruthInfoContainer->GetParticle(g4particle_id);
0279 if (!particle)
0280 {
0281 remove_ids.insert(g4particle_id);
0282 continue;
0283 }
0284 }
0285
0286 for (int remove_id : remove_ids)
0287 {
0288 shower->remove_g4particle_id(remove_id);
0289 }
0290
0291 std::set<int> remove_more_ids;
0292 for (std::map<int, std::set<PHG4HitDefs::keytype> >::iterator jter = shower->begin_g4hit_id();
0293 jter != shower->end_g4hit_id();
0294 ++jter)
0295 {
0296 int g4hitmap_id = jter->first;
0297 std::map<int, PHG4HitContainer*>::iterator mapiter = m_HitContainerMap.find(g4hitmap_id);
0298 if (mapiter == m_HitContainerMap.end())
0299 {
0300 continue;
0301 }
0302
0303
0304 for (std::set<PHG4HitDefs::keytype>::iterator kter = jter->second.begin();
0305 kter != jter->second.end();)
0306 {
0307 PHG4HitDefs::keytype g4hit_id = *kter;
0308
0309 PHG4Hit* g4hit = mapiter->second->findHit(g4hit_id);
0310 if (!g4hit)
0311 {
0312
0313 jter->second.erase(kter++);
0314 continue;
0315 }
0316
0317 ++kter;
0318 }
0319
0320 if (jter->second.empty())
0321 {
0322 remove_more_ids.insert(g4hitmap_id);
0323 }
0324 }
0325
0326 for (int remove_more_id : remove_more_ids)
0327 {
0328 shower->remove_g4hit_volume(remove_more_id);
0329 }
0330 }
0331
0332 range = m_TruthInfoContainer->GetShowerRange();
0333 for (PHG4TruthInfoContainer::ShowerIterator iter = range.first;
0334 iter != range.second;)
0335 {
0336 PHG4Shower* shower = iter->second;
0337
0338 if (shower->empty_g4particle_id() && shower->empty_g4hit_id())
0339 {
0340 if (shower->get_edep() == 0)
0341 {
0342 m_TruthInfoContainer->delete_shower(iter++);
0343 continue;
0344 }
0345 }
0346
0347 ++iter;
0348 }
0349 }
0350
0351 void PHG4TruthEventAction::ProcessShowers()
0352 {
0353 PHG4TruthInfoContainer::ShowerRange range = m_TruthInfoContainer->GetShowerRange();
0354 for (PHG4TruthInfoContainer::ShowerIterator shwiter = range.first;
0355 shwiter != range.second;
0356 ++shwiter)
0357 {
0358 PHG4Shower* shower = shwiter->second;
0359
0360
0361 std::vector<std::vector<float> > points;
0362 std::vector<float> weights;
0363 float sumw = 0.0;
0364 float sumw2 = 0.0;
0365
0366 for (std::map<int, std::set<PHG4HitDefs::keytype> >::iterator iter = shower->begin_g4hit_id();
0367 iter != shower->end_g4hit_id();
0368 ++iter)
0369 {
0370 int g4hitmap_id = iter->first;
0371 std::map<int, PHG4HitContainer*>::iterator mapiter = m_HitContainerMap.find(g4hitmap_id);
0372 if (mapiter == m_HitContainerMap.end())
0373 {
0374 continue;
0375 }
0376
0377 PHG4HitContainer* hits = mapiter->second;
0378
0379 unsigned int nhits = 0;
0380 float edep = 0.0;
0381 float eion = 0.0;
0382 float light_yield = 0.0;
0383 float edep_e = 0.0;
0384 float edep_h = 0.0;
0385
0386
0387 for (unsigned long long g4hit_id : iter->second)
0388 {
0389 PHG4Hit* g4hit = hits->findHit(g4hit_id);
0390 if (!g4hit)
0391 {
0392 std::cout << PHWHERE << " missing g4hit" << std::endl;
0393 continue;
0394 }
0395
0396 PHG4Particle* particle = m_TruthInfoContainer->GetParticle(g4hit->get_trkid());
0397 if (!particle)
0398 {
0399 std::cout << PHWHERE << " missing g4particle for track "
0400 << g4hit->get_trkid() << std::endl;
0401 continue;
0402 }
0403
0404 PHG4VtxPoint* vtx = m_TruthInfoContainer->GetVtx(particle->get_vtx_id());
0405 if (!vtx)
0406 {
0407 std::cout << PHWHERE << " missing g4vertex" << std::endl;
0408 continue;
0409 }
0410
0411
0412
0413 if (!std::isnan(g4hit->get_x(0)) &&
0414 !std::isnan(g4hit->get_y(0)) &&
0415 !std::isnan(g4hit->get_z(0)))
0416 {
0417 std::vector<float> entry(3);
0418 entry[0] = g4hit->get_x(0);
0419 entry[1] = g4hit->get_y(0);
0420 entry[2] = g4hit->get_z(0);
0421
0422 points.push_back(entry);
0423 float w = g4hit->get_edep();
0424 weights.push_back(w);
0425 sumw += w;
0426 sumw2 += w * w;
0427 }
0428
0429 if (!std::isnan(g4hit->get_x(1)) &&
0430 !std::isnan(g4hit->get_y(1)) &&
0431 !std::isnan(g4hit->get_z(1)))
0432 {
0433 std::vector<float> entry(3);
0434 entry[0] = g4hit->get_x(1);
0435 entry[1] = g4hit->get_y(1);
0436 entry[2] = g4hit->get_z(1);
0437
0438 points.push_back(entry);
0439 float w = g4hit->get_edep();
0440 weights.push_back(w);
0441 sumw += w;
0442 sumw2 += w * w;
0443 }
0444
0445
0446
0447 if (!std::isnan(g4hit->get_edep()))
0448 {
0449 if (abs(particle->get_pid()) == 11)
0450 {
0451 edep_e += g4hit->get_edep();
0452 }
0453 else
0454 {
0455 edep_h += g4hit->get_edep();
0456 }
0457 }
0458
0459
0460
0461 ++nhits;
0462 if (!std::isnan(g4hit->get_edep()))
0463 {
0464 edep += g4hit->get_edep();
0465 }
0466 if (!std::isnan(g4hit->get_eion()))
0467 {
0468 eion += g4hit->get_eion();
0469 }
0470 if (!std::isnan(g4hit->get_light_yield()))
0471 {
0472 light_yield += g4hit->get_light_yield();
0473 }
0474 }
0475
0476
0477
0478 if (nhits)
0479 {
0480 shower->set_nhits(g4hitmap_id, nhits);
0481 }
0482 if (edep != 0.0)
0483 {
0484 shower->set_edep(g4hitmap_id, edep);
0485 }
0486 if (eion != 0.0)
0487 {
0488 shower->set_eion(g4hitmap_id, eion);
0489 }
0490 if (light_yield != 0.0)
0491 {
0492 shower->set_light_yield(g4hitmap_id, light_yield);
0493 }
0494 if (edep_h != 0.0)
0495 {
0496 shower->set_eh_ratio(g4hitmap_id, edep_e / edep_h);
0497 }
0498 }
0499
0500
0501
0502
0503 Eigen::Matrix<double, Eigen::Dynamic, 3> X(points.size(), 3);
0504 Eigen::Matrix<double, Eigen::Dynamic, 1> W(weights.size(), 1);
0505
0506 for (unsigned int i = 0; i < points.size(); ++i)
0507 {
0508 for (unsigned int j = 0; j < 3; ++j)
0509 {
0510 X(i, j) = points[i][j];
0511 }
0512 W(i, 0) = weights[i];
0513 }
0514
0515
0516 double prefactor = 1.0 / sumw;
0517 Eigen::Matrix<double, 1, 3> mean = prefactor * W.transpose() * X;
0518
0519
0520 for (unsigned int i = 0; i < points.size(); ++i)
0521 {
0522 for (unsigned int j = 0; j < 3; ++j)
0523 {
0524 X(i, j) = points[i][j] - mean(0, j);
0525 }
0526 }
0527
0528
0529 prefactor = sumw / (sumw * sumw - sumw2);
0530 Eigen::Matrix<double, 3, 3> covar = prefactor * (X.transpose() * W.asDiagonal() * X);
0531
0532 shower->set_x(mean(0, 0));
0533 shower->set_y(mean(0, 1));
0534 shower->set_z(mean(0, 2));
0535
0536 for (unsigned int i = 0; i < 3; ++i)
0537 {
0538 for (unsigned int j = 0; j <= i; ++j)
0539 {
0540 shower->set_covar(i, j, covar(i, j));
0541 }
0542 }
0543
0544
0545 }
0546 }