19#include "TDirectory.h"
24#include <RtypesCore.h>
25#include <TGraphErrors.h>
28#include <TVirtualPad.h>
32#include <fairlogger/Logger.h>
37using DPair = std::array<Double_t, 2>;
47 unsigned int averageSize,
48 std::vector<unsigned int>* output)
50 if (size < 2 * averageSize)
53 const auto scale = 1. / averageSize;
55 auto lastAverage = std::accumulate(data, data + averageSize, 0.) * scale;
56 const auto last = data + size;
57 auto currentPos = data + averageSize;
59 while (currentPos + averageSize < last)
61 const auto currentAverage = std::accumulate(currentPos, currentPos + averageSize, 0.) * scale;
62 if (fabs(currentAverage - lastAverage) > threshold)
64 if (output ==
nullptr)
66 output->push_back(currentPos - data);
68 lastAverage = currentAverage;
69 currentPos += averageSize;
75 template <Int_t iterations = 8>
78 auto exp = 1. + val / (1 << iterations);
79 for (
auto i = 0; i < iterations; ++i)
87 const double position,
88 const double invLightAttenuationLength,
122 const void SetStatus(Int_t& var, Int_t statusBit) { var |= (1 << statusBit); }
123 const void ClearStatus(Int_t& var, Int_t statusBit) { var &= ~(1 << statusBit); }
124 const bool IsStatus(Int_t var, Int_t statusBit) {
return (var & (1 << statusBit)); }
127 "Calibration Failed",
128 "Calibration was Successful",
129 "Energy Calibration Failed",
130 "Time Synchronisation Failed",
131 "Time Synchronisation Error large",
132 "Parameters look strange",
135 "TS",
"SE",
"??",
"TJ" };
145 , InvLightAttenuationLength(
NaN)
147 , Saturation({ 0., 0. })
156 Log.TimeDifference.SetTitle(
"Time Difference Parameter;Event Number;Parameter Value / ns");
159 Log.EffectiveSpeed.SetTitle(
"Effective Speed Parameter;Event Number;Parameter Value / cm/ns");
162 Log.LightAttenuationLength.SetTitle(
"Attenuation Length Parameter;Event Number;Parameter Value / cm");
164 for (
auto side = 0; side < 2; ++side)
167 Log.Gain[side].SetTitle(
"Gain Parameter;Event Number;Parameter Value / ns/MeVle");
169 Log.TotalHits[side] = TH1F(
"",
"Total Hits; Light at PMT / MeVle; #Hits", 64, 0., 32.);
170 Log.TotalHits[side].SetDirectory(
nullptr);
171 Log.TotalHits[side].SetStats(
false);
173 Log.MissedHits[side] = TH1F(
"",
"Missed Hits; Light at PMT / MeVle; #Hits", 64, 0., 32.);
174 Log.MissedHits[side].SetDirectory(
nullptr);
175 Log.MissedHits[side].SetStats(
false);
176 Log.MissedHits[side].SetLineColor(kGreen);
178 Log.Energy[side] = TH1F(
"",
"Energy Calibration; Gain / ns/MeVle; Counts", 100, 0., 30.);
179 Log.Energy[side].SetDirectory(
nullptr);
180 Log.Energy[side].SetStats(
false);
182 Log.Saturation[side] =
183 TH2F(
"",
"Saturation; Light at PMT / MeVle; QDC / ns", 128, 0., 128., 256, 0., 512.);
184 Log.Saturation[side].SetDirectory(
nullptr);
185 Log.Saturation[side].SetStats(
false);
187 Log.Pedestal[side] = TH1F(
"",
"Pedestal; QDC / ns", 512, 0., 512.);
188 Log.Pedestal[side].SetDirectory(
nullptr);
189 Log.Pedestal[side].SetStats(
false);
236 LOG(debug) <<
"Loaded Parameters for Bar " <<
ID;
243 R3BLOG(debug1, fmt::format(
"side: {}, time: {} qdc: {}", side, time, qdc));
246 Log.Pedestal[side].Fill(qdc);
268 LOG(debug) <<
"Bar " <<
ID <<
":"
269 <<
" Positions were too often too strange. Might be a Time-Jump in one PMT. "
270 "Removing Position-Calibration.";
285 if (std::isnan(value))
294 return CalibrationStatus::noData;
296 return CalibrationStatus::completeFail;
298 return CalibrationStatus::energyGainFail;
300 return CalibrationStatus::timeSyncFail;
302 return CalibrationStatus::timeJump;
304 return CalibrationStatus::timeSyncError;
306 return CalibrationStatus::strangeParameters;
307 return CalibrationStatus::success;
311 const Double_t entryPosition,
312 const Double_t exitPosition,
313 const Double_t energy,
314 const UInt_t eventNumber)
321 const auto centerPosition = (entryPosition + exitPosition) * 0.5;
334 for (
auto side = 0; side < 2; ++side)
336 Log.TotalHits[side].Fill(lightAtPMT[side]);
341 for (
auto side = 0; side < 2; ++side)
343 Log.Saturation[side].Fill(lightAtPMT[side],
CurrentHit.QDC[side]);
346 Log.Energy[side].Fill(gain);
358 const auto maxPos =
BarLength * 0.5 - 1.;
359 if (fabs(entryPosition) > maxPos || fabs(exitPosition) > maxPos)
364 for (
auto side = 0; side < 2; ++side)
391 fabs(0.5 * (entryPosition + exitPosition) -
GetPosition()) > 25.)
415 if (
Log.TimeDifference.GetN() > 0)
441 if (
Log.Gain[0].GetN() > 0 &&
Log.Gain[1].GetN() > 0)
443 for (
auto side = 0; side < 2; ++side)
482 for (
auto side = 0; side < 2; ++side)
490 LOG(debug) <<
ID <<
" Bar Parameters: ";
512 const auto loopSize = (
LastHits.size() >= (firstHit + nHits)) ? nHits : (
LastHits.size() - firstHit);
513 for (
auto index = 0; index < loopSize; ++index)
515 const auto& hit =
LastHits[firstHit + index];
517 const auto meanPosition = 0.5 * (hit.EntryPosition + hit.ExitPosition);
518 const auto tdiff = hit.Time[1] - hit.Time[0];
519 FitGraph.SetPoint(index, meanPosition, tdiff);
532 const auto nPoints =
Log.TimeDifference.GetN();
534 Log.TimeDifference.SetPointError(nPoints, 0, linearFit.GetParError(0));
543 const auto loopSize = (
LastHits.size() >= (firstHit + nHits)) ? nHits : (
LastHits.size() - firstHit);
550 for (
auto h_index = 0; h_index < loopSize; ++h_index)
552 auto& hit =
LastHits[firstHit + h_index];
553 for (
auto side = 0; side < 2; ++side)
555 hit.QDC[side] = std::max(hit.QDC[side] -
Pedestal[side], 1);
561 for (
auto h_index = 0; h_index < loopSize; ++h_index)
563 const auto& hit =
LastHits[firstHit + h_index];
564 const auto centerPosition = (hit.EntryPosition + hit.ExitPosition) * 0.5;
565 FitGraph.SetPoint(h_index, centerPosition, log(hit.QDC[1] * 1. / hit.QDC[0]));
574 const auto logLightAttLenPoints =
Log.LightAttenuationLength.GetN();
576 Log.LightAttenuationLength.SetPointError(
579 for (
auto h_index = 0; h_index < loopSize; ++h_index)
581 const auto& hit =
LastHits[firstHit + h_index];
582 const auto centerPosition = (hit.EntryPosition + hit.ExitPosition) * 0.5;
583 for (
auto side = 0; side < 2; ++side)
587 Log.Energy[side].Fill(gain);
591 std::array<TH1F, 2> hGainCal = { TH1F(
"",
"", 200, 0., 40.), TH1F(
"",
"", 200, 0., 40.) };
593 for (
auto h_index = 0; h_index < loopSize; ++h_index)
595 const auto& hit =
LastHits[firstHit + h_index];
596 const auto centerPosition = (hit.EntryPosition + hit.ExitPosition) * 0.5;
597 for (
auto side = 0; side < 2; ++side)
600 const auto distance = 0.5 *
TotalBarLength + (1 - 2 * side) * centerPosition;
602 hGainCal[side].Fill(gain);
606 TF1 gausFit(
"",
"gaus", 0., 30.);
607 for (
auto side = 0; side < 2; ++side)
609 const auto maxPos = hGainCal[side].GetBinCenter(hGainCal[side].GetMaximumBin());
610 gausFit.SetParameter(0, hGainCal[side].GetMaximum());
611 gausFit.SetParameter(1, maxPos);
612 hGainCal[side].Fit(&gausFit,
"NQ",
"", maxPos - 1.5, maxPos + 1.5);
614 Gain[side] = gausFit.GetParameter(1);
616 const auto nPoints =
Log.Gain[side].GetN();
618 Log.Gain[side].SetPointError(nPoints, 0, gausFit.GetParError(1));
626 for (
auto side = 0; side < 2; ++side)
627 for (
auto bin = 0; bin <
Log.Pedestal[side].GetNbinsX(); ++bin)
629 if (
Log.Pedestal[side].GetBinContent(bin + 1) > 3.)
648 TF1 missFit(
"missFit",
"(1. - [2]) * 0.5 * (1. - TMath::Erf([0] * (x - [1]))) + [2]", 0., 20.);
650 for (
auto side = 0; side < 2; ++side)
652 const auto nPoints =
Log.TotalHits[side].GetNbinsX();
653 Log.MissRatio[side].Expand(nPoints);
654 Log.MissRatio[side].Set(0);
655 for (
auto bin = 1; bin <= nPoints; ++bin)
657 if (
Log.MissedHits[side].GetBinContent(bin) > 0)
659 const auto nextPoint =
Log.MissRatio[side].GetN();
660 const auto binCenter =
Log.MissedHits[side].GetBinCenter(bin);
662 Log.MissedHits[side].GetBinContent(bin) /
Log.TotalHits[side].GetBinContent(bin);
663 Log.MissRatio[side].SetPoint(nextPoint, binCenter, ratio);
667 if (
Log.MissRatio[side].GetN() > 5)
669 missFit.SetParameter(0, 0.25);
671 missFit.SetParLimits(1, 0., 10.);
672 missFit.SetParameter(2, 0.);
673 missFit.SetParLimits(2, 0., 0.5);
674 Log.MissRatio[side].Fit(&missFit,
"QNE");
675 Threshold[side] = missFit.GetParameter(1);
683 std::array<Int_t, 256> remove;
684 auto totalRemoved = 0;
686 graph.Fit(&fit,
"QN ROB=0.90");
688 auto removePosition = 0;
689 auto x = graph.GetX();
690 auto y = graph.GetY();
691 auto nPoints = graph.GetN();
692 for (
auto p = 0; p < nPoints; ++p)
694 if (fabs(y[p] - fit.Eval(x[p])) < maxDifference)
697 remove[removePosition] = p;
698 if (++removePosition == remove.size())
701 totalRemoved += removePosition;
702 nPoints -= removePosition;
712 totalRemoved += removePosition;
714 graph.Fit(&fit,
"QN");
725 const auto totalPoints = graph.GetN() - nPoints;
726 const auto x = graph.GetX();
727 const auto y = graph.GetY();
729 for (
auto p = points[0]; p < totalPoints; ++p)
732 if (offset < nPoints && p + offset == points[offset])
739 x[p] = x[p + offset];
740 y[p] = y[p + offset];
743 graph.Set(totalPoints);
755 posCal.SetTitle(
"Position Calibration;Position / cm;Time Difference / ns");
756 posCal.Expand(nHits);
759 for (
auto h_index = 0; h_index < loopSize; ++h_index)
761 const auto& hit =
LastHits[h_index];
762 const auto tdiff = hit.Time[1] - hit.Time[0];
763 posCal.SetPoint(posCal.GetN(), hit.EntryPosition, tdiff);
766 std::array<TF1, 2> fSatCal = { TF1(
"",
"[0]*x/(1+[1]*x)", 0.,
TotalBarLength),
769 for (
auto side = 0; side < 2; ++side)
771 fSatCal[side].SetParameter(0,
Gain[side]);
772 fSatCal[side].FixParameter(1,
Saturation[side]);
777 const auto canvname = TString::Format(
"Bar %d",
ID);
778 TCanvas Canvas(canvname, canvname);
779 Canvas.SetWindowSize(1920, 1200);
782 TVirtualPad* currentPad;
784 currentPad = Canvas.cd(++row);
785 currentPad->Divide(3, 1);
788 if (posCal.GetN() > 0)
792 if (
Log.TimeDifference.GetN() > 0)
793 Log.TimeDifference.Draw(
"A*");
796 if (
Log.EffectiveSpeed.GetN() > 0)
797 Log.EffectiveSpeed.Draw(
"A*");
799 currentPad = Canvas.cd(++row);
800 currentPad->Divide(4, 1);
803 Log.Energy[0].Draw(
"");
804 Log.Energy[1].SetLineColor(kRed);
805 Log.Energy[1].Draw(
"SAME");
808 if (
Log.LightAttenuationLength.GetN() > 0)
809 Log.LightAttenuationLength.Draw(
"A*");
812 if (
Log.Gain[0].GetN() > 0)
813 Log.Gain[0].Draw(
"A*");
816 if (
Log.Gain[1].GetN() > 0)
817 Log.Gain[1].Draw(
"A*");
819 currentPad = Canvas.cd(++row);
820 currentPad->Divide(4, 1);
823 TPad* overlayPads[2];
824 TGaxis* overlayAxis[2];
825 for (
auto side = 0; side < 2; ++side)
828 auto pad = currentPad->cd(1 + side);
829 mainPads[side] =
new TPad(
"",
"", 0, 0, 1, 1);
830 mainPads[side]->Draw();
831 mainPads[side]->cd();
832 Log.TotalHits[side].Draw();
833 Log.MissedHits[side].Draw(
"SAME");
834 mainPads[side]->Update();
837 overlayPads[side] =
new TPad(
"",
"", 0, 0, 1, 1);
838 overlayPads[side]->SetFillStyle(4000);
841 double dy = (ymax - ymin) / 0.8;
842 double xmin = mainPads[side]->GetUxmin();
843 double xmax = mainPads[side]->GetUxmax();
844 double dx = (xmax - xmin) / 0.8;
845 overlayPads[side]->Range(xmin - 0.1 * dx, ymin - 0.1 * dy, xmax + 0.1 * dx, ymax + 0.1 * dy);
846 overlayPads[side]->Draw();
847 overlayPads[side]->cd();
849 if (
Log.MissRatio[side].GetN() > 0)
851 Log.MissRatio[side].SetLineColor(kRed);
852 Log.MissRatio[side].Draw(
"IL");
854 overlayPads[side]->Update();
855 overlayAxis[side] =
new TGaxis(xmax, ymin, xmax, ymax, ymin, ymax, 50510,
"+L");
856 overlayAxis[side]->SetLabelColor(kRed);
857 overlayAxis[side]->Draw();
859 overlayPads[side]->Update();
865 currentPad->cd(3 + side);
866 Log.Saturation[side].Draw(
"COLZ");
867 fSatCal[side].Draw(
"SAME");
872 for (
auto side = 0; side < 2; ++side)
874 delete mainPads[side];
875 delete overlayPads[side];
876 delete overlayAxis[side];
882 const auto nPoints = graph.GetN();
887 return graph.GetY()[0];
889 TF1 constantFit(
"",
"pol0", 0, nPoints);
892 for (
auto point = 0; point < nPoints; ++point)
894 FitGraph.SetPoint(point, point, graph.GetY()[point]);
895 FitGraph.SetPointError(point, 0, graph.GetEY()[point]);
897 constantFit.SetParameter(0, expectedValue);
899 return constantFit.GetParameter(0);
#define R3BLOG(severity, x)
std::array< Double_t, 2 > DPair
static const char * CalibrationStatusAbbreviation[]
static const char * CalibrationStatusDescription[]
HitCalibrationBar(const Int_t id=0)
void thresholdCalibration()
R3BNeulandHitModulePar GetParameters()
void positionCalibration(int firstHit, int nHits)
void removePoints(Int_t *points, Int_t nPoints, TGraph &graph) const
removes points from a graph in an efficient way
Bool_t Add(const Double_t timeOffset, const Double_t entryPosition, const Double_t exitPosition, const Double_t energy, const UInt_t eventNumber)
std::array< Double_t, 2 > DPair
void Update(const R3BNeulandHitModulePar *par)
Int_t cleanupFit(TGraph &graph, TF1 &fit, Double_t maxDifference) const
struct R3B::Neuland::Calibration::HitCalibrationBar::@127153345345016036324103015046211310221211341120 Log
Double_t InvLightAttenuationLength
void SetGlobalTSync(const Double_t value, const Double_t error)
Double_t getMean(const TGraphErrors &graph, Double_t expectedValue=0.)
void pedestalCalibration()
CalibrationStatus GetCalibrationStatus() const
std::vector< Hit > LastHits
void Calibrate(TDirectory *histogramDir=nullptr)
void Set(const Int_t side, const Double_t time, const Int_t qdc)
void createHistograms(TDirectory *histogramDir)
created and writes histograms to the directory
struct R3B::Neuland::Calibration::HitCalibrationBar::Hit CurrentHit
void energyCalibration(int firstHit, int nHits)
Double_t GetPosition() const
Double_t GetPMTSaturation(const Int_t side) const
void SetModuleId(const Int_t i)
void SetPMTSaturation(const Double_t val, const Int_t side)
Double_t GetEffectiveSpeed() const
Int_t GetPedestal(const Int_t side) const
void SetTDiff(const Double_t val)
Double_t GetLightAttenuationLength() const
Double_t GetTDiff() const
Double_t GetTimeOffset(const Int_t side) const
void SetTSync(const Double_t val)
void SetPedestal(const Int_t val, const Int_t side)
void SetEnergyGain(const Double_t val, const Int_t side)
void SetPMTThreshold(const Double_t val, const Int_t side)
void SetEffectiveSpeed(const Double_t val)
Double_t GetPMTThreshold(const Int_t side) const
void SetLightAttenuationLength(const Double_t val)
Double_t GetEnergyGain(const Int_t side) const
constexpr auto LogCompleteBit
constexpr auto CalibrationLogSize
constexpr auto PedestalCalibrationBit
constexpr auto MaxTSyncError
constexpr auto RightSideHitBit
const double GetLightAtPMT(const double energyLoss, const double position, const double invLightAttenuationLength, const int side)
constexpr auto LogInitialSize
constexpr auto MaxFastTDiffError
constexpr auto ThresholdCalibrationBit
constexpr auto MaxNumberOfFails
constexpr auto TimeJumpThreshold
constexpr auto EnergyCalibrationBit
const bool IsStatus(Int_t var, Int_t statusBit)
constexpr auto TimeJumpedBit
bool GetJumps(double *data, unsigned int size, double_t threshold, unsigned int averageSize, std::vector< unsigned int > *output)
constexpr auto TSyncCalibrationBit
constexpr auto PosCalibrationBit
const void SetStatus(Int_t &var, Int_t statusBit)
constexpr auto StrangeBit
constexpr auto LeftSideHitBit
constexpr auto MinEnergyDeposit
const double FastExp(const double val)
const void ClearStatus(Int_t &var, Int_t statusBit)
constexpr auto ThresholdCalibrationSize
constexpr auto EnergyCalibrationSize
constexpr auto PositionCalibrationSize
Simulation of NeuLAND Bar/Paddle.
constexpr auto SaturationCoefficient
constexpr auto TotalBarLength
constexpr auto AvgThreshold
constexpr auto MaxCalTime
constexpr auto Sqr(const T val) -> T