/////////////////////////////////////////////////////////////////////////////
//                                                                         
// EEsmdProfile                                                            
//
// Author: Jason C. Webb <jwebb@iucf.indiana.edu>                                                                      //
//
// EEsmdProfile creates histograms of the SMD distributions which are 
// beneath the seed towers of each cluster.
//
// Example of how to improve cluster position with EEsmdProfile.  This
// example neglects several things, including the overlap of
// strips in neighboring sectors and other edge effects, and is not
// meant for production.
//
// // Will need the smd geometry class
// EEmcSmdGeom *geom = EEmcSmdGeom::instance();
//
// // We have a cluster finder from somewhere 
// EEezClAnalysis *clust = ...
//
// // The profile analysis
// EEsmdProfile *prof = new EEsmdProfile();
//
// ... code which runs the cluster finder ...
//
// // Create the SMD profiles for each cluster
// prof -> Make ( clust );
//
// // Improve the first cluster's position.  First, obtain a pointer
// // to the cluster.
// EEezCluster *cluster = clust -> getClusterPtr(0);
//
// // We will need to know what sector we are in
// Int_t sector = cluster -> getSeedTower() -> getSector();
//
// // Next, obtain the SMD histograms corresponding to the cluster
// TH1F *uHisto = prof -> getProfileU(0);
// TH1F *vHisto = prof -> getProfileV(0);
//
// // Somehow obtain the mean of these histograms... Fit to the correct
// // shower shape, once we know it...
// Float_t uMean = ...
// Float_t vMean = ...
//
// // Now, find the intersection of these two strips within the
// // sector of the seed tower using the geometry class
// TVector3 intersection = geom -> getIntersection(sector,(Int_t)uMean,(Int_t)vMean);
//
// // Make intersection a unit vector
// intersection = intersection.Unit();
//
// // Recalculate cluster momentum
// TVector3 momentum = intersection * cluster -> getEnergy();
//
// // And set its momentum
// cluster -> setMomentum( momentum );
//
// **** NOTE **** **** NOTE **** **** NOTE **** **** NOTE **** **** NOTE **** 
//
// Will need to think about whether the fit to the centroid of this 
// distribution will obtain the correct position/index or not... since
// the strips are indexed from 0... i.e. if strip number 64 (index 63)
// is fit to a gaussian... I bet the mean comes out to be 63.5... so the
// fits to these distributions should probably be incremented by 0.5,
// before being passed to EEmcSmdGeom::getIntersection().
//
// **** NOTE **** **** NOTE **** **** NOTE **** **** NOTE **** **** NOTE **** 
//
// To Do List:
//
// 1. Need to handle/flag empty histograms
// 
//
/////////////////////////////////////////////////////////////////////////////

#include "EEsmdProfile.h"
#include "EEezClAnalysis.h"
#include "EEezCluster.h"
#include "EEezTower.h"
#include "EEezStrip.h"
#include "TH1F.h"
#include "TMap.h"
#ifndef __ROOT__
#include "EEezClusterQA.h"
#endif

#include <iostream>

// Shower-shape functions
#include "eeSinglePeak.h"
#include "eeDoublePeak.h"

/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
ClassImp(EEsmdProfile);

 EEsmdProfile::EEsmdProfile() 
{
  // Default Constructor (not meant to be called, use the name/title version).

  m_MinEnergy = 0.;
  m_MaxEnergy = 999999.;

  m_ShowerShape = NULL;

}

 EEsmdProfile::EEsmdProfile( const Char_t *name, const Char_t *title )
  :TDirectory(name,title) 
{
  // Constructor w/ name and title
  EEsmdProfile();
}

/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
 Int_t EEsmdProfile::Init() 
{
  // Initialization
  if ( !m_ShowerShape ) 
    m_ShowerShape = new TF1("gauss","gaus");
  
  m_SinglePeak = new TF1("eeSinglePeak", eeSinglePeak, 0, 288, 5 );
  m_SinglePeak -> SetParameter(4,3.5);
  m_SinglePeak -> SetParLimits(4,3.5,3.5);

  m_SinglePeak -> SetLineColor(2);
  m_SinglePeak -> SetLineStyle(2);
  m_SinglePeak -> SetLineWidth(1);

  m_DoublePeak = new TF1("eeDoublePeak", eeDoublePeak, 0, 288, 10 );
  m_DoublePeak -> SetParameter(4,3.5);
  m_DoublePeak -> SetParLimits(4,3.5,3.5);
  m_DoublePeak -> SetParameter(9,3.5);
  m_DoublePeak -> SetParLimits(9,3.5,3.5);

  m_DoublePeak -> SetLineColor(2);
  m_DoublePeak -> SetLineStyle(2);
  m_DoublePeak -> SetLineWidth(1);

  cd();

  m_Converge = new TH1F("m_Converge","Number of iterations for single-peak fit to stabilize",10,0.,10.);

#ifndef __ROOT__
  for ( Int_t i = 0; i < 12; i++ ) {

    Int_t sec = i+1;
    TString name = "QAsec"; if ( sec < 10 ) name += "0"; name += sec;
    m_EEClusterQA[i] = new EEezClusterQA(name,"EEMC Cluster QA / EEsmdProfile");
    m_EEClusterQA[i] -> setSmdProfiler( this );
    m_EEClusterQA[i] -> Init();
    m_EEClusterQA[i] -> setSmdProfiler( this );

  }
#endif

  cd("..");

  return 1;

}

/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////

 Int_t EEsmdProfile::Make( EEezClAnalysis *analy, 
			  EEmcEventHeader *header 
			  ) 
{
  // Takes as input a pointer to the cluster finder and to an
  // EEmcEventHeader.  Loops over all clusters and creates a
  // histogram of the energy response of SMD strips versus
  // strip number.  The histograms ordering of the histograms
  // matches the ordering of the clusters.

  m_EEezClust = analy;
  

  // Loop over all clusters found in the cluster analysis
  Int_t nc = analy -> getNClusters();

  //  std::cout << "Preparing to loop over " << nc << " clusters" << std::endl << std::flush;

  for ( Int_t ic = 0; ic < nc; ic++ ) { 
    
    // Get the cluster from the analysis
    EEezCluster *cluster = analy -> getClusterPtr( ic );

    // Get the seed tower for this cluster
    EEezTower *seed = cluster -> getSeedTower();

    // As a starting point, we only fill a histogram
    // over the range of strips associated with the
    // seed tower.  In the future, we should probably
    // expand this to all towers in the cluster.  Of 
    // course, sector boundaries present complications.
    // As do overlap strips.
    
    // Names and titles for histograms

    TString hname="hu";
    hname += seed-> getName();
    hname += ":";
    if ( header ) 
      hname += header -> getEventNumber();
    else
      hname += "1";
    
    TString htitle="SMD u-strip distribution, event number ";
    if ( header )
      htitle += header -> getEventNumber();
    else
      htitle += "1";
    htitle += ", seed tower ";
    htitle += seed -> getName();

    TString vname="hv";
    vname += seed-> getName();
    vname += ":";
    if ( header )
      vname += header -> getEventNumber();
    else
      vname += "1";
    
    TString vtitle="SMD v-strip distributions, event number ";
    if ( header )
      vtitle += header -> getEventNumber();
    else
      vtitle += "1";
    vtitle += ", seed tower ";
    vtitle += seed -> getName();


    // Get the appropriate range of U and V strips
    EEezStripPtrVec_t *ustrips = seed -> getUStrips();
    EEezStripPtrVec_t *vstrips = seed -> getVStrips();
    
    // Get the min and max U and V strips
    EEezStripPtrVecIter_t iter;
    iter = ustrips -> begin();
    EEezStrip *ufirst = *iter;
    iter = ustrips -> end() - 1;
    EEezStrip *ulast  = *iter;
    iter = vstrips -> begin();
    EEezStrip *vfirst = *iter;
    iter = vstrips -> end() - 1;
    EEezStrip *vlast  = *iter;

    Int_t umin = ufirst -> getIndex() - 2;
    Int_t vmin = vfirst -> getIndex() - 2;
    Int_t umax = ulast  -> getIndex() + 2;
    Int_t vmax = vlast  -> getIndex() + 2;
    

    // Histograms for storage, created on the heap, so
    // we need to erase them when we clear.
    TH1F *hu = new TH1F(hname,htitle,(umax-umin),umin,umax);
    TH1F *hv = new TH1F(vname,vtitle,(vmax-vmin),vmin,vmax);

    TString xtitle = "strip number";
    TString ytitle = "N_{mips} = (E_{strip}/E_{mip}) = ( ADC - ped ) / gain[mip/ch]";

    hu -> GetXaxis() -> SetTitle(xtitle);
    hv -> GetXaxis() -> SetTitle(xtitle);
    hu -> GetYaxis() -> SetTitle(ytitle);
    hv -> GetYaxis() -> SetTitle(ytitle);


    ///////////////////////////////////////////////////////

    // Fill said histograms with energy deposit 
    // versus strip number (index)

    iter = ustrips -> begin();
    while ( iter != ustrips -> end() ) {

      //Float_t energy = (*iter)->getEnergy();
      Int_t   index  = (*iter)->getIndex();
      Float_t npe    = (*iter)->getNumPhotoElectrons();
      Float_t nmips  = (*iter)->getNumMips();
      
      if ( nmips > 0. ) {

// 	Float_t emips  = 0.;
// 	if ( npe > 0. ) { 
// 	  emips = nmips / TMath::Sqrt(npe);
// 	}


	Float_t emips = 0.;
	
	//	Float_t e_npe  = TMath::Sqrt(npe);
	//	Float_t e_nmip = TMath::Sqrt(nmips);
	Float_t e_tot  = TMath::Sqrt(npe+nmips);
	if ( e_tot > 0. ) {
	  emips = nmips / e_tot;
	}


	hu -> Fill( index, nmips );
	hu -> SetBinError( index - umin + 1, emips );

      }
          
      iter++;

    }

    ///////////////////////////////////////////////////////

    iter = vstrips -> begin();
    while ( iter != vstrips -> end() ) {

      //Float_t energy = (*iter)->getEnergy();
      Int_t   index  = (*iter)->getIndex();
      Float_t npe    = (*iter)->getNumPhotoElectrons();
      Float_t nmips  = (*iter)->getNumMips();
      
      if ( nmips > 0. ) {

	Float_t emips  = 0.;
	if ( npe > 0. ) { 
	  emips = nmips / TMath::Sqrt(npe);
	}

	hv -> Fill( index, nmips );
	hv -> SetBinError( index - vmin + 1, emips );

      }
          
      iter++;

    }

    ///////////////////////////////////////////////////////

    // Store the histograms

    m_UProfile.AddLast(hu);
    m_VProfile.AddLast(hv);

    // Store the index of the histogram, associated with
    // the name (see EEezCluster::Hash()) of the 
    m_Name2IndexU[ cluster -> Hash() ] = m_UProfile.LastIndex();
    m_Name2IndexV[ cluster -> Hash() ] = m_VProfile.LastIndex();
    
  }

  return 1;

}

/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////

 void EEsmdProfile::MakeFits( Option_t *opts ) 
{
  // Loop over all histograms and fit them to a single "eeSinglePeak()"
  // shower shape (double gaussian with common mean, constrained widths).


  // Loop over all profiles (aka clustes)
  for ( Int_t i = 0; i < m_UProfile.GetSize(); i++ ) {


    // Retrieve the histograms
    TH1F *uprofile = getProfileU(i);
    TH1F *vprofile = getProfileV(i);

    assert(uprofile != NULL);
    assert(vprofile != NULL);

    // Find the highest bin in both views
    Int_t umax_bin = uprofile -> GetMaximumBin();
    Int_t vmax_bin = vprofile -> GetMaximumBin();

    
    //-- 04/10/04 The "mean" parameter in fitSinglePeak has been
    //-- disabled.  The peak will now be auto-magically located
    
    //-- fitDoublePeak will need to be updated.


    // Convert this to a strip number...
    Float_t umax = (Float_t)umax_bin + uprofile -> GetBinLowEdge(0);
    Float_t vmax = (Float_t)vmax_bin + vprofile -> GetBinLowEdge(0);
    
    // Fit the two histograms to a single peak

    fitSinglePeak(i,0,umax,0.,-1.,opts);
    fitSinglePeak(i,1,vmax,0.,-1.,opts);

  }

}


#ifndef __ROOT__
 void EEsmdProfile::MakeQA() 
{
  // Fills QA histograms

  for ( Int_t i = 0; i < m_EEezClust -> getNClusters(); i++ ) {    

    // Fill cluster QA histograms
    EEezCluster *cluster = m_EEezClust -> getClusterPtr(i);
    Int_t sec = cluster -> getSeedTower() -> getSector();

    //-- Somehow "this" gets lost between events!?
    m_EEClusterQA[sec] -> setSmdProfiler( this );
    m_EEClusterQA[sec] -> Fill ( cluster );
    //-- All pass for now
    m_EEClusterQA[sec] -> pass( cluster );


  }

}
#endif

/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////

 void EEsmdProfile::Clear( Option_t *opts ) 
{  
  // Clear the list of profiles and delete the histograms

  m_UProfile.Delete();
  m_VProfile.Delete();

  m_UProfileSum9.Delete();
  m_VProfileSum9.Delete();
  
  m_UProfileSum5.Delete();
  m_VProfileSum5.Delete();

  m_UProfileChi2.Delete();
  m_VProfileChi2.Delete();

  m_UProfileInit.Delete();
  m_VProfileInit.Delete();

  m_UResidual.Delete();
  m_VResidual.Delete();

  m_Name2IndexU.clear();
  m_Name2IndexV.clear();

}

/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////

 void EEsmdProfile::fitProfile ( Int_t iprofile, Int_t iuv ) 
{ 
  // Fits the SMD profile ( U = 0, V = 1 ) to the functional form
  // specified in setShowerShape().  If none was specified, the 
  // method defaults to a gaussian shower shape.
  
  
  // Obtain a pointer to the requested profile
  assert( iuv>=0 && iuv <=1 ); // Only two planes
  TH1F *profile = ( iuv == 0 ) ? getProfileU(iprofile) : getProfileV(iprofile);

  // First obtain some info from the histogram to
  // come up with initial parameters
  Float_t mean = profile -> GetMean();
  Float_t rms  = profile -> GetRMS();
  Float_t sum  = profile -> Integral();

  // Next, get the bin number of the highest-responding
  // strip and the its corresponding position

  //  Int_t maxbin = profile -> GetMaximumBin();
  //Float_t xmax = profile -> GetBinLowEdge(0) + maxbin + 0.5;

  // Initial guess for gaussian parameters
  Float_t a = sum / TMath::Sqrt( TMath::TwoPi() ) / rms;
  TF1 *fit = m_ShowerShape;

  fit -> SetParameter(0,a);
  fit -> SetParameter(1,mean);
  fit -> SetParameter(2,rms);

  fit -> SetRange(mean-5.0,mean+5.0);

  // Perform the fit
  profile -> Fit(fit,"RNQ");

  // Next, increase the range to 3 sigma and refit
  Float_t min = fit -> GetParameter(1) - 3.0 * fit -> GetParameter(2);
  Float_t max = fit -> GetParameter(1) + 3.0 * fit -> GetParameter(2);

  profile -> GetXaxis() -> SetRangeUser(min,max);
  profile -> Fit(fit,"RQ");
  profile -> GetXaxis() -> SetRange(0,0);


  
}

/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////


 void EEsmdProfile::fitDoublePeak ( Int_t iprofile,
				   Int_t iuv,
				   Float_t mean1,
				   Float_t mean2,
				   Float_t min,
				   Float_t max,
				   Option_t *opts
				   )
{
  // Fit the specified cluster's profile (either U or V plane) to
  // a double shower-shape peak, over the specfied range in strip
  // number, centered on the specified mean values.
  //
  // ... essentially, the first steps towards the "final" pi0 finder.  
 


  // Obtain pointer to the appropriate histogram
  assert ( iuv == 0 || iuv == 1 );
  TH1F *profile = ( iuv == 0 ) ? getProfileU(iprofile) : getProfileV(iprofile);

  // Set the range to that specified by the user
  if ( min < max )
    profile -> GetXaxis() -> SetRangeUser(min,max);


  // Perform a single-peak fit to the first point 
  fitSinglePeak(iprofile,iuv,mean1,min,max,opts);


  // Copy its parameters over to the double-peak fit,
  // also copy the limits
  for ( Int_t i = 0; i < 5; i++ ) {
    m_DoublePeak -> SetParameter(i, m_SinglePeak -> GetParameter(i) );
    Double_t pmin, pmax;
    m_SinglePeak -> GetParLimits(i, pmin, pmax );
    m_DoublePeak -> SetParLimits(i, pmin, pmax );
  }


  // Perform a single-peak fit to the second point
  fitSinglePeak(iprofile,iuv,mean2,min,max,opts);


  // And copy the new parameters and limits
  for ( Int_t i = 0; i < 5; i++ ) {
    m_DoublePeak -> SetParameter(i+5, m_SinglePeak -> GetParameter(i) );
    Double_t pmin, pmax;
    m_SinglePeak -> GetParLimits(i, pmin, pmax );
    m_DoublePeak -> SetParLimits(i+5, pmin, pmax );
  }

#if 0
  std::cout << "Double peak parameters" << std::endl;
  m_DoublePeak -> Print();
#endif

  // Now fit the profile to the double-peak shape
  profile -> Fit ( m_DoublePeak, opts );



}


 void EEsmdProfile::fitSinglePeak ( Int_t iprofile, 
				   Int_t iuv, 
				   Float_t mean,
				   Float_t min, 
				   Float_t max,
				   Option_t *opts ) 
{
  // Fit the specified cluster's SMD profile (either U or V plane) to
  // a single shower-shape peak, over the specified range in strip 
  // number, centered on the specified mean value.  If the histogram
  // is empty, no fit will be performed.  The fit is stored within
  // this histogram's list of fits (see TH1F::GetListOfFunctions()).

  // Obtain pointer to the appropriate histogram
  assert ( iuv == 0 || iuv == 1 );
  TH1F *profile = ( iuv == 0 ) ? getProfileU(iprofile) : getProfileV(iprofile);


#if 0
  std::cout << "fitSinglePeak(" 
	    << iprofile << "," 
	    << iuv << ","
	    << mean << ","
	    << min << ","
	    << max << ","
	    << opts << ");"
	    << std::endl << std::flush;
#endif

  assert(profile);



  // If the histogram is empty, we have nothing to do here...
  if ( profile -> GetEntries() == 0 ) return;

  // Set the range to that specified by the user
  if ( min < max )
    profile -> GetXaxis() -> SetRangeUser(min,max);


  // Initialize fit parameters, step sizes, and allowed ranges
  EEezCluster *cluster = m_EEezClust -> getClusterPtr(iprofile);
  estimateSinglePeak( cluster, iuv );

#if 0
  std::cout << "Initial parameterization" << std::endl << std::flush;
  m_SinglePeak -> Print();
#endif

  //-- Perform the fit based on initial parameters, and refit
  //-- over a reduced range, to limit impact on chi2 from large-
  //-- angle bremstrahlung and MCS.
  profile -> Fit( m_SinglePeak, opts );
  Float_t oldMean = m_SinglePeak -> GetParameter(1);
  m_SinglePeak -> SetRange( oldMean - 4.5, oldMean + 4.5 );    
  //-- Refit over new range
  profile -> Fit( m_SinglePeak, opts );
  Float_t myMean  = m_SinglePeak -> GetParameter(1);
  m_SinglePeak -> SetRange( myMean - 4.5, myMean + 4.5 );



  //-- Now refit until the means converge to 1/4 strip or less,
  //-- while freeing up our restriction on the width.

  m_SinglePeak -> SetParLimits(2, 0.1, 5.0);
  Int_t   count = 0;  
  while ( TMath::Abs( myMean - oldMean ) > 0.25 && count++ < 10 ) {   
    oldMean = m_SinglePeak -> GetParameter(1);
    profile -> Fit( m_SinglePeak, opts );
    myMean = m_SinglePeak -> GetParameter(1);
    m_SinglePeak -> SetRange( myMean - 4.5, myMean + 4.5 );
  }
  m_Converge -> Fill( count+0.5 );


  //-- Create a new histogram which will hold the chi2 for each 
  //-- strip. 
  TString hname = profile -> GetName();
  hname += "_Chi2_vs_strip";
  Int_t   nbin = profile -> GetNbinsX();
  Float_t myMin  = profile -> GetBinLowEdge(1);
  Float_t myMax  = profile -> GetBinLowEdge(nbin)+1.0;
  TH1F *histo = new TH1F(hname,"#chi^{2}_{i} = (Y_{i} - f(x_{i})^2 / #sigma_{i}^{2} vs. i",nbin,myMin,myMax);
  
  //-- Histogram bin containing the mean of the fit
  Int_t imean = profile -> FindBin( myMean );

  //-- Loop over the four bins to the left and right of the mean.
  //-- Abort the procedure if the fit doesn't have any degrees
  //-- of freedom, though.
  if ( m_SinglePeak -> GetNDF() > 0 )
    for ( Int_t i = imean - 4; i <= imean + 4; i++ ) {
      
      //-- Get the center of the bin
      Float_t x = profile -> GetBinCenter(i);
      
      //-- Evaluate the function at this point
      Float_t f = m_SinglePeak -> Eval(x);

      //-- Get the strip response and standard deviation for this strip
      Float_t y = profile -> GetBinContent(i);
      Float_t s = profile -> GetBinError(i);
      
      if ( s>0. ) {
	histo -> Fill ( x, (y-f)*(y-f)/s/s );
      }

    }

  //-- Now add the new histogram to the list of histograms
  if ( iuv == 0 ) 
    m_UProfileChi2.Add( histo );
  else
    m_VProfileChi2.Add( histo );

}

/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////

 TH1F *EEsmdProfile::getResidualU( Int_t i ) 
{
  // If it doesn't exist, it calculates the residual histogram for
  // the specified U profile, stores it in m_UResidual, and returns
  // a pointer to it.  Otherwise, returns a pointer to the histogram.
  // NOTE: After looking at root's TList::AddAt() function, I do not 
  // believe the documentation!  It looks like if you attempt to add
  // an object at a position beyond the end of the list, it blindly
  // assumes that you want to add the object at the end of the list...
  // This means that, for instance, if you were to call getResidualU(5)
  // BEFORE calling getResidual(1), the residual corresponding to the
  // 5th cluster will be inserted into the list at position 2... and
  // subsequent calls to getResidualU(2) will return the 5th cluster's
  // residual!  This is why I really hate CERN code.
  
  TH1F *resid = (TH1F *)m_UResidual.At(i);
  if ( !resid ) {
    TString name = getProfileU(i) -> GetName();
    name.ReplaceAll("hu","ru");
    resid = (TH1F*)getProfileU(i) -> Clone(name);
    TF1 *fit = (TF1*)getProfileU(i)->GetListOfFunctions()->At(0);
    if ( !fit ) return NULL;
    resid -> Add(fit,-1.0);
    m_UResidual.AddAt(resid,i);
  }
  assert(resid); // Something is really messed up here
  return resid;

}

 TH1F *EEsmdProfile::getResidualV( Int_t i )
{
  // If it doesn't exist, it calculates the residual histogram for
  // the specified V profile, stores it in m_UResidual, and returns
  // a pointer to it.  Otherwise, returns a pointer to the histogram.
  // See warnings in getResidualU().

  TH1F *resid = (TH1F *)m_VResidual.At(i);
  if ( !resid ) {
    TString name = getProfileV(i) -> GetName();
    name.ReplaceAll("hv","rv");
    resid = (TH1F*)getProfileV(i) -> Clone(name);
    TF1 *fit = (TF1*)getProfileV(i)->GetListOfFunctions()->At(0);
    if ( !fit ) return NULL;
    resid -> Add(fit,-1.0);
    m_VResidual.AddAt(resid,i);
  }
  assert(resid); // Something is really messed up here
  return resid;

}

/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////

 TF1 *EEsmdProfile::getSinglePeak()
{
  // Returns a pointer to the single-peak function used in the call
  // to fitSinglePeak().
  return m_SinglePeak;
}

 TF1 *EEsmdProfile::getDoublePeak()
{
  // Returns a pointer to the double-peak function used in the call
  // to fitDoublePeak().
  return m_DoublePeak;
}

/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////

 TH1F *EEsmdProfile::getSumOverStrips ( EEezCluster *cluster, Int_t nstrip, Int_t iuv ) 
{  
  //
  // Creates a new histogram whose entries correspond to the integral
  // over nstrip strips, versus the index of the strip in the center.
  // (NOTE-- please make sure that nstrips is odd.  It won't crash, but
  // it will be harder to interpret, and its not trapped.)  
  //
  // This histogram MUST be deleted by the user!  To retrieve this 
  // histogram once it has been created, getSumStrips ( EEezCluster *cluster ), 
  // or by index or name.
  //

  //-- Name of the cluster
  TString name_cluster = cluster -> Hash();

  TString histo = "h"; histo += (iuv)?"V":"U"; histo += nstrip; histo += "sum";
  histo += name_cluster;
  TString title = "#sum_{x}^{x+9} N_{mip}(x) vs x";

  //-- Get the range of strips for this histogram
  EEezTower *seed = cluster -> getSeedTower();
  EEezStripPtrVec_t *strips = (iuv)?seed->getVStrips():seed->getUStrips();

  EEezStripPtrVecIter_t begin = strips->begin();
  EEezStripPtrVecIter_t end   = strips->end() - 1;
  Int_t myMin = (*begin) -> getIndex() - 2;
  Int_t myMax = (*end)   -> getIndex() + 2;

  // Create the new histogram
  TH1F *sum9 = new TH1F(histo,title,(myMax-myMin),myMin,myMax);
  
  // And fill it
  while ( begin < strips -> end() ) {
    Float_t sum   = 0;
    Float_t index = (*begin) -> getIndex() + nstrip/2;
    EEezStripPtrVecIter_t iter = begin;
    while ( iter < begin+nstrip && iter < strips->end() ) {
      sum += (*iter) -> getNumMips();
      iter++;
    }
    sum9 -> Fill (index, sum );
    begin++;
  }

  //$$$ Info("getSumOverStrips","returning profile sum %s", sum9 -> GetName() );

  return sum9;

}


/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////

 void EEsmdProfile::estimateSinglePeak ( EEezCluster *cluster, Int_t iuv )
{
  // For the specified cluster and plane, initialize starting parameters
  // for the single-peak fit

  //-- Save the first 50 events as examples...
  static Int_t nsave = 0;



  //-- Open an integration window, 5 and 9 strips wide.  Slide this
  //-- window from first strip to last strip, and fill a histogram
  //-- with the integrated number of mips inserted at the starting
  //-- point of the integration + 1/2 the window.  This distribution
  //-- should reach maximum at the position of the maximum bin.
  TH1F *sum5 = getSumOverStrips( cluster, 5, iuv );
  TH1F *sum9 = getSumOverStrips( cluster, 9, iuv );
  if ( iuv == 0 ) {
    m_UProfileSum9.Add(sum9);
    m_UProfileSum5.Add(sum5);
  }
  else {
    m_VProfileSum9.Add(sum9);
    m_VProfileSum5.Add(sum5);
  }

  Int_t max5 = sum5 -> GetMaximumBin();
  //$$$  Int_t max9 = sum9 -> GetMaximumBin();

  Float_t mean5 = sum5 -> GetBinLowEdge( max5 ) + 0.5;
  //$$$ Float_t mean9 = sum9 -> GetBinLowEdge( max9 ) + 0.5;

  //  Float_t sumAtMax5 = sum5 -> GetBinContent( max5 );
  //  Float_t sumAtMax9 = sum9 -> GetBinContent( max9 );
  
  //-- We estimate the mean as the average of the two preceding values.
  //-- This will reduce the effects of outlying strips.  In the future,
  //-- we may consider investigating a weighted average of some sort.
  //$$$  Float_t start_mean = 0.5 * ( mean5 + mean9 );
  Float_t start_mean = mean5;  
  Float_t min_mean = start_mean - 4.5;
  Float_t max_mean = start_mean + 4.5;
  Int_t   bin_mean = sum5 -> FindBin( start_mean );



  //-- We estimate the width of the distribution using the integration-
  //-- window histograms above.  When the integral is reduced by
  //-- ~32% from the maximum, we know that we are off by 1 sigma.
  //-- We will apply a sanity check to the result... if its less than
  //-- 0.5 strips or greater than 3.0 strips, we start our estimate 
  //-- at 1.0 strips wide.

  //---> Note: for now, just start with a constant
  Float_t start_sigma = 0.84;
  Float_t min_sigma   = 0.65 * start_sigma;
  Float_t max_sigma   = 2.00 * start_sigma;

  //-- Next, we estimate the integrated yield...  We use the integral
  //-- over 9 strips, evaluated at our starting mean.
  Float_t start_yield = sum9 -> GetBinContent( bin_mean );
  Float_t min_yield   = 0.1 * start_yield;
  Float_t max_yield   = 2.5 * start_yield;


  //-- m_SinglePeak is a 5 parameter fit: 2 gaussians w/ common
  //-- means + a constrained width.  Initially, we fix the relative
  //-- fraction of the two gaussians and the relative widths.
  m_SinglePeak -> SetParameter( 0, start_yield );
  m_SinglePeak -> SetParameter( 1, start_mean );
  m_SinglePeak -> SetParameter( 2, start_sigma );
  m_SinglePeak -> FixParameter( 3, 0.2 );
  //$$$m_SinglePeak -> FixParameter( 4, 3.5 );
  m_SinglePeak -> SetParameter( 3, 0.2 );
  m_SinglePeak -> SetParameter( 4, 3.5 );
 
  m_SinglePeak -> SetParLimits( 0, min_yield, max_yield );
  m_SinglePeak -> SetParLimits( 1, min_mean,  max_mean );
  m_SinglePeak -> SetParLimits( 2, min_sigma, max_sigma );

  //  m_SinglePeak -> SetParLimits( 3, 0.05, 0.45 );
  //  m_SinglePeak -> SetParLimits( 4, 1.1,  4.0 );



  //-- Clone and save initial parameterization for fits


  TH1F *profile = (iuv)?getProfileV(cluster):getProfileU(cluster);

  TString name = profile -> GetName();

  name += "_init_"; name += nsave;

  TH1F *cloned = (TH1F *)profile -> Clone(name);
  assert(cloned);
  cloned -> GetListOfFunctions() -> Add( m_SinglePeak -> Clone("init") ); 

  if ( iuv == 0 ) 
    m_UProfileInit.Add(cloned);
  else
    m_VProfileInit.Add(cloned);


}



#if 0
  //-- We save the first 50 events as examples
  if ( nsave < 50 ) {

    cd();

    //-- Get the specified profile histogram
    //$$$H1F *profile = (iuv)?getProfileV(cluster):getProfileU(cluster);
    //  TString name = profile -> GetName();
    //  name += "_par_init_"; name += nsave;
    //  TH1F *cloned = (TH1F *)profile -> Clone(name);
    //  cloned -> GetListOfFunctions() -> Add( m_SinglePeak -> Clone("init") );

    //-- Save the sum5 and sum9 histograms
    name = profile -> GetName();
    name += "_sum5_"; name += nsave;
    TH1F *clone5 = (TH1F *)sum5 -> Clone(name);

    name = profile -> GetName();
    name += "_sum9_"; name += nsave;
    TH1F *clone9 = (TH1F *)sum9 -> Clone(name);

    nsave++;

    cd("..");


  } 
#endif


#if 0


  m_DiffPar[0] = new TH1F("diffPar0","Difference between inital yield estimate and fit",40,-20.,20.);
  m_DiffPar[1] = new TH1F("diffPar1","Difference between inital mean estimate and fit",20,-5.,5.);
  m_DiffPar[2] = new TH1F("diffPar2","Difference between inital width estimate and fit",100,-2.,2.);
  m_DiffPar[3] = new TH1F("diffPar3","Difference between inital frac. yield estimate and fit",20,-1.,1.);
  m_DiffPar[4] = new TH1F("diffPar4","Difference between inital rel. width estimate and fit",20,-5.,5.);

  m_Par[0] = new TH1F("Par0","fit yields",40,0.,400.); 
  m_Par[1] = new TH1F("Par1","fit means",288,0.,288.);
  m_Par[2] = new TH1F("Par2","fit widths",20,0.,5.);
  m_Par[3] = new TH1F("Par3","fit frac. yields",20,0.,1.);
  m_Par[4] = new TH1F("Par4","fit rel. widths",20,0.,5.);

  m_DiffParVsChi2[0] = new TProfile("diffPar0VsChi2","Difference between inital yield estimate and fit vs chi2/ndf",40,0.,10.,-1000.,1000.);
  m_DiffParVsChi2[1] = new TProfile("diffPar1VsChi2","Difference between inital mean estimate and fit vs chi2/ndf",40,0.,10.,-1000.,1000.);
  m_DiffParVsChi2[2] = new TProfile("diffPar2VsChi2","Difference between inital width estimate and fit vs chi2/ndf",40,0.,10.,-1000.,1000.);
  m_DiffParVsChi2[3] = new TProfile("diffPar3VsChi2","Difference between inital frac. yield estimate and fit vs chi2/ndf",40,0.,10.,-1000.,1000.);
  m_DiffParVsChi2[4] = new TProfile("diffPar4VsChi2","Difference between inital rel. width estimate and fit vs chi2/ndf",40,0.,10.,-1000.,1000.);

  m_Chi2VsRMS = new TH2F("chi2VsRMS","#chi^2/ndf vs RMS of the histogram",50,0.,10.,50,0.,20.);

  m_NDF = new TH1F("ndf","Degrees of freedom in single shower shape fit",10,0.,10.);
  

#endif

#if 0

  m_DiffPar[0] -> Fill( nmip - m_SinglePeak -> GetParameter(0) );
  m_DiffPar[1] -> Fill( mean - m_SinglePeak -> GetParameter(1) );
  m_DiffPar[2] -> Fill( width - m_SinglePeak -> GetParameter(2) );
  m_DiffPar[3] -> Fill( frac - m_SinglePeak -> GetParameter(3) );
  //$$$  m_DiffPar[4] -> Fill( nmip - m_SinglePeak -> GetParameter(4) );

  Float_t chi2 = m_SinglePeak -> GetChisquare();
  m_Chi2VsRMS -> Fill( rms, chi2 );

  m_DiffParVsChi2[0] -> Fill( chi2, nmip - m_SinglePeak -> GetParameter(0) );
  m_DiffParVsChi2[1] -> Fill( chi2, mean - m_SinglePeak -> GetParameter(1) );
  m_DiffParVsChi2[2] -> Fill( chi2, width - m_SinglePeak -> GetParameter(2) );
  m_DiffParVsChi2[3] -> Fill( chi2, frac - m_SinglePeak -> GetParameter(3) );
  //$$  m_DiffParVsChi2[4] -> Fill( chi2, nmip - m_SinglePeak -> GetParameter(4) );
  
  for ( Int_t i = 0; i < 5; i++ ) m_Par[i] -> Fill( m_SinglePeak -> GetParameter(i) );

  m_NDF -> Fill ( m_SinglePeak -> GetNDF() );

  // Calculate the residual and save in the appropriate list
  TH1F *resid = (TH1F*)profile -> Clone();
  TString name = profile -> GetName();
  if ( iuv == 0 ) 
    name.ReplaceAll("hu","ru");
  else
    name.ReplaceAll("hv","rv");
  resid -> SetName(name);
  resid -> Add(m_SinglePeak,-1.0);

  if ( iuv == 0 ) 
    m_UResidual.Add( resid );
  else 
    m_VResidual.Add( resid );
  
#endif


ROOT page - Class index - Top of the page

This page has been automatically generated. If you have any comments or suggestions about the page layout send a mail to ROOT support, or contact the developers with any questions or problems regarding ROOT.