// =====================================================================
//  $Id: st02OFFctig.cc,v 1.4 2004/03/04 15:11:56 goiwai Exp $
//  $Name: CLDAQ-1-14-03 $
//  $Log: st02OFFctig.cc,v $
//  Revision 1.4  2004/03/04 15:11:56  goiwai
//  ほとんどが関数名変更にともなう更新です。
//
//  Revision 1.3  2003/12/06 11:13:03  goiwai
//  レコードのパラメーターをチェックするようにしました.
//
//  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.4  2003/08/05 20:26:49  goiwai
//  *** empty log message ***
//
//  Revision 1.3  2003/07/30 16:16:33  goiwai
//  ファイルにコミットログをつけることにしました.
//
// =====================================================================
#include "TEnvironmentVariableTable.hh"
#include "Trootinit.h"
#include "TRegularExpression.hh"
#include "TInputObjectFile.hh"
#include "TDataRecord.hh"
#include "TUtilities.hh"
#include "St02SinglePixelInterface.hh"

//フィッティングを 中心から fitregion×σ の範囲で行う
static const Tdouble fitregion = 2.0;

static Tstring sourcepath( const Tstring& f );
static Tstring darkpath( const Tstring& f );
static Tvoid check( const Tstring& f );
static Tstring _temp;
static const Tstring _rcfile = "st02setup";
static const Tstring _pattern( "^drk([0-9]*)src([0-9]*)\\.dat$" );

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 ];
  check( dataset );
  St02SinglePixelInterface spif( dataset );
  St02SinglePixelList splist = spif.GetSinglePixelList();

  TEnvironmentVariableTable envtable( _rcfile );
  //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" );
  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" );
  Tdouble m = f->GetParameter(1);
  Tdouble s = f->GetParameter(2);
  Tdouble xmin = m - fitregion * s;
  Tdouble xmax = m + fitregion * s;
  // 範囲を指定したガウシアンでフィット
  TF1* total = new TF1("total","gaus",xmin,xmax);
  total->SetParameters(f->GetParameters());
  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" );
    Tdouble mbuf = f->GetParameter(1);
    Tdouble sbuf = f->GetParameter(2);
    Tdouble xminbuf = mbuf - fitregion * sbuf;
    Tdouble xmaxbuf = mbuf + fitregion * sbuf;
    // 範囲を指定したガウシアンでフィット
    TF1* gf = new TF1("gf","gaus",xminbuf,xmaxbuf);
    gf->SetParameters(f->GetParameters());
    gf->SetLineWidth(1);
    H1Dvdivide[ i ]->Fit("gf","qr");


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

    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( vdivide, nHt, adcV, nHt_e, adcV_e );
  GEHCTI.SetName( "GEHCTI" );
  GEHCTI.Draw( "p" );
  TF1 myfitHCTI( "myfitHCTI", "[0] * pow( ( 1.0 - [ 1 ] ), x )", 0, 512 );
  myfitHCTI.SetParameters( 350.0, 0.0 );
  myfitHCTI.SetParNames( "Q0", "HCTI" );
  GEHCTI.Fit( "myfitHCTI", "qr" );

  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" );
    Tdouble mbuf = f->GetParameter(1);
    Tdouble sbuf = f->GetParameter(2);
    Tdouble xminbuf = mbuf - fitregion * sbuf;
    Tdouble xmaxbuf = mbuf + fitregion * sbuf;
    // 範囲を指定したガウシアンでフィット
    TF1* gf = new TF1("gf","gaus",xminbuf,xmaxbuf);
    gf->SetParameters(f->GetParameters());
    gf->SetLineWidth(1);
    H1Dhdivide[ i ]->Fit("gf","qr");

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

    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( hdivide, nVt, adcH, nVt_e, adcH_e );
  GEVCTI.SetName( "GEVCTI" );
  GEVCTI.Draw( "p" );
  TF1 myfitVCTI( "myfitVCTI", "[0] * pow( ( 1.0 - [ 1 ] ), x )", 0, 512 );
  myfitVCTI.SetParameters( 350.0, 0.0 );
  myfitVCTI.SetParNames( "Q0", "VCTI" );
  GEVCTI.Fit( "myfitVCTI", "qr" );

  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 << "TEMP: " << _temp << Tendl;
  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;
}

Tstring sourcepath( const Tstring& f )
{
  TEnvironmentVariableTable envtable( _rcfile );
  Tstring recpath = envtable.GetEnvironmentValue( "ST02_RECORD_DIR" );
  Tstring rechead = envtable.GetEnvironmentValue( "ST02_RECORD_HEAD" );

  Tstring b = basename( f );

  TRegularExpression regex( _pattern );
  TstringList list = regex.GetSubMatch( b );

  Tstring retval = recpath + Tslash + rechead + list[1] + ".drec";

  return retval;
}

Tstring darkpath( const Tstring& f )
{
  TEnvironmentVariableTable envtable( _rcfile );
  Tstring recpath = envtable.GetEnvironmentValue( "ST02_RECORD_DIR" );
  Tstring rechead = envtable.GetEnvironmentValue( "ST02_RECORD_HEAD" );

  Tstring b = basename( f );
  TRegularExpression regex( _pattern );
  TstringList list = regex.GetSubMatch( b );

  Tstring retval = recpath + Tslash + rechead + list[0] + ".drec";

  return retval;
}

Tvoid check( const Tstring& f )
{
  Tstring sp = sourcepath( f );
  Tstring dp = darkpath( f );

  TInputObjectFile sf( sp );
  Tstring stype, sdev, stemp;
  sf[0][0][1][1].StorePrimitive( stype ); // run type 
  sf[0][0][1][2].StorePrimitive( sdev );  // device id
  sf[0][0][1][3].StorePrimitive( stemp ); // temperature

  TInputObjectFile df( dp );
  Tstring dtype, ddev, dtemp;
  df[0][0][1][1].StorePrimitive( dtype ); // run type 
  df[0][0][1][2].StorePrimitive( ddev );  // device id
  df[0][0][1][3].StorePrimitive( dtemp ); // temperature

  if ( stype != "SOURCE RUN" ) {
    Tcout << stype << Tendl;
    CLDAQ_EXIT("NOT SOURCE RUN");
  } else if ( dtype != "DARK RUN" ) {
    Tcout << dtype << Tendl;
    CLDAQ_EXIT("NOT DARK RUN");
  } else if ( stemp != dtemp ) {
    Tcout << stemp << "!=" << dtemp << Tendl;
    CLDAQ_EXIT("TEMP INCOMPATIBILITY");
  } else if ( sdev != ddev ) {
    Tcout << sdev << "!=" << ddev << Tendl;
    CLDAQ_EXIT("DEVICE INCOMPATIBILITY");
  } else {
    _temp = stemp;
    return;
  }
}
