/*****************************************************************************
 * Copyright (C) 2009-2013   this file is part of the NPTool Project         *
 *                                                                           *
 * For the licensing terms see $NPTOOL/Licence/NPTool_Licence                *
 * For the list of contributors see $NPTOOL/Licence/Contributors             *
 *****************************************************************************/

/*****************************************************************************
 * Original Author: Adrien MATTA  contact address: matta@ipno.in2p3.fr       *
 *                                                                           *
 * Creation Date  : November 2012                                            *
 * Last update    :                                                          *
 *---------------------------------------------------------------------------*
 * Decription:                                                               *
 *  This class describe the Tigress Silicon array                              *
 *                                                                           *
 *---------------------------------------------------------------------------*
 * Comment:                                                                  *
 *                                                                           *
 *****************************************************************************/

// C++ headers
#include <sstream>
#include <cmath>
#include <limits>
//G4 Geometry object
#include "G4Box.hh"
#include "G4Tubs.hh"
#include "G4Trd.hh"
#include "G4Trap.hh"
#include "G4Cons.hh"

//G4 sensitive
#include "G4SDManager.hh"
#include "G4MultiFunctionalDetector.hh"

//G4 various object
#include "G4Material.hh"
#include "G4Polycone.hh"
#include "G4Polyhedra.hh"
#include "G4LogicalVolume.hh"
#include "G4ThreeVector.hh"
#include "G4Transform3D.hh"
#include "G4RotationMatrix.hh"
#include "G4PVPlacement.hh"
#include "G4VisAttributes.hh"
#include "G4Colour.hh"
#include "G4RunManager.hh"
#include "G4ios.hh"
#include "G4SubtractionSolid.hh"
#include "G4UnionSolid.hh"
#include "G4ThreeVector.hh"// NPS
#include "Tigress.hh"
//#include "TigressScorers.hh"

// NPL
#include "NPOptionManager.h"

//#include "TigressScorers.hh"
#include "RootOutput.h"
using namespace TIGRESS;

// CLHEP header
#include "CLHEP/Random/RandGauss.h"

using namespace std;
using namespace CLHEP;
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......

namespace {
  const G4double CrystalOuterRadius  = 30.0*mm; // outer radius for crystal
  const G4double CrystalInnerRadius  =  5.0*mm; // inner radius for hole in crystal
  const G4double CrystalLength       = 90.0*mm; // crystal length
  const G4double CrystalHoleDepth    = 15.0*mm; // depth at which starts the hole
  
  const G4double CrystalEdgeOffset1  = 26.0*mm; // distance of the edge from the center of the crystal
  const G4double CrystalEdgeOffset2  = 28.5*mm; // distance of the edge from the center of the crystal
  
  const G4double CrystalEdgeDepth    = 30.0*mm;  // depth to which the crystal is shaped
  const G4double CrystalEdgeAngle    = 22.5*deg; // bevel angle
  
  const G4double CapsuleWidth        = 1.5*mm;   // capsule width
  const G4double CapsuleLength       = 110.*mm;   // capsule length
  const G4double CapsuleEdgeDepth    = 3.3*cm;   // same as crystal !
  const G4double CrystalToCapsule    = 3.5*mm;   // to be adjusted ..
  
  const G4double BGOLength           = 120.0*mm;
  const G4double BGOWidth            = 25.0*mm;
  
  const G4double CsILength           = 20.0*mm;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
// Tigress Specific Method
Tigress::Tigress(){
  InitializeMaterial();
  m_Event = new TTigressData();
  
 BlueVisAtt   = new G4VisAttributes(G4Colour(0, 0, 1)) ;
 GreenVisAtt  = new G4VisAttributes(G4Colour(0, 1, 0)) ;
 RedVisAtt    = new G4VisAttributes(G4Colour(1, 0, 0)) ;
 WhiteVisAtt  = new G4VisAttributes(G4Colour(1, 1, 1)) ;
 TrGreyVisAtt  = new G4VisAttributes(G4Colour(0.5, 0.5, 0.5, 0.5)) ;
  
  m_LogicClover = 0;
  
}

Tigress::~Tigress(){
  delete m_MaterialSilicon;
  delete m_MaterialAl;
  delete m_MaterialVacuum;
  delete m_MaterialPCB;
}

//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
// Virtual Method of VDetector class
// Read stream at Configfile to pick-up parameters of detector (Position,...)
// Called in DetecorConstruction::ReadDetextorConfiguration Method
void Tigress::ReadConfiguration(string Path){
  ifstream ConfigFile           ;
  ConfigFile.open(Path.c_str()) ;
  string LineBuffer             ;
  string DataBuffer             ;
  istringstream LineStream      ;
  // Standard Case:
  bool check_CloverId = false;
  
  vector<int> CloverId;
  int    CloverId_Free;
  double R;
  double Theta;
  double Phi;
  double BetaX;
  double BetaY;
  double BetaZ;
  
  // Free postion case:
  bool check_R   = false ;
  bool check_Theta = false ;
  bool check_Phi = false ;
  bool check_Beta = false ;
  
  // Frame Case
  bool check_RightFrame = false ;
  bool check_LeftFrame = false ;
  
  bool ReadingStatusStandard = false ;
  bool ReadingStatusFree = false ;
  bool ReadingStatusFrame = false ;
  bool ReadingStatus = false ;
  
  while (!ConfigFile.eof()){
    int VerboseLevel = NPOptionManager::getInstance()->GetVerboseLevel();
    
    getline(ConfigFile, LineBuffer);
    
    if (LineBuffer.compare(0, 7, "Tigress") == 0)
      ReadingStatus = true;
    
    while (ReadingStatus && !ConfigFile.eof()) {
      getline(ConfigFile, LineBuffer);
      
      //   Comment Line
      while (LineBuffer.compare(0, 1, "%") == 0) {
        // Take the next line
        getline(ConfigFile, LineBuffer);
      }
      
      //   Standard case
      if (LineBuffer.compare(0, 15, "TigressStandard") == 0){
        if(VerboseLevel==1)
          G4cout << "/// Clovers in Standard Configuration : ///" << G4endl   ;
        ReadingStatusStandard = true ;
      }
      
      //  Free placing case
      else if (LineBuffer.compare(0, 13, "TigressClover") == 0){
        if(VerboseLevel==1)
          G4cout << "/// Free placed clover : ///" << G4endl   ;
        ReadingStatusFree = true ;
      }
      
      //  Frame case
      else if (LineBuffer.compare(0, 12, "TigressFrame") == 0){
        if(VerboseLevel==1)
          G4cout << "/// Support Frame : ///" << G4endl   ;
        ReadingStatusFrame = true ;
      }
      
      //   Reading Block
      while(ReadingStatusStandard){
        // Pickup Next Line
        getline(ConfigFile, LineBuffer);
        //   Comment Line
        while (LineBuffer.compare(0, 1, "%") == 0) {
          // Take the next line
          getline(ConfigFile, LineBuffer);
        }
        
        LineStream.clear();
        LineStream.str(LineBuffer);
        LineStream >> DataBuffer;

        if ( DataBuffer == "CloverId=" ) {
          check_CloverId = true;
                    
          if(VerboseLevel==1) cout << "CloverId: " ;
          while(LineStream >> DataBuffer){
            CloverId.push_back(atoi(DataBuffer.c_str()));
            if(VerboseLevel==1) G4cout << atoi(DataBuffer.c_str()) << " ";
          }
          if(VerboseLevel==1) G4cout << G4endl << G4endl;
        }
      
        ///////////////////////////////////////////////////
        //   If no Detector Token and no comment, toggle out
        else{
          ReadingStatusStandard = false;
          G4cout << "Error: Wrong Token Sequence: Getting out " << DataBuffer << G4endl ;
          exit(1);
        }
        
        /////////////////////////////////////////////////
        //   If All necessary information there, toggle out
        
        if (check_CloverId){
          ReadingStatusStandard = false;
          AddCloverStandard(CloverId);
          CloverId.clear();
          check_CloverId   = false ;
        }
      }
      
      //   Reading Block
      while(ReadingStatusFree){
        // Pickup Next Line
        getline(ConfigFile, LineBuffer);
        //   Comment Line
        while (LineBuffer.compare(0, 1, "%") == 0) {
          // Take the next line
          getline(ConfigFile, LineBuffer);
        }
        
        LineStream.clear();
        LineStream.str(LineBuffer);
        LineStream >> DataBuffer;
        
        if ( DataBuffer == "CloverId=" ) {
          check_CloverId = true;
          LineStream >> DataBuffer;
          CloverId_Free = atoi(DataBuffer.c_str());
          if(VerboseLevel==1)
            cout << "CloverId: " << atoi(DataBuffer.c_str()) << " " << endl ;
        }
        
        else if ( DataBuffer == "R=" ) {
          check_R = true;
          LineStream >> DataBuffer;
          R = atof(DataBuffer.c_str())*mm;
          if(VerboseLevel==1)
            cout << "R: " << R/mm << " " << endl ;
        }
        
        else if ( DataBuffer == "Theta=" ) {
          check_Theta = true;
          LineStream >> DataBuffer;
          Theta = atof(DataBuffer.c_str())*deg;
          if(VerboseLevel==1)
            cout << "Theta: " << Theta/deg << " " << endl ;
        }
        
        else if ( DataBuffer == "Phi=" ) {
          check_Phi = true;
          LineStream >> DataBuffer;
          Phi = atof(DataBuffer.c_str())*deg;
          if(VerboseLevel==1)
            cout << "Phi: " << Phi/deg << " " << endl ;
        }
        
        else if ( DataBuffer == "Beta=" ) {
          check_Beta = true;
          LineStream >> DataBuffer;
          BetaX = atof(DataBuffer.c_str())*deg;
          if(VerboseLevel==1)
            cout << "BetaX: " << BetaX/deg << " " << endl ;
          LineStream >> DataBuffer;
          BetaY = atof(DataBuffer.c_str())*deg;
          if(VerboseLevel==1)
            cout << "BetaY: " << BetaY/deg << " " << endl ;
          LineStream >> DataBuffer;
          BetaZ = atof(DataBuffer.c_str())*deg;
          if(VerboseLevel==1)
            cout << "BetaZ: " << BetaZ/deg << " " << endl ;
        }
        
        
        ///////////////////////////////////////////////////
        //   If no Detector Token and no comment, toggle out
        else{
          ReadingStatusStandard = false;
          G4cout << "Error: Wrong Token Sequence: Getting out " << DataBuffer << G4endl ;
          exit(1);
        }
        
        /////////////////////////////////////////////////
        //   If All necessary information there, toggle out
        
        if (check_CloverId && check_R && check_Theta && check_Phi && check_Beta){
          ReadingStatusFree = false;
          AddCloverFreePosition(CloverId_Free,R,Theta,Phi,BetaX,BetaY,BetaZ);
          check_CloverId = false ;
          check_R = false ;
          check_Theta = false ;
          check_Phi = false ;
          check_Beta = false ;
        }
      }
      
      //   Reading Block
      while(ReadingStatusFrame){
        // Pickup Next Line
        getline(ConfigFile, LineBuffer);
        //   Comment Line
        while (LineBuffer.compare(0, 1, "%") == 0) {
          // Take the next line
          getline(ConfigFile, LineBuffer);
        }
        
        LineStream.clear();
        LineStream.str(LineBuffer);
        LineStream >> DataBuffer;
        
        if ( DataBuffer == "RightFrame=" ) {
          check_RightFrame = true;
          
          LineStream >> DataBuffer;
          m_RightFrame=atoi(DataBuffer.c_str());
          
          if(VerboseLevel==1)
            if(m_RightFrame)
              cout << "Right frame: yes" << endl;
            else
              cout << "Right frame: no" << endl;
        }
        
        else if ( DataBuffer == "LeftFrame=" ) {
          check_LeftFrame = true;
          
          LineStream >> DataBuffer;
          m_LeftFrame=atoi(DataBuffer.c_str());
          
          if(VerboseLevel==1)
            if(m_LeftFrame)
              cout << "Left frame: yes" << endl;
            else
              cout << "Left frame: no" << endl;
        }
        
        ///////////////////////////////////////////////////
        //   If no Detector Token and no comment, toggle out
        else{
          ReadingStatusStandard = false;
          G4cout << "Error: Wrong Token Sequence: Getting out " << DataBuffer << G4endl ;
          exit(1);
        }
        
        /////////////////////////////////////////////////
        //   If All necessary information there, toggle out
        
        if (check_RightFrame && check_LeftFrame){
          ReadingStatusFrame = false;
          AddCloverStandard(CloverId);
          CloverId.clear();
          check_RightFrame = false;
          check_LeftFrame = false;
        }
      }
      
    }
  }
}

//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
// Return a G4VSolid modeling the Crystal
G4VSolid* Tigress::ConstructCrystal(){
  
  // Copy Past form Exogam collaboration
  
  char sName[40]; // generic for named objects
  
  // define a coaxial shape that will be modify with SubstractSolid
  G4int nbslice = 4;
  G4double zSliceGe[4] = { 0.0*mm, CrystalHoleDepth, CrystalHoleDepth + 3.0*mm, CrystalLength};  // depth where is the hole
  G4double InnRadGe[4] = { 0.0*mm, 0.0*mm, CrystalInnerRadius, CrystalInnerRadius};       // to define the hole in the crystal
  G4double OutRadGe[4] = { CrystalOuterRadius, CrystalOuterRadius, CrystalOuterRadius, CrystalOuterRadius};  // to define the external surface
  
  G4double Edge[3];
  
    sprintf(sName, "coax");
    G4Polycone *coax
    = new G4Polycone(G4String(sName), 0.*deg, 360.*deg, nbslice, zSliceGe, InnRadGe, OutRadGe);
    
    // substract boxes to remove maters.
    G4RotationMatrix rm; //  rm.SetName(G4String("RotationEdge"));
    
    // box definition to remove some matter to the crystal
    sprintf(sName, "LongEdge1");
    Edge[0] = (CrystalOuterRadius-CrystalEdgeOffset1);      // x half-width
    Edge[1] = 1.001*CrystalOuterRadius;                     // y half-width
    Edge[2] = 1.001*CrystalLength/2.0;                      // z half-width
    G4Box *cutEdge1  = new G4Box(G4String(sName),Edge[0],Edge[1],Edge[2]);
    
    sprintf(sName, "LongEdge2");
    Edge[0] = (CrystalOuterRadius-CrystalEdgeOffset2);      // x half-width
    Edge[1] = 1.001*CrystalOuterRadius;                     // y half-width
    Edge[2] = 1.001*CrystalLength/2.0;                      // z half-width
    G4Box *cutEdge2  = new G4Box(G4String(sName),Edge[0],Edge[1],Edge[2]);
    
    sprintf(sName, "Bevel");
    Edge[0] = 1.001*CrystalOuterRadius;
    Edge[1] = sin(CrystalEdgeAngle)*(CrystalEdgeDepth);
    Edge[2] = 1.001*CrystalLength/2.0;
    
    G4Box *cutBevel = new G4Box(G4String(sName),Edge[0],Edge[1],Edge[2]);
    
    // now remove previously defined box from coax. The box must be placed correctly before
    // since the box definition goes from negative to positive values.
    sprintf(sName, "coax_cut1_edge");
    G4SubtractionSolid *coax_cut1
    = new G4SubtractionSolid (G4String(sName), coax, cutEdge1, &rm, G4ThreeVector(-CrystalOuterRadius,0.0,CrystalLength/2.0));
    
    sprintf(sName, "coax_cut2_edge");
    G4SubtractionSolid *coax_cut2
    = new G4SubtractionSolid (G4String(sName), coax_cut1, cutEdge2, &rm, G4ThreeVector(CrystalOuterRadius,0.0,CrystalLength/2.0));
    
    sprintf(sName, "coax_cut3_edge");
    rm.rotateZ(90.0*deg);
    G4SubtractionSolid *coax_cut3
    = new G4SubtractionSolid (G4String(sName), coax_cut2, cutEdge2, &rm, G4ThreeVector(0.0,CrystalOuterRadius,CrystalLength/2.0));
    
    sprintf(sName, "coax_cut4_edge");
    G4SubtractionSolid *coax_cut4
    = new G4SubtractionSolid (G4String(sName), coax_cut3, cutEdge1, &rm, G4ThreeVector(0.0,-CrystalOuterRadius,CrystalLength/2.0));
    rm.rotateZ(-90.0*deg);
    
    sprintf(sName, "coax_cut5_edge");
    rm.rotateX(CrystalEdgeAngle);
    G4SubtractionSolid *coax_cut5
    = new G4SubtractionSolid (G4String(sName), coax_cut4, cutBevel, &rm, G4ThreeVector(0.,CrystalEdgeOffset2,0.));
    rm.rotateX(-CrystalEdgeAngle);
    
    sprintf(sName, "coax_cut6_edge");
    rm.rotateZ(90.0*deg);
    rm.rotateX(CrystalEdgeAngle);
    G4SubtractionSolid *coax_cut6
    = new G4SubtractionSolid (G4String(sName), coax_cut5, cutBevel, &rm, G4ThreeVector(CrystalEdgeOffset2,0.,0.));
    rm.rotateX(-CrystalEdgeAngle);
    rm.rotateZ(-90.0*deg);
  
    return  coax_cut6;
}

//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
// Return a G4VSolid modeling the Capsule
G4VSolid* Tigress::ConstructCapsule(){
  
  G4int nbslice = 7;
  const G4double widthface = 45.5*mm;
  G4double zSlice[7] = {  0.0*mm,
    CapsuleWidth-0.1*mm,
    CapsuleWidth,
    CapsuleEdgeDepth,
    CapsuleLength-CapsuleWidth,
    CapsuleLength-CapsuleWidth-0.1*mm,
    CapsuleLength  };
  G4double InnRad[7] = {  0.0*mm,
    0.0*mm,
    widthface-CapsuleWidth,
    CrystalEdgeOffset1 + CrystalEdgeOffset2 + CrystalToCapsule - CapsuleWidth,
    CrystalEdgeOffset1 + CrystalEdgeOffset2 + CrystalToCapsule - CapsuleWidth,
    0.0*mm,
    0.0*mm};
  G4double OutRad[7] = {  widthface-1.5*mm,
    widthface,
    widthface,
    CrystalEdgeOffset1 + CrystalEdgeOffset2 + CrystalToCapsule,
    CrystalEdgeOffset1 + CrystalEdgeOffset2 + CrystalToCapsule,
    CrystalEdgeOffset1 + CrystalEdgeOffset2 + CrystalToCapsule,
    CrystalEdgeOffset1 + CrystalEdgeOffset2 + CrystalToCapsule};
  
    G4Polyhedra *caps = new G4Polyhedra(G4String("Capsule"), 0.*deg, 360.*deg, 4, nbslice, zSlice, InnRad, OutRad);
  return caps;
  
}

//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
// Return a G4VSolid modeling the BGO
G4VSolid* Tigress::ConstructBGO(){
  
  
  
}

//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
// Return a clover in the configuration given by option (not use a the moment)
void Tigress::ConstructClover(string){
  
  if(m_LogicClover==0){
    
    // Construct the clover itself
    G4VSolid*   Capsule   = ConstructCapsule();
    // Place the cristal in the clover
    G4ThreeVector CrystalPosition = G4ThreeVector(+113.6*0.5*0.5*mm,+113.6*0.5*0.5*mm,0);
    G4VSolid* CrystalB = ConstructCrystal();
    
    m_LogicClover =
    new G4LogicalVolume(Capsule,m_MaterialVacuum,"LogicCloverCase", 0, 0, 0);
    
    G4LogicalVolume* logicCrystalB =
    new G4LogicalVolume(CrystalB,m_MaterialVacuum,"LogicCrystalB", 0, 0, 0);

    G4LogicalVolume* logicCrystalG =
    new G4LogicalVolume(CrystalB,m_MaterialVacuum,"LogicCrystalG", 0, 0, 0);
    
    G4LogicalVolume* logicCrystalR =
    new G4LogicalVolume(CrystalB,m_MaterialVacuum,"LogicCrystalR", 0, 0, 0);
    
    G4LogicalVolume* logicCrystalW =
    new G4LogicalVolume(CrystalB,m_MaterialVacuum,"LogicCrystalW", 0, 0, 0);
    
    G4RotationMatrix* CrystalRotation = new G4RotationMatrix(0,0,0);
    CrystalPosition = G4ThreeVector(+113.6*0.5*0.5*mm,+113.6*0.5*0.5*mm,0);
    new G4PVPlacement(G4Transform3D(*CrystalRotation, CrystalPosition),
                      logicCrystalB,"LogicCrystalB",m_LogicClover,false,m_CloverId[0]);
    logicCrystalB->SetVisAttributes(BlueVisAtt);
    
    CrystalRotation->rotate(-180*deg, G4ThreeVector(0,0,1));
    CrystalPosition = G4ThreeVector(+113.6*0.5*0.5*mm,-113.6*0.5*0.5*mm,0);
    new G4PVPlacement(G4Transform3D(*CrystalRotation, CrystalPosition),
                      logicCrystalG,"LogicCrystalG",m_LogicClover,false,m_CloverId[0]);
    logicCrystalG->SetVisAttributes(GreenVisAtt);
    
     CrystalRotation->rotate(-180*deg, G4ThreeVector(0,0,1));
    CrystalPosition = G4ThreeVector(-113.6*0.5*0.5*mm,-113.6*0.5*0.5*mm,0);
    new G4PVPlacement(G4Transform3D(*CrystalRotation, CrystalPosition),
                      logicCrystalR,"LogicCrystalR",m_LogicClover,false,m_CloverId[0]);
    logicCrystalR->SetVisAttributes(RedVisAtt);
  
    CrystalRotation->rotate(-180*deg, G4ThreeVector(0,0,1));
    CrystalPosition = G4ThreeVector(-113.6*0.5*0.5*mm,+113.6*0.5*0.5*mm,0);
    new G4PVPlacement(G4Transform3D(*CrystalRotation, CrystalPosition),
                      logicCrystalW,"LogicCrystalW",m_LogicClover,false,m_CloverId[0]);
    logicCrystalW->SetVisAttributes(WhiteVisAtt);
    
    m_LogicClover->SetVisAttributes(TrGreyVisAtt);
  }
  
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
// Construct detector and inialise sensitive part.
// Called After DetecorConstruction::AddDetector Method
void Tigress::ConstructDetector(G4LogicalVolume* world){
  ConstructClover("");
  
  G4RotationMatrix* DetectorRotation = new G4RotationMatrix(0,0,0);
  for (unsigned int i = 0 ;  i < m_CloverId.size(); i++) {
    
    // Constructing the Detector referential and the transition matrix
    G4ThreeVector U,V,W;
    G4double wX = sin(m_Theta[i]) * cos(m_Phi[i]) ;
    G4double wY = sin(m_Theta[i]) * sin(m_Phi[i]) ;
    G4double wZ = cos(m_Theta[i]);
    W = G4ThreeVector(wX, wY, wZ) ;
    
    // vector parallel to one axis of the entrance plane
    G4double vX = cos(m_Theta[i]) * cos(m_Phi[i]);
    G4double vY = cos(m_Theta[i]) * sin(m_Phi[i]);
    G4double vZ = -sin(m_Theta[i]);
    V = G4ThreeVector(vX, vY, vZ);
    
    W = W.unit();
    U = V.cross(W);
    U = U.unit();
    V = W.cross(U);
    V = V.unit();
    // Passage Matrix from Lab Referential to Clover Referential
    delete DetectorRotation;
    DetectorRotation = new G4RotationMatrix(U, V, W);
    
    DetectorRotation->rotate(m_BetaX[i], U);
    DetectorRotation->rotate(m_BetaY[i], V);
    DetectorRotation->rotate(m_BetaZ[i], W);
    DetectorRotation->rotate(45*deg, W);
    G4ThreeVector DetectorPosition = m_R[i]*W;
    
    new G4PVPlacement(G4Transform3D(*DetectorRotation, DetectorPosition),
                      m_LogicClover,"Clover",world,false,m_CloverId[0]);
  }
    
}

//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
// Add clover at the standard position of the array
// Take as argument the standard clover Id.
void Tigress::AddCloverStandard(vector<int> CloverId){
  
  for (unsigned int i = 0 ;  i < CloverId.size(); i++) {
    if(CloverId[i] == 1 ){
      m_CloverId.push_back(CloverId[i]);
      m_R.push_back(145*mm);
      m_Theta.push_back(45*deg);
      m_Phi.push_back(22.5*deg);
      m_BetaX.push_back(0);
      m_BetaY.push_back(0);
      m_BetaZ.push_back(0);
    }
    
    else if(CloverId[i] == 2 ){
      m_CloverId.push_back(CloverId[i]);
      m_R.push_back(145*mm);
      m_Theta.push_back(45*deg);
      m_Phi.push_back(112.5*deg);
      m_BetaX.push_back(0);
      m_BetaY.push_back(0);
      m_BetaZ.push_back(0);
    }
    
    else if(CloverId[i] == 3 ){
      m_CloverId.push_back(CloverId[i]);
      m_R.push_back(145*mm);
      m_Theta.push_back(45*deg);
      m_Phi.push_back(202.5*deg);
      m_BetaX.push_back(0);
      m_BetaY.push_back(0);
      m_BetaZ.push_back(0);
    }
    
    else if(CloverId[i] == 4 ){
      m_CloverId.push_back(CloverId[i]);
      m_R.push_back(145*mm);
      m_Theta.push_back(45*deg);
      m_Phi.push_back(292.5*deg);
      m_BetaX.push_back(0);
      m_BetaY.push_back(0);
      m_BetaZ.push_back(0);
    }
    
    else if(CloverId[i] == 5 ){
      m_CloverId.push_back(CloverId[i]);
      m_R.push_back(145*mm);
      m_Theta.push_back(90*deg);
      m_Phi.push_back(22.5*deg);
      m_BetaX.push_back(0);
      m_BetaY.push_back(0);
      m_BetaZ.push_back(180*deg);
    }
    
    else if(CloverId[i] == 6 ){
      m_CloverId.push_back(CloverId[i]);
      m_R.push_back(145*mm);
      m_Theta.push_back(90*deg);
      m_Phi.push_back(67.5*deg);
      m_BetaX.push_back(0);
      m_BetaY.push_back(0);
      m_BetaZ.push_back(180*deg);
    }
    
    else if(CloverId[i] == 7 ){
      m_CloverId.push_back(CloverId[i]);
      m_R.push_back(145*mm);
      m_Theta.push_back(90*deg);
      m_Phi.push_back(112.5*deg);
      m_BetaX.push_back(0);
      m_BetaY.push_back(0);
      m_BetaZ.push_back(180*deg);
    }
    
    else if(CloverId[i] == 8 ){
      m_CloverId.push_back(CloverId[i]);
      m_R.push_back(145*mm);
      m_Theta.push_back(90*deg);
      m_Phi.push_back(157.5*deg);
      m_BetaX.push_back(0);
      m_BetaY.push_back(0);
      m_BetaZ.push_back(180*deg);
    }
    
    else if(CloverId[i] == 9 ){
      m_CloverId.push_back(CloverId[i]);
      m_R.push_back(145*mm);
      m_Theta.push_back(90*deg);
      m_Phi.push_back(202.5*deg);
      m_BetaX.push_back(0);
      m_BetaY.push_back(0);
      m_BetaZ.push_back(180*deg);
    }
    
    else if(CloverId[i] == 10 ){
      m_CloverId.push_back(CloverId[i]);
      m_R.push_back(145*mm);
      m_Theta.push_back(90*deg);
      m_Phi.push_back(247.5*deg);
      m_BetaX.push_back(0);
      m_BetaY.push_back(0);
      m_BetaZ.push_back(180*deg);
    }
    
    else if(CloverId[i] == 11 ){
      m_CloverId.push_back(CloverId[i]);
      m_R.push_back(145*mm);
      m_Theta.push_back(90*deg);
      m_Phi.push_back(292.5*deg);
      m_BetaX.push_back(0);
      m_BetaY.push_back(0);
      m_BetaZ.push_back(180*deg);
    }
    
    else if(CloverId[i] == 12 ){
      m_CloverId.push_back(CloverId[i]);
      m_R.push_back(145*mm);
      m_Theta.push_back(90*deg);
      m_Phi.push_back(337.5*deg);
      m_BetaX.push_back(0);
      m_BetaY.push_back(0);
      m_BetaZ.push_back(180*deg);
    }
    
    else if(CloverId[i] == 13 ){
      m_CloverId.push_back(CloverId[i]);
      m_R.push_back(145*mm);
      m_Theta.push_back(135*deg);
      m_Phi.push_back(22.5*deg);
      m_BetaX.push_back(0);
      m_BetaY.push_back(0);
      m_BetaZ.push_back(180*deg);
    }
    
    else if(CloverId[i] == 14 ){
      m_CloverId.push_back(CloverId[i]);
      m_R.push_back(145*mm);
      m_Theta.push_back(135*deg);
      m_Phi.push_back(112.5*deg);
      m_BetaX.push_back(0);
      m_BetaY.push_back(0);
      m_BetaZ.push_back(180*deg);
    }
    
    else if(CloverId[i] == 15 ){
      m_CloverId.push_back(CloverId[i]);
      m_R.push_back(145*mm);
      m_Theta.push_back(135*deg);
      m_Phi.push_back(202.5*deg);
      m_BetaX.push_back(0);
      m_BetaY.push_back(0);
      m_BetaZ.push_back(180*deg);
    }
    
    else if(CloverId[i] == 16 ){
      m_CloverId.push_back(CloverId[i]);
      m_R.push_back(145*mm);
      m_Theta.push_back(135*deg);
      m_Phi.push_back(292.5*deg);
      m_BetaX.push_back(0);
      m_BetaY.push_back(0);
      m_BetaZ.push_back(180*deg);
    }
  }

}

//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
// Add clover at a free position in space with coordinate
// in spherical coordinate
// Beta are the three angles of rotation in the Clover frame
void Tigress::AddCloverFreePosition(int CloverId,double R,double Theta,double Phi,double BetaX,double BetaY,double BetaZ){
  
  m_CloverId.push_back(CloverId);
  m_R.push_back(R);
  m_Theta.push_back(Theta);
  m_Phi.push_back(Phi);
  m_BetaX.push_back(BetaX);
  m_BetaY.push_back(BetaY);
  m_BetaZ.push_back(BetaZ);
  
}

//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
// Add Detector branch to the EventTree.
// Called After DetecorConstruction::AddDetector Method
void Tigress::InitializeRootOutput(){
  RootOutput *pAnalysis = RootOutput::getInstance();
  TTree *pTree = pAnalysis->GetTree();
  pTree->Branch("Tigress", "TTigressData", &m_Event) ;
}

//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
// Read sensitive part and fill the Root tree.
// Called at in the EventAction::EndOfEventAvtion
void Tigress::ReadSensitive(const G4Event* event){
  /*m_Event->Clear();
  
  ///////////
  // BOX
  G4THitsMap<G4double*>*     BOXHitMap;
  std::map<G4int, G4double**>::iterator    BOX_itr;
  
  G4int BOXCollectionID = G4SDManager::GetSDMpointer()->GetCollectionID("Tigress_BOXScorer/TigressBOX");
  BOXHitMap = (G4THitsMap<G4double*>*)(event->GetHCofThisEvent()->GetHC(BOXCollectionID));
  
  // Loop on the BOX map
  for (BOX_itr = BOXHitMap->GetMap()->begin() ; BOX_itr != BOXHitMap->GetMap()->end() ; BOX_itr++){
    
    G4double* Info = *(BOX_itr->second);
    
    double Energy =  Info[0];
    double Time  = Info[1];
    int DetNbr =     (int) Info[2];
    int StripFront = (int) Info[3];
    int StripBack =  (int) Info[4];
    
    m_Event->SetFront_DetectorNbr(DetNbr);
    m_Event->SetFront_StripNbr(StripFront);
    m_Event->SetFront_Energy(RandGauss::shoot(Energy, ResoEnergy));
    m_Event->SetFront_TimeCFD(RandGauss::shoot(Time, ResoTime));
    m_Event->SetFront_TimeLED(RandGauss::shoot(Time, ResoTime));
    
    m_Event->SetBack_DetectorNbr(DetNbr);
    m_Event->SetBack_StripNbr(StripBack);
    m_Event->SetBack_Energy(RandGauss::shoot(Energy, ResoEnergy));
    m_Event->SetBack_TimeCFD(RandGauss::shoot(Time, ResoTime));
    m_Event->SetBack_TimeLED(RandGauss::shoot(Time, ResoTime));
    
    
    // Interraction Coordinates
    ms_InterCoord->SetDetectedPositionX(Info[5]) ;
    ms_InterCoord->SetDetectedPositionY(Info[6]) ;
    ms_InterCoord->SetDetectedPositionZ(Info[7]) ;
    ms_InterCoord->SetDetectedAngleTheta(Info[8]/deg) ;
    ms_InterCoord->SetDetectedAnglePhi(Info[9]/deg) ;
    
  }
  
  // clear map for next event
  BOXHitMap->clear();
  
  ///////////
  // PAD
  G4THitsMap<G4double*>*     PADHitMap;
  std::map<G4int, G4double**>::iterator    PAD_itr;
  
  G4int PADCollectionID = G4SDManager::GetSDMpointer()->GetCollectionID("Tigress_PADScorer/TigressPAD");
  PADHitMap = (G4THitsMap<G4double*>*)(event->GetHCofThisEvent()->GetHC(PADCollectionID));
  
  // Loop on the BOX map
  for (PAD_itr = PADHitMap->GetMap()->begin() ; PAD_itr != PADHitMap->GetMap()->end() ; PAD_itr++){
    
    G4double* Info = *(PAD_itr->second);
    
    double Energy =  Info[0];
    double Time  = Info[1];
    int DetNbr =     (int) Info[2];
    
    m_Event->SetPAD_DetectorNbr(DetNbr);
    m_Event->SetPAD_Energy(RandGauss::shoot(Energy, ResoEnergy));
    m_Event->SetPAD_TimeCFD(RandGauss::shoot(Time, ResoTime));
    m_Event->SetPAD_TimeLED(RandGauss::shoot(Time, ResoTime));

  }
  
  // clear map for next event
  PADHitMap->clear();
  
  ///////////
  // QQQ
  G4THitsMap<G4double*>*     QQQHitMap;
  std::map<G4int, G4double**>::iterator    QQQ_itr;
  
  G4int QQQCollectionID = G4SDManager::GetSDMpointer()->GetCollectionID("Tigress_QQQScorer/TigressQQQ");
  QQQHitMap = (G4THitsMap<G4double*>*)(event->GetHCofThisEvent()->GetHC(QQQCollectionID));
  
  // Loop on the BOX map
  for (QQQ_itr = QQQHitMap->GetMap()->begin() ; QQQ_itr != QQQHitMap->GetMap()->end() ; QQQ_itr++){
    
    G4double* Info = *(QQQ_itr->second);
    
    double Energy =  Info[0];
    double Time  = Info[1];
    int DetNbr =     (int) Info[2];
    int StripFront = (int) Info[3];
    int StripBack =  (int) Info[4];
    
    m_Event->SetFront_DetectorNbr(DetNbr);
    m_Event->SetFront_StripNbr(StripFront);
    m_Event->SetFront_Energy(RandGauss::shoot(Energy, ResoEnergy));
    m_Event->SetFront_TimeCFD(RandGauss::shoot(Time, ResoTime));
    m_Event->SetFront_TimeLED(RandGauss::shoot(Time, ResoTime));
    
    m_Event->SetBack_DetectorNbr(DetNbr);
    m_Event->SetBack_StripNbr(StripBack);
    m_Event->SetBack_Energy(RandGauss::shoot(Energy, ResoEnergy));
    m_Event->SetBack_TimeCFD(RandGauss::shoot(Time, ResoTime));
    m_Event->SetBack_TimeLED(RandGauss::shoot(Time, ResoTime));
    
    // Interraction Coordinates
    ms_InterCoord->SetDetectedPositionX(Info[5]) ;
    ms_InterCoord->SetDetectedPositionY(Info[6]) ;
    ms_InterCoord->SetDetectedPositionZ(Info[7]) ;
    ms_InterCoord->SetDetectedAngleTheta(Info[8]/deg) ;
    ms_InterCoord->SetDetectedAnglePhi(Info[9]/deg) ;
    
  }
  
  // clear map for next event
  QQQHitMap->clear();
  */
}

//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
void Tigress::InitializeScorers(){
  /*
  //   Silicon Associate Scorer
  m_BOXScorer = new G4MultiFunctionalDetector("Tigress_BOXScorer");
  m_PADScorer = new G4MultiFunctionalDetector("Tigress_PADScorer");
  m_QQQScorer = new G4MultiFunctionalDetector("Tigress_QQQScorer");
  
  G4VPrimitiveScorer* BOXScorer =
  new  Tigress::PS_Silicon_Rectangle("TigressBOX",
                                   BOX_Wafer_Length,
                                   BOX_Wafer_Width,
                                   BOX_Wafer_Back_NumberOfStrip ,
                                   BOX_Wafer_Front_NumberOfStrip,
                                   EnergyThreshold);
  
  G4VPrimitiveScorer* PADScorer =
  new  Tigress::PS_Silicon_Rectangle("TigressPAD",
                                   PAD_Wafer_Length,
                                   PAD_Wafer_Width,
                                   1 ,
                                   1,
                                   EnergyThreshold);
  
  G4VPrimitiveScorer* QQQScorer =
  new  Tigress::PS_Silicon_Annular("TigressQQQ",
                                 QQQ_Wafer_Inner_Radius,
                                 QQQ_Wafer_Outer_Radius,
                                 QQQ_Wafer_Stopping_Phi-QQQ_Wafer_Starting_Phi,
                                 QQQ_Wafer_NumberOf_RadialStrip,
                                 QQQ_Wafer_NumberOf_AnnularStrip,
                                 EnergyThreshold);
  
  
  
  //and register it to the multifunctionnal detector
  m_BOXScorer->RegisterPrimitive(BOXScorer);
  m_PADScorer->RegisterPrimitive(PADScorer);
  m_QQQScorer->RegisterPrimitive(QQQScorer);
  
  //   Add All Scorer to the Global Scorer Manager
  G4SDManager::GetSDMpointer()->AddNewDetector(m_BOXScorer) ;
  G4SDManager::GetSDMpointer()->AddNewDetector(m_PADScorer) ;
  G4SDManager::GetSDMpointer()->AddNewDetector(m_QQQScorer) ;*/
}

//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
////////////////////////////////////////////////////////////////
/////////////////Material Definition ///////////////////////////
////////////////////////////////////////////////////////////////
void Tigress::InitializeMaterial(){
  G4Element* H   = new G4Element("Hydrogen" , "H"  , 1  , 1.015  * g / mole);
  G4Element* C   = new G4Element("Carbon"   , "C"  , 6  , 12.011 * g / mole);
  G4Element* N   = new G4Element("Nitrogen" , "N"  , 7  , 14.01  * g / mole);
  G4Element* O   = new G4Element("Oxygen"   , "O"  , 8  , 15.99  * g / mole);
  
  G4double a, z, density;
  // Si
  a = 28.0855 * g / mole;
  density = 2.321 * g / cm3;
  m_MaterialSilicon = new G4Material("Si", z = 14., a, density);
  
  // Al
  density = 2.702 * g / cm3;
  a = 26.98 * g / mole;
  m_MaterialAl = new G4Material("Al", z = 13., a, density);
  
  // PCB (should be FR-4, I took Epoxy Molded from LISE++)
  density = 1.85 * g / cm3;
  m_MaterialPCB = new G4Material("PCB", density, 3);
  m_MaterialPCB->AddElement(H, .475);
  m_MaterialPCB->AddElement(C, .45);
  m_MaterialPCB->AddElement(O, .075);
  //  Vacuum
  density = 0.000000001 * mg / cm3;
  m_MaterialVacuum = new G4Material("Vacuum", density, 2);
  m_MaterialVacuum->AddElement(N, .7);
  m_MaterialVacuum->AddElement(O, .3);
}