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

In This Package:

GtDiffuserBallTool.cc

Go to the documentation of this file.
00001 #include "GtDiffuserBallTool.h"
00002 
00003 #include "GaudiKernel/IRndmGenSvc.h"
00004 #include "GaudiKernel/IParticlePropertySvc.h"
00005 #include "GaudiKernel/ParticleProperty.h"
00006 #include "GaudiKernel/Vector3DTypes.h"
00007 #include "GaudiKernel/PhysicalConstants.h"
00008 #include "HepMC/GenEvent.h"
00009 #include "HepMC/GenParticle.h"
00010 #include "HepMC/GenVertex.h"
00011 
00012 #include "CLHEP/Units/SystemOfUnits.h"
00013 #include "CLHEP/Units/PhysicalConstants.h"
00014 #include "CLHEP/Vector/ThreeVector.h"
00015 
00016 #include "DetHelpers/IPositionerTool.h"
00017 
00018 using namespace CLHEP;
00019 
00020 GtDiffuserBallTool::GtDiffuserBallTool(const std::string& type,
00021                                        const std::string& name, 
00022                                        const IInterface* parent) 
00023   :GaudiTool(type,name,parent)
00024 {
00025   // Initialization
00026   m_pid = 0;
00027   m_pdfWave.clear();   m_pdfWave.push_back(1);
00028   m_edgesWave.clear(); m_edgesWave.push_back(429*nm); m_edgesWave.push_back(431*nm);
00029   m_pdfTime.clear();   m_pdfTime.push_back(1);
00030   m_edgesTime.clear(); m_edgesTime.push_back(0*ns);   m_edgesTime.push_back(1*ns);
00031 
00032   declareInterface<IHepMCEventMutator>(this);
00033   declareProperty("PhotonsPerEvent",m_particlesPerEvent=3500,"Number of photons per event");
00034   declareProperty("PhotonsPerEventMode",m_particlesPerEventMode="Fixed","Type of distribution of number of photons per event");
00035   declareProperty("PhotonsPerEventSpread",m_particlesPerEventSpread=0,"Sigma/FWHM of number of photons per event");
00036 
00037   declareProperty("WavelengthMode",m_wavelengthMode="Fixed","Wavelength Mode");
00038   declareProperty("Wavelength", m_wavelength=430.0*nm,"Fixed (Mean) Photon Wavelength");
00039   declareProperty("WavelengthSpread",m_wavelengthSpread=5.0*nm,"Wavelength Spectrum Spread");
00040   declareProperty("PdfWave",m_pdfWave,"User-Defined PDF for Wavelength Spectrum");
00041   declareProperty("PdfEdgesWave",m_edgesWave,"Bin Edges of PdfWave");
00042 
00043   declareProperty("TimingMode",m_timingMode="Instant","Timing Mode");
00044   declareProperty("PdfTime",m_pdfTime,"User-Defined PDF for Timing Distribution");
00045   declareProperty("PdfEdgesTime",m_edgesTime,"Bin Edges of PdfTime"); 
00046 
00047   declareProperty("Radius",m_radius=0.9525*cm,"Radius of Diffuser Ball");
00048   declareProperty("Anisotropy",m_anisotropy=true,"Turn on/off anisotropy");
00049   declareProperty("BrightSpotTheta",m_bright_theta=0.0,"Polar angle of bright spot");
00050   declareProperty("BrightSpotPhi",m_bright_phi=0.0,"Azimuthal angle of bright spot");
00051   declareProperty("PhotonScaleWeight",m_photonScaleWeight = 3.74,
00052                   "Reweight photons based on maximum quantum efficiency");
00053   declareProperty("GeomPosTool",m_geomPosToolName="diffuserBallGeomPos",
00054           "Name of tool used to dynamically place the diffuser ball geometry");
00055 
00056 }
00057 
00058 GtDiffuserBallTool::~GtDiffuserBallTool() 
00059 {
00060 }
00061 
00062 StatusCode GtDiffuserBallTool::initialize() 
00063 {
00064   // Particle identification
00065   IParticlePropertySvc * ppSvc = 
00066     svc< IParticlePropertySvc >( "ParticlePropertySvc" , true ) ;
00067   ParticleProperty* particle = 0;
00068 
00069   m_particleName = "opticalphoton";
00070   particle = ppSvc->find(m_particleName);
00071   if(particle) {
00072     m_pid = particle->pdgID();
00073   }
00074 
00075   // if failed to find particle, return failure
00076   if (!particle) {
00077     fatal() << "Failed to find particle named \"" 
00078             << m_particleName << "\" and with ID " 
00079             << m_pid << endreq;
00080     return StatusCode::FAILURE;
00081   }
00082 
00083   // check modes
00084   if ((m_timingMode != "Instant") && (m_timingMode != "Defined")) {
00085     fatal() << "Not a recognized vertex timing distribution mode" << endreq;
00086     return StatusCode::FAILURE;
00087   }
00088   if ((m_wavelengthMode != "Fixed")   && (m_wavelengthMode != "Uniform") &&
00089       (m_wavelengthMode != "Smeared") && (m_wavelengthMode != "Defined")) {
00090     fatal() << "Not a recognized wavelength spectrum mode" << endreq;
00091     return StatusCode::FAILURE;
00092   }
00093 
00094   // Random number service
00095   IRndmGenSvc *rgs = 0;
00096   if (service("RndmGenSvc",rgs,true).isFailure()) {
00097     fatal() << "Failed to get random service" << endreq;
00098     return StatusCode::FAILURE;        
00099   }
00100   
00101   StatusCode sc;
00102   sc = m_uni.initialize(rgs, Rndm::Flat(0,1));
00103   if (sc.isFailure()) {
00104     fatal() << "Failed to initialize uniform random numbers" << endreq;
00105     return StatusCode::FAILURE;
00106   }
00107 
00108   // random numbers for particle number
00109   if (m_particlesPerEventMode == "Gaus") {
00110     sc = m_randPartNo.initialize(rgs, Rndm::Gauss(0,1));
00111     if (sc.isFailure()) {
00112       fatal() << "Failed to initialize random numbers for particle number distribution" << endreq;
00113       return StatusCode::FAILURE;
00114     }
00115   }
00116   else if (m_particlesPerEventMode == "Lorentz"){
00117     sc = m_randPartNo.initialize(rgs, Rndm::BreitWigner(0,1));
00118     if (sc.isFailure()) {
00119       fatal() << "Failed to initialize random numbers for particle number distribution" << endreq;
00120       return StatusCode::FAILURE;
00121     }
00122   }
00123   
00124   // random numbers for timing
00125   if (m_timingMode == "Defined") {
00126     sc = m_randTime.initialize(rgs, Rndm::DefinedPdf(m_pdfTime,0));
00127     if (sc.isFailure()) {
00128       fatal() << "Failed to initialize random numbers for timing distribution" << endreq;
00129       return StatusCode::FAILURE;
00130     }
00131   }
00132   
00133   // random numbers for wavelength spectrum
00134   if (m_wavelengthMode == "Uniform") {
00135     sc = m_randWave.initialize(rgs, Rndm::Flat(0,1));
00136     if (sc.isFailure()) {
00137       fatal() << "Failed to initialize random numbers for wavelength spectrum" << endreq;
00138       return StatusCode::FAILURE;
00139     }
00140   }
00141   else if (m_wavelengthMode == "Smeared") {
00142     sc = m_randWave.initialize(rgs, Rndm::Gauss(0,1));
00143     if (sc.isFailure()) {
00144       fatal() << "Failed to initialize random numbers for wavelength spectrum" << endreq;
00145       return StatusCode::FAILURE;
00146     }
00147   }
00148   else if (m_wavelengthMode == "Defined") {
00149     sc = m_randWave.initialize(rgs, Rndm::DefinedPdf(m_pdfWave,0));
00150     if (sc.isFailure()) {
00151       fatal() << "Failed to initialize random numbers for wavelength spectrum" << endreq;
00152       return StatusCode::FAILURE;
00153     }
00154   }
00155 
00156   // check user input for user-defined PDFs
00157   if (m_pdfWave.size()+1 != m_edgesWave.size() || 
00158       m_pdfTime.size()+1 != m_edgesTime.size() ) {
00159     fatal() << "There should be 1 more number of bin edges than bins when defining pdf" << endreq;
00160     return StatusCode::FAILURE; 
00161   }
00162 
00163   // Fill pre-calculated Cumulative Distribution Functions
00164   if(m_pdfTime.size()>0){
00165     m_cdfTime.push_back( 0 );
00166     for (unsigned int bin=0; bin<m_pdfTime.size(); bin++)
00167       m_cdfTime.push_back( m_cdfTime[bin] + m_pdfTime[bin] );
00168     // Normalize
00169     for (unsigned int bin=0; bin<m_cdfTime.size(); bin++)
00170       m_cdfTime[bin] /= m_cdfTime.back();
00171   }
00172   if(m_pdfWave.size()>0){
00173     m_cdfWave.push_back( 0 );
00174     for (unsigned int bin=0; bin<m_pdfWave.size(); bin++)
00175       m_cdfWave.push_back( m_cdfWave[bin] + m_pdfWave[bin] );
00176     // Normalize
00177     for (unsigned int bin=0; bin<m_cdfWave.size(); bin++)
00178       m_cdfWave[bin] /= m_cdfWave.back();
00179   }
00180   
00181   if( m_photonScaleWeight > 1.0 ){
00182     // Reduce number of photons, and scale each photon weight to compensate
00183     info() << "Scaling each photon weight by " << m_photonScaleWeight 
00184            << " and reducing the number of photons from "
00185            << m_particlesPerEvent << " to " 
00186            << int( m_particlesPerEvent / m_photonScaleWeight )
00187            << endreq;
00188     m_particlesPerEvent = int( m_particlesPerEvent / m_photonScaleWeight );
00189   }
00190 
00191   if( m_geomPosToolName == "" ){
00192     info() << "Placement of Diffuser Ball geometry not requested.  "
00193            << "Optical photons will still be produced at the requested "
00194            << "location." << endreq;
00195   }else{
00196     IPositionerTool* geomPosTool = 0;
00197     try{
00198       geomPosTool = tool<IPositionerTool>(m_geomPosToolName);
00199     }
00200     catch(const GaudiException& exg) {
00201       fatal() << "Failed to get geometry tool: \"" << m_geomPosToolName << "\"" 
00202               << endreq;
00203       return StatusCode::FAILURE;
00204     }
00205     info () << "Placing diffuser ball geometry using " << m_geomPosToolName 
00206             << endreq;
00207     sc = geomPosTool->placeVolume();
00208     if(sc.isFailure()) return sc;
00209     geomPosTool->release();
00210     geomPosTool = 0;
00211   }
00212 
00213   return this->GaudiTool::initialize();
00214 }
00215 
00216 StatusCode GtDiffuserBallTool::finalize()
00217 {
00218   return this->GaudiTool::finalize();
00219 }
00220 
00221 StatusCode GtDiffuserBallTool::mutate(HepMC::GenEvent& event)
00222 { 
00223   verbose() << "Mode: " << m_particlesPerEventMode << endreq;
00224   int particleNumber = m_particlesPerEvent;
00225   debug() << " particleNumber " << particleNumber << " mode " << m_particlesPerEventMode << endreq;
00226   if(m_particlesPerEventMode != "Fixed"){
00227     // Smear particle number
00228     particleNumber = m_particlesPerEvent + int(m_particlesPerEventSpread/m_photonScaleWeight * m_randPartNo()); 
00229     debug() << " smeared # of particles " << particleNumber << endreq;
00230     // Make sure that at least one dummy photon is generated
00231     if ( particleNumber < 1 ) { 
00232       particleNumber = 1; 
00233       debug() << " after requiring >0 photons. particleNumber is " << particleNumber << endreq;
00234     }
00235     else {
00236       // Cap photon number
00237       if ( particleNumber > int(m_particlesPerEvent * 4)) { particleNumber = int(m_particlesPerEvent * 4); }   
00238       debug() << " after cap. particleNumber is " << particleNumber << endreq;
00239     }
00240     debug() << "Generate " << particleNumber << " photons" << endreq;
00241   }
00242   for (int ind=0; ind<particleNumber; ++ind) {
00243     if (this->oneVertex(event).isFailure()) 
00244       return StatusCode::FAILURE;
00245   }
00246   return StatusCode::SUCCESS;
00247 }
00248 
00249 StatusCode GtDiffuserBallTool::oneVertex(HepMC::GenEvent& event)
00250 {
00251   // generate vertex time (within single event)
00252   double vertex_t = GetTime();
00253 
00254   // generate vertex position (random point on ball from which photon is emitted)
00255   double vertex_costh;
00256   double vertex_phi = m_uni()*CLHEP::twopi;  // range from 0 to 2*pi radians uniformly
00257   
00258   if (m_anisotropy){
00259     // create bright spot at top of diffuser ball, theta=0
00260     // theta=0 is 50% brighter than theta=pi (brightness taken to be linear)
00261     // see DocDB-1212
00262 
00263     bool accept = false;
00264     double vertex_theta;
00265     while (!accept){
00266       vertex_theta = m_uni()*CLHEP::pi; 
00267       double test  = m_uni()*1.25; // function below has max of 1.25 
00268       if (test <= (-vertex_theta/twopi + 1.5)*sin(vertex_theta)) 
00269         accept = true;
00270     }
00271 
00272     // rotate vertex to random bright spot location
00273     CLHEP::Hep3Vector vertex_bright;
00274     vertex_bright.setRThetaPhi(1.0,vertex_theta,vertex_phi);
00275     vertex_bright.rotateY(m_bright_theta);
00276     vertex_bright.rotateZ(m_bright_phi);
00277     vertex_bright.unit();
00278 
00279     vertex_costh = vertex_bright.cosTheta();
00280     vertex_phi   = vertex_bright.phi();
00281   }else{
00282     vertex_costh = 2*m_uni()-1;  // cos(theta) ranges from -1 to 1 uniformly
00283   }
00284 
00285   double vertex_sinth = sqrt(1-vertex_costh*vertex_costh);
00286   double vertex_x = m_radius*vertex_sinth*cos(vertex_phi);
00287   double vertex_y = m_radius*vertex_sinth*sin(vertex_phi);
00288   double vertex_z = m_radius*vertex_costh;
00289   HepMC::GenVertex* vertex = new HepMC::GenVertex(HepMC::FourVector(vertex_x,
00290                                                                     vertex_y,
00291                                                                     vertex_z,
00292                                                                     vertex_t));
00293   // Catch scaling of photon weight
00294   if( m_photonScaleWeight > 1.0 ){
00295     vertex->weights().push_back( m_photonScaleWeight );
00296   }
00297   if( !event.add_vertex(vertex) ){
00298     error() << "Failed to add vertex to event" << endreq;
00299     return StatusCode::FAILURE;
00300   }
00301 
00302   // generate momentum direction
00303   CLHEP::Hep3Vector dir;
00304   double dir_costh = m_uni(); // cos(theta) range 0 to 1
00305                               // do not want photon traveling into diffuser ball
00306   double dir_phi = m_uni()*twopi; // range from 0 to 2*pi radians
00307   
00308   dir.setRThetaPhi(1.0,acos(dir_costh),dir_phi);
00309 
00310   // rotate along Y-axis by vertex direction's theta
00311   dir.rotateY(acos(vertex_costh));
00312   // rotate along Z-axis by vertex direction's phi
00313   dir.rotateZ(vertex_phi);
00314   
00315   dir = dir.unit();
00316   
00317   // generate wavelength/momentum/energy
00318   double momentum = CLHEP::twopi*CLHEP::hbarc / GetWave();
00319   double energy = momentum;
00320   HepMC::FourVector fourmom(momentum*dir.x(),
00321                             momentum*dir.y(),
00322                             momentum*dir.z(),
00323                             energy);
00324   
00325   HepMC::GenParticle* particle = new HepMC::GenParticle(fourmom,m_pid,1/*=status*/);
00326   double pol_phi = m_uni()*CLHEP::twopi;
00327   particle->set_polarization(HepMC::Polarization(0.5*pi,pol_phi));
00328     
00329   vertex->add_particle_out(particle);
00330 
00331   return StatusCode::SUCCESS;
00332 }
00333 
00334 double GtDiffuserBallTool::GetTime()
00335 {
00336   double time = -1.0;
00337   double current_rand = m_randTime();
00338 
00339   if (m_timingMode == "Instant")      time = 0.0;
00340   else if (m_timingMode == "Defined") time = ConvertCdfRand(current_rand,m_cdfTime,m_edgesTime);
00341 
00342   return time;
00343 }
00344 
00345 double GtDiffuserBallTool::GetWave()
00346 {
00347   double wave = 0.0;
00348   double current_rand = m_randWave();
00349   double mean = m_wavelength;
00350   double spread = m_wavelengthSpread;
00351 
00352   if (m_wavelengthMode == "Fixed")        wave = m_wavelength;
00353   else if (m_wavelengthMode == "Uniform") wave = (2*current_rand-1)*spread + mean;
00354   else if (m_wavelengthMode == "Smeared") wave = current_rand*spread + mean;
00355   else if (m_wavelengthMode == "Defined") wave = ConvertCdfRand(current_rand,m_cdfWave,m_edgesWave); 
00356 
00357   return wave;
00358 }
00359 
00360 double GtDiffuserBallTool::ConvertCdfRand(const double& rand, 
00361                                           const std::vector<double>& cdf, 
00362                                           const std::vector<double>& edges) {
00363   // Convert a uniform random number in [0,1] to a random sample from
00364   // the given cumulative distribution function.
00365   int left = 0;
00366   int right = cdf.size();
00367   const double* cdfStart = &cdf[0];
00368   const double* edgesStart = &edges[0];
00369 
00370   while( right-left > 1 ){
00371     int mid = (right+left)/2;
00372     if( rand < *(cdfStart+mid) ) right = mid;
00373     else left = mid;
00374   }
00375   double value = *(edgesStart + left);
00376   double slope = (*(edgesStart+right) - *(edgesStart+left))
00377                 /(*(cdfStart+right) - *(cdfStart+left));
00378   value += slope * (rand - *(cdfStart+left));
00379   return value;
00380 }
| Classes | Job Modules | Data Objects | Services | Algorithms | Tools | Packages | Directories | Tracs |

Generated on Mon Apr 11 20:55:36 2011 for GenTools by doxygen 1.4.7