]> git.uio.no Git - u/mrichter/AliRoot.git/blobdiff - EMCAL/AliCaloCalibSignal.cxx
Example macro to get environment variables (Marian)
[u/mrichter/AliRoot.git] / EMCAL / AliCaloCalibSignal.cxx
index e77223e15339067f6ac7ed5aafa7c061af3466b0..1af0a478d05bd6fc75fd03ec247231da39d7264b 100644 (file)
 */
 // fed an event:
 //  fSignals->ProcessEvent(fCaloRawStream,fRawEventHeaderBase);
-// asked to draw graphs or profiles:
-//  fSignals->GetGraphAmpVsTimeHighGain(module,column,row)->Draw("ap");
-// or
-//  fSignals->GetProfAmpVsTimeHighGain(module,column,row)->Draw();
+// get some info:
+//  fSignals->GetXXX..()
 // etc.
 //________________________________________________________________________
 
+#include "TProfile.h"
 #include "TFile.h"
 
 #include "AliRawReader.h"
@@ -46,6 +45,13 @@ ClassImp(AliCaloCalibSignal)
 
 using namespace std;
 
+// variables for TTree filling; not sure if they should be static or not
+static int fChannelNum; // for regular towers
+static int fRefNum; // for LED
+static double fAmp;
+static double fAvgAmp;
+static double fRMS;
+
 // ctor; initialize everything in order to avoid compiler warnings
 // put some reasonable defaults
 AliCaloCalibSignal::AliCaloCalibSignal(kDetType detectorType) :  
@@ -53,6 +59,7 @@ AliCaloCalibSignal::AliCaloCalibSignal(kDetType detectorType) :
   fDetType(kNone),
   fColumns(0),
   fRows(0),
+  fLEDRefs(0),
   fModules(0),
   fCaloString(),
   fMapping(NULL),
@@ -66,12 +73,17 @@ AliCaloCalibSignal::AliCaloCalibSignal(kDetType detectorType) :
   fUseAverage(kTRUE),
   fSecInAverage(1800), 
   fNEvents(0),
-  fNAcceptedEvents(0)
+  fNAcceptedEvents(0),
+  fTreeAmpVsTime(NULL),
+  fTreeAvgAmpVsTime(NULL),
+  fTreeLEDAmpVsTime(NULL),
+  fTreeLEDAvgAmpVsTime(NULL)
 {
   //Default constructor. First we set the detector-type related constants.
   if (detectorType == kPhos) {
     fColumns = fgkPhosCols;
     fRows = fgkPhosRows;
+    fLEDRefs = fgkPhosLEDRefs;
     fModules = fgkPhosModules;
     fCaloString = "PHOS";
   } 
@@ -81,45 +93,36 @@ AliCaloCalibSignal::AliCaloCalibSignal(kDetType detectorType) :
     //case, if someone intentionally gives another number
     fColumns = fgkEmCalCols;
     fRows = fgkEmCalRows;
+    fLEDRefs = fgkEmCalLEDRefs;
     fModules = fgkEmCalModules;
     fCaloString = "EMCAL";
   }
 
   fDetType = detectorType;
 
-  // Set the number of points for each Amp vs. Time graph to 0
-  memset(fNHighGain, 0, sizeof(fNHighGain));
-  memset(fNLowGain, 0, sizeof(fNLowGain));
-
-  CreateGraphs(); // set up the TGraphs
-
-  // init TProfiles to NULL=0 also
-  memset(fProfAmpVsTimeHighGain, 0, sizeof(fProfAmpVsTimeHighGain));
-  memset(fProfAmpVsTimeLowGain, 0, sizeof(fProfAmpVsTimeLowGain));
+  ResetInfo(); // trees and counters
 } 
 
 // dtor
 //_____________________________________________________________________
 AliCaloCalibSignal::~AliCaloCalibSignal()
 {
-  ClearObjects();
+  DeleteTrees();
 }
 
 //_____________________________________________________________________
-void AliCaloCalibSignal::ClearObjects()
+void AliCaloCalibSignal::DeleteTrees()
 {
-  // delete what was created in the ctor (TGraphs), and possible later (TProfiles)
-  for (int i=0; i<fgkMaxTowers; i++) {
-    if ( fGraphAmpVsTimeHighGain[i] ) { delete fGraphAmpVsTimeHighGain[i]; }
-    if ( fGraphAmpVsTimeLowGain[i] ) { delete fGraphAmpVsTimeLowGain[i]; }
-    if ( fProfAmpVsTimeHighGain[i] ) { delete fProfAmpVsTimeHighGain[i]; }
-    if ( fProfAmpVsTimeLowGain[i] ) { delete fProfAmpVsTimeLowGain[i]; }
-  }
-  // set pointers
-  memset(fGraphAmpVsTimeHighGain, 0, sizeof(fGraphAmpVsTimeHighGain));
-  memset(fGraphAmpVsTimeLowGain, 0, sizeof(fGraphAmpVsTimeLowGain));
-  memset(fProfAmpVsTimeHighGain, 0, sizeof(fProfAmpVsTimeHighGain));
-  memset(fProfAmpVsTimeLowGain, 0, sizeof(fProfAmpVsTimeLowGain));
+  // delete what was created in the ctor (TTrees)
+  if (fTreeAmpVsTime) delete fTreeAmpVsTime;
+  if (fTreeAvgAmpVsTime) delete fTreeAvgAmpVsTime;
+  if (fTreeLEDAmpVsTime) delete fTreeLEDAmpVsTime;
+  if (fTreeLEDAvgAmpVsTime) delete fTreeLEDAvgAmpVsTime;
+  // and reset pointers
+  fTreeAmpVsTime = NULL;
+  fTreeAvgAmpVsTime = NULL;
+  fTreeLEDAmpVsTime = NULL;
+  fTreeLEDAvgAmpVsTime = NULL;
 
   return;
 }
@@ -131,6 +134,7 @@ AliCaloCalibSignal::AliCaloCalibSignal(const AliCaloCalibSignal &sig) :
   fDetType(sig.GetDetectorType()),
   fColumns(sig.GetColumns()),
   fRows(sig.GetRows()),
+  fLEDRefs(sig.GetLEDRefs()),
   fModules(sig.GetModules()),
   fCaloString(sig.GetCaloString()),
   fMapping(NULL), //! note that we are not copying the map info
@@ -144,9 +148,13 @@ AliCaloCalibSignal::AliCaloCalibSignal(const AliCaloCalibSignal &sig) :
   fUseAverage(sig.GetUseAverage()),
   fSecInAverage(sig.GetSecInAverage()),
   fNEvents(sig.GetNEvents()),
-  fNAcceptedEvents(sig.GetNAcceptedEvents())
+  fNAcceptedEvents(sig.GetNAcceptedEvents()),
+  fTreeAmpVsTime(NULL),
+  fTreeAvgAmpVsTime(NULL),
+  fTreeLEDAmpVsTime(NULL),
+  fTreeLEDAvgAmpVsTime(NULL)
 {
-  // also the TGraph contents
+  // also the TTree contents
   AddInfo(&sig);
 }
 
@@ -162,67 +170,63 @@ AliCaloCalibSignal& AliCaloCalibSignal::operator = (const AliCaloCalibSignal &so
 }
 
 //_____________________________________________________________________
-void AliCaloCalibSignal::CreateGraphs()
+void AliCaloCalibSignal::CreateTrees()
 {
-  //Then, loop for the requested number of modules
-  TString title, name;
-  for (int i = 0; i < fModules; i++) {
-    
-    // Amplitude vs. Time graph for each channel
-    for(int ic=0;ic < fColumns;ic++){
-      for(int ir=0;ir < fRows;ir++){
-       
-       int id = GetTowerNum(i, ic, ir);
-       
-       // high gain graph
-       name = "fGraphAmpVsTimeHighGain_"; name += i;
-       name += "_"; name += ic;
-       name += "_"; name += ir;
-       title = "Amp vs. Time High Gain Mod "; title += i;
-       title += " Col "; title += ic;
-       title += " Row "; title += ir;
-       
-       fGraphAmpVsTimeHighGain[id] = new TGraph();
-       fGraphAmpVsTimeHighGain[id]->SetName(name);
-       fGraphAmpVsTimeHighGain[id]->SetTitle(title);
-       fGraphAmpVsTimeHighGain[id]->SetMarkerStyle(20);
-       
-       // Low Gain
-       name = "fGraphAmpVsTimeLowGain_"; name += i;
-       name += "_"; name += ic;
-       name += "_"; name += ir;
-       title = "Amp vs. Time Low Gain Mod "; title += i;
-       title += " Col "; title += ic;
-       title += " Row "; title += ir;
-       
-       fGraphAmpVsTimeLowGain[id] = new TGraph();
-       fGraphAmpVsTimeLowGain[id]->SetName(name);
-       fGraphAmpVsTimeLowGain[id]->SetTitle(title);
-       fGraphAmpVsTimeLowGain[id]->SetMarkerStyle(20);
-       
-      }
-    }
+  // initialize trees
+  // first, regular version
+  fTreeAmpVsTime = new TTree("fTreeAmpVsTime","Amplitude vs. Time Tree Variables");
+
+  fTreeAmpVsTime->Branch("fChannelNum", &fChannelNum, "fChannelNum/I");
+  fTreeAmpVsTime->Branch("fHour", &fHour, "fHour/D");
+  fTreeAmpVsTime->Branch("fAmp", &fAmp, "fAmp/D");
+
+  // then, average version
+  fTreeAvgAmpVsTime = new TTree("fTreeAvgAmpVsTime","Average Amplitude vs. Time Tree Variables");
+
+  fTreeAvgAmpVsTime->Branch("fChannelNum", &fChannelNum, "fChannelNum/I");
+  fTreeAvgAmpVsTime->Branch("fHour", &fHour, "fHour/D");
+  fTreeAvgAmpVsTime->Branch("fAvgAmp", &fAvgAmp, "fAvgAmp/D");
+  fTreeAvgAmpVsTime->Branch("fRMS", &fRMS, "fRMS/D");
+
+  // then same for LED..
+  fTreeLEDAmpVsTime = new TTree("fTreeLEDAmpVsTime","LED Amplitude vs. Time Tree Variables");
+  fTreeLEDAmpVsTime->Branch("fRefNum", &fRefNum, "fRefNum/I");
+  fTreeLEDAmpVsTime->Branch("fHour", &fHour, "fHour/D");
+  fTreeLEDAmpVsTime->Branch("fAmp", &fAmp, "fAmp/D");
+
+  fTreeLEDAvgAmpVsTime = new TTree("fTreeLEDAvgAmpVsTime","Average LED Amplitude vs. Time Tree Variables");
+  fTreeLEDAvgAmpVsTime->Branch("fRefNum", &fRefNum, "fRefNum/I");
+  fTreeLEDAvgAmpVsTime->Branch("fHour", &fHour, "fHour/D");
+  fTreeLEDAvgAmpVsTime->Branch("fAvgAmp", &fAvgAmp, "fAvgAmp/D");
+  fTreeLEDAvgAmpVsTime->Branch("fRMS", &fRMS, "fRMS/D");
 
-  }//end for nModules 
+  return;
 }
 
 //_____________________________________________________________________
-void AliCaloCalibSignal::Reset()
+void AliCaloCalibSignal::ResetInfo()
 {
   Zero(); // set all counters to 0
-  ClearObjects(); // delete previous TGraphs and TProfiles
-  CreateGraphs(); // and create some new ones
+  DeleteTrees(); // delete previous stuff
+  CreateTrees(); // and create some new ones
   return;
 }
 
 //_____________________________________________________________________
 void AliCaloCalibSignal::Zero()
 {
-  // set all counters to 0; not cuts etc.though
+  // set all counters to 0; not cuts etc. though
   fHour = 0;
   fLatestHour = 0;
   fNEvents = 0;
   fNAcceptedEvents = 0;
+
+  // Set the number of points for each tower: Amp vs. Time 
+  memset(fNHighGain, 0, sizeof(fNHighGain));
+  memset(fNLowGain, 0, sizeof(fNLowGain));
+  // and LED reference
+  memset(fNRef, 0, sizeof(fNRef));
+
   return;
 }
 
@@ -254,56 +258,66 @@ Bool_t AliCaloCalibSignal::CheckFractionAboveAmp(int *AmpVal, int nTotChan)
 //_____________________________________________________________________
 Bool_t AliCaloCalibSignal::AddInfo(const AliCaloCalibSignal *sig)
 {
-  // just do this for the basic graphs/profiles that get filled in ProcessEvent
-  // may not have data for all channels, but let's just Add everything..
-  // Note: this method will run into problems with TProfile adding if the binning of
-  // the local profiles is not the same as those provided by the argument *sig..
-  int numGraphPoints = 0;
-  int id = 0;
-  int ip = 0;
-  for (int i = 0; i < fModules; i++) {
-    for (int j = 0; j < fColumns; j++) {
-      for (int k = 0; k < fRows; k++) {
-       
-       id = GetTowerNum(i,j,k);
-
-       if(fUseAverage){ // add to Profiles
-         if (sig->GetProfAmpVsTimeHighGain(id)) {
-           GetProfAmpVsTimeHighGain(id)->Add(sig->GetProfAmpVsTimeHighGain(id));
-         }
-         if (sig->GetProfAmpVsTimeLowGain(id)) {
-           GetProfAmpVsTimeLowGain(id)->Add(sig->GetProfAmpVsTimeLowGain(id));
-         }
-       }
-       else{ // add to Graphs    
-         // high gain
-         numGraphPoints= sig->GetGraphAmpVsTimeHighGain(id)->GetN();
-         if (numGraphPoints > 0) {
-           // get the values
-           double *graphX = sig->GetGraphAmpVsTimeHighGain(id)->GetX();
-           double *graphY = sig->GetGraphAmpVsTimeHighGain(id)->GetY();
-           for(ip=0; ip < numGraphPoints; ip++){
-             fGraphAmpVsTimeHighGain[id]->SetPoint(fNHighGain[id]++,graphX[ip],graphY[ip]);
-           }
-         }
-         // low gain
-         numGraphPoints= sig->GetGraphAmpVsTimeLowGain(id)->GetN();
-         if (numGraphPoints > 0) {
-           // get the values
-           double *graphX = sig->GetGraphAmpVsTimeLowGain(id)->GetX();
-           double *graphY = sig->GetGraphAmpVsTimeLowGain(id)->GetY();
-           for(ip=0; ip < numGraphPoints; ip++){
-             fGraphAmpVsTimeLowGain[id]->SetPoint(fNLowGain[id]++,graphX[ip],graphY[ip]);
-           }
-         }
+  // note/FIXME: we are not yet adding correctly the info for fN{HighGain,LowGain,Ref} here - but consider this a feature for now (20080905): we'll do Analyze() unless entries were found for a tower in this original object.
+
+  // add info from sig's TTrees to ours..
+  TTree *sigAmp = sig->GetTreeAmpVsTime();
+  TTree *sigAvgAmp = sig->GetTreeAvgAmpVsTime();
+
+  // we could try some merging via TList or what also as a more elegant approach
+  // but I wanted with the stupid/simple and hopefully safe approach of looping
+  // over what we want to add..
+
+  // associate variables for sigAmp and sigAvgAmp:
+  sigAmp->SetBranchAddress("fChannelNum",&fChannelNum);
+  sigAmp->SetBranchAddress("fHour",&fHour);
+  sigAmp->SetBranchAddress("fAmp",&fAmp);
+
+  // loop over the trees.. note that since we use the same variables we should not need
+  // to do any assignments between the getting and filling
+  for (int i=0; i<sigAmp->GetEntries(); i++) {
+    sigAmp->GetEntry(i);
+    fTreeAmpVsTime->Fill();
+  }
 
-       }
+  sigAvgAmp->SetBranchAddress("fChannelNum",&fChannelNum);
+  sigAvgAmp->SetBranchAddress("fHour",&fHour);
+  sigAvgAmp->SetBranchAddress("fAvgAmp",&fAvgAmp);
+  sigAvgAmp->SetBranchAddress("fRMS",&fRMS);
+
+  for (int i=0; i<sigAvgAmp->GetEntries(); i++) {
+    sigAvgAmp->GetEntry(i);
+    fTreeAvgAmpVsTime->Fill();
+  }
+
+  // also LED.. 
+  TTree *sigLEDAmp = sig->GetTreeLEDAmpVsTime();
+  TTree *sigLEDAvgAmp = sig->GetTreeLEDAvgAmpVsTime();
+
+  // associate variables for sigAmp and sigAvgAmp:
+  sigLEDAmp->SetBranchAddress("fRefNum",&fRefNum);
+  sigLEDAmp->SetBranchAddress("fHour",&fHour);
+  sigLEDAmp->SetBranchAddress("fAmp",&fAmp);
+
+  // loop over the trees.. note that since we use the same variables we should not need
+  // to do any assignments between the getting and filling
+  for (int i=0; i<sigLEDAmp->GetEntries(); i++) {
+    sigLEDAmp->GetEntry(i);
+    fTreeLEDAmpVsTime->Fill();
+  }
+
+  sigLEDAvgAmp->SetBranchAddress("fRefNum",&fRefNum);
+  sigLEDAvgAmp->SetBranchAddress("fHour",&fHour);
+  sigLEDAvgAmp->SetBranchAddress("fAvgAmp",&fAvgAmp);
+  sigLEDAvgAmp->SetBranchAddress("fRMS",&fRMS);
+
+  for (int i=0; i<sigLEDAvgAmp->GetEntries(); i++) {
+    sigLEDAvgAmp->GetEntry(i);
+    fTreeLEDAvgAmpVsTime->Fill();
+  }
 
-      }//end for nModules 
-    }//end for nColumns
-  }//end for nRows
 
-  return kTRUE;//We succesfully added info from the supplied object
+  return kTRUE;//We hopefully succesfully added info from the supplied object
 }
 
 //_____________________________________________________________________
@@ -323,61 +337,74 @@ Bool_t AliCaloCalibSignal::ProcessEvent(AliCaloRawStream *in, AliRawEventHeaderB
   
   fNEvents++; // one more event
 
-  // PHOS has more towers than EMCAL, so use PHOS numbers to set array sizes
+  // use maximum numbers to set array sizes
   int AmpValHighGain[fgkMaxTowers];
   int AmpValLowGain[fgkMaxTowers];
-
   memset(AmpValHighGain, 0, sizeof(AmpValHighGain));
   memset(AmpValLowGain, 0, sizeof(AmpValLowGain));
 
-  int sample, i = 0; //The sample temp, and the sample number in current event.
+  // also for LED reference
+  int LEDAmpVal[fgkMaxRefs * 2]; // factor 2 is for the two gain values
+  memset(LEDAmpVal, 0, sizeof(LEDAmpVal));
+
+  int sample, isample = 0; //The sample temp, and the sample number in current event.
   int max = fgkSampleMin, min = fgkSampleMax;//Use these for picking the signal
-  int gain = 0;
+  int gain = 0; // high or low gain
   
   // Number of Low and High gain channels for this event:
   int nLowChan = 0; 
   int nHighChan = 0; 
 
-  int TowerNum = 0; // array index for TGraphs etc.
+  int TowerNum = 0; // array index for regular towers
+  int RefNum = 0; // array index for LED references
 
   // loop first to get the fraction of channels with amplitudes above cut
   while (in->Next()) {
     sample = in->GetSignal(); //Get the adc signal
     if (sample < min) min = sample;
     if (sample > max) max = sample;
-    i++;
-    if ( i >= in->GetTimeLength()) {
+    isample++;
+    if ( isample >= in->GetTimeLength()) {
       //If we're here then we're done with this tower
-      gain = 1 - in->IsLowGain();
-      
+      if ( in->IsLowGain() ) {
+       gain = 0;
+      }
+      else if ( in->IsHighGain() ) {
+       gain = 1;
+      }
+      else if ( in->IsLEDMonData() ) {
+       gain = in->GetRow(); // gain coded in (in RCU/Altro mapping) as Row info for LED refs..
+      }
+
       int arrayPos = in->GetModule(); //The modules are numbered starting from 0
-      if (arrayPos >= fModules) {
-       //TODO: return an error message, if appopriate (perhaps if debug>0?)
-       return kFALSE;
-      } 
-      
       //Debug
       if (arrayPos < 0 || arrayPos >= fModules) {
-       printf("Oh no: arrayPos = %i.\n", arrayPos); 
+       printf("AliCaloCalibSignal::ProcessEvent = Oh no: arrayPos = %i.\n", arrayPos); 
+       return kFALSE;
       }
 
-      // get tower number for AmpVal array
-      TowerNum = GetTowerNum(arrayPos, in->GetColumn(), in->GetRow()); 
-
-      if (gain == 0) {
-       // fill amplitude into the array           
-        AmpValLowGain[TowerNum] = max - min;
-       nLowChan++;
-      } 
-      else if (gain==1) {//fill the high gain ones
-       // fill amplitude into the array
-       AmpValHighGain[TowerNum] = max - min;
-       nHighChan++;
-      }//end if gain
-
+      if ( in->IsHighGain() || in->IsLowGain() ) { // regular tower
+       // get tower number for AmpVal array
+       TowerNum = GetTowerNum(arrayPos, in->GetColumn(), in->GetRow()); 
+
+       if (gain == 0) {
+         // fill amplitude into the array         
+         AmpValLowGain[TowerNum] = max - min;
+         nLowChan++;
+       } 
+       else if (gain==1) {//fill the high gain ones
+         // fill amplitude into the array
+         AmpValHighGain[TowerNum] = max - min;
+         nHighChan++;
+       }//end if gain
+      } // regular tower
+      else if ( in->IsLEDMonData() ) { // LED ref.
+       RefNum = GetRefNum(arrayPos, in->GetColumn(), gain); 
+       LEDAmpVal[RefNum] = max - min;
+      } // end of LED ref
       
       max = fgkSampleMin; min = fgkSampleMax;
-      i = 0;
+      isample = 0;
       
     }//End if end of tower
    
@@ -403,60 +430,49 @@ Bool_t AliCaloCalibSignal::ProcessEvent(AliCaloRawStream *in, AliRawEventHeaderB
     fLatestHour = fHour; 
   }
   
-  // it is a led event, now fill graphs (maybe profiles later)
-  for(int i=0;i<fModules;i++){
-    for(int j=0;j<fColumns;j++){
-      for(int k=0;k<fRows;k++){
+  // it is a led event, now fill TTree
+  for(int i=0; i<fModules; i++){
+    for(int j=0; j<fColumns; j++){
+      for(int k=0; k<fRows; k++){
        
        TowerNum = GetTowerNum(i, j, k); 
 
        if(AmpValHighGain[TowerNum]) {
-         fGraphAmpVsTimeHighGain[TowerNum]->SetPoint(fNHighGain[TowerNum]++,fHour,AmpValHighGain[TowerNum]);
+         fAmp = AmpValHighGain[TowerNum];
+         fChannelNum = GetChannelNum(i,j,k,1);
+         fTreeAmpVsTime->Fill();//fChannelNum,fHour,AmpValHighGain[TowerNum]);
+         fNHighGain[TowerNum]++;
        }
        if(AmpValLowGain[TowerNum]) {
-         fGraphAmpVsTimeLowGain[TowerNum]->SetPoint(fNLowGain[TowerNum]++,fHour,AmpValLowGain[TowerNum]);
+         fAmp = AmpValLowGain[TowerNum];
+         fChannelNum = GetChannelNum(i,j,k,0);
+         fTreeAmpVsTime->Fill();//fChannelNum,fHour,AmpValLowGain[TowerNum]);
+         fNLowGain[TowerNum]++;
+       }
+      } // rows
+    } // columns
+
+    // also LED refs
+    for(int j=0; j<fLEDRefs; j++){
+      for (gain=0; gain<2; gain++) {
+       fRefNum = GetRefNum(i, j, gain); 
+       if (LEDAmpVal[RefNum]) {
+         fAmp = LEDAmpVal[RefNum];
+         fTreeLEDAmpVsTime->Fill();//fRefNum,fHour,fAmp);
+         fNRef[fRefNum]++;
        }
       }
     }
-  }
+
+  } // modules
   
   return kTRUE;
 }
 
 //_____________________________________________________________________
-void AliCaloCalibSignal::CreateProfile(int imod, int ic, int ir, int towerId, int gain,
-                                      int nbins, double min, double max)
-{ //! create/setup a TProfile
-  TString title, name;   
-  if (gain == 0) { 
-    name = "fProfAmpVsTimeLowGain_";   
-    title = "Amp vs. Time Low Gain Mod "; 
-  } 
-  else if (gain == 1) { 
-    name = "fProfAmpVsTimeHighGain_"; 
-    title = "Amp vs. Time High Gain Mod "; 
-  } 
-  name += imod;
-  name += "_"; name += ic;
-  name += "_"; name += ir;
-  title += imod;
-  title += " Col "; title += ic;
-  title += " Row "; title += ir;
-           
-  // use "s" option for RMS
-  if (gain==0) { 
-    fProfAmpVsTimeLowGain[towerId] = new TProfile(name,title, nbins, min, max,"s");
-  }
-  else if (gain==1) {
-    fProfAmpVsTimeHighGain[towerId] = new TProfile(name,title, nbins, min, max,"s");
-  }
-
-  return;
-}
-//_____________________________________________________________________
-Bool_t AliCaloCalibSignal::Save(TString fileName, Bool_t saveEmptyGraphs)
+Bool_t AliCaloCalibSignal::Save(TString fileName)
 {
-  //Saves all the histograms (or profiles, to be accurate) to the designated file
+  //Saves all the TTrees to the designated file
   
   TFile destFile(fileName, "recreate");
   
@@ -466,101 +482,164 @@ Bool_t AliCaloCalibSignal::Save(TString fileName, Bool_t saveEmptyGraphs)
   
   destFile.cd();
 
-  // setup variables for the TProfile plot
+  // save the trees
+  fTreeAmpVsTime->Write();
+  if (fUseAverage) { 
+    Analyze(); // get the latest and greatest averages
+    fTreeAvgAmpVsTime->Write();
+  }
+
+  destFile.Close();
+  
+  return kTRUE;
+}
+
+//_____________________________________________________________________
+Bool_t AliCaloCalibSignal::Analyze()
+{
+  // Fill the tree holding the average values
+  if (!fUseAverage) { return kFALSE; }
+
+  // Reset the average TTree if Analyze has already been called earlier,
+  // meaning that the TTree could have been partially filled
+  if (fTreeAvgAmpVsTime->GetEntries() > 0) {
+    fTreeAvgAmpVsTime->Reset();
+  }
+
+  //0: setup variables for the TProfile plots that we'll use to do the averages
   int numProfBins = 0;
   double timeMin = 0;
   double timeMax = 0;
-  if (fUseAverage) {
-    if (fSecInAverage > 0) {
-      numProfBins = (int)( (fLatestHour*fgkNumSecInHr)/fSecInAverage + 1 ); // round-off
+  if (fSecInAverage > 0) {
+    numProfBins = (int)( (fLatestHour*fgkNumSecInHr)/fSecInAverage + 1 ); // round-off
+  }
+  numProfBins += 2; // add extra buffer : first and last
+  double binSize = 1.0*fSecInAverage / fgkNumSecInHr;
+  timeMin = - binSize;
+  timeMax = timeMin + numProfBins*binSize;
+
+  //1: set up TProfiles for the towers that had data
+  TProfile * profile[fgkMaxTowers*2]; // *2 is since we include both high and low gains
+  memset(profile, 0, sizeof(profile));
+
+  char name[200]; // for profile id and title
+  int TowerNum = 0;
+
+  for (int i = 0; i<fModules; i++) {
+    for (int ic=0; ic<fColumns; ic++){
+      for (int ir=0; ir<fRows; ir++) {
+
+       TowerNum = GetTowerNum(i, ic, ir);
+       // high gain
+       if (fNHighGain[TowerNum] > 0) {
+         fChannelNum = GetChannelNum(i, ic, ir, 1); 
+         sprintf(name, "profileChan%d", fChannelNum);
+         profile[fChannelNum] = new TProfile(name, name, numProfBins, timeMin, timeMax, "s");
+       }
+
+       // same for low gain
+       if (fNLowGain[TowerNum] > 0) {
+         fChannelNum = GetChannelNum(i, ic, ir, 0); 
+         sprintf(name, "profileChan%d", fChannelNum);
+         profile[fChannelNum] = new TProfile(name, name, numProfBins, timeMin, timeMax, "s");
+       }
+
+      } // rows
+    } // columns
+  } // modules
+
+  //2: fill profiles by looping over tree
+  // Set addresses for tree-readback also
+  fTreeAmpVsTime->SetBranchAddress("fChannelNum", &fChannelNum);
+  fTreeAmpVsTime->SetBranchAddress("fHour", &fHour);
+  fTreeAmpVsTime->SetBranchAddress("fAmp", &fAmp);
+
+  for (int ient=0; ient<fTreeAmpVsTime->GetEntries(); ient++) {
+    fTreeAmpVsTime->GetEntry(ient);
+    if (profile[fChannelNum]) { 
+      // profile should always have been created above, for active channels
+      profile[fChannelNum]->Fill(fHour, fAmp);
     }
-    numProfBins += 2; // add extra buffer : first and last
-    double binSize = 1.0*fSecInAverage / fgkNumSecInHr;
-    timeMin = - binSize;
-    timeMax = timeMin + numProfBins*binSize;
   }
 
-  int numGraphPoints= 0;
-  int TowerNum = 0;    
-  for (int i = 0; i < fModules; i++) {
-    
-    for(int ic=0;ic < fColumns;ic++){
-      for(int ir=0;ir < fRows;ir++){
-
-       TowerNum = GetTowerNum(i, ic, ir); 
-
-       // 1st: high gain
-       numGraphPoints= fGraphAmpVsTimeHighGain[TowerNum]->GetN();
-       if( numGraphPoints>0 || saveEmptyGraphs) {
-         
-         // average the graphs points over time if requested and put them in a profile plot
-         if(fUseAverage && numGraphPoints>0) {
-           
-           // get the values
-           double *graphX = fGraphAmpVsTimeHighGain[TowerNum]->GetX();
-           double *graphY = fGraphAmpVsTimeHighGain[TowerNum]->GetY();
-
-           // create the TProfile: 1 is for High gain              
-           CreateProfile(i, ic, ir, TowerNum, 1,
-                         numProfBins, timeMin, timeMax);
-
-           // loop over graph points and fill profile
-           for(int ip=0; ip < numGraphPoints; ip++){
-             fProfAmpVsTimeHighGain[TowerNum]->Fill(graphX[ip],graphY[ip]);
-           }
-           
-           fProfAmpVsTimeHighGain[TowerNum]->GetXaxis()->SetTitle("Hours");
-           fProfAmpVsTimeHighGain[TowerNum]->GetYaxis()->SetTitle("MaxAmplitude - Pedestal");
-           fProfAmpVsTimeHighGain[TowerNum]->Write();
-
-         }
-          else{
-            //otherwise, just save the graphs and forget the profiling
-            fGraphAmpVsTimeHighGain[TowerNum]->GetXaxis()->SetTitle("Hours");
-            fGraphAmpVsTimeHighGain[TowerNum]->GetYaxis()->SetTitle("MaxAmplitude - Pedestal");
-            fGraphAmpVsTimeHighGain[TowerNum]->Write();
-          }
-         
-       } // low gain graph info should be saved in one form or another
-       
-       // 2nd: now go to the low gain case
-       numGraphPoints= fGraphAmpVsTimeLowGain[TowerNum]->GetN();
-       if( numGraphPoints>0 || saveEmptyGraphs) {
-         
-         // average the graphs points over time if requested and put them in a profile plot
-         if(fUseAverage && numGraphPoints>0) {
-           
-           double *graphX = fGraphAmpVsTimeLowGain[TowerNum]->GetX();
-           double *graphY = fGraphAmpVsTimeLowGain[TowerNum]->GetY();
-           
-           // create the TProfile: 0 is for Low gain       
-           CreateProfile(i, ic, ir, TowerNum, 0,
-                         numProfBins, timeMin, timeMax);
-
-           // loop over graph points and fill profile
-           for(int ip=0; ip < numGraphPoints; ip++){
-             fProfAmpVsTimeLowGain[TowerNum]->Fill(graphX[ip],graphY[ip]);
-           }
-           
-           fProfAmpVsTimeLowGain[TowerNum]->GetXaxis()->SetTitle("Hours");
-           fProfAmpVsTimeLowGain[TowerNum]->GetYaxis()->SetTitle("MaxAmplitude - Pedestal");
-           fProfAmpVsTimeLowGain[TowerNum]->Write();
-
-         }
-         else{
-            //otherwise, just save the graphs and forget the profiling
-           fGraphAmpVsTimeLowGain[TowerNum]->GetXaxis()->SetTitle("Hours");
-           fGraphAmpVsTimeLowGain[TowerNum]->GetYaxis()->SetTitle("MaxAmplitude - Pedestal");
-           fGraphAmpVsTimeLowGain[TowerNum]->Write();
-         }
-         
-       } // low gain graph info should be saved in one form or another
-
-      } // fRows
-    } // fColumns
-
-  } // fModules
-  destFile.Close();
-  
+  // re-associating the branch addresses here seems to be needed for OK 'average' storage          
+  fTreeAvgAmpVsTime->SetBranchAddress("fChannelNum", &fChannelNum);
+  fTreeAvgAmpVsTime->SetBranchAddress("fHour", &fHour);
+  fTreeAvgAmpVsTime->SetBranchAddress("fAvgAmp", &fAvgAmp);
+  fTreeAvgAmpVsTime->SetBranchAddress("fRMS", &fRMS);
+
+  //3: fill avg tree by looping over the profiles
+  for (fChannelNum = 0; fChannelNum<(fgkMaxTowers*2); fChannelNum++) {
+    if (profile[fChannelNum]) { // profile was created
+      if (profile[fChannelNum]->GetEntries() > 0) { // profile had some entries
+       for(int it=0; it<numProfBins; it++) {
+         if (profile[fChannelNum]->GetBinEntries(it+1) > 0) {
+           fAvgAmp = profile[fChannelNum]->GetBinContent(it+1);
+           fHour = profile[fChannelNum]->GetBinCenter(it+1);
+           fRMS = profile[fChannelNum]->GetBinError(it+1);
+           fTreeAvgAmpVsTime->Fill();
+         } // some entries for this bin
+       } // loop over bins
+      } // some entries for this profile
+    } // profile exists  
+  } // loop over all possible channels
+
+
+  // and finally, go through same exercise for LED also.. 
+
+  //1: set up TProfiles for the towers that had data
+  TProfile * profileLED[fgkMaxRefs*2]; // *2 is since we include both high and low gains
+  memset(profileLED, 0, sizeof(profileLED));
+
+  for (int i = 0; i<fModules; i++) {
+    for(int j=0; j<fLEDRefs; j++){
+      for (int gain=0; gain<2; gain++) {
+       fRefNum = GetRefNum(i, j, gain);
+       if (fNRef[fRefNum] > 0) { 
+         sprintf(name, "profileLEDRef%d", fRefNum);
+         profileLED[fRefNum] = new TProfile(name, name, numProfBins, timeMin, timeMax, "s");
+       } 
+      }// gain
+    } 
+  } // modules
+
+  //2: fill profiles by looping over tree
+  // Set addresses for tree-readback also
+  fTreeLEDAmpVsTime->SetBranchAddress("fRefNum", &fRefNum);
+  fTreeLEDAmpVsTime->SetBranchAddress("fHour", &fHour);
+  fTreeLEDAmpVsTime->SetBranchAddress("fAmp", &fAmp);
+
+  for (int ient=0; ient<fTreeLEDAmpVsTime->GetEntries(); ient++) {
+    fTreeLEDAmpVsTime->GetEntry(ient);
+    if (profileLED[fRefNum]) { 
+      // profile should always have been created above, for active channels
+      profileLED[fRefNum]->Fill(fHour, fAmp);
+    }
+  }
+
+  // re-associating the branch addresses here seems to be needed for OK 'average' storage          
+  fTreeLEDAvgAmpVsTime->SetBranchAddress("fRefNum", &fRefNum);
+  fTreeLEDAvgAmpVsTime->SetBranchAddress("fHour", &fHour);
+  fTreeLEDAvgAmpVsTime->SetBranchAddress("fAvgAmp", &fAvgAmp);
+  fTreeLEDAvgAmpVsTime->SetBranchAddress("fRMS", &fRMS);
+
+  //3: fill avg tree by looping over the profiles
+  for (fRefNum = 0; fRefNum<(fgkMaxRefs*2); fRefNum++) {
+    if (profileLED[fRefNum]) { // profile was created
+      if (profileLED[fRefNum]->GetEntries() > 0) { // profile had some entries
+       for(int it=0; it<numProfBins; it++) {
+         if (profileLED[fRefNum]->GetBinEntries(it+1) > 0) {
+           fAvgAmp = profileLED[fRefNum]->GetBinContent(it+1);
+           fHour = profileLED[fRefNum]->GetBinCenter(it+1);
+           fRMS = profileLED[fRefNum]->GetBinError(it+1);
+           fTreeLEDAvgAmpVsTime->Fill();
+         } // some entries for this bin
+       } // loop over bins
+      } // some entries for this profile
+    } // profile exists  
+  } // loop over all possible channels
+
+  // OK, we're done..
+
   return kTRUE;
 }