wavecatcher-analysis
Loading...
Searching...
No Matches
ReadRun.cc
Go to the documentation of this file.
1
20
21#include "ReadRun.h"
22
24ReadRun::ReadRun(int max_no_of_bin_files_to_read, int min_no_of_bin_files_to_read) {
25
26 cout << "\ninitializing ..." << endl;
27
28 if (max_no_of_bin_files_to_read > 0) {
29 cout << "will read " << max_no_of_bin_files_to_read - min_no_of_bin_files_to_read << " .bin files from file number "
30 << min_no_of_bin_files_to_read << " to file number " << max_no_of_bin_files_to_read << endl;
31 }
32 if (min_no_of_bin_files_to_read > 0) discard_original_eventnr = true;
33
34 ROOT::EnableImplicitMT();
35 TH1::AddDirectory(kFALSE);
36 // init counters
37 nwf = 0;
38 PrintChargeSpectrum_cnt = 0;
39 PlotChannelAverages_cnt = 0;
40 PrintWFProjection_cnt = 0;
41 PlotWFHeatmaps_cnt = 0;
42 MaxNoOfBinFilesToRead = max_no_of_bin_files_to_read;
43 MinNoOfBinFilesToRead = min_no_of_bin_files_to_read;
44
45 root_out = new TFile(); // init results file
46}
47
66void ReadRun::ReadFile(string path, bool change_polarity, int change_sign_from_to_ch_num, string out_file_name, bool debug) {
67
68 if (path.back() != '/') path += '/'; // add '/' to path if not present
69 // save output path
70 data_path = path;
71
72 if (out_file_name == "") out_file_name = "out.root";
73 printf("+++ saving analysis results in '%s' ...\n\n", out_file_name.c_str());
74 root_out = TFile::Open(out_file_name.c_str(), "recreate");
75
76 rundata = new TClonesArray("TH1F", maxNWF); //raw data will be stored here as TH1F
77 rundata->BypassStreamer(kFALSE); //kFALSE: potentially faster read & write
78 TClonesArray& testrundata = *rundata;
79
80 // verbosity
81 bool debug_header = debug;
82 bool debug_data = debug;
83
84 unsigned short output_channel;
85 unsigned int output_event;
86 unsigned short output_nbchannels;
87 unsigned short read_channels = 0;
88
89 size_t length_of_waveform = static_cast<size_t>(binNumber) * sizeof(short);
90
91 amplValuessum = new float* [nChannelsWC]; //sum of all wf for each channel
92 for (int i = 0; i < nChannelsWC; i++) {//init
93 amplValuessum[i] = new float[binNumber]();
94 }
95
96 maxSumBin = new int[nChannelsWC];
97
98 //Start reading the raw data from .bin files.
99 stringstream inFileList;
100 inFileList << Helpers::ListFiles(path.c_str(), ".bin"); //all *.bin* files in folder path
101 if (debug) cout << inFileList.str() << endl;
102 string fileName;
103 int file_counter = -1;
104 int wfcounter = 0;
105 int event_counter = 0;
106
107 while (inFileList >> fileName) {
108 // file loop
109 file_counter++;
110 // read only fraction/batch of the .bin files for testing or to reduce memory usage
112 if (MaxNoOfBinFilesToRead > 0 && file_counter >= MaxNoOfBinFilesToRead) break;
113
114 fileName = path + fileName;
115 ifstream input_file(fileName.c_str(), ios::binary | ios::in);
116
117 bool has_measurement = false;
118
119 if (!input_file.is_open()) {
120 printf("*** failed to open '%s'\n", fileName.c_str());
121 continue;
122 }
123
124 if (file_counter < 10 || file_counter % 10 == 0 || debug) printf("+++ reading '%s' ...\n", fileName.c_str());
125
126 // Header
127 string header_line;
128 // HEADER 1 //
129 //
130 // "=== DATA FILE SAVED WITH SOFTWARE VERSION: V?.??.? ==="
131 //
132 getline(input_file, header_line, '\n');
133
134 if (debug_header) printf("%s\n", header_line.data());
135 assert(header_line[0] == '=');
136
137 size_t header_version_first = header_line.find_last_of('V');
138 size_t header_version_last = header_line.find_first_of(' ', header_version_first);
139 string software_version = header_line.substr(header_version_first, header_version_last - header_version_first);
140 if (debug_header) printf(" |- data version = '%s'\n", software_version.data());
141 // convert software version
142 software_version.erase(0, 1);
143 int v_major, v_minor, v_patch;
144 istringstream software_version_iss(software_version);
145 char dot_;
146 software_version_iss >> v_major >> dot_ >> v_minor >> dot_ >> v_patch;
147
148 // HEADER 2 //
149 // "=== WAVECATCHER SYSTEM OF TYPE ?? WITH ?? CHANNELS AND GAIN: ??? ==="
150 getline(input_file, header_line, '\n');
151
152 if (debug_header) printf("%s\n", header_line.data());
153 assert(header_line[0] == '=');
154
155 // HEADER 3 //
156 // === Rate coincidence masks ... === Posttrig in ns for SamBlock ... ===
157 getline(input_file, header_line, '\n');
158
159 if (debug_header) printf("%s\n", header_line.data());
160 assert(header_line[0] == '=');
161
162 // HEADER 4 //
163 // V2.9.13: === DATA SAMPLES [1024] in Volts == NB OF CHANNELS ACQUIRED: 64 == Sampling Period: 312.5 ps == INL Correction: 1
164 // V2.9.15: === DATA SAMPLES [1024] in Volts == NB OF CHANNELS ACQUIRED: 64 == Sampling Period: 312.5 ps == INL Correction: 1 == MEASUREMENTS: 0 ===
165 getline(input_file, header_line, '\n');
166
167 if (debug_header) printf("%s\n", header_line.data());
168 assert(header_line[0] == '=');
169
170 size_t nsamples_first = 1 + header_line.find_last_of('[');
171 size_t nsamples_last = header_line.find_first_of(']', nsamples_first);
172 string nsamples_str = header_line.substr(nsamples_first, nsamples_last - nsamples_first);
173
174 binNumber = atoi(nsamples_str.data());
175 if (debug_header) printf(" |- data sample = %d\n", binNumber);
176 if (binNumber != 1024) cout << "\nERROR: Measurement must have 1024 samples.\nCheck WaveCatcher setting!" << endl;
177
178 size_t nchannels_first = 10 + header_line.find("ACQUIRED: ", nsamples_first);
179 size_t nchannels_last = header_line.find_first_of(' ', nchannels_first);
180 string nchannels_str = header_line.substr(nchannels_first, nchannels_last - nchannels_first);
181
182 nchannels = atoi(nchannels_str.data());
183 if (debug_header) printf(" |- nchannels = %d\n", nchannels);
184
185 size_t sp_first = 8 + header_line.find("Period:");
186 size_t sp_last = header_line.find(" ps");
187 float sampling_period = atof(header_line.substr(sp_first, sp_last - sp_first).data());
188 if (debug_header) printf("sampling period = %f ps\n", sampling_period);
189 SP = sampling_period * 1e-3;
190
191 // compatibility with older WC software versions
192 if (v_major ==2 && v_minor == 9 && v_patch <= 13) {
193 // V2.9.13 has always measurement stored (everything is set to 0 when disabled!)
194 has_measurement = true;
195 }
196 else {
197 size_t has_measurement_first = 14 + header_line.find("MEASUREMENTS: ", nsamples_first);
198 size_t has_measurement_last = header_line.find_first_of(' ', has_measurement_first);
199 string has_measurement_str = header_line.substr(has_measurement_first, has_measurement_last - has_measurement_first);
200 has_measurement = atoi(has_measurement_str.data());
201 }
202
203 if (debug_header) printf(" `- measurement = %d\n", has_measurement);
204
205 // end of header reader
206
207 event_data an_event;
208
209 while (input_file.read((char*)(&an_event), sizeof(an_event))) {
210 //event loop
211 if (debug_data) printf("%03d has %d channels\n", an_event.EventNumber, an_event.nchannelstored);
212
213 output_event = an_event.EventNumber;
214 output_nbchannels = an_event.nchannelstored;
215
216 if (debug_data && output_event % 200 == 0) printf("EventNr: %d, nCh: %d\n", output_event, output_nbchannels);
217 if (output_nbchannels > nChannelsWC) {
218 cout << "ERROR:\nThe number of channels in the data is " << output_nbchannels
219 << ", which is larger than the maximum allowed number of channels which is set to " << nChannelsWC
220 << "\nPlease set the parameter nChannelsWC=" << output_nbchannels << endl;
221 }
222
223 // do analysis only for limited range of channels to reduce memory usage for large datasets with many channels and many events
224 int start_at_ch = 0;
230
231 if (event_counter == 0) cout << "\nstart at ch " << start_at_ch << " end at ch " << end_at_ch << endl;
232
233 for (int ch = 0; ch < output_nbchannels; ++ch) { // channel loop
234 channel_data_with_measurement a_channel_data;
235 channel_data_without_measurement a_channel_data_without_measurement;
236
237 if (has_measurement) { // read with 'channel_data_with_measurement' struct
238 input_file.read((char*)(&a_channel_data), sizeof(channel_data_with_measurement));
239 }
240 else { // read with 'channel_data_without_measurement' struct
241 input_file.read((char*)(&a_channel_data_without_measurement), sizeof(channel_data_without_measurement));
242
243 // copy the content
245 a_channel_data.EventIDsamIndex = a_channel_data_without_measurement.EventIDsamIndex;
246 a_channel_data.FirstCellToPlotsamIndex = a_channel_data_without_measurement.FirstCellToPlotsamIndex;
248 }
249
250
252 if (debug_data) printf("- reading channel %d\n", output_channel);
253
254 //---------------------------------------------------------------------------------------------------------------
255 if (ch >= start_at_ch && ch <= end_at_ch) {
256
257 if (event_counter == 0) active_channels.push_back(static_cast<int>(output_channel));
258
259 TString name(Form("ch%02d_%05d", output_channel, an_event.EventNumber));
260 TString title(Form("ch%d, event %d;t [ns];U [mV]", output_channel, an_event.EventNumber));
261 auto hCh = (TH1F*)testrundata.ConstructedAt(wfcounter);
262 hCh->SetName(name.Data());
263 hCh->SetTitle(title.Data());
264 hCh->SetBins(binNumber, -0.5 * SP, 1023.5 * SP);
265
266 int nshift = 0;
267 if (Shift_WFs_in_file_loop) { // shift all waveforms to tWF_CF_bin
268 float max = 0.;
269 int nmax = 0;
270 float cf = tWF_CF;
271 int count_fall = 0;
272
273 // do a mini-baseline correction (needed in case a voltage offset is set in the wavecatcher)
274 short bsln = (a_channel_data.waveform[0] + a_channel_data.waveform[1] + a_channel_data.waveform[3]) / 3;
275 for (int lll = 0; lll < binNumber; lll++) a_channel_data.waveform[lll] -= bsln;
276
277 int g_max = TMath::MaxElement(binNumber, a_channel_data.waveform);
278 int g_min = TMath::Abs(TMath::MinElement(binNumber, a_channel_data.waveform));
279 int global_max = g_max < g_min ? g_min : g_max;
280
281 for (int s = tWF_CF_lo; s < tWF_CF_hi; ++s) {
282 if (max < TMath::Abs(a_channel_data.waveform[s])) {
283 max = TMath::Abs(a_channel_data.waveform[s]);
284 nmax = s;
285 }
286
287 // stop search if the current maximum is at least 0.5 * global maximum and if there are at
288 // least three consecutive bins where the waveform amplitude is decreasing
289 if (max > .5 * global_max && s - nmax < 4 && TMath::Abs(a_channel_data.waveform[s + 2]) + TMath::Abs(a_channel_data.waveform[s + 3]) < TMath::Abs(a_channel_data.waveform[s]) + TMath::Abs(a_channel_data.waveform[s + 1])) count_fall++;
290 else count_fall = 0;
291 if (count_fall == 3) break;
292 }
293 cf *= max;
294
295 for (int s = nmax; s > tWF_CF_lo; --s) {
296 if (cf >= TMath::Abs(a_channel_data.waveform[s])) {
297 if (cf - TMath::Abs(a_channel_data.waveform[s]) < TMath::Abs(a_channel_data.waveform[s - 1]) - cf) nshift = tWF_CF_bin - s;
298 else nshift = tWF_CF_bin - s - 1;
299 break;
300 }
301 }
302 }
303
304 // loop to fill waveform histograms
305 bool change_pol_ch = false;
306 float val = 0;
307 for (int s = 0; s < binNumber; ++s) {
308 // shift all waveforms
309 int shiftind = s - nshift;
310 if (shiftind < 0) shiftind += (binNumber - 1);
311 else if (shiftind > binNumber - 1) shiftind -= (binNumber - 1);
312 val = static_cast<float>(a_channel_data.waveform[shiftind]) * DAQ_factor;
313
314 // change the polarity for certain channels since our PMTs have negative signals while our SiPMs have positive signals
315 if (s == 0 && change_polarity) {
318 change_pol_ch = true;
319 }
320 else if (!switch_polarity_for_channels.empty()
323 change_pol_ch = true;
324 }
325 }
326 if (change_pol_ch == true) val *= -1;
327
328 // fill waveforms
329 hCh->SetBinContent(s + 1, val);
330
331 // channel sums
332 amplValuessum[ch][s] += val;
333 }
334
335 // baseline correction
338 }
339
340 wfcounter++;
341 }//--------------------------------------------------------------------------------------------------------------
342
343 } // for ch
344
345 skip_event.push_back(false);
346 if (!discard_original_eventnr) eventnr_storage.push_back(output_event); // Stores the current WaveCatcher event number
347 else eventnr_storage.push_back(event_counter);
349 } // while an_event
350
351 input_file.close();
352 } // for file_id
353
354 // in case there are empty channels, nchannels is the number of channels which contain data
356
357 // get bins where the sum spectrum has its maximum for runs with fixed trigger delay and fixed
358 // integration window relative to the max of the sum spectrum (not working for DC measurement)
359 for (int ch = 0; ch < nchannels; ch++) {
360 float max = 0.;
361 for (int i = 0; i < binNumber; i++) {
362 if (amplValuessum[ch][i] > max) {
363 max = amplValuessum[ch][i];
364 maxSumBin[ch] = i;
365 }
366 }
367 }
368
370 nwf = wfcounter;
371
372 printf("Finished reading %d files containing %d events with %d channels.\n\n", file_counter, nevents, nchannels);
373}
374
377 //delete rundata;
378 //plot_active_channels.clear();
379 if (root_out->IsOpen()) root_out->Close();
380 cout << "\ndeleting nothing currently..." << endl;
381}
382
396void ReadRun::PlotChannelSums(bool smooth, bool normalize, double shift, double sigma, int smooth_method) {
397
398 double* xv = getx(shift);
399 auto mgsums = new TMultiGraph();
400 mgsums->SetTitle("channel sums; t [ns]; amplitude [mV]");
401 if (normalize) mgsums->SetTitle("channel sums; t [ns]; amplitude [arb.]");
402
403 double max = 0., min = 0.;
404
405 for (int i = 0; i < nchannels; i++) {
406 if (PlotChannel(i)) {
407 double* yv = new double[binNumber];
409
411
412 TGraph* gr = new TGraph(binNumber, xv, yv);
413 delete[] yv;
414
415 double tmp_min = TMath::MinElement(gr->GetN(), gr->GetY());
416 if (tmp_min < min) min = tmp_min;
417 double tmp_max = TMath::MaxElement(gr->GetN(), gr->GetY());
418 if (tmp_max > max) max = tmp_max;
419 if (normalize) {
420 for (int j = 0; j < gr->GetN(); j++) gr->SetPointY(j, gr->GetPointY(j) / tmp_max);
421 }
422
423 TString name(Form("channel_%02d", active_channels[i]));
424 TString title(Form("Channel %d", active_channels[i]));
425 gr->SetName(name.Data());
426 gr->SetTitle(title.Data());
427 gr->SetLineColor(Helpers::rcolor(i));
428 gr->SetMarkerColor(Helpers::rcolor(i));
429 mgsums->Add(gr);
430 }
431 }
432 delete[] xv;
433
434 auto sumc = new TCanvas("Sums", "", 600, 400);
435 mgsums->Draw("AL");
436 if (normalize) mgsums->GetYaxis()->SetRangeUser(-0.2, 1);
437 else mgsums->GetYaxis()->SetRangeUser(min, max);
438 sumc->BuildLegend(0.85, 0.70, .99, .95);
439 root_out->WriteObject(mgsums, "channelsums");
440 root_out->WriteObject(sumc, "channelsums_c");
441}
444
454void ReadRun::PlotChannelAverages(bool normalize) {
455
456 double* xv = getx(0);
457 auto mgav = new TMultiGraph();
458 mgav->SetTitle("channel averages; t [ns]; amplitude [mV]");
459 if (normalize) mgav->SetTitle("channel averages; t[ns]; amplitude[arb.]");
460
461 double max = 0., min = 0.;
462
463 for (int i = 0; i < nchannels; i++) {
464 if (PlotChannel(i)) {
465
466 double* yv = new double[binNumber]();
467
468 for (int j = 0; j < nevents; j++) {
469 if (!skip_event[j]) {
470 double* y_tmp = gety(i, j);
471 for (int k = 0; k < binNumber; k++) yv[k] += y_tmp[k];
472 delete[] y_tmp;
473 }
474 }
475
476 double norm = static_cast<double>(Nevents_good());
477 for (int k = 0; k < binNumber; k++) yv[k] /= norm;
478
479 auto gr = new TGraph(binNumber, xv, yv);
480 delete[] yv;
481
482 double tmp_min = TMath::MinElement(gr->GetN(), gr->GetY());
483 if (tmp_min < min) min = tmp_min;
484 double tmp_max = TMath::MaxElement(gr->GetN(), gr->GetY());
485 if (tmp_max > max) max = tmp_max;
486 if (normalize) {
487 for (int j = 0; j < gr->GetN(); j++) gr->SetPointY(j, gr->GetPointY(j) / tmp_max);
488 }
489
490 TString name(Form("channel_%02d", active_channels[i]));
491 TString title(Form("Channel %d", active_channels[i]));
492 gr->SetName(name.Data());
493 gr->SetTitle(title.Data());
494 gr->SetLineColor(Helpers::rcolor(i));
495 gr->SetMarkerColor(Helpers::rcolor(i));
496 mgav->Add(gr);
497 }
498 }
499 delete[] xv;
500
501 string cname("Averages_" + to_string(PlotChannelAverages_cnt++));
502 auto avc = new TCanvas(cname.c_str(), cname.c_str(), 600, 400);
503 mgav->Draw("AL");
504 if (normalize) mgav->GetYaxis()->SetRangeUser(-0.2, 1);
505 else mgav->GetYaxis()->SetRangeUser(min, max);
506 avc->BuildLegend(0.85, 0.70, .99, .95);
507 root_out->WriteObject(mgav, ("channelaverages" + to_string(PlotChannelAverages_cnt)).c_str());
508 root_out->WriteObject(avc, ("channelaverages_c" + to_string(PlotChannelAverages_cnt)).c_str());
509}
513
514
524TH2F* ReadRun::WFHeatmapChannel(int channel_index, float ymin, float ymax, int n_bins_y) {
525
526 TString name(Form("channel__%02d", active_channels[channel_index]));
527 TH2F* h2 = new TH2F(name.Data(), name.Data(), binNumber, 0, SP * static_cast<float>(binNumber), n_bins_y, ymin, ymax);
528 h2->GetXaxis()->SetTitle("t [ns]");
529 h2->GetYaxis()->SetTitle("I [arb.]");
530 h2->GetZaxis()->SetTitle("entries");
531
532 for (int j = 0; j < nevents; j++) {
533 if (!skip_event[j]) {
534 auto his = Getwf(channel_index, j);
535 for (int i = 0; i < binNumber; i++) h2->Fill(his->GetBinCenter(i), his->GetBinContent(i));
536 }
537 }
538 return h2;
539}
540
556void ReadRun::PlotWFHeatmaps(float ymin, float ymax, int n_bins_y, string z_opt, float z_max, EColorPalette palette) {
557
558 gStyle->SetOptStat(0);
559 string name("waveforms_heatmap_" + to_string(PlotWFHeatmaps_cnt++));
560 auto wfhm_c = new TCanvas(name.c_str(), name.c_str(), 600, 400);
562
563 int current_canvas = 0;
564 for (int i = 0; i < nchannels; i++) {
565 if (PlotChannel(i)) {
566 wfhm_c->cd(++current_canvas);
567 // formatting
568 gPad->SetTopMargin(.1);
569 gPad->SetBottomMargin(.1);
570 gPad->SetLeftMargin(.15);
571 gPad->SetRightMargin(.15);
572 gStyle->SetPalette(palette);
573
575 h2->SetContour(99);
576 h2->SetStats(0);
577 if (z_opt == "COLZ0") h2->Draw("COLZ0");
578 else h2->Draw("CONT4Z");
579 if (z_opt == "log") {
580 gPad->SetLogz();
581 if (z_max > 1) h2->GetZaxis()->SetRangeUser(1, z_max);
582 }
583 else if (z_max > 0) h2->GetZaxis()->SetRangeUser(0, z_max);
584 }
585 }
586 wfhm_c->Update();
587
588 root_out->WriteObject(wfhm_c, name.c_str());
589}
591
599void ReadRun::SmoothAll(double sigma, int method) {
600 cout << "\nSmoothing all non-skipped waveforms:" << endl;
601 for (int j = 0; j < nwf; j++) {
603 auto his = Getwf(j);
604 double* yvals = Helpers::gety(his);
606 for (int i = 1; i <= his->GetNbinsX(); i++) his->SetBinContent(i, yvals[i - 1]);
607 delete[] yvals;
608 }
610 }
611}
612
620void ReadRun::SmoothAll(double sigma, string method) {
621 cout << "\nSmoothing all non-skipped waveforms:" << endl;
622 for (int j = 0; j < nwf; j++) {
624 auto his = Getwf(j);
625 double* yvals = Helpers::gety(his);
627 for (int i = 1; i <= binNumber; i++) his->SetBinContent(i, yvals[i - 1]);
628 delete[] yvals;
629 }
631 }
632}
633
641void ReadRun::FilterAll(double sigma1, double sigma2, double factor) {
642 cout << "\nFiltering all waveforms" << endl;
643 for (int j = 0; j < nwf; j++) {
644 auto his = Getwf(j);
645 double* yvals = Helpers::gety(his);
648 for (int i = 1; i <= binNumber; i++) his->SetBinContent(i, yvals[i - 1]);
649 delete[] yvals;
651 }
652}
653
662 cout << "\nShifting all waveforms to the average constant fraction time for each channel:" << endl;
663
664 //call GetTimingCFD() in case it was not initialized
665 if (static_cast<int>(timing_results.size()) == 0) GetTimingCFD();
666
667 double* timing_mean = new double[nchannels]();
668
669 for (int j = 0; j < nwf; j++) {
671 }
672
673 double norm = static_cast<double>(Nevents_good());
674
675 int* timing_mean_n = new int[nchannels];
676 for (int i = 0; i < nchannels; i++) {
677 timing_mean_n[i] = static_cast<int>(round(timing_mean[i] / norm));
678 }
679 delete[] timing_mean;
680
681 for (int j = 0; j < nwf; j++) {
683 int shift = static_cast<int>(timing_results[j][0]) - timing_mean_n[GetCurrentChannel(j)];
684 auto his = Getwf(j);
686 }
688 }
689 delete[] timing_mean_n;
690}
691
707void ReadRun::CorrectBaseline(float tCut, float tCutEnd) {
708 checkData();
709
710 cout << "\nPerforming simple baseline correction in fixed time window."
711 << "This method is only suitable for measurements without dark counts!" << endl;
712 tCutg = tCut;
714 if (nwf == 0) {
716 }
717 else {
718 cout << "Baseline correction (" << nwf << " waveforms):" << endl;
719 for (int j = 0; j < nwf; j++) {
722 }
723 }
724}
725
730void ReadRun::CorrectBaseline_function(TH1F* his, float tCut, float tCutEnd, int nwaveform) {
731 int iCut, iCutEnd;
732 float corr = 0;
733
734 iCut = his->GetXaxis()->FindBin(tCut);
735
736 if (tCutEnd <= 0) { //
737 corr = his->Integral(1, iCut) / static_cast<float>(iCut);
738 }
739 else {
740 iCutEnd = his->GetXaxis()->FindBin(tCutEnd);
741 corr = his->Integral(iCut, iCutEnd) / static_cast<float>(iCutEnd - iCut + 1);
742 }
743
744 // write corrected values to histograms
745 if (tCut >= 0) {
746 for (int i = 1; i <= his->GetNbinsX(); i++) his->SetBinContent(i, his->GetBinContent(i) - corr);
747 }
748
755 }
756}
757
784void ReadRun::CorrectBaselineMinSlopeRMS(vector<float> window, double sigma, int smooth_method, int increment) {
785 checkData();
786
787 cout << "\nBaseline correction (minimum slope variation method, " << nwf << " waveforms):" << endl;
788 if (window.empty()) cout << "\nWarning: Window not set in CorrectBaselineMinSlopeRMS. Will use default values." << endl;
789 if (sigma != 0.) cout << "\nNotification: Using smoothing in CorrectBaselineMinSlopeRMS." << endl;
790 if (increment < 1) increment = 1;
791
792 int nbins_average = !window.empty() ? static_cast<int>(round(abs(window[0]) / SP)) : static_cast<int>(50. / SP);
793 int start_search_at = static_cast<int>(window.size()) > 1 ? static_cast<int>(round(abs(window[1]) / SP)) : 0;
794 int end_search_at = static_cast<int>(window.size()) > 2 ?
795 min(static_cast<int>(round(abs(window[2]) / SP)), binNumber - 1) : binNumber - 1;
796
798
799 // if no valid static search window is specified, it will be dynamic from 0 ns up to 8 ns before the global maximum
800 bool search_relative_to_local_max = false;
801 int min_distance_from_max = static_cast<int>(8. / SP);
804 start_search_at = 0;
805 cout << "\nNotification: Using dynamic search window in CorrectBaselineMinSlopeRMS." << endl;
806 }
807
809
810 float minchange = 1.e99;
811 float sum = 0, change = 0, minsumsq = 0, sqsum = 0, minsqsum = 0, corr = 0;
812 int iintwindowstart = 0, imax = 0;
813
814 for (int j = 0; j < nwf; j++) {
815 minchange = 1.e99;
816 minsumsq = 0, sqsum = 0, minsqsum = 0, corr = 0;
817 iintwindowstart = 0;
818
819 auto his = Getwf(j);
821 imax = GetIntWindow(his, 0, 0, static_cast<float>(nbins_search + min_distance_from_max) * SP,
822 static_cast<float>(end_search_at) * SP)[1];
826 }
827
829 // smoothing suppresses variations in slope due to noise, so the method is potentially more sensitive to excluding peaks
831 //calculate slope
832 double slope[nbins_search - 1];
833 for (int i = 0; i < nbins_search - 1; i++) slope[i] = yvals[i + 1] - yvals[i];
834 delete[] yvals;
835
836 //find window for correction
837 for (int i = 0; i < end_search_loop_at; i += increment) { // recommendend max. 3 bins (~1 ns)
838 sum = 0., sqsum = 0., change = 0.;
839
840 for (int k = i; k < nbins_average + i; k += increment) { // recommendend max. 3 bins (~1 ns)
841 sum += slope[k];
842 sqsum += (slope[k] * slope[k]);
843 }
844 change = sqsum + sum * sum;
845
846 if (change < minchange) {
849 minsumsq = sum * sum;
850 minsqsum = sqsum;
851 }
852 }
853 // do correction
854 corr = his->Integral(iintwindowstart + 1, iintwindowstart + nbins_average + 1) / static_cast<float>(nbins_average + 1);
855 for (int i = 1; i <= binNumber; i++) his->SetBinContent(i, his->GetBinContent(i) - corr);
856
860 baseline_correction_result[j].push_back(static_cast<float>(iintwindowstart) * SP);
861 baseline_correction_result[j].push_back(static_cast<float>(iintwindowstart + nbins_average) * SP);
865 }
866}
869
902void ReadRun::CorrectBaselineMinSlopeRMS(int nIntegrationWindow, bool smooth, double sigma, int max_bin_for_baseline, int start_at, int smooth_method) {
903 checkData();
904
905 cout << "Notification: This is a deprecated version of CorrectBaselineMinSlopeRMS. "
906 << "It will be removed in future releases. Parameter bool smooth=" << smooth << " will be ignored." << endl;
908 window.push_back(static_cast<float>(nIntegrationWindow) * SP);
909 window.push_back(static_cast<float>(start_at) * SP);
910 window.push_back(static_cast<float>(max_bin_for_baseline) * SP);
912}
915
938void ReadRun::CorrectBaselineMin(vector<float> window, double sigma, int smooth_method, int increment) {
939 checkData();
940
941 cout << "\nBaseline correction (minimal sum method, " << nwf << " waveforms):" << endl;
942 if (window.empty()) cout << "\nWarning: Window not set in CorrectBaselineMin. Will use default values." << endl;
943 if (sigma != 0.) cout << "\nNotification: Using smoothing in CorrectBaselineMin." << endl;
944 if (increment < 1) increment = 1;
945
946 int nbins_average = !window.empty() ? static_cast<int>(round(abs(window[0]) / SP)) : static_cast<int>(50. / SP);
947 int start_search_at = static_cast<int>(window.size()) > 1 ? static_cast<int>(round(abs(window[1]) / SP)) : 0;
948 int end_search_at = static_cast<int>(window.size()) > 2 ?
949 min(static_cast<int>(round(abs(window[2]) / SP)), binNumber - 1) : binNumber - 1;
950
952
953 // if no valid static search window is specified, it will be dynamic from 0 ns up to 8 ns before the global maximum
954 bool search_relative_to_local_max = false;
955 int min_distance_from_max = static_cast<int>(8. / SP);
958 start_search_at = 0;
959 cout << "\nNotification: Using dynamic search window in CorrectBaselineMin." << endl;
960 }
961
963
964 float minchange = 1e9;
965 float sum = 0, corr = 0;
966 int iintwindowstart = 0, imax = 0;
967
968 for (int j = 0; j < nwf; j++) {
969 minchange = 1.e9;
970 corr = 0;
971 iintwindowstart = 0;
972
973 auto his = Getwf(j);
975 imax = GetIntWindow(his, 0, 0, (float)(nbins_search + min_distance_from_max) * SP, (float)(end_search_at)*SP)[1];
979 }
980
982 // smoothing suppresses variations in slope due to noise, so the method is potentially more sensitive to excluding peaks
984 //find window for correction
985 for (int i = 0; i < end_search_loop_at; i += increment) { // recommendend max. 2 bins or min. method
986 sum = 0;
987 for (int k = i; k < nbins_average + i; k += increment) { // recommendend max. 2 bins
988 sum += yvals[k];
989 }
990
991 if (sum < minchange) {
992 minchange = sum;
994 }
995 }
996 // do correction
997 corr = his->Integral(iintwindowstart + 1, iintwindowstart + nbins_average + 1) / static_cast<float>(nbins_average + 1);
998 for (int i = 1; i <= binNumber; i++) his->SetBinContent(i, his->GetBinContent(i) - corr);
999 delete[] yvals;
1000
1002 baseline_correction_result[j].push_back(corr);
1004 baseline_correction_result[j].push_back(static_cast<float>(iintwindowstart) * SP);
1005 baseline_correction_result[j].push_back(static_cast<float>(iintwindowstart + nbins_average) * SP);
1007 }
1008}
1009
1035void ReadRun::CorrectBaselineMin(int nIntegrationWindow, double sigma, int max_bin_for_baseline, int start_at, int smooth_method) {
1036 checkData();
1037
1038 cout << "Notification: This is a deprecated version of CorrectBaselineMin. It will be removed in future releases." << endl;
1040 window.push_back(static_cast<float>(nIntegrationWindow) * SP);
1041 window.push_back(static_cast<float>(start_at) * SP);
1042 window.push_back(static_cast<float>(max_bin_for_baseline) * SP);
1044}
1046
1052TH1F* ReadRun::WFProjectionChannel(int channel_index, int from_n, int to_n, float rangestart, float rangeend, int nbins) {
1053
1054 TString name(Form("channel__%02d", active_channels[channel_index]));
1055 auto h1 = new TH1F(name.Data(), name.Data(), nbins, rangestart, rangeend);
1056
1057 for (int j = 0; j < nevents; j++) {
1058 if (!skip_event[j]) {
1059 auto his = Getwf(channel_index, j);
1060 for (int i = from_n; i <= to_n; i++) h1->Fill(his->GetBinContent(i));
1061 }
1062 }
1063 return h1;
1064}
1065
1079void ReadRun::PrintWFProjection(float from, float to, float rangestart, float rangeend, int nbins) {
1080 gStyle->SetOptFit(111);
1081 float default_rangestart = -10;
1082 float default_rangeend = 20;
1085 int default_nbins = static_cast<int>((default_rangeend - default_rangestart) * nbins / (rangeend - rangestart));
1086
1087 string ctitle("WFProjection" + to_string(PrintWFProjection_cnt++));
1088 auto wf_projection_c = new TCanvas(ctitle.c_str(), ctitle.c_str(), 600, 400);
1090 int current_canvas = 0;
1091
1092 int from_n = (from > 0 && from < static_cast<float>(binNumber) * SP) ? static_cast<int>(round(abs(from) / SP)) + 1 : 0;
1093 int to_n = (to > 0 && to < static_cast<float>(binNumber) * SP) ? static_cast<int>(round(abs(to) / SP)) + 1 : binNumber;
1094
1095 for (int i = 0; i < nchannels; i++) {
1096 if (PlotChannel(i)) {
1098
1100 his->GetYaxis()->SetTitle("#Entries");
1101 his->GetXaxis()->SetTitle("amplitude in mV");
1102 TString name(Form("WFProjection channel_%02d_%d", active_channels[i], PrintWFProjection_cnt));
1103 his->Draw();
1104 his->Fit("gaus", "WWM", "same");
1105 root_out->WriteObject(his, name.Data());
1106 }
1107 }
1108
1110 root_out->WriteObject(wf_projection_c, ("WFProjections" + to_string(PrintWFProjection_cnt)).c_str());
1111}
1112
1118TH1F* ReadRun::BaselineCorrectionResults(int channel_index, int which, float rangestart, float rangeend, int nbins) {
1119 if (baseline_correction_result.empty() || static_cast<int>(baseline_correction_result[0].size()) < which - 1) {
1120 cout << "\nError: baseline_correction_result empty. Call baseline correction first." << endl;
1121 }
1122 TString name(Form("channel__%02d", active_channels[channel_index]));
1123 auto h1 = new TH1F(name.Data(), name.Data(), nbins, rangestart, rangeend);
1124
1125 for (int j = 0; j < nevents; j++) {
1127 }
1128 return h1;
1129}
1130
1138void ReadRun::PrintBaselineCorrectionResults(float rangestart, float rangeend, int nbins) {
1139 gStyle->SetOptFit(111);
1140 float default_rangestart = -10;
1141 float default_rangeend = 20;
1144 int default_nbins = static_cast<int>((default_rangeend - default_rangestart) * nbins / (rangeend - rangestart));
1145
1146 string ctitle;
1147 ctitle = "Correction values in mV";
1148 auto blc_res_c = new TCanvas(ctitle.c_str(), ctitle.c_str(), 600, 400);
1150 int current_canvas = 0;
1151
1152 for (int i = 0; i < nchannels; i++) {
1153 if (PlotChannel(i)) {
1155
1157 his->GetYaxis()->SetTitle("#Entries");
1158 his->GetXaxis()->SetTitle(ctitle.c_str());
1159 his->Draw();
1160 his->Fit("gaus", "WWM", "same");
1161 }
1162 }
1164 root_out->WriteObject(blc_res_c, ctitle.c_str());
1165}
1166
1188void ReadRun::GetTimingCFD(float cf_r, float start_at_t, float end_at_t, double sigma, bool find_CF_from_start, int smooth_method, bool use_spline) {
1189
1190 int start_at = max(static_cast<int>(floor(start_at_t / SP)), 0);
1191 int end_at = min(static_cast<int>(ceil(end_at_t / SP)), binNumber - 1);
1192 int n_range = end_at - start_at;
1193
1194 cout << "\nGet timing at " << (cf_r > 0 && cf_r <= 1 ? "CF=" : "threshold=");
1195 printf("%.2f between %.2f ns and %.2f ns (%d waveforms):\n", cf_r, start_at_t, end_at_t, nwf);
1196
1197 for (int j = 0; j < nwf; j++) {
1198 double* yvals = Helpers::gety(Getwf(j), start_at, end_at); // get range where to search for CFD for timing
1199
1200 if (sigma > 0.) Filters::SmoothArray(yvals, n_range, sigma, smooth_method); // smoothing to suppress noise, will also change timing so use with care!
1201
1202 float max = 0.;
1203 int n_max = 0;
1204 int i = 0;
1205 for (i = 0; i < n_range; i++) {
1206 if (yvals[i] > max) {
1207 max = yvals[i];
1208 n_max = i;
1209 }
1210 }
1211
1212 float cf = cf_r;
1213 if (cf_r > 0 && cf_r <= 1) cf *= max;
1214
1215 if (!find_CF_from_start) {
1216 i = n_max;
1217 while (yvals[i] > cf && i >= 0) i--;
1218 i++;
1219 }
1220 else {
1221 i = 0;
1222 while (yvals[i] < cf && i < n_max) i++;
1223 i--;
1224 }
1225
1226 // do interpolation for cf
1228 lin_interpol_res = LinearInterpolation(cf, static_cast<float>(i), static_cast<float>(i + 1), yvals[i], yvals[i + 1]);
1229 // go to center of bin
1230 float interpol_bin = lin_interpol_res.first + .5;
1231
1232 if (use_spline) { // use spline interpolation with tolerance epsilon*bin_size
1233 double epsilon = 1e-4;
1234 double x_low = interpol_bin - .5;
1235 double x_high = interpol_bin + .5;
1236
1237 double* xvals = new double[n_range];
1239
1240 TSpline5* wfspl = 0;
1241 wfspl = new TSpline5("wf_spline", xvals, yvals, n_range, "b1e1b2e2", 0., 0., 0., 0.);
1242 delete[] xvals;
1243
1244 // using bisection method: halving search window until cf is less than epsilon bins from spline value
1245 while (x_high - x_low > epsilon) {
1246 double x_mid = (x_low + x_high) / 2;
1247 double f_mid = wfspl->Eval(x_mid);
1248 if (f_mid == cf) break;
1249
1250 if (f_mid > cf) x_high = x_mid;
1251 else x_low = x_mid;
1252 }
1253 interpol_bin = (x_low + x_high) / 2;
1254 delete wfspl;
1255 }
1256
1257 timing_results.push_back(vector<float>());
1258 timing_results[j].push_back(interpol_bin); // the bin we looked for
1259 timing_results[j].push_back((interpol_bin + static_cast<float>(start_at)) * SP); // cfd-time we looked for
1260 timing_results[j].push_back(max); // maximum value
1261 timing_results[j].push_back(n_max); // bin of maximum
1262 timing_results[j].push_back(cf); // constant fraction
1263 timing_results[j].push_back(static_cast<float>(start_at) * SP); // starting time
1264 timing_results[j].push_back(static_cast<float>(end_at) * SP); // end time
1265 timing_results[j].push_back(static_cast<float>(lin_interpol_res.second)); // flag will be 1 if linear interpolation worked
1266 delete[] yvals;
1267
1269 }
1270}
1272
1285void ReadRun::SkipEventsTimeDiffCut(int first_channel_abs, int second_channel_abs, double time_diff_min, double time_diff_max, bool verbose) {
1286
1287 cout << "\n Removing events if the event-wise time difference between the main peaks in ch"
1288 << first_channel_abs << " and ch" << second_channel_abs << " is <" << setprecision(2)
1289 << time_diff_min << " ns or >" << time_diff_max << " ns" << endl;
1290
1291 int counter = 0;
1294 int timing_results_size = static_cast<int>(timing_results.size());
1295
1296 // call GetTimingCFD() in case it was not initialized
1297 if (static_cast<int>(timing_results.size()) == 0) GetTimingCFD();
1298
1299 // loop through events, calculate timing difference between channels and compare with cuts
1300 for (int j = 0; j < nwf; j += nchannels) {
1301 if (!skip_event[GetCurrentEvent(j)]) {
1303
1306 if (verbose) cout << "\nevent:\t" << currevent << "\tchannels:\t" << first_channel_abs << " & " << second_channel_abs << "\ttime diff:\t" << time_diff;
1307 skip_event[GetCurrentEvent(j)] = true;
1308 counter++;
1309 }
1310 }
1312 }
1313 cout << "\t" << counter << " events will be cut out of " << nevents << endl;
1314}
1316
1328void ReadRun::FractionEventsAboveThreshold(float threshold, bool max, bool greater, double from, double to, bool verbose) {
1329
1330 int occurences = 0;
1331 int occurences2ch = 0;
1332 int o2ch = 0;
1333 int currchannel = 0;
1334 int currevent = 0;
1335 int lastevent = 0;
1337 vector<int> counter_abovethr(static_cast<int>(plot_active_channels.size()));
1338 // DORAMAS: It stores a counter of events above threshold for each channel that will be plotted
1339
1340 cout << "\nSearching for fraction of events with " << (max ? "max" : "min") << (greater ? " > " : " < ") << threshold << " mV:" << endl;
1341
1342 for (int j = 0; j < nwf; j++) {
1343 auto his = (TH1F*)(Getwf(j))->Clone(); // use Clone() to not change ranges of original histogram
1344
1345 // set range where to search for amplitudes above threshold
1346 if (from >= 0 && to > 0) {
1347 his->GetXaxis()->SetRange(his->GetXaxis()->FindBin(from), his->GetXaxis()->FindBin(to));
1348 }
1349
1352 if ((max && greater && his->GetMaximum() > threshold) || (max && !greater && his->GetMaximum() < threshold) || (!max && greater && his->GetMinimum() > threshold) || (!max && !greater && his->GetMinimum() < threshold)) {
1354
1355 if (verbose) cout << "\nevent:\t" << currevent << "\tchannel:\t" << active_channels[currchannel];
1356
1357 // We must use 'distance' to make sure the position in 'counter_above' matches with the corresponding channel's position at 'plot_active_channels'
1359 // This is to detect events w/ at least two channels above threshold
1360 if (lastevent != currevent) occurences += 1;
1361 if (lastevent == currevent && o2ch != occurences) {
1362 occurences2ch += 1;
1363 o2ch = occurences;
1364 }
1366 }
1367 }
1368 delete his;
1370 }
1371
1372 // Loop to show the fraction of events above threshold for each channel that will be plotted
1373 for (int i = 0; i < static_cast<int>(plot_active_channels.size()); i++) {
1374 cout << "Fraction of events in channel " << plot_active_channels[i] << " above threshold: "
1375 << 100. * static_cast<float>(counter_abovethr[i]) / static_cast<float>(nevents) << "%\n";
1376 }
1377
1378 cout << "Fraction of events w/ at least 2 channels above threshold: "
1379 << 100. * static_cast<float>(occurences2ch) / static_cast<float>(nevents) << "%\n"
1380 << "For a total of " << nevents << " events" << endl;
1381}
1382
1393void ReadRun::SkipEventsPerChannel(vector<float> thresholds, float rangestart, float rangeend, bool verbose) { // merge with IntegralFilter()?
1394
1395 if (thresholds.empty()) cout << "\nError: thresholds is empty";
1396 while (thresholds.size() <= active_channels.size()) thresholds.push_back(thresholds[0]);
1397
1398 cout << "\n Removing events with individual amplitude threshold per channel:" << endl;
1399 int counter = 0;
1400 int n_thrshld = static_cast<int>(thresholds.size());
1401 int currchannel = 0;
1402
1403 for (int j = 0; j < nwf; j++) {
1404 if (!skip_event[GetCurrentEvent(j)]) {
1406 if (currchannel < n_thrshld) {
1407 auto his = (TH1F*)(Getwf(j))->Clone(); // use Clone() to not change ranges of original histogram
1408 if (rangestart != 0 && rangeend != 0) his->GetXaxis()->SetRange(his->GetXaxis()->FindBin(rangestart), his->GetXaxis()->FindBin(rangeend));
1409
1410 if (thresholds[currchannel] != 0. && !skip_event[GetCurrentEvent(j)] && ((thresholds[currchannel] > 0 && his->GetMaximum() > thresholds[currchannel]) || (thresholds[currchannel] < 0 && his->GetMinimum() < thresholds[currchannel]))) {
1411
1413 if (verbose) cout << "\nevent:\t" << currevent << "\tchannel:\t" << active_channels[currchannel] << "\tthreshold\t" << thresholds[currchannel];
1414 skip_event[GetCurrentEvent(j)] = true;
1415 counter++;
1416 }
1417 delete his;
1418 }
1419 }
1421 }
1422
1423 cout << "\t" << counter << " events will be cut out of " << nevents << endl;
1424}
1425
1443void ReadRun::IntegralFilter(vector<float> thresholds, vector<bool> highlow, float windowlow, float windowhi, float start, float end, bool use_AND_condition, bool verbose) {
1444
1445 if (thresholds.empty() || highlow.empty()) cout << "\nError: thresholds or highlow are empty";
1446 while (thresholds.size() <= active_channels.size()) { thresholds.push_back(thresholds[0]); }
1447 while (highlow.size() <= active_channels.size()) { highlow.push_back(highlow[0]); }
1448
1449 cout << "\n\nRemoving events with individual integral threshold per channel:" << endl;
1450 int counter = 0;
1451 float integral = 0;
1452 int currevent_counter = 0;
1453 int currchannel = 0;
1454 int currevent = 0;
1455
1456 for (int j = 0; j < nwf; j++) {
1458
1461
1462 if (currchannel < static_cast<int>(thresholds.size())) {
1463 auto his = (TH1F*)(Getwf(j))->Clone(); // use Clone() to not change ranges of original histogram
1465
1469 if (verbose) cout << "\nevent:\t" << currevent << "\tchannel:\t" << active_channels[currchannel] << "\tthreshold\t" << thresholds[currchannel] << "\tintegral:\t" << integral;
1471 while (floor((j + 1) / nchannels) == currevent_counter) j++;
1472 counter++;
1473 }
1477 if (verbose) cout << "\nevent:\t" << currevent << "\tchannel:\t" << active_channels[currchannel] << "\thas been flagged good by integral:\t" << integral;
1478 }
1479 delete his;
1480 }
1482 }
1483 }
1484 cout << "\t" << counter << " events will be cut out of " << nevents << endl;
1485}
1489
1492 int counter = 0;
1493 for (int j = 0; j < static_cast<int>(skip_event.size()); j++) {
1494 if (skip_event[j]) {
1496 cout << "\nevent:\t" << currevent;
1497 counter++;
1498 }
1499 }
1500 cout << "\n\ntotal number of skipped events:\t" << counter << "\tout of:\t" << nevents << endl;
1501}
1502
1505 for (int j = 0; j < static_cast<int>(skip_event.size()); j++) skip_event[j] = false;
1506 cout << "\n\nAll event cuts were removed" << endl;
1507}
1508
1511 int nevents_good = 0;
1512 for (int i = 0; i < nevents; i++) if (!skip_event[i]) nevents_good++;
1513 return nevents_good;
1514}
1515
1516// functions for charge spectrum
1517
1534int* ReadRun::GetIntWindow(TH1F* his, float windowlow, float windowhi, float start, float end, int channel) {
1535
1536 int istart, iend;
1537 int* foundindices = new int[3]();
1538
1539 if (start < 0 || end < 0) { // fixed integration window relative to maximum of sum spectrum for each channel
1540 foundindices[1] = his->GetXaxis()->FindBin(his->GetXaxis()->GetBinCenter(maxSumBin[channel]) - windowlow);
1541 foundindices[2] = his->GetXaxis()->FindBin(his->GetXaxis()->GetBinCenter(maxSumBin[channel]) + windowhi);
1542 }
1543 else if (windowlow == start && windowhi == end) { // fixed integration window for all channels
1544 foundindices[1] = his->GetXaxis()->FindBin(windowlow);
1545 foundindices[2] = his->GetXaxis()->FindBin(windowhi);
1546 }
1547 else { // fixed integration window relative to maximum of each individual waveform
1548 istart = his->GetXaxis()->FindBin(start);
1549 iend = his->GetXaxis()->FindBin(end);
1550 foundindices[0] = istart;
1551
1552 if (istart < 1 || iend > his->GetNbinsX()) {
1553 cout << "\nError: start or end out of range" << endl;
1554 return 0;
1555 }
1556
1557 float max = -9.e99;
1558 float val = 0;
1559 for (int i = istart; i < iend; i++) {
1560 val = his->GetBinContent(i);
1561 if (val > max) {
1562 max = val;
1563 foundindices[0] = i;
1564 }
1565 }
1566
1567 foundindices[1] = his->GetXaxis()->FindBin(his->GetXaxis()->GetBinCenter(foundindices[0]) - windowlow);
1568 foundindices[2] = his->GetXaxis()->FindBin(his->GetXaxis()->GetBinCenter(foundindices[0]) + windowhi);
1569 }
1570 return foundindices;
1571}
1572
1588float ReadRun::GetPeakIntegral(TH1F* his, float windowlow, float windowhi, float start, float end, int channel_index) {
1589 int* windowind = GetIntWindow(his, windowlow, windowhi, start, end, channel_index); // find integration window
1590 string integral_option(""); // For amplitude -> unit[mV].
1591 if (windowind[1] != windowind[2]) integral_option = "width"; // 'width' (bin width) for integral -> unit[mV x ns].
1592 float integral = his->Integral(windowind[1], windowind[2], integral_option.c_str());
1593 delete[] windowind;
1594 return integral;
1595}
1596
1613void ReadRun::PrintChargeSpectrumWF(float windowlow, float windowhi, float start, float end, int eventnr, float ymin, float ymax, float xmin, float xmax) {
1614
1615 gStyle->SetOptStat(0);
1616
1617 TString name(Form("waveforms_event__%05d", eventnr));
1618 auto intwinc = new TCanvas(name.Data(), name.Data(), 600, 400);
1621
1622 int current_canvas = 0;
1623 for (int i = 0; i < nchannels; i++) {
1624 if (PlotChannel(i)) {
1625 intwinc->cd(++current_canvas);
1626
1627 auto his = Getwf(i, event_index);
1629 // create lines to indicate the integration window
1630 TLine* low = new TLine(his->GetXaxis()->GetBinCenter(windowind[1]), -5, his->GetXaxis()->GetBinCenter(windowind[1]), 10);
1631 low->SetLineColor(2);
1632 TLine* hi = new TLine(his->GetXaxis()->GetBinCenter(windowind[2]), -2, his->GetXaxis()->GetBinCenter(windowind[2]), 3);
1633 hi->SetLineColor(2);
1634 TLine* zero = new TLine(0, 0, 320, 0); // draw line at x=0 to check if baseline correction worked
1635 zero->SetLineColor(1);
1636 delete[] windowind;
1637
1638 // drawing and formatting
1639 gPad->SetTopMargin(.01);
1640 int last_canvas = nchannels;
1641 if (!plot_active_channels.empty()) last_canvas = static_cast<int>(plot_active_channels.size());
1642 if (current_canvas == 1 && last_canvas < 4) gPad->SetLeftMargin(.15);
1643 if (current_canvas % 4 == 0 || current_canvas == last_canvas) gPad->SetRightMargin(.01);
1644 his->Draw("HIST");
1645 his->SetStats(0);
1646
1647 low->Draw("same");
1648 hi->Draw("same");
1649 zero->Draw("same");
1650
1651 // draw baseline parameters
1652 if (static_cast<int>(baseline_correction_result.size()) > event_index * nchannels + i) {
1654 baselinel->SetLineColor(6);
1655 baselinel->SetLineWidth(2);
1657 baselineh->SetLineColor(6);
1658 baselineh->SetLineWidth(2);
1660 baseline->SetLineColor(6);
1662 correction_value->SetLineColor(2);
1663
1664 baselinel->Draw("same");
1665 baselineh->Draw("same");
1666 baseline->Draw("same");
1667 correction_value->Draw("same");
1668 }
1669
1670 if (static_cast<int>(timing_results.size()) > event_index * nchannels + i) {
1672 timing->SetLineColor(9);
1673 timing->SetLineWidth(2);
1674 timing->Draw("same");
1675 }
1676
1677 if (ymin != 0. && ymax != 0.) his->GetYaxis()->SetRangeUser(ymin, ymax); // fix y range for better comparison
1678 if (xmin != 0. && xmax != 0.) his->GetXaxis()->SetRangeUser(xmin, xmax);
1679 }
1680 }
1681 intwinc->Update();
1682
1683 root_out->WriteObject(intwinc, name.Data());
1684}
1686
1697float* ReadRun::ChargeList(int channel_index, float windowlow, float windowhi, float start, float end, bool negative_vals) {
1698 float* charge_list = new float[nevents]();
1699 for (int j = 0; j < nevents; j++) {
1700 auto his = Getwf(j * nchannels + channel_index);
1702 if (!negative_vals && charge_list[j] < 0.) charge_list[j] = 0.;
1703 }
1704 return charge_list;
1705}
1706
1717void ReadRun::SaveChargeLists(float windowlow, float windowhi, float start, float end, bool negative_vals) {
1718 float* event_list = new float[nevents];
1720
1721 auto charge_list_mg = new TMultiGraph();
1722 if (windowlow + windowhi > 0.) charge_list_mg->SetTitle("event-wise integrals; Event number; integral [mV#timesns]");
1723 else charge_list_mg->SetTitle("event-wise amplitudes; Event number; amplitude [mV]");
1724
1725 for (int i = 0; i < nchannels; i++) {
1726 if (PlotChannel(i)) {
1727 TString name(Form("charge_list_ch_%02d", active_channels[i]));
1730 charge_list_graph->SetLineWidth(0);
1731 charge_list_graph->SetMarkerStyle(2);
1732 charge_list_graph->SetMarkerColor(Helpers::rcolor(i));
1733 charge_list_graph->SetTitle(name.Data());
1734
1735 //remove skipped events
1736 for (int j = 0; j < nevents; j++) {
1737 if (skip_event[j]) charge_list_graph->RemovePoint(j);
1738 }
1739
1741 root_out->WriteObject(charge_list_graph, name.Data());
1742 delete[] charge_list;
1743 }
1744 }
1745 root_out->WriteObject(charge_list_mg, "all_charge_lists");
1746 delete[] event_list;
1747}
1748
1765void ReadRun::ChargeCorrelation(float windowlow, float windowhi, float start, float end, float rangestart, float rangeend, int nbins, int channel1, int channel2, bool ignore_skipped_events) {
1766 gStyle->SetOptStat(1111);
1768 name << "charge_correlation_ch" << channel1 << "_ch" << channel2;
1770 if (windowlow + windowhi > 0.) title << ";integral ch" << channel1 << " in mV#timesns;integral ch" << channel2 << " in mV#timesns;Entries";
1771 else title << ";amplitude ch" << channel1 << " in mV;amplitude ch" << channel2 << " in mV;Entries";
1772
1773 auto charge_corr_canvas = new TCanvas(name.str().c_str(), "canvas", 600, 600);
1774 charge_corr_canvas->SetRightMargin(0.15);
1775
1778
1779 auto charge_corr = new TH2F(name.str().c_str(), title.str().c_str(), nbins, rangestart, rangeend, nbins, rangestart, rangeend);
1780 for (int i = 0; i < nevents; i++) {
1782 }
1783
1784 charge_corr->Draw("colz");
1785 root_out->WriteObject(charge_corr, name.str().c_str());
1786
1787 charge_corr_canvas->Update();
1788 charge_corr_canvas->SetGrid();
1789 // move stat box out of the way (causing problems since May 23?)
1790 //TPaveStats* stat_box = (TPaveStats*)charge_corr->FindObject("stats");
1791 //stat_box->SetX1NDC(0.6);
1792 //stat_box->SetX2NDC(0.85);
1793 charge_corr->SetStats(0);
1794 charge_corr_canvas->Modified();
1795 name << "_c";
1796 root_out->WriteObject(charge_corr_canvas, name.str().c_str());
1797 delete[] charge1;
1798 delete[] charge2;
1799}
1801
1807TH1F* ReadRun::ChargeSpectrum(int channel_index, float windowlow, float windowhi, float start, float end, float rangestart, float rangeend, int nbins) {
1808
1809 TString name(Form("channel__%02d", active_channels[channel_index]));
1810 TH1F* h1 = new TH1F(name.Data(), name.Data(), nbins, rangestart, rangeend);
1811
1812 float pedestal = 0;
1813 float gain = 1;
1814 if (channel_index < static_cast<int>(PrintChargeSpectrum_cal.size())) {
1817 }
1818
1819 for (int j = 0; j < nevents; j++) {
1820 if (!skip_event[j]) {
1821 auto his = Getwf(channel_index, j);
1823 }
1824 }
1825 return h1;
1826}
1827
1861void ReadRun::PrintChargeSpectrum(float windowlow, float windowhi, float start, float end, float rangestart, float rangeend, int nbins, float fitrangestart, float fitrangeend, int max_channel_nr_to_fit, int which_fitf, bool use_log_y) {
1862 // print ReadRun::ChargeSpectrum for all channels optimized for SiPM signals
1863 checkData();
1864
1865 gStyle->SetOptStat("ne");
1866 gStyle->SetOptFit(1111);
1867
1869 if (fitrangeend == 0.) fitrangeend = rangeend;
1870
1871 string ctitle("\"charge\" spectra" + to_string(PrintChargeSpectrum_cnt++));
1872 auto chargec = new TCanvas(ctitle.c_str(), ctitle.c_str(), 600, 400);
1874
1875 cout << "\n\nThere is data recorded in " << active_channels.size() << " channels \n\n\n";
1876 int current_canvas = 0;
1877
1878 float default_rangestart = -2000;
1879 float default_rangeend = 30000;
1882
1883 int default_nbins = static_cast<int>((default_rangeend - default_rangestart) * nbins / (rangeend - rangestart));
1884
1885 for (int i = 0; i < nchannels; i++) {
1886 if (PlotChannel(i)) {
1887 chargec->cd(++current_canvas);
1888 if (use_log_y) gPad->SetLogy();
1889
1891 his->GetYaxis()->SetTitle("#Entries");
1892 if (windowlow + windowhi > 0.) his->GetXaxis()->SetTitle("Integral in mV#timesns");
1893 else his->GetXaxis()->SetTitle("Amplitude in mV");
1894
1895 if (i < static_cast<int>(PrintChargeSpectrum_cal.size()) && PrintChargeSpectrum_cal[i][0] != 1) {
1896 cout << "Charge spectrum for channel index " << i << " will be normalized using a gain of "
1897 << PrintChargeSpectrum_cal[i][0] << " and a pedestal value of " << PrintChargeSpectrum_cal[i][1] << endl;
1898 his->GetXaxis()->SetTitle("Number of photoelectrons");
1899 }
1900
1901 //store the mean integral of each channel --> used for correction factors of phi_ew analysis
1902 mean_integral.push_back(his->GetMean());
1903
1904 //fitting
1905 if (i < max_channel_nr_to_fit) {
1906 if (which_fitf == 0) {}
1907 else if (which_fitf == 1) { // landau gauss convolution for large number of photons
1909 int n_par = 4;
1910 TF1* f = new TF1("fitf_langaus", fitf, fitrangestart, fitrangeend, n_par); f->SetLineColor(3); f->SetNpx(1000);
1911
1912 f->SetParName(0, "Width"); f->SetParameter(0, 35);
1913 f->SetParName(1, "MPV"); f->SetParameter(1, 1000);
1914 f->SetParName(2, "Area"); f->SetParameter(2, 10000);
1915 f->SetParName(3, "#sigma_{Gauss}"); f->SetParameter(3, 100);
1916
1917 if (!PrintChargeSpectrum_pars.empty()) for (int j = 0; j < min(4, static_cast<int>(PrintChargeSpectrum_pars.size())); j++) f->SetParameter(j, PrintChargeSpectrum_pars[j]);
1918
1919 if (i < max_channel_nr_to_fit) {
1920 cout << "\n\n---------------------- Fit for channel " << active_channels[i] << " ----------------------\n";
1921 TFitResultPtr fresults = his->Fit(f, "LRS");
1922 fit_results.push_back(fresults);
1923 }
1924 }
1925 else if (which_fitf == 2) { // if pedestal is biased because of peak finder algorithm
1927 int n_par = 9;
1928 TF1* f = new TF1("fitf_biased", fitf, fitrangestart, fitrangeend, n_par); f->SetLineColor(3); f->SetNpx(1000);
1929
1930 f->SetParName(0, "N_{0}"); f->SetParameter(0, his->Integral());
1931 f->SetParName(1, "#mu"); f->SetParameter(1, 2.);
1932 f->SetParName(2, "#lambda"); f->SetParameter(2, .04);
1933 f->SetParName(3, "#sigma_{0}"); f->SetParameter(3, 2.1);
1934 f->SetParName(4, "#sigma_{1}"); f->SetParameter(4, 3.4); //f->SetParLimits(4, 1.e-9, 1.e3);
1935 f->SetParName(5, "Gain"); f->SetParameter(5, 30.); //f->FixParameter(5, 10.);
1936 f->SetParName(6, "Pedestal"); f->SetParameter(6, 2.);
1937 f->SetParName(7, "norm_{0}"); f->SetParameter(7, 0.7);
1938 f->SetParName(8, "x_{0}"); f->SetParameter(8, 5.);
1939
1940 if (!PrintChargeSpectrum_pars.empty()) for (int j = 0; j < min(n_par, static_cast<int>(PrintChargeSpectrum_pars.size())); j++) f->SetParameter(j, PrintChargeSpectrum_pars[j]);
1941
1942 if (i < max_channel_nr_to_fit) {
1943 cout << "\n\n---------------------- Fit for channel " << active_channels[i] << " ----------------------\n";
1944 TFitResultPtr fresults = his->Fit(f, "LRS");
1945 fit_results.push_back(fresults);
1946 }
1947
1948 // get number of excess events in the pedestal in the fit region. To get the absolute number of excess events the full pedestal needs to be inside of the fit range (fitrangestart, fitrangeend)
1949 //double excessEventsInPedestal = f->Integral(fitrangestart, fitrangeend)/.3125;
1950 //f->SetParameter(7, 1.);
1951 //excessEventsInPedestal -= f->Integral(fitrangestart, fitrangeend)/.3125;
1952 //cout << "\nNumber of excess events in the pedestal within the fit range:\t" << excessEventsInPedestal << "\n\n";
1953 }
1954 else if (which_fitf == 3) { // SiPM fit function with exponential delayed after pulsing
1956 int n_par = 9;
1957 TF1* f = new TF1("fitf", fitf, fitrangestart, fitrangeend, n_par); f->SetLineColor(3); f->SetNpx(1000);
1958
1959 f->SetParName(0, "N_{0}"); f->SetParameter(0, his->Integral());
1960 f->SetParName(1, "#mu"); f->SetParameter(1, 2.);
1961 f->SetParName(2, "#lambda"); f->SetParameter(2, .04);
1962 f->SetParName(3, "#sigma_{0}"); f->SetParameter(3, 2.1);
1963 f->SetParName(4, "#sigma_{1}"); f->SetParameter(4, 3.4);
1964 f->SetParName(5, "Gain"); f->SetParameter(5, 30.); //f->FixParameter(5, 40.);
1965 f->SetParName(6, "Pedestal"); f->SetParameter(6, 2.);
1966 f->SetParName(7, "#alpha"); f->SetParameter(7, .1); //f->FixParameter(7, .2);
1967 f->SetParName(8, "#beta"); f->SetParameter(8, 80.); //f->FixParameter(8, 80);
1968
1969 if (!PrintChargeSpectrum_pars.empty()) for (int j = 0; j < min(n_par, static_cast<int>(PrintChargeSpectrum_pars.size())); j++) f->SetParameter(j, PrintChargeSpectrum_pars[j]);
1970
1971 if (i < max_channel_nr_to_fit) {
1972 cout << "\n\n---------------------- Fit for channel " << active_channels[i] << " ----------------------\n";
1973 TFitResultPtr fresults = his->Fit(f, "LRS");
1974 fit_results.push_back(fresults);
1975 }
1976 }
1977 else if (which_fitf == 4) { // ideal PMT fit function
1979 int n_par = 4;
1980 TF1* f = new TF1("fitf", fitf, fitrangestart, fitrangeend, n_par); f->SetLineColor(3); f->SetNpx(1000);
1981
1982 f->SetParName(0, "N_{0}"); f->SetParameter(0, his->Integral());
1983 f->SetParName(1, "#mu"); f->SetParameter(1, 1.);
1984 f->SetParName(2, "#sigma"); f->SetParameter(2, 5.);
1985 f->SetParName(3, "gain"); f->SetParameter(3, 10.);
1986
1987 if (!PrintChargeSpectrum_pars.empty()) for (int j = 0; j < min(n_par, static_cast<int>(PrintChargeSpectrum_pars.size())); j++) f->SetParameter(j, PrintChargeSpectrum_pars[j]);
1988
1989 if (i < max_channel_nr_to_fit) {
1990 cout << "\n\n---------------------- Fit for channel " << active_channels[i] << " ----------------------\n";
1991 TFitResultPtr fresults = his->Fit(f, "LRS");
1992 fit_results.push_back(fresults);
1993 }
1994 }
1995 else if (which_fitf == 5) { // PMT fit function
1996 Fitf_PMT fitf;
1997 int n_par = 8;
1998 TF1* f = new TF1("fitf", fitf, fitrangestart, fitrangeend, n_par); f->SetLineColor(3); f->SetNpx(1000);
1999
2000 f->SetParName(0, "N_{0}"); f->SetParameter(0, his->Integral());
2001 f->SetParName(1, "w"); f->SetParameter(1, .05); f->SetParLimits(1, 1.e-99, 4.e-1); //probability for type II BG
2002 f->SetParName(2, "#alpha"); f->SetParameter(2, .05); f->SetParLimits(2, 1.e-99, 5.e-2); //coefficient of exponential decrease of typ II BG
2003 f->SetParName(3, "#sigma_{0}"); f->SetParameter(3, 5.); f->SetParLimits(3, 1.e-9, 1.e3);
2004 f->SetParName(4, "Q_{0}"); f->SetParameter(4, 0.);
2005 f->SetParName(5, "#mu"); f->SetParameter(5, 1.);
2006 f->SetParName(6, "#sigma_{1}"); f->SetParameter(6, 5.); f->SetParLimits(6, 1.e-9, 1.e3);
2007 f->SetParName(7, "Q_{1}"); f->SetParameter(7, 10.);
2008
2009 if (!PrintChargeSpectrum_pars.empty()) for (int j = 0; j < min(n_par, static_cast<int>(PrintChargeSpectrum_pars.size())); j++) f->SetParameter(j, PrintChargeSpectrum_pars[j]);
2010
2011 if (i < max_channel_nr_to_fit) {
2012 cout << "\n\n---------------------- Fit for channel " << active_channels[i] << " ----------------------\n";
2013 TFitResultPtr fresults = his->Fit(f, "LRS");
2014 fit_results.push_back(fresults);
2015 }
2016 }
2017 else if (which_fitf == 6) { // PMT fit function with biased pedestal
2019 int n_par = 9;
2020 TF1* f = new TF1("fitf", fitf, fitrangestart, fitrangeend, n_par); f->SetLineColor(3); f->SetNpx(1000);
2021
2022 f->SetParName(0, "A"); f->SetParameter(0, his->Integral());
2023 f->SetParName(1, "w"); f->SetParameter(1, .05); f->SetParLimits(1, 1.e-9, 4.e-1); //probability for type II BG
2024 f->SetParName(2, "#alpha"); f->SetParameter(2, .05); f->SetParLimits(2, 1.e-9, 5.e-2); //coefficient of exponential decrease of typ II BG
2025 f->SetParName(3, "#sigma_{0}"); f->SetParameter(3, 5.); f->SetParLimits(3, 1.e-9, 1.e3);
2026 f->SetParName(4, "Q_{0}"); f->SetParameter(4, 0.); f->SetParLimits(4, -1.e2, 1.e2);
2027 f->SetParName(5, "#mu"); f->SetParameter(5, 1.); f->SetParLimits(5, 1.e-9, 1.e2);
2028 f->SetParName(6, "#sigma_{1}"); f->SetParameter(6, 5.); f->SetParLimits(6, 1.e-9, 1.e3);
2029 f->SetParName(7, "Q_{1}"); f->SetParameter(7, 10.); f->SetParLimits(7, 1.e-9, 1.e9);
2030 f->SetParName(8, "A_{0}"); f->SetParameter(8, 1.); f->SetParLimits(8, 1.e-9, 1.e1);
2031
2032 if (!PrintChargeSpectrum_pars.empty()) for (int j = 0; j < min(n_par, static_cast<int>(PrintChargeSpectrum_pars.size())); j++) f->SetParameter(j, PrintChargeSpectrum_pars[j]);
2033
2034 if (i < max_channel_nr_to_fit) {
2035 cout << "\n\n---------------------- Fit for channel " << active_channels[i] << " ----------------------\n";
2036 TFitResultPtr fresults = his->Fit(f, "LRS");
2037 fit_results.push_back(fresults);
2038 }
2039 }
2040 else if (which_fitf == 7) { // default SiPM fit function + dark count spectrum (for lots of false triggers)
2042 int n_par = 9;
2043 TF1* f = new TF1("fitf", fitf, fitrangestart, fitrangeend, n_par); f->SetLineColor(3); f->SetNpx(1000);
2044
2045 f->SetParName(0, "A"); f->SetParameter(0, his->Integral());
2046 f->SetParName(1, "w"); f->SetParameter(1, .05); f->SetParLimits(1, 1.e-9, 4.e-1); //probability for type II BG
2047 f->SetParName(2, "#alpha"); f->SetParameter(2, .05); f->SetParLimits(2, 1.e-9, 5.e-2); //coefficient of exponential decrease of typ II BG
2048 f->SetParName(3, "#sigma_{0}"); f->SetParameter(3, 5.); f->SetParLimits(3, 1.e-9, 1.e3);
2049 f->SetParName(4, "Q_{0}"); f->SetParameter(4, 0.); f->SetParLimits(4, -1.e2, 1.e2);
2050 f->SetParName(5, "#mu"); f->SetParameter(5, 1.); f->SetParLimits(5, 1.e-9, 1.e2);
2051 f->SetParName(6, "#sigma_{1}"); f->SetParameter(6, 5.); f->SetParLimits(6, 1.e-9, 1.e3);
2052 f->SetParName(7, "#mu_darkcount"); f->SetParameter(7, .1); f->SetParLimits(7, 1.e-9, 1.);
2053 f->SetParName(8, "N_{0}_darkcount"); f->SetParameter(8, .05); f->SetParLimits(8, 1.e-9, .3);
2054
2055 if (!PrintChargeSpectrum_pars.empty()) for (int j = 0; j < min(n_par, static_cast<int>(PrintChargeSpectrum_pars.size())); j++) f->SetParameter(j, PrintChargeSpectrum_pars[j]);
2056
2057 if (i < max_channel_nr_to_fit) {
2058 cout << "\n\n---------------------- Fit for channel " << active_channels[i] << " ----------------------\n";
2059 TFitResultPtr fresults = his->Fit(f, "LRS");
2060 fit_results.push_back(fresults);
2061 }
2062 }
2063 else { // default SiPM fit function
2064 Fitf fitf;
2065 int n_par = 7;
2066 TF1* f = new TF1("fitf", fitf, fitrangestart, fitrangeend, n_par); f->SetLineColor(3); f->SetNpx(1000);
2067
2068 f->SetParName(0, "N_{0}"); f->SetParameter(0, his->Integral());
2069 f->SetParName(1, "#mu"); f->SetParameter(1, 2.);
2070 f->SetParName(2, "#lambda"); f->SetParameter(2, .04);
2071 f->SetParName(3, "#sigma_{0}"); f->SetParameter(3, 2.1);
2072 f->SetParName(4, "#sigma_{1}"); f->SetParameter(4, 3.4);
2073 f->SetParName(5, "Gain"); f->SetParameter(5, 30.); //f->FixParameter(5, 40.);
2074 f->SetParName(6, "Pedestal"); f->SetParameter(6, 2.);
2075
2076 if (!PrintChargeSpectrum_pars.empty()) for (int j = 0; j < min(n_par, static_cast<int>(PrintChargeSpectrum_pars.size())); j++) f->SetParameter(j, PrintChargeSpectrum_pars[j]);
2077
2078 if (i < max_channel_nr_to_fit) {
2079 cout << "\n\n---------------------- Fit for channel " << active_channels[i] << " ----------------------\n";
2080 TFitResultPtr fresults = his->Fit(f, "LRS");
2081 fit_results.push_back(fresults);
2082 }
2083 }
2084 }
2085 TString name(Form("ChargeSpectrum channel_%02d_%d", active_channels[i], PrintChargeSpectrum_cnt));
2086 root_out->WriteObject(his, name.Data());
2087 his->Draw();
2088 }
2089 }
2090
2092 root_out->WriteObject(chargec, ("ChargeSpectra" + to_string(PrintChargeSpectrum_cnt)).c_str());
2093}
2097
2103void ReadRun::PrintDCR(float windowlow, float windowhi, float rangestart, float rangeend, double threshold) {
2104
2105 string unit(" mV");
2106 if (windowlow + windowhi > 0.) unit = " mV*ns";
2107
2108 for (int i = 0; i < nchannels; i++) {
2109 if (PlotChannel(i)) {
2111
2113 lonamerate << "<0.5 pe=" << threshold << unit << " -> " << his->Integral(his->GetXaxis()->FindBin(rangestart), his->GetXaxis()->FindBin(threshold)) / his->GetEntries() / (1.e-3 * (rangeend - rangestart)) << " MHz";
2114 cout << "\n" << lonamerate.str().c_str() << endl;
2115
2117 hinamerate << ">0.5 pe=" << threshold << unit << " -> " << his->Integral(his->GetXaxis()->FindBin(threshold) + 1, his->GetXaxis()->FindBin(rangeend)) / his->GetEntries() / (1.e-3 * (rangeend - rangestart)) << " MHz";
2118 cout << "\n" << hinamerate.str().c_str() << endl;
2119 }
2120 }
2121}
2122
2127TH1F* ReadRun::TimeDist(int channel_index, float from, float to, float rangestart, float rangeend, int nbins, int which, float cf_r) {
2128
2129 TString name(Form("timedist_ch%02d", active_channels[channel_index]));
2130 auto h1 = new TH1F(name.Data(), name.Data(), nbins, rangestart, rangeend);
2131
2132 for (int j = 0; j < nevents; j++) {
2133 if (!skip_event[j]) {
2134 auto his = (TH1F*)(Getwf(j * nchannels + channel_index));
2135
2136 int from_n = his->GetXaxis()->FindBin(from);
2137
2138 int max_n = GetIntWindow(his, 0, 0, from, to)[0];
2139 float max = his->GetBinContent(max_n);
2140
2141 if (which == 0) { // time of maximum
2142 h1->Fill(max);
2143 }
2144 else if (which == 1) { // time of 50% CFD
2145 do {
2146 max_n--;
2147 } while (his->GetBinContent(max_n) >= cf_r * max && max_n > from_n);
2148 max_n++;
2149
2150 h1->Fill(LinearInterpolation(cf_r * max, his->GetXaxis()->GetBinCenter(max_n - 1), his->GetXaxis()->GetBinCenter(max_n), his->GetBinContent(max_n - 1), his->GetBinContent(max_n)).first);
2151 }
2152 else { // 10%-90% rise time
2153 // search backwards from maximum
2154 int n10 = -1;
2155 int n90 = -1;
2156 do {
2157 max_n--;
2158 if (n10 == -1 && his->GetBinContent(max_n) >= .1 * max && his->GetBinContent(max_n - 1) <= .1 * max) n10 = max_n;
2159 if (n90 == -1 && his->GetBinContent(max_n) >= .9 * max && his->GetBinContent(max_n - 1) <= .9 * max) n90 = max_n;
2160 } while (his->GetBinContent(max_n) <= max && max_n > from_n);
2161
2162 float t10 = LinearInterpolation(.1 * max, his->GetXaxis()->GetBinCenter(n10 - 1), his->GetXaxis()->GetBinCenter(n10), his->GetBinContent(n10 - 1), his->GetBinContent(n10)).first;
2163 float t90 = LinearInterpolation(.9 * max, his->GetXaxis()->GetBinCenter(n90 - 1), his->GetXaxis()->GetBinCenter(n90), his->GetBinContent(n90 - 1), his->GetBinContent(n90)).first;
2164
2165 h1->Fill(t90 - t10);
2166 }
2167 }
2168 }
2169 if (which == 1) h1->Fit("gaus", "WWM", "same");
2170 return h1;
2171}
2172
2191void ReadRun::PrintTimeDist(float from, float to, float rangestart, float rangeend, int nbins, int which, float cf_r) {
2192 gStyle->SetOptStat(1111); // 11 is title + entries
2193
2194 auto time_dist_c = new TCanvas("timing of maximum", "timing of maximum", 600, 400);
2196
2197 int current_canvas = 0;
2198
2199 for (int i = 0; i < nchannels; i++) {
2200 if (PlotChannel(i)) {
2202
2204 his->GetYaxis()->SetTitle("#Entries");
2205 his->GetXaxis()->SetTitle("time [ns]");
2206 his->Draw();
2207 stringstream name; name << "t_{max} for " << from << "<t<" << to << " ns";
2208 his->SetTitle(name.str().c_str());
2209
2210 TString name_save(Form("TimeDist channel_%02d", active_channels[i]));
2211 root_out->WriteObject(his, name_save.Data());
2212 }
2213 }
2214
2215 time_dist_c->Update();
2216 root_out->WriteObject(time_dist_c, "TimeDist");
2217}
2220
2227TGraph2D* ReadRun::MaxDist(int channel_index, float from, float to) {
2228 // find maximum amplitude for a given channel in time window [from, to] and return 3d histogram with the number of bins nbinsy,z
2229
2230 TString name(Form("maxdist_ch%02d", active_channels[channel_index]));
2231 TGraph2D* g3d = new TGraph2D((binNumber + 2) * nevents);
2232 g3d->SetTitle("waveforms; t [ns]; max. amplitude [mv]; amplitude [mV]");
2233
2234 for (int j = 0; j < nevents; j++) {
2235 if (!skip_event[j]) {
2236 auto his = (TH1F*)(Getwf(j * nchannels + channel_index))->Clone();
2237 if (from >= 0 && to > 0) his->GetXaxis()->SetRange(his->GetXaxis()->FindBin(from), his->GetXaxis()->FindBin(to));
2238 double max = his->GetMaximum();
2239 for (int i = 0; i < binNumber; i++) g3d->SetPoint(j * binNumber + i, his->GetXaxis()->GetBinCenter(i), max, his->GetBinContent(i));
2240 delete his;
2241 }
2242 }
2243 root_out->WriteObject(g3d, name.Data());
2244 return g3d;
2245}
2246
2254void ReadRun::PrintMaxDist(float from, float to) {
2255
2256 auto max_dist_c = new TCanvas("wf grouped by maximum", "wf grouped by maximum", 600, 400);
2258
2259 int current_canvas = 0;
2260
2261 for (int i = 0; i < nchannels; i++) {
2262 if (PlotChannel(i)) {
2264 auto g3d = MaxDist(i, from, to);
2265 g3d->Draw();
2266 }
2267 }
2268 max_dist_c->Update();
2269 root_out->WriteObject(max_dist_c, "MaxDist");
2270}
2271
2277TH1F* ReadRun::His_GetTimingCFD(int channel_index, float rangestart, float rangeend, int nbins) {
2278
2279 if (nbins == -999) nbins = static_cast<int>((rangeend - rangestart) / SP);
2280
2281 TString name(Form("GetTimingCFD_ch%02d", active_channels[channel_index]));
2282 auto h1 = new TH1F(name.Data(), name.Data(), nbins, rangestart, rangeend);
2283 for (int j = 0; j < nevents; j++) if (!skip_event[j]) h1->Fill(timing_results[j * nchannels + channel_index][1]);
2284 return h1;
2285}
2286
2300void ReadRun::Print_GetTimingCFD(float rangestart, float rangeend, int do_fit, int nbins, string fitoption, bool set_errors) {
2301
2302 // call GetTimingCFD() in case it was not initialized
2303 if (static_cast<int>(timing_results.size()) == 0) GetTimingCFD();
2304
2305 gStyle->SetOptStat(1111);
2306 gStyle->SetOptFit(111);
2307
2308 auto timing_cfd_c = new TCanvas("timing of cfd", "timing of cfd", 600, 400);
2310 int current_canvas = 0;
2311
2312 for (int i = 0; i < nchannels; i++) {
2313 if (PlotChannel(i)) {
2315
2317 his->GetYaxis()->SetTitle("#Entries");
2318 his->GetXaxis()->SetTitle("time [ns]");
2319
2320 if (set_errors) {
2321 int end = his->GetNbinsX();
2322 for (int i = 1; i <= end; i++) {
2323 if (his->GetBinContent(i) < 2) his->SetBinError(i, 1);
2324 else his->SetBinError(i, sqrt(his->GetBinContent(i)));
2325 }
2326 }
2327
2328 his->Draw();
2329
2330 if (do_fit == 1) {
2331 TFitResultPtr fresults = his->Fit("gaus", fitoption.c_str(), "same");
2332 timing_fit_results.push_back(fresults);
2333 }
2334
2335 TString name_save(Form("Timing_cfd_channel_%02d", active_channels[i]));
2336 root_out->WriteObject(his, name_save.Data());
2337 }
2338 }
2339
2340 timing_cfd_c->Update();
2341 root_out->WriteObject(timing_cfd_c, "TimingCFD");
2342}
2344
2350TH1F* ReadRun::His_GetTimingCFD_diff(vector<int> channels1, vector<int> channels2, float rangestart, float rangeend, int nbins) {
2351
2352 if (nbins == -999) nbins = static_cast<int>((rangeend - rangestart) / SP);
2353
2355 name << "GetTimingCFD_diff <";
2356
2357 // find channel indices and assemble title
2358 int counter = 0;
2359 for (int& entry : channels2) {
2360 if (counter > 0) name << "&";
2361 auto chin2 = find(active_channels.begin(), active_channels.end(), entry);
2362 if (chin2 != active_channels.end()) {
2363 name << "ch" << entry;
2364 entry = chin2 - active_channels.begin();
2365 }
2366 else cout << "\n\n ERROR: channels2 = " << entry << " does not exist in data. Check parameters for Print_GetTimingCFD_diff()\n\n";
2367 counter++;
2368 }
2369 name << ">-<";
2370 counter = 0;
2371
2372 for (int& entry : channels1) {
2373 if (counter > 0) name << "&";
2374 auto chin1 = find(active_channels.begin(), active_channels.end(), entry);
2375 if (chin1 != active_channels.end()) {
2376 name << "ch" << entry;
2377 entry = chin1 - active_channels.begin();
2378 }
2379 else cout << "\n\n ERROR: channels1 = " << entry << " does not exist in data. Check parameters for Print_GetTimingCFD_diff()\n\n";
2380 counter++;
2381 }
2382 name << ">";
2383
2384 // fill histogram
2385 auto h1 = new TH1F(name.str().c_str(), name.str().c_str(), nbins, rangestart, rangeend);
2386 for (int j = 0; j < nevents; j++) {
2387 if (!skip_event[j]) {
2388 float mean1 = 0., mean2 = 0., cnt1 = 0., cnt2 = 0.;
2389 for (int i : channels1) {
2390 mean1 += timing_results[j * nchannels + i][1];
2391 cnt1 += 1.;
2392 }
2393 for (int i : channels2) {
2394 mean2 += timing_results[j * nchannels + i][1];
2395 cnt2 += 1.;
2396 }
2397 h1->Fill(mean2 / cnt2 - mean1 / cnt1);
2398 }
2399 }
2400
2401 return h1;
2402}
2403
2438void ReadRun::Print_GetTimingCFD_diff(vector<int> channels1, vector<int> channels2, float rangestart, float rangeend, int do_fit, int nbins, float fitrangestart, float fitrangeend, string fitoption, bool set_errors) {
2439
2440 // call GetTimingCFD() in case it was not initialized
2441 if (static_cast<int>(timing_results.size()) == 0) GetTimingCFD();
2442
2443 if (fitrangestart == -999) {
2446 }
2447
2448 //gStyle->SetOptStat(1111);
2449 gStyle->SetOptFit(111);
2450
2451 auto timing_cfd_d_c = new TCanvas("timing of cfd diff", "timing of cfd diff", 600, 400);
2452
2454 his->GetYaxis()->SetTitle("#Entries");
2455 his->GetXaxis()->SetTitle("time [ns]");
2456
2457 if (set_errors) {
2458 int end = his->GetNbinsX();
2459 for (int i = 1; i <= end; i++) {
2460 if (his->GetBinContent(i) < 2) his->SetBinError(i, 1);
2461 else his->SetBinError(i, sqrt(his->GetBinContent(i)));
2462 }
2463 }
2464
2465 his->Draw();
2466
2467 double skewness = his->GetSkewness();
2468
2469 if (do_fit == 1 || (do_fit == 2 && abs(skewness) < .15)) {
2470 // gauss (default)
2471 TFitResultPtr fresults = his->Fit("gaus", fitoption.c_str(), "same", fitrangestart, fitrangeend);
2472 timing_fit_results.push_back(fresults);
2473 if (do_fit == 2) cout << "\nWARNING: Print_GetTimingCFD_diff\nFITTING GAUSS INSTEAD OF GAUSS x EXP CONVOLUTION BC SYMMETRY" << endl;
2474 }
2475 else if (do_fit == 2) {
2476 // gauss x exp convolution (effective delay from random light path and/or self-absorption and reemission)
2478 auto expgconv = new TF1("exp x gauss convolution", fitf_exp_gauss, fitrangestart, fitrangeend, 4);
2479 expgconv->SetNpx(5000);
2480
2481 // this parameter describes the sigma from different light paths
2482 // and/or the effective decay time constant for self-absorption and reemission
2483 expgconv->SetParName(0, "#tau_{eff}"); expgconv->SetParameter(0, skewness);
2484 if (skewness > 0) expgconv->SetParLimits(0, .15, 5.);
2485 else expgconv->SetParLimits(0, -5., -.15);
2486 //expgconv->FixParameter(0, 1.55);
2487
2488 expgconv->SetParName(1, "#sigma_{gaus}"); expgconv->SetParameter(1, his->GetStdDev());
2489 expgconv->SetParLimits(1, 1e-1, 7.); //expgconv->FixParameter(1, .7);
2490
2491 expgconv->SetParName(2, "t_{0}"); expgconv->SetParameter(2, his->GetMean());
2492 expgconv->SetParLimits(2, fitrangestart, fitrangeend); //expgconv->FixParameter(2, 6.6);
2493
2494 expgconv->SetParName(3, "norm"); expgconv->SetParameter(3, his->Integral("width"));
2495 expgconv->SetParLimits(3, 1., 1e8); //expgconv->FixParameter(3, 105.5);
2496
2497 TFitResultPtr fresults = his->Fit(expgconv, "SR", "same");
2498 timing_fit_results.push_back(fresults);
2499
2500 // for the phi_ew-analysis: print out the time value of the maximum of the best fit --> used to determine timing cuts
2501 float t_of_maximum = expgconv->GetMaximumX(-5, 5);
2502 cout << "Maximum of the fit is at t=" << t_of_maximum << " ns and the ";
2503
2504 double max_val = expgconv->GetMaximum();
2505 double fwhm_x1 = expgconv->GetX(max_val / 2, fitrangestart, fitrangeend);
2506 double fwhm_x2 = expgconv->GetX(max_val / 2, fwhm_x1 + 1e-3, fitrangeend);
2507 double fwhm = fwhm_x2 - fwhm_x1;
2508 auto fwhm_line = new TLine(fwhm_x1, max_val/2, fwhm_x2, max_val/2);
2509 fwhm_line->SetLineColor(2); fwhm_line->SetLineWidth(2);
2510 fwhm_line->Draw("same");
2511 cout << "FWHM=" << fwhm << " ns" << endl;
2512
2513 // TLatex l;
2514 // l.SetTextSize(0.025);
2515 // l.DrawLatex(t_of_maximum/(rangeend - rangestart), 0.4, Form("FWHM = %.2f ns", fwhm));
2516
2517 auto mean = new TLine(expgconv->GetParameter(2), 1e-2, expgconv->GetParameter(2), his->GetMaximum());
2518 mean->SetLineColor(1); mean->SetLineWidth(2);
2519 mean->Draw("same");
2520 }
2521 else if (do_fit == 3) {
2522 // sum of two gaussians (one as background estimate)
2523 auto two_gauss = new TF1("two gaussians", "gaus(0)+gaus(3)", rangestart, rangeend);
2524 two_gauss->SetTitle("Sum of two gauss");
2525 float posmax = his->GetXaxis()->GetBinCenter(his->GetMaximumBin());
2526 two_gauss->SetParameters(his->Integral("width"), posmax, 0.35, his->Integral("width") / 30, posmax, 2);
2527 two_gauss->SetParName(0, "norm_{peak}"); two_gauss->SetParName(1, "#mu_{peak}"); two_gauss->SetParName(2, "#sigma_{peak}"); two_gauss->SetParLimits(2, 1e-9, 1e2);
2528 two_gauss->SetParName(3, "norm_{background}"); two_gauss->SetParName(4, "#mu_{background}"); two_gauss->SetParName(5, "#sigma_{background}"); two_gauss->SetParLimits(5, 1e-9, 1e2);
2530 timing_fit_results.push_back(fresults);
2531 }
2532
2533 root_out->WriteObject(his, his->GetTitle());
2534 timing_cfd_d_c->Update();
2535 root_out->WriteObject(timing_cfd_d_c, "TimingCFD_diff");
2536}
2538
2539
2540
2541
2542
2543
2547TH1F* ReadRun::Getwf(int wf_nr) {
2548 checkData();
2549 return (TH1F*)rundata->At(wf_nr);
2550}
2551
2557TH1F* ReadRun::Getwf(int channelnr, int eventnr, int color) {
2558 checkData();
2559 TH1F* his;
2561 his->SetLineColor(color);
2562 his->SetMarkerColor(color);
2563 return his;
2564}
2565
2569double* ReadRun::getx(double shift) {
2570 double* xvals = new double[binNumber];
2571 for (int i = 0; i < binNumber; i++) {
2572 xvals[i] = static_cast<double>(SP) * static_cast<double>(i) + shift;
2573 }
2574 return xvals;
2575}
2576
2580double* ReadRun::gety(int waveform_index) {
2581 auto his = Getwf(waveform_index);
2582 return Helpers::gety(his);
2583}
2584
2589double* ReadRun::gety(int channelnr, int eventnr) {
2590 auto his = Getwf(channelnr, eventnr);
2591 return Helpers::gety(his);
2592}
2593
2597int ReadRun::GetEventIndex(unsigned int eventnr) {
2598 auto event_pos = find(eventnr_storage.begin(), eventnr_storage.end(), eventnr);
2599 if (event_pos == eventnr_storage.end()) {
2600 cout << "WARNING: Event number " << eventnr << " for GetEventIndex() does not exist in data.\n"
2601 << "Please check the events in the data or set discard_original_eventnr = true before calling ReadFile()." << endl;
2602
2603 if (static_cast<int>(eventnr) < nevents) {
2606 cout << "Found event number " << eventnr << " in data and will use it." << endl;
2607 }
2608 }
2609 return static_cast<int>(distance(eventnr_storage.begin(), event_pos));
2610}
2611
2615int ReadRun::GetChannelIndex(int channel_number) {
2616 int channel_index = -1;
2617 for (int i = 0; i < static_cast<int>(active_channels.size()); i++) {
2619 }
2620 if (channel_index == -1) {
2621 cout << "\n\n\tERROR: channel " << channel_number << " does not exist in data. Will continue with first channel\n\n";
2622 channel_index = 0;
2623 }
2624 return channel_index;
2625}
2626
2630int ReadRun::GetCurrentChannel(int waveform_index) {
2632}
2633
2637int ReadRun::GetCurrentEvent(int waveform_index) {
2638 return floor(waveform_index / nchannels);
2639}
2640
2644 if (plot_active_channels.empty() || find(plot_active_channels.begin(), plot_active_channels.end(), active_channels[i]) != plot_active_channels.end()) return true;
2645 else return false;
2646}
2647
2658pair<float, bool> ReadRun::LinearInterpolation(float ym, float x1, float x2, float y1, float y2) {
2659 if (y1 == y2) return {(x1 + x2) / 2., false};
2660 else if (y1 > ym) {
2661 cout << "\nError in LinearInterpolation: Value ym=" << ym << " out of range (" << y1 << "|" << y2 << ").\n"
2662 << "Will return x1. Increase window for search.\n";
2663 return {x1, false};
2664 }
2665 else return {x1 + (ym - y1) * (x2 - x1) / (y2 - y1), true};
2666}
static void ResponseFilter(double *&, int, double=.4, double=1.2, double=.25, double=.3125)
Custom filter emulating primitive response function.
Definition Filters.cc:421
static void SecondOrderUnderdampedFilter(double *&, int, double, double, double, double=.3125, bool=false)
Shifted second order underdamped filter.
Definition Filters.cc:466
static void SmoothArray(double *&, int, double=.625, string="Gaus", double=.3125, double=1.5)
Apply smoothing array of double with length nbins.
Definition Filters.cc:160
Ideal PMT charge spectrum.
Gauss-Poisson distribution for fit of PMT charge spectra.
Gauss-Poisson distribution for fit of PMT charge spectra.
Fit function for SiPMs missing after-pulses and dark counts but with biased pedestal.
Convolution of an exponential and a gaussian.
Default fit function for SiPMs with after-pulses missing dark counts.
Landau-Gauss-convolution.
Fit function for SiPMs missing after-pulses and dark counts but including additional dark count spect...
Default fit function for SiPMs missing after-pulses and dark counts.
Definition FitFunctions.h:6
static void SplitCanvas(TCanvas *&, vector< int >, vector< int >)
Helper to split canvas according to the number of channels to be plotted.
Definition Helpers.cc:97
static void SetRangeCanvas(TCanvas *&, double, double, double=-999, double=-999)
Set consistent x-axis and y-axis range for all TH1 histograms on a canvas.
Definition Helpers.cc:59
static void ShiftTH1F(TH1F *&, int=0)
Shift a histogram in x.
Definition Helpers.cc:157
static int rcolor(unsigned int)
Translate a random number into a useful root color https://root.cern.ch/doc/master/classTColor....
Definition Helpers.cc:44
static void PrintProgressBar(int, int)
Print progress bar for a loop in steps of 10 percent.
Definition Helpers.cc:28
static double * gety(TH1F *)
Get array of y values for a histogram.
Definition Helpers.cc:125
static string ListFiles(const char *, const char *)
Helper. Creates a list of .bin data files in data folder to be read in.
Definition Helpers.cc:7
TH1F * Getwf(int)
Helper that returns the waveform histogram for a certain waveform number number.
Definition ReadRun.cc:2547
int maxNWF
Maximum possible number of waveforms in data: number of active channels x number of events.
Definition ReadRun.h:271
void Print_GetTimingCFD(float=100, float=140, int=0, int=-999, string="S", bool=true)
Plot results of GetTimingCFD()
Definition ReadRun.cc:2300
void ChargeCorrelation(float, float, float, float, float, float, int, int, int, bool=false)
Plot correlation of integrals/amplitudes between two channels.
Definition ReadRun.cc:1765
float tCutEndg
End of time window for baseline correction when using ReadRun::Using_BaselineCorrection_in_file_loop.
Definition ReadRun.h:348
TH1F * ChargeSpectrum(int, float, float, float=0, float=300, float=-50, float=600, int=750)
Histogram of the "charge" spectrum for one channel.
Definition ReadRun.cc:1807
float DAQ_factor
DAQ conversion factor for wavecatcher output to mV.
Definition ReadRun.h:278
int nevents
Number of triggered events in data.
Definition ReadRun.h:263
vector< bool > skip_event
Stores the event numbers which should be skipped in the analysis.
Definition ReadRun.h:311
double * gety(int)
Get array of y values for a certain waveform.
Definition ReadRun.cc:2580
vector< int > active_channels
Stores the numbers of the active channels.
Definition ReadRun.h:290
void checkData() const
Primitive check to see if data has been loaded.
Definition ReadRun.h:113
float GetPeakIntegral(TH1F *, float, float, float, float, int=0)
Calculate the integral around a peak with several options explained in GetIntWindow().
Definition ReadRun.cc:1588
int GetEventIndex(unsigned int)
Returns index of a certain event number (if data files are read in parallel threads)
Definition ReadRun.cc:2597
TH1F * His_GetTimingCFD(int, float, float, int=-999)
Plot results of GetTimingCFD()
Definition ReadRun.cc:2277
void FilterAll(double=.3, double=.9, double=.2)
Filter all waveforms.
Definition ReadRun.cc:641
int GetChannelIndex(int)
Match channel number (wavecatcher input channel) to channel index.
Definition ReadRun.cc:2615
float tCutg
Start of time window for baseline correction when using ReadRun::Using_BaselineCorrection_in_file_loo...
Definition ReadRun.h:346
float * ChargeList(int, float=20, float=80, float=0, float=300, bool=1)
Returns array with the individual "charge"/amplitude for all events of one channel.
Definition ReadRun.cc:1697
TFile * root_out
Stores results of analysis.
Definition ReadRun.h:338
int tWF_CF_lo
Start of range of bins where the signal is expected for ReadRun::Shift_WFs_in_file_loop.
Definition ReadRun.h:360
int nChannelsWC
Wavecatcher hardware max. number of channels (reduce/increase if not using the 64 channel crate)
Definition ReadRun.h:282
void FractionEventsAboveThreshold(float=4, bool=true, bool=true, double=0., double=0., bool=false)
Find events with max/min above/below a certain threshold.
Definition ReadRun.cc:1328
void CorrectBaselineMinSlopeRMS(vector< float >, double=0, int=2, int=3)
Baseline correction method searching for non-monotonic, rather constant regions.
Definition ReadRun.cc:784
void PrintBaselineCorrectionResults(float=-5, float=5, int=200)
Print histogram of the baseline correction values for all channels.
Definition ReadRun.cc:1138
vector< float > PrintChargeSpectrum_pars
Starting values of the fit parameters for PrintChargeSpectrum()
Definition ReadRun.h:176
ReadRun(int max_no_of_bin_files_to_read=0, int min_no_of_bin_files_to_read=0)
Constructor of the class.
Definition ReadRun.cc:24
bool Using_BaselineCorrection_in_file_loop
Set true for baseline correction during data reading. Needs to be called before ReadFile().
Definition ReadRun.h:344
void PrintWFProjection(float=0, float=320, float=-50, float=50, int=200)
Plots waveform projection histograms of all channels.
Definition ReadRun.cc:1079
void PlotChannelAverages(bool=false)
Plot averages only of the good, corrected waveforms for each channel.
Definition ReadRun.cc:454
bool PlotChannel(int)
Check if a channel index should be plotted according to ReadRun::plot_active_channels.
Definition ReadRun.cc:2643
int Nevents_good()
Number of good events that are not skipped.
Definition ReadRun.cc:1510
void ReadFile(string, bool=false, int=9, string="out.root", bool=false)
Routine to read files created by the wavecatcher.
Definition ReadRun.cc:66
int MaxNoOfBinFilesToRead
Number of last .bin file to be read in.
Definition ReadRun.h:235
int tWF_CF_hi
End of range of bins where the signal is expected for ReadRun::Shift_WFs_in_file_loop.
Definition ReadRun.h:362
int start_read_at_channel
Do analysis only for limited range of channels to reduce memory usage.
Definition ReadRun.h:258
int * GetIntWindow(TH1F *, float, float, float, float, int=0)
Determine indices for integration window for peaks.
Definition ReadRun.cc:1534
void PrintChargeSpectrumWF(float, float, float=0, float=300, int=1, float=0., float=0., float=0., float=0.)
Plot waveforms of all channels for a given event number and add the determined integration windows to...
Definition ReadRun.cc:1613
float tWF_CF
Constant fraction of maximum (between ~0.1 and 1) for ReadRun::Shift_WFs_in_file_loop.
Definition ReadRun.h:355
vector< float > mean_integral
Stores the mean integral/lightyield from PrintChargeSpectrum() for all channels.
Definition ReadRun.h:306
bool discard_original_eventnr
Can be used to discard the original event numbering of the data.
Definition ReadRun.h:247
vector< int > switch_polarity_for_channels
Stores the channel number where the polarity should be inverted. Example use to switch polarity for c...
Definition ReadRun.h:300
TH1F * WFProjectionChannel(int, int=0, int=1024, float=-50, float=50, int=200)
Waveform projections for one channel.
Definition ReadRun.cc:1052
void GetTimingCFD(float=.3, float=100, float=140, double=0., bool=true, int=2, bool=false)
Determine the timing of the maximum peak with constant fraction discrimination.
Definition ReadRun.cc:1188
TGraph2D * MaxDist(int, float=0, float=300)
Finds maximum amplitude for a given channel in time window ["from", "to"] and creates 3d map of wavef...
Definition ReadRun.cc:2227
int nwf
Total number of waveforms read from data: number of active channels x number of events.
Definition ReadRun.h:267
TH1F * TimeDist(int, float=0, float=300, float=0, float=300, int=100, int=0, float=.3)
Time distribution of maximum, CFD, or 10% - 90% rise time in a certain time window.
Definition ReadRun.cc:2127
void IntegralFilter(vector< float >, vector< bool >, float, float, float=50, float=250, bool=false, bool=false)
Skip events with threshold on integral.
Definition ReadRun.cc:1443
TH1F * BaselineCorrectionResults(int, int, float=-5, float=5, int=200)
Histograms of the contents of baseline_correction_result.
Definition ReadRun.cc:1118
void PrintDCR(float=15, float=85, float=0, float=300, double=3)
Calculate (SiPM) dark count rate.
Definition ReadRun.cc:2103
void SmoothAll(double, int)
Smoothing all waveforms which are not skipped (for testing, careful when using for analysis!...
Definition ReadRun.cc:599
void CorrectBaseline(float, float=-999)
Baseline correction constant window.
Definition ReadRun.cc:707
void CorrectBaselineMin(vector< float >, double=0, int=2, int=2)
Baseline correction using minimum sum ( mean) in range for correction.
Definition ReadRun.cc:938
int binNumber
Number of bins (always 1024 samples per waveform). Do not change!
Definition ReadRun.h:280
vector< vector< float > > PrintChargeSpectrum_cal
Calibration values to normalize charge spectrum to number of photoelectrons Chennels must be ordered ...
Definition ReadRun.h:367
vector< vector< float > > timing_results
Matrix to store timing of peaks from GetTimingCFD()
Definition ReadRun.h:333
void SaveChargeLists(float=20, float=80, float=0, float=300, bool=1)
Saves TGraphs to root file with the individual "charge"/amplitude for all events and all channels.
Definition ReadRun.cc:1717
vector< vector< float > > baseline_correction_result
Stores baseline correction results for CorrectBaseline() and related functions.
Definition ReadRun.h:320
TH1F * His_GetTimingCFD_diff(vector< int >, vector< int >, float, float, int=-999)
Plot timing difference between the mean timings of two channel ranges.
Definition ReadRun.cc:2350
void SkipEventsTimeDiffCut(int, int, double, double, bool=false)
Skip events where the time difference between two channels is outside of specified range.
Definition ReadRun.cc:1285
void SkipEventsPerChannel(vector< float >, float=0, float=0, bool=false)
Skip events above/below individual thresholds per channel.
Definition ReadRun.cc:1393
string data_path
Path to data.
Definition ReadRun.h:230
TClonesArray * rundata
Stores data.
Definition ReadRun.h:124
void PrintMaxDist(float=0, float=300)
Finds maximum amplitude for a given channel in time window ["from", "to"] and creates 3d map of wavef...
Definition ReadRun.cc:2254
void PrintChargeSpectrum(float, float, float=0, float=300, float=-50, float=600, int=750, float=0., float=0., int=99, int=0, bool=false)
Plots the "charge" spectrums of all channels.
Definition ReadRun.cc:1861
int end_read_at_channel
See ReadRun::start_read_at_channel.
Definition ReadRun.h:260
int nchannels
Number of active channels in data.
Definition ReadRun.h:265
void UnskipAll()
Sets skip_event flag to false for all events, removing any previous cuts.
Definition ReadRun.cc:1504
float SP
Sampling: ns per bin of data, sampling rate 3.2 GS/s -> 0.3125 ns.
Definition ReadRun.h:274
vector< TFitResultPtr > timing_fit_results
Stores the fit results of Print_GetTimingCFD() for all channels.
Definition ReadRun.h:335
void PlotWFHeatmaps(float=-20, float=200, int=880, string="", float=0, EColorPalette=kGistEarth)
Plot stacks of all non-skipped waveforms for all active channels.
Definition ReadRun.cc:556
int GetCurrentEvent(int)
Get the current event index for a certain waveform index.
Definition ReadRun.cc:2637
int tWF_CF_bin
Time bin all events will be shifted to for ReadRun::Shift_WFs_in_file_loop Needs to be 300<"tWF_CF_bi...
Definition ReadRun.h:358
virtual ~ReadRun()
Destructor.
Definition ReadRun.cc:376
void PlotChannelSums(bool=false, bool=false, double=0., double=0., int=2)
Plot sums of all raw waveforms for each channel.
Definition ReadRun.cc:396
void CorrectBaseline_function(TH1F *, float, float, int)
Helper function called by CorrectBaseline()
Definition ReadRun.cc:730
void PrintTimeDist(float=0, float=300, float=0, float=300, int=100, int=0, float=.3)
Time distribution of maximum, CFD, or 10% - 90% rise time in a certain time window.
Definition ReadRun.cc:2191
float ** amplValuessum
Collects sums of all waveforms for each channel.
Definition ReadRun.h:127
vector< int > plot_active_channels
Stores the numbers of the active channels which should be plotted.
Definition ReadRun.h:295
static pair< float, bool > LinearInterpolation(float, float, float, float, float)
Simple linear interpolation for x.
Definition ReadRun.cc:2658
void ShiftAllToAverageCF()
This function shifts all waveforms to the average signal starting times for each channel.
Definition ReadRun.cc:661
vector< TFitResultPtr > fit_results
Stores the fit results of PrintChargeSpectrum() for all channels and all function calls in ascending ...
Definition ReadRun.h:303
int GetCurrentChannel(int)
Get the current channel index for a certain waveform index.
Definition ReadRun.cc:2630
int MinNoOfBinFilesToRead
Number first of .bin file to be read in.
Definition ReadRun.h:239
void PrintSkippedEvents()
Prints a list of all skipped events into the terminal for diagnostics.
Definition ReadRun.cc:1491
double * getx(double=0.)
Get array of x axis (time) for standard wavecatcher settings.
Definition ReadRun.cc:2569
int * maxSumBin
Stores bin numbers where the sum of waveforms have their maximum.
Definition ReadRun.h:287
bool Shift_WFs_in_file_loop
Shift waveforms with CFD so that all events start at the same time Call after initializing class and ...
Definition ReadRun.h:353
TH2F * WFHeatmapChannel(int, float=-20, float=200, int=880)
2D histogram of all non-skipped waveforms for one channel
Definition ReadRun.cc:524
void Print_GetTimingCFD_diff(vector< int >, vector< int >, float=100, float=140, int=0, int=-999, float=-999, float=-999, string="RS", bool=true)
Plot timing difference between the mean timings of two channel ranges.
Definition ReadRun.cc:2438
vector< unsigned int > eventnr_storage
Events will be stored here in the order they have been read.
Definition ReadRun.h:130