sipm-characterisation 0.1.0
SiPM characterisation for ePIC — IV/DCR/gain, laser, readout, irradiation
Loading...
Searching...
No Matches
breakdown_voltage.h
Go to the documentation of this file.
1#pragma once
2
3#include "general_utility.h"
4
5// TODO: clean.up in another header
6// std::array<std::array<float, 2>, 2> get_intercept(TF1 *pol1, TF1 *pol2) { return utility::get_intercept(pol1->GetParameter(1), pol1->GetParError(1), pol1->GetParameter(0), pol1->GetParError(0), pol2->GetParameter(1), pol2->GetParError(1), pol2->GetParameter(0), pol2->GetParError(0)); }
7std::array<std::array<float, 2>, 2> get_intercept_x(TF1 *pol1) { return utility::get_intercept_x(pol1->GetParameter(1), pol1->GetParError(1), pol1->GetParameter(0), pol1->GetParError(0)); }
8// std::array<std::array<float, 2>, 2> get_intercept_pol1_pol2(TF1 *pol1, TF1 *pol2) { return utility::get_intercept_pol1_pol2(pol1->GetParameter(0), pol1->GetParError(0), pol1->GetParameter(1), pol1->GetParError(1), pol2->GetParameter(0), pol2->GetParError(0), pol2->GetParameter(1), pol2->GetParError(1), pol2->GetParameter(2), pol2->GetParError(2)); }
9
11{
12 // Basic method to find a first Vbd guess
13 std::array<double, 2> find_vbd_guess(TGraphErrors *gLogTarget, float threshold = 0.35);
14
15 // Implemented methods to measure Vbd
16 std::array<float, 2> measure_breakdown_0(TGraphErrors *gTarget, std::string image_folder = "", float threshold_guess = 0.75, bool erf_mediate = true, float min_before_fit = 5., float max_before_fit = 0.2, float min_after_fit = 0.2, float max_after_fit = 1.);
17 std::array<float, 2> measure_breakdown_1(TGraphErrors *gTarget, std::string image_folder = "", float threshold_guess = 0.75);
18 std::array<float, 2> measure_breakdown_2(TGraphErrors *gTarget, std::string image_folder = "", float threshold_guess = 0.75);
19 std::array<float, 2> measure_breakdown_3(TGraphErrors *gTarget, std::string image_folder = "", float threshold_guess = 0.75);
20 std::array<float, 2> measure_breakdown_4(TGraphErrors *gTarget, std::string image_folder = "", float threshold_guess = 0.75, bool erf_mediate = true, float min_before_fit = 5., float max_before_fit = 0.2, float min_after_fit = 0.2, float max_after_fit = 1.);
21 std::array<float, 2> measure_breakdown_5(TGraphErrors *gTarget, std::string image_folder = "", float threshold_guess = 0.75);
22}
23
25{
26 auto vbd_guess = 0.;
27 auto mean_baseline = gLogTarget->GetY()[0];
28 auto mean_contributors = 1;
29 for (int iPnt = 1; iPnt < gLogTarget->GetN(); iPnt++)
30 {
31 auto current_Y = gLogTarget->GetY()[iPnt];
33 {
34 vbd_guess = gLogTarget->GetX()[iPnt - 1];
35 break;
36 }
41 }
42 return {vbd_guess, mean_baseline};
43}
44
46{
47 // Method 0:
48 // Linear fit before and after guess of breakdown voltage, take the intersection of the two as the Vbd value
49
50 // Create result container
51 std::array<float, 2> result = {-1, -1};
52
53 // Make the log graph
55
56 // Calculate a guess for the Vbd and have the measured baseline value
58 auto vbd_guess = guess_result[0];
60
61 // Define the functions to find the Vbd
62 TF1 *pol1_before = new TF1("pol1_before", "[0]+x*[1]");
63 TF1 *pol1_after = new TF1("pol1_after", "[0]+x*[1]");
64
65 // Fit before and after the Vbd guess
66 // --- before fit
67 pol1_before->SetParameter(0, mean_baseline);
68 pol1_before->SetParameter(1, 0.);
70 // --- after fit
71 pol1_after->SetParameter(0, -100);
72 pol1_after->SetParameter(1, 4);
74
75 // Intercept of the two lines
77 result[0] = intercept[0][0];
78 result[1] = intercept[0][1];
79
80 TF1 *ffull;
81 // Mediate with erf if requested
82 if (erf_mediate)
83 {
84 ffull = new TF1("ffull", "((0.5-0.5*TMath::Erf(((x-[0])/[1])))*([2]+x*[3])+(0.5+0.5*TMath::Erf(((x-[0])/[1])))*([4]+x*[5]))");
85 ffull->SetParameter(0, intercept[0][0]);
86 ffull->SetParLimits(0, intercept[0][0] - max_before_fit, intercept[0][0] + min_after_fit);
87 ffull->SetParameter(1, 0.0000015);
88 ffull->SetParLimits(1, 0.000001, 0.01);
89 ffull->FixParameter(2, pol1_before->GetParameter(0));
90 ffull->FixParameter(3, pol1_before->GetParameter(1));
91 ffull->FixParameter(4, pol1_after->GetParameter(0));
92 ffull->FixParameter(5, pol1_after->GetParameter(1));
93 log_graph->Fit(ffull, "RQ", "SAME", result[0] - 4, result[0] + 3.);
94 ffull->SetParLimits(0, intercept[0][0] + ffull->GetParameter(1), intercept[0][0] + 0.2);
95 log_graph->Fit(ffull, "RQ", "SAME", result[0] - 4, result[0] + +3.);
96 result[0] = ffull->GetParameter(0) - ffull->GetParameter(1);
97 result[1] = sqrt(ffull->GetParError(0) * ffull->GetParError(0) + ffull->GetParameter(1) * ffull->GetParameter(1));
98 }
99
100 if (!image_folder.empty())
101 {
102 // Create Canvas with result
103 TCanvas *c1 = new TCanvas("c1", "c1", 600, 500);
104 gPad->SetMargin(0.15, 0.05, 0.10, 0.05);
105
106 // Set-up graph graphics
107 log_graph->GetXaxis()->SetTitle("bias voltage (V)");
108 log_graph->GetYaxis()->SetTitle("log of current");
109 log_graph->SetMarkerStyle(20);
110 log_graph->SetMarkerColor(kAzure - 3);
111 log_graph->GetXaxis()->SetRangeUser(result[0] - 6, result[0] + 3);
112 log_graph->GetYaxis()->SetRangeUser(pol1_before->Eval(result[0] - 6) - 1, pol1_after->Eval(result[0] + 3) + 1);
113 log_graph->Draw("ALPE");
114
115 // Plot all fits
116 pol1_before->SetRange(result[0] - 5, result[0] + 5);
117 pol1_before->SetLineColor(kBlue);
118 pol1_before->DrawCopy("SAME");
119 pol1_after->SetRange(result[0] - 5, result[0] + 5);
120 pol1_after->SetLineColor(kGreen);
121 pol1_after->DrawCopy("SAME");
122 ffull->SetRange(result[0] - 5, result[0] + 5);
123 ffull->SetLineColor(kRed);
124 ffull->DrawCopy("SAME");
125
126 // Write on canvas results
127 TLatex *l1 = new TLatex();
128 l1->DrawLatexNDC(0.45, 0.90, Form("V_{bd} (V)"));
129 l1->DrawLatexNDC(0.18, 0.85, Form("guess"));
130 l1->DrawLatexNDC(0.35, 0.85, Form("= %.2f ", vbd_guess));
131 l1->DrawLatexNDC(0.18, 0.80, Form("intercept"));
132 l1->DrawLatexNDC(0.35, 0.80, Form("= %.2f #pm %.2f", intercept[0][0], intercept[0][1]));
133 if (erf_mediate)
134 {
135 l1->DrawLatexNDC(0.18, 0.75, Form("fit"));
136 l1->DrawLatexNDC(0.35, 0.75, Form("= %.2f #pm %.2f", result[0], result[1]));
137 }
138 //
139 gROOT->ProcessLine(Form(".! mkdir -p %s", image_folder.c_str()));
140 c1->SaveAs((image_folder + "/measure_breakdown_0.pdf").c_str());
141 delete c1;
142 }
143
144 delete log_graph;
145 return result;
146}
147
149{
150 // Method 1:
151 // TODO: write what it does
152
153 // Create result container
154 std::array<float, 2> result = {-1, -1};
155
156 // Make the log-derivative graph
159
160 // Calculate a guess for the Vbd and have the measured baseline value
162 auto vbd_guess = guess_result[0];
163 auto mean_baseline = guess_result[1];
164
165 TF1 *ffull = new TF1("ffull", "[0]*TMath::Landau(x,[1],[2],0)*TMath::Gaus(x,[1],[3])");
166 ffull->SetParameter(0, 0.5);
167 ffull->SetParameter(1, vbd_guess);
168 ffull->SetParameter(2, 1);
169 ffull->SetParameter(3, 0.5);
170 ldv_graph->Fit(ffull, "Q", "SAME", vbd_guess - 2, vbd_guess + 2);
171 result[0] = ffull->GetParameter(1);
172 result[1] = ffull->GetParError(1);
173
174 if (!image_folder.empty())
175 {
176 // Create Canvas with result
177 TCanvas *c1 = new TCanvas("c1", "c1", 600, 500);
178 gPad->SetMargin(0.15, 0.05, 0.10, 0.05);
179
180 // Set-up graph graphics
181 ldv_graph->GetXaxis()->SetTitle("bias voltage (V)");
182 ldv_graph->GetYaxis()->SetTitle("log of current");
183 ldv_graph->SetMarkerStyle(20);
184 ldv_graph->SetMarkerColor(kAzure - 3);
185 ldv_graph->GetXaxis()->SetRangeUser(result[0] - 6, result[0] + 3);
186 ldv_graph->GetYaxis()->SetRangeUser(ffull->Eval(result[0] - 6) - 1, ffull->Eval(result[0]) + 1);
187 ldv_graph->Draw("ALPE");
188
189 // Plot all fits
190 ffull->SetRange(result[0] - 5, result[0] + 5);
191 ffull->SetLineColor(kRed);
192 ffull->DrawCopy("SAME");
193
194 // Write on canvas results
195 TLatex *l1 = new TLatex();
196 l1->DrawLatexNDC(0.45, 0.90, Form("V_{bd} (V)"));
197 l1->DrawLatexNDC(0.18, 0.85, Form("guess"));
198 l1->DrawLatexNDC(0.35, 0.85, Form("= %.2f ", vbd_guess));
199 l1->DrawLatexNDC(0.18, 0.80, Form("fit"));
200 l1->DrawLatexNDC(0.35, 0.80, Form("= %.2f #pm %.2f", result[0], result[1]));
201 //
202 gROOT->ProcessLine(Form(".! mkdir -p %s", image_folder.c_str()));
203 c1->SaveAs((image_folder + "/measure_breakdown_1.pdf").c_str());
204 delete c1;
205 }
206 delete log_graph;
207 delete ldv_graph;
208 return result;
209}
210
212{
213 // Method 2:
214 // TODO: write what it does
215
216 // Create result container
217 std::array<float, 2> result = {-1, -1};
218
219 // Make the log-derivative graph
223
224 // Calculate a guess for the Vbd and have the measured baseline value
226 auto vbd_guess = guess_result[0];
227 auto mean_baseline = guess_result[1];
228
229 // Fit the graph
230 TF1 *pol1_after = new TF1("pol1_after", "[0]+x*[1]");
231 ild_graph->Fit(pol1_after, "Q", "SAME", vbd_guess + 0.5, vbd_guess + 3.5);
232
233 // Get intercept
235 result[0] = intercept[0][0];
236 result[1] = intercept[0][1];
237
238 if (!image_folder.empty())
239 {
240 // Create Canvas with result
241 TCanvas *c1 = new TCanvas("c1", "c1", 600, 500);
242 gPad->SetMargin(0.15, 0.05, 0.10, 0.05);
243
244 // Set-up graph graphics
245 ild_graph->GetXaxis()->SetTitle("bias voltage (V)");
246 ild_graph->GetYaxis()->SetTitle("inverse log of current");
247 ild_graph->SetMarkerStyle(20);
248 ild_graph->SetMarkerColor(kAzure - 3);
249 ild_graph->GetXaxis()->SetRangeUser(result[0] - 3, result[0] + 6);
250 ild_graph->GetYaxis()->SetRangeUser(pol1_after->Eval(result[0] - 1), pol1_after->Eval(result[0] + 4) + 1);
251 ild_graph->Draw("ALPE");
252
253 // Plot all fits
254 pol1_after->SetRange(result[0] - 5, result[0] + 5);
255 pol1_after->SetLineColor(kRed);
256 pol1_after->DrawCopy("SAME");
257
258 // Write on canvas results
259 TLatex *l1 = new TLatex();
260 l1->DrawLatexNDC(0.45, 0.90, Form("V_{bd} (V)"));
261 l1->DrawLatexNDC(0.18, 0.85, Form("guess"));
262 l1->DrawLatexNDC(0.35, 0.85, Form("= %.2f ", vbd_guess));
263 l1->DrawLatexNDC(0.18, 0.80, Form("fit"));
264 l1->DrawLatexNDC(0.35, 0.80, Form("= %.2f #pm %.2f", result[0], result[1]));
265 //
266 gROOT->ProcessLine(Form(".! mkdir -p %s", image_folder.c_str()));
267 c1->SaveAs((image_folder + "/measure_breakdown_2.pdf").c_str());
268 delete c1;
269 }
270
271 delete log_graph;
272 delete ldv_graph;
273 delete ild_graph;
274 return result;
275}
276
278{
279 // Method 3:
280 // TODO: write what it does
281
282 // Create result container
283 std::array<float, 2> result = {-1, -1};
284
285 // Make the log-derivative graph
289
290 // Calculate a guess for the Vbd and have the measured baseline value
292 auto vbd_guess = guess_result[0];
293 auto mean_baseline = guess_result[1];
294
295 // Fit the graph
296 TF1 *gaus_peak = new TF1("gaus_peak", "gaus(0)");
297 ld2_graph->Fit(gaus_peak, "Q", "SAME", vbd_guess - 3.5, vbd_guess + 3.5);
298 result[0] = gaus_peak->GetParameter(1);
299 result[1] = gaus_peak->GetParError(1);
300
301 if (!image_folder.empty())
302 {
303 // Create Canvas with result
304 TCanvas *c1 = new TCanvas("c1", "c1", 600, 500);
305 gPad->SetMargin(0.15, 0.05, 0.10, 0.05);
306
307 // Set-up graph graphics
308 ld2_graph->GetXaxis()->SetTitle("bias voltage (V)");
309 ld2_graph->GetYaxis()->SetTitle("double derivative of log of current");
310 ld2_graph->SetMarkerStyle(20);
311 ld2_graph->SetMarkerColor(kAzure - 3);
312 ld2_graph->GetXaxis()->SetRangeUser(result[0] - 4, result[0] + 4);
313 ld2_graph->GetYaxis()->SetRangeUser(gaus_peak->Eval(result[0] + 4) - 1, gaus_peak->Eval(result[0]) + 1);
314 ld2_graph->Draw("ALPE");
315
316 // Plot all fits
317 gaus_peak->SetRange(result[0] - 4, result[0] + 4);
318 gaus_peak->SetLineColor(kRed);
319 gaus_peak->DrawCopy("SAME");
320
321 // Write on canvas results
322 TLatex *l1 = new TLatex();
323 l1->DrawLatexNDC(0.45, 0.90, Form("V_{bd} (V)"));
324 l1->DrawLatexNDC(0.18, 0.85, Form("guess"));
325 l1->DrawLatexNDC(0.35, 0.85, Form("= %.2f ", vbd_guess));
326 l1->DrawLatexNDC(0.18, 0.80, Form("fit"));
327 l1->DrawLatexNDC(0.35, 0.80, Form("= %.2f #pm %.2f", result[0], result[1]));
328 //
329 gROOT->ProcessLine(Form(".! mkdir -p %s", image_folder.c_str()));
330 c1->SaveAs((image_folder + "/measure_breakdown_3.pdf").c_str());
331 delete c1;
332 }
333
334 delete log_graph;
335 delete ldv_graph;
336 delete ld2_graph;
337 return result;
338}
339
341{
342 // Method 4:
343 // TODO: write what it does
344
345 // Create result container
346 std::array<float, 2> result = {-1, -1};
347
348 // Make the log graph
350
351 // Calculate a guess for the Vbd and have the measured baseline value
353 auto vbd_guess = guess_result[0];
354 auto mean_baseline = guess_result[1];
355
356 // Define the functions to find the Vbd
357 TF1 *pol1_before = new TF1("pol1_before", "[0]+x*[1]");
358 TF1 *pol2_after = new TF1("pol2_after", "[0]+x*[1]+x*x*[2]");
359
360 // Fit before and after the Vbd guess
361 // --- before fit
362 pol1_before->SetParameter(0, mean_baseline);
363 pol1_before->SetParameter(1, 0.);
365 // --- after fit
366 pol2_after->SetParameter(0, -500);
367 pol2_after->SetParameter(1, 20);
368 pol2_after->SetParameter(2, -0.5);
370
371 // Intercept of the two lines
372 std::array<std::array<float, 2>, 2> intercept = {{{33, 0.1}, {-25, 0.1}}}; // get_intercept_pol1_pol2(pol1_before, pol2_after);
373 result[0] = intercept[0][0];
374 result[1] = intercept[0][1];
375
376 TF1 *ffull;
377 // Mediate with erf if requested
378 if (erf_mediate)
379 {
380 ffull = new TF1("ffull", "((0.5-0.5*TMath::Erf(((x-[0])/[1])))*([2]+x*[3])+(0.5+0.5*TMath::Erf(((x-[0])/[1])))*([4]+x*[5]+x*x*[6]))");
381 ffull->SetParameter(0, result[0]);
382 ffull->SetParLimits(0, result[0] - max_before_fit, result[0] + min_after_fit);
383 ffull->SetParameter(1, 0.001);
384 ffull->SetParLimits(1, 0.000001, 0.1);
385 ffull->FixParameter(2, pol1_before->GetParameter(0));
386 ffull->FixParameter(3, pol1_before->GetParameter(1));
387 ffull->FixParameter(4, pol2_after->GetParameter(0));
388 ffull->FixParameter(5, pol2_after->GetParameter(1));
389 ffull->FixParameter(6, pol2_after->GetParameter(2));
390 log_graph->Fit(ffull, "RQ", "SAME", result[0] - 4, result[0] + 3.);
391 ffull->SetParLimits(0, intercept[0][0] + ffull->GetParameter(1), intercept[0][0] + 0.2);
392 log_graph->Fit(ffull, "RQ", "SAME", result[0] - 4, result[0] + +3.);
393 result[0] = ffull->GetParameter(0) - ffull->GetParameter(1);
394 result[1] = sqrt(ffull->GetParError(0) * ffull->GetParError(0) + ffull->GetParameter(1) * ffull->GetParameter(1));
395 }
396
397 if (!image_folder.empty())
398 {
399 // Create Canvas with result
400 TCanvas *c1 = new TCanvas("c1", "c1", 600, 500);
401 gPad->SetMargin(0.15, 0.05, 0.10, 0.05);
402
403 // Set-up graph graphics
404 log_graph->GetXaxis()->SetTitle("bias voltage (V)");
405 log_graph->GetYaxis()->SetTitle("log of current");
406 log_graph->SetMarkerStyle(20);
407 log_graph->SetMarkerColor(kAzure - 3);
408 log_graph->GetXaxis()->SetRangeUser(guess_result[0] - 6, guess_result[0] + 3);
409 log_graph->GetYaxis()->SetRangeUser(pol1_before->Eval(result[0] - 6) - 1, pol2_after->Eval(result[0] + 3) + 1);
410 log_graph->Draw("ALPE");
411
412 // Plot all fits
413 pol1_before->SetRange(result[0] - 5, result[0] + 5);
414 pol1_before->SetLineColor(kBlue);
415 pol1_before->DrawCopy("SAME");
416 pol2_after->SetRange(result[0] - 5, result[0] + 5);
417 pol2_after->SetLineColor(kGreen);
418 pol2_after->DrawCopy("SAME");
419 ffull->SetRange(result[0] - 5, result[0] + 5);
420 ffull->SetLineColor(kRed);
421 ffull->DrawCopy("SAME");
422
423 // Write on canvas results
424 TLatex *l1 = new TLatex();
425 l1->DrawLatexNDC(0.45, 0.90, Form("V_{bd} (V)"));
426 l1->DrawLatexNDC(0.18, 0.85, Form("guess"));
427 l1->DrawLatexNDC(0.35, 0.85, Form("= %.2f ", vbd_guess));
428 l1->DrawLatexNDC(0.18, 0.80, Form("intercept"));
429 l1->DrawLatexNDC(0.35, 0.80, Form("= %.2f #pm %.2f", intercept[0][0], intercept[0][1]));
430 if (erf_mediate)
431 {
432 l1->DrawLatexNDC(0.18, 0.75, Form("fit"));
433 l1->DrawLatexNDC(0.35, 0.75, Form("= %.2f #pm %.2f", result[0], result[1]));
434 }
435 //
436 gROOT->ProcessLine(Form(".! mkdir -p %s", image_folder.c_str()));
437 c1->SaveAs((image_folder + "/measure_breakdown_4.pdf").c_str());
438 // delete c1;
439 }
440
441 // delete log_graph;
442 return result;
443
444 /*
445 // Make the log graph
446 auto log_graph = graphutils::log(gTarget);
447
448 // Calculate a guess for the Vbd and have the measured baseline value
449 auto guess_result = breakdown_voltage::find_vbd_guess(log_graph, threshold_guess);
450 auto vbd_guess = guess_result[0];
451 auto mean_baseline = guess_result[1];
452
453 std::array<float, 2> result = {-1, -1};
454 auto log_graph = graphutils::log(gTarget);
455 // Calculate a guess for the Vbd and have the measured baseline value
456 auto vbd_guess_baseline = find_vbd_guess(log_graph);
457 vbd_guess = get<0>(vbd_guess_baseline);
458 auto mean_baseline = get<1>(vbd_guess_baseline);
459 TF1 *pol1_before = new TF1("pol1_before", "[0]+x*[1]");
460 TF1 *pol1_after = new TF1("pol1_after", "[0]+x*[1]+x*x*[2]");
461 pol1_before->SetParameter(0, mean_baseline);
462 pol1_before->SetParameter(1, 0.);
463 pol1_after->SetParameter(0, 0.);
464 pol1_after->SetParameter(1, 4);
465 pol1_after->SetParLimits(2, -1.e3, 0.);
466 pol1_after->SetParameter(2, -0.03);
467 log_graph->Fit(pol1_before, "Q", "", vbd_guess - 5, vbd_guess - 0.3);
468 log_graph->Fit(pol1_after, "Q", "", vbd_guess + 0.3, vbd_guess + 2.3);
469 auto intercept_before = pol1_before->GetParameter(0);
470 auto angularc_before = pol1_before->GetParameter(1);
471 auto c0_after = pol1_after->GetParameter(0);
472 auto c1_after = pol1_after->GetParameter(1);
473 auto c2_after = pol1_after->GetParameter(2);
474 auto delta = sqrt((c1_after - angularc_before) * (c1_after - angularc_before) - 4 * c2_after * (c0_after - intercept_before));
475 auto intercept_before_econtrib = pol1_before->GetParError(0) / (delta);
476 auto angularc_before_econtrib = pol1_before->GetParError(1) * ((c1_after - angularc_before) / (delta) + 1) / (2 * c2_after);
477 auto c0_after_econtrib = pol1_after->GetParError(0) / (delta);
478 auto c1_after_econtrib = -pol1_after->GetParError(1) * ((c1_after - angularc_before) / (delta) + 1) / (2 * c2_after);
479 auto c2_after_econtrib = pol1_after->GetParError(2) * ((c0_after - intercept_before) / (c2_after * delta) - (-delta - c1_after + angularc_before) / (2 * c2_after * c2_after));
480 auto intercept_val = result[0] = (-(c1_after - angularc_before) + delta) / (2 * c2_after);
481 auto intercept_err = result[1] = sqrt(intercept_before_econtrib * intercept_before_econtrib + angularc_before_econtrib * angularc_before_econtrib + c0_after_econtrib * c0_after_econtrib + c1_after_econtrib * c1_after_econtrib + c2_after_econtrib * c2_after_econtrib);
482 TF1 *ffull = new TF1("ffull", "(0.5-0.5*TMath::Erf(((x-[0])/[1])))*([2]+x*[3])+(0.5+0.5*TMath::Erf(((x-[0])/[1])))*([4]+x*[5]+x*x*[6])");
483 ffull->SetParameter(0, result[0] + 0.2);
484 ffull->SetParLimits(0, intercept_val - 0.3, intercept_val + 5.);
485 ffull->SetParameter(1, 0.2);
486 ffull->SetParLimits(1, 0.0001, 0.3);
487 ffull->FixParameter(2, pol1_before->GetParameter(0));
488 ffull->FixParameter(3, pol1_before->GetParameter(1));
489 ffull->FixParameter(4, pol1_after->GetParameter(0));
490 ffull->FixParameter(5, pol1_after->GetParameter(1));
491 ffull->FixParameter(6, pol1_after->GetParameter(2));
492 log_graph->Fit(ffull, "Q", "SAME", result[0] - 4, result[0] + 4.);
493 // ffull->SetParLimits(0, intercept_val + ffull->GetParameter(1), intercept_val + 5.);
494 // log_graph->Fit(ffull, "RQ", "SAME", result[0] - 4, result[0] + 3);
495 result[0] = ffull->GetParameter(0) - ffull->GetParameter(1);
496 result[1] = sqrt(ffull->GetParError(0) * ffull->GetParError(0) + ffull->GetParameter(1) * ffull->GetParameter(1));
497 if (graphics)
498 {
499 TCanvas *c1 = new TCanvas(gTarget->GetName(), "c1", 600, 500);
500 log_graph->Draw("ALP");
501 log_graph->GetXaxis()->SetRangeUser(result[0] - 6, result[0] + 3);
502 auto max = ffull->Eval(result[0] + 2);
503 max = max > 0 ? max * 1.1 : max * 0.9;
504 log_graph->SetMaximum(max);
505 pol1_before->SetRange(result[0] - 5, result[0] + 5);
506 pol1_before->SetLineColor(kBlue);
507 pol1_before->DrawCopy("SAME");
508 pol1_after->SetRange(result[0] - 5, result[0] + 5);
509 pol1_after->SetLineColor(kGreen);
510 pol1_after->DrawCopy("SAME");
511 ffull->SetRange(result[0] - 5, result[0] + 5);
512 ffull->DrawCopy("SAME");
513 TLatex *l1 = new TLatex();
514 l1->DrawLatexNDC(0.2, 0.85, Form("V_{bd} = %.2f #pm %.2f", result[0], result[1]));
515 l1->DrawLatexNDC(0.2, 0.80, Form("V_{bd} (int.) = %.2f #pm %.2f", intercept_val, intercept_err));
516 //
517 TString basedir = get_environment_variable("SIPM4EIC_WORKDIR");
518 basedir += TString("/plots/vbdcheck/");
519 gROOT->ProcessLine(Form(".! mkdir -p %s", basedir.Data()));
520 c1->SaveAs(basedir + gTarget->GetName() + TString(".pdf"));
521 delete c1;
522 }
523 delete log_graph;
524
525 return result;
526 */
527}
528
530{
531 // Method 5:
532 // TODO: write what it does
533
534 // Create result container
535 std::array<float, 2> result = {-1, -1};
536
537 /*
538
539 // Make the log-derivative graph
540 auto log_graph = graphutils::log(gTarget);
541 auto ldv_graph = graphutils::derivate(log_graph);
542 auto ld2_graph = graphutils::derivate(ldv_graph);
543
544 // Calculate a guess for the Vbd and have the measured baseline value
545 auto guess_result = breakdown_voltage::find_vbd_guess(log_graph, threshold_guess);
546 auto vbd_guess = guess_result[0];
547 auto mean_baseline = guess_result[1];
548
549 // Fit the graph
550 TF1 *gaus_peak = new TF1("gaus_peak", "gaus(0)");
551 ld2_graph->Fit(gaus_peak, "Q", "SAME", vbd_guess - 3.5, vbd_guess + 3.5);
552 result[0] = gaus_peak->GetParameter(1);
553 result[1] = gaus_peak->GetParError(1);
554
555 if (!image_folder.empty())
556 {
557 // Create Canvas with result
558 TCanvas *c1 = new TCanvas("c1", "c1", 600, 500);
559 gPad->SetMargin(0.15, 0.05, 0.10, 0.05);
560
561 // Set-up graph graphics
562 ld2_graph->GetXaxis()->SetTitle("bias voltage (V)");
563 ld2_graph->GetYaxis()->SetTitle("double derivative of log of current");
564 ld2_graph->SetMarkerStyle(20);
565 ld2_graph->SetMarkerColor(kAzure - 3);
566 ld2_graph->GetXaxis()->SetRangeUser(result[0] - 4, result[0] + 4);
567 ld2_graph->GetYaxis()->SetRangeUser(gaus_peak->Eval(result[0] + 4) - 1, gaus_peak->Eval(result[0]) + 1);
568 ld2_graph->Draw("ALPE");
569
570 // Plot all fits
571 gaus_peak->SetRange(result[0] - 4, result[0] + 4);
572 gaus_peak->SetLineColor(kRed);
573 gaus_peak->DrawCopy("SAME");
574
575 // Write on canvas results
576 TLatex *l1 = new TLatex();
577 l1->DrawLatexNDC(0.45, 0.90, Form("V_{bd} (V)"));
578 l1->DrawLatexNDC(0.18, 0.85, Form("guess"));
579 l1->DrawLatexNDC(0.35, 0.85, Form("= %.2f ", vbd_guess));
580 l1->DrawLatexNDC(0.18, 0.80, Form("fit"));
581 l1->DrawLatexNDC(0.35, 0.80, Form("= %.2f #pm %.2f", result[0], result[1]));
582 //
583 gROOT->ProcessLine(Form(".! mkdir -p %s", image_folder.c_str()));
584 c1->SaveAs((image_folder + "/measure_breakdown_3.pdf").c_str());
585 delete c1;
586 }
587
588 delete log_graph;
589 delete ldv_graph;
590 delete ld2_graph;
591 return result;
592
593 std::array<float, 2> result = {-1, -1};
594 auto log_graph = graphutils::log(gTarget);
595 TF1 *pol1_before = new TF1("pol1_before", "[0]+x*[1]");
596 TF1 *pol1_after = new TF1("pol1_after", "[0]*(x-[1])^([2])");
597 pol1_after->SetParameter(1, vbd_guess);
598 log_graph->Fit(pol1_before, "MERQ", "", vbd_guess - 5, vbd_guess - 0.2);
599 log_graph->Fit(pol1_after, "MERQ", "", vbd_guess + 0.2, vbd_guess + 5);
600 TF1 *ffull = new TF1("ffull", "([1]+x*[2])+(x>[0])*(+[3]*(x-[4])^([5]))");
601 ffull->SetParameter(0, vbd_guess);
602 ffull->FixParameter(1, pol1_before->GetParameter(0));
603 ffull->FixParameter(2, pol1_before->GetParameter(1));
604 ffull->FixParameter(3, pol1_after->GetParameter(0));
605 ffull->FixParameter(4, pol1_after->GetParameter(1));
606 ffull->FixParameter(5, pol1_after->GetParameter(2));
607 log_graph->Fit(ffull, "MERQ", "SAME", vbd_guess - 3, vbd_guess + 3);
608 result[0] = 48; // ffull->GetParameter(0) - ffull->GetParameter(1);
609 result[1] = sqrt(ffull->GetParError(0) * ffull->GetParError(0) + ffull->GetParameter(1) * ffull->GetParameter(1));
610 if (graphics)
611 {
612 TCanvas *c1 = new TCanvas();
613 log_graph->Draw("ALP");
614 log_graph->GetXaxis()->SetRangeUser(result[0] - 2, result[0] + 2);
615 pol1_before->SetRange(result[0] - 5, result[0] + 5);
616 pol1_before->SetLineColor(kBlue);
617 pol1_before->DrawCopy("SAME");
618 pol1_after->SetRange(result[0] - 5, result[0] + 5);
619 pol1_after->SetLineColor(kGreen);
620 pol1_after->DrawCopy("SAME");
621 ffull->SetRange(result[0] - 5, result[0] + 5);
622 ffull->DrawCopy("SAME");
623 TLatex *l1 = new TLatex();
624 l1->DrawLatexNDC(0.2, 0.85, Form("V_{bd} = %.2f #pm %.2f", result[0], result[1]));
625 //
626 TString basedir = get_environment_variable("SIPM4EIC_WORKDIR");
627 basedir += TString("/plots/vbdcheck/");
628 gROOT->ProcessLine(Form(".! mkdir -p %s", basedir.Data()));
629 c1->SaveAs(basedir + gTarget->GetName() + TString(".pdf"));
630 delete c1;
631 }
632 delete log_graph;
633 result[0] = ffull->GetParameter(0);
634 result[1] = sqrt(ffull->GetParError(0) * ffull->GetParError(0));
635 */
636 return result;
637}
638
639// database::get_average_iv_at_overvoltage(current_boards, current_sensor, current_status, {3});
640
641std::array<float, 2> breakdown_voltage::measure_breakdown_4(std::string board, std::string sensor, std::string step)
642{
644 current_overvoltage += sensor_to_vbd[sensor] + sensor_to_vbd_Tdep[sensor] * (std::stof(get_database_info(board_list[0], step, "temp")) - 243);
646 for (auto iPnt = 0; iPnt < result->GetN(); ++iPnt)
647 result->GetX()[iPnt] -= sensor_to_vbd[sensor] + sensor_to_vbd_Tdep[sensor] * (std::stof(get_database_info(board_list[0], step, "temp")) - 243);
648 result->SetMarkerStyle(marker);
649 result->SetMarkerColor(color);
650 return result;
651}
652
653/*
654namespace threshold_scan
655{
656 std::array<std::array<float, 2>, 2> measure_cross_talk_and_signal_amp(TGraphErrors *gTarget, std::string plot_name)
657}
658
659std::array<std::array<float, 2>, 2> threshold_scan::measure_cross_talk_and_signal_amp(TGraphErrors *gTarget, std::string plot_name)
660{
661 // Clone the target TGraphErrors for drawing check
662 auto new_target = (TGraphErrors *)(gTarget->Clone("new_target"));
663
664 // --- Beautifying
665 new_target->SetMarkerStyle(20);
666 new_target->SetMarkerColor(kAzure - 3);
667
668 // --- Drawing check
669 TGraphErrors *check_my_points = new TGraphErrors();
670 check_my_points->SetMarkerStyle(24);
671 check_my_points->SetMarkerColor(kRed);
672 check_my_points->SetMarkerSize(1.2);
673
674 // Plateau calculation
675 std::array<std::array<float, 2>, 2> plateau_values;
676
677 // --- Start roughly at mid-point of first plateau
678 auto first_plateau_tolerance = 0.25;
679 auto second_plateau_tolerance = 0.50;
680 auto start_point_plateau = 5;
681 plateau_values[0][0] = gTarget->GetPointY(start_point_plateau);
682 plateau_values[0][1] = gTarget->GetErrorY(start_point_plateau) * gTarget->GetErrorY(start_point_plateau);
683 first_plateau_tolerance += (gTarget->GetErrorY(start_point_plateau) / gTarget->GetPointY(start_point_plateau));
684
685 // --- Add point to check drawing
686 check_my_points->SetPoint(0, gTarget->GetPointX(start_point_plateau), gTarget->GetPointY(start_point_plateau));
687
688 // --- Utility for the mean calculation
689 auto cuncurrent_points = 1;
690
691 // Start looping to the left
692 for (auto iPnt = start_point_plateau + 1; iPnt < gTarget->GetN(); iPnt++)
693 {
694 auto current_x_val = gTarget->GetPointX(iPnt);
695 auto current_x_err = gTarget->GetErrorX(iPnt);
696 auto current_y_val = gTarget->GetPointY(iPnt);
697 auto current_y_err = gTarget->GetErrorY(iPnt);
698 // Stop when the points deviate over tolerance
699 if (fabs((current_y_val - plateau_values[0][0] / cuncurrent_points) / (plateau_values[0][0] / cuncurrent_points)) > first_plateau_tolerance)
700 break;
701 cuncurrent_points++;
702 plateau_values[0][0] += current_y_val;
703 plateau_values[0][1] += current_y_err * current_y_err;
704
705 // --- Add point to check drawing
706 check_my_points->SetPoint(check_my_points->GetN(), gTarget->GetPointX(iPnt), gTarget->GetPointY(iPnt));
707 }
708 // Start looping to the right
709 for (auto iPnt = start_point_plateau - 1; iPnt >= 0; iPnt--)
710 {
711 auto current_y_val = gTarget->GetPointY(iPnt);
712 auto current_y_err = gTarget->GetErrorY(iPnt);
713 // Stop when the points deviate over 15%
714 if (fabs((current_y_val - plateau_values[0][0] / cuncurrent_points) / (plateau_values[0][0] / cuncurrent_points)) > first_plateau_tolerance)
715 break;
716 cuncurrent_points++;
717 plateau_values[0][0] += current_y_val;
718 plateau_values[0][1] += current_y_err * current_y_err;
719 // --- Add point to check drawing
720 check_my_points->SetPoint(check_my_points->GetN(), gTarget->GetPointX(iPnt), gTarget->GetPointY(iPnt));
721 }
722
723 // --- Finalise calculation
724 plateau_values[0][0] /= cuncurrent_points;
725 plateau_values[0][1] = sqrt(plateau_values[0][1]);
726 plateau_values[0][1] /= cuncurrent_points;
727
728 // --- Start roughly at mid-point of first plateau
729 start_point_plateau = cuncurrent_points + 5;
730 plateau_values[1][0] = gTarget->GetPointY(start_point_plateau);
731 plateau_values[1][1] = gTarget->GetErrorY(start_point_plateau) * gTarget->GetErrorY(start_point_plateau);
732 second_plateau_tolerance += (gTarget->GetErrorY(start_point_plateau) / gTarget->GetPointY(start_point_plateau));
733
734 // --- Add point to check drawing
735 check_my_points->SetPoint(check_my_points->GetN(), gTarget->GetPointX(start_point_plateau), gTarget->GetPointY(start_point_plateau));
736
737 // --- Utility for the mean calculation
738 cuncurrent_points = 1;
739
740 // Start looping to the left
741 for (auto iPnt = start_point_plateau + 1; iPnt < gTarget->GetN(); iPnt++)
742 {
743 auto current_y_val = gTarget->GetPointY(iPnt);
744 auto current_y_err = gTarget->GetErrorY(iPnt);
745 // Stop when the points deviate over 15%
746 if (fabs((current_y_val - plateau_values[1][0] / cuncurrent_points) / (plateau_values[1][0] / cuncurrent_points)) > second_plateau_tolerance)
747 break;
748 cuncurrent_points++;
749 plateau_values[1][0] += current_y_val;
750 plateau_values[1][1] += current_y_err * current_y_err;
751 // --- Add point to check drawing
752 check_my_points->SetPoint(check_my_points->GetN(), gTarget->GetPointX(iPnt), gTarget->GetPointY(iPnt));
753 }
754 for (auto iPnt = start_point_plateau - 1; iPnt >= 0; iPnt--)
755 {
756 auto current_y_val = gTarget->GetPointY(iPnt);
757 auto current_y_err = gTarget->GetErrorY(iPnt);
758 // Stop when the points deviate over 15%
759 if (fabs((current_y_val - plateau_values[1][0] / cuncurrent_points) / (plateau_values[1][0] / cuncurrent_points)) > second_plateau_tolerance)
760 break;
761 cuncurrent_points++;
762 plateau_values[1][0] += current_y_val;
763 plateau_values[1][1] += current_y_err * current_y_err;
764 // --- Add point to check drawing
765 check_my_points->SetPoint(check_my_points->GetN(), gTarget->GetPointX(iPnt), gTarget->GetPointY(iPnt));
766 }
767 // --- Finalise calculation
768 plateau_values[1][0] /= cuncurrent_points;
769 plateau_values[1][1] = sqrt(plateau_values[1][1]);
770 plateau_values[1][1] /= cuncurrent_points;
771
772 // Error calculation
773 auto error_on_first_plateau = plateau_values[0][1] * plateau_values[0][1] * ((plateau_values[1][0]) / ((plateau_values[0][0] - plateau_values[1][0]) * (plateau_values[0][0] - plateau_values[1][0])));
774 auto error_on_second_plateau = plateau_values[1][1] * plateau_values[1][1] * ((plateau_values[0][0]) / ((plateau_values[0][0] - plateau_values[1][0]) * (plateau_values[0][0] - plateau_values[1][0])));
775
776 // Plot if requested
777 if (!plot_name.empty())
778 {
779 TCanvas *c1 = new TCanvas();
780 TLatex *lLatex = new TLatex();
781 gPad->SetLogy();
782 new_target->Draw("AP");
783 check_my_points->Draw("SAME P");
784 lLatex->DrawLatexNDC(0.6, 0.8, Form("CT: %.1f#pm%.1f%% ", 100 * plateau_values[1][0] / (plateau_values[0][0] - plateau_values[1][0]), 100 * sqrt(error_on_first_plateau * error_on_first_plateau + error_on_second_plateau * error_on_second_plateau)));
785 c1->SaveAs(Form("%s.pdf", plot_name.c_str()));
786 }
787
788 // Return
789 std::array<float, 2> cross_talk = {plateau_values[1][0] / (plateau_values[0][0] - plateau_values[1][0]), sqrt(error_on_first_plateau * error_on_first_plateau + error_on_second_plateau * error_on_second_plateau)};
790 std::array<float, 2> sig_ampl = {-1., -1.};
791 return {cross_talk, sig_ampl};
792}
793*/
794/*
795
796// List of methods to determine the breakdwon voltage in a I-V curve
797// methods taken from https://arxiv.org/abs/1606.07805
798//
799// !TODO: Clean-up graph utils and make new general util repository
800//
801typedef std::map<std::string, std::map<std::string, std::map<std::string, std::array<double, 2>>>> breakdown_voltages_type;
802typedef std::map<std::string, std::map<std::string, std::map<std::string, std::map<std::string, std::array<double, 2>>>>> breakdown_voltages_sensors_type;
803//
804//
805std::array<float, 2>
806measure_breakdown_4(TGraphErrors *gTarget, float vbd_guess, bool graphics = false)
807{
808 std::array<float, 2> result = {-1, -1};
809 auto log_graph = graphutils::log(gTarget);
810 // Calculate a guess for the Vbd and have the measured baseline value
811 auto vbd_guess_baseline = find_vbd_guess(log_graph);
812 vbd_guess = get<0>(vbd_guess_baseline);
813 auto mean_baseline = get<1>(vbd_guess_baseline);
814 TF1 *pol1_before = new TF1("pol1_before", "[0]+x*[1]");
815 TF1 *pol1_after = new TF1("pol1_after", "[0]+x*[1]+x*x*[2]");
816 pol1_before->SetParameter(0, mean_baseline);
817 pol1_before->SetParameter(1, 0.);
818 pol1_after->SetParameter(0, 0.);
819 pol1_after->SetParameter(1, 4);
820 pol1_after->SetParLimits(2, -1.e3, 0.);
821 pol1_after->SetParameter(2, -0.03);
822 log_graph->Fit(pol1_before, "Q", "", vbd_guess - 5, vbd_guess - 0.3);
823 log_graph->Fit(pol1_after, "Q", "", vbd_guess + 0.3, vbd_guess + 2.3);
824 auto intercept_before = pol1_before->GetParameter(0);
825 auto angularc_before = pol1_before->GetParameter(1);
826 auto c0_after = pol1_after->GetParameter(0);
827 auto c1_after = pol1_after->GetParameter(1);
828 auto c2_after = pol1_after->GetParameter(2);
829 auto delta = sqrt((c1_after - angularc_before) * (c1_after - angularc_before) - 4 * c2_after * (c0_after - intercept_before));
830 auto intercept_before_econtrib = pol1_before->GetParError(0) / (delta);
831 auto angularc_before_econtrib = pol1_before->GetParError(1) * ((c1_after - angularc_before) / (delta) + 1) / (2 * c2_after);
832 auto c0_after_econtrib = pol1_after->GetParError(0) / (delta);
833 auto c1_after_econtrib = -pol1_after->GetParError(1) * ((c1_after - angularc_before) / (delta) + 1) / (2 * c2_after);
834 auto c2_after_econtrib = pol1_after->GetParError(2) * ((c0_after - intercept_before) / (c2_after * delta) - (-delta - c1_after + angularc_before) / (2 * c2_after * c2_after));
835 auto intercept_val = result[0] = (-(c1_after - angularc_before) + delta) / (2 * c2_after);
836 auto intercept_err = result[1] = sqrt(intercept_before_econtrib * intercept_before_econtrib + angularc_before_econtrib * angularc_before_econtrib + c0_after_econtrib * c0_after_econtrib + c1_after_econtrib * c1_after_econtrib + c2_after_econtrib * c2_after_econtrib);
837 TF1 *ffull = new TF1("ffull", "(0.5-0.5*TMath::Erf(((x-[0])/[1])))*([2]+x*[3])+(0.5+0.5*TMath::Erf(((x-[0])/[1])))*([4]+x*[5]+x*x*[6])");
838 ffull->SetParameter(0, result[0] + 0.2);
839 ffull->SetParLimits(0, intercept_val - 0.3, intercept_val + 5.);
840 ffull->SetParameter(1, 0.2);
841 ffull->SetParLimits(1, 0.0001, 0.3);
842 ffull->FixParameter(2, pol1_before->GetParameter(0));
843 ffull->FixParameter(3, pol1_before->GetParameter(1));
844 ffull->FixParameter(4, pol1_after->GetParameter(0));
845 ffull->FixParameter(5, pol1_after->GetParameter(1));
846 ffull->FixParameter(6, pol1_after->GetParameter(2));
847 log_graph->Fit(ffull, "Q", "SAME", result[0] - 4, result[0] + 4.);
848 // ffull->SetParLimits(0, intercept_val + ffull->GetParameter(1), intercept_val + 5.);
849 // log_graph->Fit(ffull, "RQ", "SAME", result[0] - 4, result[0] + 3);
850 result[0] = ffull->GetParameter(0) - ffull->GetParameter(1);
851 result[1] = sqrt(ffull->GetParError(0) * ffull->GetParError(0) + ffull->GetParameter(1) * ffull->GetParameter(1));
852 if (graphics)
853 {
854 TCanvas *c1 = new TCanvas(gTarget->GetName(), "c1", 600, 500);
855 log_graph->Draw("ALP");
856 log_graph->GetXaxis()->SetRangeUser(result[0] - 6, result[0] + 3);
857 auto max = ffull->Eval(result[0] + 2);
858 max = max > 0 ? max * 1.1 : max * 0.9;
859 log_graph->SetMaximum(max);
860 pol1_before->SetRange(result[0] - 5, result[0] + 5);
861 pol1_before->SetLineColor(kBlue);
862 pol1_before->DrawCopy("SAME");
863 pol1_after->SetRange(result[0] - 5, result[0] + 5);
864 pol1_after->SetLineColor(kGreen);
865 pol1_after->DrawCopy("SAME");
866 ffull->SetRange(result[0] - 5, result[0] + 5);
867 ffull->DrawCopy("SAME");
868 TLatex *l1 = new TLatex();
869 l1->DrawLatexNDC(0.2, 0.85, Form("V_{bd} = %.2f #pm %.2f", result[0], result[1]));
870 l1->DrawLatexNDC(0.2, 0.80, Form("V_{bd} (int.) = %.2f #pm %.2f", intercept_val, intercept_err));
871 //
872 TString basedir = get_environment_variable("SIPM4EIC_WORKDIR");
873 basedir += TString("/plots/vbdcheck/");
874 gROOT->ProcessLine(Form(".! mkdir -p %s", basedir.Data()));
875 c1->SaveAs(basedir + gTarget->GetName() + TString(".pdf"));
876 delete c1;
877 }
878 delete log_graph;
879 return result;
880}
881//
882//
883std::array<float, 2>
884measure_breakdown_6(TGraphErrors *gTarget, float vbd_guess, bool graphics = false)
885{
886 std::array<float, 2> result = {-1, -1};
887 auto current_graph = (TGraphErrors *)gTarget->Clone("tmp");
888 TF1 *fprebefore = new TF1("fprebefore", "[0]");
889 TF1 *pol1_before = new TF1("pol1_before", "[0]+x*[1]");
890 TF1 *pol1_after = new TF1("pol1_after", "(TMath::Sign([3],(x-[0])))*(TMath::Power(TMath::Abs(x-[0])/([1]),[2]))");
891 pol1_before->FixParameter(0, fprebefore->GetParameter(0));
892 pol1_after->FixParameter(0, vbd_guess);
893 pol1_after->SetParLimits(1, 1.e-12, 1.e1);
894 pol1_after->SetParameter(1, .7);
895 pol1_after->SetParLimits(2, 1.e-12, 1.e1);
896 pol1_after->SetParameter(2, .1);
897 pol1_after->SetParameter(3, fprebefore->GetParameter(0));
898 pol1_after->FixParameter(0, vbd_guess);
899 pol1_after->SetParameter(1, 7.17717e-01);
900 pol1_after->SetParameter(2, 1.);
901 pol1_after->SetParameter(3, 4.59948e-09);
902 current_graph->Fit(pol1_before, "MERQ", "", vbd_guess - 5, vbd_guess - 0.2);
903 current_graph->Fit(pol1_after, "MERQ", "", vbd_guess + 0.2, vbd_guess + 5);
904 TF1 *ffull = new TF1("ffull", "(0.5-0.5*TMath::Erf((x-[0])/[1]))*([2]+x*[3])+(0.5+0.5*TMath::Erf(((x-[0])/[1])))*([2]+x*[3]+(TMath::Sign([7],(x-[4])))*(TMath::Power(TMath::Abs(x-[4])/([5]),[6])))");
905 ffull->SetParameter(0, vbd_guess);
906 ffull->SetParameter(1, 0.2);
907 ffull->SetParLimits(1, 0.0001, 0.3);
908 ffull->FixParameter(2, pol1_before->GetParameter(0));
909 ffull->FixParameter(3, pol1_before->GetParameter(1));
910 ffull->FixParameter(4, pol1_after->GetParameter(0));
911 ffull->FixParameter(5, pol1_after->GetParameter(1));
912 ffull->FixParameter(6, pol1_after->GetParameter(2));
913 ffull->FixParameter(7, pol1_after->GetParameter(3));
914 current_graph->Fit(ffull, "MERQ", "SAME", vbd_guess - 5, vbd_guess + 5);
915 result[0] = ffull->GetParameter(0) - ffull->GetParameter(1);
916 result[1] = sqrt(ffull->GetParError(0) * ffull->GetParError(0) + ffull->GetParameter(1) * ffull->GetParameter(1));
917 if (graphics)
918 {
919 TCanvas *c1 = new TCanvas();
920 gPad->SetLogy();
921 current_graph->Draw("ALP");
922 current_graph->GetXaxis()->SetRangeUser(result[0] - 5, result[0] + 5);
923 pol1_before->SetRange(result[0] - 5, result[0] + 5);
924 pol1_before->SetLineColor(kBlue);
925 pol1_before->DrawCopy("SAME");
926 pol1_after->SetRange(result[0] - 5, result[0] + 5);
927 pol1_after->SetLineColor(kGreen);
928 pol1_after->DrawCopy("SAME");
929 ffull->SetRange(result[0] - 5, result[0] + 5);
930 ffull->DrawCopy("SAME");
931 TLatex *l1 = new TLatex();
932 l1->DrawLatexNDC(0.2, 0.85, Form("V_{bd} = %.2f #pm %.2f", result[0], result[1]));
933 //
934 TString basedir = get_environment_variable("SIPM4EIC_WORKDIR");
935 basedir += TString("/plots/vbdcheck/");
936 gROOT->ProcessLine(Form(".! mkdir -p %s", basedir.Data()));
937 c1->SaveAs(basedir + gTarget->GetName() + TString(".pdf"));
938 delete c1;
939 }
940 delete current_graph;
941 result[0] = ffull->GetParameter(0);
942 result[1] = sqrt(ffull->GetParError(0) * ffull->GetParError(0));
943 return result;
944}
945//
946std::array<float, 2>
947measure_breakdown_100(TGraphErrors *gTarget, float vbd_guess, bool graphics = false)
948{
949 // Generate result pair
950 std::array<float, 2> result = {-1, -1};
951 // Geenrate local copy of graph
952 auto current_graph = (TGraphErrors *)gTarget->Clone();
953 // Linear fit to find with extrapolation the crossing of X-axis
954 TF1 *pol1_after = new TF1("pol1_after", "(x-[0])/[1]");
955 TF1 *ffull = new TF1("ffull", "(x-[0])/[1]+[2]/(x-[3])");
956 ffull->SetParLimits(2, 0., 1.e8);
957 // Function prepping
958 // After fitting
959 pol1_after->FixParameter(0, vbd_guess);
960 pol1_after->SetParameter(1, 1. / (current_graph->Eval(vbd_guess + 3) - current_graph->Eval(vbd_guess + 2)));
961 current_graph->Fit(pol1_after, "MEQ", "", vbd_guess + 2.0, vbd_guess + 2.5);
962 pol1_after->SetParLimits(0, vbd_guess - 3, vbd_guess + 3);
963 current_graph->Fit(pol1_after, "MEQ", "", vbd_guess + 2.0, vbd_guess + 2.5);
964 // Full fitting
965 ffull->FixParameter(0, pol1_after->GetParameter(0));
966 ffull->FixParameter(1, pol1_after->GetParameter(1));
967 ffull->SetParameter(2, 1.e+05);
968 ffull->FixParameter(3, pol1_after->GetParameter(0) + 0.5);
969 current_graph->Fit(ffull, "MEQ", "", vbd_guess + 0.5, vbd_guess + 2.5);
970 ffull->SetParLimits(0, vbd_guess - 3, vbd_guess + 3);
971 ffull->ReleaseParameter(1);
972 ffull->SetParLimits(3, vbd_guess - 3, vbd_guess + 3);
973 current_graph->Fit(ffull, "MEQ", "", vbd_guess + 0.5, vbd_guess + 2.5);
974 // Set Parameters for show
975 pol1_after->SetParameter(0, ffull->GetParameter(0));
976 pol1_after->SetParameter(1, ffull->GetParameter(1));
977 // Save result
978 result[0] = ffull->GetParameter(0);
979 result[1] = ffull->GetParError(0);
980 // Plot if requested
981 if (graphics)
982 {
983 TCanvas *c1 = new TCanvas();
984 gPad->SetLogy();
985 current_graph->Draw("ALP");
986 current_graph->GetXaxis()->SetRangeUser(result[0] - 5, result[0] + 5);
987 pol1_after->SetRange(result[0] - 5, result[0] + 5);
988 pol1_after->SetLineColor(kBlue);
989 pol1_after->DrawCopy("SAME");
990 ffull->SetRange(result[0] - 5, result[0] + 5);
991 ffull->SetLineColor(kRed);
992 ffull->DrawCopy("SAME");
993 // Declare found Vbd value
994 TLatex *l1 = new TLatex();
995 l1->DrawLatexNDC(0.2, 0.85, Form("V_{bd} = %.2f #pm %.2f", result[0], result[1]));
996 // Save plot
997 TString basedir = get_environment_variable("SIPM4EIC_WORKDIR");
998 basedir += TString("/plots/vbdcheck/");
999 gROOT->ProcessLine(Form(".! mkdir -p %s", basedir.Data()));
1000 c1->SaveAs(basedir + gTarget->GetName() + TString(".pdf"));
1001 delete c1;
1002 }
1003 delete current_graph;
1004 return result;
1005}
1006//
1007template <int mode_select = 6>
1008std::array<float, 2>
1009measure_breakdown(TGraphErrors *gTarget, float vbd_guess, bool graphics = true)
1010{
1011 switch (mode_select)
1012 {
1013 // Breakdown Voltage from IV curves
1014 case 0:
1015 return measure_breakdown_0(gTarget, vbd_guess, graphics);
1016 break;
1017 case 1:
1018 return measure_breakdown_1(gTarget, vbd_guess, graphics);
1019 break;
1020 case 2:
1021 return measure_breakdown_2(gTarget, vbd_guess, graphics);
1022 break;
1023 case 3:
1024 return measure_breakdown_3(gTarget, vbd_guess, graphics);
1025 break;
1026 case 4:
1027 return measure_breakdown_4(gTarget, vbd_guess, graphics);
1028 break;
1029 case 5:
1030 return measure_breakdown_5(gTarget, vbd_guess, graphics);
1031 break;
1032 case 6:
1033 return measure_breakdown_6(gTarget, vbd_guess, graphics);
1034 break;
1035 // Breakdown Voltage from DCR curves
1036 case 100:
1037 return measure_breakdown_100(gTarget, vbd_guess, graphics);
1038 break;
1039 default:
1040 return measure_breakdown_4(gTarget, vbd_guess, graphics);
1041 break;
1042 }
1043}
1044//
1045template <int mode_select = 1000>
1046std::array<float, 2>
1047measure_breakdown(TGraphErrors *gTarget, float vbd_guess, int ncycles, float tolerance = 1.e-2)
1048{
1049 auto initial_guess = measure_breakdown<mode_select>(gTarget, vbd_guess);
1050 for (int iTer = 0; iTer < ncycles; iTer++)
1051 {
1052 auto new_guess = measure_breakdown<mode_select>(gTarget, get<0>(initial_guess));
1053 if (fabs(get<0>(new_guess) - get<0>(initial_guess)) < tolerance)
1054 {
1055 return new_guess;
1056 }
1057 initial_guess = new_guess;
1058 }
1059 return initial_guess;
1060}
1061//
1062template <bool recalulate_vbd = true,
1063 int method = 4>
1064TGraphErrors *
1065shift_with_vbd(TGraphErrors *gTarget, float vbd_guess)
1066{
1067 auto new_target = (TGraphErrors *)gTarget->Clone(gTarget->GetName() + TString("_tmp"));
1068 auto vbd_shift_by = 0.;
1069 if (recalulate_vbd)
1070 {
1071 vbd_shift_by = get<0>(measure_breakdown<method>(new_target, vbd_guess));
1072 }
1073 else
1074 {
1075 vbd_shift_by = vbd_guess;
1076 }
1077 graphutils::x_shift(new_target, vbd_shift_by);
1078 return new_target;
1079}
1080//
1081template <bool recalulate_vbd = true>
1082std::array<float, 2>
1083overvoltage_ratio(TGraphErrors *gNumerator, TGraphErrors *gDenominator, float guess_vbd_num, float guess_vbd_den, float _xcoordinate)
1084{
1085 std::array<float, 2> result;
1086 std::array<float, 2> numerator;
1087 std::array<float, 2> denominator;
1088 if (recalulate_vbd)
1089 {
1090 gNumerator->SetName("gNumerator");
1091 gDenominator->SetName("gDenominator");
1092 numerator = eval_with_errors(shift_with_vbd(gNumerator, guess_vbd_num), _xcoordinate);
1093 denominator = eval_with_errors(shift_with_vbd(gDenominator, guess_vbd_den), _xcoordinate);
1094 }
1095 else
1096 {
1097 auto new_numerator = (TGraphErrors *)gNumerator->Clone("tmp");
1098 auto new_denominator = (TGraphErrors *)gDenominator->Clone("tmp");
1099 graphutils::x_shift(new_numerator, guess_vbd_num);
1100 graphutils::x_shift(new_denominator, guess_vbd_den);
1101 numerator = eval_with_errors(new_numerator, _xcoordinate);
1102 denominator = eval_with_errors(new_denominator, _xcoordinate);
1103 }
1104 result[0] = get<0>(numerator) / get<0>(denominator);
1105 result[1] = result[0] * ((get<1>(numerator) / get<0>(numerator)) * (get<1>(numerator) / get<0>(numerator)) + (get<1>(denominator) / get<0>(denominator)) * (get<1>(denominator) / get<0>(denominator)));
1106 return result;
1107}
1108//
1109template <bool recalulate_vbd = true>
1110TGraphErrors *
1111overvoltage_ratio(TGraphErrors *gNumerator, TGraphErrors *gDenominator, float guess_vbd_num, float guess_vbd_den, std::vector<float> _xcoordinates)
1112{
1113 TGraphErrors *result = new TGraphErrors();
1114 std::array<float, 2> current_ratio;
1115 std::array<float, 2> numerator;
1116 std::array<float, 2> denominator;
1117 auto new_numerator = (TGraphErrors *)gNumerator->Clone("gNumerator");
1118 auto new_denominator = (TGraphErrors *)gDenominator->Clone("gDenominator");
1119 if (recalulate_vbd)
1120 {
1121 shift_with_vbd(gNumerator, guess_vbd_num);
1122 shift_with_vbd(gDenominator, guess_vbd_den);
1123 }
1124 else
1125 {
1126 graphutils::x_shift(new_numerator, guess_vbd_num);
1127 graphutils::x_shift(new_denominator, guess_vbd_den);
1128 }
1129 for (auto _xcoordinate : _xcoordinates)
1130 {
1131 numerator = eval_with_errors(new_numerator, _xcoordinate);
1132 denominator = eval_with_errors(new_denominator, _xcoordinate);
1133 if (get<0>(denominator) == 0)
1134 {
1135 continue;
1136 }
1137 if ((get<0>(numerator) == get<1>(numerator)) && (get<0>(numerator) == -1))
1138 {
1139 continue;
1140 }
1141 if ((get<0>(denominator) == get<1>(denominator)) && (get<0>(denominator) == -1))
1142 {
1143 continue;
1144 }
1145 get<0>(current_ratio) = get<0>(numerator) / get<0>(denominator);
1146 auto numerator_err = (get<1>(numerator) / get<0>(numerator));
1147 auto denominator_err = (get<1>(denominator) / get<0>(denominator));
1148 get<1>(current_ratio) = get<0>(current_ratio) * sqrt(numerator_err * numerator_err + denominator_err * denominator_err);
1149 auto current_point = result->GetN();
1150 result->SetPoint(current_point, _xcoordinate, get<0>(current_ratio));
1151 result->SetPointError(current_point, 0, get<1>(current_ratio));
1152 }
1153 return result;
1154}
1155//
1156template <bool recalulate_vbd = true>
1157TGraphErrors *
1158overvoltage_difference(TGraphErrors *gNumerator, TGraphErrors *gDenominator, float guess_vbd_num, float guess_vbd_den, std::vector<float> _xcoordinates)
1159{
1160 TGraphErrors *result = new TGraphErrors();
1161 std::array<float, 2> current_ratio;
1162 std::array<float, 2> numerator;
1163 std::array<float, 2> denominator;
1164 auto new_numerator = (TGraphErrors *)gNumerator->Clone("gNumerator");
1165 auto new_denominator = (TGraphErrors *)gDenominator->Clone("gDenominator");
1166 if (recalulate_vbd)
1167 {
1168 shift_with_vbd(gNumerator, guess_vbd_num);
1169 shift_with_vbd(gDenominator, guess_vbd_den);
1170 }
1171 else
1172 {
1173 graphutils::x_shift(new_numerator, guess_vbd_num);
1174 graphutils::x_shift(new_denominator, guess_vbd_den);
1175 }
1176 for (auto _xcoordinate : _xcoordinates)
1177 {
1178 numerator = eval_with_errors(new_numerator, _xcoordinate);
1179 denominator = eval_with_errors(new_denominator, _xcoordinate);
1180 if ((get<0>(numerator) == get<1>(numerator)) && (get<0>(numerator) == -1))
1181 {
1182 continue;
1183 }
1184 if ((get<0>(denominator) == get<1>(denominator)) && (get<0>(denominator) == -1))
1185 {
1186 continue;
1187 }
1188 get<0>(current_ratio) = get<0>(numerator) - get<0>(denominator);
1189 get<1>(current_ratio) = sqrt(get<1>(numerator) * get<1>(numerator) + get<1>(numerator) * get<1>(numerator));
1190 auto current_point = result->GetN();
1191 result->SetPoint(current_point, _xcoordinate, get<0>(current_ratio));
1192 result->SetPointError(current_point, 0, get<1>(current_ratio));
1193 }
1194 return result;
1195}
1196//
1197template <int method = 6>
1198TGraphErrors *
1199measure_gain(TGraphErrors *iv_graph, TGraphErrors *dcr_graph, double vbd_guess)
1200{
1201 // Make tmp
1202 auto current_iv = (TGraphErrors *)iv_graph->Clone("tmp_IV");
1203 auto current_dcr = (TGraphErrors *)dcr_graph->Clone("tmp_DCR");
1204
1205 // Shift with Vbd
1206 auto current_vbd = method < 0 ? vbd_guess : get<0>(measure_breakdown<method>(current_iv, vbd_guess));
1207 graphutils::x_shift(current_iv, current_vbd);
1208 graphutils::x_shift(current_dcr, current_vbd);
1209
1210 // Subtract surface current from IV
1211 float surface_current_average = 0.;
1212 for (int iPoint = 0; iPoint < 5; ++iPoint)
1213 {
1214 surface_current_average += current_iv->GetY()[iPoint];
1215 }
1216 graphutils::y_shift(current_iv, surface_current_average / 5.);
1217
1218 // Calculate gain
1219 auto current_gain = graphutils::ratio(current_iv, current_dcr);
1220 graphutils::y_scale(current_gain, 1. / TMath::Qe());
1221
1222 // Delete tmp
1223 delete current_iv;
1224 delete current_dcr;
1225
1226 // return
1227 return current_gain;
1228}
1229//
1230template <int method = 6>
1231std::vector<TGraphErrors *>
1232measure_gain(std::vector<TGraphErrors *> iv_graphs, std::vector<TGraphErrors *> dcr_graphs, std::vector<double> vbd_guess)
1233{
1234 std::vector<TGraphErrors *> result;
1235 auto iTer = -1;
1236 for (auto current_iv : iv_graphs)
1237 {
1238 iTer++;
1239 result.push_back(measure_gain<method>(iv_graphs.at(iTer), dcr_graphs.at(iTer), vbd_guess.at(iTer)));
1240 }
1241 //
1242 return result;
1243}
1244//
1245template <int method = 6>
1246std::vector<TGraphErrors *>
1247measure_gain(std::vector<TGraphErrors *> iv_graphs, std::vector<TGraphErrors *> dcr_graphs, double vbd_guess)
1248{
1249 std::vector<TGraphErrors *> result;
1250 auto iTer = -1;
1251 for (auto current_iv : iv_graphs)
1252 {
1253 iTer++;
1254 result.push_back(measure_gain<method>(iv_graphs.at(iTer), dcr_graphs.at(iTer), vbd_guess));
1255 }
1256 //
1257 return result;
1258}
1259//
1260template <int method = 6>
1261std::vector<TGraphErrors *>
1262measure_gain(std::vector<TGraphErrors *> iv_graphs, std::vector<TGraphErrors *> dcr_graphs, std::map<TString, std::array<double, 2>> breakdown_voltages)
1263{
1264 std::vector<TGraphErrors *> result;
1265 auto iTer = -1;
1266 for (auto current_iv : iv_graphs)
1267 {
1268 iTer++;
1269 result.push_back(measure_gain<-1>(iv_graphs.at(iTer), dcr_graphs.at(iTer), get<0>(breakdown_voltages[iv_graphs.at(iTer)->GetName()])));
1270 }
1271 //
1272 return result;
1273}
1274//
1275namespace database
1276{
1277 // https://docs.google.com/document/d/1Z3A6zrad5A-7HcmOVEIBOqT7nCkWAe4-ilvuk-I16rs/edit#heading=h.a7bxpd1bw3ht
1278 //
1279 // --- Breakdown voltage
1280 // Storage for on-the-fly Vbd
1281 // --- board - channel - step
1282 breakdown_voltages_type breakdown_voltages;
1283 // --- sensor - step - board - channel
1284 breakdown_voltages_sensors_type breakdown_voltages_sensors;
1285 //
1286 std::map<std::string, double> sensor_vbd_guess = {
1287 {"Hamamatsu S13361-3050", 48.3},
1288 {"Hamamatsu S13361-3075", 47.8},
1289 {"Hamamatsu S14161-3050", 36.5}};
1290 //
1291 template <int method = -1>
1292 void calculate_breakdown_voltages()
1293 {
1294 for (auto current_status : database::all_statuses)
1295 {
1296 for (auto current_board : database::all_boards)
1297 {
1298 for (auto current_channel : database::all_channels)
1299 {
1300 auto vbd_guess = 0.;
1301 if (current_channel.find("A") != std::string::npos)
1302 {
1303 vbd_guess = 48.3;
1304 }
1305 if (current_channel.find("B") != std::string::npos)
1306 {
1307 vbd_guess = 47.8;
1308 }
1309 if (current_channel.find("C") != std::string::npos)
1310 {
1311 vbd_guess = 36.5;
1312 }
1313 // Recover IV
1314 auto current_iv = database::get_iv_scan(current_board, current_channel, current_status);
1315 if (!current_iv)
1316 continue;
1317 current_iv->SetName(TString(current_board) + "/" + TString(current_status) + "/" + TString(current_channel));
1318 TString basedir = (TString(get_environment_variable("SIPM4EIC_WORKDIR")) + TString("/plots/vbdcheck/") + TString(current_board) + "/" + TString(current_status) + "/");
1319 gROOT->ProcessLine(Form(".! mkdir -p %s", basedir.Data()));
1320 if (method < 0)
1321 {
1322 if ((current_channel.find("A") != std::string::npos) && (current_status.find("NEW") != std::string::npos))
1323 {
1324 breakdown_voltages[current_board][current_channel][current_status] = measure_breakdown<0>(current_iv, vbd_guess);
1325 breakdown_voltages_sensors[channel_to_sensor[current_channel]][current_status][current_board][current_channel] = measure_breakdown<0>(current_iv, vbd_guess);
1326 }
1327 else
1328 {
1329
1330 breakdown_voltages[current_board][current_channel][current_status] = measure_breakdown<4>(current_iv, vbd_guess);
1331 breakdown_voltages_sensors[channel_to_sensor[current_channel]][current_status][current_board][current_channel] = measure_breakdown<4>(current_iv, vbd_guess);
1332 }
1333 }
1334 else
1335 {
1336 breakdown_voltages[current_board][current_channel][current_status] = measure_breakdown<method>(current_iv, vbd_guess);
1337 breakdown_voltages_sensors[channel_to_sensor[current_channel]][current_status][current_board][current_channel] = measure_breakdown<method>(current_iv, vbd_guess);
1338 }
1339 }
1340 }
1341 }
1342 }
1343 std::array<double, 2> get_breakdown_voltage(std::string board, std::string channel, std::string step)
1344 {
1345 return breakdown_voltages[board][channel][step];
1346 }
1347 breakdown_voltages_type get_all_breakdown_voltages()
1348 {
1349 return breakdown_voltages;
1350 }
1351}*/
1352
1353/*
1354#pragma once
1355// List of methods to determine the breakdwon voltage in a I-V curve
1356// methods taken from https://arxiv.org/abs/1606.07805
1357//
1358// !TODO: Clean-up graph utils and make new general util repository
1359//
1360typedef std::map<std::string, std::map<std::string, std::map<std::string, std::pair<double, double>>>> breakdown_voltages_type;
1361typedef std::map<std::string, std::map<std::string, std::map<std::string, std::map<std::string, std::pair<double, double>>>>> breakdown_voltages_sensors_type;
1362//
1363std::pair<double, double> find_vbd_guess(TGraphErrors *gLogTarget)
1364{
1365 auto vbd_guess = 0.;
1366 auto mean_baseline = gLogTarget->GetY()[0];
1367 auto mean_contributors = 1;
1368 for (int iPnt = 1; iPnt < gLogTarget->GetN(); iPnt++)
1369 {
1370 auto current_Y = gLogTarget->GetY()[iPnt];
1371 if (fabs(mean_baseline - current_Y) > 0.35)
1372 {
1373 vbd_guess = gLogTarget->GetX()[iPnt-1];
1374 break;
1375 }
1376 mean_baseline *= mean_contributors;
1377 mean_baseline += current_Y;
1378 mean_contributors++;
1379 mean_baseline /= mean_contributors;
1380 }
1381 return {vbd_guess, mean_baseline};
1382}
1383//
1384std::pair<float, float> measure_breakdown_0(TGraphErrors *gTarget, float vbd_guess, bool graphics = false)
1385{
1386 // Create the result pair
1387 std::pair<float, float> result = {-1, -1};
1388 // Make the log graph
1389 auto log_graph = graphutils::log(gTarget);
1390 // Calculate a guess for the Vbd and have the measured baseline value
1391 auto vbd_guess_baseline = find_vbd_guess(log_graph);
1392 vbd_guess = get<0>(vbd_guess_baseline);
1393 auto mean_baseline = get<1>(vbd_guess_baseline);
1394 // Define the functions to find the Vbd
1395 TF1 *fbefore = new TF1("fbefore", "[0]+x*[1]");
1396 TF1 *fafter = new TF1("fafter", "[0]+x*[1]");
1397 // Fit before and after the Vbd guess
1398 fbefore->SetParameter(0, mean_baseline);
1399 fbefore->SetParameter(1, 0.);
1400 log_graph->Fit(fbefore, "RQ", "", vbd_guess - 5, vbd_guess - 0.2);
1401 fafter->SetParameter(0, -100);
1402 fafter->SetParameter(1, 4);
1403 log_graph->Fit(fafter, "RQ", "", vbd_guess + 0.2, vbd_guess + 1.);
1404 auto intercept_before = fbefore->GetParameter(0);
1405 auto angularc_before = fbefore->GetParameter(1);
1406 auto intercept_after = fafter->GetParameter(0);
1407 auto angularc_after = fafter->GetParameter(1);
1408 auto numerator_contribe = sqrt(fbefore->GetParError(0) * fbefore->GetParError(0) + fafter->GetParError(0) * fafter->GetParError(0)) / (intercept_after - intercept_before);
1409 auto denominator_contribe = sqrt(fbefore->GetParError(1) * fbefore->GetParError(1) + fafter->GetParError(1) * fafter->GetParError(1)) / (angularc_before - angularc_after);
1410 auto intercept_val = get<0>(result) = (intercept_after - intercept_before) / (angularc_before - angularc_after);
1411 auto intercept_err = get<1>(result) = get<0>(result) * sqrt(numerator_contribe * numerator_contribe + denominator_contribe * denominator_contribe);
1412 TF1 *ffull = new TF1("ffull", "((0.5-0.5*TMath::Erf(((x-[0])/[1])))*([2]+x*[3])+(0.5+0.5*TMath::Erf(((x-[0])/[1])))*([4]+x*[5]))");
1413 ffull->SetParameter(0, intercept_val);
1414 ffull->SetParLimits(0, intercept_val - 0.2, intercept_val + 0.2);
1415 ffull->SetParameter(1, 0.0000015);
1416 ffull->SetParLimits(1, 0.000001, 0.01);
1417 ffull->FixParameter(2, fbefore->GetParameter(0));
1418 ffull->FixParameter(3, fbefore->GetParameter(1));
1419 ffull->FixParameter(4, fafter->GetParameter(0));
1420 ffull->FixParameter(5, fafter->GetParameter(1));
1421 log_graph->Fit(ffull, "RQ", "SAME", get<0>(result) - 4, get<0>(result) + 3.);
1422 ffull->SetParLimits(0, intercept_val + ffull->GetParameter(1), intercept_val + 0.2);
1423 log_graph->Fit(ffull, "RQ", "SAME", get<0>(result) - 4, get<0>(result) + +3.);
1424 get<0>(result) = ffull->GetParameter(0) - ffull->GetParameter(1);
1425 get<1>(result) = sqrt(ffull->GetParError(0) * ffull->GetParError(0) + ffull->GetParameter(1) * ffull->GetParameter(1));
1426 if (graphics)
1427 {
1428 TCanvas *c1 = new TCanvas(gTarget->GetName(), "c1", 600, 500);
1429 log_graph->Draw("ALP");
1430 log_graph->GetXaxis()->SetRangeUser(get<0>(result) - 6, get<0>(result) + 3);
1431 auto max = ffull->Eval(get<0>(result) + 2);
1432 max = max > 0 ? max * 1.1 : max * 0.9;
1433 log_graph->SetMaximum(max);
1434 fbefore->SetRange(get<0>(result) - 5, get<0>(result) + 5);
1435 fbefore->SetLineColor(kBlue);
1436 fbefore->DrawCopy("SAME");
1437 fafter->SetRange(get<0>(result) - 5, get<0>(result) + 5);
1438 fafter->SetLineColor(kGreen);
1439 fafter->DrawCopy("SAME");
1440 ffull->SetRange(get<0>(result) - 5, get<0>(result) + 5);
1441 ffull->DrawCopy("SAME");
1442 TLatex *l1 = new TLatex();
1443 l1->DrawLatexNDC(0.2, 0.85, Form("V_{bd} guess = %.2f ", vbd_guess));
1444 l1->DrawLatexNDC(0.2, 0.80, Form("V_{bd} = %.2f #pm %.2f", get<0>(result), get<1>(result)));
1445 l1->DrawLatexNDC(0.2, 0.75, Form("V_{bd} (int.) = %.2f #pm %.2f", intercept_val, intercept_err));
1446 //
1447 TString basedir = get_environment_variable("SIPM4EIC_WORKDIR");
1448 basedir += TString("/plots/vbdcheck/");
1449 gROOT->ProcessLine(Form(".! mkdir -p %s", basedir.Data()));
1450 c1->SaveAs(basedir + gTarget->GetName() + TString(".pdf"));
1451 delete c1;
1452 }
1453 delete log_graph;
1454 return result;
1455}
1456//
1457std::pair<float, float>
1458measure_breakdown_1(TGraphErrors *gTarget, float vbd_guess, bool graphics = true)
1459{
1460 std::pair<float, float> result = {-1, -1};
1461 auto log_graph = graphutils::log(gTarget);
1462 auto deriv_graph = graphutils::derivate(log_graph);
1463 auto baseline_reference = 0.;
1464 for (auto iPnt = 0; iPnt < 5; iPnt++)
1465 baseline_reference += deriv_graph->GetY()[iPnt] / 5.;
1466 auto vbd_reference = 0.;
1467 auto peak_reference = 0.;
1468 for (auto iPnt = 5; iPnt < 25; iPnt++)
1469 {
1470 if (peak_reference < deriv_graph->GetY()[iPnt])
1471 {
1472 vbd_reference = deriv_graph->GetX()[iPnt];
1473 peak_reference = deriv_graph->GetY()[iPnt];
1474 }
1475 }
1476 // TF1 *fpeak = new TF1("fpeak", "(([0]*[1])/(2))*TMath::Exp(([1]/2)*(2*[2]+[1]*[3]*[3]-2*x))*(1-TMath::Erf(([2]+[1]*[3]*[3]-x)/(TMath::Sqrt(2)*[3])))");
1477 TF1 *fpeak = new TF1("fpeak", "[0]*TMath::Landau(x,[1],[2],1)");
1478 TF1 *ffull = new TF1("ffull", "[0]*TMath::Landau(x,[1],[2],0)*TMath::Gaus(x,[1],[3])");
1479 fpeak->SetParameter(0, 1.);
1480 fpeak->SetParameter(1, vbd_reference);
1481 fpeak->SetParameter(2, .1);
1482 deriv_graph->Fit(fpeak, "Q", "SAME", vbd_reference - 1.5, vbd_reference + 1.5);
1483 deriv_graph->Fit(fpeak, "Q", "SAME", vbd_reference - 1.5, vbd_reference + 1.5);
1484 deriv_graph->Fit(fpeak, "Q", "SAME", vbd_reference - 1.5, vbd_reference + 1.5);
1485 get<0>(result) = fpeak->GetParameter(1);
1486 get<1>(result) = fpeak->GetParError(1);
1487 if (graphics)
1488 {
1489 TCanvas *c1 = new TCanvas(gTarget->GetName(), "c1", 600, 500);
1490 deriv_graph->Draw("ALP");
1491 deriv_graph->GetXaxis()->SetRangeUser(get<0>(result) - 6, get<0>(result) + 3);
1492 fpeak->SetRange(get<0>(result) - 6, get<0>(result) + 3);
1493 fpeak->SetLineColor(kBlue);
1494 fpeak->SetLineStyle(kDashed);
1495 fpeak->DrawCopy("SAME");
1496 ffull->SetRange(get<0>(result) - 6, get<0>(result) + 3);
1497 ffull->DrawCopy("SAME");
1498 TLatex *l1 = new TLatex();
1499 l1->DrawLatexNDC(0.2, 0.85, Form("V_{bd} = %.2f #pm %.2f", get<0>(result), get<1>(result)));
1500 l1->DrawLatexNDC(0.2, 0.80, Form("V_{bd} = %.2f", vbd_reference));
1501 //
1502 TString basedir = get_environment_variable("SIPM4EIC_WORKDIR");
1503 basedir += TString("/plots/vbdcheck/");
1504 gROOT->ProcessLine(Form(".! mkdir -p %s", basedir.Data()));
1505 c1->SaveAs(basedir + gTarget->GetName() + TString(".pdf"));
1506 delete c1;
1507 }
1508 delete log_graph;
1509 delete deriv_graph;
1510 return result;
1511}
1512//
1513std::pair<float, float>
1514measure_breakdown_2(TGraphErrors *gTarget, float vbd_guess, bool graphics = false)
1515{
1516 std::pair<float, float> result = {-1, -1};
1517 auto log_graph = graphutils::log(gTarget);
1518 auto deriv_graph = graphutils::derivate(log_graph);
1519 auto inverse_graph = graphutils::power(deriv_graph, -1);
1520 for (auto iPnt = 3; iPnt < inverse_graph->GetN() - 3; iPnt++)
1521 {
1522 auto current_x = inverse_graph->GetX()[iPnt];
1523 auto current_y = inverse_graph->GetY()[iPnt];
1524 auto prev1_y = inverse_graph->GetY()[iPnt - 1];
1525 auto prev2_y = inverse_graph->GetY()[iPnt - 2];
1526 auto prev3_y = inverse_graph->GetY()[iPnt - 2];
1527 auto next1_y = inverse_graph->GetY()[iPnt + 1];
1528 auto next2_y = inverse_graph->GetY()[iPnt + 2];
1529 auto next3_y = inverse_graph->GetY()[iPnt + 2];
1530 if (!((current_y < prev1_y) && (prev1_y < prev2_y) && (prev2_y <= prev3_y)))
1531 continue;
1532 if (!((current_y < next1_y) && (next1_y < next2_y) && (next2_y <= next3_y)))
1533 continue;
1534 vbd_guess = current_x;
1535 break;
1536 }
1537 TF1 *fafter = new TF1("fafter", "[0]+x*[1]");
1538 inverse_graph->Fit(fafter, "Q", "SAME", vbd_guess, vbd_guess + 2);
1539 auto qcoeff = fafter->GetParameter(0);
1540 auto mcoeff = fafter->GetParameter(1);
1541 auto qcoefe = fafter->GetParError(0);
1542 auto mcoefe = fafter->GetParError(1);
1543 get<0>(result) = -(qcoeff) / (mcoeff);
1544 get<1>(result) = -(qcoeff) / (mcoeff)*sqrt(((qcoefe / qcoeff) * (qcoefe / qcoeff)) + ((mcoefe / mcoeff) * (mcoefe / mcoeff)));
1545 if (graphics)
1546 {
1547 TCanvas *c1 = new TCanvas(gTarget->GetName(), "c1", 600, 500);
1548 inverse_graph->Draw("ALP");
1549 inverse_graph->GetXaxis()->SetRangeUser(get<0>(result) - 6, get<0>(result) + 3);
1550 fafter->SetRange(get<0>(result) - 6, get<0>(result) + 3);
1551 fafter->DrawCopy("SAME");
1552 TLatex *l1 = new TLatex();
1553 l1->DrawLatexNDC(0.2, 0.85, Form("V_{bd} = %.2f #pm %.2f", get<0>(result), get<1>(result)));
1554 //
1555 TString basedir = get_environment_variable("SIPM4EIC_WORKDIR");
1556 basedir += TString("/plots/vbdcheck/");
1557 gROOT->ProcessLine(Form(".! mkdir -p %s", basedir.Data()));
1558 c1->SaveAs(basedir + gTarget->GetName() + TString(".pdf"));
1559 delete c1;
1560 }
1561 delete log_graph;
1562 delete deriv_graph;
1563 delete inverse_graph;
1564 return result;
1565}
1566//
1567std::pair<float, float>
1568measure_breakdown_3(TGraphErrors *gTarget, float vbd_guess, bool graphics = false)
1569{
1570 std::pair<float, float> result = {-1, -1};
1571 auto log_graph = graphutils::log(gTarget);
1572 auto deriv_graph = graphutils::derivate(log_graph);
1573 auto deriv2_graph = graphutils::derivate(deriv_graph);
1574 TF1 *fpeak = new TF1("fpeak", "gaus(0)");
1575 deriv2_graph->Fit(fpeak, "Q", "SAME", vbd_guess - 0.7, vbd_guess + 0.7);
1576 get<0>(result) = fpeak->GetParameter(1);
1577 get<1>(result) = fpeak->GetParError(1);
1578 delete log_graph;
1579 delete deriv_graph;
1580 // delete deriv2_graph;
1581 return result;
1582}
1583//
1584std::pair<float, float>
1585measure_breakdown_4(TGraphErrors *gTarget, float vbd_guess, bool graphics = false)
1586{
1587 std::pair<float, float> result = {-1, -1};
1588 auto log_graph = graphutils::log(gTarget);
1589 // Calculate a guess for the Vbd and have the measured baseline value
1590 auto vbd_guess_baseline = find_vbd_guess(log_graph);
1591 vbd_guess = get<0>(vbd_guess_baseline);
1592 auto mean_baseline = get<1>(vbd_guess_baseline);
1593 TF1 *fbefore = new TF1("fbefore", "[0]+x*[1]");
1594 TF1 *fafter = new TF1("fafter", "[0]+x*[1]+x*x*[2]");
1595 fbefore->SetParameter(0, mean_baseline);
1596 fbefore->SetParameter(1, 0.);
1597 fafter->SetParameter(0, 0.);
1598 fafter->SetParameter(1, 4);
1599 fafter->SetParLimits(2, -1.e3, 0.);
1600 fafter->SetParameter(2, -0.03);
1601 log_graph->Fit(fbefore, "Q", "", vbd_guess - 5, vbd_guess - 0.3);
1602 log_graph->Fit(fafter, "Q", "", vbd_guess + 0.3, vbd_guess + 2.3);
1603 auto intercept_before = fbefore->GetParameter(0);
1604 auto angularc_before = fbefore->GetParameter(1);
1605 auto c0_after = fafter->GetParameter(0);
1606 auto c1_after = fafter->GetParameter(1);
1607 auto c2_after = fafter->GetParameter(2);
1608 auto delta = sqrt((c1_after - angularc_before) * (c1_after - angularc_before) - 4 * c2_after * (c0_after - intercept_before));
1609 auto intercept_before_econtrib = fbefore->GetParError(0) / (delta);
1610 auto angularc_before_econtrib = fbefore->GetParError(1) * ((c1_after - angularc_before) / (delta) + 1) / (2 * c2_after);
1611 auto c0_after_econtrib = fafter->GetParError(0) / (delta);
1612 auto c1_after_econtrib = -fafter->GetParError(1) * ((c1_after - angularc_before) / (delta) + 1) / (2 * c2_after);
1613 auto c2_after_econtrib = fafter->GetParError(2) * ((c0_after - intercept_before) / (c2_after * delta) - (-delta - c1_after + angularc_before) / (2 * c2_after * c2_after));
1614 auto intercept_val = get<0>(result) = (-(c1_after - angularc_before) + delta) / (2 * c2_after);
1615 auto intercept_err = get<1>(result) = sqrt(intercept_before_econtrib * intercept_before_econtrib + angularc_before_econtrib * angularc_before_econtrib + c0_after_econtrib * c0_after_econtrib + c1_after_econtrib * c1_after_econtrib + c2_after_econtrib * c2_after_econtrib);
1616 TF1 *ffull = new TF1("ffull", "(0.5-0.5*TMath::Erf(((x-[0])/[1])))*([2]+x*[3])+(0.5+0.5*TMath::Erf(((x-[0])/[1])))*([4]+x*[5]+x*x*[6])");
1617 ffull->SetParameter(0, get<0>(result) + 0.2);
1618 ffull->SetParLimits(0, intercept_val - 0.3, intercept_val + 5.);
1619 ffull->SetParameter(1, 0.2);
1620 ffull->SetParLimits(1, 0.0001, 0.3);
1621 ffull->FixParameter(2, fbefore->GetParameter(0));
1622 ffull->FixParameter(3, fbefore->GetParameter(1));
1623 ffull->FixParameter(4, fafter->GetParameter(0));
1624 ffull->FixParameter(5, fafter->GetParameter(1));
1625 ffull->FixParameter(6, fafter->GetParameter(2));
1626 log_graph->Fit(ffull, "Q", "SAME", get<0>(result) - 4, get<0>(result) + 4.);
1627 // ffull->SetParLimits(0, intercept_val + ffull->GetParameter(1), intercept_val + 5.);
1628 // log_graph->Fit(ffull, "RQ", "SAME", get<0>(result) - 4, get<0>(result) + 3);
1629 get<0>(result) = ffull->GetParameter(0) - ffull->GetParameter(1);
1630 get<1>(result) = sqrt(ffull->GetParError(0) * ffull->GetParError(0) + ffull->GetParameter(1) * ffull->GetParameter(1));
1631 if (graphics)
1632 {
1633 TCanvas *c1 = new TCanvas(gTarget->GetName(), "c1", 600, 500);
1634 log_graph->Draw("ALP");
1635 log_graph->GetXaxis()->SetRangeUser(get<0>(result) - 6, get<0>(result) + 3);
1636 auto max = ffull->Eval(get<0>(result) + 2);
1637 max = max > 0 ? max * 1.1 : max * 0.9;
1638 log_graph->SetMaximum(max);
1639 fbefore->SetRange(get<0>(result) - 5, get<0>(result) + 5);
1640 fbefore->SetLineColor(kBlue);
1641 fbefore->DrawCopy("SAME");
1642 fafter->SetRange(get<0>(result) - 5, get<0>(result) + 5);
1643 fafter->SetLineColor(kGreen);
1644 fafter->DrawCopy("SAME");
1645 ffull->SetRange(get<0>(result) - 5, get<0>(result) + 5);
1646 ffull->DrawCopy("SAME");
1647 TLatex *l1 = new TLatex();
1648 l1->DrawLatexNDC(0.2, 0.85, Form("V_{bd} = %.2f #pm %.2f", get<0>(result), get<1>(result)));
1649 l1->DrawLatexNDC(0.2, 0.80, Form("V_{bd} (int.) = %.2f #pm %.2f", intercept_val, intercept_err));
1650 //
1651 TString basedir = get_environment_variable("SIPM4EIC_WORKDIR");
1652 basedir += TString("/plots/vbdcheck/");
1653 gROOT->ProcessLine(Form(".! mkdir -p %s", basedir.Data()));
1654 c1->SaveAs(basedir + gTarget->GetName() + TString(".pdf"));
1655 delete c1;
1656 }
1657 delete log_graph;
1658 return result;
1659}
1660//
1661std::pair<float, float>
1662measure_breakdown_5(TGraphErrors *gTarget, float vbd_guess, bool graphics = false)
1663{
1664 std::pair<float, float> result = {-1, -1};
1665 auto log_graph = graphutils::log(gTarget);
1666 TF1 *fbefore = new TF1("fbefore", "[0]+x*[1]");
1667 TF1 *fafter = new TF1("fafter", "[0]*(x-[1])^([2])");
1668 fafter->SetParameter(1, vbd_guess);
1669 log_graph->Fit(fbefore, "MERQ", "", vbd_guess - 5, vbd_guess - 0.2);
1670 log_graph->Fit(fafter, "MERQ", "", vbd_guess + 0.2, vbd_guess + 5);
1671 TF1 *ffull = new TF1("ffull", "([1]+x*[2])+(x>[0])*(+[3]*(x-[4])^([5]))");
1672 ffull->SetParameter(0, vbd_guess);
1673 ffull->FixParameter(1, fbefore->GetParameter(0));
1674 ffull->FixParameter(2, fbefore->GetParameter(1));
1675 ffull->FixParameter(3, fafter->GetParameter(0));
1676 ffull->FixParameter(4, fafter->GetParameter(1));
1677 ffull->FixParameter(5, fafter->GetParameter(2));
1678 log_graph->Fit(ffull, "MERQ", "SAME", vbd_guess - 3, vbd_guess + 3);
1679 get<0>(result) = 48; // ffull->GetParameter(0) - ffull->GetParameter(1);
1680 get<1>(result) = sqrt(ffull->GetParError(0) * ffull->GetParError(0) + ffull->GetParameter(1) * ffull->GetParameter(1));
1681 if (graphics)
1682 {
1683 TCanvas *c1 = new TCanvas();
1684 log_graph->Draw("ALP");
1685 log_graph->GetXaxis()->SetRangeUser(get<0>(result) - 2, get<0>(result) + 2);
1686 fbefore->SetRange(get<0>(result) - 5, get<0>(result) + 5);
1687 fbefore->SetLineColor(kBlue);
1688 fbefore->DrawCopy("SAME");
1689 fafter->SetRange(get<0>(result) - 5, get<0>(result) + 5);
1690 fafter->SetLineColor(kGreen);
1691 fafter->DrawCopy("SAME");
1692 ffull->SetRange(get<0>(result) - 5, get<0>(result) + 5);
1693 ffull->DrawCopy("SAME");
1694 TLatex *l1 = new TLatex();
1695 l1->DrawLatexNDC(0.2, 0.85, Form("V_{bd} = %.2f #pm %.2f", get<0>(result), get<1>(result)));
1696 //
1697 TString basedir = get_environment_variable("SIPM4EIC_WORKDIR");
1698 basedir += TString("/plots/vbdcheck/");
1699 gROOT->ProcessLine(Form(".! mkdir -p %s", basedir.Data()));
1700 c1->SaveAs(basedir + gTarget->GetName() + TString(".pdf"));
1701 delete c1;
1702 }
1703 delete log_graph;
1704 get<0>(result) = ffull->GetParameter(0);
1705 get<1>(result) = sqrt(ffull->GetParError(0) * ffull->GetParError(0));
1706 return result;
1707}
1708//
1709std::pair<float, float>
1710measure_breakdown_6(TGraphErrors *gTarget, float vbd_guess, bool graphics = false)
1711{
1712 std::pair<float, float> result = {-1, -1};
1713 auto current_graph = (TGraphErrors *)gTarget->Clone("tmp");
1714 TF1 *fprebefore = new TF1("fprebefore", "[0]");
1715 TF1 *fbefore = new TF1("fbefore", "[0]+x*[1]");
1716 TF1 *fafter = new TF1("fafter", "(TMath::Sign([3],(x-[0])))*(TMath::Power(TMath::Abs(x-[0])/([1]),[2]))");
1717 fbefore->FixParameter(0, fprebefore->GetParameter(0));
1718 fafter->FixParameter(0, vbd_guess);
1719 fafter->SetParLimits(1, 1.e-12, 1.e1);
1720 fafter->SetParameter(1, .7);
1721 fafter->SetParLimits(2, 1.e-12, 1.e1);
1722 fafter->SetParameter(2, .1);
1723 fafter->SetParameter(3, fprebefore->GetParameter(0));
1724 fafter->FixParameter(0, vbd_guess);
1725 fafter->SetParameter(1, 7.17717e-01);
1726 fafter->SetParameter(2, 1.);
1727 fafter->SetParameter(3, 4.59948e-09);
1728 current_graph->Fit(fbefore, "MERQ", "", vbd_guess - 5, vbd_guess - 0.2);
1729 current_graph->Fit(fafter, "MERQ", "", vbd_guess + 0.2, vbd_guess + 5);
1730 TF1 *ffull = new TF1("ffull", "(0.5-0.5*TMath::Erf((x-[0])/[1]))*([2]+x*[3])+(0.5+0.5*TMath::Erf(((x-[0])/[1])))*([2]+x*[3]+(TMath::Sign([7],(x-[4])))*(TMath::Power(TMath::Abs(x-[4])/([5]),[6])))");
1731 ffull->SetParameter(0, vbd_guess);
1732 ffull->SetParameter(1, 0.2);
1733 ffull->SetParLimits(1, 0.0001, 0.3);
1734 ffull->FixParameter(2, fbefore->GetParameter(0));
1735 ffull->FixParameter(3, fbefore->GetParameter(1));
1736 ffull->FixParameter(4, fafter->GetParameter(0));
1737 ffull->FixParameter(5, fafter->GetParameter(1));
1738 ffull->FixParameter(6, fafter->GetParameter(2));
1739 ffull->FixParameter(7, fafter->GetParameter(3));
1740 current_graph->Fit(ffull, "MERQ", "SAME", vbd_guess - 5, vbd_guess + 5);
1741 get<0>(result) = ffull->GetParameter(0) - ffull->GetParameter(1);
1742 get<1>(result) = sqrt(ffull->GetParError(0) * ffull->GetParError(0) + ffull->GetParameter(1) * ffull->GetParameter(1));
1743 if (graphics)
1744 {
1745 TCanvas *c1 = new TCanvas();
1746 gPad->SetLogy();
1747 current_graph->Draw("ALP");
1748 current_graph->GetXaxis()->SetRangeUser(get<0>(result) - 5, get<0>(result) + 5);
1749 fbefore->SetRange(get<0>(result) - 5, get<0>(result) + 5);
1750 fbefore->SetLineColor(kBlue);
1751 fbefore->DrawCopy("SAME");
1752 fafter->SetRange(get<0>(result) - 5, get<0>(result) + 5);
1753 fafter->SetLineColor(kGreen);
1754 fafter->DrawCopy("SAME");
1755 ffull->SetRange(get<0>(result) - 5, get<0>(result) + 5);
1756 ffull->DrawCopy("SAME");
1757 TLatex *l1 = new TLatex();
1758 l1->DrawLatexNDC(0.2, 0.85, Form("V_{bd} = %.2f #pm %.2f", get<0>(result), get<1>(result)));
1759 //
1760 TString basedir = get_environment_variable("SIPM4EIC_WORKDIR");
1761 basedir += TString("/plots/vbdcheck/");
1762 gROOT->ProcessLine(Form(".! mkdir -p %s", basedir.Data()));
1763 c1->SaveAs(basedir + gTarget->GetName() + TString(".pdf"));
1764 delete c1;
1765 }
1766 delete current_graph;
1767 get<0>(result) = ffull->GetParameter(0);
1768 get<1>(result) = sqrt(ffull->GetParError(0) * ffull->GetParError(0));
1769 return result;
1770}
1771//
1772std::pair<float, float>
1773measure_breakdown_100(TGraphErrors *gTarget, float vbd_guess, bool graphics = false)
1774{
1775 // Generate result pair
1776 std::pair<float, float> result = {-1, -1};
1777 // Geenrate local copy of graph
1778 auto current_graph = (TGraphErrors *)gTarget->Clone();
1779 // Linear fit to find with extrapolation the crossing of X-axis
1780 TF1 *fafter = new TF1("fafter", "(x-[0])/[1]");
1781 TF1 *ffull = new TF1("ffull", "(x-[0])/[1]+[2]/(x-[3])");
1782 ffull->SetParLimits(2, 0., 1.e8);
1783 // Function prepping
1784 // After fitting
1785 fafter->FixParameter(0, vbd_guess);
1786 fafter->SetParameter(1, 1. / (current_graph->Eval(vbd_guess + 3) - current_graph->Eval(vbd_guess + 2)));
1787 current_graph->Fit(fafter, "MEQ", "", vbd_guess + 2.0, vbd_guess + 2.5);
1788 fafter->SetParLimits(0, vbd_guess - 3, vbd_guess + 3);
1789 current_graph->Fit(fafter, "MEQ", "", vbd_guess + 2.0, vbd_guess + 2.5);
1790 // Full fitting
1791 ffull->FixParameter(0, fafter->GetParameter(0));
1792 ffull->FixParameter(1, fafter->GetParameter(1));
1793 ffull->SetParameter(2, 1.e+05);
1794 ffull->FixParameter(3, fafter->GetParameter(0) + 0.5);
1795 current_graph->Fit(ffull, "MEQ", "", vbd_guess + 0.5, vbd_guess + 2.5);
1796 ffull->SetParLimits(0, vbd_guess - 3, vbd_guess + 3);
1797 ffull->ReleaseParameter(1);
1798 ffull->SetParLimits(3, vbd_guess - 3, vbd_guess + 3);
1799 current_graph->Fit(ffull, "MEQ", "", vbd_guess + 0.5, vbd_guess + 2.5);
1800 // Set Parameters for show
1801 fafter->SetParameter(0, ffull->GetParameter(0));
1802 fafter->SetParameter(1, ffull->GetParameter(1));
1803 // Save result
1804 get<0>(result) = ffull->GetParameter(0);
1805 get<1>(result) = ffull->GetParError(0);
1806 // Plot if requested
1807 if (graphics)
1808 {
1809 TCanvas *c1 = new TCanvas();
1810 gPad->SetLogy();
1811 current_graph->Draw("ALP");
1812 current_graph->GetXaxis()->SetRangeUser(get<0>(result) - 5, get<0>(result) + 5);
1813 fafter->SetRange(get<0>(result) - 5, get<0>(result) + 5);
1814 fafter->SetLineColor(kBlue);
1815 fafter->DrawCopy("SAME");
1816 ffull->SetRange(get<0>(result) - 5, get<0>(result) + 5);
1817 ffull->SetLineColor(kRed);
1818 ffull->DrawCopy("SAME");
1819 // Declare found Vbd value
1820 TLatex *l1 = new TLatex();
1821 l1->DrawLatexNDC(0.2, 0.85, Form("V_{bd} = %.2f #pm %.2f", get<0>(result), get<1>(result)));
1822 // Save plot
1823 TString basedir = get_environment_variable("SIPM4EIC_WORKDIR");
1824 basedir += TString("/plots/vbdcheck/");
1825 gROOT->ProcessLine(Form(".! mkdir -p %s", basedir.Data()));
1826 c1->SaveAs(basedir + gTarget->GetName() + TString(".pdf"));
1827 delete c1;
1828 }
1829 delete current_graph;
1830 return result;
1831}
1832//
1833template <int mode_select = 6>
1834std::pair<float, float>
1835measure_breakdown(TGraphErrors *gTarget, float vbd_guess, bool graphics = true)
1836{
1837 switch (mode_select)
1838 {
1839 // Breakdown Voltage from IV curves
1840 case 0:
1841 return measure_breakdown_0(gTarget, vbd_guess, graphics);
1842 break;
1843 case 1:
1844 return measure_breakdown_1(gTarget, vbd_guess, graphics);
1845 break;
1846 case 2:
1847 return measure_breakdown_2(gTarget, vbd_guess, graphics);
1848 break;
1849 case 3:
1850 return measure_breakdown_3(gTarget, vbd_guess, graphics);
1851 break;
1852 case 4:
1853 return measure_breakdown_4(gTarget, vbd_guess, graphics);
1854 break;
1855 case 5:
1856 return measure_breakdown_5(gTarget, vbd_guess, graphics);
1857 break;
1858 case 6:
1859 return measure_breakdown_6(gTarget, vbd_guess, graphics);
1860 break;
1861 // Breakdown Voltage from DCR curves
1862 case 100:
1863 return measure_breakdown_100(gTarget, vbd_guess, graphics);
1864 break;
1865 default:
1866 return measure_breakdown_4(gTarget, vbd_guess, graphics);
1867 break;
1868 }
1869}
1870//
1871template <int mode_select = 1000>
1872std::pair<float, float>
1873measure_breakdown(TGraphErrors *gTarget, float vbd_guess, int ncycles, float tolerance = 1.e-2)
1874{
1875 auto initial_guess = measure_breakdown<mode_select>(gTarget, vbd_guess);
1876 for (int iTer = 0; iTer < ncycles; iTer++)
1877 {
1878 auto new_guess = measure_breakdown<mode_select>(gTarget, get<0>(initial_guess));
1879 if (fabs(get<0>(new_guess) - get<0>(initial_guess)) < tolerance)
1880 {
1881 return new_guess;
1882 }
1883 initial_guess = new_guess;
1884 }
1885 return initial_guess;
1886}
1887//
1888template <bool recalulate_vbd = true,
1889 int method = 4>
1890TGraphErrors *
1891shift_with_vbd(TGraphErrors *gTarget, float vbd_guess)
1892{
1893 auto new_target = (TGraphErrors *)gTarget->Clone(gTarget->GetName() + TString("_tmp"));
1894 auto vbd_shift_by = 0.;
1895 if (recalulate_vbd)
1896 {
1897 vbd_shift_by = get<0>(measure_breakdown<method>(new_target, vbd_guess));
1898 }
1899 else
1900 {
1901 vbd_shift_by = vbd_guess;
1902 }
1903 graphutils::x_shift(new_target, vbd_shift_by);
1904 return new_target;
1905}
1906//
1907template <bool recalulate_vbd = true>
1908std::pair<float, float>
1909overvoltage_ratio(TGraphErrors *gNumerator, TGraphErrors *gDenominator, float guess_vbd_num, float guess_vbd_den, float _xcoordinate)
1910{
1911 std::pair<float, float> result;
1912 std::pair<float, float> numerator;
1913 std::pair<float, float> denominator;
1914 if (recalulate_vbd)
1915 {
1916 gNumerator->SetName("gNumerator");
1917 gDenominator->SetName("gDenominator");
1918 numerator = eval_with_errors(shift_with_vbd(gNumerator, guess_vbd_num), _xcoordinate);
1919 denominator = eval_with_errors(shift_with_vbd(gDenominator, guess_vbd_den), _xcoordinate);
1920 }
1921 else
1922 {
1923 auto new_numerator = (TGraphErrors *)gNumerator->Clone("tmp");
1924 auto new_denominator = (TGraphErrors *)gDenominator->Clone("tmp");
1925 graphutils::x_shift(new_numerator, guess_vbd_num);
1926 graphutils::x_shift(new_denominator, guess_vbd_den);
1927 numerator = eval_with_errors(new_numerator, _xcoordinate);
1928 denominator = eval_with_errors(new_denominator, _xcoordinate);
1929 }
1930 get<0>(result) = get<0>(numerator) / get<0>(denominator);
1931 get<1>(result) = get<0>(result) * ((get<1>(numerator) / get<0>(numerator)) * (get<1>(numerator) / get<0>(numerator)) + (get<1>(denominator) / get<0>(denominator)) * (get<1>(denominator) / get<0>(denominator)));
1932 return result;
1933}
1934//
1935template <bool recalulate_vbd = true>
1936TGraphErrors *
1937overvoltage_ratio(TGraphErrors *gNumerator, TGraphErrors *gDenominator, float guess_vbd_num, float guess_vbd_den, std::vector<float> _xcoordinates)
1938{
1939 TGraphErrors *result = new TGraphErrors();
1940 std::pair<float, float> current_ratio;
1941 std::pair<float, float> numerator;
1942 std::pair<float, float> denominator;
1943 auto new_numerator = (TGraphErrors *)gNumerator->Clone("gNumerator");
1944 auto new_denominator = (TGraphErrors *)gDenominator->Clone("gDenominator");
1945 if (recalulate_vbd)
1946 {
1947 shift_with_vbd(gNumerator, guess_vbd_num);
1948 shift_with_vbd(gDenominator, guess_vbd_den);
1949 }
1950 else
1951 {
1952 graphutils::x_shift(new_numerator, guess_vbd_num);
1953 graphutils::x_shift(new_denominator, guess_vbd_den);
1954 }
1955 for (auto _xcoordinate : _xcoordinates)
1956 {
1957 numerator = eval_with_errors(new_numerator, _xcoordinate);
1958 denominator = eval_with_errors(new_denominator, _xcoordinate);
1959 if (get<0>(denominator) == 0)
1960 {
1961 continue;
1962 }
1963 if ((get<0>(numerator) == get<1>(numerator)) && (get<0>(numerator) == -1))
1964 {
1965 continue;
1966 }
1967 if ((get<0>(denominator) == get<1>(denominator)) && (get<0>(denominator) == -1))
1968 {
1969 continue;
1970 }
1971 get<0>(current_ratio) = get<0>(numerator) / get<0>(denominator);
1972 auto numerator_err = (get<1>(numerator) / get<0>(numerator));
1973 auto denominator_err = (get<1>(denominator) / get<0>(denominator));
1974 get<1>(current_ratio) = get<0>(current_ratio) * sqrt(numerator_err * numerator_err + denominator_err * denominator_err);
1975 auto current_point = result->GetN();
1976 result->SetPoint(current_point, _xcoordinate, get<0>(current_ratio));
1977 result->SetPointError(current_point, 0, get<1>(current_ratio));
1978 }
1979 return result;
1980}
1981//
1982template <bool recalulate_vbd = true>
1983TGraphErrors *
1984overvoltage_difference(TGraphErrors *gNumerator, TGraphErrors *gDenominator, float guess_vbd_num, float guess_vbd_den, std::vector<float> _xcoordinates)
1985{
1986 TGraphErrors *result = new TGraphErrors();
1987 std::pair<float, float> current_ratio;
1988 std::pair<float, float> numerator;
1989 std::pair<float, float> denominator;
1990 auto new_numerator = (TGraphErrors *)gNumerator->Clone("gNumerator");
1991 auto new_denominator = (TGraphErrors *)gDenominator->Clone("gDenominator");
1992 if (recalulate_vbd)
1993 {
1994 shift_with_vbd(gNumerator, guess_vbd_num);
1995 shift_with_vbd(gDenominator, guess_vbd_den);
1996 }
1997 else
1998 {
1999 graphutils::x_shift(new_numerator, guess_vbd_num);
2000 graphutils::x_shift(new_denominator, guess_vbd_den);
2001 }
2002 for (auto _xcoordinate : _xcoordinates)
2003 {
2004 numerator = eval_with_errors(new_numerator, _xcoordinate);
2005 denominator = eval_with_errors(new_denominator, _xcoordinate);
2006 if ((get<0>(numerator) == get<1>(numerator)) && (get<0>(numerator) == -1))
2007 {
2008 continue;
2009 }
2010 if ((get<0>(denominator) == get<1>(denominator)) && (get<0>(denominator) == -1))
2011 {
2012 continue;
2013 }
2014 get<0>(current_ratio) = get<0>(numerator) - get<0>(denominator);
2015 get<1>(current_ratio) = sqrt(get<1>(numerator) * get<1>(numerator) + get<1>(numerator) * get<1>(numerator));
2016 auto current_point = result->GetN();
2017 result->SetPoint(current_point, _xcoordinate, get<0>(current_ratio));
2018 result->SetPointError(current_point, 0, get<1>(current_ratio));
2019 }
2020 return result;
2021}
2022//
2023template <int method = 6>
2024TGraphErrors *
2025measure_gain(TGraphErrors *iv_graph, TGraphErrors *dcr_graph, double vbd_guess)
2026{
2027 // Make tmp
2028 auto current_iv = (TGraphErrors *)iv_graph->Clone("tmp_IV");
2029 auto current_dcr = (TGraphErrors *)dcr_graph->Clone("tmp_DCR");
2030
2031 // Shift with Vbd
2032 auto current_vbd = method < 0 ? vbd_guess : get<0>(measure_breakdown<method>(current_iv, vbd_guess));
2033 graphutils::x_shift(current_iv, current_vbd);
2034 graphutils::x_shift(current_dcr, current_vbd);
2035
2036 // Subtract surface current from IV
2037 float surface_current_average = 0.;
2038 for (int iPoint = 0; iPoint < 5; ++iPoint)
2039 {
2040 surface_current_average += current_iv->GetY()[iPoint];
2041 }
2042 graphutils::y_shift(current_iv, surface_current_average / 5.);
2043
2044 // Calculate gain
2045 auto current_gain = graphutils::ratio(current_iv, current_dcr);
2046 graphutils::y_scale(current_gain, 1. / TMath::Qe());
2047
2048 // Delete tmp
2049 delete current_iv;
2050 delete current_dcr;
2051
2052 // return
2053 return current_gain;
2054}
2055//
2056template <int method = 6>
2057std::vector<TGraphErrors *>
2058measure_gain(std::vector<TGraphErrors *> iv_graphs, std::vector<TGraphErrors *> dcr_graphs, std::vector<double> vbd_guess)
2059{
2060 std::vector<TGraphErrors *> result;
2061 auto iTer = -1;
2062 for (auto current_iv : iv_graphs)
2063 {
2064 iTer++;
2065 result.push_back(measure_gain<method>(iv_graphs.at(iTer), dcr_graphs.at(iTer), vbd_guess.at(iTer)));
2066 }
2067 //
2068 return result;
2069}
2070//
2071template <int method = 6>
2072std::vector<TGraphErrors *>
2073measure_gain(std::vector<TGraphErrors *> iv_graphs, std::vector<TGraphErrors *> dcr_graphs, double vbd_guess)
2074{
2075 std::vector<TGraphErrors *> result;
2076 auto iTer = -1;
2077 for (auto current_iv : iv_graphs)
2078 {
2079 iTer++;
2080 result.push_back(measure_gain<method>(iv_graphs.at(iTer), dcr_graphs.at(iTer), vbd_guess));
2081 }
2082 //
2083 return result;
2084}
2085//
2086template <int method = 6>
2087std::vector<TGraphErrors *>
2088measure_gain(std::vector<TGraphErrors *> iv_graphs, std::vector<TGraphErrors *> dcr_graphs, std::map<TString, std::pair<double, double>> breakdown_voltages)
2089{
2090 std::vector<TGraphErrors *> result;
2091 auto iTer = -1;
2092 for (auto current_iv : iv_graphs)
2093 {
2094 iTer++;
2095 result.push_back(measure_gain<-1>(iv_graphs.at(iTer), dcr_graphs.at(iTer), get<0>(breakdown_voltages[iv_graphs.at(iTer)->GetName()])));
2096 }
2097 //
2098 return result;
2099}
2100//
2101namespace database
2102{
2103 // https://docs.google.com/document/d/1Z3A6zrad5A-7HcmOVEIBOqT7nCkWAe4-ilvuk-I16rs/edit#heading=h.a7bxpd1bw3ht
2104 //
2105 // --- Breakdown voltage
2106 // Storage for on-the-fly Vbd
2107 // --- board - channel - step
2108 breakdown_voltages_type breakdown_voltages;
2109 // --- sensor - step - board - channel
2110 breakdown_voltages_sensors_type breakdown_voltages_sensors;
2111 //
2112 std::map<std::string, double> sensor_vbd_guess = {
2113 {"Hamamatsu S13361-3050", 48.3},
2114 {"Hamamatsu S13361-3075", 47.8},
2115 {"Hamamatsu S14161-3050", 36.5}};
2116 //
2117 template <int method = -1>
2118 void calculate_breakdown_voltages()
2119 {
2120 for (auto current_status : database::all_statuses)
2121 {
2122 for (auto current_board : database::all_boards)
2123 {
2124 for (auto current_channel : database::all_channels)
2125 {
2126 auto vbd_guess = 0.;
2127 if (current_channel.find("A") != std::string::npos)
2128 {
2129 vbd_guess = 48.3;
2130 }
2131 if (current_channel.find("B") != std::string::npos)
2132 {
2133 vbd_guess = 47.8;
2134 }
2135 if (current_channel.find("C") != std::string::npos)
2136 {
2137 vbd_guess = 36.5;
2138 }
2139 // Recover IV
2140 auto current_iv = database::get_iv_scan(current_board, current_channel, current_status);
2141 if (!current_iv)
2142 continue;
2143 current_iv->SetName(TString(current_board) + "/" + TString(current_status) + "/" + TString(current_channel));
2144 TString basedir = (TString(get_environment_variable("SIPM4EIC_WORKDIR")) + TString("/plots/vbdcheck/") + TString(current_board) + "/" + TString(current_status) + "/");
2145 gROOT->ProcessLine(Form(".! mkdir -p %s", basedir.Data()));
2146 if (method < 0)
2147 {
2148 if ((current_channel.find("A") != std::string::npos) && (current_status.find("NEW") != std::string::npos))
2149 {
2150 breakdown_voltages[current_board][current_channel][current_status] = measure_breakdown<0>(current_iv, vbd_guess);
2151 breakdown_voltages_sensors[channel_to_sensor[current_channel]][current_status][current_board][current_channel] = measure_breakdown<0>(current_iv, vbd_guess);
2152 }
2153 else
2154 {
2155
2156 breakdown_voltages[current_board][current_channel][current_status] = measure_breakdown<4>(current_iv, vbd_guess);
2157 breakdown_voltages_sensors[channel_to_sensor[current_channel]][current_status][current_board][current_channel] = measure_breakdown<4>(current_iv, vbd_guess);
2158 }
2159 }
2160 else
2161 {
2162 breakdown_voltages[current_board][current_channel][current_status] = measure_breakdown<method>(current_iv, vbd_guess);
2163 breakdown_voltages_sensors[channel_to_sensor[current_channel]][current_status][current_board][current_channel] = measure_breakdown<method>(current_iv, vbd_guess);
2164 }
2165 }
2166 }
2167 }
2168 }
2169 std::pair<double, double> get_breakdown_voltage(std::string board, std::string channel, std::string step)
2170 {
2171 return breakdown_voltages[board][channel][step];
2172 }
2173 breakdown_voltages_type get_all_breakdown_voltages()
2174 {
2175 return breakdown_voltages;
2176 }
2177}
2178
2179*/
std::array< std::array< float, 2 >, 2 > get_intercept_x(TF1 *pol1)
Definition breakdown_voltage.h:7
TH2_Type * build_fine_tune_raw_histogram(std::vector< TString > kInputFileNames, TString kRunTag, TString kOutputFileName, bool kRecalculate)
Functions -------------------------------------------------------------------------------------------...
Definition fine_analysis.h:80
float threshold
Definition my_test_macro_for_WF_fitting.C:6
Definition breakdown_voltage.h:11
std::array< float, 2 > measure_breakdown_1(TGraphErrors *gTarget, std::string image_folder="", float threshold_guess=0.75)
Definition breakdown_voltage.h:148
std::array< float, 2 > measure_breakdown_0(TGraphErrors *gTarget, std::string image_folder="", float threshold_guess=0.75, bool erf_mediate=true, float min_before_fit=5., float max_before_fit=0.2, float min_after_fit=0.2, float max_after_fit=1.)
Definition breakdown_voltage.h:45
std::array< float, 2 > measure_breakdown_4(TGraphErrors *gTarget, std::string image_folder="", float threshold_guess=0.75, bool erf_mediate=true, float min_before_fit=5., float max_before_fit=0.2, float min_after_fit=0.2, float max_after_fit=1.)
Definition breakdown_voltage.h:340
std::array< double, 2 > find_vbd_guess(TGraphErrors *gLogTarget, float threshold=0.35)
Definition breakdown_voltage.h:24
std::array< float, 2 > measure_breakdown_2(TGraphErrors *gTarget, std::string image_folder="", float threshold_guess=0.75)
Definition breakdown_voltage.h:211
std::array< float, 2 > measure_breakdown_5(TGraphErrors *gTarget, std::string image_folder="", float threshold_guess=0.75)
Definition breakdown_voltage.h:529
std::array< float, 2 > measure_breakdown_3(TGraphErrors *gTarget, std::string image_folder="", float threshold_guess=0.75)
Definition breakdown_voltage.h:277
TGraphErrors * derivate(TGraphErrors *gin, double sign=1.)
Definition graphutils.C:399
TGraphErrors * log(TGraphErrors *gin)
Definition graphutils.C:564
TGraphErrors * power(TGraphErrors *target_graph, double exponent=1.)
Definition graphutils.C:16
std::array< std::array< float, 2 >, 2 > get_intercept_x(float m, float em, float q, float eq)
Definition general_utility.h:42
std::array< std::array< float, 2 >, 2 > get_intercept(TF1 *pol1, TF1 *pol2)
Definition utility.h:115