Project
Loading...
Searching...
No Matches
CalibratorVdExB.cxx
Go to the documentation of this file.
1// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
2// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
3// All rights not expressly granted are reserved.
4//
5// This software is distributed under the terms of the GNU General Public
6// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
7//
8// In applying this license CERN does not waive the privileges and immunities
9// granted to it by virtue of its status as an Intergovernmental Organization
10// or submit itself to any jurisdiction.
11
15
22#include "TStopwatch.h"
23#include "CCDB/CcdbApi.h"
27#include <TFile.h>
28#include <TTree.h>
29
30#include <string>
31#include <map>
32#include <memory>
33#include <ctime>
34
35using namespace o2::trd::constants;
36
37namespace o2::trd
38{
39
40double FitFunctor::calculateDeltaAlphaSim(double vdFit, double laFit, double impactAng) const
41{
42 auto xDir = TMath::Cos(impactAng);
43 auto yDir = TMath::Sin(impactAng);
44 double slope = (TMath::Abs(xDir) < 1e-7) ? 1e7 : yDir / xDir;
45 auto laTan = TMath::Tan(laFit);
46 double lorentzSlope = (TMath::Abs(laTan) < 1e-7) ? 1e7 : 1. / laTan;
47
48 // hit point of incoming track with anode plane
49 double xAnodeHit = mAnodePlane / slope;
50 double yAnodeHit = mAnodePlane;
51
52 // hit point at anode plane of Lorentz angle shifted cluster from the entrance -> independent of true drift velocity
53 double xLorentzAnodeHit = mAnodePlane / lorentzSlope;
54 double yLorentzAnodeHit = mAnodePlane;
55
56 // cluster location within drift cell of cluster from entrance after drift velocity ratio is applied
57 double xLorentzDriftHit = xLorentzAnodeHit;
58 double yLorentzDriftHit = mAnodePlane - mAnodePlane * (vdPreCorr[currDet] / vdFit);
59
60 // reconstructed hit of first cluster at chamber entrance after pre Lorentz angle correction
61 double xLorentzDriftHitPreCorr = xLorentzAnodeHit - (mAnodePlane - yLorentzDriftHit) * TMath::Tan(laPreCorr[currDet]);
62 double yLorentzDriftHitPreCorr = mAnodePlane - mAnodePlane * (vdPreCorr[currDet] / vdFit);
63
64 double impactAngleSim = TMath::ATan2(yAnodeHit, xAnodeHit);
65
66 double deltaXLorentzDriftHit = xAnodeHit - xLorentzDriftHitPreCorr;
67 double deltaYLorentzDriftHit = yAnodeHit - yLorentzDriftHitPreCorr;
68 double impactAngleRec = TMath::ATan2(deltaYLorentzDriftHit, deltaXLorentzDriftHit);
69
70 double deltaAngle = (impactAngleRec - impactAngleSim); // * TMath::RadToDeg());
71
72 return deltaAngle;
73}
74
75double FitFunctor::operator()(const double* par) const
76{
77 double sum = 0; // this value is minimized
78 for (int iBin = 1; iBin <= profiles[currDet]->GetNbinsX(); ++iBin) {
79 auto impactAngle = (profiles[currDet]->GetBinCenter(iBin) + 90) * TMath::DegToRad();
80 auto deltaAlpha = profiles[currDet]->GetBinContent(iBin) * TMath::DegToRad();
81 if (TMath::Abs(deltaAlpha) < 1e-7) {
82 continue;
83 }
84 if (impactAngle < lowerBoundAngleFit || impactAngle > upperBoundAngleFit) {
85 continue;
86 }
88 sum += TMath::Power(deltaAlphaSim - deltaAlpha, 2);
89 }
90 return sum;
91}
92
94
96{
97 // reset the CCDB output vectors
98 mInfoVector.clear();
99 mObjectVector.clear();
100}
101
103{
104 if (mInitDone) {
105 return;
106 }
107
108 mFitFunctor.lowerBoundAngleFit = 80 * TMath::DegToRad();
109 mFitFunctor.upperBoundAngleFit = 100 * TMath::DegToRad();
110 mFitFunctor.mAnodePlane = GeometryBase::camHght() / (2.f * 100.f);
111 for (int iDet = 0; iDet < MAXCHAMBER; ++iDet) {
112 mFitFunctor.profiles[iDet] = std::make_unique<TProfile>(Form("profAngleDiff_%i", iDet), Form("profAngleDiff_%i", iDet), NBINSANGLEDIFF, -MAXIMPACTANGLE, MAXIMPACTANGLE);
113 }
114
115 mFitter.SetFCN<FitFunctor>(2, mFitFunctor, mParamsStart);
116 mFitter.Config().ParSettings(ParamIndex::LA).SetLimits(-0.7, 0.7);
117 mFitter.Config().ParSettings(ParamIndex::LA).SetStepSize(.01);
118 mFitter.Config().ParSettings(ParamIndex::VD).SetLimits(0.01, 3.);
119 mFitter.Config().ParSettings(ParamIndex::VD).SetStepSize(.01);
120 ROOT::Math::MinimizerOptions opt;
121 opt.SetMinimizerType("Minuit2");
122 opt.SetMinimizerAlgorithm("Migrad");
123 opt.SetPrintLevel(0);
124 opt.SetMaxFunctionCalls(1'000);
125 opt.SetTolerance(.001);
126 mFitter.Config().SetMinimizerOptions(opt);
127
128 // set tree addresses
129 if (mEnableOutput) {
130 mOutTree->Branch("lorentzAngle", &mFitFunctor.laPreCorr);
131 mOutTree->Branch("vDrift", &mFitFunctor.vdPreCorr);
132 for (int iDet = 0; iDet < MAXCHAMBER; ++iDet) {
133 mOutTree->Branch(fmt::format("residuals_{:d}", iDet).c_str(), mFitFunctor.profiles[iDet].get());
134 }
135 }
136
137 mInitDone = true;
138}
139
141{
142 // We either get a pointer to a valid object from the last ~hour or to the default object
143 // which is always present. The first has precedence over the latter.
144 auto dataCalVdriftExB = pc.inputs().get<o2::trd::CalVdriftExB*>("calvdexb");
145 std::string msg = "Default Object";
146 // We check if the object we got is the default one by comparing it to the defaults.
147 for (int iDet = 0; iDet < MAXCHAMBER; ++iDet) {
148 if (dataCalVdriftExB->getVdrift(iDet) != VDRIFTDEFAULT ||
149 dataCalVdriftExB->getExB(iDet) != EXBDEFAULT) {
150 msg = "Previous Object";
151 break;
152 }
153 }
154 LOG(info) << "Calibrator: From CCDB retrieved " << msg;
155
156 // Here we set each entry regardless if it is the default or not.
157 for (int iDet = 0; iDet < MAXCHAMBER; ++iDet) {
158 mFitFunctor.laPreCorr[iDet] = dataCalVdriftExB->getExB(iDet);
159 mFitFunctor.vdPreCorr[iDet] = dataCalVdriftExB->getVdrift(iDet);
160 }
161}
162
164{
165 // do actual calibration for the data provided in the given slot
166 TStopwatch timer;
167 timer.Start();
169 auto laFitResults = mFitFunctor.laPreCorr;
170 auto vdFitResults = mFitFunctor.vdPreCorr;
171 auto residHists = slot.getContainer();
172 for (int iDet = 0; iDet < MAXCHAMBER; ++iDet) {
173 int sumEntries = 0;
174 mFitFunctor.profiles[iDet]->Reset();
175 mFitFunctor.currDet = iDet;
176 for (int iBin = 0; iBin < NBINSANGLEDIFF; ++iBin) {
177 // fill profiles
178 auto angleDiffSum = residHists->getHistogramEntry(iDet * NBINSANGLEDIFF + iBin);
179 auto nEntries = residHists->getBinCount(iDet * NBINSANGLEDIFF + iBin);
180 sumEntries += nEntries;
181 if (nEntries > 0) {
182 mFitFunctor.profiles[iDet]->Fill(2 * iBin - MAXIMPACTANGLE, angleDiffSum / nEntries, nEntries);
183 }
184 }
185 // Check if we have the minimum amount of entries
186 if (sumEntries < mMinEntriesChamber) {
187 LOGF(debug, "Chamber %d did not reach minimum amount of entries for refit", iDet);
188 continue;
189 }
190 // Reset Start Parameter
191 mParamsStart[ParamIndex::LA] = 0.0;
192 mParamsStart[ParamIndex::VD] = 1.0;
193 mFitter.FitFCN();
194 auto fitResult = mFitter.Result();
195 laFitResults[iDet] = fitResult.Parameter(ParamIndex::LA);
196 vdFitResults[iDet] = fitResult.Parameter(ParamIndex::VD);
197 LOGF(debug, "Fit result for chamber %i: vd=%f, la=%f", iDet, vdFitResults[iDet], laFitResults[iDet] * TMath::RadToDeg());
198 // Update fit values for next fit
199 mFitFunctor.laPreCorr[iDet] = laFitResults[iDet];
200 mFitFunctor.vdPreCorr[iDet] = vdFitResults[iDet];
201 }
202 timer.Stop();
203 LOGF(info, "Done fitting angular residual histograms. CPU time: %f, real time: %f", timer.CpuTime(), timer.RealTime());
204
205 // Fill Tree and log to debug
206 if (mEnableOutput) {
207 mOutTree->Fill();
208 for (int iDet = 0; iDet < MAXCHAMBER; ++iDet) {
209 LOGF(debug, "Fit result for chamber %i: vd=%f, la=%f", iDet, vdFitResults[iDet], laFitResults[iDet] * TMath::RadToDeg());
210 }
211 }
212
213 // assemble CCDB object
214 CalVdriftExB calObject;
215 for (int iDet = 0; iDet < MAXCHAMBER; ++iDet) {
216 // For Chambers which did not have the minimum amount of entries in this slot e.g. missing, empty chambers.
217 // We will reuse the prevoius one. This would have been read either from the ccdb or come from a previous successful fit.
218 calObject.setVdrift(iDet, vdFitResults[iDet]);
219 calObject.setExB(iDet, laFitResults[iDet]);
220 }
221 auto clName = o2::utils::MemFileHelper::getClassName(calObject);
222 auto flName = o2::ccdb::CcdbApi::generateFileName(clName);
223 std::map<std::string, std::string> metadata; // TODO: do we want to store any meta data?
224 long startValidity = slot.getStartTimeMS() - 10 * o2::ccdb::CcdbObjectInfo::SECOND;
225 mInfoVector.emplace_back("TRD/Calib/CalVdriftExB", clName, flName, metadata, startValidity, startValidity + o2::ccdb::CcdbObjectInfo::HOUR);
226 mObjectVector.push_back(calObject);
227}
228
230{
231 auto& container = getSlots();
232 auto& slot = front ? container.emplace_front(tStart, tEnd) : container.emplace_back(tStart, tEnd);
233 slot.setContainer(std::make_unique<AngularResidHistos>());
234 return slot;
235}
236
238{
239 mEnableOutput = true;
240 mOutFile = std::make_unique<TFile>("trd_calibVdriftExB.root", "RECREATE");
241 if (mOutFile->IsZombie()) {
242 LOG(error) << "Failed to create output file!";
243 mEnableOutput = false;
244 return;
245 }
246 mOutTree = std::make_unique<TTree>("calib", "VDrift&ExB calibration");
247 LOG(info) << "Created output file trd_calibVdriftExB.root";
248}
249
251{
252 if (!mEnableOutput) {
253 return;
254 }
255
256 try {
257 mOutFile->cd();
258 mOutTree->Write();
259 mOutTree.reset();
260 mOutFile->Close();
261 mOutFile.reset();
262 } catch (std::exception const& e) {
263 LOG(error) << "Failed to write calibration data file, reason: " << e.what();
264 }
265 // after closing, we won't open a new file
266 mEnableOutput = false;
267}
268
269} // namespace o2::trd
TimeSlot-based calibration of vDrift and ExB.
Global TRD definitions and constants.
Definition of the Names Generator class.
uint16_t slope
Definition RawData.h:1
std::ostringstream debug
long getStartTimeMS() const
Definition TimeSlot.h:50
const Container * getContainer() const
Definition TimeSlot.h:53
static std::string generateFileName(const std::string &inp)
Definition CcdbApi.cxx:798
static constexpr long HOUR
static constexpr long SECOND
decltype(auto) get(R binding, int part=0) const
InputRecord & inputs()
The inputs associated with this processing context.
void setExB(int iDet, float exb)
void setVdrift(int iDet, float vd)
void retrievePrev(o2::framework::ProcessingContext &pc)
void finalizeSlot(Slot &slot) final
Slot & emplaceNewSlot(bool front, TFType tStart, TFType tEnd) final
float sum(float s, o2::dcs::DataPointValue v)
Definition dcs-ccdb.cxx:39
constexpr double EXBDEFAULT
default value for LorentzAngle
Definition Constants.h:78
constexpr int MAXCHAMBER
the maximum number of installed chambers
Definition Constants.h:30
constexpr double VDRIFTDEFAULT
default value for vDrift
Definition Constants.h:77
constexpr int NBINSANGLEDIFF
the number of bins for the track angle used for the vDrift and ExB calibration based on the tracking
Definition Constants.h:76
constexpr float MAXIMPACTANGLE
the maximum impact angle for tracks relative to the TRD detector plane to be considered for vDrift an...
Definition Constants.h:75
std::array< double, constants::MAXCHAMBER > laPreCorr
LorentzAngle from previous Run.
double mAnodePlane
distance of the TRD anode plane from the drift cathodes in m
int currDet
the current TRD chamber number
double operator()(const double *par) const
std::array< std::unique_ptr< TProfile >, constants::MAXCHAMBER > profiles
profile histograms for each TRD chamber
double calculateDeltaAlphaSim(double vdFit, double laFit, double impactAng) const
std::array< double, constants::MAXCHAMBER > vdPreCorr
vDrift from previous Run
float upperBoundAngleFit
upper bound for fit angle
float lowerBoundAngleFit
lower bound for fit angle
static std::string getClassName(const T &obj)
get the class name of the object
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"
uint64_t const void const *restrict const msg
Definition x9.h:153