Belle II Software  release-06-02-00
MillepedeCollectorModule.cc
1 /**************************************************************************
2  * basf2 (Belle II Analysis Software Framework) *
3  * Author: The Belle II Collaboration *
4  * *
5  * See git log for contributors and copyright holders. *
6  * This file is licensed under LGPL-3.0, see LICENSE.md. *
7  **************************************************************************/
8 
9 #include <alignment/modules/MillepedeCollector/MillepedeCollectorModule.h>
10 
11 #include <alignment/dataobjects/MilleData.h>
12 #include <alignment/GblMultipleScatteringController.h>
13 #include <alignment/GlobalDerivatives.h>
14 #include <alignment/GlobalLabel.h>
15 #include <alignment/GlobalParam.h>
16 #include <alignment/GlobalTimeLine.h>
17 #include <alignment/Manager.h>
18 #include <alignment/reconstruction/AlignableCDCRecoHit.h>
19 #include <alignment/reconstruction/AlignablePXDRecoHit.h>
20 #include <alignment/reconstruction/AlignableSVDRecoHit.h>
21 #include <alignment/reconstruction/AlignableSVDRecoHit2D.h>
22 #include <alignment/reconstruction/AlignableBKLMRecoHit.h>
23 #include <alignment/reconstruction/AlignableEKLMRecoHit.h>
24 #include <analysis/dataobjects/ParticleList.h>
25 #include <analysis/utility/ReferenceFrame.h>
26 #include <framework/core/FileCatalog.h>
27 #include <framework/database/DBObjPtr.h>
28 #include <framework/dataobjects/EventT0.h>
29 #include <framework/dataobjects/FileMetaData.h>
30 #include <framework/datastore/StoreArray.h>
31 #include <framework/datastore/StoreObjPtr.h>
32 #include <framework/dbobjects/BeamParameters.h>
33 #include <framework/particledb/EvtGenDatabasePDG.h>
34 #include <framework/pcore/ProcHandler.h>
35 #include <mdst/dbobjects/BeamSpot.h>
36 #include <mdst/dataobjects/Track.h>
37 #include <tracking/trackFitting/fitter/base/TrackFitter.h>
38 #include <tracking/trackFitting/measurementCreator/adder/MeasurementAdder.h>
39 
40 #include <genfit/FullMeasurement.h>
41 #include <genfit/GblFitter.h>
42 #include <genfit/KalmanFitterInfo.h>
43 #include <genfit/PlanarMeasurement.h>
44 #include <genfit/Track.h>
45 
46 #include <TMath.h>
47 #include <TH1F.h>
48 #include <TTree.h>
49 #include <TDecompSVD.h>
50 
51 using namespace std;
52 using namespace Belle2;
53 using namespace alignment;
54 
55 //-----------------------------------------------------------------
56 // Register the Module
57 //-----------------------------------------------------------------
58 REG_MODULE(MillepedeCollector)
59 
60 //-----------------------------------------------------------------
61 // Implementation
62 //-----------------------------------------------------------------
63 
65 {
66  setPropertyFlags(c_ParallelProcessingCertified);
67  setDescription("Calibration data collector for Millepede Algorithm");
68 
69  // Configure input sample types
70  addParam("tracks", m_tracks, "Names of collections of RecoTracks (already fitted with DAF) for calibration", vector<string>({""}));
71  addParam("particles", m_particles, "Names of particle list of single particles", vector<string>());
72  addParam("vertices", m_vertices,
73  "Name of particle list of (mother) particles with daughters for calibration using vertex constraint", vector<string>());
74  addParam("primaryVertices", m_primaryVertices,
75  "Name of particle list of (mother) particles with daughters for calibration using vertex + IP profile constraint",
76  vector<string>());
77  addParam("twoBodyDecays", m_twoBodyDecays,
78  "Name of particle list of (mother) particles with daughters for calibration using vertex + mass constraint",
79  vector<string>());
80  addParam("primaryTwoBodyDecays", m_primaryTwoBodyDecays,
81  "Name of particle list of (mother) particles with daughters for calibration using vertex + IP profile + kinematics constraint",
82  vector<string>());
83  addParam("primaryMassTwoBodyDecays", m_primaryMassTwoBodyDecays,
84  "Name of particle list of (mother) particles with daughters for calibration using vertex + mass constraint",
85  vector<string>());
86  addParam("primaryMassVertexTwoBodyDecays", m_primaryMassVertexTwoBodyDecays,
87  "Name of particle list of (mother) particles with daughters for calibration using vertex + IP profile + mass constraint",
88  vector<string>());
89 
90  addParam("stableParticleWidth", m_stableParticleWidth,
91  "Width (in GeV/c/c) to use for invariant mass constraint for 'stable' particles (like K short). Temporary until proper solution is found.",
92  double(0.002));
93  // Configure output
94  addParam("doublePrecision", m_doublePrecision, "Use double (=true) or single/float (=false) precision for writing binary files",
95  bool(false));
96  addParam("useGblTree", m_useGblTree, "Store GBL trajectories in a tree instead of output to binary files",
97  bool(true));
98  addParam("absFilePaths", m_absFilePaths, "Use absolute paths to remember binary files. Only applies if useGblTree=False",
99  bool(false));
100 
101  // Configure global parameters
102  addParam("components", m_components,
103  "Specify which DB objects are calibrated, like ['BeamSpot', 'CDCTimeWalks'] or leave empty to use all components available.",
104  m_components);
105  addParam("calibrateVertex", m_calibrateVertex,
106  "For primary vertices / two body decays, beam spot vertex calibration derivatives are added",
107  bool(true));
108  addParam("calibrateKinematics", m_calibrateKinematics,
109  "For primary two body decays, beam spot kinematics calibration derivatives are added",
110  bool(true));
111 
112  //Configure GBL fit of individual tracks
113  addParam("externalIterations", m_externalIterations, "Number of external iterations of GBL fitter",
114  int(0));
115  addParam("internalIterations", m_internalIterations, "String defining internal GBL iterations for outlier down-weighting",
116  string(""));
117  addParam("recalcJacobians", m_recalcJacobians, "Up to which external iteration propagation Jacobians should be re-calculated",
118  int(0));
119 
120  addParam("minPValue", m_minPValue, "Minimum p-value to write out a (combined) trajectory. Set <0 to write out all.",
121  double(-1.));
122 
123  // Configure CDC specific options
124  addParam("fitTrackT0", m_fitTrackT0, "Add local parameter for track T0 fit in GBL",
125  bool(true));
126  addParam("updateCDCWeights", m_updateCDCWeights, "Update L/R weights from previous DAF fit result",
127  bool(true));
128  addParam("minCDCHitWeight", m_minCDCHitWeight, "Minimum (DAF) CDC hit weight for usage by GBL",
129  double(1.0E-6));
130  addParam("minUsedCDCHitFraction", m_minUsedCDCHitFraction, "Minimum used CDC hit fraction to write out a trajectory",
131  double(0.85));
132 
133  addParam("hierarchyType", m_hierarchyType, "Type of (VXD only now) hierarchy: 0 = None, 1 = Flat, 2 = Half-Shells, 3 = Full",
134  int(3));
135  addParam("enablePXDHierarchy", m_enablePXDHierarchy, "Enable PXD in hierarchy (flat or full)",
136  bool(true));
137  addParam("enableSVDHierarchy", m_enableSVDHierarchy, "Enable SVD in hierarchy (flat or full)",
138  bool(true));
139 
140  addParam("enableWireByWireAlignment", m_enableWireByWireAlignment, "Enable global derivatives for wire-by-wire alignment",
141  bool(false));
142  addParam("enableWireSagging", m_enableWireSagging, "Enable global derivatives for wire sagging",
143  bool(false));
144 
145  // Time dependence
146  addParam("events", m_eventNumbers,
147  "List of (event, run, exp) with event numbers at which payloads can change for timedep calibration.",
148  m_eventNumbers);
149  // Time dependence config
150  addParam("timedepConfig", m_timedepConfig,
151  "list{ {list{param1, param2, ...}, list{(ev1, run1, exp1), ...}}, ... }.",
152  m_timedepConfig);
153 
154  // Custom mass+width config
155  addParam("customMassConfig", m_customMassConfig,
156  "dict{ list_name: (mass, width), ... } with custom mass and width to use as external measurement.",
157  m_customMassConfig);
158 }
159 
160 void MillepedeCollectorModule::prepare()
161 {
163  emd.isRequired();
164 
165  StoreObjPtr<EventT0> eventT0;
166  //eventT0.isRequired();
167 
168  if (m_tracks.empty() &&
169  m_particles.empty() &&
170  m_vertices.empty() &&
171  m_primaryVertices.empty() &&
172  m_twoBodyDecays.empty() &&
173  m_primaryTwoBodyDecays.empty() &&
174  m_primaryMassTwoBodyDecays.empty() &&
175  m_primaryMassVertexTwoBodyDecays.empty())
176  B2ERROR("You have to specify either arrays of single tracks or particle lists of single single particles or mothers with vertex constrained daughters.");
177 
178  if (!m_tracks.empty()) {
179  for (auto arrayName : m_tracks)
180  continue;
181  // StoreArray<RecoTrack>::required(arrayName);
182  }
183 
184  if (!m_particles.empty() || !m_vertices.empty() || !m_primaryVertices.empty()) {
185  StoreArray<RecoTrack> recoTracks;
186  StoreArray<Track> tracks;
187  StoreArray<TrackFitResult> trackFitResults;
188 
189  //recoTracks.isRequired();
190  //tracks.isRequired();
191  //trackFitResults.isRequired();
192  }
193 
194  for (auto listName : m_particles) {
195  StoreObjPtr<ParticleList> list(listName);
196  //list.isRequired();
197  }
198 
199  for (auto listName : m_vertices) {
200  StoreObjPtr<ParticleList> list(listName);
201  //list.isRequired();
202  }
203 
204  for (auto listName : m_primaryVertices) {
205  StoreObjPtr<ParticleList> list(listName);
206  //list.isRequired();
207  }
208 
209  // Register Mille output
210  registerObject<MilleData>("mille", new MilleData(m_doublePrecision, m_absFilePaths));
211 
212  auto gblDataTree = new TTree("GblDataTree", "GblDataTree");
213  gblDataTree->Branch<std::vector<gbl::GblData>>("GblData", &m_currentGblData, 32000, 99);
214  registerObject<TTree>("GblDataTree", gblDataTree);
215 
216  registerObject<TH1I>("ndf", new TH1I("ndf", "ndf", 200, 0, 200));
217  registerObject<TH1F>("chi2_per_ndf", new TH1F("chi2_per_ndf", "chi2 divided by ndf", 200, 0., 50.));
218  registerObject<TH1F>("pval", new TH1F("pval", "pval", 100, 0., 1.));
219 
220  registerObject<TH1F>("cdc_hit_fraction", new TH1F("cdc_hit_fraction", "cdc_hit_fraction", 100, 0., 1.));
221  registerObject<TH1F>("evt0", new TH1F("evt0", "evt0", 400, -100., 100.));
222 
223  // Configure the (VXD) hierarchy before being built
224  if (m_hierarchyType == 0)
225  Belle2::alignment::VXDGlobalParamInterface::s_hierarchyType = VXDGlobalParamInterface::c_None;
226  else if (m_hierarchyType == 1)
227  Belle2::alignment::VXDGlobalParamInterface::s_hierarchyType = VXDGlobalParamInterface::c_Flat;
228  else if (m_hierarchyType == 2)
229  Belle2::alignment::VXDGlobalParamInterface::s_hierarchyType = VXDGlobalParamInterface::c_HalfShells;
230  else if (m_hierarchyType == 3)
231  Belle2::alignment::VXDGlobalParamInterface::s_hierarchyType = VXDGlobalParamInterface::c_Full;
232 
235 
236  std::vector<EventMetaData> events;
237  for (auto& ev_run_exp : m_eventNumbers) {
238  events.push_back(EventMetaData(std::get<0>(ev_run_exp), std::get<1>(ev_run_exp), std::get<2>(ev_run_exp)));
239  }
240 
241  // This will also build the hierarchy for the first time:
242  if (!m_timedepConfig.empty() && m_eventNumbers.empty()) {
243  auto autoEvents = Belle2::alignment::timeline::setupTimedepGlobalLabels(m_timedepConfig);
245  } else if (m_timedepConfig.empty() && !m_eventNumbers.empty()) {
247  } else if (m_timedepConfig.empty() && m_eventNumbers.empty()) {
249  } else {
250  B2ERROR("Cannot set both, event list and timedep config.");
251  }
252 
253 // Belle2::alignment::GlobalCalibrationManager::getInstance().writeConstraints("constraints.txt");
254 
255  AlignableCDCRecoHit::s_enableTrackT0LocalDerivative = m_fitTrackT0;
256  AlignableCDCRecoHit::s_enableWireSaggingGlobalDerivative = m_enableWireSagging;
257  AlignableCDCRecoHit::s_enableWireByWireAlignmentGlobalDerivatives = m_enableWireByWireAlignment;
258 }
259 
260 void MillepedeCollectorModule::collect()
261 {
263  alignment::GlobalCalibrationManager::getInstance().preCollect(*emd);
264  StoreObjPtr<EventT0> eventT0;
265 
266  if (!m_useGblTree) {
267  // Open new file on request (at start or after being closed)
268  auto mille = getObjectPtr<MilleData>("mille");
269  if (!mille->isOpen())
270  mille->open(getUniqueMilleName());
271  }
272 
273  std::shared_ptr<genfit::GblFitter> gbl(new genfit::GblFitter());
274  double chi2 = -1.;
275  double lostWeight = -1.;
276  int ndf = -1;
277  float evt0 = -9999.;
278 
279  for (auto arrayName : m_tracks) {
280  StoreArray<RecoTrack> recoTracks(arrayName);
281  if (!recoTracks.isValid())
282  continue;
283 
284  for (auto& recoTrack : recoTracks) {
285 
286  if (!fitRecoTrack(recoTrack))
287  continue;
288 
289  auto& track = RecoTrackGenfitAccess::getGenfitTrack(recoTrack);
290  if (!track.hasFitStatus())
291  continue;
292  genfit::GblFitStatus* fs = dynamic_cast<genfit::GblFitStatus*>(track.getFitStatus());
293  if (!fs)
294  continue;
295 
296  if (!fs->isFittedWithReferenceTrack())
297  continue;
298 
299  using namespace gbl;
300  GblTrajectory trajectory(gbl->collectGblPoints(&track, track.getCardinalRep()), fs->hasCurvature());
301 
302  trajectory.fit(chi2, ndf, lostWeight);
303  getObjectPtr<TH1I>("ndf")->Fill(ndf);
304  getObjectPtr<TH1F>("chi2_per_ndf")->Fill(chi2 / double(ndf));
305  getObjectPtr<TH1F>("pval")->Fill(TMath::Prob(chi2, ndf));
306  if (eventT0.isValid() && eventT0->hasEventT0()) {
307  evt0 = eventT0->getEventT0();
308  getObjectPtr<TH1F>("evt0")->Fill(evt0);
309  }
310 
311  if (TMath::Prob(chi2, ndf) > m_minPValue) storeTrajectory(trajectory);
312 
313  }
314 
315  }
316 
317  for (auto listName : m_particles) {
318  StoreObjPtr<ParticleList> list(listName);
319  if (!list.isValid())
320  continue;
321 
322  for (unsigned int iParticle = 0; iParticle < list->getListSize(); ++iParticle) {
323  for (auto& track : getParticlesTracks({list->getParticle(iParticle)}, false)) {
324  auto gblfs = dynamic_cast<genfit::GblFitStatus*>(track->getFitStatus());
325 
326  gbl::GblTrajectory trajectory(gbl->collectGblPoints(track, track->getCardinalRep()), gblfs->hasCurvature());
327 
328  trajectory.fit(chi2, ndf, lostWeight);
329  getObjectPtr<TH1I>("ndf")->Fill(ndf);
330  getObjectPtr<TH1F>("chi2_per_ndf")->Fill(chi2 / double(ndf));
331  getObjectPtr<TH1F>("pval")->Fill(TMath::Prob(chi2, ndf));
332  if (eventT0.isValid() && eventT0->hasEventT0()) {
333  evt0 = eventT0->getEventT0();
334  getObjectPtr<TH1F>("evt0")->Fill(evt0);
335  }
336 
337  if (TMath::Prob(chi2, ndf) > m_minPValue) storeTrajectory(trajectory);
338 
339  }
340  }
341  }
342 
343  for (auto listName : m_vertices) {
344  StoreObjPtr<ParticleList> list(listName);
345  if (!list.isValid())
346  continue;
347 
348  for (unsigned int iParticle = 0; iParticle < list->getListSize(); ++iParticle) {
349  auto mother = list->getParticle(iParticle);
350  std::vector<std::pair<std::vector<gbl::GblPoint>, TMatrixD> > daughters;
351 
352  for (auto& track : getParticlesTracks(mother->getDaughters()))
353  daughters.push_back({
354  gbl->collectGblPoints(track, track->getCardinalRep()),
355  getGlobalToLocalTransform(track->getFittedState()).GetSub(0, 4, 0, 2)
356  });
357 
358  if (daughters.size() > 1) {
359  gbl::GblTrajectory combined(daughters);
360 
361  combined.fit(chi2, ndf, lostWeight);
362  getObjectPtr<TH1I>("ndf")->Fill(ndf);
363  getObjectPtr<TH1F>("chi2_per_ndf")->Fill(chi2 / double(ndf));
364  getObjectPtr<TH1F>("pval")->Fill(TMath::Prob(chi2, ndf));
365  if (eventT0.isValid() && eventT0->hasEventT0()) {
366  evt0 = eventT0->getEventT0();
367  getObjectPtr<TH1F>("evt0")->Fill(evt0);
368  }
369 
370 
371  if (TMath::Prob(chi2, ndf) > m_minPValue) storeTrajectory(combined);
372 
373  B2RESULT("Vertex-constrained fit NDF = " << ndf << " Chi2/NDF = " << chi2 / double(ndf));
374 
375  }
376  }
377  }
378 
379  for (auto listName : m_primaryVertices) {
380  StoreObjPtr<ParticleList> list(listName);
381  if (!list.isValid())
382  continue;
383 
384  for (unsigned int iParticle = 0; iParticle < list->getListSize(); ++iParticle) {
385  auto mother = list->getParticle(iParticle);
386  std::vector<std::pair<std::vector<gbl::GblPoint>, TMatrixD> > daughters;
387 
388  TMatrixD extProjection(5, 3);
389  TMatrixD locProjection(3, 5);
390 
391  bool first(true);
392  for (auto& track : getParticlesTracks(mother->getDaughters())) {
393  if (first) {
394  // For first trajectory only
395  extProjection = getGlobalToLocalTransform(track->getFittedState()).GetSub(0, 4, 0, 2);
396  locProjection = getLocalToGlobalTransform(track->getFittedState()).GetSub(0, 2, 0, 4);
397  first = false;
398  }
399  daughters.push_back({
400  gbl->collectGblPoints(track, track->getCardinalRep()),
401  getGlobalToLocalTransform(track->getFittedState()).GetSub(0, 4, 0, 2)
402  });
403  }
404 
405  if (daughters.size() > 1) {
406  auto beam = getPrimaryVertexAndCov();
407 
408  TMatrixDSym vertexCov(get<TMatrixDSym>(beam));
409  TMatrixDSym vertexPrec(get<TMatrixDSym>(beam).Invert());
410  B2Vector3D vertexResidual = - (mother->getVertex() - get<B2Vector3D>(beam));
411 
412  TVectorD extMeasurements(3);
413  extMeasurements[0] = vertexResidual[0];
414  extMeasurements[1] = vertexResidual[1];
415  extMeasurements[2] = vertexResidual[2];
416 
417  TMatrixD extDeriv(3, 3);
418  extDeriv.Zero();
419  // beam vertex constraint
420  extDeriv(0, 0) = 1.;
421  extDeriv(1, 1) = 1.;
422  extDeriv(2, 2) = 1.;
423 
424  if (m_calibrateVertex) {
425  TMatrixD derivatives(3, 3);
426  derivatives.Zero();
427  derivatives(0, 0) = 1.;
428  derivatives(1, 1) = 1.;
429  derivatives(2, 2) = 1.;
430 
431  std::vector<int> labels;
432  GlobalLabel label = GlobalLabel::construct<BeamSpot>(0, 0);
433  labels.push_back(label.setParameterId(1));
434  labels.push_back(label.setParameterId(2));
435  labels.push_back(label.setParameterId(3));
436 
437  // Allow to disable BeamSpot externally
438  alignment::GlobalDerivatives globals(labels, derivatives);
439  // Add derivatives for vertex calibration to first point of first trajectory
440  // NOTE: use GlobalDerivatives operators vector<int> and TMatrixD which filter
441  // the derivatives to not pass those with zero labels (usefull to get rid of some params)
442  std::vector<int> lab(globals); TMatrixD der(globals);
443 
444  // Transformation from local system at (vertex) point to global (vx,vy,vz)
445  // of the (decay) vertex
446  //
447  // d(q/p,u',v',u,v)/d(vy,vy,vz) = dLocal_dExt
448  //
449  //
450  // Note its transpose is its "inverse" in the sense that
451  //
452  // dloc/dext * (dloc/dext)^T = diag(0, 0, 0, 0, 1, 1)
453  //
454  //
455  // N.B. typical dLocal_dExt matrix (5x3):
456  //
457  // | 0 | 1 | 2 |
458  // --------------------------------------------
459  // 0 | 0 0 0
460  // 1 | 0 0 0
461  // 2 | 0 0 0
462  // 3 | -0.02614 -0.9997 0
463  // 4 | 0 0 1
464  //
465  // Therefore one can simplify things by only taking the last two rows/columns in vectors/matrices
466  // and vertex measurement can be expressed as standard 2D measurement in GBL.
467  //
468  TMatrixD dLocal_dExt = extProjection;
469  TMatrixD dExt_dLocal = locProjection;
470 
471  TVectorD locRes = dLocal_dExt * extMeasurements;
472  // Do not use inverted covariance - seems to have issues with numeric precision
473  TMatrixD locCov = dLocal_dExt * vertexCov * dExt_dLocal;
474  // Invert here only the 2D sub-matrix (rest is zero due to the foÅ•m of dLocal_dExt)
475  TMatrixD locPrec = locCov.GetSub(3, 4, 3, 4).Invert();
476  TMatrixDSym locPrec2D(2); locPrec2D.Zero();
477  for (int i = 0; i < 2; ++i)
478  for (int j = 0; j < 2; ++j)
479  locPrec2D(i, j) = locPrec(i, j);
480 
481  // Take the 2 last components also for residuals and global derivatives
482  // (in local system of vertex point - defined during fitRecoTrack(..., particle) and using
483  // the (hopefully) updated momentum and position seed after vertex fit by modularAnalysis
484  TVectorD locRes2D = locRes.GetSub(3, 4);
485  TMatrixD locDerivs2D = (extProjection * der).GetSub(3, 4, 0, 2);
486 
487  // Attach the primary beamspot vertex position as a measurement at 1st point
488  // of first trajectory (and optionaly also the global derivatives for beamspot alignment
489  daughters[0].first[0].addMeasurement(locRes2D, locPrec2D);
490  if (!lab.empty()) {
491  daughters[0].first[0].addGlobals(lab, locDerivs2D);
492  }
493 
494  gbl::GblTrajectory combined(daughters);
495  //combined.printTrajectory(100);
496  //combined.printPoints(100);
497 
498  combined.fit(chi2, ndf, lostWeight);
499  getObjectPtr<TH1I>("ndf")->Fill(ndf);
500  getObjectPtr<TH1F>("chi2_per_ndf")->Fill(chi2 / double(ndf));
501  getObjectPtr<TH1F>("pval")->Fill(TMath::Prob(chi2, ndf));
502  if (eventT0.isValid() && eventT0->hasEventT0()) {
503  evt0 = eventT0->getEventT0();
504  getObjectPtr<TH1F>("evt0")->Fill(evt0);
505  }
506 
507  if (TMath::Prob(chi2, ndf) > m_minPValue) storeTrajectory(combined);
508  B2RESULT("Beam vertex constrained fit results NDF = " << ndf << " Chi2/NDF = " << chi2 / double(ndf));
509 
510  } else {
511 
512  gbl::GblTrajectory combined(daughters, extDeriv, extMeasurements, vertexPrec);
513 
514  combined.fit(chi2, ndf, lostWeight);
515  getObjectPtr<TH1I>("ndf")->Fill(ndf);
516  getObjectPtr<TH1F>("chi2_per_ndf")->Fill(chi2 / double(ndf));
517  getObjectPtr<TH1F>("pval")->Fill(TMath::Prob(chi2, ndf));
518  if (eventT0.isValid() && eventT0->hasEventT0()) {
519  evt0 = eventT0->getEventT0();
520  getObjectPtr<TH1F>("evt0")->Fill(evt0);
521  }
522 
523  if (TMath::Prob(chi2, ndf) > m_minPValue) storeTrajectory(combined);
524 
525  B2RESULT("Beam vertex constrained fit results NDF = " << ndf << " Chi2/NDF = " << chi2 / double(ndf));
526 
527  }
528  }
529  }
530  }
531 
532  for (auto listName : m_twoBodyDecays) {
533  StoreObjPtr<ParticleList> list(listName);
534  if (!list.isValid())
535  continue;
536 
537  for (unsigned int iParticle = 0; iParticle < list->getListSize(); ++iParticle) {
538 
539  auto mother = list->getParticle(iParticle);
540  auto track12 = getParticlesTracks(mother->getDaughters());
541  if (track12.size() != 2) {
542  B2ERROR("Did not get 2 fitted tracks. Skipping this mother.");
543  continue;
544  }
545 
546  auto pdgdb = EvtGenDatabasePDG::Instance();
547  double motherMass = mother->getPDGMass();
548  double motherWidth = pdgdb->GetParticle(mother->getPDGCode())->Width();
549 
550  updateMassWidthIfSet(listName, motherMass, motherWidth);
551 
552  //TODO: what to take as width for "real" particles? -> make a param for default detector mass resolution??
553  if (motherWidth == 0.) {
554  motherWidth = m_stableParticleWidth * Unit::GeV;
555  B2WARNING("Using artificial width for " << pdgdb->GetParticle(mother->getPDGCode())->GetName() << " : " << motherWidth << " GeV");
556  }
557 
558  auto dfdextPlusMinus = getTwoBodyToLocalTransform(*mother, motherMass);
559  std::vector<std::pair<std::vector<gbl::GblPoint>, TMatrixD> > daughters;
560 
561  daughters.push_back({gbl->collectGblPoints(track12[0], track12[0]->getCardinalRep()), dfdextPlusMinus.first});
562  daughters.push_back({gbl->collectGblPoints(track12[1], track12[1]->getCardinalRep()), dfdextPlusMinus.second});
563 
564  TMatrixDSym massPrec(1); massPrec(0, 0) = 1. / motherWidth / motherWidth;
565  TVectorD massResidual(1); massResidual = - (mother->getMass() - motherMass);
566 
567  TVectorD extMeasurements(1);
568  extMeasurements[0] = massResidual[0];
569 
570  TMatrixD extDeriv(1, 9);
571  extDeriv.Zero();
572  extDeriv(0, 8) = 1.;
573 
574  gbl::GblTrajectory combined(daughters, extDeriv, extMeasurements, massPrec);
575 
576  combined.fit(chi2, ndf, lostWeight);
577  //combined.printTrajectory(1000);
578  //combined.printPoints(1000);
579  getObjectPtr<TH1I>("ndf")->Fill(ndf);
580  getObjectPtr<TH1F>("chi2_per_ndf")->Fill(chi2 / double(ndf));
581  getObjectPtr<TH1F>("pval")->Fill(TMath::Prob(chi2, ndf));
582  if (eventT0.isValid() && eventT0->hasEventT0()) {
583  evt0 = eventT0->getEventT0();
584  getObjectPtr<TH1F>("evt0")->Fill(evt0);
585  }
586 
587 
588  B2RESULT("Mass(PDG) + vertex constrained fit results NDF = " << ndf << " Chi2/NDF = " << chi2 / double(ndf));
589 
590  if (TMath::Prob(chi2, ndf) > m_minPValue) storeTrajectory(combined);
591 
592  }
593  }
594 
595  for (auto listName : m_primaryMassTwoBodyDecays) {
596  StoreObjPtr<ParticleList> list(listName);
597  if (!list.isValid())
598  continue;
599 
601 
602  double motherMass = beam->getMass();
603  double motherWidth = sqrt((beam->getCovHER() + beam->getCovLER())(0, 0));
604 
605  updateMassWidthIfSet(listName, motherMass, motherWidth);
606 
607  for (unsigned int iParticle = 0; iParticle < list->getListSize(); ++iParticle) {
608 
609  auto mother = list->getParticle(iParticle);
610  auto track12 = getParticlesTracks(mother->getDaughters());
611  if (track12.size() != 2) {
612  B2ERROR("Did not get 2 fitted tracks. Skipping this mother.");
613  continue;
614  }
615 
616  auto dfdextPlusMinus = getTwoBodyToLocalTransform(*mother, motherMass);
617  std::vector<std::pair<std::vector<gbl::GblPoint>, TMatrixD> > daughters;
618 
619  daughters.push_back({gbl->collectGblPoints(track12[0], track12[0]->getCardinalRep()), dfdextPlusMinus.first});
620  daughters.push_back({gbl->collectGblPoints(track12[1], track12[1]->getCardinalRep()), dfdextPlusMinus.second});
621 
622  TMatrixDSym massPrec(1); massPrec(0, 0) = 1. / motherWidth / motherWidth;
623  TVectorD massResidual(1); massResidual = - (mother->getMass() - motherMass);
624 
625  TVectorD extMeasurements(1);
626  extMeasurements[0] = massResidual[0];
627 
628  TMatrixD extDeriv(1, 9);
629  extDeriv.Zero();
630  extDeriv(0, 8) = 1.;
631 
632  gbl::GblTrajectory combined(daughters, extDeriv, extMeasurements, massPrec);
633 
634  combined.fit(chi2, ndf, lostWeight);
635  getObjectPtr<TH1I>("ndf")->Fill(ndf);
636  getObjectPtr<TH1F>("chi2_per_ndf")->Fill(chi2 / double(ndf));
637  getObjectPtr<TH1F>("pval")->Fill(TMath::Prob(chi2, ndf));
638  if (eventT0.isValid() && eventT0->hasEventT0()) {
639  evt0 = eventT0->getEventT0();
640  getObjectPtr<TH1F>("evt0")->Fill(evt0);
641  }
642 
643 
644  B2RESULT("Mass constrained fit results NDF = " << ndf << " Chi2/NDF = " << chi2 / double(ndf));
645 
646  if (TMath::Prob(chi2, ndf) > m_minPValue) storeTrajectory(combined);
647 
648  }
649  }
650 
651  for (auto listName : m_primaryMassVertexTwoBodyDecays) {
652  StoreObjPtr<ParticleList> list(listName);
653  if (!list.isValid())
654  continue;
655 
657 
658  double motherMass = beam->getMass();
659  double motherWidth = sqrt((beam->getCovHER() + beam->getCovLER())(0, 0));
660 
661  updateMassWidthIfSet(listName, motherMass, motherWidth);
662 
663  for (unsigned int iParticle = 0; iParticle < list->getListSize(); ++iParticle) {
664 
665  auto mother = list->getParticle(iParticle);
666  auto track12 = getParticlesTracks(mother->getDaughters());
667  if (track12.size() != 2) {
668  B2ERROR("Did not get 2 fitted tracks. Skipping this mother.");
669  continue;
670  }
671 
672  auto dfdextPlusMinus = getTwoBodyToLocalTransform(*mother, motherMass);
673  std::vector<std::pair<std::vector<gbl::GblPoint>, TMatrixD> > daughters;
674 
675  daughters.push_back({gbl->collectGblPoints(track12[0], track12[0]->getCardinalRep()), dfdextPlusMinus.first});
676  daughters.push_back({gbl->collectGblPoints(track12[1], track12[1]->getCardinalRep()), dfdextPlusMinus.second});
677 
678  TMatrixDSym vertexPrec(get<TMatrixDSym>(getPrimaryVertexAndCov()).Invert());
679  B2Vector3D vertexResidual = - (mother->getVertex() - get<B2Vector3D>(getPrimaryVertexAndCov()));
680 
681  TMatrixDSym massPrec(1); massPrec(0, 0) = 1. / motherWidth / motherWidth;
682  TVectorD massResidual(1); massResidual = - (mother->getMass() - motherMass);
683 
684  TMatrixDSym extPrec(4); extPrec.Zero();
685  extPrec.SetSub(0, 0, vertexPrec);
686  extPrec(3, 3) = massPrec(0, 0);
687 
688  TVectorD extMeasurements(4);
689  extMeasurements[0] = vertexResidual[0];
690  extMeasurements[1] = vertexResidual[1];
691  extMeasurements[2] = vertexResidual[2];
692  extMeasurements[3] = massResidual[0];
693 
694  TMatrixD extDeriv(4, 9);
695  extDeriv.Zero();
696  extDeriv(0, 0) = 1.;
697  extDeriv(1, 1) = 1.;
698  extDeriv(2, 2) = 1.;
699  extDeriv(3, 8) = 1.;
700 
701  gbl::GblTrajectory combined(daughters, extDeriv, extMeasurements, extPrec);
702 
703  combined.fit(chi2, ndf, lostWeight);
704  getObjectPtr<TH1I>("ndf")->Fill(ndf);
705  getObjectPtr<TH1F>("chi2_per_ndf")->Fill(chi2 / double(ndf));
706  getObjectPtr<TH1F>("pval")->Fill(TMath::Prob(chi2, ndf));
707  if (eventT0.isValid() && eventT0->hasEventT0()) {
708  evt0 = eventT0->getEventT0();
709  getObjectPtr<TH1F>("evt0")->Fill(evt0);
710  }
711 
712 
713  if (TMath::Prob(chi2, ndf) > m_minPValue) storeTrajectory(combined);
714 
715  B2RESULT("Mass + vertex constrained fit results NDF = " << ndf << " Chi2/NDF = " << chi2 / double(ndf));
716 
717  }
718  }
719 
720  for (auto listName : m_primaryTwoBodyDecays) {
721  B2WARNING("This should NOT be used for production of calibration constants for the real detector (yet)!");
722 
723  StoreObjPtr<ParticleList> list(listName);
724  if (!list.isValid())
725  continue;
726 
728 
729  // For the error of invariant mass M = 2 * sqrt(E_HER * E_LER) (for m_e ~ 0)
730  double M = beam->getMass();
731  double E_HER = beam->getHER().E();
732  double E_LER = beam->getLER().E();
733 
734  double pz = (beam->getHER().Vect() + beam->getLER().Vect())[2];
735  double E = (beam->getHER() + beam->getLER()).E();
736 
737  double motherMass = beam->getMass();
738  double motherWidth = sqrt((E_HER / M) * (E_HER / M) * beam->getCovLER()(0, 0) + (E_LER / M) * (E_LER / M) * beam->getCovHER()(0,
739  0));
740 
741  updateMassWidthIfSet(listName, motherMass, motherWidth);
742 
743  for (unsigned int iParticle = 0; iParticle < list->getListSize(); ++iParticle) {
744 
745  B2WARNING("Two body decays with full kinematic constraint not yet correct - need to resolve strange covariance provided by BeamParameters!");
746 
747  auto mother = list->getParticle(iParticle);
748 
749  auto track12 = getParticlesTracks(mother->getDaughters());
750  if (track12.size() != 2) {
751  B2ERROR("Did not get exactly 2 fitted tracks. Skipping this mother in list " << listName);
752  continue;
753  }
754 
755  auto dfdextPlusMinus = getTwoBodyToLocalTransform(*mother, motherMass);
756  std::vector<std::pair<std::vector<gbl::GblPoint>, TMatrixD> > daughters;
757 
758  daughters.push_back({gbl->collectGblPoints(track12[0], track12[0]->getCardinalRep()), dfdextPlusMinus.first});
759  daughters.push_back({gbl->collectGblPoints(track12[1], track12[1]->getCardinalRep()), dfdextPlusMinus.second});
760 
761  TMatrixDSym extCov(7); extCov.Zero();
762 
763  // 3x3 IP vertex covariance
764  extCov.SetSub(0, 0, get<TMatrixDSym>(getPrimaryVertexAndCov()));
765 
766  // 3x3 boost vector covariance
767  //NOTE: BeamSpot return covarince in variables (E, theta_x, theta_y)
768  // We need to transform it to our variables (px, py, pz)
769 
770  TMatrixD dBoost_dVect(3, 3);
771  dBoost_dVect(0, 0) = 0.; dBoost_dVect(0, 1) = 1. / pz; dBoost_dVect(0, 2) = 0.;
772  dBoost_dVect(1, 0) = 0.; dBoost_dVect(1, 1) = 0.; dBoost_dVect(1, 2) = 1. / pz;
773  dBoost_dVect(2, 0) = pz / E; dBoost_dVect(2, 1) = 0.; dBoost_dVect(2, 2) = 0.;
774 
775  TMatrixD dVect_dBoost(3, 3);
776  dVect_dBoost(0, 0) = 0.; dVect_dBoost(0, 1) = 0.; dVect_dBoost(0, 2) = E / pz;
777  dVect_dBoost(1, 0) = pz; dVect_dBoost(1, 1) = 0.; dVect_dBoost(1, 2) = 0.;
778  dVect_dBoost(2, 0) = 0.; dVect_dBoost(2, 1) = pz; dVect_dBoost(2, 2) = 0.;
779 
780  TMatrixD covBoost(3, 3);
781  for (int i = 0; i < 3; ++i) {
782  for (int j = i; j < 3; ++j) {
783  covBoost(j, i) = covBoost(i, j) = (beam->getCovHER() + beam->getCovLER())(i, j);
784  }
785  }
786  //TODO: Temporary fix: if theta_x, theta_y covariance is zero, use arbitrary 10mrad^2
787 // if (covBoost(1, 1) == 0.) covBoost(1, 1) = 1.;
788 // if (covBoost(2, 2) == 0.) covBoost(2, 2) = 1.;
789  if (covBoost(1, 1) == 0.) covBoost(1, 1) = 1.e-4;
790  if (covBoost(2, 2) == 0.) covBoost(2, 2) = 1.e-4;
791 
792  TMatrixD covVect = dBoost_dVect * covBoost * dVect_dBoost;
793 
794  extCov.SetSub(3, 3, covVect);
795 
796  extCov(6, 6) = motherWidth * motherWidth;
797  auto extPrec = extCov; extPrec.Invert();
798 
799  TVectorD extMeasurements(7);
800  extMeasurements[0] = - (mother->getVertex() - get<B2Vector3D>(getPrimaryVertexAndCov()))[0];
801  extMeasurements[1] = - (mother->getVertex() - get<B2Vector3D>(getPrimaryVertexAndCov()))[1];
802  extMeasurements[2] = - (mother->getVertex() - get<B2Vector3D>(getPrimaryVertexAndCov()))[2];
803  extMeasurements[3] = - (mother->getMomentum() - (beam->getHER().Vect() + beam->getLER().Vect()))[0];
804  extMeasurements[4] = - (mother->getMomentum() - (beam->getHER().Vect() + beam->getLER().Vect()))[1];
805  extMeasurements[5] = - (mother->getMomentum() - (beam->getHER().Vect() + beam->getLER().Vect()))[2];
806  extMeasurements[6] = - (mother->getMass() - motherMass);
807 
808  B2INFO("mother mass = " << mother->getMass() << " and beam mass = " << beam->getMass());
809 
810  TMatrixD extDeriv(7, 9);
811  extDeriv.Zero();
812  // beam vertex constraint
813  extDeriv(0, 0) = 1.;
814  extDeriv(1, 1) = 1.;
815  extDeriv(2, 2) = 1.;
816  // beam kinematics constraint
817  extDeriv(3, 3) = 1.;
818  extDeriv(4, 4) = 1.;
819  extDeriv(5, 5) = 1.;
820  // beam inv. mass constraint
821  extDeriv(6, 8) = 1;
822 
823  if (m_calibrateVertex || m_calibrateKinematics) {
824  B2WARNING("Primary vertex+kinematics calibration not (yet?) fully implemented!");
825  B2WARNING("This code is highly experimental and has (un)known issues!");
826 
827  // up to d(x,y,z,px,py,pz,theta,phi,M)/d(vx,vy,vz,theta_x,theta_y,E)
828  TMatrixD derivatives(9, 6);
829  std::vector<int> labels;
830  derivatives.Zero();
831 
832  if (m_calibrateVertex) {
833  derivatives(0, 0) = 1.;
834  derivatives(1, 1) = 1.;
835  derivatives(2, 2) = 1.;
836  GlobalLabel label = GlobalLabel::construct<BeamSpot>(0, 0);
837  labels.push_back(label.setParameterId(1));
838  labels.push_back(label.setParameterId(2));
839  labels.push_back(label.setParameterId(3));
840  } else {
841  labels.push_back(0);
842  labels.push_back(0);
843  labels.push_back(0);
844  }
845 
846  if (m_calibrateKinematics) {
847  derivatives(3, 3) = mother->getMomentumMagnitude();
848  derivatives(4, 4) = mother->getMomentumMagnitude();
849  derivatives(8, 5) = (beam->getLER().E() + beam->getHER().E()) / beam->getMass();
850 
851  GlobalLabel label = GlobalLabel::construct<BeamSpot>(0, 0);
852  labels.push_back(label.setParameterId(4)); //theta_x
853  labels.push_back(label.setParameterId(5)); //theta_y
854  labels.push_back(label.setParameterId(6)); //E
855 
856  } else {
857  labels.push_back(0);
858  labels.push_back(0);
859  labels.push_back(0);
860  }
861 
862  // Allow to disable BeamSpot externally
863  alignment::GlobalDerivatives globals(labels, derivatives);
864 
865  // Add derivatives for vertex calibration to first point of first trajectory
866  // NOTE: use GlobalDerivatives operators vector<int> and TMatrixD which filter
867  // the derivatives to not pass those with zero labels (usefull to get rid of some params)
868  std::vector<int> lab(globals); TMatrixD der(globals);
869 
870  // I want: dlocal/dext = dlocal/dtwobody * dtwobody/dext = dfdextPlusMinus * dtwobody/dext
871  TMatrixD dTwoBody_dExt(9, 7);
872  dTwoBody_dExt.Zero();
873  // beam vertex constraint
874  dTwoBody_dExt(0, 0) = 1.;
875  dTwoBody_dExt(1, 1) = 1.;
876  dTwoBody_dExt(2, 2) = 1.;
877  // beam kinematics constraint
878  dTwoBody_dExt(3, 3) = 1.;
879  dTwoBody_dExt(4, 4) = 1.;
880  dTwoBody_dExt(5, 5) = 1.;
881  // beam inv. mass constraint
882  dTwoBody_dExt(8, 6) = 1.;
883 
884  const TMatrixD dLocal_dExt = dfdextPlusMinus.first * dTwoBody_dExt;
885  TMatrixD dLocal_dExt_T = dLocal_dExt; dLocal_dExt_T.T();
886 
887  // The 5x7 transformation matrix d(q/p,u',v',u,v)/d(vx,vy,vz,px,py,pz,M) needs to be "inverted"
888  // to transform the covariance of the beamspot and boost vector of SuperKEKB into the local system
889  // of one GBL point - such that Millepede can align the beamspot (or even beam kinematics) if requested.
890  //
891  // I tested also other methods, but only the Singular Value Decomposition gives nice-enough results,
892  // with almost no code:
893  //
894  TDecompSVD svd(dLocal_dExt_T);
895  TMatrixD dExt_dLocal = svd.Invert().T();
896  //
897  // (dLocal_dExt * dExt_dLocal).Print(); // Check how close we are to unit matrix
898  //
899  // 5x5 matrix is as follows
900  //
901  // | 0 | 1 | 2 | 3 | 4 |
902  // ----------------------------------------------------------------------
903  // 0 | 1 -2.58e-17 6.939e-18 1.571e-17 -1.649e-19
904  // 1 | 1.787e-14 1 5.135e-16 -3.689e-16 -2.316e-18
905  // 2 | -1.776e-15 -7.806e-17 1 5.636e-17 6.193e-18
906  // 3 | -2.453e-15 7.26e-18 2.009e-16 1 -1.14e-16
907  // 4 | -1.689e-14 -9.593e-17 -2.317e-15 -3.396e-17 1
908  //
909  // It took me half a day to find out how to do this with 2 lines of code (3 with the include).
910  // Source: ROOT macro example - actually found at:
911  // <https://root.cern.ch/root/html/tutorials/matrix/solveLinear.C.html>
912  for (int i = 0; i < 7; ++i) {
913  for (int j = 0; j < 5; ++j) {
914  if (fabs(dExt_dLocal(i, j)) < 1.e-6)
915  dExt_dLocal(i, j) = 0.;
916  }
917  }
918  const TVectorD locRes = dLocal_dExt * extMeasurements;
919  const TMatrixD locPrec = dLocal_dExt * extPrec * dExt_dLocal;
920 
921  TMatrixDSym locPrecSym(5); locPrecSym.Zero();
922  for (int i = 0; i < 5; ++i) {
923  for (int j = i; j < 5; ++j) {
924  //locPrecSym(j, i) = locPrecSym(i, j) = locPrec(i, j);
925  locPrecSym(j, i) = locPrecSym(i, j) = (fabs(locPrec(i, j)) > 1.e-6) ? locPrec(i, j) : 0.;
926  }
927  }
928 
929  daughters[0].first[0].addMeasurement(locRes, locPrecSym);
930  if (!lab.empty())
931  daughters[0].first[0].addGlobals(lab, dfdextPlusMinus.first * der);
932 
933  //TODO: Understand this: either find a bug somewhere or improve the parametrization or .... ?
934  // This should be enough, but the parametrization seems to fail for nearly horizontal pairs...
935  //gbl::GblTrajectory combined(daughters);
936  // This should not be needed, it actually seems to make worse Chi2/NDF, but GBL does not fail.
937  // The measurement added just to be able to add the global derivatives (done just above) is redundant
938  // to the external measurement added here:
939  gbl::GblTrajectory combined(daughters, extDeriv, extMeasurements, extPrec);
940  //combined.printTrajectory(1000);
941  //combined.printPoints(1000);
942 
943  combined.fit(chi2, ndf, lostWeight);
944  getObjectPtr<TH1I>("ndf")->Fill(ndf);
945  getObjectPtr<TH1F>("chi2_per_ndf")->Fill(chi2 / double(ndf));
946  getObjectPtr<TH1F>("pval")->Fill(TMath::Prob(chi2, ndf));
947  if (eventT0.isValid() && eventT0->hasEventT0()) {
948  evt0 = eventT0->getEventT0();
949  getObjectPtr<TH1F>("evt0")->Fill(evt0);
950  }
951 
952 
953  B2RESULT("Full kinematic-constrained fit (calibration version) results NDF = " << ndf << " Chi2/NDF = " << chi2 / double(ndf));
954 
955  if (TMath::Prob(chi2, ndf) > m_minPValue) storeTrajectory(combined);
956 
957  } else {
958 
959  gbl::GblTrajectory combined(daughters, extDeriv, extMeasurements, extPrec);
960  //combined.printTrajectory(1000);
961  //combined.printPoints(1000);
962 
963  combined.fit(chi2, ndf, lostWeight);
964  getObjectPtr<TH1I>("ndf")->Fill(ndf);
965  getObjectPtr<TH1F>("chi2_per_ndf")->Fill(chi2 / double(ndf));
966  getObjectPtr<TH1F>("pval")->Fill(TMath::Prob(chi2, ndf));
967  if (eventT0.isValid() && eventT0->hasEventT0()) {
968  evt0 = eventT0->getEventT0();
969  getObjectPtr<TH1F>("evt0")->Fill(evt0);
970  }
971 
972 
973  B2RESULT("Full kinematic-constrained fit results NDF = " << ndf << " Chi2/NDF = " << chi2 / double(ndf));
974 
975  if (TMath::Prob(chi2, ndf) > m_minPValue) storeTrajectory(combined);
976  }
977  }
978  }
979 }
980 
981 void MillepedeCollectorModule::closeRun()
982 {
983  // We close the file at end of run, producing
984  // one file per run (and process id) which is more
985  // convenient than one large binary block.
986  auto mille = getObjectPtr<MilleData>("mille");
987  if (mille->isOpen())
988  mille->close();
989 }
990 
991 void MillepedeCollectorModule::finish()
992 {
994 
995  StoreObjPtr<FileMetaData> fileMetaData("", DataStore::c_Persistent);
996  if (!fileMetaData.isValid()) {
997  B2ERROR("Cannot register binaries in FileCatalog.");
998  return;
999  }
1000 
1001 
1002  const std::vector<string> parents = {fileMetaData->getLfn()};
1003  for (auto binary : getObjectPtr<MilleData>("mille")->getFiles()) {
1004  FileMetaData milleMetaData(*fileMetaData);
1005  // We reset filename to be set directly by the registerFile procedure
1006  milleMetaData.setLfn("");
1007  milleMetaData.setParents(parents);
1008  FileCatalog::Instance().registerFile(binary, milleMetaData);
1009  }
1010 
1011 }
1012 
1013 void MillepedeCollectorModule::storeTrajectory(gbl::GblTrajectory& trajectory)
1014 {
1015  if (m_useGblTree) {
1016  if (trajectory.isValid())
1017  m_currentGblData = trajectory.getData();
1018  else
1019  m_currentGblData.clear();
1020 
1021  if (!m_currentGblData.empty())
1022  getObjectPtr<TTree>("GblDataTree")->Fill();
1023  } else {
1024  getObjectPtr<MilleData>("mille")->fill(trajectory);
1025  }
1026 }
1027 
1028 std::string MillepedeCollectorModule::getUniqueMilleName()
1029 {
1031  string name = getName();
1032 
1033  name += "-e" + to_string(emd->getExperiment());
1034  name += "-r" + to_string(emd->getRun());
1035  name += "-ev" + to_string(emd->getEvent());
1036 
1037  if (ProcHandler::parallelProcessingUsed())
1038  name += "-pid" + to_string(ProcHandler::EvtProcID());
1039 
1040  name += ".mille";
1041 
1042  return name;
1043 }
1044 
1045 bool MillepedeCollectorModule::fitRecoTrack(RecoTrack& recoTrack, Particle* particle)
1046 {
1047  try {
1048  // For already fitted tracks, try to get fitted (DAF) weights for CDC
1049  if (m_updateCDCWeights && recoTrack.getNumberOfCDCHits() && recoTrack.getTrackFitStatus()
1050  && recoTrack.getTrackFitStatus()->isFitted()) {
1051  double sumCDCWeights = recoTrack.getNumberOfCDCHits(); // start with full weights
1052  // Do the hits synchronisation
1053  auto relatedRecoHitInformation =
1055 
1056  for (RecoHitInformation& recoHitInformation : relatedRecoHitInformation) {
1057 
1058  if (recoHitInformation.getFlag() == RecoHitInformation::c_pruned) {
1059  B2FATAL("Found pruned point in RecoTrack. Pruned tracks cannot be used in MillepedeCollector.");
1060  }
1061 
1062  if (recoHitInformation.getTrackingDetector() != RecoHitInformation::c_CDC) continue;
1063 
1064  const genfit::TrackPoint* trackPoint = recoTrack.getCreatedTrackPoint(&recoHitInformation);
1065  if (trackPoint) {
1066  if (not trackPoint->hasFitterInfo(recoTrack.getCardinalRepresentation()))
1067  continue;
1068  auto kalmanFitterInfo = dynamic_cast<genfit::KalmanFitterInfo*>(trackPoint->getFitterInfo());
1069  if (not kalmanFitterInfo) {
1070  continue;
1071  } else {
1072  std::vector<double> weights = kalmanFitterInfo->getWeights();
1073  if (weights.size() == 2) {
1074  if (weights.at(0) > weights.at(1))
1075  recoHitInformation.setRightLeftInformation(RecoHitInformation::c_left);
1076  else if (weights.at(0) < weights.at(1))
1077  recoHitInformation.setRightLeftInformation(RecoHitInformation::c_right);
1078 
1079  double weightLR = weights.at(0) + weights.at(1);
1080  if (weightLR < m_minCDCHitWeight) recoHitInformation.setUseInFit(false);
1081  sumCDCWeights += weightLR - 1.; // reduce weight sum if weightLR<1
1082  }
1083  }
1084  }
1085  }
1086 
1087  double usedCDCHitFraction = sumCDCWeights / double(recoTrack.getNumberOfCDCHits());
1088  getObjectPtr<TH1F>("cdc_hit_fraction")->Fill(usedCDCHitFraction);
1089  if (usedCDCHitFraction < m_minUsedCDCHitFraction)
1090  return false;
1091  }
1092  } catch (...) {
1093  B2ERROR("Error in checking DAF weights from previous fit to resolve hit ambiguity. Why? Failed fit points in DAF? Skip track to be sure.");
1094  return false;
1095  }
1096 
1097  std::shared_ptr<genfit::GblFitter> gbl(new genfit::GblFitter());
1098  gbl->setOptions(m_internalIterations, true, true, m_externalIterations, m_recalcJacobians);
1099  gbl->setTrackSegmentController(new GblMultipleScatteringController);
1100 
1101  MeasurementAdder factory("", "", "", "", "");
1102 
1103  // We need the store arrays
1109 
1110  // Create the genfit::MeasurementFactory
1111  genfit::MeasurementFactory<genfit::AbsMeasurement> genfitMeasurementFactory;
1112 
1113  // Add producer for alignable RecoHits to factory
1114  if (pxdHits.isOptional()) {
1117  genfitMeasurementFactory.addProducer(Const::PXD, PXDProducer);
1118  }
1119 
1120  if (svdHits.isOptional()) {
1123  genfitMeasurementFactory.addProducer(Const::SVD, SVDProducer);
1124  }
1125 
1126  if (cdcHits.isOptional()) {
1129  genfitMeasurementFactory.addProducer(Const::CDC, CDCProducer);
1130  }
1131 
1132  if (bklmHits.isOptional()) {
1135  genfitMeasurementFactory.addProducer(Const::BKLM, BKLMProducer);
1136  }
1137 
1138  if (eklmHits.isOptional()) {
1141  genfitMeasurementFactory.addProducer(Const::EKLM, EKLMProducer);
1142  }
1143 
1144 
1145  // Create the measurement creators
1146  std::vector<std::shared_ptr<PXDBaseMeasurementCreator>> pxdMeasurementCreators = { std::shared_ptr<PXDBaseMeasurementCreator>(new PXDCoordinateMeasurementCreator(genfitMeasurementFactory)) };
1147  std::vector<std::shared_ptr<SVDBaseMeasurementCreator>> svdMeasurementCreators = { std::shared_ptr<SVDBaseMeasurementCreator>(new SVDCoordinateMeasurementCreator(genfitMeasurementFactory)) };
1148  // TODO: Create a new MeasurementCreator based on SVDBaseMeasurementCreator (or on SVDCoordinateMeasurementCreator), which does the combination on the fly.
1149 
1150  std::vector<std::shared_ptr<CDCBaseMeasurementCreator>> cdcMeasurementCreators = { std::shared_ptr<CDCBaseMeasurementCreator>(new CDCCoordinateMeasurementCreator(genfitMeasurementFactory)) };
1151  std::vector<std::shared_ptr<BKLMBaseMeasurementCreator>> bklmMeasurementCreators = { std::shared_ptr<BKLMBaseMeasurementCreator>(new BKLMCoordinateMeasurementCreator(genfitMeasurementFactory)) };
1152  std::vector<std::shared_ptr<EKLMBaseMeasurementCreator>> eklmMeasurementCreators = { std::shared_ptr<EKLMBaseMeasurementCreator>(new EKLMCoordinateMeasurementCreator(genfitMeasurementFactory)) };
1153 
1154  // TODO: Or put it in here and leave the svdMeasurementCreators empty.
1155  std::vector<std::shared_ptr<BaseMeasurementCreator>> additionalMeasurementCreators = {};
1156  factory.resetMeasurementCreators(pxdMeasurementCreators, svdMeasurementCreators, cdcMeasurementCreators, bklmMeasurementCreators,
1157  eklmMeasurementCreators, additionalMeasurementCreators);
1158  factory.addMeasurements(recoTrack);
1159 
1160  auto& gfTrack = RecoTrackGenfitAccess::getGenfitTrack(recoTrack);
1161 
1162  int currentPdgCode = TrackFitter::createCorrectPDGCodeForChargedStable(Const::muon, recoTrack);
1163  if (particle)
1164  currentPdgCode = particle->getPDGCode();
1165 
1166  genfit::AbsTrackRep* trackRep = RecoTrackGenfitAccess::createOrReturnRKTrackRep(recoTrack, currentPdgCode);
1167  gfTrack.setCardinalRep(gfTrack.getIdForRep(trackRep));
1168 
1169  if (particle) {
1170  B2Vector3D vertexPos = particle->getVertex();
1171  B2Vector3D vertexMom = particle->getMomentum();
1172  gfTrack.setStateSeed(vertexPos, vertexMom);
1173 
1174  genfit::StateOnPlane vertexSOP(gfTrack.getCardinalRep());
1175  B2Vector3D vertexRPhiDir(vertexPos[0], vertexPos[1], 0);
1176  B2Vector3D vertexZDir(0, 0, vertexPos[2]);
1177  //FIXME: This causes problem to current GBL version in genfit -> needs update of GBL to re-enable
1178  // genfit::SharedPlanePtr vertexPlane(new genfit::DetPlane(vertexPos, vertexRPhiDir, vertexZDir));
1179  //This works instead fine:
1180  genfit::SharedPlanePtr vertexPlane(new genfit::DetPlane(vertexPos, vertexMom));
1181 
1182  vertexSOP.setPlane(vertexPlane);
1183  vertexSOP.setPosMom(vertexPos, vertexMom);
1184  TMatrixDSym vertexCov(5);
1185  vertexCov.UnitMatrix();
1186  // By using negative covariance no measurement is added to GBL. But this first point
1187  // is then used as additional point in trajectory at the assumed point of its fitted vertex
1188  vertexCov *= -1.;
1189  genfit::MeasuredStateOnPlane mop(vertexSOP, vertexCov);
1190  genfit::FullMeasurement* vertex = new genfit::FullMeasurement(mop, Const::IR);
1191  gfTrack.insertMeasurement(vertex, 0);
1192  }
1193 
1194  try {
1195  for (unsigned int i = 0; i < gfTrack.getNumPoints() - 1; ++i) {
1196  //if (gfTrack.getPointWithMeasurement(i)->getNumRawMeasurements() != 1)
1197  // continue;
1198  genfit::PlanarMeasurement* planarMeas1 = dynamic_cast<genfit::PlanarMeasurement*>(gfTrack.getPointWithMeasurement(
1199  i)->getRawMeasurement(0));
1200  genfit::PlanarMeasurement* planarMeas2 = dynamic_cast<genfit::PlanarMeasurement*>(gfTrack.getPointWithMeasurement(
1201  i + 1)->getRawMeasurement(0));
1202 
1203  if (planarMeas1 != NULL && planarMeas2 != NULL &&
1204  planarMeas1->getDetId() == planarMeas2->getDetId() &&
1205  planarMeas1->getPlaneId() != -1 && // -1 is default plane id
1206  planarMeas1->getPlaneId() == planarMeas2->getPlaneId()) {
1207  Belle2::AlignableSVDRecoHit* hit1 = dynamic_cast<Belle2::AlignableSVDRecoHit*>(planarMeas1);
1208  Belle2::AlignableSVDRecoHit* hit2 = dynamic_cast<Belle2::AlignableSVDRecoHit*>(planarMeas2);
1209  if (hit1 && hit2) {
1210  Belle2::AlignableSVDRecoHit* hitU(NULL);
1211  Belle2::AlignableSVDRecoHit* hitV(NULL);
1212  // We have to decide U/V now (else AlignableSVDRecoHit2D could throw FATAL)
1213  if (hit1->isU() && !hit2->isU()) {
1214  hitU = hit1;
1215  hitV = hit2;
1216  } else if (!hit1->isU() && hit2->isU()) {
1217  hitU = hit2;
1218  hitV = hit1;
1219  } else {
1220  continue;
1221  }
1223  // insert measurement before point i (increases number of currect point to i+1)
1224  gfTrack.insertMeasurement(hit, i);
1225  // now delete current point (at its original place, we have the new 2D recohit)
1226  gfTrack.deletePoint(i + 1);
1227  gfTrack.deletePoint(i + 1);
1228  }
1229  }
1230  }
1231  } catch (std::exception& e) {
1232  B2ERROR(e.what());
1233  B2ERROR("SVD Cluster combination failed. This is symptomatic of pruned tracks. MillepedeCollector cannot process pruned tracks.");
1234  return false;
1235  }
1236 
1237  try {
1238  gbl->processTrackWithRep(&gfTrack, gfTrack.getCardinalRep(), true);
1239  } catch (genfit::Exception& e) {
1240  B2ERROR(e.what());
1241  return false;
1242  } catch (...) {
1243  B2ERROR("GBL fit failed.");
1244  return false;
1245  }
1246 
1247  return true;
1248 }
1249 
1250 std::vector< genfit::Track* > MillepedeCollectorModule::getParticlesTracks(std::vector<Particle*> particles, bool addVertexPoint)
1251 {
1252  std::vector< genfit::Track* > tracks;
1253  for (auto particle : particles) {
1254  auto belle2Track = particle->getTrack();
1255  if (!belle2Track) {
1256  B2WARNING("No Belle2::Track for particle (particle->X");
1257  continue;
1258  }
1259 // auto trackFitResult = belle2Track->getTrackFitResult(Const::chargedStableSet.find(abs(particle->getPDGCode())));
1260 // if (!trackFitResult) {
1261 // B2INFO("No track fit result for track");
1262 // continue;
1263 // }
1264 // auto recoTrack = trackFitResult->getRelatedFrom<RecoTrack>();
1265  auto recoTrack = belle2Track->getRelatedTo<RecoTrack>();
1266 
1267  if (!recoTrack) {
1268  B2WARNING("No related RecoTrack for Belle2::Track (particle->Track->X)");
1269  continue;
1270  }
1271 
1272  // If any track fails, fail completely
1273  if (!fitRecoTrack(*recoTrack, (addVertexPoint) ? particle : nullptr))
1274  return {};
1275 
1276  auto& track = RecoTrackGenfitAccess::getGenfitTrack(*recoTrack);
1277 
1278  if (!track.hasFitStatus()) {
1279  B2WARNING("Track has no fit status");
1280  continue;
1281  }
1282  genfit::GblFitStatus* fs = dynamic_cast<genfit::GblFitStatus*>(track.getFitStatus());
1283  if (!fs) {
1284  B2WARNING("Track FitStatus is not GblFitStatus.");
1285  continue;
1286  }
1287  if (!fs->isFittedWithReferenceTrack()) {
1288  B2WARNING("Track is not fitted with reference track.");
1289  continue;
1290  }
1291 
1292  tracks.push_back(&track);
1293  }
1294 
1295  return tracks;
1296 }
1297 
1298 std::pair<TMatrixD, TMatrixD> MillepedeCollectorModule::getTwoBodyToLocalTransform(Particle& mother,
1299  double motherMass)
1300 {
1301  std::vector<TMatrixD> result;
1302 
1303  double px = mother.getMomentum()[0];
1304  double py = mother.getMomentum()[1];
1305  double pz = mother.getMomentum()[2];
1306  double pt = sqrt(px * px + py * py);
1307  double p = mother.getMomentumMagnitude();
1308  double M = motherMass;
1309  double m = mother.getDaughter(0)->getPDGMass();
1310 
1311  if (mother.getNDaughters() != 2
1312  || m != mother.getDaughter(1)->getPDGMass()) B2FATAL("Only two same-mass daughters (V0->f+f- decays) allowed.");
1313 
1314  // Rotation matrix from mother reference system to lab system
1315  TMatrixD mother2lab(3, 3);
1316  mother2lab(0, 0) = px * pz / pt / p; mother2lab(0, 1) = - py / pt; mother2lab(0, 2) = px / p;
1317  mother2lab(1, 0) = py * pz / pt / p; mother2lab(1, 1) = px / pt; mother2lab(1, 2) = py / p;
1318  mother2lab(2, 0) = - pt / p; mother2lab(2, 1) = 0; mother2lab(2, 2) = pz / p;
1319  auto lab2mother = mother2lab; lab2mother.Invert();
1320 
1321  // Need to rotate and boost daughters' momenta to know which goes forward (+sign in decay model)
1322  // and to get the angles theta, phi of the decaying daughter system in mothers' reference frame
1323  RestFrame boostedFrame(&mother);
1324  TLorentzVector fourVector1 = mother.getDaughter(0)->get4Vector();
1325  TLorentzVector fourVector2 = mother.getDaughter(1)->get4Vector();
1326 
1327  auto mom1 = lab2mother * boostedFrame.getMomentum(fourVector1).Vect();
1328  auto mom2 = lab2mother * boostedFrame.getMomentum(fourVector2).Vect();
1329  // One momentum has opposite direction (otherwise should be same in CMS of mother), but which?
1330  double sign = 1.;
1331  auto avgMom = 0.5 * (mom1 - mom2);
1332  if (avgMom[2] < 0.) {
1333  avgMom *= -1.;
1334  // switch meaning of plus/minus trajectories
1335  sign = -1.;
1336  }
1337 
1338  double theta = atan2(avgMom.Perp(), avgMom[2]);
1339  double phi = atan2(avgMom[1], avgMom[0]);
1340  if (phi < 0.) phi += 2. * TMath::Pi();
1341 
1342  double alpha = M / 2. / m;
1343  double c1 = m * sqrt(alpha * alpha - 1.);
1344  double c2 = 0.5 * sqrt((alpha * alpha - 1.) / alpha / alpha * (p * p + M * M));
1345 
1346  double p3 = p * p * p;
1347  double pt3 = pt * pt * pt;
1348 
1349 
1350  for (auto& track : getParticlesTracks(mother.getDaughters())) {
1351 
1352 
1353  TMatrixD R = mother2lab;
1354  B2Vector3D P(sign * c1 * sin(theta) * cos(phi),
1355  sign * c1 * sin(theta) * sin(phi),
1356  p / 2. + sign * c2 * cos(theta));
1357 
1358  TMatrixD dRdpx(3, 3);
1359  dRdpx(0, 0) = - pz * (pow(px, 4.) - pow(py, 4.) - py * py * pz * pz) / pt3 / p3;
1360  dRdpx(0, 1) = px * py / pt3;
1361  dRdpx(0, 2) = (py * py + pz * pz) / p3;
1362 
1363  dRdpx(1, 0) = - px * py * pz * (2. * px * px + 2. * py * py + pz * pz) / pt3 / p3;
1364  dRdpx(1, 1) = - py * py / pt3;
1365  dRdpx(1, 2) = px * py / p3;
1366 
1367  dRdpx(2, 0) = - px * pz * pz / pt / p3;
1368  dRdpx(2, 1) = 0.;
1369  dRdpx(2, 2) = - px * pz / p3;
1370 
1371  TMatrixD dRdpy(3, 3);
1372  dRdpy(0, 0) = - px * py * pz * (2. * px * px + 2. * py * py + pz * pz) / pt3 / p3;
1373  dRdpy(0, 1) = - px * px / pt3;
1374  dRdpy(0, 2) = px * pz / p3;
1375 
1376  dRdpy(1, 0) = - pz * (- pow(px, 4.) - px * px * pz * pz + pow(py, 4.)) / pt3 / p3;
1377  dRdpy(1, 1) = px * py / pt3;
1378  dRdpy(1, 2) = (px * px + pz * pz) / p3;
1379 
1380  dRdpy(2, 0) = - py * pz * pz / pt / p3;
1381  dRdpy(2, 1) = 0.;
1382  dRdpy(2, 2) = - py * pz / p3;
1383 
1384  TMatrixD dRdpz(3, 3);
1385  dRdpz(0, 0) = px * pt / p3;
1386  dRdpz(0, 1) = 0.;
1387  dRdpz(0, 2) = - px * pz / p3;
1388 
1389  dRdpz(1, 0) = py * pt / p3;
1390  dRdpz(1, 1) = 0.;
1391  dRdpz(1, 2) = py * pz / p3;
1392 
1393  dRdpz(2, 0) = pz * pt / p3;
1394  dRdpz(2, 1) = 0.;
1395  dRdpz(2, 2) = (px * px + py * py) / p3;
1396 
1397  auto K = 1. / 2. / p + sign * cos(theta) * m * m * (M * M / 4. / m / m - 1.) / M / M / sqrt(m * m * (M * M / 4. / m / m - 1.) *
1398  (M * M + p * p) / M / M);
1399 
1400  B2Vector3D dpdpx = dRdpx * P + R * K * px * B2Vector3D(0., 0., 1.);
1401  B2Vector3D dpdpy = dRdpy * P + R * K * py * B2Vector3D(0., 0., 1.);
1402  B2Vector3D dpdpz = dRdpz * P + R * K * pz * B2Vector3D(0., 0., 1.);
1403 
1404  B2Vector3D dpdtheta = R * B2Vector3D(sign * c1 * cos(theta) * cos(phi),
1405  sign * c1 * cos(theta) * sin(phi),
1406  sign * c2 * (- sin(theta)));
1407 
1408 
1409  B2Vector3D dpdphi = R * B2Vector3D(sign * c1 * sin(theta) * (- sin(phi)),
1410  sign * c1 * sin(theta) * cos(phi),
1411  0.);
1412 
1413  double dc1dM = m * M / (2. * sqrt(M * M - 4. * m * m));
1414  double dc2dM = M * (4. * m * m * p * p + pow(M, 4)) / (2 * M * M * M * sqrt((M * M - 4. * m * m) * (p * p + M * M)));
1415 
1416  B2Vector3D dpdM = R * B2Vector3D(sign * sin(theta) * cos(phi) * dc1dM,
1417  sign * sin(theta) * sin(phi) * dc1dM,
1418  sign * cos(theta) * dc2dM);
1419 
1420  TMatrixD dpdz(3, 6);
1421  dpdz(0, 0) = dpdpx(0); dpdz(0, 1) = dpdpy(0); dpdz(0, 2) = dpdpz(0); dpdz(0, 3) = dpdtheta(0); dpdz(0, 4) = dpdphi(0);
1422  dpdz(0, 5) = dpdM(0);
1423  dpdz(1, 0) = dpdpx(1); dpdz(1, 1) = dpdpy(1); dpdz(1, 2) = dpdpz(1); dpdz(1, 3) = dpdtheta(1); dpdz(1, 4) = dpdphi(1);
1424  dpdz(1, 5) = dpdM(1);
1425  dpdz(2, 0) = dpdpx(2); dpdz(2, 1) = dpdpy(2); dpdz(2, 2) = dpdpz(2); dpdz(2, 3) = dpdtheta(2); dpdz(2, 4) = dpdphi(2);
1426  dpdz(2, 5) = dpdM(2);
1427 
1428  TMatrixD dqdv = getGlobalToLocalTransform(track->getFittedState()).GetSub(0, 4, 0, 2);
1429  TMatrixD dqdp = getGlobalToLocalTransform(track->getFittedState()).GetSub(0, 4, 3, 5);
1430  TMatrixD dfdvz(5, 9);
1431  dfdvz.SetSub(0, 0, dqdv);
1432  dfdvz.SetSub(0, 3, dqdp * dpdz);
1433 
1434  result.push_back(dfdvz);
1435 
1436  // switch sign for second trajectory
1437  sign *= -1.;
1438  }
1439 
1440  return {result[0], result[1]};
1441 }
1442 
1443 TMatrixD MillepedeCollectorModule::getGlobalToLocalTransform(const genfit::MeasuredStateOnPlane& msop)
1444 {
1445  auto state = msop;
1446  const B2Vector3D& U(state.getPlane()->getU());
1447  const B2Vector3D& V(state.getPlane()->getV());
1448  const B2Vector3D& O(state.getPlane()->getO());
1449  const B2Vector3D& W(state.getPlane()->getNormal());
1450 
1451  const double* state5 = state.getState().GetMatrixArray();
1452 
1453  double spu = 1.;
1454 
1455  const TVectorD& auxInfo = state.getAuxInfo();
1456  if (auxInfo.GetNrows() == 2
1457  || auxInfo.GetNrows() == 1) // backwards compatibility with old RKTrackRep
1458  spu = state.getAuxInfo()(0);
1459 
1460  TVectorD state7(7);
1461 
1462  state7[0] = O.X() + state5[3] * U.X() + state5[4] * V.X(); // x
1463  state7[1] = O.Y() + state5[3] * U.Y() + state5[4] * V.Y(); // y
1464  state7[2] = O.Z() + state5[3] * U.Z() + state5[4] * V.Z(); // z
1465 
1466  state7[3] = spu * (W.X() + state5[1] * U.X() + state5[2] * V.X()); // a_x
1467  state7[4] = spu * (W.Y() + state5[1] * U.Y() + state5[2] * V.Y()); // a_y
1468  state7[5] = spu * (W.Z() + state5[1] * U.Z() + state5[2] * V.Z()); // a_z
1469 
1470  // normalize dir
1471  double norm = 1. / sqrt(state7[3] * state7[3] + state7[4] * state7[4] + state7[5] * state7[5]);
1472  for (unsigned int i = 3; i < 6; ++i) state7[i] *= norm;
1473 
1474  state7[6] = state5[0]; // q/p
1475 
1476  const double AtU = state7[3] * U.X() + state7[4] * U.Y() + state7[5] * U.Z();
1477  const double AtV = state7[3] * V.X() + state7[4] * V.Y() + state7[5] * V.Z();
1478  const double AtW = state7[3] * W.X() + state7[4] * W.Y() + state7[5] * W.Z();
1479 
1480  // J_Mp matrix is d(q/p,u',v',u,v) / d(x,y,z,px,py,pz) (in is 6x6)
1481 
1482  const double qop = state7[6];
1483  const double p = state.getCharge() / qop; // momentum
1484 
1485  TMatrixD J_Mp_6x5(6, 5);
1486  J_Mp_6x5.Zero();
1487 
1488  //d(u)/d(x,y,z)
1489  J_Mp_6x5(0, 3) = U.X(); // [0][3]
1490  J_Mp_6x5(1, 3) = U.Y(); // [1][3]
1491  J_Mp_6x5(2, 3) = U.Z(); // [2][3]
1492  //d(v)/d(x,y,z)
1493  J_Mp_6x5(0, 4) = V.X(); // [0][4]
1494  J_Mp_6x5(1, 4) = V.Y(); // [1][4]
1495  J_Mp_6x5(2, 4) = V.Z(); // [2][4]
1496 
1497  // d(q/p)/d(px,py,pz)
1498  double fact = (-1.) * qop / p;
1499  J_Mp_6x5(3, 0) = fact * state7[3]; // [3][0]
1500  J_Mp_6x5(4, 0) = fact * state7[4]; // [4][0]
1501  J_Mp_6x5(5, 0) = fact * state7[5]; // [5][0]
1502  // d(u')/d(px,py,pz)
1503  fact = 1. / (p * AtW * AtW);
1504  J_Mp_6x5(3, 1) = fact * (U.X() * AtW - W.X() * AtU); // [3][1]
1505  J_Mp_6x5(4, 1) = fact * (U.Y() * AtW - W.Y() * AtU); // [4][1]
1506  J_Mp_6x5(5, 1) = fact * (U.Z() * AtW - W.Z() * AtU); // [5][1]
1507  // d(v')/d(px,py,pz)
1508  J_Mp_6x5(3, 2) = fact * (V.X() * AtW - W.X() * AtV); // [3][2]
1509  J_Mp_6x5(4, 2) = fact * (V.Y() * AtW - W.Y() * AtV); // [4][2]
1510  J_Mp_6x5(5, 2) = fact * (V.Z() * AtW - W.Z() * AtV); // [5][2]
1511 
1512  return J_Mp_6x5.T();
1513 }
1514 
1515 TMatrixD MillepedeCollectorModule::getLocalToGlobalTransform(const genfit::MeasuredStateOnPlane& msop)
1516 {
1517  auto state = msop;
1518  // get vectors and aux variables
1519  const B2Vector3D& U(state.getPlane()->getU());
1520  const B2Vector3D& V(state.getPlane()->getV());
1521  const B2Vector3D& W(state.getPlane()->getNormal());
1522 
1523  const TVectorD& state5(state.getState());
1524  double spu = 1.;
1525 
1526  const TVectorD& auxInfo = state.getAuxInfo();
1527  if (auxInfo.GetNrows() == 2
1528  || auxInfo.GetNrows() == 1) // backwards compatibility with old RKTrackRep
1529  spu = state.getAuxInfo()(0);
1530 
1531  TVectorD pTilde(3);
1532  pTilde[0] = spu * (W.X() + state5(1) * U.X() + state5(2) * V.X()); // a_x
1533  pTilde[1] = spu * (W.Y() + state5(1) * U.Y() + state5(2) * V.Y()); // a_y
1534  pTilde[2] = spu * (W.Z() + state5(1) * U.Z() + state5(2) * V.Z()); // a_z
1535 
1536  const double pTildeMag = sqrt(pTilde[0] * pTilde[0] + pTilde[1] * pTilde[1] + pTilde[2] * pTilde[2]);
1537  const double pTildeMag2 = pTildeMag * pTildeMag;
1538 
1539  const double utpTildeOverpTildeMag2 = (U.X() * pTilde[0] + U.Y() * pTilde[1] + U.Z() * pTilde[2]) / pTildeMag2;
1540  const double vtpTildeOverpTildeMag2 = (V.X() * pTilde[0] + V.Y() * pTilde[1] + V.Z() * pTilde[2]) / pTildeMag2;
1541 
1542  //J_pM matrix is d(x,y,z,px,py,pz) / d(q/p,u',v',u,v) (out is 6x6)
1543 
1544  const double qop = state5(0);
1545  const double p = state.getCharge() / qop; // momentum
1546 
1547  TMatrixD J_pM_5x6(5, 6);
1548  J_pM_5x6.Zero();
1549 
1550  // d(px,py,pz)/d(q/p)
1551  double fact = -1. * p / (pTildeMag * qop);
1552  J_pM_5x6(0, 3) = fact * pTilde[0]; // [0][3]
1553  J_pM_5x6(0, 4) = fact * pTilde[1]; // [0][4]
1554  J_pM_5x6(0, 5) = fact * pTilde[2]; // [0][5]
1555  // d(px,py,pz)/d(u')
1556  fact = p * spu / pTildeMag;
1557  J_pM_5x6(1, 3) = fact * (U.X() - pTilde[0] * utpTildeOverpTildeMag2); // [1][3]
1558  J_pM_5x6(1, 4) = fact * (U.Y() - pTilde[1] * utpTildeOverpTildeMag2); // [1][4]
1559  J_pM_5x6(1, 5) = fact * (U.Z() - pTilde[2] * utpTildeOverpTildeMag2); // [1][5]
1560  // d(px,py,pz)/d(v')
1561  J_pM_5x6(2, 3) = fact * (V.X() - pTilde[0] * vtpTildeOverpTildeMag2); // [2][3]
1562  J_pM_5x6(2, 4) = fact * (V.Y() - pTilde[1] * vtpTildeOverpTildeMag2); // [2][4]
1563  J_pM_5x6(2, 5) = fact * (V.Z() - pTilde[2] * vtpTildeOverpTildeMag2); // [2][5]
1564  // d(x,y,z)/d(u)
1565  J_pM_5x6(3, 0) = U.X(); // [3][0]
1566  J_pM_5x6(3, 1) = U.Y(); // [3][1]
1567  J_pM_5x6(3, 2) = U.Z(); // [3][2]
1568  // d(x,y,z)/d(v)
1569  J_pM_5x6(4, 0) = V.X(); // [4][0]
1570  J_pM_5x6(4, 1) = V.Y(); // [4][1]
1571  J_pM_5x6(4, 2) = V.Z(); // [4][2]
1572 
1573  return J_pM_5x6.T();
1574 
1575 }
1576 
1577 tuple<B2Vector3D, TMatrixDSym> MillepedeCollectorModule::getPrimaryVertexAndCov() const
1578 {
1579  DBObjPtr<BeamSpot> beam;
1580  return {beam->getIPPosition(), beam->getSizeCovMatrix()};
1581 }
1582 
1583 void MillepedeCollectorModule::updateMassWidthIfSet(string listName, double& mass, double& width)
1584 {
1585  if (m_customMassConfig.find(listName) != m_customMassConfig.end()) {
1586  auto massWidth = m_customMassConfig.at(listName);
1587  mass = std::get<0>(massWidth);
1588  width = std::get<1>(massWidth);
1589  }
1590 }
1591 
This class is used to transfer CDC information to the track fit and Millepede.
This class is used to transfer PXD information to the track fit.
This class is used to transfer SVD information to the track fit.
This class is used to transfer SVD information to the track fit.
DataType Z() const
access variable Z (= .at(2) without boundary check)
Definition: B2Vector3.h:420
DataType X() const
access variable X (= .at(0) without boundary check)
Definition: B2Vector3.h:416
DataType Y() const
access variable Y (= .at(1) without boundary check)
Definition: B2Vector3.h:418
Store one BKLM strip hit as a ROOT object.
Definition: BKLMHit2d.h:32
Class containing the result of the unpacker in raw data and the result of the digitizer in simulation...
Definition: CDCHit.h:40
Calibration collector module base class.
Class for accessing objects in the database.
Definition: DBObjPtr.h:21
This dataobject is used only for EKLM alignment.
Store event, run, and experiment numbers.
Definition: EventMetaData.h:33
Metadata information about a file.
Definition: FileMetaData.h:29
void setLfn(const std::string &lfn)
Setter for LFN.
Definition: FileMetaData.h:135
void setParents(const std::vector< std::string > &parents)
Parents setter.
Definition: FileMetaData.h:163
TrackSegmentController for use with GblFitter in Belle2.
Class to convert to/from global labels for Millepede II to/from detector & parameter identificators.
Definition: GlobalLabel.h:41
Algorithm class to translate the added detector hits (e.g.
void resetMeasurementCreators(const std::vector< std::shared_ptr< PXDBaseMeasurementCreator >> &pxdMeasurementCreators, const std::vector< std::shared_ptr< SVDBaseMeasurementCreator >> &svdMeasurementCreators, const std::vector< std::shared_ptr< CDCBaseMeasurementCreator >> &cdcMeasurementCreators, const std::vector< std::shared_ptr< BKLMBaseMeasurementCreator >> &bklmMeasurementCreators, const std::vector< std::shared_ptr< EKLMBaseMeasurementCreator >> &eklmMeasurementCreators, const std::vector< std::shared_ptr< BaseMeasurementCreator >> &additionalMeasurementCreators)
If you want to use non-default settings for the store arrays, you can create your own instances of th...
bool addMeasurements(RecoTrack &recoTrack) const
After you have filled the internal storage with measurement creators (either by providing your own or...
Mergeable class holding list of so far opened mille binaries and providing the binaries.
Definition: MilleData.h:24
Calibration data collector for Millepede Algorithm.
The PXD Cluster class This class stores all information about reconstructed PXD clusters The position...
Definition: PXDCluster.h:30
Class to store reconstructed particles.
Definition: Particle.h:74
This class stores additional information to every CDC/SVD/PXD hit stored in a RecoTrack.
This is the Reconstruction Event-Data Model Track.
Definition: RecoTrack.h:76
const genfit::FitStatus * getTrackFitStatus(const genfit::AbsTrackRep *representation=nullptr) const
Return the track fit status for the given representation or for the cardinal one. You are not allowed...
Definition: RecoTrack.h:536
unsigned int getNumberOfCDCHits() const
Return the number of cdc hits.
Definition: RecoTrack.h:416
const genfit::TrackPoint * getCreatedTrackPoint(const RecoHitInformation *recoHitInformation) const
Get a pointer to the TrackPoint that was created from this hit.
Definition: RecoTrack.cc:227
genfit::AbsTrackRep * getCardinalRepresentation() const
Get a pointer to the cardinal track representation. You are not allowed to modify or delete it!
Definition: RecoTrack.h:546
const std::string & getStoreArrayNameOfRecoHitInformation() const
Name of the store array of the reco hit informations.
Definition: RecoTrack.h:645
RelationVector< TO > getRelationsTo(const std::string &name="", const std::string &namedRelation="") const
Get the relations that point from this object to another store array.
Rest frame of a particle.
virtual TLorentzVector getMomentum(const TLorentzVector &vector) const override
Get Lorentz vector in rest frame System.
The SVD Cluster class This class stores all information about reconstructed SVD clusters.
Definition: SVDCluster.h:28
bool isU() const
Is the coordinate u or v?
Definition: SVDRecoHit.h:91
bool isRequired(const std::string &name="")
Ensure this array/object has been registered previously.
bool isOptional(const std::string &name="")
Tell the DataStore about an optional input.
Accessor to arrays stored in the data store.
Definition: StoreArray.h:113
bool isValid() const
Check wether the array was registered.
Definition: StoreArray.h:288
TClonesArray * getPtr() const
Raw access to the underlying TClonesArray.
Definition: StoreArray.h:311
Type-safe access to single objects in the data store.
Definition: StoreObjPtr.h:95
bool isValid() const
Check whether the object was created.
Definition: StoreObjPtr.h:110
void writeConstraints(std::string txtFilename)
Write-out complete hierarchy to a text file.
Definition: Manager.cc:169
void initialize(const std::vector< std::string > &components={}, const std::vector< EventMetaData > &timeSlices={})
Initialize the manager with given configuration (from MillepedeCollector)
Definition: Manager.cc:52
static GlobalCalibrationManager & getInstance()
Get instance of the Manager auto& gcm = GlobalCalibrationManager::getInstance();.
Definition: Manager.cc:27
Class for easier manipulation with global derivatives (and their labels)
static bool s_enablePXD
Enable PXD in hierarchy?
Definition: GlobalParam.h:84
static bool s_enableSVD
Enable SVD in hierarchy?
Definition: GlobalParam.h:86
static E_VXDHierarchyType s_hierarchyType
What type of hierarchy to use for VXD?
Definition: GlobalParam.h:82
GBL trajectory.
Definition: GblTrajectory.h:48
unsigned int fit(double &Chi2, int &Ndf, double &lostWeight, std::string optionList="")
Perform fit of (valid) trajectory.
bool isValid() const
Retrieve validity of trajectory.
Abstract base class for a track representation.
Definition: AbsTrackRep.h:66
Detector plane.
Definition: DetPlane.h:59
Exception class for error handling in GENFIT (provides storage for diagnostic information)
Definition: Exception.h:48
bool isFitted() const
Has the track been fitted?
Definition: FitStatus.h:94
Measurement class implementing a measurement of all track parameters.
FitStatus for use with GblFitter.
Definition: GblFitStatus.h:39
Generic GBL implementation.
Definition: GblFitter.h:53
Collects information needed and produced by a AbsKalmanFitter implementations and is specific to one ...
#StateOnPlane with additional covariance matrix.
void addProducer(int detID, AbsMeasurementProducer< measurement_T > *hitProd)
Register a producer module to the factory.
Template class for a measurement producer module.
Measurement class implementing a planar hit geometry (1 or 2D).
A state with arbitrary dimension defined in a DetPlane.
Definition: StateOnPlane.h:47
Object containing AbsMeasurement and AbsFitterInfo objects.
Definition: TrackPoint.h:46
AbsFitterInfo * getFitterInfo(const AbsTrackRep *rep=nullptr) const
Get fitterInfo for rep. Per default, use cardinal rep.
Definition: TrackPoint.cc:170
#define REG_MODULE(moduleName)
Register the given module (without 'Module' suffix) with the framework.
Definition: Module.h:650
B2Vector3< double > B2Vector3D
typedef for common usage with double
Definition: B2Vector3.h:493
CoordinateMeasurementCreator< RecoHitInformation::UsedSVDHit, Const::SVD > SVDCoordinateMeasurementCreator
Hit to reco hit measurement creator for the SVD.
CoordinateMeasurementCreator< RecoHitInformation::UsedPXDHit, Const::PXD > PXDCoordinateMeasurementCreator
Hit to reco hit measurement creator for the PXD.
CoordinateMeasurementCreator< RecoHitInformation::UsedBKLMHit, Const::BKLM > BKLMCoordinateMeasurementCreator
Hit to reco hit measurement creator for the BKLM.
CoordinateMeasurementCreator< RecoHitInformation::UsedCDCHit, Const::CDC > CDCCoordinateMeasurementCreator
Needed for templating.
CoordinateMeasurementCreator< RecoHitInformation::UsedEKLMHit, Const::EKLM > EKLMCoordinateMeasurementCreator
Hit to reco hit measurement creator for the EKLM.
Abstract base class for different kinds of events.
Namespace for the general broken lines package.
std::shared_ptr< genfit::DetPlane > SharedPlanePtr
Shared Pointer to a DetPlane.