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 }
175 size_t waveform_bytes = static_cast<size_t>(binNumber) * sizeof(short);
176 vector<short> waveform(binNumber);
177 vector<float> waveform_f(binNumber);
178
179 if (file_counter == 0) amplValuessum.resize(nChannelsWC, vector<float>(binNumber, 0.));
180
181 size_t nchannels_first = 10 + header_line.find("ACQUIRED: ", nsamples_first);
182 size_t nchannels_last = header_line.find_first_of(' ', nchannels_first);
183 string nchannels_str = header_line.substr(nchannels_first, nchannels_last - nchannels_first);
184
185 nchannels = atoi(nchannels_str.data());
186 if (debug_header) printf(" |- nchannels = %d\n", nchannels);
187
188 size_t sp_first = 8 + header_line.find("Period:");
189 size_t sp_last = header_line.find(" ps");
190 float sampling_period = atof(header_line.substr(sp_first, sp_last - sp_first).data());
191 if (debug_header) printf("sampling period = %f ps\n", sampling_period);
192 SP = sampling_period * 1e-3;
193 SP_inv = 1/SP;
194
195 // compatibility with older WC software versions
196 if (v_major ==2 && v_minor == 9 && v_patch <= 13) {
197 // V2.9.13 has always measurement stored (everything is set to 0 when disabled!)
198 has_measurement = true;
199 }
200 else {
201 size_t has_measurement_first = 14 + header_line.find("MEASUREMENTS: ", nsamples_first);
202 size_t has_measurement_last = header_line.find_first_of(' ', has_measurement_first);
203 string has_measurement_str = header_line.substr(has_measurement_first, has_measurement_last - has_measurement_first);
204 has_measurement = atoi(has_measurement_str.data());
205 }
206
207 if (debug_header) printf(" `- measurement = %d\n", has_measurement);
208
209 // end of header reader
210
211 event_data an_event;
212
213 while (input_file.read((char*)(&an_event), sizeof(an_event))) {
214 //event loop
215 if (debug_data) printf("%03d has %d channels\n", an_event.EventNumber, an_event.nchannelstored);
216
217 output_event = an_event.EventNumber;
218 output_nbchannels = an_event.nchannelstored;
219
220 if (debug_data && output_event % 200 == 0) printf("EventNr: %d, nCh: %d\n", output_event, output_nbchannels);
221 if (output_nbchannels > nChannelsWC) {
222 cout << "ERROR:\nThe number of channels in the data is " << output_nbchannels
223 << ", which is larger than the maximum allowed number of channels which is set to " << nChannelsWC
224 << "\nPlease set the parameter nChannelsWC=" << output_nbchannels << endl;
225 }
226
227 // do analysis only for limited range of channels to reduce memory usage for large datasets with many channels and many events
228 int start_at_ch = 0;
234
235 if (event_counter == 0) cout << "\nstart at ch " << start_at_ch << " end at ch " << end_at_ch << endl;
236
237 for (int ch = 0; ch < output_nbchannels; ++ch) { // channel loop
238 channel_data_with_measurement a_channel_data;
239 channel_data_without_measurement a_channel_data_without_measurement;
240
241 if (has_measurement) { // read with 'channel_data_with_measurement' struct
242 input_file.read((char*)(&a_channel_data), sizeof(channel_data_with_measurement));
243 }
244 else { // read with 'channel_data_without_measurement' struct
245 input_file.read((char*)(&a_channel_data_without_measurement), sizeof(channel_data_without_measurement));
246
247 // copy the content
249 a_channel_data.EventIDsamIndex = a_channel_data_without_measurement.EventIDsamIndex;
250 a_channel_data.FirstCellToPlotsamIndex = a_channel_data_without_measurement.FirstCellToPlotsamIndex;
251 }
252
254 if (debug_data) cout << "- reading channel " << output_channel << endl;
255
256 // read waveform
257 input_file.read((char*)waveform.data(), waveform_bytes);
258
259 //---------------------------------------------------------------------------------------------------------------
260 if (ch >= start_at_ch && ch <= end_at_ch) {
261 if (event_counter == 0) active_channels.push_back(static_cast<int>(output_channel));
262
263 float factor = DAQ_factor;
264 if (polarity_map[static_cast<int>(output_channel)]) factor = -factor;
265
266 // loop to fill waveform histograms
267 for (int i = 0; i < binNumber; i++) {
268 waveform_f[i] = static_cast<float>(waveform[i]) * factor;
269 amplValuessum[static_cast<int>(output_channel)][i] += waveform_f[i];
270 }
271 rundata.push_back(waveform_f);
272
273 // baseline correction
276 }
277
278 wfcounter++;
279 }//--------------------------------------------------------------------------------------------------------------
280
281 } // for ch
282
283 skip_event.push_back(false);
284 if (!discard_original_eventnr) eventnr_storage.push_back(output_event); // Stores the current WaveCatcher event number
285 else eventnr_storage.push_back(event_counter);
288 cout << "Stopped reading events after max_nevents_to_read=" << max_nevents_to_read << endl;
289 break;
290 }
291 } // while an_event
292
293 input_file.close();
294 file_counter++;
295 } // for file_id
296
297 // in case there are empty channels, nchannels is the number of channels which contain data
299
300 // get bins where the sum spectrum has its maximum for runs with fixed trigger delay and fixed
301 // integration window relative to the max of the sum spectrum (not working for DC measurement)
302 for (int ch = 0; ch < nChannelsWC; ch++) {
304 float max_val = -9.e99;
305 int i_max = 0;
306 for (int i = 0; i < binNumber; i++) {
307 if (amplValuessum[ch][i] > max_val) {
309 i_max = i;
310 }
311 }
312 maxSumBin.push_back(i_max);
313 }
314 }
315
317 nwf = wfcounter;
318
319 printf("Finished reading %d files containing %d events with %d channels.\n\n", file_counter, nevents, nchannels);
320}
321
324 // plot_active_channels.clear();
325 rundata.clear();
326 if (root_out->IsOpen()) root_out->Close();
327 cout << "\nAnalysis completed." << endl;
328}
329
343void ReadRun::PlotChannelSums(bool smooth, bool normalize, double shift, double sigma, int smooth_method) {
344
345 double* xv = getx<double>(shift);
346 auto mgsums = new TMultiGraph();
347 mgsums->SetTitle("channel sums; t [ns]; amplitude [mV]");
348 if (normalize) mgsums->SetTitle("channel sums; t [ns]; amplitude [arb.]");
349
350 double max_val = 0., min_val = 0.;
351 int color = 0;
352
353 for (int i = 0; i < nchannels; i++) {
354 if (PlotChannel(i)) {
355 color++;
356 double* yv = new double[binNumber];
358
360
361 TGraph* gr = new TGraph(binNumber, xv, yv);
362 delete[] yv;
363
364 double tmp_min = TMath::MinElement(gr->GetN(), gr->GetY());
366 double tmp_max = TMath::MaxElement(gr->GetN(), gr->GetY());
368 if (normalize) {
369 double i_tmp_max = (tmp_max != 0) ? 1. / tmp_max : 1.;
370 for (int j = 0; j < gr->GetN(); j++) gr->SetPointY(j, gr->GetPointY(j) * i_tmp_max);
371 }
372
373 TString name(Form("channel_%02d", active_channels[i]));
374 TString title(Form("Channel %d", active_channels[i]));
375 gr->SetName(name.Data());
376 gr->SetTitle(title.Data());
377 gr->SetLineColor(Helpers::rcolor(color));
378 gr->SetMarkerColor(Helpers::rcolor(color));
379 mgsums->Add(gr);
380 }
381 }
382 delete[] xv;
383
384 auto sumc = new TCanvas("Sums", "", 600, 400);
385 mgsums->Draw("AL");
386 if (normalize) mgsums->GetYaxis()->SetRangeUser(-0.2, 1);
387 else mgsums->GetYaxis()->SetRangeUser(min_val, max_val);
388 sumc->BuildLegend(0.85, 0.70, .99, .95);
389 sumc->SetGrid();
390 root_out->WriteObject(mgsums, "channelsums");
391 root_out->WriteObject(sumc, "channelsums_c");
392}
395
405void ReadRun::PlotChannelAverages(bool normalize) {
406 float* xv = getx<float>();
407
408 auto mgav = new TMultiGraph();
409 mgav->SetTitle("channel averages; t [ns]; amplitude [mV]");
410 if (normalize) mgav->SetTitle("channel averages; t[ns]; amplitude[arb.]");
411
412 float max_val = 0., min_val = 0.;
413 int color = 0;
414
415 for (int i = 0; i < nchannels; i++) {
416 if (PlotChannel(i)) {
417 color++;
418 float* yv = new float[binNumber]();
419
420 for (int j = 0; j < nevents; j++) {
421 if (!SkipEvent(j, i)) {
422 for (int k = 0; k < binNumber; k++) yv[k] += rundata[GetWaveformIndex(j, i)][k];
423 }
424 }
425
426 float norm = max(1.f, static_cast<float>(Nevents_good(i)));
427 for (int k = 0; k < binNumber; k++) yv[k] /= norm;
428
429 auto gr = new TGraph(binNumber, xv, yv);
430 delete[] yv;
431
432 double tmp_min = TMath::MinElement(gr->GetN(), gr->GetY());
434 double tmp_max = TMath::MaxElement(gr->GetN(), gr->GetY());
436 if (normalize) {
437 double i_tmp_max = (tmp_max != 0) ? 1. / tmp_max : 1.;
438 for (int j = 0; j < gr->GetN(); j++) gr->SetPointY(j, gr->GetPointY(j) * i_tmp_max);
439 }
440
441 TString name(Form("channel_%02d", active_channels[i]));
442 TString title(Form("Channel %d", active_channels[i]));
443 gr->SetName(name.Data());
444 gr->SetTitle(title.Data());
445 gr->SetLineColor(Helpers::rcolor(color));
446 gr->SetMarkerColor(Helpers::rcolor(color));
447 mgav->Add(gr);
448 }
449 }
450 delete[] xv;
451
452 string cname("Averages_" + to_string(PlotChannelAverages_cnt++));
453 auto avc = new TCanvas(cname.c_str(), cname.c_str(), 600, 400);
454 mgav->Draw("AL");
455 if (normalize) mgav->GetYaxis()->SetRangeUser(-0.2, 1);
456 else mgav->GetYaxis()->SetRangeUser(min_val, max_val);
457 avc->BuildLegend(0.85, 0.70, .99, .95);
458 avc->SetGrid();
459 root_out->WriteObject(mgav, ("channelaverages" + to_string(PlotChannelAverages_cnt)).c_str());
460 root_out->WriteObject(avc, ("channelaverages_c" + to_string(PlotChannelAverages_cnt)).c_str());
461}
465
466
476TH2F* ReadRun::WFHeatmapChannel(int channel_index, float ymin, float ymax, int n_bins_y) {
477
478 TString name(Form("channel__%02d", active_channels[channel_index]));
479 TH2F* h2 = new TH2F(name.Data(), name.Data(), binNumber, 0, SP * static_cast<float>(binNumber), n_bins_y, ymin, ymax);
480 h2->GetXaxis()->SetTitle("t [ns]");
481 h2->GetYaxis()->SetTitle("I [arb.]");
482 h2->GetZaxis()->SetTitle("entries");
483
484 auto xv = getx<float>();
485 // create temporary histo per thread
488 for (int t = 0; t < n_threads; ++t) {
489 h2_thread[t] = new TH2F("", "", binNumber, 0, SP * static_cast<float>(binNumber), n_bins_y, ymin, ymax);
490 }
491
492 #pragma omp parallel
493 {
494 int t_id = omp_get_thread_num();
496
497 #pragma omp for
498 for (int j = 0; j < nevents; ++j) {
499 if (!SkipEvent(j, channel_index)) {
501 for (int i = 0; i < binNumber; ++i) {
502 hlocal->Fill(xv[i], rundata[wf_index][i]);
503 }
504 }
505 }
506 }
507
508 //merge
509 for (int t = 0; t < n_threads; ++t) {
510 h2->Add(h2_thread[t]);
511 delete h2_thread[t];
512 }
513
514 delete[] xv;
515 return h2;
516}
517
533void ReadRun::PlotWFHeatmaps(float ymin, float ymax, int n_bins_y, string z_opt, float z_max, EColorPalette palette) {
534
535 gStyle->SetOptStat(0);
536 string name("waveforms_heatmap_" + to_string(PlotWFHeatmaps_cnt++));
537 auto wfhm_c = new TCanvas(name.c_str(), name.c_str(), 600, 400);
539
540 // create histograms in parallel
542 for (int i = 0; i < nchannels; ++i) {
543 if (PlotChannel(i)) {
544 h2_future[i] = async(launch::async, [this, i, ymin, ymax, n_bins_y]() {
546 });
547 }
548 }
549
550 // plot histograms
551 int current_canvas = 0;
552 for (int i = 0; i < nchannels; ++i) {
553 if (PlotChannel(i)) {
554 wfhm_c->cd(++current_canvas);
555
556 gPad->SetTopMargin(.1);
557 gPad->SetBottomMargin(.1);
558 gPad->SetLeftMargin(.15);
559 gPad->SetRightMargin(.15);
560 gStyle->SetPalette(palette);
561
562 auto h2 = h2_future[i].get();
563
564 h2->SetContour(99);
565 h2->SetStats(0);
566 if (z_opt == "COLZ0") h2->Draw("COLZ0");
567 else h2->Draw("CONT4Z");
568
569 if (z_opt == "log") {
570 gPad->SetLogz();
571 if (z_max > 1) h2->GetZaxis()->SetRangeUser(1, z_max);
572 }
573 else if (z_max > 0) h2->GetZaxis()->SetRangeUser(0, z_max);
574 }
575 }
576
577 wfhm_c->Update();
578 root_out->WriteObject(wfhm_c, name.c_str());
579}
581
589void ReadRun::SmoothAll(double sigma, int method) {
590 cout << "Smoothing all non-skipped waveforms..." << endl;
591
592 #pragma omp parallel for
593 for (int j = 0; j < nwf; j++) {
596 double* tmp_wf = tmp_.data();
597
600 }
601 }
602}
603
611void ReadRun::SmoothAll(double sigma, string method) {
612 cout << "\nSmoothing all non-skipped waveforms:" << endl;
613
614 #pragma omp parallel for
615 for (int j = 0; j < nwf; j++) {
618 double* tmp_wf = tmp_.data();
619
622 }
623 }
624}
625
633void ReadRun::FilterAll(double sigma1, double sigma2, double factor) {
634 cout << "\nFiltering all waveforms..." << endl;
635
636 #pragma omp parallel for
637 for (int j = 0; j < nwf; j++) {
639 double* tmp_wf = tmp_.data();
640
644 }
645}
646
654 cout << "\nShifting all waveforms to the average constant fraction time for each channel:" << endl;
655
656 //call GetTimingCFD() in case it was not initialized
657 if (static_cast<int>(timing_results.size()) == 0) GetTimingCFD();
658
659 double* timing_mean = new double[nchannels]();
660
661 for (int j = 0; j < nwf; j++) {
664 }
665
666 int* timing_mean_n = new int[nchannels];
667 for (int i = 0; i < nchannels; i++) {
668 double i_norm = 1. / max(1., static_cast<double>(Nevents_good(i)));
669 timing_mean_n[i] = static_cast<int>(round(timing_mean[i] * i_norm));
670 }
671 delete[] timing_mean;
672
673 #pragma omp parallel for
674 for (int j = 0; j < nwf; j++) {
677 int shift = static_cast<int>(timing_results[j][0]) - timing_mean_n[curr_ch];
679 if (shift < 0) shift += binNumber;
681 }
682 }
683 delete[] timing_mean_n;
684}
685
701void ReadRun::CorrectBaseline(float tCut, float tCutEnd) {
702 checkData(true);
703
704 cout << "\nPerforming simple baseline correction in fixed time window."
705 << "This method is only suitable for measurements without dark counts!" << endl;
706 tCutg = tCut;
708 if (nwf == 0) {
710 }
711 else {
712 cout << "Baseline correction (" << nwf << " waveforms):" << endl;
714
715 #pragma omp parallel for
716 for (int j = 0; j < nwf; j++) {
718 }
719 }
720}
721
726void ReadRun::CorrectBaseline_function(vector<float>& waveform, float tCut, float tCutEnd, int waveform_index) {
727 int iCut, iCutEnd;
728 float corr = 0;
729
731
732 if (tCutEnd <= 0) { //
733 for (int i=0; i<=iCut; i++) corr += waveform[i];
734 corr /= static_cast<float>(iCut);
735 }
736 else {
738 for (int i=iCut; i<=iCutEnd; i++) corr += waveform[i];
739 corr /= static_cast<float>(iCutEnd - iCut + 1);
740 }
741
742 // write corrected values to histograms
743 if (tCut >= 0) {
744 for (int i = 0; i < binNumber; i++) waveform[i] -= corr;
745 }
746
752 }
753}
754
780void ReadRun::CorrectBaselineMinSlopeRMS(vector<float> window, double sigma, int smooth_method) {
781 checkData(true);
782
783 cout << "\nBaseline correction (minimum slope variation method, " << nwf << " waveforms):" << endl;
784 if (window.empty()) cout << "\nWarning: Window not set in CorrectBaselineMinSlopeRMS. Will use default values." << endl;
785 if (sigma != 0.) cout << "\nNotification: Using smoothing in CorrectBaselineMinSlopeRMS." << endl;
786
787 int nbins_average = !window.empty() ? TimeToIndex(window[0]) : TimeToIndex(50.);
788 int start_search_at = static_cast<int>(window.size()) > 1 ? TimeToIndex(window[1]) : 0;
789 int end_search_at = static_cast<int>(window.size()) > 2 ? TimeToIndex(window[2]) : binNumber - 1;
790
792
793 // if no valid static search window is specified, it will be dynamic from 0 ns up to 8 ns before the global maximum
794 bool search_relative_to_local_max = false;
796 if (start_search_at < 0) {
798 start_search_at = 0;
799 cout << "\nNotification: Using dynamic search window in CorrectBaselineMinSlopeRMS." << endl;
800 }
801
803
805
806 #pragma omp parallel for
807 for (int j = 0; j < nwf; j++) {
808 float minchange = 1.e99;
809 float sum = 0, sumsum = 0, change = 0, minsumsq = 0, sqsum = 0, minsqsum = 0, corr = 0;
810 int iintwindowstart = 0, imax = 0;
814
818 nbins_search_ = end_search_at_; // starts at 0
820 }
821
823 // smoothing suppresses variations in slope due to noise, so the method is potentially more sensitive to excluding peaks
825 //calculate slope
827 double* slope = new double[nbins_search_];
828 double* slope_sq = new double[nbins_search_];
829 for (int i = 0; i < nbins_search_; i++) {
830 slope[i] = yvals[i + 1] - yvals[i];
831 slope_sq[i] = slope[i] * slope[i];
832 if (i < nbins_average) { // init
833 sum += slope[i];
834 sqsum += slope_sq[i];
835 }
836 }
837 delete[] yvals;
838
839 //find window for correction
840 for (int i = 0; i < end_search_loop_at_; i++) {
841 sumsum = sum * sum;
842 change = sqsum + sumsum;
843
844 if (change < minchange) {
848 minsqsum = sqsum;
849 }
850
851 sum -= slope[i];
852 sum += slope[i + nbins_average];
853 sqsum -= slope_sq[i];
855 }
856 delete[] slope;
857 delete[] slope_sq;
858
859 // do correction
861 corr /= static_cast<float>(nbins_average + 1);
862 for (int i = 0; i < binNumber; i++) rundata[j][i] -= corr;
863
870 }
871}
874
907void ReadRun::CorrectBaselineMinSlopeRMS(int nIntegrationWindow, bool smooth, double sigma, int max_bin_for_baseline, int start_at, int smooth_method) {
908 cout << "WARNING: This is a deprecated version of CorrectBaselineMinSlopeRMS. "
909 << "It will be removed in future releases. Parameter bool smooth=" << smooth << " will be ignored." << endl;
912 window.push_back(IndexToTime(start_at));
915}
918
924void ReadRun::CorrectBaselineMinSlopeRMS(vector<float> window, double sigma, int smooth_method, int increment) {
926 cout << "WARNING: This is a deprecated version of CorrectBaselineMinSlopeRMS. "
927 << "It will be removed in future releases. Parameter increment=" << increment << " will be ignored." << endl;
929}
930
952void ReadRun::CorrectBaselineMin(vector<float> window, double sigma, int smooth_method) {
953 checkData(true);
954
955 cout << "\nBaseline correction (minimal sum method, " << nwf << " waveforms):" << endl;
956 if (window.empty()) cout << "\nWarning: Window not set in CorrectBaselineMin. Will use default values." << endl;
957 if (sigma != 0.) cout << "\nNotification: Using smoothing in CorrectBaselineMin." << endl;
958
959 int nbins_average = !window.empty() ? TimeToIndex(window[0]) : TimeToIndex(10.);
960 int start_search_at = static_cast<int>(window.size()) > 1 ? TimeToIndex(window[1]) : 0;
961 int end_search_at = static_cast<int>(window.size()) > 2 ? TimeToIndex(window[2]) : binNumber - 1;
962
964
965 // if no valid static search window is specified, it will be dynamic from 0 ns up to 8 ns before the global maximum
966 bool search_relative_to_local_max = false;
968 if (start_search_at < 0 || end_search_loop_at < 0) {
970 start_search_at = 0;
971 cout << "\nNotification: Using dynamic search window in CorrectBaselineMin." << endl;
972 }
973
975
977
978 #pragma omp parallel for
979 for (int j = 0; j < nwf; j++) {
980 float minchange = 1e9;
981 float sum = 0, corr = 0;
982 int iintwindowstart = 0, imax = 0;
986
992 }
993
995 // smoothing suppresses variations in slope due to noise, so the method is potentially more sensitive to excluding peaks
997 //find window for correction
998 for (int i = 0; i < nbins_average; i++) sum += yvals[i]; // init
999 for (int i = 0; i < end_search_loop_at_; i++) {
1000 if (sum < minchange) {
1001 minchange = sum;
1003 }
1004
1005 sum -= yvals[i];
1006 sum += yvals[i + nbins_average];
1007 }
1008 delete[] yvals;
1009
1010 // do correction
1012 corr /= static_cast<float>(nbins_average + 1);
1013 for (int i = 0; i < binNumber; i++) rundata[j][i] -= corr;
1014
1019 }
1020}
1021
1047void ReadRun::CorrectBaselineMin(int nIntegrationWindow, double sigma, int max_bin_for_baseline, int start_at, int smooth_method) {
1048 cout << "WARNING: This is a deprecated version of CorrectBaselineMin. It will be removed in future releases." << endl;
1051 window.push_back(IndexToTime(start_at));
1054}
1056
1062void ReadRun::CorrectBaselineMin(vector<float> window, double sigma, int smooth_method, int increment) {
1063 (void)increment;
1064 cout << "WARNING: This is a deprecated version of CorrectBaselineMin. It will be removed in future releases." << endl;
1066}
1067
1073TH1F* ReadRun::WFProjectionChannel(int channel_index, int from_n, int to_n, float rangestart, float rangeend, int nbins) {
1076
1077 TString name(Form("channel__%02d", active_channels[channel_index]));
1078 auto h1 = new TH1F(name.Data(), name.Data(), nbins, rangestart, rangeend);
1079
1080 for (int j = 0; j < nevents; j++) {
1081 if (!SkipEvent(j, channel_index)) {
1082 for (int i = from_n; i <= to_n; i++) h1->Fill(rundata[GetWaveformIndex(j, channel_index)][i]);
1083 }
1084 }
1085 return h1;
1086}
1087
1101void ReadRun::PrintWFProjection(float from, float to, float rangestart, float rangeend, int nbins) {
1102 gStyle->SetOptFit(111);
1103 float default_rangestart = -10;
1104 float default_rangeend = 20;
1107 int default_nbins = static_cast<int>((default_rangeend - default_rangestart) * nbins / (rangeend - rangestart));
1108
1109 string ctitle("WFProjection" + to_string(PrintWFProjection_cnt++));
1110 auto wf_projection_c = new TCanvas(ctitle.c_str(), ctitle.c_str(), 600, 400);
1112 int current_canvas = 0;
1113
1114 int from_n = TimeToIndex(from);
1115 int to_n = TimeToIndex(to);
1116
1117 for (int i = 0; i < nchannels; i++) {
1118 if (PlotChannel(i)) {
1120
1122 his->GetYaxis()->SetTitle("#Entries");
1123 his->GetXaxis()->SetTitle("amplitude in mV");
1124 TString name(Form("WFProjection channel_%02d_%d", active_channels[i], PrintWFProjection_cnt));
1125 his->Draw();
1126 his->Fit("gaus", "M", "same");
1127 root_out->WriteObject(his, name.Data());
1128 }
1129 }
1130
1132 root_out->WriteObject(wf_projection_c, ("WFProjections" + to_string(PrintWFProjection_cnt)).c_str());
1133}
1134
1140TH1F* ReadRun::BaselineCorrectionResults(int channel_index, int which, float rangestart, float rangeend, int nbins) {
1141 if (baseline_correction_result.empty() || static_cast<int>(baseline_correction_result[0].size()) < which - 1) {
1142 cout << "\nError: baseline_correction_result empty. Call baseline correction first." << endl;
1143 }
1144 TString name(Form("channel__%02d", active_channels[channel_index]));
1145 auto h1 = new TH1F(name.Data(), name.Data(), nbins, rangestart, rangeend);
1146
1147 float average_baseline = 0.;
1148 int counter = 0;
1149 for (int j = 0; j < nevents; j++) {
1150 if (!SkipEvent(j, channel_index)) {
1153 counter++;
1154 h1->Fill(current_baseline);
1155 }
1156 }
1157 cout << "Mean baseline ch" << active_channels[channel_index] << ": " << average_baseline / max(1.f, static_cast<float>(counter)) << endl;
1158 return h1;
1159}
1160
1168void ReadRun::PrintBaselineCorrectionResults(float rangestart, float rangeend, int nbins) {
1169 checkData();
1170 gStyle->SetOptFit(111);
1171 float default_rangestart = -10;
1172 float default_rangeend = 20;
1175 int default_nbins = static_cast<int>((default_rangeend - default_rangestart) * nbins / (rangeend - rangestart));
1176
1177 string ctitle;
1178 ctitle = "Correction values in mV";
1179 auto blc_res_c = new TCanvas(ctitle.c_str(), ctitle.c_str(), 600, 400);
1181 int current_canvas = 0;
1182
1183 for (int i = 0; i < nchannels; i++) {
1184 if (PlotChannel(i)) {
1186
1188 his->GetYaxis()->SetTitle("#Entries");
1189 his->GetXaxis()->SetTitle(ctitle.c_str());
1190 his->Draw();
1191 his->Fit("gaus", "WWM", "same");
1192 }
1193 }
1195 root_out->WriteObject(blc_res_c, ctitle.c_str());
1196}
1197
1220void 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) {
1221
1224 int n_range = end_at - start_at;
1225
1226 if (cf_r <= 0) cf_r = 1;
1227 cout << "\nGet timing at " << (cf_r > 0 && cf_r <= 1 ? "CF=" : "threshold=");
1228 printf("%.2f between %.2f ns and %.2f ns (%d waveforms):\n", cf_r, start_at_t, end_at_t, nwf);
1229
1230 timing_results.resize(nwf, vector<float>(8));
1231
1232 double* xvals = new double[n_range]; // x values for spline interpolation
1234
1235 #pragma omp parallel for
1236 for (int j = 0; j < nwf; j++) {
1237 double* yvals = Helpers::gety(rundata[j], start_at, end_at); // get range where to search for CFD for timing
1238
1239 // smoothing to suppress noise, will also change timing so use with care!
1241
1242 double* max_ptr = max_element(yvals, yvals + n_range);
1243 float max_val = *max_ptr;
1244 int n_max = static_cast<int>(max_ptr - yvals);
1245
1246 float cf = (cf_r <= 1) ? cf_r * max_val : cf_r;
1247
1248 int i = 0;
1249 if (!find_CF_from_start) {
1250 i = n_max;
1251 while (i > 0 && yvals[i] > cf) i--;
1252 }
1253 else {
1254 i = 0;
1255 while (i < n_max && yvals[i] < cf) i++;
1256 i--;
1257 }
1258
1259 float interpol_bin = 0.;
1261 if (i==0) {
1262 if (verbose) cout << "WARNING: CFD failed for Ch" << GetCurrentChannel(j) << ", event " << GetCurrentEvent(j) << endl;
1263 }
1264 else {
1265 // do interpolation for cf
1266 lin_interpol_res = LinearInterpolation(cf, static_cast<float>(i), static_cast<float>(i + 1), yvals[i], yvals[i + 1]);
1267 // go to center of bin
1268 interpol_bin = lin_interpol_res.first + .5;
1269
1270 if (use_spline) { // use spline interpolation with tolerance epsilon*bin_size
1271 double epsilon = 1e-4;
1272 double x_low = interpol_bin - .5;
1273 double x_high = interpol_bin + .5;
1274
1275 TSpline5* wfspl = 0;
1276 wfspl = new TSpline5("wf_spline", xvals, yvals, n_range, "b1e1b2e2", 0., 0., 0., 0.);
1277
1278 // using bisection method: halving search window until cf is less than epsilon bins from spline value
1279 while (x_high - x_low > epsilon) {
1280 double x_mid = (x_low + x_high) * 0.5;
1281 double f_mid = wfspl->Eval(x_mid);
1282 if (f_mid == cf) break;
1283
1284 if (f_mid > cf) x_high = x_mid;
1285 else x_low = x_mid;
1286 }
1287 interpol_bin = (x_low + x_high) * 0.5;
1288 delete wfspl;
1289 }
1290 }
1291 timing_results[j][0] = interpol_bin; // the bin we looked for
1292 timing_results[j][1] = (interpol_bin + static_cast<float>(start_at)) * SP; // cfd-time we looked for
1293 timing_results[j][2] = max_val; // maximum value
1294 timing_results[j][3] = n_max; // bin of maximum
1295 timing_results[j][4] = cf; // constant fraction
1296 timing_results[j][5] = IndexToTime(start_at); // starting time
1297 timing_results[j][6] = IndexToTime(end_at); // end time
1298 timing_results[j][7] = static_cast<float>(lin_interpol_res.second); // flag will be 1 if linear interpolation worked
1299 delete[] yvals;
1300 }
1301 delete[] xvals;
1302}
1304
1317void ReadRun::SkipEventsTimeDiffCut(int first_channel_abs, int second_channel_abs, double time_diff_min, double time_diff_max, bool verbose) {
1318
1319 cout << "\n Removing events if the event-wise time difference between the main peaks in ch"
1320 << first_channel_abs << " and ch" << second_channel_abs << " is <" << setprecision(2)
1321 << time_diff_min << " ns or >" << time_diff_max << " ns" << endl;
1322
1323 int counter = 0;
1326
1327 // call GetTimingCFD() in case it was not initialized
1328 if (static_cast<int>(timing_results.size()) == 0) GetTimingCFD();
1329
1330 // loop through events, calculate timing difference between channels and compare with cuts
1331 #pragma omp parallel for reduction(+:counter)
1332 for (int j = 0; j < nevents; j++) {
1336 if (max(ind_first, ind_second) >= static_cast<int>(timing_results.size())) continue;
1337
1339
1342 if (verbose) cout << "\nevent:\t" << currevent << "\tchannels:\t" << first_channel_abs << " & " << second_channel_abs << "\ttime diff:\t" << time_diff;
1343 skip_event[j] = true;
1344 counter++;
1345 }
1346 }
1347 }
1348 cout << "\t" << counter << " events will be cut out of " << nevents << endl;
1349}
1351
1352
1363void ReadRun::SkipEventsPerChannel(vector<float> thresholds, float rangestart, float rangeend, bool verbose) { // merge with IntegralFilter()?
1364
1365 if (thresholds.empty()) cout << "\nError: thresholds is empty";
1366 while (thresholds.size() <= active_channels.size()) thresholds.push_back(thresholds[0]);
1367
1368 cout << "\n Removing events with individual amplitude threshold per channel:" << endl;
1369 int counter = 0;
1370 int n_thrshld = static_cast<int>(thresholds.size());
1371
1374
1375 #pragma omp parallel for reduction(+:counter)
1376 for (int j = 0; j < nwf; j++) {
1380 if (current_channel < n_thrshld) {
1382 if (current_threshold == 0.) continue;
1383
1386
1387 float max_val = (max_it != rundata[j].end()) ? *max_it : 0.;
1388 float min_val = (min_it != rundata[j].end()) ? *min_it : 0.;
1389
1390
1393
1395 if (verbose) cout << "\nevent:\t" << currevent << "\tchannel:\t" << active_channels[current_channel] << "\tthreshold\t" << current_threshold;
1396 skip_event[current_event] = true;
1397 counter++;
1398 }
1399 }
1400 }
1401 }
1402
1403 cout << "\t" << counter << " events will be cut out of " << nevents << endl;
1404}
1405
1423void ReadRun::IntegralFilter(vector<float> thresholds, vector<bool> g_thr, float windowlow, float windowhi, float start, float end, bool use_AND_condition , bool verbose) {
1424
1425 if (thresholds.empty() || g_thr.empty()) cout << "\nERROR: thresholds or g_thr are empty in ReadRun::IntegralFilter().";
1426 while (thresholds.size() <= active_channels.size()) { thresholds.push_back(thresholds[0]); }
1427 while (g_thr.size() <= active_channels.size()) { g_thr.push_back(g_thr[0]); }
1428
1429 cout << "\n\nRemoving events with individual integral threshold per channel:" << endl;
1430 int counter = 0;
1431 int n_thresholds = static_cast<int>(thresholds.size());
1432
1433 #pragma omp parallel for reduction(+:counter)
1434 for (int j = 0; j < nwf; j++) {
1436 if (currevent_counter < 0) continue;
1437
1440 if (current_channel >= n_thresholds) continue;
1441
1443 if (current_threshold == 0.) continue;
1444
1446
1448 // skip if above/below thresholds
1451 if (verbose) cout << "Event:\t" << currevent << "\tchannel:\t" << active_channels[current_channel] << "\tthreshold\t" << thresholds[current_channel] << "\tintegral:\t" << integral << endl;
1453 // go to last wf of current event
1454 while (GetCurrentEvent(++j) == currevent_counter);
1455 j--;
1456 counter++;
1457 }
1458 }
1459 else if (use_AND_condition) { // don't skip if not
1461 if (verbose) cout << "Event:\t" << currevent << "\tchannel:\t" << active_channels[current_channel] << "\thas been flagged good by integral:\t" << integral << endl;
1462 counter--;
1463 }
1464 }
1465 }
1466 cout << counter << " additional events will be cut out of " << nevents << " (" << static_cast<float>(100*counter/nevents) << "%)" << endl;
1467}
1471
1474 int counter = 0;
1476 for (int j = 0; j < static_cast<int>(skip_event.size()); j++) {
1477 if (skip_event[j]) {
1479 buffer << "Event:\t" << currevent << endl;
1480 counter++;
1481 }
1482 }
1483 cout << buffer.str().c_str();
1484 cout << "Total number of skipped events:\t" << counter << "\tout of:\t" << nevents << endl;
1485}
1486
1489 const int skip_event_size = static_cast<int>(skip_event.size());
1490 for (int j = 0; j < skip_event_size; j++) skip_event[j] = false;
1491 cout << "\n\nAll event cuts were removed" << endl;
1492}
1493
1497bool ReadRun::SkipEvent(int event_index, int channel_index) {
1498 (void)channel_index; // avoid unused parameter warning
1499 if (event_index >= static_cast<int>(skip_event.size()) || event_index < 0) return true;
1500 else return skip_event[event_index];
1501}
1502
1505int ReadRun::Nevents_good(int channel_index) {
1506 int nevents_good = 0;
1507 for (int i = 0; i < nevents; i++) if (!SkipEvent(i, channel_index)) nevents_good++;
1508 return nevents_good;
1509}
1510
1511// functions for charge spectrum
1512
1529array<int, 3> ReadRun::GetIntWindow(TH1F* his, float windowlow, float windowhi, float start, float end, int channel) {
1530
1531 int istart, iend;
1532 array<int, 3> foundindices = {0, 0, 0};
1533
1534 if (start < 0 || end < 0) { // fixed integration window relative to maximum of sum spectrum for each channel
1535 foundindices[1] = his->GetXaxis()->FindBin(his->GetXaxis()->GetBinCenter(maxSumBin[channel]) - windowlow);
1536 foundindices[2] = his->GetXaxis()->FindBin(his->GetXaxis()->GetBinCenter(maxSumBin[channel]) + windowhi);
1537 }
1538 else if (windowlow == start && windowhi == end) { // fixed integration window for all channels
1539 foundindices[1] = his->GetXaxis()->FindBin(windowlow);
1540 foundindices[2] = his->GetXaxis()->FindBin(windowhi);
1541 }
1542 else { // fixed integration window relative to maximum of each individual waveform
1543 istart = his->GetXaxis()->FindBin(start);
1544 iend = his->GetXaxis()->FindBin(end);
1545 foundindices[0] = istart;
1546
1547 if (istart < 1 || iend > his->GetNbinsX()) {
1548 cout << "\nError: Start=" << istart << " or end=" << iend << " of GetIntWindow() out of range. Fix integration window." << endl;
1549 }
1550
1551 float max_val = -9.e99;
1552 float curr_val = 0;
1553 for (int i = istart; i < iend; i++) {
1554 curr_val = his->GetBinContent(i);
1555 if (curr_val > max_val) {
1556 max_val = curr_val;
1557 foundindices[0] = i;
1558 }
1559 }
1560
1561 foundindices[1] = his->GetXaxis()->FindBin(his->GetXaxis()->GetBinCenter(foundindices[0]) - windowlow);
1562 foundindices[2] = his->GetXaxis()->FindBin(his->GetXaxis()->GetBinCenter(foundindices[0]) + windowhi);
1563 }
1564 return foundindices;
1565}
1566
1583array<int, 3> ReadRun::GetIntWindow(const vector<float>& waveform, float windowlow, float windowhi, float start, float end, int channel) {
1584
1585 array<int, 3> foundindices = {0, 0, 0};
1586
1587 if (start < 0 || end < 0) { // fixed integration window relative to maximum of sum spectrum for each channel
1589 foundindices[2] = maxSumBin[channel] + TimeToIndex(windowhi);
1590 }
1591 else if (windowlow == start && windowhi == end) { // fixed integration window for all channels
1594 }
1595 else { // fixed integration window relative to maximum of each individual waveform
1596 int istart = TimeToIndex(start);
1597 int iend = TimeToIndex(end);
1598 foundindices[0] = istart;
1599
1600 auto max_it = max_element(waveform.begin() + istart, waveform.begin() + iend);
1601 foundindices[0] = static_cast<int>(distance(waveform.begin(), max_it));
1602
1603 float t_max = IndexToTime(foundindices[0]) + SP * 0.5; // time at center of maximum bin
1606 }
1607 return foundindices;
1608}
1609
1619array<int, 3> ReadRun::GetIntWindow(const vector<float>& waveform, int windowlow, int windowhi, int start, int end, int channel) {
1620
1621 array<int, 3> foundindices = {0, 0, 0};
1622
1623 if (start < 0 || end < 0) { // fixed integration window relative to maximum of sum spectrum for each channel
1624 foundindices[1] = maxSumBin[channel] - windowlow;
1625 foundindices[2] = maxSumBin[channel] + windowhi;
1626 }
1627 else if (windowlow == start && windowhi == end) { // fixed integration window for all channels
1630 }
1631 else { // fixed integration window relative to maximum of each individual waveform
1632 int istart = CheckBoundsX(start);
1633 int iend = CheckBoundsX(end);
1634 foundindices[0] = istart;
1635
1636 auto max_it = max_element(waveform.begin() + istart, waveform.begin() + iend);
1637 foundindices[0] = static_cast<int>(distance(waveform.begin(), max_it));
1638
1641 }
1642 return foundindices;
1643}
1644
1660float ReadRun::GetPeakIntegral(TH1F* his, float windowlow, float windowhi, float start, float end, int channel_index) {
1661 auto windowind = GetIntWindow(his, windowlow, windowhi, start, end, channel_index); // find integration window
1662 string integral_option(""); // For amplitude -> unit[mV].
1663 if (windowind[1] != windowind[2]) integral_option = "width"; // 'width' (bin width) for integral -> unit[mV x ns].
1664 float integral = his->Integral(windowind[1], windowind[2], integral_option.c_str());
1665 return integral;
1666}
1667
1683float ReadRun::GetPeakIntegral(const vector<float>& waveform, float windowlow, float windowhi, float start, float end, int channel_index) {
1684 auto windowind = GetIntWindow(waveform, windowlow, windowhi, start, end, channel_index); // find integration window
1685 float integral = 0;
1686 for (int i = windowind[1]; i <= windowind[2]; ++i) integral += waveform[i]; // sum -> unit[mV].
1687 if (windowind[1] != windowind[2]) integral *= SP; // integral -> unit[mV x ns].
1688 return integral;
1689}
1690
1707void ReadRun::PrintChargeSpectrumWF(float windowlow, float windowhi, float start, float end, int eventnr, float ymin, float ymax, float xmin, float xmax) {
1708
1709 gStyle->SetOptStat(0);
1710 TString name(Form("waveforms_event__%05d", eventnr));
1711 auto intwinc = new TCanvas(name.Data(), name.Data(), 600, 400);
1714
1715 int current_canvas = 0;
1716 for (int i = 0; i < nchannels; i++) {
1717 if (PlotChannel(i)) {
1718 intwinc->cd(++current_canvas);
1719
1720 auto his = Getwf(i, event_index);
1722
1723 // drawing and formatting
1724 gPad->SetTopMargin(.01);
1725 int last_canvas = nchannels;
1726 if (!plot_active_channels.empty()) last_canvas = static_cast<int>(plot_active_channels.size());
1727 if (current_canvas == 1 && last_canvas < 4) gPad->SetLeftMargin(.15);
1728 if (current_canvas % 4 == 0 || current_canvas == last_canvas) gPad->SetRightMargin(.01);
1729 his->Draw("HIST");
1730 his->SetStats(0);
1731
1732 if (wf_index != -1) {
1733 // create lines to indicate the integration window
1735 TLine* low = new TLine(his->GetXaxis()->GetBinCenter(windowind[1]), -5, his->GetXaxis()->GetBinCenter(windowind[1]), 10);
1736 low->SetLineColor(2);
1737 TLine* hi = new TLine(his->GetXaxis()->GetBinCenter(windowind[2]), -2, his->GetXaxis()->GetBinCenter(windowind[2]), 3);
1738 hi->SetLineColor(2);
1739 TLine* zero = new TLine(0, 0, 320, 0); // draw line at x=0 to check if baseline correction worked
1740 zero->SetLineColor(1);
1741
1742 low->Draw("same");
1743 hi->Draw("same");
1744 zero->Draw("same");
1745
1746 // draw baseline and CFD parameters
1747 if (wf_index < static_cast<int>(baseline_correction_result.size())) {
1749 baselinel->SetLineColor(6);
1750 baselinel->SetLineWidth(2);
1752 baselineh->SetLineColor(6);
1753 baselineh->SetLineWidth(2);
1755 baseline->SetLineColor(6);
1757 correction_value->SetLineColor(2);
1758
1759 baselinel->Draw("same");
1760 baselineh->Draw("same");
1761 baseline->Draw("same");
1762 correction_value->Draw("same");
1763 }
1764
1765 if (wf_index < static_cast<int>(timing_results.size())) {
1766 TLine* timing = new TLine(timing_results[wf_index][1], -10, timing_results[wf_index][1], 100);
1767 timing->SetLineColor(9);
1768 timing->SetLineWidth(2);
1769 timing->Draw("same");
1770 }
1771 }
1772
1773 if (ymin != 0. && ymax != 0.) his->GetYaxis()->SetRangeUser(ymin, ymax); // fix y range for better comparison
1774 if (xmin != 0. && xmax != 0.) his->GetXaxis()->SetRangeUser(xmin, xmax);
1775 }
1776 }
1777 intwinc->Update();
1778
1779 root_out->WriteObject(intwinc, name.Data());
1780}
1782
1793float* ReadRun::ChargeList(int channel_index, float windowlow, float windowhi, float start, float end, bool negative_vals) {
1794 float* charge_list = new float[nevents]();
1795
1796 #pragma omp parallel for
1797 for (int j = 0; j < nevents; j++) {
1799 if (wf_index == -1) {
1800 charge_list[j] = -999.;
1801 continue;
1802 }
1803
1805 if (!negative_vals && charge_list[j] < 0.) charge_list[j] = 0.;
1806 }
1807 return charge_list;
1808}
1809
1820void ReadRun::SaveChargeLists(float windowlow, float windowhi, float start, float end, bool negative_vals) {
1821 float* event_list = new float[nevents];
1823
1824 auto charge_list_mg = new TMultiGraph();
1825 if (windowlow + windowhi > 0.) charge_list_mg->SetTitle("event-wise integrals; Event number; integral [mV#timesns]");
1826 else charge_list_mg->SetTitle("event-wise amplitudes; Event number; amplitude [mV]");
1827 int color = 0;
1828
1829 for (int i = 0; i < nchannels; i++) {
1830 if (PlotChannel(i)) {
1831 color++;
1832 TString name(Form("charge_list_ch_%02d", active_channels[i]));
1835 charge_list_graph->SetLineWidth(0);
1836 charge_list_graph->SetMarkerStyle(2);
1837 charge_list_graph->SetMarkerColor(Helpers::rcolor(color));
1838 charge_list_graph->SetTitle(name.Data());
1839
1840 //remove skipped events
1841 for (int j = 0; j < nevents; j++) {
1842 if (skip_event[j]) charge_list_graph->RemovePoint(j);
1843 }
1844
1846 root_out->WriteObject(charge_list_graph, name.Data());
1847 delete[] charge_list;
1848 }
1849 }
1850 root_out->WriteObject(charge_list_mg, "all_charge_lists");
1851 delete[] event_list;
1852}
1853
1870void ReadRun::ChargeCorrelation(float windowlow, float windowhi, float start, float end, float rangestart, float rangeend, int nbins, int channel1, int channel2, bool ignore_skipped_events) {
1871 gStyle->SetOptStat(1111);
1873 name << "charge_correlation_ch" << channel1 << "_ch" << channel2;
1875 if (windowlow + windowhi > 0.) title << ";integral ch" << channel1 << " in mV#timesns;integral ch" << channel2 << " in mV#timesns;Entries";
1876 else title << ";amplitude ch" << channel1 << " in mV;amplitude ch" << channel2 << " in mV;Entries";
1877
1878 auto charge_corr_canvas = new TCanvas(name.str().c_str(), "canvas", 600, 600);
1879 charge_corr_canvas->SetRightMargin(0.15);
1880
1883
1884 auto charge_corr = new TH2F(name.str().c_str(), title.str().c_str(), nbins, rangestart, rangeend, nbins, rangestart, rangeend);
1885
1886 for (int i = 0; i < nevents; i++) {
1887 if (charge1[i] == -999. || charge2[i] == -999.) continue; // skip if data is missing for one of the channels
1889 }
1890
1891 charge_corr->Draw("colz");
1892 root_out->WriteObject(charge_corr, name.str().c_str());
1893
1894 charge_corr_canvas->Update();
1895 charge_corr_canvas->SetGrid();
1896 // move stat box out of the way (causing problems since May 23?)
1897 //TPaveStats* stat_box = (TPaveStats*)charge_corr->FindObject("stats");
1898 //stat_box->SetX1NDC(0.6);
1899 //stat_box->SetX2NDC(0.85);
1900 charge_corr->SetStats(0);
1901 charge_corr_canvas->Modified();
1902 name << "_c";
1903 root_out->WriteObject(charge_corr_canvas, name.str().c_str());
1904 delete[] charge1;
1905 delete[] charge2;
1906}
1908
1914TH1F* ReadRun::ChargeSpectrum(int channel_index, float windowlow, float windowhi, float start, float end, float rangestart, float rangeend, int nbins) {
1915 TString name(Form("channel__%02d", active_channels[channel_index]));
1916 auto h1 = new TH1F(name.Data(), name.Data(), nbins, rangestart, rangeend);
1917
1918 float pedestal = 0;
1919 float gain = 1;
1920 if (channel_index < static_cast<int>(PrintChargeSpectrum_cal.size())) {
1923 }
1924 float i_gain = 1. / gain;
1925
1926 // create temporary histo per thread
1929 h1_thread.resize(n_threads);
1930 for (int t = 0; t < n_threads; ++t) h1_thread[t] = new TH1F("", "", nbins, rangestart, rangeend);
1931
1932 #pragma omp parallel
1933 {
1934 int t_id = omp_get_thread_num();
1936
1937 #pragma omp for
1938 for (int j = 0; j < nevents; ++j) {
1939 if (!SkipEvent(j, channel_index)) {
1941 hlocal->Fill((integral_value - pedestal) * i_gain);
1942 }
1943 }
1944 }
1945 // merge
1946 for (auto htmp : h1_thread) {
1947 h1->Add(htmp);
1948 delete htmp;
1949 }
1950 return h1;
1951}
1952
1986void 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) {
1987 // print ReadRun::ChargeSpectrum for all channels optimized for SiPM signals
1988 checkData();
1989 cout << "Creating charge spectrum ..." << endl;
1990
1991 gStyle->SetOptStat("ne");
1992 gStyle->SetOptFit(1111);
1993
1995 if (fitrangeend == 0.) fitrangeend = rangeend;
1996
1997 string ctitle("\"charge\" spectra" + to_string(PrintChargeSpectrum_cnt++));
1998 auto chargec = new TCanvas(ctitle.c_str(), ctitle.c_str(), 600, 400);
2000 int current_canvas = 0;
2001
2002 float default_rangestart = -2000;
2003 float default_rangeend = 30000;
2006 int default_nbins = static_cast<int>((default_rangeend - default_rangestart) * nbins / (rangeend - rangestart));
2007
2008 // create histograms in parallel
2010 for (int i = 0; i < nchannels; ++i) {
2011 if (PlotChannel(i)) {
2014 });
2015 }
2016 }
2017
2018 for (int i = 0; i < nchannels; i++) {
2019 if (PlotChannel(i)) {
2020 chargec->cd(++current_canvas);
2021
2022 auto his = h1_future[i].get();
2023 his->GetYaxis()->SetTitle("#Entries");
2024 if (windowlow + windowhi > 0.) his->GetXaxis()->SetTitle("Integral in mV#timesns");
2025 else his->GetXaxis()->SetTitle("Amplitude in mV");
2026
2027 if (i < static_cast<int>(PrintChargeSpectrum_cal.size()) && PrintChargeSpectrum_cal[i][0] != 1) {
2028 cout << "Charge spectrum for channel index " << i << " will be normalized using a gain of "
2029 << PrintChargeSpectrum_cal[i][0] << " and a pedestal value of " << PrintChargeSpectrum_cal[i][1] << endl;
2030 his->GetXaxis()->SetTitle("Number of photoelectrons");
2031 }
2032
2033 //store the mean integral of each channel --> used for correction factors of phi_ew analysis
2034 mean_integral.push_back(his->GetMean());
2035
2036 //fitting
2037 if (i < max_channel_nr_to_fit) {
2038 if (which_fitf == 0) {}
2039 else if (which_fitf == 1) { // landau gauss convolution for large number of photons
2041 int n_par = 4;
2042 TF1* f = new TF1("fitf_langaus", fitf, fitrangestart, fitrangeend, n_par); f->SetLineColor(3); f->SetNpx(1000);
2043
2044 f->SetParName(0, "Width"); f->SetParameter(0, 35);
2045 f->SetParName(1, "MPV"); f->SetParameter(1, 1000);
2046 f->SetParName(2, "Area"); f->SetParameter(2, 10000);
2047 f->SetParName(3, "#sigma_{Gauss}"); f->SetParameter(3, 100);
2048
2049 if (!PrintChargeSpectrum_pars.empty()) for (int j = 0; j < min(4, static_cast<int>(PrintChargeSpectrum_pars.size())); j++) f->SetParameter(j, PrintChargeSpectrum_pars[j]);
2050
2051 if (i < max_channel_nr_to_fit) {
2052 cout << "\n\n---------------------- Fit for channel " << active_channels[i] << " ----------------------\n";
2053 TFitResultPtr fresults = his->Fit(f, "LRS");
2054 fit_results.push_back(fresults);
2055 }
2056 }
2057 else if (which_fitf == 2) { // if pedestal is biased because of peak finder algorithm
2059 int n_par = 9;
2060 TF1* f = new TF1("fitf_biased", fitf, fitrangestart, fitrangeend, n_par); f->SetLineColor(3); f->SetNpx(1000);
2061
2062 f->SetParName(0, "N_{0}"); f->SetParameter(0, his->Integral());
2063 f->SetParName(1, "#mu"); f->SetParameter(1, 2.);
2064 f->SetParName(2, "#lambda"); f->SetParameter(2, .04);
2065 f->SetParName(3, "#sigma_{0}"); f->SetParameter(3, 2.1);
2066 f->SetParName(4, "#sigma_{1}"); f->SetParameter(4, 3.4); //f->SetParLimits(4, 1.e-9, 1.e3);
2067 f->SetParName(5, "Gain"); f->SetParameter(5, 30.); //f->FixParameter(5, 10.);
2068 f->SetParName(6, "Pedestal"); f->SetParameter(6, 2.);
2069 f->SetParName(7, "norm_{0}"); f->SetParameter(7, 0.7);
2070 f->SetParName(8, "x_{0}"); f->SetParameter(8, 5.);
2071
2072 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]);
2073
2074 if (i < max_channel_nr_to_fit) {
2075 cout << "\n\n---------------------- Fit for channel " << active_channels[i] << " ----------------------\n";
2076 TFitResultPtr fresults = his->Fit(f, "LRS");
2077 fit_results.push_back(fresults);
2078 }
2079
2080 // 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)
2081 //double excessEventsInPedestal = f->Integral(fitrangestart, fitrangeend)/.3125;
2082 //f->SetParameter(7, 1.);
2083 //excessEventsInPedestal -= f->Integral(fitrangestart, fitrangeend)/.3125;
2084 //cout << "\nNumber of excess events in the pedestal within the fit range:\t" << excessEventsInPedestal << "\n\n";
2085 }
2086 else if (which_fitf == 3) { // SiPM fit function with exponential delayed after pulsing
2088 int n_par = 9;
2089 TF1* f = new TF1("fitf", fitf, fitrangestart, fitrangeend, n_par); f->SetLineColor(3); f->SetNpx(1000);
2090
2091 f->SetParName(0, "N_{0}"); f->SetParameter(0, his->Integral());
2092 f->SetParName(1, "#mu"); f->SetParameter(1, 2.);
2093 f->SetParName(2, "#lambda"); f->SetParameter(2, .04);
2094 f->SetParName(3, "#sigma_{0}"); f->SetParameter(3, 2.1);
2095 f->SetParName(4, "#sigma_{1}"); f->SetParameter(4, 3.4);
2096 f->SetParName(5, "Gain"); f->SetParameter(5, 30.); //f->FixParameter(5, 40.);
2097 f->SetParName(6, "Pedestal"); f->SetParameter(6, 2.);
2098 f->SetParName(7, "#alpha"); f->SetParameter(7, .1); //f->FixParameter(7, .2);
2099 f->SetParName(8, "#beta"); f->SetParameter(8, 80.); //f->FixParameter(8, 80);
2100
2101 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]);
2102
2103 if (i < max_channel_nr_to_fit) {
2104 cout << "\n\n---------------------- Fit for channel " << active_channels[i] << " ----------------------\n";
2105 TFitResultPtr fresults = his->Fit(f, "LRS");
2106 fit_results.push_back(fresults);
2107 }
2108 }
2109 else if (which_fitf == 4) { // ideal PMT fit function
2111 int n_par = 4;
2112 TF1* f = new TF1("fitf", fitf, fitrangestart, fitrangeend, n_par); f->SetLineColor(3); f->SetNpx(1000);
2113
2114 f->SetParName(0, "N_{0}"); f->SetParameter(0, his->Integral());
2115 f->SetParName(1, "#mu"); f->SetParameter(1, 1.);
2116 f->SetParName(2, "#sigma"); f->SetParameter(2, 5.);
2117 f->SetParName(3, "gain"); f->SetParameter(3, 10.);
2118
2119 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]);
2120
2121 if (i < max_channel_nr_to_fit) {
2122 cout << "\n\n---------------------- Fit for channel " << active_channels[i] << " ----------------------\n";
2123 TFitResultPtr fresults = his->Fit(f, "LRS");
2124 fit_results.push_back(fresults);
2125 }
2126 }
2127 else if (which_fitf == 5) { // PMT fit function
2128 Fitf_PMT fitf;
2129 int n_par = 8;
2130 TF1* f = new TF1("fitf", fitf, fitrangestart, fitrangeend, n_par); f->SetLineColor(3); f->SetNpx(1000);
2131
2132 f->SetParName(0, "N_{0}"); f->SetParameter(0, his->Integral());
2133 f->SetParName(1, "w"); f->SetParameter(1, .05); f->SetParLimits(1, 1.e-99, 4.e-1); //probability for type II BG
2134 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
2135 f->SetParName(3, "#sigma_{0}"); f->SetParameter(3, 5.); f->SetParLimits(3, 1.e-9, 1.e3);
2136 f->SetParName(4, "Q_{0}"); f->SetParameter(4, 0.);
2137 f->SetParName(5, "#mu"); f->SetParameter(5, 1.);
2138 f->SetParName(6, "#sigma_{1}"); f->SetParameter(6, 5.); f->SetParLimits(6, 1.e-9, 1.e3);
2139 f->SetParName(7, "Q_{1}"); f->SetParameter(7, 10.);
2140
2141 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]);
2142
2143 if (i < max_channel_nr_to_fit) {
2144 cout << "\n\n---------------------- Fit for channel " << active_channels[i] << " ----------------------\n";
2145 TFitResultPtr fresults = his->Fit(f, "LRS");
2146 fit_results.push_back(fresults);
2147 }
2148 }
2149 else if (which_fitf == 6) { // PMT fit function with biased pedestal
2151 int n_par = 9;
2152 TF1* f = new TF1("fitf", fitf, fitrangestart, fitrangeend, n_par); f->SetLineColor(3); f->SetNpx(1000);
2153
2154 f->SetParName(0, "A"); f->SetParameter(0, his->Integral());
2155 f->SetParName(1, "w"); f->SetParameter(1, .05); f->SetParLimits(1, 1.e-9, 4.e-1); //probability for type II BG
2156 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
2157 f->SetParName(3, "#sigma_{0}"); f->SetParameter(3, 5.); f->SetParLimits(3, 1.e-9, 1.e3);
2158 f->SetParName(4, "Q_{0}"); f->SetParameter(4, 0.); f->SetParLimits(4, -1.e2, 1.e2);
2159 f->SetParName(5, "#mu"); f->SetParameter(5, 1.); f->SetParLimits(5, 1.e-9, 1.e2);
2160 f->SetParName(6, "#sigma_{1}"); f->SetParameter(6, 5.); f->SetParLimits(6, 1.e-9, 1.e3);
2161 f->SetParName(7, "Q_{1}"); f->SetParameter(7, 10.); f->SetParLimits(7, 1.e-9, 1.e9);
2162 f->SetParName(8, "A_{0}"); f->SetParameter(8, 1.); f->SetParLimits(8, 1.e-9, 1.e1);
2163
2164 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]);
2165
2166 if (i < max_channel_nr_to_fit) {
2167 cout << "\n\n---------------------- Fit for channel " << active_channels[i] << " ----------------------\n";
2168 TFitResultPtr fresults = his->Fit(f, "LRS");
2169 fit_results.push_back(fresults);
2170 }
2171 }
2172 else if (which_fitf == 7) { // default SiPM fit function + dark count spectrum (for lots of false triggers)
2174 int n_par = 9;
2175 TF1* f = new TF1("fitf", fitf, fitrangestart, fitrangeend, n_par); f->SetLineColor(3); f->SetNpx(1000);
2176
2177 f->SetParName(0, "A"); f->SetParameter(0, his->Integral());
2178 f->SetParName(1, "w"); f->SetParameter(1, .05); f->SetParLimits(1, 1.e-9, 4.e-1); //probability for type II BG
2179 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
2180 f->SetParName(3, "#sigma_{0}"); f->SetParameter(3, 5.); f->SetParLimits(3, 1.e-9, 1.e3);
2181 f->SetParName(4, "Q_{0}"); f->SetParameter(4, 0.); f->SetParLimits(4, -1.e2, 1.e2);
2182 f->SetParName(5, "#mu"); f->SetParameter(5, 1.); f->SetParLimits(5, 1.e-9, 1.e2);
2183 f->SetParName(6, "#sigma_{1}"); f->SetParameter(6, 5.); f->SetParLimits(6, 1.e-9, 1.e3);
2184 f->SetParName(7, "#mu_darkcount"); f->SetParameter(7, .1); f->SetParLimits(7, 1.e-9, 1.);
2185 f->SetParName(8, "N_{0}_darkcount"); f->SetParameter(8, .05); f->SetParLimits(8, 1.e-9, .3);
2186
2187 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]);
2188
2189 if (i < max_channel_nr_to_fit) {
2190 cout << "\n\n---------------------- Fit for channel " << active_channels[i] << " ----------------------\n";
2191 TFitResultPtr fresults = his->Fit(f, "LRS");
2192 fit_results.push_back(fresults);
2193 }
2194 }
2195 else { // default SiPM fit function
2196 Fitf fitf;
2197 int n_par = 7;
2198 TF1* f = new TF1("fitf", fitf, fitrangestart, fitrangeend, n_par); f->SetLineColor(3); f->SetNpx(1000);
2199
2200 f->SetParName(0, "N_{0}"); f->SetParameter(0, his->Integral());
2201 f->SetParName(1, "#mu"); f->SetParameter(1, 2.);
2202 f->SetParName(2, "#lambda"); f->SetParameter(2, .04);
2203 f->SetParName(3, "#sigma_{0}"); f->SetParameter(3, 2.1);
2204 f->SetParName(4, "#sigma_{1}"); f->SetParameter(4, 3.4);
2205 f->SetParName(5, "Gain"); f->SetParameter(5, 30.); //f->FixParameter(5, 40.);
2206 f->SetParName(6, "Pedestal"); f->SetParameter(6, 2.);
2207
2208 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]);
2209
2210 if (i < max_channel_nr_to_fit) {
2211 cout << "\n\n---------------------- Fit for channel " << active_channels[i] << " ----------------------\n";
2212 TFitResultPtr fresults = his->Fit(f, "LRS");
2213 fit_results.push_back(fresults);
2214 }
2215 }
2216 }
2217 TString name(Form("ChargeSpectrum channel_%02d_%d", active_channels[i], PrintChargeSpectrum_cnt));
2218 root_out->WriteObject(his, name.Data());
2219 his->Draw();
2220 if (use_log_y) gPad->SetLogy();
2221 }
2222 }
2223
2225 root_out->WriteObject(chargec, ("ChargeSpectra" + to_string(PrintChargeSpectrum_cnt)).c_str());
2226}
2230
2236void ReadRun::PrintDCR(float windowlow, float windowhi, float rangestart, float rangeend, double threshold) {
2237
2238 string unit(" mV");
2239 if (windowlow + windowhi > 0.) unit = " mV*ns";
2240
2241 for (int i = 0; i < nchannels; i++) {
2242 if (PlotChannel(i)) {
2244
2246 lonamerate << "<0.5 pe=" << threshold << unit << " -> " << his->Integral(his->GetXaxis()->FindBin(rangestart), his->GetXaxis()->FindBin(threshold)) / his->GetEntries() / (1.e-3 * (rangeend - rangestart)) << " MHz";
2247 cout << "\n" << lonamerate.str().c_str() << endl;
2248
2250 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";
2251 cout << "\n" << hinamerate.str().c_str() << endl;
2252 }
2253 }
2254}
2255
2260TH1F* ReadRun::TimeDist(int channel_index, float from, float to, float rangestart, float rangeend, int nbins, int which, float cf_r) {
2261 int from_n = TimeToIndex(from);
2262 int to_n = TimeToIndex(to);
2263
2264 TString name(Form("timedist_ch%02d", active_channels[channel_index]));
2265 auto h1 = new TH1F(name.Data(), name.Data(), nbins, rangestart, rangeend);
2266
2267 for (int j = 0; j < nevents; j++) {
2268 if (!SkipEvent(j, channel_index)) {
2270 int max_n = GetIntWindow(rundata[wf_index], 0, 0, from_n, to_n)[0];
2271 float max_val = rundata[wf_index][max_n];
2272
2273 if (which == 0) { // time of maximum
2274 h1->Fill(max_val);
2275 }
2276 else if (which == 1) { // time of 50% CFD
2277 do {
2278 max_n--;
2279 } while (rundata[wf_index][max_n] >= cf_r * max_val && max_n >= from_n);
2280 max_n++;
2281
2283 }
2284 else { // 10%-90% rise time
2285 // search backwards from maximum
2286 int n10 = -1;
2287 int n90 = -1;
2288 do {
2289 max_n--;
2290 if (n10 == -1 && rundata[wf_index][max_n] >= .1 * max_val && rundata[wf_index][max_n - 1] <= .1 * max_val) n10 = max_n;
2291 if (n90 == -1 && rundata[wf_index][max_n] >= .9 * max_val && rundata[wf_index][max_n - 1] <= .9 * max_val) n90 = max_n;
2292 } while (rundata[wf_index][max_n] <= max_val && max_n > from_n);
2293
2296
2297 h1->Fill(t90 - t10);
2298 }
2299 }
2300 }
2301 if (which == 1) h1->Fit("gaus", "WWM", "same");
2302 return h1;
2303}
2304
2323void ReadRun::PrintTimeDist(float from, float to, float rangestart, float rangeend, int nbins, int which, float cf_r) {
2324 gStyle->SetOptStat(1111); // 11 is title + entries
2325
2326 auto time_dist_c = new TCanvas("timing of maximum", "timing of maximum", 600, 400);
2328
2329 int current_canvas = 0;
2330
2331 for (int i = 0; i < nchannels; i++) {
2332 if (PlotChannel(i)) {
2334
2336 his->GetYaxis()->SetTitle("#Entries");
2337 his->GetXaxis()->SetTitle("time [ns]");
2338 his->Draw();
2339 stringstream name; name << "t_{max} for " << from << "<t<" << to << " ns";
2340 his->SetTitle(name.str().c_str());
2341
2342 TString name_save(Form("TimeDist channel_%02d", active_channels[i]));
2343 root_out->WriteObject(his, name_save.Data());
2344 }
2345 }
2346
2347 time_dist_c->Update();
2348 root_out->WriteObject(time_dist_c, "TimeDist");
2349}
2352
2359TGraph2D* ReadRun::MaxDist(int channel_index, float from, float to) {
2360 // find maximum amplitude for a given channel in time window [from, to] and return 3d histogram with the number of bins nbinsy,z
2361
2362 TString name(Form("maxdist_ch%02d", active_channels[channel_index]));
2363 TGraph2D* g3d = new TGraph2D((binNumber + 2) * nevents);
2364 g3d->SetTitle("waveforms; t [ns]; max. amplitude [mv]; amplitude [mV]");
2365 g3d->SetMarkerStyle(7);
2366 double* xvals = getx<double>();
2367
2368 for (int j = 0; j < nevents; j++) {
2369 if (!SkipEvent(j, channel_index)) {
2371
2372 int bin_from = TimeToIndex(from);
2373 int bin_to = TimeToIndex(to);
2374 double max_val = rundata[wf_index][bin_from];
2375 for (int i = bin_from; i <= bin_to; ++i) {
2376 double val = rundata[wf_index][i];
2377 if (val > max_val) max_val = val;
2378 }
2379
2380 for (int i = 0; i < binNumber; i++) g3d->SetPoint(j * binNumber + i, xvals[i], max_val, rundata[wf_index][i]);
2381 }
2382 }
2383 delete[] xvals;
2384 root_out->WriteObject(g3d, name.Data());
2385 return g3d;
2386}
2387
2388
2396void ReadRun::PrintMaxDist(float from, float to) {
2397
2398 auto max_dist_c = new TCanvas("wf grouped by maximum", "wf grouped by maximum", 600, 400);
2400
2401 int current_canvas = 0;
2402
2403 for (int i = 0; i < nchannels; i++) {
2404 if (PlotChannel(i)) {
2406 auto g3d = MaxDist(i, from, to);
2407 g3d->Draw("AP");
2408 }
2409 }
2410 max_dist_c->Update();
2411 root_out->WriteObject(max_dist_c, "MaxDist");
2412}
2413
2419TH1F* ReadRun::His_GetTimingCFD(int channel_index, float rangestart, float rangeend, int nbins) {
2420
2421 if (nbins == -999) nbins = static_cast<int>((rangeend - rangestart) * SP_inv);
2422
2423 TString name(Form("GetTimingCFD_ch%02d", active_channels[channel_index]));
2424 auto his = new TH1F(name.Data(), name.Data(), nbins, rangestart, rangeend);
2425 for (int j = 0; j < nevents; j++) {
2427 }
2428 return his;
2429}
2430
2444void ReadRun::Print_GetTimingCFD(float rangestart, float rangeend, int do_fit, int nbins, string fitoption, bool set_errors) {
2445
2446 // call GetTimingCFD() in case it was not initialized
2447 if (static_cast<int>(timing_results.size()) == 0) GetTimingCFD();
2448
2449 gStyle->SetOptStat(1111);
2450 gStyle->SetOptFit(111);
2451
2452 auto timing_cfd_c = new TCanvas("timing of cfd", "timing of cfd", 600, 400);
2454 int current_canvas = 0;
2455
2456 for (int i = 0; i < nchannels; i++) {
2457 if (PlotChannel(i)) {
2459
2461 his->GetYaxis()->SetTitle("#Entries");
2462 his->GetXaxis()->SetTitle("time [ns]");
2463
2464 if (set_errors) {
2465 int end = his->GetNbinsX();
2466 for (int k = 1; k <= end; k++) {
2467 if (his->GetBinContent(k) < 2) his->SetBinError(k, 1);
2468 else his->SetBinError(k, sqrt(his->GetBinContent(k)));
2469 }
2470 }
2471
2472 his->Draw();
2473
2474 if (do_fit == 1) {
2475 TFitResultPtr fresults = his->Fit("gaus", fitoption.c_str(), "same");
2476 timing_fit_results.push_back(fresults);
2477 }
2478
2479 TString name_save(Form("Timing_cfd_channel_%02d", active_channels[i]));
2480 root_out->WriteObject(his, name_save.Data());
2481 }
2482 }
2483
2484 timing_cfd_c->Update();
2485 root_out->WriteObject(timing_cfd_c, "TimingCFD");
2486}
2488
2494TH1F* ReadRun::His_GetTimingCFD_diff(vector<int> channels1, vector<int> channels2, float rangestart, float rangeend, int nbins) {
2495
2496 if (nbins == -999) nbins = static_cast<int>((rangeend - rangestart) * SP_inv);
2497
2499 name << "GetTimingCFD_diff <";
2500
2501 // find channel indices and assemble title
2502 int counter = 0;
2503 for (int& entry : channels2) {
2504 if (counter > 0) name << "&";
2505 auto chin2 = find(active_channels.begin(), active_channels.end(), entry);
2506 if (chin2 != active_channels.end()) {
2507 name << "ch" << entry;
2508 entry = chin2 - active_channels.begin();
2509 }
2510 else cout << "\n\n ERROR: channels2 = " << entry << " does not exist in data. Check parameters for Print_GetTimingCFD_diff()\n\n";
2511 counter++;
2512 }
2513 name << ">-<";
2514 counter = 0;
2515
2516 for (int& entry : channels1) {
2517 if (counter > 0) name << "&";
2518 auto chin1 = find(active_channels.begin(), active_channels.end(), entry);
2519 if (chin1 != active_channels.end()) {
2520 name << "ch" << entry;
2521 entry = chin1 - active_channels.begin();
2522 }
2523 else cout << "\n\n ERROR: channels1 = " << entry << " does not exist in data. Check parameters for Print_GetTimingCFD_diff()\n\n";
2524 counter++;
2525 }
2526 name << ">";
2527
2528 // fill histogram
2529 auto his = new TH1F(name.str().c_str(), name.str().c_str(), nbins, rangestart, rangeend);
2530 for (int j = 0; j < nevents; j++) {
2531 if (!SkipEvent(j)) {
2532 float mean1 = 0., mean2 = 0., cnt1 = 0., cnt2 = 0.;
2533 for (int i : channels1) {
2534 int wf_index = GetWaveformIndex(j, i);
2535 if (wf_index >= 0) {
2537 cnt1 += 1.;
2538 }
2539 }
2540 for (int i : channels2) {
2541 int wf_index = GetWaveformIndex(j, i);
2542 if (wf_index >= 0) {
2544 cnt2 += 1.;
2545 }
2546 }
2547
2548 if (cnt1 != 0. && cnt2 !=0.) his->Fill(mean2 / cnt2 - mean1 / cnt1);
2549 }
2550 }
2551
2552 return his;
2553}
2554
2589void 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) {
2590
2591 // call GetTimingCFD() in case it was not initialized
2592 if (static_cast<int>(timing_results.size()) == 0) GetTimingCFD();
2593
2594 if (fitrangestart == -999) {
2597 }
2598
2599 //gStyle->SetOptStat(1111);
2600 gStyle->SetOptFit(111);
2601
2602 auto timing_cfd_d_c = new TCanvas("timing of cfd diff", "timing of cfd diff", 600, 400);
2603
2605 his->GetYaxis()->SetTitle("#Entries");
2606 his->GetXaxis()->SetTitle("time [ns]");
2607
2608 if (set_errors) {
2609 int end = his->GetNbinsX();
2610 for (int i = 1; i <= end; i++) {
2611 if (his->GetBinContent(i) < 2) his->SetBinError(i, 1);
2612 else his->SetBinError(i, sqrt(his->GetBinContent(i)));
2613 }
2614 }
2615
2616 his->Draw();
2617
2618 double skewness = his->GetSkewness();
2619
2620 if (do_fit == 1 || (do_fit == 2 && abs(skewness) < .15)) {
2621 // gauss (default)
2622 TFitResultPtr fresults = his->Fit("gaus", fitoption.c_str(), "same", fitrangestart, fitrangeend);
2623 timing_fit_results.push_back(fresults);
2624 if (do_fit == 2) cout << "\nWARNING: Print_GetTimingCFD_diff\nFITTING GAUSS INSTEAD OF GAUSS x EXP CONVOLUTION BC SYMMETRY" << endl;
2625 }
2626 else if (do_fit == 2) {
2627 // gauss x exp convolution (effective delay from random light path and/or self-absorption and reemission)
2629 auto expgconv = new TF1("exp x gauss convolution", fitf_exp_gauss, fitrangestart, fitrangeend, 4);
2630 expgconv->SetNpx(5000);
2631
2632 // this parameter describes the sigma from different light paths
2633 // and/or the effective decay time constant for self-absorption and reemission
2634 expgconv->SetParName(0, "#tau_{eff}"); expgconv->SetParameter(0, skewness);
2635 if (skewness > 0) expgconv->SetParLimits(0, .15, 5.);
2636 else expgconv->SetParLimits(0, -5., -.15);
2637 //expgconv->FixParameter(0, 1.55);
2638
2639 expgconv->SetParName(1, "#sigma_{gaus}"); expgconv->SetParameter(1, his->GetStdDev());
2640 expgconv->SetParLimits(1, 1e-1, 7.); //expgconv->FixParameter(1, .7);
2641
2642 expgconv->SetParName(2, "t_{0}"); expgconv->SetParameter(2, his->GetMean());
2643 expgconv->SetParLimits(2, fitrangestart, fitrangeend); //expgconv->FixParameter(2, 6.6);
2644
2645 expgconv->SetParName(3, "norm"); expgconv->SetParameter(3, his->Integral("width"));
2646 expgconv->SetParLimits(3, 1., 1e8); //expgconv->FixParameter(3, 105.5);
2647
2648 TFitResultPtr fresults = his->Fit(expgconv, "SR", "same");
2649 timing_fit_results.push_back(fresults);
2650
2651 // for the phi_ew-analysis: print out the time value of the maximum of the best fit --> used to determine timing cuts
2652 float t_of_maximum = expgconv->GetMaximumX(-5, 5);
2653 cout << "Maximum of the fit is at t=" << t_of_maximum << " ns and the ";
2654
2655 double max_val = expgconv->GetMaximum();
2656 double fwhm_x1 = expgconv->GetX(max_val * 0.5, fitrangestart, fitrangeend);
2657 double fwhm_x2 = expgconv->GetX(max_val * 0.5, fwhm_x1 + 1e-3, fitrangeend);
2658 double fwhm = fwhm_x2 - fwhm_x1;
2659 auto fwhm_line = new TLine(fwhm_x1, max_val/2, fwhm_x2, max_val/2);
2660 fwhm_line->SetLineColor(2); fwhm_line->SetLineWidth(2);
2661 fwhm_line->Draw("same");
2662 cout << "FWHM=" << fwhm << " ns" << endl;
2663
2664 // TLatex l;
2665 // l.SetTextSize(0.025);
2666 // l.DrawLatex(t_of_maximum/(rangeend - rangestart), 0.4, Form("FWHM = %.2f ns", fwhm));
2667
2668 auto mean = new TLine(expgconv->GetParameter(2), 1e-2, expgconv->GetParameter(2), his->GetMaximum());
2669 mean->SetLineColor(1); mean->SetLineWidth(2);
2670 mean->Draw("same");
2671 }
2672 else if (do_fit == 3) {
2673 // sum of two gaussians (one as background estimate)
2674 auto two_gauss = new TF1("two gaussians", "gaus(0)+gaus(3)", rangestart, rangeend);
2675 two_gauss->SetTitle("Sum of two gauss");
2676 float posmax = his->GetXaxis()->GetBinCenter(his->GetMaximumBin());
2677 two_gauss->SetParameters(his->Integral("width"), posmax, 0.35, his->Integral("width") * 0.03, posmax, 2);
2678 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);
2679 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);
2681 timing_fit_results.push_back(fresults);
2682 }
2683
2684 root_out->WriteObject(his, his->GetTitle());
2685 timing_cfd_d_c->Update();
2686 root_out->WriteObject(timing_cfd_d_c, "TimingCFD_diff");
2687}
2689
2690
2691
2692
2693
2694
2698TH1F* ReadRun::Getwf(int wfindex) {
2699 int channel = GetCurrentChannel(wfindex);
2701 TString name(Form("ch%02d_%05d", channel, event_nr));
2702 TString title(Form("ch%d, event %d;t [ns];U [mV]", channel, event_nr));
2703 auto his = new TH1F(name.Data(), title.Data(), binNumber, 0, static_cast<float>(binNumber) * SP);
2704 for (int i = 1; i <= binNumber; i++) his->SetBinContent(i, rundata[wfindex][i - 1]);
2705 return his;
2706}
2707
2713TH1F* ReadRun::Getwf(int channelnr, int eventnr, int color) {
2714 TString name(Form("ch%02d_%05d", channelnr, eventnr));
2715 TString title(Form("ch%d, event %d;t [ns];U [mV]", channelnr, eventnr));
2716 auto his = new TH1F(name.Data(), title.Data(), binNumber, 0, static_cast<float>(binNumber) * SP);
2717 for (int i = 1; i <= binNumber; i++) his->SetBinContent(i, rundata[eventnr * nchannels + channelnr][i - 1]);
2718 his->SetLineColor(color);
2719 his->SetMarkerColor(color);
2720 return his;
2721}
2722
2727template<typename T>
2728T* ReadRun::getx(double shift) {
2729 T* xvals = new T[binNumber];
2730 for (int i = 0; i < binNumber; ++i) {
2731 xvals[i] = static_cast<T>(SP) * (static_cast<T>(i) + 0.5) + shift;
2732 }
2733 return xvals;
2734}
2735template double* ReadRun::getx<double>(double);
2736template float* ReadRun::getx<float>(double);
2737
2738
2742double* ReadRun::gety(int waveform_index) {
2743 double* waveform = new double[binNumber];
2745 return waveform;
2746}
2747
2752double* ReadRun::gety(int channelnr, int eventnr) {
2753 double* waveform = new double[binNumber];
2756 return waveform;
2757}
2758
2763int ReadRun::GetWaveformIndex(int eventnr, int channel_index) {
2764 return max(0, min(nwf - 1, eventnr * nchannels + channel_index));
2765}
2766
2770int ReadRun::GetEventIndex(unsigned int eventnr) {
2771 auto event_pos = find(eventnr_storage.begin(), eventnr_storage.end(), eventnr);
2772 if (event_pos == eventnr_storage.end()) {
2773 cout << "WARNING: Event number " << eventnr << " for GetEventIndex() does not exist in data.\n"
2774 << "Please check the events in the data or set discard_original_eventnr = true before calling ReadFile()." << endl;
2775
2776 if (static_cast<int>(eventnr) < nevents) {
2779 cout << "Found event number " << eventnr << " in data and will use it." << endl;
2780 }
2781 }
2782 return static_cast<int>(distance(eventnr_storage.begin(), event_pos));
2783}
2784
2788int ReadRun::GetChannelIndex(int channel_number) {
2789 int channel_index = -1;
2790 for (int i = 0; i < static_cast<int>(active_channels.size()); i++) {
2792 }
2793 if (channel_index == -1) {
2794 cout << "\n\n\tERROR: channel " << channel_number << " does not exist in data. Will continue with first channel\n\n";
2795 channel_index = 0;
2796 }
2797 return channel_index;
2798}
2799
2803int ReadRun::GetCurrentChannel(int waveform_index) {
2805}
2806
2810int ReadRun::GetCurrentEvent(int waveform_index) {
2811 return floor(waveform_index / nchannels);
2812}
2813
2818 else return false;
2819}
2820
2832pair<float, bool> ReadRun::LinearInterpolation(float ym, float x1, float x2, float y1, float y2, bool verbose) {
2833 if (y1 == y2) return {(x1 + x2) * 0.5, false};
2834 else if ((y1 > ym && y2 > ym) || (y1 < ym && y2 < ym)) {
2835 if (verbose){
2836 cout << "\nError in LinearInterpolation: Value ym=" << ym << " out of range (" << y1 << "|" << y2 << ")." << endl;
2837 cout << "Will return x1. Increase window for search." << endl;
2838 }
2839 return {x1, false};
2840 }
2841 else return {x1 + (ym - y1) * (x2 - x1) / (y2 - y1), true};
2842}
2843
2846vector<bool> ReadRun::PolarityMap(bool change_polarity, int change_sign_from_to_ch_num) {
2848 if (!change_polarity) {
2849 return pol;
2850 }
2851 else if (!switch_polarity_for_channels.empty()) {
2854 pol[current_channel] = true;
2855 }
2856 }
2857 return pol;
2858 }
2859 else {
2863 pol[current_channel] = true;
2864 }
2865 }
2866 return pol;
2867 }
2868}
2869
2874 return min(max(0, index), binNumber - 1);
2875}
2876
2880int ReadRun::TimeToIndex(float time) {
2881 return CheckBoundsX(static_cast<int>(time * SP_inv));
2882}
2883
2887float ReadRun::IndexToTime(int bin_index) {
2888 return static_cast<float>(CheckBoundsX(bin_index)) * SP;
2889}
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:2832
TH1F * Getwf(int)
Helper that returns the waveform histogram for a certain waveform number number.
Definition ReadRun.cc:2698
void Print_GetTimingCFD(float=100, float=140, int=0, int=-999, string="S", bool=true)
Plot results of GetTimingCFD()
Definition ReadRun.cc:2444
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:1870
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:1914
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:952
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:2887
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:2742
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:726
vector< bool > PolarityMap(bool, int)
Channel map of polarity changes during reading. For parameters see ReadFile().
Definition ReadRun.cc:2846
int TimeToIndex(float)
Convert time to the bin number of the waveform.
Definition ReadRun.cc:2880
float GetPeakIntegral(TH1F *, float, float, float, float, int=0)
Calculate the integral around a peak with several options explained in GetIntWindow().
Definition ReadRun.cc:1660
int GetEventIndex(unsigned int)
Returns index of a certain event number (if data files are read in parallel threads)
Definition ReadRun.cc:2770
TH1F * His_GetTimingCFD(int, float, float, int=-999)
Plot results of GetTimingCFD()
Definition ReadRun.cc:2419
void FilterAll(double=.3, double=.9, double=.2)
Filter all waveforms.
Definition ReadRun.cc:633
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:533
int GetChannelIndex(int)
Match channel number (wavecatcher input channel) to channel index.
Definition ReadRun.cc:2788
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:1793
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:1168
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:2763
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:1101
void PlotChannelAverages(bool=false)
Plot averages only of the good, corrected waveforms for each channel.
Definition ReadRun.cc:405
bool PlotChannel(int)
Check if a channel index should be plotted according to ReadRun::plot_active_channels.
Definition ReadRun.cc:2816
array< int, 3 > GetIntWindow(TH1F *, float, float, float, float, int=0)
Determine indices for integration window for peaks.
Definition ReadRun.cc:1529
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:1707
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:1505
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:1073
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:2359
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:2260
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:1220
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:1423
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:1140
void PrintDCR(float=15, float=85, float=0, float=300, double=3)
Calculate (SiPM) dark count rate.
Definition ReadRun.cc:2236
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:589
void CorrectBaseline(float, float=-999)
Baseline correction constant window.
Definition ReadRun.cc:701
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:1820
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:2494
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:1317
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:1363
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:2396
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:1986
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:1488
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:2728
virtual int GetCurrentEvent(int)
Get the current event index for a certain waveform index.
Definition ReadRun.cc:2810
virtual ~ReadRun()
Destructor.
Definition ReadRun.cc:323
virtual bool SkipEvent(int, int=-1)
Check if event should be skipped.
Definition ReadRun.cc:1497
void PlotChannelSums(bool=false, bool=false, double=0., double=0., int=2)
Plot sums of all raw waveforms for each channel.
Definition ReadRun.cc:343
int CheckBoundsX(int)
Check if index exists in time of waveforms.
Definition ReadRun.cc:2873
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:2323
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:653
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:2803
void PrintSkippedEvents()
Prints a list of all skipped events into the terminal for diagnostics.
Definition ReadRun.cc:1473
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:780
TH2F * WFHeatmapChannel(int, float=-20, float=200, int=880)
2D histogram of all non-skipped waveforms for one channel
Definition ReadRun.cc:476
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:2589
vector< unsigned int > eventnr_storage
Events will be stored here in the order they have been read.
Definition ReadRun.h:138