6#include "CLHEP/Units/PhysicalConstants.h" 
   12#include <unordered_map> 
   22    size_t startPos = input.find_first_not_of(
" \t"); 
 
   23    size_t endPos   = input.find_last_not_of(
" \t");  
 
   26    if (startPos == std::string::npos || endPos == std::string::npos) { 
return ""; }
 
   29    return input.substr(startPos, endPos - startPos + 1);
 
 
   34    while (!s.empty() && std::isspace(
static_cast<unsigned char>(s.front()))) s.remove_prefix(1);
 
   35    while (!s.empty() && std::isspace(
static_cast<unsigned char>(s.back())))  s.remove_suffix(1);
 
 
   41    result.erase(std::remove(result.begin(), result.end(), 
' '), result.end());
 
 
   46    std::size_t lastSlashPos = path.find_last_of(
'/');
 
   47    if (lastSlashPos == std::string::npos) {
 
   51    return path.substr(lastSlashPos + 1);
 
 
   55    auto lastSlash = path.find_last_of(
'/');
 
   56    if (lastSlash == std::string::npos) 
return ".";
 
   57    return path.substr(0, lastSlash);
 
 
   60namespace fs = std::filesystem;
 
   64    std::vector<std::string> pvalues;
 
   65    std::stringstream        plist(input);
 
   67    while (plist >> tmp) {
 
   69        if (!trimmed.empty()) { pvalues.push_back(trimmed); }
 
 
   76                                    const std::string& replacement) {
 
   78    for (
const char& ch : input) {
 
   79        if (toReplace.find(ch) != std::string::npos) { output.append(replacement); }
 
   80        else { output.push_back(ch); }
 
 
   86    if (from.empty()) 
return source; 
 
   90    size_t findPos = source.find(from, lastPos);
 
   92    while (findPos != string::npos) {
 
   94        newString.append(source, lastPos, findPos - lastPos);
 
   96        lastPos = findPos + from.length();
 
   97        findPos = source.find(from, lastPos);
 
  101    newString += source.substr(lastPos);
 
 
  107string fillDigits(
const string& word, 
const string& c, 
int ndigits) {
 
  108    if (c.empty() || ndigits <= 
static_cast<int>(word.size())) 
return word; 
 
  112    int toFill = ndigits - 
static_cast<int>(word.size());
 
  113    filled.reserve(ndigits);
 
  115    filled.append(toFill, c[0]); 
 
 
  126static bool parse_double_clocale(std::string_view sv, 
double& out) {
 
  129    _locale_t loc = _create_locale(LC_NUMERIC, 
"C");
 
  131    out = _strtod_l(tmp.c_str(), &end, loc);
 
  133    return end == tmp.c_str() + tmp.size();
 
  135    locale_t loc = newlocale(LC_NUMERIC_MASK, 
"C", (locale_t)0);
 
  137    out = strtod_l(tmp.c_str(), &end, loc);
 
  139    return end == tmp.c_str() + tmp.size();
 
  148        std::cerr << 
FATALERRORL << 
"empty numeric string.\n";
 
  153    if (value.find(
'.') == string::npos) {
 
  154        size_t firstComma = value.find(
',');
 
  155        if (firstComma != string::npos && value.find(
',', firstComma + 1) == string::npos) {
 
  160    const size_t starCount = 
static_cast<size_t>(std::count(value.begin(), value.end(), 
'*'));
 
  163    if (value.find(
'*') == string::npos) {
 
  166        if (value.find(
'.') == string::npos) {
 
  167            auto firstComma = value.find(
',');
 
  168            if (firstComma != string::npos && value.find(
',', firstComma + 1) == string::npos)
 
  171        if (!parse_double_clocale(value, out)) {
 
  172            std::cerr << 
FATALERRORL << 
"missing '*' before unit or invalid number in <" << v << 
">.\n";
 
  175        if (warnIfNotUnit && out != 0.0) {
 
  176            std::cerr << 
" ! Warning: value " << v << 
" does not contain units." << std::endl;
 
  184        std::cerr << 
FATALERRORL << 
"multiple '*' separators are not allowed in <" << v << 
">.\n";
 
  189    const size_t pos = value.find(
'*');
 
  192    if (left.empty() || right.empty()) {
 
  193        std::cerr << 
FATALERRORL << 
"expected '<number>*<unit>', got <" << v << 
">.\n";
 
  198    if (left.find(
'.') == string::npos) {
 
  199        auto c = left.find(
',');
 
  200        if (c != string::npos && left.find(
',', c + 1) == string::npos)
 
  204    double numeric = 0.0;
 
  205    if (!parse_double_clocale(left, numeric)) {
 
  206        std::cerr << 
FATALERRORL << 
"invalid numeric part before '*' in <" << v << 
">.\n";
 
  218    static const std::unordered_map<string, double> unitConversion = {
 
  220        {
"m", CLHEP::m}, {
"cm", CLHEP::cm}, {
"mm", CLHEP::mm},
 
  221        {
"um", 1E-6 * CLHEP::m}, {
"fm", 1E-15 * CLHEP::m},
 
  222        {
"inch", 2.54 * CLHEP::cm}, {
"inches", 2.54 * CLHEP::cm},
 
  224        {
"deg", CLHEP::deg}, {
"degrees", CLHEP::deg}, {
"arcmin", CLHEP::deg / 60.0},
 
  225        {
"rad", CLHEP::rad}, {
"mrad", CLHEP::mrad},
 
  227        {
"ev", CLHEP::eV}, {
"kev", 1e3 * CLHEP::eV}, {
"mev", CLHEP::MeV}, {
"gev", CLHEP::GeV},
 
  229        {
"t", CLHEP::tesla}, {
"tesla", CLHEP::tesla}, {
"t/m", CLHEP::tesla / CLHEP::m},
 
  230        {
"gauss", CLHEP::gauss}, {
"kilogauss", 1000.0 * CLHEP::gauss},
 
  232        {
"s", CLHEP::s}, {
"ns", CLHEP::ns}, {
"ms", CLHEP::ms}, {
"us", CLHEP::us},
 
  238    if (
auto it = unitConversion.find(unit); it != unitConversion.end()) {
 
  239        return numeric * it->second;
 
  243    auto si_prefix_factor = [](
char p) -> 
double {
 
  245            case 'Y': 
return 1e24;  
case 'Z': 
return 1e21;  
case 'E': 
return 1e18;
 
  246            case 'P': 
return 1e15;  
case 'T': 
return 1e12;  
case 'G': 
return 1e9;
 
  247            case 'M': 
return 1e6;   
case 'k': 
return 1e3;   
case 'h': 
return 1e2;
 
  248            case 'd': 
return 1e-1;  
case 'c': 
return 1e-2;  
case 'm': 
return 1e-3;
 
  249            case 'u': 
return 1e-6;  
case 'n': 
return 1e-9;  
case 'p': 
return 1e-12;
 
  250            case 'f': 
return 1e-15; 
case 'a': 
return 1e-18; 
case 'z': 
return 1e-21; 
case 'y': 
return 1e-24;
 
  255    if (unit.size() >= 2) {
 
  256        const double pf = si_prefix_factor(unit.front());
 
  258            const string base = unit.substr(1);
 
  259            if (
auto it2 = unitConversion.find(base); it2 != unitConversion.end()) {
 
  260                return numeric * pf * it2->second;
 
  266    std::cerr << 
GWARNING << 
">" << right << 
"<: unit not recognized for string <" << v << 
">" << std::endl;
 
 
  272    string gnumber = std::to_string(input) + 
"*" + unit;
 
 
  277    vector<double> output;
 
  278    output.reserve(vstring.size());
 
  280    for (
const auto& s : vstring) { output.push_back(
getG4Number(s, warnIfNotUnit)); }
 
 
  292    std::ifstream in(filename);
 
  294        std::cerr << 
FATALERRORL << 
"can't open input file " << filename << 
". Check your spelling. " << std::endl;
 
  298    std::stringstream strStream;
 
  299    if (verbosity > 0) { std::cout << std::endl << 
CIRCLEITEM << 
" Loading string from " << filename << std::endl; }
 
  300    strStream << in.rdbuf(); 
 
  303    string parsedString = strStream.str();
 
  307    while ((nFPos = parsedString.find(commentChars)) != string::npos) {
 
  308        size_t firstNL  = parsedString.rfind(
'\n', nFPos);
 
  309        size_t secondNL = parsedString.find(
'\n', nFPos);
 
  310        parsedString.erase(firstNL, secondNL - firstNL);
 
 
  317    size_t firstpos  = input.find(firstDelimiter);
 
  318    size_t secondpos = input.find(secondDelimiter);
 
  320    if (firstpos == string::npos || secondpos == string::npos) { 
return ""; }
 
  321    return input.substr(firstpos + firstDelimiter.length(), secondpos - firstpos - firstDelimiter.length());
 
 
  325    vector<string> pvalues;
 
  328    for (
char ch : input) {
 
  329        if (ch != x[0]) { tmp += ch; }
 
 
  382    if (stat(path.c_str(), &info) != 0) {
 
  385    return (info.st_mode & S_IFDIR) != 0; 
 
 
  389    for (
const auto& trialLocation : possibleLocations) {
 
  390        string possibleDir = trialLocation + 
"/" + dirName;
 
  393    return "UNINITIALIZEDSTRINGQUANTITY";
 
 
  397bool hasExtension(
const std::string& filename, 
const std::vector<std::string>& extensions) {
 
  398    for (
const auto& ext : extensions) {
 
  399        if (filename.size() >= ext.size() &&
 
  400            filename.compare(filename.size() - ext.size(), ext.size(), ext) == 0) { 
return true; }
 
 
  406    vector<string> fileList;
 
  408    DIR* dir = opendir(dirName.c_str());
 
  410        struct dirent* entry;
 
  411        while ((entry = readdir(dir)) != 
nullptr) {
 
  413            string      filepath = dirName + 
"/" + entry->d_name;
 
  414            if (stat(filepath.c_str(), &info) == 0 && S_ISREG(info.st_mode)) {
 
  415                string filename = entry->d_name;
 
  416                if (
hasExtension(filename, extensions)) { fileList.push_back(filename); }
 
 
  427    transform(lower.begin(), lower.end(), lower.begin(), ::tolower);
 
 
  432template <
class KEY, 
class VALUE>
 
  433vector<KEY> 
getKeys(
const map<KEY, VALUE>& map) {
 
  435    keys.reserve(map.size()); 
 
  437    for (
const auto& it : map) { keys.push_back(it.first); }
 
 
  443    static const std::unordered_map<std::string, randomModel> strToEnum = {
 
  450    auto it = strToEnum.find(str);
 
  451    if (it != strToEnum.end()) { 
return it->second; }
 
  452    else { 
throw std::invalid_argument(
"Invalid string for randomModel: " + str); }
 
 
  457    if (code.empty()) 
throw std::invalid_argument(
"empty colour string");
 
  458    if (code.front() == 
'#') code.remove_prefix(1);
 
  459    if (code.size() != 6)
 
  460        throw std::invalid_argument(
"colour must have 6 or 7 hex digits");
 
  462    auto hexNibble = [](
char c) -> 
unsigned {
 
  463        if (
'0' <= c && c <= 
'9') 
return c - 
'0';
 
  464        c = 
static_cast<char>(std::toupper(
static_cast<unsigned char>(c)));
 
  465        if (
'A' <= c && c <= 
'F') 
return c - 
'A' + 10;
 
  466        throw std::invalid_argument(
"invalid hex digit");
 
  471    for (
int i = 0; i < 6; ++i)
 
  472        rgb    = (rgb << 4) | hexNibble(code[i]);
 
  474    auto   byteToDouble = [](
unsigned byte) { 
return byte / 255.0; };
 
  475    double r            = byteToDouble((rgb >> 16) & 0xFF);
 
  476    double g            = byteToDouble((rgb >> 8) & 0xFF);
 
  477    double b            = byteToDouble(rgb & 0xFF);
 
  479    return {r, g, b, opacity}; 
 
 
  483    const std::vector<std::string>& locations,
 
  484    std::string_view                filename) {
 
  485    namespace fs = std::filesystem;
 
  487    for (
const auto& loc : locations) {
 
  488        if (loc.empty()) 
continue;
 
  491        fs::path candidate = (!filename.empty() && fs::is_directory(p))
 
  496        const bool      ok = fs::exists(candidate, ec) && fs::is_regular_file(candidate, ec);
 
  497        if (ok) 
return candidate.string();
 
 
  504    if (s.empty()) 
return true;
 
  506    auto eq = [](std::string_view a, std::string_view b){
 
  507        if (a.size()!=b.size()) 
return false;
 
  508        for (
size_t i=0;i<a.size();++i)
 
  509            if (std::tolower(
static_cast<unsigned char>(a[i])) != std::tolower(
static_cast<unsigned char>(b[i])))
 
 
 
#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 UNINITIALIZEDSTRINGQUANTITY
Represents an uninitialized string quantity.
 
#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.
 
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.
 
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)
 
randomModel
Enumeration of random models.
 
@ gaussian
Gaussian distribution.
 
@ uniform
Uniform distribution.
 
@ sphere
Sphere distribution.
 
@ cosine
Cosine distribution.
 
string getDirFromPath(const std::string &path)
Extracts the directory path from a given file path.
 
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.
 
std::optional< std::string > searchForFileInLocations(const std::vector< std::string > &locations, std::string_view filename)
 
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.
 
vector< std::string > getStringVectorFromString(const std::string &input)
Splits a string into a vector of strings using spaces as delimiters.