#include <TROOT.h>
#include <TSystem.h>
#include <TChain.h>
#include <TFile.h>
#include <TString.h>
#include <iostream>

//
// To define cut monitors
// uncomments line below
//
// #define MONITORS

//Constants for analyses
//Event information
const int mPrimVertZbins = 6;                // number of z bins for analysis
const double mPrimVertZ[2] = {-30., 30.};    // redefine values of the vertex Z for each run [cm]
const double mPrimVertR = 2.;                // distance in the XY plane [cm]
const double mPrimVertVpdVz[2] = {-5., 5.};  // VpdZ - TPCZ difference
const double mPrimVertXShift = 0.;
const double mPrimVertYShift = 0.;
const bool mUseZdcCorrection = true;         // valid for AuAu collisions. True for 200GeV only!

//Track information
const double mChargedKaonMass = 0.493677;
const double mChargedPionMass = 0.13957018;
const int mPosCharge = +1;
const int mNegCharge = -1;
const int mTrackType = 1;                     // primary track
const int mPythiaKaonCode = 321;              // pythia particle code
const int mPythiaPionCode = 211;              // pythia particle code

const int mTrackNHits[2] = {15, 50};          // number of track hits
const double mTrackNHitsFit[2] = {15, 50};    // number of track hits used in fit
const double mTrackDCA[2] = {0., 2.};         // DCA of the track and PV [cm]
const double mTrackASplitVal = 0.52;
const double mTrackMom[2] = {0.15, 1.55};        // general momentum of the track [GeV/c]
const double mTrackTransvMom[2] = {0.15, 1.55};  // general transverse momentum of the track [GeV/c]
const double mTrackEta[2] = { -1., 1.};

const short mDetectorSelection = 4;  // 0-TPC, 1-ToF, 2-TPC+ToF, 3-ToF||TPC, 4-TPC&&TOF(P>Pthr)||TPC(P<Pthr)

const double mTrackTpcMom[2] = {0.15, 0.55};  // track momentum for TPC idnetification [GeV/c]
const double mnSigmaElectron[2] = {-1e9, 1e9};
const double mnSigmaPion[2] = {-2., 2.};
const double mnSigmaKaon[2] = {-1e9, 1e9};
const double mnSigmaProton[2] = {-1e9, 1e9};

const double mTrackTofMom[2] = {0.15, 1.55};   // track momentum for ToF identification [GeV/c]
const double mPionTofMsqr[2] = {-0.02, 0.062}; // based on p+p data
const double mKaonTofMsqr[2] = {0.18, 0.3};    // based on p+p data

const double mTrackTnTMom[2] = {0.15, 1.55};
const double mTnTNSigmaElectron[2] = {-1e9, 1e9};
const double mTnTNSigmaPion[2] = {-2., 2.};
const double mTnTNSigmaKaon[2] = {-1e9., 1e9.};
const double mTnTNSigmaProton[2] = {-1e9, 1e9};

const double mTTTMomThresh = 0.45; // TPC&&TOF (P>Pthr)||TPC(P<Pthr)

// pair information
const double mFmrCut[2] = {-1.1, 0.1};         // not more than 10% of merged rows
const double mSplitLevelCut[2] = {-0.5, 0.6};  // splitting level from paper. StHbtPair::quality()
const double mPairKt[2] = {0.,1.5};            // pair transverse momentum cut
const double mPairQinv[2] = {0., 1.5};         // pair relative momentum
const double mAveSep[2] = {5., 5000.};         // average separation of tracks within TPC

// histograms values
const int mPairKtBins = 24;
const double mPairKtVal[2] = {0.05, 1.25};
const int mQinvBins = 40;                      // 20 MeV/c^2 bin width
const double mQinvVal[2] = {0., 0.8};          // redefine for each analysis

const Char_t *defaultInFile = "pions.list";
const Char_t *defaultOutFile = "oExpPion_pp500_3D.root";

//_________________
void expPionHBT_pp500_3D(const Char_t *inFileList = defaultInFile,
			 const Char_t *oFileName = defaultOutFile) {


  std::cout << "********************************" << std::endl
	    << "*       expPionHBT_pp500_3D    *" << std::endl
	    << "*               Start          *" << std::endl
	    << "********************************" << std::endl << endl;

  // load libraries
  std::cout << "Loading libraries..." << std::endl;
  gROOT->LoadMacro("$STAR/StRoot/StMuDSTMaker/COMMON/macros/loadSharedLibraries.C");
  loadSharedLibraries();
  gSystem->Load("libMinuit");
  gSystem->Load("StRefMultCorr");
  gSystem->Load("StFlowMaker");   // should be placed before HBT
  gSystem->Load("StHbtMaker");
  gSystem->Load("StarClassLibrary");
  gSystem->Load("libgsl");
  gSystem->Load("libgslcblas");
  gSystem->Load("StFemtoDstMaker");

  std::cout << "Libraries have been successfully loaded" << std::endl;

  // create chain
  StChain* mChain = new StChain("StChain");
  mChain->SetDebug(0);
  StMuDebug::setLevel(0);

  // set StHbtMaker and StHbtManager
  StHbtMaker *mHbtMaker = new StHbtMaker();
  mHbtMaker->SetDebug(0);
  StHbtManager *mHbtManager = mHbtMaker->HbtManager();

  // set StHbtReader
  StHbtFemtoDstReader *femtoReader = new StHbtFemtoDstReader("", inFileList, "root", -1, false);
  femtoReader->AddTrigId(320000);  // trigger selection for pp500 y2011
  femtoReader->AddTrigId(320001);
  femtoReader->AddTrigId(320011);
  femtoReader->AddTrigId(320021);
  femtoReader->AddTrigId(330021);
  Long64_t mNEvents = femtoReader->GetNEvents();
  mHbtManager->SetEventReader(femtoReader);

  // set basic event cut
  gregsEventCut *mBasicEventCut = new gregsEventCut();
  mBasicEventCut->SetCollisionType(0);     //0-pp, 1-AuAu
  mBasicEventCut->SetEventMult(0, 45);
  mBasicEventCut->SetVertZPos(mPrimVertZ[0], mPrimVertZ[1]);
  mBasicEventCut->SetVzVpdVzDiff(mPrimVertVpdVz[0],mPrimVertVpdVz[1]);
  mBasicEventCut->SetVertRPos(mPrimVertR);

  //Set basic kaon single-particle cut
  gregsSimpleTrackCut *mBasicTrackCut = new gregsSimpleTrackCut();
  mBasicTrackCut->SetCharge(mPosCharge);
  mBasicTrackCut->SetMass(mChargedPionMass);
  mBasicTrackCut->SetType(mTrackType);
  mBasicTrackCut->SetNHits(mTrackNHits[0], mTrackNHits[1]);
  mBasicTrackCut->SetNHitsFit(mTrackNHitsFit[0], mTrackNHitsFit[1]);
  mBasicTrackCut->SetAntiSplit(mTrackASplitVal);
  mBasicTrackCut->SetEta(mTrackEta[0], mTrackEta[1]);
  mBasicTrackCut->SetDCA(mTrackDCA[0], mTrackDCA[1]);
  mBasicTrackCut->SetDCAGlobal(mTrackDCA[0], mTrackDCA[1]);
  mBasicTrackCut->SetP(mTrackMom[0], mTrackMom[1]);

  mBasicTrackCut->SetDetectorSelection(mDetectorSelection);

  mBasicTrackCut->SetTpcMomentum(mTrackTpcMom[0], mTrackTpcMom[1]);
  mBasicTrackCut->SetNSigmaElectron(mnSigmaElectron[0],mnSigmaElectron[1]);
  mBasicTrackCut->SetNSigmaPion(mnSigmaPion[0], mnSigmaPion[1]);
  mBasicTrackCut->SetNSigmaKaon(mnSigmaKaon[0], mnSigmaKaon[1]);
  mBasicTrackCut->SetNSigmaProton(mnSigmaProton[0], mnSigmaProton[1]);

  mBasicTrackCut->SetTofMassSqr(mPionTofMsqr[0],mPionTofMsqr[1]);
  mBasicTrackCut->SetTofMomentum(mTrackTofMom[0], mTrackTofMom[1]);

  mBasicTrackCut->SetTnTMomentum(mTrackTnTMom[0], mTrackTnTMom[1]);
  mBasicTrackCut->SetTnTNSigmaElectron(mTnTNSigmaElectron[0], mTnTNSigmaElectron[1]);
  mBasicTrackCut->SetTnTNSigmaPion(mTnTNSigmaPion[0], mTnTNSigmaPion[1]);
  mBasicTrackCut->SetTnTNSigmaKaon(mTnTNSigmaKaon[0], mTnTNSigmaKaon[1]);
  mBasicTrackCut->SetTnTNSigmaProton(mTnTNSigmaProton[0], mTnTNSigmaProton[1]);

  mBasicTrackCut->SetTTTMomentumThresh(mTTTMomThresh);

  //Set basic kaon pair cut
  gregsTrackPairCut *mBasicPairCut = new gregsTrackPairCut();
  mBasicPairCut->SetFracOfMergedRow(mFmrCut[0],mFmrCut[1]);
  mBasicPairCut->SetQuality(mSplitLevelCut[0],mSplitLevelCut[1]);
  mBasicPairCut->SetKt(mPairKt[0],mPairKt[1]);
  mBasicPairCut->SetQinv(mPairQinv[0],mPairQinv[1]);
  mBasicPairCut->SetAverageSeparation(mAveSep[0],mAveSep[1]);

  Int_t mLocalCharge, mMultBins, mMultLow, mMultHi, mEvents2Mix, mCurrentPid;

  ////////////////////////////////////////////
  //                                        //
  //       Like-sign pion analysis          //
  //                                        //
  ////////////////////////////////////////////

  // The multiplicity analysis matrix is 2x5x10, where
  // the first element corresponds to the particle charge: (pos, neg),
  // the second one corresponds to the PID selection: 
  // 0-TPC, 1-ToF, 2-TPC+ToF, 3-ToF||TPC, 4-TPC&&TOF(P>Pthr)||TPC(P<Pthr),
  // and the third one corresponds to the RefMult intervals as listed below:
  // Mult: 0-60, 0-2, 3-4, 5-6, 7-8, 9-10, 11-12, 13-14, 14-17, 18-60

  // StHbtAnalysis, cut, CF and monitor declarations
  StHbtVertexMultAnalysis *mPionMultAnalysis[2][5][10]; 

  // cuts
  gregsEventCut       *mPionEventCut[10];
  gregsSimpleTrackCut *mPionTrackCut[2][5][10];
  gregsTrackPairCut   *mPionPairCut[2][5][10];

  // corrFctns
  /*
  QinvCorrFctnKt                *mPionQinvMixKtCF[2][5][10];
  QinvCorrFctnOpposHemisphereKt *mPionQinvOppKtCF[2][5][10];
  QinvCorrFctnRotationKt        *mPionQinvRotKtCF[2][5][10];
  */
  BPLCMSFrame3DCorrFctnKt       *mPionBPlcmsQinvKtCF[2][5][10];

#ifdef MONITORS
  // cut monitors
  fxtEventCutMonitor *mFxtPionEventCutMonitorPass[2][5][10];
  fxtTrackCutMonitor *mFxtPionTrackCutMonitorPass[2][5][10];
  fxtPairCutMonitor  *mFxtPionPairCutMonitorPass[2][5][10];
  fxtEventCutMonitor *mFxtPionEventCutMonitorFail[2][5][10];
  fxtTrackCutMonitor *mFxtPionTrackCutMonitorFail[2][5][10];
  fxtPairCutMonitor  *mFxtPionPairCutMonitorFail[2][5][10];
#endif
  for(Int_t iMult = 0; iMult < 10; iMult++) {
    switch(iMult) {
    case 0:  mMultLow=0;  mMultHi=45; mMultBins=6;  mEvents2Mix=10; break;
    case 1:  mMultLow=0;  mMultHi=2;  mMultBins=1;  mEvents2Mix=10; break;
    case 2:  mMultLow=3;  mMultHi=4;  mMultBins=1;  mEvents2Mix=10; break;
    case 3:  mMultLow=5;  mMultHi=6;  mMultBins=1;  mEvents2Mix=10; break;
    case 4:  mMultLow=7;  mMultHi=8;  mMultBins=1;  mEvents2Mix=10; break;
    case 5:  mMultLow=9;  mMultHi=10; mMultBins=1;  mEvents2Mix=10; break;
    case 6:  mMultLow=11; mMultHi=12; mMultBins=1;  mEvents2Mix=10; break; // 11 - 45 
    case 7:  mMultLow=13; mMultHi=14; mMultBins=1;  mEvents2Mix=10; break; // cheack less or less equale
    case 8:  mMultLow=14; mMultHi=17; mMultBins=1;  mEvents2Mix=10; break;
    case 9:  mMultLow=18; mMultHi=30; mMultBins=2;  mEvents2Mix=10; break;
    default: mMultLow=0;  mMultHi=30; mMultBins=6;  mEvents2Mix=10; break;
    };
    
    for(Int_t iCharge = 0; iCharge < 2; iCharge++) {
      for(Int_t iPid = 0; iPid < 5; iPid++) {

	switch(iCharge) {
	case 0:  mLocalCharge = mPosCharge;    break;
	case 1:  mLocalCharge = mNegCharge;    break;
	default: mLocalCharge = mPosCharge;    break;
	};

	switch(iPid) {
	case 0:  mCurrentPid = 0; break; // TPC only
	case 1:  mCurrentPid = 1; break; // TOF only
	case 2:  mCurrentPid = 2; break; // TPC+TOF
	case 3:  mCurrentPid = 3; break; // TPC||TOF
	case 4:  mCurrentPid = 4; break; // TPC (p<pthresh) && TOF+TPC (p>pthresh)
	default: mCurrentPid = 4; break;
	};


	/////////////////////////////////////
	//                                 //
	//      Like-sign pion analysis    //
	//                                 //
	/////////////////////////////////////

	// create analysis
	mPionMultAnalysis[iCharge][iPid][iMult] = new StHbtVertexMultAnalysis(mPrimVertZbins,
									      mPrimVertZ[0],
									      mPrimVertZ[1],
									      mMultBins,
									      mMultLow,
									      mMultHi);

	// create event cut
	mPionEventCut[iMult] = new gregsEventCut(*mBasicEventCut);
	mPionEventCut[iMult]->SetEventMult(mMultLow, mMultHi);
#ifdef MONITORS
	mFxtPionEventCutMonitorPass[iCharge][iPid][iMult] = 
	  new fxtEventCutMonitor("eventPionPass", Form("_%d_%d_%d",iCharge,iPid,iMult));
	mFxtPionEventCutMonitorFail[iCharge][iPid][iMult] = 
	  new fxtEventCutMonitor("eventPionFail", Form("_%d_%d_%d",iCharge,iPid,iMult));
	mPionEventCut[iCharge][iPid][iMult]->AddCutMonitor(mFxtPionEventCutMonitorPass[iCharge][iPid][iMult],
							   mFxtPionEventCutMonitorFail[iCharge][iPid][iMult]);
#endif
	mPionMultAnalysis[iCharge][iPid][iMult]->SetEventCut(mPionEventCut[iCharge][iPid][iMult]);


	// create single-track cuts and add them to the analysis
	mPionTrackCut[iCharge][iPid][iMult] = new gregsSimpleTrackCut(*mBasicTrackCut);
	mPionTrackCut[iCharge][iPid][iMult]->SetMass(mChargedPionMass);
	mPionTrackCut[iCharge][iPid][iMult]->SetCharge(mLocalCharge);
	mPionTrackCut[iCharge][iPid][iMult]->SetDetectorSelection(mCurrentPid);


	mPionTrackCut[iCharge][iPid][iMult]->SetTpcMomentum(0.15, 0.55);
	mPionTrackCut[iCharge][iPid][iMult]->SetNSigmaElectron(-1e9,1e9);
	mPionTrackCut[iCharge][iPid][iMult]->SetNSigmaPion(-2., 2.);
	mPionTrackCut[iCharge][iPid][iMult]->SetNSigmaKaon(-1e9, 1e9);
	mPionTrackCut[iCharge][iPid][iMult]->SetNSigmaProton(-1e9, 1e9);

	mPionTrackCut[iCharge][iPid][iMult]->SetTofMassSqr(-0.02, 0.062);
	mPionTrackCut[iCharge][iPid][iMult]->SetTofMomentum(0.15, 1.55);

	mPionTrackCut[iCharge][iPid][iMult]->SetTnTMomentum(0.15, 1.55);
	mPionTrackCut[iCharge][iPid][iMult]->SetTnTNSigmaElectron(-1e9, 1e9);
	mPionTrackCut[iCharge][iPid][iMult]->SetTnTNSigmaPion(-3., 3.);
	mPionTrackCut[iCharge][iPid][iMult]->SetTnTNSigmaKaon(-1e9, 1e9);
	mPionTrackCut[iCharge][iPid][iMult]->SetTnTNSigmaProton(-1e9, 1e9);

	mPionTrackCut[iCharge][iPid][iMult]->SetTTTMomentumThresh(0.45);

#ifdef MONITORS
	mFxtPionTrackCutMonitorPass[iCharge][iPid][iMult] = 
	  new fxtTrackCutMonitor(Form("_trackPionPass_%d_%d_%d_",iCharge,iPid,iMult), mChargedPionMass);
	mFxtPionTrackCutMonitorFail[iCharge][iPid][iMult] = 
	  new fxtTrackCutMonitor(Form("_trackPionFail_%d_%d_%d_",iCharge,iPid,iMult), mChargedPionMass);
	mPionTrackCut[iCharge][iPid][iMult]->AddCutMonitor(mFxtPionTrackCutMonitorPass[iCharge][iPid][iMult],
							   mFxtPionTrackCutMonitorFail[iCharge][iPid][iMult]);
#endif
	mPionMultAnalysis[iCharge][iPid][iMult]->SetFirstParticleCut(mPionTrackCut[iCharge][iPid][iMult]);
	mPionMultAnalysis[iCharge][iPid][iMult]->SetSecondParticleCut(mPionTrackCut[iCharge][iPid][iMult]);

	// create pair cut
	mPionPairCut[iCharge][iPid][iMult] = new gregsTrackPairCut(*mBasicPairCut);
#ifdef MONITORS
	mFxtPionPairCutMonitorPass[iCharge][iPid][iMult] = 
	  new fxtPairCutMonitor(Form("_pairPionPass_%d_%d_%d_",iCharge,iPid,iMult));
	mFxtPionPairCutMonitorPass[iCharge][iPid][iMult]->SetParticleMass(mChargedPionMass);
	mFxtPionPairCutMonitorFail[iCharge][iPid][iMult] = 
	  new fxtPairCutMonitor(Form("_pairPionFail_%d_%d_%d_",iCharge,iPid,iMult));
	mFxtPionPairCutMonitorFail[iCharge][iPid][iMult]->SetParticleMass(mChargedPionMass);
	mPionPairCut[iCharge][iPid][iMult]->AddCutMonitor(mFxtPionPairCutMonitorPass[iCharge][iPid][iMult],
							  mFxtPionPairCutMonitorFail[iCharge][iPid][iMult]);
#endif
	mPionMultAnalysis[iCharge][iPid][iMult]->SetPairCut(mPionPairCut[iCharge][iPid][iMult]);

	// correlation function initialization
	/*
	mPionQinvMixKtCF[iCharge][iPid][iMult] = 
	  new QinvCorrFctnKt(Form("hPionQinvMixKt_%d_%d_%d",iCharge,iPid,iMult),
			     mQinvBins, mQinvVal[0], mQinvVal[1],
			     mPairKtBins, mPairKtVal[0], mPairKtVal[1]);
	mPionQinvOppKtCF[iCharge][iPid][iMult] = 
	  new QinvCorrFctnOpposHemisphereKt(Form("hPionQinvOppKt_%d_%d_%d",iCharge,iPid,iMult),
					    mQinvBins, mQinvVal[0], mQinvVal[1],
					    mPairKtBins, mPairKtVal[0], mPairKtVal[1]);
	mPionQinvRotKtCF[iCharge][iPid][iMult] = 
	  new QinvCorrFctnRotationKt(Form("hPionQinvRotKt_%d_%d_%d",iCharge,iPid,iMult),
				     mQinvBins, mQinvVal[0], mQinvVal[1],
				     mPairKtBins, mPairKtVal[0], mPairKtVal[1]);
	*/
	mPionBPlcmsQinvKtCF[iCharge][iPid][iMult] =
	  new BPLCMSFrame3DCorrFctnKt(Form("hPionBPlcmsQinvKt_%d_%d_%d", iCharge, iPid, iMult),
				      mQinvBins, mQinvVal[0], mQinvVal[1],
				      mPairKtBins, mPairKtVal[0], mPairKtVal[1]);
	/*
	mPionMultAnalysis[iCharge][iPid][iMult]->AddCorrFctn(mPionQinvMixKtCF[iCharge][iPid][iMult]);
	mPionMultAnalysis[iCharge][iPid][iMult]->AddCorrFctn(mPionQinvOppKtCF[iCharge][iPid][iMult]);
	mPionMultAnalysis[iCharge][iPid][iMult]->AddCorrFctn(mPionQinvRotKtCF[iCharge][iPid][iMult]);
	*/
	mPionMultAnalysis[iCharge][iPid][iMult]->AddCorrFctn(mPionBPlcmsQinvKtCF[iCharge][iPid][iMult]);
	
	// set number of events to mix
	mPionMultAnalysis[iCharge][iPid][iMult]->SetNumEventsToMix(mEvents2Mix);

	// add analysis to the manager
	mHbtManager->AddAnalysis(mPionMultAnalysis[iCharge][iPid][iMult]);
	
      } // for(Int_t iPid=0; iPid<5; iPid++)
    } // for(Int_t iCharge=0; iCharge<2; iCharge++)
  } // for(Int_t iMult=0; iMult<10; iMult++)
    

  //StChain initialization
  mChain->Init();

  // start processing
  Int_t iRet = 0;
  Int_t mNEventsProcessed = 0;
  Float_t mPercentCounter = 0.05;
  Float_t mProgress = 0.;

  unsigned int mSubCounter = 1;              // time
  time_t mStartTime, mStopTime, mDiffTime;   // time
  float mFrac;                               // time
  mStartTime = time(0);                      // time

  // mNEvents = 15;
  for(Int_t iEvent=0; iEvent<mNEvents; iEvent++) {

    mProgress = (Float_t)iEvent / (Float_t)mNEvents;
    mNEventsProcessed++;
    
    if(mProgress >= mPercentCounter) {
      mPercentCounter += 0.05;
      mStopTime = time(0);
      mDiffTime = difftime(mStopTime, mStartTime);
      mFrac = (float)mDiffTime*(float)(mNEvents - iEvent)/(float)iEvent;
      mSubCounter++;
      std::cout << Form("Processing progress: %4.2f%%. Time left: %.1f sec", mProgress*100., mFrac)
		<< std::endl;
    }

    mChain->Clear();
    iRet = mChain->Make(iEvent);
    if(iRet!=0) {
      std::cout << "expMesonHBT_pp500_1D[ERROR] - iRet: " << iRet << std::endl;
      break;
    }
  }

  mChain->Finish();

  // create output file
  TFile *oFile = new TFile(oFileName, "RECREATE");

  // write hbt histograms to the file
  std::cout << "Writing histograms to the output file...";

#ifdef MONITORS
  for(Int_t iCharge = 0; iCharge < 2; iCharge++) {
    for(Int_t iPid = 0; iPid < 5; iPid++) {
      for(Int_t iMult = 0; iMult < 10; iMult++) {

	// pions
        mFxtPionEventCutMonitorPass[iCharge][iPid][iMult]->VertexZ()->Write();
	mFxtPionEventCutMonitorPass[iCharge][iPid][iMult]->VertexYvsVertexX()->Write();
	mFxtPionEventCutMonitorPass[iCharge][iPid][iMult]->RefMult()->Write();
	mFxtPionEventCutMonitorPass[iCharge][iPid][iMult]->VpdVzDiff()->Write();
	mFxtPionEventCutMonitorFail[iCharge][iPid][iMult]->VertexZ()->Write();
	mFxtPionEventCutMonitorFail[iCharge][iPid][iMult]->VertexYvsVertexX()->Write();
	mFxtPionEventCutMonitorFail[iCharge][iPid][iMult]->RefMult()->Write();
	mFxtPionEventCutMonitorFail[iCharge][iPid][iMult]->VpdVzDiff()->Write();

	mFxtPionTrackCutMonitorPass[iCharge][iPid][iMult]->DCAGlobal()->Write();
	mFxtPionTrackCutMonitorPass[iCharge][iPid][iMult]->Nhits()->Write();
	mFxtPionTrackCutMonitorPass[iCharge][iPid][iMult]->P()->Write();
	mFxtPionTrackCutMonitorPass[iCharge][iPid][iMult]->Pt()->Write();
	mFxtPionTrackCutMonitorPass[iCharge][iPid][iMult]->PtVsNsigmaPion()->Write();
	mFxtPionTrackCutMonitorPass[iCharge][iPid][iMult]->PtVsNsigmaKaon()->Write();
	mFxtPionTrackCutMonitorPass[iCharge][iPid][iMult]->PtVsNsigmaProton()->Write();
	mFxtPionTrackCutMonitorPass[iCharge][iPid][iMult]->PvsDedx()->Write();
	mFxtPionTrackCutMonitorPass[iCharge][iPid][iMult]->Rapidity()->Write();
	mFxtPionTrackCutMonitorPass[iCharge][iPid][iMult]->PseudoRapidity()->Write();
	mFxtPionTrackCutMonitorPass[iCharge][iPid][iMult]->PtVsMassSqr()->Write();
	mFxtPionTrackCutMonitorFail[iCharge][iPid][iMult]->DCAGlobal()->Write();
	mFxtPionTrackCutMonitorFail[iCharge][iPid][iMult]->Nhits()->Write();
	mFxtPionTrackCutMonitorFail[iCharge][iPid][iMult]->P()->Write();
	mFxtPionTrackCutMonitorFail[iCharge][iPid][iMult]->Pt()->Write();
	mFxtPionTrackCutMonitorFail[iCharge][iPid][iMult]->PtVsNsigmaPion()->Write();
	mFxtPionTrackCutMonitorFail[iCharge][iPid][iMult]->PtVsNsigmaKaon()->Write();
	mFxtPionTrackCutMonitorFail[iCharge][iPid][iMult]->PtVsNsigmaProton()->Write();
	mFxtPionTrackCutMonitorFail[iCharge][iPid][iMult]->PvsDedx()->Write();
	mFxtPionTrackCutMonitorFail[iCharge][iPid][iMult]->Rapidity()->Write();
	mFxtPionTrackCutMonitorFail[iCharge][iPid][iMult]->PseudoRapidity()->Write();
	mFxtPionTrackCutMonitorFail[iCharge][iPid][iMult]->PtVsMassSqr()->Write();

	mFxtPionPairCutMonitorPass[iCharge][iPid][iMult]->Kt()->Write();
	mFxtPionPairCutMonitorPass[iCharge][iPid][iMult]->Pt1Pt2Qinv()->Write();
	mFxtPionPairCutMonitorPass[iCharge][iPid][iMult]->FMRvsQinv()->Write();
	mFxtPionPairCutMonitorPass[iCharge][iPid][iMult]->SLvsQinv()->Write();
	mFxtPionPairCutMonitorPass[iCharge][iPid][iMult]->AveSepVsQinv()->Write();
	mFxtPionPairCutMonitorFail[iCharge][iPid][iMult]->Kt()->Write();
	mFxtPionPairCutMonitorFail[iCharge][iPid][iMult]->Pt1Pt2Qinv()->Write();
	mFxtPionPairCutMonitorFail[iCharge][iPid][iMult]->FMRvsQinv()->Write();
	mFxtPionPairCutMonitorFail[iCharge][iPid][iMult]->SLvsQinv()->Write();
	mFxtPionPairCutMonitorFail[iCharge][iPid][iMult]->AveSepVsQinv()->Write();
      } // for(Int_t iMult=0; iMult<10; iMult++)
    } // for(Int_t iPid=0; iPid<5; iPid++)
  } // for(Int_t iCharge=0; iCharge<2; iCharge++)
#endif

  for(Int_t iCharge = 0; iCharge < 2; iCharge++) {
    for(Int_t iPid = 4; iPid < 5; iPid++) {
      for(Int_t iMult = 0; iMult < 10; iMult++) {
	for(Int_t iKt = 0; iKt < mPairKtBins; iKt++) {

	  // pion analysis
	  /*
	  mPionQinvMixKtCF[iCharge][iPid][iMult]->Numerator(iKt)->Write();
	  mPionQinvMixKtCF[iCharge][iPid][iMult]->Denominator(iKt)->Write();
	  mPionQinvOppKtCF[iCharge][iPid][iMult]->Numerator(iKt)->Write();
	  mPionQinvOppKtCF[iCharge][iPid][iMult]->Denominator(iKt)->Write();
	  mPionQinvRotKtCF[iCharge][iPid][iMult]->Numerator(iKt)->Write();
	  mPionQinvRotKtCF[iCharge][iPid][iMult]->Denominator(iKt)->Write();
	  */
	  mPionBPlcmsQinvKtCF[iCharge][iPid][iMult]->Numerator(iKt)->Write();
	  mPionBPlcmsQinvKtCF[iCharge][iPid][iMult]->Denominator(iKt)->Write();
	  mPionBPlcmsQinvKtCF[iCharge][iPid][iMult]->QinvHisto(iKt)->Write();
	} // for(Int_t iKt=0; iKt<mPairKtBins; iKt++)
      } // for(Int_t iMult=0; iMult<10; iMult++)
    } // for(Int_t iPid=0; iPid<5; iPid++)
  } // for(Int_t iCharge=0; iCharge<2; iCharge++

  std::cout << "\t[DONE]" << std::endl;

  // write the output file and close it
  std::cout << "Saving the output file...";
  oFile->Close();
  std::cout << "\t[DONE]" << std::endl;

  delete mChain;

  std::cout << "********************************" << std::endl
	    << "*       expPionHBT_pp500_3D    *" << std::endl
	    << "*              Finish          *" << std::endl
	    << "********************************" << std::endl << std::endl;
}
