Analysis Software
Documentation for sPHENIX simulation software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
KFParticle_sPHENIX.cc
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file KFParticle_sPHENIX.cc
1 /*
2  * This file is part of KFParticle package
3  * Copyright ( C ) 2007-2019 FIAS Frankfurt Institute for Advanced Studies
4  * 2007-2019 Goethe University of Frankfurt
5  * 2007-2019 Ivan Kisel <I.Kisel@compeng.uni-frankfurt.de>
6  * 2007-2019 Maksym Zyzak
7  *
8  * KFParticle is free software: you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation, either version 3 of the License, or
11  * ( at your option ) any later version.
12  *
13  * KFParticle is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program. If not, see <https://www.gnu.org/licenses/>.
20  */
21 
22 #include "KFParticle_sPHENIX.h"
23 
26 
28 
29 #include <phool/getClass.h>
30 
31 #include <TFile.h>
32 #include <TH1.h> // for obtaining the B field value
33 #include <TTree.h> // for getting the TTree from the file
34 
35 #include <KFPVertex.h>
36 #include <KFParticle.h> // for KFParticle
37 #include <fun4all/Fun4AllBase.h> // for Fun4AllBase::VERBOSITY...
38 #include <fun4all/SubsysReco.h> // for SubsysReco
39 
40 #include <ffamodules/CDBInterface.h> // for accessing the field map file from the CDB
41 #include <cctype> // for toupper
42 #include <cmath> // for sqrt
43 #include <cstdlib> // for size_t, exit
44 #include <iostream> // for operator<<, endl, basi...
45 #include <map> // for map
46 #include <tuple> // for tie, tuple
47 
48 class PHCompositeNode;
49 
50 namespace TMVA
51 {
52  class Reader;
53 }
54 
56 
59  : SubsysReco("KFPARTICLE")
60  , m_has_intermediates_sPHENIX(false)
61  , m_constrain_to_vertex_sPHENIX(false)
62  , m_require_mva(false)
63  , m_save_dst(false)
64  , m_save_output(true)
65  , m_outfile_name("outputData.root")
66  , m_outfile(nullptr)
67 {
68 }
69 
71  : SubsysReco(name)
72  , m_has_intermediates_sPHENIX(false)
73  , m_constrain_to_vertex_sPHENIX(false)
74  , m_require_mva(false)
75  , m_save_dst(false)
76  , m_save_output(true)
77  , m_outfile_name("outputData.root")
78  , m_outfile(nullptr)
79 {
80 }
81 
83 {
85  {
86  std::cout << "Output nTuple: " << m_outfile_name << std::endl;
87  }
88 
89  if (m_save_dst)
90  {
91  createParticleNode(topNode);
92  }
93 
94  if (m_require_mva)
95  {
96  TMVA::Reader *reader;
97  std::vector<Float_t> MVA_parValues;
98  tie(reader, MVA_parValues) = initMVA();
99  }
100 
101  int returnCode = 0;
102  if (!m_decayDescriptor.empty())
103  {
104  returnCode = parseDecayDescriptor();
105  }
106 
107  return returnCode;
108 }
109 
111 {
112  assert(topNode);
113 
114  // Load the official offline B-field map that is also used in tracking, basically copying the codes from: https://github.com/sPHENIX-Collaboration/coresoftware/blob/master/offline/packages/trackreco/MakeActsGeometry.cc#L478-L483, provide by Joe Osborn.
115  char *calibrationsroot = getenv("CALIBRATIONROOT");
116  std::string m_magField = "sphenix3dtrackingmapxyz.root";
117 
118  if (calibrationsroot != nullptr)
119  {
120  m_magField = std::string(calibrationsroot) + std::string("/Field/Map/") + m_magField;
121  }
122 
123  m_magField = CDBInterface::instance()->getUrl("FIELDMAPTRACKING", m_magField); // Joe's New Implementation to get the field map file name on 05/10/2023
124 
125  TFile *fin = new TFile(m_magField.c_str());
126  fin->cd();
127 
128  TTree *fieldmap = (TTree *) fin->Get("fieldmap");
129 
130  TH1F *BzHist = new TH1F("BzHist", "", 100, 0, 10);
131 
132  int NBFieldEntries = fieldmap->Project("BzHist", "bz", "x==0 && y==0 && z==0");
133 
134  if (NBFieldEntries != 1)
135  { // Validate exactly 1 B field value at (0,0,0) in the field map
136  std::cout << "Not a single B field value at (0,0,0) in the field map, need to check why" << std::endl;
137  exit(1);
138  }
139 
140  // The actual unit of KFParticle is in kilo Gauss (kG), which is equivalent to 0.1 T, instead of Tesla (T). The positive value indicates the B field is in the +z direction
141  float m_Bz = BzHist->GetMean() * 10; // Factor of 10 to convert the B field unit from kG to T
142  KFParticle::SetField(m_Bz);
143 
144  fieldmap->Delete();
145  BzHist->Delete();
146  fin->Close();
147 
148  return 0;
149 }
150 
152 {
153  std::vector<KFParticle> mother, vertex;
154  std::vector<std::vector<KFParticle>> daughters, intermediates;
155  int nPVs, multiplicity;
156 
157  if (!m_use_fake_pv)
158  {
159  SvtxVertexMap *check_vertexmap = findNode::getClass<SvtxVertexMap>(topNode, m_vtx_map_node_name);
160  if (check_vertexmap->size() == 0)
161  {
162  if (Verbosity() >= VERBOSITY_SOME)
163  {
164  std::cout << "KFParticle: Event skipped as there are no vertices" << std::endl;
165  }
167  }
168  }
169 
170  SvtxTrackMap *check_trackmap = findNode::getClass<SvtxTrackMap>(topNode, m_trk_map_node_name);
171  if (check_trackmap->size() == 0)
172  {
173  if (Verbosity() >= VERBOSITY_SOME)
174  {
175  std::cout << "KFParticle: Event skipped as there are no tracks" << std::endl;
176  }
178  }
179 
180  createDecay(topNode, mother, vertex, daughters, intermediates, nPVs, multiplicity);
181 
183  {
184  intermediates = daughters;
185  }
187  {
188  vertex = mother;
189  }
190 
191  if (mother.size() != 0)
192  {
193  for (unsigned int i = 0; i < mother.size(); ++i)
194  {
195  if (m_save_output && candidateCounter == 0)
196  {
197  m_outfile = new TFile(m_outfile_name.c_str(), "RECREATE");
199  }
200 
201  candidateCounter += 1;
202 
203  if (m_save_output)
204  {
205  fillBranch(topNode, mother[i], vertex[i], daughters[i], intermediates[i], nPVs, multiplicity);
206  }
207  if (m_save_dst)
208  {
209  fillParticleNode(topNode, mother[i], daughters[i], intermediates[i]);
210  }
211 
212  if (Verbosity() >= VERBOSITY_SOME)
213  {
214  printParticles(mother[i], vertex[i], daughters[i], intermediates[i], nPVs, multiplicity);
215  }
216  if (Verbosity() >= VERBOSITY_MORE)
217  {
218  if (m_save_dst)
219  {
220  printNode(topNode);
221  }
222  }
223  }
224  }
225 
227 }
228 
230 {
231  std::cout << "KFParticle_sPHENIX object " << Name() << " finished. Number of candidates: " << candidateCounter << std::endl;
232 
233  if (m_save_output && candidateCounter != 0)
234  {
235  m_outfile->Write();
236  m_outfile->Close();
237  delete m_outfile;
238  }
239 
240  return 0;
241 }
242 
244  const KFParticle &chosenVertex,
245  const std::vector<KFParticle> &daughterParticles,
246  const std::vector<KFParticle> &intermediateParticles,
247  const int numPVs, const int numTracks)
248 {
249  std::cout << "\n---------------KFParticle candidate information---------------" << std::endl;
250 
251  std::cout << "Mother information:" << std::endl;
252  identify(motherParticle);
253 
255  {
256  std::cout << "Intermediate state information:" << std::endl;
257  for (const auto &intermediateParticle : intermediateParticles)
258  {
259  identify(intermediateParticle);
260  }
261  }
262 
263  std::cout << "Final track information:" << std::endl;
264  for (const auto &daughterParticle : daughterParticles)
265  {
266  identify(daughterParticle);
267  }
268 
270  {
271  std::cout << "Primary vertex information:" << std::endl;
272  std::cout << "(x,y,z) = (" << chosenVertex.GetX() << " +/- " << std::sqrt(chosenVertex.GetCovariance(0, 0)) << ", ";
273  std::cout << chosenVertex.GetY() << " +/- " << std::sqrt(chosenVertex.GetCovariance(1, 1)) << ", ";
274  std::cout << chosenVertex.GetZ() << " +/- " << std::sqrt(chosenVertex.GetCovariance(2, 2)) << ") cm\n"
275  << std::endl;
276  }
277 
278  std::cout << "The number of primary vertices is: " << numPVs << std::endl;
279  std::cout << "The number of tracks in the event is: " << numTracks << std::endl;
280 
281  std::cout << "------------------------------------------------------------\n"
282  << std::endl;
283 }
284 
286 {
287  bool ddCanBeParsed = true;
288 
289  size_t daughterLocator;
290 
291  std::string mother;
292  std::string intermediate;
293  std::string daughter;
294 
295  std::vector<std::pair<std::string, int>> intermediate_list;
296  std::vector<std::string> intermediates_name;
297  std::vector<int> intermediates_charge;
298 
299  std::vector<std::pair<std::string, int>> daughter_list;
300  std::vector<std::string> daughters_name;
301  std::vector<int> daughters_charge;
302 
303  int nTracks = 0;
304  std::vector<int> m_nTracksFromIntermediates;
305 
306  std::string decayArrow = "->";
307  std::string chargeIndicator = "^";
308  std::string startIntermediate = "{";
309  std::string endIntermediate = "}";
310 
311  // These tracks require a + or - after their name for TDatabasePDG
312  std::string specialTracks[] = {"e", "mu", "pi", "K"};
313 
314  std::string manipulateDecayDescriptor = m_decayDescriptor;
315 
316  // Remove all white space before we begin
317  size_t pos;
318  while ((pos = manipulateDecayDescriptor.find(' ')) != std::string::npos)
319  {
320  manipulateDecayDescriptor.replace(pos, 1, "");
321  }
322 
323  // Check for charge conjugate requirement
324  std::string checkForCC = manipulateDecayDescriptor.substr(0, 1) + manipulateDecayDescriptor.substr(manipulateDecayDescriptor.size() - 3, 3);
325  std::for_each(checkForCC.begin(), checkForCC.end(), [](char &c)
326  { c = ::toupper(c); });
327 
328  // Remove the CC check if needed
329  if (checkForCC == "[]CC")
330  {
331  manipulateDecayDescriptor = manipulateDecayDescriptor.substr(1, manipulateDecayDescriptor.size() - 4);
332  getChargeConjugate(true);
333  }
334 
335  // Find the initial particle
336  size_t findMotherEndPoint = manipulateDecayDescriptor.find(decayArrow);
337  mother = manipulateDecayDescriptor.substr(0, findMotherEndPoint);
338  if (!findParticle(mother))
339  {
340  ddCanBeParsed = false;
341  }
342  manipulateDecayDescriptor.erase(0, findMotherEndPoint + decayArrow.length());
343 
344  // Try and find the intermediates
345  while ((pos = manipulateDecayDescriptor.find(startIntermediate)) != std::string::npos)
346  {
347  size_t findIntermediateStartPoint = manipulateDecayDescriptor.find(startIntermediate, pos);
348  size_t findIntermediateEndPoint = manipulateDecayDescriptor.find(endIntermediate, pos);
349  std::string intermediateDecay = manipulateDecayDescriptor.substr(pos + 1, findIntermediateEndPoint - (pos + 1));
350 
351  intermediate = intermediateDecay.substr(0, intermediateDecay.find(decayArrow));
352  if (findParticle(intermediate))
353  {
354  intermediates_name.emplace_back(intermediate.c_str());
355  }
356  else
357  {
358  ddCanBeParsed = false;
359  }
360 
361  // Now find the daughters associated to this intermediate
362  int nDaughters = 0;
363  intermediateDecay.erase(0, intermediateDecay.find(decayArrow) + decayArrow.length());
364  while ((daughterLocator = intermediateDecay.find(chargeIndicator)) != std::string::npos)
365  {
366  daughter = intermediateDecay.substr(0, daughterLocator);
367  std::string daughterChargeString = intermediateDecay.substr(daughterLocator + 1, 1);
368  if (std::find(std::begin(specialTracks), std::end(specialTracks), daughter) != std::end(specialTracks))
369  {
370  daughter += daughterChargeString;
371  }
372  if (findParticle(daughter))
373  {
374  daughters_name.emplace_back(daughter.c_str());
375 
376  if (daughterChargeString == "+")
377  {
378  daughters_charge.push_back(+1);
379  }
380  else if (daughterChargeString == "-")
381  {
382  daughters_charge.push_back(-1);
383  }
384  else if (daughterChargeString == "0")
385  {
386  daughters_charge.push_back(0);
387  }
388  else
389  {
390  if (Verbosity() >= VERBOSITY_MORE)
391  {
392  std::cout << "The charge of " << daughterChargeString << " was not known" << std::endl;
393  }
394  ddCanBeParsed = false;
395  }
396  }
397  else
398  {
399  ddCanBeParsed = false;
400  }
401  intermediateDecay.erase(0, daughterLocator + 2);
402  ++nDaughters;
403  }
404  manipulateDecayDescriptor.erase(findIntermediateStartPoint, findIntermediateEndPoint + 1 - findIntermediateStartPoint);
405  m_nTracksFromIntermediates.push_back(nDaughters);
406  nTracks += nDaughters;
407  }
408 
409  // Now find any remaining reconstructable tracks from the mother
410  while ((daughterLocator = manipulateDecayDescriptor.find(chargeIndicator)) != std::string::npos)
411  {
412  daughter = manipulateDecayDescriptor.substr(0, daughterLocator);
413  std::string daughterChargeString = manipulateDecayDescriptor.substr(daughterLocator + 1, 1);
414  if (std::find(std::begin(specialTracks), std::end(specialTracks), daughter) != std::end(specialTracks))
415  {
416  daughter += daughterChargeString;
417  }
418  if (findParticle(daughter))
419  {
420  daughters_name.emplace_back(daughter.c_str());
421  if (daughterChargeString == "+")
422  {
423  daughters_charge.push_back(+1);
424  }
425  else if (daughterChargeString == "-")
426  {
427  daughters_charge.push_back(-1);
428  }
429  else if (daughterChargeString == "0")
430  {
431  daughters_charge.push_back(0);
432  }
433  else
434  {
435  if (Verbosity() >= VERBOSITY_MORE)
436  {
437  std::cout << "The charge of " << daughterChargeString << " was not known" << std::endl;
438  }
439  ddCanBeParsed = false;
440  }
441  }
442  else
443  {
444  ddCanBeParsed = false;
445  }
446  manipulateDecayDescriptor.erase(0, daughterLocator + 2);
447  nTracks += 1;
448  }
449 
450  int trackEnd = 0;
451  for (unsigned int i = 0; i < intermediates_name.size(); ++i)
452  {
453  int trackStart = trackEnd;
454  trackEnd = m_nTracksFromIntermediates[i] + trackStart;
455 
456  int vtxCharge = 0;
457 
458  for (int j = trackStart; j < trackEnd; ++j)
459  {
460  vtxCharge += daughters_charge[j];
461  }
462 
463  intermediates_charge.push_back(vtxCharge);
464 
465  intermediate_list.emplace_back(intermediates_name[i], intermediates_charge[i]);
466  }
467 
468  for (int i = 0; i < nTracks; ++i)
469  {
470  daughter_list.emplace_back(daughters_name[i], daughters_charge[i]);
471  }
472 
473  setMotherName(mother);
474  setNumberOfTracks(nTracks);
475  setDaughters(daughter_list);
476 
477  if (intermediates_name.size() > 0)
478  {
479  hasIntermediateStates(true);
480  setIntermediateStates(intermediate_list);
481  setNumberOfIntermediateStates(intermediates_name.size());
482  setNumberTracksFromIntermeditateState(m_nTracksFromIntermediates);
483  }
484 
485  if (ddCanBeParsed)
486  {
487  if (Verbosity() >= VERBOSITY_MORE)
488  {
489  std::cout << "Your decay descriptor can be parsed" << std::endl;
490  }
491  return 0;
492  }
493  else
494  {
495  if (Verbosity() >= VERBOSITY_SOME)
496  {
497  std::cout << "KFParticle: Your decay descriptor, " << Name() << " cannot be parsed"
498  << "\nExiting!" << std::endl;
499  }
501  }
502 }