// =====================================================================
//  $Id: st02OFFctiag.cc,v 1.2 2003/10/06 16:28:19 goiwai Exp $
//  $Name: CLDAQ-1-14-03 $
//  $Log: st02OFFctiag.cc,v $
//  Revision 1.2  2003/10/06 16:28:19  goiwai
//  *** empty log message ***
//
//  Revision 1.1  2003/09/09 22:19:49  goiwai
//  これまで,OFFxxx.ccというファイル名だったオフライン解析用のプログラムを
//  st02OFFxxx.ccに変更しました.
//  ファイル名競合の防止が目的です.
//
//  Revision 1.1  2003/08/14 20:37:46  goiwai
//  シングルピクセルイベントのプロットを非対称のガウシアンでフィッティング
//  してCTIを求めます.
//
//
// =====================================================================
#include "TEnvironmentVariableTable.hh"
#include "Trootinit.h"
#include "St02SinglePixelInterface.hh"

Tdouble asymmetryg( Tdouble* x, Tdouble* par );
// Tbool goodfit( Tdouble par[], Tdouble pare[] );
// //変数で設定させたほうがいいかな?
// static const Tdouble lowfitxmin = 0.0;
// static const Tdouble lowfitxmax = 120.0;
// static const Tdouble highfitxmin = 300.0;
// static const Tdouble highfitxmax = 500.0;

int main( int argc, char** argv, char** envv )
{
  if ( argc != 2 ) {
    Tcerr << "usage: " << argv[ 0 ] << " <dataset>" << Tendl;
    return -1;
  }

  TApplication* theApplication = rootinit();

  TCanvas CVcti( "CVcti", "CTI", 960, 720 );
  CVcti.ToggleEventStatus();
  CVcti.Divide( 2, 2 );
  TH1D H1Dspx( "H1Dspx", "Single Pixel Events", 100, 0.0, 500.0 );
  TGaxis::SetMaxDigits( 2 );
  H1Dspx.GetXaxis()->SetTitle("Pulseheight (ADU)");
  H1Dspx.GetXaxis()->CenterTitle();
  H1Dspx.GetXaxis()->SetNoExponent();
  H1Dspx.GetYaxis()->SetTitle("Counts");
  H1Dspx.GetYaxis()->CenterTitle();




  Tstring dataset = argv[ 1 ];
  St02SinglePixelInterface spif( dataset );
  St02SinglePixelList splist = spif.GetSinglePixelList();

  TEnvironmentVariableTable envtable( "st02setup" );
  //Tdouble left = envtable.GetDoubleValue( "ST02_MANUALCUT_LEFT" );
  //Tdouble right = envtable.GetDoubleValue( "ST02_MANUALCUT_RIGHT" );
  // 分割方式のパラメーター
  const Tint hdivide = envtable.GetIntegerValue( "ST02_CTI_HDIVIDE" );
  const Tint vdivide = envtable.GetIntegerValue( "ST02_CTI_VDIVIDE" );

  // HCTI,VCTIのプロット何点あるか
  Tint nptHCTI = 0;
  Tint nptVCTI = 0;

  Tint nh = envtable.GetIntegerValue( "ST02_HPIXEL" );
  Tint nv = envtable.GetIntegerValue( "ST02_VPIXEL" );
  Tint hpitch = nh / vdivide;
  Tint vpitch = nv / hdivide;


  for ( Tsize_t i = 0; i < splist.size(); i ++ ) {
    H1Dspx.Fill( splist[ i ].GetSignal() );
  }


  CVcti.cd( 1 );
  //先に分割フィットして粗くパラメーターを求める
  H1Dspx.Fit("gaus","q0");
  TF1* f = H1Dspx.GetFunction("gaus");
  //全体のフィット
  TF1* total = new TF1("total",asymmetryg,0.0,500.0,4);
  total->SetParameters(f->GetParameter(0),f->GetParameter(1),f->GetParameter(2),f->GetParameter(2));
  total->SetParNames( "Constant", "Mean", "Sigma:Left", "Sigma:Right" );
  total->SetLineWidth( 1 );
  H1Dspx.Fit(total,"qr");

  CVcti.Update();
  ((TPaveStats*)(H1Dspx.FindObject( "stats" )))->SetY1NDC(0.2);





  //==================================================================
  //                                          ___________
  // 縦方向にフレームを分割しHCTIを求める    |  |  |  |  |
  //                                         |  |  |  |  |
  //                                         |  |  |  |  |
  //                                         |  |  |  |  |
  //                                         |__|__|__|__|
  //
  //==================================================================
  //領域分のヒストを作って表示する
  TH1D** H1Dvdivide = new TH1D*[ vdivide ];
  for ( Tint i = 0; i < vdivide; i ++ ) {
    Tstring title = "Vertical Partition(for HCTI): " + itostr( i, 0 );
    Tstring name = "H1Dvdivide" + itostr( i, 3 );

    H1Dvdivide[ i ] = new TH1D( name.c_str(), title.c_str(), 100, 0.0, 500.0 );

    H1Dvdivide[ i ] -> GetXaxis()->SetTitle("Pulseheight (ADU)");
    H1Dvdivide[ i ] -> GetXaxis()->CenterTitle();
    H1Dvdivide[ i ] -> GetXaxis()->SetNoExponent();
    H1Dvdivide[ i ] -> GetYaxis()->SetTitle("Counts");
    H1Dvdivide[ i ] -> GetYaxis()->CenterTitle();
  }
  for ( Tsize_t i = 0; i < splist.size(); i ++ ) {
    Tint h = splist[ i ].GetHorizontalID() ;
    Tdouble s = splist[ i ].GetSignal();
    H1Dvdivide[ h/hpitch ] -> Fill( s );
  }

  TCanvas CVvdivide( "CVvdivide", "Divide Vertical Direction for HCTI", 960, 720 );
  CVvdivide.ToggleEventStatus();
  CVvdivide.Divide( 4, 4 );

  Tdouble* nHt = new Tdouble[ vdivide ];       // 水平転送の回数
  Tdouble* nHt_e = new Tdouble[ vdivide ];     // 水平転送のエラー初期値
  Tdouble* adcV = new Tdouble[ vdivide ];      // 縦に切った範囲でのADC中心値
  Tdouble* adcV_e = new Tdouble[ vdivide ];    // ADCのエラー初期値
  for ( Tint i = 0; i < vdivide; i ++ ) {
    CVvdivide.cd( i + 1 );

    //先に分割フィットして粗くパラメーターを求める
    H1Dvdivide[ i ]->Fit("gaus","q0");
    TF1* f = H1Dvdivide[ i ]->GetFunction("gaus");
    //全体のフィット
    TF1* total = new TF1("total",asymmetryg,0.0,500.0,4);
    total->SetParameters(f->GetParameter(0),f->GetParameter(1),f->GetParameter(2),f->GetParameter(2));
    total->SetParNames( "Constant", "Mean", "Sigma:Left", "Sigma:Right" );
    total->SetLineWidth( 1 );
    H1Dvdivide[ i ]->Fit(total,"qr");


    nHt[ nptHCTI ] = ((hpitch-1)/2.0) + hpitch*i;
    //nHt_e[ nptHCTI ] = (hpitch-1)/2.0;
    nHt_e[ nptHCTI ] = 0.0;
    adcV[ nptHCTI ] = total -> GetParameter( 1 );      // Mean
    adcV_e[ nptHCTI ] = total -> GetParError( 1 );     // Mean Error
    nptHCTI ++;


    CVvdivide.Modified();
    CVvdivide.Update();
  }




  //各領域の転送回数とその領域で観測されたADCカウントをプロットする
  CVcti.cd(2);
  gPad -> DrawFrame( 0.0, 0.0, 256.0, 500.0 );
  TH1F* hframe = (TH1F*)( gPad -> FindObject( "hframe" ) );
  hframe->GetXaxis() -> SetTitle( "Average Horizontal Transfer" );
  hframe->GetXaxis() -> CenterTitle();
  hframe->GetXaxis() -> SetNoExponent();
  //hframe.GetXaxis() -> SetTitleOffset( 1.2 );
  hframe->GetYaxis() -> SetTitle( "Pulseheight (ADU)" );
  hframe->GetYaxis() -> CenterTitle();
  hframe->GetYaxis() -> SetNoExponent();
  hframe->SetTitle( "Horizontal Charge Transfer Inefficiency" );

  TGraphErrors GEHCTI( nptHCTI, nHt, adcV, nHt_e, adcV_e );
  GEHCTI.SetName( "GEHCTI" );
  GEHCTI.Draw( "p" );
  TF1 myfitHCTI( "myfitHCTI", "[0] * pow( ( 1.0 - [ 1 ] ), x )", 0.0, 512.0 );
  myfitHCTI.SetParameters( 350.0, 0.0 );
  myfitHCTI.SetParNames( "Q0", "HCTI" );
  GEHCTI.Fit( "myfitHCTI", "qm" );

  Tdouble Q0H = myfitHCTI.GetParameter( 0 );
  Tdouble Q0H_e = myfitHCTI.GetParError( 0 );
  Tdouble HCTI = myfitHCTI.GetParameter( 1 );
  Tdouble HCTI_e = myfitHCTI.GetParError( 1 );
  Tstring myfitHCTItitle = myfitHCTI.GetTitle();








  //==================================================================
  //                                         ________
  // 横方向にフレームを分割しVCTIを求める   |________|
  //                                        |________|
  //                                        |________|
  //                                        |________|
  //
  //==================================================================
  //領域分のヒストを作って表示する
  TH1D** H1Dhdivide = new TH1D*[ hdivide ];
  for ( Tint i = 0; i < hdivide; i ++ ) {
    Tstring name = "H1Dhdivide" + itostr( i, 3 );
    Tstring title = "Horizontal Partition(for VCTI): " + itostr( i, 0 );

    H1Dhdivide[ i ] = new TH1D( name.c_str(), title.c_str(), 100, 0.0, 500.0 );

    H1Dhdivide[ i ] -> GetXaxis()->SetTitle("Pulseheight (ADU)");
    H1Dhdivide[ i ] -> GetXaxis()->CenterTitle();
    H1Dhdivide[ i ] -> GetXaxis()->SetNoExponent();
    H1Dhdivide[ i ] -> GetYaxis()->SetTitle("Counts");
    H1Dhdivide[ i ] -> GetYaxis()->CenterTitle();
  }
  for ( Tsize_t i = 0; i < splist.size(); i ++ ) {
    Tint v = splist[ i ].GetVerticalID();
    Tdouble s = splist[ i ].GetSignal();
    H1Dhdivide[ v/vpitch ] -> Fill( s );
  }

  TCanvas CVhdivide( "CVhdivide", "Divide Horizontal Direction for VCTI", 960, 720 );
  CVhdivide.ToggleEventStatus();
  CVhdivide.Divide( 4, 4 );

  Tdouble* nVt = new Tdouble[ hdivide ];       // 鉛直転送の回数
  Tdouble* nVt_e = new Tdouble[ hdivide ];     // 鉛直転送のエラー初期値
  Tdouble* adcH = new Tdouble[ hdivide ];      // 横に切った範囲でのADC中心値
  Tdouble* adcH_e = new Tdouble[ hdivide ];    // ADCのエラー初期値
  for ( Tint i = 0; i < hdivide; i ++ ) {
    CVhdivide.cd( i + 1 );


    //先に分割フィットして粗くパラメーターを求める
    H1Dhdivide[ i ]->Fit("gaus","q0");
    TF1* f = H1Dhdivide[ i ]->GetFunction("gaus");
    //全体のフィット
    TF1* total = new TF1("total",asymmetryg,0.0,500.0,4);
    total->SetParameters(f->GetParameter(0),f->GetParameter(1),f->GetParameter(2),f->GetParameter(2));
    total->SetParNames( "Constant", "Mean", "Sigma:Left", "Sigma:Right" );
    total->SetLineWidth( 1 );
    H1Dhdivide[ i ]->Fit(total,"qr");

    nVt[ nptVCTI ] = ((vpitch-1)/2.0) + vpitch*i;
    //nVt_e[ nptVCTI ] = (vpitch-1)/2.0;
    nVt_e[ nptVCTI ] = 0.0;
    adcH[ nptVCTI ] = total -> GetParameter( 1 );    // Mean
    adcH_e[ nptVCTI ] = total -> GetParError( 1 );   // Mean Error
    nptVCTI ++;


    CVhdivide.Modified();
    CVhdivide.Update();
  }


  //各領域の転送回数とその領域で観測されたADCカウントをプロットする
  CVcti.cd(4);
  gPad -> DrawFrame( 0.0, 0.0, 256.0, 500.0 );
  hframe = (TH1F*)( gPad -> FindObject( "hframe" ) );
  hframe->GetXaxis() -> SetTitle( "Average Vertical Transfer" );
  hframe->GetXaxis() -> CenterTitle();
  hframe->GetXaxis() -> SetNoExponent();
  //hframe.GetXaxis() -> SetTitleOffset( 1.2 );
  hframe->GetYaxis() -> SetTitle( "Pulseheight (ADU)" );
  hframe->GetYaxis() -> CenterTitle();
  hframe->GetYaxis() -> SetNoExponent();
  hframe->SetTitle( "Vertical Charge Transfer Inefficiency" );


  TGraphErrors GEVCTI( nptVCTI, nVt, adcH, nVt_e, adcH_e );
  GEVCTI.SetName( "GEVCTI" );
  GEVCTI.Draw( "p" );
  TF1 myfitVCTI( "myfitVCTI", "[0] * pow( ( 1.0 - [ 1 ] ), x )", 0.0, 512.0 );
  myfitVCTI.SetParameters( 350.0, 0.0 );
  myfitVCTI.SetParNames( "Q0", "VCTI" );
  GEVCTI.Fit( "myfitVCTI", "qm" );

  Tdouble Q0V = myfitVCTI.GetParameter( 0 );
  Tdouble Q0V_e = myfitVCTI.GetParError( 0 );
  Tdouble VCTI = myfitVCTI.GetParameter( 1 );
  Tdouble VCTI_e = myfitVCTI.GetParError( 1 );
  Tstring myfitVCTItitle = myfitVCTI.GetTitle();





  //==================================================================
  //
  // SUMMARYを埋め込む
  //
  //==================================================================
  TPaveText PTsum( 0.0, 0.0, 1.0, 1.0 );
  PTsum.SetName("PTsum");
  PTsum.SetFillColor( 10 );
  PTsum.SetFillStyle( 0 );
  PTsum.SetBorderSize( 0 );
  PTsum.SetTextAlign( 12 );
  //PTainfo.SetTextSize( 0.06 );
  TstringList summary;
  summary.push_back( "FILE: " + dataset );
  summary.push_back( "ST02_CTI_HDIVIDE: " + itostr( hdivide,0 ) );
  summary.push_back( "ST02_CTI_VDIVIDE: " + itostr( vdivide,0 ) );

  summary.push_back( "Divide Vertical " + itostr( vdivide, 0 ) + " Region" );
  summary.push_back( "  #Rightarrow Function: " + myfitHCTItitle );
  summary.push_back( "  #Rightarrow Q: " + dtostr( Q0H ) + " #pm " + dtostr( Q0H_e ) );
  summary.push_back( "  #Rightarrow HCTI: " + dtostr( HCTI ) + " #pm " + dtostr( HCTI_e ) );
  summary.push_back( "Divide Horizontal " + itostr( hdivide, 0 ) + " Region" );
  summary.push_back( "  #Rightarrow Function: " +  myfitVCTItitle );
  summary.push_back( "  #Rightarrow Q: " + dtostr( Q0V ) + " #pm " + dtostr( Q0V_e ) );
   summary.push_back( "  #Rightarrow VCTI: " + dtostr( VCTI ) + " #pm " + dtostr( VCTI_e ) );

  for ( Tsize_t i = 0; i < summary.size(); i ++ ) {
    PTsum.AddText( summary[ i ].c_str() );
  }
  PTsum.AddText( "" );
  CVcti.cd( 3 );
  PTsum.Draw();

  CVcti.cd();
  CVcti.Modified();
  CVcti.Update();




  //印刷したけりゃ
  CVcti.Print( "CTIspselect.ps" );
  CVcti.Print( "CTIspselect.gif" );
  CVcti.Print( "CTIspselect.C" );

  CVvdivide.Print( "CTIvdivide.ps" );
  CVvdivide.Print( "CTIvdivide.gif" );
  CVvdivide.Print( "CTIvdivide.C" );

  CVhdivide.Print( "CTIhdivide.ps" );
  CVhdivide.Print( "CTIhdivide.gif" );
  CVhdivide.Print( "CTIhdivide.C" );


  TFile file( "CTIobjects.root", "RECREATE", "OFFLINE CTI" );
  H1Dspx.Write();
  GEHCTI.Write();
  GEVCTI.Write();
  for ( Tint i = 0; i < vdivide; i ++ ) {
    H1Dvdivide[ i ]->Write();
  }
  for ( Tint i = 0; i < hdivide; i ++ ) {
    H1Dhdivide[ i ]->Write();
  }
  PTsum.Write();
  CVcti.Write();
  CVvdivide.Write();
  CVhdivide.Write();
  file.Close();

  Tofstream olog("LOGCTI", Tapp );
  olog << "X-ray: " << total->GetParameter(1) << " " << total->GetParError(1) << Tendl;
  olog << "HCTI: " << HCTI << " " << HCTI_e << Tendl;
  olog << "VCTI: " << VCTI << " " << VCTI_e << Tendl;
  olog << "----" << Tendl;
  olog.close();

  theApplication -> Terminate();
  //theApplication -> Run();

  return 0;
}

//左右で異なるσをもつガウス分布
Tdouble asymmetryg( Tdouble* x, Tdouble* par )
{
  Tdouble c = par[0];     // 高さ
  Tdouble m = par[1];     // 中心
  Tdouble sl = par[2];    // σ左
  Tdouble sr = par[3];    // σ右
  Tdouble X = x[0];       // Xの値

  Tdouble arg = 0.0;
  if ( sl != 0.0 && sr != 0.0 ) {  //分母が0になるようではいかんので
    if ( X - m < 0 ) {
      arg = (X-m)/sl;          // 中心より左について
    } else {
      arg = (X-m)/sr;          // 中心より右について
    }
  }

  return c*exp(-0.5*arg*arg);
}
