49 setDescription(
"Calibration collector module to find optimal number of crystal for cluster energies");
52 addParam(
"energiesForward",
m_energiesForward,
"generated photon energies, forward", std::vector<double> {0.030, 0.050, 0.100, 0.200, 0.483, 1.166, 2.816, 6.800});
53 addParam(
"energiesBarrel",
m_energiesBarrel,
"generated photon energies, barrel", std::vector<double> {0.030, 0.050, 0.100, 0.200, 0.458, 1.049, 2.402, 5.500});
54 addParam(
"energiesBackward",
m_energiesBackward,
"generated photon energies, backward", std::vector<double> {0.030, 0.050, 0.100, 0.200, 0.428, 0.917, 1.962, 4.200});
71 B2FATAL(
"eclNOptimalCollector: length of energy vectors inconsistent with parameter numberEnergies: " << nForward <<
" " <<
97 std::vector<int> nCrysPerRing;
98 for (
int thID = 0; thID < 69; thID++) {
99 const int nCrys =
neighbours->getCrystalsPerRing(thID);
100 nCrysPerRing.push_back(nCrys);
101 for (
int phID = 0; phID < nCrys; phID++) {
107 std::vector<int> firstCrysIdPerRing;
108 firstCrysIdPerRing.push_back(0);
109 for (
int thID = 1; thID < 69; thID++) {
110 const int iCrysID = firstCrysIdPerRing[thID - 1] + nCrysPerRing[thID - 1];
111 firstCrysIdPerRing.push_back(iCrysID);
119 const int specialThetaID[4] = {5, 11, 60, 65};
122 for (
int thID = firstThetaId; thID <= lastThetaId; thID++) {
125 for (
int phID = 0; phID < nCrysPerRing[thID]; phID++) {
126 const int iCrysID = firstCrysIdPerRing[thID] + phID;
127 const int iLocalGroup = phID / nCrysPerGroup;
132 if (thID == specialThetaID[iSp]) {
135 for (
int phID = 1; phID < nCrysPerRing[thID]; phID += 3) {
136 const int iCrysID = firstCrysIdPerRing[thID] + phID;
137 const int iLocalGroup = phID / nCrysPerGroup;
146 const int iCrysID = ic - 1;
151 const int iCrysID = ic - 1;
161 auto inputParameters =
new TH1F(
"inputParameters",
"eclNOptimalCollector job parameters", nBinX, 0, nBinX);
165 auto groupNumberOfEachCellID =
new TH1F(
"groupNumberOfEachCellID",
"group number of each cellID;cellID",
172 auto entriesPerThetaIdEnergy =
new TH2F(
"entriesPerThetaIdEnergy",
"Entries per thetaID/energy point;thetaID;energy point", 69, 0,
176 auto mcEnergyDiff =
new TH2F(
"mcEnergyDiff",
"mc E minus nominal (MeV) per thetaID/energy point;thetaID;energy point", 69, 0, 69,
178 mcEnergyDiff->Sumw2();
182 auto eMCOverEGenerated =
new TH1D(
"eMCOverEGenerated",
"MC energy of cluster divided by generated;ratio", 101, 0, 1.01);
185 auto clusterTime =
new TH1D(
"clusterTime",
"clusterTiming of matched clusters;clusterTiming (ns)", 2048, -1000, 1000);
188 auto angularDiff =
new TH1D(
"angularDiff",
189 "angular difference between generated photon and cluster;angular difference (rad);photons per 0.01", 300, 0, 0.3);
192 auto nOutOfTimeCrystals =
new TH1D(
"nOutOfTimeCrystals",
"Out-of-time crystals in single particle MC;Out of time crystals", 2000, 0,
196 auto timeSinceInjection =
new TH1D(
"timeSinceInjection",
197 "Time since injection in single particle MC;time (micro seconds);events per 10 us", 8000, 0, 80000);
205 vector<TH2F*> eSum(nHist);
206 vector<TH2F*> biasSum(nHist);
211 std::string name =
"eSum_" + std::to_string(ig) +
"_" + std::to_string(ie);
212 TString hname = name;
213 TString title =
"energy summed over nCrys divided by eMC, group " + std::to_string(ig) +
", E point " + std::to_string(
214 ie) +
";nCrys;energy sum / Etrue";
215 eSum[iHist] =
new TH2F(hname, title,
nCrysMax + 1, 1.,
nCrysMax + 2., 2000, 0., 2.);
218 name =
"biasSum_" + std::to_string(ig) +
"_" + std::to_string(ie);
220 title =
"energy minus mc true summing over nCrys, group " + std::to_string(ig) +
", E point " + std::to_string(
221 ie) +
";nCrys;bias = energy minus mc truth (GeV)";
222 biasSum[iHist] =
new TH2F(hname, title,
nCrysMax + 1, 1.,
nCrysMax + 2., 1000, -0.1, 0.1);
227 B2INFO(
"Finished setup for eclNOptimalCollectorModule");
241 double firstBin = 2.01;
259 for (
int ic = 1; ic < 8737; ic++) {
266 std::string histName =
"eSum_" + std::to_string(ig) +
"_" + std::to_string(ie);
269 std::string histNameBias =
"biasSum_" + std::to_string(ig) +
"_" + std::to_string(ie);
280 double showerMaxE = 0.;
282 for (
int i = 0; i < nShower; i++) {
285 if (nominalE > showerMaxE) {
286 showerMaxE = nominalE;
293 if (iMax == -1) {
return;}
299 double timing = -1000.;
300 double thetaLab = 0.;
304 const unsigned int nRelatedClusters = showerClusterRelations.size();
305 if (nRelatedClusters > 0) {
306 const auto cluster = showerClusterRelations.object(0);
307 iCellId = cluster->getMaxECellId();
308 timing = cluster->getTime();
309 thetaLab = cluster->getTheta();
310 phiLab = cluster->getPhi();
311 rLab = cluster->getR();
315 if (iCellId<iFirstCellId or iCellId>
iLastCellId) {
return;}
330 if (nMC != 1) {
return;}
334 const float genEnergyMeV = 1000.*eTrue;
335 const float tolerance = std::max(0.002 * genEnergyMeV, 1.0);
339 double minDiff = 9999.;
341 double diff = std::abs(genEnergyMeV -
iEnergies[iRegion][ie]);
342 if (diff < std::abs(minDiff)) {
343 minDiff = genEnergyMeV -
iEnergies[iRegion][ie];
345 if (diff < tolerance) {
353 if (iEnergy == -1) {
return;}
363 std::vector<double> digitEnergies;
364 std::vector < std::pair<double, double> > energies;
367 unsigned int nRelatedDigits = showerDigitRelations.size();
368 double eMCTotal = 0.;
369 for (
unsigned int ir = 0; ir < nRelatedDigits; ir++) {
370 const auto calDigit = showerDigitRelations.object(ir);
371 const auto weight = showerDigitRelations.weight(ir);
372 digitEnergies.push_back(calDigit->getEnergy() * weight);
373 const double eCalDigit = weight * calDigit->getEnergy();
376 auto digitMCRelations = calDigit->getRelationsTo<
MCParticle>();
378 for (
unsigned int i = 0; i < digitMCRelations.size(); i++) {
379 eMC += digitMCRelations.weight(i);
381 std::pair<double, double> pTemp = std::make_pair(eCalDigit, eMC);
382 energies.push_back(pTemp);
387 std::sort(energies.begin(), energies.end());
395 const double minTrueFrac = 0.15;
396 if (eMCTotal < minTrueFrac * eTrue) {
return;}
400 const double maxClusterTiming = 200.;
401 if (abs(timing) > maxClusterTiming) {
return;}
408 ROOT::Math::Polar3DVector position(rLab, thetaLab, phiLab);
409 ROOT::Math::XYZVector direction = ROOT::Math::XYZVector(position) - vertex;
411 double angle = ROOT::Math::VectorUtil::Angle(direction, momentumGen);
413 const double maxAngularDiff = 0.09;
414 if (angle > maxAngularDiff) {
return;}
419 const double maxOutOfTime = 900.;
420 if (OutOfTime > maxOutOfTime) {
return;}
429 std::string histName =
"eSum_" + std::to_string(
iGroupOfCrystal[iCellId - 1]) +
"_" + std::to_string(iEnergy);
430 std::string histNameBias =
"biasSum_" + std::to_string(
iGroupOfCrystal[iCellId - 1]) +
"_" + std::to_string(iEnergy);
433 double biasSumOfN = 0.;
434 for (
int isum = 0; isum <
nCrysMax; isum++) {
435 int i = (int)nRelatedDigits - 1 - isum;
437 eSumOfN += energies[i].first;
438 biasSumOfN += (energies[i].first - energies[i].second);
A Class to store the Monte Carlo particle information.