wavecatcher-analysis
Loading...
Searching...
No Matches
ReadRun.cc
Go to the documentation of this file.
1
24
25#include "ReadRun.h"
26
28ReadRun::ReadRun(int last_bin_file, int first_bin_file) {
29
30 cout << "\ninitializing ..." << endl;
31
32 if (last_bin_file > 0) {
33 cout << "will read " << last_bin_file - first_bin_file << " .bin files from file number "
34 << first_bin_file << " to file number " << last_bin_file << endl;
35 }
36 if (first_bin_file > 0) discard_original_eventnr = true;
37
38 ROOT::EnableImplicitMT();
39 TH1::AddDirectory(kFALSE);
40 // init counters
41 nwf = 0;
46 LastBinFileToRead = last_bin_file;
47 FirstBinFileToRead = first_bin_file;
48
49 root_out = new TFile(); // init results file
50}
51
71void ReadRun::ReadFile(string path, bool change_polarity, int change_sign_from_to_ch_num, string out_file_name, bool debug, long long max_nevents_to_read) {
72 if (max_nevents_to_read <= 0) max_nevents_to_read = static_cast<long long>(1e9);
73 rundata.reserve(1'000'000); // reserve space for 1M waveforms
74 if (path.back() != '/') path += '/';
75 data_path = path;
76
77 // save results to root file
78 if (out_file_name.empty()) out_file_name = "out.root";
79 printf("+++ saving analysis results in '%s' ...\n\n", out_file_name.c_str());
80 root_out = TFile::Open(out_file_name.c_str(), "recreate");
81
82 // invert channels
83 auto polarity_map = PolarityMap(change_polarity, change_sign_from_to_ch_num);
84
85 // verbosity
86 bool debug_header = debug;
87 bool debug_data = debug;
88
89 unsigned short output_channel;
90 unsigned int output_event;
91 unsigned short output_nbchannels;
92 unsigned short read_channels = 0;
93
94 //Start reading the raw data from .bin files.
95 stringstream inFileList;
96 inFileList << Helpers::ListFiles(path.c_str(), ".bin"); //all *.bin* files in folder path
97 if (debug) cout << inFileList.str() << endl;
98 string fileName;
99 int file_counter = 0;
100 int wfcounter = 0;
101 int event_counter = 0;
102
103 // file loop
104 while (inFileList >> fileName) {
105 // read only fraction/batch of the .bin files for testing or to reduce memory usage
106 if (FirstBinFileToRead > 0 && FirstBinFileToRead < LastBinFileToRead && file_counter < FirstBinFileToRead) continue;
107 if (LastBinFileToRead > 0 && file_counter > LastBinFileToRead) break;
108
109 fileName = path + fileName;
110 ifstream input_file(fileName.c_str(), ios::binary | ios::in);
111
112 bool has_measurement = false;
113
114 if (!input_file.is_open()) {
115 printf("*** failed to open '%s'\n", fileName.c_str());
116 continue;
117 }
118
119 if (file_counter < 10 || file_counter % 10 == 0 || debug) printf("+++ reading '%s' ...\n", fileName.c_str());
120
121 // Header
122 string header_line;
123 // HEADER 1 //
124 //
125 // "=== DATA FILE SAVED WITH SOFTWARE VERSION: V?.??.? ==="
126 //
127 getline(input_file, header_line, '\n');
128
129 if (debug_header) printf("%s\n", header_line.data());
130 assert(header_line[0] == '=');
131
132 size_t header_version_first = header_line.find_last_of('V');
133 size_t header_version_last = header_line.find_first_of(' ', header_version_first);
134 string software_version = header_line.substr(header_version_first, header_version_last - header_version_first);
135 if (debug_header) printf(" |- data version = '%s'\n", software_version.data());
136 // convert software version
137 software_version.erase(0, 1);
138 int v_major, v_minor, v_patch;
139 istringstream software_version_iss(software_version);
140 char dot_;
141 software_version_iss >> v_major >> dot_ >> v_minor >> dot_ >> v_patch;
142
143 // HEADER 2 //
144 // "=== WAVECATCHER SYSTEM OF TYPE ?? WITH ?? CHANNELS AND GAIN: ??? ==="
145 getline(input_file, header_line, '\n');
146
147 if (debug_header) printf("%s\n", header_line.data());
148 assert(header_line[0] == '=');
149
150 // HEADER 3 //
151 // === Rate coincidence masks ... === Posttrig in ns for SamBlock ... ===
152 getline(input_file, header_line, '\n');
153
154 if (debug_header) printf("%s\n", header_line.data());
155 assert(header_line[0] == '=');
156
157 // HEADER 4 //
158 // V2.9.13: === DATA SAMPLES [1024] in Volts == NB OF CHANNELS ACQUIRED: 64 == Sampling Period: 312.5 ps == INL Correction: 1
159 // V2.9.15: === DATA SAMPLES [1024] in Volts == NB OF CHANNELS ACQUIRED: 64 == Sampling Period: 312.5 ps == INL Correction: 1 == MEASUREMENTS: 0 ===
160 getline(input_file, header_line, '\n');
161
162 if (debug_header) printf("%s\n", header_line.data());
163 assert(header_line[0] == '=');
164
165 size_t nsamples_first = 1 + header_line.find_last_of('[');
166 size_t nsamples_last = header_line.find_first_of(']', nsamples_first);
167 string nsamples_str = header_line.substr(nsamples_first, nsamples_last - nsamples_first);
168
169 binNumber = atoi(nsamples_str.data());
170 if (debug_header) printf(" |- data sample = %d\n", binNumber);
171 if (file_counter == 0 && binNumber != 1024) {
172 cout << "\nWARNING: Measurement has " << binNumber << " samples, which is non-standard. Please report any bugs!" << endl;
173 cout << "If this was not intentional check the WaveCatcher settings!" << endl;
174 if (binNumber <= 0) {
175 cout << "Aborting execution." << endl;
176 exit(1);
177 }
178 }
179 size_t waveform_bytes = static_cast<size_t>(binNumber) * sizeof(short);
180 vector<short> waveform(binNumber);
181 vector<float> waveform_f(binNumber);
182
183 if (file_counter == 0) amplValuessum.resize(nChannelsWC, vector<float>(binNumber, 0.));
184
185 size_t nchannels_first = 10 + header_line.find("ACQUIRED: ", nsamples_first);
186 size_t nchannels_last = header_line.find_first_of(' ', nchannels_first);
187 string nchannels_str = header_line.substr(nchannels_first, nchannels_last - nchannels_first);
188
189 nchannels = atoi(nchannels_str.data());
190 if (debug_header) printf(" |- nchannels = %d\n", nchannels);
191
192 size_t sp_first = 8 + header_line.find("Period:");
193 size_t sp_last = header_line.find(" ps");
194 float sampling_period = atof(header_line.substr(sp_first, sp_last - sp_first).data());
195 if (debug_header) printf("sampling period = %f ps\n", sampling_period);
196 SP = sampling_period * 1e-3;
197 SP_inv = 1/SP;
198
199 // compatibility with older WC software versions
200 if (v_major ==2 && v_minor == 9 && v_patch <= 13) {
201 // V2.9.13 has always measurement stored (everything is set to 0 when disabled!)
202 has_measurement = true;
203 }
204 else {
205 size_t has_measurement_first = 14 + header_line.find("MEASUREMENTS: ", nsamples_first);
206 size_t has_measurement_last = header_line.find_first_of(' ', has_measurement_first);
207 string has_measurement_str = header_line.substr(has_measurement_first, has_measurement_last - has_measurement_first);
208 has_measurement = atoi(has_measurement_str.data());
209 }
210
211 if (debug_header) printf(" `- measurement = %d\n", has_measurement);
212
213 // end of header reader
214
215 event_data an_event;
216
217 while (input_file.read((char*)(&an_event), sizeof(an_event))) {
218 //event loop
219 if (debug_data) printf("%03d has %d channels\n", an_event.EventNumber, an_event.nchannelstored);
220
221 output_event = an_event.EventNumber;
222 output_nbchannels = an_event.nchannelstored;
223
224 if (debug_data && output_event % 200 == 0) printf("EventNr: %d, nCh: %d\n", output_event, output_nbchannels);
225 if (output_nbchannels > nChannelsWC) {
226 cout << "ERROR:\nThe number of channels in the data is " << output_nbchannels
227 << ", which is larger than the maximum allowed number of channels which is set to " << nChannelsWC
228 << "\nPlease set the parameter nChannelsWC=" << output_nbchannels << endl;
229 }
230
231 // do analysis only for limited range of channels to reduce memory usage for large datasets with many channels and many events
232 int start_at_ch = 0;
238
239 if (event_counter == 0) cout << "\nstart at ch " << start_at_ch << " end at ch " << end_at_ch << endl;
240
241 for (int ch = 0; ch < output_nbchannels; ++ch) { // channel loop
242 channel_data_with_measurement a_channel_data;
243 channel_data_without_measurement a_channel_data_without_measurement;
244
245 if (has_measurement) { // read with 'channel_data_with_measurement' struct
246 input_file.read((char*)(&a_channel_data), sizeof(channel_data_with_measurement));
247 }
248 else { // read with 'channel_data_without_measurement' struct
249 input_file.read((char*)(&a_channel_data_without_measurement), sizeof(channel_data_without_measurement));
250
251 // copy the content
253 a_channel_data.EventIDsamIndex = a_channel_data_without_measurement.EventIDsamIndex;
254 a_channel_data.FirstCellToPlotsamIndex = a_channel_data_without_measurement.FirstCellToPlotsamIndex;
255 }
256
258 if (debug_data) cout << "- reading channel " << output_channel << endl;
259
260 // read waveform
261 input_file.read((char*)waveform.data(), waveform_bytes);
262
263 //---------------------------------------------------------------------------------------------------------------
264 if (ch >= start_at_ch && ch <= end_at_ch) {
265 if (event_counter == 0) active_channels.push_back(static_cast<int>(output_channel));
266
267 float factor = DAQ_factor;
268 if (polarity_map[static_cast<int>(output_channel)]) factor = -factor;
269
270 // loop to fill waveform histograms
271 for (int i = 0; i < binNumber; i++) {
272 waveform_f[i] = static_cast<float>(waveform[i]) * factor;
273 amplValuessum[static_cast<int>(output_channel)][i] += waveform_f[i];
274 }
275 rundata.push_back(waveform_f);
276
277 // baseline correction
280 }
281
282 wfcounter++;
283 }//--------------------------------------------------------------------------------------------------------------
284
285 } // for ch
286
287 skip_event.push_back(false);
288 if (!discard_original_eventnr) eventnr_storage.push_back(output_event); // Stores the current WaveCatcher event number
289 else eventnr_storage.push_back(event_counter);
292 cout << "Stopped reading events after max_nevents_to_read=" << max_nevents_to_read << endl;
293 break;
294 }
295 } // while an_event
296
297 input_file.close();
298 file_counter++;
299 } // for file_id
300
301 // in case there are empty channels, nchannels is the number of channels which contain data
303
304 // get bins where the sum spectrum has its maximum for runs with fixed trigger delay and fixed
305 // integration window relative to the max of the sum spectrum (not working for DC measurement)
306 for (int ch = 0; ch < nChannelsWC; ch++) {
308 float max_val = -9.e99;
309 int i_max = 0;
310 for (int i = 0; i < binNumber; i++) {
311 if (amplValuessum[ch][i] > max_val) {
313 i_max = i;
314 }
315 }
316 maxSumBin.push_back(i_max);
317 }
318 }
319
321 nwf = wfcounter;
322
323 printf("Finished reading %d files containing %d events with %d channels.\n\n", file_counter, nevents, nchannels);
324}
325
328 // plot_active_channels.clear();
329 rundata.clear();
330 if (root_out->IsOpen()) root_out->Close();
331 cout << "\nAnalysis completed." << endl;
332}
333
347void ReadRun::PlotChannelSums(bool smooth, bool normalize, double shift, double sigma, int smooth_method) {
348
349 double* xv = getx<double>(shift);
350 auto mgsums = new TMultiGraph();
351 mgsums->SetTitle("channel sums; t [ns]; amplitude [mV]");
352 if (normalize) mgsums->SetTitle("channel sums; t [ns]; amplitude [arb.]");
353
354 double max_val = 0., min_val = 0.;
355 int color = 0;
356
357 for (int i = 0; i < nchannels; i++) {
358 if (PlotChannel(i)) {
359 color++;
360 double* yv = new double[binNumber];
362
364
365 TGraph* gr = new TGraph(binNumber, xv, yv);
366 delete[] yv;
367
368 double tmp_min = TMath::MinElement(gr->GetN(), gr->GetY());
370 double tmp_max = TMath::MaxElement(gr->GetN(), gr->GetY());
372 if (normalize) {
373 double i_tmp_max = (tmp_max != 0) ? 1. / tmp_max : 1.;
374 for (int j = 0; j < gr->GetN(); j++) gr->SetPointY(j, gr->GetPointY(j) * i_tmp_max);
375 }
376
377 TString name(Form("channel_%02d", active_channels[i]));
378 TString title(Form("Channel %d", active_channels[i]));
379 gr->SetName(name.Data());
380 gr->SetTitle(title.Data());
381 gr->SetLineColor(Helpers::rcolor(color));
382 gr->SetMarkerColor(Helpers::rcolor(color));
383 mgsums->Add(gr);
384 }
385 }
386 delete[] xv;
387
388 auto sumc = new TCanvas("Sums", "", 600, 400);
389 mgsums->Draw("AL");
390 if (normalize) mgsums->GetYaxis()->SetRangeUser(-0.2, 1);
391 else mgsums->GetYaxis()->SetRangeUser(min_val, max_val);
392 sumc->BuildLegend(0.85, 0.70, .99, .95);
393 sumc->SetGrid();
394 root_out->WriteObject(mgsums, "channelsums");
395 root_out->WriteObject(sumc, "channelsums_c");
396}
399
409void ReadRun::PlotChannelAverages(bool normalize) {
410 float* xv = getx<float>();
411
412 auto mgav = new TMultiGraph();
413 mgav->SetTitle("channel averages; t [ns]; amplitude [mV]");
414 if (normalize) mgav->SetTitle("channel averages; t[ns]; amplitude[arb.]");
415
416 float max_val = 0., min_val = 0.;
417 int color = 0;
418
419 for (int i = 0; i < nchannels; i++) {
420 if (PlotChannel(i)) {
421 color++;
422 float* yv = new float[binNumber]();
423
424 for (int j = 0; j < nevents; j++) {
425 if (!SkipEvent(j, i)) {
426 for (int k = 0; k < binNumber; k++) yv[k] += rundata[GetWaveformIndex(j, i)][k];
427 }
428 }
429
430 float norm = max(1.f, static_cast<float>(Nevents_good(i)));
431 for (int k = 0; k < binNumber; k++) yv[k] /= norm;
432
433 auto gr = new TGraph(binNumber, xv, yv);
434 delete[] yv;
435
436 double tmp_min = TMath::MinElement(gr->GetN(), gr->GetY());
438 double tmp_max = TMath::MaxElement(gr->GetN(), gr->GetY());
440 if (normalize) {
441 double i_tmp_max = (tmp_max != 0) ? 1. / tmp_max : 1.;
442 for (int j = 0; j < gr->GetN(); j++) gr->SetPointY(j, gr->GetPointY(j) * i_tmp_max);
443 }
444
445 TString name(Form("channel_%02d", active_channels[i]));
446 TString title(Form("Channel %d", active_channels[i]));
447 gr->SetName(name.Data());
448 gr->SetTitle(title.Data());
449 gr->SetLineColor(Helpers::rcolor(color));
450 gr->SetMarkerColor(Helpers::rcolor(color));
451 mgav->Add(gr);
452 }
453 }
454 delete[] xv;
455
456 string cname("Averages_" + to_string(PlotChannelAverages_cnt++));
457 auto avc = new TCanvas(cname.c_str(), cname.c_str(), 600, 400);
458 mgav->Draw("AL");
459 if (normalize) mgav->GetYaxis()->SetRangeUser(-0.2, 1);
460 else mgav->GetYaxis()->SetRangeUser(min_val, max_val);
461 avc->BuildLegend(0.85, 0.70, .99, .95);
462 avc->SetGrid();
463 root_out->WriteObject(mgav, ("channelaverages" + to_string(PlotChannelAverages_cnt)).c_str());
464 root_out->WriteObject(avc, ("channelaverages_c" + to_string(PlotChannelAverages_cnt)).c_str());
465}
469
470
480TH2F* ReadRun::WFHeatmapChannel(int channel_index, float ymin, float ymax, int n_bins_y) {
481
482 TString name(Form("channel__%02d", active_channels[channel_index]));
483 TH2F* h2 = new TH2F(name.Data(), name.Data(), binNumber, 0, SP * static_cast<float>(binNumber), n_bins_y, ymin, ymax);
484 h2->GetXaxis()->SetTitle("t [ns]");
485 h2->GetYaxis()->SetTitle("I [arb.]");
486 h2->GetZaxis()->SetTitle("entries");
487
488 auto xv = getx<float>();
489 // create temporary histo per thread
492 for (int t = 0; t < n_threads; ++t) {
493 h2_thread[t] = new TH2F("", "", binNumber, 0, SP * static_cast<float>(binNumber), n_bins_y, ymin, ymax);
494 }
495
496 #pragma omp parallel
497 {
498 int t_id = omp_get_thread_num();
500
501 #pragma omp for
502 for (int j = 0; j < nevents; ++j) {
503 if (!SkipEvent(j, channel_index)) {
505 for (int i = 0; i < binNumber; ++i) {
506 hlocal->Fill(xv[i], rundata[wf_index][i]);
507 }
508 }
509 }
510 }
511
512 //merge
513 for (int t = 0; t < n_threads; ++t) {
514 h2->Add(h2_thread[t]);
515 delete h2_thread[t];
516 }
517
518 delete[] xv;
519 return h2;
520}
521
537void ReadRun::PlotWFHeatmaps(float ymin, float ymax, int n_bins_y, string z_opt, float z_max, EColorPalette palette) {
538
539 gStyle->SetOptStat(0);
540 string name("waveforms_heatmap_" + to_string(PlotWFHeatmaps_cnt++));
541 auto wfhm_c = new TCanvas(name.c_str(), name.c_str(), 600, 400);
543
544 // create histograms in parallel
546 for (int i = 0; i < nchannels; ++i) {
547 if (PlotChannel(i)) {
548 h2_future[i] = async(launch::async, [this, i, ymin, ymax, n_bins_y]() {
550 });
551 }
552 }
553
554 // plot histograms
555 int current_canvas = 0;
556 for (int i = 0; i < nchannels; ++i) {
557 if (PlotChannel(i)) {
558 wfhm_c->cd(++current_canvas);
559
560 gPad->SetTopMargin(.1);
561 gPad->SetBottomMargin(.1);
562 gPad->SetLeftMargin(.15);
563 gPad->SetRightMargin(.15);
564 gStyle->SetPalette(palette);
565
566 auto h2 = h2_future[i].get();
567
568 h2->SetContour(99);
569 h2->SetStats(0);
570 if (z_opt == "COLZ0") h2->Draw("COLZ0");
571 else h2->Draw("CONT4Z");
572
573 if (z_opt == "log") {
574 gPad->SetLogz();
575 if (z_max > 1) h2->GetZaxis()->SetRangeUser(1, z_max);
576 }
577 else if (z_max > 0) h2->GetZaxis()->SetRangeUser(0, z_max);
578 }
579 }
580
581 wfhm_c->Update();
582 root_out->WriteObject(wfhm_c, name.c_str());
583}
585
593void ReadRun::SmoothAll(double sigma, int method) {
594 cout << "Smoothing all non-skipped waveforms..." << endl;
595
596 #pragma omp parallel for
597 for (int j = 0; j < nwf; j++) {
600 double* tmp_wf = tmp_.data();
601
604 }
605 }
606}
607
615void ReadRun::SmoothAll(double sigma, string method) {
616 cout << "\nSmoothing all non-skipped waveforms:" << endl;
617
618 #pragma omp parallel for
619 for (int j = 0; j < nwf; j++) {
622 double* tmp_wf = tmp_.data();
623
626 }
627 }
628}
629
637void ReadRun::FilterAll(double sigma1, double sigma2, double factor) {
638 cout << "\nFiltering all waveforms..." << endl;
639
640 #pragma omp parallel for
641 for (int j = 0; j < nwf; j++) {
643 double* tmp_wf = tmp_.data();
644
648 }
649}
650
658 cout << "\nShifting all waveforms to the average constant fraction time for each channel:" << endl;
659
660 //call GetTimingCFD() in case it was not initialized
661 if (static_cast<int>(timing_results.size()) == 0) GetTimingCFD();
662
663 double* timing_mean = new double[nchannels]();
664
665 for (int j = 0; j < nwf; j++) {
668 }
669
670 int* timing_mean_n = new int[nchannels];
671 for (int i = 0; i < nchannels; i++) {
672 double i_norm = 1. / max(1., static_cast<double>(Nevents_good(i)));
673 timing_mean_n[i] = static_cast<int>(round(timing_mean[i] * i_norm));
674 }
675 delete[] timing_mean;
676
677 #pragma omp parallel for
678 for (int j = 0; j < nwf; j++) {
681 int shift = static_cast<int>(timing_results[j][0]) - timing_mean_n[curr_ch];
683 if (shift < 0) shift += binNumber;
685 }
686 }
687 delete[] timing_mean_n;
688}
689
705void ReadRun::CorrectBaseline(float tCut, float tCutEnd) {
706 checkData(true);
707
708 cout << "\nPerforming simple baseline correction in fixed time window."
709 << "This method is only suitable for measurements without dark counts!" << endl;
710 tCutg = tCut;
712 if (nwf == 0) {
714 }
715 else {
716 cout << "Baseline correction (" << nwf << " waveforms):" << endl;
718
719 #pragma omp parallel for
720 for (int j = 0; j < nwf; j++) {
722 }
723 }
724}
725
730void ReadRun::CorrectBaseline_function(vector<float>& waveform, float tCut, float tCutEnd, int waveform_index) {
731 int iCut, iCutEnd;
732 float corr = 0;
733
735
736 if (tCutEnd <= 0) { //
737 for (int i=0; i<=iCut; i++) corr += waveform[i];
738 corr /= static_cast<float>(iCut);
739 }
740 else {
742 for (int i=iCut; i<=iCutEnd; i++) corr += waveform[i];
743 corr /= static_cast<float>(iCutEnd - iCut + 1);
744 }
745
746 // write corrected values to histograms
747 if (tCut >= 0) {
748 for (int i = 0; i < binNumber; i++) waveform[i] -= corr;
749 }
750
756 }
757}
758
784void ReadRun::CorrectBaselineMinSlopeRMS(vector<float> window, double sigma, int smooth_method) {
785 checkData(true);
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
791 int nbins_average = !window.empty() ? TimeToIndex(window[0]) : TimeToIndex(50.);
792 int start_search_at = static_cast<int>(window.size()) > 1 ? TimeToIndex(window[1]) : 0;
793 int end_search_at = static_cast<int>(window.size()) > 2 ? TimeToIndex(window[2]) : binNumber - 1;
794
796
797 // if no valid static search window is specified, it will be dynamic from 0 ns up to 8 ns before the global maximum
798 bool search_relative_to_local_max = false;
800 if (start_search_at < 0) {
802 start_search_at = 0;
803 cout << "\nNotification: Using dynamic search window in CorrectBaselineMinSlopeRMS." << endl;
804 }
805
807
809
810 #pragma omp parallel for
811 for (int j = 0; j < nwf; j++) {
812 float minchange = 1.e99;
813 float sum = 0, sumsum = 0, change = 0, minsumsq = 0, sqsum = 0, minsqsum = 0, corr = 0;
814 int iintwindowstart = 0, imax = 0;
818
822 nbins_search_ = end_search_at_; // starts at 0
824 }
825
827 // smoothing suppresses variations in slope due to noise, so the method is potentially more sensitive to excluding peaks
829 //calculate slope
831 double* slope = new double[nbins_search_];
832 double* slope_sq = new double[nbins_search_];
833 for (int i = 0; i < nbins_search_; i++) {
834 slope[i] = yvals[i + 1] - yvals[i];
835 slope_sq[i] = slope[i] * slope[i];
836 if (i < nbins_average) { // init
837 sum += slope[i];
838 sqsum += slope_sq[i];
839 }
840 }
841 delete[] yvals;
842
843 //find window for correction
844 for (int i = 0; i < end_search_loop_at_; i++) {
845 sumsum = sum * sum;
846 change = sqsum + sumsum;
847
848 if (change < minchange) {
852 minsqsum = sqsum;
853 }
854
855 sum -= slope[i];
856 sum += slope[i + nbins_average];
857 sqsum -= slope_sq[i];
859 }
860 delete[] slope;
861 delete[] slope_sq;
862
863 // do correction
865 corr /= static_cast<float>(nbins_average + 1);
866 for (int i = 0; i < binNumber; i++) rundata[j][i] -= corr;
867
874 }
875}
878
911void ReadRun::CorrectBaselineMinSlopeRMS(int nIntegrationWindow, bool smooth, double sigma, int max_bin_for_baseline, int start_at, int smooth_method) {
912 cout << "WARNING: This is a deprecated version of CorrectBaselineMinSlopeRMS. "
913 << "It will be removed in future releases. Parameter bool smooth=" << smooth << " will be ignored." << endl;
916 window.push_back(IndexToTime(start_at));
919}
922
928void ReadRun::CorrectBaselineMinSlopeRMS(vector<float> window, double sigma, int smooth_method, int increment) {
930 cout << "WARNING: This is a deprecated version of CorrectBaselineMinSlopeRMS. "
931 << "It will be removed in future releases. Parameter increment=" << increment << " will be ignored." << endl;
933}
934
956void ReadRun::CorrectBaselineMin(vector<float> window, double sigma, int smooth_method) {
957 checkData(true);
958
959 cout << "\nBaseline correction (minimal sum method, " << nwf << " waveforms):" << endl;
960 if (window.empty()) cout << "\nWarning: Window not set in CorrectBaselineMin. Will use default values." << endl;
961 if (sigma != 0.) cout << "\nNotification: Using smoothing in CorrectBaselineMin." << endl;
962
963 int nbins_average = !window.empty() ? TimeToIndex(window[0]) : TimeToIndex(10.);
964 int start_search_at = static_cast<int>(window.size()) > 1 ? TimeToIndex(window[1]) : 0;
965 int end_search_at = static_cast<int>(window.size()) > 2 ? TimeToIndex(window[2]) : binNumber - 1;
966
968
969 // if no valid static search window is specified, it will be dynamic from 0 ns up to 8 ns before the global maximum
970 bool search_relative_to_local_max = false;
972 if (start_search_at < 0 || end_search_loop_at < 0) {
974 start_search_at = 0;
975 cout << "\nNotification: Using dynamic search window in CorrectBaselineMin." << endl;
976 }
977
979
981
982 #pragma omp parallel for
983 for (int j = 0; j < nwf; j++) {
984 float minchange = 1e9;
985 float sum = 0, corr = 0;
986 int iintwindowstart = 0, imax = 0;
990
996 }
997
999 // smoothing suppresses variations in slope due to noise, so the method is potentially more sensitive to excluding peaks
1001 //find window for correction
1002 for (int i = 0; i < nbins_average; i++) sum += yvals[i]; // init
1003 for (int i = 0; i < end_search_loop_at_; i++) {
1004 if (sum < minchange) {
1005 minchange = sum;
1007 }
1008
1009 sum -= yvals[i];
1010 sum += yvals[i + nbins_average];
1011 }
1012 delete[] yvals;
1013
1014 // do correction
1016 corr /= static_cast<float>(nbins_average + 1);
1017 for (int i = 0; i < binNumber; i++) rundata[j][i] -= corr;
1018
1023 }
1024}
1025
1051void ReadRun::CorrectBaselineMin(int nIntegrationWindow, double sigma, int max_bin_for_baseline, int start_at, int smooth_method) {
1052 cout << "WARNING: This is a deprecated version of CorrectBaselineMin. It will be removed in future releases." << endl;
1055 window.push_back(IndexToTime(start_at));
1058}
1060
1066void ReadRun::CorrectBaselineMin(vector<float> window, double sigma, int smooth_method, int increment) {
1067 (void)increment;
1068 cout << "WARNING: This is a deprecated version of CorrectBaselineMin. It will be removed in future releases." << endl;
1070}
1071
1077TH1F* ReadRun::WFProjectionChannel(int channel_index, int from_n, int to_n, float rangestart, float rangeend, int nbins) {
1080
1081 TString name(Form("channel__%02d", active_channels[channel_index]));
1082 auto h1 = new TH1F(name.Data(), name.Data(), nbins, rangestart, rangeend);
1083
1084 for (int j = 0; j < nevents; j++) {
1085 if (!SkipEvent(j, channel_index)) {
1086 for (int i = from_n; i <= to_n; i++) h1->Fill(rundata[GetWaveformIndex(j, channel_index)][i]);
1087 }
1088 }
1089 return h1;
1090}
1091
1105void ReadRun::PrintWFProjection(float from, float to, float rangestart, float rangeend, int nbins) {
1106 gStyle->SetOptFit(111);
1107 float default_rangestart = -10;
1108 float default_rangeend = 20;
1111 int default_nbins = static_cast<int>((default_rangeend - default_rangestart) * nbins / (rangeend - rangestart));
1112
1113 string ctitle("WFProjection" + to_string(PrintWFProjection_cnt++));
1114 auto wf_projection_c = new TCanvas(ctitle.c_str(), ctitle.c_str(), 600, 400);
1116 int current_canvas = 0;
1117
1118 int from_n = TimeToIndex(from);
1119 int to_n = TimeToIndex(to);
1120
1121 for (int i = 0; i < nchannels; i++) {
1122 if (PlotChannel(i)) {
1124
1126 his->GetYaxis()->SetTitle("#Entries");
1127 his->GetXaxis()->SetTitle("amplitude in mV");
1128 TString name(Form("WFProjection channel_%02d_%d", active_channels[i], PrintWFProjection_cnt));
1129 his->Draw();
1130 his->Fit("gaus", "M", "same");
1131 root_out->WriteObject(his, name.Data());
1132 }
1133 }
1134
1136 root_out->WriteObject(wf_projection_c, ("WFProjections" + to_string(PrintWFProjection_cnt)).c_str());
1137}
1138
1144TH1F* ReadRun::BaselineCorrectionResults(int channel_index, int which, float rangestart, float rangeend, int nbins) {
1145 if (baseline_correction_result.empty() || static_cast<int>(baseline_correction_result[0].size()) < which - 1) {
1146 cout << "\nError: baseline_correction_result empty. Call baseline correction first." << endl;
1147 }
1148 TString name(Form("channel__%02d", active_channels[channel_index]));
1149 auto h1 = new TH1F(name.Data(), name.Data(), nbins, rangestart, rangeend);
1150
1151 float average_baseline = 0.;
1152 int counter = 0;
1153 for (int j = 0; j < nevents; j++) {
1154 if (!SkipEvent(j, channel_index)) {
1157 counter++;
1158 h1->Fill(current_baseline);
1159 }
1160 }
1161 cout << "Mean baseline ch" << active_channels[channel_index] << ": " << average_baseline / max(1.f, static_cast<float>(counter)) << endl;
1162 return h1;
1163}
1164
1172void ReadRun::PrintBaselineCorrectionResults(float rangestart, float rangeend, int nbins) {
1173 checkData();
1174 gStyle->SetOptFit(111);
1175 float default_rangestart = -10;
1176 float default_rangeend = 20;
1179 int default_nbins = static_cast<int>((default_rangeend - default_rangestart) * nbins / (rangeend - rangestart));
1180
1181 string ctitle;
1182 ctitle = "Correction values in mV";
1183 auto blc_res_c = new TCanvas(ctitle.c_str(), ctitle.c_str(), 600, 400);
1185 int current_canvas = 0;
1186
1187 for (int i = 0; i < nchannels; i++) {
1188 if (PlotChannel(i)) {
1190
1192 his->GetYaxis()->SetTitle("#Entries");
1193 his->GetXaxis()->SetTitle(ctitle.c_str());
1194 his->Draw();
1195 his->Fit("gaus", "WWM", "same");
1196 }
1197 }
1199 root_out->WriteObject(blc_res_c, ctitle.c_str());
1200}
1201
1224void 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, bool verbose) {
1225
1228 int n_range = end_at - start_at;
1229
1230 if (cf_r <= 0) cf_r = 1;
1231 cout << "\nGet timing at " << (cf_r > 0 && cf_r <= 1 ? "CF=" : "threshold=");
1232 printf("%.2f between %.2f ns and %.2f ns (%d waveforms):\n", cf_r, start_at_t, end_at_t, nwf);
1233
1234 timing_results.resize(nwf, vector<float>(8));
1235
1236 double* xvals = new double[n_range]; // x values for spline interpolation
1238
1239 #pragma omp parallel for
1240 for (int j = 0; j < nwf; j++) {
1241 double* yvals = Helpers::gety(rundata[j], start_at, end_at); // get range where to search for CFD for timing
1242
1243 // smoothing to suppress noise, will also change timing so use with care!
1245
1246 double* max_ptr = max_element(yvals, yvals + n_range);
1247 float max_val = *max_ptr;
1248 int n_max = static_cast<int>(max_ptr - yvals);
1249
1250 float cf = (cf_r <= 1) ? cf_r * max_val : cf_r;
1251
1252 int i = 0;
1253 if (!find_CF_from_start) {
1254 i = n_max;
1255 while (i > 0 && yvals[i] > cf) i--;
1256 }
1257 else {
1258 i = 0;
1259 while (i < n_max && yvals[i] < cf) i++;
1260 i--;
1261 }
1262
1263 float interpol_bin = 0.;
1265 if (i==0) {
1266 if (verbose) cout << "WARNING: CFD failed for Ch" << GetCurrentChannel(j) << ", event " << GetCurrentEvent(j) << endl;
1267 }
1268 else {
1269 // do interpolation for cf
1270 lin_interpol_res = LinearInterpolation(cf, static_cast<float>(i), static_cast<float>(i + 1), yvals[i], yvals[i + 1]);
1271 // go to center of bin
1272 interpol_bin = lin_interpol_res.first + .5;
1273
1274 if (use_spline) { // use spline interpolation with tolerance epsilon*bin_size
1275 double epsilon = 1e-4;
1276 double x_low = interpol_bin - .5;
1277 double x_high = interpol_bin + .5;
1278
1279 TSpline5* wfspl = 0;
1280 wfspl = new TSpline5("wf_spline", xvals, yvals, n_range, "b1e1b2e2", 0., 0., 0., 0.);
1281
1282 // using bisection method: halving search window until cf is less than epsilon bins from spline value
1283 while (x_high - x_low > epsilon) {
1284 double x_mid = (x_low + x_high) * 0.5;
1285 double f_mid = wfspl->Eval(x_mid);
1286 if (f_mid == cf) break;
1287
1288 if (f_mid > cf) x_high = x_mid;
1289 else x_low = x_mid;
1290 }
1291 interpol_bin = (x_low + x_high) * 0.5;
1292 delete wfspl;
1293 }
1294 }
1295 timing_results[j][0] = interpol_bin; // the bin we looked for
1296 timing_results[j][1] = (interpol_bin + static_cast<float>(start_at)) * SP; // cfd-time we looked for
1297 timing_results[j][2] = max_val; // maximum value
1298 timing_results[j][3] = n_max; // bin of maximum
1299 timing_results[j][4] = cf; // constant fraction
1300 timing_results[j][5] = IndexToTime(start_at); // starting time
1301 timing_results[j][6] = IndexToTime(end_at); // end time
1302 timing_results[j][7] = static_cast<float>(lin_interpol_res.second); // flag will be 1 if linear interpolation worked
1303 delete[] yvals;
1304 }
1305 delete[] xvals;
1306}
1308
1321void ReadRun::SkipEventsTimeDiffCut(int first_channel_abs, int second_channel_abs, double time_diff_min, double time_diff_max, bool verbose) {
1322
1323 cout << "\n Removing events if the event-wise time difference between the main peaks in ch"
1324 << first_channel_abs << " and ch" << second_channel_abs << " is <" << setprecision(2)
1325 << time_diff_min << " ns or >" << time_diff_max << " ns" << endl;
1326
1327 int counter = 0;
1330
1331 // call GetTimingCFD() in case it was not initialized
1332 if (static_cast<int>(timing_results.size()) == 0) GetTimingCFD();
1333
1334 // loop through events, calculate timing difference between channels and compare with cuts
1335 #pragma omp parallel for reduction(+:counter)
1336 for (int j = 0; j < nevents; j++) {
1340 if (max(ind_first, ind_second) >= static_cast<int>(timing_results.size())) continue;
1341
1343
1346 if (verbose) cout << "\nevent:\t" << currevent << "\tchannels:\t" << first_channel_abs << " & " << second_channel_abs << "\ttime diff:\t" << time_diff;
1347 skip_event[j] = true;
1348 counter++;
1349 }
1350 }
1351 }
1352 cout << "\t" << counter << " events will be cut out of " << nevents << endl;
1353}
1355
1356
1367void ReadRun::SkipEventsPerChannel(vector<float> thresholds, float rangestart, float rangeend, bool verbose) { // merge with IntegralFilter()?
1368
1369 if (thresholds.empty()) cout << "\nError: thresholds is empty";
1370 while (thresholds.size() <= active_channels.size()) thresholds.push_back(thresholds[0]);
1371
1372 cout << "\n Removing events with individual amplitude threshold per channel:" << endl;
1373 int counter = 0;
1374 int n_thrshld = static_cast<int>(thresholds.size());
1375
1378
1379 #pragma omp parallel for reduction(+:counter)
1380 for (int j = 0; j < nwf; j++) {
1384 if (current_channel < n_thrshld) {
1386 if (current_threshold == 0.) continue;
1387
1390
1391 float max_val = (max_it != rundata[j].end()) ? *max_it : 0.;
1392 float min_val = (min_it != rundata[j].end()) ? *min_it : 0.;
1393
1394
1397
1399 if (verbose) cout << "\nevent:\t" << currevent << "\tchannel:\t" << active_channels[current_channel] << "\tthreshold\t" << current_threshold;
1400 skip_event[current_event] = true;
1401 counter++;
1402 }
1403 }
1404 }
1405 }
1406
1407 cout << "\t" << counter << " events will be cut out of " << nevents << endl;
1408}
1409
1427void ReadRun::IntegralFilter(vector<float> thresholds, vector<bool> g_thr, float windowlow, float windowhi, float start, float end, bool use_AND_condition , bool verbose) {
1428
1429 if (thresholds.empty() || g_thr.empty()) cout << "\nERROR: thresholds or g_thr are empty in ReadRun::IntegralFilter().";
1430 while (thresholds.size() <= active_channels.size()) { thresholds.push_back(thresholds[0]); }
1431 while (g_thr.size() <= active_channels.size()) { g_thr.push_back(g_thr[0]); }
1432
1433 cout << "\n\nRemoving events with individual integral threshold per channel:" << endl;
1434 int counter = 0;
1435 int n_thresholds = static_cast<int>(thresholds.size());
1436
1437 #pragma omp parallel for reduction(+:counter)
1438 for (int j = 0; j < nwf; j++) {
1440 if (currevent_counter < 0) continue;
1441
1444 if (current_channel >= n_thresholds) continue;
1445
1447 if (current_threshold == 0.) continue;
1448
1450
1452 // skip if above/below thresholds
1455 if (verbose) cout << "Event:\t" << currevent << "\tchannel:\t" << active_channels[current_channel] << "\tthreshold\t" << thresholds[current_channel] << "\tintegral:\t" << integral << endl;
1457 // go to last wf of current event
1458 while (GetCurrentEvent(++j) == currevent_counter);
1459 j--;
1460 counter++;
1461 }
1462 }
1463 else if (use_AND_condition) { // don't skip if not
1465 if (verbose) cout << "Event:\t" << currevent << "\tchannel:\t" << active_channels[current_channel] << "\thas been flagged good by integral:\t" << integral << endl;
1466 counter--;
1467 }
1468 }
1469 }
1470 cout << counter << " additional events will be cut out of " << nevents << " (" << static_cast<float>(100*counter/nevents) << "%)" << endl;
1471}
1475
1478 int counter = 0;
1480 for (int j = 0; j < static_cast<int>(skip_event.size()); j++) {
1481 if (skip_event[j]) {
1483 buffer << "Event:\t" << currevent << endl;
1484 counter++;
1485 }
1486 }
1487 cout << buffer.str().c_str();
1488 cout << "Total number of skipped events:\t" << counter << "\tout of:\t" << nevents << endl;
1489}
1490
1493 const int skip_event_size = static_cast<int>(skip_event.size());
1494 for (int j = 0; j < skip_event_size; j++) skip_event[j] = false;
1495 cout << "\n\nAll event cuts were removed" << endl;
1496}
1497
1501bool ReadRun::SkipEvent(int event_index, int channel_index) {
1502 (void)channel_index; // avoid unused parameter warning
1503 if (event_index >= static_cast<int>(skip_event.size()) || event_index < 0) return true;
1504 else return skip_event[event_index];
1505}
1506
1509int ReadRun::Nevents_good(int channel_index) {
1510 int nevents_good = 0;
1511 for (int i = 0; i < nevents; i++) if (!SkipEvent(i, channel_index)) nevents_good++;
1512 return nevents_good;
1513}
1514
1515// functions for charge spectrum
1516
1533array<int, 3> ReadRun::GetIntWindow(TH1F* his, float windowlow, float windowhi, float start, float end, int channel) {
1534
1535 int istart, iend;
1536 array<int, 3> foundindices = {0, 0, 0};
1537
1538 if (start < 0 || end < 0) { // fixed integration window relative to maximum of sum spectrum for each channel
1539 foundindices[1] = his->GetXaxis()->FindBin(his->GetXaxis()->GetBinCenter(maxSumBin[channel]) - windowlow);
1540 foundindices[2] = his->GetXaxis()->FindBin(his->GetXaxis()->GetBinCenter(maxSumBin[channel]) + windowhi);
1541 }
1542 else if (windowlow == start && windowhi == end) { // fixed integration window for all channels
1543 foundindices[1] = his->GetXaxis()->FindBin(windowlow);
1544 foundindices[2] = his->GetXaxis()->FindBin(windowhi);
1545 }
1546 else { // fixed integration window relative to maximum of each individual waveform
1547 istart = his->GetXaxis()->FindBin(start);
1548 iend = his->GetXaxis()->FindBin(end);
1549 foundindices[0] = istart;
1550
1551 if (istart < 1 || iend > his->GetNbinsX()) {
1552 cout << "\nError: Start=" << istart << " or end=" << iend << " of GetIntWindow() out of range. Fix integration window." << endl;
1553 }
1554
1555 float max_val = -9.e99;
1556 float curr_val = 0;
1557 for (int i = istart; i < iend; i++) {
1558 curr_val = his->GetBinContent(i);
1559 if (curr_val > max_val) {
1560 max_val = curr_val;
1561 foundindices[0] = i;
1562 }
1563 }
1564
1565 foundindices[1] = his->GetXaxis()->FindBin(his->GetXaxis()->GetBinCenter(foundindices[0]) - windowlow);
1566 foundindices[2] = his->GetXaxis()->FindBin(his->GetXaxis()->GetBinCenter(foundindices[0]) + windowhi);
1567 }
1568 return foundindices;
1569}
1570
1587array<int, 3> ReadRun::GetIntWindow(const vector<float>& waveform, float windowlow, float windowhi, float start, float end, int channel) {
1588
1589 array<int, 3> foundindices = {0, 0, 0};
1590
1591 if (start < 0 || end < 0) { // fixed integration window relative to maximum of sum spectrum for each channel
1593 foundindices[2] = maxSumBin[channel] + TimeToIndex(windowhi);
1594 }
1595 else if (windowlow == start && windowhi == end) { // fixed integration window for all channels
1598 }
1599 else { // fixed integration window relative to maximum of each individual waveform
1600 int istart = TimeToIndex(start);
1601 int iend = TimeToIndex(end);
1602 foundindices[0] = istart;
1603
1604 auto max_it = max_element(waveform.begin() + istart, waveform.begin() + iend);
1605 foundindices[0] = static_cast<int>(distance(waveform.begin(), max_it));
1606
1607 float t_max = IndexToTime(foundindices[0]) + SP * 0.5; // time at center of maximum bin
1610 }
1611 return foundindices;
1612}
1613
1623array<int, 3> ReadRun::GetIntWindow(const vector<float>& waveform, int windowlow, int windowhi, int start, int end, int channel) {
1624
1625 array<int, 3> foundindices = {0, 0, 0};
1626
1627 if (start < 0 || end < 0) { // fixed integration window relative to maximum of sum spectrum for each channel
1628 foundindices[1] = maxSumBin[channel] - windowlow;
1629 foundindices[2] = maxSumBin[channel] + windowhi;
1630 }
1631 else if (windowlow == start && windowhi == end) { // fixed integration window for all channels
1634 }
1635 else { // fixed integration window relative to maximum of each individual waveform
1636 int istart = CheckBoundsX(start);
1637 int iend = CheckBoundsX(end);
1638 foundindices[0] = istart;
1639
1640 auto max_it = max_element(waveform.begin() + istart, waveform.begin() + iend);
1641 foundindices[0] = static_cast<int>(distance(waveform.begin(), max_it));
1642
1645 }
1646 return foundindices;
1647}
1648
1664float ReadRun::GetPeakIntegral(TH1F* his, float windowlow, float windowhi, float start, float end, int channel_index) {
1665 auto windowind = GetIntWindow(his, windowlow, windowhi, start, end, channel_index); // find integration window
1666 string integral_option(""); // For amplitude -> unit[mV].
1667 if (windowind[1] != windowind[2]) integral_option = "width"; // 'width' (bin width) for integral -> unit[mV x ns].
1668 float integral = his->Integral(windowind[1], windowind[2], integral_option.c_str());
1669 return integral;
1670}
1671
1687float ReadRun::GetPeakIntegral(const vector<float>& waveform, float windowlow, float windowhi, float start, float end, int channel_index) {
1688 auto windowind = GetIntWindow(waveform, windowlow, windowhi, start, end, channel_index); // find integration window
1689 float integral = 0;
1690 for (int i = windowind[1]; i <= windowind[2]; ++i) integral += waveform[i]; // sum -> unit[mV].
1691 if (windowind[1] != windowind[2]) integral *= SP; // integral -> unit[mV x ns].
1692 return integral;
1693}
1694
1711void ReadRun::PrintChargeSpectrumWF(float windowlow, float windowhi, float start, float end, int eventnr, float ymin, float ymax, float xmin, float xmax) {
1712
1713 gStyle->SetOptStat(0);
1714 TString name(Form("waveforms_event__%05d", eventnr));
1715 auto intwinc = new TCanvas(name.Data(), name.Data(), 600, 400);
1718
1719 int current_canvas = 0;
1720 for (int i = 0; i < nchannels; i++) {
1721 if (PlotChannel(i)) {
1722 intwinc->cd(++current_canvas);
1723
1724 auto his = Getwf(i, event_index);
1726
1727 // drawing and formatting
1728 gPad->SetTopMargin(.01);
1729 int last_canvas = nchannels;
1730 if (!plot_active_channels.empty()) last_canvas = static_cast<int>(plot_active_channels.size());
1731 if (current_canvas == 1 && last_canvas < 4) gPad->SetLeftMargin(.15);
1732 if (current_canvas % 4 == 0 || current_canvas == last_canvas) gPad->SetRightMargin(.01);
1733 his->Draw("HIST");
1734 his->SetStats(0);
1735
1736 if (wf_index != -1) {
1737 // create lines to indicate the integration window
1739 TLine* low = new TLine(his->GetXaxis()->GetBinCenter(windowind[1]), -5, his->GetXaxis()->GetBinCenter(windowind[1]), 10);
1740 low->SetLineColor(2);
1741 TLine* hi = new TLine(his->GetXaxis()->GetBinCenter(windowind[2]), -2, his->GetXaxis()->GetBinCenter(windowind[2]), 3);
1742 hi->SetLineColor(2);
1743 TLine* zero = new TLine(0, 0, 320, 0); // draw line at x=0 to check if baseline correction worked
1744 zero->SetLineColor(1);
1745
1746 low->Draw("same");
1747 hi->Draw("same");
1748 zero->Draw("same");
1749
1750 // draw baseline and CFD parameters
1751 if (wf_index < static_cast<int>(baseline_correction_result.size())) {
1753 baselinel->SetLineColor(6);
1754 baselinel->SetLineWidth(2);
1756 baselineh->SetLineColor(6);
1757 baselineh->SetLineWidth(2);
1759 baseline->SetLineColor(6);
1761 correction_value->SetLineColor(2);
1762
1763 baselinel->Draw("same");
1764 baselineh->Draw("same");
1765 baseline->Draw("same");
1766 correction_value->Draw("same");
1767 }
1768
1769 if (wf_index < static_cast<int>(timing_results.size())) {
1770 TLine* timing = new TLine(timing_results[wf_index][1], -10, timing_results[wf_index][1], 100);
1771 timing->SetLineColor(9);
1772 timing->SetLineWidth(2);
1773 timing->Draw("same");
1774 }
1775 }
1776
1777 if (ymin != 0. && ymax != 0.) his->GetYaxis()->SetRangeUser(ymin, ymax); // fix y range for better comparison
1778 if (xmin != 0. && xmax != 0.) his->GetXaxis()->SetRangeUser(xmin, xmax);
1779 }
1780 }
1781 intwinc->Update();
1782
1783 root_out->WriteObject(intwinc, name.Data());
1784}
1786
1797float* ReadRun::ChargeList(int channel_index, float windowlow, float windowhi, float start, float end, bool negative_vals) {
1798 float* charge_list = new float[nevents]();
1799
1800 #pragma omp parallel for
1801 for (int j = 0; j < nevents; j++) {
1803 if (wf_index == -1) {
1804 charge_list[j] = -999.;
1805 continue;
1806 }
1807
1809 if (!negative_vals && charge_list[j] < 0.) charge_list[j] = 0.;
1810 }
1811 return charge_list;
1812}
1813
1824void ReadRun::SaveChargeLists(float windowlow, float windowhi, float start, float end, bool negative_vals) {
1825 float* event_list = new float[nevents];
1827
1828 auto charge_list_mg = new TMultiGraph();
1829 if (windowlow + windowhi > 0.) charge_list_mg->SetTitle("event-wise integrals; Event number; integral [mV#timesns]");
1830 else charge_list_mg->SetTitle("event-wise amplitudes; Event number; amplitude [mV]");
1831 int color = 0;
1832
1833 for (int i = 0; i < nchannels; i++) {
1834 if (PlotChannel(i)) {
1835 color++;
1836 TString name(Form("charge_list_ch_%02d", active_channels[i]));
1839 charge_list_graph->SetLineWidth(0);
1840 charge_list_graph->SetMarkerStyle(2);
1841 charge_list_graph->SetMarkerColor(Helpers::rcolor(color));
1842 charge_list_graph->SetTitle(name.Data());
1843
1844 //remove skipped events
1845 for (int j = 0; j < nevents; j++) {
1846 if (skip_event[j]) charge_list_graph->RemovePoint(j);
1847 }
1848
1850 root_out->WriteObject(charge_list_graph, name.Data());
1851 delete[] charge_list;
1852 }
1853 }
1854 root_out->WriteObject(charge_list_mg, "all_charge_lists");
1855 delete[] event_list;
1856}
1857
1874void ReadRun::ChargeCorrelation(float windowlow, float windowhi, float start, float end, float rangestart, float rangeend, int nbins, int channel1, int channel2, bool ignore_skipped_events) {
1875 gStyle->SetOptStat(1111);
1877 name << "charge_correlation_ch" << channel1 << "_ch" << channel2;
1879 if (windowlow + windowhi > 0.) title << ";integral ch" << channel1 << " in mV#timesns;integral ch" << channel2 << " in mV#timesns;Entries";
1880 else title << ";amplitude ch" << channel1 << " in mV;amplitude ch" << channel2 << " in mV;Entries";
1881
1882 auto charge_corr_canvas = new TCanvas(name.str().c_str(), "canvas", 600, 600);
1883 charge_corr_canvas->SetRightMargin(0.15);
1884
1887
1888 auto charge_corr = new TH2F(name.str().c_str(), title.str().c_str(), nbins, rangestart, rangeend, nbins, rangestart, rangeend);
1889
1890 for (int i = 0; i < nevents; i++) {
1891 if (charge1[i] == -999. || charge2[i] == -999.) continue; // skip if data is missing for one of the channels
1893 }
1894
1895 charge_corr->Draw("colz");
1896 root_out->WriteObject(charge_corr, name.str().c_str());
1897
1898 charge_corr_canvas->Update();
1899 charge_corr_canvas->SetGrid();
1900 // move stat box out of the way (causing problems since May 23?)
1901 //TPaveStats* stat_box = (TPaveStats*)charge_corr->FindObject("stats");
1902 //stat_box->SetX1NDC(0.6);
1903 //stat_box->SetX2NDC(0.85);
1904 charge_corr->SetStats(0);
1905 charge_corr_canvas->Modified();
1906 name << "_c";
1907 root_out->WriteObject(charge_corr_canvas, name.str().c_str());
1908 delete[] charge1;
1909 delete[] charge2;
1910}
1912
1918TH1F* ReadRun::ChargeSpectrum(int channel_index, float windowlow, float windowhi, float start, float end, float rangestart, float rangeend, int nbins) {
1919 TString name(Form("channel__%02d", active_channels[channel_index]));
1920 auto h1 = new TH1F(name.Data(), name.Data(), nbins, rangestart, rangeend);
1921
1922 float pedestal = 0;
1923 float gain = 1;
1924 if (channel_index < static_cast<int>(PrintChargeSpectrum_cal.size())) {
1927 }
1928 float i_gain = 1. / gain;
1929
1930 // create temporary histo per thread
1933 h1_thread.resize(n_threads);
1934 for (int t = 0; t < n_threads; ++t) h1_thread[t] = new TH1F("", "", nbins, rangestart, rangeend);
1935
1936 #pragma omp parallel
1937 {
1938 int t_id = omp_get_thread_num();
1940
1941 #pragma omp for
1942 for (int j = 0; j < nevents; ++j) {
1943 if (!SkipEvent(j, channel_index)) {
1945 hlocal->Fill((integral_value - pedestal) * i_gain);
1946 }
1947 }
1948 }
1949 // merge
1950 for (auto htmp : h1_thread) {
1951 h1->Add(htmp);
1952 delete htmp;
1953 }
1954 return h1;
1955}
1956
1990void 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) {
1991 // print ReadRun::ChargeSpectrum for all channels optimized for SiPM signals
1992 checkData();
1993 cout << "Creating charge spectrum ..." << endl;
1994
1995 gStyle->SetOptStat("ne");
1996 gStyle->SetOptFit(1111);
1997
1999 if (fitrangeend == 0.) fitrangeend = rangeend;
2000
2001 string ctitle("\"charge\" spectra" + to_string(PrintChargeSpectrum_cnt++));
2002 auto chargec = new TCanvas(ctitle.c_str(), ctitle.c_str(), 600, 400);
2004 int current_canvas = 0;
2005
2006 float default_rangestart = -2000;
2007 float default_rangeend = 30000;
2010 int default_nbins = static_cast<int>((default_rangeend - default_rangestart) * nbins / (rangeend - rangestart));
2011
2012 // create histograms in parallel
2014 for (int i = 0; i < nchannels; ++i) {
2015 if (PlotChannel(i)) {
2018 });
2019 }
2020 }
2021
2022 for (int i = 0; i < nchannels; i++) {
2023 if (PlotChannel(i)) {
2024 chargec->cd(++current_canvas);
2025
2026 auto his = h1_future[i].get();
2027 his->GetYaxis()->SetTitle("#Entries");
2028 if (windowlow + windowhi > 0.) his->GetXaxis()->SetTitle("Integral in mV#timesns");
2029 else his->GetXaxis()->SetTitle("Amplitude in mV");
2030
2031 if (i < static_cast<int>(PrintChargeSpectrum_cal.size()) && PrintChargeSpectrum_cal[i][0] != 1) {
2032 cout << "Charge spectrum for channel index " << i << " will be normalized using a gain of "
2033 << PrintChargeSpectrum_cal[i][0] << " and a pedestal value of " << PrintChargeSpectrum_cal[i][1] << endl;
2034 his->GetXaxis()->SetTitle("Number of photoelectrons");
2035 }
2036
2037 //store the mean integral of each channel --> used for correction factors of phi_ew analysis
2038 mean_integral.push_back(his->GetMean());
2039
2040 //fitting
2041 if (i < max_channel_nr_to_fit) {
2042 if (which_fitf == 0) {}
2043 else if (which_fitf == 1) { // landau gauss convolution for large number of photons
2045 int n_par = 4;
2046 TF1* f = new TF1("fitf_langaus", fitf, fitrangestart, fitrangeend, n_par); f->SetLineColor(3); f->SetNpx(1000);
2047
2048 f->SetParName(0, "Width"); f->SetParameter(0, 35);
2049 f->SetParName(1, "MPV"); f->SetParameter(1, 1000);
2050 f->SetParName(2, "Area"); f->SetParameter(2, 10000);
2051 f->SetParName(3, "#sigma_{Gauss}"); f->SetParameter(3, 100);
2052
2053 if (!PrintChargeSpectrum_pars.empty()) for (int j = 0; j < min(4, static_cast<int>(PrintChargeSpectrum_pars.size())); j++) f->SetParameter(j, PrintChargeSpectrum_pars[j]);
2054
2055 if (i < max_channel_nr_to_fit) {
2056 cout << "\n\n---------------------- Fit for channel " << active_channels[i] << " ----------------------\n";
2057 TFitResultPtr fresults = his->Fit(f, "LRS");
2058 fit_results.push_back(fresults);
2059 }
2060 }
2061 else if (which_fitf == 2) { // if pedestal is biased because of peak finder algorithm
2063 int n_par = 9;
2064 TF1* f = new TF1("fitf_biased", fitf, fitrangestart, fitrangeend, n_par); f->SetLineColor(3); f->SetNpx(1000);
2065
2066 f->SetParName(0, "N_{0}"); f->SetParameter(0, his->Integral());
2067 f->SetParName(1, "#mu"); f->SetParameter(1, 2.);
2068 f->SetParName(2, "#lambda"); f->SetParameter(2, .04);
2069 f->SetParName(3, "#sigma_{0}"); f->SetParameter(3, 2.1);
2070 f->SetParName(4, "#sigma_{1}"); f->SetParameter(4, 3.4); //f->SetParLimits(4, 1.e-9, 1.e3);
2071 f->SetParName(5, "Gain"); f->SetParameter(5, 30.); //f->FixParameter(5, 10.);
2072 f->SetParName(6, "Pedestal"); f->SetParameter(6, 2.);
2073 f->SetParName(7, "norm_{0}"); f->SetParameter(7, 0.7);
2074 f->SetParName(8, "x_{0}"); f->SetParameter(8, 5.);
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 // 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)
2085 //double excessEventsInPedestal = f->Integral(fitrangestart, fitrangeend)/.3125;
2086 //f->SetParameter(7, 1.);
2087 //excessEventsInPedestal -= f->Integral(fitrangestart, fitrangeend)/.3125;
2088 //cout << "\nNumber of excess events in the pedestal within the fit range:\t" << excessEventsInPedestal << "\n\n";
2089 }
2090 else if (which_fitf == 3) { // SiPM fit function with exponential delayed after pulsing
2092 int n_par = 9;
2093 TF1* f = new TF1("fitf", fitf, fitrangestart, fitrangeend, n_par); f->SetLineColor(3); f->SetNpx(1000);
2094
2095 f->SetParName(0, "N_{0}"); f->SetParameter(0, his->Integral());
2096 f->SetParName(1, "#mu"); f->SetParameter(1, 2.);
2097 f->SetParName(2, "#lambda"); f->SetParameter(2, .04);
2098 f->SetParName(3, "#sigma_{0}"); f->SetParameter(3, 2.1);
2099 f->SetParName(4, "#sigma_{1}"); f->SetParameter(4, 3.4);
2100 f->SetParName(5, "Gain"); f->SetParameter(5, 30.); //f->FixParameter(5, 40.);
2101 f->SetParName(6, "Pedestal"); f->SetParameter(6, 2.);
2102 f->SetParName(7, "#alpha"); f->SetParameter(7, .1); //f->FixParameter(7, .2);
2103 f->SetParName(8, "#beta"); f->SetParameter(8, 80.); //f->FixParameter(8, 80);
2104
2105 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]);
2106
2107 if (i < max_channel_nr_to_fit) {
2108 cout << "\n\n---------------------- Fit for channel " << active_channels[i] << " ----------------------\n";
2109 TFitResultPtr fresults = his->Fit(f, "LRS");
2110 fit_results.push_back(fresults);
2111 }
2112 }
2113 else if (which_fitf == 4) { // ideal PMT fit function
2115 int n_par = 4;
2116 TF1* f = new TF1("fitf", fitf, fitrangestart, fitrangeend, n_par); f->SetLineColor(3); f->SetNpx(1000);
2117
2118 f->SetParName(0, "N_{0}"); f->SetParameter(0, his->Integral());
2119 f->SetParName(1, "#mu"); f->SetParameter(1, 1.);
2120 f->SetParName(2, "#sigma"); f->SetParameter(2, 5.);
2121 f->SetParName(3, "gain"); f->SetParameter(3, 10.);
2122
2123 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]);
2124
2125 if (i < max_channel_nr_to_fit) {
2126 cout << "\n\n---------------------- Fit for channel " << active_channels[i] << " ----------------------\n";
2127 TFitResultPtr fresults = his->Fit(f, "LRS");
2128 fit_results.push_back(fresults);
2129 }
2130 }
2131 else if (which_fitf == 5) { // PMT fit function
2132 Fitf_PMT fitf;
2133 int n_par = 8;
2134 TF1* f = new TF1("fitf", fitf, fitrangestart, fitrangeend, n_par); f->SetLineColor(3); f->SetNpx(1000);
2135
2136 f->SetParName(0, "N_{0}"); f->SetParameter(0, his->Integral());
2137 f->SetParName(1, "w"); f->SetParameter(1, .05); f->SetParLimits(1, 1.e-99, 4.e-1); //probability for type II BG
2138 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
2139 f->SetParName(3, "#sigma_{0}"); f->SetParameter(3, 5.); f->SetParLimits(3, 1.e-9, 1.e3);
2140 f->SetParName(4, "Q_{0}"); f->SetParameter(4, 0.);
2141 f->SetParName(5, "#mu"); f->SetParameter(5, 1.);
2142 f->SetParName(6, "#sigma_{1}"); f->SetParameter(6, 5.); f->SetParLimits(6, 1.e-9, 1.e3);
2143 f->SetParName(7, "Q_{1}"); f->SetParameter(7, 10.);
2144
2145 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]);
2146
2147 if (i < max_channel_nr_to_fit) {
2148 cout << "\n\n---------------------- Fit for channel " << active_channels[i] << " ----------------------\n";
2149 TFitResultPtr fresults = his->Fit(f, "LRS");
2150 fit_results.push_back(fresults);
2151 }
2152 }
2153 else if (which_fitf == 6) { // PMT fit function with biased pedestal
2155 int n_par = 9;
2156 TF1* f = new TF1("fitf", fitf, fitrangestart, fitrangeend, n_par); f->SetLineColor(3); f->SetNpx(1000);
2157
2158 f->SetParName(0, "A"); f->SetParameter(0, his->Integral());
2159 f->SetParName(1, "w"); f->SetParameter(1, .05); f->SetParLimits(1, 1.e-9, 4.e-1); //probability for type II BG
2160 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
2161 f->SetParName(3, "#sigma_{0}"); f->SetParameter(3, 5.); f->SetParLimits(3, 1.e-9, 1.e3);
2162 f->SetParName(4, "Q_{0}"); f->SetParameter(4, 0.); f->SetParLimits(4, -1.e2, 1.e2);
2163 f->SetParName(5, "#mu"); f->SetParameter(5, 1.); f->SetParLimits(5, 1.e-9, 1.e2);
2164 f->SetParName(6, "#sigma_{1}"); f->SetParameter(6, 5.); f->SetParLimits(6, 1.e-9, 1.e3);
2165 f->SetParName(7, "Q_{1}"); f->SetParameter(7, 10.); f->SetParLimits(7, 1.e-9, 1.e9);
2166 f->SetParName(8, "A_{0}"); f->SetParameter(8, 1.); f->SetParLimits(8, 1.e-9, 1.e1);
2167
2168 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]);
2169
2170 if (i < max_channel_nr_to_fit) {
2171 cout << "\n\n---------------------- Fit for channel " << active_channels[i] << " ----------------------\n";
2172 TFitResultPtr fresults = his->Fit(f, "LRS");
2173 fit_results.push_back(fresults);
2174 }
2175 }
2176 else if (which_fitf == 7) { // default SiPM fit function + dark count spectrum (for lots of false triggers)
2178 int n_par = 9;
2179 TF1* f = new TF1("fitf", fitf, fitrangestart, fitrangeend, n_par); f->SetLineColor(3); f->SetNpx(1000);
2180
2181 f->SetParName(0, "A"); f->SetParameter(0, his->Integral());
2182 f->SetParName(1, "w"); f->SetParameter(1, .05); f->SetParLimits(1, 1.e-9, 4.e-1); //probability for type II BG
2183 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
2184 f->SetParName(3, "#sigma_{0}"); f->SetParameter(3, 5.); f->SetParLimits(3, 1.e-9, 1.e3);
2185 f->SetParName(4, "Q_{0}"); f->SetParameter(4, 0.); f->SetParLimits(4, -1.e2, 1.e2);
2186 f->SetParName(5, "#mu"); f->SetParameter(5, 1.); f->SetParLimits(5, 1.e-9, 1.e2);
2187 f->SetParName(6, "#sigma_{1}"); f->SetParameter(6, 5.); f->SetParLimits(6, 1.e-9, 1.e3);
2188 f->SetParName(7, "#mu_darkcount"); f->SetParameter(7, .1); f->SetParLimits(7, 1.e-9, 1.);
2189 f->SetParName(8, "N_{0}_darkcount"); f->SetParameter(8, .05); f->SetParLimits(8, 1.e-9, .3);
2190
2191 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]);
2192
2193 if (i < max_channel_nr_to_fit) {
2194 cout << "\n\n---------------------- Fit for channel " << active_channels[i] << " ----------------------\n";
2195 TFitResultPtr fresults = his->Fit(f, "LRS");
2196 fit_results.push_back(fresults);
2197 }
2198 }
2199 else { // default SiPM fit function
2200 Fitf fitf;
2201 int n_par = 7;
2202 TF1* f = new TF1("fitf", fitf, fitrangestart, fitrangeend, n_par); f->SetLineColor(3); f->SetNpx(1000);
2203
2204 f->SetParName(0, "N_{0}"); f->SetParameter(0, his->Integral());
2205 f->SetParName(1, "#mu"); f->SetParameter(1, 2.);
2206 f->SetParName(2, "#lambda"); f->SetParameter(2, .04);
2207 f->SetParName(3, "#sigma_{0}"); f->SetParameter(3, 2.1);
2208 f->SetParName(4, "#sigma_{1}"); f->SetParameter(4, 3.4);
2209 f->SetParName(5, "Gain"); f->SetParameter(5, 30.); //f->FixParameter(5, 40.);
2210 f->SetParName(6, "Pedestal"); f->SetParameter(6, 2.);
2211
2212 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]);
2213
2214 if (i < max_channel_nr_to_fit) {
2215 cout << "\n\n---------------------- Fit for channel " << active_channels[i] << " ----------------------\n";
2216 TFitResultPtr fresults = his->Fit(f, "LRS");
2217 fit_results.push_back(fresults);
2218 }
2219 }
2220 }
2221 TString name(Form("ChargeSpectrum channel_%02d_%d", active_channels[i], PrintChargeSpectrum_cnt));
2222 root_out->WriteObject(his, name.Data());
2223 his->Draw();
2224 if (use_log_y) gPad->SetLogy();
2225 }
2226 }
2227
2229 root_out->WriteObject(chargec, ("ChargeSpectra" + to_string(PrintChargeSpectrum_cnt)).c_str());
2230}
2234
2240void ReadRun::PrintDCR(float windowlow, float windowhi, float rangestart, float rangeend, double threshold) {
2241
2242 string unit(" mV");
2243 if (windowlow + windowhi > 0.) unit = " mV*ns";
2244
2245 for (int i = 0; i < nchannels; i++) {
2246 if (PlotChannel(i)) {
2248
2250 lonamerate << "<0.5 pe=" << threshold << unit << " -> " << his->Integral(his->GetXaxis()->FindBin(rangestart), his->GetXaxis()->FindBin(threshold)) / his->GetEntries() / (1.e-3 * (rangeend - rangestart)) << " MHz";
2251 cout << "\n" << lonamerate.str().c_str() << endl;
2252
2254 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";
2255 cout << "\n" << hinamerate.str().c_str() << endl;
2256 }
2257 }
2258}
2259
2264TH1F* ReadRun::TimeDist(int channel_index, float from, float to, float rangestart, float rangeend, int nbins, int which, float cf_r) {
2265 int from_n = TimeToIndex(from);
2266 int to_n = TimeToIndex(to);
2267
2268 TString name(Form("timedist_ch%02d", active_channels[channel_index]));
2269 auto h1 = new TH1F(name.Data(), name.Data(), nbins, rangestart, rangeend);
2270
2271 for (int j = 0; j < nevents; j++) {
2272 if (!SkipEvent(j, channel_index)) {
2274 int max_n = GetIntWindow(rundata[wf_index], 0, 0, from_n, to_n)[0];
2275 float max_val = rundata[wf_index][max_n];
2276
2277 if (which == 0) { // time of maximum
2278 h1->Fill(max_val);
2279 }
2280 else if (which == 1) { // time of 50% CFD
2281 do {
2282 max_n--;
2283 } while (rundata[wf_index][max_n] >= cf_r * max_val && max_n >= from_n);
2284 max_n++;
2285
2287 }
2288 else { // 10%-90% rise time
2289 // search backwards from maximum
2290 int n10 = -1;
2291 int n90 = -1;
2292 do {
2293 max_n--;
2294 if (n10 == -1 && rundata[wf_index][max_n] >= .1 * max_val && rundata[wf_index][max_n - 1] <= .1 * max_val) n10 = max_n;
2295 if (n90 == -1 && rundata[wf_index][max_n] >= .9 * max_val && rundata[wf_index][max_n - 1] <= .9 * max_val) n90 = max_n;
2296 } while (rundata[wf_index][max_n] <= max_val && max_n > from_n);
2297
2300
2301 h1->Fill(t90 - t10);
2302 }
2303 }
2304 }
2305 if (which == 1) h1->Fit("gaus", "WWM", "same");
2306 return h1;
2307}
2308
2327void ReadRun::PrintTimeDist(float from, float to, float rangestart, float rangeend, int nbins, int which, float cf_r) {
2328 gStyle->SetOptStat(1111); // 11 is title + entries
2329
2330 auto time_dist_c = new TCanvas("timing of maximum", "timing of maximum", 600, 400);
2332
2333 int current_canvas = 0;
2334
2335 for (int i = 0; i < nchannels; i++) {
2336 if (PlotChannel(i)) {
2338
2340 his->GetYaxis()->SetTitle("#Entries");
2341 his->GetXaxis()->SetTitle("time [ns]");
2342 his->Draw();
2343 stringstream name; name << "t_{max} for " << from << "<t<" << to << " ns";
2344 his->SetTitle(name.str().c_str());
2345
2346 TString name_save(Form("TimeDist channel_%02d", active_channels[i]));
2347 root_out->WriteObject(his, name_save.Data());
2348 }
2349 }
2350
2351 time_dist_c->Update();
2352 root_out->WriteObject(time_dist_c, "TimeDist");
2353}
2356
2363TGraph2D* ReadRun::MaxDist(int channel_index, float from, float to) {
2364 // find maximum amplitude for a given channel in time window [from, to] and return 3d histogram with the number of bins nbinsy,z
2365
2366 TString name(Form("maxdist_ch%02d", active_channels[channel_index]));
2367 TGraph2D* g3d = new TGraph2D((binNumber + 2) * nevents);
2368 g3d->SetTitle("waveforms; t [ns]; max. amplitude [mv]; amplitude [mV]");
2369 g3d->SetMarkerStyle(7);
2370 double* xvals = getx<double>();
2371
2372 for (int j = 0; j < nevents; j++) {
2373 if (!SkipEvent(j, channel_index)) {
2375
2376 int bin_from = TimeToIndex(from);
2377 int bin_to = TimeToIndex(to);
2378 double max_val = rundata[wf_index][bin_from];
2379 for (int i = bin_from; i <= bin_to; ++i) {
2380 double val = rundata[wf_index][i];
2381 if (val > max_val) max_val = val;
2382 }
2383
2384 for (int i = 0; i < binNumber; i++) g3d->SetPoint(j * binNumber + i, xvals[i], max_val, rundata[wf_index][i]);
2385 }
2386 }
2387 delete[] xvals;
2388 root_out->WriteObject(g3d, name.Data());
2389 return g3d;
2390}
2391
2392
2400void ReadRun::PrintMaxDist(float from, float to) {
2401
2402 auto max_dist_c = new TCanvas("wf grouped by maximum", "wf grouped by maximum", 600, 400);
2404
2405 int current_canvas = 0;
2406
2407 for (int i = 0; i < nchannels; i++) {
2408 if (PlotChannel(i)) {
2410 auto g3d = MaxDist(i, from, to);
2411 g3d->Draw("AP");
2412 }
2413 }
2414 max_dist_c->Update();
2415 root_out->WriteObject(max_dist_c, "MaxDist");
2416}
2417
2423TH1F* ReadRun::His_GetTimingCFD(int channel_index, float rangestart, float rangeend, int nbins) {
2424
2425 if (nbins == -999) nbins = static_cast<int>((rangeend - rangestart) * SP_inv);
2426
2427 TString name(Form("GetTimingCFD_ch%02d", active_channels[channel_index]));
2428 auto his = new TH1F(name.Data(), name.Data(), nbins, rangestart, rangeend);
2429 for (int j = 0; j < nevents; j++) {
2431 }
2432 return his;
2433}
2434
2448void ReadRun::Print_GetTimingCFD(float rangestart, float rangeend, int do_fit, int nbins, string fitoption, bool set_errors) {
2449
2450 // call GetTimingCFD() in case it was not initialized
2451 if (static_cast<int>(timing_results.size()) == 0) GetTimingCFD();
2452
2453 gStyle->SetOptStat(1111);
2454 gStyle->SetOptFit(111);
2455
2456 auto timing_cfd_c = new TCanvas("timing of cfd", "timing of cfd", 600, 400);
2458 int current_canvas = 0;
2459
2460 for (int i = 0; i < nchannels; i++) {
2461 if (PlotChannel(i)) {
2463
2465 his->GetYaxis()->SetTitle("#Entries");
2466 his->GetXaxis()->SetTitle("time [ns]");
2467
2468 if (set_errors) {
2469 int end = his->GetNbinsX();
2470 for (int k = 1; k <= end; k++) {
2471 if (his->GetBinContent(k) < 2) his->SetBinError(k, 1);
2472 else his->SetBinError(k, sqrt(his->GetBinContent(k)));
2473 }
2474 }
2475
2476 his->Draw();
2477
2478 if (do_fit == 1) {
2479 TFitResultPtr fresults = his->Fit("gaus", fitoption.c_str(), "same");
2480 timing_fit_results.push_back(fresults);
2481 }
2482
2483 TString name_save(Form("Timing_cfd_channel_%02d", active_channels[i]));
2484 root_out->WriteObject(his, name_save.Data());
2485 }
2486 }
2487
2488 timing_cfd_c->Update();
2489 root_out->WriteObject(timing_cfd_c, "TimingCFD");
2490}
2492
2498TH1F* ReadRun::His_GetTimingCFD_diff(vector<int> channels1, vector<int> channels2, float rangestart, float rangeend, int nbins) {
2499
2500 if (nbins == -999) nbins = static_cast<int>((rangeend - rangestart) * SP_inv);
2501
2503 name << "GetTimingCFD_diff <";
2504
2505 // find channel indices and assemble title
2506 int counter = 0;
2507 for (int& entry : channels2) {
2508 if (counter > 0) name << "&";
2509 auto chin2 = find(active_channels.begin(), active_channels.end(), entry);
2510 if (chin2 != active_channels.end()) {
2511 name << "ch" << entry;
2512 entry = chin2 - active_channels.begin();
2513 }
2514 else cout << "\n\n ERROR: channels2 = " << entry << " does not exist in data. Check parameters for Print_GetTimingCFD_diff()\n\n";
2515 counter++;
2516 }
2517 name << ">-<";
2518 counter = 0;
2519
2520 for (int& entry : channels1) {
2521 if (counter > 0) name << "&";
2522 auto chin1 = find(active_channels.begin(), active_channels.end(), entry);
2523 if (chin1 != active_channels.end()) {
2524 name << "ch" << entry;
2525 entry = chin1 - active_channels.begin();
2526 }
2527 else cout << "\n\n ERROR: channels1 = " << entry << " does not exist in data. Check parameters for Print_GetTimingCFD_diff()\n\n";
2528 counter++;
2529 }
2530 name << ">";
2531
2532 // fill histogram
2533 auto his = new TH1F(name.str().c_str(), name.str().c_str(), nbins, rangestart, rangeend);
2534 for (int j = 0; j < nevents; j++) {
2535 if (!SkipEvent(j)) {
2536 float mean1 = 0., mean2 = 0., cnt1 = 0., cnt2 = 0.;
2537 for (int i : channels1) {
2538 int wf_index = GetWaveformIndex(j, i);
2539 if (wf_index >= 0) {
2541 cnt1 += 1.;
2542 }
2543 }
2544 for (int i : channels2) {
2545 int wf_index = GetWaveformIndex(j, i);
2546 if (wf_index >= 0) {
2548 cnt2 += 1.;
2549 }
2550 }
2551
2552 if (cnt1 != 0. && cnt2 !=0.) his->Fill(mean2 / cnt2 - mean1 / cnt1);
2553 }
2554 }
2555
2556 return his;
2557}
2558
2593void 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) {
2594
2595 // call GetTimingCFD() in case it was not initialized
2596 if (static_cast<int>(timing_results.size()) == 0) GetTimingCFD();
2597
2598 if (fitrangestart == -999) {
2601 }
2602
2603 //gStyle->SetOptStat(1111);
2604 gStyle->SetOptFit(111);
2605
2606 auto timing_cfd_d_c = new TCanvas("timing of cfd diff", "timing of cfd diff", 600, 400);
2607
2609 his->GetYaxis()->SetTitle("#Entries");
2610 his->GetXaxis()->SetTitle("time [ns]");
2611
2612 if (set_errors) {
2613 int end = his->GetNbinsX();
2614 for (int i = 1; i <= end; i++) {
2615 if (his->GetBinContent(i) < 2) his->SetBinError(i, 1);
2616 else his->SetBinError(i, sqrt(his->GetBinContent(i)));
2617 }
2618 }
2619
2620 his->Draw();
2621
2622 double skewness = his->GetSkewness();
2623
2624 if (do_fit == 1 || (do_fit == 2 && abs(skewness) < .15)) {
2625 // gauss (default)
2626 TFitResultPtr fresults = his->Fit("gaus", fitoption.c_str(), "same", fitrangestart, fitrangeend);
2627 timing_fit_results.push_back(fresults);
2628 if (do_fit == 2) cout << "\nWARNING: Print_GetTimingCFD_diff\nFITTING GAUSS INSTEAD OF GAUSS x EXP CONVOLUTION BC SYMMETRY" << endl;
2629 }
2630 else if (do_fit == 2) {
2631 // gauss x exp convolution (effective delay from random light path and/or self-absorption and reemission)
2633 auto expgconv = new TF1("exp x gauss convolution", fitf_exp_gauss, fitrangestart, fitrangeend, 4);
2634 expgconv->SetNpx(5000);
2635
2636 // this parameter describes the sigma from different light paths
2637 // and/or the effective decay time constant for self-absorption and reemission
2638 expgconv->SetParName(0, "#tau_{eff}"); expgconv->SetParameter(0, skewness);
2639 if (skewness > 0) expgconv->SetParLimits(0, .15, 5.);
2640 else expgconv->SetParLimits(0, -5., -.15);
2641 //expgconv->FixParameter(0, 1.55);
2642
2643 expgconv->SetParName(1, "#sigma_{gaus}"); expgconv->SetParameter(1, his->GetStdDev());
2644 expgconv->SetParLimits(1, 1e-1, 7.); //expgconv->FixParameter(1, .7);
2645
2646 expgconv->SetParName(2, "t_{0}"); expgconv->SetParameter(2, his->GetMean());
2647 expgconv->SetParLimits(2, fitrangestart, fitrangeend); //expgconv->FixParameter(2, 6.6);
2648
2649 expgconv->SetParName(3, "norm"); expgconv->SetParameter(3, his->Integral("width"));
2650 expgconv->SetParLimits(3, 1., 1e8); //expgconv->FixParameter(3, 105.5);
2651
2652 TFitResultPtr fresults = his->Fit(expgconv, "SR", "same");
2653 timing_fit_results.push_back(fresults);
2654
2655 // for the phi_ew-analysis: print out the time value of the maximum of the best fit --> used to determine timing cuts
2656 float t_of_maximum = expgconv->GetMaximumX(-5, 5);
2657 cout << "Maximum of the fit is at t=" << t_of_maximum << " ns and the ";
2658
2659 double max_val = expgconv->GetMaximum();
2660 double fwhm_x1 = expgconv->GetX(max_val * 0.5, fitrangestart, fitrangeend);
2661 double fwhm_x2 = expgconv->GetX(max_val * 0.5, fwhm_x1 + 1e-3, fitrangeend);
2662 double fwhm = fwhm_x2 - fwhm_x1;
2663 auto fwhm_line = new TLine(fwhm_x1, max_val/2, fwhm_x2, max_val/2);
2664 fwhm_line->SetLineColor(2); fwhm_line->SetLineWidth(2);
2665 fwhm_line->Draw("same");
2666 cout << "FWHM=" << fwhm << " ns" << endl;
2667
2668 // TLatex l;
2669 // l.SetTextSize(0.025);
2670 // l.DrawLatex(t_of_maximum/(rangeend - rangestart), 0.4, Form("FWHM = %.2f ns", fwhm));
2671
2672 auto mean = new TLine(expgconv->GetParameter(2), 1e-2, expgconv->GetParameter(2), his->GetMaximum());
2673 mean->SetLineColor(1); mean->SetLineWidth(2);
2674 mean->Draw("same");
2675 }
2676 else if (do_fit == 3) {
2677 // sum of two gaussians (one as background estimate)
2678 auto two_gauss = new TF1("two gaussians", "gaus(0)+gaus(3)", rangestart, rangeend);
2679 two_gauss->SetTitle("Sum of two gauss");
2680 float posmax = his->GetXaxis()->GetBinCenter(his->GetMaximumBin());
2681 two_gauss->SetParameters(his->Integral("width"), posmax, 0.35, his->Integral("width") * 0.03, posmax, 2);
2682 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);
2683 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);
2685 timing_fit_results.push_back(fresults);
2686 }
2687
2688 root_out->WriteObject(his, his->GetTitle());
2689 timing_cfd_d_c->Update();
2690 root_out->WriteObject(timing_cfd_d_c, "TimingCFD_diff");
2691}
2693
2694
2695
2696
2697
2698
2702TH1F* ReadRun::Getwf(int wfindex) {
2703 int channel = GetCurrentChannel(wfindex);
2705 TString name(Form("ch%02d_%05d", channel, event_nr));
2706 TString title(Form("ch%d, event %d;t [ns];U [mV]", channel, event_nr));
2707 auto his = new TH1F(name.Data(), title.Data(), binNumber, 0, static_cast<float>(binNumber) * SP);
2708 for (int i = 1; i <= binNumber; i++) his->SetBinContent(i, rundata[wfindex][i - 1]);
2709 return his;
2710}
2711
2717TH1F* ReadRun::Getwf(int channelnr, int eventnr, int color) {
2718 TString name(Form("ch%02d_%05d", channelnr, eventnr));
2719 TString title(Form("ch%d, event %d;t [ns];U [mV]", channelnr, eventnr));
2720 auto his = new TH1F(name.Data(), title.Data(), binNumber, 0, static_cast<float>(binNumber) * SP);
2721 for (int i = 1; i <= binNumber; i++) his->SetBinContent(i, rundata[eventnr * nchannels + channelnr][i - 1]);
2722 his->SetLineColor(color);
2723 his->SetMarkerColor(color);
2724 return his;
2725}
2726
2731template<typename T>
2732T* ReadRun::getx(double shift) {
2733 T* xvals = new T[binNumber];
2734 for (int i = 0; i < binNumber; ++i) {
2735 xvals[i] = static_cast<T>(SP) * (static_cast<T>(i) + 0.5) + shift;
2736 }
2737 return xvals;
2738}
2739template double* ReadRun::getx<double>(double);
2740template float* ReadRun::getx<float>(double);
2741
2742
2746double* ReadRun::gety(int waveform_index) {
2747 double* waveform = new double[binNumber];
2749 return waveform;
2750}
2751
2756double* ReadRun::gety(int channelnr, int eventnr) {
2757 double* waveform = new double[binNumber];
2760 return waveform;
2761}
2762
2767int ReadRun::GetWaveformIndex(int eventnr, int channel_index) {
2768 return max(0, min(nwf - 1, eventnr * nchannels + channel_index));
2769}
2770
2774int ReadRun::GetEventIndex(unsigned int eventnr) {
2775 auto event_pos = find(eventnr_storage.begin(), eventnr_storage.end(), eventnr);
2776 if (event_pos == eventnr_storage.end()) {
2777 cout << "WARNING: Event number " << eventnr << " for GetEventIndex() does not exist in data.\n"
2778 << "Please check the events in the data or set discard_original_eventnr = true before calling ReadFile()." << endl;
2779
2780 if (static_cast<int>(eventnr) < nevents) {
2783 cout << "Found event number " << eventnr << " in data and will use it." << endl;
2784 }
2785 }
2786 return static_cast<int>(distance(eventnr_storage.begin(), event_pos));
2787}
2788
2792int ReadRun::GetChannelIndex(int channel_number) {
2793 int channel_index = -1;
2794 for (int i = 0; i < static_cast<int>(active_channels.size()); i++) {
2796 }
2797 if (channel_index == -1) {
2798 cout << "\n\n\tERROR: channel " << channel_number << " does not exist in data. Will continue with first channel\n\n";
2799 channel_index = 0;
2800 }
2801 return channel_index;
2802}
2803
2807int ReadRun::GetCurrentChannel(int waveform_index) {
2809}
2810
2814int ReadRun::GetCurrentEvent(int waveform_index) {
2815 return floor(waveform_index / nchannels);
2816}
2817
2822 else return false;
2823}
2824
2836pair<float, bool> ReadRun::LinearInterpolation(float ym, float x1, float x2, float y1, float y2, bool verbose) {
2837 if (y1 == y2) return {(x1 + x2) * 0.5, false};
2838 else if ((y1 > ym && y2 > ym) || (y1 < ym && y2 < ym)) {
2839 if (verbose){
2840 cout << "\nError in LinearInterpolation: Value ym=" << ym << " out of range (" << y1 << "|" << y2 << ")." << endl;
2841 cout << "Will return x1. Increase window for search." << endl;
2842 }
2843 return {x1, false};
2844 }
2845 else return {x1 + (ym - y1) * (x2 - x1) / (y2 - y1), true};
2846}
2847
2850vector<bool> ReadRun::PolarityMap(bool change_polarity, int change_sign_from_to_ch_num) {
2852 if (!change_polarity) {
2853 return pol;
2854 }
2855 else if (!switch_polarity_for_channels.empty()) {
2858 pol[current_channel] = true;
2859 }
2860 }
2861 return pol;
2862 }
2863 else {
2867 pol[current_channel] = true;
2868 }
2869 }
2870 return pol;
2871 }
2872}
2873
2878 return min(max(0, index), binNumber - 1);
2879}
2880
2884int ReadRun::TimeToIndex(float time) {
2885 return CheckBoundsX(static_cast<int>(time * SP_inv));
2886}
2887
2891float ReadRun::IndexToTime(int bin_index) {
2892 return static_cast<float>(CheckBoundsX(bin_index)) * SP;
2893}
int omp_get_max_threads()
Main class containing the file reader and most analysis functions.
int omp_get_thread_num()
static void ResponseFilter(double *&, int, double=.4, double=1.2, double=.25, double=.3125)
Custom filter emulating primitive response function.
Definition Filters.cc:445
static void SecondOrderUnderdampedFilter(double *&, int, double, double, double, double=.3125, bool=false)
Shifted second order underdamped filter.
Definition Filters.cc:492
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:162
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:121
static double * gety(HistType *his)
Get array of y values for a histogram.
Definition Helpers.cc:138
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 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 bool Contains(const vector< T > &vec, const T &val)
Returns true if vector vec contains value val.
Definition Helpers.h:55
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
int FirstBinFileToRead
Number first of .bin file to be read in.
Definition ReadRun.h:257
static pair< float, bool > LinearInterpolation(float, float, float, float, float, bool=false)
Simple linear interpolation for x.
Definition ReadRun.cc:2836
TH1F * Getwf(int)
Helper that returns the waveform histogram for a certain waveform number number.
Definition ReadRun.cc:2702
void Print_GetTimingCFD(float=100, float=140, int=0, int=-999, string="S", bool=true)
Plot results of GetTimingCFD()
Definition ReadRun.cc:2448
int PlotChannelAverages_cnt
Index for multiple executions of the same plotting function.
Definition ReadRun.h:112
void ChargeCorrelation(float, float, float, float, float, float, int, int, int, bool=false)
Plot correlation of integrals/amplitudes between two channels.
Definition ReadRun.cc:1874
float tCutEndg
End of time window for baseline correction when using ReadRun::Using_BaselineCorrection_in_file_loop.
Definition ReadRun.h:370
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:1918
float DAQ_factor
DAQ conversion factor for wavecatcher output to mV.
Definition ReadRun.h:299
void CorrectBaselineMin(vector< float >, double=0, int=2)
Baseline correction using minimum sum ( mean) in range for correction.
Definition ReadRun.cc:956
int nevents
Number of triggered events in data.
Definition ReadRun.h:282
float IndexToTime(int)
Convert the bin number of the waveform to the time of the left bin edge
Definition ReadRun.cc:2891
vector< bool > skip_event
Stores the event numbers which should be skipped in the analysis.
Definition ReadRun.h:332
double * gety(int)
Get array of y values for a certain waveform.
Definition ReadRun.cc:2746
vector< int > active_channels
Stores the numbers of the active channels.
Definition ReadRun.h:311
vector< vector< float > > rundata
Stores waveforms.
Definition ReadRun.h:132
void CorrectBaseline_function(vector< float > &, float, float, int)
Helper function called by CorrectBaseline()
Definition ReadRun.cc:730
vector< bool > PolarityMap(bool, int)
Channel map of polarity changes during reading. For parameters see ReadFile().
Definition ReadRun.cc:2850
int TimeToIndex(float)
Convert time to the bin number of the waveform.
Definition ReadRun.cc:2884
float GetPeakIntegral(TH1F *, float, float, float, float, int=0)
Calculate the integral around a peak with several options explained in GetIntWindow().
Definition ReadRun.cc:1664
int GetEventIndex(unsigned int)
Returns index of a certain event number (if data files are read in parallel threads)
Definition ReadRun.cc:2774
TH1F * His_GetTimingCFD(int, float, float, int=-999)
Plot results of GetTimingCFD()
Definition ReadRun.cc:2423
void FilterAll(double=.3, double=.9, double=.2)
Filter all waveforms.
Definition ReadRun.cc:637
void PlotWFHeatmaps(float=-20, float=200, int=880, string="", float=0, EColorPalette=kRainBow)
Plot stacks of all non-skipped waveforms for all active channels.
Definition ReadRun.cc:537
int GetChannelIndex(int)
Match channel number (wavecatcher input channel) to channel index.
Definition ReadRun.cc:2792
float tCutg
Start of time window for baseline correction when using ReadRun::Using_BaselineCorrection_in_file_loo...
Definition ReadRun.h:368
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:1797
TFile * root_out
Stores results of analysis.
Definition ReadRun.h:360
int nChannelsWC
Wavecatcher hardware max. number of channels (reduce/increase if not using the 64 channel crate)
Definition ReadRun.h:303
void PrintBaselineCorrectionResults(float=-5, float=5, int=200)
Print histogram of the baseline correction values for all channels.
Definition ReadRun.cc:1172
virtual void ReadFile(string, bool=false, int=9, string="out.root", bool=false, long long=-1)
Routine to read files created by the wavecatcher.
Definition ReadRun.cc:71
virtual int GetWaveformIndex(int, int)
Returns index of a certain event number (if data files are read in parallel threads)
Definition ReadRun.cc:2767
vector< float > PrintChargeSpectrum_pars
Starting values of the fit parameters for PrintChargeSpectrum()
Definition ReadRun.h:187
bool Using_BaselineCorrection_in_file_loop
Set true for baseline correction during data reading. Needs to be called before ReadFile().
Definition ReadRun.h:366
void PrintWFProjection(float=0, float=320, float=-50, float=50, int=200)
Plots waveform projection histograms of all channels.
Definition ReadRun.cc:1105
void PlotChannelAverages(bool=false)
Plot averages only of the good, corrected waveforms for each channel.
Definition ReadRun.cc:409
bool PlotChannel(int)
Check if a channel index should be plotted according to ReadRun::plot_active_channels.
Definition ReadRun.cc:2820
array< int, 3 > GetIntWindow(TH1F *, float, float, float, float, int=0)
Determine indices for integration window for peaks.
Definition ReadRun.cc:1533
int PrintWFProjection_cnt
Index for multiple executions of the same plotting function.
Definition ReadRun.h:114
int start_read_at_channel
Do analysis only for limited range of channels to reduce memory usage.
Definition ReadRun.h:277
vector< int > maxSumBin
Stores bin numbers where the sum of waveforms have their maximum.
Definition ReadRun.h:308
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:1711
vector< float > mean_integral
Stores the mean integral/lightyield from PrintChargeSpectrum() for all channels.
Definition ReadRun.h:327
bool discard_original_eventnr
Can be used to discard the original event numbering of the data.
Definition ReadRun.h:266
virtual int Nevents_good(int=0)
Number of good events that are not skipped.
Definition ReadRun.cc:1509
vector< vector< float > > amplValuessum
Collects sums of all waveforms for each channel.
Definition ReadRun.h:135
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:321
TH1F * WFProjectionChannel(int, int=0, int=1024, float=-50, float=50, int=200)
Waveform projections for one channel.
Definition ReadRun.cc:1077
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:2363
int nwf
Total number of waveforms read from data: number of active channels x number of events.
Definition ReadRun.h:286
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:2264
void GetTimingCFD(float=.3, float=100, float=140, double=0., bool=true, int=2, bool=false, bool=false)
Determine the timing of the maximum peak with constant fraction discrimination.
Definition ReadRun.cc:1224
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:1427
ReadRun(int last_bin_file=0, int first_bin_file=0)
Constructor of the class.
Definition ReadRun.cc:28
TH1F * BaselineCorrectionResults(int, int, float=-5, float=5, int=200)
Histograms of the contents of baseline_correction_result.
Definition ReadRun.cc:1144
void PrintDCR(float=15, float=85, float=0, float=300, double=3)
Calculate (SiPM) dark count rate.
Definition ReadRun.cc:2240
int PrintChargeSpectrum_cnt
Index for multiple executions of the same plotting function.
Definition ReadRun.h:110
void SmoothAll(double, int)
Smoothing all waveforms which are not skipped (for testing, careful when using for analysis!...
Definition ReadRun.cc:593
void CorrectBaseline(float, float=-999)
Baseline correction constant window.
Definition ReadRun.cc:705
int binNumber
Number of bins (usually 1024 samples per waveform).
Definition ReadRun.h:301
vector< vector< float > > PrintChargeSpectrum_cal
Calibration values to normalize charge spectrum to number of photoelectrons Chennels must be ordered ...
Definition ReadRun.h:375
vector< vector< float > > timing_results
Matrix to store timing of peaks from GetTimingCFD()
Definition ReadRun.h:355
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:1824
vector< vector< float > > baseline_correction_result
Stores baseline correction results for CorrectBaseline() and related functions.
Definition ReadRun.h:342
float SP_inv
1/SP
Definition ReadRun.h:295
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:2498
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:1321
int PlotWFHeatmaps_cnt
Index for multiple executions of the same plotting function.
Definition ReadRun.h:116
void SkipEventsPerChannel(vector< float >, float=0, float=0, bool=false)
Skip events above/below individual thresholds per channel.
Definition ReadRun.cc:1367
string data_path
Path to data.
Definition ReadRun.h:248
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:2400
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:1990
virtual void checkData(bool isBaselineCorrection=false) const
Primitive check to see if data has been loaded.
Definition ReadRun.h:119
int end_read_at_channel
See ReadRun::start_read_at_channel.
Definition ReadRun.h:279
int nchannels
Number of active channels in data.
Definition ReadRun.h:284
void UnskipAll()
Sets skip_event flag to false for all events, removing any previous cuts.
Definition ReadRun.cc:1492
float SP
Sampling: ns per bin of data, sampling rate 3.2 GS/s -> 0.3125 ns.
Definition ReadRun.h:293
vector< TFitResultPtr > timing_fit_results
Stores the fit results of Print_GetTimingCFD() for all channels.
Definition ReadRun.h:357
T * getx(double shift=0.)
Get array of x axis (time of the bin centers) for standard wavecatcher settings.
Definition ReadRun.cc:2732
virtual int GetCurrentEvent(int)
Get the current event index for a certain waveform index.
Definition ReadRun.cc:2814
virtual ~ReadRun()
Destructor.
Definition ReadRun.cc:327
virtual bool SkipEvent(int, int=-1)
Check if event should be skipped.
Definition ReadRun.cc:1501
void PlotChannelSums(bool=false, bool=false, double=0., double=0., int=2)
Plot sums of all raw waveforms for each channel.
Definition ReadRun.cc:347
int CheckBoundsX(int)
Check if index exists in time of waveforms.
Definition ReadRun.cc:2877
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:2327
vector< int > plot_active_channels
Stores the numbers of the active channels which should be plotted.
Definition ReadRun.h:316
void ShiftAllToAverageCF()
This function shifts all waveforms to the average signal starting times for each channel.
Definition ReadRun.cc:657
vector< TFitResultPtr > fit_results
Stores the fit results of PrintChargeSpectrum() for all channels and all function calls in ascending ...
Definition ReadRun.h:324
virtual int GetCurrentChannel(int)
Get the current channel index for a certain waveform index.
Definition ReadRun.cc:2807
void PrintSkippedEvents()
Prints a list of all skipped events into the terminal for diagnostics.
Definition ReadRun.cc:1477
int LastBinFileToRead
Number of last .bin file to be read in.
Definition ReadRun.h:253
void CorrectBaselineMinSlopeRMS(vector< float >, double=0, int=2)
Baseline correction method searching for non-monotonic, rather constant regions.
Definition ReadRun.cc:784
TH2F * WFHeatmapChannel(int, float=-20, float=200, int=880)
2D histogram of all non-skipped waveforms for one channel
Definition ReadRun.cc:480
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:2593
vector< unsigned int > eventnr_storage
Events will be stored here in the order they have been read.
Definition ReadRun.h:138