Hall-D Software  alpha
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
DEventProcessor_phys_tree.cc
Go to the documentation of this file.
1 // $Id$
2 //
3 // File: DEventProcessor_phys_tree.cc
4 // Created: Wed Sep 2 20:25:05 EDT 2009
5 // Creator: davidl (on Darwin harriet.jlab.org 9.6.0 i386)
6 //
7 
9 
10 #include <iostream>
11 #include <iomanip>
12 #include <cmath>
13 #include <utility>
14 #include <vector>
15 using namespace std;
16 
17 #include <TThread.h>
18 #include <TDirectoryFile.h>
19 #include <TLorentzVector.h>
20 
21 #include <TROOT.h>
22 
23 #include <JANA/JApplication.h>
24 #include <JANA/JEventLoop.h>
25 using namespace jana;
26 
27 #include <PID/DKinematicData.h>
28 #include <PID/DBeamPhoton.h>
29 #include <PID/DParticleSet.h>
30 #include <PID/DPhysicsEvent.h>
31 #include <TRACKING/DMCThrown.h>
32 
33 bool static CompareLorentzEnergy(const Particle &a, const Particle &b){
34  return a.p.E()<b.p.E();
35 }
36 
37 // Routine used to create our DEventProcessor
38 extern "C"{
39 void InitPlugin(JApplication *app){
40  InitJANAPlugin(app);
41  app->AddProcessor(new DEventProcessor_phys_tree());
42 }
43 } // "C"
44 
45 
46 //------------------
47 // DEventProcessor_track_hists
48 //------------------
50 {
51  pthread_mutex_init(&mutex, NULL);
52 }
53 
54 //------------------
55 // ~DEventProcessor_track_hists
56 //------------------
58 {
59 
60 }
61 
62 //------------------
63 // init
64 //------------------
66 {
67  // Create PHYSICS directory
68  TDirectory *dir = (TDirectory*)gROOT->FindObject("PHYSICS");
69  if(!dir)dir = new TDirectoryFile("PHYSICS","PHYSICS");
70  dir->cd();
71 
72  // Here we define a tree with two identical branches based on the Event class.
73  // One to hold the thrown values and the other to hold the recon(structed) ones.
74 
75  // Create "tree
76  tree_thrwn = new TTree("thrown","Thrown Event parameters");
77  tree_recon = new TTree("recon","Reconstructed Event parameters");
78 
79  // Create branches for thrown and reconstructed values
80  evt_thrown = new Event();
81  evt_recon = new Event();
82  tree_thrwn->Branch("T",&evt_thrown);
83  tree_recon->Branch("R",&evt_recon);
84 
85  // Empty tree with thrown and recon values as friends
86  TTree *evt = new TTree("evt","Thrown and Reconstructed Event parameters");
87  evt->AddFriend("tree_thrwn");
88  evt->AddFriend("tree_recon");
89 
90  dir->cd("../");
91 
92  return NOERROR;
93 }
94 
95 //------------------
96 // brun
97 //------------------
98 jerror_t DEventProcessor_phys_tree::brun(JEventLoop *loop, int32_t runnumber)
99 {
100 
101  return NOERROR;
102 }
103 
104 //------------------
105 // evnt
106 //------------------
107 jerror_t DEventProcessor_phys_tree::evnt(JEventLoop *loop, uint64_t eventnumber)
108 {
109  // Get reconstructed objects and make TLorentz vectors out of each of them
110  vector<const DBeamPhoton*> beam_photons;
111  vector<const DMCThrown*> mcthrowns;
112  vector<const DPhysicsEvent*> physicsevents;
113 
114  loop->Get(beam_photons);
115  loop->Get(mcthrowns);
116  loop->Get(physicsevents);
117 
118  TVector3 VertexRec, VertexGen;
119  VertexGen = TVector3(mcthrowns[0]->position().X(),mcthrowns[0]->position().Y(),mcthrowns[0]->position().Z());
120  // Make Particle object for beam photon
121  TLorentzVector beam_photon(0.0, 0.0, 9.0, 9.0);
122  if(beam_photons.size()>0){
123  const DLorentzVector &lv = beam_photons[0]->lorentzMomentum();
124  beam_photon.SetPxPyPzE(lv.Px(), lv.Py(), lv.Pz(), lv.E());
125  }
126 
127  // Target is proton at rest in lab frame
128  TLorentzVector target(0.0, 0.0, 0.0, 0.93827);
129  // Find the DPhysicsEvent with the most particles and only use that one.
130  // This is not a long term solution, but is motivated by the fact that
131  // we have only one set of DMCThrown particles and one DBeamPhoton
132  const DPhysicsEvent *physicsevent = NULL;
133  int max_parts=0;
134  for(unsigned int i=0; i<physicsevents.size(); i++){
135  if(physicsevents[i]->particle_sets.size()==0)continue;
136  const DParticleSet *ps = physicsevents[i]->particle_sets[0];
137  int Nparts = ps->pip.size() + ps->pim.size()
138  + ps->photon.size() + ps->proton.size()
139  + ps->Kp.size() + ps->Km.size()
140  + ps->otherp.size() + ps->othern.size()
141  + ps->otherz.size() + ps->neutron.size();
142  if(Nparts>max_parts || physicsevents[i]==NULL){
143  physicsevent = physicsevents[i];
144  max_parts = Nparts;
145  }
146  VertexRec.SetX(ps->vertex->dSpacetimeVertex.X());
147  VertexRec.SetY(ps->vertex->dSpacetimeVertex.Y());
148  VertexRec.SetZ(ps->vertex->dSpacetimeVertex.Z());
149  }
150 
151  // Create Particle objects for each of the common particle types
152  particle_set rec;
153 
154  if (physicsevent!=NULL){
155  const DParticleSet *particle_set=physicsevent->particle_sets[0];
156  for(unsigned int j=0; j<particle_set->photon.size(); j++){
157  // photon
158  rec.photons.push_back(MakeParticle(particle_set->photon[j]->dNeutralParticleHypotheses[0], 0.0));
159  }
160  for(unsigned int j=0; j<particle_set->neutron.size(); j++){
161  // neutron
162  rec.neutrons.push_back(MakeParticle(particle_set->neutron[j]->dNeutralParticleHypotheses[0], 0.939565));
163  }
164  for(unsigned int j=0; j<particle_set->pip.size(); j++){
165  // pi+
166  rec.piplus.push_back(MakeParticle(particle_set->pip[j]->dChargedTrackHypotheses[0], 0.13957));
167  }
168  for(unsigned int j=0; j<particle_set->pim.size(); j++){
169  // pi-
170  rec.piminus.push_back(MakeParticle(particle_set->pim[j]->dChargedTrackHypotheses[0], 0.13957));
171  }
172  for(unsigned int j=0; j<particle_set->proton.size(); j++){
173  // proton
174  rec.protons.push_back(MakeParticle(particle_set->proton[j]->dChargedTrackHypotheses[0], 0.93827));
175  }
176  for(unsigned int j=0; j<particle_set->Kp.size(); j++){
177  // K+
178  rec.Kplus.push_back(MakeParticle(particle_set->Kp[j]->dChargedTrackHypotheses[0], 0.493677));
179  }
180  for(unsigned int j=0; j<particle_set->Km.size(); j++){
181  // K-
182  rec.Kminus.push_back(MakeParticle(particle_set->Km[j]->dChargedTrackHypotheses[0], 0.493677));
183  }
184  }
185 
186  // Create Particle objects for thrown particles
187  bool all_mesons_fiducial = true;
188  bool all_photons_fiducial = true;
189  bool all_neutrons_fiducial = true;
190  bool all_protons_fiducial = true;
191  particle_set thr;
192  for(unsigned int k=0; k<mcthrowns.size(); k++){
193  switch(mcthrowns[k]->type){
194  case 1: thr.photons.push_back(MakeParticle((DKinematicData*)mcthrowns[k], 0.0));
195  all_photons_fiducial &= IsFiducial(mcthrowns[k]);
196  break;
197  case 8: thr.piplus.push_back(MakeParticle((DKinematicData*)mcthrowns[k], 0.13957));
198  all_mesons_fiducial &= IsFiducial(mcthrowns[k]);
199  break;
200  case 9: thr.piminus.push_back(MakeParticle((DKinematicData*)mcthrowns[k], 0.13957));
201  all_mesons_fiducial &= IsFiducial(mcthrowns[k]);
202  break;
203  case 11: thr.Kplus.push_back(MakeParticle((DKinematicData*)mcthrowns[k], 0.493677));
204  all_mesons_fiducial &= IsFiducial(mcthrowns[k]);
205  break;
206  case 12: thr.Kminus.push_back(MakeParticle((DKinematicData*)mcthrowns[k], 0.493677));
207  all_mesons_fiducial &= IsFiducial(mcthrowns[k]);
208  break;
209  case 13: thr.neutrons.push_back(MakeParticle((DKinematicData*)mcthrowns[k], 0.939565));
210  all_neutrons_fiducial &= IsFiducial(mcthrowns[k]);
211  break;
212  case 14: thr.protons.push_back(MakeParticle((DKinematicData*)mcthrowns[k], 0.93827));
213  all_protons_fiducial &= IsFiducial(mcthrowns[k]);
214  break;
215  }
216  }
217 
218  // Lock mutex
219  japp->RootWriteLock();
220  //pthread_mutex_lock(&mutex);
221 
222  // Fill in Event objects for both thrown and reconstructed
223  evt_recon->Clear();
224  evt_thrown->Clear();
225  FillEvent(evt_recon, rec, thr);
226  FillEvent(evt_thrown, thr, rec);
227 
228  // Copy fiducial cuts (based only on thrown values) to both trees
229  bool all_fiducial = all_mesons_fiducial && all_photons_fiducial && all_protons_fiducial && all_neutrons_fiducial;
230  evt_recon->all_fiducial = all_fiducial;
231  evt_recon->all_mesons_fiducial = all_mesons_fiducial;
232  evt_recon->all_photons_fiducial = all_photons_fiducial;
233  evt_recon->all_neutrons_fiducial = all_neutrons_fiducial;
234  evt_recon->all_protons_fiducial = all_protons_fiducial;
235  evt_recon->vertex = VertexRec;
236 
237  evt_thrown->all_fiducial = all_fiducial;
238  evt_thrown->all_mesons_fiducial = all_mesons_fiducial;
239  evt_thrown->all_photons_fiducial = all_photons_fiducial;
240  evt_thrown->all_neutrons_fiducial = all_neutrons_fiducial;
241  evt_thrown->all_protons_fiducial = all_protons_fiducial;
242  evt_thrown->vertex = VertexGen;
243 
244  // Copy event number to both trees and add this event to them
245  evt_recon->event = eventnumber;
246  evt_thrown->event = eventnumber;
247  tree_thrwn->Fill();
248  tree_recon->Fill();
249 
250  // Unlock mutex
251  japp->RootUnLock();
252  //pthread_mutex_unlock(&mutex);
253 
254  return NOERROR;
255 }
256 
257 
258 //------------------
259 // MakeParticle
260 //------------------
262 {
263  // Create a ROOT TLorentzVector object out of a Hall-D DKinematic Data object.
264  // Here, we have the mass passed in explicitly rather than use the mass contained in
265  // the DKinematicData object itself. This is because right now (Feb. 2009) the
266  // PID code is not mature enough to give reasonable guesses. See above code.
267 
268  double p = kd->momentum().Mag();
269  double theta = kd->momentum().Theta();
270  double phi = kd->momentum().Phi();
271  double px = p*sin(theta)*cos(phi);
272  double py = p*sin(theta)*sin(phi);
273  double pz = p*cos(theta);
274  double E = sqrt(mass*mass + p*p);
275  double x = kd->position().X();
276  double y = kd->position().Y();
277  double z = kd->position().Z();
278 
279  Particle part;
280  part.p.SetPxPyPzE(px,py,pz,E);
281  part.x.SetXYZ(x, y, z);
282  part.is_fiducial = IsFiducial(kd);
283  part.chisq = -1.0;
284  part.Ndof = 0;
285  part.FOM_pid = -1.0;
286 
287  return part;
288 }
289 
290 //------------------
291 // MakeParticle
292 //------------------
293 Particle DEventProcessor_phys_tree::MakeParticle(const DChargedTrackHypothesis *locChargedTrackHypothesis, double mass)
294 {
295  // Most values get set using DKinematicData part
296  Particle part = MakeParticle((DKinematicData*)locChargedTrackHypothesis, mass);
297 
298  // Things specific to DChargedTrackHypothesis
299  part.chisq = locChargedTrackHypothesis->dChiSq;
300  part.Ndof = locChargedTrackHypothesis->dNDF;
301  part.FOM_pid = locChargedTrackHypothesis->dFOM;
302 
303  return part;
304 }
305 
306 //------------------
307 // MakeParticle
308 //------------------
309 Particle DEventProcessor_phys_tree::MakeParticle(const DNeutralParticleHypothesis *locNeutralParticleHypothesis, double mass)
310 {
311  // Most values get set using DKinematicData part
312  Particle part = MakeParticle((DKinematicData*)locNeutralParticleHypothesis, mass);
313 
314  // Things specific to DNeutralParticleHypothesis
315  part.chisq = locNeutralParticleHypothesis->dChiSq;
316  part.Ndof = locNeutralParticleHypothesis->dNDF;
317  part.FOM_pid = locNeutralParticleHypothesis->dFOM;
318 
319  return part;
320 }
321 
322 //------------------
323 // FillEvent
324 //------------------
326 {
327 
328  vector<Particle> &photon = pset.photons;
329  vector<Particle> &neutron = pset.neutrons;
330  vector<Particle> &pip = pset.piplus;
331  vector<Particle> &pim = pset.piminus;
332  vector<Particle> &Kp = pset.Kplus;
333  vector<Particle> &Km = pset.Kminus;
334  vector<Particle> &proton = pset.protons;
335 
336  vector<Particle> &photon_match = pset_match.photons;
337  vector<Particle> &neutron_match = pset_match.neutrons;
338  vector<Particle> &pip_match = pset_match.piplus;
339  vector<Particle> &pim_match = pset_match.piminus;
340  vector<Particle> &Kp_match = pset_match.Kplus;
341  vector<Particle> &Km_match = pset_match.Kminus;
342  vector<Particle> &proton_match = pset_match.protons;
343 
344  // Sort particle arrays by energy
345  sort(photon.begin(), photon.end(), CompareLorentzEnergy);
346  sort(neutron.begin(), neutron.end(), CompareLorentzEnergy);
347  sort(pip.begin(), pip.end(), CompareLorentzEnergy);
348  sort(pim.begin(), pim.end(), CompareLorentzEnergy);
349  sort(Kp.begin(), Kp.end(), CompareLorentzEnergy);
350  sort(Km.begin(), Km.end(), CompareLorentzEnergy);
351  sort(proton.begin(), proton.end(), CompareLorentzEnergy);
352 
353  // Add photons
354  for(unsigned int i=0; i<photon.size(); i++){
355  TClonesArray &prts_match = *(evt->photon_match);
356  Particle *prt_match = new(prts_match[evt->Nphoton]) Particle();
357  *prt_match = FindBestMatch(photon[i], photon_match);
358 
359  TClonesArray &prts = *(evt->photon);
360  Particle *prt = new(prts[evt->Nphoton++]) Particle();
361  *prt = photon[i];
362  }
363 
364  // Add neutrons
365  for(unsigned int i=0; i<neutron.size(); i++){
366  TClonesArray &prts_match = *(evt->neutron_match);
367  Particle *prt_match = new(prts_match[evt->Nneutron]) Particle();
368  *prt_match = FindBestMatch(neutron[i], neutron_match);
369 
370  TClonesArray &prts = *(evt->neutron);
371  Particle *prt = new(prts[evt->Nneutron++]) Particle();
372  *prt = neutron[i];
373  }
374 
375  // Add piplus
376  for(unsigned int i=0; i<pip.size(); i++){
377  TClonesArray &prts_match = *(evt->pip_match);
378  Particle *prt_match = new(prts_match[evt->Npip]) Particle();
379  *prt_match = FindBestMatch(pip[i], pip_match);
380 
381  TClonesArray &prts = *(evt->pip);
382  Particle *prt = new(prts[evt->Npip++]) Particle();
383  *prt = pip[i];
384  }
385 
386  // Add piminus
387  for(unsigned int i=0; i<pim.size(); i++){
388  TClonesArray &prts_match = *(evt->pim_match);
389  Particle *prt_match = new(prts_match[evt->Npim]) Particle();
390  *prt_match = FindBestMatch(pim[i], pim_match);
391 
392  TClonesArray &prts = *(evt->pim);
393  Particle *prt = new(prts[evt->Npim++]) Particle();
394  *prt = pim[i];
395  }
396 
397  // Add Kplus
398  for(unsigned int i=0; i<Kp.size(); i++){
399  TClonesArray &prts_match = *(evt->Kp_match);
400  Particle *prt_match = new(prts_match[evt->NKp]) Particle();
401  *prt_match = FindBestMatch(Kp[i], Kp_match);
402 
403  TClonesArray &prts = *(evt->Kp);
404  Particle *prt = new(prts[evt->NKp++]) Particle();
405  *prt = Kp[i];
406  }
407 
408  // Add Kminus
409  for(unsigned int i=0; i<Km.size(); i++){
410  TClonesArray &prts_match = *(evt->Km_match);
411  Particle *prt_match = new(prts_match[evt->NKm]) Particle();
412  *prt_match = FindBestMatch(Km[i], Km_match);
413 
414  TClonesArray &prts = *(evt->Km);
415  Particle *prt = new(prts[evt->NKm++]) Particle();
416  *prt = Km[i];
417  }
418 
419  // Add proton
420  for(unsigned int i=0; i<proton.size(); i++){
421  TClonesArray &prts_match = *(evt->proton_match);
422  Particle *prt_match = new(prts_match[evt->Nproton]) Particle();
423  *prt_match = FindBestMatch(proton[i], proton_match);
424 
425  TClonesArray &prts = *(evt->proton);
426  Particle *prt = new(prts[evt->Nproton++]) Particle();
427  *prt = proton[i];
428  }
429 
430  // Calculate W of reconstructed particles
431  for(unsigned int i=0; i<photon.size(); i++)evt->W += photon[i].p;
432  for(unsigned int i=0; i<neutron.size(); i++)evt->W += neutron[i].p;
433  for(unsigned int i=0; i<pip.size(); i++)evt->W += pip[i].p;
434  for(unsigned int i=0; i<pim.size(); i++)evt->W += pim[i].p;
435  for(unsigned int i=0; i<Kp.size(); i++)evt->W += Kp[i].p;
436  for(unsigned int i=0; i<Km.size(); i++)evt->W += Km[i].p;
437 }
438 
439 //------------------
440 // FindBestMatch
441 //------------------
442 Particle DEventProcessor_phys_tree::FindBestMatch(const Particle &primary, vector<Particle> &secondaries)
443 {
444  // Loop over secondaries and keep the one with the best figure of merit
445  // to return. Initialize return vector with zeros in case not good match
446  // is found.
447  double max_fom = 0.1;
448  Particle best_match;
449  best_match.p.SetXYZT(0.0, 0.0, 0.0, 0.0);
450  for(unsigned int i=0; i<secondaries.size(); i++){
451  double fom = GetFOM(primary, secondaries[i]);
452  if(fom > max_fom){
453  max_fom = fom;
454  best_match = secondaries[i];
455  }
456  }
457 
458  return best_match;
459 }
460 
461 //------------------
462 // GetFOM
463 //------------------
464 double DEventProcessor_phys_tree::GetFOM(const Particle &a, const Particle &b) const
465 {
466  // This is a kind of brain-dead algorithm. It wants to use both the
467  // momentum direction and magnitude to determine the FOM. For the
468  // magnitude, we use the curvature which becomes close to zero for
469  // high momentum tracks (good because a 4GeV/c and an 8GeV/c track
470  // both look more or less like straight lines).
471  //
472  // For the direction, we just use the relative angle between the
473  // two tracks.
474  //
475  // For both, we take a reciprocal so that the closer the match,
476  // the higher the FOM. We take a product of the 2 FOM components
477  // so that both components must have a high value in order for the
478  // total FOM to be large.
479 
480  double epsilon = 1.0E-6; // prevent reciprocals from resulting in infinity
481 
482  double curature_a = 1.0/a.p.P();
483  double curature_b = 1.0/b.p.P();
484  double curvature_diff = fabs(curature_a - curature_b);
485  double curvature_fom = 1.0/(curvature_diff + epsilon);
486 
487  double theta_rel = fabs(a.p.Angle(b.p.Vect()));
488  double theta_fom = 1.0/(theta_rel + epsilon);
489 
490  double fom = curvature_fom*theta_fom;
491 
492  return fom;
493 }
494 
495 //------------------
496 // IsFiducial
497 //------------------
499 {
500  double theta_degrees = kd->momentum().Theta()*TMath::RadToDeg();
501  double p = kd->momentum().Mag();
502 
503  if(kd->charge()==0.0){
504  // photon
505  if(theta_degrees<2.0 || theta_degrees>110.0)return false;
506  if(p<0.100)return false;
507  }else{
508  // charged particle
509  if(theta_degrees<1.0 || theta_degrees>120.0)return false;
510  if(p<0.400)return false;
511  }
512 
513  return true;
514 }
515 
516 //------------------
517 // erun
518 //------------------
520 {
521 
522  return NOERROR;
523 }
524 
525 //------------------
526 // fini
527 //------------------
529 {
530 
531  return NOERROR;
532 }
533 
TClonesArray * proton_match
Closest match proton (truth or recon, whatever is not in proton)
Particle MakeParticle(const DKinematicData *kd, double mass)
TClonesArray * Kp
Definition: mc_tree/Event.h:51
Definition: photon.h:15
bool IsFiducial(const DKinematicData *kd)
jerror_t fini(void)
Called after last event of last event source has been processed.
Double_t x[NCHANNELS]
Definition: st_tw_resols.C:39
#define y
TClonesArray * pip
Definition: mc_tree/Event.h:49
const DVector3 & position(void) const
UInt_t Npip
Definition: mc_tree/Event.h:36
TClonesArray * photon
Definition: mc_tree/Event.h:54
UInt_t Nphoton
Definition: mc_tree/Event.h:41
UInt_t Npim
Definition: mc_tree/Event.h:37
UInt_t Nneutron
Definition: mc_tree/Event.h:42
TClonesArray * Km_match
Closest match K- (truth or recon, whatever is not in Km)
Particle FindBestMatch(const Particle &primary, vector< Particle > &secondaries)
jerror_t evnt(JEventLoop *eventLoop, uint64_t eventnumber)
Called every event.
TLorentzVector DLorentzVector
TClonesArray * neutron
Definition: mc_tree/Event.h:55
#define X(str)
Definition: hddm-c.cpp:83
TClonesArray * pip_match
Closest match pi+ (truth or recon, whatever is not in pip)
JApplication * japp
UInt_t NKm
Definition: mc_tree/Event.h:39
jerror_t brun(JEventLoop *eventLoop, int32_t runnumber)
Called everytime a new run number is detected.
UInt_t NKp
Definition: mc_tree/Event.h:38
TVector3 x
InitPlugin_t InitPlugin
Double_t FOM_pid
TClonesArray * proton
Definition: mc_tree/Event.h:53
TLorentzVector W
Definition: mc_tree/Event.h:65
TClonesArray * pim_match
Closest match pi- (truth or recon, whatever is not in pim)
UInt_t Nproton
Definition: mc_tree/Event.h:40
Bool_t is_fiducial
TLorentzVector p
jerror_t init(void)
Called once at program start.
double charge(void) const
TH1D * py[NCHANNELS]
double sqrt(double)
double sin(double)
TClonesArray * pim
Definition: mc_tree/Event.h:50
const DVector3 & momentum(void) const
Double_t chisq
jerror_t erun(void)
Called everytime run number changes, provided brun has been called.
double GetFOM(const Particle &a, const Particle &b) const
TClonesArray * Km
Definition: mc_tree/Event.h:52
TClonesArray * neutron_match
Closest match neutron (truth or recon, whatever is not in neutron)
void FillEvent(Event *evt, particle_set &pset, particle_set &pset_match)
TDirectory * dir
Definition: bcal_hist_eff.C:31
static bool CompareLorentzEnergy(const Particle &a, const Particle &b)
TClonesArray * Kp_match
Closest match K+ (truth or recon, whatever is not in Kp)
TClonesArray * photon_match
Closest match photon (truth or recon, whatever is not in photon)