sipm-characterisation 0.1.0
SiPM characterisation for ePIC — IV/DCR/gain, laser, readout, irradiation
Loading...
Searching...
No Matches
general_utility.h
Go to the documentation of this file.
1// --- --- ---
2// General utility functions
3//
4// Auth: Nicola Rubini
5// Mail: nicola.rubini@bo.infn.it
6//
7#pragma once
8
9#include "graphutils.C"
10
11namespace utility
12{
13 // Swap two values
14 template <typename arg_type>
16 // Square sum
17 template <typename arg_type>
19 template <typename arg_type, typename... Args>
20 inline arg_type sq_sum(arg_type first, Args... args);
21 // Average
22 // template <typename T, typename = typename std::enable_if<std::is_arithmetic<T>::value>::type>
23 // std::map<std::string, std::array<T, 2>> average(std::vector<std::array<T, 2>> list_of_measurements, bool skip_unfit_skim = false);
24 // Set precision of the number
25 template <typename T>
27 // Concatenate vectors
28 template <typename T>
29 std::vector<T> merge(const std::vector<T> &vec1, const std::vector<T> &vec2);
30 // Get folder list of a location
31 std::vector<std::string> get_folders(const std::string &dir_path);
32
33 // Read a txt file with some numbers
34 void readFileToMap(const std::string &filename, std::map<std::string, std::vector<std::string>> &dataMap);
35 void readTxtToMap(const std::string &filename, std::map<std::string, std::vector<std::string>> &dataMap);
36 void readCsvToMap(const std::string &filename, std::map<std::string, std::vector<std::string>> &dataMap);
37
38 // Calculate intercept between lines
39 std::array<std::array<float, 2>, 2> get_intercept(float x0_1, float ex0_1, float x1_1, float ex1_1, float x0_2, float ex0_2, float x1_2, float ex1_2);
40 std::array<std::array<float, 2>, 2> get_intercept_pol1_pol1(float x0_1, float ex0_1, float x1_1, float ex1_1, float x0_2, float ex0_2, float x1_2, float ex1_2);
41 std::array<std::array<float, 2>, 2> get_intercept(std::array<float, 2> m1, std::array<float, 2> q1, std::array<float, 2> m2, std::array<float, 2> q2) { return get_intercept(m1[0], m1[1], q1[0], q1[1], m2[0], m2[1], q2[0], q2[1]); };
42 std::array<std::array<float, 2>, 2> get_intercept_x(float m, float em, float q, float eq) { return utility::get_intercept(m, em, q, eq, 0, 0, 0, 0); };
43 std::array<std::array<float, 2>, 2> get_intercept_y(float m, float em, float q, float eq) { return {q, eq}; };
44 std::array<std::array<float, 2>, 2> get_intercept_pol1_pol2(float x0_1, float ex0_1, float x1_1, float ex1_1, float x0_2, float ex0_2, float x1_2, float ex1_2, float x2_2, float ex2_2);
45 std::array<std::array<float, 2>, 2> get_intercept_tf1(TF1 *first_target, TF2 *second_target, double first_guess, double starting_coarse, double req_precision);
46}
47
48template <typename arg_type>
55
56template <typename arg_type>
58{
59 return value * value; // Base case: square the single argument
60}
61
62template <typename arg_type, typename... Args>
64{
65 return first * first + sq_sum(args...); // Recursive call
66}
67
68template <typename T>
70{
71 // Check the passed argument is a number
72 static_assert(std::is_arithmetic<T>::value, "Type must be numeric");
73 T factor = std::pow(10, digits);
74 return std::ceil(value * factor) / factor;
75}
76
77template <typename T>
78std::vector<T> utility::merge(const std::vector<T> &vec1, const std::vector<T> &vec2)
79{
80 std::vector<T> result = vec1; // Start with the first vector
81 result.insert(result.end(), vec2.begin(), vec2.end()); // Concatenate the second vector
82 return result;
83}
84
85std::vector<std::string> utility::get_folders(const std::string &dir_path)
86{
87 std::vector<std::string> folders;
88 for (const auto &entry : std::filesystem::directory_iterator(dir_path))
89 if (entry.is_directory())
90 folders.push_back(entry.path().filename().string());
91 return folders;
92}
93
94namespace utility
95{
96 // Check again
98 std::map<std::string, std::array<T, 2>> average(std::vector<std::array<T, 2>> list_of_measurements, bool skip_unfit_skim = false)
99 {
100 // Final result
101 std::map<std::string, std::array<T, 2>> result;
102 std::vector<std::array<T, 2>> skimmed_data;
103
104 // Skim dataset from dangerous values
106 if (!skip_unfit_skim)
107 {
108 skimmed_data.clear();
110 {
111 if (std::isnan(current_measurement[0]) || std::isnan(current_measurement[1]))
112 continue;
113 if (std::isinf(current_measurement[0]) || std::isinf(current_measurement[1]))
114 continue;
116 }
117 }
118
119 // Measure average and error on the average
121 {
122 result["ave_err"][0] += current_measurement[0];
123 result["ave_rms"][0] += current_measurement[0];
124 result["ave_sqe"][0] += current_measurement[0];
125 result["sqa_err"][0] += current_measurement[0] * current_measurement[0];
126 result["sqa_rms"][0] += current_measurement[0] * current_measurement[0];
127 result["sqa_sqe"][0] += current_measurement[0] * current_measurement[0];
128 result["ave_err"][1] += current_measurement[1];
129 // result["ave_rms"][1] += current_measurement[1];
130 result["ave_sqe"][1] += current_measurement[1] * current_measurement[1];
131 result["sqa_err"][1] += current_measurement[1];
132 // result["sqa_rms"][1] += current_measurement[1];
133 result["sqa_sqe"][1] += current_measurement[1] * current_measurement[1];
134 }
135 result["ave_err"][0] /= skimmed_data.size();
136 result["ave_rms"][0] /= skimmed_data.size();
137 result["ave_sqe"][0] /= skimmed_data.size();
138 result["sqa_err"][0] /= skimmed_data.size();
139 result["sqa_rms"][0] /= skimmed_data.size();
140 result["sqa_sqe"][0] /= skimmed_data.size();
141 result["sqa_err"][0] = sqrt(result["sqa_err"][0]);
142 result["sqa_rms"][0] = sqrt(result["sqa_rms"][0]);
143 result["sqa_sqe"][0] = sqrt(result["sqa_sqe"][0]);
144 result["ave_err"][1] /= skimmed_data.size();
145 // result["ave_rms"][1] += current_measurement[1];
146 result["ave_sqe"][1] = sqrt(result["ave_sqe"][1]);
147 result["sqa_err"][1] /= skimmed_data.size();
148 // result["sqa_rms"][1] += current_measurement[1];
149 result["sqa_sqe"][1] = sqrt(result["sqa_sqe"][1]);
150
151 // Measure RMS
152
153 return result;
154 }
155}
156
157void utility::readCsvToMap(const std::string &filename, std::map<std::string, std::vector<std::string>> &dataMap)
158{
159 if (!std::filesystem::exists(filename))
160 {
161 throw std::runtime_error("[ERROR][readFileToMap] File does not exist: " + filename);
162 }
163
164 std::ifstream file(filename);
165 if (!file)
166 {
167 throw std::runtime_error("[ERROR][readFileToMap] Could not open file " + filename);
168 }
169
170 // Read header line
171 std::string headerLine;
172 if (!std::getline(file, headerLine))
173 {
174 throw std::runtime_error("[ERROR][readFileToMap] File " + filename + " is empty or missing header row.");
175 }
176
177 // Ensure the string has at least 3 characters to check
178 if (filename.size() < 3)
179 {
180 std::cerr << "[ERROR][utility::readFileToMap] Filename too short to determine file type: " << filename << std::endl;
181 return;
182 }
183
184 // Parse column titles
185 std::vector<std::string> columnTitles;
186 std::istringstream headerStream(headerLine);
187 std::string title;
188
189 // Split header line by commas
190 size_t start = 0, end = 0;
191 while ((end = headerLine.find(',', start)) != std::string::npos)
192 {
193 columnTitles.push_back(std::regex_replace(headerLine.substr(start, end - start), std::regex("^\\s+|\\s+$"), ""));
194 start = end + 1;
195 }
196 columnTitles.push_back(std::regex_replace(headerLine.substr(start), std::regex("^\\s+|\\s+$"), ""));
197
198 for (const auto &col : columnTitles)
199 {
200 if (dataMap.find(col) == dataMap.end())
201 {
202 dataMap[col] = {}; // Initialize vector if not already present
203 }
204 }
205
206 // Define the allowed characters regex pattern
207 const std::regex validPattern(R"(^\s*[+-]?[0-9]+(\.[0-9]*)?([eE][+-]?[0-9]+)?\s*$)");
208
209 // Read remaining lines
210 std::string line;
211 while (std::getline(file, line))
212 {
213 std::vector<std::string> rowValues;
214 start = 0;
215
216 // Split the line by commas
217 while ((end = line.find(',', start)) != std::string::npos)
218 {
219 rowValues.push_back(line.substr(start, end - start));
220 start = end + 1;
221 }
222 rowValues.push_back(line.substr(start));
223
224 if (rowValues.size() != columnTitles.size())
225 {
226 throw std::runtime_error("[ERROR][readFileToMap] Mismatched data and header columns in file " + filename);
227 }
228
229 bool isValidLine = true;
230
231 // Check each value for allowed characters
232 for (const auto &value : rowValues)
233 {
234 if (!std::regex_match(value, validPattern))
235 {
236 isValidLine = false;
237 break;
238 }
239 }
240
241 // If the line is valid, add its values to the respective columns
242 if (isValidLine)
243 {
244 for (size_t i = 0; i < columnTitles.size(); ++i)
245 {
246 dataMap[columnTitles[i]].push_back(rowValues[i]);
247 }
248 }
249 else
250 {
251 std::cout << "[WARNING] Skipping line for character incompatibility: " << line << std::endl;
252 }
253 }
254
255 file.close();
256}
257
258void utility::readTxtToMap(const std::string &filename, std::map<std::string, std::vector<std::string>> &dataMap)
259{
260 if (!std::filesystem::exists(filename))
261 {
262 throw std::runtime_error("[ERROR][readFileToMap] File does not exist: " + filename);
263 }
264
265 std::ifstream file(filename);
266 if (!file)
267 {
268 throw std::runtime_error("[ERROR][readFileToMap] Could not open file " + filename);
269 }
270
271 // Read header line
272 std::string headerLine;
273 if (!std::getline(file, headerLine))
274 {
275 throw std::runtime_error("[ERROR][readFileToMap] File " + filename + " is empty or missing header row.");
276 }
277
278 // Parse column titles
279 std::istringstream headerStream(headerLine);
280 std::vector<std::string> columnTitles;
281 std::string title;
282 while (headerStream >> title)
283 {
284 columnTitles.push_back(title);
285 if (dataMap.find(title) == dataMap.end())
286 {
287 dataMap[title] = {}; // Initialize vector if not already present
288 }
289 }
290
291 // Define the allowed characters regex pattern
292 const std::regex validPattern(R"(^\s*[+-]?[0-9]+(\.[0-9]*)?([eE][+-]?[0-9]+)?\s*$)");
293
294 // Read remaining lines
295 std::string line;
296 while (std::getline(file, line))
297 {
298 std::istringstream lineStream(line);
299 std::vector<std::string> rowValues;
300 std::string value;
301 bool isValidLine = true;
302
303 // Process each column in the line
304 for (size_t i = 0; i < columnTitles.size(); ++i)
305 {
306 if (!(lineStream >> value))
307 {
308 throw std::runtime_error("[ERROR][readFileToMap] Mismatched data and header columns.");
309 }
310
311 // Check if the value contains only allowed characters
312 if (!std::regex_match(value, validPattern))
313 {
314 isValidLine = false;
315 break; // Skip the rest of the line
316 }
317
318 rowValues.push_back(value);
319 }
320
321 // If the line is valid, add its values to the respective columns
322 if (isValidLine)
323 {
324 for (size_t i = 0; i < rowValues.size(); ++i)
325 {
326 dataMap[columnTitles[i]].push_back(rowValues[i]);
327 }
328 }
329 else
330 cout << "[WARNING] Skipping line for character incompatibility" << endl;
331 }
332
333 file.close();
334}
335
336void utility::readFileToMap(const std::string &filename, std::map<std::string, std::vector<std::string>> &dataMap)
337{
338 if (!std::filesystem::exists(filename))
339 {
340 throw std::runtime_error("[ERROR][readFileToMap] File does not exist: " + filename);
341 }
342
343 std::ifstream file(filename);
344 if (!file)
345 {
346 throw std::runtime_error("[ERROR][readFileToMap] Could not open file " + filename);
347 }
348
349 // Read header line
350 std::string headerLine;
351 if (!std::getline(file, headerLine))
352 {
353 throw std::runtime_error("[ERROR][readFileToMap] File " + filename + " is empty or missing header row.");
354 }
355
356 // Ensure the string has at least 3 characters to check
357 if (filename.size() < 3)
358 {
359 std::cerr << "[ERROR][utility::readFileToMap] Filename too short to determine file type: " << filename << std::endl;
360 return;
361 }
362
363 // Get the last three characters of the string
364 std::string fileExtension = filename.substr(filename.size() - 3);
365
366 // Convert to lowercase for case-insensitive comparison
367 for (char &c : fileExtension)
368 c = std::tolower(c);
369
370 // Perform actions based on the file extension
371 if (fileExtension == "txt")
372 {
374 }
375 else if (fileExtension == "csv")
376 {
378 }
379 else
380 {
381 std::cerr << "[WARNING][utility::readFileToMap] Unknown file type: " << filename << ", treating as txt" << std::endl;
382 }
383}
384
385std::array<std::array<float, 2>, 2> utility::get_intercept(float x0_1, float ex0_1, float x1_1, float ex1_1, float x0_2, float ex0_2, float x1_2, float ex1_2)
386{
387 // Intercept of pol1 and pol1:
388 // The analytic solution with the subtraction of the linear equation to the second linear equation
389
390 // Define the result container
391 std::array<std::array<float, 2>, 2> result;
392 return result;
393}
394
395std::array<std::array<float, 2>, 2> utility::get_intercept_pol1_pol1(float x0_1, float ex0_1, float x1_1, float ex1_1, float x0_2, float ex0_2, float x1_2, float ex1_2)
396{
397 // Intercept of pol1 and pol1:
398 // The analytic solution with the subtraction of the linear equation to the second linear equation
399
400 // Define the result container
401 std::array<std::array<float, 2>, 2> result = {0};
402 return result;
403
404 /*
405 // Analytic solution
406 // xi_j: (i) is the coefficient of x^i and (j) means it is related to the equation of position 1,2
407 result[0][0] = (x0_2 - x0_1) / (x1_1 - x1_2);
408 result[1][0] = (x1_1 * x0_2 - x1_2 * x0_1) / (x1_1 - x1_2);
409
410 // Error evaluation
411 // eabs_i_xi_j : (i) is the x (0) or y (1) relative to the xi_j component
412 // eabs: absolute error
413 // Errors are calculated with the derivative method
414 auto eabs_1_x0_1 = ex0_1 * fabs(1. / (d_delta));
415 auto eabs_0_x0_1 = ex0_1 * fabs(1 + x1_1 / (d_delta));
416 auto eabs_1_x1_1 = ex1_1 * fabs(1 - (x1_2 - x1_1) / (2 * x2_2 * d_delta));
417 auto eabs_0_x1_1 = ex1_1 * fabs((-(x1_2 - x1_1) * x1_1 / (2 * x2_2 * d_delta)) + ((d_delta) / (2 * x2_2)) + 2 * x1_1 - x1_2);
418 auto eabs_1_x0_2 = ex0_2 * fabs(-1. / (d_delta));
419 auto eabs_0_x0_2 = ex0_2 * fabs(-x1_1 / (d_delta));
420 auto eabs_1_x1_2 = ex1_2 * fabs((x1_2 - x1_1) / (d_delta * 2 * x2_2) - 1);
421 auto eabs_0_x1_2 = ex1_2 * fabs(x1_1 * (x1_2 - x1_1) / (d_delta * 2 * x2_2) - 1);
422
423 // Assign errors on result
424 result[0][1] = sqrt(eabs_0_x0_1 * eabs_0_x0_1 + eabs_0_x1_1 * eabs_0_x1_1 + eabs_0_x0_2 * eabs_0_x0_2 + eabs_0_x1_2 * eabs_0_x1_2 + eabs_0_x2_2 * eabs_0_x2_2);
425 result[1][1] = sqrt(eabs_1_x0_1 * eabs_1_x0_1 + eabs_1_x1_1 * eabs_1_x1_1 + eabs_1_x0_2 * eabs_1_x0_2 + eabs_1_x1_2 * eabs_1_x1_2 + eabs_1_x2_2 * eabs_1_x2_2);
426 return result;
427 }
428
429 std::array<std::array<float, 2>, 2> utility::get_intercept_pol1_pol2(float x0_1, float ex0_1, float x1_1, float ex1_1, float x0_2, float ex0_2, float x1_2, float ex1_2, float x2_2, float ex2_2)
430 {
431 // Intercept of pol1 and pol2:
432 // The analytic solution with the subtraction of the linear equation to the quadratic equation
433
434 // Define the result container
435 std::array<std::array<float, 2>, 2> result;
436
437 // Analytic solution
438 // xi_j: (i) is the coefficient of x^i and (j) means it is related to the equation of degree 1,2
439 result[0][0] = (-(x1_2 - x1_1) + sqrt((x1_2 - x1_1) * (x1_2 - x1_1) - 4 * x2_2 * (x0_2 - x0_1))) / (2 * x2_2);
440 result[1][0] = x0_1 + result[0][0] * x1_1;
441
442 // Error evaluation
443 // eabs_i_xi_j : (i) is the x (0) or y (1) relative to the xi_j component
444 // eabs: absolute error
445 // Errors are calculated with the derivative method
446 auto d_delta = sqrt((x1_2 - x1_1) * (x1_2 - x1_1) + 4 * x2_2 * (x0_1 - x0_2));
447 auto eabs_1_x0_1 = ex0_1 * fabs(1. / (d_delta));
448 auto eabs_0_x0_1 = ex0_1 * fabs(1 + x1_1 / (d_delta));
449 auto eabs_1_x1_1 = ex1_1 * fabs(1 - (x1_2 - x1_1) / (2 * x2_2 * d_delta));
450 auto eabs_0_x1_1 = ex1_1 * fabs((-(x1_2 - x1_1) * x1_1 / (2 * x2_2 * d_delta)) + ((d_delta) / (2 * x2_2)) + 2 * x1_1 - x1_2);
451 auto eabs_1_x0_2 = ex0_2 * fabs(-1. / (d_delta));
452 auto eabs_0_x0_2 = ex0_2 * fabs(-x1_1 / (d_delta));
453 auto eabs_1_x1_2 = ex1_2 * fabs((x1_2 - x1_1) / (d_delta * 2 * x2_2) - 1);
454 auto eabs_0_x1_2 = ex1_2 * fabs(x1_1 * (x1_2 - x1_1) / (d_delta * 2 * x2_2) - 1);
455 auto eabs_1_x2_2 = ex2_2 * fabs(((x1_2 - x1_1) * (x1_2 - x1_1) + 2 * x2_2 * (x0_1 - x0_2)) / (d_delta * 2 * x2_2) - 1);
456 auto eabs_0_x2_2 = ex2_2 * fabs(-x1_1 * ((x1_2 - x1_1) * (x1_2 - x1_1) + 2 * x2_2 * (x0_1 - x0_2)) / (d_delta * 2 * x2_2) - 1);
457
458 // Assign errors on result
459 result[0][1] = sqrt(eabs_0_x0_1 * eabs_0_x0_1 + eabs_0_x1_1 * eabs_0_x1_1 + eabs_0_x0_2 * eabs_0_x0_2 + eabs_0_x1_2 * eabs_0_x1_2 + eabs_0_x2_2 * eabs_0_x2_2);
460 result[1][1] = sqrt(eabs_1_x0_1 * eabs_1_x0_1 + eabs_1_x1_1 * eabs_1_x1_1 + eabs_1_x0_2 * eabs_1_x0_2 + eabs_1_x1_2 * eabs_1_x1_2 + eabs_1_x2_2 * eabs_1_x2_2);
461 return result;
462 */
463}
464
465std::array<std::array<float, 2>, 2> utility::get_intercept_tf1(TF1 *first_target, TF2 *second_target, double first_guess, double starting_coarse, double req_precision)
466{
467 // Result
468 std::array<std::array<float, 2>, 2> result = {0};
469
470 // Start while loop for look for the zero
472 auto sign_alternate = 1;
473 while (true)
474 {
477 }
478 return result;
479}
TH2_Type * build_fine_tune_raw_histogram(std::vector< TString > kInputFileNames, TString kRunTag, TString kOutputFileName, bool kRecalculate)
Functions -------------------------------------------------------------------------------------------...
Definition fine_analysis.h:80
Definition general_utility.h:12
void readTxtToMap(const std::string &filename, std::map< std::string, std::vector< std::string > > &dataMap)
Definition general_utility.h:258
void swap_values(arg_type &first_element, arg_type &second_element)
Definition general_utility.h:49
arg_type sq_sum(arg_type value)
Definition general_utility.h:57
std::array< std::array< float, 2 >, 2 > get_intercept_pol1_pol1(float x0_1, float ex0_1, float x1_1, float ex1_1, float x0_2, float ex0_2, float x1_2, float ex1_2)
Definition general_utility.h:395
std::map< std::string, std::array< T, 2 > > average(std::vector< std::array< T, 2 > > list_of_measurements, bool skip_unfit_skim=false)
Definition general_utility.h:98
std::vector< std::string > get_folders(const std::string &dir_path)
Definition general_utility.h:85
std::array< std::array< float, 2 >, 2 > get_intercept_tf1(TF1 *first_target, TF2 *second_target, double first_guess, double starting_coarse, double req_precision)
Definition general_utility.h:465
std::array< std::array< float, 2 >, 2 > get_intercept_pol1_pol2(float x0_1, float ex0_1, float x1_1, float ex1_1, float x0_2, float ex0_2, float x1_2, float ex1_2, float x2_2, float ex2_2)
std::array< std::array< float, 2 >, 2 > get_intercept_y(float m, float em, float q, float eq)
Definition general_utility.h:43
std::array< std::array< float, 2 >, 2 > get_intercept(float x0_1, float ex0_1, float x1_1, float ex1_1, float x0_2, float ex0_2, float x1_2, float ex1_2)
Definition general_utility.h:385
T round_digits(T value, int digits)
Definition general_utility.h:69
std::vector< T > merge(const std::vector< T > &vec1, const std::vector< T > &vec2)
Definition general_utility.h:78
void readFileToMap(const std::string &filename, std::map< std::string, std::vector< std::string > > &dataMap)
Definition general_utility.h:336
void readCsvToMap(const std::string &filename, std::map< std::string, std::vector< std::string > > &dataMap)
Definition general_utility.h:157
std::array< std::array< float, 2 >, 2 > get_intercept_x(float m, float em, float q, float eq)
Definition general_utility.h:42