guts
Loading...
Searching...
No Matches
gutilities.cc
Go to the documentation of this file.
1// gutilities
2#include "gutilities.h"
3#include "gutsConventions.h"
4
5// Numbers / strings with units / io interface to CLHEP units
6#include "CLHEP/Units/PhysicalConstants.h"
7
8// c++
9// algorithm for 'transform'
10#include <algorithm>
11#include <sstream>
12#include <unordered_map>
13#include <iostream>
14#include <fstream>
15#include <vector>
16#include <charconv>
17#include <filesystem>
18
19namespace gutilities {
20
21string removeLeadingAndTrailingSpacesFromString(const std::string& input) {
22 size_t startPos = input.find_first_not_of(" \t"); // Find the first non-whitespace character
23 size_t endPos = input.find_last_not_of(" \t"); // Find the last non-whitespace character
24
25 // If all spaces or empty, return an empty string
26 if (startPos == std::string::npos || endPos == std::string::npos) { return ""; }
27
28 // Return the substring between startPos and endPos
29 return input.substr(startPos, endPos - startPos + 1);
30}
31
32string removeAllSpacesFromString(const std::string& str) {
33 string result = str;
34 result.erase(std::remove(result.begin(), result.end(), ' '), result.end());
35 return result;
36}
37
38string getFileFromPath(const std::string& path) {
39 std::size_t lastSlashPos = path.find_last_of('/');
40 if (lastSlashPos == std::string::npos) {
41 // No slashes found, return the entire path
42 return path;
43 }
44 return path.substr(lastSlashPos + 1);
45}
46
47string getDirFromPath(const std::string& path) {
48 auto lastSlash = path.find_last_of('/');
49 if (lastSlash == std::string::npos) return ".";
50 return path.substr(0, lastSlash);
51}
52
53namespace fs = std::filesystem;
54
55
56vector<std::string> getStringVectorFromString(const std::string& input) {
57 std::vector<std::string> pvalues;
58 std::stringstream plist(input);
59 string tmp;
60 while (plist >> tmp) {
61 string trimmed = removeLeadingAndTrailingSpacesFromString(tmp);
62 if (!trimmed.empty()) { pvalues.push_back(trimmed); }
63 }
64 return pvalues;
65}
66
67// Replace all occurences of specific chars in a string with a string
68string replaceCharInStringWithChars(const std::string& input, const std::string& toReplace,
69 const std::string& replacement) {
70 string output;
71 for (const char& ch : input) {
72 if (toReplace.find(ch) != std::string::npos) { output.append(replacement); }
73 else { output.push_back(ch); }
74 }
75 return output;
76}
77
78string replaceAllStringsWithString(const string& source, const string& from, const string& to) {
79 if (from.empty()) return source; // Avoid infinite loop
80
81 string newString;
82 size_t lastPos = 0;
83 size_t findPos = source.find(from, lastPos);
84
85 while (findPos != string::npos) {
86 // Append part before the match and the replacement string
87 newString.append(source, lastPos, findPos - lastPos);
88 newString += to;
89 lastPos = findPos + from.length();
90 findPos = source.find(from, lastPos);
91 }
92
93 // Append the remaining part of the string after the last occurrence
94 newString += source.substr(lastPos);
95
96 return newString;
97}
98
99
100string fillDigits(const string& word, const string& c, int ndigits) {
101 if (c.empty() || ndigits <= static_cast<int>(word.size())) return word; // Return original if no padding needed
102
103 string filled;
104
105 int toFill = ndigits - static_cast<int>(word.size());
106 filled.reserve(ndigits);
107
108 filled.append(toFill, c[0]); // Use the first character of the string 'c'
109 filled += word;
110
111 return filled;
112}
113
114
115double getG4Number(const string& v, bool warnIfNotUnit) {
117
118 // If no '*' is found, the input is assumed to be a number without units
119 if (value.find('*') == string::npos) {
120 if (!value.empty() && warnIfNotUnit && stod(value) != 0) { std::cerr << " ! Warning: value " << v << " does not contain units." << std::endl; }
121
122 try { return stod(value); }
123 catch (const std::exception& e) {
124 std::cerr << FATALERRORL << "stod exception in gutilities: could not convert string to double. "
125 << "Value: >" << v << "<, error: " << e.what() << std::endl;
126 exit(EC__G4NUMBERERROR);
127 }
128 }
129 else {
130 // Split the input string into the numeric part and the unit part
131 size_t pos = value.find('*');
132 string rootValue = value.substr(0, pos);
133 string units = value.substr(pos + 1);
134
135 double answer = 0;
136 try { answer = stod(rootValue); }
137 catch (const std::exception& e) {
138 std::cerr << FATALERRORL << "stod exception in gutilities: could not convert string to double. "
139 << "Value: >" << v << "<, error: " << e.what() << std::endl;
140 exit(EC__G4NUMBERERROR);
141 }
142
143 // Map of unit conversions for easier lookup and maintenance
144 static const std::unordered_map<string, double> unitConversion = {
145 {"m", CLHEP::m},
146 {"cm", CLHEP::cm},
147 {"mm", CLHEP::mm},
148 {"um", 1E-6 * CLHEP::m},
149 {"fm", 1E-15 * CLHEP::m},
150 {"inches", 2.54 * CLHEP::cm},
151 {"inch", 2.54 * CLHEP::cm},
152 {"deg", CLHEP::deg},
153 {"degrees", CLHEP::deg},
154 {"arcmin", CLHEP::deg / 60.0},
155 {"rad", CLHEP::rad},
156 {"mrad", CLHEP::mrad},
157 {"eV", CLHEP::eV},
158 {"MeV", CLHEP::MeV},
159 {"KeV", 0.001 * CLHEP::MeV},
160 {"GeV", CLHEP::GeV},
161 {"T", CLHEP::tesla},
162 {"T/m", CLHEP::tesla / CLHEP::m},
163 {"Tesla", CLHEP::tesla},
164 {"gauss", CLHEP::gauss},
165 {"kilogauss", CLHEP::gauss * 1000},
166 {"s", CLHEP::s},
167 {"ns", CLHEP::ns},
168 {"ms", CLHEP::ms},
169 {"us", CLHEP::us},
170 {"counts", 1}
171 };
172
173 auto it = unitConversion.find(units);
174 if (it != unitConversion.end()) { answer *= it->second; }
175 else { std::cerr << GWARNING << ">" << units << "<: unit not recognized for string <" << v << ">" << std::endl; }
176
177 return answer;
178 }
179}
180
181double getG4Number(double input, const string& unit) {
182 string gnumber = std::to_string(input) + "*" + unit;
183 return getG4Number(gnumber, true);
184}
185
186vector<double> getG4NumbersFromStringVector(const vector<string>& vstring, bool warnIfNotUnit) {
187 vector<double> output;
188 output.reserve(vstring.size());
189
190 for (const auto& s : vstring) { output.push_back(getG4Number(s, warnIfNotUnit)); }
191
192 return output;
193}
194
195vector<double> getG4NumbersFromString(const string& vstring, bool warnIfNotUnit) {
196 return getG4NumbersFromStringVector(getStringVectorFromStringWithDelimiter(vstring, ","), warnIfNotUnit);
197}
198
199
200string parseFileAndRemoveComments(const string& filename, const string& commentChars, int verbosity) {
201 // Reading file
202 std::ifstream in(filename);
203 if (!in) {
204 std::cerr << FATALERRORL << "can't open input file " << filename << ". Check your spelling. " << std::endl;
205 exit(EC__FILENOTFOUND);
206 }
207
208 std::stringstream strStream;
209 if (verbosity > 0) { std::cout << std::endl << CIRCLEITEM << " Loading string from " << filename << std::endl; }
210 strStream << in.rdbuf(); // Read the file
211 in.close();
212
213 string parsedString = strStream.str();
214
215 // Removing all occurrences of commentChars
216 size_t nFPos;
217 while ((nFPos = parsedString.find(commentChars)) != string::npos) {
218 size_t firstNL = parsedString.rfind('\n', nFPos);
219 size_t secondNL = parsedString.find('\n', nFPos);
220 parsedString.erase(firstNL, secondNL - firstNL);
221 }
222
223 return parsedString;
224}
225
226string retrieveStringBetweenChars(const string& input, const string& firstDelimiter, const string& secondDelimiter) {
227 size_t firstpos = input.find(firstDelimiter);
228 size_t secondpos = input.find(secondDelimiter);
229
230 if (firstpos == string::npos || secondpos == string::npos) { return ""; }
231 return input.substr(firstpos + firstDelimiter.length(), secondpos - firstpos - firstDelimiter.length());
232}
233
234vector<string> getStringVectorFromStringWithDelimiter(const string& input, const string& x) {
235 vector<string> pvalues;
236 string tmp;
237
238 for (char ch : input) {
239 if (ch != x[0]) { tmp += ch; }
240 else {
241 if (!tmp.empty()) {
242 pvalues.push_back(removeLeadingAndTrailingSpacesFromString(tmp));
243 tmp.clear();
244 }
245 }
246 }
247
248 if (!tmp.empty()) { pvalues.push_back(removeLeadingAndTrailingSpacesFromString(tmp)); }
249
250 return pvalues;
251}
252
253
254// string search for a path with <name> from a possible list of absolute paths
255// returns UNINITIALIZEDSTRINGQUANTITY if not found
256// the filesystem solution does not work on linux systems.
257// TODO: periodically try this?
258//#include <filesystem>
259//
260// string searchForDirInLocations(string dirName, vector <string> possibleLocations) {
261//
262// for (auto trialLocation: possibleLocations) {
263// string possibleDir = trialLocation + "/" + dirName;
264// if (std::filesystem::exists(possibleDir)) {
265// return possibleDir;
266// }
267// }
268// return UNINITIALIZEDSTRINGQUANTITY;
269// }
270//
271// vector <string> getListOfFilesInDirectory(string dirName, vector <string> extensions) {
272//
273// vector <string> fileList;
274//
275// for (const auto &entry: std::filesystem::directory_iterator(dirName)) {
276// for (auto &extension: extensions) {
277// if (entry.path().extension() == extension) {
278// fileList.push_back(entry.path().filename());
279// }
280// }
281// }
282//
283// return fileList;
284// }
285// end of TODO
286
287#include <dirent.h>
288#include <sys/stat.h>
289
290bool directoryExists(const std::string& path) {
291 struct stat info{};
292 if (stat(path.c_str(), &info) != 0) {
293 return false; // Path does not exist
294 }
295 return (info.st_mode & S_IFDIR) != 0; // Check if it's a directory
296}
297
298string searchForDirInLocations(const string& dirName, const vector<string>& possibleLocations) {
299 for (const auto& trialLocation : possibleLocations) {
300 string possibleDir = trialLocation + "/" + dirName;
301 if (directoryExists(possibleDir)) { return possibleDir; }
302 }
303 return "UNINITIALIZEDSTRINGQUANTITY";
304}
305
306
307bool hasExtension(const std::string& filename, const std::vector<std::string>& extensions) {
308 for (const auto& ext : extensions) {
309 if (filename.size() >= ext.size() &&
310 filename.compare(filename.size() - ext.size(), ext.size(), ext) == 0) { return true; }
311 }
312 return false;
313}
314
315vector<string> getListOfFilesInDirectory(const string& dirName, const vector<string>& extensions) {
316 vector<string> fileList;
317
318 DIR* dir = opendir(dirName.c_str());
319 if (dir) {
320 struct dirent* entry;
321 while ((entry = readdir(dir)) != nullptr) {
322 struct stat info{};
323 string filepath = dirName + "/" + entry->d_name;
324 if (stat(filepath.c_str(), &info) == 0 && S_ISREG(info.st_mode)) {
325 string filename = entry->d_name;
326 if (hasExtension(filename, extensions)) { fileList.push_back(filename); }
327 }
328 }
329 closedir(dir);
330 }
331
332 return fileList;
333}
334
335string convertToLowercase(const string& str) {
336 string lower = str;
337 transform(lower.begin(), lower.end(), lower.begin(), ::tolower);
338 return lower;
339}
340
341
342template <class KEY, class VALUE>
343vector<KEY> getKeys(const map<KEY, VALUE>& map) {
344 vector<KEY> keys;
345 keys.reserve(map.size()); // Reserve space for efficiency
346
347 for (const auto& it : map) { keys.push_back(it.first); }
348
349 return keys;
350}
351
352randomModel stringToRandomModel(const std::string& str) {
353 static const std::unordered_map<std::string, randomModel> strToEnum = {
354 {"uniform", uniform},
355 {"gaussian", gaussian},
356 {"cosine", cosine},
357 {"sphere", sphere}
358 };
359
360 auto it = strToEnum.find(str);
361 if (it != strToEnum.end()) { return it->second; }
362 else { throw std::invalid_argument("Invalid string for randomModel: " + str); }
363}
364
365
366G4Colour makeColour(std::string_view code) {
367 if (code.empty()) throw std::invalid_argument("empty colour string");
368 if (code.front() == '#') code.remove_prefix(1);
369 if (code.size() != 6 && code.size() != 7)
370 throw std::invalid_argument("colour must have 6 or 7 hex digits");
371
372 auto hexNibble = [](char c) -> unsigned {
373 if ('0' <= c && c <= '9') return c - '0';
374 c = static_cast<char>(std::toupper(static_cast<unsigned char>(c)));
375 if ('A' <= c && c <= 'F') return c - 'A' + 10;
376 throw std::invalid_argument("invalid hex digit");
377 };
378
379 // ---- parse RRGGBB ----
380 unsigned rgb = 0;
381 for (int i = 0; i < 6; ++i)
382 rgb = (rgb << 4) | hexNibble(code[i]);
383
384 auto byteToDouble = [](unsigned byte) { return byte / 255.0; };
385 double r = byteToDouble((rgb >> 16) & 0xFF);
386 double g = byteToDouble((rgb >> 8) & 0xFF);
387 double b = byteToDouble(rgb & 0xFF);
388
389 // ---- optional transparency nibble ----
390 double a = 1.0;
391 if (code.size() == 7)
392 a = hexNibble(code[6]) / 15.0;
393
394 return {r, g, b, a}; // G4Colour
395}
396
397
398}
399
#define GWARNING
Warning label.
#define EC__FILENOTFOUND
File not found error code.
#define CIRCLEITEM
Symbol for circle item.
#define EC__G4NUMBERERROR
G4 number error code.
#define FATALERRORL
Fatal error label.
string replaceAllStringsWithString(const string &source, const string &from, const string &to)
Replaces all occurrences of a substring with another string.
Definition gutilities.cc:78
double getG4Number(const string &v, bool warnIfNotUnit)
Converts a string representation of a number with optional units to a double.
bool hasExtension(const std::string &filename, const std::vector< std::string > &extensions)
Checks if a filename has one of the specified extensions.
vector< double > getG4NumbersFromString(const string &vstring, bool warnIfNotUnit)
Converts a comma-separated string of numbers with units to a vector of doubles.
string removeAllSpacesFromString(const std::string &str)
Removes all spaces from a string.
Definition gutilities.cc:32
vector< string > getStringVectorFromStringWithDelimiter(const string &input, const string &x)
Splits a string into a vector of substrings using a specified delimiter.
randomModel stringToRandomModel(const std::string &str)
Converts a string to a corresponding randomModel enum value.
vector< string > getListOfFilesInDirectory(const string &dirName, const vector< string > &extensions)
Retrieves a list of files with specific extensions from a directory.
vector< double > getG4NumbersFromStringVector(const vector< string > &vstring, bool warnIfNotUnit)
Converts a vector of strings representing numbers with units to a vector of doubles.
string retrieveStringBetweenChars(const string &input, const string &firstDelimiter, const string &secondDelimiter)
Retrieves a substring between two specified delimiters in a string.
string replaceCharInStringWithChars(const std::string &input, const std::string &toReplace, const std::string &replacement)
Replaces all occurrences of specified characters in a string with another string.
Definition gutilities.cc:68
string fillDigits(const string &word, const string &c, int ndigits)
Pads a string with a specified character until it reaches a desired length.
randomModel
Enumeration of random models.
Definition gutilities.h:265
@ gaussian
Gaussian distribution.
Definition gutilities.h:267
@ uniform
Uniform distribution.
Definition gutilities.h:266
@ sphere
Sphere distribution.
Definition gutilities.h:269
@ cosine
Cosine distribution.
Definition gutilities.h:268
string getDirFromPath(const std::string &path)
Extracts the directory path from a given file path.
Definition gutilities.cc:47
string convertToLowercase(const string &str)
Converts a string to lowercase.
bool directoryExists(const std::string &path)
Checks if a directory exists at the given path.
G4Colour makeColour(std::string_view code)
Convert a hex colour string to G4Colour.
vector< KEY > getKeys(const map< KEY, VALUE > &map)
Retrieves all keys from a map.
string removeLeadingAndTrailingSpacesFromString(const std::string &input)
Removes leading and trailing spaces and tabs from a string.
Definition gutilities.cc:21
string searchForDirInLocations(const string &dirName, const vector< string > &possibleLocations)
Searches for a directory within a list of possible locations.
string parseFileAndRemoveComments(const string &filename, const string &commentChars, int verbosity)
Parses a file and removes all lines containing specified comment characters.
string getFileFromPath(const std::string &path)
Extracts the filename from a given file path.
Definition gutilities.cc:38
vector< std::string > getStringVectorFromString(const std::string &input)
Splits a string into a vector of strings using spaces as delimiters.
Definition gutilities.cc:56