CMS 3D CMS Logo

/afs/cern.ch/work/a/aaltunda/public/www/CMSSW_6_2_5/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   std::cout << __LINE__ << " DQMStore::DQMStore " << std::endl;
00272 }
00273 
00274 DQMStore::DQMStore(const edm::ParameterSet &pset)
00275   : verbose_ (1),
00276     verboseQT_ (1),
00277     reset_ (false),
00278     collateHistograms_ (false),
00279     readSelectedDirectory_ (""),
00280     pwd_ ("")
00281 {
00282   initializeFrom(pset);
00283 }
00284 
00285 DQMStore::~DQMStore(void)
00286 {
00287   for (QCMap::iterator i = qtests_.begin(), e = qtests_.end(); i != e; ++i)
00288     delete i->second;
00289 
00290   for (QTestSpecs::iterator i = qtestspecs_.begin(), e = qtestspecs_.end(); i != e; ++i)
00291     delete i->first;
00292 
00293 }
00294 
00295 void
00296 DQMStore::initializeFrom(const edm::ParameterSet& pset) {
00297   makeDirectory("");
00298   reset();
00299 
00300   // set steerable parameters
00301   verbose_ = pset.getUntrackedParameter<int>("verbose", 0);
00302   if (verbose_ > 0)
00303     std::cout << "DQMStore: verbosity set to " << verbose_ << std::endl;
00304   
00305   verboseQT_ = pset.getUntrackedParameter<int>("verboseQT", 0);
00306   if (verbose_ > 0)
00307     std::cout << "DQMStore: QTest verbosity set to " << verboseQT_ << std::endl;
00308   
00309   collateHistograms_ = pset.getUntrackedParameter<bool>("collateHistograms", false);
00310   if (collateHistograms_)
00311     std::cout << "DQMStore: histogram collation is enabled\n";
00312 
00313   std::string ref = pset.getUntrackedParameter<std::string>("referenceFileName", "");
00314   if (! ref.empty())
00315   {
00316     std::cout << "DQMStore: using reference file '" << ref << "'\n";
00317     readFile(ref, true, "", s_referenceDirName, StripRunDirs, false);
00318   }  
00319 
00320   initQCriterion<Comp2RefChi2>(qalgos_);
00321   initQCriterion<Comp2RefKolmogorov>(qalgos_);
00322   initQCriterion<ContentsXRange>(qalgos_);
00323   initQCriterion<ContentsYRange>(qalgos_);
00324   initQCriterion<MeanWithinExpected>(qalgos_);
00325   initQCriterion<Comp2RefEqualH>(qalgos_);
00326   initQCriterion<DeadChannel>(qalgos_);
00327   initQCriterion<NoisyChannel>(qalgos_);
00328   initQCriterion<ContentsWithinExpected>(qalgos_);
00329   initQCriterion<CompareToMedian>(qalgos_);
00330   initQCriterion<CompareLastFilledBin>(qalgos_);
00331 
00332   scaleFlag_ = pset.getUntrackedParameter<double>("ScalingFlag", 0.0);
00333   if (verbose_ > 0)
00334     std::cout << "DQMStore: Scaling Flag set to " << scaleFlag_ << std::endl;
00335 }
00336 
00337 /* Generic method to do a backtrace and print it to stdout. It is
00338  customised to properly get the routine that called the booking of the
00339  histograms, which, following the usual stack, is at position 4. The
00340  name of the calling function is properly demangled and the original
00341  shared library including this function is also printed. For a more
00342  detailed explanation of the routines involved, see here:
00343  http://www.gnu.org/software/libc/manual/html_node/Backtraces.html
00344  http://gcc.gnu.org/onlinedocs/libstdc++/manual/ext_demangling.html.*/
00345 
00346 void
00347 DQMStore::print_trace (const std::string &dir, const std::string &name)
00348 {
00349   static std::ofstream stream("histogramBookingBT.log");
00350   void *array[10];
00351   size_t size;
00352   char **strings;
00353   int r=0;
00354   lat::RegexpMatch m;
00355   m.reset();
00356 
00357   size = backtrace (array, 10);
00358   strings = backtrace_symbols (array, size);
00359 
00360   if ((size > 4)
00361       &&s_rxtrace.match(strings[4], 0, 0, &m))
00362   {
00363     char * demangled = abi::__cxa_demangle(m.matchString(strings[4], 2).c_str(), 0, 0, &r);
00364     stream << "\"" << dir << "/"
00365            << name << "\" "
00366            << (r ? m.matchString(strings[4], 2) : demangled) << " "
00367            << m.matchString(strings[4], 1) << "\n";
00368     free(demangled);
00369   }
00370   else
00371     stream << "Skipping "<< dir << "/" << name
00372            << " with stack size " << size << "\n";
00373   /* In this case print the full stack trace, up to main or to the
00374    * maximum stack size, i.e. 10. */
00375   if (verbose_ > 4)
00376   {
00377     size_t i;
00378     m.reset();
00379 
00380     for (i = 0; i < size; i++)
00381       if (s_rxtrace.match(strings[i], 0, 0, &m))
00382       {
00383         char * demangled = abi::__cxa_demangle(m.matchString(strings[i], 2).c_str(), 0, 0, &r);
00384         stream << "\t\t" << i << "/" << size << " "
00385                << (r ? m.matchString(strings[i], 2) : demangled) << " "
00386                << m.matchString(strings[i], 1) << std::endl;
00387         free (demangled);
00388       }
00389   }
00390   free (strings);
00391 }
00392 
00397 void
00398 DQMStore::setVerbose(unsigned /* level */)
00399 { return; }
00400 
00405 const std::string &
00406 DQMStore::pwd(void) const
00407 { return pwd_; }
00408 
00410 void
00411 DQMStore::cd(void)
00412 { setCurrentFolder(""); }
00413 
00415 void
00416 DQMStore::cd(const std::string &subdir)
00417 {
00418   std::string clean;
00419   const std::string *cleaned = 0;
00420   cleanTrailingSlashes(subdir, clean, cleaned);
00421 
00422   if (! dirExists(*cleaned))
00423     raiseDQMError("DQMStore", "Cannot 'cd' into non-existent directory '%s'",
00424                   cleaned->c_str());
00425   
00426   setCurrentFolder(*cleaned);
00427 }
00428 
00433 void
00434 DQMStore::setCurrentFolder(const std::string &fullpath)
00435 {
00436   std::string clean;
00437   const std::string *cleaned = 0;
00438   cleanTrailingSlashes(fullpath, clean, cleaned);
00439   makeDirectory(*cleaned);
00440   pwd_ = *cleaned;
00441 }
00442 
00444 void
00445 DQMStore::goUp(void)
00446 {
00447   size_t pos = pwd_.rfind('/');
00448   if (pos == std::string::npos)
00449     setCurrentFolder("");
00450   else
00451     setCurrentFolder(pwd_.substr(0, pos));
00452 }
00453 
00454 // -------------------------------------------------------------------
00456 void
00457 DQMStore::makeDirectory(const std::string &path)
00458 {
00459   std::string prev;
00460   std::string subdir;
00461   std::string name;
00462   prev.reserve(path.size());
00463   subdir.reserve(path.size());
00464   name.reserve(path.size());
00465   size_t prevname = 0;
00466   size_t slash = 0;
00467 
00468   while (true)
00469   {
00470     // Create this subdirectory component.
00471     subdir.clear();
00472     subdir.append(path, 0, slash);
00473     name.clear();
00474     name.append(subdir, prevname, std::string::npos);
00475     if (! prev.empty() && findObject(prev, name))
00476       raiseDQMError("DQMStore", "Attempt to create subdirectory '%s'"
00477                     " which already exists as a monitor element",
00478                     subdir.c_str());
00479 
00480     if (! dirs_.count(subdir))
00481       dirs_.insert(subdir);
00482 
00483     // Stop if we've reached the end (including possibly a trailing slash).
00484     if (slash+1 >= path.size())
00485       break;
00486 
00487     // Find the next slash, making sure we progress.  If reach the end,
00488     // process the last path component; the next loop round will terminate.
00489     prevname = slash ? slash+1 : slash;
00490     prev = subdir;
00491     if ((slash = path.find('/', ++slash)) == std::string::npos)
00492       slash = path.size();
00493   }
00494 }
00495 
00497 bool
00498 DQMStore::dirExists(const std::string &path) const
00499 { return dirs_.count(path) > 0; }
00500 
00504 template <class HISTO, class COLLATE>
00505 MonitorElement *
00506 DQMStore::book(const std::string &dir, const std::string &name,
00507                const char *context, int kind,
00508                HISTO *h, COLLATE collate)
00509 {
00510   assert(name.find('/') == std::string::npos);
00511   if (verbose_ > 3)
00512     print_trace(dir, name);
00513   std::string path;
00514   mergePath(path, dir, name);
00515 
00516   // Put us in charge of h.
00517   h->SetDirectory(0);
00518 
00519   // Check if the request monitor element already exists.
00520   MonitorElement *me = findObject(dir, name);
00521   if (me)
00522   {
00523     if (collateHistograms_)
00524     {
00525       collate(me, h);
00526       delete h;
00527       return me;
00528     }
00529     else
00530     {    
00531       if (verbose_ > 1)
00532         std::cout << "DQMStore: "
00533                   << context << ": monitor element '"
00534                   << path << "' already exists, collating" << std::endl;
00535       me->Reset();
00536       collate(me, h);
00537       delete h;
00538       return me;
00539     }
00540   }
00541   else
00542   {
00543     // Create and initialise core object.
00544     assert(dirs_.count(dir));
00545     MonitorElement proto(&*dirs_.find(dir), name);
00546     me = const_cast<MonitorElement &>(*data_.insert(proto).first)
00547       .initialise((MonitorElement::Kind)kind, h);
00548 
00549     // Initialise quality test information.
00550     QTestSpecs::iterator qi = qtestspecs_.begin();
00551     QTestSpecs::iterator qe = qtestspecs_.end();
00552     for ( ; qi != qe; ++qi)
00553     {
00554         if ( qi->first->match(path) )
00555                 me->addQReport(qi->second);
00556     }
00557 
00558     // Assign reference if we have one.
00559     std::string refdir;
00560     refdir.reserve(s_referenceDirName.size() + dir.size() + 2);
00561     refdir += s_referenceDirName;
00562     refdir += '/';
00563     refdir += dir;
00564 
00565     if (MonitorElement *refme = findObject(refdir, name))
00566     {
00567       me->data_.flags |= DQMNet::DQM_PROP_HAS_REFERENCE;
00568       me->reference_ = refme->object_;
00569     }
00570 
00571     // Return the monitor element.
00572     return me;
00573   }
00574 }
00575 
00576 MonitorElement *
00577 DQMStore::book(const std::string &dir,
00578                const std::string &name,
00579                const char *context)
00580 {
00581   assert(name.find('/') == std::string::npos);
00582   if (verbose_ > 3)
00583     print_trace(dir, name);
00584 
00585   // Check if the request monitor element already exists.
00586   if (MonitorElement *me = findObject(dir, name))
00587   {
00588     if (verbose_ > 1)
00589     {
00590       std::string path;
00591       mergePath(path, dir, name);
00592 
00593       std::cout << "DQMStore: "
00594                 << context << ": monitor element '"
00595                 << path << "' already exists, resetting" << std::endl;
00596     }
00597     me->Reset();
00598     return me;
00599   }
00600   else
00601   {
00602     // Create it and return for initialisation.
00603     assert(dirs_.count(dir));
00604     MonitorElement nme(&*dirs_.find(dir), name);
00605     return &const_cast<MonitorElement &>(*data_.insert(nme).first);
00606   }
00607 }
00608 
00609 // -------------------------------------------------------------------
00611 MonitorElement *
00612 DQMStore::bookInt(const std::string &dir, const std::string &name)
00613 {
00614   if (collateHistograms_)
00615   {
00616     if (MonitorElement *me = findObject(dir, name))
00617     {
00618       me->Fill(0);
00619       return me;
00620     }
00621   }
00622 
00623   return book(dir, name, "bookInt")
00624     ->initialise(MonitorElement::DQM_KIND_INT);
00625 }
00626 
00628 MonitorElement *
00629 DQMStore::bookInt(const char *name)
00630 { return bookInt(pwd_, name); }
00631 
00633 MonitorElement *
00634 DQMStore::bookInt(const std::string &name)
00635 {
00636   return bookInt(pwd_, name);
00637 }
00638 
00639 // -------------------------------------------------------------------
00641 MonitorElement *
00642 DQMStore::bookFloat(const std::string &dir, const std::string &name)
00643 {
00644   if (collateHistograms_)
00645   {
00646     if (MonitorElement *me = findObject(dir, name))
00647     {
00648       me->Fill(0.);
00649       return me;
00650     }
00651   }
00652 
00653   return book(dir, name, "bookFloat")
00654     ->initialise(MonitorElement::DQM_KIND_REAL);
00655 }
00656 
00658 MonitorElement *
00659 DQMStore::bookFloat(const char *name)
00660 { return bookFloat(pwd_, name); }
00661 
00663 MonitorElement *
00664 DQMStore::bookFloat(const std::string &name)
00665 {
00666   return bookFloat(pwd_, name);
00667 }
00668 
00669 // -------------------------------------------------------------------
00671 MonitorElement *
00672 DQMStore::bookString(const std::string &dir,
00673                      const std::string &name,
00674                      const std::string &value)
00675 {
00676   if (collateHistograms_)
00677   {
00678     if (MonitorElement *me = findObject(dir, name))
00679       return me;
00680   }
00681 
00682   return book(dir, name, "bookString")
00683     ->initialise(MonitorElement::DQM_KIND_STRING, value);
00684 }
00685 
00687 MonitorElement *
00688 DQMStore::bookString(const char *name, const char *value)
00689 { return bookString(pwd_, name, value); }
00690 
00692 MonitorElement *
00693 DQMStore::bookString(const std::string &name, const std::string &value)
00694 {
00695   return bookString(pwd_, name, value);
00696 }
00697 
00698 // -------------------------------------------------------------------
00700 MonitorElement *
00701 DQMStore::book1D(const std::string &dir, const std::string &name, TH1F *h)
00702 {
00703   return book(dir, name, "book1D", MonitorElement::DQM_KIND_TH1F, h, collate1D);
00704 }
00705 
00707 MonitorElement *
00708 DQMStore::book1S(const std::string &dir, const std::string &name, TH1S *h)
00709 {
00710   return book(dir, name, "book1S", MonitorElement::DQM_KIND_TH1S, h, collate1S);
00711 }
00712 
00714 MonitorElement *
00715 DQMStore::book1DD(const std::string &dir, const std::string &name, TH1D *h)
00716 {
00717   return book(dir, name, "book1DD", MonitorElement::DQM_KIND_TH1D, h, collate1DD);
00718 }
00719 
00721 MonitorElement *
00722 DQMStore::book1D(const char *name, const char *title,
00723                  int nchX, double lowX, double highX)
00724 {
00725   return book1D(pwd_, name, new TH1F(name, title, nchX, lowX, highX));
00726 }
00727 
00729 MonitorElement *
00730 DQMStore::book1D(const std::string &name, const std::string &title,
00731                  int nchX, double lowX, double highX)
00732 {
00733   return book1D(pwd_, name, new TH1F(name.c_str(), title.c_str(), nchX, lowX, highX));
00734 }
00735 
00737 MonitorElement *
00738 DQMStore::book1S(const char *name, const char *title,
00739                  int nchX, double lowX, double highX)
00740 {
00741   return book1S(pwd_, name, new TH1S(name, title, nchX, lowX, highX));
00742 }
00743 
00745 MonitorElement *
00746 DQMStore::book1S(const std::string &name, const std::string &title,
00747                  int nchX, double lowX, double highX)
00748 {
00749   return book1S(pwd_, name, new TH1S(name.c_str(), title.c_str(), nchX, lowX, highX));
00750 }
00751 
00753 MonitorElement *
00754 DQMStore::book1DD(const char *name, const char *title,
00755                   int nchX, double lowX, double highX)
00756 {
00757   return book1DD(pwd_, name, new TH1D(name, title, nchX, lowX, highX));
00758 }
00759 
00761 MonitorElement *
00762 DQMStore::book1DD(const std::string &name, const std::string &title,
00763                   int nchX, double lowX, double highX)
00764 {
00765   return book1DD(pwd_, name, new TH1D(name.c_str(), title.c_str(), nchX, lowX, highX));
00766 }
00767 
00769 MonitorElement *
00770 DQMStore::book1D(const char *name, const char *title,
00771                  int nchX, float *xbinsize)
00772 {
00773   return book1D(pwd_, name, new TH1F(name, title, nchX, xbinsize));
00774 }
00775 
00777 MonitorElement *
00778 DQMStore::book1D(const std::string &name, const std::string &title,
00779                  int nchX, float *xbinsize)
00780 {
00781   return book1D(pwd_, name, new TH1F(name.c_str(), title.c_str(), nchX, xbinsize));
00782 }
00783 
00785 MonitorElement *
00786 DQMStore::book1D(const char *name, TH1F *source)
00787 {
00788   return book1D(pwd_, name, static_cast<TH1F *>(source->Clone(name)));
00789 }
00790 
00792 MonitorElement *
00793 DQMStore::book1D(const std::string &name, TH1F *source)
00794 {
00795   return book1D(pwd_, name, static_cast<TH1F *>(source->Clone(name.c_str())));
00796 }
00797 
00799 MonitorElement *
00800 DQMStore::book1S(const char *name, TH1S *source)
00801 {
00802   return book1S(pwd_, name, static_cast<TH1S *>(source->Clone(name)));
00803 }
00804 
00806 MonitorElement *
00807 DQMStore::book1S(const std::string &name, TH1S *source)
00808 {
00809   return book1S(pwd_, name, static_cast<TH1S *>(source->Clone(name.c_str())));
00810 }
00811 
00813 MonitorElement *
00814 DQMStore::book1DD(const char *name, TH1D *source)
00815 {
00816   return book1DD(pwd_, name, static_cast<TH1D *>(source->Clone(name)));
00817 }
00818 
00820 MonitorElement *
00821 DQMStore::book1DD(const std::string &name, TH1D *source)
00822 {
00823   return book1DD(pwd_, name, static_cast<TH1D *>(source->Clone(name.c_str())));
00824 }
00825 
00826 // -------------------------------------------------------------------
00828 MonitorElement *
00829 DQMStore::book2D(const std::string &dir, const std::string &name, TH2F *h)
00830 {
00831   return book(dir, name, "book2D", MonitorElement::DQM_KIND_TH2F, h, collate2D);
00832 }
00833 
00835 MonitorElement *
00836 DQMStore::book2S(const std::string &dir, const std::string &name, TH2S *h)
00837 {
00838   return book(dir, name, "book2S", MonitorElement::DQM_KIND_TH2S, h, collate2S);
00839 }
00840 
00842 MonitorElement *
00843 DQMStore::book2DD(const std::string &dir, const std::string &name, TH2D *h)
00844 {
00845   return book(dir, name, "book2DD", MonitorElement::DQM_KIND_TH2D, h, collate2DD);
00846 }
00847 
00849 MonitorElement *
00850 DQMStore::book2D(const char *name, const char *title,
00851                  int nchX, double lowX, double highX,
00852                  int nchY, double lowY, double highY)
00853 {
00854   return book2D(pwd_, name, new TH2F(name, title,
00855                                      nchX, lowX, highX,
00856                                      nchY, lowY, highY));
00857 }
00858 
00860 MonitorElement *
00861 DQMStore::book2D(const std::string &name, const std::string &title,
00862                  int nchX, double lowX, double highX,
00863                  int nchY, double lowY, double highY)
00864 {
00865   return book2D(pwd_, name, new TH2F(name.c_str(), title.c_str(),
00866                                      nchX, lowX, highX,
00867                                      nchY, lowY, highY));
00868 }
00869 
00871 MonitorElement *
00872 DQMStore::book2S(const char *name, const char *title,
00873                  int nchX, double lowX, double highX,
00874                  int nchY, double lowY, double highY)
00875 {
00876   return book2S(pwd_, name, new TH2S(name, title,
00877                                      nchX, lowX, highX,
00878                                      nchY, lowY, highY));
00879 }
00880 
00882 MonitorElement *
00883 DQMStore::book2S(const std::string &name, const std::string &title,
00884                  int nchX, double lowX, double highX,
00885                  int nchY, double lowY, double highY)
00886 {
00887   return book2S(pwd_, name, new TH2S(name.c_str(), title.c_str(),
00888                                      nchX, lowX, highX,
00889                                      nchY, lowY, highY));
00890 }
00891 
00893 MonitorElement *
00894 DQMStore::book2DD(const char *name, const char *title,
00895                   int nchX, double lowX, double highX,
00896                   int nchY, double lowY, double highY)
00897 {
00898   return book2DD(pwd_, name, new TH2D(name, title,
00899                                       nchX, lowX, highX,
00900                                       nchY, lowY, highY));
00901 }
00902 
00904 MonitorElement *
00905 DQMStore::book2DD(const std::string &name, const std::string &title,
00906                   int nchX, double lowX, double highX,
00907                   int nchY, double lowY, double highY)
00908 {
00909   return book2DD(pwd_, name, new TH2D(name.c_str(), title.c_str(),
00910                                       nchX, lowX, highX,
00911                                       nchY, lowY, highY));
00912 }
00913 
00915 MonitorElement *
00916 DQMStore::book2D(const char *name, const char *title,
00917                  int nchX, float *xbinsize, int nchY, float *ybinsize)
00918 {
00919   return book2D(pwd_, name, new TH2F(name, title, 
00920                                      nchX, xbinsize, nchY, ybinsize));
00921 }
00922 
00924 MonitorElement *
00925 DQMStore::book2D(const std::string &name, const std::string &title,
00926                  int nchX, float *xbinsize, int nchY, float *ybinsize)
00927 {
00928   return book2D(pwd_, name, new TH2F(name.c_str(), title.c_str(), 
00929                                      nchX, xbinsize, nchY, ybinsize));
00930 }
00931 
00933 MonitorElement *
00934 DQMStore::book2D(const char *name, TH2F *source)
00935 {
00936   return book2D(pwd_, name, static_cast<TH2F *>(source->Clone(name)));
00937 }
00938 
00940 MonitorElement *
00941 DQMStore::book2D(const std::string &name, TH2F *source)
00942 {
00943   return book2D(pwd_, name, static_cast<TH2F *>(source->Clone(name.c_str())));
00944 }
00945 
00947 MonitorElement *
00948 DQMStore::book2S(const char *name, TH2S *source)
00949 {
00950   return book2S(pwd_, name, static_cast<TH2S *>(source->Clone(name)));
00951 }
00952 
00954 MonitorElement *
00955 DQMStore::book2S(const std::string &name, TH2S *source)
00956 {
00957   return book2S(pwd_, name, static_cast<TH2S *>(source->Clone(name.c_str())));
00958 }
00959 
00961 MonitorElement *
00962 DQMStore::book2DD(const char *name, TH2D *source)
00963 {
00964   return book2DD(pwd_, name, static_cast<TH2D *>(source->Clone(name)));
00965 }
00966 
00968 MonitorElement *
00969 DQMStore::book2DD(const std::string &name, TH2D *source)
00970 {
00971   return book2DD(pwd_, name, static_cast<TH2D *>(source->Clone(name.c_str())));
00972 }
00973 
00974 // -------------------------------------------------------------------
00976 MonitorElement *
00977 DQMStore::book3D(const std::string &dir, const std::string &name, TH3F *h)
00978 {
00979   return book(dir, name, "book3D", MonitorElement::DQM_KIND_TH3F, h, collate3D);
00980 }
00981 
00983 MonitorElement *
00984 DQMStore::book3D(const char *name, const char *title,
00985                  int nchX, double lowX, double highX,
00986                  int nchY, double lowY, double highY,
00987                  int nchZ, double lowZ, double highZ)
00988 {
00989   return book3D(pwd_, name, new TH3F(name, title,
00990                                      nchX, lowX, highX,
00991                                      nchY, lowY, highY,
00992                                      nchZ, lowZ, highZ));
00993 }
00994 
00996 MonitorElement *
00997 DQMStore::book3D(const std::string &name, const std::string &title,
00998                  int nchX, double lowX, double highX,
00999                  int nchY, double lowY, double highY,
01000                  int nchZ, double lowZ, double highZ)
01001 {
01002   return book3D(pwd_, name, new TH3F(name.c_str(), title.c_str(),
01003                                      nchX, lowX, highX,
01004                                      nchY, lowY, highY,
01005                                      nchZ, lowZ, highZ));
01006 }
01007 
01009 MonitorElement *
01010 DQMStore::book3D(const char *name, TH3F *source)
01011 {
01012   return book3D(pwd_, name, static_cast<TH3F *>(source->Clone(name)));
01013 }
01014 
01016 MonitorElement *
01017 DQMStore::book3D(const std::string &name, TH3F *source)
01018 {
01019   return book3D(pwd_, name, static_cast<TH3F *>(source->Clone(name.c_str())));
01020 }
01021 
01022 // -------------------------------------------------------------------
01024 MonitorElement *
01025 DQMStore::bookProfile(const std::string &dir, const std::string &name, TProfile *h)
01026 {
01027   return book(dir, name, "bookProfile",
01028               MonitorElement::DQM_KIND_TPROFILE,
01029               h, collateProfile);
01030 }
01031 
01035 MonitorElement *
01036 DQMStore::bookProfile(const char *name, const char *title,
01037                       int nchX, double lowX, double highX,
01038                       int /* nchY */, double lowY, double highY,
01039                       const char *option /* = "s" */)
01040 {
01041   return bookProfile(pwd_, name, new TProfile(name, title,
01042                                               nchX, lowX, highX,
01043                                               lowY, highY,
01044                                               option));
01045 }
01046 
01050 MonitorElement *
01051 DQMStore::bookProfile(const std::string &name, const std::string &title,
01052                       int nchX, double lowX, double highX,
01053                       int /* nchY */, double lowY, double highY,
01054                       const char *option /* = "s" */)
01055 {
01056   return bookProfile(pwd_, name, new TProfile(name.c_str(), title.c_str(),
01057                                               nchX, lowX, highX,
01058                                               lowY, highY,
01059                                               option));
01060 }
01061 
01065 MonitorElement *
01066 DQMStore::bookProfile(const char *name, const char *title,
01067                       int nchX, double lowX, double highX,
01068                       double lowY, double highY,
01069                       const char *option /* = "s" */)
01070 {
01071   return bookProfile(pwd_, name, new TProfile(name, title,
01072                                               nchX, lowX, highX,
01073                                               lowY, highY,
01074                                               option));
01075 }
01076 
01080 MonitorElement *
01081 DQMStore::bookProfile(const std::string &name, const std::string &title,
01082                       int nchX, double lowX, double highX,
01083                       double lowY, double highY,
01084                       const char *option /* = "s" */)
01085 {
01086   return bookProfile(pwd_, name, new TProfile(name.c_str(), title.c_str(),
01087                                               nchX, lowX, highX,
01088                                               lowY, highY,
01089                                               option));
01090 }
01091 
01095 MonitorElement *
01096 DQMStore::bookProfile(const char *name, const char *title,
01097                       int nchX, double *xbinsize,
01098                       int /* nchY */, double lowY, double highY,
01099                       const char *option /* = "s" */)
01100 {
01101   return bookProfile(pwd_, name, new TProfile(name, title,
01102                                               nchX, xbinsize,
01103                                               lowY, highY,
01104                                               option));
01105 }
01106 
01110 MonitorElement *
01111 DQMStore::bookProfile(const std::string &name, const std::string &title,
01112                       int nchX, double *xbinsize,
01113                       int /* nchY */, double lowY, double highY,
01114                       const char *option /* = "s" */)
01115 {
01116   return bookProfile(pwd_, name, new TProfile(name.c_str(), title.c_str(),
01117                                               nchX, xbinsize,
01118                                               lowY, highY,
01119                                               option));
01120 }
01121 
01125 MonitorElement *
01126 DQMStore::bookProfile(const char *name, const char *title,
01127                       int nchX, double *xbinsize,
01128                       double lowY, double highY,
01129                       const char *option /* = "s" */)
01130 {
01131   return bookProfile(pwd_, name, new TProfile(name, title,
01132                                               nchX, xbinsize,
01133                                               lowY, highY,
01134                                               option));
01135 }
01136 
01140 MonitorElement *
01141 DQMStore::bookProfile(const std::string &name, const std::string &title,
01142                       int nchX, double *xbinsize,
01143                       double lowY, double highY,
01144                       const char *option /* = "s" */)
01145 {
01146   return bookProfile(pwd_, name, new TProfile(name.c_str(), title.c_str(),
01147                                               nchX, xbinsize,
01148                                               lowY, highY,
01149                                               option));
01150 }
01151 
01153 MonitorElement *
01154 DQMStore::bookProfile(const char *name, TProfile *source)
01155 {
01156   return bookProfile(pwd_, name, static_cast<TProfile *>(source->Clone(name)));
01157 }
01158 
01160 MonitorElement *
01161 DQMStore::bookProfile(const std::string &name, TProfile *source)
01162 {
01163   return bookProfile(pwd_, name, static_cast<TProfile *>(source->Clone(name.c_str())));
01164 }
01165 
01166 // -------------------------------------------------------------------
01168 MonitorElement *
01169 DQMStore::bookProfile2D(const std::string &dir, const std::string &name, TProfile2D *h)
01170 {
01171   return book(dir, name, "bookProfile2D",
01172               MonitorElement::DQM_KIND_TPROFILE2D,
01173               h, collateProfile2D);
01174 }
01175 
01179 MonitorElement *
01180 DQMStore::bookProfile2D(const char *name, const char *title,
01181                         int nchX, double lowX, double highX,
01182                         int nchY, double lowY, double highY,
01183                         int /* nchZ */, double lowZ, double highZ,
01184                         const char *option /* = "s" */)
01185 {
01186   return bookProfile2D(pwd_, name, new TProfile2D(name, title,
01187                                                   nchX, lowX, highX,
01188                                                   nchY, lowY, highY,
01189                                                   lowZ, highZ,
01190                                                   option));
01191 }
01192 
01196 MonitorElement *
01197 DQMStore::bookProfile2D(const std::string &name, const std::string &title,
01198                         int nchX, double lowX, double highX,
01199                         int nchY, double lowY, double highY,
01200                         int /* nchZ */, double lowZ, double highZ,
01201                         const char *option /* = "s" */)
01202 {
01203   return bookProfile2D(pwd_, name, new TProfile2D(name.c_str(), title.c_str(),
01204                                                   nchX, lowX, highX,
01205                                                   nchY, lowY, highY,
01206                                                   lowZ, highZ,
01207                                                   option));
01208 }
01209 
01213 MonitorElement *
01214 DQMStore::bookProfile2D(const char *name, const char *title,
01215                         int nchX, double lowX, double highX,
01216                         int nchY, double lowY, double highY,
01217                         double lowZ, double highZ,
01218                         const char *option /* = "s" */)
01219 {
01220   return bookProfile2D(pwd_, name, new TProfile2D(name, title,
01221                                                   nchX, lowX, highX,
01222                                                   nchY, lowY, highY,
01223                                                   lowZ, highZ,
01224                                                   option));
01225 }
01226 
01230 MonitorElement *
01231 DQMStore::bookProfile2D(const std::string &name, const std::string &title,
01232                         int nchX, double lowX, double highX,
01233                         int nchY, double lowY, double highY,
01234                         double lowZ, double highZ,
01235                         const char *option /* = "s" */)
01236 {
01237   return bookProfile2D(pwd_, name, new TProfile2D(name.c_str(), title.c_str(),
01238                                                   nchX, lowX, highX,
01239                                                   nchY, lowY, highY,
01240                                                   lowZ, highZ,
01241                                                   option));
01242 }
01243 
01245 MonitorElement *
01246 DQMStore::bookProfile2D(const char *name, TProfile2D *source)
01247 {
01248   return bookProfile2D(pwd_, name, static_cast<TProfile2D *>(source->Clone(name)));
01249 }
01250 
01252 MonitorElement *
01253 DQMStore::bookProfile2D(const std::string &name, TProfile2D *source)
01254 {
01255   return bookProfile2D(pwd_, name, static_cast<TProfile2D *>(source->Clone(name.c_str())));
01256 }
01257 
01261 bool
01262 DQMStore::checkBinningMatches(MonitorElement *me, TH1 *h)
01263 {
01264   if (me->getTH1()->GetNbinsX() != h->GetNbinsX()
01265       || me->getTH1()->GetNbinsY() != h->GetNbinsY()
01266       || me->getTH1()->GetNbinsZ() != h->GetNbinsZ()
01267       || me->getTH1()->GetXaxis()->GetXmin() != h->GetXaxis()->GetXmin()
01268       || me->getTH1()->GetYaxis()->GetXmin() != h->GetYaxis()->GetXmin()
01269       || me->getTH1()->GetZaxis()->GetXmin() != h->GetZaxis()->GetXmin()
01270       || me->getTH1()->GetXaxis()->GetXmax() != h->GetXaxis()->GetXmax()
01271       || me->getTH1()->GetYaxis()->GetXmax() != h->GetYaxis()->GetXmax()
01272       || me->getTH1()->GetZaxis()->GetXmax() != h->GetZaxis()->GetXmax())
01273   {
01274     //  edm::LogWarning ("DQMStore")
01275     std::cout << "*** DQMStore: WARNING:"
01276               << "checkBinningMatches: different binning - cannot add object '"
01277               << h->GetName() << "' of type "
01278               << h->IsA()->GetName() << " to existing ME: '"
01279               << me->getFullname() << "'\n";
01280     return false;
01281   }
01282   return true;     
01283 }
01284 
01285 void
01286 DQMStore::collate1D(MonitorElement *me, TH1F *h)
01287 { 
01288   if (checkBinningMatches(me,h)) 
01289     me->getTH1F()->Add(h); 
01290 }
01291 
01292 void
01293 DQMStore::collate1S(MonitorElement *me, TH1S *h)
01294 {  
01295   if (checkBinningMatches(me,h)) 
01296     me->getTH1S()->Add(h); 
01297 }
01298 
01299 void
01300 DQMStore::collate1DD(MonitorElement *me, TH1D *h)
01301 {  
01302   if (checkBinningMatches(me,h)) 
01303     me->getTH1D()->Add(h); 
01304 }
01305 
01306 void
01307 DQMStore::collate2D(MonitorElement *me, TH2F *h)
01308 {  
01309   if (checkBinningMatches(me,h)) 
01310     me->getTH2F()->Add(h); 
01311 }
01312 
01313 void
01314 DQMStore::collate2S(MonitorElement *me, TH2S *h)
01315 {  
01316   if (checkBinningMatches(me,h)) 
01317     me->getTH2S()->Add(h); 
01318 }
01319 
01320 void
01321 DQMStore::collate2DD(MonitorElement *me, TH2D *h)
01322 {  
01323   if (checkBinningMatches(me,h)) 
01324     me->getTH2D()->Add(h); 
01325 }
01326 
01327 void
01328 DQMStore::collate3D(MonitorElement *me, TH3F *h)
01329 {  
01330   if (checkBinningMatches(me,h)) 
01331     me->getTH3F()->Add(h); 
01332 }
01333 
01334 void
01335 DQMStore::collateProfile(MonitorElement *me, TProfile *h)
01336 {
01337   if (checkBinningMatches(me,h)) 
01338   {
01339     TProfile *meh = me->getTProfile();
01340     me->addProfiles(h, meh, meh, 1, 1);
01341   }
01342 }
01343 
01344 void
01345 DQMStore::collateProfile2D(MonitorElement *me, TProfile2D *h)
01346 {
01347   if (checkBinningMatches(me,h)) 
01348   {
01349     TProfile2D *meh = me->getTProfile2D();
01350     me->addProfiles(h, meh, meh, 1, 1);
01351   }
01352 }
01353 
01358 void
01359 DQMStore::tag(MonitorElement *me, unsigned int myTag)
01360 {
01361   if (! myTag)
01362     raiseDQMError("DQMStore", "Attempt to tag monitor element '%s'"
01363                   " with a zero tag", me->getFullname().c_str());
01364   if ((me->data_.flags & DQMNet::DQM_PROP_TAGGED) && myTag != me->data_.tag)
01365     raiseDQMError("DQMStore", "Attempt to tag monitor element '%s'"
01366                   " twice with multiple tags", me->getFullname().c_str());
01367 
01368   me->data_.tag = myTag;
01369   me->data_.flags |= DQMNet::DQM_PROP_TAGGED;
01370 }
01371 
01373 void
01374 DQMStore::tag(const std::string &path, unsigned int myTag)
01375 {
01376   std::string dir;
01377   std::string name;
01378   splitPath(dir, name, path);
01379 
01380   if (MonitorElement *me = findObject(dir, name))
01381     tag(me, myTag);
01382   else
01383     raiseDQMError("DQMStore", "Attempt to tag non-existent monitor element"
01384                   " '%s' with tag %u", path.c_str(), myTag);
01385 
01386 }
01387 
01389 void
01390 DQMStore::tagContents(const std::string &path, unsigned int myTag)
01391 {
01392   MonitorElement proto(&path, std::string());
01393   MEMap::iterator e = data_.end();
01394   MEMap::iterator i = data_.lower_bound(proto);
01395   for ( ; i != e && path == *i->data_.dirname; ++i)
01396     tag(const_cast<MonitorElement *>(&*i), myTag);
01397 }
01398 
01401 void
01402 DQMStore::tagAllContents(const std::string &path, unsigned int myTag)
01403 {
01404   std::string clean;
01405   const std::string *cleaned = 0;
01406   cleanTrailingSlashes(path, clean, cleaned);
01407   MonitorElement proto(cleaned, std::string());
01408 
01409   // FIXME: WILDCARDS? Old one supported them, but nobody seemed to use them.
01410   MEMap::iterator e = data_.end();
01411   MEMap::iterator i = data_.lower_bound(proto);
01412   while (i != e && isSubdirectory(*cleaned, *i->data_.dirname))
01413   {
01414     tag(const_cast<MonitorElement *>(&*i), myTag);
01415     ++i;
01416   }
01417 }
01418 
01423 std::vector<std::string>
01424 DQMStore::getSubdirs(void) const
01425 {
01426   std::vector<std::string> result;
01427   std::set<std::string>::const_iterator e = dirs_.end();
01428   std::set<std::string>::const_iterator i = dirs_.find(pwd_);
01429 
01430   // If we didn't find current directory, the tree is empty, so quit.
01431   if (i == e)
01432     return result;
01433 
01434   // Skip the current directory and then start looking for immediate
01435   // subdirectories in the dirs_ list.  Stop when we are no longer in
01436   // (direct or indirect) subdirectories of pwd_.  Note that we don't
01437   // "know" which order the set will sort A/B, A/B/C and A/D.
01438   while (++i != e && isSubdirectory(pwd_, *i))
01439     if (i->find('/', pwd_.size()+1) == std::string::npos)
01440       result.push_back(*i);
01441 
01442   return result;
01443 }
01444 
01446 std::vector<std::string>
01447 DQMStore::getMEs(void) const
01448 {
01449   MonitorElement proto(&pwd_, std::string());
01450   std::vector<std::string> result;
01451   MEMap::const_iterator e = data_.end();
01452   MEMap::const_iterator i = data_.lower_bound(proto);
01453   for ( ; i != e && isSubdirectory(pwd_, *i->data_.dirname); ++i)
01454     if (pwd_ == *i->data_.dirname)
01455       result.push_back(i->getName());
01456 
01457   return result;
01458 }
01459 
01462 bool
01463 DQMStore::containsAnyMonitorable(const std::string &path) const
01464 {
01465   MonitorElement proto(&path, std::string());
01466   MEMap::const_iterator e = data_.end();
01467   MEMap::const_iterator i = data_.lower_bound(proto);
01468   return (i != e && isSubdirectory(path, *i->data_.dirname));
01469 }
01470 
01472 MonitorElement *
01473 DQMStore::get(const std::string &path) const
01474 {
01475   std::string dir;
01476   std::string name;
01477   splitPath(dir, name, path);
01478   MonitorElement proto(&dir, name);
01479   MEMap::const_iterator mepos = data_.find(proto);
01480   return (mepos == data_.end() ? 0
01481           : const_cast<MonitorElement *>(&*mepos));
01482 }
01483 
01485 std::vector<MonitorElement *>
01486 DQMStore::get(unsigned int tag) const
01487 {
01488   // FIXME: Use reverse map [tag -> path] / [tag -> dir]?
01489   std::vector<MonitorElement *> result;
01490   for (MEMap::const_iterator i = data_.begin(), e = data_.end(); i != e; ++i)
01491   {
01492     const MonitorElement &me = *i;
01493     if ((me.data_.flags & DQMNet::DQM_PROP_TAGGED) && me.data_.tag == tag)
01494       result.push_back(const_cast<MonitorElement *>(&me));
01495   }
01496   return result;
01497 }
01498 
01501 std::vector<MonitorElement *>
01502 DQMStore::getContents(const std::string &path) const
01503 {
01504   std::string clean;
01505   const std::string *cleaned = 0;
01506   cleanTrailingSlashes(path, clean, cleaned);
01507   MonitorElement proto(cleaned, std::string());
01508 
01509   std::vector<MonitorElement *> result;
01510   MEMap::const_iterator e = data_.end();
01511   MEMap::const_iterator i = data_.lower_bound(proto);
01512   for ( ; i != e && isSubdirectory(*cleaned, *i->data_.dirname); ++i)
01513     if (*cleaned == *i->data_.dirname)
01514       result.push_back(const_cast<MonitorElement *>(&*i));
01515 
01516   return result;
01517 }
01518 
01520 std::vector<MonitorElement *>
01521 DQMStore::getContents(const std::string &path, unsigned int tag) const
01522 {
01523   std::string clean;
01524   const std::string *cleaned = 0;
01525   cleanTrailingSlashes(path, clean, cleaned);
01526   MonitorElement proto(cleaned, std::string());
01527 
01528   std::vector<MonitorElement *> result;
01529   MEMap::const_iterator e = data_.end();
01530   MEMap::const_iterator i = data_.lower_bound(proto);
01531   for ( ; i != e && isSubdirectory(*cleaned, *i->data_.dirname); ++i)
01532     if (*cleaned == *i->data_.dirname
01533         && (i->data_.flags & DQMNet::DQM_PROP_TAGGED)
01534         && i->data_.tag == tag)
01535       result.push_back(const_cast<MonitorElement *>(&*i));
01536 
01537   return result;
01538 }
01539 
01544 void
01545 DQMStore::getContents(std::vector<std::string> &into, bool showContents /* = true */) const
01546 {
01547   into.clear();
01548   into.reserve(dirs_.size());
01549 
01550   MEMap::const_iterator me = data_.end();
01551   std::set<std::string>::const_iterator di = dirs_.begin();
01552   std::set<std::string>::const_iterator de = dirs_.end();
01553   for ( ; di != de; ++di)
01554   {
01555     MonitorElement proto(&*di, std::string());
01556     MEMap::const_iterator mi = data_.lower_bound(proto);
01557     MEMap::const_iterator m = mi;
01558     size_t sz = di->size() + 2;
01559     size_t nfound = 0;
01560     for ( ; m != me && isSubdirectory(*di, *m->data_.dirname); ++m)
01561       if (*di == *m->data_.dirname)
01562       {
01563         sz += m->data_.objname.size() + 1;
01564         ++nfound;
01565       }
01566 
01567     if (! nfound)
01568       continue;
01569 
01570     std::vector<std::string>::iterator istr
01571       = into.insert(into.end(), std::string());
01572 
01573     if (showContents)
01574     {
01575       istr->reserve(sz);
01576 
01577       *istr += *di;
01578       *istr += ':';
01579       for (sz = 0; mi != m; ++mi)
01580       {
01581         if (*di != *mi->data_.dirname)
01582           continue;
01583 
01584         if (sz > 0)
01585           *istr += ',';
01586 
01587         *istr += mi->data_.objname;
01588         ++sz;
01589       }
01590     }
01591     else
01592     {
01593       istr->reserve(di->size() + 2);
01594       *istr += *di;
01595       *istr += ':';
01596     }
01597   }
01598 }
01599 
01602 MonitorElement *
01603 DQMStore::findObject(const std::string &dir, const std::string &name) const
01604 {
01605   if (dir.find_first_not_of(s_safe) != std::string::npos)
01606     raiseDQMError("DQMStore", "Monitor element path name '%s' uses"
01607                   " unacceptable characters", dir.c_str());
01608   if (name.find_first_not_of(s_safe) != std::string::npos)
01609     raiseDQMError("DQMStore", "Monitor element path name '%s' uses"
01610                   " unacceptable characters", name.c_str());
01611 
01612   MonitorElement proto;
01613   proto.data_.dirname = &dir;
01614   proto.data_.objname = name;
01615 
01616   MEMap::const_iterator mepos = data_.find(proto);
01617   return (mepos == data_.end() ? 0
01618           : const_cast<MonitorElement *>(&*mepos));
01619 }
01620 
01623 void
01624 DQMStore::getAllTags(std::vector<std::string> &into) const
01625 {
01626   into.clear();
01627   into.reserve(dirs_.size());
01628 
01629   MEMap::const_iterator me = data_.end();
01630   std::set<std::string>::const_iterator di = dirs_.begin();
01631   std::set<std::string>::const_iterator de = dirs_.end();
01632   char tagbuf[32]; // more than enough for '/' and up to 10 digits
01633 
01634   for ( ; di != de; ++di)
01635   {
01636     MonitorElement proto(&*di, std::string());
01637     MEMap::const_iterator mi = data_.lower_bound(proto);
01638     MEMap::const_iterator m = mi;
01639     size_t sz = di->size() + 2;
01640     size_t nfound = 0;
01641     for ( ; m != me && isSubdirectory(*di, *m->data_.dirname); ++m)
01642       if (*di == *m->data_.dirname && (m->data_.flags & DQMNet::DQM_PROP_TAGGED))
01643       {
01644         // the tags count for '/' + up to 10 digits, otherwise ',' + ME name
01645         sz += 1 + m->data_.objname.size() + 11;
01646         ++nfound;
01647       }
01648 
01649     if (! nfound)
01650       continue;
01651 
01652     std::vector<std::string>::iterator istr
01653       = into.insert(into.end(), std::string());
01654 
01655     istr->reserve(sz);
01656 
01657     *istr += *di;
01658     *istr += ':';
01659     for (sz = 0; mi != m; ++mi)
01660     {
01661       if (*di == *m->data_.dirname && (m->data_.flags & DQMNet::DQM_PROP_TAGGED))
01662       {
01663         sprintf(tagbuf, "/%u", mi->data_.tag);
01664         if (sz > 0)
01665           *istr += ',';
01666         *istr += m->data_.objname;
01667         *istr += tagbuf;
01668         ++sz;
01669       }
01670     }
01671   }
01672 }
01673 
01676 std::vector<MonitorElement*>
01677 DQMStore::getAllContents(const std::string &path) const
01678 {
01679   std::string clean;
01680   const std::string *cleaned = 0;
01681   cleanTrailingSlashes(path, clean, cleaned);
01682   MonitorElement proto(cleaned, std::string());
01683 
01684   std::vector<MonitorElement *> result;
01685   MEMap::const_iterator e = data_.end();
01686   MEMap::const_iterator i = data_.lower_bound(proto);
01687   for ( ; i != e && isSubdirectory(*cleaned, *i->data_.dirname); ++i)
01688     result.push_back(const_cast<MonitorElement *>(&*i));
01689 
01690   return result;
01691 }
01692 
01695 std::vector<MonitorElement*>
01696 DQMStore::getMatchingContents(const std::string &pattern, lat::Regexp::Syntax syntaxType /* = Wildcard */) const
01697 {
01698   lat::Regexp rx;
01699   try
01700   {
01701     rx = lat::Regexp(pattern, 0, syntaxType);
01702     rx.study();
01703   }
01704   catch (lat::Error &e)
01705   {
01706     raiseDQMError("DQMStore", "Invalid regular expression '%s': %s",
01707                   pattern.c_str(), e.explain().c_str());
01708   }
01709 
01710   std::string path;
01711   std::vector<MonitorElement *> result;
01712   MEMap::const_iterator i = data_.begin();
01713   MEMap::const_iterator e = data_.end();
01714   for ( ; i != e; ++i)
01715   {
01716     path.clear();
01717     mergePath(path, *i->data_.dirname, i->data_.objname);
01718     if (rx.match(path))
01719       result.push_back(const_cast<MonitorElement *>(&*i));
01720   }
01721 
01722   return result;
01723 }
01724 
01728 
01731 void
01732 DQMStore::reset(void)
01733 {
01734   MEMap::iterator mi = data_.begin();
01735   MEMap::iterator me = data_.end();
01736   for ( ; mi != me; ++mi)
01737   {
01738     MonitorElement &me = const_cast<MonitorElement &>(*mi);
01739     if (mi->wasUpdated())
01740     {
01741       if (me.resetMe())
01742         me.Reset();
01743       me.resetUpdate();
01744     }
01745   }
01746 
01747   reset_ = true;
01748 }
01749 
01753 
01755 void
01756 DQMStore::forceReset(void)
01757 {
01758   MEMap::iterator mi = data_.begin();
01759   MEMap::iterator me = data_.end();
01760   for ( ; mi != me; ++mi)
01761   {
01762     MonitorElement &me = const_cast<MonitorElement &>(*mi);
01763     me.Reset();
01764     me.resetUpdate();
01765   }
01766 
01767   reset_ = true;
01768 }
01769 
01775 bool
01776 DQMStore::extract(TObject *obj, const std::string &dir, bool overwrite)
01777 {
01778   // NB: Profile histograms inherit from TH*D, checking order matters.
01779   MonitorElement *refcheck = 0;
01780   if (TProfile *h = dynamic_cast<TProfile *>(obj))
01781   {
01782     MonitorElement *me = findObject(dir, h->GetName());
01783     if (! me)
01784       me = bookProfile(dir, h->GetName(), (TProfile *) h->Clone());
01785     else if (overwrite)
01786       me->copyFrom(h);
01787     else if (isCollateME(me) || collateHistograms_)
01788       collateProfile(me, h);
01789     refcheck = me;
01790   }
01791   else if (TProfile2D *h = dynamic_cast<TProfile2D *>(obj))
01792   {
01793     MonitorElement *me = findObject(dir, h->GetName());
01794     if (! me)
01795       me = bookProfile2D(dir, h->GetName(), (TProfile2D *) h->Clone());
01796     else if (overwrite)
01797       me->copyFrom(h);
01798     else if (isCollateME(me) || collateHistograms_)
01799       collateProfile2D(me, h);
01800     refcheck = me;
01801   }
01802   else if (TH1F *h = dynamic_cast<TH1F *>(obj))
01803   {
01804     MonitorElement *me = findObject(dir, h->GetName());
01805     if (! me)
01806       me = book1D(dir, h->GetName(), (TH1F *) h->Clone());
01807     else if (overwrite)
01808       me->copyFrom(h);
01809     else if (isCollateME(me) || collateHistograms_)
01810       collate1D(me, h);
01811     refcheck = me;
01812   }
01813   else if (TH1S *h = dynamic_cast<TH1S *>(obj))
01814   {
01815     MonitorElement *me = findObject(dir, h->GetName());
01816     if (! me)
01817       me = book1S(dir, h->GetName(), (TH1S *) h->Clone());
01818     else if (overwrite)
01819       me->copyFrom(h);
01820     else if (isCollateME(me) || collateHistograms_)
01821       collate1S(me, h);
01822     refcheck = me;
01823   }
01824   else if (TH1D *h = dynamic_cast<TH1D *>(obj))
01825   {
01826     MonitorElement *me = findObject(dir, h->GetName());
01827     if (! me)
01828       me = book1DD(dir, h->GetName(), (TH1D *) h->Clone());
01829     else if (overwrite)
01830       me->copyFrom(h);
01831     else if (isCollateME(me) || collateHistograms_)
01832       collate1DD(me, h);
01833     refcheck = me;
01834   }
01835   else if (TH2F *h = dynamic_cast<TH2F *>(obj))
01836   {
01837     MonitorElement *me = findObject(dir, h->GetName());
01838     if (! me)
01839       me = book2D(dir, h->GetName(), (TH2F *) h->Clone());
01840     else if (overwrite)
01841       me->copyFrom(h);
01842     else if (isCollateME(me) || collateHistograms_)
01843       collate2D(me, h);
01844     refcheck = me;
01845   }
01846   else if (TH2S *h = dynamic_cast<TH2S *>(obj))
01847   {
01848     MonitorElement *me = findObject(dir, h->GetName());
01849     if (! me)
01850       me = book2S(dir, h->GetName(), (TH2S *) h->Clone());
01851     else if (overwrite)
01852       me->copyFrom(h);
01853     else if (isCollateME(me) || collateHistograms_)
01854       collate2S(me, h);
01855     refcheck = me;
01856   }
01857   else if (TH2D *h = dynamic_cast<TH2D *>(obj))
01858   {
01859     MonitorElement *me = findObject(dir, h->GetName());
01860     if (! me)
01861       me = book2DD(dir, h->GetName(), (TH2D *) h->Clone());
01862     else if (overwrite)
01863       me->copyFrom(h);
01864     else if (isCollateME(me) || collateHistograms_)
01865       collate2DD(me, h);
01866     refcheck = me;
01867   }
01868   else if (TH3F *h = dynamic_cast<TH3F *>(obj))
01869   {
01870     MonitorElement *me = findObject(dir, h->GetName());
01871     if (! me)
01872       me = book3D(dir, h->GetName(), (TH3F *) h->Clone());
01873     else if (overwrite)
01874       me->copyFrom(h);
01875     else if (isCollateME(me) || collateHistograms_)
01876       collate3D(me, h);
01877     refcheck = me;
01878   }
01879   else if (dynamic_cast<TObjString *>(obj))
01880   {
01881     lat::RegexpMatch m;
01882     if (! s_rxmeval.match(obj->GetName(), 0, 0, &m))
01883     {
01884       if (strstr(obj->GetName(), "CMSSW"))
01885       {
01886         if (verbose_)
01887           std::cout << "Input file version: " << obj->GetName() << std::endl;
01888         return true;
01889       }
01890       else if (strstr(obj->GetName(), "DQMPATCH"))
01891       {
01892         if (verbose_)
01893           std::cout << "DQM patch version: " << obj->GetName() << std::endl;
01894         return true;
01895       }
01896       else
01897       {
01898         std::cout << "*** DQMStore: WARNING: cannot extract object '"
01899                   << obj->GetName() << "' of type '"
01900                   << obj->IsA()->GetName() << "'\n";
01901         return false;
01902       }
01903     }
01904 
01905     std::string label = m.matchString(obj->GetName(), 1);
01906     std::string kind = m.matchString(obj->GetName(), 2);
01907     std::string value = m.matchString(obj->GetName(), 3);
01908 
01909     if (kind == "i")
01910     {
01911       MonitorElement *me = findObject(dir, label);
01912       if (! me || overwrite)
01913       {
01914         if (! me) me = bookInt(dir, label);
01915         me->Fill(atoll(value.c_str()));
01916       }
01917     }
01918     else if (kind == "f")
01919     {
01920       MonitorElement *me = findObject(dir, label);
01921       if (! me || overwrite)
01922       {
01923         if (! me) me = bookFloat(dir, label);
01924         me->Fill(atof(value.c_str()));
01925       }
01926     }
01927     else if (kind == "s")
01928     {
01929       MonitorElement *me = findObject(dir, label);
01930       if (! me)
01931         me = bookString(dir, label, value);
01932       else if (overwrite)
01933         me->Fill(value);
01934     }
01935     else if (kind == "e")
01936     {
01937       MonitorElement *me = findObject(dir, label);
01938       if (! me)
01939       {
01940         std::cout << "*** DQMStore: WARNING: no monitor element '"
01941                   << label << "' in directory '"
01942                   << dir << "' to be marked as efficiency plot.\n";
01943         return false;
01944       }
01945       me->setEfficiencyFlag();
01946     }
01947     else if (kind == "t")
01948     {
01949       MonitorElement *me = findObject(dir, label);
01950       if (! me)
01951       {
01952         std::cout << "*** DQMStore: WARNING: no monitor element '"
01953                   << label << "' in directory '"
01954                   << dir << "' for a tag\n";
01955         return false;
01956       }
01957       errno = 0;
01958       char *endp = 0;
01959       unsigned long val = strtoul(value.c_str(), &endp, 10);
01960       if ((val == 0 && errno) || *endp || val > ~uint32_t(0))
01961       {
01962         std::cout << "*** DQMStore: WARNING: cannot restore tag '"
01963                   << value << "' for monitor element '"
01964                   << label << "' in directory '"
01965                   << dir << "' - invalid value\n";
01966         return false;
01967       }
01968       tag(me, val);
01969     }
01970     else if (kind == "qr")
01971     {
01972       // Handle qreports, but skip them while reading in references.
01973       if (! isSubdirectory(s_referenceDirName, dir))
01974       {
01975         size_t dot = label.find('.');
01976         if (dot == std::string::npos)
01977         {
01978           std::cout << "*** DQMStore: WARNING: quality report label in '" << label
01979                     << "' is missing a '.' and cannot be extracted\n";
01980           return false;
01981         }
01982 
01983         std::string mename (label, 0, dot);
01984         std::string qrname (label, dot+1, std::string::npos);
01985 
01986         m.reset();
01987         DQMNet::QValue qv;
01988         if (s_rxmeqr1.match(value, 0, 0, &m))
01989         {
01990           qv.code = atoi(m.matchString(value, 1).c_str());
01991           qv.qtresult = strtod(m.matchString(value, 2).c_str(), 0);
01992           qv.message = m.matchString(value, 4);
01993           qv.qtname = qrname;
01994           qv.algorithm = m.matchString(value, 3);
01995         }
01996         else if (s_rxmeqr2.match(value, 0, 0, &m))
01997         {
01998           qv.code = atoi(m.matchString(value, 1).c_str());
01999           qv.qtresult = 0; // unavailable in old format
02000           qv.message = m.matchString(value, 2);
02001           qv.qtname = qrname;
02002           // qv.algorithm unavailable in old format
02003         }
02004         else
02005         {
02006           std::cout << "*** DQMStore: WARNING: quality test value '"
02007                     << value << "' is incorrectly formatted\n";
02008           return false;
02009         }
02010 
02011         MonitorElement *me = findObject(dir, mename);
02012         if (! me)
02013         {
02014           std::cout << "*** DQMStore: WARNING: no monitor element '"
02015                     << mename << "' in directory '"
02016                     << dir << "' for quality test '"
02017                     << label << "'\n";
02018           return false;
02019         }
02020 
02021         me->addQReport(qv, /* FIXME: getQTest(qv.qtname)? */ 0);
02022       }
02023     }
02024     else
02025     {
02026       std::cout << "*** DQMStore: WARNING: cannot extract object '"
02027                 << obj->GetName() << "' of type '"
02028                 << obj->IsA()->GetName() << "'\n";
02029       return false;
02030     }
02031   }
02032   else if (TNamed *n = dynamic_cast<TNamed *>(obj))
02033   {
02034     // For old DQM data.
02035     std::string s;
02036     s.reserve(6 + strlen(n->GetTitle()) + 2*strlen(n->GetName()));
02037     s += '<'; s += n->GetName(); s += '>';
02038     s += n->GetTitle();
02039     s += '<'; s += '/'; s += n->GetName(); s += '>';
02040     TObjString os(s.c_str());
02041     return extract(&os, dir, overwrite);
02042   }
02043   else
02044   {
02045     std::cout << "*** DQMStore: WARNING: cannot extract object '"
02046               << obj->GetName() << "' of type '" << obj->IsA()->GetName()
02047               << "' and with title '" << obj->GetTitle() << "'\n";
02048     return false;
02049   }
02050 
02051   // If we just read in a reference monitor element, and there is a
02052   // monitor element with the same name, link the two together. The
02053   // other direction is handled by the initialise() method.
02054   if (refcheck && isSubdirectory(s_referenceDirName, dir))
02055   {
02056     std::string mdir(dir, s_referenceDirName.size()+1, std::string::npos);
02057     if (MonitorElement *master = findObject(mdir, obj->GetName()))
02058     {
02059       master->data_.flags |= DQMNet::DQM_PROP_HAS_REFERENCE;
02060       master->reference_ = refcheck->object_;
02061     }
02062   }
02063 
02064   return true;
02065 }
02066 
02070 bool
02071 DQMStore::cdInto(const std::string &path) const
02072 {
02073   assert(! path.empty());
02074 
02075   // Find the first path component.
02076   size_t start = 0;
02077   size_t end = path.find('/', start);
02078   if (end == std::string::npos)
02079     end = path.size();
02080 
02081   while (true)
02082   {
02083     // Check if this subdirectory component exists.  If yes, make sure
02084     // it is actually a subdirectory.  Otherwise create or cd into it.
02085     std::string part(path, start, end-start);
02086     TObject *o = gDirectory->Get(part.c_str());
02087     if (o && ! dynamic_cast<TDirectory *>(o))
02088       raiseDQMError("DQMStore", "Attempt to create directory '%s' in a file"
02089                     " fails because the part '%s' already exists and is not"
02090                     " directory", path.c_str(), part.c_str());
02091     else if (! o)
02092       gDirectory->mkdir(part.c_str());
02093 
02094     if (! gDirectory->cd(part.c_str()))
02095       raiseDQMError("DQMStore", "Attempt to create directory '%s' in a file"
02096                     " fails because could not cd into subdirectory '%s'",
02097                     path.c_str(), part.c_str());
02098 
02099     // Stop if we reached the end, ignoring any trailing '/'.
02100     if (end+1 >= path.size())
02101       break;
02102 
02103     // Find the next path component.
02104     start = end+1;
02105     end = path.find('/', start);
02106     if (end == std::string::npos)
02107       end = path.size();
02108   }
02109 
02110   return true;
02111 }
02112 
02117 void
02118 DQMStore::save(const std::string &filename,
02119                const std::string &path /* = "" */,
02120                const std::string &pattern /* = "" */,
02121                const std::string &rewrite /* = "" */,
02122                SaveReferenceTag ref /* = SaveWithReference */,
02123                int minStatus /* = dqm::qstatus::STATUS_OK */,
02124                const std::string &fileupdate /* = RECREATE */)
02125 {
02126   std::set<std::string>::iterator di, de;
02127   MEMap::iterator mi, me = data_.end();
02128   DQMNet::QReports::const_iterator qi, qe;
02129   int nme=0;
02130 
02131   // TFile flushes to disk with fsync() on every TDirectory written to the
02132   // file.  This makes DQM file saving painfully slow, and ironically makes
02133   // it _more_ likely the file saving gets interrupted and corrupts the file.
02134   // The utility class below simply ignores the flush synchronisation.
02135   class TFileNoSync : public TFile
02136   {
02137   public:
02138     TFileNoSync(const char *file, const char *opt) : TFile(file, opt) {}
02139     virtual Int_t SysSync(Int_t) { return 0; }
02140   };
02141 
02142   // open output file, on 1st save recreate, later update
02143   if (verbose_)
02144     std::cout << "\n DQMStore: Opening TFile '" << filename 
02145               << "' with option '" << fileupdate <<"'\n";
02146 
02147   TFileNoSync f(filename.c_str(), fileupdate.c_str()); // open file
02148   if(f.IsZombie())
02149     raiseDQMError("DQMStore", "Failed to create/update file '%s'", filename.c_str());
02150   f.cd();
02151   
02152   // Construct a regular expression from the pattern string.
02153   std::auto_ptr<lat::Regexp> rxpat;
02154   if (! pattern.empty())
02155     rxpat.reset(new lat::Regexp(pattern.c_str()));
02156 
02157   // Prepare a path for the reference object selection.
02158   std::string refpath;
02159   refpath.reserve(s_referenceDirName.size() + path.size() + 2);
02160   refpath += s_referenceDirName;
02161   if (! path.empty())
02162   {
02163     refpath += '/';
02164     refpath += path;
02165   }
02166 
02167   // Loop over the directory structure.
02168   for (di = dirs_.begin(), de = dirs_.end(); di != de; ++di)
02169   {
02170     // Check if we should process this directory.  We process the
02171     // requested part of the object tree, including references.
02172     if (! path.empty()
02173         && ! isSubdirectory(path, *di)
02174         && ! isSubdirectory(refpath, *di))
02175       continue;
02176     
02177     // Loop over monitor elements in this directory.
02178     MonitorElement proto(&*di, std::string());
02179     mi = data_.lower_bound(proto);
02180     for ( ; mi != me && isSubdirectory(*di, *mi->data_.dirname); ++mi)
02181     {
02182       // Skip if it isn't a direct child.
02183       if (*di != *mi->data_.dirname)
02184         continue;
02185 
02186       // Handle reference histograms, with three distinct cases:
02187       // 1) Skip all references entirely on saving.
02188       // 2) Blanket saving of all references.
02189       // 3) Save only references for monitor elements with qtests.
02190       // The latter two are affected by "path" sub-tree selection,
02191       // i.e. references are saved only in the selected tree part.
02192       if (isSubdirectory(refpath, *mi->data_.dirname))
02193       {
02194         if (ref == SaveWithoutReference)
02195           // Skip the reference entirely.
02196           continue;
02197         else if (ref == SaveWithReference)
02198           // Save all references regardless of qtests.
02199           ;
02200         else if (ref == SaveWithReferenceForQTest)
02201         {
02202           // Save only references for monitor elements with qtests
02203           // with an optional cut on minimum quality test result.
02204           int status = -1;
02205           std::string mname(mi->getFullname(), s_referenceDirName.size()+1, std::string::npos);
02206           MonitorElement *master = get(mname);
02207           if (master)
02208             for (size_t i = 0, e = master->data_.qreports.size(); i != e; ++i)
02209               status = std::max(status, master->data_.qreports[i].code);
02210 
02211           if (! master || status < minStatus)
02212           {
02213             if (verbose_ > 1)
02214               std::cout << "DQMStore::save: skipping monitor element '"
02215                         << mi->data_.objname << "' while saving, status is "
02216                         << status << ", required minimum status is "
02217                         << minStatus << std::endl;
02218             continue;
02219           }
02220         }
02221       }
02222 
02223       if (verbose_ > 1)
02224         std::cout << "DQMStore::save: saving monitor element '"
02225                   << mi->data_.objname << "'\n";
02226       nme++; // count saved histograms
02227 
02228       // Create the directory.
02229       gDirectory->cd("/");
02230       if (di->empty())
02231         cdInto(s_monitorDirName);
02232       else if (rxpat.get())
02233         cdInto(s_monitorDirName + '/' + lat::StringOps::replace(*di, *rxpat, rewrite));
02234       else
02235         cdInto(s_monitorDirName + '/' + *di);
02236 
02237       // Save the object.
02238       switch (mi->kind())
02239       {
02240       case MonitorElement::DQM_KIND_INT:
02241       case MonitorElement::DQM_KIND_REAL:
02242       case MonitorElement::DQM_KIND_STRING:
02243         TObjString(mi->tagString().c_str()).Write();
02244         break;
02245 
02246       default:
02247         mi->object_->Write();
02248         break;
02249       }
02250 
02251       // Save quality reports if this is not in reference section.
02252       if (! isSubdirectory(s_referenceDirName, *mi->data_.dirname))
02253       {
02254         qi = mi->data_.qreports.begin();
02255         qe = mi->data_.qreports.end();
02256         for ( ; qi != qe; ++qi)
02257           TObjString(mi->qualityTagString(*qi).c_str()).Write();
02258       }
02259 
02260       // Save efficiency tag, if any
02261       if (mi->data_.flags & DQMNet::DQM_PROP_EFFICIENCY_PLOT)
02262         TObjString(mi->effLabelString().c_str()).Write();
02263 
02264       // Save tag if any
02265       if (mi->data_.flags & DQMNet::DQM_PROP_TAGGED)
02266         TObjString(mi->tagLabelString().c_str()).Write();
02267     }
02268   }
02269 
02270   f.Close();
02271 
02272   // Maybe make some noise.
02273   if (verbose_)
02274     std::cout << "DQMStore::save: successfully wrote " << nme 
02275               << " objects from path '" << path  
02276               << "' into DQM file '" << filename << "'\n";
02277 }
02278 
02281 unsigned int
02282 DQMStore::readDirectory(TFile *file,
02283                         bool overwrite,
02284                         const std::string &onlypath,
02285                         const std::string &prepend,
02286                         const std::string &curdir,
02287                         OpenRunDirs stripdirs)
02288 {
02289   unsigned int ntot = 0;
02290   unsigned int count = 0;
02291 
02292   if (! file->cd(curdir.c_str()))
02293     raiseDQMError("DQMStore", "Failed to process directory '%s' while"
02294                   " reading file '%s'", curdir.c_str(), file->GetName());
02295 
02296   // Figure out current directory name, but strip out the top
02297   // directory into which we dump everything.
02298   std::string dirpart = curdir;
02299   if (dirpart.compare(0, s_monitorDirName.size(), s_monitorDirName) == 0)
02300   {
02301     if (dirpart.size() == s_monitorDirName.size())
02302       dirpart.clear();
02303     else if (dirpart[s_monitorDirName.size()] == '/')
02304       dirpart.erase(0, s_monitorDirName.size()+1);
02305   }
02306 
02307   // See if we are going to skip this directory.
02308   bool skip = (! onlypath.empty() && ! isSubdirectory(onlypath, dirpart));
02309   
02310   if (prepend == s_collateDirName || 
02311       prepend == s_referenceDirName || 
02312       stripdirs == StripRunDirs )
02313   {
02314     // Remove Run # and RunSummary dirs
02315     // first look for Run summary, 
02316     // if that is found and erased, also erase Run dir
02317     size_t slash = dirpart.find('/');
02318     size_t pos = dirpart.find("/Run summary");
02319     if (slash != std::string::npos && pos !=std::string::npos) 
02320     {
02321       dirpart.erase(pos,12);
02322     
02323       pos = dirpart.find("Run ");
02324       size_t length = dirpart.find('/',pos+1)-pos+1;
02325       if (pos !=std::string::npos) 
02326         dirpart.erase(pos,length);
02327     }
02328   } 
02329 
02330   // If we are prepending, add it to the directory name, 
02331   // and suppress reading of already existing reference histograms
02332   if (prepend == s_collateDirName || 
02333       prepend == s_referenceDirName)
02334   {
02335     size_t slash = dirpart.find('/');
02336     // If we are reading reference, skip previous reference.
02337     if (slash == std::string::npos   // skip if Reference is toplevel folder, i.e. no slash
02338         && slash+1+s_referenceDirName.size() == dirpart.size()
02339         && dirpart.compare(slash+1, s_referenceDirName.size(), s_referenceDirName) == 0)
02340       return 0;
02341 
02342     slash = dirpart.find('/');    
02343     // Skip reading of EventInfo subdirectory.
02344     if (slash != std::string::npos
02345         && slash + 10 == dirpart.size()
02346         && dirpart.compare( slash+1 , 9 , "EventInfo") == 0) {
02347       if (verbose_)
02348         std::cout << "DQMStore::readDirectory: skipping '" << dirpart << "'\n";
02349       return 0;
02350     }
02351 
02352     // Add prefix.
02353     if (dirpart.empty())
02354       dirpart = prepend;
02355     else
02356       dirpart = prepend + '/' + dirpart;
02357   }
02358   else if (! prepend.empty())
02359   {
02360     if (dirpart.empty())
02361       dirpart = prepend;
02362     else
02363       dirpart = prepend + '/' + dirpart;
02364   }
02365 
02366   // Loop over the contents of this directory in the file.
02367   // Post-pone string object handling to happen after other
02368   // objects have been read in so we are guaranteed to have
02369   // histograms by the time we read in quality tests and tags.
02370   TKey *key;
02371   TIter next (gDirectory->GetListOfKeys());
02372   std::list<TObject *> delayed;
02373   while ((key = (TKey *) next()))
02374   {
02375     std::auto_ptr<TObject> obj(key->ReadObj());
02376     if (dynamic_cast<TDirectory *>(obj.get()))
02377     {
02378       std::string subdir;
02379       subdir.reserve(curdir.size() + strlen(obj->GetName()) + 2);
02380       subdir += curdir;
02381       if (! curdir.empty())
02382         subdir += '/';
02383       subdir += obj->GetName();
02384 
02385       ntot += readDirectory(file, overwrite, onlypath, prepend, subdir, stripdirs);
02386     }
02387     else if (skip)
02388       ;
02389     else if (dynamic_cast<TObjString *>(obj.get()))
02390     {
02391       delayed.push_back(obj.release());
02392     }
02393     else
02394     {
02395       if (verbose_ > 2)
02396         std::cout << "DQMStore: reading object '" << obj->GetName()
02397                   << "' of type '" << obj->IsA()->GetName()
02398                   << "' from '" << file->GetName()
02399                   << "' into '" << dirpart << "'\n";
02400 
02401       makeDirectory(dirpart);
02402       if (extract(obj.get(), dirpart, overwrite))
02403         ++count;
02404     }
02405   }
02406 
02407   while (! delayed.empty())
02408   {
02409     if (verbose_ > 2)
02410       std::cout << "DQMStore: reading object '" << delayed.front()->GetName()
02411                 << "' of type '" << delayed.front()->IsA()->GetName()
02412                 << "' from '" << file->GetName()
02413                 << "' into '" << dirpart << "'\n";
02414 
02415     makeDirectory(dirpart);
02416     if (extract(delayed.front(), dirpart, overwrite))
02417       ++count;
02418 
02419     delete delayed.front();
02420     delayed.pop_front();
02421   }
02422 
02423   if (verbose_ > 1)
02424     std::cout << "DQMStore: read " << count << '/' << ntot
02425               << " objects from directory '" << dirpart << "'\n";
02426 
02427   return ntot + count;
02428 }
02429 
02436 bool
02437 DQMStore::open(const std::string &filename,
02438                bool overwrite /* = false */,
02439                const std::string &onlypath /* ="" */,
02440                const std::string &prepend /* ="" */, 
02441                OpenRunDirs stripdirs /* =KeepRunDirs */, 
02442                bool fileMustExist /* =true */)
02443 {
02444   return readFile(filename,overwrite,onlypath,prepend,stripdirs,fileMustExist);
02445 }
02446 
02451 bool 
02452 DQMStore::load(const std::string &filename,
02453                OpenRunDirs stripdirs /* =StripRunDirs */, 
02454                bool fileMustExist /* =true */)
02455 {
02456   bool overwrite = true;
02457   if (collateHistograms_) overwrite = false;
02458   if (verbose_) 
02459   {
02460     std::cout << "DQMStore::load: reading from file '" << filename << "'\n";
02461     if (collateHistograms_)
02462       std::cout << "DQMStore::load: in collate mode   " << "\n";
02463     else
02464       std::cout << "DQMStore::load: in overwrite mode   " << "\n";
02465   }
02466     
02467   return readFile(filename,overwrite,"","",stripdirs,fileMustExist);
02468      
02469 }
02470 
02476 bool
02477 DQMStore::readFile(const std::string &filename,
02478                    bool overwrite /* = false */,
02479                    const std::string &onlypath /* ="" */,
02480                    const std::string &prepend /* ="" */,
02481                    OpenRunDirs stripdirs /* =StripRunDirs */,
02482                    bool fileMustExist /* =true */)
02483 {
02484   
02485   if (verbose_)
02486     std::cout << "DQMStore::readFile: reading from file '" << filename << "'\n";
02487 
02488   std::auto_ptr<TFile> f;
02489 
02490   try 
02491   {
02492     f.reset(TFile::Open(filename.c_str()));
02493     if (! f.get() || f->IsZombie())
02494       raiseDQMError("DQMStore", "Failed to open file '%s'", filename.c_str());
02495   }
02496   catch (std::exception &)
02497   {
02498     if (fileMustExist)
02499       throw;
02500     else
02501     {  
02502     if (verbose_)
02503       std::cout << "DQMStore::readFile: file '" << filename << "' does not exist, continuing\n";
02504     return false;
02505     }
02506   }
02507 
02508   unsigned n = readDirectory(f.get(), overwrite, onlypath, prepend, "", stripdirs);
02509   f->Close();
02510 
02511   MEMap::iterator mi = data_.begin();
02512   MEMap::iterator me = data_.end();
02513   for ( ; mi != me; ++mi)
02514     const_cast<MonitorElement &>(*mi).updateQReportStats();
02515 
02516   if (verbose_)
02517   {
02518     std::cout << "DQMStore::open: successfully read " << n
02519               << " objects from file '" << filename << "'";
02520     if (! onlypath.empty())
02521       std::cout << " from directory '" << onlypath << "'";
02522     if (! prepend.empty())
02523       std::cout << " into directory '" << prepend << "'";
02524     std::cout << std::endl;
02525   }
02526   return true;
02527 }
02528 
02534 void
02535 DQMStore::rmdir(const std::string &path)
02536 {
02537   std::string clean;
02538   const std::string *cleaned = 0;
02539   cleanTrailingSlashes(path, clean, cleaned);
02540   MonitorElement proto(cleaned, std::string());
02541 
02542   MEMap::iterator e = data_.end();
02543   MEMap::iterator i = data_.lower_bound(proto);
02544   while (i != e && isSubdirectory(*cleaned, *i->data_.dirname))
02545     data_.erase(i++);
02546 
02547   std::set<std::string>::iterator de = dirs_.end();
02548   std::set<std::string>::iterator di = dirs_.lower_bound(*cleaned);
02549   while (di != de && isSubdirectory(*cleaned, *di))
02550     dirs_.erase(di++);
02551 }
02552 
02554 void
02555 DQMStore::removeContents(const std::string &dir)
02556 {
02557   MonitorElement proto(&dir, std::string());
02558   MEMap::iterator e = data_.end();
02559   MEMap::iterator i = data_.lower_bound(proto);
02560   while (i != e && isSubdirectory(dir, *i->data_.dirname))
02561     if (dir == *i->data_.dirname)
02562       data_.erase(i++);
02563     else
02564       ++i;
02565 }
02566 
02568 void
02569 DQMStore::removeContents(void)
02570 {
02571   removeContents(pwd_);
02572 }
02573 
02576 void
02577 DQMStore::removeElement(const std::string &name)
02578 {
02579   removeElement(pwd_, name);
02580 }
02581 
02584 void
02585 DQMStore::removeElement(const std::string &dir, const std::string &name, bool warning /* = true */)
02586 {
02587   MonitorElement proto(&dir, name);
02588   MEMap::iterator pos = data_.find(proto);
02589   if (pos == data_.end() && warning)
02590     std::cout << "DQMStore: WARNING: attempt to remove non-existent"
02591               << " monitor element '" << name << "' in '" << dir << "'\n";
02592   else
02593     data_.erase(pos);
02594 }
02595 
02601 QCriterion *
02602 DQMStore::getQCriterion(const std::string &qtname) const
02603 {
02604   QCMap::const_iterator i = qtests_.find(qtname);
02605   QCMap::const_iterator e = qtests_.end();
02606   return (i == e ? 0 : i->second);
02607 }
02608 
02612 QCriterion *
02613 DQMStore::createQTest(const std::string &algoname, const std::string &qtname)
02614 {
02615   if (qtests_.count(qtname))
02616     raiseDQMError("DQMStore", "Attempt to create duplicate quality test '%s'",
02617                   qtname.c_str());
02618 
02619   QAMap::iterator i = qalgos_.find(algoname);
02620   if (i == qalgos_.end())
02621     raiseDQMError("DQMStore", "Cannot create a quality test using unknown"
02622                   " algorithm '%s'", algoname.c_str());
02623 
02624   QCriterion *qc = i->second(qtname);
02625   qc->setVerbose(verboseQT_);
02626 
02627   qtests_[qtname] = qc;
02628   return qc;
02629 }
02630 
02633 void
02634 DQMStore::useQTest(const std::string &dir, const std::string &qtname)
02635 {
02636   // Clean the path
02637   std::string clean;
02638   const std::string *cleaned = 0;
02639   cleanTrailingSlashes(dir, clean, cleaned);
02640 
02641   // Validate the path.
02642   if (cleaned->find_first_not_of(s_safe) != std::string::npos)
02643     raiseDQMError("DQMStore", "Monitor element path name '%s'"
02644                   " uses unacceptable characters", cleaned->c_str());
02645 
02646   // Redirect to the pattern match version.
02647   useQTestByMatch(*cleaned + "/*", qtname);
02648 }
02649 
02651 int 
02652 DQMStore::useQTestByMatch(const std::string &pattern, const std::string &qtname)
02653 {
02654   QCriterion *qc = getQCriterion(qtname);
02655   if (! qc)
02656     raiseDQMError("DQMStore", "Cannot apply non-existent quality test '%s'",
02657                   qtname.c_str());
02658 
02659   fastmatch * fm = new fastmatch( pattern );
02660 
02661   // Record the test for future reference.
02662   QTestSpec qts(fm, qc);
02663   qtestspecs_.push_back(qts);
02664 
02665   // Apply the quality test.
02666   MEMap::iterator mi = data_.begin();
02667   MEMap::iterator me = data_.end();
02668   std::string path;
02669   int cases = 0;
02670   for ( ; mi != me; ++mi)
02671   {
02672     path.clear();
02673     mergePath(path, *mi->data_.dirname, mi->data_.objname);
02674     if (fm->match(path))
02675     {
02676       ++cases;
02677       const_cast<MonitorElement &>(*mi).addQReport(qts.second);
02678     }
02679   }
02680 
02681   //return the number of matched cases
02682   return cases;
02683 }
02686 void
02687 DQMStore::runQTests(void)
02688 {
02689 
02690   if (verbose_ > 0)
02691     std::cout << "DQMStore: running runQTests() with reset = "
02692               << ( reset_ ? "true" : "false" ) << std::endl;
02693 
02694   // Apply quality tests to each monitor element, skipping references.
02695   MEMap::iterator mi = data_.begin();
02696   MEMap::iterator me = data_.end();
02697   for ( ; mi != me; ++mi)
02698     if (! isSubdirectory(s_referenceDirName, *mi->data_.dirname))
02699       const_cast<MonitorElement &>(*mi).runQTests();
02700 
02701   reset_ = false;
02702 }
02703 
02707 int
02708 DQMStore::getStatus(const std::string &path /* = "" */) const
02709 {
02710   std::string clean;
02711   const std::string *cleaned = 0;
02712   cleanTrailingSlashes(path, clean, cleaned);
02713 
02714   int status = dqm::qstatus::STATUS_OK;
02715   MEMap::const_iterator mi = data_.begin();
02716   MEMap::const_iterator me = data_.end();
02717   for ( ; mi != me; ++mi)
02718   {
02719     if (! cleaned->empty() && ! isSubdirectory(*cleaned, *mi->data_.dirname))
02720       continue;
02721 
02722     if (mi->hasError())
02723       return dqm::qstatus::ERROR;
02724     else if (mi->hasWarning())
02725       status = dqm::qstatus::WARNING;
02726     else if (status < dqm::qstatus::WARNING
02727              && mi->hasOtherReport())
02728       status = dqm::qstatus::OTHER;
02729   }
02730   return status;
02731 }
02732 
02738 void
02739 DQMStore::softReset(MonitorElement *me)
02740 {
02741   if (me)
02742     me->softReset();
02743 }
02744 
02745 // reverts action of softReset
02746 void
02747 DQMStore::disableSoftReset(MonitorElement *me)
02748 {
02749   if (me)
02750     me->disableSoftReset();
02751 }
02752 
02755 void
02756 DQMStore::setAccumulate(MonitorElement *me, bool flag)
02757 {
02758   if (me)
02759     me->setAccumulate(flag);
02760 }
02761 
02765 void
02766 DQMStore::showDirStructure(void) const
02767 {
02768   std::vector<std::string> contents;
02769   getContents(contents);
02770 
02771   std::cout << " ------------------------------------------------------------\n"
02772             << "                    Directory structure:                     \n"
02773             << " ------------------------------------------------------------\n";
02774 
02775   std::copy(contents.begin(), contents.end(),
02776             std::ostream_iterator<std::string>(std::cout, "\n"));
02777 
02778   std::cout << " ------------------------------------------------------------\n";
02779 }
02780 
02784 // check if the collate option is active on the DQMStore
02785 bool
02786 DQMStore::isCollate(void) const
02787 {
02788   return collateHistograms_;
02789 }
02793 // check if the monitor element is in auto-collation folder
02794 bool
02795 DQMStore::isCollateME(MonitorElement *me) const
02796 { return me && isSubdirectory(s_collateDirName, *me->data_.dirname); }
02800 
02802 void
02803 DQMStore::scaleElements(void)
02804 {
02805   if (scaleFlag_ == 0.0) return;
02806   if (verbose_ > 0)
02807     std::cout << " =========== " << " ScaleFlag " << scaleFlag_ << std::endl;
02808   double factor = scaleFlag_; 
02809   int events = 1;
02810   if (dirExists("Info/EventInfo")) {
02811     if ( scaleFlag_ == -1.0) {
02812       MonitorElement * scale_me = get("Info/EventInfo/ScaleFactor");
02813       if (scale_me && scale_me->kind()==MonitorElement::DQM_KIND_REAL) factor = scale_me->getFloatValue(); 
02814     }
02815     MonitorElement * event_me = get("Info/EventInfo/processedEvents");
02816     if (event_me && event_me->kind()==MonitorElement::DQM_KIND_INT) events = event_me->getIntValue();      
02817   }  
02818   factor = factor/(events*1.0);
02819 
02820   MEMap::iterator mi = data_.begin();
02821   MEMap::iterator me = data_.end();
02822   for ( ; mi != me; ++mi)
02823   {
02824     MonitorElement &me = const_cast<MonitorElement &>(*mi);
02825     switch (me.kind())
02826       {
02827       case MonitorElement::DQM_KIND_TH1F:
02828         {
02829           me.getTH1F()->Scale(factor);
02830           break;
02831         }
02832       case MonitorElement::DQM_KIND_TH1S:
02833         {
02834           me.getTH1S()->Scale(factor);
02835           break;
02836         }
02837       case MonitorElement::DQM_KIND_TH1D:
02838         {
02839           me.getTH1D()->Scale(factor);
02840           break;
02841         }
02842       case MonitorElement::DQM_KIND_TH2F:
02843         {
02844           me.getTH2F()->Scale(factor);
02845           break;
02846         }
02847       case MonitorElement::DQM_KIND_TH2S:
02848         {
02849           me.getTH2S()->Scale(factor);
02850           break;
02851         }
02852       case MonitorElement::DQM_KIND_TH2D:
02853         {
02854           me.getTH2D()->Scale(factor);
02855           break;
02856         }
02857       case MonitorElement::DQM_KIND_TH3F:
02858         {
02859           me.getTH3F()->Scale(factor);
02860           break;
02861         }
02862       case MonitorElement::DQM_KIND_TPROFILE:
02863         {
02864           me.getTProfile()->Scale(factor);
02865           break;
02866         }
02867       case MonitorElement::DQM_KIND_TPROFILE2D:
02868         {
02869           me.getTProfile2D()->Scale(factor);
02870           break;
02871         }
02872       default:
02873         if (verbose_ > 0)
02874           std::cout << " The DQM object '" << me.getFullname() << "' is not scalable object " << std::endl;
02875         continue;
02876       }
02877   }
02878 }