Belle II Software development
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
34using namespace std;
35using namespace Belle2;
36
37
38//-----------------------------------------------------------------
39// Register the Module
40//-----------------------------------------------------------------
41REG_MODULE(eclGammaGammaECollector);
42
43//-----------------------------------------------------------------
44// Implementation
45//-----------------------------------------------------------------
46
47//-----------------------------------------------------------------------------------------------------
48
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:36
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:589
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
eclGammaGammaECollectorModule()
Constructor: Sets the description, the properties and the parameters of the module.
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.
STL namespace.