/* ======================================================================== *\
!
! *
! * This file is part of MARS, the MAGIC Analysis and Reconstruction
! * Software. It is distributed to you in the hope that it can be a useful
! * and timesaving tool in analysing Data of imaging Cerenkov telescopes.
! * It is distributed WITHOUT ANY WARRANTY.
! *
! * Permission to use, copy, modify and distribute this software and its
! * documentation for any purpose is hereby granted without fee,
! * provided that the above copyright notice appear in all copies and
! * that both that copyright notice and this permission notice appear
! * in supporting documentation. It is provided "as is" without express
! * or implied warranty.

! *
!
!
!   Author(s): Markus Gaug   11/2003 <mailto:markus@ifae.es>
!
!   Copyright: MAGIC Software Development, 2000-2004
!
!
\* ======================================================================== */

/////////////////////////////////////////////////////////////////////////////
//                                                               
// MCalibrationChargeCam                                               
//                                                               
// Hold the whole Calibration results of the camera:
//                                                               
// 1) MCalibrationChargeCam initializes a TClonesArray whose elements are 
//    pointers to MCalibrationPix Containers
// 2) It initializes a pointer to an MCalibrationBlindPix container
// 3) It initializes a pointer to an MCalibrationPINDiode container
//
//
// The calculated values (types of GetPixelContent) are:
// 
// --------------------------------------------------------------------------
//
// The types are as follows:
// 
// Fitted values:
// ============== 
//
// 0: Fitted Charge
// 1: Error of fitted Charge
// 2: Sigma of fitted Charge
// 3: Error of Sigma of fitted Charge
//
// Useful variables derived from the fit results:
// =============================================
//
// 4: Returned probability of Gauss fit to Charge distribution
// 5: Reduced Sigma of fitted Charge --> sqrt(sigma_Q^2 - PedRMS^2)
// 6: Error Reduced Sigma of fitted Charge 
// 7: Reduced Sigma per Charge 
// 8: Error of Reduced Sigma per Charge 
//
// Results of the different calibration methods:
// =============================================
//
// 9: Number of Photo-electrons obtained with the F-Factor method
// 10: Error on Number of Photo-electrons obtained with the F-Factor method
// 11: Mean conversion factor obtained with the F-Factor method
// 12: Error on the mean conversion factor obtained with the F-Factor method
// 13: Overall F-Factor of the readout obtained with the F-Factor method
// 14: Error on Overall F-Factor of the readout obtained with the F-Factor method
// 15: Number of Photons inside Plexiglass obtained with the Blind Pixel method
// 16: Error on Number of Photons inside Plexiglass obtained with the Blind Pixel method
// 17: Mean conversion factor obtained with the Blind Pixel method
// 18: Error on the mean conversion factor obtained with the Blind Pixel method
// 19: Overall F-Factor of the readout obtained with the Blind Pixel method
// 20: Error on Overall F-Factor of the readout obtained with the Blind Pixel method
// 21: Number of Photons outside Plexiglass obtained with the PIN Diode method
// 22: Error on Number of Photons outside Plexiglass obtained with the PIN Diode method
// 23: Mean conversion factor obtained with the PIN Diode method
// 24: Error on the mean conversion factor obtained with the PIN Diode method
// 25: Overall F-Factor of the readout obtained with the PIN Diode method
// 26: Error on Overall F-Factor of the readout obtained with the PIN Diode method
//
// Localized defects:
// ==================
//
// 27: Excluded Pixels
// 28: Pixels where the fit did not succeed --> results obtained only from the histograms
// 29: Pixels with apparently wrong results
// 30: Pixels with un-expected behavior in the Hi Gain fourier spectrum (e.g. oscillations)
// 31: Pixels with un-expected behavior in the Lo Gain fourier spectrum (e.g. oscillations)a
// 32: Number of probable pickup events in the Hi Gain 
// 33: Number of probable pickup events in the Lo Gain
//
// Other classifications of pixels:
// ================================
//
// 34: Pixels with saturated Hi-Gain
//
// Classification of validity of the calibrations:
// ===============================================
//
// 35: Pixels with valid calibration by the F-Factor-Method
// 36: Pixels with valid calibration by the Blind Pixel-Method
// 37: Pixels with valid calibration by the PIN Diode-Method
//
// Used Pedestals:
// ===============
//
// 38: Mean Pedestal over the entire range of signal extraction
// 39: Error on the Mean Pedestal over the entire range of signal extraction
// 40: Pedestal RMS over the entire range of signal extraction
// 41: Error on the Pedestal RMS over the entire range of signal extraction
//
// Calculated absolute arrival times (very low precision!):
// ========================================================
//
// 42: Absolute Arrival time of the signal
// 43: RMS of the Absolute Arrival time of the signal
//
/////////////////////////////////////////////////////////////////////////////
#include "MCalibrationChargeCam.h"

#include <TH2.h>
#include <TCanvas.h>
#include <TClonesArray.h>

#include "MLog.h"
#include "MLogManip.h"

#include "MGeomCam.h"
#include "MGeomPix.h"

#include "MCalibrationChargePix.h"
#include "MCalibrationChargeBlindPix.h"
#include "MCalibrationChargePINDiode.h"


ClassImp(MCalibrationChargeCam);

using namespace std;

const Int_t   MCalibrationChargeCam::gkBlindPixelId   =  559;
const Int_t   MCalibrationChargeCam::gkPINDiodeId     = 9999;

// --------------------------------------------------------------------------
//
// Default constructor. 
//
// Creates a TClonesArray of MCalibrationPix containers, initialized to 1 entry
// Later, a call to MCalibrationChargeCam::InitSize(Int_t size) has to be performed
//
// Creates an MCalibrationBlindPix container 
//
MCalibrationChargeCam::MCalibrationChargeCam(const char *name, const char *title)
    : fBlindPixel(NULL), 
      fPINDiode(NULL),
      fOffsets(NULL),
      fSlopes(NULL),
      fOffvsSlope(NULL)
{
    fName  = name  ? name  : "MCalibrationChargeCam";
    fTitle = title ? title : "Storage container for the Calibration Information in the camera";

    fPixels     = new TClonesArray("MCalibrationChargePix",1);

    Clear();
}

// --------------------------------------------------------------------------
//
// Delete the TClonesArray of MCalibrationPix containers
// Delete the MCalibrationPINDiode and the MCalibrationBlindPix
//
// Delete the histograms if they exist
//
MCalibrationChargeCam::~MCalibrationChargeCam()
{

  //
  // delete fPixels should delete all Objects stored inside
  // 
  delete fPixels;

  if (fOffsets)
    delete fOffsets;
  if (fSlopes)
    delete fSlopes;
  if (fOffvsSlope)
    delete fOffvsSlope;

}

// -------------------------------------------------------------------
//
// This function simply allocates memory via the ROOT command:
// (TObject**) TStorage::ReAlloc(fCont, newSize * sizeof(TObject*),
//                                      fSize * sizeof(TObject*));
// newSize corresponds to size in our case
// fSize is the old size (in most cases: 1)
//
void MCalibrationChargeCam::InitSize(const UInt_t i)
{
  
  //
  // check if we have already initialized to size
  //
  if (CheckBounds(i))
    return;
  
  fPixels->ExpandCreate(i);

}

// --------------------------------------------------------------------------
//
// This function returns the current size of the TClonesArray 
// independently if the MCalibrationPix is filled with values or not.
//
// It is the size of the array fPixels.
//
Int_t MCalibrationChargeCam::GetSize() const
{
  return fPixels->GetEntriesFast();
}

// --------------------------------------------------------------------------
//
// Check if position i is inside the current bounds of the TClonesArray
//
Bool_t MCalibrationChargeCam::CheckBounds(Int_t i) const 
{
  return i < GetSize();
} 


// --------------------------------------------------------------------------
//
// Get i-th pixel (pixel number)
//
MCalibrationChargePix &MCalibrationChargeCam::operator[](UInt_t i)
{
  return *static_cast<MCalibrationChargePix*>(fPixels->UncheckedAt(i));
}

// --------------------------------------------------------------------------
//
// Get i-th pixel (pixel number)
//
const MCalibrationChargePix &MCalibrationChargeCam::operator[](UInt_t i) const
{
  return *static_cast<MCalibrationChargePix*>(fPixels->UncheckedAt(i));
}


// --------------------------------------
//
void MCalibrationChargeCam::Clear(Option_t *o)
{

  fPixels->ForEach(TObject, Clear)();

  fNumExcludedPixels                 = 0;

  CLRBIT(fFlags,kBlindPixelMethodValid);
  CLRBIT(fFlags,kPINDiodeMethodValid);

  return;
}

void MCalibrationChargeCam::SetBlindPixelMethodValid(const Bool_t b)
{
    b ? SETBIT(fFlags, kBlindPixelMethodValid) : CLRBIT(fFlags, kBlindPixelMethodValid); 
}

void MCalibrationChargeCam::SetPINDiodeMethodValid(const Bool_t b)
{
    b ? SETBIT(fFlags, kPINDiodeMethodValid) : CLRBIT(fFlags, kPINDiodeMethodValid); 
}

Bool_t  MCalibrationChargeCam::IsBlindPixelMethodValid()   const
{
  return TESTBIT(fFlags,kBlindPixelMethodValid);
}

Bool_t  MCalibrationChargeCam::IsPINDiodeMethodValid() const
{
  return TESTBIT(fFlags,kPINDiodeMethodValid);  
}


// --------------------------------------------------------------------------
//
// Print first the well fitted pixels 
// and then the ones which are not FitValid
//
void MCalibrationChargeCam::Print(Option_t *o) const
{

  *fLog << all << GetDescriptor() << ":" << endl;
  int id = 0;
  
  *fLog << all << "Succesfully calibrated pixels:" << endl;
  *fLog << all << endl;

  TIter Next(fPixels);
  MCalibrationChargePix *pix;
  while ((pix=(MCalibrationChargePix*)Next()))
    {
      
      if (pix->IsChargeValid() && !pix->IsExcluded() && !pix->IsOscillating()) 
	{

	    *fLog << all << "Pix " << pix->GetPixId() 
		<< ":  Ped.  Rms: "            << pix->GetPedRms()        << " +- " << pix->GetPedRmsErr() 
		<< "   Mean signal: "          << pix->GetMeanCharge()    << " +- " << pix->GetSigmaCharge() 
		<< "   Reduced Sigma: "        << pix->GetRSigmaCharge() 
		<< "   Nr Phe's: "             << pix->GetPheFFactorMethod() 
		<< endl;
          id++;
	}
    }
  
  *fLog << all << id << " succesful pixels :-))" << endl;
  id = 0;
  
  *fLog << all << endl;
  *fLog << all << "Pixels with errors:" << endl;
  *fLog << all << endl;
  
  TIter Next2(fPixels);
    while ((pix=(MCalibrationChargePix*)Next2()))
      {
        
        if (!pix->IsExcluded() && !pix->IsChargeValid())
          {


	    *fLog << all << "Pix " << pix->GetPixId() 
		<< ":  Ped.  Rms: "            << pix->GetPedRms()        << " +- " << pix->GetPedRmsErr() 
		<< "   Mean signal: "          << pix->GetMeanCharge()    << " +- " << pix->GetSigmaCharge() 
		<< "   Reduced Sigma: "        << pix->GetRSigmaCharge() 
		<< "   Nr Phe's: "             << pix->GetPheFFactorMethod() 
		<< endl;
            id++;
          }
      }
    *fLog << all << id << " pixels with errors :-((" << endl;

  *fLog << all << endl;
  *fLog << all << "Pixels with oscillations:" << endl;
  *fLog << all << endl;
  
  id = 0;

  TIter Next3(fPixels);
  while ((pix=(MCalibrationChargePix*)Next3()))
    {

      if ( pix->IsOscillating()  && !pix->IsExcluded())
        {

	    *fLog << all << "Pix " << pix->GetPixId() 
		<< ":  Ped.  Rms: "            << pix->GetPedRms()        << " +- " << pix->GetPedRmsErr() 
		<< "   Mean signal: "          << pix->GetMeanCharge()    << " +- " << pix->GetSigmaCharge() 
		<< "   Reduced Sigma: "        << pix->GetRSigmaCharge() 
		<< "   Nr Phe's: "             << pix->GetPheFFactorMethod() 
		<< endl;
	    id++;
        }
    }
  *fLog << all << id << " Oscillating pixels :-((" << endl;
  
    
  *fLog << all << endl;
  *fLog << all << "Excluded pixels:" << endl;
  *fLog << all << endl;
  
  id = 0;

  TIter Next4(fPixels);
  while ((pix=(MCalibrationChargePix*)Next4()))
  {
      if (pix->IsExcluded())
      {
	  *fLog << all << pix->GetPixId() << endl;
	  id++;
      }
  }
  *fLog << all << id << " Excluded pixels " << endl;
}


// --------------------------------------------------------------------------
//
// The types are as follows:
// 
// Fitted values:
// ============== 
//
// 0: Fitted Charge
// 1: Error of fitted Charge
// 2: Sigma of fitted Charge
// 3: Error of Sigma of fitted Charge
//
// Useful variables derived from the fit results:
// =============================================
//
// 4: Returned probability of Gauss fit to Charge distribution
// 5: Reduced Sigma of fitted Charge --> sqrt(sigma_Q^2 - PedRMS^2)
// 6: Error Reduced Sigma of fitted Charge 
// 7: Reduced Sigma per Charge 
// 8: Error of Reduced Sigma per Charge 
//
// Results of the different calibration methods:
// =============================================
//
// 9: Number of Photo-electrons obtained with the F-Factor method
// 10: Error on Number of Photo-electrons obtained with the F-Factor method
// 11: Mean conversion factor obtained with the F-Factor method
// 12: Error on the mean conversion factor obtained with the F-Factor method
// 13: Overall F-Factor of the readout obtained with the F-Factor method
// 14: Error on Overall F-Factor of the readout obtained with the F-Factor method
// 15: Number of Photons inside Plexiglass obtained with the Blind Pixel method
// 16: Error on Number of Photons inside Plexiglass obtained with the Blind Pixel method
// 17: Mean conversion factor obtained with the Blind Pixel method
// 18: Error on the mean conversion factor obtained with the Blind Pixel method
// 19: Overall F-Factor of the readout obtained with the Blind Pixel method
// 20: Error on Overall F-Factor of the readout obtained with the Blind Pixel method
// 21: Number of Photons outside Plexiglass obtained with the PIN Diode method
// 22: Error on Number of Photons outside Plexiglass obtained with the PIN Diode method
// 23: Mean conversion factor obtained with the PIN Diode method
// 24: Error on the mean conversion factor obtained with the PIN Diode method
// 25: Overall F-Factor of the readout obtained with the PIN Diode method
// 26: Error on Overall F-Factor of the readout obtained with the PIN Diode method
//
// Localized defects:
// ==================
//
// 27: Excluded Pixels
// 28: Pixels where the fit did not succeed --> results obtained only from the histograms
// 29: Pixels with apparently wrong results
// 30: Pixels with un-expected behavior in the Hi Gain fourier spectrum (e.g. oscillations)
// 31: Pixels with un-expected behavior in the Lo Gain fourier spectrum (e.g. oscillations)a
// 32: Number of probable pickup events in the Hi Gain 
// 33: Number of probable pickup events in the Lo Gain
//
// Other classifications of pixels:
// ================================
//
// 34: Pixels with saturated Hi-Gain
//
// Classification of validity of the calibrations:
// ===============================================
//
// 35: Pixels with valid calibration by the F-Factor-Method
// 36: Pixels with valid calibration by the Blind Pixel-Method
// 37: Pixels with valid calibration by the PIN Diode-Method
//
// Used Pedestals:
// ===============
//
// 38: Mean Pedestal over the entire range of signal extraction
// 39: Error on the Mean Pedestal over the entire range of signal extraction
// 40: Pedestal RMS over the entire range of signal extraction
// 41: Error on the Pedestal RMS over the entire range of signal extraction
//
// Calculated absolute arrival times (very low precision!):
// ========================================================
//
// 42: Absolute Arrival time of the signal
// 43: RMS of the Absolute Arrival time of the signal
//
Bool_t MCalibrationChargeCam::GetPixelContent(Double_t &val, Int_t idx, const MGeomCam &cam, Int_t type) const
{

  if (idx > GetSize())
    return kFALSE;

  Float_t area = cam[idx].GetA();

 if (area == 0)
    return kFALSE;

  switch (type)
    {
    case 0:
      if ((*this)[idx].IsExcluded())
        return kFALSE;
      val = (*this)[idx].GetMeanCharge();
      break;
    case 1:
      if ((*this)[idx].IsExcluded())
        return kFALSE;
      val = (*this)[idx].GetMeanChargeErr();
      break;
    case 2:
      if ((*this)[idx].IsExcluded())
        return kFALSE;
      val = (*this)[idx].GetSigmaCharge();
      break;
    case 3:
      if ((*this)[idx].IsExcluded())
        return kFALSE;
      val = (*this)[idx].GetSigmaChargeErr();
      break;
    case 4:
      if ((*this)[idx].IsExcluded())
        return kFALSE;
      val = (*this)[idx].GetChargeProb();
      break;
    case 5:
      if ((*this)[idx].IsExcluded())
        return kFALSE;
      val = (*this)[idx].GetRSigmaCharge();
      break;
    case 6:
      if ((*this)[idx].IsExcluded())
        return kFALSE;
      val = (*this)[idx].GetRSigmaChargeErr();
      break;
    case 7:
      if ((*this)[idx].IsExcluded())
        return kFALSE;
      val = (*this)[idx].GetRSigmaCharge() / (*this)[idx].GetMeanCharge();
      break;
    case 8:
      if ((*this)[idx].IsExcluded())
        return kFALSE;
      // relative error RsigmaCharge square
      val =    (*this)[idx].GetRSigmaChargeErr()* (*this)[idx].GetRSigmaChargeErr() 
            / ((*this)[idx].GetRSigmaCharge()   * (*this)[idx].GetRSigmaCharge()   );
      // relative error Charge square
      val +=   (*this)[idx].GetMeanChargeErr() * (*this)[idx].GetMeanChargeErr()
            / ((*this)[idx].GetMeanCharge()    * (*this)[idx].GetMeanCharge()   );
      // calculate relative error out of squares
      val  =   TMath::Sqrt(val) ;
      // multiply with value to get absolute error
      val  *=  (*this)[idx].GetRSigmaCharge() / (*this)[idx].GetMeanCharge();
      break;
    case 9:
      if ((*this)[idx].IsExcluded())
        return kFALSE;
      val = (*this)[idx].GetPheFFactorMethod();
      break;
    case 10:
      if ((*this)[idx].IsExcluded())
        return kFALSE;
      val = (*this)[idx].GetPheFFactorMethodErr();
      break;
    case 11:
      if ((*this)[idx].IsExcluded())
        return kFALSE;
      val = (*this)[idx].GetMeanConversionFFactorMethod();
      break;
    case 12:
      if ((*this)[idx].IsExcluded())
        return kFALSE;
      val = (*this)[idx].GetConversionFFactorMethodErr();
      break;
    case 13:
      if ((*this)[idx].IsExcluded())
        return kFALSE;
      val = (*this)[idx].GetTotalFFactorFFactorMethod();
      break;
    case 14:
      if ((*this)[idx].IsExcluded())
        return kFALSE;
      val = (*this)[idx].GetTotalFFactorErrFFactorMethod();
      break;
    case 15:
      if ((*this)[idx].IsExcluded())
        return kFALSE;
      val = fBlindPixel->GetMeanFluxInsidePlexiglass()*area;
      break;
    case 16:
      if ((*this)[idx].IsExcluded())
        return kFALSE;
      val = fBlindPixel->GetMeanFluxErrInsidePlexiglass()*area;
      break;
    case 17:
      if ((*this)[idx].IsExcluded())
        return kFALSE;
      val = (*this)[idx].GetMeanConversionBlindPixelMethod();
      break;
    case 18:
      if ((*this)[idx].IsExcluded())
        return kFALSE;
      val = (*this)[idx].GetConversionBlindPixelMethodErr();
      break;
    case 19:
      if ((*this)[idx].IsExcluded())
        return kFALSE;
      val = (*this)[idx].GetTotalFFactorBlindPixelMethod();
      break;
    case 20:
      if ((*this)[idx].IsExcluded())
        return kFALSE;
      val = (*this)[idx].GetTotalFFactorErrBlindPixelMethod();
      break;
    case 21:
      if ((*this)[idx].IsExcluded())
        return kFALSE;
      val = fPINDiode->GetMeanFluxOutsidePlexiglass()*area;
      break;
    case 22:
      if ((*this)[idx].IsExcluded())
        return kFALSE;
      val = fPINDiode->GetMeanFluxErrOutsidePlexiglass()*area;
      break;
    case 23:
      if ((*this)[idx].IsExcluded())
        return kFALSE;
      val = (*this)[idx].GetMeanConversionPINDiodeMethod();
      break;
    case 24:
      if ((*this)[idx].IsExcluded())
        return kFALSE;
      val = (*this)[idx].GetConversionPINDiodeMethodErr();
      break;
    case 25:
      if ((*this)[idx].IsExcluded())
        return kFALSE;
      val = (*this)[idx].GetTotalFFactorBlindPixelMethod();
      break;
    case 26:
      if ((*this)[idx].IsExcluded())
        return kFALSE;
      val = (*this)[idx].GetTotalFFactorErrBlindPixelMethod();
      break;
    case 27:
      if ((*this)[idx].IsExcluded())
        val = 1.;
      else
        return kFALSE;
      break;
    case 28:
      if ((*this)[idx].IsExcluded())
        return kFALSE;
      if (!(*this)[idx].IsFitted())
        val = 1;
      else
        return kFALSE;
      break;
    case 29:
      if ((*this)[idx].IsExcluded())
        return kFALSE;
      if (!(*this)[idx].IsChargeValid())
        val = 1;
      else
        return kFALSE;
      break;
    case 30:
      if ((*this)[idx].IsExcluded())
        return kFALSE;
      if ((*this)[idx].IsHiGainOscillating())
        val = 1;
      else
        return kFALSE;
      break;
    case 31:
      if ((*this)[idx].IsExcluded())
        return kFALSE;
      if ((*this)[idx].IsLoGainOscillating())
        val = 1;
      else
        return kFALSE;
      break;
    case 32:
      if ((*this)[idx].IsExcluded())
        return kFALSE;
      val = (*this)[idx].GetHiGainNumPickup();
      break;
    case 33:
      if ((*this)[idx].IsExcluded())
        return kFALSE;
      val = (*this)[idx].GetLoGainNumPickup();
      break;
    case 34:
      if ((*this)[idx].IsExcluded())
        return kFALSE;
      if ((*this)[idx].IsHiGainSaturation())
        val = 1;
      else
        return kFALSE;
      break;
    case 35:
      if ((*this)[idx].IsExcluded())
        return kFALSE;
      if ((*this)[idx].IsFFactorMethodValid())
        val = 1;
      else
        return kFALSE;
      break;
    case 36:
      if ((*this)[idx].IsExcluded())
        return kFALSE;
      if ((*this)[idx].IsBlindPixelMethodValid())
        val = 1;
      else
        return kFALSE;
      break;
    case 37:
      if ((*this)[idx].IsExcluded())
        return kFALSE;
      if ((*this)[idx].IsPINDiodeMethodValid())
        val = 1;
      else
        return kFALSE;
      break;
    case 38:
      if ((*this)[idx].IsExcluded())
        return kFALSE;
      val = (*this)[idx].GetPed();
      break;
    case 39:
      if ((*this)[idx].IsExcluded())
        return kFALSE;
      val = (*this)[idx].GetPedErr();
      break;
    case 40:
      if ((*this)[idx].IsExcluded())
        return kFALSE;
      val = (*this)[idx].GetPedRms();
      break;
    case 41:
      if ((*this)[idx].IsExcluded())
        return kFALSE;
      val = (*this)[idx].GetPedErr()/2.;
      break;
    case 42:
      if ((*this)[idx].IsExcluded())
        return kFALSE;
      val = (*this)[idx].GetAbsTimeMean();
      break;
    case 43:
      if ((*this)[idx].IsExcluded())
        return kFALSE;
      val = (*this)[idx].GetAbsTimeRms();
      break;
    default:
      return kFALSE;
    }
  return val!=-1.;
}

// --------------------------------------------------------------------------
//
// What MHCamera needs in order to draw an individual pixel in the camera
//
void MCalibrationChargeCam::DrawPixelContent(Int_t idx) const
{
  (*this)[idx].DrawClone();
}

void MCalibrationChargeCam::ApplyBlindPixelCalibration()
{

  Float_t flux    = fBlindPixel->GetMeanFluxInsidePlexiglass();
  Float_t fluxerr = fBlindPixel->GetMeanFluxErrInsidePlexiglass();

  TIter Next(fPixels);
  MCalibrationChargePix *pix;
  while ((pix=(MCalibrationChargePix*)Next()))
    {

      if(pix->IsChargeValid())
        {
          
          const Int_t idx = pix->GetPixId();

          const Float_t charge    = pix->GetMeanCharge();
          const Float_t area      = (*fGeomCam)[idx].GetA();
          const Float_t chargeerr = pix->GetMeanChargeErr();          

          const Float_t nphot      = flux    * area;
          const Float_t nphoterr   = fluxerr * area;
          const Float_t conversion = nphot/charge;
          Float_t conversionerr;
          
          conversionerr  = nphoterr/charge 
                         * nphoterr/charge ;
          conversionerr += chargeerr/charge
                         * chargeerr/charge
                         * conversion*conversion;
          conversionerr = TMath::Sqrt(conversionerr);

          const Float_t conversionsigma = 0.;

          pix->SetConversionBlindPixelMethod(conversion, conversionerr, conversionsigma);

          if (conversionerr/conversion < 0.1) 
            pix->SetBlindPixelMethodValid();
        }
    }
}


void MCalibrationChargeCam::ApplyPINDiodeCalibration()
{

  Float_t flux    = fPINDiode->GetMeanFluxOutsidePlexiglass();
  Float_t fluxerr = fPINDiode->GetMeanFluxErrOutsidePlexiglass();

  TIter Next(fPixels);
  MCalibrationChargePix *pix;
  while ((pix=(MCalibrationChargePix*)Next()))
    {

      if (pix->IsChargeValid())
        {

          const Int_t idx = pix->GetPixId();

          const Float_t charge    = pix->GetMeanCharge();
          const Float_t area      = (*fGeomCam)[idx].GetA();
          const Float_t chargeerr = pix->GetMeanChargeErr();          

          const Float_t nphot      = flux    * area;
          const Float_t nphoterr   = fluxerr * area;
          const Float_t conversion = nphot/charge;

          Float_t conversionerr;
          
          conversionerr  = nphoterr/charge 
                         * nphoterr/charge ;
          conversionerr += chargeerr/charge
                         * chargeerr/charge
                         * conversion*conversion;
          if (conversionerr > 0.)
            conversionerr = TMath::Sqrt(conversionerr);

          const Float_t conversionsigma = 0.;

          pix->SetConversionPINDiodeMethod(conversion, conversionerr, conversionsigma);

          if (conversionerr/conversion < 0.1) 
            pix->SetPINDiodeMethodValid();
          
        }
    }
}



Bool_t MCalibrationChargeCam::GetConversionFactorBlindPixel(Int_t ipx, Float_t &mean, Float_t &err, Float_t &sigma)
{

  mean  = (*this)[ipx].GetMeanConversionBlindPixelMethod();
  err   = (*this)[ipx].GetConversionBlindPixelMethodErr();
  sigma = (*this)[ipx].GetSigmaConversionBlindPixelMethod();

  return kTRUE;
}


Bool_t MCalibrationChargeCam::GetConversionFactorFFactor(Int_t ipx, Float_t &mean, Float_t &err, Float_t &sigma)
{

  Float_t conv = (*this)[ipx].GetMeanConversionFFactorMethod();

  if (conv < 0.)
    return kFALSE;

  mean  = conv;
  err   = (*this)[ipx].GetConversionFFactorMethodErr();
  sigma = (*this)[ipx].GetSigmaConversionFFactorMethod();

  return kTRUE;
}


//-----------------------------------------------------------------------------------
//
// Calculates the conversion factor between the integral of FADCs slices 
// (as defined in the signal extractor MExtractSignal.cc)
// and the number of photons reaching the plexiglass for one Inner Pixel 
//
// FIXME: The PINDiode is still not working and so is the code 
//
Bool_t MCalibrationChargeCam::GetConversionFactorPINDiode(Int_t ipx, Float_t &mean, Float_t &err, Float_t &sigma)
{

  mean  = (*this)[ipx].GetMeanConversionPINDiodeMethod();
  err   = (*this)[ipx].GetConversionPINDiodeMethodErr();
  sigma = (*this)[ipx].GetSigmaConversionPINDiodeMethod();

  return kFALSE;

}

//-----------------------------------------------------------------------------------
//
// Calculates the best combination of the three used methods possible 
// between the integral of FADCs slices 
// (as defined in the signal extractor MExtractSignal.cc)
// and the number of photons reaching one Inner Pixel. 
// The procedure is not yet defined.
//
// FIXME: The PINDiode is still not working and so is the code 
//
Bool_t MCalibrationChargeCam::GetConversionFactorCombined(Int_t ipx, Float_t &mean, Float_t &err, Float_t &sigma)
{
  return kFALSE;

}

/*
void MCalibrationChargeCam::DrawHiLoFits()
{

  if (!fOffsets)
    fOffsets = new TH1D("pp","Offsets of the HiGain LoGain Fit",100,-600.,400.);
  if (!fSlopes)
    fSlopes  = new TH1D("mm","Slopes of the HiGain LoGain Fit",100,-2.,2.);
  if (!fOffvsSlope)
    fOffvsSlope = new TH2D("aa","Slopes vs Offsets of the HiGain LoGain Fit",100,-600.,400.,100,-2.,2.);

  TIter Next(fPixels);
  MCalibrationPix *pix;
  MHCalibrationPixel *hist;
  while ((pix=(MCalibrationPix*)Next()))
    {
      hist = pix->GetHist();
      hist->FitHiGainvsLoGain();
      fOffsets->Fill(hist->GetOffset(),1.);
      fSlopes->Fill(hist->GetSlope(),1.);
      fOffvsSlope->Fill(hist->GetOffset(),hist->GetSlope(),1.);
    }

   TCanvas *c1 = new TCanvas();

   c1->Divide(1,3);
   c1->cd(1);
   fOffsets->Draw();
   gPad->Modified();
   gPad->Update();

   c1->cd(2);
  fSlopes->Draw();
  gPad->Modified();
  gPad->Update();

  c1->cd(3);
  fOffvsSlope->Draw("col1");
  gPad->Modified();
  gPad->Update();
}

*/
