CMS 3D CMS Logo

/data/refman/pasoursint/CMSSW_5_3_10/src/DQMServices/Core/src/DQMStore.cc

Go to the documentation of this file.
00001 #include "DQMServices/Core/interface/Standalone.h"
00002 #include "DQMServices/Core/interface/DQMStore.h"
00003 #include "DQMServices/Core/interface/QReport.h"
00004 #include "DQMServices/Core/interface/QTest.h"
00005 #include "DQMServices/Core/src/DQMError.h"
00006 #include "classlib/utils/RegexpMatch.h"
00007 #include "classlib/utils/Regexp.h"
00008 #include "classlib/utils/StringOps.h"
00009 #include "TFile.h"
00010 #include "TROOT.h"
00011 #include "TKey.h"
00012 #include "TClass.h"
00013 #include "TSystem.h"
00014 #include <iterator>
00015 #include <cerrno>
00016 #include <boost/algorithm/string.hpp>
00017 #include <fstream>
00018 
00045 
00046 
00047 static std::string s_monitorDirName = "DQMData";
00048 static std::string s_referenceDirName = "Reference";
00049 static std::string s_collateDirName = "Collate";
00050 static std::string s_safe = "/ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+=_()# ";
00051 
00052 static const lat::Regexp s_rxmeval ("^<(.*)>(i|f|s|e|t|qr)=(.*)</\\1>$");
00053 static const lat::Regexp s_rxmeqr1 ("^st:(\\d+):([-+e.\\d]+):([^:]*):(.*)$");
00054 static const lat::Regexp s_rxmeqr2 ("^st\\.(\\d+)\\.(.*)$");
00055 static const lat::Regexp s_rxtrace ("(.*)\\((.*)\\+0x.*\\).*");
00056 
00060 static bool
00061 isSubdirectory(const std::string &ofdir, const std::string &path)
00062 {
00063   return (ofdir.empty()
00064           || (path.size() >= ofdir.size()
00065               && path.compare(0, ofdir.size(), ofdir) == 0
00066               && (path.size() == ofdir.size()
00067                   || path[ofdir.size()] == '/')));
00068 }
00069 
00070 static void
00071 cleanTrailingSlashes(const std::string &path, std::string &clean, const std::string *&cleaned)
00072 {
00073   clean.clear();
00074   cleaned = &path;
00075 
00076   size_t len = path.size();
00077   for ( ; len > 0 && path[len-1] == '/'; --len)
00078     ;
00079 
00080   if (len != path.size())
00081   {
00082     clean = path.substr(0, len);
00083     cleaned = &clean;
00084   }
00085 }
00086 
00087 static void
00088 splitPath(std::string &dir, std::string &name, const std::string &path)
00089 {
00090   size_t slash = path.rfind('/');
00091   if (slash != std::string::npos)
00092   {
00093     dir.append(path, 0, slash);
00094     name.append(path, slash+1, std::string::npos);
00095   }
00096   else
00097     name = path;
00098 }
00099 
00100 static void
00101 mergePath(std::string &path, const std::string &dir, const std::string &name)
00102 {
00103   path.reserve(dir.size() + name.size() + 2);
00104   path += dir;
00105   if (! path.empty())
00106     path += '/';
00107   path += name;
00108 }
00109 
00110 template <class T>
00111 QCriterion *
00112 makeQCriterion(const std::string &qtname)
00113 { return new T(qtname); }
00114 
00115 template <class T>
00116 void
00117 initQCriterion(std::map<std::string, QCriterion *(*)(const std::string &)> &m)
00118 { m[T::getAlgoName()] = &makeQCriterion<T>; }
00119 
00120 
00122 fastmatch::fastmatch (std::string const& _fastString) :
00123   fastString_ (_fastString),  matching_ (UseFull)
00124 {
00125   try
00126   {
00127     regexp_ = NULL;
00128     regexp_ = new lat::Regexp(fastString_, 0, lat::Regexp::Wildcard);
00129     regexp_->study();
00130   }
00131   catch (lat::Error &e)
00132   {
00133     delete regexp_;
00134     raiseDQMError("DQMStore", "Invalid wildcard pattern '%s' in quality"
00135                   " test specification", fastString_.c_str());
00136   }
00137 
00138   // count stars ( "*" )
00139   size_t starCount = 0;
00140   int pos = -1;
00141   while (true)
00142   {
00143     pos = fastString_.find("*", pos + 1 );
00144     if ((size_t)pos == std::string::npos)
00145       break;
00146     starCount ++;
00147   }
00148 
00149   // investigate for heuristics
00150   if ((fastString_.find('"') != std::string::npos)  ||
00151       (fastString_.find(']') != std::string::npos)  ||
00152       (fastString_.find('?') != std::string::npos)  ||
00153       (fastString_.find('\\') != std::string::npos) ||
00154       (starCount > 2))
00155   {
00156     // no fast version can be used
00157     return;
00158   }
00159 
00160   // match for pattern "*MyString" and "MyString*"
00161   if (starCount == 1)
00162   {
00163     if (boost::algorithm::starts_with(fastString_, "*"))
00164     {
00165       matching_ = OneStarStart;
00166       fastString_.erase(0,1);
00167       return;
00168     }
00169 
00170     if (boost::algorithm::ends_with(fastString_, "*"))
00171     {
00172       matching_ = OneStarEnd;
00173       fastString_.erase(fastString_.length()-1,1);
00174       return;
00175     }
00176   }
00177 
00178   // match for pattern "*MyString*"
00179   if (starCount == 2)
00180   {
00181     if (boost::algorithm::starts_with(fastString_, "*") &&
00182         boost::algorithm::ends_with(fastString_, "*"))
00183     {
00184       matching_ = TwoStar;
00185       fastString_.erase(0,1);
00186       fastString_.erase(fastString_.size() - 1, 1);
00187       return;
00188     }
00189   }
00190 }
00191 
00192 fastmatch::~fastmatch()
00193 {
00194   if (regexp_ != NULL)
00195     delete regexp_;
00196 }
00197 
00198 bool fastmatch::compare_strings_reverse(std::string const& pattern,
00199                                         std::string const& input) const
00200 {
00201   if (input.size() < pattern.size())
00202     return false;
00203 
00204   // compare the two strings character by character for equalness:
00205   // this does not create uneeded copies of std::string. The
00206   // boost::algorithm implementation does
00207   std::string::const_reverse_iterator rit_pattern = pattern.rbegin();
00208   std::string::const_reverse_iterator rit_input = input.rbegin();
00209 
00210   for (; rit_pattern < pattern.rend(); rit_pattern++, rit_input++)
00211   {
00212     if (*rit_pattern != *rit_input)
00213       // found a difference, fail
00214       return false;
00215   }
00216   return true;
00217 }
00218 
00219 bool fastmatch::compare_strings(std::string const& pattern,
00220                                 std::string const& input) const
00221 {
00222   if (input.size() < pattern.size())
00223     return false;
00224 
00225   // compare the two strings character by character for equalness:
00226   // this does not create uneeded copies of std::string. The
00227   // boost::algorithm implementation does.
00228   std::string::const_iterator rit_pattern = pattern.begin();
00229   std::string::const_iterator rit_input = input.begin();
00230 
00231   for (; rit_pattern < pattern.end(); rit_pattern++, rit_input++)
00232   {
00233     if (*rit_pattern != *rit_input)
00234       // found a difference, fail
00235       return false;
00236   }
00237   return true;
00238 }
00239 
00240 bool fastmatch::match(std::string const& s) const
00241 {
00242   switch (matching_)
00243   {
00244   case OneStarStart:
00245     return compare_strings_reverse(fastString_, s);
00246 
00247   case OneStarEnd:
00248     return compare_strings(fastString_, s);
00249 
00250   case TwoStar:
00251     return (s.find(fastString_) != std::string::npos);
00252 
00253   default:
00254     return regexp_->match(s);
00255   }
00256 }
00257 
00259 DQMStore::DQMStore(const edm::ParameterSet &pset, edm::ActivityRegistry& ar)
00260   : verbose_ (1),
00261     verboseQT_ (1),
00262     reset_ (false),
00263     collateHistograms_ (false),
00264     readSelectedDirectory_ (""),
00265     pwd_ ("")
00266 {
00267   initializeFrom(pset);
00268   if(pset.getUntrackedParameter<bool>("forceResetOnBeginRun",false)) {
00269     ar.watchPostSourceRun(this,&DQMStore::forceReset);
00270   }
00271 }
00272 
00273 DQMStore::DQMStore(const edm::ParameterSet &pset)
00274   : verbose_ (1),
00275     verboseQT_ (1),
00276     reset_ (false),
00277     collateHistograms_ (false),
00278     readSelectedDirectory_ (""),
00279     pwd_ ("")
00280 {
00281   initializeFrom(pset);
00282 }
00283 
00284 DQMStore::~DQMStore(void)
00285 {
00286   for (QCMap::iterator i = qtests_.begin(), e = qtests_.end(); i != e; ++i)
00287     delete i->second;
00288 
00289   for (QTestSpecs::iterator i = qtestspecs_.begin(), e = qtestspecs_.end(); i != e; ++i)
00290     delete i->first;
00291 
00292 }
00293 
00294 void
00295 DQMStore::initializeFrom(const edm::ParameterSet& pset) {
00296   makeDirectory("");
00297   reset();
00298 
00299   // set steerable parameters
00300   verbose_ = pset.getUntrackedParameter<int>("verbose", 0);
00301   if (verbose_ > 0)
00302     std::cout << "DQMStore: verbosity set to " << verbose_ << std::endl;
00303   
00304   verboseQT_ = pset.getUntrackedParameter<int>("verboseQT", 0);
00305   if (verbose_ > 0)
00306     std::cout << "DQMStore: QTest verbosity set to " << verboseQT_ << std::endl;
00307   
00308   collateHistograms_ = pset.getUntrackedParameter<bool>("collateHistograms", false);
00309   if (collateHistograms_)
00310     std::cout << "DQMStore: histogram collation is enabled\n";
00311 
00312   std::string ref = pset.getUntrackedParameter<std::string>("referenceFileName", "");
00313   if (! ref.empty())
00314   {
00315     std::cout << "DQMStore: using reference file '" << ref << "'\n";
00316     readFile(ref, true, "", s_referenceDirName, StripRunDirs, false);
00317   }  
00318 
00319   initQCriterion<Comp2RefChi2>(qalgos_);
00320   initQCriterion<Comp2RefKolmogorov>(qalgos_);
00321   initQCriterion<ContentsXRange>(qalgos_);
00322   initQCriterion<ContentsYRange>(qalgos_);
00323   initQCriterion<MeanWithinExpected>(qalgos_);
00324   initQCriterion<Comp2RefEqualH>(qalgos_);
00325   initQCriterion<DeadChannel>(qalgos_);
00326   initQCriterion<NoisyChannel>(qalgos_);
00327   initQCriterion<ContentsWithinExpected>(qalgos_);
00328   initQCriterion<CompareToMedian>(qalgos_);
00329   initQCriterion<CompareLastFilledBin>(qalgos_);
00330 }
00331 
00332 /* Generic method to do a backtrace and print it to stdout. It is
00333  customised to properly get the routine that called the booking of the
00334  histograms, which, following the usual stack, is at position 4. The
00335  name of the calling function is properly demangled and the original
00336  shared library including this function is also printed. For a more
00337  detailed explanation of the routines involved, see here:
00338  http://www.gnu.org/software/libc/manual/html_node/Backtraces.html
00339  http://gcc.gnu.org/onlinedocs/libstdc++/manual/ext_demangling.html.*/
00340 
00341 void
00342 DQMStore::print_trace (const std::string &dir, const std::string &name)
00343 {
00344   static std::ofstream stream("histogramBookingBT.log");
00345   void *array[10];
00346   size_t size;
00347   char **strings;
00348   int r=0;
00349   lat::RegexpMatch m;
00350   m.reset();
00351 
00352   size = backtrace (array, 10);
00353   strings = backtrace_symbols (array, size);
00354 
00355   if ((size > 4)
00356       &&s_rxtrace.match(strings[4], 0, 0, &m))
00357   {
00358     char * demangled = abi::__cxa_demangle(m.matchString(strings[4], 2).c_str(), 0, 0, &r);
00359     stream << "\"" << dir << "/"
00360            << name << "\" "
00361            << (r ? m.matchString(strings[4], 2) : demangled) << " "
00362            << m.matchString(strings[4], 1) << "\n";
00363     free(demangled);
00364   }
00365   else
00366     stream << "Skipping "<< dir << "/" << name
00367            << " with stack size " << size << "\n";
00368   /* In this case print the full stack trace, up to main or to the
00369    * maximum stack size, i.e. 10. */
00370   if (verbose_ > 4)
00371   {
00372     size_t i;
00373     m.reset();
00374 
00375     for (i = 0; i < size; i++)
00376       if (s_rxtrace.match(strings[i], 0, 0, &m))
00377       {
00378         char * demangled = abi::__cxa_demangle(m.matchString(strings[i], 2).c_str(), 0, 0, &r);
00379         stream << "\t\t" << i << "/" << size << " "
00380                << (r ? m.matchString(strings[i], 2) : demangled) << " "
00381                << m.matchString(strings[i], 1) << std::endl;
00382         free (demangled);
00383       }
00384   }
00385   free (strings);
00386 }
00387 
00392 void
00393 DQMStore::setVerbose(unsigned /* level */)
00394 { return; }
00395 
00400 const std::string &
00401 DQMStore::pwd(void) const
00402 { return pwd_; }
00403 
00405 void
00406 DQMStore::cd(void)
00407 { setCurrentFolder(""); }
00408 
00410 void
00411 DQMStore::cd(const std::string &subdir)
00412 {
00413   std::string clean;
00414   const std::string *cleaned = 0;
00415   cleanTrailingSlashes(subdir, clean, cleaned);
00416 
00417   if (! dirExists(*cleaned))
00418     raiseDQMError("DQMStore", "Cannot 'cd' into non-existent directory '%s'",
00419                   cleaned->c_str());
00420   
00421   setCurrentFolder(*cleaned);
00422 }
00423 
00428 void
00429 DQMStore::setCurrentFolder(const std::string &fullpath)
00430 {
00431   std::string clean;
00432   const std::string *cleaned = 0;
00433   cleanTrailingSlashes(fullpath, clean, cleaned);
00434   makeDirectory(*cleaned);
00435   pwd_ = *cleaned;
00436 }
00437 
00439 void
00440 DQMStore::goUp(void)
00441 {
00442   size_t pos = pwd_.rfind('/');
00443   if (pos == std::string::npos)
00444     setCurrentFolder("");
00445   else
00446     setCurrentFolder(pwd_.substr(0, pos));
00447 }
00448 
00449 // -------------------------------------------------------------------
00451 void
00452 DQMStore::makeDirectory(const std::string &path)
00453 {
00454   std::string prev;
00455   std::string subdir;
00456   std::string name;
00457   prev.reserve(path.size());
00458   subdir.reserve(path.size());
00459   name.reserve(path.size());
00460   size_t prevname = 0;
00461   size_t slash = 0;
00462 
00463   while (true)
00464   {
00465     // Create this subdirectory component.
00466     subdir.clear();
00467     subdir.append(path, 0, slash);
00468     name.clear();
00469     name.append(subdir, prevname, std::string::npos);
00470     if (! prev.empty() && findObject(prev, name))
00471       raiseDQMError("DQMStore", "Attempt to create subdirectory '%s'"
00472                     " which already exists as a monitor element",
00473                     subdir.c_str());
00474 
00475     if (! dirs_.count(subdir))
00476       dirs_.insert(subdir);
00477 
00478     // Stop if we've reached the end (including possibly a trailing slash).
00479     if (slash+1 >= path.size())
00480       break;
00481 
00482     // Find the next slash, making sure we progress.  If reach the end,
00483     // process the last path component; the next loop round will terminate.
00484     prevname = slash ? slash+1 : slash;
00485     prev = subdir;
00486     if ((slash = path.find('/', ++slash)) == std::string::npos)
00487       slash = path.size();
00488   }
00489 }
00490 
00492 bool
00493 DQMStore::dirExists(const std::string &path) const
00494 { return dirs_.count(path) > 0; }
00495 
00499 template <class HISTO, class COLLATE>
00500 MonitorElement *
00501 DQMStore::book(const std::string &dir, const std::string &name,
00502                const char *context, int kind,
00503                HISTO *h, COLLATE collate)
00504 {
00505   assert(name.find('/') == std::string::npos);
00506   if (verbose_ > 3)
00507     print_trace(dir, name);
00508   std::string path;
00509   mergePath(path, dir, name);
00510 
00511   // Put us in charge of h.
00512   h->SetDirectory(0);
00513 
00514   // Check if the request monitor element already exists.
00515   MonitorElement *me = findObject(dir, name);
00516   if (me)
00517   {
00518     if (collateHistograms_)
00519     {
00520       collate(me, h);
00521       delete h;
00522       return me;
00523     }
00524     else
00525     {    
00526       if (verbose_ > 1)
00527         std::cout << "DQMStore: "
00528                   << context << ": monitor element '"
00529                   << path << "' already exists, collating" << std::endl;
00530       me->Reset();
00531       collate(me, h);
00532       delete h;
00533       return me;
00534     }
00535   }
00536   else
00537   {
00538     // Create and initialise core object.
00539     assert(dirs_.count(dir));
00540     MonitorElement proto(&*dirs_.find(dir), name);
00541     me = const_cast<MonitorElement &>(*data_.insert(proto).first)
00542       .initialise((MonitorElement::Kind)kind, h);
00543 
00544     // Initialise quality test information.
00545     QTestSpecs::iterator qi = qtestspecs_.begin();
00546     QTestSpecs::iterator qe = qtestspecs_.end();
00547     for ( ; qi != qe; ++qi)
00548     {
00549         if ( qi->first->match(path) )
00550                 me->addQReport(qi->second);
00551     }
00552 
00553     // Assign reference if we have one.
00554     std::string refdir;
00555     refdir.reserve(s_referenceDirName.size() + dir.size() + 2);
00556     refdir += s_referenceDirName;
00557     refdir += '/';
00558     refdir += dir;
00559 
00560     if (MonitorElement *refme = findObject(refdir, name))
00561     {
00562       me->data_.flags |= DQMNet::DQM_PROP_HAS_REFERENCE;
00563       me->reference_ = refme->object_;
00564     }
00565 
00566     // Return the monitor element.
00567     return me;
00568   }
00569 }
00570 
00571 MonitorElement *
00572 DQMStore::book(const std::string &dir,
00573                const std::string &name,
00574                const char *context)
00575 {
00576   assert(name.find('/') == std::string::npos);
00577   if (verbose_ > 3)
00578     print_trace(dir, name);
00579 
00580   // Check if the request monitor element already exists.
00581   if (MonitorElement *me = findObject(dir, name))
00582   {
00583     if (verbose_ > 1)
00584     {
00585       std::string path;
00586       mergePath(path, dir, name);
00587 
00588       std::cout << "DQMStore: "
00589                 << context << ": monitor element '"
00590                 << path << "' already exists, resetting" << std::endl;
00591     }
00592     me->Reset();
00593     return me;
00594   }
00595   else
00596   {
00597     // Create it and return for initialisation.
00598     assert(dirs_.count(dir));
00599     MonitorElement nme(&*dirs_.find(dir), name);
00600     return &const_cast<MonitorElement &>(*data_.insert(nme).first);
00601   }
00602 }
00603 
00604 // -------------------------------------------------------------------
00606 MonitorElement *
00607 DQMStore::bookInt(const std::string &dir, const std::string &name)
00608 {
00609   if (collateHistograms_)
00610   {
00611     if (MonitorElement *me = findObject(dir, name))
00612     {
00613       me->Fill(0);
00614       return me;
00615     }
00616   }
00617 
00618   return book(dir, name, "bookInt")
00619     ->initialise(MonitorElement::DQM_KIND_INT);
00620 }
00621 
00623 MonitorElement *
00624 DQMStore::bookInt(const char *name)
00625 { return bookInt(pwd_, name); }
00626 
00628 MonitorElement *
00629 DQMStore::bookInt(const std::string &name)
00630 {
00631   return bookInt(pwd_, name);
00632 }
00633 
00634 // -------------------------------------------------------------------
00636 MonitorElement *
00637 DQMStore::bookFloat(const std::string &dir, const std::string &name)
00638 {
00639   if (collateHistograms_)
00640   {
00641     if (MonitorElement *me = findObject(dir, name))
00642     {
00643       me->Fill(0.);
00644       return me;
00645     }
00646   }
00647 
00648   return book(dir, name, "bookFloat")
00649     ->initialise(MonitorElement::DQM_KIND_REAL);
00650 }
00651 
00653 MonitorElement *
00654 DQMStore::bookFloat(const char *name)
00655 { return bookFloat(pwd_, name); }
00656 
00658 MonitorElement *
00659 DQMStore::bookFloat(const std::string &name)
00660 {
00661   return bookFloat(pwd_, name);
00662 }
00663 
00664 // -------------------------------------------------------------------
00666 MonitorElement *
00667 DQMStore::bookString(const std::string &dir,
00668                      const std::string &name,
00669                      const std::string &value)
00670 {
00671   if (collateHistograms_)
00672   {
00673     if (MonitorElement *me = findObject(dir, name))
00674       return me;
00675   }
00676 
00677   return book(dir, name, "bookString")
00678     ->initialise(MonitorElement::DQM_KIND_STRING, value);
00679 }
00680 
00682 MonitorElement *
00683 DQMStore::bookString(const char *name, const char *value)
00684 { return bookString(pwd_, name, value); }
00685 
00687 MonitorElement *
00688 DQMStore::bookString(const std::string &name, const std::string &value)
00689 {
00690   return bookString(pwd_, name, value);
00691 }
00692 
00693 // -------------------------------------------------------------------
00695 MonitorElement *
00696 DQMStore::book1D(const std::string &dir, const std::string &name, TH1F *h)
00697 {
00698   return book(dir, name, "book1D", MonitorElement::DQM_KIND_TH1F, h, collate1D);
00699 }
00700 
00702 MonitorElement *
00703 DQMStore::book1S(const std::string &dir, const std::string &name, TH1S *h)
00704 {
00705   return book(dir, name, "book1S", MonitorElement::DQM_KIND_TH1S, h, collate1S);
00706 }
00707 
00709 MonitorElement *
00710 DQMStore::book1DD(const std::string &dir, const std::string &name, TH1D *h)
00711 {
00712   return book(dir, name, "book1DD", MonitorElement::DQM_KIND_TH1D, h, collate1DD);
00713 }
00714 
00716 MonitorElement *
00717 DQMStore::book1D(const char *name, const char *title,
00718                  int nchX, double lowX, double highX)
00719 {
00720   return book1D(pwd_, name, new TH1F(name, title, nchX, lowX, highX));
00721 }
00722 
00724 MonitorElement *
00725 DQMStore::book1D(const std::string &name, const std::string &title,
00726                  int nchX, double lowX, double highX)
00727 {
00728   return book1D(pwd_, name, new TH1F(name.c_str(), title.c_str(), nchX, lowX, highX));
00729 }
00730 
00732 MonitorElement *
00733 DQMStore::book1S(const char *name, const char *title,
00734                  int nchX, double lowX, double highX)
00735 {
00736   return book1S(pwd_, name, new TH1S(name, title, nchX, lowX, highX));
00737 }
00738 
00740 MonitorElement *
00741 DQMStore::book1S(const std::string &name, const std::string &title,
00742                  int nchX, double lowX, double highX)
00743 {
00744   return book1S(pwd_, name, new TH1S(name.c_str(), title.c_str(), nchX, lowX, highX));
00745 }
00746 
00748 MonitorElement *
00749 DQMStore::book1DD(const char *name, const char *title,
00750                   int nchX, double lowX, double highX)
00751 {
00752   return book1DD(pwd_, name, new TH1D(name, title, nchX, lowX, highX));
00753 }
00754 
00756 MonitorElement *
00757 DQMStore::book1DD(const std::string &name, const std::string &title,
00758                   int nchX, double lowX, double highX)
00759 {
00760   return book1DD(pwd_, name, new TH1D(name.c_str(), title.c_str(), nchX, lowX, highX));
00761 }
00762 
00764 MonitorElement *
00765 DQMStore::book1D(const char *name, const char *title,
00766                  int nchX, float *xbinsize)
00767 {
00768   return book1D(pwd_, name, new TH1F(name, title, nchX, xbinsize));
00769 }
00770 
00772 MonitorElement *
00773 DQMStore::book1D(const std::string &name, const std::string &title,
00774                  int nchX, float *xbinsize)
00775 {
00776   return book1D(pwd_, name, new TH1F(name.c_str(), title.c_str(), nchX, xbinsize));
00777 }
00778 
00780 MonitorElement *
00781 DQMStore::book1D(const char *name, TH1F *source)
00782 {
00783   return book1D(pwd_, name, static_cast<TH1F *>(source->Clone(name)));
00784 }
00785 
00787 MonitorElement *
00788 DQMStore::book1D(const std::string &name, TH1F *source)
00789 {
00790   return book1D(pwd_, name, static_cast<TH1F *>(source->Clone(name.c_str())));
00791 }
00792 
00794 MonitorElement *
00795 DQMStore::book1S(const char *name, TH1S *source)
00796 {
00797   return book1S(pwd_, name, static_cast<TH1S *>(source->Clone(name)));
00798 }
00799 
00801 MonitorElement *
00802 DQMStore::book1S(const std::string &name, TH1S *source)
00803 {
00804   return book1S(pwd_, name, static_cast<TH1S *>(source->Clone(name.c_str())));
00805 }
00806 
00808 MonitorElement *
00809 DQMStore::book1DD(const char *name, TH1D *source)
00810 {
00811   return book1DD(pwd_, name, static_cast<TH1D *>(source->Clone(name)));
00812 }
00813 
00815 MonitorElement *
00816 DQMStore::book1DD(const std::string &name, TH1D *source)
00817 {
00818   return book1DD(pwd_, name, static_cast<TH1D *>(source->Clone(name.c_str())));
00819 }
00820 
00821 // -------------------------------------------------------------------
00823 MonitorElement *
00824 DQMStore::book2D(const std::string &dir, const std::string &name, TH2F *h)
00825 {
00826   return book(dir, name, "book2D", MonitorElement::DQM_KIND_TH2F, h, collate2D);
00827 }
00828 
00830 MonitorElement *
00831 DQMStore::book2S(const std::string &dir, const std::string &name, TH2S *h)
00832 {
00833   return book(dir, name, "book2S", MonitorElement::DQM_KIND_TH2S, h, collate2S);
00834 }
00835 
00837 MonitorElement *
00838 DQMStore::book2DD(const std::string &dir, const std::string &name, TH2D *h)
00839 {
00840   return book(dir, name, "book2DD", MonitorElement::DQM_KIND_TH2D, h, collate2DD);
00841 }
00842 
00844 MonitorElement *
00845 DQMStore::book2D(const char *name, const char *title,
00846                  int nchX, double lowX, double highX,
00847                  int nchY, double lowY, double highY)
00848 {
00849   return book2D(pwd_, name, new TH2F(name, title,
00850                                      nchX, lowX, highX,
00851                                      nchY, lowY, highY));
00852 }
00853 
00855 MonitorElement *
00856 DQMStore::book2D(const std::string &name, const std::string &title,
00857                  int nchX, double lowX, double highX,
00858                  int nchY, double lowY, double highY)
00859 {
00860   return book2D(pwd_, name, new TH2F(name.c_str(), title.c_str(),
00861                                      nchX, lowX, highX,
00862                                      nchY, lowY, highY));
00863 }
00864 
00866 MonitorElement *
00867 DQMStore::book2S(const char *name, const char *title,
00868                  int nchX, double lowX, double highX,
00869                  int nchY, double lowY, double highY)
00870 {
00871   return book2S(pwd_, name, new TH2S(name, title,
00872                                      nchX, lowX, highX,
00873                                      nchY, lowY, highY));
00874 }
00875 
00877 MonitorElement *
00878 DQMStore::book2S(const std::string &name, const std::string &title,
00879                  int nchX, double lowX, double highX,
00880                  int nchY, double lowY, double highY)
00881 {
00882   return book2S(pwd_, name, new TH2S(name.c_str(), title.c_str(),
00883                                      nchX, lowX, highX,
00884                                      nchY, lowY, highY));
00885 }
00886 
00888 MonitorElement *
00889 DQMStore::book2DD(const char *name, const char *title,
00890                   int nchX, double lowX, double highX,
00891                   int nchY, double lowY, double highY)
00892 {
00893   return book2DD(pwd_, name, new TH2D(name, title,
00894                                       nchX, lowX, highX,
00895                                       nchY, lowY, highY));
00896 }
00897 
00899 MonitorElement *
00900 DQMStore::book2DD(const std::string &name, const std::string &title,
00901                   int nchX, double lowX, double highX,
00902                   int nchY, double lowY, double highY)
00903 {
00904   return book2DD(pwd_, name, new TH2D(name.c_str(), title.c_str(),
00905                                       nchX, lowX, highX,
00906                                       nchY, lowY, highY));
00907 }
00908 
00910 MonitorElement *
00911 DQMStore::book2D(const char *name, const char *title,
00912                  int nchX, float *xbinsize, int nchY, float *ybinsize)
00913 {
00914   return book2D(pwd_, name, new TH2F(name, title, 
00915                                      nchX, xbinsize, nchY, ybinsize));
00916 }
00917 
00919 MonitorElement *
00920 DQMStore::book2D(const std::string &name, const std::string &title,
00921                  int nchX, float *xbinsize, int nchY, float *ybinsize)
00922 {
00923   return book2D(pwd_, name, new TH2F(name.c_str(), title.c_str(), 
00924                                      nchX, xbinsize, nchY, ybinsize));
00925 }
00926 
00928 MonitorElement *
00929 DQMStore::book2D(const char *name, TH2F *source)
00930 {
00931   return book2D(pwd_, name, static_cast<TH2F *>(source->Clone(name)));
00932 }
00933 
00935 MonitorElement *
00936 DQMStore::book2D(const std::string &name, TH2F *source)
00937 {
00938   return book2D(pwd_, name, static_cast<TH2F *>(source->Clone(name.c_str())));
00939 }
00940 
00942 MonitorElement *
00943 DQMStore::book2S(const char *name, TH2S *source)
00944 {
00945   return book2S(pwd_, name, static_cast<TH2S *>(source->Clone(name)));
00946 }
00947 
00949 MonitorElement *
00950 DQMStore::book2S(const std::string &name, TH2S *source)
00951 {
00952   return book2S(pwd_, name, static_cast<TH2S *>(source->Clone(name.c_str())));
00953 }
00954 
00956 MonitorElement *
00957 DQMStore::book2DD(const char *name, TH2D *source)
00958 {
00959   return book2DD(pwd_, name, static_cast<TH2D *>(source->Clone(name)));
00960 }
00961 
00963 MonitorElement *
00964 DQMStore::book2DD(const std::string &name, TH2D *source)
00965 {
00966   return book2DD(pwd_, name, static_cast<TH2D *>(source->Clone(name.c_str())));
00967 }
00968 
00969 // -------------------------------------------------------------------
00971 MonitorElement *
00972 DQMStore::book3D(const std::string &dir, const std::string &name, TH3F *h)
00973 {
00974   return book(dir, name, "book3D", MonitorElement::DQM_KIND_TH3F, h, collate3D);
00975 }
00976 
00978 MonitorElement *
00979 DQMStore::book3D(const char *name, const char *title,
00980                  int nchX, double lowX, double highX,
00981                  int nchY, double lowY, double highY,
00982                  int nchZ, double lowZ, double highZ)
00983 {
00984   return book3D(pwd_, name, new TH3F(name, title,
00985                                      nchX, lowX, highX,
00986                                      nchY, lowY, highY,
00987                                      nchZ, lowZ, highZ));
00988 }
00989 
00991 MonitorElement *
00992 DQMStore::book3D(const std::string &name, const std::string &title,
00993                  int nchX, double lowX, double highX,
00994                  int nchY, double lowY, double highY,
00995                  int nchZ, double lowZ, double highZ)
00996 {
00997   return book3D(pwd_, name, new TH3F(name.c_str(), title.c_str(),
00998                                      nchX, lowX, highX,
00999                                      nchY, lowY, highY,
01000                                      nchZ, lowZ, highZ));
01001 }
01002 
01004 MonitorElement *
01005 DQMStore::book3D(const char *name, TH3F *source)
01006 {
01007   return book3D(pwd_, name, static_cast<TH3F *>(source->Clone(name)));
01008 }
01009 
01011 MonitorElement *
01012 DQMStore::book3D(const std::string &name, TH3F *source)
01013 {
01014   return book3D(pwd_, name, static_cast<TH3F *>(source->Clone(name.c_str())));
01015 }
01016 
01017 // -------------------------------------------------------------------
01019 MonitorElement *
01020 DQMStore::bookProfile(const std::string &dir, const std::string &name, TProfile *h)
01021 {
01022   return book(dir, name, "bookProfile",
01023               MonitorElement::DQM_KIND_TPROFILE,
01024               h, collateProfile);
01025 }
01026 
01030 MonitorElement *
01031 DQMStore::bookProfile(const char *name, const char *title,
01032                       int nchX, double lowX, double highX,
01033                       int /* nchY */, double lowY, double highY,
01034                       const char *option /* = "s" */)
01035 {
01036   return bookProfile(pwd_, name, new TProfile(name, title,
01037                                               nchX, lowX, highX,
01038                                               lowY, highY,
01039                                               option));
01040 }
01041 
01045 MonitorElement *
01046 DQMStore::bookProfile(const std::string &name, const std::string &title,
01047                       int nchX, double lowX, double highX,
01048                       int /* nchY */, double lowY, double highY,
01049                       const char *option /* = "s" */)
01050 {
01051   return bookProfile(pwd_, name, new TProfile(name.c_str(), title.c_str(),
01052                                               nchX, lowX, highX,
01053                                               lowY, highY,
01054                                               option));
01055 }
01056 
01060 MonitorElement *
01061 DQMStore::bookProfile(const char *name, const char *title,
01062                       int nchX, double lowX, double highX,
01063                       double lowY, double highY,
01064                       const char *option /* = "s" */)
01065 {
01066   return bookProfile(pwd_, name, new TProfile(name, title,
01067                                               nchX, lowX, highX,
01068                                               lowY, highY,
01069                                               option));
01070 }
01071 
01075 MonitorElement *
01076 DQMStore::bookProfile(const std::string &name, const std::string &title,
01077                       int nchX, double lowX, double highX,
01078                       double lowY, double highY,
01079                       const char *option /* = "s" */)
01080 {
01081   return bookProfile(pwd_, name, new TProfile(name.c_str(), title.c_str(),
01082                                               nchX, lowX, highX,
01083                                               lowY, highY,
01084                                               option));
01085 }
01086 
01090 MonitorElement *
01091 DQMStore::bookProfile(const char *name, const char *title,
01092                       int nchX, double *xbinsize,
01093                       int /* nchY */, double lowY, double highY,
01094                       const char *option /* = "s" */)
01095 {
01096   return bookProfile(pwd_, name, new TProfile(name, title,
01097                                               nchX, xbinsize,
01098                                               lowY, highY,
01099                                               option));
01100 }
01101 
01105 MonitorElement *
01106 DQMStore::bookProfile(const std::string &name, const std::string &title,
01107                       int nchX, double *xbinsize,
01108                       int /* nchY */, double lowY, double highY,
01109                       const char *option /* = "s" */)
01110 {
01111   return bookProfile(pwd_, name, new TProfile(name.c_str(), title.c_str(),
01112                                               nchX, xbinsize,
01113                                               lowY, highY,
01114                                               option));
01115 }
01116 
01120 MonitorElement *
01121 DQMStore::bookProfile(const char *name, const char *title,
01122                       int nchX, double *xbinsize,
01123                       double lowY, double highY,
01124                       const char *option /* = "s" */)
01125 {
01126   return bookProfile(pwd_, name, new TProfile(name, title,
01127                                               nchX, xbinsize,
01128                                               lowY, highY,
01129                                               option));
01130 }
01131 
01135 MonitorElement *
01136 DQMStore::bookProfile(const std::string &name, const std::string &title,
01137                       int nchX, double *xbinsize,
01138                       double lowY, double highY,
01139                       const char *option /* = "s" */)
01140 {
01141   return bookProfile(pwd_, name, new TProfile(name.c_str(), title.c_str(),
01142                                               nchX, xbinsize,
01143                                               lowY, highY,
01144                                               option));
01145 }
01146 
01148 MonitorElement *
01149 DQMStore::bookProfile(const char *name, TProfile *source)
01150 {
01151   return bookProfile(pwd_, name, static_cast<TProfile *>(source->Clone(name)));
01152 }
01153 
01155 MonitorElement *
01156 DQMStore::bookProfile(const std::string &name, TProfile *source)
01157 {
01158   return bookProfile(pwd_, name, static_cast<TProfile *>(source->Clone(name.c_str())));
01159 }
01160 
01161 // -------------------------------------------------------------------
01163 MonitorElement *
01164 DQMStore::bookProfile2D(const std::string &dir, const std::string &name, TProfile2D *h)
01165 {
01166   return book(dir, name, "bookProfile2D",
01167               MonitorElement::DQM_KIND_TPROFILE2D,
01168               h, collateProfile2D);
01169 }
01170 
01174 MonitorElement *
01175 DQMStore::bookProfile2D(const char *name, const char *title,
01176                         int nchX, double lowX, double highX,
01177                         int nchY, double lowY, double highY,
01178                         int /* nchZ */, double lowZ, double highZ,
01179                         const char *option /* = "s" */)
01180 {
01181   return bookProfile2D(pwd_, name, new TProfile2D(name, title,
01182                                                   nchX, lowX, highX,
01183                                                   nchY, lowY, highY,
01184                                                   lowZ, highZ,
01185                                                   option));
01186 }
01187 
01191 MonitorElement *
01192 DQMStore::bookProfile2D(const std::string &name, const std::string &title,
01193                         int nchX, double lowX, double highX,
01194                         int nchY, double lowY, double highY,
01195                         int /* nchZ */, double lowZ, double highZ,
01196                         const char *option /* = "s" */)
01197 {
01198   return bookProfile2D(pwd_, name, new TProfile2D(name.c_str(), title.c_str(),
01199                                                   nchX, lowX, highX,
01200                                                   nchY, lowY, highY,
01201                                                   lowZ, highZ,
01202                                                   option));
01203 }
01204 
01208 MonitorElement *
01209 DQMStore::bookProfile2D(const char *name, const char *title,
01210                         int nchX, double lowX, double highX,
01211                         int nchY, double lowY, double highY,
01212                         double lowZ, double highZ,
01213                         const char *option /* = "s" */)
01214 {
01215   return bookProfile2D(pwd_, name, new TProfile2D(name, title,
01216                                                   nchX, lowX, highX,
01217                                                   nchY, lowY, highY,
01218                                                   lowZ, highZ,
01219                                                   option));
01220 }
01221 
01225 MonitorElement *
01226 DQMStore::bookProfile2D(const std::string &name, const std::string &title,
01227                         int nchX, double lowX, double highX,
01228                         int nchY, double lowY, double highY,
01229                         double lowZ, double highZ,
01230                         const char *option /* = "s" */)
01231 {
01232   return bookProfile2D(pwd_, name, new TProfile2D(name.c_str(), title.c_str(),
01233                                                   nchX, lowX, highX,
01234                                                   nchY, lowY, highY,
01235                                                   lowZ, highZ,
01236                                                   option));
01237 }
01238 
01240 MonitorElement *
01241 DQMStore::bookProfile2D(const char *name, TProfile2D *source)
01242 {
01243   return bookProfile2D(pwd_, name, static_cast<TProfile2D *>(source->Clone(name)));
01244 }
01245 
01247 MonitorElement *
01248 DQMStore::bookProfile2D(const std::string &name, TProfile2D *source)
01249 {
01250   return bookProfile2D(pwd_, name, static_cast<TProfile2D *>(source->Clone(name.c_str())));
01251 }
01252 
01256 bool
01257 DQMStore::checkBinningMatches(MonitorElement *me, TH1 *h)
01258 {
01259   if (me->getTH1()->GetNbinsX() != h->GetNbinsX()
01260       || me->getTH1()->GetNbinsY() != h->GetNbinsY()
01261       || me->getTH1()->GetNbinsZ() != h->GetNbinsZ()
01262       || me->getTH1()->GetXaxis()->GetXmin() != h->GetXaxis()->GetXmin()
01263       || me->getTH1()->GetYaxis()->GetXmin() != h->GetYaxis()->GetXmin()
01264       || me->getTH1()->GetZaxis()->GetXmin() != h->GetZaxis()->GetXmin()
01265       || me->getTH1()->GetXaxis()->GetXmax() != h->GetXaxis()->GetXmax()
01266       || me->getTH1()->GetYaxis()->GetXmax() != h->GetYaxis()->GetXmax()
01267       || me->getTH1()->GetZaxis()->GetXmax() != h->GetZaxis()->GetXmax())
01268   {
01269     //  edm::LogWarning ("DQMStore")
01270     std::cout << "*** DQMStore: WARNING:"
01271               << "checkBinningMatches: different binning - cannot add object '"
01272               << h->GetName() << "' of type "
01273               << h->IsA()->GetName() << " to existing ME: '"
01274               << me->getFullname() << "'\n";
01275     return false;
01276   }
01277   return true;     
01278 }
01279 
01280 void
01281 DQMStore::collate1D(MonitorElement *me, TH1F *h)
01282 { 
01283   if (checkBinningMatches(me,h)) 
01284     me->getTH1F()->Add(h); 
01285 }
01286 
01287 void
01288 DQMStore::collate1S(MonitorElement *me, TH1S *h)
01289 {  
01290   if (checkBinningMatches(me,h)) 
01291     me->getTH1S()->Add(h); 
01292 }
01293 
01294 void
01295 DQMStore::collate1DD(MonitorElement *me, TH1D *h)
01296 {  
01297   if (checkBinningMatches(me,h)) 
01298     me->getTH1D()->Add(h); 
01299 }
01300 
01301 void
01302 DQMStore::collate2D(MonitorElement *me, TH2F *h)
01303 {  
01304   if (checkBinningMatches(me,h)) 
01305     me->getTH2F()->Add(h); 
01306 }
01307 
01308 void
01309 DQMStore::collate2S(MonitorElement *me, TH2S *h)
01310 {  
01311   if (checkBinningMatches(me,h)) 
01312     me->getTH2S()->Add(h); 
01313 }
01314 
01315 void
01316 DQMStore::collate2DD(MonitorElement *me, TH2D *h)
01317 {  
01318   if (checkBinningMatches(me,h)) 
01319     me->getTH2D()->Add(h); 
01320 }
01321 
01322 void
01323 DQMStore::collate3D(MonitorElement *me, TH3F *h)
01324 {  
01325   if (checkBinningMatches(me,h)) 
01326     me->getTH3F()->Add(h); 
01327 }
01328 
01329 void
01330 DQMStore::collateProfile(MonitorElement *me, TProfile *h)
01331 {
01332   if (checkBinningMatches(me,h)) 
01333   {
01334     TProfile *meh = me->getTProfile();
01335     me->addProfiles(h, meh, meh, 1, 1);
01336   }
01337 }
01338 
01339 void
01340 DQMStore::collateProfile2D(MonitorElement *me, TProfile2D *h)
01341 {
01342   if (checkBinningMatches(me,h)) 
01343   {
01344     TProfile2D *meh = me->getTProfile2D();
01345     me->addProfiles(h, meh, meh, 1, 1);
01346   }
01347 }
01348 
01353 void
01354 DQMStore::tag(MonitorElement *me, unsigned int myTag)
01355 {
01356   if (! myTag)
01357     raiseDQMError("DQMStore", "Attempt to tag monitor element '%s'"
01358                   " with a zero tag", me->getFullname().c_str());
01359   if ((me->data_.flags & DQMNet::DQM_PROP_TAGGED) && myTag != me->data_.tag)
01360     raiseDQMError("DQMStore", "Attempt to tag monitor element '%s'"
01361                   " twice with multiple tags", me->getFullname().c_str());
01362 
01363   me->data_.tag = myTag;
01364   me->data_.flags |= DQMNet::DQM_PROP_TAGGED;
01365 }
01366 
01368 void
01369 DQMStore::tag(const std::string &path, unsigned int myTag)
01370 {
01371   std::string dir;
01372   std::string name;
01373   splitPath(dir, name, path);
01374 
01375   if (MonitorElement *me = findObject(dir, name))
01376     tag(me, myTag);
01377   else
01378     raiseDQMError("DQMStore", "Attempt to tag non-existent monitor element"
01379                   " '%s' with tag %u", path.c_str(), myTag);
01380 
01381 }
01382 
01384 void
01385 DQMStore::tagContents(const std::string &path, unsigned int myTag)
01386 {
01387   MonitorElement proto(&path, std::string());
01388   MEMap::iterator e = data_.end();
01389   MEMap::iterator i = data_.lower_bound(proto);
01390   for ( ; i != e && path == *i->data_.dirname; ++i)
01391     tag(const_cast<MonitorElement *>(&*i), myTag);
01392 }
01393 
01396 void
01397 DQMStore::tagAllContents(const std::string &path, unsigned int myTag)
01398 {
01399   std::string clean;
01400   const std::string *cleaned = 0;
01401   cleanTrailingSlashes(path, clean, cleaned);
01402   MonitorElement proto(cleaned, std::string());
01403 
01404   // FIXME: WILDCARDS? Old one supported them, but nobody seemed to use them.
01405   MEMap::iterator e = data_.end();
01406   MEMap::iterator i = data_.lower_bound(proto);
01407   while (i != e && isSubdirectory(*cleaned, *i->data_.dirname))
01408   {
01409     tag(const_cast<MonitorElement *>(&*i), myTag);
01410     ++i;
01411   }
01412 }
01413 
01418 std::vector<std::string>
01419 DQMStore::getSubdirs(void) const
01420 {
01421   std::vector<std::string> result;
01422   std::set<std::string>::const_iterator e = dirs_.end();
01423   std::set<std::string>::const_iterator i = dirs_.find(pwd_);
01424 
01425   // If we didn't find current directory, the tree is empty, so quit.
01426   if (i == e)
01427     return result;
01428 
01429   // Skip the current directory and then start looking for immediate
01430   // subdirectories in the dirs_ list.  Stop when we are no longer in
01431   // (direct or indirect) subdirectories of pwd_.  Note that we don't
01432   // "know" which order the set will sort A/B, A/B/C and A/D.
01433   while (++i != e && isSubdirectory(pwd_, *i))
01434     if (i->find('/', pwd_.size()+1) == std::string::npos)
01435       result.push_back(*i);
01436 
01437   return result;
01438 }
01439 
01441 std::vector<std::string>
01442 DQMStore::getMEs(void) const
01443 {
01444   MonitorElement proto(&pwd_, std::string());
01445   std::vector<std::string> result;
01446   MEMap::const_iterator e = data_.end();
01447   MEMap::const_iterator i = data_.lower_bound(proto);
01448   for ( ; i != e && isSubdirectory(pwd_, *i->data_.dirname); ++i)
01449     if (pwd_ == *i->data_.dirname)
01450       result.push_back(i->getName());
01451 
01452   return result;
01453 }
01454 
01457 bool
01458 DQMStore::containsAnyMonitorable(const std::string &path) const
01459 {
01460   MonitorElement proto(&path, std::string());
01461   MEMap::const_iterator e = data_.end();
01462   MEMap::const_iterator i = data_.lower_bound(proto);
01463   return (i != e && isSubdirectory(path, *i->data_.dirname));
01464 }
01465 
01467 MonitorElement *
01468 DQMStore::get(const std::string &path) const
01469 {
01470   std::string dir;
01471   std::string name;
01472   splitPath(dir, name, path);
01473   MonitorElement proto(&dir, name);
01474   MEMap::const_iterator mepos = data_.find(proto);
01475   return (mepos == data_.end() ? 0
01476           : const_cast<MonitorElement *>(&*mepos));
01477 }
01478 
01480 std::vector<MonitorElement *>
01481 DQMStore::get(unsigned int tag) const
01482 {
01483   // FIXME: Use reverse map [tag -> path] / [tag -> dir]?
01484   std::vector<MonitorElement *> result;
01485   for (MEMap::const_iterator i = data_.begin(), e = data_.end(); i != e; ++i)
01486   {
01487     const MonitorElement &me = *i;
01488     if ((me.data_.flags & DQMNet::DQM_PROP_TAGGED) && me.data_.tag == tag)
01489       result.push_back(const_cast<MonitorElement *>(&me));
01490   }
01491   return result;
01492 }
01493 
01496 std::vector<MonitorElement *>
01497 DQMStore::getContents(const std::string &path) const
01498 {
01499   std::string clean;
01500   const std::string *cleaned = 0;
01501   cleanTrailingSlashes(path, clean, cleaned);
01502   MonitorElement proto(cleaned, std::string());
01503 
01504   std::vector<MonitorElement *> result;
01505   MEMap::const_iterator e = data_.end();
01506   MEMap::const_iterator i = data_.lower_bound(proto);
01507   for ( ; i != e && isSubdirectory(*cleaned, *i->data_.dirname); ++i)
01508     if (*cleaned == *i->data_.dirname)
01509       result.push_back(const_cast<MonitorElement *>(&*i));
01510 
01511   return result;
01512 }
01513 
01515 std::vector<MonitorElement *>
01516 DQMStore::getContents(const std::string &path, unsigned int tag) const
01517 {
01518   std::string clean;
01519   const std::string *cleaned = 0;
01520   cleanTrailingSlashes(path, clean, cleaned);
01521   MonitorElement proto(cleaned, std::string());
01522 
01523   std::vector<MonitorElement *> result;
01524   MEMap::const_iterator e = data_.end();
01525   MEMap::const_iterator i = data_.lower_bound(proto);
01526   for ( ; i != e && isSubdirectory(*cleaned, *i->data_.dirname); ++i)
01527     if (*cleaned == *i->data_.dirname
01528         && (i->data_.flags & DQMNet::DQM_PROP_TAGGED)
01529         && i->data_.tag == tag)
01530       result.push_back(const_cast<MonitorElement *>(&*i));
01531 
01532   return result;
01533 }
01534 
01539 void
01540 DQMStore::getContents(std::vector<std::string> &into, bool showContents /* = true */) const
01541 {
01542   into.clear();
01543   into.reserve(dirs_.size());
01544 
01545   MEMap::const_iterator me = data_.end();
01546   std::set<std::string>::const_iterator di = dirs_.begin();
01547   std::set<std::string>::const_iterator de = dirs_.end();
01548   for ( ; di != de; ++di)
01549   {
01550     MonitorElement proto(&*di, std::string());
01551     MEMap::const_iterator mi = data_.lower_bound(proto);
01552     MEMap::const_iterator m = mi;
01553     size_t sz = di->size() + 2;
01554     size_t nfound = 0;
01555     for ( ; m != me && isSubdirectory(*di, *m->data_.dirname); ++m)
01556       if (*di == *m->data_.dirname)
01557       {
01558         sz += m->data_.objname.size() + 1;
01559         ++nfound;
01560       }
01561 
01562     if (! nfound)
01563       continue;
01564 
01565     std::vector<std::string>::iterator istr
01566       = into.insert(into.end(), std::string());
01567 
01568     if (showContents)
01569     {
01570       istr->reserve(sz);
01571 
01572       *istr += *di;
01573       *istr += ':';
01574       for (sz = 0; mi != m; ++mi)
01575       {
01576         if (*di != *mi->data_.dirname)
01577           continue;
01578 
01579         if (sz > 0)
01580           *istr += ',';
01581 
01582         *istr += mi->data_.objname;
01583         ++sz;
01584       }
01585     }
01586     else
01587     {
01588       istr->reserve(di->size() + 2);
01589       *istr += *di;
01590       *istr += ':';
01591     }
01592   }
01593 }
01594 
01597 MonitorElement *
01598 DQMStore::findObject(const std::string &dir, const std::string &name) const
01599 {
01600   if (dir.find_first_not_of(s_safe) != std::string::npos)
01601     raiseDQMError("DQMStore", "Monitor element path name '%s' uses"
01602                   " unacceptable characters", dir.c_str());
01603   if (name.find_first_not_of(s_safe) != std::string::npos)
01604     raiseDQMError("DQMStore", "Monitor element path name '%s' uses"
01605                   " unacceptable characters", name.c_str());
01606 
01607   MonitorElement proto;
01608   proto.data_.dirname = &dir;
01609   proto.data_.objname = name;
01610 
01611   MEMap::const_iterator mepos = data_.find(proto);
01612   return (mepos == data_.end() ? 0
01613           : const_cast<MonitorElement *>(&*mepos));
01614 }
01615 
01618 void
01619 DQMStore::getAllTags(std::vector<std::string> &into) const
01620 {
01621   into.clear();
01622   into.reserve(dirs_.size());
01623 
01624   MEMap::const_iterator me = data_.end();
01625   std::set<std::string>::const_iterator di = dirs_.begin();
01626   std::set<std::string>::const_iterator de = dirs_.end();
01627   char tagbuf[32]; // more than enough for '/' and up to 10 digits
01628 
01629   for ( ; di != de; ++di)
01630   {
01631     MonitorElement proto(&*di, std::string());
01632     MEMap::const_iterator mi = data_.lower_bound(proto);
01633     MEMap::const_iterator m = mi;
01634     size_t sz = di->size() + 2;
01635     size_t nfound = 0;
01636     for ( ; m != me && isSubdirectory(*di, *m->data_.dirname); ++m)
01637       if (*di == *m->data_.dirname && (m->data_.flags & DQMNet::DQM_PROP_TAGGED))
01638       {
01639         // the tags count for '/' + up to 10 digits, otherwise ',' + ME name
01640         sz += 1 + m->data_.objname.size() + 11;
01641         ++nfound;
01642       }
01643 
01644     if (! nfound)
01645       continue;
01646 
01647     std::vector<std::string>::iterator istr
01648       = into.insert(into.end(), std::string());
01649 
01650     istr->reserve(sz);
01651 
01652     *istr += *di;
01653     *istr += ':';
01654     for (sz = 0; mi != m; ++mi)
01655     {
01656       if (*di == *m->data_.dirname && (m->data_.flags & DQMNet::DQM_PROP_TAGGED))
01657       {
01658         sprintf(tagbuf, "/%u", mi->data_.tag);
01659         if (sz > 0)
01660           *istr += ',';
01661         *istr += m->data_.objname;
01662         *istr += tagbuf;
01663         ++sz;
01664       }
01665     }
01666   }
01667 }
01668 
01671 std::vector<MonitorElement*>
01672 DQMStore::getAllContents(const std::string &path) const
01673 {
01674   std::string clean;
01675   const std::string *cleaned = 0;
01676   cleanTrailingSlashes(path, clean, cleaned);
01677   MonitorElement proto(cleaned, std::string());
01678 
01679   std::vector<MonitorElement *> result;
01680   MEMap::const_iterator e = data_.end();
01681   MEMap::const_iterator i = data_.lower_bound(proto);
01682   for ( ; i != e && isSubdirectory(*cleaned, *i->data_.dirname); ++i)
01683     result.push_back(const_cast<MonitorElement *>(&*i));
01684 
01685   return result;
01686 }
01687 
01690 std::vector<MonitorElement*>
01691 DQMStore::getMatchingContents(const std::string &pattern, lat::Regexp::Syntax syntaxType /* = Wildcard */) const
01692 {
01693   lat::Regexp rx;
01694   try
01695   {
01696     rx = lat::Regexp(pattern, 0, syntaxType);
01697     rx.study();
01698   }
01699   catch (lat::Error &e)
01700   {
01701     raiseDQMError("DQMStore", "Invalid regular expression '%s': %s",
01702                   pattern.c_str(), e.explain().c_str());
01703   }
01704 
01705   std::string path;
01706   std::vector<MonitorElement *> result;
01707   MEMap::const_iterator i = data_.begin();
01708   MEMap::const_iterator e = data_.end();
01709   for ( ; i != e; ++i)
01710   {
01711     path.clear();
01712     mergePath(path, *i->data_.dirname, i->data_.objname);
01713     if (rx.match(path))
01714       result.push_back(const_cast<MonitorElement *>(&*i));
01715   }
01716 
01717   return result;
01718 }
01719 
01723 
01726 void
01727 DQMStore::reset(void)
01728 {
01729   MEMap::iterator mi = data_.begin();
01730   MEMap::iterator me = data_.end();
01731   for ( ; mi != me; ++mi)
01732   {
01733     MonitorElement &me = const_cast<MonitorElement &>(*mi);
01734     if (mi->wasUpdated())
01735     {
01736       if (me.resetMe())
01737         me.Reset();
01738       me.resetUpdate();
01739     }
01740   }
01741 
01742   reset_ = true;
01743 }
01744 
01748 
01750 void
01751 DQMStore::forceReset(void)
01752 {
01753   MEMap::iterator mi = data_.begin();
01754   MEMap::iterator me = data_.end();
01755   for ( ; mi != me; ++mi)
01756   {
01757     MonitorElement &me = const_cast<MonitorElement &>(*mi);
01758     me.Reset();
01759     me.resetUpdate();
01760   }
01761 
01762   reset_ = true;
01763 }
01764 
01770 bool
01771 DQMStore::extract(TObject *obj, const std::string &dir, bool overwrite)
01772 {
01773   // NB: Profile histograms inherit from TH*D, checking order matters.
01774   MonitorElement *refcheck = 0;
01775   if (TProfile *h = dynamic_cast<TProfile *>(obj))
01776   {
01777     MonitorElement *me = findObject(dir, h->GetName());
01778     if (! me)
01779       me = bookProfile(dir, h->GetName(), (TProfile *) h->Clone());
01780     else if (overwrite)
01781       me->copyFrom(h);
01782     else if (isCollateME(me) || collateHistograms_)
01783       collateProfile(me, h);
01784     refcheck = me;
01785   }
01786   else if (TProfile2D *h = dynamic_cast<TProfile2D *>(obj))
01787   {
01788     MonitorElement *me = findObject(dir, h->GetName());
01789     if (! me)
01790       me = bookProfile2D(dir, h->GetName(), (TProfile2D *) h->Clone());
01791     else if (overwrite)
01792       me->copyFrom(h);
01793     else if (isCollateME(me) || collateHistograms_)
01794       collateProfile2D(me, h);
01795     refcheck = me;
01796   }
01797   else if (TH1F *h = dynamic_cast<TH1F *>(obj))
01798   {
01799     MonitorElement *me = findObject(dir, h->GetName());
01800     if (! me)
01801       me = book1D(dir, h->GetName(), (TH1F *) h->Clone());
01802     else if (overwrite)
01803       me->copyFrom(h);
01804     else if (isCollateME(me) || collateHistograms_)
01805       collate1D(me, h);
01806     refcheck = me;
01807   }
01808   else if (TH1S *h = dynamic_cast<TH1S *>(obj))
01809   {
01810     MonitorElement *me = findObject(dir, h->GetName());
01811     if (! me)
01812       me = book1S(dir, h->GetName(), (TH1S *) h->Clone());
01813     else if (overwrite)
01814       me->copyFrom(h);
01815     else if (isCollateME(me) || collateHistograms_)
01816       collate1S(me, h);
01817     refcheck = me;
01818   }
01819   else if (TH1D *h = dynamic_cast<TH1D *>(obj))
01820   {
01821     MonitorElement *me = findObject(dir, h->GetName());
01822     if (! me)
01823       me = book1DD(dir, h->GetName(), (TH1D *) h->Clone());
01824     else if (overwrite)
01825       me->copyFrom(h);
01826     else if (isCollateME(me) || collateHistograms_)
01827       collate1DD(me, h);
01828     refcheck = me;
01829   }
01830   else if (TH2F *h = dynamic_cast<TH2F *>(obj))
01831   {
01832     MonitorElement *me = findObject(dir, h->GetName());
01833     if (! me)
01834       me = book2D(dir, h->GetName(), (TH2F *) h->Clone());
01835     else if (overwrite)
01836       me->copyFrom(h);
01837     else if (isCollateME(me) || collateHistograms_)
01838       collate2D(me, h);
01839     refcheck = me;
01840   }
01841   else if (TH2S *h = dynamic_cast<TH2S *>(obj))
01842   {
01843     MonitorElement *me = findObject(dir, h->GetName());
01844     if (! me)
01845       me = book2S(dir, h->GetName(), (TH2S *) h->Clone());
01846     else if (overwrite)
01847       me->copyFrom(h);
01848     else if (isCollateME(me) || collateHistograms_)
01849       collate2S(me, h);
01850     refcheck = me;
01851   }
01852   else if (TH2D *h = dynamic_cast<TH2D *>(obj))
01853   {
01854     MonitorElement *me = findObject(dir, h->GetName());
01855     if (! me)
01856       me = book2DD(dir, h->GetName(), (TH2D *) h->Clone());
01857     else if (overwrite)
01858       me->copyFrom(h);
01859     else if (isCollateME(me) || collateHistograms_)
01860       collate2DD(me, h);
01861     refcheck = me;
01862   }
01863   else if (TH3F *h = dynamic_cast<TH3F *>(obj))
01864   {
01865     MonitorElement *me = findObject(dir, h->GetName());
01866     if (! me)
01867       me = book3D(dir, h->GetName(), (TH3F *) h->Clone());
01868     else if (overwrite)
01869       me->copyFrom(h);
01870     else if (isCollateME(me) || collateHistograms_)
01871       collate3D(me, h);
01872     refcheck = me;
01873   }
01874   else if (dynamic_cast<TObjString *>(obj))
01875   {
01876     lat::RegexpMatch m;
01877     if (! s_rxmeval.match(obj->GetName(), 0, 0, &m))
01878     {
01879       if (strstr(obj->GetName(), "CMSSW"))
01880       {
01881         if (verbose_)
01882           std::cout << "Input file version: " << obj->GetName() << std::endl;
01883         return true;
01884       }
01885       else if (strstr(obj->GetName(), "DQMPATCH"))
01886       {
01887         if (verbose_)
01888           std::cout << "DQM patch version: " << obj->GetName() << std::endl;
01889         return true;
01890       }
01891       else
01892       {
01893         std::cout << "*** DQMStore: WARNING: cannot extract object '"
01894                   << obj->GetName() << "' of type '"
01895                   << obj->IsA()->GetName() << "'\n";
01896         return false;
01897       }
01898     }
01899 
01900     std::string label = m.matchString(obj->GetName(), 1);
01901     std::string kind = m.matchString(obj->GetName(), 2);
01902     std::string value = m.matchString(obj->GetName(), 3);
01903 
01904     if (kind == "i")
01905     {
01906       MonitorElement *me = findObject(dir, label);
01907       if (! me || overwrite)
01908       {
01909         if (! me) me = bookInt(dir, label);
01910         me->Fill(atoll(value.c_str()));
01911       }
01912     }
01913     else if (kind == "f")
01914     {
01915       MonitorElement *me = findObject(dir, label);
01916       if (! me || overwrite)
01917       {
01918         if (! me) me = bookFloat(dir, label);
01919         me->Fill(atof(value.c_str()));
01920       }
01921     }
01922     else if (kind == "s")
01923     {
01924       MonitorElement *me = findObject(dir, label);
01925       if (! me)
01926         me = bookString(dir, label, value);
01927       else if (overwrite)
01928         me->Fill(value);
01929     }
01930     else if (kind == "e")
01931     {
01932       MonitorElement *me = findObject(dir, label);
01933       if (! me)
01934       {
01935         std::cout << "*** DQMStore: WARNING: no monitor element '"
01936                   << label << "' in directory '"
01937                   << dir << "' to be marked as efficiency plot.\n";
01938         return false;
01939       }
01940       me->setEfficiencyFlag();
01941     }
01942     else if (kind == "t")
01943     {
01944       MonitorElement *me = findObject(dir, label);
01945       if (! me)
01946       {
01947         std::cout << "*** DQMStore: WARNING: no monitor element '"
01948                   << label << "' in directory '"
01949                   << dir << "' for a tag\n";
01950         return false;
01951       }
01952       errno = 0;
01953       char *endp = 0;
01954       unsigned long val = strtoul(value.c_str(), &endp, 10);
01955       if ((val == 0 && errno) || *endp || val > ~uint32_t(0))
01956       {
01957         std::cout << "*** DQMStore: WARNING: cannot restore tag '"
01958                   << value << "' for monitor element '"
01959                   << label << "' in directory '"
01960                   << dir << "' - invalid value\n";
01961         return false;
01962       }
01963       tag(me, val);
01964     }
01965     else if (kind == "qr")
01966     {
01967       // Handle qreports, but skip them while reading in references.
01968       if (! isSubdirectory(s_referenceDirName, dir))
01969       {
01970         size_t dot = label.find('.');
01971         if (dot == std::string::npos)
01972         {
01973           std::cout << "*** DQMStore: WARNING: quality report label in '" << label
01974                     << "' is missing a '.' and cannot be extracted\n";
01975           return false;
01976         }
01977 
01978         std::string mename (label, 0, dot);
01979         std::string qrname (label, dot+1, std::string::npos);
01980 
01981         m.reset();
01982         DQMNet::QValue qv;
01983         if (s_rxmeqr1.match(value, 0, 0, &m))
01984         {
01985           qv.code = atoi(m.matchString(value, 1).c_str());
01986           qv.qtresult = strtod(m.matchString(value, 2).c_str(), 0);
01987           qv.message = m.matchString(value, 4);
01988           qv.qtname = qrname;
01989           qv.algorithm = m.matchString(value, 3);
01990         }
01991         else if (s_rxmeqr2.match(value, 0, 0, &m))
01992         {
01993           qv.code = atoi(m.matchString(value, 1).c_str());
01994           qv.qtresult = 0; // unavailable in old format
01995           qv.message = m.matchString(value, 2);
01996           qv.qtname = qrname;
01997           // qv.algorithm unavailable in old format
01998         }
01999         else
02000         {
02001           std::cout << "*** DQMStore: WARNING: quality test value '"
02002                     << value << "' is incorrectly formatted\n";
02003           return false;
02004         }
02005 
02006         MonitorElement *me = findObject(dir, mename);
02007         if (! me)
02008         {
02009           std::cout << "*** DQMStore: WARNING: no monitor element '"
02010                     << mename << "' in directory '"
02011                     << dir << "' for quality test '"
02012                     << label << "'\n";
02013           return false;
02014         }
02015 
02016         me->addQReport(qv, /* FIXME: getQTest(qv.qtname)? */ 0);
02017       }
02018     }
02019     else
02020     {
02021       std::cout << "*** DQMStore: WARNING: cannot extract object '"
02022                 << obj->GetName() << "' of type '"
02023                 << obj->IsA()->GetName() << "'\n";
02024       return false;
02025     }
02026   }
02027   else if (TNamed *n = dynamic_cast<TNamed *>(obj))
02028   {
02029     // For old DQM data.
02030     std::string s;
02031     s.reserve(6 + strlen(n->GetTitle()) + 2*strlen(n->GetName()));
02032     s += '<'; s += n->GetName(); s += '>';
02033     s += n->GetTitle();
02034     s += '<'; s += '/'; s += n->GetName(); s += '>';
02035     TObjString os(s.c_str());
02036     return extract(&os, dir, overwrite);
02037   }
02038   else
02039   {
02040     std::cout << "*** DQMStore: WARNING: cannot extract object '"
02041               << obj->GetName() << "' of type '" << obj->IsA()->GetName()
02042               << "' and with title '" << obj->GetTitle() << "'\n";
02043     return false;
02044   }
02045 
02046   // If we just read in a reference monitor element, and there is a
02047   // monitor element with the same name, link the two together. The
02048   // other direction is handled by the initialise() method.
02049   if (refcheck && isSubdirectory(s_referenceDirName, dir))
02050   {
02051     std::string mdir(dir, s_referenceDirName.size()+1, std::string::npos);
02052     if (MonitorElement *master = findObject(mdir, obj->GetName()))
02053     {
02054       master->data_.flags |= DQMNet::DQM_PROP_HAS_REFERENCE;
02055       master->reference_ = refcheck->object_;
02056     }
02057   }
02058 
02059   return true;
02060 }
02061 
02065 bool
02066 DQMStore::cdInto(const std::string &path) const
02067 {
02068   assert(! path.empty());
02069 
02070   // Find the first path component.
02071   size_t start = 0;
02072   size_t end = path.find('/', start);
02073   if (end == std::string::npos)
02074     end = path.size();
02075 
02076   while (true)
02077   {
02078     // Check if this subdirectory component exists.  If yes, make sure
02079     // it is actually a subdirectory.  Otherwise create or cd into it.
02080     std::string part(path, start, end-start);
02081     TObject *o = gDirectory->Get(part.c_str());
02082     if (o && ! dynamic_cast<TDirectory *>(o))
02083       raiseDQMError("DQMStore", "Attempt to create directory '%s' in a file"
02084                     " fails because the part '%s' already exists and is not"
02085                     " directory", path.c_str(), part.c_str());
02086     else if (! o)
02087       gDirectory->mkdir(part.c_str());
02088 
02089     if (! gDirectory->cd(part.c_str()))
02090       raiseDQMError("DQMStore", "Attempt to create directory '%s' in a file"
02091                     " fails because could not cd into subdirectory '%s'",
02092                     path.c_str(), part.c_str());
02093 
02094     // Stop if we reached the end, ignoring any trailing '/'.
02095     if (end+1 >= path.size())
02096       break;
02097 
02098     // Find the next path component.
02099     start = end+1;
02100     end = path.find('/', start);
02101     if (end == std::string::npos)
02102       end = path.size();
02103   }
02104 
02105   return true;
02106 }
02107 
02112 void
02113 DQMStore::save(const std::string &filename,
02114                const std::string &path /* = "" */,
02115                const std::string &pattern /* = "" */,
02116                const std::string &rewrite /* = "" */,
02117                SaveReferenceTag ref /* = SaveWithReference */,
02118                int minStatus /* = dqm::qstatus::STATUS_OK */,
02119                const std::string &fileupdate /* = RECREATE */)
02120 {
02121   std::set<std::string>::iterator di, de;
02122   MEMap::iterator mi, me = data_.end();
02123   DQMNet::QReports::const_iterator qi, qe;
02124   int nme=0;
02125 
02126   // TFile flushes to disk with fsync() on every TDirectory written to the
02127   // file.  This makes DQM file saving painfully slow, and ironically makes
02128   // it _more_ likely the file saving gets interrupted and corrupts the file.
02129   // The utility class below simply ignores the flush synchronisation.
02130   class TFileNoSync : public TFile
02131   {
02132   public:
02133     TFileNoSync(const char *file, const char *opt) : TFile(file, opt) {}
02134     virtual Int_t SysSync(Int_t) { return 0; }
02135   };
02136 
02137   // open output file, on 1st save recreate, later update
02138   if (verbose_)
02139     std::cout << "\n DQMStore: Opening TFile '" << filename 
02140               << "' with option '" << fileupdate <<"'\n";
02141 
02142   TFileNoSync f(filename.c_str(), fileupdate.c_str()); // open file
02143   if(f.IsZombie())
02144     raiseDQMError("DQMStore", "Failed to create/update file '%s'", filename.c_str());
02145   f.cd();
02146   
02147   // Construct a regular expression from the pattern string.
02148   std::auto_ptr<lat::Regexp> rxpat;
02149   if (! pattern.empty())
02150     rxpat.reset(new lat::Regexp(pattern.c_str()));
02151 
02152   // Prepare a path for the reference object selection.
02153   std::string refpath;
02154   refpath.reserve(s_referenceDirName.size() + path.size() + 2);
02155   refpath += s_referenceDirName;
02156   if (! path.empty())
02157   {
02158     refpath += '/';
02159     refpath += path;
02160   }
02161 
02162   // Loop over the directory structure.
02163   for (di = dirs_.begin(), de = dirs_.end(); di != de; ++di)
02164   {
02165     // Check if we should process this directory.  We process the
02166     // requested part of the object tree, including references.
02167     if (! path.empty()
02168         && ! isSubdirectory(path, *di)
02169         && ! isSubdirectory(refpath, *di))
02170       continue;
02171     
02172     // Loop over monitor elements in this directory.
02173     MonitorElement proto(&*di, std::string());
02174     mi = data_.lower_bound(proto);
02175     for ( ; mi != me && isSubdirectory(*di, *mi->data_.dirname); ++mi)
02176     {
02177       // Skip if it isn't a direct child.
02178       if (*di != *mi->data_.dirname)
02179         continue;
02180 
02181       // Handle reference histograms, with three distinct cases:
02182       // 1) Skip all references entirely on saving.
02183       // 2) Blanket saving of all references.
02184       // 3) Save only references for monitor elements with qtests.
02185       // The latter two are affected by "path" sub-tree selection,
02186       // i.e. references are saved only in the selected tree part.
02187       if (isSubdirectory(refpath, *mi->data_.dirname))
02188       {
02189         if (ref == SaveWithoutReference)
02190           // Skip the reference entirely.
02191           continue;
02192         else if (ref == SaveWithReference)
02193           // Save all references regardless of qtests.
02194           ;
02195         else if (ref == SaveWithReferenceForQTest)
02196         {
02197           // Save only references for monitor elements with qtests
02198           // with an optional cut on minimum quality test result.
02199           int status = -1;
02200           std::string mname(mi->getFullname(), s_referenceDirName.size()+1, std::string::npos);
02201           MonitorElement *master = get(mname);
02202           if (master)
02203             for (size_t i = 0, e = master->data_.qreports.size(); i != e; ++i)
02204               status = std::max(status, master->data_.qreports[i].code);
02205 
02206           if (! master || status < minStatus)
02207           {
02208             if (verbose_ > 1)
02209               std::cout << "DQMStore::save: skipping monitor element '"
02210                         << mi->data_.objname << "' while saving, status is "
02211                         << status << ", required minimum status is "
02212                         << minStatus << std::endl;
02213             continue;
02214           }
02215         }
02216       }
02217 
02218       if (verbose_ > 1)
02219         std::cout << "DQMStore::save: saving monitor element '"
02220                   << mi->data_.objname << "'\n";
02221       nme++; // count saved histograms
02222 
02223       // Create the directory.
02224       gDirectory->cd("/");
02225       if (di->empty())
02226         cdInto(s_monitorDirName);
02227       else if (rxpat.get())
02228         cdInto(s_monitorDirName + '/' + lat::StringOps::replace(*di, *rxpat, rewrite));
02229       else
02230         cdInto(s_monitorDirName + '/' + *di);
02231 
02232       // Save the object.
02233       switch (mi->kind())
02234       {
02235       case MonitorElement::DQM_KIND_INT:
02236       case MonitorElement::DQM_KIND_REAL:
02237       case MonitorElement::DQM_KIND_STRING:
02238         TObjString(mi->tagString().c_str()).Write();
02239         break;
02240 
02241       default:
02242         mi->object_->Write();
02243         break;
02244       }
02245 
02246       // Save quality reports if this is not in reference section.
02247       if (! isSubdirectory(s_referenceDirName, *mi->data_.dirname))
02248       {
02249         qi = mi->data_.qreports.begin();
02250         qe = mi->data_.qreports.end();
02251         for ( ; qi != qe; ++qi)
02252           TObjString(mi->qualityTagString(*qi).c_str()).Write();
02253       }
02254 
02255       // Save efficiency tag, if any
02256       if (mi->data_.flags & DQMNet::DQM_PROP_EFFICIENCY_PLOT)
02257         TObjString(mi->effLabelString().c_str()).Write();
02258 
02259       // Save tag if any
02260       if (mi->data_.flags & DQMNet::DQM_PROP_TAGGED)
02261         TObjString(mi->tagLabelString().c_str()).Write();
02262     }
02263   }
02264 
02265   f.Close();
02266 
02267   // Maybe make some noise.
02268   if (verbose_)
02269     std::cout << "DQMStore::save: successfully wrote " << nme 
02270               << " objects from path '" << path  
02271               << "' into DQM file '" << filename << "'\n";
02272 }
02273 
02276 unsigned int
02277 DQMStore::readDirectory(TFile *file,
02278                         bool overwrite,
02279                         const std::string &onlypath,
02280                         const std::string &prepend,
02281                         const std::string &curdir,
02282                         OpenRunDirs stripdirs)
02283 {
02284   unsigned int ntot = 0;
02285   unsigned int count = 0;
02286 
02287   if (! file->cd(curdir.c_str()))
02288     raiseDQMError("DQMStore", "Failed to process directory '%s' while"
02289                   " reading file '%s'", curdir.c_str(), file->GetName());
02290 
02291   // Figure out current directory name, but strip out the top
02292   // directory into which we dump everything.
02293   std::string dirpart = curdir;
02294   if (dirpart.compare(0, s_monitorDirName.size(), s_monitorDirName) == 0)
02295   {
02296     if (dirpart.size() == s_monitorDirName.size())
02297       dirpart.clear();
02298     else if (dirpart[s_monitorDirName.size()] == '/')
02299       dirpart.erase(0, s_monitorDirName.size()+1);
02300   }
02301 
02302   // See if we are going to skip this directory.
02303   bool skip = (! onlypath.empty() && ! isSubdirectory(onlypath, dirpart));
02304   
02305   if (prepend == s_collateDirName || 
02306       prepend == s_referenceDirName || 
02307       stripdirs == StripRunDirs )
02308   {
02309     // Remove Run # and RunSummary dirs
02310     // first look for Run summary, 
02311     // if that is found and erased, also erase Run dir
02312     size_t slash = dirpart.find('/');
02313     size_t pos = dirpart.find("/Run summary");
02314     if (slash != std::string::npos && pos !=std::string::npos) 
02315     {
02316       dirpart.erase(pos,12);
02317     
02318       pos = dirpart.find("Run ");
02319       size_t length = dirpart.find('/',pos+1)-pos+1;
02320       if (pos !=std::string::npos) 
02321         dirpart.erase(pos,length);
02322     }
02323   } 
02324 
02325   // If we are prepending, add it to the directory name, 
02326   // and suppress reading of already existing reference histograms
02327   if (prepend == s_collateDirName || 
02328       prepend == s_referenceDirName)
02329   {
02330     size_t slash = dirpart.find('/');
02331     // If we are reading reference, skip previous reference.
02332     if (slash == std::string::npos   // skip if Reference is toplevel folder, i.e. no slash
02333         && slash+1+s_referenceDirName.size() == dirpart.size()
02334         && dirpart.compare(slash+1, s_referenceDirName.size(), s_referenceDirName) == 0)
02335       return 0;
02336 
02337     slash = dirpart.find('/');    
02338     // Skip reading of EventInfo subdirectory.
02339     if (slash != std::string::npos
02340         && slash + 10 == dirpart.size()
02341         && dirpart.compare( slash+1 , 9 , "EventInfo") == 0) {
02342       if (verbose_)
02343         std::cout << "DQMStore::readDirectory: skipping '" << dirpart << "'\n";
02344       return 0;
02345     }
02346 
02347     // Add prefix.
02348     if (dirpart.empty())
02349       dirpart = prepend;
02350     else
02351       dirpart = prepend + '/' + dirpart;
02352   }
02353   else if (! prepend.empty())
02354   {
02355     if (dirpart.empty())
02356       dirpart = prepend;
02357     else
02358       dirpart = prepend + '/' + dirpart;
02359   }
02360 
02361   // Loop over the contents of this directory in the file.
02362   // Post-pone string object handling to happen after other
02363   // objects have been read in so we are guaranteed to have
02364   // histograms by the time we read in quality tests and tags.
02365   TKey *key;
02366   TIter next (gDirectory->GetListOfKeys());
02367   std::list<TObject *> delayed;
02368   while ((key = (TKey *) next()))
02369   {
02370     std::auto_ptr<TObject> obj(key->ReadObj());
02371     if (dynamic_cast<TDirectory *>(obj.get()))
02372     {
02373       std::string subdir;
02374       subdir.reserve(curdir.size() + strlen(obj->GetName()) + 2);
02375       subdir += curdir;
02376       if (! curdir.empty())
02377         subdir += '/';
02378       subdir += obj->GetName();
02379 
02380       ntot += readDirectory(file, overwrite, onlypath, prepend, subdir, stripdirs);
02381     }
02382     else if (skip)
02383       ;
02384     else if (dynamic_cast<TObjString *>(obj.get()))
02385     {
02386       delayed.push_back(obj.release());
02387     }
02388     else
02389     {
02390       if (verbose_ > 2)
02391         std::cout << "DQMStore: reading object '" << obj->GetName()
02392                   << "' of type '" << obj->IsA()->GetName()
02393                   << "' from '" << file->GetName()
02394                   << "' into '" << dirpart << "'\n";
02395 
02396       makeDirectory(dirpart);
02397       if (extract(obj.get(), dirpart, overwrite))
02398         ++count;
02399     }
02400   }
02401 
02402   while (! delayed.empty())
02403   {
02404     if (verbose_ > 2)
02405       std::cout << "DQMStore: reading object '" << delayed.front()->GetName()
02406                 << "' of type '" << delayed.front()->IsA()->GetName()
02407                 << "' from '" << file->GetName()
02408                 << "' into '" << dirpart << "'\n";
02409 
02410     makeDirectory(dirpart);
02411     if (extract(delayed.front(), dirpart, overwrite))
02412       ++count;
02413 
02414     delete delayed.front();
02415     delayed.pop_front();
02416   }
02417 
02418   if (verbose_ > 1)
02419     std::cout << "DQMStore: read " << count << '/' << ntot
02420               << " objects from directory '" << dirpart << "'\n";
02421 
02422   return ntot + count;
02423 }
02424 
02431 bool
02432 DQMStore::open(const std::string &filename,
02433                bool overwrite /* = false */,
02434                const std::string &onlypath /* ="" */,
02435                const std::string &prepend /* ="" */, 
02436                OpenRunDirs stripdirs /* =KeepRunDirs */, 
02437                bool fileMustExist /* =true */)
02438 {
02439   return readFile(filename,overwrite,onlypath,prepend,stripdirs,fileMustExist);
02440 }
02441 
02446 bool 
02447 DQMStore::load(const std::string &filename,
02448                OpenRunDirs stripdirs /* =StripRunDirs */, 
02449                bool fileMustExist /* =true */)
02450 {
02451   bool overwrite = true;
02452   if (collateHistograms_) overwrite = false;
02453   if (verbose_) 
02454   {
02455     std::cout << "DQMStore::load: reading from file '" << filename << "'\n";
02456     if (collateHistograms_)
02457       std::cout << "DQMStore::load: in collate mode   " << "\n";
02458     else
02459       std::cout << "DQMStore::load: in overwrite mode   " << "\n";
02460   }
02461     
02462   return readFile(filename,overwrite,"","",stripdirs,fileMustExist);
02463      
02464 }
02465 
02471 bool
02472 DQMStore::readFile(const std::string &filename,
02473                    bool overwrite /* = false */,
02474                    const std::string &onlypath /* ="" */,
02475                    const std::string &prepend /* ="" */,
02476                    OpenRunDirs stripdirs /* =StripRunDirs */,
02477                    bool fileMustExist /* =true */)
02478 {
02479   
02480   if (verbose_)
02481     std::cout << "DQMStore::readFile: reading from file '" << filename << "'\n";
02482 
02483   std::auto_ptr<TFile> f;
02484 
02485   try 
02486   {
02487     f.reset(TFile::Open(filename.c_str()));
02488     if (! f.get() || f->IsZombie())
02489       raiseDQMError("DQMStore", "Failed to open file '%s'", filename.c_str());
02490   }
02491   catch (std::exception &)
02492   {
02493     if (fileMustExist)
02494       throw;
02495     else
02496     {  
02497     if (verbose_)
02498       std::cout << "DQMStore::readFile: file '" << filename << "' does not exist, continuing\n";
02499     return false;
02500     }
02501   }
02502 
02503   unsigned n = readDirectory(f.get(), overwrite, onlypath, prepend, "", stripdirs);
02504   f->Close();
02505 
02506   MEMap::iterator mi = data_.begin();
02507   MEMap::iterator me = data_.end();
02508   for ( ; mi != me; ++mi)
02509     const_cast<MonitorElement &>(*mi).updateQReportStats();
02510 
02511   if (verbose_)
02512   {
02513     std::cout << "DQMStore::open: successfully read " << n
02514               << " objects from file '" << filename << "'";
02515     if (! onlypath.empty())
02516       std::cout << " from directory '" << onlypath << "'";
02517     if (! prepend.empty())
02518       std::cout << " into directory '" << prepend << "'";
02519     std::cout << std::endl;
02520   }
02521   return true;
02522 }
02523 
02529 void
02530 DQMStore::rmdir(const std::string &path)
02531 {
02532   std::string clean;
02533   const std::string *cleaned = 0;
02534   cleanTrailingSlashes(path, clean, cleaned);
02535   MonitorElement proto(cleaned, std::string());
02536 
02537   MEMap::iterator e = data_.end();
02538   MEMap::iterator i = data_.lower_bound(proto);
02539   while (i != e && isSubdirectory(*cleaned, *i->data_.dirname))
02540     data_.erase(i++);
02541 
02542   std::set<std::string>::iterator de = dirs_.end();
02543   std::set<std::string>::iterator di = dirs_.lower_bound(*cleaned);
02544   while (di != de && isSubdirectory(*cleaned, *di))
02545     dirs_.erase(di++);
02546 }
02547 
02549 void
02550 DQMStore::removeContents(const std::string &dir)
02551 {
02552   MonitorElement proto(&dir, std::string());
02553   MEMap::iterator e = data_.end();
02554   MEMap::iterator i = data_.lower_bound(proto);
02555   while (i != e && isSubdirectory(dir, *i->data_.dirname))
02556     if (dir == *i->data_.dirname)
02557       data_.erase(i++);
02558     else
02559       ++i;
02560 }
02561 
02563 void
02564 DQMStore::removeContents(void)
02565 {
02566   removeContents(pwd_);
02567 }
02568 
02571 void
02572 DQMStore::removeElement(const std::string &name)
02573 {
02574   removeElement(pwd_, name);
02575 }
02576 
02579 void
02580 DQMStore::removeElement(const std::string &dir, const std::string &name, bool warning /* = true */)
02581 {
02582   MonitorElement proto(&dir, name);
02583   MEMap::iterator pos = data_.find(proto);
02584   if (pos == data_.end() && warning)
02585     std::cout << "DQMStore: WARNING: attempt to remove non-existent"
02586               << " monitor element '" << name << "' in '" << dir << "'\n";
02587   else
02588     data_.erase(pos);
02589 }
02590 
02596 QCriterion *
02597 DQMStore::getQCriterion(const std::string &qtname) const
02598 {
02599   QCMap::const_iterator i = qtests_.find(qtname);
02600   QCMap::const_iterator e = qtests_.end();
02601   return (i == e ? 0 : i->second);
02602 }
02603 
02607 QCriterion *
02608 DQMStore::createQTest(const std::string &algoname, const std::string &qtname)
02609 {
02610   if (qtests_.count(qtname))
02611     raiseDQMError("DQMStore", "Attempt to create duplicate quality test '%s'",
02612                   qtname.c_str());
02613 
02614   QAMap::iterator i = qalgos_.find(algoname);
02615   if (i == qalgos_.end())
02616     raiseDQMError("DQMStore", "Cannot create a quality test using unknown"
02617                   " algorithm '%s'", algoname.c_str());
02618 
02619   QCriterion *qc = i->second(qtname);
02620   qc->setVerbose(verboseQT_);
02621 
02622   qtests_[qtname] = qc;
02623   return qc;
02624 }
02625 
02628 void
02629 DQMStore::useQTest(const std::string &dir, const std::string &qtname)
02630 {
02631   // Clean the path
02632   std::string clean;
02633   const std::string *cleaned = 0;
02634   cleanTrailingSlashes(dir, clean, cleaned);
02635 
02636   // Validate the path.
02637   if (cleaned->find_first_not_of(s_safe) != std::string::npos)
02638     raiseDQMError("DQMStore", "Monitor element path name '%s'"
02639                   " uses unacceptable characters", cleaned->c_str());
02640 
02641   // Redirect to the pattern match version.
02642   useQTestByMatch(*cleaned + "/*", qtname);
02643 }
02644 
02646 int 
02647 DQMStore::useQTestByMatch(const std::string &pattern, const std::string &qtname)
02648 {
02649   QCriterion *qc = getQCriterion(qtname);
02650   if (! qc)
02651     raiseDQMError("DQMStore", "Cannot apply non-existent quality test '%s'",
02652                   qtname.c_str());
02653 
02654   fastmatch * fm = new fastmatch( pattern );
02655 
02656   // Record the test for future reference.
02657   QTestSpec qts(fm, qc);
02658   qtestspecs_.push_back(qts);
02659 
02660   // Apply the quality test.
02661   MEMap::iterator mi = data_.begin();
02662   MEMap::iterator me = data_.end();
02663   std::string path;
02664   int cases = 0;
02665   for ( ; mi != me; ++mi)
02666   {
02667     path.clear();
02668     mergePath(path, *mi->data_.dirname, mi->data_.objname);
02669     if (fm->match(path))
02670     {
02671       ++cases;
02672       const_cast<MonitorElement &>(*mi).addQReport(qts.second);
02673     }
02674   }
02675 
02676   //return the number of matched cases
02677   return cases;
02678 }
02681 void
02682 DQMStore::runQTests(void)
02683 {
02684 
02685   if (verbose_ > 0)
02686     std::cout << "DQMStore: running runQTests() with reset = "
02687               << ( reset_ ? "true" : "false" ) << std::endl;
02688 
02689   // Apply quality tests to each monitor element, skipping references.
02690   MEMap::iterator mi = data_.begin();
02691   MEMap::iterator me = data_.end();
02692   for ( ; mi != me; ++mi)
02693     if (! isSubdirectory(s_referenceDirName, *mi->data_.dirname))
02694       const_cast<MonitorElement &>(*mi).runQTests();
02695 
02696   reset_ = false;
02697 }
02698 
02702 int
02703 DQMStore::getStatus(const std::string &path /* = "" */) const
02704 {
02705   std::string clean;
02706   const std::string *cleaned = 0;
02707   cleanTrailingSlashes(path, clean, cleaned);
02708 
02709   int status = dqm::qstatus::STATUS_OK;
02710   MEMap::const_iterator mi = data_.begin();
02711   MEMap::const_iterator me = data_.end();
02712   for ( ; mi != me; ++mi)
02713   {
02714     if (! cleaned->empty() && ! isSubdirectory(*cleaned, *mi->data_.dirname))
02715       continue;
02716 
02717     if (mi->hasError())
02718       return dqm::qstatus::ERROR;
02719     else if (mi->hasWarning())
02720       status = dqm::qstatus::WARNING;
02721     else if (status < dqm::qstatus::WARNING
02722              && mi->hasOtherReport())
02723       status = dqm::qstatus::OTHER;
02724   }
02725   return status;
02726 }
02727 
02733 void
02734 DQMStore::softReset(MonitorElement *me)
02735 {
02736   if (me)
02737     me->softReset();
02738 }
02739 
02740 // reverts action of softReset
02741 void
02742 DQMStore::disableSoftReset(MonitorElement *me)
02743 {
02744   if (me)
02745     me->disableSoftReset();
02746 }
02747 
02750 void
02751 DQMStore::setAccumulate(MonitorElement *me, bool flag)
02752 {
02753   if (me)
02754     me->setAccumulate(flag);
02755 }
02756 
02760 void
02761 DQMStore::showDirStructure(void) const
02762 {
02763   std::vector<std::string> contents;
02764   getContents(contents);
02765 
02766   std::cout << " ------------------------------------------------------------\n"
02767             << "                    Directory structure:                     \n"
02768             << " ------------------------------------------------------------\n";
02769 
02770   std::copy(contents.begin(), contents.end(),
02771             std::ostream_iterator<std::string>(std::cout, "\n"));
02772 
02773   std::cout << " ------------------------------------------------------------\n";
02774 }
02775 
02779 // check if the monitor element is in auto-collation folder
02780 bool
02781 DQMStore::isCollateME(MonitorElement *me) const
02782 { return me && isSubdirectory(s_collateDirName, *me->data_.dirname); }