R3BROOT
R3B analysis software
Loading...
Searching...
No Matches
R3BNeulandGainMatching.cxx
Go to the documentation of this file.
1/******************************************************************************
2 * Copyright (C) 2019 GSI Helmholtzzentrum für Schwerionenforschung GmbH *
3 * Copyright (C) 2019-2025 Members of R3B Collaboration *
4 * *
5 * This software is distributed under the terms of the *
6 * GNU General Public Licence (GPL) version 3, *
7 * copied verbatim in the file "LICENSE". *
8 * *
9 * In applying this license GSI does not waive the privileges and immunities *
10 * granted to it by virtue of its status as an Intergovernmental Organization *
11 * or submit itself to any jurisdiction. *
12 ******************************************************************************/
13
15#include "R3BNeulandCalData.h"
16#include "TF1.h"
17#include "TFile.h"
18#include "TSpectrum.h"
19#include <FairRootManager.h>
20#include <TClonesArray.h>
21
22#include <fstream>
23#include <sstream>
24
25namespace
26{
27 Float_t const MAX_STEPS = 10;
28 Float_t const Kp = 1.0; // Adjust PID here !!
29 Float_t const Ki = 0.075; // Adjust PID here !!
30 Float_t const Kd = 0.025; // Adjust PID here !!
31 Float_t const Ta = 0.5; // Adjust PID here !!
32 Float_t const xtargetp1 = 95.;
33 Float_t const accuracy = 0.01;
34 Float_t const starthv = 1100.;
35
36 Int_t const LSEARCHNB = 0;
37 Int_t const HSEARCHNB = 200;
38 Int_t const LGETCOS = 81;
39 Int_t const HGETCOS = 200;
40} // namespace
41
43 : FairTask("NeulandGainMatching", 1)
44 , fUpdateRate(1000000)
45 , fNEventsNeeded(10000)
46 , fTrigger(-1)
47{
48}
49
50R3BNeulandGainMatching::R3BNeulandGainMatching(const char* name, Int_t iVerbose)
51 : FairTask(name, iVerbose)
52 , fUpdateRate(1000000)
53 , fNEventsNeeded(10000)
54 , fTrigger(-1)
55{
56}
57
59
61{
62 std::cout << "init init" << std::endl;
63
64 FairRootManager* rm = FairRootManager::Instance();
65 if (!rm)
66 {
67 return kFATAL;
68 }
69
70 header = (R3BEventHeader*)rm->GetObject("EventHeader.");
71 if (!header)
72 {
73 return kFATAL;
74 }
75
76 fPmt = (TClonesArray*)rm->GetObject("NeulandCalData");
77 if (!fPmt)
78 {
79 return kFATAL;
80 }
81
82 // epics Neuland HV channels
83 for (Int_t pln = 0; pln < fNofPlanes; pln++)
84 {
85 for (Int_t bar = 0; bar < fNofBarsPerPlane; bar++)
86 {
87 for (Int_t pmt = 0; pmt < 2; pmt++)
88 {
89
90 std::ostringstream oss;
91 oss << "r3b:nl:hv:p" << pln + 1 << "b" << bar + 1 << "t" << pmt + 1;
92
93 auto vmon = oss.str() + ":vmon";
94 auto vtarget = oss.str() + ":vtarget";
95
96 auto& entry = ca[pln][bar][pmt];
97 entry.group = epics.CreateGroup();
98
99 entry.vmon = entry.group->CreateChannel(vmon);
100 entry.vtarget = entry.group->CreateChannel(vtarget);
101
102 // std::cout << "r3b:nl:hv:p" << pln+1 << "b" << bar+1 << "t" << pmt+1 << std::endl;
103 entry.group->Fetch();
104 hv[pln][bar][pmt] = entry.vmon->Get();
105 // std::cout << entry.vmon->Get() << std::endl;
106
107 std::ostringstream hss;
108 hss << "h_p" << pln + 1 << "b" << bar + 1 << "t" << pmt + 1;
109
110 TString hname = hss.str();
111 hCosmicPeak[pln][bar][pmt] = new TH1F(hname, hname, 300, 0, 600);
112
113 iteration[pln][bar][pmt] = 0;
114 esum[pln][bar][pmt] = 0.;
115 ealt[pln][bar][pmt] = 0.;
116 }
117 }
118 }
119
120 // std::cout << ca[1][23][0].vmon->Get() << std::endl;
121
122 finished = false;
123
124 return kSUCCESS;
125}
126
127void R3BNeulandGainMatching::Exec(Option_t* option)
128{
129
130 Double_t maxhv = 1400;
131 // check high voltage
132
133 if (finished)
134 FinishTask();
135
136 if (fTrigger >= 0)
137 {
138 if (header->GetTrigger() != fTrigger)
139 {
140 return;
141 }
142 }
143
144 Int_t nHits = fPmt->GetEntries();
145
146 Int_t checkiteration = 0;
147
148 for (Int_t pln = 0; pln < fNofPlanes; pln++)
149 {
150 for (Int_t bar = 0; bar < fNofBarsPerPlane; bar++)
151 {
152 for (Int_t pmt = 0; pmt < 2; pmt++)
153 {
154 if (iteration[pln][bar][pmt] == MAX_STEPS)
155 {
156 checkiteration++;
157 // if (checkiteration > 0)
158 // std::cout << "Done: p" << pln+1 << "b" << bar+1 << "t" << pmt+1 << std::endl;
159 }
160 }
161 }
162 }
163
164 if (checkiteration == fNofPMTs)
165 finished = 1;
166 // std::cout << "Channels done: " << checkiteration << std::endl;
167
168 if (nHits < 10)
169 return; // better cosmic peaks
170
171 // Loop over mapped hits
172 for (Int_t i = 0; i < nHits; i++)
173 {
174
175 R3BNeulandCalData* hit = (R3BNeulandCalData*)fPmt->At(i);
176
177 if (!hit)
178 continue; // should not happen
179
180 Int_t iPlane = (hit->GetBarId() - 1) / 50;
181 Int_t iBar = (hit->GetBarId() - 1) % 50;
182 Int_t iSide = hit->GetSide() - 1;
183 Double_t fCharge = hit->GetQdc();
184
185 // fill histos with cosmics peaks
186 hCosmicPeak[iPlane][iBar][iSide]->Fill(fCharge);
187
188 // check entries in histograms
189 if (hCosmicPeak[iPlane][iBar][iSide]->GetEntries() > fNEventsNeeded &&
190 iteration[iPlane][iBar][iSide] < MAX_STEPS)
191 {
192 Int_t a = hCosmicPeak[iPlane][iBar][iSide]->GetEntries();
193 Int_t b = iteration[iPlane][iBar][iSide];
194 std::cout << "Iteration: " << iteration[iPlane][iBar][iSide] << std::endl;
195
196 std::ofstream hv_file("gainmatched_hv.txt", std::ios::app);
197
198 Double_t newhv = 0;
199 peakmethod = 0;
200
201 auto& hventry = ca[iPlane][iBar][iSide];
202
203 Double_t xtarget;
204 if (iPlane % 2 == 1)
205 {
206 xtarget = xtargetp1 * 1.16;
207 }
208 else
209 {
210 xtarget = xtargetp1; // more energy deposit for cosmics in vertical paddles
211 }
212 Double_t e = xtarget - getcosmicpeak(hCosmicPeak[iPlane][iBar][iSide]);
213 if (e == xtarget - 10000)
214 {
215 // Peak finding failed. Set HV back to last or start value.
216 if (hv[iPlane][iBar][iSide] < starthv && hv[iPlane][iBar][iSide] >= starthv - 200)
217 {
218 std::cout << "failed, try again with same hv" << std::endl;
219 }
220 else
221 {
222 hv[iPlane][iBar][iSide] = starthv;
223 std::cout << "failed, back to start hv: " << hv[iPlane][iBar][iSide] << std::endl;
224 }
225
226 maxhv = 1400;
227 if (iPlane < 2)
228 maxhv = 1800;
229 if (hv[iPlane][iBar][iSide] >= 0 && hv[iPlane][iBar][iSide] <= maxhv)
230 {
231 hventry.vtarget->Set(hv[iPlane][iBar][iSide]);
232 hventry.group->Commit();
233 }
234 hCosmicPeak[iPlane][iBar][iSide]->Reset();
235 iteration[iPlane][iBar][iSide]++;
236 }
237 else if ((e <= xtarget * accuracy) && (e >= -xtarget * accuracy))
238 {
239 // Peak finding worked. Matching finished
240 newhv = hv[iPlane][iBar][iSide];
241 std::cout << "Matching for this pm finished. New HV: " << newhv << std::endl;
242 iteration[iPlane][iBar][iSide] = MAX_STEPS;
243 }
244 else
245 {
246 // Peak finding worked.
247 esum[iPlane][iBar][iSide] = esum[iPlane][iBar][iSide] + e;
248 hventry.group->Fetch();
249 std::cout << "old hv: " << hventry.vmon->Get() << std::endl;
250 std::cout << "p" << iPlane + 1 << "b" << iBar + 1 << "t" << iSide + 1 << " e: " << e
251 << " esum: " << esum[iPlane][iBar][iSide] << " ealt: " << ealt[iPlane][iBar][iSide]
252 << std::endl;
253
254 hv[iPlane][iBar][iSide] = hv[iPlane][iBar][iSide] + Kp * e + Ki * Ta * esum[iPlane][iBar][iSide] +
255 Kd * (e - ealt[iPlane][iBar][iSide]) / Ta;
256 ealt[iPlane][iBar][iSide] = e;
257 std::cout << "new hv: " << hv[iPlane][iBar][iSide] << std::endl;
258 maxhv = 1400;
259 if (iPlane < 2)
260 maxhv = 1800;
261 if (hv[iPlane][iBar][iSide] >= 0 && hv[iPlane][iBar][iSide] <= maxhv)
262 {
263 hventry.vtarget->Set(hv[iPlane][iBar][iSide]);
264 hventry.group->Commit();
265 }
266 hCosmicPeak[iPlane][iBar][iSide]->Reset();
267 iteration[iPlane][iBar][iSide]++;
268 }
269 if (iteration[iPlane][iBar][iSide] == MAX_STEPS)
270 {
271 // Reached last Iteration -> abort
272 if (newhv == 0)
273 {
274 if ((e <= xtarget * accuracy * 5) && (e >= -xtarget * accuracy * 5))
275 {
276 std::cout
277 << "Reached max steps but last check was already inside 5% accuracy. Taking last hv value."
278 << std::endl;
279 newhv = hv[iPlane][iBar][iSide];
280 }
281 else
282 {
283 std::cout << "Error, check matching by hand. Voltage set to default value" << std::endl;
284 newhv = 1000;
285 hventry.vtarget->Set(newhv);
286 hventry.group->Commit();
287 }
288 }
289 hv_file << "caput r3b:nl:hv:p" << iPlane + 1 << "b" << iBar + 1 << "t" << iSide + 1 << ":vtarget "
290 << newhv << " " << peakmethod << " " << b << std::endl;
291 }
292 hv_file.close();
293 // End gain matching
294 }
295 }
296}
297
298Double_t R3BNeulandGainMatching::getcosmicpeak(TH1* hin)
299{
300
301 Double_t xp = 10000;
302 Double_t xpf = 0;
303 Double_t sig = 0;
304 Double_t max = 0;
305 TF1* fitgaus;
306 // std::cout << "xtarget: " << xtarget << std::endl;
307 for (Int_t q = 0; q < 5; q++)
308 {
309 xpf = searchcosmicpeaknb(hin, 15. + q * 5.);
310 if (xpf != 0)
311 {
312 xp = xpf;
313 peakmethod = 1;
314 break;
315 }
316 xpf = searchcosmicpeak(hin, 20. + q * 5.);
317 if (xpf != 0)
318 {
319 xp = xpf;
320 peakmethod = 2;
321 break;
322 }
323 }
324
325 if (xp == 10000)
326 {
327 hin->GetXaxis()->SetRange(LGETCOS, HGETCOS); // ig 81< <200
328 max = hin->GetMaximumBin();
329 for (int k = 0; k < 5; k++)
330 {
331 fitgaus = new TF1("fitgaus", "gaus(0)", max - (10 + k * 3), max + (40 + k * 5));
332 fitgaus->SetParameters(200, max, 20);
333 hin->Fit("fitgaus", "QR0");
334 xpf = fitgaus->GetParameter(1);
335 sig = fitgaus->GetParameter(2);
336 delete fitgaus;
337 if (70 < xpf && xpf < 180 && 10 < sig && sig < 50)
338 {
339 xp = xpf;
340 std::cout << "Found cosmic peak by gaus fitting at x = " << xp << std::endl;
341 peakmethod = 3;
342 break;
343 }
344 }
345 if (xp == 10000)
346 {
347 if (70 < max && max < 180)
348 {
349 xp = max;
350 std::cout << "Using maximum bin as cosmic peak position at x = " << xp << std::endl;
351 peakmethod = 4;
352 }
353 }
354 hin->GetXaxis()->SetRange(1, 600);
355 // hin->GetXaxis()->SetDefaults();
356 }
357 return xp;
358}
359
360Double_t R3BNeulandGainMatching::searchcosmicpeak(TH1* hin, Double_t width)
361{
362
363 Double_t xp = 0;
364 TSpectrum* s = new TSpectrum(3);
365 Int_t nfound = s->Search(hin, width, "", 0.05);
366 std::cout << "searchcosmicpeak: Found " << nfound << " candidate peaks" << std::endl;
367
368 Double_t* xpeaks = s->GetPositionX();
369 for (Int_t p = 0; p < nfound; p++)
370 {
371 // std::cout << "Peak " << p << " at x=" << xpeaks[p] << std::endl;
372 if (75 < xpeaks[p] && xpeaks[p] < 180)
373 {
374 xp = xpeaks[p];
375 std::cout << "searchcosmicpeak: Found cosmic peak at x = " << xp << std::endl;
376 break;
377 }
378 }
379 delete s;
380 return xp;
381}
382
383Double_t R3BNeulandGainMatching::searchcosmicpeaknb(TH1* hin, Double_t width)
384{
385
386 Int_t max = hin->GetMaximumBin();
387 hin->GetXaxis()->SetRange(LSEARCHNB, HSEARCHNB); // ig 60< <200
388 Double_t xp = 0;
389 TSpectrum* s = new TSpectrum(3);
390 Int_t nfound = s->Search(hin, width, "nobackground new", 0.05);
391 Int_t diff = 0;
392 Int_t difflast = 0;
393 Int_t icall = 0;
394 std::cout << "searchcosmicpeakNB: Found " << nfound << " candidate peaks" << std::endl;
395 std::cout << "searchcosmicpeakNB: maximum bin content at = " << max << std::endl;
396 Double_t* xpeaks = s->GetPositionX();
397 for (Int_t p = 0; p < nfound; p++)
398 {
399 std::cout << "Peak " << p << " at x=" << xpeaks[p] << std::endl;
400 if (LSEARCHNB < xpeaks[p] && xpeaks[p] < HSEARCHNB)
401 { // ig 60< <200
402 // xp = xpeaks[p];
403 diff = abs(xpeaks[p] - max);
404 std::cout << "searchcosmicpeakNB: diff = " << diff << std::endl;
405 if (0 == icall)
406 {
407 xp = xpeaks[p];
408 difflast = diff;
409 icall = 1;
410 }
411 if (diff < difflast)
412 {
413 std::cout << "searchcosmicpeakNB: diff = " << diff << std::endl;
414 std::cout << "searchcosmicpeakNB: difflast = " << difflast << std::endl;
415 xp = xpeaks[p];
416 difflast = diff;
417 }
418 }
419 //}
420 // std::cout << "searchcosmicpeakNB: Found cosmic peak at x = " << xp << std::endl;
421 // break;
422 }
423 std::cout << "searchcosmicpeakNB: Chose cosmic peak at x = " << xp << std::endl;
424 //}
425 delete s;
426 hin->GetXaxis()->SetRange(1, 600);
427 return xp;
428}
429
431
433{
434
435 TFile* fff = new TFile("histos.root", "recreate");
436
437 for (Int_t pln = 0; pln < fNofPlanes; pln++)
438 {
439 for (Int_t bar = 0; bar < fNofBarsPerPlane; bar++)
440 {
441 for (Int_t pmt = 0; pmt < 2; pmt++)
442 {
443 hCosmicPeak[pln][bar][pmt]->Write();
444 }
445 }
446 }
447 fff->Close();
448}
Int_t GetSide() const
auto GetQdc() const -> double
Int_t GetBarId() const
virtual void Exec(Option_t *option)
Method for event loop implementation.
virtual InitStatus Init()
Method for task initialization.
virtual ~R3BNeulandGainMatching()
Destructor.
R3BNeulandGainMatching()
Default constructor.
virtual void FinishEvent()
A method for finish of processing of an event.
virtual void FinishTask()
Method for finish of the task execution.