psana/src/PSAnaApp.cpp

Go to the documentation of this file.
00001 //--------------------------------------------------------------------------
00002 // File and Version Information:
00003 //     $Id: PSAnaApp.cpp 8825 2014-08-28 01:16:10Z davidsch@SLAC.STANFORD.EDU $
00004 //
00005 // Description:
00006 //     Class PSAnaApp...
00007 //
00008 // Author List:
00009 //     Andy Salnikov
00010 //
00011 //------------------------------------------------------------------------
00012 
00013 //-----------------------
00014 // This Class's Header --
00015 //-----------------------
00016 #include "psana/PSAnaApp.h"
00017 
00018 //-----------------
00019 // C/C++ Headers --
00020 //-----------------
00021 #include <iostream>
00022 #include <fstream>
00023 #include <unistd.h>
00024 #include <boost/make_shared.hpp>
00025 
00026 //-------------------------------
00027 // Collaborating Class Headers --
00028 //-------------------------------
00029 #include "MsgLogger/MsgFormatter.h"
00030 #include "MsgLogger/MsgLogger.h"
00031 #include "psana/Exceptions.h"
00032 #include "psana/PSAna.h"
00033 
00034 //-----------------------------------------------------------------------
00035 // Local Macros, Typedefs, Structures, Unions and Forward Declarations --
00036 //-----------------------------------------------------------------------
00037 
00038 //             ----------------------------------------
00039 //             -- Public Function Member Definitions --
00040 //             ----------------------------------------
00041 
00042 namespace {
00043 
00044   const std::string dumpConfigFileOption("psana.dump_config_file");
00045 
00046   bool dumpConfigFileOptionSet(const std::map<std::string, std::string> &options) {
00047     std::map<std::string, std::string>::const_iterator pos = options.find(dumpConfigFileOption);
00048     if (pos == options.end()) {
00049       return false;
00050     }
00051     return true;
00052   }
00053 
00054   void dumpConfigFile(const std::string &cfgFile) {
00055     if (cfgFile.size()==0) return;
00056     std::cout << "--------- psana config file: " << cfgFile << " ------------" << std::endl;
00057     std::ifstream cfgFileStream;
00058     cfgFileStream.open(cfgFile.c_str(), std::ifstream::in);
00059     if ( (cfgFileStream.rdstate() & std::ifstream::failbit ) == 0 ) {
00060       char c = cfgFileStream.get();
00061       while (cfgFileStream.good()) {
00062         std::cout << c;
00063         c = cfgFileStream.get();
00064       }
00065       cfgFileStream.close();
00066     } else {
00067       std::cout << " ** unable to open file ** " << std::endl;
00068     }
00069     std::cout << std::endl << "------- end psana config file ---------" << std::endl;
00070   }
00071 
00072   void removeDumpConfigFileOption(std::map<std::string, std::string> &options) {
00073     std::map<std::string, std::string>::iterator pos = options.find(dumpConfigFileOption);
00074     if (pos != options.end()) {
00075       options.erase(pos);
00076     }
00077   }
00078     
00079 } // local namespace
00080 
00081 namespace psana {
00082 
00083 //
00084 //  Application class
00085 //
00086 
00087 //----------------
00088 // Constructors --
00089 //----------------
00090 PSAnaApp::PSAnaApp ( const std::string& appName )
00091   : AppUtils::AppBase( appName )
00092   , m_calibDirOpt( parser(), "b,calib-dir", "path", "calibration directory name, may include {exp} and {instr}, if left empty then do not do calibrations", "" )
00093   , m_configOpt( parser(), "c,config", "path", "configuration file, by default use psana.cfg if it exists", "" )
00094   , m_expNameOpt( parser(), "e,experiment", "string", "experiment name, format: XPP:xpp12311 or xpp12311, by default guess it from data", "" )
00095   , m_jobNameOpt( parser(), "j,job-name", "string", "job name, default is to generate from input file names", "" )
00096   , m_modulesOpt( parser(), "m,module", "name", "module name, more than one possible" )
00097   , m_maxEventsOpt( parser(), "n,num-events", "number", "maximum number of events to process, 0 means all", 0U )
00098   , m_skipEventsOpt( parser(), "s,skip-events", "number", "number of events to skip", 0U )
00099   , m_parallelOpt( parser(), "p,num-cpu", "number", "number greater than 0 enables multi-processing", 0U )
00100   , m_optionsOpt( parser(), "o,option", "string", "configuration options, format: module.option[=value]" )
00101   , m_datasets( parser(), "dataset", "input dataset specification (list of file names or exp=cxi12345:run=123:...)", std::vector<std::string>() )
00102 {
00103 }
00104 
00105 //--------------
00106 // Destructor --
00107 //--------------
00108 PSAnaApp::~PSAnaApp ()
00109 {
00110 }
00111 
00112 /**
00113  *  Run the application, accepts arguments as vector of strings which
00114  *  should contain the same values as regular argv (first element must be
00115  *  application name).
00116  */
00117 int
00118 PSAnaApp::run(const std::vector<std::string>& argv)
00119 {
00120   // copy arguments
00121   size_t size = 0;
00122   for (std::vector<std::string>::const_iterator it = argv.begin(); it != argv.end(); ++ it) {
00123     size += it->size() + 1;
00124   }
00125 
00126   char* buf = new char[size];
00127 
00128   std::vector<char*> cargv;
00129   cargv.reserve(argv.size()+1);
00130   char* p = buf;
00131   for (std::vector<std::string>::const_iterator it = argv.begin(); it != argv.end(); ++ it) {
00132     cargv.push_back(p);
00133     p = std::copy(it->begin(), it->end(), p);
00134     *p++ = '\0';
00135   }
00136   cargv.push_back(0);
00137 
00138   // call standard method
00139   int code = this->run(argv.size(), &cargv[0]);
00140 
00141   // cleanup
00142   delete [] buf;
00143 
00144   return code;
00145 }
00146 
00147 /**
00148  *  Method called before runApp, can be overriden in subclasses.
00149  *  Usually if you override it, call base class method too.
00150  */
00151 int
00152 PSAnaApp::preRunApp ()
00153 {
00154   AppBase::preRunApp();
00155 
00156   // use different formatting for messages
00157   const char* fmt = "[%(level):%(logger)] %(message)" ;
00158   const char* errfmt = "[%(level):%(time):%(file):%(line)] %(message)" ;
00159   const char* trcfmt = "[%(level):%(time):%(logger)] %(message)" ;
00160   const char* dbgfmt = errfmt ;
00161   MsgLogger::MsgFormatter::addGlobalFormat ( fmt ) ;
00162   MsgLogger::MsgFormatter::addGlobalFormat ( MsgLogger::MsgLogLevel::debug, dbgfmt ) ;
00163   MsgLogger::MsgFormatter::addGlobalFormat ( MsgLogger::MsgLogLevel::trace, trcfmt ) ;
00164   MsgLogger::MsgFormatter::addGlobalFormat ( MsgLogger::MsgLogLevel::warning, errfmt ) ;
00165   MsgLogger::MsgFormatter::addGlobalFormat ( MsgLogger::MsgLogLevel::error, errfmt ) ;
00166   MsgLogger::MsgFormatter::addGlobalFormat ( MsgLogger::MsgLogLevel::fatal, errfmt ) ;
00167 
00168   return 0;
00169 }
00170 
00171 /**
00172  *  Main method which runs the whole application
00173  */
00174 int
00175 PSAnaApp::runApp ()
00176 {
00177   std::string cfgFile;
00178   std::map<std::string, std::string> options;
00179   setConfigFileAndOptions(cfgFile, options);
00180   
00181   // Instantiate framework
00182   PSAna fwk(cfgFile, options);
00183 
00184   // check that we have at least one module
00185   if (fwk.modules().empty()) {
00186     MsgLogRoot(error, "no analysis modules specified");
00187     return 2;
00188   }
00189 
00190   // list of inputs
00191   std::vector<std::string> input = inputDataSets();
00192 
00193   // get data source
00194   DataSource dataSource = fwk.dataSource(input);
00195   if (dataSource.empty()) return 2;
00196 
00197   // get event iterator
00198   EventIter iter = dataSource.events();
00199 
00200   // loop from begin to end
00201   while (boost::shared_ptr<PSEvt::Event> evt = iter.next()) {
00202     // nothing to do here
00203   }
00204 
00205   // return 0 on success, other values for error (like main())
00206   return 0 ;
00207 }
00208 
00209 void
00210 PSAnaApp::setConfigFileAndOptions(std::string &cfgFile, std::map<std::string, std::string> &options)
00211 {
00212   cfgFile.clear();
00213   options.clear();
00214   // if -c is not specified the try to read psana.cfg (only if present)
00215   cfgFile = m_configOpt.value();
00216   if (not m_configOpt.valueChanged()) {
00217     if (access("psana.cfg", R_OK) == 0) {
00218       cfgFile = "psana.cfg";
00219     }
00220   }
00221 
00222   // command-line -m options override config file values
00223   if (not m_modulesOpt.value().empty()) {
00224     std::string modlist;
00225     const std::vector<std::string>& modules = m_modulesOpt.value();
00226     for(std::vector<std::string>::const_iterator it = modules.begin(); it != modules.end(); ++ it) {
00227       if (not modlist.empty()) modlist += ' ';
00228       modlist += *it;
00229     }
00230     MsgLogRoot(trace, "set module list to '" << modlist << "'");
00231     options["psana.modules"] = modlist;
00232   }
00233 
00234   // set instrument and experiment names if specified
00235   if (not m_expNameOpt.value().empty()) {
00236       std::string instrName;
00237       std::string expName = m_expNameOpt.value();
00238       std::string::size_type pos = expName.find(':');
00239       if (pos == std::string::npos) {
00240           instrName = expName.substr(0, 3);
00241           boost::to_upper(instrName);
00242       } else {
00243           instrName = expName.substr(0, pos);
00244           expName.erase(0, pos+1);
00245       }
00246       MsgLogRoot(debug, "cmd line: instrument = " << instrName << " experiment = " << expName);
00247       options["psana.instrument"] = instrName;
00248       options["psana.experiment"] = expName;
00249   }
00250 
00251   // set event numbers
00252   if (m_maxEventsOpt.value()) {
00253       options["psana.events"] = boost::lexical_cast<std::string>(m_maxEventsOpt.value());
00254   }
00255   if (m_skipEventsOpt.value()) {
00256       options["psana.skip-events"] = boost::lexical_cast<std::string>(m_skipEventsOpt.value());
00257   }
00258 
00259   // multi-processing
00260   if (m_parallelOpt.value()) {
00261       options["psana.parallel"] = boost::lexical_cast<std::string>(m_parallelOpt.value());
00262   }
00263 
00264   // set calib dir name if specified
00265   if (not m_calibDirOpt.value().empty()) {
00266     options["psana.calib-dir"] = m_calibDirOpt.value();
00267   }
00268 
00269   // now copy all -o options, they may override existing options
00270   typedef AppUtils::AppCmdOptList<std::string>::const_iterator OptIter;
00271   for (OptIter it = m_optionsOpt.begin(); it != m_optionsOpt.end(); ++ it) {
00272     std::string optname = *it;
00273     std::string optval;
00274     std::string::size_type p = optname.find('=');
00275     if (p != std::string::npos) {
00276       optval = std::string(optname, p+1);
00277       optname.erase(p);
00278     }
00279     options[optname] = optval;
00280   }
00281 
00282   // dump contents of config file if requested
00283   if (dumpConfigFileOptionSet(options)) {
00284     dumpConfigFile(cfgFile);
00285     removeDumpConfigFileOption(options);
00286   }
00287 }
00288 
00289 std::vector<std::string> 
00290 PSAnaApp::inputDataSets() const 
00291 {
00292   std::vector<std::string> input(m_datasets.begin(), m_datasets.end());
00293   return input;
00294 }
00295 
00296 } // namespace psana

Generated on 19 Dec 2016 for PSANAclasses by  doxygen 1.4.7