Geant4 Cross Reference |
1 // 2 // ******************************************************************** 3 // * License and Disclaimer * 4 // * * 5 // * The Geant4 software is copyright of the Copyright Holders of * 6 // * the Geant4 Collaboration. It is provided under the terms and * 7 // * conditions of the Geant4 Software License, included in the file * 8 // * LICENSE and available at http://cern.ch/geant4/license . These * 9 // * include a list of copyright holders. * 10 // * * 11 // * Neither the authors of this software system, nor their employing * 12 // * institutes,nor the agencies providing financial support for this * 13 // * work make any representation or warranty, express or implied, * 14 // * regarding this software system or assume any liability for its * 15 // * use. Please see the license in the file LICENSE and URL above * 16 // * for the full disclaimer and the limitation of liability. * 17 // * * 18 // * This code implementation is the result of the scientific and * 19 // * technical work of the GEANT4 collaboration. * 20 // * By using, copying, modifying or distributing the software (or * 21 // * any work based on the software) you agree to acknowledge its * 22 // * use in resulting scientific publications, and indicate your * 23 // * acceptance of all terms of the Geant4 Software license. * 24 // ******************************************************************** 25 // 26 // Global environment utility functions: 27 // 28 // G4GetEnv<T> 29 // Simplifies getting environment variables 30 // Automatic conversion to non-string types 31 // Records the values used from the environment 32 // G4GetDataEnv 33 // For data library paths 34 // Will issue a G4Exception if not set 35 // G4PrintEnv 36 // Provide a way for users to determine (and log) the environment 37 // variables were used as settings in simulation 38 39 // Author: Jonathan Madsen, 25 October 2018 40 // --------------------------------------------------------------------------- 41 #ifndef G4ENVIRONMENTUTILS_HH 42 #define G4ENVIRONMENTUTILS_HH 43 44 #include <cstdlib> 45 #include <iomanip> 46 #include <iostream> 47 #include <map> 48 #include <mutex> 49 #include <sstream> 50 #include <string> 51 52 #include "G4Exception.hh" 53 #include "G4ExceptionSeverity.hh" 54 #include "G4String.hh" 55 #include "G4ios.hh" 56 57 class G4EnvSettings 58 { 59 // Static singleton class storing environment variables and 60 // their values that were used by Geant4 in the simulation 61 62 public: 63 using string_t = std::string; 64 using env_map_t = std::map<string_t, string_t>; 65 using env_pair_t = std::pair<string_t, string_t>; 66 67 static G4EnvSettings* GetInstance() 68 { 69 static auto* _instance = new G4EnvSettings(); 70 return _instance; 71 } 72 73 template <typename _Tp> 74 void insert(const std::string& env_id, _Tp val) 75 { 76 std::stringstream ss; 77 ss << val; 78 // lock for MT mode, use C++ type not Geant4 because this file 79 // is included by the those headers 80 static std::mutex _mutex; 81 _mutex.lock(); 82 m_env.insert(env_pair_t(env_id, ss.str())); 83 _mutex.unlock(); 84 } 85 86 const env_map_t& get() const { return m_env; } 87 88 friend std::ostream& operator<<(std::ostream& os, const G4EnvSettings& env) 89 { 90 std::stringstream filler; 91 filler.fill('#'); 92 filler << std::setw(90) << ""; 93 std::stringstream ss; 94 ss << filler.str() << "\n# Environment settings:\n"; 95 for(const auto& itr : env.get()) 96 { 97 ss << "# " << std::setw(35) << std::right << itr.first << "\t = \t" 98 << std::left << itr.second << "\n"; 99 } 100 ss << filler.str(); 101 os << ss.str() << std::endl; 102 return os; 103 } 104 105 private: 106 env_map_t m_env; 107 }; 108 109 // --------------------------------------------------------------------------- 110 // Use this function to get an environment variable setting + 111 // a default if not defined, e.g. 112 // int num_threads = 113 // G4GetEnv<int>("G4FORCENUMBEROFTHREADS", 114 // std::thread::hardware_concurrency()); 115 template <typename _Tp> 116 _Tp G4GetEnv(const std::string& env_id, _Tp _default = _Tp()) 117 { 118 char* env_var = std::getenv(env_id.c_str()); 119 if(env_var) 120 { 121 std::string str_var = std::string(env_var); 122 std::istringstream iss(str_var); 123 _Tp var = _Tp(); 124 iss >> var; 125 // record value defined by environment 126 G4EnvSettings::GetInstance()->insert<_Tp>(env_id, var); 127 return var; 128 } 129 // record default value 130 G4EnvSettings::GetInstance()->insert<_Tp>(env_id, _default); 131 132 // return default if not specified in environment 133 return _default; 134 } 135 136 // --------------------------------------------------------------------------- 137 // Use this function to get an environment variable setting + 138 // a default if not defined, e.g. 139 // int num_threads = 140 // GetEnv<int>("FORCENUMBEROFTHREADS", 141 // std::thread::hardware_concurrency()); 142 template <> 143 inline G4bool G4GetEnv(const std::string& env_id, bool _default) 144 { 145 char* env_var = std::getenv(env_id.c_str()); 146 if(env_var != nullptr) 147 { 148 // record value defined by environment 149 G4EnvSettings::GetInstance()->insert<bool>(env_id, true); 150 return true; 151 } 152 // record default value 153 G4EnvSettings::GetInstance()->insert<bool>(env_id, false); 154 155 // return default if not specified in environment 156 return _default; 157 } 158 159 // --------------------------------------------------------------------------- 160 // Use this function to get an environment variable setting + 161 // a default if not defined and a message about the setting, e.g. 162 // int num_threads = 163 // G4GetEnv<int>("G4FORCENUMBEROFTHREADS", 164 // std::thread::hardware_concurrency(), 165 // "Forcing number of threads"); 166 template <typename _Tp> 167 _Tp G4GetEnv(const std::string& env_id, _Tp _default, const std::string& msg) 168 { 169 char* env_var = std::getenv(env_id.c_str()); 170 if(env_var) 171 { 172 std::string str_var = std::string(env_var); 173 std::istringstream iss(str_var); 174 _Tp var = _Tp(); 175 iss >> var; 176 G4cout << "Environment variable \"" << env_id << "\" enabled with " 177 << "value == " << var << ". " << msg << G4endl; 178 // record value defined by environment 179 G4EnvSettings::GetInstance()->insert<_Tp>(env_id, var); 180 return var; 181 } 182 // record default value 183 G4EnvSettings::GetInstance()->insert<_Tp>(env_id, _default); 184 185 // return default if not specified in environment 186 return _default; 187 } 188 189 // --------------------------------------------------------------------------- 190 // Use this function to get a data directory environment variable setting + 191 // and raise a G4Exception if the value is not set, e.g. 192 // 193 // G4String filename = G4GetDataEnv("G4ENSDFSTATEDATA", 194 // "G4NuclideTable", "PART70000", 195 // FatalException, 196 // "G4ENSDFSTATEDATA environment variable" 197 // " must be set"); 198 inline G4String G4GetDataEnv(const std::string& env_id, 199 const char* originOfException, 200 const char* exceptionCode, 201 G4ExceptionSeverity severity, 202 const char* description) 203 { 204 char* env_var = std::getenv(env_id.c_str()); 205 if(env_var != nullptr) 206 { 207 std::string str_var = std::string(env_var); 208 std::istringstream iss(str_var); 209 G4String var = ""; 210 iss >> var; 211 // record value defined by environment 212 G4EnvSettings::GetInstance()->insert<G4String>(env_id, var); 213 return var; 214 } 215 216 // issue an exception 217 G4Exception(originOfException, exceptionCode, severity, description); 218 219 // return default initialized 220 return ""; 221 } 222 223 const char* G4FindDataDir(const char*); 224 225 // --------------------------------------------------------------------------- 226 // Use this function to print the environment 227 // 228 inline void G4PrintEnv(std::ostream& os = G4cout) 229 { 230 os << (*G4EnvSettings::GetInstance()); 231 } 232 233 #endif /* G4ENVIRONMENTUTILS_HH */ 234