CASToR  1.0
Tomographic Reconstruction (PET/SPECT)
sOutputManager.cc
Go to the documentation of this file.
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 }
 All Classes Files Functions Variables Typedefs Defines