CMS 3D CMS Logo

DreamSD.cc

Go to the documentation of this file.
00001 
00002 #include "SimG4Core/Notification/interface/TrackInformation.h"
00003 #include "DetectorDescription/Core/interface/DDFilter.h"
00004 #include "DetectorDescription/Core/interface/DDFilteredView.h"
00005 #include "DetectorDescription/Core/interface/DDSolid.h"
00006 #include "DetectorDescription/Core/interface/DDSplit.h"
00007 #include "DetectorDescription/Core/interface/DDValue.h"
00008 
00009 #include "G4LogicalVolumeStore.hh"
00010 #include "G4LogicalVolume.hh"
00011 #include "G4Step.hh"
00012 #include "G4Track.hh"
00013 #include "G4VProcess.hh"
00014 #include "G4Poisson.hh"
00015 
00016 // Histogramming
00017 #include "FWCore/ServiceRegistry/interface/Service.h"
00018 #include "PhysicsTools/UtilAlgos/interface/TFileService.h"
00019 #include <TTree.h>
00020 
00021 // Cherenkov
00022 #include "SimG4CMS/CherenkovAnalysis/interface/DreamSD.h"
00023 #include "SimG4CMS/CherenkovAnalysis/interface/PMTResponse.h"
00024 
00025 
00026 //________________________________________________________________________________________
00027 DreamSD::DreamSD(G4String name, const DDCompactView & cpv,
00028                SensitiveDetectorCatalog & clg, 
00029                edm::ParameterSet const & p, const SimTrackManager* manager) : 
00030   CaloSD(name, cpv, clg, p, manager) {
00031 
00032   edm::ParameterSet m_EC = p.getParameter<edm::ParameterSet>("ECalSD");
00033   useBirk= m_EC.getParameter<bool>("UseBirkLaw");
00034   doCherenkov_ = m_EC.getParameter<bool>("doCherenkov");
00035   birk1  = m_EC.getParameter<double>("BirkC1")*(g/(MeV*cm2));
00036   birk2  = m_EC.getParameter<double>("BirkC2");
00037   birk3  = m_EC.getParameter<double>("BirkC3");
00038   slopeLY= m_EC.getParameter<double>("SlopeLightYield");
00039   readBothSide_ = m_EC.getUntrackedParameter<bool>("ReadBothSide", false);
00040   
00041   edm::LogInfo("EcalSim")  << "Constructing a DreamSD  with name " << GetName() << "\n"
00042                            << "DreamSD:: Use of Birks law is set to      " 
00043                            << useBirk << "  with three constants kB = "
00044                            << birk1 << ", C1 = " << birk2 << ", C2 = " 
00045                            << birk3 << "\n"
00046                            << "          Slope for Light yield is set to "
00047                            << slopeLY << "\n"
00048                            << "          Parameterization of Cherenkov is set to " 
00049                            << doCherenkov_ << " and readout both sides is "
00050                            << readBothSide_;
00051 
00052   initMap(name,cpv);
00053 
00054   // Init histogramming
00055   edm::Service<TFileService> tfile;
00056 
00057   if ( !tfile.isAvailable() )
00058     throw cms::Exception("BadConfig") << "TFileService unavailable: "
00059                                       << "please add it to config file";
00060 
00061   ntuple_ = tfile->make<TTree>("tree","Cherenkov photons");
00062   if (doCherenkov_) {
00063     ntuple_->Branch("nphotons",&nphotons_,"nphotons/I");
00064     ntuple_->Branch("px",px_,"px[nphotons]/F");
00065     ntuple_->Branch("py",py_,"py[nphotons]/F");
00066     ntuple_->Branch("pz",pz_,"pz[nphotons]/F");
00067     ntuple_->Branch("x",x_,"x[nphotons]/F");
00068     ntuple_->Branch("y",y_,"y[nphotons]/F");
00069     ntuple_->Branch("z",z_,"z[nphotons]/F");
00070   }
00071 
00072 }
00073 
00074 //________________________________________________________________________________________
00075 bool DreamSD::ProcessHits(G4Step * aStep, G4TouchableHistory *) {
00076 
00077   if (aStep == NULL) {
00078     return true;
00079   } else {
00080     side = 1;
00081     if (getStepInfo(aStep)) {
00082       if (hitExists() == false && edepositEM+edepositHAD>0.)
00083         currentHit = createNewHit();
00084       if (readBothSide_) {
00085         side = -1;
00086         getStepInfo(aStep);
00087         if (hitExists() == false && edepositEM+edepositHAD>0.)
00088           currentHit = createNewHit();
00089       }
00090     }
00091   }
00092   return true;
00093 }
00094 
00095 
00096 //________________________________________________________________________________________
00097 bool DreamSD::getStepInfo(G4Step* aStep) {
00098 
00099   preStepPoint = aStep->GetPreStepPoint();
00100   theTrack     = aStep->GetTrack();
00101   G4String nameVolume = preStepPoint->GetPhysicalVolume()->GetName();
00102 
00103   // take into account light collection curve for crystals
00104   double weight = 1.;
00105   weight *= curve_LY(aStep, side);
00106   if (useBirk)   weight *= getAttenuation(aStep, birk1, birk2, birk3);
00107   edepositEM  = aStep->GetTotalEnergyDeposit() * weight;
00108   LogDebug("EcalSim") << "DreamSD:: " << nameVolume << " Side " << side
00109                       <<" Light Collection Efficiency " << weight 
00110                       << " Weighted Energy Deposit " << edepositEM/MeV 
00111                       << " MeV";
00112   // Get cherenkov contribution
00113   if ( doCherenkov_ ) {
00114     edepositHAD = cherenkovDeposit_( aStep );
00115   } else {
00116     edepositHAD = 0;
00117   }
00118 
00119   double       time  = (aStep->GetPostStepPoint()->GetGlobalTime())/nanosecond;
00120   unsigned int unitID= setDetUnitId(aStep);
00121   if (side < 0) unitID++;
00122   TrackInformation * trkInfo = (TrackInformation *)(theTrack->GetUserInformation());
00123   int      primaryID;
00124 
00125   if (trkInfo)
00126     primaryID = trkInfo->getIDonCaloSurface();
00127   else
00128     primaryID = 0;
00129 
00130   if (primaryID == 0) {
00131     edm::LogWarning("EcalSim") << "CaloSD: Problem with primaryID **** set by "
00132                                << "force to TkID **** "
00133                                << theTrack->GetTrackID() << " in Volume "
00134                                << preStepPoint->GetTouchable()->GetVolume(0)->GetName();
00135     primaryID = theTrack->GetTrackID();
00136   }
00137 
00138   bool flag = (unitID > 0);
00139   G4TouchableHistory* touch =(G4TouchableHistory*)(theTrack->GetTouchable());
00140   if (flag) {
00141     currentID.setID(unitID, time, primaryID, 0);
00142 
00143     LogDebug("EcalSim") << "CaloSD:: GetStepInfo for"
00144                         << " PV "     << touch->GetVolume(0)->GetName()
00145                         << " PVid = " << touch->GetReplicaNumber(0)
00146                         << " MVid = " << touch->GetReplicaNumber(1)
00147                         << " Unit   " << currentID.unitID()
00148                         << " Edeposit = " << edepositEM << " " << edepositHAD;
00149   } else {
00150     LogDebug("EcalSim") << "CaloSD:: GetStepInfo for"
00151                         << " PV "     << touch->GetVolume(0)->GetName()
00152                         << " PVid = " << touch->GetReplicaNumber(0)
00153                         << " MVid = " << touch->GetReplicaNumber(1)
00154                         << " Unit   " << std::hex << unitID << std::dec
00155                         << " Edeposit = " << edepositEM << " " << edepositHAD;
00156   }
00157   return flag;
00158 
00159 }
00160 
00161 
00162 //________________________________________________________________________________________
00163 void DreamSD::initRun() {
00164 
00165   // Get the material and set properties if needed
00166   DimensionMap::const_iterator ite = xtalLMap.begin();
00167   G4LogicalVolume* lv = (ite->first);
00168   G4Material* material = lv->GetMaterial();
00169   edm::LogInfo("EcalSim") << "DreamSD::initRun: Initializes for material " 
00170                           << material->GetName() << " in " << lv->GetName();
00171   materialPropertiesTable = material->GetMaterialPropertiesTable();
00172   if ( !materialPropertiesTable ) {
00173     if ( !setPbWO2MaterialProperties_( material ) ) {
00174       edm::LogWarning("EcalSim") << "Couldn't retrieve material properties table\n"
00175                                  << " Material = " << material->GetName();
00176     }
00177     materialPropertiesTable = material->GetMaterialPropertiesTable();
00178   }
00179 }
00180 
00181 
00182 //________________________________________________________________________________________
00183 uint32_t DreamSD::setDetUnitId(G4Step * aStep) { 
00184   const G4VTouchable* touch = aStep->GetPreStepPoint()->GetTouchable();
00185   uint32_t id = (touch->GetReplicaNumber(1))*10 + (touch->GetReplicaNumber(0));
00186   LogDebug("EcalSim") << "DreamSD:: ID " << id;
00187   return id;
00188 }
00189 
00190 
00191 //________________________________________________________________________________________
00192 void DreamSD::initMap(G4String sd, const DDCompactView & cpv) {
00193 
00194   G4String attribute = "ReadOutName";
00195   DDSpecificsFilter filter;
00196   DDValue           ddv(attribute,sd,0);
00197   filter.setCriteria(ddv,DDSpecificsFilter::equals);
00198   DDFilteredView fv(cpv);
00199   fv.addFilter(filter);
00200   fv.firstChild();
00201 
00202   const G4LogicalVolumeStore * lvs = G4LogicalVolumeStore::GetInstance();
00203   std::vector<G4LogicalVolume *>::const_iterator lvcite;
00204   bool dodet=true;
00205   while (dodet) {
00206     const DDSolid & sol  = fv.logicalPart().solid();
00207     std::vector<double> paras(sol.parameters());
00208     G4String name = DDSplit(sol.name()).first;
00209     G4LogicalVolume* lv=0;
00210     for (lvcite = lvs->begin(); lvcite != lvs->end(); lvcite++) 
00211       if ((*lvcite)->GetName() == name) {
00212         lv = (*lvcite);
00213         break;
00214       }
00215     LogDebug("EcalSim") << "DreamSD::initMap (for " << sd << "): Solid " 
00216                         << name << " Shape " << sol.shape() <<" Parameter 0 = "
00217                         << paras[0] << " Logical Volume " << lv;
00218     double length = 0, width = 0;
00219     // Set length to be the largest size, width the smallest
00220     std::sort( paras.begin(), paras.end() );
00221     length = 2.0*paras.back();
00222     width  = 2.0*paras.front();
00223     xtalLMap.insert( std::pair<G4LogicalVolume*,Doubles>(lv,Doubles(length,width)) );
00224     dodet = fv.next();
00225   }
00226   LogDebug("EcalSim") << "DreamSD: Length Table for " << attribute << " = " 
00227                       << sd << ":";   
00228   DimensionMap::const_iterator ite = xtalLMap.begin();
00229   int i=0;
00230   for (; ite != xtalLMap.end(); ite++, i++) {
00231     G4String name = "Unknown";
00232     if (ite->first != 0) name = (ite->first)->GetName();
00233     LogDebug("EcalSim") << " " << i << " " << ite->first << " " << name 
00234                         << " L = " << ite->second.first
00235                         << " W = " << ite->second.second;
00236   }
00237 }
00238 
00239 //________________________________________________________________________________________
00240 double DreamSD::curve_LY(G4Step* aStep, int flag) {
00241 
00242   G4StepPoint*     stepPoint = aStep->GetPreStepPoint();
00243   G4LogicalVolume* lv        = stepPoint->GetTouchable()->GetVolume(0)->GetLogicalVolume();
00244   G4String         nameVolume= lv->GetName();
00245 
00246   double weight = 1.;
00247   G4ThreeVector  localPoint = setToLocal(stepPoint->GetPosition(),
00248                                          stepPoint->GetTouchable());
00249   double crlength = crystalLength(lv);
00250   double localz   = localPoint.x();
00251   double dapd = 0.5 * crlength - flag*localz; // Distance from closest APD
00252   if (dapd >= -0.1 || dapd <= crlength+0.1) {
00253     if (dapd <= 100.)
00254       weight = 1.0 + slopeLY - dapd * 0.01 * slopeLY;
00255   } else {
00256     edm::LogWarning("EcalSim") << "DreamSD: light coll curve : wrong distance "
00257                                << "to APD " << dapd << " crlength = " 
00258                                << crlength << " crystal name = " << nameVolume 
00259                                << " z of localPoint = " << localz
00260                                << " take weight = " << weight;
00261   }
00262   LogDebug("EcalSim") << "DreamSD, light coll curve : " << dapd 
00263                       << " crlength = " << crlength
00264                       << " crystal name = " << nameVolume 
00265                       << " z of localPoint = " << localz
00266                       << " take weight = " << weight;
00267   return weight;
00268 }
00269 
00270 //________________________________________________________________________________________
00271 const double DreamSD::crystalLength(G4LogicalVolume* lv) const {
00272 
00273   double length= -1.;
00274   DimensionMap::const_iterator ite = xtalLMap.find(lv);
00275   if (ite != xtalLMap.end()) length = ite->second.first;
00276   return length;
00277 
00278 }
00279 
00280 //________________________________________________________________________________________
00281 const double DreamSD::crystalWidth(G4LogicalVolume* lv) const {
00282 
00283   double width= -1.;
00284   DimensionMap::const_iterator ite = xtalLMap.find(lv);
00285   if (ite != xtalLMap.end()) width = ite->second.second;
00286   return width;
00287 
00288 }
00289 
00290 
00291 //________________________________________________________________________________________
00292 // Calculate total cherenkov deposit
00293 // Inspired by Geant4's Cherenkov implementation
00294 double DreamSD::cherenkovDeposit_( G4Step* aStep ) {
00295 
00296   double cherenkovEnergy = 0;
00297   if (!materialPropertiesTable) return cherenkovEnergy;
00298   G4Material* material = aStep->GetTrack()->GetMaterial();
00299 
00300   // Retrieve refractive index
00301   const G4MaterialPropertyVector* Rindex = materialPropertiesTable->GetProperty("RINDEX"); 
00302   if ( Rindex == NULL ) {
00303     edm::LogWarning("EcalSim") << "Couldn't retrieve refractive index";
00304     return cherenkovEnergy;
00305   }
00306 
00307   LogDebug("EcalSim") << "Material properties: " << "\n"
00308                       << "  Pmin = " << Rindex->GetMinPhotonMomentum()
00309                       << "  Pmax = " << Rindex->GetMaxPhotonMomentum();
00310   
00311   // Get particle properties
00312   G4StepPoint* pPreStepPoint  = aStep->GetPreStepPoint();
00313   G4StepPoint* pPostStepPoint = aStep->GetPostStepPoint();
00314   G4ThreeVector x0 = pPreStepPoint->GetPosition();
00315   G4ThreeVector p0 = aStep->GetDeltaPosition().unit();
00316   const G4DynamicParticle* aParticle = aStep->GetTrack()->GetDynamicParticle();
00317   const double charge = aParticle->GetDefinition()->GetPDGCharge();
00318   // beta is averaged over step
00319   double beta = 0.5*( pPreStepPoint->GetBeta() + pPostStepPoint->GetBeta() );
00320   double BetaInverse = 1.0/beta;
00321 
00322   LogDebug("EcalSim") << "Particle properties: " << "\n"
00323                       << "  charge = " << charge
00324                       << "  beta   = " << beta;
00325 
00326   // Now get number of photons generated in this step
00327   double meanNumberOfPhotons = getAverageNumberOfPhotons_( charge, beta, material, Rindex );
00328   if ( meanNumberOfPhotons <= 0.0 ) { // Don't do anything
00329     LogDebug("EcalSim") << "Mean number of photons is zero: " << meanNumberOfPhotons
00330                         << ", stopping here";
00331     return cherenkovEnergy;
00332   }
00333 
00334   // number of photons is in unit of Geant4...
00335   meanNumberOfPhotons *= aStep->GetStepLength();
00336 
00337   // Now get a poisson distribution
00338   int numPhotons = static_cast<int>( G4Poisson(meanNumberOfPhotons) );
00339   //edm::LogVerbatim("EcalSim") << "Number of photons = " << numPhotons;
00340   if ( numPhotons <= 0 ) {
00341     LogDebug("EcalSim") << "Poission number of photons is zero: " << numPhotons
00342                       << ", stopping here";
00343     return cherenkovEnergy;
00344   }
00345 
00346   // Material refraction properties
00347   double Pmin = Rindex->GetMinPhotonMomentum();
00348   double Pmax = Rindex->GetMaxPhotonMomentum();
00349   double dp = Pmax - Pmin;
00350   double maxCos = BetaInverse / Rindex->GetMaxProperty(); 
00351   double maxSin2 = (1.0 - maxCos) * (1.0 + maxCos);
00352 
00353   // Finally: get contribution of each photon
00354   for ( int iPhoton = 0; iPhoton<numPhotons; ++iPhoton ) {
00355 
00356     // Determine photon momentum
00357     double randomNumber;
00358     double sampledMomentum, sampledRI; 
00359     double cosTheta, sin2Theta;
00360 
00361     // sample a momentum (not sure why this is needed!)
00362     do {
00363       randomNumber = G4UniformRand();   
00364       sampledMomentum = Pmin + randomNumber * dp; 
00365       sampledRI = Rindex->GetProperty(sampledMomentum);
00366       cosTheta = BetaInverse / sampledRI;  
00367       
00368       sin2Theta = (1.0 - cosTheta)*(1.0 + cosTheta);
00369       randomNumber = G4UniformRand();   
00370       
00371     } while (randomNumber*maxSin2 > sin2Theta);
00372 
00373     // Generate random position of photon on cone surface 
00374     // defined by Theta 
00375     randomNumber = G4UniformRand();
00376 
00377     double phi =  twopi*randomNumber;
00378     double sinPhi = sin(phi);
00379     double cosPhi = cos(phi);
00380 
00381     // Create photon momentum direction vector 
00382     // The momentum direction is still w.r.t. the coordinate system where the primary
00383     // particle direction is aligned with the z axis  
00384     double sinTheta = sqrt(sin2Theta); 
00385     double px = sinTheta*cosPhi;
00386     double py = sinTheta*sinPhi;
00387     double pz = cosTheta;
00388     G4ThreeVector photonDirection(px, py, pz);
00389 
00390     // Rotate momentum direction back to global (crystal) reference system 
00391     photonDirection.rotateUz(p0);
00392 
00393     // Create photon position and momentum
00394     randomNumber = G4UniformRand();
00395     G4ThreeVector photonPosition = x0 + randomNumber * aStep->GetDeltaPosition();
00396     G4ThreeVector photonMomentum = sampledMomentum*photonDirection;
00397 
00398     // Collect energy on APD
00399     cherenkovEnergy += getPhotonEnergyDeposit_( photonMomentum, photonPosition, aStep );
00400 
00401     // Ntuple variables
00402     nphotons_ = numPhotons;
00403     px_[iPhoton] = photonMomentum.x();
00404     py_[iPhoton] = photonMomentum.y();
00405     pz_[iPhoton] = photonMomentum.z();
00406     x_[iPhoton] = photonPosition.x();
00407     y_[iPhoton] = photonPosition.y();
00408     z_[iPhoton] = photonPosition.z();
00409   }
00410   
00411   // Fill ntuple
00412   ntuple_->Fill();
00413 
00414 
00415   return cherenkovEnergy;
00416 
00417 }
00418 
00419 
00420 //________________________________________________________________________________________
00421 // Returns number of photons produced per GEANT-unit (millimeter) in the current medium. 
00422 // From G4Cerenkov.cc
00423 const double DreamSD::getAverageNumberOfPhotons_( const double charge,
00424                                                   const double beta,
00425                                                   const G4Material* aMaterial,
00426                                                   const G4MaterialPropertyVector* Rindex ) const
00427 {
00428   const G4double rFact = 369.81/(eV * cm);
00429 
00430   if( beta <= 0.0 ) return 0.0;
00431 
00432   double BetaInverse = 1./beta;
00433 
00434   // Vectors used in computation of Cerenkov Angle Integral:
00435   //    - Refraction Indices for the current material
00436   //    - new G4PhysicsOrderedFreeVector allocated to hold CAI's
00437  
00438   // Min and Max photon momenta  
00439   double Pmin = Rindex->GetMinPhotonMomentum();
00440   double Pmax = Rindex->GetMaxPhotonMomentum();
00441 
00442   // Min and Max Refraction Indices 
00443   double nMin = Rindex->GetMinProperty();       
00444   double nMax = Rindex->GetMaxProperty();
00445 
00446   // Max Cerenkov Angle Integral 
00447   double CAImax = chAngleIntegrals_->GetMaxValue();
00448 
00449   double dp = 0., ge = 0., CAImin = 0.;
00450 
00451   // If n(Pmax) < 1/Beta -- no photons generated 
00452   if ( nMax < BetaInverse) { } 
00453 
00454   // otherwise if n(Pmin) >= 1/Beta -- photons generated  
00455   else if (nMin > BetaInverse) {
00456     dp = Pmax - Pmin;   
00457     ge = CAImax; 
00458   } 
00459   // If n(Pmin) < 1/Beta, and n(Pmax) >= 1/Beta, then
00460   // we need to find a P such that the value of n(P) == 1/Beta.
00461   // Interpolation is performed by the GetPhotonMomentum() and
00462   // GetProperty() methods of the G4MaterialPropertiesTable and
00463   // the GetValue() method of G4PhysicsVector.  
00464   else {
00465     Pmin = Rindex->GetPhotonMomentum(BetaInverse);
00466     dp = Pmax - Pmin;
00467     // need boolean for current implementation of G4PhysicsVector
00468     // ==> being phased out
00469     bool isOutRange;
00470     double CAImin = chAngleIntegrals_->GetValue(Pmin, isOutRange);
00471     ge = CAImax - CAImin;
00472     
00473   }
00474 
00475   // Calculate number of photons 
00476   double numPhotons = rFact * charge/eplus * charge/eplus *
00477     (dp - ge * BetaInverse*BetaInverse);
00478 
00479   LogDebug("EcalSim") << "@SUB=getAverageNumberOfPhotons" 
00480                       << "CAImin = " << CAImin << "\n"
00481                       << "CAImax = " << CAImax << "\n"
00482                       << "dp = " << dp << ", ge = " << ge << "\n"
00483                       << "numPhotons = " << numPhotons;
00484 
00485 
00486   
00487   return numPhotons;
00488 
00489 }
00490 
00491 
00492 //________________________________________________________________________________________
00493 // Set lead tungstate material properties on the fly.
00494 // Values from Ts42 detector construction
00495 bool DreamSD::setPbWO2MaterialProperties_( G4Material* aMaterial ) {
00496 
00497   std::string pbWO2Name("E_PbWO4");
00498   if ( pbWO2Name != aMaterial->GetName() ) { // Wrong material!
00499     edm::LogWarning("EcalSim") << "This is not the right material: "
00500                                << "expecting " << pbWO2Name 
00501                                << ", got " << aMaterial->GetName();
00502     return false;
00503   }
00504 
00505   G4MaterialPropertiesTable* table = new G4MaterialPropertiesTable();
00506 
00507   // Refractive index as a function of photon momentum
00508   // FIXME: Should somehow put that in the configuration
00509   const int nEntries = 14;
00510   double PhotonEnergy[nEntries] = { 1.7712*eV,  1.8368*eV,  1.90745*eV, 1.98375*eV, 2.0664*eV, 
00511                                     2.15625*eV, 2.25426*eV, 2.3616*eV,  2.47968*eV, 2.61019*eV, 
00512                                     2.75521*eV, 2.91728*eV, 3.09961*eV, 3.30625*eV };
00513   double RefractiveIndex[nEntries] = { 2.17728, 2.18025, 2.18357, 2.18753, 2.19285, 
00514                                        2.19813, 2.20441, 2.21337, 2.22328, 2.23619, 
00515                                        2.25203, 2.27381, 2.30282, 2.34666 };
00516   
00517   table->AddProperty( "RINDEX", PhotonEnergy, RefractiveIndex, nEntries );
00518   aMaterial->SetMaterialPropertiesTable(table); // FIXME: could this leak? What does G4 do?
00519 
00520   // Calculate Cherenkov angle integrals: 
00521   // This is an ad-hoc solution (we hold it in the class, not in the material)
00522   chAngleIntegrals_ = 
00523     std::auto_ptr<G4PhysicsOrderedFreeVector>( new G4PhysicsOrderedFreeVector() );
00524 
00525   int index = 0;
00526   double currentRI = RefractiveIndex[index];
00527   double currentPM = PhotonEnergy[index];
00528   double currentCAI = 0.0;
00529   chAngleIntegrals_->InsertValues(currentPM, currentCAI);
00530   double prevPM  = currentPM;
00531   double prevCAI = currentCAI;
00532   double prevRI  = currentRI;
00533   while ( ++index < nEntries ) {
00534     currentRI = RefractiveIndex[index];
00535     currentPM = PhotonEnergy[index];
00536     currentCAI = 0.5*(1.0/(prevRI*prevRI) + 1.0/(currentRI*currentRI));
00537     currentCAI = prevCAI + (currentPM - prevPM) * currentCAI;
00538 
00539     chAngleIntegrals_->InsertValues(currentPM, currentCAI);
00540 
00541     prevPM  = currentPM;
00542     prevCAI = currentCAI;
00543     prevRI  = currentRI;
00544   }
00545 
00546   LogDebug("EcalSim") << "Material properties set for " << aMaterial->GetName();
00547 
00548   return true;
00549 
00550 }
00551 
00552 
00553 //________________________________________________________________________________________
00554 // Calculate energy deposit of a photon on APD
00555 // - simple tracing to APD position (straight line);
00556 // - configurable reflection probability if not straight to APD;
00557 // - APD response function
00558 const double DreamSD::getPhotonEnergyDeposit_( const G4ThreeVector& p, 
00559                                                const G4ThreeVector& x,
00560                                                const G4Step* aStep )
00561 {
00562 
00563   double energy = 0;
00564 
00565   // Crystal dimensions
00566   
00567   //edm::LogVerbatim("EcalSim") << p << x;
00568 
00569   // 1. Check if this photon goes straight to the APD:
00570   //    - assume that APD is at x=xtalLength/2.0
00571   //    - extrapolate from x=x0 to x=xtalLength/2.0 using momentum in x-y
00572   
00573   G4StepPoint*     stepPoint = aStep->GetPreStepPoint();
00574   G4LogicalVolume* lv        = stepPoint->GetTouchable()->GetVolume(0)->GetLogicalVolume();
00575   G4String         nameVolume= lv->GetName();
00576 
00577   double crlength = crystalLength(lv);
00578   double crwidth  = crystalWidth(lv);
00579   double dapd = 0.5 * crlength - x.x(); // Distance from closest APD
00580   double y = p.y()/p.x()*dapd;
00581 
00582   LogDebug("EcalSim") << "Distance to APD: " << dapd
00583                       << " - y at APD: " << y;
00584 
00585   // Not straight: compute probability
00586   if ( fabs(y)>crwidth*0.5 ) {
00587     
00588   }
00589 
00590   // 2. Retrieve efficiency for this wavelength (in nm, from MeV)
00591   double waveLength = p.mag()*1.239e8;
00592   
00593 
00594   energy = p.mag()*PMTResponse::getEfficiency(waveLength);
00595 
00596   LogDebug("EcalSim") << "Wavelength: " << waveLength << " - Energy: " << energy;
00597 
00598   return energy;
00599 
00600 }

Generated on Tue Jun 9 17:46:50 2009 for CMSSW by  doxygen 1.5.4