Analysis Software
Documentation for sPHENIX simulation software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
ParticleFlowReco.cc
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file ParticleFlowReco.cc
1 #include "ParticleFlowReco.h"
2 
5 
8 
9 #include <calobase/RawCluster.h>
10 #include <calobase/RawClusterContainer.h>
11 #include <calobase/RawTowerGeom.h>
12 #include <calobase/RawTowerGeomContainer.h>
13 #include <calobase/RawClusterUtility.h>
14 
18 
20 
21 #include <phool/PHCompositeNode.h>
22 #include <phool/PHRandomSeed.h>
23 #include <phool/getClass.h>
24 
25 
26 #include <TLorentzVector.h>
27 
28 #include <gsl/gsl_randist.h>
29 #include <gsl/gsl_rng.h> // for gsl_rng_uniform_pos
30 
31 #include <cmath>
32 #include <iostream>
33 
34 // examine second value of std::pair, sort by smallest
35 bool sort_by_pair_second_lowest( const std::pair<int,float> &a, const std::pair<int,float> &b)
36 {
37  return (a.second < b.second);
38 }
39 
40 float ParticleFlowReco::calculate_dR( float eta1, float eta2, float phi1, float phi2 ) {
41 
42  float deta = eta1 - eta2;
43  float dphi = phi1 - phi2;
44  while ( dphi > M_PI ) dphi -= 2 * M_PI;
45  while ( dphi < -M_PI ) dphi += 2 * M_PI;
46  return sqrt( pow( deta, 2 ) + pow( dphi ,2 ) );
47 
48 }
49 
50 std::pair<float, float> ParticleFlowReco::get_expected_signature( int trk ) {
51 
52  float response = ( 0.553437 + 0.0572246 * log( _pflow_TRK_p[ trk ] ) ) * _pflow_TRK_p[ trk ];
53  float resolution = sqrt( pow( 0.119123 , 2 ) + pow( 0.312361 , 2 ) / _pflow_TRK_p[ trk ] ) * _pflow_TRK_p[ trk ] ;
54 
55  std::pair<float, float> expected_signature( response , resolution );
56 
57  return expected_signature;
58 
59 }
60 
61 //____________________________________________________________________________..
63  SubsysReco(name),
64  _energy_match_Nsigma( 1.5 )
65 {
66 }
67 
68 //____________________________________________________________________________..
70 {
71 }
72 
73 //____________________________________________________________________________..
75 {
77 }
78 
79 //____________________________________________________________________________..
81 {
82  return CreateNode(topNode);
83 
84 }
85 
86 //____________________________________________________________________________..
88 {
89  if (Verbosity() > 0)
90  {
91  std::cout << "ParticleFlowReco::process_event with Nsigma = " << _energy_match_Nsigma << std::endl;
92  }
93  // get handle to pflow node
94  ParticleFlowElementContainer *pflowContainer = findNode::getClass<ParticleFlowElementContainer>(topNode, "ParticleFlowElements");
95  if (!pflowContainer) {
96  std::cout << " ERROR -- can't find ParticleFlowElements node after it should have been created" << std::endl;
98  }
99 
100  // used for indexing PFlow elements in container
101  int global_pflow_index = 0;
102 
103  // read in tower geometries
104  RawTowerGeomContainer *geomEM = findNode::getClass<RawTowerGeomContainer>(topNode, "TOWERGEOM_CEMC");
105  RawTowerGeomContainer *geomIH = findNode::getClass<RawTowerGeomContainer>(topNode, "TOWERGEOM_HCALIN");
106  RawTowerGeomContainer *geomOH = findNode::getClass<RawTowerGeomContainer>(topNode, "TOWERGEOM_HCALOUT");
107 
108  if ( !geomEM || !geomIH || !geomOH ) {
109  std::cout << "ParticleFlowReco::process_event : FATAL ERROR, cannot find tower geometry containers" << std::endl;
111  }
112 
113  // read in clusters
114  RawClusterContainer *clustersEM = findNode::getClass<RawClusterContainer>(topNode, "TOPOCLUSTER_EMCAL");
115  RawClusterContainer *clustersHAD = findNode::getClass<RawClusterContainer>(topNode, "TOPOCLUSTER_HCAL");
116 
117  if ( !clustersEM ) {
118  std::cout << "ParticleFlowReco::process_event : FATAL ERROR, cannot find cluster container TOPOCLUSTER_EMCAL" << std::endl;
120  }
121  if ( !clustersHAD ) {
122  std::cout << "ParticleFlowReco::process_event : FATAL ERROR, cannot find cluster container TOPOCLUSTER_HCAL" << std::endl;
124  }
125 
126  // reset internal particle-flow representation
127  _pflow_TRK_p.clear();
128  _pflow_TRK_eta.clear();
129  _pflow_TRK_phi.clear();
130  _pflow_TRK_match_EM.clear();
131  _pflow_TRK_match_HAD.clear();
133  _pflow_TRK_trk.clear();
134  _pflow_TRK_EMproj_phi.clear();
135  _pflow_TRK_EMproj_eta.clear();
136  _pflow_TRK_HADproj_eta.clear();
137  _pflow_TRK_HADproj_phi.clear();
138 
139  _pflow_EM_E.clear();
140  _pflow_EM_eta.clear();
141  _pflow_EM_phi.clear();
142  _pflow_EM_tower_eta.clear();
143  _pflow_EM_tower_phi.clear();
144  _pflow_EM_match_HAD.clear();
145  _pflow_EM_match_TRK.clear();
146  _pflow_EM_cluster.clear();
147 
148  _pflow_HAD_E.clear();
149  _pflow_HAD_eta.clear();
150  _pflow_HAD_phi.clear();
151  _pflow_HAD_tower_eta.clear();
152  _pflow_HAD_tower_phi.clear();
153  _pflow_HAD_match_EM.clear();
154  _pflow_HAD_match_TRK.clear();
155  _pflow_HAD_cluster.clear();
156 
157  GlobalVertexMap* vertexmap = findNode::getClass<GlobalVertexMap>(topNode, "GlobalVertexMap");
158  GlobalVertex* vertex = nullptr;
159 
160  if(vertexmap)
161  {
162  if (!vertexmap->empty())
163  {
164  vertex = (vertexmap->begin()->second);
165  }
166  }
167 
168  if ( Verbosity() > 2 )
169  std::cout << "ParticleFlowReco::process_event : initial population of TRK, EM, HAD objects " << std::endl;
170 
171  // read in tracks with > 0.5 GeV
172  {
173  SvtxTrackMap* trackmap = findNode::getClass<SvtxTrackMap>(topNode, _track_map_name);
174 
175  float cemcradius = geomEM->get_radius();
176  float ohcalradius = geomOH->get_radius();
177 
178  for(auto iter = trackmap->begin(); iter != trackmap->end(); ++iter)
179  {
180  SvtxTrack *track = iter->second;
181 
182  if(track->get_pt() < 0.5)
183  { continue; }
184 
185  if(fabs(track->get_eta()) > 1.1)
186  { continue; }
187 
188  if(Verbosity() > 2)
189  {
190  std::cout << "Track with p= " << track->get_p() <<", eta / phi = "
191  << track->get_eta() << " / " << track->get_phi()
192  << std::endl;
193  }
194 
195  _pflow_TRK_trk.push_back(track);
196  _pflow_TRK_p.push_back(track->get_p());
197  _pflow_TRK_eta.push_back(track->get_eta());
198  _pflow_TRK_phi.push_back(track->get_phi());
199  _pflow_TRK_match_EM.push_back( std::vector<int>() );
200  _pflow_TRK_match_HAD.push_back( std::vector<int>() );
201  _pflow_TRK_addtl_match_EM.push_back( std::vector< std::pair<int,float> >() );
202 
203  SvtxTrackState* cemcstate = track->get_state(cemcradius);
204  SvtxTrackState* ohstate = track->get_state(ohcalradius);
207  if(cemcstate)
208  {
209  _pflow_TRK_EMproj_phi.push_back(atan2(cemcstate->get_y(), cemcstate->get_x()));
210  _pflow_TRK_EMproj_eta.push_back(asinh(cemcstate->get_z()/sqrt(cemcstate->get_x()*cemcstate->get_x() + cemcstate->get_y()*cemcstate->get_y())));
211  }
212  else {
213  _pflow_TRK_EMproj_phi.push_back(track->get_phi());
214  _pflow_TRK_EMproj_eta.push_back(track->get_eta());
215  }
216  if(ohstate)
217  {
218  _pflow_TRK_HADproj_phi.push_back(atan2(ohstate->get_y(), ohstate->get_x()));
219  _pflow_TRK_HADproj_eta.push_back(asinh(ohstate->get_z()/sqrt(ohstate->get_x()*ohstate->get_x() + ohstate->get_y()*ohstate->get_y())));
220  }
221  else {
222  _pflow_TRK_HADproj_phi.push_back(track->get_phi());
223  _pflow_TRK_HADproj_eta.push_back(track->get_eta());
224  }
225  }
226 
227  } //
228 
229 
230 
231  // read in EMCal topoClusters with E > 0.2 GeV
232  {
233  RawClusterContainer::ConstRange begin_end = clustersEM->getClusters();
234  for ( RawClusterContainer::ConstIterator hiter = begin_end.first; hiter != begin_end.second; ++hiter)
235  {
236  float cluster_E = hiter->second->get_energy();
237  if ( cluster_E < 0.2 ) continue;
238 
239  float cluster_phi = hiter->second->get_phi();
241  float cluster_theta = M_PI / 2.0 - atan2( hiter->second->get_z() , hiter->second->get_r() );
242  float cluster_eta = -1 * log( tan( cluster_theta / 2.0 ) );
243 
244  if(vertex)
245  {
246  cluster_eta = RawClusterUtility::GetPseudorapidity(*(hiter->second),CLHEP::Hep3Vector(vertex->get_x(), vertex->get_y(), vertex->get_z()));
247  }
248 
249  _pflow_EM_E.push_back( cluster_E );
250  _pflow_EM_eta.push_back( cluster_eta );
251  _pflow_EM_phi.push_back( cluster_phi );
252  _pflow_EM_cluster.push_back(hiter->second);
253  _pflow_EM_match_HAD.push_back( std::vector<int>() );
254  _pflow_EM_match_TRK.push_back( std::vector<int>() );
255 
256  if ( Verbosity() > 5 && cluster_E > 0.2 )
257  std::cout << " EM topoCluster with E = " << cluster_E << ", eta / phi = " << cluster_eta << " / " << cluster_phi << " , nTow = " << hiter->second->getNTowers() << std::endl;
258 
259  std::vector<float> this_cluster_tower_eta;
260  std::vector<float> this_cluster_tower_phi;
261 
262  // read in towers
263  RawCluster::TowerConstRange begin_end_towers = hiter->second->get_towers();
264  for (RawCluster::TowerConstIterator iter = begin_end_towers.first; iter != begin_end_towers.second; ++iter) {
265 
267  RawTowerGeom *tower_geom = geomEM->get_tower_geometry(iter->first);
268 
269  this_cluster_tower_phi.push_back( tower_geom->get_phi() );
270  this_cluster_tower_eta.push_back( tower_geom->get_eta() );
271  }
272  else {
273  std::cout << "ParticleFlowReco::process_event : FATAL ERROR , EM topoClusters seem to contain HCal towers" << std::endl;
275  }
276  } // close tower loop
277 
278  _pflow_EM_tower_eta.push_back( this_cluster_tower_eta );
279  _pflow_EM_tower_phi.push_back( this_cluster_tower_phi );
280 
281  } // close cluster loop
282 
283  } // close
284 
285  // read in HCal topoClusters with E > 0.2 GeV
286  {
287  RawClusterContainer::ConstRange begin_end = clustersHAD->getClusters();
288  for ( RawClusterContainer::ConstIterator hiter = begin_end.first; hiter != begin_end.second; ++hiter)
289  {
290  float cluster_E = hiter->second->get_energy();
291  if ( cluster_E < 0.2 ) continue;
292 
293  float cluster_phi = hiter->second->get_phi();
294  // for now, assume event at vx_z = 0
295  float cluster_theta = M_PI / 2.0 - atan2( hiter->second->get_z() , hiter->second->get_r() );
296  float cluster_eta = -1 * log( tan( cluster_theta / 2.0 ) );
297  if(vertex)
298  {
299  cluster_eta = RawClusterUtility::GetPseudorapidity(*(hiter->second),CLHEP::Hep3Vector(vertex->get_x(), vertex->get_y(), vertex->get_z()));
300  }
301 
302  _pflow_HAD_E.push_back( cluster_E );
303  _pflow_HAD_eta.push_back( cluster_eta );
304  _pflow_HAD_phi.push_back( cluster_phi );
305  _pflow_HAD_cluster.push_back(hiter->second);
306 
307  _pflow_HAD_match_EM.push_back( std::vector<int>() );
308  _pflow_HAD_match_TRK.push_back( std::vector<int>() );
309 
310  if ( Verbosity() > 5 && cluster_E > 0.2 )
311  std::cout << " HAD topoCluster with E = " << cluster_E << ", eta / phi = " << cluster_eta << " / " << cluster_phi << " , nTow = " << hiter->second->getNTowers() << std::endl;
312 
313  std::vector<float> this_cluster_tower_eta;
314  std::vector<float> this_cluster_tower_phi;
315 
316  // read in towers
317  RawCluster::TowerConstRange begin_end_towers = hiter->second->get_towers();
318  for (RawCluster::TowerConstIterator iter = begin_end_towers.first; iter != begin_end_towers.second; ++iter) {
319 
321 
322  RawTowerGeom *tower_geom = geomIH->get_tower_geometry(iter->first);
323 
324  this_cluster_tower_phi.push_back( tower_geom->get_phi() );
325  this_cluster_tower_eta.push_back( tower_geom->get_eta() );
326  }
327 
329 
330  RawTowerGeom *tower_geom = geomOH->get_tower_geometry(iter->first);
331 
332  this_cluster_tower_phi.push_back( tower_geom->get_phi() );
333  this_cluster_tower_eta.push_back( tower_geom->get_eta() );
334  } else {
335  std::cout << "ParticleFlowReco::process_event : FATAL ERROR , HCal topoClusters seem to contain EM towers" << std::endl;
337  }
338 
339 
340  } // close tower loop
341 
342  _pflow_HAD_tower_eta.push_back( this_cluster_tower_eta );
343  _pflow_HAD_tower_phi.push_back( this_cluster_tower_phi );
344 
345  } // close cluster loop
346 
347  } // close
348 
349  // BEGIN LINKING STEP
350 
351  // Link TRK -> EM (best match, but keep reserve of others), and TRK -> HAD (best match)
352  if ( Verbosity() > 2 )
353  std::cout << "ParticleFlowReco::process_event : TRK -> EM and TRK -> HAD linking " << std::endl;
354 
355  for (unsigned int trk = 0; trk < _pflow_TRK_p.size() ; trk++ ) {
356 
357  if ( Verbosity() > 10 )
358  std::cout << " TRK " << trk << " with p / eta / phi = " << _pflow_TRK_p[ trk ] << " / " << _pflow_TRK_eta[ trk ] << " / " << _pflow_TRK_phi[ trk ] << std::endl;
359 
360  // TRK -> EM link
361  float min_em_dR = 0.2;
362  int min_em_index = -1;
363 
364  for (unsigned int em = 0 ; em < _pflow_EM_E.size() ; em++) {
365 
366  float dR = calculate_dR( _pflow_TRK_EMproj_eta[ trk ] , _pflow_EM_eta[ em ] , _pflow_TRK_EMproj_phi[ trk ] , _pflow_EM_phi[ em ] );
367 
368  if ( dR > 0.2 ) continue;
369 
370  bool has_overlap = false;
371 
372  for (unsigned int tow = 0; tow < _pflow_EM_tower_eta.at( em ).size() ; tow++) {
373 
374  float tower_eta = _pflow_EM_tower_eta.at( em ).at( tow );
375  float tower_phi = _pflow_EM_tower_phi.at( em ).at( tow );
376 
377  float deta = tower_eta - _pflow_TRK_EMproj_eta[ trk ];
378  float dphi = tower_phi - _pflow_TRK_EMproj_phi[ trk ];
379  if ( dphi > M_PI ) dphi -= 2 * M_PI;
380  if ( dphi < -M_PI ) dphi += 2 * M_PI;
381 
382  if ( fabs( deta ) < 0.025 * 2.5 && fabs( dphi ) < 0.025 * 2.5 ) {
383  has_overlap = true;
384  break;
385  }
386 
387  }
388 
389  if ( has_overlap ) {
390 
391  if ( Verbosity() > 5 )
392  std::cout << " -> possible match to EM " << em << " with dR = " << dR << std::endl;
393 
394  _pflow_TRK_addtl_match_EM.at( trk ).push_back( std::pair<int,float>( em, dR ) );
395 
396  } else {
397 
398  if ( Verbosity() > 5 )
399  std::cout << " -> no match to EM " << em << " (even though dR = " << dR << " )" << std::endl;
400 
401  }
402 
403  }
404 
405  // sort possible matches
406 
408  if ( Verbosity() > 10 ) {
409  for (unsigned int n = 0; n < _pflow_TRK_addtl_match_EM.at( trk ).size(); n++) {
410  std::cout << " -> sorted list of matches, EM / dR = " << _pflow_TRK_addtl_match_EM.at( trk ).at( n ).first << " / " << _pflow_TRK_addtl_match_EM.at( trk ).at( n ).second << std::endl;
411  }
412  }
413 
414  if ( _pflow_TRK_addtl_match_EM.at( trk ).size() > 0 ) {
415  min_em_index = _pflow_TRK_addtl_match_EM.at( trk ).at( 0 ).first;
416  min_em_dR = _pflow_TRK_addtl_match_EM.at( trk ).at( 0 ).second;
417  // delete best matched element
418  _pflow_TRK_addtl_match_EM.at( trk ).erase( _pflow_TRK_addtl_match_EM.at( trk ).begin() );
419  }
420 
421 
422  if ( min_em_index > -1 ) {
423  _pflow_EM_match_TRK.at( min_em_index ).push_back( trk );
424  _pflow_TRK_match_EM.at( trk ).push_back( min_em_index );
425 
426  if ( Verbosity() > 5 ) {
427  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;
428  std::cout << " ( " << _pflow_TRK_addtl_match_EM.at( trk ).size() << " other possible matches ) " << std::endl;
429  }
430 
431  } else {
432 
433  if ( Verbosity() > 5 )
434  std::cout << " -> no EM match! ( best dR = " << min_em_dR << " ) " << std::endl;
435  }
436 
437  // TRK -> HAD link
438  float min_had_dR = 0.2;
439  int min_had_index = -1;
440  float max_had_pt = 0;
441 
442  // TODO: sequential linking should better happen here -- i.e. allow EM-matched HAD's into the possible pool
443  for (unsigned int had = 0 ; had < _pflow_HAD_E.size() ; had++) {
444 
445  float dR = calculate_dR( _pflow_TRK_HADproj_eta[ trk ] , _pflow_HAD_eta[ had ] , _pflow_TRK_HADproj_phi[ trk ] , _pflow_HAD_phi[ had ] );
446 
447  if ( dR > 0.5 ) continue;
448 
449  bool has_overlap = false;
450 
451  for (unsigned int tow = 0; tow < _pflow_HAD_tower_eta.at( had ).size() ; tow++) {
452 
453  float tower_eta = _pflow_HAD_tower_eta.at( had ).at( tow );
454  float tower_phi = _pflow_HAD_tower_phi.at( had ).at( tow );
455 
456  float deta = tower_eta - _pflow_TRK_HADproj_eta[ trk ];
457  float dphi = tower_phi - _pflow_TRK_HADproj_phi[ trk ];
458  if ( dphi > M_PI ) dphi -= 2 * M_PI;
459  if ( dphi < -M_PI ) dphi += 2 * M_PI;
460 
461  if ( fabs( deta ) < 0.1 * 1.5 && fabs( dphi ) < 0.1 * 1.5 ) {
462  has_overlap = true;
463  break;
464  }
465 
466  }
467 
468  if ( has_overlap ) {
469 
470  if ( Verbosity() > 5 )
471  std::cout << " -> possible match to HAD " << had << " with dR = " << dR << std::endl;
472 
473  if ( _pflow_HAD_E.at( had ) > max_had_pt ) {
474  max_had_pt = _pflow_HAD_E.at( had );
475  min_had_index = had;
476  min_had_dR = dR;
477  }
478 
479  } else {
480 
481  if ( Verbosity() > 5 )
482  std::cout << " -> no match to HAD " << had << " (even though dR = " << dR << " )" << std::endl;
483 
484  }
485 
486  }
487 
488  if ( min_had_index > -1 ) {
489  _pflow_HAD_match_TRK.at( min_had_index ).push_back( trk );
490  _pflow_TRK_match_HAD.at( trk ).push_back( min_had_index );
491 
492  if ( Verbosity() > 5 )
493  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;
494 
495  } else {
496  if ( Verbosity() > 5 )
497  std::cout << " -> no HAD match! ( best dR = " << min_had_dR << " ) " << std::endl;
498  }
499 
500 
501  }
502 
503 
504  // EM->HAD linking
505  if ( Verbosity() > 2 )
506  std::cout << "ParticleFlowReco::process_event : EM -> HAD linking " << std::endl;
507 
508  for (unsigned int em = 0; em < _pflow_EM_E.size() ; em++ ) {
509 
510  if ( Verbosity() > 10 )
511  std::cout << " EM with E / eta / phi = " << _pflow_EM_E[ em ] << " / " << _pflow_EM_eta[ em ] << " / " << _pflow_EM_phi[ em ] << std::endl;
512 
513  // TRK -> HAD link
514  float min_had_dR = 0.2;
515  int min_had_index = -1;
516  float max_had_pt = 0;
517 
518  for (unsigned int had = 0 ; had < _pflow_HAD_E.size() ; had++) {
519 
520  float dR = calculate_dR( _pflow_EM_eta[ em ] , _pflow_HAD_eta[ had ] , _pflow_EM_phi[ em ] , _pflow_HAD_phi[ had ] );
521  if ( dR > 0.5 ) continue;
522 
523  bool has_overlap = false;
524 
525  for (unsigned int tow = 0; tow < _pflow_HAD_tower_eta.at( had ).size() ; tow++) {
526 
527  float tower_eta = _pflow_HAD_tower_eta.at( had ).at( tow );
528  float tower_phi = _pflow_HAD_tower_phi.at( had ).at( tow );
529 
530  float deta = tower_eta - _pflow_EM_eta[ em ];
531  float dphi = tower_phi - _pflow_EM_phi[ em ];
532  if ( dphi > M_PI ) dphi -= 2 * M_PI;
533  if ( dphi < -M_PI ) dphi += 2 * M_PI;
534 
535  if ( fabs( deta ) < 0.1 * 1.5 && fabs( dphi ) < 0.1 * 1.5 ) {
536  has_overlap = true;
537  break;
538  }
539 
540  }
541 
542  if ( has_overlap ) {
543 
544  if ( Verbosity() > 5 )
545  std::cout << " -> possible match to HAD " << had << " with dR = " << dR << std::endl;
546 
547  if ( _pflow_HAD_E.at( had ) > max_had_pt ) {
548  max_had_pt = _pflow_HAD_E.at( had );
549  min_had_index = had;
550  min_had_dR = dR;
551  }
552 
553  } else {
554 
555  if ( Verbosity() > 5 )
556  std::cout << " -> no match to HAD " << had << " (even though dR = " << dR << " )" << std::endl;
557 
558  }
559 
560  }
561 
562  if ( min_had_index > -1 ) {
563  _pflow_HAD_match_EM.at( min_had_index ).push_back( em );
564  _pflow_EM_match_HAD.at( em ).push_back( min_had_index );
565 
566  if ( Verbosity() > 5 )
567  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;
568 
569  } else {
570  if ( Verbosity() > 5 )
571  std::cout << " -> no HAD match! ( best dR = " << min_had_dR << " ) " << std::endl;
572  }
573 
574  }
575 
576 
577  // SEQUENTIAL MATCHING: if TRK -> EM and EM -> HAD, ensure that TRK -> HAD
578  if ( Verbosity() > 2 )
579  std::cout << "ParticleFlowReco::process_event : sequential TRK -> EM && EM -> HAD ==> TRK -> HAD matching " << std::endl;
580 
581  for (unsigned int trk = 0; trk < _pflow_TRK_p.size() ; trk++ ) {
582 
583  // go through all matched EMs
584  for (unsigned int i = 0; i < _pflow_TRK_match_EM.at( trk ).size(); i++) {
585 
586  int em = _pflow_TRK_match_EM.at( trk ).at( i );
587 
588  // if this EM has a matched HAD...
589  for (unsigned int j = 0; j < _pflow_EM_match_HAD.at( em ).size() ; j++) {
590 
591  int had = _pflow_EM_match_HAD.at( em ).at( j );
592 
593  // and the TRK is NOT matched to this HAD...
594  bool is_trk_matched_to_HAD = false;
595  for (unsigned int k = 0; k < _pflow_TRK_match_HAD.at( trk ).size(); k++) {
596  int existing_had = _pflow_TRK_match_HAD.at( trk ).at( k );
597  if ( had == existing_had ) is_trk_matched_to_HAD = true;
598  }
599 
600  // if this is the case, create TRK->HAD link
601  if ( ! is_trk_matched_to_HAD ) {
602  _pflow_TRK_match_HAD.at( trk ).push_back( had );
603  _pflow_HAD_match_TRK.at( had ).push_back( trk );
604 
605  if ( Verbosity() > 5 ) {
606  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;
607  std::cout << " -> sequential match to HAD " << had << " through EM " << j << std::endl;
608  }
609 
610  }
611 
612  } // close the HAD loop
613 
614  } // close the EM loop
615 
616  } // close the TRK loop
617 
618  // TRK->EM->HAD removal
619  if ( Verbosity() > 2 )
620  std::cout << "ParticleFlowReco::process_event : resolve TRK(s) + EM(s) -> HAD systems " << std::endl;
621 
622  for (unsigned int had = 0; had < _pflow_HAD_E.size() ; had++ ) {
623 
624  // only consider HAD with matched tracks ... others we will deal with later
625  if ( _pflow_HAD_match_TRK.at( had ).size() == 0 ) continue;
626 
627  if ( Verbosity() > 5 ) {
628  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;
629  }
630 
631  // setup for Sum-pT^trk -> calo prediction
632  float total_TRK_p = 0;
633  float total_expected_E = 0;
634  float total_expected_E_var = 0;
635 
636  // begin with this HAD calo energy
637  float total_EMHAD_E = _pflow_HAD_E.at( had );
638 
639  std::vector<RawCluster*> matchedEClusters;
640 
641  // iterate over the EMs matched to this HAD
642  for (unsigned int j = 0; j < _pflow_HAD_match_EM.at( had ).size() ; j++ ) {
643 
644  int em = _pflow_HAD_match_EM.at( had ).at( j );
645 
646  // ensure there is at least one track matched to this EM
647  if ( _pflow_EM_match_TRK.at( em ).size() == 0 ) continue;
648 
649  // add it to the total calo E
650  total_EMHAD_E += _pflow_EM_E.at( em );
651  matchedEClusters.push_back(_pflow_EM_cluster.at(em));
652  if ( Verbosity() > 5 ) {
653  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;
654  }
655 
656  }
657 
658  // iterate over the TRKs matched to this HAD
659  for (unsigned int j = 0 ; j < _pflow_HAD_match_TRK.at( had ).size() ; j++) {
660 
661  int trk = _pflow_HAD_match_TRK.at( had ).at( j );
662 
663  if ( Verbosity() > 5 ) {
664  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;
665  }
666 
667  total_TRK_p += _pflow_TRK_p.at( trk );
668 
669  std::pair<float, float> expected_signature = get_expected_signature( trk );
670 
671  float expected_E_mean = expected_signature.first;
672  float expected_E_sigma = expected_signature.second;
673 
674  if ( Verbosity() > 5 ) {
675  std::cout << " -> -> -> expected calo signature is " << expected_E_mean << " +/- " << expected_E_sigma << std::endl;
676  }
677 
678  total_expected_E += expected_E_mean;
679  total_expected_E_var += pow( expected_E_sigma , 2 );
680 
681  // add PFlow element for each track
683 
684  // assume pion mass
685  TLorentzVector tlv;
686  tlv.SetPtEtaPhiM( _pflow_TRK_p[ trk ] / cosh( _pflow_TRK_eta[ trk ] ) , _pflow_TRK_eta[ trk ] , _pflow_TRK_phi[ trk ] , 0.135 );
687 
688  pflow->set_px( tlv.Px() );
689  pflow->set_py( tlv.Py() );
690  pflow->set_pz( tlv.Pz() );
691  pflow->set_e( tlv.E() );
692  pflow->set_track(_pflow_TRK_trk[ trk ]);
693  pflow->set_eclusters(matchedEClusters);
694  pflow->set_hcluster(_pflow_HAD_cluster.at(had));
695  pflow->set_id( global_pflow_index );
696  pflow->set_type( ParticleFlowElement::PFLOWTYPE::MATCHED_CHARGED_HADRON );
697 
698  pflowContainer->AddParticleFlowElement( global_pflow_index, pflow );
699  global_pflow_index++;
700 
701  }
702  // Track + E+HCal PF elements are created
703 
704  // process compatibility of fit
705  float total_expected_E_err = sqrt( total_expected_E_var );
706 
707  if ( Verbosity() > 5 ) {
708  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;
709  }
710 
711  // if Sum pT > calo, add in additional possible matched EMs associated with tracks until that is no longer the case
712 
713  if ( total_expected_E > total_EMHAD_E ) {
714 
715  if ( Verbosity() > 5 )
716  std::cout << " -> Expected E > Observed E, looking for additional potential TRK->EM matches" << std::endl;
717 
718  std::map<int, float> additional_EMs;
719 
720  for (unsigned int j = 0 ; j < _pflow_HAD_match_TRK.at( had ).size() ; j++) {
721 
722  int trk = _pflow_HAD_match_TRK.at( had ).at( j );
723 
724  int addtl_matches = _pflow_TRK_addtl_match_EM.at( trk ).size();
725 
726  if ( Verbosity() > 10 )
727  std::cout << " -> -> TRK " << trk << " has " << addtl_matches << " additional matches! " << std::endl;
728 
729  for (unsigned int n = 0 ; n < _pflow_TRK_addtl_match_EM.at( trk ).size() ; n++ ) {
730  if ( Verbosity() > 10 )
731  std::cout << " -> -> -> additional match to EM = " << _pflow_TRK_addtl_match_EM.at( trk ).at( n ).first << " with dR = " << _pflow_TRK_addtl_match_EM.at( trk ).at( n ).second << std::endl;
732 
733  float existing_dR = 0.21;
734  int counts = additional_EMs.count( _pflow_TRK_addtl_match_EM.at( trk ).at( n ).first );
735  if ( counts > 0 ) {
736  existing_dR = additional_EMs[ _pflow_TRK_addtl_match_EM.at( trk ).at( n ).first ];
737  }
738  if ( _pflow_TRK_addtl_match_EM.at( trk ).at( n ).second < existing_dR )
739  additional_EMs[ _pflow_TRK_addtl_match_EM.at( trk ).at( n ).first ] = _pflow_TRK_addtl_match_EM.at( trk ).at( n ).second;
740  }
741 
742  }
743 
744  // map now assured to have only minimal dR values for each possible additional EM
745  // translate the map to a vector of pairs, then sort by smallest dR
746 
747  std::vector< std::pair<int,float> > additional_EMs_vec;
748 
749  for (auto& x : additional_EMs) {
750  additional_EMs_vec.push_back( std::pair<int,float>( x.first , x.second ) );
751  }
752 
753  std::sort( additional_EMs_vec.begin(), additional_EMs_vec.end(), sort_by_pair_second_lowest );
754 
755  if ( Verbosity() > 5 )
756  std::cout << " -> Sorting the set of potential additional EMs " << std::endl;
757 
758  // now add in additional EMs until there are none left or it is no longer the case that Sum pT > calo
759 
760  int n_EM_added = 0;
761  while ( additional_EMs_vec.size() != 0 && total_expected_E > total_EMHAD_E ) {
762 
763  int new_EM = additional_EMs_vec.at( 0 ).first;
764 
765  if ( Verbosity() > 5 )
766  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;
767 
768  // for now, just make the first HAD-linked track point to this new EM, and vice versa
769  _pflow_EM_match_TRK.at( new_EM ).push_back( _pflow_HAD_match_TRK.at( had ).at( 0 ) );
770  _pflow_TRK_match_EM.at( _pflow_HAD_match_TRK.at( had ).at( 0 ) ).push_back( new_EM );
771 
772  // add to expected calo
773  total_EMHAD_E += _pflow_EM_E.at( new_EM );
774 
775  // erase lowest-dR EM
776  additional_EMs_vec.erase( additional_EMs_vec.begin() );
777 
778  n_EM_added++;
779  }
780 
781  if ( Verbosity() > 5) {
782  if ( n_EM_added > 0 ) {
783  std::cout << "After adding N = " << n_EM_added << " any additional EMs : " << std::endl;
784  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;
785  }
786  else {
787  std::cout << "No additional EMs found, continuing hypothesis check" << std::endl;
788  }
789  }
790  }
791 
792 
793 
794  if ( total_expected_E + _energy_match_Nsigma * total_expected_E_err > total_EMHAD_E ) {
795 
796  if ( Verbosity() > 5 ) {
797  std::cout << " -> -> calo compatible within Nsigma = " << _energy_match_Nsigma << " , remove and keep tracks " << std::endl;
798  }
799 
800  // PFlow elements already created from tracks above, no more needs to be done
801 
802  } else {
803 
804  float residual_energy = total_EMHAD_E - total_expected_E;
805 
806  if ( Verbosity() > 5 ) {
807  std::cout << " -> -> calo not compatible, create leftover cluster with " << residual_energy << std::endl;
808  }
809 
810  // create additional PFlow element (tracks already created above)
812 
813  // assume no mass, but could update to use K0L mass(?)
814  TLorentzVector tlv; tlv.SetPtEtaPhiM( residual_energy / cosh( _pflow_HAD_eta[ had ] ) , _pflow_HAD_eta[ had ] , _pflow_HAD_phi[ had ] , 0 );
815 
816  pflow->set_px( tlv.Px() );
817  pflow->set_py( tlv.Py() );
818  pflow->set_pz( tlv.Pz() );
819  pflow->set_e( tlv.E() );
820  pflow->set_track(nullptr);
821  pflow->set_eclusters(matchedEClusters);
822  pflow->set_hcluster(_pflow_HAD_cluster.at(had));
823  pflow->set_id( global_pflow_index );
824  pflow->set_type( ParticleFlowElement::PFLOWTYPE::LEFTOVER_EM_PARTICLE );
825 
826  pflowContainer->AddParticleFlowElement( global_pflow_index, pflow );
827  global_pflow_index++;
828 
829  }
830 
831  } // close HAD loop
832 
833  // TRK->EM removal
834 
835  if ( Verbosity() > 2 )
836  std::cout << "ParticleFlowReco::process_event : resolve TRK(s) -> EM(s) ( + no HAD) systems " << std::endl;
837 
838  for (unsigned int em = 0; em < _pflow_EM_E.size() ; em++ ) {
839 
840  // only consider EM with matched tracks, but no matched HADs
841  if ( _pflow_EM_match_HAD.at( em ).size() != 0 ) continue;
842  if ( _pflow_EM_match_TRK.at( em ).size() == 0 ) continue;
843 
844  if ( Verbosity() > 5 ) {
845  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;
846  }
847 
848  // setup for Sum-pT^trk -> calo prediction
849  float total_TRK_p = 0;
850  float total_expected_E = 0;
851  float total_expected_E_var = 0;
852 
853  // begin with this EM calo energy
854  float total_EM_E = _pflow_EM_E.at( em );
855 
856  // iterate over the TRKs matched to this EM
857  for (unsigned int j = 0 ; j < _pflow_EM_match_TRK.at( em ).size() ; j++) {
858 
859  int trk = _pflow_EM_match_TRK.at( em ).at( j );
860 
861  if ( Verbosity() > 5 ) {
862  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;
863  }
864 
865  total_TRK_p += _pflow_TRK_p.at( trk );
866 
867  std::pair<float, float> expected_signature = get_expected_signature( trk );
868 
869  float expected_E_mean = expected_signature.first;
870  float expected_E_sigma = expected_signature.second;
871 
872  if ( Verbosity() > 5 ) {
873  std::cout << " -> -> -> expected calo signature is " << expected_E_mean << " +/- " << expected_E_sigma << std::endl;
874  }
875 
876  total_expected_E += expected_E_mean;
877  total_expected_E_var += pow( expected_E_sigma , 2 );
878 
879  // add PFlow element for each track
881 
882  // assume pion mass
883  TLorentzVector tlv; tlv.SetPtEtaPhiM( _pflow_TRK_p[ trk ] / cosh( _pflow_TRK_eta[ trk ] ) , _pflow_TRK_eta[ trk ] , _pflow_TRK_phi[ trk ] , 0.135 );
884 
885  std::vector<RawCluster*> eclus;
886  eclus.push_back(_pflow_EM_cluster.at(em));
887 
888  pflow->set_px( tlv.Px() );
889  pflow->set_py( tlv.Py() );
890  pflow->set_pz( tlv.Pz() );
891  pflow->set_e( tlv.E() );
892  pflow->set_track(_pflow_TRK_trk.at(trk));
893  pflow->set_eclusters(eclus);
894  pflow->set_hcluster(nullptr);
895  pflow->set_id( global_pflow_index );
896  pflow->set_type( ParticleFlowElement::PFLOWTYPE::MATCHED_CHARGED_HADRON );
897 
898  pflowContainer->AddParticleFlowElement( global_pflow_index, pflow );
899  global_pflow_index++;
900 
901  }
902 
903  // process compatibility of fit
904  float total_expected_E_err = sqrt( total_expected_E_var );
905 
906  if ( Verbosity() > 5 ) {
907  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;
908  }
909 
910  if ( total_expected_E + _energy_match_Nsigma * total_expected_E_err > total_EM_E ) {
911 
912  if ( Verbosity() > 5 ) {
913  std::cout << " -> -> calo compatible within Nsigma = " << _energy_match_Nsigma << " , remove and keep tracks " << std::endl;
914  }
915 
916  // PFlow elements already created from tracks above, no more needs to be done
917 
918  } else {
919 
920  float residual_energy = total_EM_E - total_expected_E;
921 
922  if ( Verbosity() > 5 ) {
923  std::cout << " -> -> calo not compatible, create leftover cluster with " << residual_energy << std::endl;
924  }
925 
926  // create additional PFlow element (tracks already created above)
928 
929  // assume no mass, but could update to use K0L mass(?)
930  TLorentzVector tlv; tlv.SetPtEtaPhiM( residual_energy / cosh( _pflow_EM_eta[ em ] ) , _pflow_EM_eta[ em ] , _pflow_EM_phi[ em ] , 0 );
931 
932  std::vector<RawCluster*> eclus;
933  eclus.push_back(_pflow_EM_cluster.at(em));
934 
935  pflow->set_px( tlv.Px() );
936  pflow->set_py( tlv.Py() );
937  pflow->set_pz( tlv.Pz() );
938  pflow->set_e( tlv.E() );
939  pflow->set_eclusters(eclus);
940  pflow->set_hcluster(nullptr);
941  pflow->set_track(nullptr);
942  pflow->set_id( global_pflow_index );
943  pflow->set_type( ParticleFlowElement::PFLOWTYPE::LEFTOVER_EM_PARTICLE );
944 
945  pflowContainer->AddParticleFlowElement( global_pflow_index, pflow );
946  global_pflow_index++;
947 
948  }
949 
950  } // close EM loop
951 
952  // now remove unmatched elements
953 
954  if ( Verbosity() > 2 )
955  std::cout << "ParticleFlowReco::process_event : remove TRK-unlinked EMs and HADs " << std::endl;
956 
957  for (unsigned int em = 0; em < _pflow_EM_E.size() ; em++ ) {
958 
959  // only consider EMs withOUT matched tracks ... we have dealt with the matched cases above
960  if ( _pflow_EM_match_TRK.at( em ).size() != 0 ) continue;
961 
962  if ( Verbosity() > 5 ) {
963  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;
964  }
965 
966  // add PFlow element for this EM
968 
969  // assume massless, could be updated to use K0L
970  TLorentzVector tlv; tlv.SetPtEtaPhiM( _pflow_EM_E[ em ] / cosh( _pflow_EM_eta[ em ] ) , _pflow_EM_eta[ em ] , _pflow_EM_phi[ em ] , 0 );
971 
972  std::vector<RawCluster*> eclus;
973  eclus.push_back(_pflow_EM_cluster.at(em));
974 
975  pflow->set_px( tlv.Px() );
976  pflow->set_py( tlv.Py() );
977  pflow->set_pz( tlv.Pz() );
978  pflow->set_e( tlv.E() );
979  pflow->set_eclusters(eclus);
980  pflow->set_hcluster(nullptr);
981  pflow->set_track(nullptr);
982  pflow->set_id( global_pflow_index );
983  pflow->set_type( ParticleFlowElement::PFLOWTYPE::UNMATCHED_EM_PARTICLE );
984 
985  pflowContainer->AddParticleFlowElement( global_pflow_index, pflow );
986  global_pflow_index++;
987 
988 
989  } // close EM loop
990 
991  for (unsigned int had = 0; had < _pflow_HAD_E.size() ; had++ ) {
992 
993  // only consider HADs withOUT matched tracks ... we have dealt with the matched cases above
994  if ( _pflow_HAD_match_TRK.at( had ).size() != 0 ) continue;
995 
996  if ( Verbosity() > 5 ) {
997  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;
998  }
999 
1000  // add PFlow element for this HAD
1002 
1003  // assume massless, could be updated to use K0L
1004  TLorentzVector tlv; tlv.SetPtEtaPhiM( _pflow_HAD_E[ had ] / cosh( _pflow_HAD_eta[ had ] ) , _pflow_HAD_eta[ had ] , _pflow_HAD_phi[ had ] , 0 );
1005 
1006  pflow->set_px( tlv.Px() );
1007  pflow->set_py( tlv.Py() );
1008  pflow->set_pz( tlv.Pz() );
1009  pflow->set_e( tlv.E() );
1010  pflow->set_track(nullptr);
1011  pflow->set_eclusters(std::vector<RawCluster*>());
1012  pflow->set_hcluster(_pflow_HAD_cluster.at(had));
1013  pflow->set_id( global_pflow_index );
1014  pflow->set_type( ParticleFlowElement::PFLOWTYPE::UNMATCHED_NEUTRAL_HADRON );
1015 
1016  pflowContainer->AddParticleFlowElement( global_pflow_index, pflow );
1017  global_pflow_index++;
1018 
1019 
1020  } // close HAD loop
1021 
1022  for (unsigned int trk = 0; trk < _pflow_TRK_p.size() ; trk++ ) {
1023 
1024  // only consider TRKs withOUT matched EM or HAD
1025  if ( _pflow_TRK_match_EM.at( trk ).size() != 0 || _pflow_TRK_match_HAD.at( trk ).size() != 0 ) continue;
1026 
1027  if ( Verbosity() > 5 ) {
1028  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;
1029  }
1030 
1031  // add PFlow element for this TRK
1033 
1034  // assume massless, could be updated to use K0L
1035  TLorentzVector tlv; tlv.SetPtEtaPhiM( _pflow_TRK_p[ trk ] / cosh( _pflow_TRK_eta[ trk ] ) , _pflow_TRK_eta[ trk ] , _pflow_TRK_phi[ trk ] , 0.135 );
1036 
1037  pflow->set_px( tlv.Px() );
1038  pflow->set_py( tlv.Py() );
1039  pflow->set_pz( tlv.Pz() );
1040  pflow->set_e( tlv.E() );
1041  pflow->set_track(_pflow_TRK_trk.at(trk));
1042  pflow->set_eclusters(std::vector<RawCluster*>());
1043  pflow->set_hcluster(nullptr);
1044  pflow->set_id( global_pflow_index );
1045  pflow->set_type( ParticleFlowElement::PFLOWTYPE::UNMATCHED_CHARGED_HADRON );
1046 
1047  pflowContainer->AddParticleFlowElement( global_pflow_index, pflow );
1048  global_pflow_index++;
1049 
1050  } // close TRK loop
1051 
1052  // DEBUG: print out all PFLow elements
1053  if ( Verbosity() > 5 ) {
1054  std::cout << "ParticleFlowReco::process_event: summary of PFlow objects " << std::endl;
1055 
1057  for ( ParticleFlowElementContainer::ConstIterator hiter = begin_end.first; hiter != begin_end.second; ++hiter) {
1058  hiter->second->identify();
1059  }
1060 
1061  }
1062 
1064 }
1065 
1067 {
1068  PHNodeIterator iter(topNode);
1069 
1070  // Looking for the DST node
1071  PHCompositeNode *dstNode = dynamic_cast<PHCompositeNode *>(iter.findFirst("PHCompositeNode", "DST"));
1072  if (!dstNode)
1073  {
1074  std::cout << PHWHERE << "DST Node missing, doing nothing." << std::endl;
1076  }
1077 
1078  // store the PFlow elements under a sub-node directory
1079  PHCompositeNode *pflowNode = dynamic_cast<PHCompositeNode *>(iter.findFirst("PHCompositeNode", "PARTICLEFLOW"));
1080  if (!pflowNode)
1081  {
1082  pflowNode = new PHCompositeNode("PARTICLEFLOW");
1083  dstNode->addNode( pflowNode );
1084  }
1085 
1086  // create the ParticleFlowElementContainer node...
1087  ParticleFlowElementContainer *pflowElementContainer = findNode::getClass<ParticleFlowElementContainer>(topNode, "ParticleFlowElements");
1088  if (!pflowElementContainer)
1089  {
1090  pflowElementContainer = new ParticleFlowElementContainer();
1091  PHIODataNode<PHObject> *pflowElementNode = new PHIODataNode<PHObject>(pflowElementContainer, "ParticleFlowElements", "PHObject");
1092  pflowNode->addNode( pflowElementNode );
1093  }
1094  else
1095  {
1096  std::cout << PHWHERE << "::ERROR - ParticleFlowElements node alerady exists, but should not" << std::endl;
1097  exit(-1);
1098  }
1099 
1101 }
1102 
1103 //____________________________________________________________________________..
1105 {
1106  if (Verbosity() > 0)
1107  {
1108  std::cout << "ParticleFlowReco::ResetEvent(PHCompositeNode *topNode) Resetting internal structures, prepare for next event" << std::endl;
1109  }
1111 }
1112 
1113 //____________________________________________________________________________..
1115 {
1116  if (Verbosity() > 0)
1117  {
1118  std::cout << "ParticleFlowReco::EndRun(const int runnumber) Ending Run for Run " << runnumber << std::endl;
1119  }
1121 }
1122 
1123 //____________________________________________________________________________..
1125 {
1126  if (Verbosity() > 0)
1127  {
1128  std::cout << "ParticleFlowReco::End(PHCompositeNode *topNode) This is the End..." << std::endl;
1129  }
1131 }
1132 
1133 //____________________________________________________________________________..
1135 {
1136  if (Verbosity() > 0)
1137  {
1138  std::cout << "ParticleFlowReco::Reset(PHCompositeNode *topNode) being Reset" << std::endl;
1139  }
1141 }
1142 
1143 //____________________________________________________________________________..
1144 void ParticleFlowReco::Print(const std::string &what) const
1145 {
1146  std::cout << "ParticleFlowReco::Print(const std::string &what) const Printing info for " << what << std::endl;
1147 }