All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups
GammaGammaSolutionFinder.cc
Go to the documentation of this file.
1 #include "EVENT/LCIO.h"
2 #include "EVENT/LCRunHeader.h"
3 #include "EVENT/LCCollection.h"
4 #include "EVENT/LCParameters.h"
5 #include "EVENT/ReconstructedParticle.h"
6 #include "IMPL/ReconstructedParticleImpl.h"
8 #include "CLHEP/Vector/LorentzVector.h"
9 #include "CLHEP/Vector/ThreeVector.h"
10 
11 typedef CLHEP::HepLorentzVector LorentzVector ;
12 typedef CLHEP::Hep3Vector Vector3D ;
13 
14 // Marlin stuff
15 #include <marlin/Global.h>
16 // the event display
17 
18 // ROOT stuff
19 #include "TMath.h"
20 #include "TMatrixD.h"
21 
22 #include <cstdlib>
23 
24 using namespace lcio;
25 
27 
28 GammaGammaSolutionFinder::GammaGammaSolutionFinder() : marlin::Processor("GammaGammaSolutionFinder") {
29 
30  registerProcessorParameter( "Printing" ,
31  "Print certain messages" ,
32  _printing,
33  (int)1 ) ;
34 
35  std::vector<std::string> gammagammaCandidateCollections;
36  gammagammaCandidateCollections.push_back(std::string("GammaGammaCandidatePi0s"));
37  gammagammaCandidateCollections.push_back(std::string("GammaGammaCandidateEtas"));
38  gammagammaCandidateCollections.push_back(std::string("GammaGammaCandidateEtaPrimes"));
39  registerInputCollections( LCIO::RECONSTRUCTEDPARTICLE,
40  "GammaGammaCandidateCollections" ,
41  "Gamma-Gamma Candidate Collection Names" ,
43  gammagammaCandidateCollections);
44 
45  std::string outputParticleCollectionName = "GammaGammaSolutions";
46  registerOutputCollection( LCIO::RECONSTRUCTEDPARTICLE,
47  "OutputParticleCollectionName" ,
48  "Output Particle Collection Name " ,
50  outputParticleCollectionName);
51 
52  registerProcessorParameter( "MaxCombinationsCut" ,
53  "Maximum Number of Explorable Combinations" ,
55  (double)100000000.0) ;
56 
57  registerProcessorParameter( "LessThanMaximalCut" ,
58  "Maximum Number of Fewer GammaGammaParticles" ,
59  _nToRemove,
60  (int)0) ; // (set to huge number - like 999 if want to explore all)
61 
62  registerProcessorParameter( "SolutionFindingAlgorithm" ,
63  "Solution Finding Algorithm" ,
64  _algorithm,
65  (int)2) ;
66 
67  return;
68 
69 }
70 
71 //===================================================================================
72 
74  if(_printing>1)printParameters();
75  return;
76 }
77 
78 //===================================================================================
79 
80 void GammaGammaSolutionFinder::processRunHeader( LCRunHeader* /*run*/) {
81  return;
82 }
83 
84 //===================================================================================
85 
87 
88  // Make a new vector of particles
89  LCCollectionVec * recparcol = new LCCollectionVec(LCIO::RECONSTRUCTEDPARTICLE);
90  recparcol->setSubset(true);
91 
92  // Access PFO collection
93  bool found = this->FindPFOs(evt);
94  if(found){
95  if(_printing>1)std::cout << "Find GammaGamma Solution: " << std::endl;
96  unsigned int nphotons=this->CountIndependentPhotons();
97  unsigned int nedges=_pfovec.size();
98 
99  if(_printing>1)std::cout << "nphotons = " << nphotons << " nedges = " << nedges << std::endl;
100  unsigned long int nCr = this->CombinatorialFactor(nedges,nphotons/2);
101  if(_printing>1)std::cout << "Naive combinatorial factor of " << std::setw(22) << nCr << std::endl;
102 
103  if(_algorithm == 1 ){
104 // Greedy algorithm
105  this->FindGammaGammaSolutionZero(recparcol);
106  }
107  else if(_algorithm == 2){
108  if(double(nCr) < _maxCombinationsCut){
109  if(_printing>1)std::cout << " Pursuing full combinatoric exploration " << std::endl;
110  this->FindGammaGammaSolutions(recparcol);
111  }
112  else{
113  if(_printing>1)std::cout << " Too many combinations - assigning quick greedy solution " << std::endl;
114  this->FindGammaGammaSolutionZero(recparcol);
115  }
116  }
117  else{
118  std::cout << "Unsupported solution finding algorithm " << _algorithm << std::endl;
119  }
120  }
121 
122  // Add new collection to event
123  evt->addCollection( recparcol , _outputParticleCollectionName.c_str() );
124 
125  return;
126 
127 }
128 
129 //===================================================================================
130 
132  return;
133 }
134 
135 unsigned long int GammaGammaSolutionFinder::CombinatorialFactor(int n, int k )
136 {
137  if (k > n) return 0;
138  if (k * 2 > n) k = n-k;
139  if (k == 0) return 1;
140 
141  unsigned long int result = n;
142  for( int i = 2; i <= k; ++i ) {
143  result *= (n-i+1);
144  result /= i;
145  }
146  return result;
147 }
148 
149 //===================================================================================
150 
151 void GammaGammaSolutionFinder::FindCombinations(std::vector<std::vector<int> > array, unsigned int i, std::vector<int> accum)
152 {
153  if (i == array.size()) // done, no more rows
154  {
155  comb.push_back(accum); // assuming comb is global
156  }
157  else
158  {
159  std::vector<int> row = array[i]; // NB Each row of array may have a different length
160  for(unsigned int j = 0; j < row.size(); ++j)
161  {
162  std::vector<int> tmp(accum);
163  tmp.push_back(row[j]);
164  FindCombinations(array,i+1,tmp);
165  }
166  }
167 }
168 
169 
171 
172 // Add all 3 GammaGammaCandidate collections to the PFO vector (pi0s , etas, eta's)
173 
174  bool tf = false;
175 
176  // clear old vector
177  _pfovec.clear();
178  typedef const std::vector<std::string> StringVec ;
179  StringVec* strVec = evt->getCollectionNames() ;
180 
181 
182 // All GammaGammaCandidates
183  for(StringVec::const_iterator name=strVec->begin(); name!=strVec->end(); name++){
184  for (unsigned int j=0; j < _gammagammaCandidateCollections.size(); ++j) {
185  if(*name==_gammagammaCandidateCollections[j]){
186  LCCollection* col = evt->getCollection(*name);
187  unsigned int nelem = col->getNumberOfElements();
188  tf = true;
189  for(unsigned int i=0;i<nelem;i++){
190  ReconstructedParticle* recoPart = dynamic_cast<ReconstructedParticle*>(col->getElementAt(i));
191  _pfovec.push_back(recoPart);
192  }
193  }
194  }
195  }
196 
197  if(_printing>1)std::cout << "FindPFOs : (nPFOs = " << _pfovec.size() << " )" << std::endl;
198 
199  if(_printing>1)std::cout << "Find PFOs : " << tf << std::endl;
200 
201  return tf;
202 
203 }
204 
205 // ===================================================================================
206 // Initial Greedy Algorithm
208 
209  if(_printing>1)std::cout << "FindGammaGammaSolutionZero : (nPFOs = " << _pfovec.size() << " )" << std::endl;
210 
211  typedef std::set<const ReconstructedParticle*> PfoSet;
212  PfoSet particles_assigned; // Set with pointers to the daughter particles (photons for now) that are already used in the solution
213 
214  // For convenience sort the GammaGammaCandidates by fit probability
216 
217  // Algorithm 1. Based on fit probability ordering, add GammaGammaCandidates to the output GammaGammaParticles collection
218  // if they do not contain already assigned constituent particles. For now, the constituents are always two photons
219  // - but may not hurt to keep this generic for when other decay modes (eg. Dalitz decay) are included
220  for(unsigned int i = 0; i < _pfovec.size(); i++){
221  const ReconstructedParticleVec particles = _pfovec[i]->getParticles();
222  if(_printing>3)std::cout << "FindGammaGammaSolutionZero: (nparticles = " << particles.size() << " )" << std::endl;
223  bool assignable = true;
224  for(unsigned int j = 0; j < particles.size(); j++){ // TODO - maybe double check these are indeed photons ..
225  const ReconstructedParticle *particle = particles[j];
226  if( particles_assigned.find(particle) != particles_assigned.end() )assignable = false; // If particle is already assigned then it is not still assignable
227  }
228  if(assignable){
229  recparcol->addElement(_pfovec[i]); // Add meson to the output collection if all constituent particles are still assignable
230  for(unsigned int j = 0; j < particles.size(); j++){
231  const ReconstructedParticle *particle = particles[j];
232  particles_assigned.insert(particle); // Update set of particles already assigned in this solution
233  }
234  }
235  }
236  return;
237 }
238 
239 // ===================================================================================
240 // Count how many independent daughter photons are available in the GammaGammaParticle collections
242 
243  if(_printing>1)std::cout << "Count Independent Photons : (nPFOs = " << _pfovec.size() << " )" << std::endl;
244 
245  typedef std::set<const ReconstructedParticle*> PfoSet;
246  PfoSet daughter_particles; // Set with all the daughter particles
247 
248  // For convenience sort the GammaGammaCandidates by fit probability
250 
251  int k=-1;
252 
253  for(unsigned int i = 0; i < _pfovec.size(); i++){
254  const ReconstructedParticleVec particles = _pfovec[i]->getParticles();
255 // if(_printing>3)std::cout << "FindGammaGammaSolutions: (nparticles = " << particles.size() << " )" << std::endl;
256  for(unsigned int j = 0; j < particles.size(); j++){ // TODO - maybe double check these are indeed photons ..
257  const ReconstructedParticle *particle = particles[j];
258 // GWW DEBUG
259 // std::cout << "GWWWW " << i << " " << j << " " << particle << std::endl;
260  if( daughter_particles.find(particle) == daughter_particles.end() ){
261  daughter_particles.insert(particle); // Add particle to the set
262  k++; // Increment photon index
263  //std::cout << i << " " << k << std::endl;
264  }
265  }
266  }
267 
268  if(_printing>1)std::cout << "Number of independent photons available = " << daughter_particles.size() << std::endl;
269 
270  unsigned int nphotons = daughter_particles.size();
271 
272  return nphotons;
273 }
274 
275 //===================================================================================
276 
278 
279  struct timeval tv;
280  gettimeofday(&tv,NULL);
281  double t0 = tv.tv_sec+(tv.tv_usec/1000000.0);
282 
283  std::vector<MyEdge> evec; // Vector of edges available
284  evec.reserve(NEMAX*25);
285  std::vector<CandidateSolution> svec; // Vector with candidate solutions
286  svec.reserve(1000);
287  std::vector<FirstVertex> fvec; // Vector with first vertices
288  fvec.reserve(NVMAX*25);
289  int u=-1;
290  int v=-1;
291  double edge_chisq;
292 // TODO Add some checks that the bitsets are big enough ...
293  std::bitset<NVMAX> vbits;
294  std::bitset<NVMAX> ored_vbits;
295  std::bitset<NEMAX> ebits;
296  std::bitset<NEMAX> febits;
297  unsigned long int nCr;
298  unsigned long int nCr2;
299 
300  if(_printing>1)std::cout << "FindGammaGammaSolutions : (nPFOs = " << _pfovec.size() << " )" << std::endl;
301 
302  typedef std::set<const ReconstructedParticle*> PfoSet;
303  PfoSet daughter_particles; // Set with all the daughter particles
304  PfoSet particles_assigned; // Set with pointers to the daughter particles (photons for now) that are already used in the solution
305 
306  // For convenience sort the GammaGammaCandidates by fit probability
308 
309  // First pass through - keep track of the photons involved - add each photon once to the daughter_particles set
310  int k = -1;
311 
312  for(unsigned int i = 0; i < _pfovec.size(); i++){
313  const ReconstructedParticleVec particles = _pfovec[i]->getParticles();
314  if(_printing>3)std::cout << "FindGammaGammaSolutions: (nparticles = " << particles.size() << " )" << std::endl;
315  for(unsigned int j = 0; j < particles.size(); j++){ // TODO - maybe double check these are indeed photons ..
316  const ReconstructedParticle *particle = particles[j];
317 // GWW DEBUG
318  if(_printing>7)std::cout << "GWWWW " << i << " " << j << " " << particle << std::endl;
319  if( daughter_particles.find(particle) == daughter_particles.end() ){
320  daughter_particles.insert(particle); // Add particle to the set
321  k++; // Increment photon index
322  if(_printing>3)std::cout << "New photon " << particle << " " << k << std::endl;
323  }
324  }
325  }
326 
327  // See what we have in the set
328  // (Note that since these are pointers they are by default ordered by their address in memory).
329  if(_printing>3)std::cout << "Set size " << daughter_particles.size() << std::endl;
330  for(std::set<const ReconstructedParticle*>::iterator it=daughter_particles.begin(); it!=daughter_particles.end(); ++it){
331  if(_printing>3)std::cout << *it << std::endl;
332  }
333 
334 // At this point we basically know the number of photons and GammaGammaCandidates
335 
336  if(_printing>5)std::cout << "Graph definition file information Dry-Run" << std::endl;
337  if(_printing>5)std::cout << std::setw(4) << daughter_particles.size() << std::setw(4) << _pfovec.size() << std::endl;
338  std::set<const ReconstructedParticle*>::iterator it;
339  std::pair<std::set<const ReconstructedParticle*>::iterator,bool> retcode;
340 
341 // Second pass through. This time each photon should already be in the set.
342  for(unsigned int i = 0; i < _pfovec.size(); i++){
343  const ReconstructedParticleVec particles = _pfovec[i]->getParticles();
344  if(_printing>5)std::cout << "GammaGammaCandidate " << std::setw(4) << i << std::endl;
345  for(unsigned int j = 0; j < particles.size(); j++){ // TODO - maybe double check these are indeed photons ..
346  const ReconstructedParticle *particle = particles[j];
347 
348  retcode = daughter_particles.insert(particle); // insert should fail as all photons should already be in the set
349  if (retcode.second) {
350  if(_printing>5)std::cout << particle << " inserted as element ";
351  }
352  else {
353  if(_printing>5)std::cout << particle << " already exists as element ";
354  }
355  if(_printing>5)std::cout << std::distance(daughter_particles.begin(),retcode.first) << std::endl;
356  }
357  }
358 // Code here is designed to both write out a version of the problem that can be analyzed stand-alone
359 // and to construct the information needed for defining the graph problem.
360 
361  if(_printing>6)std::cout << "GRAPH definition file information" << std::endl;
362  int nvertices = daughter_particles.size();
363  int nedges = _pfovec.size();
364  typedef adjacency_list<vecS, vecS, undirectedS> my_graph;
365  my_graph g(nvertices);
366  int vertex_degree[NVMAX];
367  for (int i = 0; i < NVMAX; ++i) {
368  vertex_degree[i] = 0;
369  }
370  if(_printing>6)std::cout << std::setw(4) << daughter_particles.size() << std::setw(4) << _pfovec.size() << std::endl;
371 // Third pass through with more terse information suitable for further analysis
372  for(unsigned int i = 0; i < _pfovec.size(); i++){
373  const ReconstructedParticleVec particles = _pfovec[i]->getParticles();
374  if(_printing>6)std::cout << std::setw(4) << i;
375  for(unsigned int j = 0; j < particles.size(); j++){ // TODO - maybe double check these are indeed photons ..
376  const ReconstructedParticle *particle = particles[j];
377  retcode = daughter_particles.insert(particle); // insert should fail as all photons should already be in the set
378  if(_printing>6)std::cout << " " << std::setw(4) << std::distance(daughter_particles.begin(),retcode.first) ;
379  if(j==0)u = std::distance(daughter_particles.begin(),retcode.first);
380  if(j!=0)v = std::distance(daughter_particles.begin(),retcode.first);
381  }
382  const int particleType = _pfovec[i]->getType();
383  // GoodnessOfPID currently filled with fit probability
384  // - may at some point be more convenient to fill with the fit chi-squared ...
385  const float GoodnessOfPID = _pfovec[i]->getGoodnessOfPID();
386  if(_printing>6)std::cout << " " << std::setw(4) << particleType << " " <<
387  std::fixed << std::setw(10) << std::setprecision(6) << GoodnessOfPID << std::endl;
388 
389  evec.push_back(MyEdge());
390  evec[i].u = std::min(u,v);
391  evec[i].v = std::max(u,v);
392  evec[i].pdgid = particleType;
393  evec[i].edge_pvalue = double(GoodnessOfPID);
394  edge_chisq = gsl_cdf_chisq_Qinv(double(GoodnessOfPID), 1.0);
395  evec[i].edge_chisq = edge_chisq;
396  evec[i].w = edge_chisq;
397  vbits = 0; // Initialize all bits in the bitset to 0
398  vbits.flip(u); // Set appropriate bit in the bitset for vertex u
399  vbits.flip(v); // Set appropriate bit in the bitset for vertex v
400  evec[i].vbits = vbits;
401  vertex_degree[u] = vertex_degree[u]+1;
402  vertex_degree[v] = vertex_degree[v]+1;
403 // BGL graph
404  add_edge(std::min(u,v),std::max(u,v),g);
405  }
406 
407 // Lots of print-out specifying the problem
408 
409  if(_printing>6)std::cout << " " << std::endl;
410  if(_printing>6)std::cout << "Edge summary " << std::endl;
411  for (int i = 0; i < nedges; ++i) {
412  if(_printing>6)std::cout << std::setw(3) << i << " " << evec[i].vbits << " "
413  << std::setw(2) << evec[i].u << " " << std::setw(2) << evec[i].v << std::endl;
414  }
415  if(_printing>6)std::cout << " " << std::endl;
416  if(_printing>6)std::cout << "Vertex degrees " << std::endl;
417  int vdsum = 0;
418  for (int i = 0; i < nvertices; ++i){
419  if(_printing>6)std::cout << std::setw(3) << i << " " << std::setw(3) << vertex_degree[i] << std::endl;
420  vdsum += vertex_degree[i];
421  }
422  if(_printing>6)std::cout << "vdsum = " << vdsum << std::endl;
423 
424  if(_printing>6)std::cout << "Vertex - Vertex partnerships" << std::endl;
425  for(int iv =0; iv < nvertices; ++iv){
426  if(_printing>6)std::cout << "Vertex " << std::setw(2) << iv << ": " ;
427  for (int je = 0; je < nedges; ++je) {
428  if(evec[je].u == iv){
429  if(_printing>6)std::cout << std::setw(2) << evec[je].v << " ";
430  }
431  }
432  if(_printing>6)std::cout << std::endl;
433  }
434 
435  if(_printing>6)std::cout << "Vertex - Edge partnerships" << std::endl;
436  for(int iv =0; iv < nvertices; ++iv){
437  if(_printing>6)std::cout << "Vertex " << std::setw(2) << iv << ": " ;
438  febits = 0;
439  int nfvedges = 0;
440  for (int je = 0; je < nedges; ++je) {
441  if(evec[je].u == iv){
442  if(_printing>6)std::cout << std::setw(2) << je << " ";
443  nfvedges ++;
444  febits.flip(je); // Set appropriate bit in the bitset for this first vertex u
445  }
446  }
447  if(nfvedges>0){
448  fvec.push_back(FirstVertex());
449  fvec.back().ivertex = iv;
450  fvec.back().nedges = nfvedges;
451  fvec.back().febits = febits;
452  std::list<int> fvelist;
453  for (int je = 0; je < nedges; ++je) {
454  int nfound = 0;
455  if(febits.test(je)){
456  fvelist.push_back(je);
457  nfound++;
458  if(nfound==1)fvec.back().fedge = je;
459  }
460  }
461  fvec.back().fvelist = fvelist;
462  }
463  if(_printing>6)std::cout << std::endl;
464  }
465  if(_printing>6)std::cout << " " << std::endl;
466  if(_printing>6)std::cout << "Check FirstVertex structure" << std::endl;
467  if(_printing>6)std::cout << std::setw(2) << fvec.size() << " FirstVertices out of "
468  << std::setw(2) << nvertices << " vertices in total" << std::endl;
469  if(_printing>6)std::cout << " i iv ne febits Edges" << std::endl;
470 
471  int nfirst_vertices = 0;
472  for(unsigned int i = 0; i < fvec.size(); ++i) {
473  nfirst_vertices++;
474  if(_printing>6)std::cout << std::setw(2) << i << " " << std::setw(2) << fvec[i].ivertex << " "
475  << std::setw(2) << fvec[i].nedges << " " << fvec[i].febits << " { ";
476  for (std::list<int>::iterator it=fvec[i].fvelist.begin(); it!=fvec[i].fvelist.end(); ++it){
477  if(_printing>6)std::cout << std::setw(2) << *it << " ";
478  }
479  if(_printing>6)std::cout << "}" << std::endl;
480  }
481  if(_printing>6)std::cout << "nfirst_vertices = "<<nfirst_vertices << std::endl;
482 
483 // Graph analysis by boost
484  std::vector<graph_traits<my_graph>::vertex_descriptor> mate(nvertices);
485  // find the maximum cardinality matching. we'll use a checked version
486  // of the algorithm, which takes a little longer than the unchecked
487  // version, but has the advantage that it will return "false" if the
488  // matching returned is not actually a maximum cardinality matching
489  // in the graph.
490  bool success = checked_edmonds_maximum_cardinality_matching(g, &mate[0]);
491  assert(success);
492  if(_printing>6)std::cout << std::endl << "Found a matching of size " << matching_size(g, &mate[0]) << std::endl;
493  if(_printing>6)std::cout << "The matching is:" << std::endl;
494  graph_traits<my_graph>::vertex_iterator vi, vi_end;
495  for(boost::tie(vi,vi_end) = vertices(g); vi != vi_end; ++vi)
496  if (mate[*vi] != graph_traits<my_graph>::null_vertex() && *vi < mate[*vi])
497  if(_printing>6)std::cout << "{" << *vi << ", " << mate[*vi] << "}" << std::endl;
498  if(_printing>6)std::cout << std::endl;
499 // Probably wouldn't hurt to check that this is a matching ......
500 
501  int n = nfirst_vertices; // n: Number of edges to choose from.
502  int nmatch = 0;
503  const unsigned int rmax = matching_size(g, &mate[0]);
504  if(_printing>2)std::cout << "Setting rmax to " << rmax << std::endl;
505 
506  int rminA = 1;
507  int rminB = rmax - _nToRemove;
508  int rminC;
509  rminC = rminA;
510  if(rminB>rminA)rminC = rminB;
511  const unsigned int rmin = rminC;
512 
513 // const int rmin = std::max(1,rmax - _nToRemove);
514  if(_printing>2)std::cout << "Setting rmin to " << rmin << std::endl;
515 
516  gettimeofday(&tv,NULL);
517  double t1 = tv.tv_sec+(tv.tv_usec/1000000.0);
518  double t2 = 0.0;
519  if(_printing>3)std::cout << "Initialization took " << std::fixed << std::setw(12) << std::setprecision(6) << t1-t0 << " (s) " << std::endl;
520 
521 // Now the initial combination finding is with respect to first-vertex edges.
522  for (unsigned int r=rmax; r>=rmin; --r){ // Try various size matchings
523 
524  if(_printing>2)std::cout << "subsidiary matching problem: find " << r << " edges from the set of size " << n << " with no overlaps " << std::endl;
525  nCr = this->CombinatorialFactor(nedges,r); // Choose r edges from nedges
526  nCr2 = this->CombinatorialFactor(n,r); // Choose r first-vertices
527  if(_printing>2)std::cout << "combination counting ... nfv = " << n << " r = " << std::setw(2) << r
528  << " nCr = " << std::setw(22) << nCr << " nCr (fv) = " << std::setw(22) << nCr2 << std::endl;
529  if(_printing>2)std::cout << std::endl;
530  int nmatch_withr = 0;
531 
532  unsigned long int icombi=0;
533 
534 // Check each combination with r edges. Use nextpermutation method from StackOverflow for generating combinations
535  std::vector<bool> vb(n);
536  std::vector<int> d; // Vector to store integers denoting the first vertices in the potential match
537  std::fill(vb.begin() + r, vb.end(), true); // fill elements vb[r] .... vb[n-1] with true -- other elements should be false
538  do {
539  for (int i = 0; i < n; ++i) {
540  if (!vb[i]) {
541  d.push_back(i); // Keep track of the indices in vector d where the bool is false
542  }
543  }
544 
545 // Probably best to create a vector of vectors with all the combinations of edges associated with each first vertex, and loop through those.
546 // http://stackoverflow.com/questions/8620030/generate-all-combination-of-elements-in-2d-vector may be helpful
547 
548  std::vector<int> c; // Vector to store integers denoting the edges in the potential match
549  c.reserve(NEMAX);
550 
551 // Form array with edge possibilities when nedges > 1
552  std::vector< std::vector<int> > array;
553  int nfilled = 0;
554  for(unsigned int i=0; i<r; ++i) {
555 // std::cout << " First vertex " << i << ": ";
556  std::vector<int> tmp;
557  if(fvec[d[i]].nedges>1){ // Only do this for those first vertices with more than one edge
558 // Iterate over the elements of the list associated with first vertex d[i]
559  for (std::list<int>::iterator it=fvec[d[i]].fvelist.begin(); it!=fvec[d[i]].fvelist.end(); ++it){
560 // std::cout << std::setw(2) << *it << " ";
561  tmp.push_back(*it);
562  }
563 // std::cout << std::endl;
564  array.push_back(tmp);
565  }
566  else{
567  c.push_back(fvec[d[i]].fedge); // Should be OK at front of vector ??
568  nfilled++;
569  }
570  }
571 
572  // Generate all combinations consisting of 1 element from each row
573  std::vector<int> accum; // empty on input
574  if(!comb.empty())comb.clear(); // Need to also clear the output array - otherwise it just keeps accumulating.
575  this->FindCombinations(array,0,accum); // recursive algorithm - start with 0
576  for ( std::vector<std::vector<int> >::size_type i = 0; i < comb.size(); ++i )
577  {
578  icombi++;
579 // if(icombi%1000000==0)std::cout << "C " << std::setw(16) << icombi << std::endl;
580  if(c.size()==r && comb[i].size()>0){
581  c.erase(c.begin()+nfilled,c.end()); // Remove the entries at the end.
582  }
583  for ( std::vector<int>::size_type j = 0; j < comb[i].size(); ++j )
584  {
585  c.push_back(comb[i][j]); // May need to be more careful about potential reallocation
586  }
587 
588 // Check to see how many vertices are used in this edge set
589  ored_vbits = evec[c[0]].vbits;
590  for (unsigned int i=1; i<r; ++i){
591  ored_vbits = (ored_vbits | evec[c[i]].vbits);
592  if(ored_vbits.count()!=2*(i+1))break;
593  }
594  size_t nused = ored_vbits.count();
595 
596 
597  if(nused==2*r){ // Number of vertices used equals twice the number of requested edges ( = MATCH )
598 
599  ebits = 0; // Initialize all bits in the bitset to 0
600 
601  double wsum = 0.0;
602  int npi0 = 0;
603  int neta = 0;
604  int netap = 0;
605  for (unsigned int i=0; i<r; ++i){
606 /* std::cout << "Assigned edge details" << std::endl;
607  std::cout << std::setw(2) << c[i] << " " << evec[c[i]].vbits << " " << std::setw(2) << evec[c[i]].u << " "
608  << std::setw(2) << evec[c[i]].v << " " << evec[c[i]].pdgid
609  << std::fixed << std::setw(10) << std::setprecision(5) << evec[c[i]].w << " "
610  << std::fixed << std::setw(10) << std::setprecision(6) << evec[c[i]].edge_pvalue << std::endl; */
611  ebits.flip(c[i]); // Set appropriate bit in the bitset for edge c[i]
612  wsum += evec[c[i]].w;
613  if(evec[c[i]].pdgid==111)npi0++;
614  if(evec[c[i]].pdgid==221)neta++;
615  if(evec[c[i]].pdgid==331)netap++;
616  }
617 // Store the CandidateSolution for later perusal
618  svec.push_back(CandidateSolution());
619  svec.back().ne = r;
620  svec.back().nv = nused;
621  svec.back().wsum = wsum;
622  svec.back().ebits = ebits;
623  svec.back().npi0 = npi0;
624  svec.back().neta = neta;
625  svec.back().netap = netap;
626 // Not really needed to calculate the pvalue - but this was measured to be fairly fast (0.1s degradation for 47000 matches).
627  double dof = double(r);
628  double chisq_value = wsum;
629  double pvalue = gsl_cdf_chisq_Q(chisq_value,dof);
630  svec.back().pvalue = pvalue;
631  svec.back().icomb = icombi;
632 /* std::cout << "Candidate solution" << std::endl;
633  std::cout << std::setw(2) << r << " " << ored_vbits << " "
634  << std::setw(2) << npi0 << " " << std::setw(2) << neta << " " << std::setw(2) << netap << " "
635  << std::fixed << std::setw(10) << std::setprecision(5) << wsum << " "
636  << std::fixed << std::setw(10) << std::setprecision(6) << pvalue << std::endl; */
637  nmatch++;
638  nmatch_withr++;
639  }
640  }
641 
642  if(!d.empty())d.clear(); // Clear vector d
643  if(!array.empty())array.clear(); // Clear vector of vectors array
644 
645  icombi++; // Increment combination index
646  } while ( std::next_permutation(vb.begin(), vb.end() ) );
647 
648  if(_printing>2)std::cout << "Found " << std::setw(7) << nmatch_withr << " matches with "
649  << std::setw(3) << r << " edges from " << std::setw(22) << nCr << " combinations " << std::endl;
650 
651  gettimeofday(&tv,NULL);
652  t2 = tv.tv_sec+(tv.tv_usec/1000000.0);
653  if(_printing>3)std::cout << "Match search for n = " << std::setw(2) << n << " r = " << std::setw(2) << r << " "
654  << std::fixed << std::setw(12) << std::setprecision(6) << t2-t1 << " (s) "
655  << std::fixed << std::setw(12) << std::setprecision(6) << 1.0e6*(t2-t1)/double(nCr)
656  << " micro-seconds per combination " << std::endl;
657  t1 = t2;
658 
659  } // r loop
660 
661  if(_printing>2)std::cout << "Found " << std::setw(7) << nmatch << " matches total " << std::endl;
662 
663  if(_printing>5)std::cout << "Two particle hypothesis results (pi0, eta) with rmax = " << rmax << std::endl;
664 // hard-coded min and max searches (could probably do more elegantly ...)
665  int ibest = -1;
666  int imin;
667  int imax;
668  for (unsigned int r=rmax; r>0; --r){
669  double min_wsum = 999999.0;
670  double max_wsum = -999999.0;
671  imin = -1;
672  imax = -1;
673 // std::cout << "Test r = " << r << std::endl;
674  for(unsigned int i = 0; i < svec.size(); ++i) {
675  if(svec[i].ne == int(r) && svec[i].netap ==0){
676 // std::cout << "Testing i = " << i << " " << svec[i].wsum << std::endl;
677  if(svec[i].wsum > max_wsum){
678  max_wsum = svec[i].wsum;
679  imax = i;
680  }
681 
682  if(svec[i].wsum < min_wsum){
683  min_wsum = svec[i].wsum;
684  imin = i;
685  }
686 // std::cout << "Sums etc " << imin << " " << min_wsum << " " << imax << " " << max_wsum << std::endl;
687  }
688  }
689 // std::cout << " Checking solutions " << r << " " << imin << " " << imax << std::endl;
690  if(r==rmax && imin >= 0)ibest = imin; // Flag this as the "best solution".
691  if(imin>=0 && imax >=0)
692  if(_printing>5)std::cout << "wsum extrema for r = " << std::setw(2) << r << " " << std::setw(10) << min_wsum << " " << std::setw(10) << max_wsum
693  << " pvalues " << std::setw(12) << svec[imin].pvalue << " " << std::setw(12) << svec[imax].pvalue
694  << " ( " << imin << " " << imax << " ) " << " Combinations " << svec[imin].icomb << " " << svec[imax].icomb << std::endl;
695  }
696 // Examine best solution
697  if(ibest>=0){
698  double pvalue = gsl_cdf_chisq_Q(svec[ibest].wsum,svec[ibest].ne);
699  if(_printing>4)std::cout << "Best candidate solution " << ibest << std::endl;
700  if(_printing>4)std::cout << "npi0, neta, netap " << svec[ibest].npi0 << " " << svec[ibest].neta << " " << svec[ibest].netap << std::endl;
701  if(_printing>4)std::cout << std::setw(4) << ibest << " " << std::setw(2) << svec[ibest].ne << " "
702  << std::setw(2) << svec[ibest].nv << " " << svec[ibest].ebits << " "
703  << std::fixed << std::setw(10) << std::setprecision(5) << svec[ibest].wsum << " "
704  << std::fixed << std::setw(10) << std::setprecision(6) << pvalue << std::endl;
705 // Now loop over the edges
706  for (unsigned int i=0; i<NEMAX; ++i){
707  if( (svec[ibest].ebits).test(i) ){
708  if(_printing>4)std:: cout << "Edge " << std::setw(2) << i << " " << std::setw(2) << evec[i].u << " "
709  << std::setw(2) << evec[i].v << " " << evec[i].pdgid << " "
710  << std::fixed << std::setw(10) << std::setprecision(6) << evec[i].edge_pvalue << std::endl;
711  }
712  }
713  }
714 
715  gettimeofday(&tv,NULL);
716  double t3 = tv.tv_sec+(tv.tv_usec/1000000.0);
717  if(_printing>2)std::cout << "Solution analysis time = " << std::fixed << std::setw(12) << std::setprecision(6) << t3-t2 << " (s) " << std::endl;
718  if(_printing>2)std::cout << "Total elapsed time = " << std::fixed << std::setw(12) << std::setprecision(6) << t3-t0 << " (s) " << std::endl;
719 
720  // Algorithm 1. Based on fit probability ordering, add GammaGammaCandidates to the output GammaGammaParticles collection
721  // if they do not contain already assigned constituent particles. For now, the constituents are always two photons
722  // - but may not hurt to keep this generic for when other decay modes (eg. Dalitz decay) are included
723 
724 
725  // Algorithm 2. Maximal solution containing pi0s and/or etas (but no etaprimes) with lowest chi-squared.
726 
727  if(_printing>3)std::cout << "ALGORITHM2 RESULTS" << std::endl;
728  for(unsigned int i = 0; i < _pfovec.size(); ++i){
729  if( (svec[ibest].ebits).test(i) ){
730  const ReconstructedParticleVec particles = _pfovec[i]->getParticles();
731  bool assignable = true;
732  for(unsigned int j = 0; j < particles.size(); ++j){ // TODO - maybe double check these are indeed photons ..
733  const ReconstructedParticle *particle = particles[j];
734  if( particles_assigned.find(particle) != particles_assigned.end() )assignable = false; // If particle is already assigned then it is not still assignable
735  }
736  if(assignable){
737  recparcol->addElement(_pfovec[i]); // Add meson to the output collection if all constituent particles are still assignable
738  if(_printing>3)std::cout << std::setw(4) << i;
739  for(unsigned int j = 0; j < particles.size(); ++j){
740  const ReconstructedParticle *particle = particles[j];
741  particles_assigned.insert(particle); // Update set of particles already assigned in this solution
742 // also keep track of photon indices as above
743  retcode = daughter_particles.insert(particle); // insert should fail as all photons should already be in the set
744  if(_printing>3)std::cout << " " << std::setw(4) << std::distance(daughter_particles.begin(),retcode.first) ;
745  }
746  const int particleType = _pfovec[i]->getType();
747  // GoodnessOfPID currently filled with fit probability - may at some point be more convenient to fill with the fit chi-squared ...
748  const float GoodnessOfPID = _pfovec[i]->getGoodnessOfPID();
749  if(_printing>3)std::cout << " " << std::setw(4) << particleType << " "
750  << std::fixed << std::setw( 10 ) << std::setprecision( 6 ) << GoodnessOfPID << std::endl;
751  }
752  }
753  }
754  return;
755 }
756 
757 bool GammaGammaSolutionFinder::PfoProbabilitySortFunction(ReconstructedParticle* lhs,ReconstructedParticle* rhs){
758 
759  // Sort gamma gamma candidates by type and by decreasing fit probability
760 
761  // true if lhs goes before
762 
763 /*
764  const double lhs_energy = lhs->getEnergy();
765  const double rhs_energy = rhs->getEnergy();
766 */
767  const int lhs_particleType = lhs->getType();
768  const int rhs_particleType = rhs->getType();
769 
770  // GoodnessOfPID currently filled with fit probability - may at some point be more convenient to fill with the fit chi-squared ...
771  const float lhs_GoodnessOfPID = lhs->getGoodnessOfPID();
772  const float rhs_GoodnessOfPID = rhs->getGoodnessOfPID();
773 
774  if(lhs_particleType==rhs_particleType)return (lhs_GoodnessOfPID>rhs_GoodnessOfPID); // This rank makes sense when GoodnessOfPID has the fit probability
775  return (lhs_particleType<rhs_particleType); // Favor lower valued types (pi0s cf etas cf eta's)
776 
777 }
778 
void FindGammaGammaSolutions(LCCollectionVec *)
virtual void processEvent(LCEvent *evt)
Called for every event - the working horse.
unsigned long int CombinatorialFactor(int n, int k)
CLHEP::Hep3Vector Vector3D
virtual void init()
Called at the beginning of the job before anything is read.
static const float k
GammaGammaSolutionFinder:
GammaGammaSolutionFinder aGammaGammaSolutionFinder
static bool PfoProbabilitySortFunction(ReconstructedParticle *lhs, ReconstructedParticle *rhs)
std::vector< std::string > _gammagammaCandidateCollections
CLHEP::HepLorentzVector LorentzVector
std::vector< ReconstructedParticle * > _pfovec
virtual void processRunHeader(LCRunHeader *run)
Called for every run.
std::vector< LCCollection * > LCCollectionVec
Definition: SiStripClus.h:55
virtual void end()
Called after data processing for clean up.
void FindCombinations(std::vector< std::vector< int > > array, unsigned int i, std::vector< int > accum)
void FindGammaGammaSolutionZero(LCCollectionVec *)
std::vector< std::vector< int > > comb
std::vector< std::string > StringVec
Definition: SiStripClus.h:56