]> git.uio.no Git - u/mrichter/AliRoot.git/commitdiff
Updates for cleaning database and fixes for making local QA passes
authorcholm <Christian.Holm.Christensen@cern.ch>
Fri, 9 May 2014 13:12:32 +0000 (15:12 +0200)
committercholm <Christian.Holm.Christensen@cern.ch>
Fri, 9 May 2014 13:12:32 +0000 (15:12 +0200)
PWGLF/FORWARD/analysis2/AliCorrectionManagerBase.cxx
PWGLF/FORWARD/analysis2/AliCorrectionManagerBase.h
PWGLF/FORWARD/analysis2/AliForwardCorrectionManager.cxx
PWGLF/FORWARD/analysis2/AliOADBForward.cxx
PWGLF/FORWARD/analysis2/AliOADBForward.h
PWGLF/FORWARD/analysis2/corrs/Browse.C
PWGLF/FORWARD/analysis2/corrs/ForwardOADBGui.C
PWGLF/FORWARD/analysis2/qa/QABase.h
PWGLF/FORWARD/analysis2/qa/RunQAMT.sh

index 6e71b9f6097258dbf1f421aa1ee3ad13836ab30a..b0747529d03cb9c4e7dffb556e25199891b53f90 100644 (file)
@@ -9,6 +9,8 @@
 #include <TBrowser.h>
 #include <TParameter.h>
 #include <TFileMerger.h>
+#include <TBits.h>
+#include <TTree.h>
 
 //____________________________________________________________________
 AliCorrectionManagerBase::AliCorrectionManagerBase()
@@ -205,9 +207,30 @@ AliCorrectionManagerBase::Append(const TString& addition,
   }
   if (destination.BeginsWith("$OADB_PATH") ||
       destination.BeginsWith("$ALICE_ROOT"))
-    AliInfoF("Now commit %s to subversion", destination.Data());
+    AliInfoF("Now commit %s to git", destination.Data());
   return true;
 }
+//____________________________________________________________________
+Bool_t
+AliCorrectionManagerBase::CleanUp(const TString& destination, Bool_t verb) const
+{
+  AliOADBForward* db = fDB;
+  if (!db) db = new AliOADBForward;
+
+  for (Int_t i = 0; i < 32; i++) {
+    const Correction* c = GetCorrection(i);
+    if (!c) continue;
+
+    if (!c->fEnabled) {
+      Info("CleanUp", "Table %s not enabled", c->GetName());
+      continue;
+    }
+    Info("CleanUp", "Will clean up table %s", c->GetName());
+    c->CleanIt(db, destination, verb);
+  }
+  return true;
+}
   
 //____________________________________________________________________
 void
@@ -544,6 +567,49 @@ AliCorrectionManagerBase::Correction::operator=(const Correction& o)
   return *this;
 }
 
+//____________________________________________________________________
+void
+AliCorrectionManagerBase::Correction::MassageFields(ULong_t&  run,
+                                                   UShort_t& sys,
+                                                   UShort_t& sNN, 
+                                                   Short_t & fld, 
+                                                   Bool_t&   mc, 
+                                                   Bool_t&   sat) const
+{
+  // Massage fields according to settings 
+  if (!(fQueryFields & kRun))       run = kIgnoreValue;
+  if (!(fQueryFields & kSys))       sys = kIgnoreValue;
+  if (!(fQueryFields & kSNN))       sNN = kIgnoreValue;
+  if (!(fQueryFields & kField))     fld = AliOADBForward::kInvalidField; 
+  if (!(fQueryFields & kMC))        mc  = false;
+  if (!(fQueryFields & kSatellite)) sat = false;
+}
+
+//____________________________________________________________________
+Bool_t
+AliCorrectionManagerBase::Correction::OpenIt(AliOADBForward* db, 
+                                            Bool_t vrb, 
+                                            Bool_t fallback) const
+{
+  if (!db) {
+    Warning("OpenIt", "No DB passed");
+    return false;
+  }
+
+  // Check if table is open
+  if (db->FindTable(fName, true)) return true;
+
+  //  if not try to open it 
+  if (db->Open(fTitle, fName, false, vrb, fallback)) return true;
+
+  // Give warning 
+  AliWarningF("Failed to open table %s from %s", GetName(), GetTitle());
+  AliWarningF("content of %s for %s:", 
+             gSystem->WorkingDirectory(), GetName());
+  gSystem->Exec("pwd; ls -l");
+  return false;
+}
 //____________________________________________________________________
 Bool_t
 AliCorrectionManagerBase::Correction::ReadIt(AliOADBForward* db, 
@@ -565,24 +631,10 @@ AliCorrectionManagerBase::Correction::ReadIt(AliOADBForward* db,
   fObject = 0;
 
   // Massage fields according to settings 
-  if (!(fQueryFields & kRun))       run = kIgnoreValue;
-  if (!(fQueryFields & kSys))       sys = kIgnoreValue;
-  if (!(fQueryFields & kSNN))       sNN = kIgnoreValue;
-  if (!(fQueryFields & kField))     fld = AliOADBForward::kInvalidField; // kIgnoreField;
-  if (!(fQueryFields & kMC))        mc  = false;
-  if (!(fQueryFields & kSatellite)) sat = false;
+  MassageFields(run, sys, sNN, fld, mc, sat);
+
+  if (!OpenIt(db, vrb, fallback)) return false;
 
-  // Check if table is open, and if not try to open it 
-  if (!db->FindTable(fName, true)) {
-    if (!db->Open(fTitle, fName, false, vrb, fallback)) {
-      AliWarningF("Failed to open table %s from %s", GetName(), GetTitle());
-      AliWarningF("content of %s for %s:", 
-                 gSystem->WorkingDirectory(), GetName());
-      gSystem->Exec("pwd; ls -l");
-      return false;
-    }
-  }
-  
   // Query database 
   AliOADBForward::Entry* e = db->Get(fName, run, AliOADBForward::kDefault, 
                                     sys, sNN, fld, mc, sat);
@@ -642,18 +694,13 @@ AliCorrectionManagerBase::Correction::StoreIt(AliOADBForward* db,
   AliOADBForward* tdb      = (local ? new AliOADBForward : db);
   
   // Try to open the table read/write 
-  if (!tdb->Open(fileName, Form("%s/%s", GetName(), meth), true, true)) {
+  if (!tdb->Open(fileName, Form("%s/%s", GetName(), meth), true, false)) {
     AliWarningF("Failed to open table %s in %s", GetName(), fileName.Data());
     return false;
   }
 
   // Massage fields according to settings 
-  if (!(fQueryFields & kRun))       run = kIgnoreValue;
-  if (!(fQueryFields & kSys))       sys = kIgnoreValue;
-  if (!(fQueryFields & kSNN))       sNN = kIgnoreValue;
-  if (!(fQueryFields & kField))     fld = AliOADBForward::kInvalidField; // kIgnoreField;
-  if (!(fQueryFields & kMC))        mc  = false;
-  if (!(fQueryFields & kSatellite)) sat = false;
+  MassageFields(run, sys, sNN, fld, mc, sat);
   
   // Try to insert the object 
   if (!tdb->Insert(fName, obj, run, sys, sNN, fld, mc, sat)) { 
@@ -773,6 +820,126 @@ AliCorrectionManagerBase::Correction::Browse(TBrowser* b)
   b->Add(new TObjString(fLastEntry), "Entry");
   if (fObject) b->Add(fObject);
 }
+//____________________________________________________________________
+Bool_t
+AliCorrectionManagerBase::Correction::CleanIt(AliOADBForward* db,
+                                             const TString& dest,
+                                             Bool_t verb) const
+{
+  // Open the table for this correction 
+  if (!OpenIt(db, verb , false)) {
+    Warning("CleanIt", "Failed to open table for %s", GetName());
+    return false;
+  }
+
+  // Get our table - should be here if the above succeeded
+  AliOADBForward::Table* t = db->FindTable(fName, !verb);
+  if (!t) {
+    Warning("CleanIt", "Failed to get table for %s", GetName());
+    return false;
+  }
+
+  // Get some pointers and make a bit mask of entries to copy
+  TTree* tree = t->fTree;
+  Int_t  nEnt = tree->GetEntries();
+  TBits  copy(nEnt);
+  copy.ResetAllBits(false);
+  // TString runs;
+
+  // Loop over all entries 
+  Info("CleanIt", "Looping over %d entries in tree", nEnt);
+  for (Int_t i = 0; i < nEnt; i++) { 
+    // Read in next entry 
+    tree->GetEntry(i);
+
+    // Check if we got an object 
+    AliOADBForward::Entry* e = t->fEntry;    
+    if (!e) continue;
+    
+    // Let's see it 
+    // if (verb) e->Print();
+
+    // Now query the DB with this entry's fields 
+    ULong_t  run = e->fRunNo;
+    UShort_t sys = e->fSys;
+    UShort_t sNN = e->fSNN;
+    Short_t  fld = e->fField;
+    Bool_t   mc  = e->fMC;
+    Bool_t   sat = e->fSatellite;
+    TString  txt = e->GetTitle();
+    MassageFields(run, sys, sNN, fld, mc, sat);
+
+    
+    Int_t r = t->GetEntry(run, AliOADBForward::kDefault, 
+                         sys, sNN, fld, mc, sat);
+    if (r < 0) { 
+      Warning("CleanIt","Uh! didn't get an entry for %s (%d)",
+             txt.Data(), i);
+      r = i;
+      // continue;
+    }
+#if 0
+    // Here, we hard-code some fixes to remove bad entries 
+    if (fld != AliOADBForward::kInvalidField) {
+      switch (sys) {
+      case 1:
+       if      (sNN ==  900 &&  fld <= 0) r = -1;
+       else if (sNN == 7000 &&  fld >= 0) r = -1;
+       else if (sNN == 2760 &&  fld >= 0) r = -1;
+       break;
+      case 2:
+       if (fld >= 0) r = -1;
+       break;
+      }
+    }
+#endif
+
+    Printf("%-10s (%3d %3d): %s %s", 
+          (i==r ? "copied" : "ignored"), i, r, txt.Data(), GetName());
+
+    if (r != i) continue;
+
+    // If the entry found by the query and this entry is the same, 
+    // then we should keep it 
+        copy.SetBitNumber(i,true);
+    // runs.Append(Form("%7lu", run));
+  }
+  
+  // Now loop over the entries of the tree again, this time 
+  // checking if we should copy or not. 
+  // Loop over all entries 
+  for (Int_t i = 0; i < nEnt; i++) { 
+    // If not marked for copy, continue to the next. 
+    if (!copy.TestBitNumber(i)) continue; 
+
+    // Read in next entry 
+    tree->GetEntry(i);
+
+    // Check if we got an object 
+    AliOADBForward::Entry* e = t->fEntry;    
+    if (!e) continue;
+  
+    // Let's get the entry data and store that in a new correction
+    // table
+    ULong_t  run = e->fRunNo;
+    UShort_t sys = e->fSys;
+    UShort_t sNN = e->fSNN;
+    Short_t  fld = e->fField;
+    Bool_t   mc  = e->fMC;
+    Bool_t   sat = e->fSatellite;
+    TObject* obj = e->fData;
+    TString  txt = e->GetTitle();
+    Printf("Storing %3d: %s %s", i, txt.Data(), GetName());
+    if (!StoreIt(0, obj, run, sys, sNN, fld, mc, sat, dest.Data(),
+                AliOADBForward::Mode2String(t->fMode))) {
+      Warning("CleanIt", "Failed to write new entry to %s", dest.Data());
+      continue;
+    }
+  }
+  // Printf("Runs: %s", runs.Data());
+  return true;
+}
+
 //
 // EOF
 //
index c9543f48ac3b070f7c617826142bd934730bad0a..57bf2961b69c0357b3f95af6adf8cb8fd6285721 100644 (file)
@@ -98,21 +98,6 @@ public:
    * Destructor 
    */
   virtual ~AliCorrectionManagerBase();
-  /** 
-   * Check if the manager is initialized 
-   * 
-   * @return True if initialized
-   */
-  virtual Bool_t IsInit() const { return fIsInit; }
-  /** 
-   * Print information
-   * 
-   * @param option Options:
-   * 
-   *   - R  Recursive list each correction 
-   *   - D  Also give details for each correction
-   */
-  virtual void Print(Option_t* option="") const;
   /** 
    * Set the prefix to use when looking for the input files 
    * 
@@ -125,6 +110,11 @@ public:
    * @param use If true, enable fall-back queries 
    */
   virtual void SetEnableFallBack(Bool_t use=true) { fFallBack = use; }
+
+  /** 
+   * @{ 
+   * @name Storing corrections 
+   */
   /** 
    * Store a correction 
    * 
@@ -161,23 +151,20 @@ public:
   virtual Bool_t Append(const TString& addition,
                        const TString& destination="") const;
   /** 
-   * Browse this object
+   * Write a new database file with tables that only has one entry for
+   * each query tuple.
    * 
-   * @param b Browser to use 
-   */
-  virtual void Browse(TBrowser* b);
-  /** 
-   * Flag that this is a folder 
+   * @param destination Where to write the new file 
    * 
-   * @return Always true
+   * @return true on success, false otherwise 
    */
-  virtual Bool_t IsFolder() const { return true; }
+  virtual Bool_t CleanUp(const TString& destination, Bool_t verb=false) const;
+  /* @} */
+
   /** 
-   * Set whehter to enable debug information 
-   * 
-   * @param debug if true, do verbose queries 
+   * @{ 
+   * @name Getting the corrections 
    */
-  virtual void SetDebug(Bool_t debug) { fDebug = debug; }
   /** 
    * Convinience function to enable corrections on-mass.  User class
    * should overload this to properly enable corrections based on the
@@ -215,6 +202,8 @@ public:
                         Bool_t     mc, 
                         Bool_t     sat,
                         Bool_t     force=false);
+  /* @} */
+
   /** 
    * @{ 
    * @name Get axis objects. 
@@ -232,6 +221,45 @@ public:
    */
   virtual const TAxis* GetEtaAxis() const { return 0; }
   /* @} */
+
+  /** 
+   * @{ 
+   * @name Misc
+   */
+  /** 
+   * Check if the manager is initialized 
+   * 
+   * @return True if initialized
+   */
+  virtual Bool_t IsInit() const { return fIsInit; }
+  /** 
+   * Print information
+   * 
+   * @param option Options:
+   * 
+   *   - R  Recursive list each correction 
+   *   - D  Also give details for each correction
+   */
+  virtual void Print(Option_t* option="") const;
+  /** 
+   * Browse this object
+   * 
+   * @param b Browser to use 
+   */
+  virtual void Browse(TBrowser* b);
+  /** 
+   * Flag that this is a folder 
+   * 
+   * @return Always true
+   */
+  virtual Bool_t IsFolder() const { return true; }
+  /** 
+   * Set whehter to enable debug information 
+   * 
+   * @param debug if true, do verbose queries 
+   */
+  virtual void SetDebug(Bool_t debug) { fDebug = debug; }
+  /* @} */
 protected:
   /** 
    * Correction registration
@@ -373,7 +401,21 @@ protected:
      * @return Always true
      */
     Bool_t IsFolder() const { return true; }
-
+    /**
+     * Massage fields according to settings 
+     */
+    void MassageFields(ULong_t&  run,
+                      UShort_t& sys,
+                      UShort_t& sNN, 
+                      Short_t & fld, 
+                      Bool_t&   mc, 
+                      Bool_t&   sat) const;
+    Bool_t CleanIt(AliOADBForward* db, 
+                  const TString& dest, 
+                  Bool_t verb=false) const;
+    Bool_t OpenIt(AliOADBForward* db, 
+                 Bool_t vrb=false, 
+                 Bool_t fallback=false) const;
 
     mutable TClass*  fCls;      //! Class of correction objects
     const TString fClientCls; // Class name
index dad4cbf4eaeb6f246a513df9af9738cc763acfc4..e110549450520315198f0e276524a2efcc74a281 100644 (file)
@@ -121,13 +121,13 @@ AliForwardCorrectionManager::Init(ULong_t     runNo,
 //____________________________________________________________________
 Bool_t
 AliForwardCorrectionManager::Init(ULong_t  runNo, 
-                                     UShort_t sys, 
-                                     UShort_t sNN, 
-                                     Short_t  field,
-                                     Bool_t   mc,
-                                     Bool_t   sat,
-                                     UInt_t   what,
-                                     Bool_t   force)
+                                 UShort_t sys, 
+                                 UShort_t sNN, 
+                                 Short_t  field,
+                                 Bool_t   mc,
+                                 Bool_t   sat,
+                                 UInt_t   what,
+                                 Bool_t   force)
 {
   // 
   // Read in corrections based on the parameters given 
index fb1ab0b5540d922437f9206bfb705f694fce3f73..fe4408132085adac07a6e2be098156c5d323e29f 100644 (file)
@@ -127,9 +127,11 @@ const char*
 AliOADBForward::Entry::GetTitle() const
 {
   TDatime d(fTimestamp);
-  return Form("%09ld, %4s, %4huGeV, %+2hd, %4s, %3s, %19s: %p (%s) by %s", 
+  return Form("%09ld, %4s, %4huGeV, %+4hd, %4s, %3s, %19s: %p (%s) by %s", 
              (fRunNo == 0xFFFFFFFF ? -1 : fRunNo), 
-             (fSys == 1 ? "pp" : fSys == 2 ? "PbPb" : fSys == 3 ? "pPb" :"?"), 
+             (fSys == 1 ? "pp"   : 
+              fSys == 2 ? "PbPb" : 
+              fSys == 3 ? "pPb"  : "?"), 
              fSNN, fField, (fMC ? "mc" : "real"),
              (fSatellite ? "sat" : "nom"), d.AsSQLString(), fData,
              (fData ? fData->GetName() : "?"), fAuthor.Data());
@@ -454,14 +456,14 @@ AliOADBForward::Table::Insert(TObject* o,
 }
 
 //____________________________________________________________________
-AliOADBForward::Entry*
-AliOADBForward::Table::Get(ULong_t        run,
-                          ERunSelectMode mode,
-                          UShort_t       sys,
-                          UShort_t       sNN, 
-                          Short_t        fld,
-                          Bool_t         mc,
-                          Bool_t         sat) const
+Int_t
+AliOADBForward::Table::GetEntry(ULong_t        run,
+                               ERunSelectMode mode,
+                               UShort_t       sys,
+                               UShort_t       sNN, 
+                               Short_t        fld,
+                               Bool_t         mc,
+                               Bool_t         sat) const
 {
   // Query the tree for an object.  The strategy is as follows. 
   // 
@@ -474,12 +476,13 @@ AliOADBForward::Table::Get(ULong_t        run,
   //          - If this returns a single entry, return that.  
   //          - If not, ignore all passed values 
   //            - If this returns a single entry, return that.
-  //            - Otherwise, give up and return null
-  //      - Otherwise, give up and return null
+  //            - Otherwise, give up and return -1
+  //      - Otherwise, give up and return -1
   //
   // This allow us to specify default objects for a period, and for
   // collision system, energy, and field setting.
   //
+
   if (fVerbose)
     Printf("run=%lu mode=%s sys=%hu sNN=%hu fld=%hd mc=%d sat=%d (fall=%d)",
           run, Mode2String(mode), sys, sNN, fld, mc, sat, fFallBack);
@@ -498,9 +501,41 @@ AliOADBForward::Table::Get(ULong_t        run,
   }
   if (entry < 0) {
     Warning("Get", "No valid object could be found");
-    return 0;
+    return -1;
   }
-  
+  return entry;
+}
+
+//____________________________________________________________________
+AliOADBForward::Entry*
+AliOADBForward::Table::Get(ULong_t        run,
+                          ERunSelectMode mode,
+                          UShort_t       sys,
+                          UShort_t       sNN, 
+                          Short_t        fld,
+                          Bool_t         mc,
+                          Bool_t         sat) const
+{
+  // Query the tree for an object.  The strategy is as follows. 
+  // 
+  //  - First query with all fields 
+  //    - If this returns a single entry, return that. 
+  //    - If not, then ignore the run number (if given)
+  //      - If this returns a single entry, return that 
+  //      - If not, and fall-back is enabled, then 
+  //        - Ignore the collision energy (if given) 
+  //          - If this returns a single entry, return that.  
+  //          - If not, ignore all passed values 
+  //            - If this returns a single entry, return that.
+  //            - Otherwise, give up and return null
+  //      - Otherwise, give up and return null
+  //
+  // This allow us to specify default objects for a period, and for
+  // collision system, energy, and field setting.
+  //
+  Int_t entry  = GetEntry(run, mode, sys, sNN, fld, mc, sat);
+  if (entry < 0) return 0;
+
   Int_t nBytes = fTree->GetEntry(entry);
   if (nBytes <= 0) { 
     Warning("Get", "Failed to get entry # %d\n", entry);
@@ -666,15 +701,7 @@ AliOADBForward::Open(TFile*         file,
       if (!cl) continue; 
       if (!cl->InheritsFrom(TTree::Class())) continue; 
        
-      Table* t = GetTableFromFile(file, false, key->GetName(), "DEFAULT");
-      if (!t) continue;
-
-      fTables.Add(new TObjString(key->GetName()), t);
-      t->SetVerbose(verb);
-      t->SetEnableFallBack(fallback);
-      if (verb) 
-       Printf("Found table %s. Opened with verbose=%d, fallback=%d", 
-              key->GetName(), verb, fallback);
+      OpenTable(file, rw, key->GetName(), "DEFAULT", verb, fallback);
     }
     // file->Close();
     return true;
@@ -693,15 +720,8 @@ AliOADBForward::Open(TFile*         file,
     if (parts->GetEntries() > 1) 
       mode = static_cast<TObjString*>(parts->At(1))->String();
     mode.ToUpper();
-    Table* t = GetTableFromFile(file, rw, name, mode);
-    if (!t) continue;
 
-    t->SetVerbose(verb);
-    t->SetEnableFallBack(fallback);
-    fTables.Add(onam->Clone(), t);
-      if (verb) 
-       Printf("Has table %s. Opened with verbose=%d, fallback=%d", 
-              name.Data(), verb, fallback);
+    OpenTable(file, rw, name, mode, verb, fallback);
 
     delete parts;
   }
@@ -951,6 +971,29 @@ AliOADBForward::GetTableFromFile(TFile*         file,
   Table* ret = new Table(t, n, String2Mode(mode));
   return ret;
 }
+
+//____________________________________________________________________
+void
+AliOADBForward::OpenTable(TFile*         file, 
+                         Bool_t         rw, 
+                         const TString& name,
+                         const TString& mode,
+                         Bool_t         verb, 
+                         Bool_t         fallback)
+{
+  if (!file) return;
+
+  Table* t = GetTableFromFile(file, rw, name, mode);
+  if (!t) return;
+
+  fTables.Add(new TObjString(name), t);
+  t->SetVerbose(verb);
+  t->SetEnableFallBack(fallback);
+  if (verb) 
+    Printf("Found table %s. Opened with verbose=%d, fallback=%d", 
+          name.Data(), verb, fallback);
+}
+
 //____________________________________________________________________
 void
 AliOADBForward::AppendToQuery(TString& q, const TString& s, Bool_t andNotOr)
index 0ef7279173bd32018ac37ae97b1e77d35b75f262..d22f14c9ede3e528e3db83474dac36ba825ba7c5 100644 (file)
@@ -300,6 +300,41 @@ public:
                  Bool_t   sat=false,
                  ULong_t  aliRev=0,
                  const TString& author="");
+    /** 
+     * Query the tree for an object.  The strategy is as follows. 
+     * 
+     *  - First query with all fields 
+     *    - If this returns a single entry, return that. 
+     *    - If not, then ignore the run number (if given)
+     *      - If this returns a single entry, return that 
+     *      - If not, and fall-back is enabled, then 
+     *        - Ignore the collision energy (if given) 
+     *          - If this returns a single entry, return that.  
+     *          - If not, ignore all passed values 
+     *            - If this returns a single entry, return that.
+     *            - Otherwise, give up and return -1
+     *      - Otherwise, give up and return -1
+     *
+     * This allow us to specify default objects for a period, and for
+     * collision system, energy, and field setting.
+     *
+     * @param run    Run number 
+     * @param mode   Run selection mode 
+     * @param sys    Collision system (1: pp, 2: PbPb, 3: pPb)
+     * @param sNN    Center of mass energy (GeV)
+     * @param fld    L3 magnetic field (kG)
+     * @param mc     For MC only 
+     * @param sat    For satellite interactions 
+     * 
+     * @return Found entry number, or -1
+     */
+    Int_t GetEntry(ULong_t        run      = 0,
+                  ERunSelectMode mode     = kNear,
+                  UShort_t       sys      = 0,
+                  UShort_t       sNN      = 0, 
+                  Short_t        fld      = 0,
+                  Bool_t         mc       = false,
+                  Bool_t         sat      = false) const;
     /** 
      * Query the tree for an object.  The strategy is as follows. 
      * 
@@ -634,6 +669,20 @@ protected:
   Table* GetTableFromFile(TFile* file, Bool_t rw, 
                          const TString& name,
                          const TString& mode) const;
+
+  /** 
+   * Get a table (TTree) from a file and attach
+   * 
+   * @param file   File to look in 
+   * @param rw     If true, open read/write, false read-only
+   * @param name   Name of the table 
+   * @param mode   Default mode for new table, or override mode 
+   *               for existing tables if not default
+   * 
+   * @return Table or (if rw=true) possibly newly created table
+   */
+  void OpenTable(TFile* file, Bool_t rw, const TString& name, 
+                const TString& mode, Bool_t verb, Bool_t fallback);
   /** 
    * Helper function to append to query string 
    * 
index 6bf58d88cc6578b740fd15b76897686348b88b05..2742853cc9c5b56d7690cd9a2b6c12cc5b15d83f 100644 (file)
@@ -1,13 +1,15 @@
-       TObject* Browse()
+TObject* Browse(Bool_t rw=false)
 {
-  const char* fwd = "/opt/alice/aliroot/trunk-inst/PWGLF/FORWARD/analysis2";
+  const char* fwd = "${ALICE_ROOT}/PWGLF/FORWARD/analysis2";
   if (!gROOT->GetClass("AliOADBForward"))
     gROOT->Macro(Form("%s/scripts/LoadLibs.C", fwd));
   gSystem->AddIncludePath(Form("-I%s -I$ALICE_ROOT/include", fwd));
-  gROOT->LoadMacro(Form("%s/corrs/ForwardOADBGui.C", fwd));
+  TString macro = Form("%s/corrs/ForwardOADBGui.C+", fwd);
+  Info("", "Loading macro %s", macro.Data());
+  gROOT->LoadMacro(macro);
   
   AliOADBForward* db = new AliOADBForward;
-  db->Open("fmd_corrections.root", "*");
+  db->Open("fmd_corrections.root", "*", rw);
   
   ForwardOADBGui(db);
 
index f040909f48b23bdd1f57ca73166052bc0f95b3c1..b0f23e9a142aa8b6e6929cb6feb0eaf984f94ab1 100644 (file)
@@ -43,11 +43,13 @@ namespace {
 #else 
 class AliOADBForward;
 class AliOADBForward::Entry;
-#if 0
+// #if 0
+class TGTransientFrame;
 class TGFrame;
 class TGLVEntry;
 class TGHorizontalFrame;
 class TGTextButton;
+class TGCheckButton;
 class TGTextEntry;
 class TGVerticalFrame;
 class TGLabel;
@@ -58,7 +60,7 @@ class TGLVContainer;
 class TGHButtonGroup;
 class TGLayoutHints;
 class TGNumberEntry;
-#endif
+// #endif
 #endif
 
 struct ForwardOADBDialog
@@ -77,9 +79,11 @@ struct ForwardOADBDialog
     // fProgress.SetRange(0,1);
     fIncrement.Connect("Timeout()","ForwardOADBDialog",this,"HandleIncr()");
   }
+  ForwardOADBDialog(const ForwardOADBDialog&) {}
+  ForwardOADBDialog& operator=(const ForwardOADBDialog&) { return *this; }
   void HandleIncr()
   {
-    Float_t dp = 0.1;
+    // Float_t dp = 0.1;
     // Float_t p  = fProgress.GetPosition();
     // Info("HandleIncr", "Handing increment (%f)", p);
     // if (p+dp >= 1) fProgress.SetPosition(0);
@@ -127,6 +131,7 @@ struct ForwardOADBGUI
       fFileSelect(&fOpenFrame, "Browse"), 
       fTablesText(&fOpenFrame, "*"),
       fOpenButton(&fOpenFrame, "Open"),
+      fRWButton(&fOpenFrame, "R/W"),
       fCloseButton(&fOpenFrame, "Close"),
       fSelectFrame(&fMain), 
       fTableFrame(&fSelectFrame), 
@@ -160,6 +165,7 @@ struct ForwardOADBGUI
     fQueryButton(&fCommandFrame, "Query"),
     fListButton(&fCommandFrame, "List table"),
     fPrintButton(&fCommandFrame, "Print entry"),
+    fCopyButton(&fCommandFrame, "Copy entry"),
     fDrawButton(&fCommandFrame, "Draw entry"),
     fPDFButton(&fCommandFrame, "Summarize entry"),
     fList(&fMain, 800, 400), 
@@ -184,6 +190,7 @@ struct ForwardOADBGUI
     fOpenFrame.AddFrame(&fFileSelect, &fEntryHints);
     fOpenFrame.AddFrame(&fTablesText, &fEntryHints);
     fOpenFrame.AddFrame(&fOpenButton, &fEntryHints);
+    fOpenFrame.AddFrame(&fRWButton,   &fButtonHints);
     fOpenFrame.AddFrame(&fCloseButton, &fEntryHints);
 
     fMain.AddFrame(&fSelectFrame, &fFrameHints);
@@ -249,9 +256,11 @@ struct ForwardOADBGUI
     fOptionsFrame.AddFrame(&fOptionsLabel, &fLabelHints);
     fOptionsFrame.AddFrame(&fOptionsText, &fEntryHints);
 
+    Info("", "Connecting signals");
     fQueryButton.Connect("Clicked()", "ForwardOADBGUI", this, "HandleQuery()");
     fListButton.Connect("Clicked()", "ForwardOADBGUI", this, "HandleList()");
     fDrawButton.Connect("Clicked()", "ForwardOADBGUI", this, "HandleDraw()");
+    fCopyButton.Connect("Clicked()", "ForwardOADBGUI", this, "HandleCopy()");
     fPDFButton.Connect("Clicked()", "ForwardOADBGUI", this, "HandlePDF()");
     fPrintButton.Connect("Clicked()", "ForwardOADBGUI", this, "HandlePrint()");
     fSelectFrame.AddFrame(&fCommandFrame, &fFrameHints);
@@ -301,6 +310,58 @@ struct ForwardOADBGUI
 #endif
     Info("~ForwardOADBGUI", "Closing");
   }
+  ForwardOADBGUI(const ForwardOADBGUI&) 
+    : fMain(gClient->GetRoot(), 10, 10, kVerticalFrame),
+      fOpenFrame(&fMain),
+      fFileText(&fOpenFrame, ""),
+      fFileSelect(&fOpenFrame, ""), 
+      fTablesText(&fOpenFrame, ""),
+      fOpenButton(&fOpenFrame, ""),
+      fRWButton(&fOpenFrame, ""),
+      fCloseButton(&fOpenFrame, ""),
+      fSelectFrame(&fMain), 
+      fTableFrame(&fSelectFrame), 
+      fTableLabel(&fTableFrame, ""), 
+      fTableSelect(&fTableFrame),
+      fRunFrame(&fSelectFrame), 
+      fRunLabel(&fRunFrame, ""), 
+      fRunInput(&fRunFrame),
+    fRunMode(&fRunFrame),
+    fSysFrame(&fSelectFrame), 
+    fSysLabel(&fSysFrame, ""), 
+    fSysSelect(&fSysFrame),
+    fSNNFrame(&fSelectFrame), 
+    fSNNLabel(&fSNNFrame, ""), 
+    fSNNInput(&fSNNFrame),
+    fFldFrame(&fSelectFrame), 
+    fFldLabel(&fFldFrame, ""), 
+    fFldSelect(&fFldFrame),
+    fOtherFrame(&fSelectFrame),
+    fMCButton(&fOtherFrame, ""),
+    fSatButton(&fOtherFrame, ""),
+    fOptionsFrame(&fSelectFrame), 
+    fOptionsLabel(&fOptionsFrame, ""),
+    fOptionsText(&fOptionsFrame, ""),
+    fCommandFrame(&fSelectFrame), 
+    fQueryButton(&fCommandFrame, ""),
+    fListButton(&fCommandFrame, ""),
+    fPrintButton(&fCommandFrame, ""),
+    fCopyButton(&fCommandFrame, ""),
+    fDrawButton(&fCommandFrame, ""),
+    fPDFButton(&fCommandFrame, ""),
+    fList(&fMain, 800, 400), 
+    fListContainer(&fList),
+    fFrameHints(),
+    fLabelHints(),
+    fEntryHints(),
+    fButtonHints(),
+    fListHints(),
+    fMsg(0),
+    fDB(0),
+    fEntry(0)
+  {}
+  ForwardOADBGUI& operator=(const ForwardOADBGUI&) { return *this; }
+
   void UseDB(AliOADBForward* db)
   {
     if (!db) return;
@@ -335,6 +396,7 @@ struct ForwardOADBGUI
     Info("HandleDBEntry", "Selected entry %p", e);
     Bool_t en = (e != 0);
     fDrawButton.SetEnabled(en);
+    fCopyButton.SetEnabled(en);
     fPrintButton.SetEnabled(en);
     fPDFButton.SetEnabled(en);
     
@@ -355,6 +417,7 @@ struct ForwardOADBGUI
     fListButton.SetEnabled(enabled && hasTable);
     fPrintButton.SetEnabled(enabled && hasTable);
     fDrawButton.SetEnabled(enabled && hasTable);
+    fCopyButton.SetEnabled(enabled && hasTable);
     fPDFButton.SetEnabled(enabled && hasTable);
     fOpenButton.SetEnabled(!enabled);
     fCloseButton.SetEnabled(enabled);
@@ -393,12 +456,13 @@ struct ForwardOADBGUI
   void HandleOpen()
   {
     if (fDB) HandleClose();
+    Bool_t rw = fRWButton.IsOn();
     fDB = new AliOADBForward;
     Info("HandleOpen", "Opening DB file %s for tables %s", 
         fFileText.GetText(), fTablesText.GetText());
     TString fn(fFileText.GetText());
     TString tn(fTablesText.GetText());
-    if (!fDB->Open(fn, tn, false, true, true)) { 
+    if (!fDB->Open(fn, tn, rw, true, true)) { 
       Error("HandleOpen", "Failed to open database");
       delete fDB;
       fDB = 0;
@@ -573,6 +637,62 @@ struct ForwardOADBGUI
     CorrDraw(o, false);
     // o->Draw(fOptionsText.GetText()); 
   }
+  void HandleCopy()
+  {
+    TString table;
+    SelectedTable(table);
+    if (table.IsNull()) return;
+
+    if (!fEntry) { 
+      Warning("HandleCopy", "No entry selected");
+      return;
+    }
+
+    TObject* o = fEntry->fData;
+    Info("HandleCopy", "Will copy object of type %s", o->ClassName());
+
+
+    ULong_t  newRun   = fRunInput.GetHexNumber();
+    UShort_t newSys   = fSysSelect.GetSelected();
+    UShort_t newSNN   = fSNNInput.GetIntNumber();
+    Short_t  newFld   = fFldSelect.GetSelected();
+    Bool_t   mc       = fMCButton.IsDown();
+    Bool_t   sat      = fSatButton.IsDown();
+    ULong_t  oldRun   = fEntry->fRunNo;
+    UShort_t oldSys   = fEntry->fSys;
+    UShort_t oldSNN   = fEntry->fSNN;
+    Short_t  oldFld   = fEntry->fField;
+
+    TString msg;
+    msg = Form("Will copy %lu/%hu/%hu/%hd -> %lu/%hu/%hu/%hd (%s,%s) in %s",
+              oldRun, oldSys, oldSNN, oldFld, 
+              newRun, newSys, newSNN, newFld, 
+              (mc ? "mc" : "real"), (sat ? "satellite" : "nominal"),
+              table.Data());
+    
+    Int_t ret = 0;
+    new TGMsgBox(gClient->GetRoot(), gClient->GetRoot(), 
+                "Confirm copy of OADB entry",
+                msg.Data(), 0, kMBOk|kMBCancel, &ret);
+    
+    if (ret ==  kMBCancel) {
+      Info("HandleCopy", "%s CANCELLED", msg.Data());
+      return;
+    }
+    Info("HandleCopy", "%s CONFIRMED", msg.Data());
+
+    if (!fDB->CopyEntry(table, 
+                       oldRun, oldSys, oldSNN, oldFld, 
+                       newRun, newSys, newSNN, newFld, 
+                       mc, sat)) { 
+      // Warning("HandleCopy", "Copy failed!");
+      return;
+    }
+    fDB->Update();
+    
+
+    // o->Draw(fOptionsText.GetText()); 
+  }
   void HandlePDF()
   {
     if (!fEntry) { 
@@ -715,6 +835,7 @@ struct ForwardOADBGUI
   TGTextButton      fFileSelect;
   TGTextEntry       fTablesText;
   TGTextButton      fOpenButton;
+  TGCheckButton     fRWButton;
   TGTextButton      fCloseButton;
   TGVerticalFrame   fSelectFrame;
   TGHorizontalFrame fTableFrame;
@@ -743,6 +864,7 @@ struct ForwardOADBGUI
   TGTextButton      fQueryButton;  
   TGTextButton      fListButton;
   TGTextButton      fPrintButton;
+  TGTextButton      fCopyButton;
   TGTextButton      fDrawButton;
   TGTextButton      fPDFButton;
   TGListView        fList;
index 44600c4c2986fef7440f91024a8775b91f0f2177..2b23eecff596178cca981413569269ff3ca48eb6 100644 (file)
@@ -185,11 +185,15 @@ struct QABase
 
     fTeX = new std::ofstream(Form("%s.tex", base));
     fHtml = new std::ofstream(Form("%s.html", base));
+    
+    TString texTitle(title);
+    texTitle.ReplaceAll("_", "-");
 
     *fTeX << "\\documentclass[landscape,a4paper,12pt]{article}\n"
+         << "\\nonstopmode\n"
          << "\\usepackage[margin=2cm,a4paper]{geometry}\n"
          << "\\usepackage{graphicx}\n"
-         << "\\title{{\\Huge\\bf " << title << "}}\n"
+         << "\\title{{\\Huge\\bf " << texTitle << "}}\n"
          << "\\author{{\\LARGE FMD Team}}\n"
          << "\\date{{\\Large \\today}}\n"
          << "\\begin{document}\n"
index 5395c777390475228230ba64e7c262f662d4b474..4ab48c99ca473637995da6fc0cf7e125624c94bc 100755 (executable)
@@ -12,42 +12,6 @@ logo=$ALICE_ROOT/PWGLF/FORWARD/analysis2/qa/fmd_logo.png
 script=$ALICE_ROOT/PWGLF/FORWARD/analysis2/qa/script.js
 topmk=$ALICE_ROOT/PWGLF/FORWARD/analysis2/qa/makeIndex.sh
 
-# --- Help output ----------------------------------------------
-usage()
-{
-    cat <<EOF
-Usage: $0 [OPTIONS] -j [JOBID]
-       $0 [OPTIONS] -p PRODUCTION -P PASS 
-
-Options:
-       -h,--help                  This help 
-       -j,--jobid      NUMBER     The master job id of the production [$jobid]
-       -v,--verbose               Increase verbosity [$verb]
-       -m,--max-files  NUMBER     Max number of files to get [$maxf]
-       -M,--max-jobs   NUMBER     Max number of consequtive jobs [$maxjobs]
-       -t,--top        DIRECTORY  Output directory [$top]
-       -R,--also-results          Also get QAresults.root for each run
-       -Q,--qa-number  NUMBER     Custom QA id [$qanumber]
-       -p,--production IDENTIFIER Production identifier [$prodfull]
-       -P,--pass       IDENTIFIER Pass identifier [$passfull]
-       -l,--log-file              Log file output [$redir]
-       -b,--barrel     MODE       Fetch barrel data  [$barrel]
-       -f,--force                 Force re-run analysis [$force]
-       -V,--variance              Errors=variance (not min/max) [$variance]
-        -L,--local                 Local trending_<X>.root files [$from_local]
-       -d,--directory  DIR        Search custom AliEn directory [$path]
-
-Note the option -j and the options -p and -P are mutually exclusive,
-The option -Q is only used if the options -p and -P are given.
-Production identifiers are of the form LHC11h, LHC11h3, or LHC11h_2. 
-Pass identifers are of the form pass2, pass1_HLT, or cpass1.  
-If barrel mode>0, then do not assume ESD directory.  
-If barrel mode>1, then get trending_barrel.root and QAresults_barrel.root
-Option -d is for hand-made QA passes. 
-If optiond -d is not specified then official QA passes are assumed.
-EOF
-}
-
 # --- Check AliEn token ----------------------------------------------
 check_token()
 {
@@ -69,11 +33,37 @@ check_token()
 
 # --- Diagnostics output ---------------------------------------------
 verb=0
+print() { 
+    local col=$1 ; shift 
+    local lvl=$1 ; shift 
+    local opt=
+    if test $lvl -gt $verb; then return ; fi 
+    case $1 in 
+       -*) opt=$1 ; shift ;; 
+    esac
+    echo -e ${opt} "\e[${col}m$*\e[0m"
+    # echo -e ${opt} "\e[${col}m$*\e[0m"
+}
 mess()
 {
-    if test $1 -gt $verb ; then return ; fi 
-    shift
-    echo $*
+    print 95 $@ 
+}
+
+err() 
+{
+    echo -e "\e[1mError: \e[91m$*\e[0m" > /dev/stderr 
+}
+warn()
+{
+    echo -e "\e[1mWarning: \e[93m$*\e[0m" > /dev/stderr 
+}
+info() 
+{
+    print 96 0 $@ 
+}
+ok() 
+{
+    print 92 0 "OK"
 }
 
 # --- Handling of exit -----------------------------------------------
@@ -93,7 +83,7 @@ trap handle_exit EXIT
 last=
 handle_err()
 {
-    echo "Error: $last" 
+    err "$last"
     exit 1
 }
 enable_trap()
@@ -112,18 +102,18 @@ check_lock()
     lock=$loc/.lock
 
     if test -f $lock ; then 
-       echo "Another QA process is already running:" > /dev/stderr 
-       echo "Content of ${lock}:" > /dev/stderr 
+       err "Another QA process is already running:"
+       err "Content of ${lock}:"
        cat $lock > /dev/stderr 
        trap - EXIT
-    exit 1
+       exit 1
+    fi 
     local now=`date` 
-    cat <<EOF > $lock
-Process: $$
-User:    $USER
-Start:   $now
-EOF
-    fi
+    cat <<-EOF > $lock
+       Process: $$
+       User:    $USER
+       Start:   $now
+       EOF
 }
 
 # --- Parse production information -----------------------------------
@@ -155,56 +145,6 @@ prodpost=
 remainder=
 qanumber=0
 barrel=0
-get_parts()
-{
-    mess 1 "Parsing information from job $@" 
-    year=$1 ; shift 
-    prodfull=$1 ; shift 
-    local lrunn=$1 ; shift
-    local ltype=$1 ; shift 
-    passfull=$1 ; shift 
-    remainder=$1 
-
-    mess 10 "year=$year" 
-    mess 10 "prodfull=$prodfull" 
-    mess 10 "lrunn=$lrunn" 
-    mess 10 "ltype=$ltype" 
-    mess 10 "passfull=$passfull" 
-    mess 10 "remainder=$remainder"
-
-    if test "x$passfull" = "x" ; then 
-       remainder=
-       passfull=$ltype 
-    fi
-    case x$passfull in 
-       *pass*) ;; 
-       *) remainder=$passfull 
-           passfull= 
-           ;;
-    esac
-    parse_pass 
-    parse_prod
-
-    case x$remainder in 
-       xQA*) qanumber=`echo $remainder | sed 's/QA//'`  ;; 
-       *) ;; 
-    esac
-
-}
-# --- Get the index for information ----------------------------------
-skip=0
-jobu="http://alimonitor.cern.ch/prod/jobs.jsp?t="
-jobid=
-get_job() 
-{ 
-    mess 1 "Getting the job information" 
-    wget -q ${jobu}${jobid} -O job.html
-    local lskip
-    let lskip=$skip+1
-    p=`grep "/catalogue/index.jsp?path" job.html | head -n $lskip | tail -n 1 | sed -e 's,.*/alice/\(data\|sim\)/\([^<]*\)<.*,\2,' | tr '/' ' '` 
-    rm -f job.html
-    get_parts $p 
-}
 
 # --- Append path element --------------------------------------------
 append_to_path()
@@ -224,6 +164,7 @@ numf=0
 from_local=0
 type=data
 passid=
+mc=0
 get_filelist()
 {
     mess 3 "Getting file list" 
@@ -237,17 +178,12 @@ get_filelist()
        file=trending_barrel.root
        other=QAresults_barrel.root
     fi
-    case x$prodpost in 
-       x_*) ;; 
-       x) ;; 
-       *)  mess 3 "Assuming simulation output"
-           datd=sim 
-           type=sim
-           passfull=passMC
-           esdd= 
-           ;; 
-    esac
-    
+    if test $mc -gt 0 ; then 
+       datd=sim 
+       type=sim
+       esdd= 
+    fi 
+
     local paid=
     if echo "$passno" | grep -q -E '^[0-9]*[.]?[0-9]*$' ; then 
        if test "x$passfull" != "x" && test $passno -gt 0 ; then 
@@ -259,6 +195,7 @@ get_filelist()
        post=
     fi
     passid=${paid}
+    if test $mc -gt 0 ; then passid="passMC" ; fi 
     local post=${passpost}
     case x$post in 
        x_*) ;; 
@@ -288,32 +225,36 @@ get_filelist()
 EOF
     if test $from_local -lt 1 ; then 
 
-       mess 1 "Getting list of files from AliEn - can take minutes - be patient"
+       mess 1 "Get list of files from AliEn - can take minutes - be patient"
        mess 2 "alien_find ${path} ${search}"
-       files=`alien_find ${path} ${search} | grep -v "\(files found\|AND THE\)" 2>> ${redir}` 
+       files=`alien_find ${path} ${search} | \
+         grep -v "\(files found\|AND THE\)" 2>> ${redir}` 
     else 
-       files=`ls ${top}/${store}/trending_*.root | sed 's,${top}/${store}/,,g'`
+       files=`ls ${top}/${store}/*/input.root | \
+         sed 's,${top}/${store}/,,g'`
     fi
     for i in $files ; do 
        let numf=$numf+1
     done 
     mess 1 -n "Total of $numf files ... "
+    ret=$numf
     if test $maxf -lt 0 ; then 
        mess 1 "using all" 
     else
        mess 1 "using $maxf first of these"
+       ret=$maxf
     fi
+    return $ret
 }
 
 # --- Change permissions on files ------------------------------------
 fix_perm()
 {
-    # if test ! -f $1 ; then return ; fi 
-    chmod g+rwX $1 >> /dev/null 2>&1 
-    chmod o+rX $1 >> /dev/null 2>&1 
-    # 
-    # chmod g+rwX $1 >> ${redir} 2>&1 
-    # chmod o+rX $1 >> ${redir} 2>&1 
+    local tgt=$1
+    local opt= 
+    if test -d $tgt ; then opt="-R" ; fi 
+    chmod ${opt} g+rwX $tgt >> /dev/null 2>&1 
+    chmod ${opt} o+rX $tgt >> /dev/null 2>&1 
 }
 
 # --- Check if a file is OK ------------------------------------------
@@ -352,23 +293,19 @@ analyse_file()
     fi
 
     
-    mess 1 "Running runQA.sh '$inp' '$type' '$prodyear' '$prodfull' '$passid' '$r' in '$dir'"
+    mess 3 "runQA.sh '$inp' '$type' '$prodyear' '$prodfull' '$passid' '$r'"
     (cd $dir 
+       for i in QABase QAPlotter QARing QAStructs QATrender ; do 
+           ln -s ../${i}* . 
+       done 
        $ALICE_ROOT/PWGLF/FORWARD/analysis2/qa/runQA.sh \
-           "$inp" "$type" $prodyear "$prodfull" "$passid" "$r" 
-       ret=$? 
-       mess 2 " -> $ret")
-#     (cd $dir 
-#      root -l -b  <<EOF 
-# .L RunFileQA.C
-# RunFileQA("$inp", "$out", $prodyear, "$prodletter");
-# .q
-# EOF
-#      ret=$? 
-#      mess 2 " -> $ret"
-#      # rm -f ${scr}.C 
-#     ) 2>> $redir
-
+           "$inp" "$type" $prodyear "$prodfull" "$passid" "$r" > runQA.log 2>&1
+       ret=$? ) 
+    if test ! -f $dir/trending.root ; then ret=1 ; fi
+    mess 2 " -> $ret"
+    if test $ret -ne 0 ; then 
+       err "Failed to analyse $1"
+    fi
     return $ret
 }
 
@@ -443,10 +380,11 @@ submit_runs()
            local b=`echo $i | sed -e "s,${path},,"` 
            r=`echo $b | sed -e "s,/.*,,"` 
        else
-           r=`basename $i .root | sed 's/trending_//'` 
+            r=`basename \`dirname $i\` | sed 's/^0*//'`
        fi
 
-       printf "%3d/%3d: %s\n" $cur $max $r 
+       local m=`printf "%3d/%3d: %s\n" $cur $max $r` 
+       info "$m"
        runs[$counter]=$r
 
        let counter=$counter+1
@@ -520,151 +458,147 @@ copy_style()
 }      
 
 # --- Run the final trending -----------------------------------------
-variance=0
+variance=1
 make_trend()
 {
     local dir=$1 
     local ret=0
-    mess 1 -n "Analysing for trend $dir ... "
+    info -n "Analysing for trend $dir ... "
     (cd $dir 
-       echo "hadd trending.root 000*/trending.root"
+       mess 1 "hadd trending.root 000*/trending.root"
        rm -f trending.root 
        hadd -k trending.root 000*/trending.root 
-       $ALICE_ROOT/PWGLF/FORWARD/analysis2/qa/periodQA.sh trending.root 
-       ret=$?
-    )
+       if test $? -eq 0 && test -f trending.root ; then 
+         $ALICE_ROOT/PWGLF/FORWARD/analysis2/qa/periodQA.sh trending.root 
+         ret=$?
+       else 
+         ret=1
+        fi
+    ) >>${redir} 2>&1
+    if test $ret -ne 0 ; then 
+       err "Failed to make trending in $dir"
+    else
+       ok
+    fi
     return $ret
 }
 
-# --- Make index file ------------------------------------------------
-make_index()
+
+# --- Help output ----------------------------------------------
+usage()
 {
-    local dir=$1   ; shift  
-    local title=$1 ; shift
-    local desc=$1  ; shift 
-    mess 1 "Making index in $dir ($title)"
-    
-    (cd $dir
-       local date=`date` 
-       
-       rm -f index.html 
-
-       cat <<EOF > index.html
-<!DOCTYPE html>
-<html>
-  <head>
-    <title>$title</title>
-    <link rel='stylesheet' href='style.css'>
-    <link rel='shortcut icon' href='fmd_favicon.png' type='image/x-png'>
-  </head>
-  <body>
-    <h1><img style='width: 200px;' src='fmd_logo.png'>  &nbsp;$title</h1>
-EOF
-       if test ! "x$desc" = "x" ; then 
-           echo "<p>$desc</p>" >> index.html
-       fi
-       echo "      <ul>" >> index.html
-       for i in * ; do 
-           if test ! -d $i ; then continue ; fi 
-           echo "      <li><a href='$i'>$i</a></li>" >> index.html
-       done
-       echo "      </ul>" >> index.html 
-       if test "x$desc" = "x" ; then 
-           echo "      <div class='back'><a href='../'>Back</a></div>" \
-               >> index.html
-       fi
-       cat <<EOF >> index.html    
-    <div class='change'>Last update: $date</div>
-  </body>
-</html>
+    cat <<EOF
+Usage: $0 [OPTIONS] -p PRODUCTION [-P PASS]
+
+Options:
+  -b,--barrel       MODE       Fetch barrel data              [$barrel]
+  -d,--directory    DIR        Search custom AliEn directory  [$path]
+  -f,--force                   Force re-run analysis          [$force]
+  -h,--help                   This help 
+  -i,--no-index                Do not make index              [$index]
+  -l,--log-file                Log file output                [$redir]
+  -L,--local                   Local trending_<X>.root files  [$from_local]
+  -m,--max-files    NUMBER     Max number of files to get     [$maxf]
+  -M,--max-jobs     NUMBER     Max number of consequtive jobs [$maxjobs]
+  -p,--production   IDENTIFIER Production identifier          [$prodfull]
+  -P,--pass         IDENTIFIER Pass identifier                [$passfull]
+  -Q,--qa-number    NUMBER     Custom QA id                   [$qanumber]
+  -R,--also-results            Also get QAresults.root/run    [$also_results]
+  -t,--top          DIRECTORY  Output directory               [$top]
+  -T,--min-max                 Errors=min/max
+  -v,--verbose                Increase verbosity             [$verb]
+  -V,--variance                Errors=variance                [$variance]
+
+Production identifiers are of the form LHC11h, LHC11h3, or LHC11h_2. 
+Pass identifers are of the form pass2, pass1_HLT, or cpass1.  
+If barrel mode>0, then do not assume ESD directory.  
+If barrel mode>1, then get trending_barrel.root and QAresults_barrel.root
+Option -d is for hand-made QA passes. 
+If optiond -d is not specified then official QA passes are assumed.
 EOF
-       copy_style 
-       copy_aliroot_file $favicon
-       copy_aliroot_file $logo
-       fix_perm index.html
-       fix_perm . > /dev/null 2>&1 
-    )
 }
 
 
-# --- Pass command line options --------------------------------------
+# --- Parse command line options -------------------------------------
 redir=/dev/null
 maxf=-1
 top=.
+index=0
 while test $# -gt 0 ; do 
     case $1 in 
-       -h|--help) usage ; exit 0 ;; 
-       -v|--verbose)      let verb=$verb+1   ;; 
-       -j|--jobid)        jobid=$2           ; shift ;; 
+       -b|--barrel)       barrel=$2          ; shift ;;
+       -d|--directory)    path=$2            ; shift ;;
+       -f|--force)        let force=$force+1 ;; 
+       -h|--help)         usage              ; exit 0 ;; 
+       -i|--index)        index=1            ;; 
+       -l|--log-file)     redir=             ;; 
+       -L|--local)        from_local=1       ;;
        -m|--max-files)    maxf=$2            ; shift ;; 
        -M|--max-jobs)     maxjobs=$2         ; shift ;;
-       -t|--top)          top=$2             ; shift ;;
-       -R|--also-results) also_results=1     ;; 
+       -p|--production)   prodfull=$2        ; shift ; parse_prod ;;
+       -P|--pass)         passfull=$2        ; shift ; parse_pass ;;
        -Q|--qa-number)    qanumber=$2        ; shift ;;
-       -l|--log-file)     redir=             ;; 
-       -L|--local)        from_local=1       ;;
+       -R|--also-results) also_results=1     ;; 
+       -t|--top)          top=$2             ; shift ;;
+       -T|--min-max)      variance=0         ;; 
+       -v|--verbose)      let verb=$verb+1   ;; 
        -V|--variance)     variance=1         ;;
-       -b|--barrel)       barrel=$2          ; shift ;;
-       -f|--force)        let force=$force+1 ;; 
-       -p|--production) 
-           prodfull=$2; shift; parse_prod ; year=20${prodyear} ;;
-       -P|--pass) 
-           passfull=$2; shift; parse_pass ;;
-       -d|--directory)    path=$2              ; shift ;;
        *) echo "$0: Unknown argument: $1" > /dev/stderr ; exit 1 ;; 
     esac
     shift
 done
-# --- Initial setup --------------------------------------------------
-# First, check we have a valid AliEn token, then retrieve the job 
-# information to parse out the location of the files we need, and 
-# finally make our output directory and check the lock 
+# === Initial setup ==================================================
+# --- Check for AliEn token ------------------------------------------
 check_token
 
-if test ! "x$jobid" = x ; then 
-    if test ! "x$prodfull" = "x" || test ! "x$passfull" = "x" ; then 
-       cat <<EOF > /dev/stderr
-Option -j ${jobid} and options -p and -P are mutually exclusive 
-EOF
-       exit 1
-    fi
-    get_job
+# --- Check settings -------------------------------------------------
+if test "x$prodfull" = "x" ; then
+    err "No production specified" 
+    exit 1
+fi 
+if test "x$prodpost" = "x" && test "x$passfull" = "x" ; then 
+    err "No pass specified for non-MC production"
+    exit 1
+elif test "x$passfull" = "x" || test "x$passfull" = "xpassMC"; then 
+    warn "No pass specified, assuming MC"
+    passfull=
+    mc=1
+fi 
+
+# --- Construct output -----------------------------------------------
+proddir=
+passdir=
+store=
+year=20${prodyear}
+if test $mc -gt 0 ; then 
+    proddir=${prodfull}
+    passdir=passMC
+    store=sim
 else 
-    if test "x$prodfull" = "x" || test "x$passfull" = "x" ; then 
-       cat<<EOF > /dev/stderr
-When specifying prodcution and/or pass both options -p and -P _must_ 
-be specified. 
-EOF
-       exit 1
-    elif test ! "x$jobid"  = "x" ; then 
-       cat <<EOF > /dev/stderr
-Option -j and options -p ${prodfull} and -P ${passfull} are mutually exclusive 
-EOF
-       exit 1
+    proddir=LHC${prodyear}${prodletter}
+    store=data
+    if test "x$passno" = "x" ; then 
+       err "No pass number"
+    fi 
+    if test "x$passpre" != "x" ; then 
+       passdir=${passpre}
     fi
-fi     
-
-proddir=LHC${prodyear}${prodletter}
-store=${proddir}
-if test ! "x$passno" = "x" ; then 
-    if test "x${passpre}" = "xv" || test "x${passpre}" = "xc"; then 
-       store=${store}/${passpre}pass${passno}
-    else
-       store=${store}/pass${passno}
+    passdir=${passdir}pass${passno}
+    if test "x$passpost" != "x" ; then 
+       passdir=${passdir}_${passpost}
     fi
-elif test ! "x$prodpost" = "x" ; then 
-    proddir=${proddir}${prodpost}
-    store=${proddir}/sim
-elif test ! "x$remainder" = "x" ; then 
-    store=${store}/${remainder}
-fi
+    if test "x$remainder" != "x" ; then 
+       passdir=${passdir}/${remainder}
+    fi
+fi 
+store=${store}/${year}/${proddir}/${passdir}
 if test ! "x$qanumber" = "x" && test $qanumber -gt 0 ; then 
     store=${store}_QA${qanumber}
 fi
 mkdir -p ${top}/$store 
-fix_perm ${top}/${proddir}
 fix_perm ${top}/$store
 
+# --- Check for logging ----------------------------------------------
 if test "x$redir" = "x" ; then 
     redir=${top}/$store/qa.log 
     rm -f $redir
@@ -693,16 +627,20 @@ cat <<EOF
        Use variance:           ${variance}
        Use pre-downloaded:     ${from_local}
 EOF
+
 # --- Do a search to find our files ----------------------------------
 get_filelist
-
+nf=$?
+if test $nf -le 0 ; then 
+    err "No files to process"
+    exit 1
+fi
 if test $maxf -gt 0 && test $maxf -lt $numf ; then 
     numf=$maxf 
 fi
 
 # --- Copy scripts to target and compile -----------------------------
-for i in QABase.h QAPlotter.C QARing.h QAStructs.h QATrender.C \
-    RunFileQA.C RunFinalQA.C ; do
+for i in QABase.h QAPlotter.C QARing.h QAStructs.h QATrender.C ; do
     cp $ALICE_ROOT/PWGLF/FORWARD/analysis2/qa/$i ${store}/${i}
     rm -f ${store}/`echo $i | tr '.' '_'`.{so,d}
     fix_perm ${store}/${i}
@@ -713,14 +651,14 @@ gROOT->LoadMacro("QABase.h++g");
 gROOT->LoadMacro("QATrender.C++g");
 .q
 EOF
-)
+) 2>> ${redir}
 mess 1 "Compiling QAPlotter.C"
 (cd $store && root -l -b <<EOF 
 gROOT->LoadMacro("QABase.h++g");
 gROOT->LoadMacro("QAPlotter.C++g");
 .q
 EOF
-)
+) 2>> ${redir}
 (cd ${store} && for i in *.so *.d ; do fix_perm $i ; done)
 
 # --- Now get and analyse each run -----------------------------------
@@ -730,19 +668,23 @@ analyse_runs ${top}/$store $numf $files
 make_trend ${top}/$store
 
 # --- Make index files -----------------------------------------------
-make_index ${top}/${proddir} ${proddir}
-# make_index ${top} "QA for the FMD" \
-#    "For more information see <a href='https://twiki.cern.ch/twiki/bin/viewauth/ALICE/FMDQA'>TWiki pages</a>."
-$topmk --title "QA for the FMD" \
-    --description "For more information see <a href='https://twiki.cern.ch/twiki/bin/viewauth/ALICE/FMDQA'>TWiki pages</a>." \
-    --link \
-    --max-depth 2 \
-    --output index.html 
-fix_perm index.html
-copy_aliroot_file $script
-
+if test $index -gt 0 ; then 
+    info -n "Making index ... "
+    desc="For more information see <a href='https://twiki.cern.ch/twiki/"
+    desc="${desc}bin/viewauth/ALICE/FMDQA'>TWiki pages</a>."
+    $topmk --title "QA for the FMD" \
+       --description "$desc" \
+       --link \
+       --max-depth 4 \
+       --output index.html 
+    # >> ${redir} 2>&1 
+    fix_perm index.html
+    copy_aliroot_file $script
+    ok
+fi 
 chmod -R g+rwX ${top}/${proddir} >> ${redir} 2>&1
 
+
 #
 # EOF
 #