Index: trunk/MagicSoft/Mars/Changelog
===================================================================
--- trunk/MagicSoft/Mars/Changelog	(revision 8968)
+++ trunk/MagicSoft/Mars/Changelog	(revision 8969)
@@ -20,4 +20,25 @@
 
 
+ 2008/06/18 Thomas Bretz
+
+   * datacenter/macros/buildsequenceentries.C:
+     - replaced the old calculation of the run-time of one sequence
+       by a more sophisticated using the TIMEDIFF function
+
+   * mjobs/MJStar.cc:
+     - Use File id instead of run number
+
+   * mjobs/MSequence.[h,cc]:
+     - reorganized header
+     - implemented new scheme including file numbers
+     - increased class version number accordingly
+     - removed some obsolete old, never used, functions and comments
+
+   * mraw/MRawRunHeader.[h,cc]:
+     - renamed RunID to TypeID
+     - return 0 in RunLength if one of the times is invalid
+
+
+
  2008/06/17 Daniel Hoehne
 
@@ -29,5 +50,5 @@
        the relevant parameters in the MC database
 
-   * datacenter/scripts/[runmccallisto, runmcstar]:
+   * datacenter/scripts/runmccallisto, datacenter/scripts/runmcstar:
      - added
 
Index: trunk/MagicSoft/Mars/mjobs/MJStar.cc
===================================================================
--- trunk/MagicSoft/Mars/mjobs/MJStar.cc	(revision 8968)
+++ trunk/MagicSoft/Mars/mjobs/MJStar.cc	(revision 8969)
@@ -268,8 +268,8 @@
 
     // Plot the trigger pattern rates vs. run-number
-    MH3 hrate("MRawRunHeader.fRunNumber", "MTriggerPattern.GetUnprescaled");
+    MH3 hrate("MRawRunHeader.GetFileID", "MTriggerPattern.GetUnprescaled");
     hrate.SetWeight("1./MRawRunHeader.GetRunLength");
     hrate.SetName("Rate");
-    hrate.SetTitle("Event rate after cleaning [Hz];Run Number;Trigger Type;");
+    hrate.SetTitle("Event rate after cleaning [Hz];File Id;Trigger Type;");
     hrate.InitLabels(MH3::kLabelsX);
     hrate.DefaultLabelY("ERROR");
Index: trunk/MagicSoft/Mars/mjobs/MSequence.cc
===================================================================
--- trunk/MagicSoft/Mars/mjobs/MSequence.cc	(revision 8968)
+++ trunk/MagicSoft/Mars/mjobs/MSequence.cc	(revision 8969)
@@ -18,5 +18,5 @@
 !   Author(s): Thomas Bretz, 8/2004 <mailto:tbretz@astro.uni-wuerzburg.de>
 !
-!   Copyright: MAGIC Software Development, 2004-2007
+!   Copyright: MAGIC Software Development, 2004-2008
 !
 !
@@ -80,5 +80,5 @@
 //
 //   # List of all runs of this sequence (not needed)
-//   Runs: 31015 31016 31017 31018 31019 31020 31021 31022 31023 31024 31025 31026 31027 31028 31029 31030 31031 31032
+//   Runs: 31015:31017 31018 31019.0 31019.3 31019.5:7 31020+ 31021::3
 //
 //   # List of all calibration runs of this sequence (necessary if accessed)
@@ -87,5 +87,7 @@
 //   PedRuns: 31018
 //   # List of all data runs belonging to this sequence (necessary)
-//   DatRuns: 31019 31020 31022 31023 31024 31025 31027 31028 31030 31032
+//   DatRuns: 31019.0 31019.3 31019:5:7 31020+ 31021::3
+//
+//   Run00031020: :3 7:9 15
 //
 //   # Just for fun ;-) (not needed, but helpful)
@@ -94,4 +96,25 @@
 // ===========================================================================
 //
+//   Runs are devided into file since run 1000000. These Run-/Filenumbers
+//   are given by a dot. X.Y means Run X, File Y.
+//
+//   In the Runs, CalRuns, PedRuns and DatRuns tag you can use
+//   several abbreviationa:
+//
+//    31015:31017     means      31015.0 31016.0 31017.0
+//    31018           means      31018.0
+//    31019.3         means      31019.3
+//    31019.5:7       means      31019.5 31019.6 31019.7
+//    31020+          means      file list for run 21020 given below
+//    31021::3        means      31021.0 31021.1 31021.2 31021.3
+//
+//   For the run-list defined above (note the number must have 8 digits,
+//   for example 'Run00031020') you can also use abbreviations:
+//
+//    :3              means      0 1 2 3
+//    7:9             means      7 8 9
+//
+// ===========================================================================
+//
 //  For special cases you can also setup a sequence directly from a macro,
 //  for example:
@@ -101,7 +124,7 @@
 //    MSequence seq;
 //    seq.SetNight("2004-07-06");
-//    seq.AddPedRuns(31751);
-//    seq.AddCalRuns(31752);
-//    seq.AddDatRuns(31753, 31764);
+//    seq.AddRun(31751, 'P');
+//    seq.AddRun(31752, 'C');
+//    seq.AddRuns(31753, 31764, 'D');
 //    seq.SetupPedRuns(pediter);
 //    seq.SetupCalRuns(caliter);
@@ -114,5 +137,5 @@
 //    MSequence seq;
 //    seq.SetNight("2004-07-06");
-//    seq.AddRuns(31753, 31764);
+//    seq.AddFiles(31753, 0, 120);
 //    seq.SetupRuns(iter);
 //    seq.SetupPedRuns(iter, "/mypath", "[DPC]");
@@ -129,4 +152,11 @@
 //   + fExclRuns
 //
+//  Class Version 5:
+//   + fRunsSub
+//   + fDatRunsSub
+//   + fPedRunsSub
+//   + fCalRunsSub
+//   + fExclRunsSub
+//
 /////////////////////////////////////////////////////////////////////////////
 #include "MSequence.h"
@@ -135,5 +165,5 @@
 
 #include <TEnv.h>
-#include <TRegexp.h>
+#include <TPRegexp.h>
 #include <TSystem.h> // TSystem::ExpandPath
 
@@ -151,28 +181,156 @@
 using namespace std;
 
-MSequence::~MSequence()
-{
-    /*
-    TExMapIter iter(&fFileNames);
-
-    Long_t key, val;
-
-    while (iter.Next(key, val))
-        delete (TString*)val;
-        */
-}
-
-
-// --------------------------------------------------------------------------
-//
-// Copy the run numbers from the TString runs into the TArrayI data.
-// Runs which are twice in the list are only added once. In this case
+// --------------------------------------------------------------------------
+//
+// This adds an run/file entry to the data/sub arrays. If it is already
+// contained a waring is printed.
+//
+void MSequence::AddEntry(Int_t run, Int_t file, TArrayI &data, TArrayI &sub) const
+{
+    const Int_t n = data.GetSize();
+
+    // skip already existing entries
+    if (IsContained(data, sub, run, file))
+    {
+        *fLog << warn << "WARNING - File " << run << "." << file << " already in list... skipped." << endl;
+        return;
+    }
+
+    if (run<1000000 && file>0)
+        *fLog << warn << "WARNING - Run number " << run << "<" << "1,000,000 but file " << file << ">0..." << endl;
+
+    // set new entry
+    data.Set(n+1);
+    sub.Set(n+1);
+
+    data[n] = run;
+    sub[n]  = file;
+}
+
+// --------------------------------------------------------------------------
+//
+// Evaluate a token in thr Run string. Add the coresponding run/files
+// with AddEntry
+//
+void MSequence::EvalEntry(const TEnv *env, const TString &prefix, const TString &num, TArrayI &data, TArrayI &sub) const
+{
+    // Split entry into run and file
+    const Int_t run = num.Atoi();
+
+    // Syntax error forbidden by construction
+    const Ssiz_t p1 = num.First('.');
+    const Ssiz_t p2 = num.Last(':');
+
+    // ---------------------------------------------------------------
+
+    const Int_t n1 = atoi(num.Data()+p1+1);
+    const Int_t n2 = atoi(num.Data()+p2+1);
+
+    // ---------------------------------------------------------------
+    //  p1>=0 && p2<0  (. but no :)    run.n1     run.file1
+    if (p1>=0 && p2<0)
+    {
+        AddEntry(run, n1, data, sub);
+        return;
+    }
+
+    // ---------------------------------------------------------------
+    //  p1>=0 && p2>=0  (. and :)      run:n1:n2  run.file1-run.file2
+    if (p1>=0 && p2>=0)
+    {
+        if (n2<n1)
+        {
+            *fLog << warn << "WARNING - Invalid range '" << num << "'... ignored." << endl;
+            return;
+        }
+
+        for (int i=n1; i<=n2; i++)
+            AddEntry(run, i, data, sub);
+        return;
+    }
+
+    // ---------------------------------------------------------------
+    //  p1<0 && p2>=0  (no . but :)    n1:n2      run1-run2
+    if (p1<0 && p2>=0)
+    {
+        if (n2<run)
+        {
+            *fLog << warn << "WARNING - Invalid range in '" << num << "'... ignored." << endl;
+            return;
+        }
+
+        for (int i=run; i<=n2; i++)
+            AddEntry(i, 0, data, sub);
+        return;
+    }
+
+    // ---------------------------------------------------------------
+    //  p0<0 and p1<0  (no . and no :)   run     run
+
+    if (!num.EndsWith("+"))
+    {
+        AddEntry(run, 0, data, sub);
+        return;
+    }
+
+    if (!env)
+        return;
+
+    TPRegexp regexp("([0-9]*:[0-9]+|[0-9]+(:[0-9]*)?)( +|$)");
+
+    TString files = GetEnvValue2(*env, prefix, Form("Run%08d", run), "");
+    if (files.IsNull())
+    {
+        AddEntry(run, 0, data, sub);
+        return;
+    }
+
+    while (!files.IsNull())
+    {
+        const TString num = files(regexp);
+        if (num.IsNull())
+        {
+            *fLog << warn << "WARNING - File in run " << run << " is NaN (not a number): '" << files << "'" << endl;
+            break;
+        }
+
+        const Ssiz_t p1 = num.First(':');
+        if (p1>=0)
+        {
+            const Int_t n1 = atoi(num.Data());
+            const Int_t n2 = atoi(num.Data()+p1+1);
+
+            if (n2<n1)
+            {
+                *fLog << warn << "WARNING - Invalid range in '" << num << "'... ignored." << endl;
+                return;
+            }
+
+            // FIXME: n2==0 || n2<n1
+            for (int i=n1; i<=n2; i++)
+                AddEntry(run, i, data, sub);
+        }
+        else
+        {
+            const Int_t file = atoi(num.Data());
+            AddEntry(run, file, data, sub);
+        }
+
+        files.Remove(0, files.First(num)+num.Length());
+    }
+}
+
+// --------------------------------------------------------------------------
+//
+// Interprete the TString and add the run/files to the arrays.
+// Run/files which are twice in the list are only added once. In this case
 // a warning is emitted.
 //
-void MSequence::Split(TString &runs, TArrayI &data) const
-{
-    const TRegexp regexp("[0-9]+");
+void MSequence::Split(TString &runs, TArrayI &data, TArrayI &sub, const TEnv *env, const TString prefix) const
+{
+    TPRegexp regexp("^[0-9]+([+]|(:|[.]([0-9]*:)?)[0-9]+)?( +|$)");
 
     data.Set(0);
+    sub.Set(0);
 
     runs.ReplaceAll("\t", " ");
@@ -182,49 +340,39 @@
     {
         const TString num = runs(regexp);
-
         if (num.IsNull())
         {
-            *fLog << warn << "WARNING - Run is NaN (not a number): '" << runs << "'" << endl;
+            *fLog << warn << "WARNING - Run syntax error: '" << runs << "'" << endl;
             break;
         }
 
-        const Int_t run = atoi(num.Data());
-        const Int_t n   = data.GetSize();
-
-        // skip already existing entries
-        int i;
-        for (i=0; i<n; i++)
-            if (data[i] == run)
-                break;
-
-        if (i<n)
-            *fLog << warn << "WARNING - Run #" << run << " already in list... skipped." << endl;
-        else
-        {
-            // set new entry
-            data.Set(n+1);
-            data[n] = run;
-        }
+        EvalEntry(env, prefix, num.Strip(TString::kTrailing), data, sub);
 
         runs.Remove(0, runs.First(num)+num.Length());
     }
 
-    MJob::SortArray(data);
-}
-
-UInt_t MSequence::SetupRuns(MDirIter &iter, const TArrayI &arr, FileType_t type, const char *path) const
-{
-    TString d(path);
+    SortArrays(data, sub);
+}
+
+// --------------------------------------------------------------------------
+//
+// Get the String from the TEnv file prefixed by prefix-name.
+// Intepret the string using Split which adds the run/files to the arrays.
+//
+void MSequence::Split(const TEnv &env, const TString &prefix, const char *name, TArrayI &data, TArrayI &sub) const
+{
+    TString str = GetEnvValue2(env, prefix, name, "");
+    Split(str, data, sub, &env, prefix);
+}
+
+// --------------------------------------------------------------------------
+//
+// Compile path from the given path name and expand it. If it IsNull()
+// the path is compiled as standard path from tha datacenter). The
+// returned path will end with a "/".
+//
+TString MSequence::GetPathName(TString d, FileType_t type) const
+{
+    // Setup path
     if (d.IsNull())
-        d = fDataPath;
-
-    const Bool_t def = d.IsNull();
-
-    // For this particular case we assume that the files are added one by
-    // one without wildcards.
-    const Int_t n0 = iter.GetNumEntries();
-
-    // Setup path
-    if (def)
     {
         d = GetStandardPath();
@@ -256,8 +404,101 @@
         d += '/';
 
+    return d;
+}
+
+// --------------------------------------------------------------------------
+//
+// Return the expression describing the file-name for the file defined
+// by i-th entry of the the given arrays. The file type identifier is
+// defined by type. The source name is replaced by a wildcard and
+// the extension is defined by the type as well.
+//
+TString MSequence::GetFileName(UInt_t i, const TArrayI &arr, const TArrayI &sub, FileType_t type) const
+{
+    const char *id="_";
+    switch (type)
+    {
+    case kRawDat:
+    case kRootDat:
+        id = "D";
+        break;
+    case kRawPed:
+    case kRootPed:
+        id = "P";
+        break;
+    case kRawCal:
+    case kRootCal:
+        id = "C";
+        break;
+    case kRawAll:
+    case kRootAll:
+        id = "[PCD]";
+        break;
+    case kCalibrated:
+        id = "Y";
+        break;
+    case kImages:
+        id = "I";
+        break;
+    }
+
+    // ------------- Create file name --------------
+    TString n = fNight.GetStringFmt("%Y%m%d_");
+
+    if (arr[i]>999999)
+        n += "M1_";
+
+    // R. DeLosReyes and T. Bretz
+    // Changes to read the DAQ numbering format. Changes takes place
+    // between runs 35487 and 00035488 (2004_08_30)
+    n += Form(arr[i]>35487 || fMonteCarlo ? "%08d" : "%05d", arr[i]);
+
+    if (arr[i]>999999 && sub.GetSize()>0)
+        n += Form(".%05d", sub[i]);
+
+    n += "_";
+    n += id;
+    n += "_*";
+
+    if (arr[i]<1000000)
+        n += "_E";
+
+    switch (type)
+    {
+    case kRawDat:
+    case kRawPed:
+    case kRawCal:
+    case kRawAll:
+        n += ".raw.?g?z?";
+        break;
+    default:
+        n += ".root";
+    }
+
+    return n;
+}
+
+// --------------------------------------------------------------------------
+//
+// Add the entries from the arrays to the MDirIter
+//
+UInt_t MSequence::SetupRuns(MDirIter &iter, const TArrayI &arr, const TArrayI &sub, FileType_t type, const char *path) const
+{
+    TString d(path);
+    if (d.IsNull())
+        d = fDataPath;
+
+    const Bool_t def = d.IsNull();
+
+    d = GetPathName(d, type);
+
+    // For this particular case we assume that the files are added one by
+    // one without wildcards.
+    const Int_t n0 = iter.GetNumEntries();
+
     Int_t excluded = 0;
     for (int i=0; i<arr.GetSize(); i++)
     {
-        if (IsExcluded(arr[i]))
+        if (IsExcluded(arr[i], sub[i]))
         {
             excluded++;
@@ -265,52 +506,5 @@
         }
 
-        // R. DeLosReyes and T. Bretz
-        // Changes to read the DAQ numbering format. Changes takes place
-        // between runs 35487 and 00035488 (2004_08_30)
-        const char *fmt = arr[i]>35487 || fMonteCarlo ? "%08d_%s_*_E" : "%05d_%s_*_E";
-
-        TString n;
-        const char *id="_";
-        switch (type)
-        {
-        case kRawDat:
-        case kRootDat:
-            id = "D";
-            break;
-        case kRawPed:
-        case kRootPed:
-            id = "P";
-            break;
-        case kRawCal:
-        case kRootCal:
-            id = "C";
-            break;
-        case kRawAll:
-        case kRootAll:
-            id = "[PCD]";
-            break;
-        case kCalibrated:
-            id = "Y";
-            break;
-        case kImages:
-            id = "I";
-            break;
-        }
-
-        // Create file name
-        n =  fNight.GetStringFmt("%Y%m%d_");
-        n += Form(fmt, arr[i], id);
-
-        switch (type)
-        {
-        case kRawDat:
-        case kRawPed:
-        case kRawCal:
-        case kRawAll:
-            n += ".raw.?g?z?";
-            break;
-        default:
-            n += ".root";
-        }
+        const TString n = GetFileName(i, arr, sub, type);
 
         // Check existance and accessibility of file
@@ -367,36 +561,6 @@
 // --------------------------------------------------------------------------
 //
-// Read the file fname as setup file for the sequence.
-//
-//void MSequence::GetFileNames(TEnv &env, const TArrayI &arr)
-//{
-    /*
-    for (int i=0; i<arr.GetSize(); i++)
-    {
-        // Get run number
-        const Int_t num = arr[i];
-
-        // Check if name already set
-        if (fFileNames.GetValue(num))
-            continue;
-
-        TString *str = new TString(env.GetValue(Form("%d", num), ""));
-        fFileNames.Add(num, (Long_t)str);
-        }
-        */
-//}
-
-// --------------------------------------------------------------------------
-//
-// Get a file name corresponding to the run-number num, returns 0 if n/a
-//
-//const char *MSequence::GetFileName(UInt_t num)
-//{
-//    return 0;
-    /*
-    TString *str = (TString*)fFileNames.GetValue(num);
-    return str ? str->Data() : 0;*/
-//}
-
+// Get LightCondition from resource file and convert it to LIghtCondition_t
+//
 MSequence::LightCondition_t MSequence::ReadLightCondition(TEnv &env, const char *prefix) const
 {
@@ -472,19 +636,9 @@
     fComment      = GetEnvValue2(env, prefix, "Comment",    "");
 
-    str = GetEnvValue2(env, prefix, "Runs", "");
-    Split(str, fRuns);
-    str = GetEnvValue2(env, prefix, "CalRuns", "");
-    Split(str, fCalRuns);
-    str = GetEnvValue2(env, prefix, "PedRuns", "");
-    Split(str, fPedRuns);
-    str = GetEnvValue2(env, prefix, "DatRuns", "");
-    Split(str, fDatRuns);
-    str = GetEnvValue2(env, prefix, "Exclude", "");
-    Split(str, fExclRuns);
-
-  //  GetFileNames(env, fRuns);
-  //  GetFileNames(env, fCalRuns);
-  //  GetFileNames(env, fPedRuns);
-  //  GetFileNames(env, fDatRuns);
+    Split(env, prefix, "Runs",    fRuns,     fRunsSub);
+    Split(env, prefix, "CalRuns", fCalRuns,  fCalRunsSub);
+    Split(env, prefix, "PedRuns", fPedRuns,  fPedRunsSub);
+    Split(env, prefix, "DatRuns", fDatRuns,  fDatRunsSub);
+    Split(env, prefix, "Exclude", fExclRuns, fExclRunsSub);
 
     // Dummies:
@@ -513,9 +667,184 @@
 // --------------------------------------------------------------------------
 //
+// Find a sequence of continous numbers in f starting at pos (looking
+// only at n entries). The output is converted into sequences
+// of X (single r) and X:Y (a sequence between x and r). The function
+// returnes when position pos+n is reached
+//
+TString MSequence::GetNumSequence(Int_t pos, Int_t n, const TArrayI &f) const
+{
+    TString str;
+
+    Int_t p=pos;
+    while (p<pos+n)
+    {
+        str += Form(" %d", f[p]);
+
+        if (p==pos+n-1)
+            break;
+
+        int i=0;
+        while (++i<n)
+            if (f[p+i]-f[p]!=i)
+                break;
+
+        if (i>1)
+            str += Form(":%d", f[p+i-1]);
+
+        p += i;
+    }
+
+    return str;
+}
+
+// --------------------------------------------------------------------------
+//
+// Search for a sequence of continous numbers in r with f==0 starting at p.
+// A new starting p is returned. The output is converted into sequences
+// of X (single r) and X:Y (a sequence between x and r). The function
+// returnes with the next f!=0.
+//
+TString MSequence::GetNumSequence(Int_t &p, const TArrayI &r, const TArrayI &f) const
+{
+    TString str;
+
+    while (p<r.GetSize() && f[p]==0)
+    {
+        // serach for the first entry which doesn't fit
+        // or has a file number which is != 0
+        int i=0;
+        while (p+ ++i<r.GetSize())
+            if (r[p+i]-r[p]!=i || f[p+i]!=0)
+                break;
+
+        // None found (i-1==0)
+        if (i-1==0)
+            return str;
+
+        // The last run found in the sequence (e.g. 5.0) is followed
+        // by an identical run number but file != 0 (e.g. 5.1)
+        if (p+i<f.GetSize() && r[p+i]==r[p] && f[p+i]!=0)
+            i--;
+
+        // Now we have to check again whether found no valid entry
+        if (i-1==0)
+            return str;
+
+        str += Form(" %d", r[p]);
+        // p now points to the last entry which fits and
+        // has a file number == 0
+        p += i-1;
+        // Only one      found (i-1==1)
+        // More tahn one found (i-1>1)
+        str += i-1==1 ? " " : ":";
+        str += Form("%d", r[p]);
+
+        // One step forward
+        p++;
+    }
+
+    return str;
+}
+
+// --------------------------------------------------------------------------
+//
+// Print the runs in a compressed wa. Returns the RunXXXXXXX string
+// simplyfing the file setup
+//
+TString MSequence::PrintRuns(const char *pre, const char *name, const TArrayI &r, const TArrayI &f) const
+{
+    if (r.GetSize()==0)
+        return "";
+
+    gLog << pre << name;
+    if (f.GetSize()==0)
+        const_cast<TArrayI&>(f).Set(r.GetSize());
+
+#ifdef DEBUG
+    for (int i=0; i<r.GetSize(); i++)
+        gLog << "  " << r[i] << "." << f[i];
+    gLog << endl;
+    return "";
+#endif
+
+    TString str;
+
+    Int_t pos = 0;
+    while (pos<r.GetSize())
+    {
+        TString rc = GetNumSequence(pos, r, f);
+        if (!rc.IsNull())
+        {
+            gLog << rc;
+            continue;
+        }
+
+        Int_t n = GetSubArray(pos, r.GetSize(), (Int_t*)r.GetArray());
+        // end reached
+        if (n<0)
+            break;
+
+        // This can happen if it is the last entry
+        if (n==1)
+        {
+            gLog << " " << r[pos];
+            if (f[pos]>0)
+                gLog << "." << f[pos];
+        }
+        else
+        {
+            // Check for sequence
+            Bool_t isseq = kTRUE;
+            for (int i=1; i<n; i++)
+                if (f[pos+i]-f[pos]!=i)
+                    isseq=kFALSE;
+
+            if (isseq)
+            {
+                gLog << " " << r[pos] << ".";
+                if (f[pos]!=0)
+                    gLog << f[pos];
+                gLog << ":" << f[pos+n-1];
+            }
+            else
+            {
+                gLog << " " << r[pos] << "+";
+
+                str += '\n';
+                str += pre;
+                str += Form("Run%08d:", r[pos]);
+                str += GetNumSequence(pos, n, f);
+            }
+        }
+
+        pos += n;
+    }
+
+    gLog << endl;
+
+    return str;
+}
+
+// --------------------------------------------------------------------------
+//
+// Print the numbers in the classical way (one run after the other)
+//
+void MSequence::PrintRunsClassic(const char *pre, const char *name, const TArrayI &r) const
+{
+    gLog << pre << name;
+    for (int i=0; i<r.GetSize(); i++)
+        gLog << " " << r[i];
+    gLog << endl;
+}
+
+// --------------------------------------------------------------------------
+//
 // Print the contents of the sequence
 //
 void MSequence::Print(Option_t *o) const
 {
-    const TString pre = TString(o).Contains("prefixed") ? Form("Sequence%08d.", fSequence) : "";
+    const TString opt(o);
+
+    const TString pre = opt.Contains("prefixed") ? Form("Sequence%08d.", fSequence) : "";
 
     gLog << all;
@@ -550,41 +879,28 @@
     gLog << pre << "TriggerTable:   " << fTriggerTable << endl;
     gLog << pre << "HvSettings:     " << fHvSettings << endl << endl;
-    if (fRuns.GetSize()>0)
-    {
-        gLog << pre << "Runs:";
-        for (int i=0; i<fRuns.GetSize(); i++)
-            gLog << " " << fRuns[i];
-        gLog << endl;
-    }
-    if (fCalRuns.GetSize()>0)
-    {
-        gLog << pre << "CalRuns:";
-        for (int i=0; i<fCalRuns.GetSize(); i++)
-            gLog << " " << fCalRuns[i];
-        gLog << endl;
-    }
-    if (fPedRuns.GetSize()>0)
-    {
-        gLog << pre << "PedRuns:";
-        for (int i=0; i<fPedRuns.GetSize(); i++)
-            gLog << " " << fPedRuns[i];
-        gLog << endl;
-    }
-    if (fDatRuns.GetSize()>0)
-    {
-        gLog << pre << "DatRuns:";
-        for (int i=0; i<fDatRuns.GetSize(); i++)
-            gLog << " " << fDatRuns[i];
-        gLog << endl;
-    }
-    if (fExclRuns.GetSize()>0)
-    {
-        gLog << pre << "Exclude:";
-        for (int i=0; i<fExclRuns.GetSize(); i++)
-            gLog << " " << fExclRuns[i];
-        gLog << endl;
-    }
+
+    TString str;
+    if (!HasSubRuns() && opt.Contains("classic"))
+    {
+        PrintRunsClassic(pre, "Runs:     ", fRuns);
+        PrintRunsClassic(pre, "CalRuns:  ", fCalRuns);
+        PrintRunsClassic(pre, "PedRuns:  ", fPedRuns);
+        PrintRunsClassic(pre, "DataRuns: ", fDatRuns);
+        PrintRunsClassic(pre, "Exclude:  ", fExclRuns);
+    }
+    else
+    {
+        str += PrintRuns(pre, "Runs:     ", fRuns,     fRunsSub);
+        str += PrintRuns(pre, "CalRuns:  ", fCalRuns,  fCalRunsSub);
+        str += PrintRuns(pre, "PedRuns:  ", fPedRuns,  fPedRunsSub);
+        str += PrintRuns(pre, "DataRuns: ", fDatRuns,  fDatRunsSub);
+        str += PrintRuns(pre, "Exclude:  ", fExclRuns, fExclRunsSub);
+    }
+
     if (!fDataPath.IsNull())
         gLog << endl << pre << "DataPath: " << fDataPath << endl;
+
+    if (!str.IsNull())
+        gLog << str << endl;
 
     gLog << endl << pre << "Comment: " << fComment << endl;
@@ -604,5 +920,5 @@
 UInt_t MSequence::SetupPedRuns(MDirIter &iter, const char *path, Bool_t raw) const
 {
-    return SetupRuns(iter, fPedRuns, raw?kRawPed:kRootPed, path);
+    return SetupRuns(iter, fPedRuns, fPedRunsSub, raw?kRawPed:kRootPed, path);
 }
 
@@ -620,5 +936,5 @@
 UInt_t MSequence::SetupDatRuns(MDirIter &iter, const char *path, Bool_t raw) const
 {
-    return SetupRuns(iter, fDatRuns, raw?kRawDat:kRootDat, path);
+    return SetupRuns(iter, fDatRuns, fDatRunsSub, raw?kRawDat:kRootDat, path);
 }
 
@@ -636,5 +952,5 @@
 UInt_t MSequence::SetupAllRuns(MDirIter &iter, const char *path, Bool_t raw) const
 {
-    return SetupRuns(iter, fRuns, raw?kRawAll:kRootAll, path);
+    return SetupRuns(iter, fRuns, fRunsSub, raw?kRawAll:kRootAll, path);
 }
 
@@ -652,5 +968,5 @@
 UInt_t MSequence::SetupCalRuns(MDirIter &iter, const char *path, Bool_t raw) const
 {
-    return SetupRuns(iter, fCalRuns, raw?kRawCal:kRootCal, path);
+    return SetupRuns(iter, fCalRuns, fCalRunsSub, raw?kRawCal:kRootCal, path);
 }
 
@@ -668,74 +984,60 @@
 UInt_t MSequence::SetupDatRuns(MDirIter &iter, FileType_t type, const char *path) const
 {
-    return SetupRuns(iter, fDatRuns, type, path);
-}
-
-// --------------------------------------------------------------------------
-//
-// If you want to add runs manually, use this function.
-//
-UInt_t MSequence::AddRuns(UInt_t first, UInt_t last, TArrayI *runs)
-{
-    if (last<first)
-    {
-        *fLog << warn << "MSequence::AddRuns - WARNING: Last runnumber " << last;
-        *fLog << " smaller than first " << first << "... ignored." << endl;
-        return 0;
-    }
-    if (!IsValid())
-    {
-        *fLog << inf << "Setting Sequence number to #" << first << endl;
-        fSequence = first;
-    }
-
-    const UInt_t nall = fRuns.GetSize();
-    const UInt_t nrun = runs ? runs->GetSize() : 0;
-    const UInt_t add  = last-first+1;
-
-    fRuns.Set(nall+add);
-    if (runs)
-        runs->Set(nrun+add);
-
-    for (UInt_t i=0; i<add; i++)
-    {
-        fRuns[nall+i] = first+i;
-        if (runs)
-            (*runs)[nrun+i] = first+i;
-    }
-    return add;
-}
-
-Bool_t MSequence::IsContained(const TArrayI &arr, UInt_t run) const
-{
-    for (int i=0; i<arr.GetSize(); i++)
-        if (run==(UInt_t)arr[i])
-            return kTRUE;
+    return SetupRuns(iter, fDatRuns, fDatRunsSub, type, path);
+}
+
+// --------------------------------------------------------------------------
+//
+// check if the run/file is contained in the arrays.
+//
+Bool_t MSequence::IsContained(const TArrayI &arr, const TArrayI &sub, UInt_t run, UInt_t file) const
+{
+    // Backward compatibilty
+    if (sub.GetSize()==0)
+    {
+        for (int i=0; i<arr.GetSize(); i++)
+            if (run==(UInt_t)arr[i])
+                return kTRUE;
+    }
+    else
+    {
+        for (int i=0; i<arr.GetSize(); i++)
+            if (run==(UInt_t)arr[i] && file==(UInt_t)sub[i])
+                return kTRUE;
+    }
     return kFALSE;
 }
 
-/*
-// --------------------------------------------------------------------------
-//
-// Check if num is found in arr. If it is found remove it. Copy all
-// following entries one back and decrease the array size by 1.
-//
-void MSequence::ExcludeRun(TArrayI &arr, UInt_t num)
-{
-    UInt_t *ptr = (UInt_t*)arr.GetArray();
-
-    Int_t i = 0;
-    for (i=0; i<arr.GetSize(); i++)
-        if (ptr[i]==num)
-            break;
-
-    if (i==arr.GetSize())
-        return;
-
-    for (; i<arr.GetSize()-1; i++)
-        ptr[i] = ptr[i+1];
-
-    arr.Set(arr.GetSize()-1);
-}
-*/
+// --------------------------------------------------------------------------
+//
+// Add a file (run/file) to the arrays defined by type (P, C, D, X)
+//
+void MSequence::AddFile(UInt_t run, UInt_t file, char type)
+{
+    TArrayI *r=0, *f=0;
+    switch (type)
+    {
+    case 'P':
+        r = &fPedRuns;
+        f = &fPedRunsSub;
+        break;
+    case 'D':
+        r = &fDatRuns;
+        f = &fDatRunsSub;
+        break;
+    case 'C':
+        r = &fCalRuns;
+        f = &fCalRunsSub;
+        break;
+    default:
+        r = &fRuns;
+        f = &fRunsSub;
+        break;
+    }
+
+    AddEntry(run, file, *r, *f);
+
+    MJob::SortArray(fExclRuns);
+}
 
 // --------------------------------------------------------------------------
@@ -743,20 +1045,10 @@
 // Exclude this run (i.e. add it to fExclRuns)
 //
-void MSequence::ExcludeRun(UInt_t num)
-{
-    /*
-     ExcludeRun(fRuns,    num);
-     ExcludeRun(fCalRuns, num);
-     ExcludeRun(fPedRuns, num);
-     ExcludeRun(fDatRuns, num);
-     */
-
-    if (IsExcluded(num))
-        return;
-
-    // set new entry
-    const Int_t n = fExclRuns.GetSize();
-    fExclRuns.Set(n+1);
-    fExclRuns[n] = num;
+void MSequence::ExcludeFile(UInt_t run, UInt_t file/*, Bool_t force*/)
+{
+//    if (force && IsExcluded(run, file))
+//        return;
+
+    AddEntry(run, file, fExclRuns, fExclRunsSub);
 
     MJob::SortArray(fExclRuns);
@@ -769,11 +1061,17 @@
 void MSequence::ExcludeRuns(TString runs)
 {
-    TArrayI data;
-    Split(runs, data);
-
+    // FIXME: Decode stream!!!
+
+    TArrayI data, sub;
+    Split(runs, data, sub);
     for (int i=0; i<data.GetSize(); i++)
-        ExcludeRun(data[i]);
-}
-
+        ExcludeFile(data[i], sub[i]);
+}
+
+// --------------------------------------------------------------------------
+//
+// Return the excluded runs (to be more precise:the excluded files)
+// in a string
+//
 const TString MSequence::GetExcludedRuns() const
 {
@@ -782,4 +1080,9 @@
     {
         rc += fExclRuns[i];
+        if (fExclRunsSub.GetSize()>0)
+        {
+            rc += ".";
+            rc += fExclRunsSub[i];
+        }
         rc += " ";
     }
@@ -828,2 +1131,67 @@
 }
 
+// --------------------------------------------------------------------------
+//
+// Search starting at position p in array arr and return the number
+// of elemets which are identical to the starting entry (the starting entry
+// is also counted)
+//
+Int_t MSequence::GetSubArray(Int_t p, Int_t n, Int_t *arr)
+{
+    Int_t *ptr0 = arr+p;
+
+    Int_t *ptr = ptr0;
+    Int_t *end = arr+n;
+
+    while (ptr<end && *ptr==*ptr0)
+        ptr++;
+
+    return ptr-ptr0;
+}
+
+// --------------------------------------------------------------------------
+//
+// Sort the array arr2 starting at position p for following entries
+// for which arr1 is equal. If not at least two entries are found which
+// can be sorted return -1.
+//
+// The absolute index of the next entry in arr1 is returned.
+//
+Int_t MSequence::SortArraySub(Int_t p, Int_t n, Int_t *arr1, Int_t *arr2)
+{
+    Int_t *ptr2 = arr2+p;
+
+    Int_t cnt = GetSubArray(p, n, arr1);
+    if (cnt==0)
+        return -1;
+
+    TArrayI srt(cnt, ptr2);
+    MJob::SortArray(srt);
+
+    memcpy(ptr2, srt.GetArray(), srt.GetSize()*sizeof(Int_t));
+
+    return p+srt.GetSize();
+}
+
+void MSequence::SortArrays(TArrayI &arr1, TArrayI &arr2)
+{
+    if (arr1.GetSize()!=arr2.GetSize())
+        return;
+
+    TArrayI idx(arr1.GetSize());
+
+    TArrayI srt1(arr1);
+    TArrayI srt2(arr2);
+
+    TMath::Sort(arr1.GetSize(), srt1.GetArray(), idx.GetArray(), kFALSE);
+
+    for (int i=0; i<arr1.GetSize(); i++)
+    {
+        arr1[i] = srt1[idx[i]];
+        arr2[i] = srt2[idx[i]];
+    }
+
+    Int_t p = 0;
+    while (p>=0)
+        p = SortArraySub(p, arr1.GetSize(), arr1.GetArray(), arr2.GetArray());
+}
Index: trunk/MagicSoft/Mars/mjobs/MSequence.h
===================================================================
--- trunk/MagicSoft/Mars/mjobs/MSequence.h	(revision 8968)
+++ trunk/MagicSoft/Mars/mjobs/MSequence.h	(revision 8969)
@@ -4,8 +4,4 @@
 #ifndef ROOT_TArrayI
 #include <TArrayI.h>
-#endif
-
-#ifndef ROOT_TExMap
-#include <TExMap.h>
 #endif
 
@@ -48,26 +44,49 @@
 
     TArrayI fRuns;
+    TArrayI fRunsSub;
+
     TArrayI fCalRuns;
+    TArrayI fCalRunsSub;
+
     TArrayI fPedRuns;
+    TArrayI fPedRunsSub;
+
     TArrayI fDatRuns;
+    TArrayI fDatRunsSub;
 
     TArrayI fExclRuns;
+    TArrayI fExclRunsSub;
 
     Bool_t fMonteCarlo;
 
-    //TExMap fFileNames;
+    // Helper for interpretation
+    void    AddEntry(Int_t run, Int_t file, TArrayI &data, TArrayI &sub) const;
+    void    EvalEntry(const TEnv *env, const TString &prefix, const TString &num, TArrayI &data, TArrayI &sub) const;
 
-    void Split(TString &runs, TArrayI &data) const;
-    //void GetFileNames(TEnv &env, const TArrayI &arr);
+    void    Split(TString &runs, TArrayI &data, TArrayI &sub, const TEnv *env=0, const TString prefix="") const;
+    void    Split(const TEnv &env, const TString &prefix, const char *name, TArrayI &data, TArrayI &sub) const;
 
     LightCondition_t ReadLightCondition(TEnv &env, const char *prefix) const;
 
-    const char *GetFileName(UInt_t num);
+    // Helper for file setup
+    TString GetPathName(TString d, FileType_t type) const;
+    TString GetFileName(UInt_t num, const TArrayI &arr, const TArrayI &sub, FileType_t type) const;
+    UInt_t  SetupRuns(MDirIter &iter, const TArrayI &arr, const TArrayI &file, FileType_t type, const char *path=0) const;
 
-    //UInt_t SetupRuns(MDirIter &iter, const TArrayI &arr, const char *path, char *id, Bool_t raw=kFALSE) const;
-    UInt_t SetupRuns(MDirIter &iter, const TArrayI &arr, FileType_t type, const char *path=0) const;
-    UInt_t AddRuns(UInt_t first, UInt_t last, TArrayI *runs);
-    void   ExcludeRun(TArrayI &arr, UInt_t num);
-    Bool_t IsContained(const TArrayI &arr, UInt_t num) const;
+    // Helper for Print()
+    TString GetNumSequence(Int_t pos, Int_t n, const TArrayI &f) const;
+    TString GetNumSequence(Int_t &pos, const TArrayI &n, const TArrayI &f) const;
+
+    void    PrintRunsClassic(const char *pre, const char *name, const TArrayI &r) const;
+    TString PrintRuns(const char *pre, const char *name, const TArrayI &r, const TArrayI &f) const;
+
+    // General helper
+    Bool_t  HasSubRuns() const { return fRunsSub.GetSize()!=0 || fDatRunsSub.GetSize()!=0 || fPedRunsSub.GetSize()!=0 || fCalRunsSub.GetSize()!=0 || fExclRunsSub.GetSize()!=0; }
+    Bool_t  IsContained(const TArrayI &arr, const TArrayI &sub, UInt_t num, UInt_t file) const;
+
+    // Some helpers to handle the arrays
+    static Int_t SortArraySub(Int_t p, Int_t n, Int_t *arr1, Int_t *arr2);
+    static void  SortArrays(TArrayI &arr1, TArrayI &arr2);
+    static Int_t GetSubArray(Int_t p, Int_t n, Int_t *arr1);
 
 public:
@@ -81,9 +100,8 @@
         fRuns(s.fRuns), fCalRuns(s.fCalRuns), fPedRuns(s.fPedRuns),
         fDatRuns(s.fDatRuns), fMonteCarlo(s.fMonteCarlo) { }
-    ~MSequence();
 
     // TObject
     void Print(Option_t *o) const;
-    void Print() const { Print(); } //*MENU*
+    void Print() const { Print(""); } //*MENU*
 
     const char *GetName() const;
@@ -93,9 +111,37 @@
     Bool_t IsValid() const { return fSequence!=(UInt_t)-1; }
     Bool_t IsMonteCarlo() const { return fMonteCarlo; }
-    Bool_t IsExcluded(UInt_t run) const { return IsContained(fExclRuns, run); }
-    Bool_t IsContained(UInt_t run) const { return IsContained(fCalRuns, run) || IsContained(fPedRuns, run) || IsContained(fDatRuns, run); }
+    Bool_t IsExcluded(UInt_t run, UInt_t file) const { return IsContained(fExclRuns, fExclRunsSub, run, file); }
+    Bool_t IsContained(UInt_t run, UInt_t file) const { return IsContained(fCalRuns, fCalRunsSub, run, file) || IsContained(fPedRuns, fPedRunsSub, run, file) || IsContained(fDatRuns, fDatRunsSub, run, file); }
+
+    // Setter
+    void SetNight(const char*night);
+
+    void AddRun(UInt_t run, char type='*') { AddFile(run, 0, type); }
+    void AddRuns(UInt_t run1, UInt_t run2, char type='*') { for (UInt_t i=run1; i<=run2; i++) AddFile(i, 0, type); }
+    void AddFile(UInt_t run, UInt_t file, char type='*');
+    void AddFiles(UInt_t run, UInt_t f1, UInt_t f2, char type='*') { for (UInt_t i=f1; i<=f2; i++) AddFile(run, i, type); }
+
+    void ExcludeFile(UInt_t num, UInt_t file=0);
+    void ExcludeRuns(TString runs);
 
     void SetMonteCarlo(Bool_t ismc=kTRUE) { fMonteCarlo=ismc; }
 
+    // Getter
+    UInt_t GetNumExclRuns() const { return fExclRuns.GetSize(); }
+
+    UInt_t GetSequence() const { return fSequence; }
+    UInt_t GetLastRun() const  { return fLastRun; }
+    UInt_t GetPeriod() const   { return fPeriod; }
+    Bool_t HasMoon() const { return fLightCondition==kMoon; }
+
+    LightCondition_t GetLightCondition() const { return fLightCondition; }
+
+    const MTime   &GetStart() const { return fStart; }
+    const MTime   &GetNight() const { return fNight; }
+    const TString &GetSource() const { return fSource; } 
+
+    const TString GetExcludedRuns() const;
+
+    // Filesystem interface
     UInt_t SetupPedRuns(MDirIter &iter, const char *path=0, Bool_t raw=kFALSE) const;
     UInt_t SetupDatRuns(MDirIter &iter, const char *path=0, Bool_t raw=kFALSE) const;
@@ -103,62 +149,14 @@
     UInt_t SetupCalRuns(MDirIter &iter, const char *path=0, Bool_t raw=kFALSE) const;
     UInt_t SetupDatRuns(MDirIter &iter, FileType_t type, const char *path=0) const;
- /*
-    UInt_t SetupPedRuns(MDirIter &iter, FileType_t type, const char *path=0);
-    UInt_t SetupDatRuns(MDirIter &iter, FileType_t type, const char *path=0);
-    UInt_t SetupAllRuns(MDirIter &iter, FileType_t type, const char *path=0);
-    UInt_t SetupCalRuns(MDirIter &iter, FileType_t type, const char *path=0);
-   */
 
-    // Getter
-//    UInt_t GetNumAllRuns() const { return fRuns.GetSize(); }
-//    UInt_t GetNumDatRuns() const { return fDatRuns.GetSize(); }
-//    UInt_t GetNumPedRuns() const { return fPedRuns.GetSize(); }
-//    UInt_t GetNumCalRuns() const { return fCalRuns.GetSize(); }
-    UInt_t GetNumExclRuns() const { return fExclRuns.GetSize(); }
-
-    UInt_t GetSequence() const { return fSequence; }
-    UInt_t GetLastRun() const  { return fLastRun; }
-    UInt_t GetPeriod() const   { return fPeriod; }
-    LightCondition_t GetLightCondition() const { return fLightCondition; }
-    Bool_t HasMoon() const { return fLightCondition==kMoon; }
-
-    const UInt_t GetFirstRun() const { return fRuns[0]; }
-    const UInt_t GetFirstCalRun() const { return fCalRuns[0]; }
-    const UInt_t GetLastCalRun() const { return fCalRuns[fCalRuns.GetSize()-1]; }
-//    const TArrayI &GetDatRuns() const { return fDatRuns; }
-//    const TArrayI &GetPedRuns() const { return fPedRuns; }
-//    const TArrayI &GetCalRuns() const { return fCalRuns; }
-    const TArrayI &GetExclRuns() const { return fExclRuns; }
-
-    const MTime &GetStart() const { return fStart; }
-    const MTime &GetNight() const { return fNight; }
-    const TString &GetSource() const { return fSource; } 
+    // Filesystem getter
+    const TString &GetFileName() const { return fFileName; }
+    const TString &GetDataPath() const { return fDataPath; }
 
     const TString GetStandardPath() const { return fMonteCarlo?"/magic/montecarlo/":"/magic/data/"; }
 
-    const TString &GetFileName() const { return fFileName; }
-    const TString &GetDataPath() const { return fDataPath; }
-
-    const TString GetExcludedRuns() const;
-
-    // Setter
-    void SetNight(const char*night);
-
-    UInt_t AddRuns(UInt_t first, UInt_t last)    { return MSequence::AddRuns(first, last, 0); }
-    UInt_t AddCalRuns(UInt_t first, UInt_t last) { return MSequence::AddRuns(first, last, &fCalRuns); }
-    UInt_t AddPedRuns(UInt_t first, UInt_t last) { return MSequence::AddRuns(first, last, &fPedRuns); }
-    UInt_t AddDatRuns(UInt_t first, UInt_t last) { return MSequence::AddRuns(first, last, &fDatRuns); }
-
-    UInt_t AddRuns(UInt_t num)    { return AddRuns(num, num); }
-    UInt_t AddCalRuns(UInt_t num) { return AddCalRuns(num, num); }
-    UInt_t AddPedRuns(UInt_t num) { return AddPedRuns(num, num); }
-    UInt_t AddDatRuns(UInt_t num) { return AddDatRuns(num, num); }
-
-    void ExcludeRun(UInt_t num);
-    void ExcludeRuns(TString runs);
-
     static Bool_t InflatePath(TString &seq, Bool_t ismc=kFALSE);
 
-    ClassDef(MSequence, 4)
+    ClassDef(MSequence, 5) // Describes a sequences, reads and writes sequence files
 };
 
