File indexing completed on 2025-12-16 09:20:18
0001 #include "ParticleFlowReco.h"
0002
0003 #include "ParticleFlowElementContainer.h"
0004 #include "ParticleFlowElementv1.h"
0005
0006 #include <globalvertex/GlobalVertex.h>
0007 #include <globalvertex/GlobalVertexMap.h>
0008
0009 #include <calobase/RawCluster.h>
0010 #include <calobase/RawClusterContainer.h>
0011 #include <calobase/RawClusterUtility.h>
0012 #include <calobase/RawTowerGeom.h>
0013 #include <calobase/RawTowerGeomContainer.h>
0014
0015 #include <trackbase_historic/SvtxTrack.h>
0016 #include <trackbase_historic/SvtxTrackMap.h>
0017 #include <trackbase_historic/SvtxTrackState.h>
0018
0019 #include <fun4all/Fun4AllReturnCodes.h>
0020
0021 #include <phool/PHCompositeNode.h>
0022 #include <phool/PHRandomSeed.h>
0023 #include <phool/getClass.h>
0024
0025 #include <TLorentzVector.h>
0026
0027 #include <gsl/gsl_randist.h>
0028 #include <gsl/gsl_rng.h> // for gsl_rng_uniform_pos
0029
0030 #include <cmath>
0031 #include <iostream>
0032
0033
0034 bool sort_by_pair_second_lowest(const std::pair<int, float> &a, const std::pair<int, float> &b)
0035 {
0036 return (a.second < b.second);
0037 }
0038
0039 float ParticleFlowReco::calculate_dR(float eta1, float eta2, float phi1, float phi2)
0040 {
0041 float deta = eta1 - eta2;
0042 float dphi = phi1 - phi2;
0043 while (dphi > M_PI)
0044 {
0045 dphi -= 2 * M_PI;
0046 }
0047 while (dphi < -M_PI)
0048 {
0049 dphi += 2 * M_PI;
0050 }
0051 return sqrt(pow(deta, 2) + pow(dphi, 2));
0052 }
0053
0054 std::pair<float, float> ParticleFlowReco::get_expected_signature(int trk)
0055 {
0056 float response = (0.553437 + 0.0572246 * log(_pflow_TRK_p[trk])) * _pflow_TRK_p[trk];
0057 float resolution = sqrt(pow(0.119123, 2) + (pow(0.312361, 2) / _pflow_TRK_p[trk])) * _pflow_TRK_p[trk];
0058
0059 std::pair<float, float> expected_signature(response, resolution);
0060
0061 return expected_signature;
0062 }
0063
0064
0065 ParticleFlowReco::ParticleFlowReco(const std::string &name)
0066 : SubsysReco(name)
0067 {
0068 }
0069
0070
0071 int ParticleFlowReco::InitRun(PHCompositeNode *topNode)
0072 {
0073 return CreateNode(topNode);
0074 }
0075
0076
0077 int ParticleFlowReco::process_event(PHCompositeNode *topNode)
0078 {
0079 if (Verbosity() > 0)
0080 {
0081 std::cout << "ParticleFlowReco::process_event with Nsigma = " << _energy_match_Nsigma << std::endl;
0082 }
0083
0084 ParticleFlowElementContainer *pflowContainer = findNode::getClass<ParticleFlowElementContainer>(topNode, "ParticleFlowElements");
0085 if (!pflowContainer)
0086 {
0087 std::cout << " ERROR -- can't find ParticleFlowElements node after it should have been created" << std::endl;
0088 return Fun4AllReturnCodes::ABORTEVENT;
0089 }
0090
0091
0092 int global_pflow_index = 0;
0093
0094
0095 RawTowerGeomContainer *geomEM = findNode::getClass<RawTowerGeomContainer>(topNode, "TOWERGEOM_CEMC");
0096 RawTowerGeomContainer *geomIH = findNode::getClass<RawTowerGeomContainer>(topNode, "TOWERGEOM_HCALIN");
0097 RawTowerGeomContainer *geomOH = findNode::getClass<RawTowerGeomContainer>(topNode, "TOWERGEOM_HCALOUT");
0098
0099 if (!geomEM || !geomIH || !geomOH)
0100 {
0101 std::cout << "ParticleFlowReco::process_event : FATAL ERROR, cannot find tower geometry containers" << std::endl;
0102 return Fun4AllReturnCodes::ABORTEVENT;
0103 }
0104
0105
0106 RawClusterContainer *clustersEM = findNode::getClass<RawClusterContainer>(topNode, "TOPOCLUSTER_EMCAL");
0107 RawClusterContainer *clustersHAD = findNode::getClass<RawClusterContainer>(topNode, "TOPOCLUSTER_HCAL");
0108
0109 if (!clustersEM)
0110 {
0111 std::cout << "ParticleFlowReco::process_event : FATAL ERROR, cannot find cluster container TOPOCLUSTER_EMCAL" << std::endl;
0112 return Fun4AllReturnCodes::ABORTEVENT;
0113 }
0114 if (!clustersHAD)
0115 {
0116 std::cout << "ParticleFlowReco::process_event : FATAL ERROR, cannot find cluster container TOPOCLUSTER_HCAL" << std::endl;
0117 return Fun4AllReturnCodes::ABORTEVENT;
0118 }
0119
0120
0121 _pflow_TRK_p.clear();
0122 _pflow_TRK_eta.clear();
0123 _pflow_TRK_phi.clear();
0124 _pflow_TRK_match_EM.clear();
0125 _pflow_TRK_match_HAD.clear();
0126 _pflow_TRK_addtl_match_EM.clear();
0127 _pflow_TRK_trk.clear();
0128 _pflow_TRK_EMproj_phi.clear();
0129 _pflow_TRK_EMproj_eta.clear();
0130 _pflow_TRK_HADproj_eta.clear();
0131 _pflow_TRK_HADproj_phi.clear();
0132
0133 _pflow_EM_E.clear();
0134 _pflow_EM_eta.clear();
0135 _pflow_EM_phi.clear();
0136 _pflow_EM_tower_eta.clear();
0137 _pflow_EM_tower_phi.clear();
0138 _pflow_EM_match_HAD.clear();
0139 _pflow_EM_match_TRK.clear();
0140 _pflow_EM_cluster.clear();
0141
0142 _pflow_HAD_E.clear();
0143 _pflow_HAD_eta.clear();
0144 _pflow_HAD_phi.clear();
0145 _pflow_HAD_tower_eta.clear();
0146 _pflow_HAD_tower_phi.clear();
0147 _pflow_HAD_match_EM.clear();
0148 _pflow_HAD_match_TRK.clear();
0149 _pflow_HAD_cluster.clear();
0150
0151 GlobalVertexMap *vertexmap = findNode::getClass<GlobalVertexMap>(topNode, "GlobalVertexMap");
0152 GlobalVertex *vertex = nullptr;
0153
0154 if (vertexmap)
0155 {
0156 if (!vertexmap->empty())
0157 {
0158 vertex = (vertexmap->begin()->second);
0159 }
0160 }
0161
0162 if (Verbosity() > 2)
0163 {
0164 std::cout << "ParticleFlowReco::process_event : initial population of TRK, EM, HAD objects " << std::endl;
0165 }
0166
0167
0168 {
0169 SvtxTrackMap *trackmap = findNode::getClass<SvtxTrackMap>(topNode, _track_map_name);
0170
0171 float cemcradius = geomEM->get_radius();
0172 float ohcalradius = geomOH->get_radius();
0173
0174 for (auto &iter : *trackmap)
0175 {
0176 SvtxTrack *track = iter.second;
0177
0178 if(_only_crossing_zero && (track->get_crossing() != 0))
0179 {
0180 continue;
0181 }
0182
0183 if (track->get_pt() < 0.5)
0184 {
0185 continue;
0186 }
0187
0188 if (std::fabs(track->get_eta()) > 1.1)
0189 {
0190 continue;
0191 }
0192
0193 if (Verbosity() > 2)
0194 {
0195 std::cout << "Track with p= " << track->get_p() << ", eta / phi = "
0196 << track->get_eta() << " / " << track->get_phi()
0197 << std::endl;
0198 }
0199
0200 _pflow_TRK_trk.push_back(track);
0201 _pflow_TRK_p.push_back(track->get_p());
0202 _pflow_TRK_eta.push_back(track->get_eta());
0203 _pflow_TRK_phi.push_back(track->get_phi());
0204 _pflow_TRK_match_EM.emplace_back();
0205 _pflow_TRK_match_HAD.emplace_back();
0206 _pflow_TRK_addtl_match_EM.emplace_back();
0207
0208 SvtxTrackState *cemcstate = track->get_state(cemcradius);
0209 SvtxTrackState *ohstate = track->get_state(ohcalradius);
0210
0211
0212 if (cemcstate)
0213 {
0214 _pflow_TRK_EMproj_phi.push_back(std::atan2(cemcstate->get_y(), cemcstate->get_x()));
0215 _pflow_TRK_EMproj_eta.push_back(std::asinh(cemcstate->get_z() / std::sqrt((cemcstate->get_x() * cemcstate->get_x()) + (cemcstate->get_y() * cemcstate->get_y()))));
0216 }
0217 else
0218 {
0219 _pflow_TRK_EMproj_phi.push_back(track->get_phi());
0220 _pflow_TRK_EMproj_eta.push_back(track->get_eta());
0221 }
0222 if (ohstate)
0223 {
0224 _pflow_TRK_HADproj_phi.push_back(std::atan2(ohstate->get_y(), ohstate->get_x()));
0225 _pflow_TRK_HADproj_eta.push_back(std::asinh(ohstate->get_z() / std::sqrt((ohstate->get_x() * ohstate->get_x()) + (ohstate->get_y() * ohstate->get_y()))));
0226 }
0227 else
0228 {
0229 _pflow_TRK_HADproj_phi.push_back(track->get_phi());
0230 _pflow_TRK_HADproj_eta.push_back(track->get_eta());
0231 }
0232 }
0233
0234 }
0235
0236
0237 {
0238 RawClusterContainer::ConstRange begin_end = clustersEM->getClusters();
0239 for (RawClusterContainer::ConstIterator hiter = begin_end.first; hiter != begin_end.second; ++hiter)
0240 {
0241 float cluster_E = hiter->second->get_energy();
0242 if (cluster_E < 0.2)
0243 {
0244 continue;
0245 }
0246
0247 float cluster_phi = hiter->second->get_phi();
0248
0249 float cluster_theta = M_PI / 2.0 - std::atan2(hiter->second->get_z(), hiter->second->get_r());
0250 float cluster_eta = -1 * log(tan(cluster_theta / 2.0));
0251
0252 if (vertex)
0253 {
0254 cluster_eta = RawClusterUtility::GetPseudorapidity(*(hiter->second), CLHEP::Hep3Vector(vertex->get_x(), vertex->get_y(), vertex->get_z()));
0255 }
0256
0257 _pflow_EM_E.push_back(cluster_E);
0258 _pflow_EM_eta.push_back(cluster_eta);
0259 _pflow_EM_phi.push_back(cluster_phi);
0260 _pflow_EM_cluster.push_back(hiter->second);
0261 _pflow_EM_match_HAD.emplace_back();
0262 _pflow_EM_match_TRK.emplace_back();
0263
0264 if (Verbosity() > 5 && cluster_E > 0.2)
0265 {
0266 std::cout << " EM topoCluster with E = " << cluster_E << ", eta / phi = " << cluster_eta << " / " << cluster_phi << " , nTow = " << hiter->second->getNTowers() << std::endl;
0267 }
0268
0269 std::vector<float> this_cluster_tower_eta;
0270 std::vector<float> this_cluster_tower_phi;
0271
0272
0273 RawCluster::TowerConstRange begin_end_towers = hiter->second->get_towers();
0274 for (RawCluster::TowerConstIterator iter = begin_end_towers.first; iter != begin_end_towers.second; ++iter)
0275 {
0276 if (RawTowerDefs::decode_caloid(iter->first) == RawTowerDefs::CalorimeterId::CEMC)
0277 {
0278 RawTowerGeom *tower_geom = geomEM->get_tower_geometry(iter->first);
0279
0280 this_cluster_tower_phi.push_back(tower_geom->get_phi());
0281 this_cluster_tower_eta.push_back(tower_geom->get_eta());
0282 }
0283 else
0284 {
0285 std::cout << "ParticleFlowReco::process_event : FATAL ERROR , EM topoClusters seem to contain HCal towers" << std::endl;
0286 return Fun4AllReturnCodes::ABORTEVENT;
0287 }
0288 }
0289
0290 _pflow_EM_tower_eta.push_back(this_cluster_tower_eta);
0291 _pflow_EM_tower_phi.push_back(this_cluster_tower_phi);
0292
0293 }
0294
0295 }
0296
0297
0298 {
0299 RawClusterContainer::ConstRange begin_end = clustersHAD->getClusters();
0300 for (RawClusterContainer::ConstIterator hiter = begin_end.first; hiter != begin_end.second; ++hiter)
0301 {
0302 float cluster_E = hiter->second->get_energy();
0303 if (cluster_E < 0.2)
0304 {
0305 continue;
0306 }
0307
0308 float cluster_phi = hiter->second->get_phi();
0309
0310 float cluster_theta = M_PI / 2.0 - std::atan2(hiter->second->get_z(), hiter->second->get_r());
0311 float cluster_eta = -1 * log(tan(cluster_theta / 2.0));
0312 if (vertex)
0313 {
0314 cluster_eta = RawClusterUtility::GetPseudorapidity(*(hiter->second), CLHEP::Hep3Vector(vertex->get_x(), vertex->get_y(), vertex->get_z()));
0315 }
0316
0317 _pflow_HAD_E.push_back(cluster_E);
0318 _pflow_HAD_eta.push_back(cluster_eta);
0319 _pflow_HAD_phi.push_back(cluster_phi);
0320 _pflow_HAD_cluster.push_back(hiter->second);
0321
0322 _pflow_HAD_match_EM.emplace_back();
0323 _pflow_HAD_match_TRK.emplace_back();
0324
0325 if (Verbosity() > 5 && cluster_E > 0.2)
0326 {
0327 std::cout << " HAD topoCluster with E = " << cluster_E << ", eta / phi = " << cluster_eta << " / " << cluster_phi << " , nTow = " << hiter->second->getNTowers() << std::endl;
0328 }
0329
0330 std::vector<float> this_cluster_tower_eta;
0331 std::vector<float> this_cluster_tower_phi;
0332
0333
0334 RawCluster::TowerConstRange begin_end_towers = hiter->second->get_towers();
0335 for (RawCluster::TowerConstIterator iter = begin_end_towers.first; iter != begin_end_towers.second; ++iter)
0336 {
0337 if (RawTowerDefs::decode_caloid(iter->first) == RawTowerDefs::CalorimeterId::HCALIN)
0338 {
0339 RawTowerGeom *tower_geom = geomIH->get_tower_geometry(iter->first);
0340
0341 this_cluster_tower_phi.push_back(tower_geom->get_phi());
0342 this_cluster_tower_eta.push_back(tower_geom->get_eta());
0343 }
0344
0345 else if (RawTowerDefs::decode_caloid(iter->first) == RawTowerDefs::CalorimeterId::HCALOUT)
0346 {
0347 RawTowerGeom *tower_geom = geomOH->get_tower_geometry(iter->first);
0348
0349 this_cluster_tower_phi.push_back(tower_geom->get_phi());
0350 this_cluster_tower_eta.push_back(tower_geom->get_eta());
0351 }
0352 else
0353 {
0354 std::cout << "ParticleFlowReco::process_event : FATAL ERROR , HCal topoClusters seem to contain EM towers" << std::endl;
0355 return Fun4AllReturnCodes::ABORTEVENT;
0356 }
0357
0358 }
0359
0360 _pflow_HAD_tower_eta.push_back(this_cluster_tower_eta);
0361 _pflow_HAD_tower_phi.push_back(this_cluster_tower_phi);
0362
0363 }
0364
0365 }
0366
0367
0368
0369
0370 if (Verbosity() > 2)
0371 {
0372 std::cout << "ParticleFlowReco::process_event : TRK -> EM and TRK -> HAD linking " << std::endl;
0373 }
0374
0375 for (unsigned int trk = 0; trk < _pflow_TRK_p.size(); trk++)
0376 {
0377 if (Verbosity() > 10)
0378 {
0379 std::cout << " TRK " << trk << " with p / eta / phi = " << _pflow_TRK_p[trk] << " / " << _pflow_TRK_eta[trk] << " / " << _pflow_TRK_phi[trk] << std::endl;
0380 }
0381
0382
0383 float min_em_dR = 0.2;
0384 int min_em_index = -1;
0385
0386 for (unsigned int em = 0; em < _pflow_EM_E.size(); em++)
0387 {
0388 float dR = calculate_dR(_pflow_TRK_EMproj_eta[trk], _pflow_EM_eta[em], _pflow_TRK_EMproj_phi[trk], _pflow_EM_phi[em]);
0389
0390 if (dR > 0.2)
0391 {
0392 continue;
0393 }
0394
0395 bool has_overlap = false;
0396
0397 for (unsigned int tow = 0; tow < _pflow_EM_tower_eta.at(em).size(); tow++)
0398 {
0399 float tower_eta = _pflow_EM_tower_eta.at(em).at(tow);
0400 float tower_phi = _pflow_EM_tower_phi.at(em).at(tow);
0401
0402 float deta = tower_eta - _pflow_TRK_EMproj_eta[trk];
0403 float dphi = tower_phi - _pflow_TRK_EMproj_phi[trk];
0404 if (dphi > M_PI)
0405 {
0406 dphi -= 2 * M_PI;
0407 }
0408 if (dphi < -M_PI)
0409 {
0410 dphi += 2 * M_PI;
0411 }
0412
0413 if (std::fabs(deta) < 0.025 * 2.5 && std::fabs(dphi) < 0.025 * 2.5)
0414 {
0415 has_overlap = true;
0416 break;
0417 }
0418 }
0419
0420 if (has_overlap)
0421 {
0422 if (Verbosity() > 5)
0423 {
0424 std::cout << " -> possible match to EM " << em << " with dR = " << dR << std::endl;
0425 }
0426
0427 _pflow_TRK_addtl_match_EM.at(trk).emplace_back(em, dR);
0428 }
0429 else
0430 {
0431 if (Verbosity() > 5)
0432 {
0433 std::cout << " -> no match to EM " << em << " (even though dR = " << dR << " )" << std::endl;
0434 }
0435 }
0436 }
0437
0438
0439
0440 std::sort(_pflow_TRK_addtl_match_EM.at(trk).begin(), _pflow_TRK_addtl_match_EM.at(trk).end(), sort_by_pair_second_lowest);
0441 if (Verbosity() > 10)
0442 {
0443 for (auto &n : _pflow_TRK_addtl_match_EM.at(trk))
0444 {
0445 std::cout << " -> sorted list of matches, EM / dR = " << n.first << " / " << n.second << std::endl;
0446 }
0447 }
0448
0449 if (!_pflow_TRK_addtl_match_EM.at(trk).empty())
0450 {
0451 min_em_index = _pflow_TRK_addtl_match_EM.at(trk).at(0).first;
0452 min_em_dR = _pflow_TRK_addtl_match_EM.at(trk).at(0).second;
0453
0454 _pflow_TRK_addtl_match_EM.at(trk).erase(_pflow_TRK_addtl_match_EM.at(trk).begin());
0455 }
0456
0457 if (min_em_index > -1)
0458 {
0459 _pflow_EM_match_TRK.at(min_em_index).push_back(trk);
0460 _pflow_TRK_match_EM.at(trk).push_back(min_em_index);
0461
0462 if (Verbosity() > 5)
0463 {
0464 std::cout << " -> matched EM " << min_em_index << " with pt / eta / phi = " << _pflow_EM_E.at(min_em_index) << " / " << _pflow_EM_eta.at(min_em_index) << " / " << _pflow_EM_phi.at(min_em_index) << ", dR = " << min_em_dR;
0465 std::cout << " ( " << _pflow_TRK_addtl_match_EM.at(trk).size() << " other possible matches ) " << std::endl;
0466 }
0467 }
0468 else
0469 {
0470 if (Verbosity() > 5)
0471 {
0472 std::cout << " -> no EM match! ( best dR = " << min_em_dR << " ) " << std::endl;
0473 }
0474 }
0475
0476
0477 float min_had_dR = 0.2;
0478 int min_had_index = -1;
0479 float max_had_pt = 0;
0480
0481
0482 for (unsigned int had = 0; had < _pflow_HAD_E.size(); had++)
0483 {
0484 float dR = calculate_dR(_pflow_TRK_HADproj_eta[trk], _pflow_HAD_eta[had], _pflow_TRK_HADproj_phi[trk], _pflow_HAD_phi[had]);
0485
0486 if (dR > 0.5)
0487 {
0488 continue;
0489 }
0490
0491 bool has_overlap = false;
0492
0493 for (unsigned int tow = 0; tow < _pflow_HAD_tower_eta.at(had).size(); tow++)
0494 {
0495 float tower_eta = _pflow_HAD_tower_eta.at(had).at(tow);
0496 float tower_phi = _pflow_HAD_tower_phi.at(had).at(tow);
0497
0498 float deta = tower_eta - _pflow_TRK_HADproj_eta[trk];
0499 float dphi = tower_phi - _pflow_TRK_HADproj_phi[trk];
0500 if (dphi > M_PI)
0501 {
0502 dphi -= 2 * M_PI;
0503 }
0504 if (dphi < -M_PI)
0505 {
0506 dphi += 2 * M_PI;
0507 }
0508
0509 if (std::fabs(deta) < 0.1 * 1.5 && std::fabs(dphi) < 0.1 * 1.5)
0510 {
0511 has_overlap = true;
0512 break;
0513 }
0514 }
0515
0516 if (has_overlap)
0517 {
0518 if (Verbosity() > 5)
0519 {
0520 std::cout << " -> possible match to HAD " << had << " with dR = " << dR << std::endl;
0521 }
0522
0523 if (_pflow_HAD_E.at(had) > max_had_pt)
0524 {
0525 max_had_pt = _pflow_HAD_E.at(had);
0526 min_had_index = had;
0527 min_had_dR = dR;
0528 }
0529 }
0530 else
0531 {
0532 if (Verbosity() > 5)
0533 {
0534 std::cout << " -> no match to HAD " << had << " (even though dR = " << dR << " )" << std::endl;
0535 }
0536 }
0537 }
0538
0539 if (min_had_index > -1)
0540 {
0541 _pflow_HAD_match_TRK.at(min_had_index).push_back(trk);
0542 _pflow_TRK_match_HAD.at(trk).push_back(min_had_index);
0543
0544 if (Verbosity() > 5)
0545 {
0546 std::cout << " -> matched HAD " << min_had_index << " with pt / eta / phi = " << _pflow_HAD_E.at(min_had_index) << " / " << _pflow_HAD_eta.at(min_had_index) << " / " << _pflow_HAD_phi.at(min_had_index) << ", dR = " << min_had_dR << std::endl;
0547 }
0548 }
0549 else
0550 {
0551 if (Verbosity() > 5)
0552 {
0553 std::cout << " -> no HAD match! ( best dR = " << min_had_dR << " ) " << std::endl;
0554 }
0555 }
0556 }
0557
0558
0559 if (Verbosity() > 2)
0560 {
0561 std::cout << "ParticleFlowReco::process_event : EM -> HAD linking " << std::endl;
0562 }
0563
0564 for (unsigned int em = 0; em < _pflow_EM_E.size(); em++)
0565 {
0566 if (Verbosity() > 10)
0567 {
0568 std::cout << " EM with E / eta / phi = " << _pflow_EM_E[em] << " / " << _pflow_EM_eta[em] << " / " << _pflow_EM_phi[em] << std::endl;
0569 }
0570
0571
0572 float min_had_dR = 0.2;
0573 int min_had_index = -1;
0574 float max_had_pt = 0;
0575
0576 for (unsigned int had = 0; had < _pflow_HAD_E.size(); had++)
0577 {
0578 float dR = calculate_dR(_pflow_EM_eta[em], _pflow_HAD_eta[had], _pflow_EM_phi[em], _pflow_HAD_phi[had]);
0579 if (dR > 0.5)
0580 {
0581 continue;
0582 }
0583
0584 bool has_overlap = false;
0585
0586 for (unsigned int tow = 0; tow < _pflow_HAD_tower_eta.at(had).size(); tow++)
0587 {
0588 float tower_eta = _pflow_HAD_tower_eta.at(had).at(tow);
0589 float tower_phi = _pflow_HAD_tower_phi.at(had).at(tow);
0590
0591 float deta = tower_eta - _pflow_EM_eta[em];
0592 float dphi = tower_phi - _pflow_EM_phi[em];
0593 if (dphi > M_PI)
0594 {
0595 dphi -= 2 * M_PI;
0596 }
0597 if (dphi < -M_PI)
0598 {
0599 dphi += 2 * M_PI;
0600 }
0601
0602 if (std::fabs(deta) < 0.1 * 1.5 && std::fabs(dphi) < 0.1 * 1.5)
0603 {
0604 has_overlap = true;
0605 break;
0606 }
0607 }
0608
0609 if (has_overlap)
0610 {
0611 if (Verbosity() > 5)
0612 {
0613 std::cout << " -> possible match to HAD " << had << " with dR = " << dR << std::endl;
0614 }
0615
0616 if (_pflow_HAD_E.at(had) > max_had_pt)
0617 {
0618 max_had_pt = _pflow_HAD_E.at(had);
0619 min_had_index = had;
0620 min_had_dR = dR;
0621 }
0622 }
0623 else
0624 {
0625 if (Verbosity() > 5)
0626 {
0627 std::cout << " -> no match to HAD " << had << " (even though dR = " << dR << " )" << std::endl;
0628 }
0629 }
0630 }
0631
0632 if (min_had_index > -1)
0633 {
0634 _pflow_HAD_match_EM.at(min_had_index).push_back(em);
0635 _pflow_EM_match_HAD.at(em).push_back(min_had_index);
0636
0637 if (Verbosity() > 5)
0638 {
0639 std::cout << " -> matched HAD with E / eta / phi = " << _pflow_HAD_E.at(min_had_index) << " / " << _pflow_HAD_eta.at(min_had_index) << " / " << _pflow_HAD_phi.at(min_had_index) << ", dR = " << min_had_dR << std::endl;
0640 }
0641 }
0642 else
0643 {
0644 if (Verbosity() > 5)
0645 {
0646 std::cout << " -> no HAD match! ( best dR = " << min_had_dR << " ) " << std::endl;
0647 }
0648 }
0649 }
0650
0651
0652 if (Verbosity() > 2)
0653 {
0654 std::cout << "ParticleFlowReco::process_event : sequential TRK -> EM && EM -> HAD ==> TRK -> HAD matching " << std::endl;
0655 }
0656
0657 for (unsigned int trk = 0; trk < _pflow_TRK_p.size(); trk++)
0658 {
0659
0660 for (unsigned int i = 0; i < _pflow_TRK_match_EM.at(trk).size(); i++)
0661 {
0662 int em = _pflow_TRK_match_EM.at(trk).at(i);
0663
0664
0665 for (unsigned int j = 0; j < _pflow_EM_match_HAD.at(em).size(); j++)
0666 {
0667 int had = _pflow_EM_match_HAD.at(em).at(j);
0668
0669
0670 bool is_trk_matched_to_HAD = false;
0671 for (int existing_had : _pflow_TRK_match_HAD.at(trk))
0672 {
0673 if (had == existing_had)
0674 {
0675 is_trk_matched_to_HAD = true;
0676 }
0677 }
0678
0679
0680 if (!is_trk_matched_to_HAD)
0681 {
0682 _pflow_TRK_match_HAD.at(trk).push_back(had);
0683 _pflow_HAD_match_TRK.at(had).push_back(trk);
0684
0685 if (Verbosity() > 5)
0686 {
0687 std::cout << " TRK " << trk << " with pt / eta / phi = " << _pflow_TRK_p.at(trk) << " / " << _pflow_TRK_eta.at(trk) << " / " << _pflow_TRK_phi.at(trk) << std::endl;
0688 std::cout << " -> sequential match to HAD " << had << " through EM " << j << std::endl;
0689 }
0690 }
0691
0692 }
0693
0694 }
0695
0696 }
0697
0698
0699 if (Verbosity() > 2)
0700 {
0701 std::cout << "ParticleFlowReco::process_event : resolve TRK(s) + EM(s) -> HAD systems " << std::endl;
0702 }
0703
0704 for (unsigned int had = 0; had < _pflow_HAD_E.size(); had++)
0705 {
0706
0707 if (_pflow_HAD_match_TRK.at(had).empty())
0708 {
0709 continue;
0710 }
0711
0712 if (Verbosity() > 5)
0713 {
0714 std::cout << " HAD " << had << " with E / eta / phi = " << _pflow_HAD_E.at(had) << " / " << _pflow_HAD_eta.at(had) << " / " << _pflow_HAD_phi.at(had) << std::endl;
0715 }
0716
0717
0718 float total_TRK_p = 0;
0719 float total_expected_E = 0;
0720 float total_expected_E_var = 0;
0721
0722
0723 float total_EMHAD_E = _pflow_HAD_E.at(had);
0724
0725 std::vector<RawCluster *> matchedEClusters;
0726
0727
0728 for (int em : _pflow_HAD_match_EM.at(had))
0729 {
0730
0731 if (_pflow_EM_match_TRK.at(em).empty())
0732 {
0733 continue;
0734 }
0735
0736
0737 total_EMHAD_E += _pflow_EM_E.at(em);
0738 matchedEClusters.push_back(_pflow_EM_cluster.at(em));
0739 if (Verbosity() > 5)
0740 {
0741 std::cout << " -> -> LINKED EM " << em << " with E / eta / phi = " << _pflow_EM_E.at(em) << " / " << _pflow_EM_eta.at(em) << " / " << _pflow_EM_phi.at(em) << std::endl;
0742 }
0743 }
0744
0745
0746 for (unsigned int j = 0; j < _pflow_HAD_match_TRK.at(had).size(); j++)
0747 {
0748 int trk = _pflow_HAD_match_TRK.at(had).at(j);
0749
0750 if (Verbosity() > 5)
0751 {
0752 std::cout << " -> -> LINKED TRK " << trk << " with p / eta / phi = " << _pflow_TRK_p.at(trk) << " / " << _pflow_TRK_eta.at(trk) << " / " << _pflow_TRK_phi.at(trk) << std::endl;
0753 }
0754
0755 total_TRK_p += _pflow_TRK_p.at(trk);
0756
0757 std::pair<float, float> expected_signature = get_expected_signature(trk);
0758
0759 float expected_E_mean = expected_signature.first;
0760 float expected_E_sigma = expected_signature.second;
0761
0762 if (Verbosity() > 5)
0763 {
0764 std::cout << " -> -> -> expected calo signature is " << expected_E_mean << " +/- " << expected_E_sigma << std::endl;
0765 }
0766
0767 total_expected_E += expected_E_mean;
0768 total_expected_E_var += pow(expected_E_sigma, 2);
0769
0770
0771 ParticleFlowElement *pflow = new ParticleFlowElementv1();
0772
0773
0774 TLorentzVector tlv;
0775 tlv.SetPtEtaPhiM(_pflow_TRK_p[trk] / cosh(_pflow_TRK_eta[trk]), _pflow_TRK_eta[trk], _pflow_TRK_phi[trk], 0.135);
0776
0777 pflow->set_px(tlv.Px());
0778 pflow->set_py(tlv.Py());
0779 pflow->set_pz(tlv.Pz());
0780 pflow->set_e(tlv.E());
0781 pflow->set_track(_pflow_TRK_trk[trk]);
0782 pflow->set_eclusters(matchedEClusters);
0783 pflow->set_hcluster(_pflow_HAD_cluster.at(had));
0784 pflow->set_id(global_pflow_index);
0785 pflow->set_type(ParticleFlowElement::PFLOWTYPE::MATCHED_CHARGED_HADRON);
0786
0787 pflowContainer->AddParticleFlowElement(global_pflow_index, pflow);
0788 global_pflow_index++;
0789 }
0790
0791
0792
0793 float total_expected_E_err = std::sqrt(total_expected_E_var);
0794
0795 if (Verbosity() > 5)
0796 {
0797 std::cout << " -> Total track Sum p = " << total_TRK_p << " , expected calo Sum E = " << total_expected_E << " +/- " << total_expected_E_err << " , observed EM+HAD Sum E = " << total_EMHAD_E << std::endl;
0798 }
0799
0800
0801
0802 if (total_expected_E > total_EMHAD_E)
0803 {
0804 if (Verbosity() > 5)
0805 {
0806 std::cout << " -> Expected E > Observed E, looking for additional potential TRK->EM matches" << std::endl;
0807 }
0808
0809 std::map<int, float> additional_EMs;
0810
0811 for (int trk : _pflow_HAD_match_TRK.at(had))
0812 {
0813 int addtl_matches = _pflow_TRK_addtl_match_EM.at(trk).size();
0814
0815 if (Verbosity() > 10)
0816 {
0817 std::cout << " -> -> TRK " << trk << " has " << addtl_matches << " additional matches! " << std::endl;
0818 }
0819
0820 for (auto &n : _pflow_TRK_addtl_match_EM.at(trk))
0821 {
0822 if (Verbosity() > 10)
0823 {
0824 std::cout << " -> -> -> additional match to EM = " << n.first << " with dR = " << n.second << std::endl;
0825 }
0826
0827 float existing_dR = 0.21;
0828 int counts = additional_EMs.count(n.first);
0829 if (counts > 0)
0830 {
0831 existing_dR = additional_EMs[n.first];
0832 }
0833 if (n.second < existing_dR)
0834 {
0835 additional_EMs[n.first] = n.second;
0836 }
0837 }
0838 }
0839
0840
0841
0842
0843 std::vector<std::pair<int, float> > additional_EMs_vec;
0844
0845 additional_EMs_vec.reserve(additional_EMs.size());
0846 for (auto &x : additional_EMs)
0847 {
0848 additional_EMs_vec.emplace_back(x.first, x.second);
0849 }
0850
0851 std::sort(additional_EMs_vec.begin(), additional_EMs_vec.end(), sort_by_pair_second_lowest);
0852
0853 if (Verbosity() > 5)
0854 {
0855 std::cout << " -> Sorting the set of potential additional EMs " << std::endl;
0856 }
0857
0858
0859
0860 int n_EM_added = 0;
0861 while (!additional_EMs_vec.empty() && total_expected_E > total_EMHAD_E)
0862 {
0863 int new_EM = additional_EMs_vec.at(0).first;
0864
0865 if (Verbosity() > 5)
0866 {
0867 std::cout << " -> adding EM " << new_EM << " ( dR = " << additional_EMs_vec.at(0).second << " to the system (should not see it as orphan below)" << std::endl;
0868 }
0869
0870
0871 _pflow_EM_match_TRK.at(new_EM).push_back(_pflow_HAD_match_TRK.at(had).at(0));
0872 _pflow_TRK_match_EM.at(_pflow_HAD_match_TRK.at(had).at(0)).push_back(new_EM);
0873
0874
0875 total_EMHAD_E += _pflow_EM_E.at(new_EM);
0876
0877
0878 additional_EMs_vec.erase(additional_EMs_vec.begin());
0879
0880 n_EM_added++;
0881 }
0882
0883 if (Verbosity() > 5)
0884 {
0885 if (n_EM_added > 0)
0886 {
0887 std::cout << "After adding N = " << n_EM_added << " any additional EMs : " << std::endl;
0888 std::cout << "-> Total track Sum p = " << total_TRK_p << " , expected calo Sum E = " << total_expected_E << " +/- " << total_expected_E_err << " , observed EM+HAD Sum E = " << total_EMHAD_E << std::endl;
0889 }
0890 else
0891 {
0892 std::cout << "No additional EMs found, continuing hypothesis check" << std::endl;
0893 }
0894 }
0895 }
0896
0897 if (total_expected_E + _energy_match_Nsigma * total_expected_E_err > total_EMHAD_E)
0898 {
0899 if (Verbosity() > 5)
0900 {
0901 std::cout << " -> -> calo compatible within Nsigma = " << _energy_match_Nsigma << " , remove and keep tracks " << std::endl;
0902 }
0903
0904
0905 }
0906 else
0907 {
0908 float residual_energy = total_EMHAD_E - total_expected_E;
0909
0910 if (Verbosity() > 5)
0911 {
0912 std::cout << " -> -> calo not compatible, create leftover cluster with " << residual_energy << std::endl;
0913 }
0914
0915
0916 ParticleFlowElement *pflow = new ParticleFlowElementv1();
0917
0918
0919 TLorentzVector tlv;
0920 tlv.SetPtEtaPhiM(residual_energy / cosh(_pflow_HAD_eta[had]), _pflow_HAD_eta[had], _pflow_HAD_phi[had], 0);
0921
0922 pflow->set_px(tlv.Px());
0923 pflow->set_py(tlv.Py());
0924 pflow->set_pz(tlv.Pz());
0925 pflow->set_e(tlv.E());
0926 pflow->set_track(nullptr);
0927 pflow->set_eclusters(matchedEClusters);
0928 pflow->set_hcluster(_pflow_HAD_cluster.at(had));
0929 pflow->set_id(global_pflow_index);
0930 pflow->set_type(ParticleFlowElement::PFLOWTYPE::LEFTOVER_EM_PARTICLE);
0931
0932 pflowContainer->AddParticleFlowElement(global_pflow_index, pflow);
0933 global_pflow_index++;
0934 }
0935
0936 }
0937
0938
0939
0940 if (Verbosity() > 2)
0941 {
0942 std::cout << "ParticleFlowReco::process_event : resolve TRK(s) -> EM(s) ( + no HAD) systems " << std::endl;
0943 }
0944
0945 for (unsigned int em = 0; em < _pflow_EM_E.size(); em++)
0946 {
0947
0948 if (!_pflow_EM_match_HAD.at(em).empty())
0949 {
0950 continue;
0951 }
0952 if (_pflow_EM_match_TRK.at(em).empty())
0953 {
0954 continue;
0955 }
0956
0957 if (Verbosity() > 5)
0958 {
0959 std::cout << " EM " << em << " with E / eta / phi = " << _pflow_EM_E.at(em) << " / " << _pflow_EM_eta.at(em) << " / " << _pflow_EM_phi.at(em) << std::endl;
0960 }
0961
0962
0963 float total_TRK_p = 0;
0964 float total_expected_E = 0;
0965 float total_expected_E_var = 0;
0966
0967
0968 float total_EM_E = _pflow_EM_E.at(em);
0969
0970
0971 for (unsigned int j = 0; j < _pflow_EM_match_TRK.at(em).size(); j++)
0972 {
0973 int trk = _pflow_EM_match_TRK.at(em).at(j);
0974
0975 if (Verbosity() > 5)
0976 {
0977 std::cout << " -> -> LINKED TRK with p / eta / phi = " << _pflow_TRK_p.at(trk) << " / " << _pflow_TRK_eta.at(trk) << " / " << _pflow_TRK_phi.at(trk) << std::endl;
0978 }
0979
0980 total_TRK_p += _pflow_TRK_p.at(trk);
0981
0982 std::pair<float, float> expected_signature = get_expected_signature(trk);
0983
0984 float expected_E_mean = expected_signature.first;
0985 float expected_E_sigma = expected_signature.second;
0986
0987 if (Verbosity() > 5)
0988 {
0989 std::cout << " -> -> -> expected calo signature is " << expected_E_mean << " +/- " << expected_E_sigma << std::endl;
0990 }
0991
0992 total_expected_E += expected_E_mean;
0993 total_expected_E_var += pow(expected_E_sigma, 2);
0994
0995
0996 ParticleFlowElement *pflow = new ParticleFlowElementv1();
0997
0998
0999 TLorentzVector tlv;
1000 tlv.SetPtEtaPhiM(_pflow_TRK_p[trk] / cosh(_pflow_TRK_eta[trk]), _pflow_TRK_eta[trk], _pflow_TRK_phi[trk], 0.135);
1001
1002 std::vector<RawCluster *> eclus;
1003 eclus.push_back(_pflow_EM_cluster.at(em));
1004
1005 pflow->set_px(tlv.Px());
1006 pflow->set_py(tlv.Py());
1007 pflow->set_pz(tlv.Pz());
1008 pflow->set_e(tlv.E());
1009 pflow->set_track(_pflow_TRK_trk.at(trk));
1010 pflow->set_eclusters(eclus);
1011 pflow->set_hcluster(nullptr);
1012 pflow->set_id(global_pflow_index);
1013 pflow->set_type(ParticleFlowElement::PFLOWTYPE::MATCHED_CHARGED_HADRON);
1014
1015 pflowContainer->AddParticleFlowElement(global_pflow_index, pflow);
1016 global_pflow_index++;
1017 }
1018
1019
1020 float total_expected_E_err = std::sqrt(total_expected_E_var);
1021
1022 if (Verbosity() > 5)
1023 {
1024 std::cout << " -> Total track Sum p = " << total_TRK_p << " , expected calo Sum E = " << total_expected_E << " +/- " << total_expected_E_err << " , observed EM Sum E = " << total_EM_E << std::endl;
1025 }
1026
1027 if (total_expected_E + _energy_match_Nsigma * total_expected_E_err > total_EM_E)
1028 {
1029 if (Verbosity() > 5)
1030 {
1031 std::cout << " -> -> calo compatible within Nsigma = " << _energy_match_Nsigma << " , remove and keep tracks " << std::endl;
1032 }
1033
1034
1035 }
1036 else
1037 {
1038 float residual_energy = total_EM_E - total_expected_E;
1039
1040 if (Verbosity() > 5)
1041 {
1042 std::cout << " -> -> calo not compatible, create leftover cluster with " << residual_energy << std::endl;
1043 }
1044
1045
1046 ParticleFlowElement *pflow = new ParticleFlowElementv1();
1047
1048
1049 TLorentzVector tlv;
1050 tlv.SetPtEtaPhiM(residual_energy / cosh(_pflow_EM_eta[em]), _pflow_EM_eta[em], _pflow_EM_phi[em], 0);
1051
1052 std::vector<RawCluster *> eclus;
1053 eclus.push_back(_pflow_EM_cluster.at(em));
1054
1055 pflow->set_px(tlv.Px());
1056 pflow->set_py(tlv.Py());
1057 pflow->set_pz(tlv.Pz());
1058 pflow->set_e(tlv.E());
1059 pflow->set_eclusters(eclus);
1060 pflow->set_hcluster(nullptr);
1061 pflow->set_track(nullptr);
1062 pflow->set_id(global_pflow_index);
1063 pflow->set_type(ParticleFlowElement::PFLOWTYPE::LEFTOVER_EM_PARTICLE);
1064
1065 pflowContainer->AddParticleFlowElement(global_pflow_index, pflow);
1066 global_pflow_index++;
1067 }
1068
1069 }
1070
1071
1072
1073 if (Verbosity() > 2)
1074 {
1075 std::cout << "ParticleFlowReco::process_event : remove TRK-unlinked EMs and HADs " << std::endl;
1076 }
1077
1078 for (unsigned int em = 0; em < _pflow_EM_E.size(); em++)
1079 {
1080
1081 if (!_pflow_EM_match_TRK.at(em).empty())
1082 {
1083 continue;
1084 }
1085
1086 if (Verbosity() > 5)
1087 {
1088 std::cout << " unmatched EM " << em << " with E / eta / phi = " << _pflow_EM_E.at(em) << " / " << _pflow_EM_eta.at(em) << " / " << _pflow_EM_phi.at(em) << std::endl;
1089 }
1090
1091
1092 ParticleFlowElement *pflow = new ParticleFlowElementv1();
1093
1094
1095 TLorentzVector tlv;
1096 tlv.SetPtEtaPhiM(_pflow_EM_E[em] / cosh(_pflow_EM_eta[em]), _pflow_EM_eta[em], _pflow_EM_phi[em], 0);
1097
1098 std::vector<RawCluster *> eclus;
1099 eclus.push_back(_pflow_EM_cluster.at(em));
1100
1101 pflow->set_px(tlv.Px());
1102 pflow->set_py(tlv.Py());
1103 pflow->set_pz(tlv.Pz());
1104 pflow->set_e(tlv.E());
1105 pflow->set_eclusters(eclus);
1106 pflow->set_hcluster(nullptr);
1107 pflow->set_track(nullptr);
1108 pflow->set_id(global_pflow_index);
1109 pflow->set_type(ParticleFlowElement::PFLOWTYPE::UNMATCHED_EM_PARTICLE);
1110
1111 pflowContainer->AddParticleFlowElement(global_pflow_index, pflow);
1112 global_pflow_index++;
1113
1114 }
1115
1116 for (unsigned int had = 0; had < _pflow_HAD_E.size(); had++)
1117 {
1118
1119 if (!_pflow_HAD_match_TRK.at(had).empty())
1120 {
1121 continue;
1122 }
1123
1124 if (Verbosity() > 5)
1125 {
1126 std::cout << " unmatched HAD " << had << " with E / eta / phi = " << _pflow_HAD_E.at(had) << " / " << _pflow_HAD_eta.at(had) << " / " << _pflow_HAD_phi.at(had) << std::endl;
1127 }
1128
1129
1130 ParticleFlowElement *pflow = new ParticleFlowElementv1();
1131
1132
1133 TLorentzVector tlv;
1134 tlv.SetPtEtaPhiM(_pflow_HAD_E[had] / cosh(_pflow_HAD_eta[had]), _pflow_HAD_eta[had], _pflow_HAD_phi[had], 0);
1135
1136 pflow->set_px(tlv.Px());
1137 pflow->set_py(tlv.Py());
1138 pflow->set_pz(tlv.Pz());
1139 pflow->set_e(tlv.E());
1140 pflow->set_track(nullptr);
1141 pflow->set_eclusters(std::vector<RawCluster *>());
1142 pflow->set_hcluster(_pflow_HAD_cluster.at(had));
1143 pflow->set_id(global_pflow_index);
1144 pflow->set_type(ParticleFlowElement::PFLOWTYPE::UNMATCHED_NEUTRAL_HADRON);
1145
1146 pflowContainer->AddParticleFlowElement(global_pflow_index, pflow);
1147 global_pflow_index++;
1148
1149 }
1150
1151 for (unsigned int trk = 0; trk < _pflow_TRK_p.size(); trk++)
1152 {
1153
1154 if (!_pflow_TRK_match_EM.at(trk).empty() || !_pflow_TRK_match_HAD.at(trk).empty())
1155 {
1156 continue;
1157 }
1158
1159 if (Verbosity() > 5)
1160 {
1161 std::cout << " unmatched TRK " << trk << " with p / eta / phi = " << _pflow_TRK_p.at(trk) << " / " << _pflow_TRK_eta.at(trk) << " / " << _pflow_TRK_phi.at(trk) << std::endl;
1162 }
1163
1164
1165 ParticleFlowElement *pflow = new ParticleFlowElementv1();
1166
1167
1168 TLorentzVector tlv;
1169 tlv.SetPtEtaPhiM(_pflow_TRK_p[trk] / cosh(_pflow_TRK_eta[trk]), _pflow_TRK_eta[trk], _pflow_TRK_phi[trk], 0.135);
1170
1171 pflow->set_px(tlv.Px());
1172 pflow->set_py(tlv.Py());
1173 pflow->set_pz(tlv.Pz());
1174 pflow->set_e(tlv.E());
1175 pflow->set_track(_pflow_TRK_trk.at(trk));
1176 pflow->set_eclusters(std::vector<RawCluster *>());
1177 pflow->set_hcluster(nullptr);
1178 pflow->set_id(global_pflow_index);
1179 pflow->set_type(ParticleFlowElement::PFLOWTYPE::UNMATCHED_CHARGED_HADRON);
1180
1181 pflowContainer->AddParticleFlowElement(global_pflow_index, pflow);
1182 global_pflow_index++;
1183
1184 }
1185
1186
1187 if (Verbosity() > 5)
1188 {
1189 std::cout << "ParticleFlowReco::process_event: summary of PFlow objects " << std::endl;
1190
1191 ParticleFlowElementContainer::ConstRange begin_end = pflowContainer->getParticleFlowElements();
1192 for (ParticleFlowElementContainer::ConstIterator hiter = begin_end.first; hiter != begin_end.second; ++hiter)
1193 {
1194 hiter->second->identify();
1195 }
1196 }
1197
1198 return Fun4AllReturnCodes::EVENT_OK;
1199 }
1200
1201 int ParticleFlowReco::CreateNode(PHCompositeNode *topNode)
1202 {
1203 PHNodeIterator iter(topNode);
1204
1205
1206 PHCompositeNode *dstNode = dynamic_cast<PHCompositeNode *>(iter.findFirst("PHCompositeNode", "DST"));
1207 if (!dstNode)
1208 {
1209 std::cout << PHWHERE << "DST Node missing, doing nothing." << std::endl;
1210 return Fun4AllReturnCodes::ABORTRUN;
1211 }
1212
1213
1214 PHCompositeNode *pflowNode = dynamic_cast<PHCompositeNode *>(iter.findFirst("PHCompositeNode", "PARTICLEFLOW"));
1215 if (!pflowNode)
1216 {
1217 pflowNode = new PHCompositeNode("PARTICLEFLOW");
1218 dstNode->addNode(pflowNode);
1219 }
1220
1221
1222 ParticleFlowElementContainer *pflowElementContainer = findNode::getClass<ParticleFlowElementContainer>(topNode, "ParticleFlowElements");
1223 if (!pflowElementContainer)
1224 {
1225 pflowElementContainer = new ParticleFlowElementContainer();
1226 PHIODataNode<PHObject> *pflowElementNode = new PHIODataNode<PHObject>(pflowElementContainer, "ParticleFlowElements", "PHObject");
1227 pflowNode->addNode(pflowElementNode);
1228 }
1229 else
1230 {
1231 std::cout << PHWHERE << "::ERROR - ParticleFlowElements node alerady exists, but should not" << std::endl;
1232 exit(-1);
1233 }
1234
1235 return Fun4AllReturnCodes::EVENT_OK;
1236 }