![]() |
CASToR
1.0
Tomographic Reconstruction (PET/SPECT)
|
00001 00002 /* 00003 Implementation of class sOutputManager 00004 00005 - separators: X 00006 - doxygen: X 00007 - default initialization: X 00008 - CASTOR_DEBUG: none 00009 - CASTOR_VERBOSE: none 00010 */ 00011 00019 #include "sOutputManager.hh" 00020 #include "oImageSpace.hh" 00021 #include "oImageDimensionsAndQuantification.hh" 00022 #include <iomanip> 00023 00024 #ifdef CASToR_USE_CMAKE 00025 #include "oCASToRConfig.hh" 00026 #endif 00027 00028 // ===================================================================== 00029 // --------------------------------------------------------------------- 00030 // --------------------------------------------------------------------- 00031 // ===================================================================== 00032 00033 // Implementation of the exit function that must be used instead of the standard exit 00034 void Exit(int code) 00035 { 00036 if (code!=0) Cerr("***** Exit function called. Abort with code " << code << "." << endl); 00037 #ifdef CASTOR_MPI 00038 MPI_Finalize(); 00039 #endif 00040 exit(code); 00041 } 00042 00043 // Singleton : set pointer to object to NULL 00044 sOutputManager *sOutputManager::mp_Instance = NULL; 00045 00046 // ===================================================================== 00047 // --------------------------------------------------------------------- 00048 // --------------------------------------------------------------------- 00049 // ===================================================================== 00050 /* 00051 \brief sOutputManager constructor. 00052 \details It is private at this class is singleton. 00053 It should be instanciated using the GetInstance() function 00054 Initialize the member variables to their default values. 00055 */ 00056 sOutputManager::sOutputManager() 00057 { 00058 // Initialize all members as default 00059 m_verbose = 0; 00060 m_mpiRank = 0; 00061 m_baseName = ""; 00062 m_pathName = ""; 00063 m_pathToConfigDir = ""; 00064 m_mergeOutputDynImgFlag = false; 00065 // Set scientific numbers 00066 cout << std::scientific; 00067 //cout << std::setprecision(std::numeric_limits<FLTNB>::digits10+1); 00068 cerr << std::setprecision(std::numeric_limits<FLTNB>::digits10+1); 00069 } 00070 00071 00072 00073 // ===================================================================== 00074 // --------------------------------------------------------------------- 00075 // --------------------------------------------------------------------- 00076 // ===================================================================== 00077 /* 00078 \brief sOutputManager destructor. 00079 */ 00080 sOutputManager::~sOutputManager() 00081 { 00082 // Just have to close the log file 00083 if (m_mpiRank==0 && m_logFile) m_logFile.close(); 00084 } 00085 00086 00087 00088 // ===================================================================== 00089 // --------------------------------------------------------------------- 00090 // --------------------------------------------------------------------- 00091 // ===================================================================== 00092 /* 00093 \fn CheckConfigDir 00094 \param a_path 00095 \brief Set the path to the CASTOR config directory 00096 \details Set the path to the CASTOR config directory from the given path if it is provided 00097 Otherwise, try to get it from the environment variable CASTOR_CONFIG 00098 \return 0 if success, positive value otherwise 00099 */ 00100 int sOutputManager::CheckConfigDir(const string& a_path) 00101 { 00102 if(m_verbose>=3) Cout("sOutputManager::CheckConfigDir ..."<< endl); 00103 00104 // Case 1: a path is provided 00105 if (a_path!="") 00106 { 00107 m_pathToConfigDir = a_path + OS_SEP; 00108 } 00109 // Case 2: no path provided so we look after the CASTOR_CONFIG environment variable 00110 else 00111 { 00112 #ifdef CASToR_USE_CMAKE 00113 string tmp_path = CASTOR_CONFIG; 00114 if (tmp_path.empty()) // throw error if empty 00115 #elif defined(CASTOR_USE_MINGW) 00116 #ifdef CASTOR_CONFIG 00117 // This macro CASTOR_CONFIG_STRING is declared in sOutputManager.hh and automatically convert the value from the environment 00118 // CASTOR_CONFIG into a string (i.e. including the double quotes so that it can be used here in the affectation) 00119 string tmp_path = ConvertAllSlashOccurrencesToBackSlash(CASTOR_CONFIG_STRING); 00120 if (tmp_path.empty()) 00121 #else 00122 // Here the CASTOR_CONFIG variable must have been defined before cross-compilation, so we write a message that will make the 00123 // compiler crash and display this fake line! Please let it as is. 00124 When cross-compiling, you must define the CASTOR_CONFIG environment variable before that. This compilation error you are seeing is normal! 00125 #endif 00126 #else 00127 char* tmp_path = getenv("CASTOR_CONFIG"); 00128 if (tmp_path==NULL) // throw error if empty 00129 #endif 00130 00131 { 00132 Cerr("***** sOutputManager::CheckConfigDir() -> No path nor CASTOR_CONFIG variable provided !" << endl); 00133 return 1; 00134 } 00135 00136 #ifdef CASToR_USE_CMAKE 00137 m_pathToConfigDir = tmp_path + OS_SEP; 00138 #else 00139 m_pathToConfigDir = ((string)tmp_path) + OS_SEP; 00140 #endif 00141 } 00142 // End 00143 return 0; 00144 } 00145 00146 00147 00148 // ===================================================================== 00149 // --------------------------------------------------------------------- 00150 // --------------------------------------------------------------------- 00151 // ===================================================================== 00152 /* 00153 \fn GetPathToConfigDir 00154 \brief Return the path to the CASTOR config directory 00155 \details Just return the path if it has already been initialized 00156 Otherwise, the function recovers the path from environnement variables 00157 If any error, the working directory is returned instead 00158 \return a string containing path to the CASToR configuration directory 00159 */ 00160 const string& sOutputManager::GetPathToConfigDir() 00161 { 00162 // If the config directory has already been initialized, then simply return its current value 00163 if (m_pathToConfigDir!="") return m_pathToConfigDir; 00164 // Otherwise, this means that this function is probably called from before the singleton initialization. 00165 else 00166 { 00167 if(m_verbose>=3) Cout("sOutputManager::GetPathToConfigDir ..."<< endl); 00168 00169 // We get the directory from the environment variable 00170 #if defined(CASToR_USE_CMAKE) 00171 string tmp_path = CASTOR_CONFIG; 00172 if (tmp_path.empty()) 00173 #elif defined(CASTOR_USE_MINGW) 00174 #ifdef CASTOR_CONFIG 00175 // This macro CASTOR_CONFIG_STRING is declared in sOutputManager.hh and automatically convert the value from the environment 00176 // CASTOR_CONFIG into a string (i.e. including the double quotes so that it can be used here in the affectation) 00177 string tmp_path = ConvertAllSlashOccurrencesToBackSlash(CASTOR_CONFIG_STRING); 00178 if (tmp_path.empty()) 00179 #else 00180 // Here the CASTOR_CONFIG variable must have been defined before cross-compilation, so we write a message that will make the 00181 // compiler crash and display this fake line! Please let it as is. 00182 When cross-compiling, you must define the CASTOR_CONFIG environment variable before that. This compilation error you are seeing is normal! 00183 #endif 00184 #else 00185 char* tmp_path = getenv("CASTOR_CONFIG"); 00186 if (tmp_path==NULL) 00187 #endif 00188 { 00189 Cerr("***** sOutputManager::CheckConfigDir() ->OOOOOO No path nor CASTOR_CONFIG variable provided ! Try working directory instead." << endl); 00190 cout << "hahahahaha" << endl; 00191 m_pathToConfigDir = "."; 00192 } 00193 else 00194 #if defined(CASToR_USE_CMAKE) || defined(CASTOR_USE_MINGW) 00195 m_pathToConfigDir = tmp_path + OS_SEP; 00196 #else 00197 m_pathToConfigDir = ((string)tmp_path) + OS_SEP; 00198 #endif 00199 00200 return m_pathToConfigDir; 00201 } 00202 } 00203 00204 00205 00206 // ===================================================================== 00207 // --------------------------------------------------------------------- 00208 // --------------------------------------------------------------------- 00209 // ===================================================================== 00210 /* 00211 \fn InitOutputDirectory 00212 \param a_pathFout : path to an output file as provided by the user 00213 \param a_pathDout : path to an output directory as provided by the user 00214 \brief Create the output directory if any, extract the base name and create the log file. 00215 \return 0 if success, and positive value otherwise. 00216 */ 00217 int sOutputManager::InitOutputDirectory(const string& a_pathFout, const string& a_pathDout) 00218 { 00219 if(m_verbose>=3) Cout("sOutputManager::InitOutputDirectory ..."<< endl); 00220 00221 // Exit function if MPI rank is anything other than 0 00222 if (m_mpiRank!=0) return 0; 00223 00224 // Check unicity of the path 00225 if (a_pathFout!="" && a_pathDout!="") 00226 { 00227 Cerr("***** sOutputManager::InitOutputDirectory() -> Either a file path (-fout) or a directory path (dout) should be provided. cannot be both provided, make your choice !" << endl); 00228 return 1; 00229 } 00230 00231 // Check if the provided path ends with '.' or '/' or '\', then alert and crash 00232 string the_path = a_pathFout; 00233 if (a_pathDout!="") the_path = a_pathDout; 00234 string last_char = the_path.substr(the_path.length()-1); 00235 if (last_char=="." || last_char==OS_SEP) 00236 { 00237 Cerr("***** sOutputManager::InitOutputDirectory() -> Please provide a path not finishing by '.', '"<< OS_SEP <<"' character !" << endl); 00238 return 1; 00239 } 00240 00241 // Verbose 00242 if (m_verbose>=1) Cout("sOutputManager::InitOutputDirectory() -> Output path is '" << a_pathFout << a_pathDout << "'" << endl); 00243 00244 // ------------------------------------------------- 00245 // First case: a file path is provided 00246 // ------------------------------------------------- 00247 00248 if (a_pathFout!="") 00249 { 00250 // Get the last slash position 00251 size_t last_slash_pos = a_pathFout.find_last_of(OS_SEP); 00252 // No slash 00253 if (last_slash_pos==string::npos) 00254 { 00255 m_pathName = ""; 00256 m_baseName = a_pathFout; 00257 } 00258 // Some slashes 00259 else 00260 { 00261 // Everything before the slash becomes the path 00262 m_pathName = a_pathFout.substr(0,last_slash_pos+1); 00263 // Everything after the slash becomes the base name 00264 m_baseName = a_pathFout.substr(last_slash_pos+1); 00265 } 00266 } 00267 00268 // ------------------------------------------------- 00269 // Second case: a directory path is provided 00270 // ------------------------------------------------- 00271 00272 else if (a_pathDout!="") 00273 { 00274 // Get the last slash position 00275 size_t last_slash_pos = a_pathDout.find_last_of(OS_SEP); 00276 // No slash 00277 if (last_slash_pos==string::npos) 00278 { 00279 m_pathName = a_pathDout + OS_SEP; 00280 m_baseName = a_pathDout; 00281 } 00282 // Some slashes 00283 else 00284 { 00285 // The whole becomes the path 00286 m_pathName = a_pathDout + OS_SEP; 00287 // Everything after the slash becomes the base name 00288 m_baseName = a_pathDout.substr(last_slash_pos+1); 00289 } 00290 // Create directory 00291 #ifdef _WIN32 00292 //string instruction = "md " + m_pathName; 00293 string instruction = "if not exist " + m_pathName + " mkdir " + m_pathName; 00294 #else 00295 string instruction = "mkdir -p " + m_pathName; 00296 #endif 00297 int error = system(instruction.c_str()); 00298 if (error) 00299 { 00300 Cerr("***** sOutputManager::InitOutputDirectory() -> Failed to create output directory with name '" << m_pathName << "' !" << endl); 00301 return 1; 00302 } 00303 // Verbose 00304 if (m_verbose>=3) Cout(" --> Output files will be written inside directory '" << m_pathName << "'" << endl); 00305 } 00306 00307 // ------------------------------------------------- 00308 // Third: create the log file 00309 // ------------------------------------------------- 00310 00311 // Create file name 00312 string log_file_name = m_pathName + m_baseName + ".log"; 00313 00314 // Open and check 00315 m_logFile.open(log_file_name.c_str()); 00316 if (!m_logFile) 00317 { 00318 Cerr("***** sOutputManager::InitOutputDirectory() -> Failed to create output log file as '" << log_file_name << "' ! Are you sure the provided output path exists ?" << endl); 00319 return 1; 00320 } 00321 00322 // End 00323 return 0; 00324 } 00325 00326 00327 00328 // ===================================================================== 00329 // --------------------------------------------------------------------- 00330 // --------------------------------------------------------------------- 00331 // ===================================================================== 00332 /* 00333 \fn LogCommandLine 00334 \param argc 00335 \param argv 00336 \brief Write log file header with the provided command line options and different informations 00337 \return 0 if success, positive value otherwise. 00338 */ 00339 int sOutputManager::LogCommandLine(int argc, char** argv) 00340 { 00341 if(m_verbose>=3) Cout("LogCommandLine ..."<< endl); 00342 00343 // Exit function is MPI rank is anything other than 0 00344 if (m_mpiRank!=0) return 0; 00345 00346 if (m_logFile) 00347 { 00348 m_logFile << "==================================================================================================" << endl; 00349 m_logFile << " COMMAND LINE CONTEXT" << endl; 00350 m_logFile << "==================================================================================================" << endl; 00351 // Print command line 00352 m_logFile << "Command line: "; 00353 for (int i=0; i<argc; i++) m_logFile << argv[i] << " "; 00354 m_logFile << endl; 00355 #ifdef _WIN32 00356 char pwd[MAX_PATH]; 00357 GetCurrentDirectory(MAX_PATH,pwd); 00358 m_logFile << "Working directory: " << pwd << endl; 00359 #else 00360 m_logFile << "Working directory: " << getenv("PWD") << endl; 00361 #endif 00362 m_logFile << "Date of execution (since Epoch): " << time(NULL) << endl; 00363 m_logFile << "Float numbers precision in bytes (for computation): " << sizeof(FLTNB) << endl; 00364 m_logFile << "Float numbers precision in bytes (for datafile reading/writing): " << sizeof(FLTNBDATA) << endl; 00365 m_logFile << "Float numbers precision in bytes (for scanner LUT reading/writing): " << sizeof(FLTNBLUT) << endl; 00366 m_logFile << "==================================================================================================" << endl << flush; 00367 } 00368 else 00369 return 1; 00370 00371 // End 00372 return 0; 00373 }