9 #include <ecl/modules/eclMuMuECollector/eclMuMuECollectorModule.h>
15 #include <framework/gearbox/Const.h>
16 #include <framework/dataobjects/EventMetaData.h>
19 #include <tracking/dataobjects/ExtHit.h>
22 #include <ecl/dataobjects/ECLDigit.h>
23 #include <ecl/geometry/ECLNeighbours.h>
24 #include <ecl/dbobjects/ECLCrystalCalib.h>
27 #include <mdst/dataobjects/Track.h>
28 #include <mdst/dataobjects/TRGSummary.h>
29 #include <mdst/dataobjects/ECLCluster.h>
48 m_ElectronicsCalib("ECLCrystalElectronics"), m_MuMuECalib("ECLCrystalEnergyMuMu"), m_CrystalEnergy("ECLCrystalEnergy")
51 setDescription(
"Calibration Collector Module for ECL single crystal energy calibration using muons");
52 setPropertyFlags(c_ParallelProcessingCertified);
53 addParam(
"minPairMass", m_minPairMass,
"minimum invariant mass of the muon pair (GeV/c^2)", 9.0);
54 addParam(
"minTrackLength", m_minTrackLength,
"minimum extrapolated track length in the crystal (cm)", 30.);
55 addParam(
"MaxNeighbourE", m_MaxNeighbourE,
"maximum energy allowed in a neighbouring crystal (GeV)", 0.010);
56 addParam(
"thetaLabMinDeg", m_thetaLabMinDeg,
"miniumum muon theta in lab (degrees)", 17.);
57 addParam(
"thetaLabMaxDeg", m_thetaLabMaxDeg,
"maximum muon theta in lab (degrees)", 150.);
58 addParam(
"measureTrueEnergy", m_measureTrueEnergy,
"use MC events to obtain expected energies",
false);
59 addParam(
"requireL1", m_requireL1,
"only use events that have a level 1 trigger",
true);
64 void eclMuMuECollectorModule::prepare()
70 B2INFO(
"eclMuMuECollector: Experiment = " << m_evtMetaData->getExperiment() <<
" run = " << m_evtMetaData->getRun());
74 auto TrkPerCrysID =
new TH1F(
"TrkPerCrysID",
"track extrapolations per crystalID;crystal ID", 8736, 0, 8736);
75 registerObject<TH1F>(
"TrkPerCrysID", TrkPerCrysID);
77 auto EnVsCrysID =
new TH2F(
"EnVsCrysID",
"Normalized energy for each crystal;crystal ID;E/Expected", 8736, 0, 8736, 240, 0.1, 2.5);
78 registerObject<TH2F>(
"EnVsCrysID", EnVsCrysID);
80 auto ExpEvsCrys =
new TH1F(
"ExpEvsCrys",
"Sum expected energy vs crystal ID;crystal ID;Energy (GeV)", 8736, 0, 8736);
81 registerObject<TH1F>(
"ExpEvsCrys", ExpEvsCrys);
83 auto ElecCalibvsCrys =
new TH1F(
"ElecCalibvsCrys",
"Sum electronics calib const vs crystal ID;crystal ID;calibration constant",
85 registerObject<TH1F>(
"ElecCalibvsCrys", ElecCalibvsCrys);
87 auto InitialCalibvsCrys =
new TH1F(
"InitialCalibvsCrys",
88 "Sum initial muon pair calib const vs crystal ID;crystal ID;calibration constant", 8736, 0, 8736);
89 registerObject<TH1F>(
"InitialCalibvsCrys", InitialCalibvsCrys);
91 auto CalibEntriesvsCrys =
new TH1F(
"CalibEntriesvsCrys",
"Entries in calib vs crys histograms;crystal ID;Entries per crystal", 8736,
93 registerObject<TH1F>(
"CalibEntriesvsCrys", CalibEntriesvsCrys);
96 auto RawDigitAmpvsCrys =
new TH2F(
"RawDigitAmpvsCrys",
"Digit Amplitude vs crystal ID;crystal ID;Amplitude", 8736, 0, 8736, 250, 0,
98 registerObject<TH2F>(
"RawDigitAmpvsCrys", RawDigitAmpvsCrys);
100 auto RawDigitTimevsCrys =
new TH2F(
"RawDigitTimevsCrys",
"Digit Time vs crystal ID;crystal ID;Time", 8736, 0, 8736, 200, -2000,
102 registerObject<TH2F>(
"RawDigitTimevsCrys", RawDigitTimevsCrys);
105 auto hitCrysVsExtrapolatedCrys =
new TH2F(
"hitCrysVsExtrapolatedCrys",
106 "Crystals with high energy vs extrapolated crystals with no energy;extrapolated crystalID;High crystalID", 8736, 0, 8736, 8736, 0,
108 registerObject<TH2F>(
"hitCrysVsExtrapolatedCrys", hitCrysVsExtrapolatedCrys);
119 B2INFO(
"Input parameters to eclMuMuECollector:");
120 B2INFO(
"minPairMass: " << m_minPairMass);
121 B2INFO(
"minTrackLength: " << m_minTrackLength);
122 B2INFO(
"MaxNeighbourE: " << m_MaxNeighbourE);
123 B2INFO(
"thetaLabMinDeg: " << m_thetaLabMinDeg);
124 B2INFO(
"thetaLabMaxDeg: " << m_thetaLabMaxDeg);
125 if (m_thetaLabMinDeg < 1.) {
126 cotThetaLabMax = 9999.;
127 }
else if (m_thetaLabMinDeg > 179.) {
128 cotThetaLabMax = -9999.;
130 double thetaLabMin = m_thetaLabMinDeg * TMath::Pi() / 180.;
131 cotThetaLabMax = 1. / tan(thetaLabMin);
133 if (m_thetaLabMaxDeg < 1.) {
134 cotThetaLabMin = 9999.;
135 }
else if (m_thetaLabMaxDeg > 179.) {
136 cotThetaLabMin = -9999.;
138 double thetaLabMax = m_thetaLabMaxDeg * TMath::Pi() / 180.;
139 cotThetaLabMin = 1. / tan(thetaLabMax);
141 B2INFO(
"cotThetaLabMin: " << cotThetaLabMin);
142 B2INFO(
"cotThetaLabMax: " << cotThetaLabMax);
143 B2INFO(
"measureTrueEnergy: " << m_measureTrueEnergy);
144 B2INFO(
"requireL1: " << m_requireL1);
147 EperCrys.resize(8736);
151 if (m_ECLExpMuMuE.hasChanged()) {ExpMuMuE = m_ECLExpMuMuE->getCalibVector();}
152 if (m_ElectronicsCalib.hasChanged()) {ElectronicsCalib = m_ElectronicsCalib->getCalibVector();}
153 if (m_MuMuECalib.hasChanged()) {MuMuECalib = m_MuMuECalib->getCalibVector();}
154 if (m_CrystalEnergy.hasChanged()) {CrystalEnergy = m_CrystalEnergy->getCalibVector();}
157 for (
int ic = 1; ic < 9000; ic += 1000) {
158 B2INFO(
"DB constants for cellID=" << ic <<
": ExpMuMuE = " << ExpMuMuE[ic - 1] <<
" ElectronicsCalib = " << ElectronicsCalib[ic - 1]
159 <<
" MuMuECalib = " << MuMuECalib[ic - 1]);
163 for (
int crysID = 0; crysID < 8736; crysID++) {
164 if (ElectronicsCalib[crysID] <= 0) {B2FATAL(
"eclMuMuECollector: ElectronicsCalib = " << ElectronicsCalib[crysID] <<
" for crysID = " << crysID);}
165 if (ExpMuMuE[crysID] == 0) {B2FATAL(
"eclMuMuECollector: ExpMuMuE = 0 for crysID = " << crysID);}
166 if (MuMuECalib[crysID] == 0) {B2FATAL(
"eclMuMuECollector: MuMuECalib = 0 for crysID = " << crysID);}
171 m_trackArray.isRequired();
172 m_eclDigitArray.isRequired();
173 if (m_measureTrueEnergy) {m_eclClusterArray.isRequired();}
180 void eclMuMuECollectorModule::collect()
185 for (
int crysID = 0; crysID < 8736; crysID++) {
186 getObjectPtr<TH1F>(
"ExpEvsCrys")->Fill(crysID + 0.001, ExpMuMuE[crysID]);
187 getObjectPtr<TH1F>(
"ElecCalibvsCrys")->Fill(crysID + 0.001, ElectronicsCalib[crysID]);
188 getObjectPtr<TH1F>(
"InitialCalibvsCrys")->Fill(crysID + 0.001, MuMuECalib[crysID]);
189 getObjectPtr<TH1F>(
"CalibEntriesvsCrys")->Fill(crysID + 0.001);
193 if (iEvent % 10000 == 0) {B2INFO(
"eclMuMuECollector: iEvent = " << iEvent);}
198 bool newConst =
false;
199 if (m_ECLExpMuMuE.hasChanged()) {
201 B2INFO(
"ECLExpMuMuE has changed, exp = " << m_evtMetaData->getExperiment() <<
" run = " << m_evtMetaData->getRun());
202 ExpMuMuE = m_ECLExpMuMuE->getCalibVector();
204 if (m_ElectronicsCalib.hasChanged()) {
206 B2INFO(
"ECLCrystalElectronics has changed, exp = " << m_evtMetaData->getExperiment() <<
" run = " << m_evtMetaData->getRun());
207 ElectronicsCalib = m_ElectronicsCalib->getCalibVector();
209 if (m_MuMuECalib.hasChanged()) {
211 B2INFO(
"ECLCrystalEnergyMuMu has changed, exp = " << m_evtMetaData->getExperiment() <<
" run = " << m_evtMetaData->getRun());
212 MuMuECalib = m_MuMuECalib->getCalibVector();
214 if (m_CrystalEnergy.hasChanged()) {
216 B2INFO(
"ECLCrystalEnergy has changed, exp = " << m_evtMetaData->getExperiment() <<
" run = " << m_evtMetaData->getRun());
217 CrystalEnergy = m_CrystalEnergy->getCalibVector();
221 for (
int ic = 1; ic < 9000; ic += 1000) {
222 B2INFO(
"DB constants for cellID=" << ic <<
": ExpMuMuE = " << ExpMuMuE[ic - 1] <<
" ElectronicsCalib = " <<
223 ElectronicsCalib[ic - 1]
224 <<
" MuMuECalib = " << MuMuECalib[ic - 1]);
228 for (
int crysID = 0; crysID < 8736; crysID++) {
229 if (ElectronicsCalib[crysID] <= 0) {B2FATAL(
"eclMuMuECollector: ElectronicsCalib = " << ElectronicsCalib[crysID] <<
" for crysID = " << crysID);}
230 if (ExpMuMuE[crysID] == 0) {B2FATAL(
"eclMuMuECollector: ExpMuMuE = 0 for crysID = " << crysID);}
231 if (MuMuECalib[crysID] == 0) {B2FATAL(
"eclMuMuECollector: MuMuECalib = 0 for crysID = " << crysID);}
240 unsigned int L1TriggerResults = m_TRGResults->getTRGSummary(0);
241 if (L1TriggerResults == 0) {
return;}
246 int nTrack = m_trackArray.getEntries();
247 if (nTrack < 2) {
return;}
250 double maxpt[2] = {0., 0.};
251 int iTrack[2] = { -1, -1};
252 for (
int it = 0; it < nTrack; it++) {
254 if (not temptrackFit) {
continue;}
260 if (temppt > maxpt[imu] && cotThetaLab > cotThetaLabMin && cotThetaLab < cotThetaLabMax) {
267 if (iTrack[0] == -1 || iTrack[1] == -1) {
return; }
270 TLorentzVector mu0 = m_trackArray[iTrack[0]]->getTrackFitResult(
Const::ChargedStable(211))->get4Momentum();
271 TLorentzVector mu1 = m_trackArray[iTrack[1]]->getTrackFitResult(
Const::ChargedStable(211))->get4Momentum();
272 if ((mu0 + mu1).M() < m_minPairMass) {
return; }
276 int extCrysID[2] = { -1, -1};
278 for (
int imu = 0; imu < 2; imu++) {
279 TVector3 temppos[2] = {};
281 for (
auto& extHit : m_trackArray[iTrack[imu]]->getRelationsTo<ExtHit>()) {
282 int pdgCode = extHit.getPdgCode();
284 int temp0 = extHit.getCopyID();
287 if (detectorID == eclID && TMath::Abs(pdgCode) == Const::muon.getPDGCode() && extHit.getStatus() == EXT_ENTER) {
289 temppos[0] = extHit.getPosition();
293 if (detectorID == eclID && TMath::Abs(pdgCode) == Const::muon.getPDGCode() && extHit.getStatus() == EXT_EXIT && temp0 == IDEnter) {
294 temppos[1] = extHit.getPosition();
297 double trackLength = (temppos[1] - temppos[0]).Mag();
298 if (trackLength > m_minTrackLength) {extCrysID[imu] = temp0;}
305 if (extCrysID[0] == -1 && extCrysID[1] == -1) {
return; }
309 std::fill(EperCrys.begin(), EperCrys.end(), 0);
312 const double highEnergyThresh = 0.18;
313 std::vector<int> highECrys;
316 for (
auto& eclDigit : m_eclDigitArray) {
317 int crysID = eclDigit.getCellId() - 1;
318 getObjectPtr<TH2F>(
"RawDigitAmpvsCrys")->Fill(crysID + 0.001, eclDigit.getAmp());
321 float calib = abs(MuMuECalib[crysID]);
322 if (m_measureTrueEnergy) {calib = CrystalEnergy[crysID];}
323 EperCrys[crysID] = eclDigit.getAmp() * calib * ElectronicsCalib[crysID];
324 if (EperCrys[crysID] > highEnergyThresh) {highECrys.push_back(crysID);}
325 if (EperCrys[crysID] > 0.01) {
326 getObjectPtr<TH2F>(
"RawDigitTimevsCrys")->Fill(crysID + 0.001, eclDigit.getTimeFit());
334 if (m_measureTrueEnergy) {
335 for (
int ic = 0; ic < m_eclClusterArray.getEntries(); ic++) {
336 if (m_eclClusterArray[ic]->hasHypothesis(ECLCluster::EHypothesisBit::c_nPhotons)) {
337 int crysID = m_eclClusterArray[ic]->getMaxECellId() - 1;
338 float undoCorrection = m_eclClusterArray[ic]->getEnergyRaw() / m_eclClusterArray[ic]->getEnergy(
339 ECLCluster::EHypothesisBit::c_nPhotons);
340 EperCrys[crysID] = undoCorrection * m_eclClusterArray[ic]->getEnergyHighestCrystal();
348 for (
int imu = 0; imu < 2; imu++) {
349 int crysID = extCrysID[imu];
350 int cellID = crysID + 1;
353 getObjectPtr<TH1F>(
"TrkPerCrysID")->Fill(crysID + 0.001);
355 bool noNeighbourSignal =
true;
356 bool highNeighourSignal =
false;
357 if (cellID >= firstcellIDN4 && crysID <= lastcellIDN4) {
358 for (
const auto& tempCellID : myNeighbours4->getNeighbours(cellID)) {
359 int tempCrysID = tempCellID - 1;
360 if (tempCellID != cellID && EperCrys[tempCrysID] > m_MaxNeighbourE) {
361 noNeighbourSignal =
false;
362 if (EperCrys[tempCrysID] > highEnergyThresh) {highNeighourSignal =
true;}
366 for (
const auto& tempCellID : myNeighbours8->getNeighbours(cellID)) {
367 int tempCrysID = tempCellID - 1;
368 if (tempCellID != cellID && EperCrys[tempCrysID] > m_MaxNeighbourE) {
369 noNeighbourSignal =
false;
370 if (EperCrys[tempCrysID] > highEnergyThresh) {highNeighourSignal =
true;}
376 if (noNeighbourSignal) {
379 getObjectPtr<TH2F>(
"EnVsCrysID")->Fill(crysID + 0.001, EperCrys[crysID] / abs(ExpMuMuE[crysID]));
380 getObjectPtr<TH1F>(
"ExpEvsCrys")->Fill(crysID + 0.001, ExpMuMuE[crysID]);
381 getObjectPtr<TH1F>(
"ElecCalibvsCrys")->Fill(crysID + 0.001, ElectronicsCalib[crysID]);
382 getObjectPtr<TH1F>(
"InitialCalibvsCrys")->Fill(crysID + 0.001, MuMuECalib[crysID]);
383 getObjectPtr<TH1F>(
"CalibEntriesvsCrys")->Fill(crysID + 0.001);
387 if (highNeighourSignal or (noNeighbourSignal and EperCrys[crysID] < m_MaxNeighbourE)) {
388 for (
auto&
id : highECrys) {
389 getObjectPtr<TH2F>(
"hitCrysVsExtrapolatedCrys")->Fill(crysID + 0.0001,
id + 0.0001);
Calibration collector module base class.
Provides a type-safe way to pass members of the chargedStableSet set.
EDetector
Enum for identifying the detector components (detector and subdetector).
Class to get the neighbours for a given cell id.
Values of the result of a track fit with a given particle hypothesis.
short getChargeSign() const
Return track charge (1 or -1).
double getCotTheta() const
Getter for tanLambda with CDF naming convention.
double getTransverseMomentum() const
Getter for the absolute value of the transverse momentum at the perigee.
Calibration collector module that uses muon pairs to do ECL single crystal energy calibration.
#define REG_MODULE(moduleName)
Register the given module (without 'Module' suffix) with the framework.
Abstract base class for different kinds of events.