Belle II Software  release-05-02-19
ParticleKinematicFitterModule.cc
1 /**************************************************************************
2  * BASF2 (Belle Analysis Framework 2) *
3  * Copyright(C) 2017 - Belle II Collaboration *
4  * *
5  * Author: The Belle II Collaboration *
6  * Contributors: Torben Ferber (torben.ferber@desy.de) *
7  * Yu Hu (yu.hu@desy.de) *
8  * *
9  * This software is provided "as is" without any warranty. *
10  **************************************************************************/
11 #include <sstream>
12 #define SSTR( x ) dynamic_cast< std::ostringstream & >(( std::ostringstream() << std::dec << x ) ).str()
13 
14 // kinfitter
15 #include <analysis/modules/ParticleKinematicFitter/ParticleKinematicFitterModule.h>
16 #include <analysis/OrcaKinFit/BaseFitObject.h>
17 #include <analysis/OrcaKinFit/OPALFitterGSL.h>
18 #include <analysis/OrcaKinFit/JetFitObject.h>
19 #include <analysis/OrcaKinFit/NewtonFitterGSL.h>
20 #include <analysis/OrcaKinFit/NewFitterGSL.h>
21 #include <analysis/OrcaKinFit/PxPyPzMFitObject.h>
22 
23 #include <mdst/dataobjects/ECLCluster.h>
24 
25 // framework utilities
26 #include <framework/logging/Logger.h>
27 
28 // analysis dataobjects
29 #include <analysis/dataobjects/Particle.h>
30 #include <analysis/dataobjects/ParticleList.h>
31 
32 // analysis utilities
33 #include <analysis/utility/PCmsLabTransform.h>
34 #include <analysis/utility/ParticleCopy.h>
35 
36 using namespace CLHEP;
37 using namespace std;
38 
39 namespace Belle2 {
44  namespace OrcaKinFit {
45 
46 
47 
48  //-----------------------------------------------------------------
49  // Register module
50  //-----------------------------------------------------------------
51 
52  REG_MODULE(ParticleKinematicFitter)
53 
54  //-----------------------------------------------------------------
55  // Implementation
56  //-----------------------------------------------------------------
57 
58  ParticleKinematicFitterModule::ParticleKinematicFitterModule() : Module(), m_textTracer(nullptr), m_eventextrainfo("",
59  DataStore::c_Event)
60  {
61  setDescription("Kinematic fitter for modular analysis");
62  setPropertyFlags(c_ParallelProcessingCertified);
63 
64  // Add parameters
65  addParam("listName", m_listName, "Name of particle list.", string(""));
66  addParam("kinematicFitter", m_kinematicFitter, "Available: OrcaKinFit.", string("OrcaKinFit"));
67  addParam("orcaFitterEngine", m_orcaFitterEngine, "OrcaKinFit engine: NewFitterGSL, NewtonFitterGSL, OPALFitterGSL.",
68  string("OPALFitterGSL"));
69  addParam("orcaTracer", m_orcaTracer, "OrcaKinFit tracer: None, Text.", string("None"));
70  addParam("orcaConstraint", m_orcaConstraint, "OrcaKinFit constraint: HardBeam, RecoilMass.", string("HardBeam"));
71  addParam("debugFitter", m_debugFitter, "Switch on/off internal debugging output if available.", false);
72  addParam("debugFitterLevel", m_debugFitterLevel, "Internal debugging output level if available.", 10);
73  addParam("addUnmeasuredPhoton", m_addUnmeasuredPhoton, "Add one unmeasured photon (-3C).", false);
74  addParam("add3CPhoton", m_add3CPhoton, "Add one photon with unmeasured energy (-1C).", false);
75  addParam("decayString", m_decayString, "Specifies which daughter particles are included in the kinematic fit.", string(""));
76  addParam("updateMother", m_updateMother, "Update the mother kinematics.", true);
77  addParam("updateDaughters", m_updateDaughters, "Update the daughter kinematics.", false);
78  addParam("recoilMass", m_recoilMass, "Recoil mass in GeV. RecoilMass constraint only.", 0.0);
79  addParam("invMass", m_invMass, "Invariant mass in GeV. Mass constraint only.", 0.0);
80 
81  }
82 
83 
84  void ParticleKinematicFitterModule::initialize()
85  {
86  m_eventextrainfo.registerInDataStore();
87 
88  if (m_decayString != "") {
89  m_decaydescriptor.init(m_decayString);
90  B2INFO("ParticleKinematicFitter: Using specified decay string: " << m_decayString);
91  }
92  }
93 
94 
95  void ParticleKinematicFitterModule::beginRun()
96  {
97  B2INFO("ParticleKinematicFitterModule::beginRun");
98  }
99 
100  void ParticleKinematicFitterModule::endRun()
101  {
102  B2INFO("ParticleKinematicFitterModule::endRun");
103  }
104 
105  void ParticleKinematicFitterModule::terminate()
106  {
107  B2INFO("ParticleKinematicFitterModule::terminate");
108  }
109 
110 
111  void ParticleKinematicFitterModule::event()
112  {
113  B2DEBUG(17, "ParticleKinematicFitterModule::event");
114 
115  StoreObjPtr<ParticleList> plist(m_listName);
116  if (!plist) {
117  B2ERROR("ParticleList " << m_listName << " not found");
118  return;
119  }
120 
121  unsigned int n = plist->getListSize();
122 
123  for (unsigned i = 0; i < n; i++) {
124  Particle* particle = plist->getParticle(i);
125 
126  if (m_updateDaughters == true) {
127  if (m_decayString.empty()) ParticleCopy::copyDaughters(particle);
128  else B2ERROR("Daughters update works only when all daughters are selected. Daughters will not be updated");
129  }
130 
131  bool ok = doKinematicFit(particle);
132 
133  if (!ok) particle->setPValue(-1.);
134  }
135 
136  }
137 
138 
139  bool ParticleKinematicFitterModule::doKinematicFit(Particle* mother)
140  {
141 
142  B2DEBUG(17, "ParticleKinematicFitterModule::doKinematicFit");
143 
144  bool ok = false;
145 
146  // fitting with OrcaKinFit
147  if (m_kinematicFitter == "OrcaKinFit") {
148 
149  // select subset of particles for the fit
150  if (m_decayString != "") {
151  B2FATAL("ParticleKinematicFitterModule: OrcaKinFit does not support yet selection of daughters via decay string!") ;
152  }
153 
154  // check requested fit engine
155  if (!(m_orcaFitterEngine == "OPALFitterGSL" or
156  m_orcaFitterEngine == "NewtonFitterGSL" or
157  m_orcaFitterEngine == "NewFitterGSL")) {
158  B2FATAL("ParticleKinematicFitterModule: " << m_orcaFitterEngine << " is an invalid OrcaKinFit fitter engine!");
159  }
160 
161  // check requested constraint
162  if (!(m_orcaConstraint == "HardBeam" or
163  m_orcaConstraint == "RecoilMass" or
164  m_orcaConstraint == "Mass")) {
165  B2FATAL("ParticleKinematicFitterModule: " << m_orcaConstraint << " is an invalid OrcaKinFit constraint!");
166  }
167 
168  // basic check is good, go to fitting routine
169  ok = doOrcaKinFitFit(mother);
170 
171  }
172  // invalid fitter
173  else {
174  B2FATAL("ParticleKinematicFitter: " << m_kinematicFitter << " is an invalid kinematic fitter!");
175  }
176 
177  if (!ok) return false;
178 
179  return true;
180 
181  }
182 
183 //==========================================================================
184  bool ParticleKinematicFitterModule::doOrcaKinFitFit(Particle* mother)
185  {
186  if (mother->getNDaughters() <= 1) {
187  B2WARNING("ParticleKinematicFitterModule: Cannot fit with " << mother->getNDaughters() << " daughters.");
188  return false;
189  }
190 
191  // fill particles
192  std::vector<Particle*> particleChildren;
193  bool validChildren = fillFitParticles(mother, particleChildren);
194 
195  if (!validChildren) {
196  B2WARNING("ParticleKinematicFitterModule: Cannot find valid children for the fit.");
197  return false;
198  }
199 
200  // set fit engine
201  BaseFitter* pfitter;
202 
203  // internal debugger
204  int debugfitter = 0;
205  if (m_debugFitter) debugfitter = m_debugFitterLevel;
206 
207  // choose minimization
208  if (m_orcaFitterEngine == "OPALFitterGSL") {
209  pfitter = new OPALFitterGSL(); // OPAL fitter has no debugger
210  } else if (m_orcaFitterEngine == "NewtonFitterGSL") {
211  pfitter = new NewtonFitterGSL();
212  (dynamic_cast<NewtonFitterGSL*>(pfitter))->setDebug(debugfitter);
213  } else if (m_orcaFitterEngine == "NewFitterGSL") {
214  pfitter = new NewFitterGSL();
215  (dynamic_cast<NewFitterGSL*>(pfitter))->setDebug(debugfitter);
216  } else {
217  B2FATAL("ParticleKinematicFitterModule: " << m_orcaFitterEngine << " is an invalid OrcaKinFit fitter engine!");
218  return false;
219  }
220 
221  if (!pfitter) return false;
222  BaseFitter& fitter(*pfitter);
223 
224  // reset fitter
225  resetFitter(fitter);
226 
227  // set constraints (not connected to a fitter or particles at this point!)
228  setConstraints();
229 
230  // add fit particles from particle list to the fitter and to all constraints
231  for (unsigned iChild = 0; iChild < particleChildren.size(); iChild++) {
232  addParticleToOrcaKinFit(fitter, particleChildren[iChild], iChild);
233  }
234 
235  // add unmeasured photon to the fitter and to all constraints
236  if (m_addUnmeasuredPhoton) addUnmeasuredGammaToOrcaKinFit(fitter);
237 
238  // add constraints to the fitter
239  addConstraintsToFitter(fitter);
240 
241  // add tracers to the fitter
242  addTracerToFitter(fitter);
243 
244  //store information before the fit
245  storeOrcaKinFitParticles("Measured", fitter, particleChildren, mother);
246 
247  double prob = fitter.fit();
248  double chi2 = fitter.getChi2();
249  int niter = fitter.getIterations();
250  int ndof = fitter.getDoF();
251  int errorcode = fitter.getError();
252 
253 
254  B2DEBUG(17, "ParticleKinematicFitterModule: -------------------------------------------");
255  B2DEBUG(17, "ParticleKinematicFitterModule: Fit result of OrcaKinFit using " << m_orcaFitterEngine);
256  B2DEBUG(17, "ParticleKinematicFitterModule: prob " << prob);
257  B2DEBUG(17, "ParticleKinematicFitterModule: chi2 " << chi2);
258  B2DEBUG(17, "ParticleKinematicFitterModule: iterations " << niter);
259  B2DEBUG(17, "ParticleKinematicFitterModule: ndf " << ndof);
260  B2DEBUG(17, "ParticleKinematicFitterModule: errorcode " << errorcode);
261  B2DEBUG(17, "ParticleKinematicFitterModule: -------------------------------------------");
262 
263  // default update mother information
264  if (m_updateMother) updateOrcaKinFitMother(fitter, particleChildren, mother);
265 
266  // update daughter information if that is requested
267  if (m_updateDaughters) updateOrcaKinFitDaughters(fitter, mother);
268 
269  // store information after the fit
270  storeOrcaKinFitParticles("Fitted", fitter, particleChildren, mother);
271 
272  //store general fit results
273  mother->addExtraInfo("OrcaKinFitProb", prob);
274  mother->addExtraInfo("OrcaKinFitChi2", chi2);
275  mother->addExtraInfo("OrcaKinFitErrorCode", errorcode);
276 
277  // if we added an unmeasured photon, add the kinematics to the mother - at some point we may want to create a particle list from this?
278  if (m_addUnmeasuredPhoton) {
279  std::vector <BaseFitObject*>* fitObjectContainer = fitter.getFitObjects();
280  for (auto fo : *fitObjectContainer) {
281  const std::string name = fo->getName();
282  if (name == "unmeasured") {
283  auto* fitobject = static_cast<ParticleFitObject*>(fo);
284  TLorentzVector tlv = getTLorentzVector(fitobject);
285  mother->addExtraInfo("OrcaKinFitUnmeasuredTheta", tlv.Theta());
286  mother->addExtraInfo("OrcaKinFitUnmeasuredPhi", tlv.Phi());
287  mother->addExtraInfo("OrcaKinFitUnmeasuredE", tlv.E());
288 
289  // Uncertainty
290 // const double err0 = getFitObjectError(fitobject, 0);
291  mother->addExtraInfo("OrcaKinFitUnmeasuredErrorTheta", getFitObjectError(fitobject, 1));
292  mother->addExtraInfo("OrcaKinFitUnmeasuredErrorPhi", getFitObjectError(fitobject, 2));
293  mother->addExtraInfo("OrcaKinFitUnmeasuredErrorE", getFitObjectError(fitobject, 0));
294 
295  }
296  }
297  }
298 
299  delete pfitter;
300  delete m_textTracer;
301  return true;
302  }
303 
304  bool ParticleKinematicFitterModule::fillFitParticles(Particle* mother, std::vector<Particle*>& particleChildren)
305  {
306  for (unsigned ichild = 0; ichild < mother->getNDaughters(); ichild++) {
307  auto* child = const_cast<Particle*>(mother->getDaughter(ichild));
308 
309  if (child->getNDaughters() > 0) {
310  bool err = fillFitParticles(child, particleChildren);
311  if (!err) {
312  B2WARNING("ParticleKinematicFitterModule: Cannot find valid children for the fit.");
313  return false;
314  }
315  } else if (child->getPValue() > 0) {
316  particleChildren.push_back(child);
317  } else {
318  B2ERROR("Daughter with PDG code " << child->getPDGCode() << " does not have a valid p-value: p=" << child->getPValue() << ", E=" <<
319  child->getEnergy() << " GeV");
320  return false; // error matrix not valid
321  }
322  }
323  return true;
324  }
325 
326  bool ParticleKinematicFitterModule::AddFour(Particle* mother)
327  {
328  TMatrixFSym MomentumVertexErrorMatrix(7);
329  for (unsigned ichild = 0; ichild < mother->getNDaughters(); ichild++) {
330  auto* child = const_cast<Particle*>(mother->getDaughter(ichild));
331 
332  if (child->getPValue() > 0) {
333  MomentumVertexErrorMatrix += child->getMomentumVertexErrorMatrix();
334  } else if (child->getNDaughters() > 0) {
335  AddFour(child);
336  MomentumVertexErrorMatrix += child->getMomentumVertexErrorMatrix();
337  } else {
338  B2ERROR("Daughter with PDG code " << child->getPDGCode() << " does not have a valid p-value: p=" << child->getPValue() << ", E=" <<
339  child->getEnergy() << " GeV");
340  return false; // error matrix not valid
341  }
342  }
343  mother->setMomentumVertexErrorMatrix(MomentumVertexErrorMatrix);
344  return true;
345  }
346 
347 
348  void ParticleKinematicFitterModule::addParticleToOrcaKinFit(BaseFitter& fitter, Particle* particle, const int index)
349  {
350  B2DEBUG(17, "ParticleKinematicFitterModule: adding a particle to the fitter!");
351 
352  if (m_add3CPhoton && index == 0) {
353  if (particle -> getPDGCode() != 22) {
354  B2ERROR("In 3C Kinematic fit, the first daughter should be the Unmeasured Photon!");
355  }
356 
357  double startingE = particle -> getECLCluster() -> getEnergy(particle -> getECLClusterEHypothesisBit());
358  double startingPhi = particle -> getECLCluster() -> getPhi();
359  double startingTheta = particle -> getECLCluster() -> getTheta();
360 
361  double startingeE = particle->getECLCluster() -> getUncertaintyEnergy();
362  double startingePhi = particle->getECLCluster() -> getUncertaintyPhi();
363  double startingeTheta = particle->getECLCluster() -> getUncertaintyTheta();
364 
365  B2DEBUG(17, startingPhi << " " << startingTheta << " " << startingePhi << " " << startingeTheta);
366  // create a fit object
367  ParticleFitObject* pfitobject;
368  pfitobject = new JetFitObject(startingE, startingTheta, startingPhi, startingeE, startingeTheta, startingePhi, 0.);
369  pfitobject->setParam(0, startingE, false, false);
370  pfitobject->setParam(1, startingTheta, true, false);
371  pfitobject->setParam(2, startingPhi, true, false);
372 
373  std::string fitObjectName = "unmeasured";
374  pfitobject->setName(fitObjectName.c_str());
375  ParticleFitObject& fitobject = *pfitobject;
376 
377  // add this fit object (=particle) to the constraints
378  addFitObjectToConstraints(fitobject);
379 
380  // add fit particle to the fitter
381  fitter.addFitObject(fitobject);
382 
383  } else {
384  // four vector
385  CLHEP::HepLorentzVector clheplorentzvector = getCLHEPLorentzVector(particle);
386 
387  // error matrix
388  CLHEP::HepSymMatrix clhepmomentumerrormatrix = getCLHEPMomentumErrorMatrix(particle);
389 
390  // create the fit object (ParticleFitObject is the base class)
391  ParticleFitObject* pfitobject;
392  pfitobject = new PxPyPzMFitObject(clheplorentzvector, clhepmomentumerrormatrix);
393  std::string fitObjectName = "particle_" + SSTR(index);
394  pfitobject->setName(fitObjectName.c_str());
395  ParticleFitObject& fitobject = *pfitobject;
396 
397  // add this fit object (=particle) to the constraints
398  addFitObjectToConstraints(fitobject);
399 
400  // add fit particle to the fitter
401  fitter.addFitObject(fitobject);
402  }
403 
404 
405  return;
406  }
407 
408 
409  CLHEP::HepSymMatrix ParticleKinematicFitterModule::getCLHEPMomentumErrorMatrix(Particle* particle)
410  {
411  CLHEP::HepSymMatrix covMatrix(4);
412  TMatrixFSym errMatrix = particle->getMomentumErrorMatrix();
413 
414  for (int i = 0; i < 4; i++) {
415  for (int j = 0; j < 4; j++) {
416  covMatrix[i][j] = errMatrix[i][j];
417  }
418  }
419 
420  return covMatrix;
421  }
422 
423 
424  CLHEP::HepSymMatrix ParticleKinematicFitterModule::getCLHEPMomentumVertexErrorMatrix(Particle* particle)
425  {
426  CLHEP::HepSymMatrix covMatrix(7);
427  TMatrixFSym errMatrix = particle->getMomentumVertexErrorMatrix();
428 
429  for (int i = 0; i < 7; i++) {
430  for (int j = 0; j < 7; j++) {
431  covMatrix[i][j] = errMatrix[i][j];
432  }
433  }
434 
435  return covMatrix;
436  }
437 
438 
439  CLHEP::HepLorentzVector ParticleKinematicFitterModule::getCLHEPLorentzVector(Particle* particle)
440  {
441  CLHEP::HepLorentzVector mom(particle->getPx(), particle->getPy(), particle->getPz(), particle->getEnergy());
442  return mom;
443  }
444 
445 
446  TLorentzVector ParticleKinematicFitterModule::getTLorentzVector(ParticleFitObject* fitobject)
447  {
448  TLorentzVector mom(fitobject->getPx(), fitobject->getPy(), fitobject->getPz(), fitobject->getE());
449  return mom;
450  }
451 
452 
453  // TMatrixFSym ParticleKinematicFitterModule::getTMatrixFSymMomentumErrorMatrix(ParticleFitObject* fitobject) //fix the warning
454  TMatrixFSym ParticleKinematicFitterModule::getTMatrixFSymMomentumErrorMatrix()
455  {
456  TMatrixFSym errMatrix(4);
457 
458  for (int i = 0; i < 4; i++) {
459  for (int j = i; j < 4; j++) {
460  errMatrix[i][j] = 0.0;
461  }
462  }
463 
464  return errMatrix;
465  }
466 
467  // TMatrixFSym ParticleKinematicFitterModule::getTMatrixFSymMomentumVertexErrorMatrix(ParticleFitObject* fitobject) //fix the warning
468  TMatrixFSym ParticleKinematicFitterModule::getTMatrixFSymMomentumVertexErrorMatrix()
469  {
470  TMatrixFSym errMatrix(7);
471 
472  for (int i = 0; i < 7; i++) {
473  for (int j = i; j < 7; j++) {
474  errMatrix[i][j] = 0.0;
475  }
476  }
477 
478  return errMatrix;
479  }
480 
481  TLorentzVector ParticleKinematicFitterModule::getTLorentzVectorConstraints()
482  {
483 
484  if (m_orcaConstraint == "HardBeam") {
485  TLorentzVector constraints4vector(m_hardConstraintPx.getValue(),
486  m_hardConstraintPy.getValue(),
487  m_hardConstraintPz.getValue(),
488  m_hardConstraintE.getValue());
489  return constraints4vector;
490  } else {
491  B2FATAL("ParticleKinematicFitterModule: " << m_orcaConstraint << " is an invalid OrcaKinFit constraint!");
492  }
493 
494  // should not reach this point...
495  return TLorentzVector(0., 0., 0., 0.);
496  }
497 
498 
499  void ParticleKinematicFitterModule::setConstraints()
500  {
501 
502  if (m_orcaConstraint == "HardBeam") {
504  const TLorentzVector boost = T.getBeamFourMomentum();
505 
506  m_hardConstraintPx = MomentumConstraint(0, 1, 0, 0, boost.Px());
507  m_hardConstraintPy = MomentumConstraint(0, 0, 1, 0, boost.Py());
508  m_hardConstraintPz = MomentumConstraint(0, 0, 0, 1, boost.Pz());
509  m_hardConstraintE = MomentumConstraint(1, 0, 0, 0, boost.E());
510 
511  m_hardConstraintPx.resetFOList();
512  m_hardConstraintPy.resetFOList();
513  m_hardConstraintPz.resetFOList();
514  m_hardConstraintE.resetFOList();
515 
516  m_hardConstraintPx.setName("Sum(p_x) [hard]");
517  m_hardConstraintPy.setName("Sum(p_y) [hard]");
518  m_hardConstraintPz.setName("Sum(p_z) [hard]");
519  m_hardConstraintE.setName("Sum(E) [hard]");
520 
521  } else if (m_orcaConstraint == "RecoilMass") {
523  const TLorentzVector boost = T.getBeamFourMomentum();
524 
525  m_hardConstraintRecoilMass = RecoilMassConstraint(m_recoilMass, boost.Px(), boost.Py(), boost.Pz(), boost.E());
526 
527  m_hardConstraintRecoilMass.resetFOList();
528  m_hardConstraintRecoilMass.setName("Recoil Mass [hard]");
529 
530  } else if (m_orcaConstraint == "Mass") {
531  m_hardConstraintMass = MassConstraint(m_invMass);
532 
533  m_hardConstraintMass.resetFOList();
534  m_hardConstraintMass.setName("Mass [hard]");
535  } else {
536  B2FATAL("ParticleKinematicFitterModule: " << m_orcaConstraint << " is an invalid OrcaKinFit constraint!");
537  }
538  }
539 
540 
541  void ParticleKinematicFitterModule::resetFitter(BaseFitter& fitter)
542  {
543  B2DEBUG(17, "ParticleKinematicFitterModule: Resetting the fitter");
544  fitter.reset();
545  }
546 
547 
548  void ParticleKinematicFitterModule::addFitObjectToConstraints(ParticleFitObject& fitobject)
549  {
550 
551  if (m_orcaConstraint == "HardBeam") {
552  m_hardConstraintPx.addToFOList(fitobject);
553  m_hardConstraintPy.addToFOList(fitobject);
554  m_hardConstraintPz.addToFOList(fitobject);
555  m_hardConstraintE.addToFOList(fitobject);
556  } else if (m_orcaConstraint == "RecoilMass") {
557  m_hardConstraintRecoilMass.addToFOList(fitobject);
558  } else if (m_orcaConstraint == "Mass") {
559  m_hardConstraintMass.addToFOList(fitobject);
560  } else {
561  B2FATAL("ParticleKinematicFitterModule: " << m_orcaConstraint << " is an invalid OrcaKinFit constraint!");
562  }
563 
564  }
565 
566 
567  void ParticleKinematicFitterModule::addConstraintsToFitter(BaseFitter& fitter)
568  {
569  if (m_orcaConstraint == "HardBeam") {
570  fitter.addConstraint(m_hardConstraintPx);
571  fitter.addConstraint(m_hardConstraintPy);
572  fitter.addConstraint(m_hardConstraintPz);
573  fitter.addConstraint(m_hardConstraintE);
574  } else if (m_orcaConstraint == "RecoilMass") {
575  fitter.addConstraint(m_hardConstraintRecoilMass);
576  } else if (m_orcaConstraint == "Mass") {
577  fitter.addConstraint(m_hardConstraintMass);
578  }
579 
580  else {
581  B2FATAL("ParticleKinematicFitterModule: " << m_orcaConstraint << " is an invalid OrcaKinFit constraint!");
582  }
583  }
584 
585 
586  void ParticleKinematicFitterModule::addTracerToFitter(BaseFitter& fitter)
587  {
588  if (m_orcaTracer == "Text") {
589  m_textTracer = new TextTracer(std::cout);
590  fitter.setTracer(m_textTracer);
591  } else if (m_orcaTracer != "None") {
592  B2FATAL("ParticleKinematicFitterModule: " << m_orcaTracer << " is an invalid OrcaKinFit tracer!");
593  }
594  }
595 
596  void ParticleKinematicFitterModule::addUnmeasuredGammaToOrcaKinFit(BaseFitter& fitter)
597  {
598  // Initialize photon using the existing constraints
599  TLorentzVector tlv = getTLorentzVectorConstraints();
600  double startingE = tlv.E();
601  double startingPhi = tlv.Phi();
602  double startingTheta = tlv.Theta();
603 
604  // create a fit object
605  ParticleFitObject* pfitobject;
606  pfitobject = new JetFitObject(startingE, startingTheta, startingPhi, 0.0, 0.0, 0.0, 0.);
607  pfitobject->setParam(0, startingE, false, false);
608  pfitobject->setParam(1, startingTheta, false, false);
609  pfitobject->setParam(2, startingPhi, false, false);
610 
611  std::string fitObjectName = "unmeasured";
612  pfitobject->setName(fitObjectName.c_str());
613  ParticleFitObject& fitobject = *pfitobject;
614 
615  // add this fit object (=particle) to the constraints
616  addFitObjectToConstraints(fitobject);
617 
618  // add fit particle to the fitter
619  fitter.addFitObject(fitobject);
620 
621  }
622 
623  bool ParticleKinematicFitterModule::updateOrcaKinFitDaughters(BaseFitter& fitter, Particle* mother)
624  {
625 
626  std::vector <Belle2::Particle*> bDau = mother->getDaughters();
627  std::vector <BaseFitObject*>* fitObjectContainer = fitter.getFitObjects();
628 
629  const unsigned nd = bDau.size();
630  unsigned l = 0;
631  std::vector<std::vector<unsigned>> pars;
632  std::vector<Particle*> allparticles;
633  for (unsigned ichild = 0; ichild < nd; ichild++) {
634  const Particle* daughter = mother->getDaughter(ichild);
635  std::vector<unsigned> pard;
636  if (daughter->getNDaughters() > 0) {
637  updateMapOfTrackAndDaughter(l, pars, pard, allparticles, daughter);
638  pars.push_back(pard);
639  allparticles.push_back(bDau[ichild]);
640  } else {
641  pard.push_back(l);
642  pars.push_back(pard);
643  allparticles.push_back(bDau[ichild]);
644  l++;
645  }
646  }
647 
648  if (l == fitObjectContainer->size() - m_addUnmeasuredPhoton) {
649 
650  if (fitter.getError() == 0) {
651  for (unsigned iDaug = 0; iDaug < allparticles.size(); iDaug++) {
652  TLorentzVector tlv ;
653  TMatrixFSym errMatrixU(7);
654  if (pars[iDaug].size() > 0) {
655  for (unsigned int iChild : pars[iDaug]) {
656  BaseFitObject* fo = fitObjectContainer->at(iChild);
657  auto* fitobject = static_cast<ParticleFitObject*>(fo);
658  TLorentzVector tlv_sub = getTLorentzVector(fitobject);
659  TMatrixFSym errMatrixU_sub = getCovMat7(fitobject);
660  tlv = tlv + tlv_sub;
661  errMatrixU = errMatrixU + errMatrixU_sub;
662  }
663  } else {
664  B2FATAL("ParticleKinematicFitterModule: no fitObject could be used to update the daughter!");
665  }
666  TVector3 pos = allparticles[iDaug]->getVertex(); // we don't update the vertex yet
667  TMatrixFSym errMatrix = allparticles[iDaug]->getMomentumVertexErrorMatrix();
668  TMatrixFSym errMatrixMom = allparticles[iDaug]->getMomentumErrorMatrix();
669  TMatrixFSym errMatrixVer = allparticles[iDaug]->getVertexErrorMatrix();
670 
671  for (int i = 0; i < 3; i++) {
672  for (int j = i; j < 3; j++) {
673  errMatrixU[i + 4][j + 4] = errMatrixVer[i][j];
674  }
675  }
676 
677  allparticles[iDaug]->set4Vector(tlv);
678  allparticles[iDaug]->setVertex(pos);
679  allparticles[iDaug]->setMomentumVertexErrorMatrix(errMatrixU);
680  }
681  }
682 
683  return true;
684  } else {
685  B2ERROR("updateOrcaKinFitDaughters: Cannot update daughters, mismatch between number of daughters and number of fitobjects!");
686  return false;
687  }
688 
689  }
690 
691  void ParticleKinematicFitterModule::updateMapOfTrackAndDaughter(unsigned& l, std::vector<std::vector<unsigned>>& pars,
692  std::vector<unsigned>& parm, std::vector<Particle*>& allparticles, const Particle* daughter)
693  {
694  std::vector <Belle2::Particle*> dDau = daughter->getDaughters();
695  for (unsigned ichild = 0; ichild < daughter->getNDaughters(); ichild++) {
696  const Particle* child = daughter->getDaughter(ichild);
697  std::vector<unsigned> pard;
698  if (child->getNDaughters() > 0) {
699  updateMapOfTrackAndDaughter(l, pars, pard, allparticles, child);
700  parm.insert(parm.end(), pard.begin(), pard.end());
701  pars.push_back(pard);
702  allparticles.push_back(dDau[ichild]);
703  } else {
704  pard.push_back(l);
705  parm.push_back(l);
706  pars.push_back(pard);
707  allparticles.push_back(dDau[ichild]);
708  l++;
709  }
710  }
711  }
712 
713 
714  void ParticleKinematicFitterModule::updateOrcaKinFitMother(BaseFitter& fitter, std::vector<Particle*>& particleChildren,
715  Particle* mother)
716  {
717  // get old values
718  TVector3 pos = mother->getVertex();
719  TMatrixFSym errMatrix = mother->getMomentumVertexErrorMatrix();
720  float pvalue = mother->getPValue();
721 
722  // update momentum vector
723  TLorentzVector momnew(0., 0., 0., 0.);
724 
725  std::vector <BaseFitObject*>* fitObjectContainer = fitter.getFitObjects();
726  for (unsigned iChild = 0; iChild < particleChildren.size(); iChild++) {
727  BaseFitObject* fo = fitObjectContainer->at(iChild);
728  auto* fitobject = static_cast<ParticleFitObject*>(fo);
729  TLorentzVector tlv = getTLorentzVector(fitobject);
730  momnew += tlv;
731  }
732 
733  // update
734  // TODO: use pvalue of the fit or the old one of the mother? use fit covariance matrix?
735  // Maybe here should use the pvalue and errmatrix of the fit ----Yu Hu
736  mother->updateMomentum(momnew, pos, errMatrix, pvalue);
737  }
738 
739 
740  bool ParticleKinematicFitterModule::storeOrcaKinFitParticles(const std::string& prefix, BaseFitter& fitter,
741  std::vector<Particle*>& particleChildren, Particle* mother)
742  {
743  bool updated = false;
744  std::vector <BaseFitObject*>* fitObjectContainer = fitter.getFitObjects();
745 
746  for (unsigned iChild = 0; iChild < particleChildren.size(); iChild++) {
747  BaseFitObject* fo = fitObjectContainer->at(iChild);
748  auto* fitobject = static_cast<ParticleFitObject*>(fo);
749  TLorentzVector tlv = getTLorentzVector(fitobject);
750 
751  // name of extra variables
752  std::string extraVariableParticlePx = "OrcaKinFit" + prefix + "_" + SSTR(iChild) + "_Px";
753  std::string extraVariableParticlePy = "OrcaKinFit" + prefix + "_" + SSTR(iChild) + "_Py";
754  std::string extraVariableParticlePz = "OrcaKinFit" + prefix + "_" + SSTR(iChild) + "_Pz";
755  std::string extraVariableParticleE = "OrcaKinFit" + prefix + "_" + SSTR(iChild) + "_E";
756  std::string extraVariableParticlePxErr = "OrcaKinFit" + prefix + "_" + SSTR(iChild) + "_PxErr";
757  std::string extraVariableParticlePyErr = "OrcaKinFit" + prefix + "_" + SSTR(iChild) + "_PyErr";
758  std::string extraVariableParticlePzErr = "OrcaKinFit" + prefix + "_" + SSTR(iChild) + "_PzErr";
759  std::string extraVariableParticleEErr = "OrcaKinFit" + prefix + "_" + SSTR(iChild) + "_EErr";
760 
761  mother->addExtraInfo(extraVariableParticlePx, tlv.Px());
762  mother->addExtraInfo(extraVariableParticlePy, tlv.Py());
763  mother->addExtraInfo(extraVariableParticlePz, tlv.Pz());
764  mother->addExtraInfo(extraVariableParticleE, tlv.E());
765  mother->addExtraInfo(extraVariableParticlePxErr, getFitObjectError(fitobject, 0));
766  mother->addExtraInfo(extraVariableParticlePyErr, getFitObjectError(fitobject, 1));
767  mother->addExtraInfo(extraVariableParticlePzErr, getFitObjectError(fitobject, 2));
768  mother->addExtraInfo(extraVariableParticleEErr, -1.0);
769 
770  }
771 
772  return updated;
773  }
774 
775  float ParticleKinematicFitterModule::getFitObjectError(ParticleFitObject* fitobject, int ilocal)
776  {
777  //check if it is a PxPyPzMFitObject
778  auto* pxpypzmfitobject = static_cast<PxPyPzMFitObject*>(fitobject);
779  if (pxpypzmfitobject) {
780  return fitobject->getError(ilocal);
781  } else {
782  B2FATAL("ParticleKinematicFitterModule: not implemented yet");
783  }
784  }
785 
786  // this returns the local covariance matrix
787  TMatrixFSym ParticleKinematicFitterModule::getFitObjectCovMat(ParticleFitObject* fitobject)
788  {
789 
790  //check if it is a PxPyPzMFitObject
791  auto* pxpypzmfitobject = static_cast<PxPyPzMFitObject*>(fitobject);
792  if (pxpypzmfitobject) {
793 
794  TMatrixFSym errMatrix(3);
795 
796  //loop over the i-j local variables.
797  for (int i = 0; i < 3; i++) {
798  for (int j = 0; j < 3; j++) {
799  errMatrix[i][j] = pxpypzmfitobject->getCov(i, j);
800  }
801  }
802 
803  return errMatrix;
804  } else {
805  B2FATAL("ParticleKinematicFitterModule: not implemented yet");
806  }
807 
808  }
809 
810 
811  TMatrixFSym ParticleKinematicFitterModule::getCovMat7(ParticleFitObject* fitobject)
812  {
813  TMatrixFSym fitCovMatrix(3);
814 
815  if (strcmp(fitobject->getParamName(0), "E") == 0) {
816  //check if it is a JetFitObject
817  auto* jetfitObject = static_cast<JetFitObject*>(fitobject);
818  if (jetfitObject) {
819 
820  fitCovMatrix = getFitObjectCovMat(fitobject);
821  TLorentzVector tlv = getTLorentzVector(fitobject);
822 
823  const double energy = tlv.E();
824  const double theta = tlv.Theta();
825  const double phi = tlv.Phi();
826 
827  const double st = sin(theta);
828  const double ct = cos(theta);
829  const double sp = sin(phi);
830  const double cp = cos(phi);
831 
832  // updated covariance matrix is: A * cov * A^T where A is the Jacobi matrix (use Similarity)
833  TMatrixF A(7, 3);
834  A(0, 0) = cp * st ; // dpx/dE
835  A(0, 1) = energy * cp * ct ; // dpx/dtheta
836  A(0, 2) = -energy * sp * st ; // dpx/dphi
837  A(1, 0) = sp * st ; // dpy/dE
838  A(1, 1) = energy * sp * ct ; // dpz/dtheta
839  A(1, 2) = energy * cp * st ; // dpy/dphi
840  A(2, 0) = ct ; // dpz/dE
841  A(2, 1) = -energy * st ; // dpz/dtheta
842  A(2, 2) = 0 ; // dpz/dphi
843  A(3, 0) = 1.0; // dE/dE
844  A(3, 1) = 0.0; // dE/dphi
845  A(3, 2) = 0.0; // dE/dtheta
846 
847  TMatrixFSym D = fitCovMatrix.Similarity(A);
848  return D;
849 
850  } else {
851  B2FATAL("ParticleKinematicFitterModule: not implemented yet");
852  }
853  } else {
854  //check if it is a PxPyPzMFitObject
855  auto* pxpypzmfitobject = static_cast<PxPyPzMFitObject*>(fitobject);
856  if (pxpypzmfitobject) {
857 
858  fitCovMatrix = getFitObjectCovMat(fitobject);
859 
860  // updated covariance matrix is: A * cov * A^T where A is the Jacobi matrix (use Similarity)
861  TLorentzVector tlv = getTLorentzVector(fitobject);
862  TMatrixF A(7, 3);
863  A[0][0] = 1.; // px/dpx
864  A[0][1] = 0.; // px/dpy
865  A[0][2] = 0.; // px/dpz
866  A[1][0] = 0.; // py/dpx
867  A[1][1] = 1.; // py/dpy
868  A[1][2] = 0.; // py/dpz
869  A[2][0] = 0.; // pz/dpx
870  A[2][1] = 0.; // pz/dpy
871  A[2][2] = 1.; // pz/dpz
872  if (tlv.E() > 0.0) {
873  A[3][0] = tlv.Px() / tlv.E(); // E/dpx, E=sqrt(px^2 + py^2 + pz^2 + m^2)
874  A[3][1] = tlv.Py() / tlv.E(); // E/dpy
875  A[3][2] = tlv.Pz() / tlv.E(); // E/dpz
876  }
877 
878  TMatrixFSym D = fitCovMatrix.Similarity(A);
879 
880  return D;
881  } else {
882  B2FATAL("ParticleKinematicFitterModule: not implemented yet");
883  }
884  }
885  }
886 
887 
888  }// end OrcaKinFit namespace
890 } // end Belle2 namespace
Belle2::OrcaKinFit::NewFitterGSL
A kinematic fitter using the Newton-Raphson method to solve the equations.
Definition: NewFitterGSL.h:65
Belle2::OrcaKinFit::BaseFitter
Abstract base class for fitting engines of kinematic fits.
Definition: BaseFitter.h:61
Belle2::OrcaKinFit::ParticleFitObject::getE
virtual double getE() const
Return E.
Definition: ParticleFitObject.cc:106
REG_MODULE
#define REG_MODULE(moduleName)
Register the given module (without 'Module' suffix) with the framework.
Definition: Module.h:652
Belle2::OrcaKinFit::MassConstraint
Implements constraint 0 = mass1 - mass2 - m.
Definition: MassConstraint.h:60
Belle2::OrcaKinFit::MomentumConstraint
Implements a constraint of the form efact*sum(E)+pxfact*sum(px)+pyfact*sum(py)+pzfact*sum(pz)=value.
Definition: MomentumConstraint.h:55
Belle2::OrcaKinFit::TextTracer
Definition: TextTracer.h:59
Belle2::OrcaKinFit::ParticleFitObject::getPx
virtual double getPx() const
Return px.
Definition: ParticleFitObject.cc:110
Belle2::Module
Base class for Modules.
Definition: Module.h:74
Belle2
Abstract base class for different kinds of events.
Definition: MillepedeAlgorithm.h:19
Belle2::StoreObjPtr
Type-safe access to single objects in the data store.
Definition: ParticleList.h:33
Belle2::PCmsLabTransform::getBeamFourMomentum
TLorentzVector getBeamFourMomentum() const
Returns LAB four-momentum of e+e-.
Definition: PCmsLabTransform.h:65
Belle2::OrcaKinFit::ParticleFitObject::getPy
virtual double getPy() const
Return py.
Definition: ParticleFitObject.cc:114
Belle2::OrcaKinFit::RecoilMassConstraint
Definition: RecoilMassConstraint.h:39
Belle2::OrcaKinFit::NewtonFitterGSL
Definition: NewtonFitterGSL.h:52
Belle2::Particle
Class to store reconstructed particles.
Definition: Particle.h:77
Belle2::OrcaKinFit::OPALFitterGSL
Description of the fit algorithm and interface:
Definition: OPALFitterGSL.h:102
Belle2::PCmsLabTransform
Class to hold Lorentz transformations from/to CMS and boost vector.
Definition: PCmsLabTransform.h:37
Belle2::OrcaKinFit::JetFitObject
Class for jets with (E, eta, phi) in kinematic fits.
Definition: JetFitObject.h:57
Belle2::OrcaKinFit::PxPyPzMFitObject
Definition: PxPyPzMFitObject.h:40
Belle2::OrcaKinFit::ParticleKinematicFitterModule
Kinematic fitter module.
Definition: ParticleKinematicFitterModule.h:67
Belle2::DataStore
In the store you can park objects that have to be accessed by various modules.
Definition: DataStore.h:53
Belle2::OrcaKinFit::ParticleFitObject
Definition: ParticleFitObject.h:93
Belle2::OrcaKinFit::ParticleFitObject::getPz
virtual double getPz() const
Return pz.
Definition: ParticleFitObject.cc:118