CMS 3D CMS Logo

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