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