Belle II Software  release-08-01-10
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 
9 /* Own header. */
10 #include <ecl/modules/eclGammaGammaECollector/eclGammaGammaECollectorModule.h>
11 
12 /* ECL headers. */
13 #include <ecl/dataobjects/ECLDigit.h>
14 #include <ecl/dataobjects/ECLElementNumbers.h>
15 #include <ecl/dbobjects/ECLCrystalCalib.h>
16 
17 /* Basf2 headers. */
18 #include <analysis/ClusterUtility/ClusterUtils.h>
19 #include <analysis/utility/PCmsLabTransform.h>
20 #include <framework/dataobjects/EventMetaData.h>
21 #include <framework/gearbox/Const.h>
22 #include <framework/geometry/VectorUtil.h>
23 #include <mdst/dataobjects/ECLCluster.h>
24 #include <mdst/dataobjects/HitPatternCDC.h>
25 #include <mdst/dataobjects/Track.h>
26 #include <mdst/dataobjects/TrackFitResult.h>
27 #include <mdst/dataobjects/TRGSummary.h>
28 
29 /* ROOT headers. */
30 #include <Math/Vector3D.h>
31 #include <Math/Vector4D.h>
32 #include <TH2F.h>
33 
34 using namespace std;
35 using namespace Belle2;
36 
37 
38 //-----------------------------------------------------------------
39 // Register the Module
40 //-----------------------------------------------------------------
41 REG_MODULE(eclGammaGammaECollector);
42 
43 //-----------------------------------------------------------------
44 // Implementation
45 //-----------------------------------------------------------------
46 
47 //-----------------------------------------------------------------------------------------------------
48 
49 eclGammaGammaECollectorModule::eclGammaGammaECollectorModule() : CalibrationCollectorModule(),
50  m_ECLExpGammaGammaE("ECLExpGammaGammaE"),
51  m_ElectronicsCalib("ECLCrystalElectronics"), m_GammaGammaECalib("ECLCrystalEnergyGammaGamma")
52 {
53  // Set module properties
54  setDescription("Calibration Collector Module for ECL single crystal energy calibration using gamma gamma events");
56  addParam("thetaLabMinDeg", m_thetaLabMinDeg, "miniumum photon theta in lab (degrees)", 0.);
57  addParam("thetaLabMaxDeg", m_thetaLabMaxDeg, "maximum photon theta in lab (degrees)", 180.);
58  addParam("minPairMass", m_minPairMass, "minimum invariant mass of the pair of photons (GeV/c^2)", 9.);
59  addParam("mindPhi", m_mindPhi, "minimum delta phi between clusters (deg)", 179.);
60  addParam("maxTime", m_maxTime, "maximum (time-<t>)/dt99 of photons", 1.);
61  addParam("measureTrueEnergy", m_measureTrueEnergy, "use MC events to obtain expected energies", false);
62  addParam("requireL1", m_requireL1, "only use events that have a level 1 trigger", true);
63 }
64 
65 
66 
70 {
71 
73  B2INFO("eclGammaGammaECollector: Experiment = " << m_evtMetaData->getExperiment() << " run = " << m_evtMetaData->getRun());
74 
77  auto EnVsCrysID = new TH2F("EnVsCrysID", "Normalized energy for each crystal;crystal ID;E/Expected", ECLElementNumbers::c_NCrystals,
78  0, ECLElementNumbers::c_NCrystals, 140, 0, 1.4);
79  registerObject<TH2F>("EnVsCrysID", EnVsCrysID);
80 
81  auto ExpEvsCrys = new TH1F("ExpEvsCrys", "Sum expected energy vs crystal ID;crystal ID;Energy (GeV)",
83  registerObject<TH1F>("ExpEvsCrys", ExpEvsCrys);
84 
85  auto ElecCalibvsCrys = new TH1F("ElecCalibvsCrys", "Sum electronics calib const vs crystal ID;crystal ID;calibration constant",
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", ECLElementNumbers::c_NCrystals, 0,
92  registerObject<TH1F>("InitialCalibvsCrys", InitialCalibvsCrys);
93 
94  auto CalibEntriesvsCrys = new TH1F("CalibEntriesvsCrys", "Entries in calib vs crys histograms;crystal ID;Entries per crystal",
97  registerObject<TH1F>("CalibEntriesvsCrys", CalibEntriesvsCrys);
98 
100  auto RawDigitAmpvsCrys = new TH2F("RawDigitAmpvsCrys", "Digit Amplitude vs crystal ID;crystal ID;Amplitude",
102  200000);
103  registerObject<TH2F>("RawDigitAmpvsCrys", RawDigitAmpvsCrys);
104 
105  auto RawDigitTimevsCrys = new TH2F("RawDigitTimevsCrys", "Digit Time vs crystal ID;crystal ID;Time", ECLElementNumbers::c_NCrystals,
106  0, ECLElementNumbers::c_NCrystals, 200, -2000,
107  2000);
108  registerObject<TH2F>("RawDigitTimevsCrys", RawDigitTimevsCrys);
109 
110  auto TimeMinusAverage = new TH1F("TimeMinusAverage", "Photon time - average / dt99;(T-T_ave)/dt99 ", 100, -10, 10);
111  registerObject<TH1F>("TimeMinusAverage", TimeMinusAverage);
112 
113 
114  //------------------------------------------------------------------------
116  B2INFO("Input parameters to eclGammaGammaECollector:");
117  B2INFO("thetaLabMinDeg: " << m_thetaLabMinDeg);
118  B2INFO("thetaLabMaxDeg: " << m_thetaLabMaxDeg);
119  thetaLabMin = m_thetaLabMinDeg / TMath::RadToDeg();
120  thetaLabMax = m_thetaLabMaxDeg / TMath::RadToDeg();
121  B2INFO("minPairMass: " << m_minPairMass);
122  B2INFO("mindPhi: " << m_mindPhi);
123  B2INFO("maxTime: " << m_maxTime);
124  B2INFO("measureTrueEnergy: " << m_measureTrueEnergy);
125  B2INFO("requireL1: " << m_requireL1);
126 
129 
132  if (m_ECLExpGammaGammaE.hasChanged()) {ExpGammaGammaE = m_ECLExpGammaGammaE->getCalibVector();}
133  if (m_ElectronicsCalib.hasChanged()) {ElectronicsCalib = m_ElectronicsCalib->getCalibVector();}
134  if (m_GammaGammaECalib.hasChanged()) {GammaGammaECalib = m_GammaGammaECalib->getCalibVector();}
135 
137  for (int ic = 1; ic < 9000; ic += 1000) {
138  B2INFO("DB constants for cellID=" << ic << ": ExpGammaGammaE = " << ExpGammaGammaE[ic - 1] << " ElectronicsCalib = " <<
139  ElectronicsCalib[ic - 1]
140  << " GammaGammaECalib = " << GammaGammaECalib[ic - 1]);
141  }
142 
144  for (int crysID = 0; crysID < ECLElementNumbers::c_NCrystals; crysID++) {
145  if (ElectronicsCalib[crysID] <= 0) {B2FATAL("eclGammaGammaECollector: ElectronicsCalib = " << ElectronicsCalib[crysID] << " for crysID = " << crysID);}
146  if (ExpGammaGammaE[crysID] == 0) {B2FATAL("eclGammaGammaECollector: ExpGammaGammaE = 0 for crysID = " << crysID);}
147  if (GammaGammaECalib[crysID] == 0) {B2FATAL("eclGammaGammaECollector: GammaGammaECalib = 0 for crysID = " << crysID);}
148  }
149 
152  m_trackArray.isRequired();
153  m_eclClusterArray.isRequired();
154  if (!m_measureTrueEnergy) {m_eclDigitArray.isRequired();}
155 
156 }
157 
158 
162 {
163 
165  if (storeCalib) {
166  for (int crysID = 0; crysID < ECLElementNumbers::c_NCrystals; crysID++) {
167  getObjectPtr<TH1F>("ExpEvsCrys")->Fill(crysID + 0.001, ExpGammaGammaE[crysID]);
168  getObjectPtr<TH1F>("ElecCalibvsCrys")->Fill(crysID + 0.001, ElectronicsCalib[crysID]);
169  getObjectPtr<TH1F>("InitialCalibvsCrys")->Fill(crysID + 0.001, GammaGammaECalib[crysID]);
170  getObjectPtr<TH1F>("CalibEntriesvsCrys")->Fill(crysID + 0.001);
171  }
172  storeCalib = false;
173  }
174 
177  bool newConst = false;
178  if (m_ECLExpGammaGammaE.hasChanged()) {
179  newConst = true;
180  B2INFO("ECLExpGammaGammaE has changed, exp = " << m_evtMetaData->getExperiment() << " run = " << m_evtMetaData->getRun());
181  ExpGammaGammaE = m_ECLExpGammaGammaE->getCalibVector();
182  }
183  if (m_ElectronicsCalib.hasChanged()) {
184  newConst = true;
185  B2INFO("ECLCrystalElectronics has changed, exp = " << m_evtMetaData->getExperiment() << " run = " << m_evtMetaData->getRun());
186  ElectronicsCalib = m_ElectronicsCalib->getCalibVector();
187  }
188  if (m_GammaGammaECalib.hasChanged()) {
189  newConst = true;
190  B2INFO("ECLCrystalEnergyGammaGamma has changed, exp = " << m_evtMetaData->getExperiment() << " run = " << m_evtMetaData->getRun());
191  GammaGammaECalib = m_GammaGammaECalib->getCalibVector();
192  }
193 
194  if (newConst) {
195  for (int ic = 1; ic < 9000; ic += 1000) {
196  B2INFO("DB constants for cellID=" << ic << ": ExpGammaGammaE = " << ExpGammaGammaE[ic - 1] << " ElectronicsCalib = " <<
197  ElectronicsCalib[ic - 1]
198  << " GammaGammaECalib = " << GammaGammaECalib[ic - 1]);
199  }
200 
202  for (int crysID = 0; crysID < ECLElementNumbers::c_NCrystals; crysID++) {
203  if (ElectronicsCalib[crysID] <= 0) {B2FATAL("eclGammaGammaECollector: ElectronicsCalib = " << ElectronicsCalib[crysID] << " for crysID = " << crysID);}
204  if (ExpGammaGammaE[crysID] == 0) {B2FATAL("eclGammaGammaECollector: ExpGammaGammaE = 0 for crysID = " << crysID);}
205  if (GammaGammaECalib[crysID] == 0) {B2FATAL("eclGammaGammaECollector: GammaGammaECalib = 0 for crysID = " << crysID);}
206  }
207  }
208 
211  if (m_requireL1) {
212  unsigned int L1TriggerResults = m_TRGResults->getTRGSummary(0);
213  if (L1TriggerResults == 0) {return;}
214  }
215 
216  //------------------------------------------------------------------------
218  int nGoodTrk = 0;
219  for (auto& track : m_trackArray) {
220  const TrackFitResult* temptrackFit = track.getTrackFitResult(Const::ChargedStable(211));
221  if (temptrackFit) {
222  double pt = temptrackFit->getTransverseMomentum();
223  double z0 = temptrackFit->getZ0();
224  double d0 = temptrackFit->getD0();
225  double pValue = temptrackFit->getPValue();
226  int nCDChits = temptrackFit->getHitPatternCDC().getNHits();
227  if (pt > minTrkpt && abs(z0) < maxZ0 && abs(d0) < maxD0 && pValue > minpValue && nCDChits >= minCDChits) {nGoodTrk++;}
228  }
229  }
230  if (nGoodTrk > 0) {return;}
231 
232  //------------------------------------------------------------------------
235  int icMax[2] = { -1, -1};
236  double maxClustE[2] = { -1., -1.};
237  int nclust = m_eclClusterArray.getEntries();
238  for (int ic = 0; ic < nclust; ic++) {
239  if (m_eclClusterArray[ic]->hasHypothesis(usePhotons)) {
240  double eClust = m_eclClusterArray[ic]->getEnergy(usePhotons);
241  if (eClust > maxClustE[0]) {
242  maxClustE[1] = maxClustE[0];
243  icMax[1] = icMax[0];
244  maxClustE[0] = eClust;
245  icMax[0] = ic;
246  } else if (eClust > maxClustE[1]) {
247  maxClustE[1] = eClust;
248  icMax[1] = ic;
249  }
250  }
251  }
252 
253  //------------------------------------------------------------------------
256  if (icMax[0] == -1 || icMax[1] == -1) {return;}
257  double theta0 = m_eclClusterArray[icMax[0]]->getTheta();
258  double theta1 = m_eclClusterArray[icMax[1]]->getTheta();
259  if (theta0 < thetaLabMin || theta0 > thetaLabMax || theta1 < thetaLabMin || theta1 > thetaLabMax) {return;}
260 
262  double t0 = m_eclClusterArray[icMax[0]]->getTime();
263  double t990 = m_eclClusterArray[icMax[0]]->getDeltaTime99();
264  double t1 = m_eclClusterArray[icMax[1]]->getTime();
265  double t991 = m_eclClusterArray[icMax[1]]->getDeltaTime99();
266  double taverage = (t0 / (t990 * t990) + t1 / (t991 * t991)) / (1. / (t990 * t990) + 1. / (t991 * t991));
267  if (abs(t0 - taverage) > t990 * m_maxTime || abs(t1 - taverage) > t991 * m_maxTime) {return;}
268 
270  ClusterUtils cUtil;
271  const ROOT::Math::XYZVector clustervertex = cUtil.GetIPPosition();
272 
273  double phi0 = m_eclClusterArray[icMax[0]]->getPhi();
274  ROOT::Math::XYZVector p30;
275  VectorUtil::setMagThetaPhi(p30, maxClustE[0], theta0, phi0);
276  const ROOT::Math::PxPyPzEVector p40 = cUtil.Get4MomentumFromCluster(m_eclClusterArray[icMax[0]], clustervertex, usePhotons);
277 
278  double phi1 = m_eclClusterArray[icMax[1]]->getPhi();
279  ROOT::Math::XYZVector p31;
280  VectorUtil::setMagThetaPhi(p31, maxClustE[1], theta1, phi1);
281  const ROOT::Math::PxPyPzEVector p41 = cUtil.Get4MomentumFromCluster(m_eclClusterArray[icMax[1]], clustervertex, usePhotons);
282 
283  double pairmass = (p40 + p41).M();
284  if (pairmass < m_minPairMass) {return;}
285 
287  PCmsLabTransform boostrotate;
288  ROOT::Math::PxPyPzEVector p40COM = boostrotate.rotateLabToCms() * p40;
289  ROOT::Math::PxPyPzEVector p41COM = boostrotate.rotateLabToCms() * p41;
290  double dphi = abs(p41COM.Phi() - p40COM.Phi()) * TMath::RadToDeg();
291  if (dphi > 180.) {dphi = 360. - dphi;}
292  if (dphi < m_mindPhi) {return;}
293 
294  //------------------------------------------------------------------------
295  //** Find the most energetic crystal in each photon cluster */
296  int crysIDMax[2] = { -1, -1};
297  for (int ic = 0; ic < 2; ic++) {
298  crysIDMax[ic] = m_eclClusterArray[icMax[ic]]->getMaxECellId() - 1;
299  }
300 
301  //------------------------------------------------------------------------
303  memset(&EperCrys[0], 0, EperCrys.size()*sizeof EperCrys[0]);
304  if (!m_measureTrueEnergy) {
305  for (auto& eclDigit : m_eclDigitArray) {
306  int crysID = eclDigit.getCellId() - 1;
307  getObjectPtr<TH2F>("RawDigitAmpvsCrys")->Fill(crysID + 0.001, eclDigit.getAmp());
308 
310  EperCrys[crysID] = eclDigit.getAmp() * abs(GammaGammaECalib[crysID]) * ElectronicsCalib[crysID];
311  if (EperCrys[crysID] > 0.01) {
312  getObjectPtr<TH2F>("RawDigitTimevsCrys")->Fill(crysID + 0.001, eclDigit.getTimeFit());
313  }
314  }
315 
317  } else {
318 
319  //..getEnergyHighestCrystal() includes the leakage correction; we want raw energy.
320  for (int ic = 0; ic < 2; ic++) {
321  float undoCorrection = m_eclClusterArray[icMax[ic]]->getEnergyRaw() / m_eclClusterArray[icMax[ic]]->getEnergy(
323  EperCrys[crysIDMax[ic]] = undoCorrection * m_eclClusterArray[icMax[ic]]->getEnergyHighestCrystal();
324 
325  }
326  }
327 
328  //------------------------------------------------------------------------
329  //** Store the normalized energies of the two crystals */
330  for (int ic = 0; ic < 2; ic++) {
331  if (crysIDMax[ic] >= 0) {
333  getObjectPtr<TH2F>("EnVsCrysID")->Fill(crysIDMax[ic] + 0.001, EperCrys[crysIDMax[ic]] / abs(ExpGammaGammaE[crysIDMax[ic]]));
334  getObjectPtr<TH1F>("ExpEvsCrys")->Fill(crysIDMax[ic] + 0.001, ExpGammaGammaE[crysIDMax[ic]]);
335  getObjectPtr<TH1F>("ElecCalibvsCrys")->Fill(crysIDMax[ic] + 0.001, ElectronicsCalib[crysIDMax[ic]]);
336  getObjectPtr<TH1F>("InitialCalibvsCrys")->Fill(crysIDMax[ic] + 0.001, GammaGammaECalib[crysIDMax[ic]]);
337  getObjectPtr<TH1F>("CalibEntriesvsCrys")->Fill(crysIDMax[ic] + 0.001);
338  }
339  }
340  if (crysIDMax[0] >= 0 && crysIDMax[1] >= 0) {
341  getObjectPtr<TH1F>("TimeMinusAverage")->Fill((t0 - taverage) / t990);
342  getObjectPtr<TH1F>("TimeMinusAverage")->Fill((t1 - taverage) / t991);
343  }
344 }
Calibration collector module base class.
Class to provide momentum-related information from ECLClusters.
Definition: ClusterUtils.h:35
const ROOT::Math::PxPyPzEVector Get4MomentumFromCluster(const ECLCluster *cluster, ECLCluster::EHypothesisBit hypo)
Returns four momentum vector.
Definition: ClusterUtils.cc:25
const ROOT::Math::XYZVector GetIPPosition()
Returns default IP position from beam parameters.
Provides a type-safe way to pass members of the chargedStableSet set.
Definition: Const.h:580
EHypothesisBit
The hypothesis bits for this ECLCluster (Connected region (CR) is split using this hypothesis.
Definition: ECLCluster.h:31
@ c_nPhotons
CR is split into n photons (N1)
unsigned short getNHits() const
Get the total Number of CDC hits in the fit.
void setDescription(const std::string &description)
Sets the description of the module.
Definition: Module.cc:214
void setPropertyFlags(unsigned int propertyFlags)
Sets the flags for the module properties.
Definition: Module.cc:208
@ c_ParallelProcessingCertified
This module can be run in parallel processing mode safely (All I/O must be done through the data stor...
Definition: Module.h:80
Class to hold Lorentz transformations from/to CMS and boost vector.
const ROOT::Math::LorentzRotation 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;.
DBObjPtr< ECLCrystalCalib > m_ECLExpGammaGammaE
Expected energies from database.
double maxD0
(cm) maximum abs(D0) of a good track
double minTrkpt
(GeV/c) minimum pt of a good track
StoreArray< ECLDigit > m_eclDigitArray
Required input array of ECLDigits.
DBObjPtr< ECLCrystalCalib > m_GammaGammaECalib
Existing single crystal calibration from DB; will be updated by CAF.
bool m_requireL1
require events to satisfy a level 1 trigger (true)
double m_maxTime
maximum photon (time - <t>)/dt99 (1)
double m_mindPhi
minimum delta phi between clusters (179 deg)
StoreArray< ECLCluster > m_eclClusterArray
Required input array of ECLClusters.
StoreObjPtr< TRGSummary > m_TRGResults
dataStore TRGSummary
std::vector< float > ExpGammaGammaE
vector obtained from DB object
double thetaLabMin
Some other useful quantities.
bool storeCalib
force the input calibration constants to be saved first event
std::vector< float > EperCrys
ECL digit energy for each crystal.
void collect() override
Select events and crystals and accumulate histograms.
double m_minPairMass
minimum invariant mass of the pair of photons (9 GeV/c^2)
StoreObjPtr< EventMetaData > m_evtMetaData
dataStore EventMetaData
std::vector< float > ElectronicsCalib
vector obtained from DB object
int minCDChits
minimum CDC hits for a good track
double minpValue
minimum p value of a good track
void prepare() override
Define histograms and read payloads from DB.
double maxZ0
(cm) maximum abs(Z0) of a good track
double thetaLabMax
m_thetaLabMaxDeg converted to radians (coneversion in Module::init)
double m_thetaLabMaxDeg
maximum photon theta in lab (180 degrees)
double m_thetaLabMinDeg
Parameters to control the job.
DBObjPtr< ECLCrystalCalib > m_ElectronicsCalib
Electronics calibration from database.
bool m_measureTrueEnergy
use eclCalDigit to determine MC deposited energy (false)
std::vector< float > GammaGammaECalib
vector obtained from DB object
StoreArray< Track > m_trackArray
Required arrays.
void addParam(const std::string &name, T &paramVariable, const std::string &description, const T &defaultValue)
Adds a new parameter to the module.
Definition: Module.h:560
#define REG_MODULE(moduleName)
Register the given module (without 'Module' suffix) with the framework.
Definition: Module.h:650
const int c_NCrystals
Number of crystals.
Abstract base class for different kinds of events.