CASToR  1.1
Tomographic Reconstruction (PET/SPECT)
 All Classes Files Functions Variables Typedefs Macros Groups Pages
sOutputManager.cc
Go to the documentation of this file.
1 
2 /*
3  Implementation of class sOutputManager
4 
5  - separators: X
6  - doxygen: X
7  - default initialization: X
8  - CASTOR_DEBUG: none
9  - CASTOR_VERBOSE: none
10 */
11 
19 #include "sOutputManager.hh"
20 #include "oImageSpace.hh"
22 #include <iomanip>
23 
24 #ifdef CASToR_USE_CMAKE
25  #include "oCASToRConfig.hh"
26 #endif
27 
28 // =====================================================================
29 // ---------------------------------------------------------------------
30 // ---------------------------------------------------------------------
31 // =====================================================================
32 
33 // Implementation of the exit function that must be used instead of the standard exit
34 void Exit(int code)
35 {
36  if (code!=0) Cerr("***** Exit function called. Abort with code " << code << "." << endl);
37  #ifdef CASTOR_MPI
38  MPI_Finalize();
39  #endif
40  exit(code);
41 }
42 
43 // Singleton : set pointer to object to NULL
45 
46 // =====================================================================
47 // ---------------------------------------------------------------------
48 // ---------------------------------------------------------------------
49 // =====================================================================
50 /*
51  \brief sOutputManager constructor.
52  \details It is private at this class is singleton.
53  It should be instanciated using the GetInstance() function
54  Initialize the member variables to their default values.
55 */
57 {
58  // Initialize all members as default
59  m_verbose = 0;
60  m_mpiRank = 0;
61  m_baseName = "";
62  m_pathName = "";
63  m_pathToConfigDir = "";
65  // Set scientific numbers
66  cout << std::scientific;
67  //cout << std::setprecision(std::numeric_limits<FLTNB>::digits10+1);
68  cerr << std::setprecision(std::numeric_limits<FLTNB>::digits10+1);
69 }
70 
71 
72 
73 // =====================================================================
74 // ---------------------------------------------------------------------
75 // ---------------------------------------------------------------------
76 // =====================================================================
77 /*
78  \brief sOutputManager destructor.
79 */
81 {
82  // Just have to close the log file
83  if (m_mpiRank==0 && m_logFile) m_logFile.close();
84 }
85 
86 
87 
88 // =====================================================================
89 // ---------------------------------------------------------------------
90 // ---------------------------------------------------------------------
91 // =====================================================================
92 /*
93  \fn CheckConfigDir
94  \param a_path
95  \brief Set the path to the CASTOR config directory
96  \details Set the path to the CASTOR config directory from the given path if it is provided
97  Otherwise, try to get it from the environment variable CASTOR_CONFIG
98  \return 0 if success, positive value otherwise
99 */
100 int sOutputManager::CheckConfigDir(const string& a_path)
101 {
102  // Case 1: a path is provided
103  if (a_path!="")
104  {
105  if (m_verbose>=3) Cout("sOutputManager::CheckConfigDir() -> Directory selected from option as '" << a_path << "'" << endl);
106  m_pathToConfigDir = a_path + OS_SEP;
107  }
108  // Case 2: no path provided so we look after the CASTOR_CONFIG environment variable
109  else
110  {
111  #ifdef CASToR_USE_CMAKE
112  string tmp_path = CASTOR_CONFIG;
113  if (tmp_path.empty()) // throw error if empty
114  #elif defined(CASTOR_USE_MINGW)
115  #ifdef CASTOR_CONFIG
116  // This macro CASTOR_CONFIG_STRING is declared in sOutputManager.hh and automatically convert the value from the environment
117  // CASTOR_CONFIG into a string (i.e. including the double quotes so that it can be used here in the affectation)
118  string tmp_path = ConvertAllSlashOccurrencesToBackSlash(CASTOR_CONFIG_STRING);
119  if (tmp_path.empty())
120  #else
121  // Here the CASTOR_CONFIG variable must have been defined before cross-compilation, so we write a message that will make the
122  // compiler crash and display this fake line! Please let it as is.
123  When cross-compiling, you must define the CASTOR_CONFIG environment variable before that. This compilation error you are seeing is normal!
124  #endif
125  #else
126  char* tmp_path = getenv("CASTOR_CONFIG");
127  if (tmp_path==NULL) // throw error if empty
128  #endif
129  {
130  Cerr("***** sOutputManager::CheckConfigDir() -> No path nor CASTOR_CONFIG variable provided !" << endl);
131  return 1;
132  }
133  if (m_verbose>=3) Cout("sOutputManager::CheckConfigDir() -> Directory selected from environment variable as '" << ((string)tmp_path) << "'" << endl);
134  m_pathToConfigDir = ((string)tmp_path) + OS_SEP;
135  }
136  // End
137  return 0;
138 }
139 
140 
141 
142 // =====================================================================
143 // ---------------------------------------------------------------------
144 // ---------------------------------------------------------------------
145 // =====================================================================
146 /*
147  \fn GetPathToConfigDir
148  \brief Return the path to the CASTOR config directory
149  \details Just return the path if it has already been initialized
150  Otherwise, the function recovers the path from environnement variables
151  If any error, the working directory is returned instead
152  \return a string containing path to the CASToR configuration directory
153 */
155 {
156  // If the config directory has already been initialized, then simply return its current value
157  if (m_pathToConfigDir!="") return m_pathToConfigDir;
158  // Otherwise, this means that this function is probably called from before the singleton initialization.
159  else
160  {
161  if (m_verbose>=3) Cout("sOutputManager::GetPathToConfigDir ..."<< endl);
162  // We get the directory from the environment variable
163  #if defined(CASToR_USE_CMAKE)
164  string tmp_path = CASTOR_CONFIG;
165  if (tmp_path.empty())
166  #elif defined(CASTOR_USE_MINGW)
167  #ifdef CASTOR_CONFIG
168  // This macro CASTOR_CONFIG_STRING is declared in sOutputManager.hh and automatically convert the value from the environment
169  // CASTOR_CONFIG into a string (i.e. including the double quotes so that it can be used here in the affectation)
170  string tmp_path = ConvertAllSlashOccurrencesToBackSlash(CASTOR_CONFIG_STRING);
171  if (tmp_path.empty())
172  #else
173  // Here the CASTOR_CONFIG variable must have been defined before cross-compilation, so we write a message that will make the
174  // compiler crash and display this fake line! Please let it as is.
175  When cross-compiling, you must define the CASTOR_CONFIG environment variable before that. This compilation error you are seeing is normal!
176  #endif
177  #else
178  char* tmp_path = getenv("CASTOR_CONFIG");
179  if (tmp_path==NULL)
180  #endif
181  {
182  Cerr("***** sOutputManager::CheckConfigDir() -> No path nor CASTOR_CONFIG variable provided ! Try working directory instead." << endl);
183  m_pathToConfigDir = ".";
184  }
185  else
186  #if defined(CASToR_USE_CMAKE) || defined(CASTOR_USE_MINGW)
187  m_pathToConfigDir = tmp_path + OS_SEP;
188  #else
189  m_pathToConfigDir = ((string)tmp_path) + OS_SEP;
190  #endif
191 
192  return m_pathToConfigDir;
193  }
194 }
195 
196 
197 
198 // =====================================================================
199 // ---------------------------------------------------------------------
200 // ---------------------------------------------------------------------
201 // =====================================================================
202 /*
203  \fn InitOutputDirectory
204  \param a_pathFout : path to an output file as provided by the user
205  \param a_pathDout : path to an output directory as provided by the user
206  \brief Create the output directory if any, extract the base name and create the log file.
207  \return 0 if success, and positive value otherwise.
208 */
209 int sOutputManager::InitOutputDirectory(const string& a_pathFout, const string& a_pathDout)
210 {
211  #ifdef CASTOR_VERBOSE
212  if (m_verbose>=4) Cout("+++++ sOutputManager::InitOutputDirectory() -> Enter"<< endl);
213  #endif
214 
215  // Check unicity of the path
216  if (a_pathFout!="" && a_pathDout!="")
217  {
218  Cerr("***** sOutputManager::InitOutputDirectory() -> Either a file path (-fout) or a directory path (dout) should be provided. cannot be both provided, make your choice !" << endl);
219  return 1;
220  }
221 
222  // Check if the provided path ends with '.' or '/' or '\', then alert and crash
223  string the_path = a_pathFout;
224  if (a_pathDout!="") the_path = a_pathDout;
225  string last_char = the_path.substr(the_path.length()-1);
226  if (last_char=="." || last_char==OS_SEP)
227  {
228  Cerr("***** sOutputManager::InitOutputDirectory() -> Please provide a path not finishing by '.', '"<< OS_SEP <<"' character !" << endl);
229  return 1;
230  }
231 
232  // Verbose
233  if (m_verbose>=1) Cout("sOutputManager::InitOutputDirectory() -> Output path is '" << a_pathFout << a_pathDout << "'" << endl);
234 
235  // -------------------------------------------------
236  // First case: a file path is provided
237  // -------------------------------------------------
238 
239  if (a_pathFout!="")
240  {
241  // Get the last slash position
242  size_t last_slash_pos = a_pathFout.find_last_of(OS_SEP);
243  // No slash
244  if (last_slash_pos==string::npos)
245  {
246  m_pathName = "";
247  m_baseName = a_pathFout;
248  }
249  // Some slashes
250  else
251  {
252  // Everything before the slash becomes the path
253  m_pathName = a_pathFout.substr(0,last_slash_pos+1);
254  // Everything after the slash becomes the base name
255  m_baseName = a_pathFout.substr(last_slash_pos+1);
256  }
257  }
258 
259  // -------------------------------------------------
260  // Second case: a directory path is provided
261  // -------------------------------------------------
262 
263  else if (a_pathDout!="")
264  {
265  // Get the last slash position
266  size_t last_slash_pos = a_pathDout.find_last_of(OS_SEP);
267  // No slash
268  if (last_slash_pos==string::npos)
269  {
270  m_pathName = a_pathDout + OS_SEP;
271  m_baseName = a_pathDout;
272  }
273  // Some slashes
274  else
275  {
276  // The whole becomes the path
277  m_pathName = a_pathDout + OS_SEP;
278  // Everything after the slash becomes the base name
279  m_baseName = a_pathDout.substr(last_slash_pos+1);
280  }
281  // Create directory only for first MPI instance
282  if (m_mpiRank==0)
283  {
284  #ifdef _WIN32
285  string instruction = "if not exist " + m_pathName + " mkdir " + m_pathName;
286  #else
287  string instruction = "mkdir -p " + m_pathName;
288  #endif
289  int error = system(instruction.c_str());
290  if (error)
291  {
292  Cerr("***** sOutputManager::InitOutputDirectory() -> Failed to create output directory with name '" << m_pathName << "' !" << endl);
293  return 1;
294  }
295  }
296  // Verbose
297  if (m_verbose>=3) Cout(" --> Output files will be written inside directory '" << m_pathName << "'" << endl);
298  }
299 
300  // -------------------------------------------------
301  // Third: create the log file
302  // -------------------------------------------------
303 
304  // Only first MPI instance deals with this
305  if (m_mpiRank==0)
306  {
307  // Create file name
308  string log_file_name = m_pathName + m_baseName + ".log";
309  // Open and check
310  m_logFile.open(log_file_name.c_str());
311  if (!m_logFile)
312  {
313  Cerr("***** sOutputManager::InitOutputDirectory() -> Failed to create output log file as '" << log_file_name << "' ! Are you sure the provided output path exists ?" << endl);
314  return 1;
315  }
316  }
317 
318  // End
319  return 0;
320 }
321 
322 // =====================================================================
323 // ---------------------------------------------------------------------
324 // ---------------------------------------------------------------------
325 // =====================================================================
326 
327 int sOutputManager::LogCommandLine(int argc, char** argv)
328 {
329  if (m_verbose>=3) Cout("sOutputManager::LogCommandLine() -> Write command line into the log file"<< endl);
330 
331  // Exit function is MPI rank is anything other than 0
332  if (m_mpiRank!=0) return 0;
333 
334  if (m_logFile)
335  {
336  m_logFile << "==================================================================================================" << endl;
337  m_logFile << " COMMAND LINE CONTEXT" << endl;
338  m_logFile << "==================================================================================================" << endl;
339  // Print command line
340  m_logFile << "Command line: ";
341  for (int i=0; i<argc; i++) m_logFile << argv[i] << " ";
342  m_logFile << endl;
343  #ifdef _WIN32
344  char pwd[MAX_PATH];
345  GetCurrentDirectory(MAX_PATH,pwd);
346  m_logFile << "Working directory: " << pwd << endl;
347  #else
348  m_logFile << "Working directory: " << getenv("PWD") << endl;
349  #endif
350  m_logFile << "Date of execution (since Epoch): " << time(NULL) << endl;
351  m_logFile << "Float numbers precision in bytes (for computation): " << sizeof(FLTNB) << endl;
352  m_logFile << "Float numbers precision in bytes (for datafile reading/writing): " << sizeof(FLTNBDATA) << endl;
353  m_logFile << "Float numbers precision in bytes (for scanner LUT reading/writing): " << sizeof(FLTNBLUT) << endl;
354  m_logFile << "CASToR version: " << CASTOR_VERSION << endl;
355  m_logFile << "==================================================================================================" << endl << flush;
356  }
357  else
358  return 1;
359 
360  // End
361  return 0;
362 }
string ConvertAllSlashOccurrencesToBackSlash(const string &a_path)
Definition: gOptions.cc:1164
Declaration of class oImageDimensionsAndQuantification.
sOutputManager()
sOutputManager constructor.
#define FLTNB
Definition: gVariables.hh:55
void Exit(int code)
bool m_mergeOutputDynImgFlag
int LogCommandLine(int argc, char **argv)
Write log file header with the provided command line options and different informations.
#define FLTNBDATA
Definition: gVariables.hh:59
int CheckConfigDir(const string &a_path)
Set the path to the CASTOR config directory from the given path if not empty or through the existence...
#define Cerr(MESSAGE)
#define FLTNBLUT
Definition: gVariables.hh:61
Singleton class that manages output writing on disk (images, sinograms, etc). It also manages loggi...
const string & GetPathToConfigDir()
Return the path to the CASTOR config directory.
string m_pathToConfigDir
static sOutputManager * mp_Instance
#define OS_SEP
Declaration of class oImageSpace.
Declaration of class sOutputManager.
int InitOutputDirectory(const string &a_pathFout, const string &a_pathDout)
Create the output directory if any, extract the base name and create the log file.
~sOutputManager()
sOutputManager destructor.
#define Cout(MESSAGE)
#define CASTOR_VERSION
Definition: gVariables.hh:44