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/*
21 * Trim leading/trailing spaces and tabs from an owning std::string.
22 *
23 * Notes:
24 * - Whitespace considered here is strictly ' ' and '\t' (tab).
25 * - If the input is all whitespace (or empty), returns an empty string.
26 *
27 * See the API documentation in gutilities.h for full Doxygen docs.
28 */
29string removeLeadingAndTrailingSpacesFromString(const std::string& input) {
30 size_t startPos = input.find_first_not_of(" \t"); // Find the first non-whitespace character
31 size_t endPos = input.find_last_not_of(" \t"); // Find the last non-whitespace character
32
33 // If all spaces or empty, return an empty string
34 if (startPos == std::string::npos || endPos == std::string::npos) { return ""; }
35
36 // Return the substring between startPos and endPos
37 return input.substr(startPos, endPos - startPos + 1);
38}
39
40/*
41 * Fast trim for std::string_view.
42 *
43 * Notes:
44 * - No allocations: adjusts the view by removing prefix/suffix.
45 * - Uses std::isspace (locale-sensitive) to classify whitespace.
46 *
47 * See the API documentation in gutilities.h for full Doxygen docs.
48 */
49std::string_view removeLeadingAndTrailingSpacesFromString(std::string_view s) {
50 while (!s.empty() && std::isspace(static_cast<unsigned char>(s.front()))) s.remove_prefix(1);
51 while (!s.empty() && std::isspace(static_cast<unsigned char>(s.back()))) s.remove_suffix(1);
52 return s;
53}
54
55/*
56 * Remove all literal spaces ' ' from a string.
57 *
58 * See the API documentation in gutilities.h for full Doxygen docs.
59 */
60string removeAllSpacesFromString(const std::string& str) {
61 string result = str;
62 result.erase(std::remove(result.begin(), result.end(), ' '), result.end());
63 return result;
64}
65
66/*
67 * Extract the filename component from a POSIX-style path (splitting on '/').
68 *
69 * See the API documentation in gutilities.h for full Doxygen docs.
70 */
71string getFileFromPath(const std::string& path) {
72 std::size_t lastSlashPos = path.find_last_of('/');
73 if (lastSlashPos == std::string::npos) {
74 // No slashes found, return the entire path
75 return path;
76 }
77 return path.substr(lastSlashPos + 1);
78}
79
80/*
81 * Extract the directory component from a POSIX-style path (splitting on '/').
82 *
83 * See the API documentation in gutilities.h for full Doxygen docs.
84 */
85string getDirFromPath(const std::string& path) {
86 auto lastSlash = path.find_last_of('/');
87 if (lastSlash == std::string::npos) return ".";
88 return path.substr(0, lastSlash);
89}
90
91namespace fs = std::filesystem;
92
93
94/*
95 * Tokenize a string on whitespace into a vector.
96 *
97 * See the API documentation in gutilities.h for full Doxygen docs.
98 */
99vector<std::string> getStringVectorFromString(const std::string& input) {
100 std::vector<std::string> pvalues;
101 std::stringstream plist(input);
102 string tmp;
103 while (plist >> tmp) {
104 string trimmed = removeLeadingAndTrailingSpacesFromString(tmp);
105 if (!trimmed.empty()) { pvalues.push_back(trimmed); }
106 }
107 return pvalues;
108}
109
110/*
111 * Replace any character found in 'toReplace' with the string 'replacement'.
112 *
113 * See the API documentation in gutilities.h for full Doxygen docs.
114 */
115string replaceCharInStringWithChars(const std::string& input, const std::string& toReplace,
116 const std::string& replacement) {
117 string output;
118 for (const char& ch : input) {
119 if (toReplace.find(ch) != std::string::npos) { output.append(replacement); }
120 else { output.push_back(ch); }
121 }
122 return output;
123}
124
125/*
126 * Replace all occurrences of substring 'from' with substring 'to'.
127 *
128 * See the API documentation in gutilities.h for full Doxygen docs.
129 */
130string replaceAllStringsWithString(const string& source, const string& from, const string& to) {
131 if (from.empty()) return source; // Avoid infinite loop
132
133 string newString;
134 size_t lastPos = 0;
135 size_t findPos = source.find(from, lastPos);
136
137 while (findPos != string::npos) {
138 // Append part before the match and the replacement string
139 newString.append(source, lastPos, findPos - lastPos);
140 newString += to;
141 lastPos = findPos + from.length();
142 findPos = source.find(from, lastPos);
143 }
144
145 // Append the remaining part of the string after the last occurrence
146 newString += source.substr(lastPos);
147
148 return newString;
149}
150
151
152/*
153 * Left-pad a string using the first character of 'c' until length reaches ndigits.
154 *
155 * See the API documentation in gutilities.h for full Doxygen docs.
156 */
157string fillDigits(const string& word, const string& c, int ndigits) {
158 if (c.empty() || ndigits <= static_cast<int>(word.size())) return word; // Return original if no padding needed
159
160 string filled;
161
162 int toFill = ndigits - static_cast<int>(word.size());
163 filled.reserve(ndigits);
164
165 filled.append(toFill, c[0]); // Use the first character of the string 'c'
166 filled += word;
167
168 return filled;
169}
170
171// add near your includes:
172#include <locale.h> // strtod_l / _strtod_l
173
191static bool parse_double_clocale(std::string_view sv, double& out) {
192 std::string tmp(sv); // strtod_l needs a 0-terminated buffer
193#if defined(_WIN32)
194 _locale_t loc = _create_locale(LC_NUMERIC, "C");
195 char* end = nullptr;
196 out = _strtod_l(tmp.c_str(), &end, loc);
197 _free_locale(loc);
198 return end == tmp.c_str() + tmp.size();
199#else
200 locale_t loc = newlocale(LC_NUMERIC_MASK, "C", (locale_t)0);
201 char* end = nullptr;
202 out = strtod_l(tmp.c_str(), &end, loc);
203 freelocale(loc);
204 return end == tmp.c_str() + tmp.size();
205#endif
206}
207
208
209// --- strict, locale-independent getG4Number: only accepts '*' as unit sep ---
210double getG4Number(const string& v, bool warnIfNotUnit) {
212 if (value.empty()) {
213 std::cerr << FATALERRORL << "empty numeric string.\n";
214 exit(EC__G4NUMBERERROR);
215 }
216
217 // Normalize a single decimal comma to dot when no dot is present
218 if (value.find('.') == string::npos) {
219 size_t firstComma = value.find(',');
220 if (firstComma != string::npos && value.find(',', firstComma + 1) == string::npos) {
221 value = replaceAllStringsWithString(value, ",", ".");
222 }
223 }
224
225 const size_t starCount = static_cast<size_t>(std::count(value.begin(), value.end(), '*'));
226
227 // --- Case 1: no '*' → pure number (strictly no trailing garbage) ---
228 if (value.find('*') == string::npos) {
229 double out = 0.0;
230 // normalize a single decimal comma to dot if needed
231 if (value.find('.') == string::npos) {
232 auto firstComma = value.find(',');
233 if (firstComma != string::npos && value.find(',', firstComma + 1) == string::npos)
234 value = replaceAllStringsWithString(value, ",", ".");
235 }
236 if (!parse_double_clocale(value, out)) {
237 std::cerr << FATALERRORL << "missing '*' before unit or invalid number in <" << v << ">.\n";
238 exit(EC__G4NUMBERERROR);
239 }
240 if (warnIfNotUnit && out != 0.0) {
241 std::cerr << " ! Warning: value " << v << " does not contain units." << std::endl;
242 }
243 return out;
244 }
245
246
247 // --- Case 2: must be exactly one '*' ---
248 if (starCount > 1) {
249 std::cerr << FATALERRORL << "multiple '*' separators are not allowed in <" << v << ">.\n";
250 exit(EC__G4NUMBERERROR);
251 }
252
253 // --- Exactly one '*' → split "<number>*<unit>" ---
254 const size_t pos = value.find('*');
255 string left = removeLeadingAndTrailingSpacesFromString(value.substr(0, pos));
256 string right = removeLeadingAndTrailingSpacesFromString(value.substr(pos + 1));
257 if (left.empty() || right.empty()) {
258 std::cerr << FATALERRORL << "expected '<number>*<unit>', got <" << v << ">.\n";
259 exit(EC__G4NUMBERERROR);
260 }
261
262 // normalize a single decimal comma in the numeric part
263 if (left.find('.') == string::npos) {
264 auto c = left.find(',');
265 if (c != string::npos && left.find(',', c + 1) == string::npos)
266 left = replaceAllStringsWithString(left, ",", ".");
267 }
268
269 double numeric = 0.0;
270 if (!parse_double_clocale(left, numeric)) {
271 std::cerr << FATALERRORL << "invalid numeric part before '*' in <" << v << ">.\n";
272 exit(EC__G4NUMBERERROR);
273 }
274
275 // sanitize unit and proceed with your existing unit table logic...
276 right = replaceAllStringsWithString(right, "µ", "u");
277 string unit = convertToLowercase(right);
278
279 // (keep your unitConversion map and SI prefix handling as-is)
280
281
282 // Unit table (lowercase keys)
283 static const std::unordered_map<string, double> unitConversion = {
284 // length
285 {"m", CLHEP::m}, {"cm", CLHEP::cm}, {"mm", CLHEP::mm},
286 {"um", 1E-6 * CLHEP::m}, {"fm", 1E-15 * CLHEP::m},
287 {"inch", 2.54 * CLHEP::cm}, {"inches", 2.54 * CLHEP::cm},
288 // angle
289 {"deg", CLHEP::deg}, {"degrees", CLHEP::deg}, {"arcmin", CLHEP::deg / 60.0},
290 {"rad", CLHEP::rad}, {"mrad", CLHEP::mrad},
291 // energy
292 {"ev", CLHEP::eV}, {"kev", 1e3 * CLHEP::eV}, {"mev", CLHEP::MeV}, {"gev", CLHEP::GeV},
293 // magnetic field
294 {"t", CLHEP::tesla}, {"tesla", CLHEP::tesla}, {"t/m", CLHEP::tesla / CLHEP::m},
295 {"gauss", CLHEP::gauss}, {"kilogauss", 1000.0 * CLHEP::gauss},
296 // time
297 {"s", CLHEP::s}, {"ns", CLHEP::ns}, {"ms", CLHEP::ms}, {"us", CLHEP::us},
298 // dimensionless
299 {"counts", 1.0}
300 };
301
302 // Exact unit match
303 if (auto it = unitConversion.find(unit); it != unitConversion.end()) {
304 return numeric * it->second;
305 }
306
307 // SI prefix handling: mT, uT, mm, um, etc.
308 auto si_prefix_factor = [](char p) -> double {
309 switch (p) {
310 case 'Y': return 1e24;
311 case 'Z': return 1e21;
312 case 'E': return 1e18;
313 case 'P': return 1e15;
314 case 'T': return 1e12;
315 case 'G': return 1e9;
316 case 'M': return 1e6;
317 case 'k': return 1e3;
318 case 'h': return 1e2;
319 case 'd': return 1e-1;
320 case 'c': return 1e-2;
321 case 'm': return 1e-3;
322 case 'u': return 1e-6;
323 case 'n': return 1e-9;
324 case 'p': return 1e-12;
325 case 'f': return 1e-15;
326 case 'a': return 1e-18;
327 case 'z': return 1e-21;
328 case 'y': return 1e-24;
329 default: return 0.0;
330 }
331 };
332
333 if (unit.size() >= 2) {
334 const double pf = si_prefix_factor(unit.front());
335 if (pf != 0.0) {
336 const string base = unit.substr(1);
337 if (auto it2 = unitConversion.find(base); it2 != unitConversion.end()) {
338 return numeric * pf * it2->second;
339 }
340 }
341 }
342
343 // Unknown unit: warn & return numeric part (keep your legacy behavior)
344 std::cerr << GWARNING << ">" << right << "<: unit not recognized for string <" << v << ">" << std::endl;
345 return numeric;
346}
347
348
349double getG4Number(double input, const string& unit) {
350 string gnumber = std::to_string(input) + "*" + unit;
351 return getG4Number(gnumber, true);
352}
353
354vector<double> getG4NumbersFromStringVector(const vector<string>& vstring, bool warnIfNotUnit) {
355 vector<double> output;
356 output.reserve(vstring.size());
357
358 for (const auto& s : vstring) { output.push_back(getG4Number(s, warnIfNotUnit)); }
359
360 return output;
361}
362
363vector<double> getG4NumbersFromString(const string& vstring, bool warnIfNotUnit) {
364 return getG4NumbersFromStringVector(getStringVectorFromStringWithDelimiter(vstring, ","), warnIfNotUnit);
365}
366
367
368string parseFileAndRemoveComments(const string& filename, const string& commentChars, int verbosity) {
369 // Reading file
370 std::ifstream in(filename);
371 if (!in) {
372 std::cerr << FATALERRORL << "can't open input file " << filename << ". Check your spelling. " << std::endl;
373 exit(EC__FILENOTFOUND);
374 }
375
376 std::stringstream strStream;
377 if (verbosity > 0) { std::cout << std::endl << CIRCLEITEM << " Loading string from " << filename << std::endl; }
378 strStream << in.rdbuf(); // Read the file
379 in.close();
380
381 string parsedString = strStream.str();
382
383 // Removing all occurrences of commentChars
384 size_t nFPos;
385 while ((nFPos = parsedString.find(commentChars)) != string::npos) {
386 size_t firstNL = parsedString.rfind('\n', nFPos);
387 size_t secondNL = parsedString.find('\n', nFPos);
388 parsedString.erase(firstNL, secondNL - firstNL);
389 }
390
391 return parsedString;
392}
393
394string retrieveStringBetweenChars(const string& input, const string& firstDelimiter, const string& secondDelimiter) {
395 size_t firstpos = input.find(firstDelimiter);
396 size_t secondpos = input.find(secondDelimiter);
397
398 if (firstpos == string::npos || secondpos == string::npos) { return ""; }
399 return input.substr(firstpos + firstDelimiter.length(), secondpos - firstpos - firstDelimiter.length());
400}
401
402vector<string> getStringVectorFromStringWithDelimiter(const string& input, const string& x) {
403 vector<string> pvalues;
404 string tmp;
405
406 for (char ch : input) {
407 if (ch != x[0]) { tmp += ch; }
408 else {
409 if (!tmp.empty()) {
410 pvalues.push_back(removeLeadingAndTrailingSpacesFromString(tmp));
411 tmp.clear();
412 }
413 }
414 }
415
416 if (!tmp.empty()) { pvalues.push_back(removeLeadingAndTrailingSpacesFromString(tmp)); }
417
418 return pvalues;
419}
420
421
422// string search for a path with <name> from a possible list of absolute paths
423// returns UNINITIALIZEDSTRINGQUANTITY if not found
424// the filesystem solution does not work on linux systems.
425// TODO: periodically try this?
426//#include <filesystem>
427//
428// string searchForDirInLocations(string dirName, vector <string> possibleLocations) {
429//
430// for (auto trialLocation: possibleLocations) {
431// string possibleDir = trialLocation + "/" + dirName;
432// if (std::filesystem::exists(possibleDir)) {
433// return possibleDir;
434// }
435// }
436// return UNINITIALIZEDSTRINGQUANTITY;
437// }
438//
439// vector <string> getListOfFilesInDirectory(string dirName, vector <string> extensions) {
440//
441// vector <string> fileList;
442//
443// for (const auto &entry: std::filesystem::directory_iterator(dirName)) {
444// for (auto &extension: extensions) {
445// if (entry.path().extension() == extension) {
446// fileList.push_back(entry.path().filename());
447// }
448// }
449// }
450//
451// return fileList;
452// }
453// end of TODO
454
455#include <dirent.h>
456#include <sys/stat.h>
457
458bool directoryExists(const std::string& path) {
459 struct stat info{};
460 if (stat(path.c_str(), &info) != 0) {
461 return false; // Path does not exist
462 }
463 return (info.st_mode & S_IFDIR) != 0; // Check if it's a directory
464}
465
466string searchForDirInLocations(const string& dirName, const vector<string>& possibleLocations) {
467 for (const auto& trialLocation : possibleLocations) {
468 string possibleDir = trialLocation + "/" + dirName;
469 if (directoryExists(possibleDir)) { return possibleDir; }
470 }
471 return "UNINITIALIZEDSTRINGQUANTITY";
472}
473
474
475bool hasExtension(const std::string& filename, const std::vector<std::string>& extensions) {
476 for (const auto& ext : extensions) {
477 if (filename.size() >= ext.size() &&
478 filename.compare(filename.size() - ext.size(), ext.size(), ext) == 0) { return true; }
479 }
480 return false;
481}
482
483vector<string> getListOfFilesInDirectory(const string& dirName, const vector<string>& extensions) {
484 vector<string> fileList;
485
486 DIR* dir = opendir(dirName.c_str());
487 if (dir) {
488 struct dirent* entry;
489 while ((entry = readdir(dir)) != nullptr) {
490 struct stat info{};
491 string filepath = dirName + "/" + entry->d_name;
492 if (stat(filepath.c_str(), &info) == 0 && S_ISREG(info.st_mode)) {
493 string filename = entry->d_name;
494 if (hasExtension(filename, extensions)) { fileList.push_back(filename); }
495 }
496 }
497 closedir(dir);
498 }
499
500 return fileList;
501}
502
503string convertToLowercase(const string& str) {
504 string lower = str;
505 transform(lower.begin(), lower.end(), lower.begin(), ::tolower);
506 return lower;
507}
508
509
510template <class KEY, class VALUE>
511vector<KEY> getKeys(const map<KEY, VALUE>& map) {
512 vector<KEY> keys;
513 keys.reserve(map.size()); // Reserve space for efficiency
514
515 for (const auto& it : map) { keys.push_back(it.first); }
516
517 return keys;
518}
519
520randomModel stringToRandomModel(const std::string& str) {
521 static const std::unordered_map<std::string, randomModel> strToEnum = {
522 {"uniform", uniform},
523 {"gaussian", gaussian},
524 {"cosine", cosine},
525 {"sphere", sphere}
526 };
527
528 auto it = strToEnum.find(str);
529 if (it != strToEnum.end()) { return it->second; }
530 else { throw std::invalid_argument("Invalid string for randomModel: " + str); }
531}
532
533
534G4Colour makeG4Colour(std::string_view code, double opacity) {
535 if (code.empty()) throw std::invalid_argument("empty colour string");
536 if (code.front() == '#') code.remove_prefix(1);
537 if (code.size() != 6)
538 throw std::invalid_argument("colour must have 6 or 7 hex digits");
539
540 auto hexNibble = [](char c) -> unsigned {
541 if ('0' <= c && c <= '9') return c - '0';
542 c = static_cast<char>(std::toupper(static_cast<unsigned char>(c)));
543 if ('A' <= c && c <= 'F') return c - 'A' + 10;
544 throw std::invalid_argument("invalid hex digit");
545 };
546
547 // ---- parse RRGGBB ----
548 unsigned rgb = 0;
549 for (int i = 0; i < 6; ++i)
550 rgb = (rgb << 4) | hexNibble(code[i]);
551
552 auto byteToDouble = [](unsigned byte) { return byte / 255.0; };
553 double r = byteToDouble((rgb >> 16) & 0xFF);
554 double g = byteToDouble((rgb >> 8) & 0xFF);
555 double b = byteToDouble(rgb & 0xFF);
556
557 return {r, g, b, opacity}; // G4Colour
558}
559
560std::optional<std::string> searchForFileInLocations(
561 const std::vector<std::string>& locations,
562 std::string_view filename) {
563 namespace fs = std::filesystem;
564
565 for (const auto& loc : locations) {
566 if (loc.empty()) continue;
567
568 fs::path p(loc);
569 fs::path candidate = (!filename.empty() && fs::is_directory(p))
570 ? (p / filename)
571 : p;
572
573 std::error_code ec;
574 const bool ok = fs::exists(candidate, ec) && fs::is_regular_file(candidate, ec);
575 if (ok) return candidate.string();
576 }
577 return std::nullopt;
578}
579
580bool is_unset(std::string_view s) {
582 if (s.empty()) return true;
583 // match your sentinel and YAML nully spellings
584 auto eq = [](std::string_view a, std::string_view b) {
585 if (a.size() != b.size()) return false;
586 for (size_t i = 0; i < a.size(); ++i)
587 if (std::tolower(static_cast<unsigned char>(a[i])) != std::tolower(static_cast<unsigned char>(b[i])))
588 return false;
589 return true;
590 };
591 return eq(s, UNINITIALIZEDSTRINGQUANTITY) || eq(s, "null") || eq(s, "~");
592}
593
594void apply_uimanager_commands(const std::string& command) {
595 G4UImanager* g4uim = G4UImanager::GetUIpointer();
596 if (g4uim == nullptr) { return; }
597 g4uim->ApplyCommand(command);
598}
599}
Public API for the gutilities namespace.
Common constants and console-formatting macros used across gutilities and related code.
#define GWARNING
Standardized warning label prefix (bold yellow).
#define EC__FILENOTFOUND
Process exit code used when an expected file cannot be opened or found.
#define CIRCLEITEM
Hollow bullet glyph used for list formatting in console logs.
#define EC__G4NUMBERERROR
Process exit code used when parsing a Geant4-style numeric string fails.
#define UNINITIALIZEDSTRINGQUANTITY
Sentinel string representing an uninitialized string quantity.
#define FATALERRORL
Standardized fatal error label prefix (bold red).
string replaceAllStringsWithString(const string &source, const string &from, const string &to)
Replaces all occurrences of a substring with another string.
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:60
vector< string > getStringVectorFromStringWithDelimiter(const string &input, const string &x)
Splits a string into a vector of substrings using a specified delimiter.
G4Colour makeG4Colour(std::string_view code, double opacity)
Convert a hex colour string to G4Colour.
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.
string fillDigits(const string &word, const string &c, int ndigits)
Pads a string with a specified character until it reaches a desired length.
bool is_unset(std::string_view s)
Determine whether a string should be treated as "unset".
randomModel
Enumeration of random models.
Definition gutilities.h:399
@ gaussian
Gaussian distribution.
Definition gutilities.h:401
@ uniform
Uniform distribution.
Definition gutilities.h:400
@ sphere
Sphere distribution.
Definition gutilities.h:403
@ cosine
Cosine distribution.
Definition gutilities.h:402
string getDirFromPath(const std::string &path)
Extracts the directory path from a given file path.
Definition gutilities.cc:85
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.
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:29
std::optional< std::string > searchForFileInLocations(const std::vector< std::string > &locations, std::string_view filename)
Search for a regular file across candidate locations.
void apply_uimanager_commands(const std::string &command)
Apply a single Geant4 UI command if a UI manager is available.
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:71
vector< std::string > getStringVectorFromString(const std::string &input)
Splits a string into a vector of strings using whitespace as delimiters.
Definition gutilities.cc:99