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
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
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
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
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
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
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
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
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
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
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
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
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
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
00228 particleNumber = m_particlesPerEvent + int(m_particlesPerEventSpread/m_photonScaleWeight * m_randPartNo());
00229 debug() << " smeared # of particles " << particleNumber << endreq;
00230
00231 if ( particleNumber < 1 ) {
00232 particleNumber = 1;
00233 debug() << " after requiring >0 photons. particleNumber is " << particleNumber << endreq;
00234 }
00235 else {
00236
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
00252 double vertex_t = GetTime();
00253
00254
00255 double vertex_costh;
00256 double vertex_phi = m_uni()*CLHEP::twopi;
00257
00258 if (m_anisotropy){
00259
00260
00261
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;
00268 if (test <= (-vertex_theta/twopi + 1.5)*sin(vertex_theta))
00269 accept = true;
00270 }
00271
00272
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;
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
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
00303 CLHEP::Hep3Vector dir;
00304 double dir_costh = m_uni();
00305
00306 double dir_phi = m_uni()*twopi;
00307
00308 dir.setRThetaPhi(1.0,acos(dir_costh),dir_phi);
00309
00310
00311 dir.rotateY(acos(vertex_costh));
00312
00313 dir.rotateZ(vertex_phi);
00314
00315 dir = dir.unit();
00316
00317
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);
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
00364
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 }