Index: /trunk/MagicSoft/Mars/Changelog
===================================================================
--- /trunk/MagicSoft/Mars/Changelog	(revision 9317)
+++ /trunk/MagicSoft/Mars/Changelog	(revision 9318)
@@ -129,4 +129,29 @@
      - corrected the emitted trigger positon
      - (re)set calibration pattern
+
+   * mbase/MLut.[h,cc]:
+     - added overload of Delete() function
+     - added IsDefault
+     - added SetDefault
+
+   * mfileio/MWriteRootFile.cc:
+     - fixed output in OpenFile
+
+   * mjobs/MSequence.cc:
+     - allow the "Night" resource to be empty
+
+   * msimcamera/MSimBundlePhotons.cc:
+     - some small improvements in case of empty maps
+
+   * msimcamera/MSimReadout.[h,cc]:
+     - reset gain. Use the new fConversionFactor instead
+     - removed some setting of fRunHeader
+
+   * msimcamera/MSimTrigger.[h,cc]:
+     - on useer request now offset and gain can be used to 
+       convert the signal back into units of phe
+     - added possibility to use empty lookup tables
+     - added debug output
+
 
 
Index: /trunk/MagicSoft/Mars/mbase/MLut.cc
===================================================================
--- /trunk/MagicSoft/Mars/mbase/MLut.cc	(revision 9317)
+++ /trunk/MagicSoft/Mars/mbase/MLut.cc	(revision 9318)
@@ -57,4 +57,57 @@
 }
 
+void MLut::Delete(Option_t *option)
+{
+    TObjArray::Delete(option);
+
+    fMaxEntries = 0;
+    fMinEntries = 0;
+
+    fMaxIndex = -1;
+}
+
+// --------------------------------------------------------------------------
+//
+// Check if it is a default lut which would just map every entry to itself
+// An empty Lut is a default lut
+//
+Bool_t MLut::IsDefault() const
+{
+    if (IsEmpty())
+        return kTRUE;
+
+    if (!HasConstantLength() || fMaxEntries!=1)
+        return kFALSE;
+
+    // Loop over all rows
+    for (Int_t y=0; y<GetEntriesFast(); y++)
+        if (GetRow(y)[0]!=y)
+            return kFALSE;
+
+    return kTRUE;
+}
+
+// --------------------------------------------------------------------------
+//
+// Setup a default lut which just maps n-entris to themself
+//
+void MLut::SetDefault(UInt_t n)
+{
+    Delete();
+
+    for (UInt_t y=0; y<n; y++)
+    {
+
+        MArrayI &idx = *new MArrayI(1);
+        idx[0] = y;
+        Add(&idx);
+    }
+
+    fMinEntries = 1;
+    fMaxEntries = 1;
+
+    fMaxIndex = n;
+}
+
 // --------------------------------------------------------------------------
 //
@@ -165,5 +218,6 @@
     MLut *lut = GetInverse(uniq);
 
-    Delete();
+    // Keep fMaxIndex
+    TObjArray::Delete();
 
     for (Int_t i=0; i<=fMaxIndex; i++)
@@ -188,8 +242,4 @@
 {
     Delete();
-
-    fMaxIndex   = -1;
-    fMaxEntries =  0;
-    fMinEntries =  0;
 
     while (1)
Index: /trunk/MagicSoft/Mars/mbase/MLut.h
===================================================================
--- /trunk/MagicSoft/Mars/mbase/MLut.h	(revision 9317)
+++ /trunk/MagicSoft/Mars/mbase/MLut.h	(revision 9318)
@@ -13,16 +13,21 @@
 {
 private:
-    UInt_t fMinEntries;
-    UInt_t fMaxEntries;
+    UInt_t fMinEntries;   // The minimum entries per row
+    UInt_t fMaxEntries;   // The maximum entries per row
 
-    Int_t  fMaxIndex;
+    Int_t  fMaxIndex;     // The maximum index fount in the lut
 
     MLut *GetInverse(Bool_t uniq=kTRUE) const;
 
 public:
-    MLut() : fMinEntries(0), fMaxEntries(0) { SetOwner(); }
+    MLut() : fMinEntries(0), fMaxEntries(0), fMaxIndex(0) { SetOwner(); }
+
+    // TObjArry
+    void Delete(Option_t *option="");
 
     // MLut Getter
     const MArrayI &GetRow(UInt_t i) const;
+
+     Int_t GetNumRows() const { return GetEntriesFast(); }
 
     UInt_t GetMaxEntries() const { return fMaxEntries; }
@@ -31,8 +36,12 @@
     Bool_t HasConstantLength() const { return fMinEntries==fMaxEntries; }
     Bool_t IsEmpty() const { return fMaxEntries==0; }
+    Bool_t IsDefault() const;
 
-    // MLut convertions
+    // MLut conversions
     void SetInverse(const MLut &lut, Bool_t uniq=kTRUE);
     void Invert(Bool_t uniq=kTRUE);
+
+    // Setter
+    void SetDefault(UInt_t n);
 
     // MLut I/O
Index: /trunk/MagicSoft/Mars/mfileio/MWriteRootFile.cc
===================================================================
--- /trunk/MagicSoft/Mars/mfileio/MWriteRootFile.cc	(revision 9317)
+++ /trunk/MagicSoft/Mars/mfileio/MWriteRootFile.cc	(revision 9318)
@@ -123,5 +123,5 @@
             if (TString(obj->GetName())=="/dev/null" && TString(obj->GetTitle())==title)
             {
-                *fLog << inf3 << "Found file '/dev/null' <Title=" << title << ">" << endl;
+                *fLog << inf2 << "Found open file '/dev/null' <Title=" << title << ">... re-using." << endl;
                 file = dynamic_cast<TFile*>(obj);
                 break;
@@ -138,4 +138,13 @@
             gSystem->ExpandPathName(fqp);
             file = dynamic_cast<TFile*>(gROOT->GetListOfFiles()->FindObject(fqp));
+        }
+
+        if (file)
+        {
+            *fLog << inf2;
+            *fLog << "Found open file '" << name << "'... re-using." << endl;
+            *fLog << inf3;
+            *fLog << "Make sure that you do NOT write to trees which are" << endl;
+            *fLog << "scheduled already by a different MWriteRootFile..." << endl;
         }
     }
@@ -162,9 +171,4 @@
     SetBit(kIsNotOwner);
 
-    *fLog << inf;
-    *fLog << "File '" << name << "' already open... using." << endl;
-    *fLog << inf3;
-    *fLog << "Make sure that you do NOT write to trees which are" << endl;
-    *fLog << "scheduled already by a different MWriteRootFile..." << endl;
     return fOut;
 }
Index: /trunk/MagicSoft/Mars/mjobs/MSequence.cc
===================================================================
--- /trunk/MagicSoft/Mars/mjobs/MSequence.cc	(revision 9317)
+++ /trunk/MagicSoft/Mars/mjobs/MSequence.cc	(revision 9318)
@@ -890,6 +890,11 @@
 
     str = GetEnvValue2(env, prefix, "Night", "");
-    str += " 00:00:00";
-    fNight.SetSqlDateTime(str);
+    if (str.IsNull())
+        fNight = MTime();
+    else
+    {
+        str += " 00:00:00";
+        fNight.SetSqlDateTime(str);
+    }
 
     fPeriod = fNight.GetMagicPeriod();
Index: /trunk/MagicSoft/Mars/msimcamera/MSimBundlePhotons.cc
===================================================================
--- /trunk/MagicSoft/Mars/msimcamera/MSimBundlePhotons.cc	(revision 9317)
+++ /trunk/MagicSoft/Mars/msimcamera/MSimBundlePhotons.cc	(revision 9318)
@@ -89,10 +89,14 @@
 
     // Read the look-up table
-    if (fLut.ReadFile(fFileName)<0)
+    fLut.Delete();
+    if (!fFileName.IsNull() && fLut.ReadFile(fFileName)<0)
         return kFALSE;
 
     // If the table is empty remove this task from the tasklist
     if (fLut.IsEmpty())
+    {
+        *fLog << inf << "Look-up table to bundle photons empty... skipping." << endl;
         return kSKIP;
+    }
 
     // Now invert the tablee. Otherwise we have to do a lot of
@@ -103,4 +107,6 @@
     if (!fLut.HasConstantLength() && fLut.GetMaxEntries()!=1)
         return kFALSE;
+
+    *fLog << inf << "Using look-up table from " << fFileName << endl;
 
     return kTRUE;
Index: /trunk/MagicSoft/Mars/msimcamera/MSimReadout.cc
===================================================================
--- /trunk/MagicSoft/Mars/msimcamera/MSimReadout.cc	(revision 9317)
+++ /trunk/MagicSoft/Mars/msimcamera/MSimReadout.cc	(revision 9318)
@@ -31,4 +31,10 @@
 // system.
 //
+// You can give a conversion factor from the unitx of your analog signal
+// to the units of your adc. This is a fixed factor because it is just
+// a matter of what the meaning of an adc count is, nothing which could
+// jitter or is a real part of the electronics. Such effects should
+// be simulated somewhere else.
+//
 //
 //  Input Containers:
@@ -73,5 +79,6 @@
 //
 MSimReadout::MSimReadout(const char* name, const char *title)
-: fRunHeader(0), fEvtHeader(0), fCamera(0), fPulsePos(0), fTrigger(0), fData(0)
+    : fRunHeader(0), fEvtHeader(0), fCamera(0), fPulsePos(0), fTrigger(0), fData(0),
+    fConversionFactor(1)
 {
     fName  = name  ? name  : "MSimReadout";
@@ -135,7 +142,4 @@
 
     fRunHeader->InitPixels(cam->GetNumPixels());
-    fRunHeader->SetValidMagicNumber();
-    fRunHeader->SetSourceInfo("MonteCarlo");  // "Muon" from first event??
-    fRunHeader->SetReadyToSave();
 
     fData->InitRead(fRunHeader);
@@ -209,6 +213,5 @@
     }
 
-    const Float_t gain      = 64./1;
-    const Float_t offset    = 128;
+    const Float_t offset    = 0;//128;
     const UInt_t  max       = fData->GetMax();
 
@@ -230,5 +233,5 @@
         {
             Float_t slice = j+trig>=(Int_t)sig.GetSize() ? offset :
-                sig[j+trig] * gain + offset;
+                sig[j+trig] * fConversionFactor + offset;
 
             // FIXME: Handle/Implement saturation!
@@ -257,2 +260,20 @@
     return kTRUE;
 }
+
+// --------------------------------------------------------------------------
+//
+// Read the parameters from the resource file.
+//
+//  ConversionFactor: 1
+//
+Int_t MSimReadout::ReadEnv(const TEnv &env, TString prefix, Bool_t print)
+{
+    Bool_t rc = kFALSE;
+    if (IsEnvDefined(env, prefix, "ConversionFactor", print))
+    {
+        rc = kTRUE;
+        fConversionFactor = GetEnvValue(env, prefix, "ConversionFactor", fConversionFactor);
+    }
+
+    return rc;
+}
Index: /trunk/MagicSoft/Mars/msimcamera/MSimReadout.h
===================================================================
--- /trunk/MagicSoft/Mars/msimcamera/MSimReadout.h	(revision 9317)
+++ /trunk/MagicSoft/Mars/msimcamera/MSimReadout.h	(revision 9318)
@@ -24,8 +24,13 @@
     MRawEvtData      *fData;       //! Digitized FADC signal
 
+    Double_t fConversionFactor;    // Conversion factor (arbitrary) from analog signal to FADC counts
+
     // MTask
     Int_t  PreProcess(MParList *pList);
     Int_t  Process();
     Bool_t ReInit(MParList *pList);
+
+    // MParContainer
+    Int_t ReadEnv(const TEnv &env, TString prefix, Bool_t print=kFALSE);
 
 public:
Index: /trunk/MagicSoft/Mars/msimcamera/MSimTrigger.cc
===================================================================
--- /trunk/MagicSoft/Mars/msimcamera/MSimTrigger.cc	(revision 9317)
+++ /trunk/MagicSoft/Mars/msimcamera/MSimTrigger.cc	(revision 9318)
@@ -82,4 +82,7 @@
 #include "MTriggerPattern.h"
 
+#include "MPedestalCam.h"
+#include "MPedestalPix.h"
+
 ClassImp(MSimTrigger);
 
@@ -91,6 +94,8 @@
 //
 MSimTrigger::MSimTrigger(const char *name, const char *title)
-    : fCamera(0), fPulsePos(0), fTrigger(0), fRunHeader(0), fEvtHeader(0),
-    fDiscriminatorThreshold(-1), fDigitalSignalLength(8), fCoincidenceTime(0.5)
+    : fCamera(0), fPulsePos(0), fTrigger(0), fRunHeader(0),
+    fEvtHeader(0), fElectronicNoise(0), fGain(0),
+    fDiscriminatorThreshold(-1), fDigitalSignalLength(8), fCoincidenceTime(0.5),
+    fShiftBaseline(kTRUE), fUngainSignal(kTRUE)
 {
     fName  = name  ? name  : "MSimTrigger";
@@ -166,4 +171,28 @@
     }
 
+    fElectronicNoise = 0;
+    if (fShiftBaseline)
+    {
+        fElectronicNoise = (MPedestalCam*)pList->FindObject("ElectronicNoise", "MPedestalCam");
+        if (!fElectronicNoise)
+        {
+            *fLog << err << "ElectronicNoise [MPedestalCam] not found... aborting." << endl;
+            return kFALSE;
+        }
+        *fLog << inf << "Baseline will be shifted back to 0 for discriminator." << endl;
+    }
+
+    fGain = 0;
+    if (fUngainSignal)
+    {
+        fGain = (MPedestalCam*)pList->FindObject("Gain", "MPedestalCam");
+        if (!fGain)
+        {
+            *fLog << err << "Gain [MPedestalCam] not found... aborting." << endl;
+            return kFALSE;
+        }
+        *fLog << inf << "Discriminator will be multiplied by applied gain." << endl;
+    }
+
     fRunHeader = (MRawRunHeader*)pList->FindObject("MRawRunHeader");
     if (!fRunHeader)
@@ -177,10 +206,22 @@
         return kFALSE;
 
-
-    if (fRouteAC.ReadFile(fNameRouteAC)<0)
-        return kFALSE;
-
-    if (fCoincidenceMap.ReadFile(fNameCoincidenceMap)<0)
-        return kFALSE;
+    fRouteAC.Delete();
+    if (!fNameRouteAC.IsNull() && fRouteAC.ReadFile(fNameRouteAC)<0)
+        return kFALSE;
+
+    fCoincidenceMap.Delete();
+    if (!fNameCoincidenceMap.IsNull() && fCoincidenceMap.ReadFile(fNameCoincidenceMap)<0)
+        return kFALSE;
+
+    // ---------------- Consistency checks ----------------------
+
+    if (!fRouteAC.IsEmpty() && !fCoincidenceMap.IsEmpty() &&
+        fCoincidenceMap.GetMaxIndex()>fRouteAC.GetNumRows()-1)
+    {
+        *fLog << err;
+        *fLog << "ERROR - AC routing produces " << fRouteAC.GetNumRows() << " analog channels," << endl;
+        *fLog << "        but the coincidence map expects at least " << fCoincidenceMap.GetMaxIndex()+1 << " channels." << endl;
+        return kERROR;
+    }
 
     if (fDiscriminatorThreshold<=0)
@@ -190,5 +231,34 @@
     }
 
-    *fLog << inf << "Using discriminator threshold of " << fDiscriminatorThreshold << endl;
+    if (fElectronicNoise && !fRouteAC.IsEmpty() && !fRouteAC.IsDefault())
+    {
+        // FIXME: Apply to analog channels when summing
+        *fLog << warn << "WARNING - A baseline shift doesn't make sense for sum-channels... reset." << endl;
+        fElectronicNoise = 0;
+    }
+
+    if (fGain && !fRouteAC.IsEmpty() && !fRouteAC.IsDefault())
+    {
+        // FIXME: Apply to analog channels when summing
+        *fLog << warn << "WARNING - Ungain doesn't make sense for sum-channels... reset." << endl;
+        fGain = 0;
+    }
+
+
+    // ---------------- Information output ----------------------
+
+    *fLog << inf;
+
+    if (fRouteAC.IsEmpty())
+        *fLog << "Re-routing/summing of analog channels before discriminator switched off." << endl;
+    else
+        *fLog << "Using " << fNameRouteAC << " for re-routing/summing of analog channels before discriminator." << endl;
+
+    if (fCoincidenceMap.IsEmpty())
+        *fLog << "No coincidences of digital channels will be checked. Signal-above-threshold trigger applied." << endl;
+    else
+        *fLog << "Using " << fNameCoincidenceMap << " to check for coincidences of the digital channels." << endl;
+
+    *fLog << "Using discriminator threshold of " << fDiscriminatorThreshold << endl;
 
     return kTRUE;
@@ -204,16 +274,29 @@
     // ================== Simulate channel bundling ====================
 
-    const UInt_t npatch = fRouteAC.GetEntriesFast();
-
-    MAnalogChannels patches(npatch, fCamera->GetNumSamples());
-
-    for (UInt_t i=0; i<npatch; i++)
-    {
-        const MArrayI &row = fRouteAC.GetRow(i);
-        for (UInt_t j=0; j<row.GetSize(); j++)
-        {
-            // FIXME: Simulate clipping
-            const UInt_t idx = row[j];
-            patches[i].AddSignal((*fCamera)[idx]);
+    // FIXME: Before we can bundle the channels we have to make a copy
+    //        and simulate clipping
+
+    // Check if routing should be done
+    const Bool_t empty = fRouteAC.IsEmpty();
+
+    // If no channels are summed the number of patches stays the same
+    const UInt_t npatch = empty ? fCamera->GetNumChannels() : fRouteAC.GetEntriesFast();
+
+    // Use the given analog channels as default out. If channels are
+    // summed overwrite with a newly allocated set of analog channels
+    MAnalogChannels *patches = fCamera;
+    if (!empty)
+    {
+        // FIXME: Can we add gain and offset here into a new container?
+
+        patches = new MAnalogChannels(npatch, fCamera->GetNumSamples());
+        for (UInt_t i=0; i<npatch; i++)
+        {
+            const MArrayI &row = fRouteAC.GetRow(i);
+            for (UInt_t j=0; j<row.GetSize(); j++)
+            {
+                const UInt_t idx = row[j];
+                (*patches)[i].AddSignal((*fCamera)[idx]);
+            }
         }
     }
@@ -227,9 +310,24 @@
 
     for (UInt_t i=0; i<npatch; i++)
-        ttls.AddAt(patches[i].Discriminate(fDiscriminatorThreshold, fDigitalSignalLength), i);
+    {
+        // FIXME: What if the gain was also allpied to the baseline?
+        const Double_t offset = fElectronicNoise ? (*fElectronicNoise)[i].GetPedestal() : 0;
+        const Double_t gain   = fGain            ? (*fGain)[i].GetPedestal()            : 1;
+        ttls.AddAt((*patches)[i].Discriminate(fDiscriminatorThreshold*gain+offset, fDigitalSignalLength), i);
+    }
 
     // FIXME: Write TTLs!
 
+    // If analog channels had been newly allocated free memmory
+    if (patches!=fCamera)
+        delete patches;
+
     // =================== Simulate coincidences ======================
+
+    // If the map is empty we create a one-pixel-coincidence map
+    // FIMXE: This could maybe be accelerated if the Clone can be
+    //        omitted in the loop
+    if (fCoincidenceMap.IsEmpty())
+        fCoincidenceMap.SetDefault(npatch);
 
     // Calculate the minimum and maximum time for a valid trigger
Index: /trunk/MagicSoft/Mars/msimcamera/MSimTrigger.h
===================================================================
--- /trunk/MagicSoft/Mars/msimcamera/MSimTrigger.h	(revision 9317)
+++ /trunk/MagicSoft/Mars/msimcamera/MSimTrigger.h	(revision 9318)
@@ -15,23 +15,29 @@
 class MRawEvtHeader;
 class MRawRunHeader;
+class MPedestalCam;
 
 class MSimTrigger : public MTask
 {
 private:
-    MAnalogChannels *fCamera;         //! The analog input channels
-    MParameterD     *fPulsePos;       //! The intended pulse positon
-    MParameterD     *fTrigger;        //! The trigger position w.r.t. the analog channels
-    MRawRunHeader   *fRunHeader;      //! The run header storing infos about the digitization
-    MRawEvtHeader   *fEvtHeader;      //! The event header storing the trigger information
+    MAnalogChannels *fCamera;           //! The analog input channels
+    MParameterD     *fPulsePos;         //! The intended pulse positon
+    MParameterD     *fTrigger;          //! The trigger position w.r.t. the analog channels
+    MRawRunHeader   *fRunHeader;        //! The run header storing infos about the digitization
+    MRawEvtHeader   *fEvtHeader;        //! The event header storing the trigger information
+    MPedestalCam    *fElectronicNoise;  //! Electronic noise (for baseline correction)
+    MPedestalCam    *fGain;             //! Gain of the pulses
 
-    MLut fRouteAC;                    // Combinination map for the AC channels
-    MLut fCoincidenceMap;             // channels for which digital coincidence is checked
+    MLut fRouteAC;                      // Combinination map for the AC channels
+    MLut fCoincidenceMap;               // channels for which digital coincidence is checked
 
-    TString fNameRouteAC;             // Name for the AC routing
-    TString fNameCoincidenceMap;      // Name for the coincidence mape
+    TString fNameRouteAC;               // Name for the AC routing
+    TString fNameCoincidenceMap;        // Name for the coincidence mape
 
-    Float_t fDiscriminatorThreshold;  // Discriminator threshold
-    Float_t fDigitalSignalLength;     // Length of the output of the discriminator
-    Float_t fCoincidenceTime;         // Minimum coincidence time (gate)
+    Float_t fDiscriminatorThreshold;    // Discriminator threshold
+    Float_t fDigitalSignalLength;       // Length of the output of the discriminator
+    Float_t fCoincidenceTime;           // Minimum coincidence time (gate)
+
+    Bool_t  fShiftBaseline;             // Shift the baseline back to 0 for the threshold (needs ElectronicNoise [MPedestalCam])
+    Bool_t  fUngainSignal;              // "Remove" the gain from the signal (needs Gain [MPedestalCam])
 
     // MSimTrigger
