Skip to content
Snippets Groups Projects
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
GeneratorAnalysis.cpp 32.95 KiB
// $Id: GeneratorAnalysis.cpp,v 1.8 2010-02-24 19:02:33 robbep Exp $
// Include files 

// from Gaudi
#include "GaudiKernel/DeclareFactoryEntries.h"
#include "GaudiKernel/SystemOfUnits.h"

// From HepMC
#include "Event/HepMCEvent.h"
#include "HepMC/GenEvent.h"
#include "HepMC/GenParticle.h"

// From LHCb
#include "Kernel/ParticleID.h"

// local
#include "GeneratorAnalysis.h"
#include "GaussGenUtil.h"

//-----------------------------------------------------------------------------
// Implementation file for class : GeneratorAnalysis
//
// 2007-01-28 : P.Szczypka
// 2007-02-16 : G.Corti, clean up of code
//-----------------------------------------------------------------------------

// Declaration of the Algorithm Factory
DECLARE_ALGORITHM_FACTORY( GeneratorAnalysis );


//=============================================================================
// Standard constructor, initializes variables
//=============================================================================
GeneratorAnalysis::GeneratorAnalysis( const std::string& name,
                              ISvcLocator* pSvcLocator)
  : GaudiHistoAlg( name , pSvcLocator )
  , m_counter          ( 0 )
  , m_counterStable    ( 0 )
  , m_counterCharged   ( 0 )
  , m_counterChInEta   ( 0 )
  , m_nEvents          ( 0 )
  , m_nAllChargedStable( 0 )
  , m_nNeutralStable   ( 0 )
  , m_nChargedStable   ( 0 )
  , m_nAllParticles    ( 0 )
  , m_nBHistos         ( 0 )
  , m_nS0L0J0          ( 0 )
  , m_nS1L1J0          ( 0 )
  , m_nS1L0J1          ( 0 )
  , m_nS0L1J1          ( 0 )
  , m_nS1L1J1          ( 0 )
  , m_nS1L1J2          ( 0 )
  , m_stateB           ( 0 )
  , m_stateBStar       ( 0 )
  , m_stateBStarStar   ( 0 )
  , m_nMesonType       ( 0 )
  , m_nBdMeson         ( 0 )
  , m_nBuMeson         ( 0 )
  , m_nBsMeson         ( 0 )
  , m_nBcMeson         ( 0 )
  , m_nBbMeson         ( 0 )
  , m_nBBaryon         ( 0 )
  , m_nTbMeson         ( 0 )
  , m_nBParticles      ( 0 )
  , m_nParticles       ( 0 )
{

  declareProperty( "MinEta", m_minEta = 2.0);
  declareProperty( "MaxEta", m_maxEta = 4.9);
  declareProperty( "Input",  m_dataPath = LHCb::HepMCEventLocation::Default );
  declareProperty( "ApplyTo", m_generatorName = "" );
  
  // Set by default not to fill histograms for neutral particles
  declareProperty( "NeutralParticleHistos", m_neutralHistos = false );

}

//=============================================================================
// Destructor
//=============================================================================
GeneratorAnalysis::~GeneratorAnalysis() {}; 

//=============================================================================
// Initialisation. Check parameters
//=============================================================================
StatusCode GeneratorAnalysis::initialize() {

  StatusCode sc = GaudiHistoAlg::initialize(); // must be executed first
  if ( sc.isFailure() ) return sc;  // error printed already by GaudiHistoAlg

  debug() << "==> Initialize" << endmsg;
  
  if ( m_generatorName.empty() ) {
    info() << "Monitor will be applied to all events in container " 
           << m_dataPath << endmsg;
  } else {
    info() << "Monitor will be applied to events produced with generator "
           << m_generatorName << " in container "
           << m_dataPath << endmsg; 
  }

  if( produceHistos() ) {
    bookHistos(m_neutralHistos);
  }
  
  return StatusCode::SUCCESS;
};

//=============================================================================
// Main execution
//=============================================================================
StatusCode GeneratorAnalysis::execute() {

  debug() << "==> Execute" << endmsg;

  // Initialize counters
  int nPileUp(0);
  int nParticles(0), nStable(0), nProtoStable(0);
  int nChargedStable(0), nChargedStableAcceptance(0), nNeutralStableAcceptance(0);
  
  //Initalize particle variables
  double ptmax_det(0.), emax_det(0.), pmax_det(0.);
  double pmax_fr(0.),emax_fr(0.),ptmax_fr(0.);
  double pmax_neut(0.),emax_neut(0.),ptmax_neut(0.);

  // Retrieve data from selected path
  SmartDataPtr< LHCb::HepMCEvents > hepMCptr( eventSvc() , m_dataPath );

  if( 0 == hepMCptr ) {
    info() << "No HepMCEvents at location " << m_dataPath << endmsg;
  } else {
    LHCb::HepMCEvents::iterator it ;
    for( it = hepMCptr->begin() ; it != hepMCptr->end(); ++it ) {

      // Check if monitor has to be applied to this event
      if( !m_generatorName.empty() ) {
        if( m_generatorName != (*it)->generatorName() ) {
          continue;
        }
      }
      debug() << "Monitor for " << (*it)->generatorName()
              << endmsg;
      
      for( HepMC::GenEvent::vertex_const_iterator pVertex = 
             (*it)->pGenEvt()->vertices_begin();
           pVertex != (*it)->pGenEvt()->vertices_end();
           pVertex++ ) {
        for( HepMC::GenVertex::particles_out_const_iterator pParticle =
               ( *pVertex )->particles_out_const_begin( );
             ( *pVertex )->particles_out_const_end( ) != pParticle;
             ++pParticle ) {   

          //Get Mother Particle ID
          LHCb::ParticleID m_mPID(0);
          if( (*pParticle)->production_vertex() ) {
            
            m_mPID.setPid( (*(*pParticle)->production_vertex()
                            -> particles_in_const_begin())->pdg_id() );
          }
          
          //Get current Particle ID
          LHCb::ParticleID m_dPID((*pParticle) -> pdg_id ( ));
          
          // Fill b hadron histos
          bHadronInfo(m_mPID,m_dPID);
        }
      }

      // Plot process type 
      if( produceHistos() ) {
        m_hProcess->fill( (*it)->pGenEvt()->signal_process_id() );
      }

      bool primFound = false;
      nPileUp++;
      for( HepMC::GenEvent::particle_const_iterator 
             itp = (*it)->pGenEvt()->particles_begin();
           itp != (*it)->pGenEvt()->particles_end(); itp++ ) {
        HepMC::GenParticle* hepMCpart = *itp;
        nParticles++ ;
        // Identify primary vertex and fill histograms
        if( !primFound ) {
          if( (hepMCpart->status() == 1) || (hepMCpart->status() == 888 ) ) {
            primFound = true;
            if( produceHistos() ) { 
              if ( hepMCpart -> production_vertex() ) {
                m_hPrimX->fill( hepMCpart->production_vertex()->position().x()/
                                Gaudi::Units::mm );
                m_hPrimY->fill( hepMCpart->production_vertex()->position().y()/
                                Gaudi::Units::mm );
                m_hPrimZ->fill( hepMCpart->production_vertex()->position().z()/
                                Gaudi::Units::mm );
                m_hPrimZZ->fill( hepMCpart->production_vertex()->position().z()/
                                 Gaudi::Units::mm );
              }
            }
            
          }
        }
        
        //Particle properties:
        double pseudoRap =  hepMCpart->momentum().pseudoRapidity();
        double energy = hepMCpart->momentum().e()/Gaudi::Units::GeV;
        double pt = hepMCpart->momentum().perp()/Gaudi::Units::GeV;
        double p =  hepMCpart->momentum().rho()/Gaudi::Units::GeV;
        int pID = hepMCpart->pdg_id();
        LHCb::ParticleID LHCb_pID( hepMCpart->pdg_id() );

        if(produceHistos()){
          m_hAllParticlesPRap->fill( pseudoRap );
          m_hAllParticlesEnergy->fill( energy );
          m_hAllParticlesP->fill( p );
          m_hAllParticlesPt->fill( pt );
          m_hAllParticlesPID->fill( pID );
          m_hPartP->fill( p );
          m_hPartPDG->fill( pID );
          //Why are these histo's here? Throwback from the original code...?
        }
        // Note that the following is really multiplicity of particle defined
        // as stable by Pythia just after hadronization: all particles known by
        // EvtGen are defined stable for Pythia (it will count rho and pi0  
        // and gamma all togheter as stable ...
        if( ( hepMCpart->status() != 2 ) && ( hepMCpart->status() != 3 ) ) {
          nProtoStable++;
          if( produceHistos() ) {
            m_hProtoP->fill( p );
            m_hProtoPDG->fill( pID );
            m_hProtoLTime->fill( GaussGenUtil::lifetime( hepMCpart )/
                                 Gaudi::Units::mm);
          }

          // A stable particle does not have an outgoing vertex
          if( !hepMCpart->end_vertex() ) {
            // should be the same as the following  
            //             if ( ( hepMCpart -> status() == 999 )  
            nStable++;
            if( 0 != int(LHCb_pID.threeCharge()) ) {
              nChargedStable++;
              if( produceHistos() ){
                m_hAllChargedStableP -> fill ( p );
                m_hAllChargedStablePt -> fill ( pt );
                m_hAllChargedStableEnergy -> fill ( energy );
                m_hAllChargedStablePRap -> fill ( pseudoRap );
                m_hAllChargedStablePID -> fill ( pID );
              }
              //Set maximum values              
              if(pt > ptmax_fr)  ptmax_fr = pt;
              //Max energy limited to overlook initial energy transfer
              if((energy > emax_fr) && (energy < 7000.)) emax_fr = energy;
              if(p > pmax_fr) pmax_fr = p;

              // in LHCb acceptance
              if( (pseudoRap > m_minEta) && (pseudoRap < m_maxEta) ) {
                //Within acceptance
                nChargedStableAcceptance++;
                if(p > pmax_det) pmax_det = p;
                if(pt > ptmax_det) ptmax_det = pt;
                if(energy > emax_det) emax_det = energy;
                if(produceHistos()){
                  m_hChargedStableP -> fill( p );
                  m_hChargedStablePt -> fill( pt );
                  m_hChargedStableEnergy -> fill( energy );
                  m_hChargedStablePRap -> fill( pseudoRap );
                  m_hChargedStablePID -> fill( pID );
                }
              }
            }else{
              if( (pseudoRap > m_minEta) && (pseudoRap < m_maxEta) ) {
                //Neutral and Stable within Acceptance
                nNeutralStableAcceptance++;
                if(pt > ptmax_neut) ptmax_neut = pt;
                if(p > pmax_neut) pmax_neut = p;
                if(energy > emax_neut) emax_neut = energy;             
                if(produceHistos() && m_neutralHistos ){
                  m_hNeutralStablePt->fill( pt );
                  m_hNeutralStableP->fill( p );
                  m_hNeutralStableEnergy->fill( energy ); 
                  m_hNeutralStablePID -> fill( pID );
                  m_hNeutralStablePRap -> fill( pseudoRap );
                }                  
              }
            }
            if( produceHistos() ) {
              m_hStableEta->fill( pseudoRap );
              m_hStablePt->fill( pt );
            }
          }
        }
      }
    }
  }
  if( produceHistos() ) {
    //All Particles
    m_hAllParticlesMult->fill(nParticles);

    //All Charged Stable PArticles
    m_hAllChargedStablePMax -> fill ( pmax_fr );
    m_hAllChargedStablePtMax -> fill( ptmax_fr );
    m_hAllChargedStableEnergyMax -> fill ( emax_fr );
    m_hAllChargedStableMult -> fill ( nChargedStable );

    //Charged Stable within EtaMin and Max
    m_hChargedStablePMax -> fill ( pmax_det );
    m_hChargedStablePtMax -> fill ( ptmax_det );
    m_hChargedStableEnergyMax -> fill ( emax_det );
    m_hChargedStableMult -> fill ( nChargedStableAcceptance );

    //Neutral Stable within EtaMin and Max
    if( m_neutralHistos ) {
      m_hNeutralStablePMax -> fill ( pmax_neut );
      m_hNeutralStablePtMax -> fill ( ptmax_neut );
      m_hNeutralStableEnergyMax -> fill ( emax_neut );
      m_hNeutralStableMult->fill ( nNeutralStableAcceptance );
    }
    
    //WHat are these histograms? Gloria?
    m_hNPart->fill( nParticles );
    m_hNStable->fill( nStable );
    m_hNSCharg->fill( nChargedStable );
    m_hNSChEta->fill( nChargedStableAcceptance );
    m_hNPileUp->fill( nPileUp );
  }
  m_counter += nParticles ;
  m_counterStable += nStable ;
  m_counterCharged += nChargedStable;
  m_counterChInEta += nChargedStableAcceptance;
  m_nEvents++ ;
  
  return StatusCode::SUCCESS;
};

//=============================================================================
//  Finalize
//=============================================================================
StatusCode GeneratorAnalysis::finalize() {

  debug() << "==> Finalize" << endmsg;
  if(produceHistos()) {
    normHistos();
  }

  // Number of B Meson states should be = totalBHadrons
  int totalBHadrons(m_nBdMeson + m_nBuMeson + m_nBsMeson
                    + m_nBcMeson + m_nBbMeson + m_nTbMeson + m_nBBaryon);
  int totalBMesonStates(m_stateB + m_stateBStar + m_stateBStarStar);

  //Set total states to avoid dividing by zero:
  if( !totalBHadrons ) totalBHadrons = 1;
  if( !totalBMesonStates ) totalBMesonStates = 1;
  info() << std::endl
         << "======================== B Hadron Statistics ===================" 
         << std::endl
         << "* B Hadron production counters                                 *" 
         << std::endl
         << "* Bd meson : " << m_nBdMeson
         << " [fraction : " << fraction( m_nBdMeson , totalBHadrons )
         << " +/- " << err_fraction( m_nBdMeson , totalBHadrons ) << " ]" 
         << std::endl
    
         << "* Bu meson : " << m_nBuMeson
         << " [fraction : " << fraction( m_nBuMeson , totalBHadrons )
         << " +/- " << err_fraction( m_nBuMeson , totalBHadrons ) << " ]" 
         << std::endl
    
         << "* Bs meson : " << m_nBsMeson
         << " [fraction : " << fraction( m_nBsMeson , totalBHadrons )
         << " +/- " << err_fraction( m_nBsMeson , totalBHadrons ) << " ]" 
         << std::endl
    
         << "* Bc meson : " << m_nBcMeson
         << " [fraction : " << fraction( m_nBcMeson , totalBHadrons )
         << " +/- " << err_fraction( m_nBcMeson , totalBHadrons ) << " ]" 
         << std::endl
    
         << "* Bb meson : " << m_nBbMeson
         << " [fraction : " << fraction( m_nBbMeson , totalBHadrons )
         << " +/- " << err_fraction( m_nBbMeson , totalBHadrons ) << " ]" 
         << std::endl
    
         << "* T  meson : " << m_nTbMeson
         << " [fraction : " << fraction( m_nTbMeson , totalBHadrons )
         << " +/- " << err_fraction( m_nTbMeson , totalBHadrons ) << " ]" 
         << std::endl
    
         << "* B Baryon : " << m_nBBaryon
         << " [fraction : " << fraction( m_nBBaryon , totalBHadrons )
         << " +/- " << err_fraction( m_nBBaryon , totalBHadrons ) << " ]" 
         << std::endl
    
         << "* Total    : " << totalBHadrons
         << " [fraction : " << fraction( totalBHadrons , totalBHadrons )
         << " +/- " << err_fraction( totalBHadrons , totalBHadrons ) << " ]" 
         << std::endl

         << "*                                                              *" 
         << std::endl
         
         << "* B Meson production state:                                    *" 
         << std::endl
         << "* Number of B   (L=0, J=0)     : " << m_stateB
         << " [fraction : " << fraction( m_stateB , totalBMesonStates )
         << " +/- " << err_fraction( m_stateB , totalBMesonStates ) <<" ]" 
         << std::endl
    
         << "* Number of B*  (L=0, J=1)     : " << m_stateBStar 
         << " [fraction : "  << fraction( m_stateBStar , totalBMesonStates)
         << " +/- " << err_fraction( m_stateBStar , totalBMesonStates ) <<" ]" 
         << std::endl
    
         << "* Number of B** (L=1, J=0,1,2) : " << m_stateBStarStar
         << " [fraction : " << fraction ( m_stateBStarStar , totalBMesonStates )
         << " +/- " << err_fraction( m_stateBStarStar , totalBMesonStates ) 
         <<" ]" << std::endl
    
         << "* Total         : " << totalBMesonStates
         << " [fraction : " << fraction ( totalBMesonStates , totalBMesonStates )
         << " +/- " << err_fraction( totalBMesonStates , totalBMesonStates ) 
         <<" ]" << std::endl
    
         << "*                                                              *" 
         << std::endl
    
         << "* B Meson Angular Momentum States:                             *" 
         << std::endl
         << "* S L J" << std::endl

         << "* 0 0 0 : " << m_nS0L0J0
         << " [fraction : " << fraction( m_nS0L0J0 , totalBMesonStates )
         << " +/- " << err_fraction( m_nS0L0J0 , totalBMesonStates ) <<" ]" 
         << std::endl

         << "* 1 1 0 : " << m_nS1L1J0
         << " [fraction : " << fraction( m_nS1L1J0 , totalBMesonStates )
         << " +/- " << err_fraction( m_nS1L1J0 , totalBMesonStates ) <<" ]" 
         << std::endl

         << "* 1 0 1 : " << m_nS1L0J1
         << " [fraction : " << fraction( m_nS1L0J1 , totalBMesonStates )
         << " +/- " << err_fraction( m_nS1L0J1 , totalBMesonStates ) <<" ]" 
         << std::endl

         << "* 0 1 1 : " << m_nS0L1J1
         << " [fraction : " << fraction( m_nS0L1J1 , totalBMesonStates )
         << " +/- " << err_fraction( m_nS0L1J1 , totalBMesonStates ) <<" ]" 
         << std::endl

         << "* 1 1 1 : " << m_nS1L1J1
         << " [fraction : " << fraction( m_nS1L1J1 , totalBMesonStates )
         << " +/- " << err_fraction( m_nS1L1J1 , totalBMesonStates ) <<" ]" 
         << std::endl

         << "* 1 1 2 : " << m_nS1L1J2
         << " [fraction : " << fraction( m_nS1L1J2 , totalBMesonStates )
         << " +/- " << err_fraction( m_nS1L1J2 , totalBMesonStates ) <<" ]" 
         << std::endl

         << "* Total : " << totalBMesonStates
         << " [fraction : " << fraction( totalBMesonStates , totalBMesonStates )
         << " +/- " << err_fraction( totalBMesonStates , totalBMesonStates ) 
         << " ]" <<std::endl
         << endmsg;
   
  info() << std::endl 
         << "======================== Generators Statistics ====================" 
         << std::endl
         << "=                                                                 ="
         << std::endl 
         << "= Number of particles generated: " << m_counter 
         << " m_nAllParticles = " << m_nAllParticles 
         << std::endl
         << std::endl 
         << "= Number of events: " << m_nEvents
         << std::endl
         << "= Mean multiplicity: " << m_counter / ( double ) m_nEvents
         << std::endl 
         << "=                                                                 ="
         << std::endl 
         << "= Number of pseudo stable particles generated: " << m_counterStable
         << std::endl 
         << "= Number of events: " << m_nEvents
         << std::endl
         << "= Mean pseudo stable multiplicity: " 
         << m_counterStable / ( double ) m_nEvents
         << std::endl 
         << "=                                                                 ="
         << std::endl 
         << "= Number of charged stable particles generated: " << m_counterCharged
         << std::endl 
         << "= Number of events: " << m_nEvents
         << std::endl
         << "= Mean charged stable multiplicity: " 
         << m_counterCharged / ( double ) m_nEvents
         << std::endl 
         << "=                                                                 ="
         << std::endl 
         << "= Number of charged stable particles in LHCb eta " << m_counterChInEta
         << std::endl 
         << "= Number of events: " << m_nEvents
         << std::endl
         << "= Mean charged stable multiplicity in LHCb eta: " 
         << m_counterChInEta / ( double ) m_nEvents
         << std::endl 
         << "=                                                                 ="
         << std::endl 
         << "==================================================================="
         << endmsg;

  return GaudiHistoAlg::finalize();
  
}

//============================================================================
// Booking of histograms
//============================================================================
void GeneratorAnalysis::bookHistos(bool neutral) 
{

  debug() << "==> Book histograms" << endmsg;
 
  int i(0);

  //
  debug() << "Booking B Hadron Histos" << endmsg;
  m_bMesonFraction = book(1000,"B Hadron Production Fractions",-0.,7.,7);
  m_pHisto.push_back( m_bMesonFraction );

  i++;
  m_nBHistos++;
  m_bMesonStates = book(1001,"B Meson Production Spin State",-0.,3.,3);
  m_pHisto.push_back( m_bMesonStates );

  i++;
  m_nBHistos++;
  m_bMesonStatesCode = book(1002,"B Meson Production Spin State Code",-0.,6.,6);
  m_pHisto.push_back( m_bMesonStatesCode );


  //General Histograms
  debug() << "Booking General Histograms." << endmsg;
  i++;
  m_hNPileUp = book( 150, "Num. of primary interaction per bunch", -0.5, 10.5, 11 );
  m_pHisto.push_back( m_hNPileUp );
  i++;
  m_hPrimX   = book( 101, "PrimaryVertex x (mm)", -0.5, 0.5, 100 );
  m_pHisto.push_back( m_hPrimX );
  i++;
  m_hPrimY   = book( 102, "PrimaryVertex y (mm)", -0.5, 0.5, 100 );
  m_pHisto.push_back( m_hPrimY );
  i++;
  m_hPrimZ   = book( 103, "PrimaryVertex z (mm)", -200., 200., 100 ); 
  m_pHisto.push_back( m_hPrimZ );
  i++;
  m_hPrimZZ  = book( 104, "PrimaryVertex z, all Velo (mm)", -1000., 1000., 100 );
  m_pHisto.push_back( m_hPrimZZ );
  i++;
  m_hNPart   = book(  105, "Multiplicity all particles", 0., 3000., 150 );
  m_pHisto.push_back( m_hNPart );
  i++;
  m_hNStable = book(  106, "Multiplicity protostable particles", 0., 3000., 75 );
  m_pHisto.push_back( m_hNStable );
  i++;
  m_hNSCharg = book(  107, "Multiplicity stable charged particles", 0., 500., 100 );
  m_pHisto.push_back( m_hNSCharg );
  i++;
  m_hNSChEta = 
    book(  108, "Multiplicity stable charged particles in LHCb eta", 0., 150., 75 );
  m_pHisto.push_back( m_hNSChEta );
  i++;
  m_hProcess = book(  109, "Process type", -0.5, 5100.5, 5101);
  m_pHisto.push_back( m_hProcess );
  i++;
  m_hPartP   = book( 120, "Momentum of all particles (GeV)", 0., 100., 100 );
  m_pHisto.push_back( m_hPartP );
  i++;
  m_hPartPDG = book( 121, "PDGid of all particles", -5000., 5000., 10000 );
  m_pHisto.push_back( m_hPartPDG );
  i++;
  m_hProtoP  = book( 130, "Momentum of protostable particles (GeV)", 0., 100., 100);
  m_pHisto.push_back( m_hProtoP );
  i++;
  m_hProtoPDG = book( 131, "PDGid of protostable particles", -5000., 5000., 10000 );
  m_pHisto.push_back( m_hProtoPDG );
  i++;
  m_hProtoLTime = 
    book( 132, "Lifetime protostable particles (mm)", -1., 20., 105 );
  m_pHisto.push_back( m_hProtoLTime );
  i++;
  m_hStableEta = 
    book( 133, "Pseudorapidity stable charged particles", -15., 15., 150 );
  m_pHisto.push_back( m_hStableEta );
  i++;
  m_hStablePt  = book( 140, "Pt stable charged particles (GeV)", 0., 5., 50 );
  m_pHisto.push_back(  m_hStablePt );


  // All Charged Stable Particle Histo's
  debug() << "Booking Histograms for all Charged Stable particles" << endmsg;
  i++;
  m_hAllChargedStableMult= 
    book(201,"All Eta: Charged Stable Multiplicity", 0., 500., 100);
  m_pHisto.push_back( m_hAllChargedStableMult );
  
  i++;
  m_hAllChargedStablePRap= 
    book(202,"All Eta: Charged Stable PseudoRapidity", -15., 15., 150);
  m_pHisto.push_back( m_hAllChargedStablePRap );
  
  i++;
  m_hAllChargedStableEnergy= 
    book(203,"All Eta: Charged Stable Energy (GeV)", 0., 100., 100);
  m_pHisto.push_back( m_hAllChargedStableEnergy );
  
  i++;
  m_hAllChargedStableEnergyMax= 
    book(204,"All Eta: Charged Stable Maximum Energy (GeV)", 0., 5000., 50);
  m_pHisto.push_back( m_hAllChargedStableEnergyMax );
  
  i++;
  m_hAllChargedStableP= 
    book(205,"All Eta: Charged Stable Momentum (GeV)", -0., 150., 150);
  m_pHisto.push_back( m_hAllChargedStableP );
  
  i++;
  m_hAllChargedStablePMax= 
    book(206,"All Eta: Charged Stable Maximum Momentum (GeV)", 0., 5000., 50);
  m_pHisto.push_back( m_hAllChargedStablePMax );
  
  i++;
  m_hAllChargedStablePt= 
    book(207,"All Eta: Charged Stable Transverse Momentum (GeV)", -0., 5., 250);
  m_pHisto.push_back( m_hAllChargedStablePt );
  
  i++;
  m_hAllChargedStablePtMax= 
    book(208,"All Eta: Charged Stable Maximum Transverse Momentum (GeV)",
         0., 10., 20);
  m_pHisto.push_back( m_hAllChargedStablePtMax );
  
  i++;
  m_hAllChargedStablePID = 
    book(209, "All Eta: Charged Stable particles PID", -5000., 5000., 10000);
  m_pHisto.push_back( m_hAllChargedStablePID );



  //Histograms for charged stable particles within the LHCb acceptance
  debug() << "Booking Histograms for Charged stable particles in the LHCb acceptance"
          << endmsg;
  i++;
  m_hChargedStableMult= 
    book(301,"Charged Stable Multiplicity in Detector", 0., 150., 30);
  m_pHisto.push_back( m_hChargedStableMult );
  
  //Histogram has 10 bins per rapidity unit 
  i++;
  m_hChargedStablePRap= 
    book(302,"Charged Stable PseudoRapidity in Detector", m_minEta, m_maxEta,
         int((m_maxEta - m_minEta)*10.) );
  m_pHisto.push_back( m_hChargedStablePRap );
  
  i++;
  m_hChargedStableEnergy= 
    book(303,"Charged Stable Energy in Detector (GeV)",0., 100., 100);
  m_pHisto.push_back( m_hChargedStableEnergy );
  
  i++;
  m_hChargedStableEnergyMax= 
    book(304,"Charged Stable Maximum Energy in Detector (GeV)", 0., 300., 75);
  m_pHisto.push_back( m_hChargedStableEnergyMax );
  
  i++;
  m_hChargedStableP= 
    book(305,"Charged Stable Momentum in Detector (GeV)", -0., 300., 150);
  m_pHisto.push_back( m_hChargedStableP );
  
  i++;
  m_hChargedStablePMax= 
    book(306,"Charged Stable Maximum Momentum in Detector (GeV)", 0., 300., 75);
  m_pHisto.push_back( m_hChargedStablePMax );
  
  i++;
  m_hChargedStablePt= 
    book(307,"Charged Stable Transverse Momentum in Detector (GeV)", -0., 5., 125);
  m_pHisto.push_back( m_hChargedStablePt );
  
  i++;
  m_hChargedStablePtMax= 
    book(308,"Charged Stable Maximum Transverse Momentum in Detector (GeV)",
         0., 10., 50);
  m_pHisto.push_back( m_hChargedStablePtMax );
  
  i++;
  m_hChargedStablePID = 
    book(309, "Charged Stable particles PID", -5000., 5000., 10000);
  m_pHisto.push_back( m_hChargedStablePID );
  
  
  
  //Histograms for all particles
  debug() << "Booking Histos for All Particles" << endmsg;
  i++;
  m_hAllParticlesMult= 
    book(401,"All Eta: Particle Multiplicity", 0., 2000., 200);
  m_pHisto.push_back( m_hAllParticlesMult );

  i++;
  m_hAllParticlesPRap= 
    book(402,"All Eta: Particle PseudoRapidity", -15., 15., 150);
  m_pHisto.push_back( m_hAllParticlesPRap );
  
  i++;
  m_hAllParticlesEnergy= 
    book(403,"All Eta: Particle Energy (GeV)", 0., 100., 100);
  m_pHisto.push_back( m_hAllParticlesEnergy );
  
  i++;
  m_hAllParticlesP= 
    book(404,"All Eta: Particle Momentum (GeV)", -0., 300., 300);
  m_pHisto.push_back( m_hAllParticlesP );
  
  i++;
  m_hAllParticlesPt= 
    book(405,"All Eta: Particle Transverse Momentum (GeV)", -0., 5., 125);
  m_pHisto.push_back( m_hAllParticlesPt );
  
  i++;
  m_hAllParticlesPID = 
    book(406, "All Eta: Particle particles PID", -5000., 5000., 10000);
  m_pHisto.push_back( m_hAllParticlesPID );
  
  
  // Histograms for neutral particles  
  if(neutral) {
    debug() << "Booking Histos for neutral particles in the LHCb acceptance" 
            << endmsg;
    i++;
    m_hNeutralStableMult= 
      book(501,"Neutral Stable Multiplicity in Detector", 0., 200., 100);
    m_pHisto.push_back( m_hNeutralStableMult );

    i++;
    m_hNeutralStablePRap= 
      book(502,"Neutral Stable PseudoRapidity in Detector", m_minEta, m_maxEta,
           int((m_maxEta - m_minEta)*10.) );
    m_pHisto.push_back( m_hNeutralStablePRap );

    i++;
    m_hNeutralStableEnergy= 
      book(503,"Neutral Stable Energy in Detector (GeV)", 0., 100., 100);
    m_pHisto.push_back( m_hNeutralStableEnergy );

    i++;
    m_hNeutralStableEnergyMax= 
      book(504,"Neutral Stable Maximum Energy in Detector (GeV)", 0., 200., 100);
    m_pHisto.push_back( m_hNeutralStableEnergyMax );

    i++;
    m_hNeutralStableP= 
      book(505,"Neutral Stable Momentum in Detector (GeV)", -0., 150., 75);
    m_pHisto.push_back( m_hNeutralStableP );

    i++;
    m_hNeutralStablePMax= 
      book(506,"Maximum Neutral Stable Momentum in Detector (GeV)", 0., 300., 150);
    m_pHisto.push_back( m_hNeutralStablePMax );

    i++;
    m_hNeutralStablePt= 
      book(507,"Neutral Stable Transverse Momentum in Detector (GeV)", -0., 5., 250);
    m_pHisto.push_back( m_hNeutralStablePt );

    i++;
    m_hNeutralStablePtMax= 
      book(508,"Neutral Stable Maximum Transverse Momentum in Detector (GeV)",
           0., 10., 50);
    m_pHisto.push_back( m_hNeutralStablePtMax );

    i++;
    m_hNeutralStablePID = 
      book(509, "Neutral Stable Particles PID", -5000., 5000., 10000);
    m_pHisto.push_back( m_hNeutralStablePID );
  }
  

  debug() << "Booked " << i+1 << " Histograms." << endmsg;
  
  return;
  
}

//============================================================================
//  Normalize Histograms
//============================================================================
void GeneratorAnalysis::normHistos() 
{
  debug() << "==> Normalize histograms" << endmsg;

  double binSize = 0;
  int i = -1;
  for( std::vector<AIDA::IHistogram1D*>::iterator iHisto = m_pHisto.begin();
       m_pHisto.end() != iHisto; ++iHisto ) {
    
    ++i;
    AIDA::IHistogram1D* pHisto = (*iHisto);
    if( (pHisto)->axis().isFixedBinning() ){ 
      binSize = ( pHisto->axis().upperEdge() - pHisto->axis().lowerEdge() ) /
        ( pHisto->axis().bins() );
      
      debug() << "Currently normalizing histo #: "<< i << " : " 
              << pHisto->title() << endmsg;    
      debug() << "nBins = " <<  pHisto->axis().bins()
              << ", Bins Width = " << pHisto->axis().binWidth(0)
              << ", Top range = " <<  pHisto->axis().upperEdge()
              << ", Lower Range = " << pHisto->axis().lowerEdge() << endmsg;
      if( (double)m_nEvents*binSize ){
        if( i <= m_nBHistos ){
          debug() << "Scale factor = " 
                  << 1./( (double)m_nMesonType*binSize) << endmsg;
          pHisto->scale(1./( (double)m_nMesonType*binSize ));            
        }else{
          debug() << "Scale factor = " 
                  << 1./( (double)m_nEvents*binSize) << endmsg;
          pHisto->scale(1./( (double)m_nEvents*binSize ));
        }
      }else{
        warning() << "Scale factor = 0, unable to normalise histo!" << endmsg;
      }
    } else {
      warning() << "Histo: " <<  pHisto->title() 
                << " not normalised (no fixed binSize)." << endmsg;
    }
  }
  
  return;
}

//============================================================================
// Obtain B Meson production information and fill histograms
//============================================================================
void GeneratorAnalysis::bHadronInfo( LHCb::ParticleID m_mPID, 
                                 LHCb::ParticleID m_dPID )
{
    if ( m_dPID.abspid() == 5 ) return ;
    if ( ! ( m_mPID.hasBottom() && m_mPID.abspid()!=5) ) {
    if(m_dPID.hasBottom()){
      m_nBParticles++;
      //Set default B Hadron Type
      bHadronType type = BdMeson;
      bool valid = false ;
      if(m_dPID.isMeson()){
        //Daughter has bottom and is a meson
        if(m_dPID.hasDown()){
          m_nBdMeson++;
          type = BdMeson;  
          valid = true ;        
        }else if(m_dPID.hasUp()){
          m_nBuMeson++;
          type = BuMeson;        
          valid = true ;
        }else if(m_dPID.hasStrange()){
          m_nBsMeson++;
          type = BsMeson;
          valid = true ;
        }else if(m_dPID.hasCharm()){
          m_nBcMeson++;
          type = BcMeson;
          valid = true ;
        }else if(m_dPID.hasTop()){
          m_nTbMeson++;            
          type = TbMeson;
          valid = true ;
        }else{
          m_nBbMeson++;
          type = BbMeson;
          valid = true ;
        }  
      } else if(m_dPID.isBaryon()){
        //Daughter is a B baryon
        type = BBaryon;
        valid = true ;
        if(    !( (m_mPID.isBaryon()) && (m_mPID.hasBottom()) )   ){
          //Mother not a BBaryon
          m_nBBaryon++;  
        }
      }
      if ( ! valid ) 
        warning() << "Unknown B code " << m_dPID << endreq ;
      if( produceHistos() )
       if ( valid ) m_bMesonFraction->fill((double)( (int) type ) - 0.1 );
    }
    
    //Set default meson spin state
    spinState spin = S0L0J0;
    if(m_dPID.isMeson() && m_dPID.hasBottom()){
      m_nMesonType++;
      if(5 == m_dPID.jSpin()){
        spin = S1L1J2;
        m_nS1L1J2++;
      }else if(3 == m_dPID.jSpin()){
        if(1 == m_dPID.lSpin()){
          if(1 == m_dPID.sSpin()){
            spin = S1L1J1;
            m_nS1L1J1++;
          }else if(0 == m_dPID.sSpin()){
            spin = S0L1J1;
            m_nS0L1J1++;
          }
        }else if(0 == m_dPID.lSpin()){
          spin = S1L0J1;    
          m_nS1L0J1++;
        }
      }else if(1 == m_dPID.jSpin()){
        if(1 == m_dPID.lSpin()){
          spin = S1L1J0;        
          m_nS1L1J0++;
        }else if(0 == m_dPID.lSpin()){
          spin = S0L0J0;        
          m_nS0L0J0++;
        }
      }

      //mind that B** is L=1 state, B* is L=0 and J=1, and B is L=0, J=0
      if(S0L0J0==spin){
        m_stateB++;
      }else if(S1L0J1==spin) {
        m_stateBStar++;   
      }else{
        m_stateBStarStar++;
      }

      if( produceHistos() ) {
        int state = 2; //L=1 state
        if (S0L0J0==spin) state = 0;
        else if (S1L0J1==spin) state = 1;
        m_bMesonStates->fill((double)state);
      }
      if( produceHistos() ) m_bMesonStatesCode->fill((double)spin);
    }
    }
}