| Classes | Job Modules | Data Objects | Services | Algorithms | Tools | Packages | Directories | Tracs |

In This Package:

GtMuoneratorTool.cc

Go to the documentation of this file.
00001 /* Generate cosmic-muons in a GenTool
00002  *   
00003  *   Brett Viren
00004  *   Wed May  5 16:47:41 2010
00005  *
00006  *   Disclaimer: this refactors the app from Generators/Muon into a
00007  *   tool. The essentials themselves is unchanged.
00008  */
00009 
00010 #include "GtMuoneratorTool.h"
00011 
00012 #include "GaudiKernel/IRndmGenSvc.h"
00013 
00014 #include "CLHEP/Units/SystemOfUnits.h"
00015 #include "CLHEP/Units/PhysicalConstants.h"
00016 
00017 #include "HepMC/GenEvent.h"
00018 #include "HepMC/GenVertex.h"
00019 
00020 #include "TH1F.h"
00021 #include "TFile.h"
00022 
00023 #include <fstream>
00024 #include <cassert>
00025 
00026 using namespace std;
00027 using namespace CLHEP;
00028 
00029 GtMuoneratorTool::GtMuoneratorTool(const std::string& type,
00030                                    const std::string& name, 
00031                                    const IInterface* parent)
00032     : GaudiTool(type,name,parent)
00033     , m_pmratio(0)
00034     , m_Sx(0), m_Sy(0), m_Sz(0), m_Smax(0)
00035     , m_dphi(0)
00036 {
00037     declareInterface<IHepMCEventMutator>(this);
00038 
00039     declareProperty("WhichSite",m_whichSite="",
00040                     "Which site (DYB, LA, Mid, Far,SAB)");
00041     declareProperty("Rotation",m_rotation=false,
00042                     "Set to true to assume rotation for the given site");
00043     declareProperty("MuonFile",m_muonFileName="",
00044                     "Name of file giving muons to sample");
00045     declareProperty("RatioFile",m_ratioFileName="",
00046                     "Name of file giving mu+/mu- ratio histogram");
00047     declareProperty("Volume",m_volume="rock",
00048                     "Volume name (rock, RPC, ADE)");
00049     info() << "Creating GtMuoneratorTool(\"" << type << "\", \"" << name << "\")" << endreq;
00050 }
00051 
00052 
00053 GtMuoneratorTool::~GtMuoneratorTool()
00054 {
00055     info() << "Destroying GtMuoneratorTool site=" << m_whichSite
00056            << " MuonFile=" << m_muonFileName
00057            << " RatioFile=" << m_ratioFileName
00058            << " Volume=" << m_volume
00059            << endreq;
00060 }
00061 
00062 StatusCode GtMuoneratorTool::initialize()
00063 {
00064     // Set up random numbers
00065     m_rgs = 0;
00066     if (service("RndmGenSvc",m_rgs,true).isFailure()) {
00067         fatal() << "Failed to get random service" << endreq;
00068         return StatusCode::FAILURE;        
00069     }
00070     if (m_uni.initialize(m_rgs, Rndm::Flat(0,1)).isFailure()) {
00071         fatal() << "Failed to initialize uniform random numbers" << endreq;
00072         return StatusCode::FAILURE;
00073     }
00074 
00075     // leak this file
00076     TFile* file = new TFile(m_ratioFileName.c_str(),"read");
00077     if (file->IsZombie()) {
00078         warning() << "Failed to open ROOT file \"" << m_ratioFileName << "\""
00079                   << " will fall back to parametrized ratio"
00080                   << endreq;
00081     }
00082     else {
00083         m_pmratio = (TH1F*)file->Get("mu_plus_minus_ratio");
00084 
00085         if (!m_pmratio) {
00086             error() << "Failed to get \"mu_plus_minus_ratio\" TH1F from ROOT file "
00087                     << m_ratioFileName << endreq;
00088             return StatusCode::FAILURE;
00089         }
00090     }
00091 
00092     return ReadMuons();
00093 }
00094 
00095 static int GetMuPlusMinusRatioParam(double momInGeV)
00096 {
00097     Double_t par[2]={0.5505,0.6745};
00098     Double_t part1=par[0]/(1+(1.1*momInGeV+1)/115);
00099     Double_t part2=0.054*par[1]/(1+(1.1*momInGeV+1)/850);
00100     Double_t part3=(1-par[0])/(1+(1.1*momInGeV-1)/115);
00101     Double_t part4=0.054*(1-par[1])/(1+(1.1*momInGeV-1)/850);
00102     return (part1+part2)/(part3+part4);
00103 }
00104 
00105 double GtMuoneratorTool::GetMuPlusMinusRatio(double momInGeV)
00106 {
00107     if (!m_pmratio) return GetMuPlusMinusRatioParam(momInGeV);
00108 
00109     int binno = m_pmratio->FindBin(momInGeV);
00110     //return the measured value if within range. otherwise return 1.4
00111     if(binno>=1&&binno<=m_pmratio->GetNbinsX()) 
00112         return m_pmratio->GetBinContent(binno);
00113     return 1.4;
00114 }
00115 
00116 int GtMuoneratorTool::GetPIDFromMomentum(double momInGeV)
00117 {
00118     double ratio = GetMuPlusMinusRatio(momInGeV);
00119     double prob_mu_plus = ratio/(1.+ratio);
00120     //int number = gRandom->Binomial(1, prob_mu_plus);
00121     Rndm::Numbers bi;
00122     if (bi.initialize(m_rgs, Rndm::Binomial(1,prob_mu_plus)).isFailure()) {
00123         fatal() << "Failed to initialize uniform random numbers" << endreq;
00124         return StatusCode::FAILURE;
00125     }
00126     int number = bi();
00127     if (number==0) return 13; //mu-
00128     return -13;//mu+
00129 }
00130 
00131 StatusCode GtMuoneratorTool::ReadMuons()
00132 {
00133     // djaffe 7mar07. (Corrected 12mar07. x-,y-dimensions were swapped.)
00134     // set dimensions and detector center based on CD1 release (doc-765,762,720)
00135     // for DYB, LA, Far and default site
00136     Double_t height_RPC = 0.50*CLHEP::m ; // RPCs are nominally 50cm above  surface of shield volume (includes 20cm of air above water)
00137     Double_t thick_RPC  = 0.056*CLHEP::m + 0.030*CLHEP::m ; // 1.4cm/layer*4layers + 1cm spacing*3spaces between layers
00138     Double_t overlap_RPC= 1.0*CLHEP::m  ; // nominal 1m overlap of RPC with rock around pool
00139     Double_t extra      = 0.05*CLHEP::m ; // 5cm extra space to make sure muons start outside of all active volumes
00140     Double_t width_near = 10.0*CLHEP::m ; // width of near pool
00141     Double_t width_far  = 16.0*CLHEP::m ; // width of far pool
00142     Double_t length     = 16.0*CLHEP::m ; // length of near and far pool
00143     Double_t depth      = 10.0*CLHEP::m ; // depth of near and far pool
00144     Double_t air_thick  =  0.2*CLHEP::m ; // 20cm of air above water
00145     Double_t height_hall= 15.0*CLHEP::m ; // 15m of air above water, from water surface to hall ceiling
00146     Double_t top_rock_extra = 2*CLHEP::m; // 2m of rock above hall ceiling
00147     Double_t side_rock_extra= 4*CLHEP::m; // this will make sure at least there is 2m rock of hall wall
00148     // for pool 4m of rock
00149     Double_t bottom_rock_extra = 2*CLHEP::m; // 2m of rock under the pool
00150 
00151     Double_t yDim ;  // depends on near,far
00152     Double_t xDim ;  // same for near,far
00153     Double_t zDim; // box height
00154     // the origin (0,0,0) is always at the center of water pool
00155     Double_t zOffset; // center of the volume
00156 
00157     // stainless steel
00158     // <!-- Radius for SST -->
00159     Double_t ADsstRadius=2500*CLHEP::mm;
00160     // <!-- Height for SST -->
00161     Double_t ADsstHeight=5000*CLHEP::mm;
00162     // AD envelop size
00163     // <!-- ADE extention beyond SST in radius -->
00164     Double_t ADadeWall=1.0*CLHEP::cm; // 0.25*m;
00165     // <!-- ADE head gap above tank -->
00166     Double_t ADadeHead=1.0*CLHEP::cm; // 1.0*m;
00167     // <!-- ADE foot gap below tank -->
00168     Double_t ADadeFoot=1.0*CLHEP::cm;
00169     // <!-- ADE radius -->
00170     Double_t ADadeRadius=ADsstRadius+ADadeWall;
00171     // <!-- ADE height -->
00172     Double_t ADadeHeight=ADadeFoot+ADsstHeight+ADadeHead;
00173 
00174     if (m_volume == "rock") {    
00175         //Z
00176         zDim=depth + height_hall + top_rock_extra + bottom_rock_extra;  // same for near, far;
00177         // the origin (0,0,0) is always at the center of water pool
00178         zOffset=(height_hall + top_rock_extra - bottom_rock_extra)/2;   // vertical offset of the certer of z
00179         //X
00180         xDim = length + 2.*overlap_RPC + 2.*side_rock_extra; // same for near,far
00181         //Y
00182         if (m_whichSite == "DYB" || m_whichSite == "LA") {
00183             yDim=width_near + 2.*overlap_RPC + 2.*side_rock_extra;
00184         }
00185         else if (m_whichSite == "Far") {
00186             yDim=width_far + 2.*overlap_RPC + 2.*side_rock_extra;
00187         }
00188         else {
00189             // fixme: error - unknown site
00190         }
00191     } 
00192     else if (m_volume == "RPC") {
00193         //Z 
00194         zDim=height_RPC + thick_RPC + depth + extra + air_thick;  // same for near,far
00195         // the origin (0,0,0) is always at the center of water pool
00196         zOffset=(height_RPC + thick_RPC + extra + air_thick)/2. ; // vertical offset of center of 'detector'
00197         //X
00198         xDim = length + 2.*overlap_RPC + 2.*extra;
00199         //Y
00200         if (m_whichSite == "DYB" || m_whichSite == "LA") {
00201             yDim=width_near + 2.*overlap_RPC + 2.*extra;
00202         }
00203         else if (m_whichSite == "Far") {
00204             yDim=width_far + 2.*overlap_RPC + 2.*extra;
00205         }
00206         else {
00207             // fixme: error - unknown site
00208         }
00209     }
00210     else if (m_volume == "ADE") {
00211         // Z
00212         zDim=ADadeHeight;
00213         // the origin (0,0,0) is always at the center of AD
00214         zOffset=0;
00215         // X
00216         xDim= 2*ADadeRadius;
00217         // Y
00218         yDim=xDim;
00219     }
00220     else {
00221         cout<<"muon_generator: *** ERROR *** Invalid volume " << m_volume
00222             << " selected. Valid volume names are rock, RPC and ADE"<<endl;
00223         assert(0); // this will end the job
00224     }
00225 
00226     Double_t dphi=0;           // detector angle.
00227 
00228 
00229     // get the right detector setting and the right muon flux file 
00230     ifstream infile;
00231     infile.open(m_muonFileName.c_str(), ios_base::in);
00232     if (!infile.is_open()) {
00233         error() << "Failed to open muon flux file \"" << m_muonFileName << "\"" 
00234                 << endreq;
00235         return StatusCode::FAILURE;
00236     }
00237     debug() << "Opened file \"" << m_muonFileName << "\"" << endreq;
00238 
00239     if(m_whichSite == "DYB") {
00240         m_detectorDim = Hep3Vector(xDim, yDim, zDim);
00241         m_detectorCenter = Hep3Vector(0, 0, zOffset );
00242         if(m_rotation) {
00243             dphi = 56.7*degree;
00244         }
00245     }
00246     else if(m_whichSite == "CDR") {
00247         m_detectorDim = Hep3Vector(16.06*CLHEP::m, 10.06*CLHEP::m, 10.0*CLHEP::m );
00248         m_detectorCenter = Hep3Vector(0, 0, -5*CLHEP::m );
00249         dphi = 0; 
00250     }
00251     else if(m_whichSite == "LA") {
00252         m_detectorDim = Hep3Vector(xDim, yDim, zDim);
00253         m_detectorCenter = Hep3Vector(0, 0, zOffset );
00254         if(m_rotation) {
00255             dphi = 79.6*degree;
00256         }
00257     }
00258     else if(m_whichSite == "Mid") {
00259         error()<<" No implemented yet. "<<endl; 
00260         return StatusCode::FAILURE;
00261     }
00262     else if(m_whichSite == "Far") {
00263         m_detectorDim = Hep3Vector(xDim, yDim, zDim);
00264         m_detectorCenter = Hep3Vector(0, 0, zOffset );
00265         if(m_rotation) {
00266             dphi = 60.5*degree;
00267         }
00268     }
00269     else if(m_whichSite == "SAB") {
00270         m_detectorDim = Hep3Vector(5.2*CLHEP::m, 5.2*CLHEP::m, 5.2*CLHEP::m );
00271         m_detectorCenter = Hep3Vector(0, 0, 0 );
00272         dphi = 0; 
00273     }
00274     else {
00275         // 23mar07 djaffe If no valid site name, then STOP
00276         error() <<"muon_generator: *** ERROR *** Invalid site " << m_whichSite
00277                 << " selected. Valid site names are Far, Mid, DYB, LA, CDR,SAB"<<endreq;
00278         return StatusCode::FAILURE;
00279     }
00280 
00281     // Calculate size of sides to generate on for later.
00282 
00283     // the detector geometry 
00284     Double_t dimx=0, dimy=0, dimz=0; 
00285     Double_t xdet=0, ydet=0, zdet=0; 
00286   
00287     dimx = m_detectorDim.x()/CLHEP::m; 
00288     dimy = m_detectorDim.y()/CLHEP::m; 
00289     dimz = m_detectorDim.z()/CLHEP::m;
00290     xdet = m_detectorCenter.x()/CLHEP::m; 
00291     ydet = m_detectorCenter.y()/CLHEP::m; 
00292     zdet = m_detectorCenter.z()/CLHEP::m; 
00293     cout<<"The detector dimension is: "
00294         <<dimx<<"*m, "<<dimy<<"*m, "<<dimz<<"*m"<<endl;
00295     cout<<"The detector center is: "
00296         <<xdet<<"*m, "<<ydet<<"*m, "<<zdet<<"*m"<<endl; 
00297     cout<<"The detector angle is: "<<dphi<<endl;
00298     cout<<"MAKE SURE the setting is consistent with Geant4 setting!!!"<<endl;
00299 
00300     m_Sz = dimx * dimy;
00301     m_Sx = dimy * dimz;
00302     m_Sy = dimx * dimz;
00303     m_Smax = sqrt(m_Sx*m_Sx + m_Sy*m_Sy + m_Sz*m_Sz);
00304     m_dphi = dphi;
00305     
00306     // read in muons
00307 
00308     //temporary variable to hold data in flux file.
00309     Double_t energy, phi, theta, energy0, phi0, theta0;  
00310   
00311     Double_t flux_of_site;
00312     // line 1 to line 6 are comments
00313     char tmp[255];
00314     for (int lineNo=0; lineNo<4; lineNo++) {      
00315         infile.getline(tmp, 255);      
00316     }
00317     // line 5 contains flux info of that site.
00318     infile.getline(tmp,255,':');
00319     infile>>flux_of_site;
00320     infile.getline(tmp,255);
00321     // line 6
00322     infile.getline(tmp,255);
00323 
00324     while (!infile.eof()) {
00325         infile>>energy>>theta>>phi>>energy0>>theta0>>phi0;   
00326         m_muonE.push_back(energy*CLHEP::GeV);
00327         m_muonPhi.push_back(phi);
00328         m_muonTheta.push_back(theta);
00329         verbose() << "Loading muon E=" << energy*CLHEP::GeV 
00330                   << " phi=" << phi
00331                   << " theta=" << theta 
00332                   << endreq;
00333     }
00334 
00335     m_muonE.pop_back();
00336     m_muonPhi.pop_back();
00337     m_muonTheta.pop_back();
00338 
00339     return StatusCode::SUCCESS;
00340 
00341 } // ReadMuons()
00342 
00343 
00344 StatusCode GtMuoneratorTool::finalize()
00345 {
00346     return StatusCode::SUCCESS;
00347 }
00348 
00349 StatusCode GtMuoneratorTool::mutate(HepMC::GenEvent& event)
00350 {
00351     double pS_z=0, pS_x=0, pS_y=0; // projected area in x, y, z direction.
00352     const double PI = 3.1415926;
00353     Hep3Vector direction;          // the muon direction.
00354     double muon_mass = 0.105658*CLHEP::GeV;
00355     double weight = 1.;
00356     double arandom=0;
00357     int ievent = 0;
00358   
00359     do {             // pick a muon       
00360         ievent = (int)(m_uni() * (m_muonE.size()-1));
00361         debug() << "Pick muon " << ievent << " out of " << m_muonE.size() << endreq;
00362 
00363         // convert coordinates from MUSIC system to digimap system.
00364         double theta = PI - PI * m_muonTheta[ievent]/180;
00365         double phi = PI/2 -PI * m_muonPhi[ievent]/180;
00366         if (phi < 0) phi = phi + 2 * PI;
00367 
00368         // The WC detector may be rotated an angle to better shield
00369         // neutrons, It is convenient to rotate muon direction instead
00370         // of rotating detector in Geant4
00371         phi = phi + m_dphi;
00372         if(phi > 2 * PI) phi = phi - 2 * PI;
00373         direction.setX(sin(theta) * cos(phi));
00374         direction.setY(sin(theta) * sin(phi));
00375         direction.setZ(cos(theta));
00376     
00377         // projected area of the WE surface to this muon.
00378         pS_z = m_Sz * abs(direction.z()); 
00379         pS_x = m_Sx * abs(direction.x()); 
00380         pS_y = m_Sy * abs(direction.y());
00381 
00382         weight = ( pS_z + pS_x + pS_y )/m_Smax; 
00383         arandom = m_uni();
00384     } while ( arandom > weight ); // drop this muon.
00385     
00386     // calculate the muon momentum and position.
00387     
00388     double eMuon = m_muonE[ievent];
00389     double pMuon = sqrt(eMuon*eMuon - muon_mass*muon_mass);
00390     Hep3Vector momentum;
00391     momentum.setX(pMuon * direction.x());
00392     momentum.setY(pMuon * direction.y());
00393     momentum.setZ(pMuon * direction.z());
00394 
00395     Hep3Vector position;
00396     // muon hits the top panel.
00397     if( arandom < pS_z/m_Smax) {
00398         position.setX(m_detectorCenter.x() +
00399                       (m_uni()-0.5) * m_detectorDim.x()); 
00400         position.setY(m_detectorCenter.y() +
00401                       (m_uni()-0.5) * m_detectorDim.y()); 
00402         position.setZ(m_detectorCenter.z() + 0.5 * m_detectorDim.z());
00403 
00404     } 
00405     // muon hits the X panel.
00406     else if( arandom < (pS_z + pS_x)/m_Smax) {
00407         position.setY( m_detectorCenter.y() +
00408                        (m_uni()-0.5) * m_detectorDim.y() ); 
00409         position.setZ( m_detectorCenter.z() +
00410                        (m_uni()-0.5) * m_detectorDim.z() ); 
00411         if (direction.x() > 0)
00412             position.setX( m_detectorCenter.x() - 0.5 * m_detectorDim.x() );
00413         if (direction.x() < 0)
00414             position.setX( m_detectorCenter.x() + 0.5 * m_detectorDim.x() );
00415     } 
00416     // muon hits the Y panel.
00417     else if( arandom < weight) {
00418         position.setX( m_detectorCenter.x() +
00419                        (m_uni()-0.5) * m_detectorDim.x() ); 
00420         position.setZ( m_detectorCenter.z() +
00421                        (m_uni()-0.5) * m_detectorDim.z() ); 
00422         if (direction.y() > 0)
00423             position.setY( m_detectorCenter.y() - 0.5 * m_detectorDim.y() );
00424         if (direction.y() < 0)
00425             position.setY( m_detectorCenter.y() + 0.5 * m_detectorDim.y() );
00426     }
00427 
00428 
00429     int pid = GetPIDFromMomentum(momentum.mag()/CLHEP::GeV);
00430 
00431     HepMC::GenVertex* vertex = new HepMC::GenVertex(HepMC::FourVector(position.x(), 
00432                                                                       position.y(), 
00433                                                                       position.z(), 0));
00434 
00435     HepMC::FourVector fourmom(momentum.x(), momentum.y(), momentum.z(), eMuon);
00436 
00437     debug() << "momentum.mag()=" << momentum.mag()/CLHEP::GeV << " GeV/c "
00438             << "pMuon=" << pMuon/CLHEP::GeV << " GeV/c "
00439             << "eMuon=" << eMuon/CLHEP::GeV << " GeV "
00440             << "muon_mass=" << muon_mass/CLHEP::MeV << " MeV/c^2 "
00441             << "sqrt(e^2-p^2)=" << sqrt(eMuon*eMuon-pMuon*pMuon)
00442             << endreq;
00443 
00444     HepMC::GenParticle* particle = new HepMC::GenParticle(fourmom,pid,1/*=status*/);
00445     particle->set_generated_mass(muon_mass);
00446 
00447     vertex->add_particle_out(particle);
00448     event.set_signal_process_vertex(vertex);
00449 
00450     return StatusCode::SUCCESS;
00451 }
00452 
| Classes | Job Modules | Data Objects | Services | Algorithms | Tools | Packages | Directories | Tracs |

Generated on Mon Apr 11 21:00:45 2011 for GenMuon by doxygen 1.4.7