Belle II Software  release-06-02-00
eclGammaGammaECollectorModule.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 //This module`
9 #include <ecl/modules/eclGammaGammaECollector/eclGammaGammaECollectorModule.h>
10 
11 //Root
12 #include <TH2F.h>
13 
14 //Analysis
15 #include <analysis/utility/PCmsLabTransform.h>
16 #include <analysis/ClusterUtility/ClusterUtils.h>
17 
18 //Framework
19 #include <framework/gearbox/Const.h>
20 #include <framework/dataobjects/EventMetaData.h>
21 #include <framework/datastore/RelationVector.h>
22 
23 //MDST
24 #include <mdst/dataobjects/TRGSummary.h>
25 #include <mdst/dataobjects/HitPatternCDC.h>
26 #include <mdst/dataobjects/TrackFitResult.h>
27 #include <mdst/dataobjects/Track.h>
28 #include <mdst/dataobjects/ECLCluster.h>
29 
30 //ECL
31 #include <ecl/dataobjects/ECLDigit.h>
32 #include <ecl/dbobjects/ECLCrystalCalib.h>
33 
34 
35 
36 using namespace std;
37 using namespace Belle2;
38 
39 
40 //-----------------------------------------------------------------
41 // Register the Module
42 //-----------------------------------------------------------------
43 REG_MODULE(eclGammaGammaECollector)
44 
45 //-----------------------------------------------------------------
46 // Implementation
47 //-----------------------------------------------------------------
48 
49 //-----------------------------------------------------------------------------------------------------
50 
52  m_ECLExpGammaGammaE("ECLExpGammaGammaE"),
53  m_ElectronicsCalib("ECLCrystalElectronics"), m_GammaGammaECalib("ECLCrystalEnergyGammaGamma")
54 {
55  // Set module properties
56  setDescription("Calibration Collector Module for ECL single crystal energy calibration using gamma gamma events");
57  setPropertyFlags(c_ParallelProcessingCertified);
58  addParam("thetaLabMinDeg", m_thetaLabMinDeg, "miniumum photon theta in lab (degrees)", 0.);
59  addParam("thetaLabMaxDeg", m_thetaLabMaxDeg, "maximum photon theta in lab (degrees)", 180.);
60  addParam("minPairMass", m_minPairMass, "minimum invariant mass of the pair of photons (GeV/c^2)", 9.);
61  addParam("mindPhi", m_mindPhi, "minimum delta phi between clusters (deg)", 179.);
62  addParam("maxTime", m_maxTime, "maximum (time-<t>)/dt99 of photons", 1.);
63  addParam("measureTrueEnergy", m_measureTrueEnergy, "use MC events to obtain expected energies", false);
64  addParam("requireL1", m_requireL1, "only use events that have a level 1 trigger", true);
65 }
66 
67 
68 
71 void eclGammaGammaECollectorModule::prepare()
72 {
73 
75  B2INFO("eclGammaGammaECollector: Experiment = " << m_evtMetaData->getExperiment() << " run = " << m_evtMetaData->getRun());
76 
79  auto EnVsCrysID = new TH2F("EnVsCrysID", "Normalized energy for each crystal;crystal ID;E/Expected", 8736, 0, 8736, 140, 0, 1.4);
80  registerObject<TH2F>("EnVsCrysID", EnVsCrysID);
81 
82  auto ExpEvsCrys = new TH1F("ExpEvsCrys", "Sum expected energy vs crystal ID;crystal ID;Energy (GeV)", 8736, 0, 8736);
83  registerObject<TH1F>("ExpEvsCrys", ExpEvsCrys);
84 
85  auto ElecCalibvsCrys = new TH1F("ElecCalibvsCrys", "Sum electronics calib const vs crystal ID;crystal ID;calibration constant",
86  8736, 0, 8736);
87  registerObject<TH1F>("ElecCalibvsCrys", ElecCalibvsCrys);
88 
89  auto InitialCalibvsCrys = new TH1F("InitialCalibvsCrys",
90  "Sum initial gamma gamma calib const vs crystal ID;crystal ID;calibration constant", 8736, 0, 8736);
91  registerObject<TH1F>("InitialCalibvsCrys", InitialCalibvsCrys);
92 
93  auto CalibEntriesvsCrys = new TH1F("CalibEntriesvsCrys", "Entries in calib vs crys histograms;crystal ID;Entries per crystal", 8736,
94  0, 8736);
95  registerObject<TH1F>("CalibEntriesvsCrys", CalibEntriesvsCrys);
96 
98  auto RawDigitAmpvsCrys = new TH2F("RawDigitAmpvsCrys", "Digit Amplitude vs crystal ID;crystal ID;Amplitude", 8736, 0, 8736, 200, 0,
99  200000);
100  registerObject<TH2F>("RawDigitAmpvsCrys", RawDigitAmpvsCrys);
101 
102  auto RawDigitTimevsCrys = new TH2F("RawDigitTimevsCrys", "Digit Time vs crystal ID;crystal ID;Time", 8736, 0, 8736, 200, -2000,
103  2000);
104  registerObject<TH2F>("RawDigitTimevsCrys", RawDigitTimevsCrys);
105 
106  auto TimeMinusAverage = new TH1F("TimeMinusAverage", "Photon time - average / dt99;(T-T_ave)/dt99 ", 100, -10, 10);
107  registerObject<TH1F>("TimeMinusAverage", TimeMinusAverage);
108 
109 
110  //------------------------------------------------------------------------
112  B2INFO("Input parameters to eclGammaGammaECollector:");
113  B2INFO("thetaLabMinDeg: " << m_thetaLabMinDeg);
114  B2INFO("thetaLabMaxDeg: " << m_thetaLabMaxDeg);
115  thetaLabMin = m_thetaLabMinDeg / TMath::RadToDeg();
116  thetaLabMax = m_thetaLabMaxDeg / TMath::RadToDeg();
117  B2INFO("minPairMass: " << m_minPairMass);
118  B2INFO("mindPhi: " << m_mindPhi);
119  B2INFO("maxTime: " << m_maxTime);
120  B2INFO("measureTrueEnergy: " << m_measureTrueEnergy);
121  B2INFO("requireL1: " << m_requireL1);
122 
124  EperCrys.resize(8736);
125 
128  if (m_ECLExpGammaGammaE.hasChanged()) {ExpGammaGammaE = m_ECLExpGammaGammaE->getCalibVector();}
129  if (m_ElectronicsCalib.hasChanged()) {ElectronicsCalib = m_ElectronicsCalib->getCalibVector();}
130  if (m_GammaGammaECalib.hasChanged()) {GammaGammaECalib = m_GammaGammaECalib->getCalibVector();}
131 
133  for (int ic = 1; ic < 9000; ic += 1000) {
134  B2INFO("DB constants for cellID=" << ic << ": ExpGammaGammaE = " << ExpGammaGammaE[ic - 1] << " ElectronicsCalib = " <<
135  ElectronicsCalib[ic - 1]
136  << " GammaGammaECalib = " << GammaGammaECalib[ic - 1]);
137  }
138 
140  for (int crysID = 0; crysID < 8736; crysID++) {
141  if (ElectronicsCalib[crysID] <= 0) {B2FATAL("eclGammaGammaECollector: ElectronicsCalib = " << ElectronicsCalib[crysID] << " for crysID = " << crysID);}
142  if (ExpGammaGammaE[crysID] == 0) {B2FATAL("eclGammaGammaECollector: ExpGammaGammaE = 0 for crysID = " << crysID);}
143  if (GammaGammaECalib[crysID] == 0) {B2FATAL("eclGammaGammaECollector: GammaGammaECalib = 0 for crysID = " << crysID);}
144  }
145 
148  m_trackArray.isRequired();
149  m_eclClusterArray.isRequired();
150  if (!m_measureTrueEnergy) {m_eclDigitArray.isRequired();}
151 
152 }
153 
154 
157 void eclGammaGammaECollectorModule::collect()
158 {
159 
161  if (storeCalib) {
162  for (int crysID = 0; crysID < 8736; crysID++) {
163  getObjectPtr<TH1F>("ExpEvsCrys")->Fill(crysID + 0.001, ExpGammaGammaE[crysID]);
164  getObjectPtr<TH1F>("ElecCalibvsCrys")->Fill(crysID + 0.001, ElectronicsCalib[crysID]);
165  getObjectPtr<TH1F>("InitialCalibvsCrys")->Fill(crysID + 0.001, GammaGammaECalib[crysID]);
166  getObjectPtr<TH1F>("CalibEntriesvsCrys")->Fill(crysID + 0.001);
167  }
168  storeCalib = false;
169  }
170 
173  bool newConst = false;
174  if (m_ECLExpGammaGammaE.hasChanged()) {
175  newConst = true;
176  B2INFO("ECLExpGammaGammaE has changed, exp = " << m_evtMetaData->getExperiment() << " run = " << m_evtMetaData->getRun());
177  ExpGammaGammaE = m_ECLExpGammaGammaE->getCalibVector();
178  }
179  if (m_ElectronicsCalib.hasChanged()) {
180  newConst = true;
181  B2INFO("ECLCrystalElectronics has changed, exp = " << m_evtMetaData->getExperiment() << " run = " << m_evtMetaData->getRun());
182  ElectronicsCalib = m_ElectronicsCalib->getCalibVector();
183  }
184  if (m_GammaGammaECalib.hasChanged()) {
185  newConst = true;
186  B2INFO("ECLCrystalEnergyGammaGamma has changed, exp = " << m_evtMetaData->getExperiment() << " run = " << m_evtMetaData->getRun());
187  GammaGammaECalib = m_GammaGammaECalib->getCalibVector();
188  }
189 
190  if (newConst) {
191  for (int ic = 1; ic < 9000; ic += 1000) {
192  B2INFO("DB constants for cellID=" << ic << ": ExpGammaGammaE = " << ExpGammaGammaE[ic - 1] << " ElectronicsCalib = " <<
193  ElectronicsCalib[ic - 1]
194  << " GammaGammaECalib = " << GammaGammaECalib[ic - 1]);
195  }
196 
198  for (int crysID = 0; crysID < 8736; crysID++) {
199  if (ElectronicsCalib[crysID] <= 0) {B2FATAL("eclGammaGammaECollector: ElectronicsCalib = " << ElectronicsCalib[crysID] << " for crysID = " << crysID);}
200  if (ExpGammaGammaE[crysID] == 0) {B2FATAL("eclGammaGammaECollector: ExpGammaGammaE = 0 for crysID = " << crysID);}
201  if (GammaGammaECalib[crysID] == 0) {B2FATAL("eclGammaGammaECollector: GammaGammaECalib = 0 for crysID = " << crysID);}
202  }
203  }
204 
207  if (m_requireL1) {
208  unsigned int L1TriggerResults = m_TRGResults->getTRGSummary(0);
209  if (L1TriggerResults == 0) {return;}
210  }
211 
212  //------------------------------------------------------------------------
214  int nGoodTrk = 0;
215  for (auto& track : m_trackArray) {
216  const TrackFitResult* temptrackFit = track.getTrackFitResult(Const::ChargedStable(211));
217  if (temptrackFit) {
218  double pt = temptrackFit->getTransverseMomentum();
219  double z0 = temptrackFit->getZ0();
220  double d0 = temptrackFit->getD0();
221  double pValue = temptrackFit->getPValue();
222  int nCDChits = temptrackFit->getHitPatternCDC().getNHits();
223  if (pt > minTrkpt && abs(z0) < maxZ0 && abs(d0) < maxD0 && pValue > minpValue && nCDChits >= minCDChits) {nGoodTrk++;}
224  }
225  }
226  if (nGoodTrk > 0) {return;}
227 
228  //------------------------------------------------------------------------
230  const ECLCluster::EHypothesisBit usePhotons = ECLCluster::EHypothesisBit::c_nPhotons;
231  int icMax[2] = { -1, -1};
232  double maxClustE[2] = { -1., -1.};
233  int nclust = m_eclClusterArray.getEntries();
234  for (int ic = 0; ic < nclust; ic++) {
235  if (m_eclClusterArray[ic]->hasHypothesis(usePhotons)) {
236  double eClust = m_eclClusterArray[ic]->getEnergy(usePhotons);
237  if (eClust > maxClustE[0]) {
238  maxClustE[1] = maxClustE[0];
239  icMax[1] = icMax[0];
240  maxClustE[0] = eClust;
241  icMax[0] = ic;
242  } else if (eClust > maxClustE[1]) {
243  maxClustE[1] = eClust;
244  icMax[1] = ic;
245  }
246  }
247  }
248 
249  //------------------------------------------------------------------------
252  if (icMax[0] == -1 || icMax[1] == -1) {return;}
253  double theta0 = m_eclClusterArray[icMax[0]]->getTheta();
254  double theta1 = m_eclClusterArray[icMax[1]]->getTheta();
255  if (theta0 < thetaLabMin || theta0 > thetaLabMax || theta1 < thetaLabMin || theta1 > thetaLabMax) {return;}
256 
258  double t0 = m_eclClusterArray[icMax[0]]->getTime();
259  double t990 = m_eclClusterArray[icMax[0]]->getDeltaTime99();
260  double t1 = m_eclClusterArray[icMax[1]]->getTime();
261  double t991 = m_eclClusterArray[icMax[1]]->getDeltaTime99();
262  double taverage = (t0 / (t990 * t990) + t1 / (t991 * t991)) / (1. / (t990 * t990) + 1. / (t991 * t991));
263  if (abs(t0 - taverage) > t990 * m_maxTime || abs(t1 - taverage) > t991 * m_maxTime) {return;}
264 
266  ClusterUtils cUtil;
267  const TVector3 clustervertex = cUtil.GetIPPosition();
268 
269  double phi0 = m_eclClusterArray[icMax[0]]->getPhi();
270  TVector3 p30(0., 0., maxClustE[0]);
271  p30.SetTheta(theta0);
272  p30.SetPhi(phi0);
273  const TLorentzVector p40 = cUtil.Get4MomentumFromCluster(m_eclClusterArray[icMax[0]], clustervertex, usePhotons);
274 
275  double phi1 = m_eclClusterArray[icMax[1]]->getPhi();
276  TVector3 p31(0., 0., maxClustE[1]);
277  p31.SetTheta(theta1);
278  p31.SetPhi(phi1);
279  const TLorentzVector p41 = cUtil.Get4MomentumFromCluster(m_eclClusterArray[icMax[1]], clustervertex, usePhotons);
280 
281  double pairmass = (p40 + p41).M();
282  if (pairmass < m_minPairMass) {return;}
283 
285  PCmsLabTransform boostrotate;
286  TLorentzVector p40COM = boostrotate.rotateLabToCms() * p40;
287  TLorentzVector p41COM = boostrotate.rotateLabToCms() * p41;
288  double dphi = abs(p41COM.Phi() - p40COM.Phi()) * TMath::RadToDeg();
289  if (dphi > 180.) {dphi = 360. - dphi;}
290  if (dphi < m_mindPhi) {return;}
291 
292  //------------------------------------------------------------------------
293  //** Find the most energetic crystal in each photon cluster */
294  int crysIDMax[2] = { -1, -1};
295  for (int ic = 0; ic < 2; ic++) {
296  crysIDMax[ic] = m_eclClusterArray[icMax[ic]]->getMaxECellId() - 1;
297  }
298 
299  //------------------------------------------------------------------------
301  memset(&EperCrys[0], 0, EperCrys.size()*sizeof EperCrys[0]);
302  if (!m_measureTrueEnergy) {
303  for (auto& eclDigit : m_eclDigitArray) {
304  int crysID = eclDigit.getCellId() - 1;
305  getObjectPtr<TH2F>("RawDigitAmpvsCrys")->Fill(crysID + 0.001, eclDigit.getAmp());
306 
308  EperCrys[crysID] = eclDigit.getAmp() * abs(GammaGammaECalib[crysID]) * ElectronicsCalib[crysID];
309  if (EperCrys[crysID] > 0.01) {
310  getObjectPtr<TH2F>("RawDigitTimevsCrys")->Fill(crysID + 0.001, eclDigit.getTimeFit());
311  }
312  }
313 
315  } else {
316 
317  //..getEnergyHighestCrystal() includes the leakage correction; we want raw energy.
318  for (int ic = 0; ic < 2; ic++) {
319  float undoCorrection = m_eclClusterArray[icMax[ic]]->getEnergyRaw() / m_eclClusterArray[icMax[ic]]->getEnergy(
320  ECLCluster::EHypothesisBit::c_nPhotons);
321  EperCrys[crysIDMax[ic]] = undoCorrection * m_eclClusterArray[icMax[ic]]->getEnergyHighestCrystal();
322 
323  }
324  }
325 
326  //------------------------------------------------------------------------
327  //** Store the normalized energies of the two crystals */
328  for (int ic = 0; ic < 2; ic++) {
329  if (crysIDMax[ic] >= 0) {
331  getObjectPtr<TH2F>("EnVsCrysID")->Fill(crysIDMax[ic] + 0.001, EperCrys[crysIDMax[ic]] / abs(ExpGammaGammaE[crysIDMax[ic]]));
332  getObjectPtr<TH1F>("ExpEvsCrys")->Fill(crysIDMax[ic] + 0.001, ExpGammaGammaE[crysIDMax[ic]]);
333  getObjectPtr<TH1F>("ElecCalibvsCrys")->Fill(crysIDMax[ic] + 0.001, ElectronicsCalib[crysIDMax[ic]]);
334  getObjectPtr<TH1F>("InitialCalibvsCrys")->Fill(crysIDMax[ic] + 0.001, GammaGammaECalib[crysIDMax[ic]]);
335  getObjectPtr<TH1F>("CalibEntriesvsCrys")->Fill(crysIDMax[ic] + 0.001);
336  }
337  }
338  if (crysIDMax[0] >= 0 && crysIDMax[1] >= 0) {
339  getObjectPtr<TH1F>("TimeMinusAverage")->Fill((t0 - taverage) / t990);
340  getObjectPtr<TH1F>("TimeMinusAverage")->Fill((t1 - taverage) / t991);
341  }
342 }
Calibration collector module base class.
Class to provide momentum-related information from ECLClusters.
Definition: ClusterUtils.h:34
const TLorentzVector Get4MomentumFromCluster(const ECLCluster *cluster, ECLCluster::EHypothesisBit hypo)
Returns four momentum vector.
Definition: ClusterUtils.cc:24
const TVector3 GetIPPosition()
Returns default IP position from beam parameters.
Provides a type-safe way to pass members of the chargedStableSet set.
Definition: Const.h:470
EHypothesisBit
The hypothesis bits for this ECLCluster (Connected region (CR) is split using this hypothesis.
Definition: ECLCluster.h:31
unsigned short getNHits() const
Get the total Number of CDC hits in the fit.
Class to hold Lorentz transformations from/to CMS and boost vector.
const TLorentzRotation rotateLabToCms() const
Returns Lorentz transformation from Lab to CMS.
Values of the result of a track fit with a given particle hypothesis.
double getPValue() const
Getter for Chi2 Probability of the track fit.
double getD0() const
Getter for d0.
double getTransverseMomentum() const
Getter for the absolute value of the transverse momentum at the perigee.
double getZ0() const
Getter for z0.
HitPatternCDC getHitPatternCDC() const
Getter for the hit pattern in the CDC;.
Calibration collector module that uses e+e- --> gamma gamma to do ECL single crystal energy calibrati...
#define REG_MODULE(moduleName)
Register the given module (without 'Module' suffix) with the framework.
Definition: Module.h:650
Abstract base class for different kinds of events.