// Author: Andrew M. Rogers, NSCL 07/01/2006
// Original Design: Daniel Bazin, NSCL
//* Copyright (C) 2006-2008 Andrew M. Rogers

#include "TS800.h"

#include <iostream>
#include <fstream>

#include <TBranch.h>
#include <TChain.h>
#include <TFile.h>
#include <TList.h>
#include <TROOT.h>
#include <TStopwatch.h>
#include <TTree.h>


ClassImp(TS800);

////////////////////////////////////////////////////////////////////////////////
/* BEGIN_HTML
<p> The TS800 class inherits from TObject.  This Class provides the structure for the 
S800 device.  Raw event data is filled into the class members.
</p>

<p> For additional information not provided here please see the S800 website at,
<a href="http://groups.nscl.msu.edu/s800/">http://groups.nscl.msu.edu/s800/</a>
</p>

<h3><a name="unpack">I. Unpacking</a></h3>

<h3><a name="coord">II. Coordinate System</a></h3>
<p>The S800 focal plane coordinate are defined in the following way,</p>
<p>Dispersive plane:      x-axis
   Non-Disperssive plane: y-axis
   Beam Direction:        z-axis</p>

   If one is standing at the target position this translates to,


<h3><a name="vars">III. Important Data Members</a></h3>

<h3><a name="examples">IV. Examples</a></h3>

<h3>Related References</h3>

<h4>[1] Bazin, D., Caggiano, JA, Sherrill, BM, Yurkon, J., and Zeller, A.: The S800 spectrograph, Nuclear Inst. and Methods in Physics Research, B 204, Elsevier, 629-633, 2003<a href="http://dx.doi.org/10.1016/S0168-583X(02)02142-0">[Full Text]</a></h4>
<h4>[2] Yurkon, J., Bazin, D., Benenson, W., Morrissey, DJ, Sherrill, BM, Swan, D., and Swanson, R.: Focal plane detector for the S800 high-resolution spectrometer, Nuclear Instruments and Methods in Physics Research Section A: Accelerators, Spectrometers, Detectors and Associated Equipment 422(1), Elsevier Science, 291-295, 1999 
<a href="http://dx.doi.org/10.1016/S0168-9002(98)00960-7">[Full Text]</a></h4>
END_HTML */
////////////////////////////////////////////////////////////////////////////////


//______________________________________________________________________________
TS800::TS800(const TS800 &s800) : TObject(s800)
{
  // -- Copy Constructor.

  ((TS800&)s800).Copy(*this);
}


//______________________________________________________________________________
Bool_t TS800::Calculate(Long64_t entry)
{
  // -- Calculate an entry for the specified S800 components.
  //
  
  if(!fChain){printf("TTree or TChain has not been initialized!!!\n"); return kFALSE;}

  //  trigger.Calculate();
  e1.Calculate(entry);
  e2.Calculate(entry);
//   crdc1.Calculate();
//   crdc2.Calculate();
//   fpTrack.Calculate();

//   #if TS800_OP_TCRDC==1
//   tcrdc1.Calculate();
//   tcrdc2.Calculate();
//   #endif
//   #if TS800_OP_TPPAC==1
//   #ifndef EXPERIMENT_02023
//   tppac1.Calculate();
//   tppac2.Calculate();
//   #endif
//   #if (TS800_OP_TCRDC==1 || TS800_OP_TPPAC==1)
//   imTrack.Calculate();
//   #endif
//   #endif

//   tof.Calculate();
//   ic.Calculate();

  return kTRUE;
}


//______________________________________________________________________________
Int_t TS800::Calculate(Option_t* prefix,Option_t* path,Option_t* treeName,
		       Bool_t calcTracking,Option_t* option)
{
  // -- Calculate specified S800 components.
  //

  if(!fChain){printf("TTree or TChain has not been initialized!!!\n"); return -1;}

  TStopwatch stopWatch;
  stopWatch.Start();

  Int_t  nTrees = 1;
  TTree *inifChain = fChain;
  if(strcmp(fChain->ClassName(),"TChain")==0) nTrees = ((TChain*)fChain)->GetNtrees();

  // Call the copy constructor.
  TS800 *newS800 = new TS800(*this);   
  newS800->crdc1.calc.pad = &newS800->crdc1.pad; newS800->crdc2.calc.pad = &newS800->crdc2.pad; // FIXME !!!
  newS800->e1.fCon         = &e1;
  newS800->e2.fCon         = &e2;
  newS800->crdc1.pad.fCon  = &crdc1.pad;
  newS800->crdc2.pad.fCon  = &crdc2.pad;
  newS800->crdc1.calc.fCon = &crdc1.calc;
  newS800->crdc2.calc.fCon = &crdc2.calc;
  newS800->crdc1.fCon      = &crdc1;
  newS800->crdc2.fCon      = &crdc2;
  newS800->fpTrack.fCon    = &fpTrack;
  #ifdef TS800_OP_TCRDC
  newS800->tcrdc1.fCon     = &crdc1;
  newS800->tcrdc2.fCon     = &crdc2;
  #endif
  #if TS800_OP_TPPAC==1
  newS800->tppac1.fCon     = &tppac1;
  newS800->tppac2.fCon     = &tppac2;
  #endif
  #if (TS800_OP_TCRDC==1 || TS800_OP_TPPAC==1)
  newS800->imTrack.fCon    = &imTrack;
  #endif
  newS800->tof.fCon        = &tof;
  newS800->ic.fCon         = &ic;

  // Loop over all trees.
  Long64_t curEntry = 0;
  for(Int_t tt=0; tt<nTrees; tt++){
    fChain->LoadTree(curEntry);
    TTree *cTree = fChain->GetTree();
    // Check the tree analysis state.
    if(strcmp(cTree->GetUserInfo()->FindObject("Analysis State")->GetTitle(),"0")!=0) {
      printf("* ERROR: Analysis State!=0\n"); return -2;
    }
    curEntry = curEntry+cTree->GetEntries()+1;
    InitTree(cTree);

    // Set the output filename.
    TString fileName;
    TNamed *runNumber = (TNamed*)cTree->GetUserInfo()->FindObject("Run Number");
    Int_t   runNum = atoi(runNumber->GetTitle());
    Char_t pLine[1000];
    sprintf(pLine,"loadS800RunSettings(%i,ex->s800)",runNum);
    gROOT->ProcessLine(pLine);
    TString fPath(path);
    TString fPrefix(prefix);
    fileName = runNumber->GetTitle();
    printf("Processing file: %s\n",fileName.Data());
    if(prefix == "") fileName = fPath+"run"+fileName+"Cal.root";
    else             fileName = fPath+fPrefix+fileName+"Cal.root";
    
    // File options.
    if(option=="RECREATE"){ cout << "Creating file: " << fileName << endl;
    }else {option="UPDATE"; cout << "Updating file: " << fileName << endl;}

    // Make a new file for our calibrated TTree.
    TString newTName((Char_t*)treeName);
    TString oldTName(cTree->GetName());
    TFile   newFile(fileName,option);
    TTree  *newTree = new TTree("Cal","Calibrated "+oldTName+" Tree",99);

    // Check for existing TTree.
    TNamed aState("Analysis State","1");
    if(newFile.FindObject(oldTName+"Cal")!=0) printf("Tree already exists!\n");
    else if(strcmp(newTName,"")==0){
      newTName = oldTName+"Cal";
      newTree->SetName(newTName);
      newTree->GetUserInfo()->Add(&aState);
    }else{
      newTree->SetName(newTName+"Cal");
      newTree->GetUserInfo()->Add(&aState);
    }

    // Copy UserInfo
    for(Int_t j=0; j<cTree->GetUserInfo()->GetEntries(); j++){
      TNamed *ntmp = (TNamed*)cTree->GetUserInfo()->At(j);
      TNamed *ctmp = (TNamed*)ntmp->Clone();
      if(strcmp(ntmp->GetName(),"Analysis State")!=0) newTree->GetUserInfo()->Add(ctmp);
    }

    // Branches.
    newTree->Branch("s800","TS800",&newS800);
    newTree->SetBranchAddress("s800",&newS800);
    newS800->InitTree(newTree);

    // Before Calaculating CRDC values set run dependant shifts.
    newS800->crdc1.SetYShift(runNum);  
    newS800->crdc2.SetYShift(runNum);
    //    newS800->crdc1.SetYGainShift(runNum); // USE SHIFTS INSTEAD.
    //    newS800->crdc2.SetYGainShift(runNum);
    newS800->SetPIDShifts(runNum);
    newS800->SetFpTrackShifts(runNum);

    // Calibrate
    Long64_t nEntries = cTree->GetEntries();
    for(Long64_t ientry=0; ientry<nEntries; ientry++){
      Double_t prog = ((Double_t)ientry/nEntries)*100;
      if(ientry%100==0){printf("Entry: %15lli \t%4.2lf %%\r",ientry,prog); cout.flush();}
      newS800->crdc1.pad.Calibrate(ientry);
      newS800->crdc2.pad.Calibrate(ientry);
      newS800->crdc1.Calculate(ientry);
      newS800->crdc2.Calculate(ientry);
      newS800->e1.Calculate(ientry);
      newS800->e2.Calculate(ientry);
      if(calcTracking) newS800->fpTrack.Calculate(ientry);
      #if TS800_OP_TCRDC==1
      newS800->tcrdc1.Calculate(ientry);
      newS800->tcrdc2.Calculate(ientry);
      #endif
      #if TS800_OP_TPPAC==1
      #ifndef EXPERIMENT_02023
      newS800->tppac1.Calculate(ientry);
      newS800->tppac2.Calculate(ientry);
      #endif
      #if (TS800_OP_TCRDC==1 || TS800_OP_TPPAC==1)
      newS800->imTrack.Calculate(ientry);
      #endif
      #endif
      newS800->tof.Calculate(ientry);
      newS800->ic.Calibrate(ientry);
      newS800->ic.Calculate(ientry);
      newTree->Fill();
    }
    newTree->AutoSave();
    newFile.Close();
    InitTree(inifChain);
  }
  stopWatch.Stop();
  stopWatch.Print();

  return 1;
}



//______________________________________________________________________________
Int_t TS800::Calibrate(Long64_t entry)
{
  // -- Calibrate an entry.
  // Current coponents callibrated:  E1,E2, and E3 scintilators ONLY.
  

  if(!fChain) { printf("TTree or TChain has not been initialized!!!\n"); return -1;}

  e1.Calibrate(entry);
  e2.Calibrate(entry);
  e3.Calibrate(entry);
  
  return 1;
}


//______________________________________________________________________________
Int_t TS800::Calibrate(Option_t* prefix,Option_t* path,Option_t* treeName,Option_t* option)
{
  // -- Calibrates TS800 components.
  //

//   if(!fChain){printf("TTree or TChain has not been initialized!!!\n"); return -1;}

//   ///////////////////////////////////
//   TStopwatch stopWatch;
//   stopWatch.Start();

//   Int_t nTrees=1;
//   TTree *inifChain = fChain;
//   if(strcmp(fChain->ClassName(),"TChain")==0) nTrees = ((TChain*)fChain)->GetNtrees();

//   Long64_t curEntry = 0;
//   for(Int_t tt=0; tt<nTrees; tt++){
//     cout << endl << curEntry << " " ;
//     fChain->LoadTree(curEntry);
//     TTree *cTree = fChain->GetTree();
//     cout << cTree ->GetEntries() << " " << fChain->GetTree()->GetDirectory()->GetName() << endl << endl;
//     curEntry = curEntry+cTree->GetEntries()+1;

//     InitTree(cTree);
//     // Set the output filename.
//     TString fileName;
//     TNamed *runNumber = (TNamed*)cTree->GetUserInfo()->FindObject("Run Number");
//     TString fPath(path);
//     TString fPrefix(prefix);
//     fileName = runNumber->GetTitle();
//     if(prefix == ""){
//       fileName = fPath+"run"+fileName+"Cal.root";
//     }else{
//       fileName = fPath+fPrefix+fileName+"Cal.root";
//     }

//     // File options.
//     if(option=="RECREATE"){ cout << "Creating file: " << fileName << endl;
//     }else {option="UPDATE"; cout << "Updating file: " << fileName << endl;}

//     // Make a new file for our calibrated TTree.
//     TFile   *newFile = new TFile(fileName,option);
//     TTree   *newTree;
//     TString oldTName(fChain->GetName());
//     TString newTName((Char_t*)treeName);

//     // Check for existing TTree.
//     if(newFile->FindObject(oldTName+"Cal")!=0){
//       //newTree = (TTree*)newFile->FindObject(oldTName+"Cal");
//       printf("Tree already exists!\n");
//     }else if(strcmp(newTName,"")==0){
//       newTName = oldTName;
//       //    newTree = new TTree(oldTName+"Cal","Calibrated "+oldTName+" Tree",99);
//       newTree = new TTree("E02023Cal","Calibrated "+oldTName+" Tree",99);
//       // We must set the entries of the calibrated tree since we will be filling individual branches.
//       newTree->SetEntries(fChain->GetEntries());
//     }else{
//       newTree = new TTree(newTName+"Cal","Calibrated "+oldTName+" Tree",99);
//       newTree->SetEntries(fChain->GetEntries());
//     }

//     cout << newTName << endl;
  
//     // Add friends.
//     //  newTree->AddFriend(fChain,"E02023",kTRUE);
  
//     // Call the copy constructor.
//     TS800 *newS800 = new TS800(*this);
//     newS800->crdc1.settag(S800_FP_CRDC_PACKET);
//     newS800->crdc1.setchannels(TS800_FP_CRDC_CHANNELS);
//     newS800->crdc1.InitFix();
//     //  newS800->crdc1.InitClass("crdc1");
//     //  newS800.InitBranch(newTree,"Cal");
  
//     newTree->Branch("s800","TS800",&newS800,64000);
//     newS800->InitTree(newTree);
//     //  cout << newTree->GetBranch("ic.raw[16]") << endl;
//     newS800->fChain = newTree;
//     newS800->crdc1.fChain = newTree;
//     newS800->crdc1.pad.fChain = newTree;
//     newTree->SetMakeClass(1);
//     fChain->SetMakeClass(1);
  
  
//     #if TS800_OP_TCRDC==1
//     newS800->tcrdc1.pad.Calibrate();
//     newS800->tcrdc2.pad.Calibrate();
//     #endif
//     #if TS800_OP_TPPAC==1
//     #ifndef EXPERIMENT_02023
//     //newS800.tppac1.Calibrate();
//     //newS800.tppac2.Calibrate();
//     #endif
//     #endif
//     fChain->SetBranchAddress(name+"crdc1.filled",&newS800->crdc1.filled,&newS800->crdc1.b_filled);
//     fChain->SetBranchAddress(name+"crdc1.data",newS800->crdc1.data,&newS800->crdc1.b_data);
//     fChain->SetBranchAddress(name+"crdc1.sample",newS800->crdc1.sample,&newS800->crdc1.b_sample);
//     fChain->SetBranchAddress(name+"crdc1.channel",newS800->crdc1.channel,&newS800->crdc1.b_channel);
//         newS800->crdc1.pad.Calibrate();
//     //  for(Int_t i=0; i<6000; i++){
//     //    newS800->crdc1.b_filled->GetEntry(i);
//     //    newS800->crdc1.pad.parent->b_filled->GetEntry(i);
//     //     newS800->crdc1.b_data->GetEntry(i);
//     //     newS800->crdc1.b_sample->GetEntry(i);
//     //    newS800->crdc1.b_channel->GetEntry(i);
//     //     //    newS800->crdc1.b_data->GetEntry(i);
//     //     cout << newS800->crdc1.filled << " " ;
//     //     for(Int_t zz=0; zz<newS800->crdc1.filled; zz++) cout << newS800->crdc1.rChannel[zz] << " " ;
//     //     cout << endl;
//     //     //    for(Int_t j=0; j<2; j++){
//     //     //      cout << " " << newS800->crdc1.channel[j] << endl; // " " << newS800->crdc1.data[j] << endl;
//     //     //    }
//     //  }
//     //  newS800->crdc2.pad.Calibrate();

//     fChain->SetBranchAddress(name+"ic.raw[16]",&newS800->ic.raw,&newS800->ic.b_raw);
//     newS800->ic.Calibrate();

//     newTree->AutoSave();
//     //  newTree->ResetBranchAddresses();
//     newFile->Close();
//     delete newS800;
//   }

//   stopWatch.Stop();
//   stopWatch.Print();

  return 1;
}


//______________________________________________________________________________
void TS800::Copy(TObject &s800) const
{
  // -- Copy this method.

  TObject::Copy((TObject&)s800);
  ((TS800&)s800).fRandom.SetSeed(0);
  ((TS800&)s800).fName    = fName;
  ((TS800&)s800).fTitle   = fTitle;
  ((TS800&)s800).name     = name;
  ((TS800&)s800).fAddRndm = fAddRndm;
  ((TS800&)s800).kBrhoA   = kBrhoA;
  ((TS800&)s800).kBrho    = kBrho;

  ((TS800&)s800).fEulerPhi   = fEulerPhi;
  ((TS800&)s800).fEulerTheta = fEulerTheta;
  ((TS800&)s800).fEulerPsi   = fEulerPsi;
  
  e1.Copy(((TS800&)s800).e1);
  ((TS800&)s800).e1.parent = &((TS800&)s800);
  e2.Copy(((TS800&)s800).e2);
  ((TS800&)s800).e2.parent = &((TS800&)s800);
  e3.Copy(((TS800&)s800).e3);
  ((TS800&)s800).e3.parent = &((TS800&)s800);
  crdc1.Copy(((TS800&)s800).crdc1);
  ((TS800&)s800).crdc1.parent = &((TS800&)s800);
  crdc2.Copy(((TS800&)s800).crdc2);
  ((TS800&)s800).crdc2.parent = &((TS800&)s800);
  s800map.Copy(((TS800&)s800).s800map);
  fpTrack.Copy(((TS800&)s800).fpTrack);
  ((TS800&)s800).fpTrack.parent = &((TS800&)s800);
  imTrack.Copy(((TS800&)s800).imTrack);
  ((TS800&)s800).imTrack.parent = &((TS800&)s800);
  ic.Copy(((TS800&)s800).ic);
  ((TS800&)s800).ic.parent = &((TS800&)s800);
  tcrdc1.Copy(((TS800&)s800).tcrdc1);
  tcrdc2.Copy(((TS800&)s800).tcrdc2);
  tppac1.Copy(((TS800&)s800).tppac1);
  tppac2.Copy(((TS800&)s800).tppac2);
  trigger.Copy(((TS800&)s800).trigger);
  tof.Copy(((TS800&)s800).tof);
  ((TS800&)s800).tof.parent = &((TS800&)s800);

  fHICShifts.Copy(((TS800&)s800).fHICShifts);
  fHToFShifts[0].Copy(((TS800&)s800).fHToFShifts[0]);
  fHToFShifts[1].Copy(((TS800&)s800).fHToFShifts[1]);
  fHYtaShifts.Copy(((TS800&)s800).fHYtaShifts);

  ((TS800&)s800).Clear();
}


//______________________________________________________________________________
Bool_t TS800::GenPrime(Option_t *output,Option_t *treeName,Option_t *option)
{
  // -- Generate primary S800 data tree.
  //

  printf("* Method not implemented.\n");
  return kFALSE;
}


//______________________________________________________________________________
void TS800::InitClass() 
{
  // -- Intialize the class to default settings.
  //

  kBrhoA = 0.0;
  kBrho  = 0.0;

  fEulerPhi   = 0;
  fEulerTheta = 0;
  fEulerPsi   = 0;

  // By default randomize data to convert to Double_t.
  fAddRndm = kTRUE;

  e1.InitClass("e1", this);
  e2.InitClass("e2", this);
  e3.InitClass("e3", this);
  cout << "* Plastic initialized . . .              \t\t\t\t\t [OK] " <<endl;

  crdc1.settag(S800_FP_CRDC_PACKET);
  crdc2.settag(S800_FP_CRDC_PACKET);
  crdc1.setchannels(TS800_FP_CRDC_CHANNELS);
  crdc2.setchannels(TS800_FP_CRDC_CHANNELS);
  crdc1.InitClass("crdc1",this);
  crdc2.InitClass("crdc2",this);
  cout << "* S800 CRDC's initialized . .            \t\t\t\t\t [OK]" <<endl;

  #if TS800_OP_TCRDC==1
  tcrdc1.InitClass("tcrdc1");
  tcrdc2.InitClass("tcrdc2");
  tcrdc1.settag(S800_II_CRDC_PACKET);
  tcrdc2.settag(S800_II_CRDC_PACKET);
  tcrdc1.setchannels(TS800_II_CRDC_CHANNELS);
  tcrdc2.setchannels(TS800_II_CRDC_CHANNELS);
  #endif
  #if TS800_OP_TPPAC==1
  tppac1.InitClass("tppac1");
  tppac2.InitClass("tppac2");
  tppac1.settag(S800_II_TRACK_PACKET);
  tppac2.settag(S800_II_TRACK_PACKET);
  tppac1.setchannels(TS800_II_PPAC_CHANNELS);
  tppac2.setchannels(TS800_II_PPAC_CHANNELS);	
  cout << "* S800 tracking PPAC's initialized . . .  \t\t\t\t\t [OK]" <<endl;
  #endif

  fpTrack.InitClass("fpTrack", this);
  cout << "* S800 Tracking initialized . . .         \t\t\t\t\t [OK]" <<endl;
  #if (TS800_OP_TCRDC==1 || TS800_OP_TPPAC==1)
  imTrack.InitClass("imTrack", this);
  cout << "* S800 IM Tracking initialized . . .      \t\t\t\t\t [OK]" <<endl;
  #endif
  s800map.InitClass(this);
  cout << "* S800 Map initialized . . .              \t\t\t\t\t [OK]" <<endl;

  ic.InitClass("ic",this);
  cout << "* Ion chamber initialized . . .           \t\t\t\t\t [OK]" <<endl;

  trigger.InitClass("trigger");
  cout << "* Trigger initialized . . .               \t\t\t\t\t [OK]" <<endl;

  tof.InitClass("tof", this);
  cout << "* TOF initialized . . .                   \t\t\t\t\t [OK]" <<endl;

  Clear();

  // Prepare histos.
  Char_t   name[1000],title[1000];
  sprintf(name,"fHICShifts_%s",GetName());
  sprintf(title,"PID Ion Chamber Shifts");
  fHICShifts.SetNameTitle(name,title);
  fHICShifts.SetBins(2000,1,2001);
  sprintf(name,"fHToFShifts0_%s",GetName());
  sprintf(title,"PID ToF Shifts XfpTar");
  fHToFShifts[0].SetNameTitle(name,title);
  fHToFShifts[0].SetBins(2000,1,2001);
  sprintf(name,"fHToFShifts1_%s",GetName());
  sprintf(title,"PID ToF Shifts TarFp");
  fHToFShifts[1].SetNameTitle(name,title);
  fHToFShifts[1].SetBins(2000,1,2001);
  sprintf(name,"fHYtaShifts_%s",GetName());
  sprintf(title,"FP Tracking Yta Shifts");
  fHYtaShifts.SetNameTitle(name,title);
  fHYtaShifts.SetBins(2000,1,2001);
}


//______________________________________________________________________________
void TS800::InitTree(TTree *tree) 
{
  // -- Associate this class with a tree containing TS800 branches.
  // Each InitTree() method of the TS800 sub-classes are called.  By initializing the
  // tree we set the data member addresses of this class with the branch addresses
  // of the tree.
  //
  // When we call GetEntry() (either for a class or individual branch) the data members
  // from this class are filled with the values of the branches in the tree
  // (See GetEntry()).
  
  fChain   = tree;
  fCurrent = -1;
  //  TS800  *p   = this;
  //  TS800  **pp = &p;
  //  fChain->SetBranchAddress("s800",&pp);
  //  TNamed *aState = (TNamed*)fChain->GetUserInfo()->FindObject("Analysis State");

  //  fChain->SetBranchAddress("fNwords",&fNwords,&b_fNwords);
  
  b_fNwords = fChain->GetBranch("fNwords");
  //  if(     strcmp(aState->GetName(),"0")) 
  //  else if(strcmp(aState->GetName(),"1")) fChain->SetBranchAddress("E02023.fNwords",&fNwords,&b_fNwords);
  //  else if(strcmp(aState->GetName(),"2")) fChain->SetBranchAddress("E02023.fNwords",&fNwords,&b_fNwords);

  e1.InitTree(tree);
  e2.InitTree(tree);
  e3.InitTree(tree);
  crdc1.InitTree(tree);
  crdc2.InitTree(tree);
  #if TS800_OP_TCRDC==1
  tcrdc1.InitTree(tree);
  tcrdc2.InitTree(tree);
  b_tcrdc1 = fChain->GetBranch("tcrdc1");
  b_tcrdc2 = fChain->GetBranch("tcrdc2");
  #else
  //  tree->SetBranchStatus("tcrdc*",0);
  #endif
  #if TS800_OP_TPPAC==1
  tppac1.InitTree(tree);
  tppac2.InitTree(tree);
  b_tppac1 = fChain->GetBranch("tppac1");
  b_tppac2 = fChain->GetBranch("tppac2");
  #else
  //  tree->SetBranchStatus("tppac*",0);
  #endif
  fpTrack.InitTree(tree);
  b_fpTrack = fChain->GetBranch("fpTrack");
  #if (TS800_OP_TCRDC==1 || TS800_OP_TPPAC==1)  
  imTrack.InitTree(tree);
  b_imTrack = fChain->GetBranch("imTrack");
  #else
  //  tree->SetBranchStatus("imTrack*",0);
  #endif
  ic.InitTree(tree);
  trigger.InitTree(tree);
  tof.InitTree(tree);

  b_e1      = fChain->GetBranch("e1");
  b_e2      = fChain->GetBranch("e2");
  b_e3      = fChain->GetBranch("e3");
  b_crdc1   = fChain->GetBranch("crdc1");
  b_crdc2   = fChain->GetBranch("crdc2");
  b_ic      = fChain->GetBranch("ic");
  b_trigger = fChain->GetBranch("trigger");
  b_tof     = fChain->GetBranch("tof");
}


//______________________________________________________________________________
void TS800::Clear(Option_t*) 
{
  // -- Clear TS800 data members and sub-classes.
  //

  fNwords = 0;

  e1.Clear();
  e2.Clear();
  e3.Clear();
  #if TS800_OP_TCRDC==1
  tcrdc1.Clear();
  tcrdc2.Clear();
  #endif
  #if TS800_OP_TPPAC==1
  tppac1.Clear();
  tppac2.Clear();
  #endif
  crdc1.Clear();
  crdc2.Clear();
  fpTrack.Clear();
  #if (TS800_OP_TCRDC==1 || TS800_OP_TPPAC==1)
  imTrack.Clear();
  #endif
  ic.Clear();
  trigger.Clear();
  tof.Clear();
}


//______________________________________________________________________________
void TS800::GetEntry(int i) 
{
  // -- Set all data member values to those of entry i in the current tree.
  //

  b_fNwords->GetEntry(i);

  e1.GetEntry(i);
  e2.GetEntry(i);
  e3.GetEntry(i);
  #if TS800_OP_TCRDC==1
  tcrdc1.GetEntry(i);
  tcrdc2.GetEntry(i);
  #endif
  #if TS800_OP_TPPAC==1
  tppac1.GetEntry(i);
  tppac2.GetEntry(i);
  #endif
  crdc1.GetEntry(i);
  crdc2.GetEntry(i);
  fpTrack.GetEntry(i);
  ic.GetEntry(i);
  trigger.GetEntry(i);
  tof.GetEntry(i);
}


//______________________________________________________________________________
Bool_t TS800::LoadPIDShifts(const Char_t *fileName)
{
  // -- Load the file containing the S800 PID shifts.
  // 
  // Commented lines are denoted by the '#' character.  Each line has the following
  // format,
  //
  // <RUN NUMBER>     <IC SHIFT>       <TOF SHIFT>
  //
  
  ifstream iFile(fileName,ios::in);
  Char_t   line[1000];
  Int_t    runNum;
  Double_t icShift,xfpShift,tarShift;
  
  if(!iFile.is_open()) {printf("* File could not be opened!\n"); return kFALSE;}

  // Ignore commented lines.
  iFile.getline(line,1000);
  while(line[0]=='#' || line[0]==' ') iFile.getline(line,1000);

  // Read in file.
  Bool_t firstLine = kTRUE;
  while (!iFile.eof()){
    if(!firstLine) iFile.getline(line,1000);
    firstLine = kFALSE;
    sscanf(line,"%i %lf %lf %lf",&runNum,&xfpShift,&tarShift,&icShift);
    fHICShifts.SetBinContent(runNum,icShift);
    fHToFShifts[0].SetBinContent(runNum,xfpShift);
    fHToFShifts[1].SetBinContent(runNum,tarShift);
  }

  iFile.close();
  printf("* Loading %s PID stablization shifts . . .  \t\t\t [OK]\n",GetName());
  
  return kTRUE;
}


//______________________________________________________________________________
Bool_t TS800::LoadYtaShifts(const Char_t *fileName)
{
  // -- Load the file containing the S800 Yta shifts.
  // 
  // Commented lines are denoted by the '#' character.  Each line has the following
  // format,
  //
  // <RUN NUMBER>     <YTA SHIFT>
  //
  
  ifstream iFile(fileName,ios::in);
  Char_t   line[1000];
  Int_t    runNum;
  Double_t ytaShift;
  
  if(!iFile.is_open()) {printf("* File could not be opened!\n"); return kFALSE;}

  // Ignore commented lines.
  iFile.getline(line,1000);
  while(line[0]=='#' || line[0]==' ') iFile.getline(line,1000);

  // Read in file.
  Bool_t firstLine = kTRUE;
  while (!iFile.eof()){
    if(!firstLine) iFile.getline(line,1000);
    firstLine = kFALSE;
    sscanf(line,"%i %lf",&runNum,&ytaShift);
    fHYtaShifts.SetBinContent(runNum,ytaShift);
  }

  iFile.close();
  printf("* Loading %s Yta stablization shifts . . .  \t\t\t [OK]\n",GetName());
  
  return kTRUE;
}


//______________________________________________________________________________
void TS800::SetCrdcCalFile(Char_t *crdc1Path,Char_t *crdc2Path) 
{
  // -- Set the path of the CRDC calibration files.
  // These files contain some or all of the following settings for each CRDC,
  //     1. CRDC pad pedestal values.
  //     2. CRDC pad slopes.
  //     3. CRDC pad offsets.
  //
  // The file is formatted to match that used for SpecTcl at the NSCL.  For example,
  //     .
  //     .
  //     set s800.fp.crdc1.pad.ped.056 294
  //     set s800.fp.crdc1.pad.ped.057 297
  //     set s800.fp.crdc1.pad.ped.058 299
  //     .
  //     .
  //     set s800.fp.crdc1.pad.slope.056 1.00
  //     set s800.fp.crdc1.pad.slope.057 1.10
  //     set s800.fp.crdc1.pad.slope.058 1.08
  //     .
  //     .
  //     set s800.fp.crdc1.pad.offset.056 14
  //     set s800.fp.crdc1.pad.offset.057 17
  //     set s800.fp.crdc1.pad.offset.058 19
  //

  crdc1CalPath = crdc1Path;
  crdc2CalPath = crdc2Path;
}


//______________________________________________________________________________
void TS800::SetPIDShifts(Int_t runNum) 
{
  // -- 
  
  Double_t icShift  = fHICShifts.GetBinContent(runNum);
  Double_t xfpShift = fHToFShifts[0].GetBinContent(runNum);
  Double_t tarShift = fHToFShifts[1].GetBinContent(runNum);
  ic.fPIDShift     = icShift;
  tof.fPIDShift[0] = xfpShift;
  tof.fPIDShift[1] = tarShift;
}


//______________________________________________________________________________
void TS800::SetFpTrackShifts(Int_t runNum) 
{
  // -- 
  
  Double_t ytaShift  = fHYtaShifts.GetBinContent(runNum);
  fpTrack.fYtaShift     = ytaShift;

}


//______________________________________________________________________________
void TS800::SetName(const Char_t *name)
{
  // -- Change (i.e. set) the name of the TS800.
  //

  fName = name;
}


//______________________________________________________________________________
void TS800::SetTitle(const Char_t *title)
{
  // -- Change (i.e. set) the title of the TS800.
  //

  fTitle = title;
}


//______________________________________________________________________________
void TS800::SetNameTitle(const Char_t *name, const Char_t *title)
{
  // -- Change (i.e. set) all the TS800 parameters (name and title).
  //

  fName  = name;
  fTitle = title;
}


//______________________________________________________________________________
Int_t TS800::Unpack(UShort_t *pEvent) 
{
  // -- Unpack raw event data from a S800 sub-packet.
  //

  UShort_t *pp = (UShort_t*)pEvent;
  UShort_t *p  = (UShort_t*)pEvent;
  UShort_t packetSize;                 // Number of words in the S800 packet.

  UShort_t subEventLength,
    subPacketSize,                     // Number of words in a sub-packet.
    pTag,
    ID,
    words;
  //    tppacBegin;
  
  *p--;
  *p--;
  packetSize = *p;                     // Number of words in the S800 packet.
  packetSize = packetSize - 3;
  *p++;                                // Advance the event pointer to beginning of packet.
  *p++;
  fNwords = packetSize;

  // Check S800 Version information.
  if (*p++ != S800_VERSION) {
    cout << "Wrong version of S800 sub-event. It is " << *p << ".  Aborting ..." << endl;
    return 1;
  }

  #ifdef TS800_DEBUG
  Int_t lineCount = 3;
  printf("---- S800 Packet ---- length = %i words\n",packetSize+3);
  *p--; *p--; *p--;
  printf("%04x ",*p++);  printf("%04x ",*p++);  printf("%04x ",*p++);
  #endif

  while (packetSize > 0) {
    #ifdef TS800_DEBUG
    printf("%04x ",*p);
    if(lineCount==10){printf("\n"); lineCount=0;}
    lineCount++; *p++; packetSize--;
    if(packetSize==0) printf("\n\n");
    #else

    subPacketSize = *p++;
    pTag          = *p++;              // S800 component packet tag.

    switch(pTag) {
    case S800_TRIGGER_PACKET:
      p = this->trigger.Unpack(p);
      break;      

    case S800_TOF_PACKET:
      p = this->tof.Unpack(p);
      break;      

    case S800_FP_SCINT_PACKET:
      words = subPacketSize-2;
      while (words > 0) {
	ID = ((*p)&0xF000)>>12;
	if (ID == 0 || ID == 1) p = this->e1.Unpack(p, ID);
	if (ID == 2 || ID == 3) p = this->e2.Unpack(p, ID);
	if (ID == 4 || ID == 5) p = this->e3.Unpack(p, ID);
	words -= 2;
      }
      break;
			
    case S800_FP_IC_PACKET:
      p = this->ic.Unpack(p);
      break;
			
    case S800_FP_CRDC_PACKET:
      ID = *p++;
      if (ID == 0) p = this->crdc1.Unpack(p);
      if (ID == 1) p = this->crdc2.Unpack(p);
      break;
			
//     case S800_TA_PIN_PACKET:
//       ID = *p++;
//       if (ID == 1) p = S800->ta.pin1.unpack(p);
//       if (ID == 2) p = S800->ta.pin2.unpack(p);
//       break;
    
    #if TS800_OP_TPPAC==1
    case S800_II_TRACK_PACKET:
      //      tppacBegin = p;
      p = this->tppac1.Unpack(p,1);
      p = this->tppac2.Unpack(p,2);
      //      p = imTrack.unpack(p);
      break;
    #endif

    #if TS800_OP_TCRDC==1
    case S800_II_CRDC_PACKET:
      ID = *p++;
      if (ID == 0) p = this->tcrdc1.unpack(p);
      if (ID == 1) p = this->tcrdc2.unpack(p);
      break;
    #endif
      
    case S800_OB_PIN_PACKET:
      //      p = S800->ob.pin.unpack(p);
      break;

    default:
      printf("%i\n",pTag);
      printf("Unrecognized packet tag: 0x%x @ packetSize = %d\n", pTag,packetSize);
      printf("Beginning of event: 0x%x 0x%x 0x%x 0x%x ...\n", *pp, *(pp+1), *(pp+2), *(pp+3));
      printf("Failing part: ");
      for (Int_t yp=subEventLength-packetSize; yp<=subEventLength-packetSize+10; yp++) {
	printf("0x%x ", *(pp+yp));
      }
      printf("\nBailing out ...\n");
      p += subPacketSize - 2;
      break;
    }
    packetSize -= subPacketSize;
    if(pTag == 1) break;
    #endif
  }

  return 0;
}



Last change: Sun Dec 21 12:38:53 2008
Last generated: 2008-12-21 12:38

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.