CMS 3D CMS Logo

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