9 #include "G4LogicalVolumeStore.hh" 10 #include "G4LogicalVolume.hh" 13 #include "G4VProcess.hh" 14 #include "G4Poisson.hh" 25 #include "G4SystemOfUnits.hh" 26 #include "G4PhysicalConstants.hh" 32 CaloSD(name, cpv, clg, p, manager) {
45 edm::LogInfo(
"EcalSim") <<
"Constructing a DreamSD with name " << GetName() <<
"\n" 46 <<
"DreamSD:: Use of Birks law is set to " 47 << useBirk <<
" with three constants kB = " 48 << birk1 <<
", C1 = " << birk2 <<
", C2 = " 50 <<
" Slope for Light yield is set to " 52 <<
" Parameterization of Cherenkov is set to " 53 << doCherenkov_ <<
" and readout both sides is " 63 <<
"please add it to config file";
65 ntuple_ = tfile->
make<TTree>(
"tree",
"Cherenkov photons");
84 double edep = aStep->GetTotalEnergyDeposit() *
weight;
88 LogDebug(
"EcalSim") <<
"DreamSD:: " << aStep->GetPreStepPoint()->GetPhysicalVolume()->GetName()
90 <<
" Light Collection Efficiency " << weight
91 <<
" Weighted Energy Deposit " << edep/
MeV 101 DimensionMap::const_iterator ite =
xtalLMap.begin();
102 const G4LogicalVolume* lv = (ite->first);
103 G4Material* material = lv->GetMaterial();
104 edm::LogInfo(
"EcalSim") <<
"DreamSD::initRun: Initializes for material " 105 << material->GetName() <<
" in " << lv->GetName();
109 edm::LogWarning(
"EcalSim") <<
"Couldn't retrieve material properties table\n" 110 <<
" Material = " << material->GetName();
119 const G4VTouchable* touch = aStep->GetPreStepPoint()->GetTouchable();
120 uint32_t
id = (touch->GetReplicaNumber(1))*10 + (touch->GetReplicaNumber(0));
131 G4String attribute =
"ReadOutName";
136 const G4LogicalVolumeStore * lvs = G4LogicalVolumeStore::GetInstance();
137 std::vector<G4LogicalVolume *>::const_iterator lvcite;
143 G4LogicalVolume* lv=
nullptr;
144 for (lvcite = lvs->begin(); lvcite != lvs->end(); lvcite++)
145 if ((*lvcite)->GetName() ==
name) {
149 LogDebug(
"EcalSim") <<
"DreamSD::initMap (for " << sd <<
"): Solid " 150 << name <<
" Shape " << sol.
shape() <<
" Parameter 0 = " 151 << paras[0] <<
" Logical Volume " << lv;
152 double length = 0,
width = 0;
154 std::sort( paras.begin(), paras.end() );
155 length = 2.0*paras.back();
156 width = 2.0*paras.front();
160 LogDebug(
"EcalSim") <<
"DreamSD: Length Table for " << attribute <<
" = " 162 DimensionMap::const_iterator ite =
xtalLMap.begin();
164 for (; ite !=
xtalLMap.end(); ite++, i++) {
165 G4String
name =
"Unknown";
166 if (ite->first !=
nullptr) name = (ite->first)->GetName();
167 LogDebug(
"EcalSim") <<
" " << i <<
" " << ite->first <<
" " << name
168 <<
" L = " << ite->second.first
169 <<
" W = " << ite->second.second;
176 auto const stepPoint = aStep->GetPreStepPoint();
177 auto const lv = stepPoint->GetTouchable()->GetVolume(0)->GetLogicalVolume();
178 G4String nameVolume= lv->GetName();
181 G4ThreeVector localPoint =
setToLocal(stepPoint->GetPosition(),
182 stepPoint->GetTouchable());
184 double localz = localPoint.x();
185 double dapd = 0.5 * crlength - flag*localz;
186 if (dapd >= -0.1 || dapd <= crlength+0.1) {
190 edm::LogWarning(
"EcalSim") <<
"DreamSD: light coll curve : wrong distance " 191 <<
"to APD " << dapd <<
" crlength = " 192 << crlength <<
" crystal name = " << nameVolume
193 <<
" z of localPoint = " << localz
194 <<
" take weight = " <<
weight;
196 LogDebug(
"EcalSim") <<
"DreamSD, light coll curve : " << dapd
197 <<
" crlength = " << crlength
198 <<
" crystal name = " << nameVolume
199 <<
" z of localPoint = " << localz
200 <<
" take weight = " <<
weight;
208 DimensionMap::const_iterator ite =
xtalLMap.find(lv);
209 if (ite !=
xtalLMap.end()) length = ite->second.first;
218 DimensionMap::const_iterator ite =
xtalLMap.find(lv);
219 if (ite !=
xtalLMap.end()) width = ite->second.second;
230 double cherenkovEnergy = 0;
232 G4Material* material = aStep->GetTrack()->GetMaterial();
236 if ( Rindex ==
nullptr ) {
238 return cherenkovEnergy;
243 int Rlength = Rindex->GetVectorLength() - 1;
244 double Pmin = Rindex->Energy(0);
245 double Pmax = Rindex->Energy(Rlength);
246 LogDebug(
"EcalSim") <<
"Material properties: " <<
"\n" 247 <<
" Pmin = " << Pmin
248 <<
" Pmax = " <<
Pmax;
251 const G4StepPoint* pPreStepPoint = aStep->GetPreStepPoint();
252 const G4StepPoint* pPostStepPoint = aStep->GetPostStepPoint();
253 const G4ThreeVector& x0 = pPreStepPoint->GetPosition();
254 G4ThreeVector p0 = aStep->GetDeltaPosition().unit();
255 const G4DynamicParticle* aParticle = aStep->GetTrack()->GetDynamicParticle();
256 const double charge = aParticle->GetDefinition()->GetPDGCharge();
258 double beta = 0.5*( pPreStepPoint->GetBeta() + pPostStepPoint->GetBeta() );
259 double BetaInverse = 1.0/
beta;
261 LogDebug(
"EcalSim") <<
"Particle properties: " <<
"\n" 262 <<
" charge = " << charge
263 <<
" beta = " <<
beta;
267 if ( meanNumberOfPhotons <= 0.0 ) {
268 LogDebug(
"EcalSim") <<
"Mean number of photons is zero: " << meanNumberOfPhotons
269 <<
", stopping here";
270 return cherenkovEnergy;
274 meanNumberOfPhotons *= aStep->GetStepLength();
277 int numPhotons =
static_cast<int>( G4Poisson(meanNumberOfPhotons) );
279 if ( numPhotons <= 0 ) {
280 LogDebug(
"EcalSim") <<
"Poission number of photons is zero: " << numPhotons
281 <<
", stopping here";
282 return cherenkovEnergy;
286 double dp = Pmax - Pmin;
287 double maxCos = BetaInverse / (*Rindex)[Rlength];
288 double maxSin2 = (1.0 - maxCos) * (1.0 + maxCos);
291 for (
int iPhoton = 0; iPhoton<numPhotons; ++iPhoton ) {
295 double sampledMomentum, sampledRI;
296 double cosTheta, sin2Theta;
300 randomNumber = G4UniformRand();
301 sampledMomentum = Pmin + randomNumber * dp;
302 sampledRI = Rindex->Value(sampledMomentum);
303 cosTheta = BetaInverse / sampledRI;
305 sin2Theta = (1.0 - cosTheta)*(1.0 + cosTheta);
306 randomNumber = G4UniformRand();
308 }
while (randomNumber*maxSin2 > sin2Theta);
312 randomNumber = G4UniformRand();
314 double phi = twopi*randomNumber;
315 double sinPhi =
sin(phi);
316 double cosPhi =
cos(phi);
321 double sinTheta =
sqrt(sin2Theta);
322 double px = sinTheta*cosPhi;
323 double py = sinTheta*sinPhi;
324 double pz = cosTheta;
325 G4ThreeVector photonDirection(px, py, pz);
328 photonDirection.rotateUz(p0);
331 randomNumber = G4UniformRand();
332 G4ThreeVector photonPosition = x0 + randomNumber * aStep->GetDeltaPosition();
333 G4ThreeVector photonMomentum = sampledMomentum*photonDirection;
340 px_[iPhoton] = photonMomentum.x();
341 py_[iPhoton] = photonMomentum.y();
342 pz_[iPhoton] = photonMomentum.z();
343 x_[iPhoton] = photonPosition.x();
344 y_[iPhoton] = photonPosition.y();
345 z_[iPhoton] = photonPosition.z();
352 return cherenkovEnergy;
362 const G4Material* aMaterial,
363 const G4MaterialPropertyVector* Rindex )
365 const G4double rFact = 369.81/(eV * cm);
367 if( beta <= 0.0 )
return 0.0;
369 double BetaInverse = 1./
beta;
376 int Rlength = Rindex->GetVectorLength() - 1;
377 double Pmin = Rindex->Energy(0);
378 double Pmax = Rindex->Energy(Rlength);
381 double nMin = (*Rindex)[0];
382 double nMax = (*Rindex)[Rlength];
387 double dp = 0., ge = 0., CAImin = 0.;
390 if ( nMax < BetaInverse) { }
393 else if (nMin > BetaInverse) {
403 Pmin = Rindex->Value(BetaInverse);
408 ge = CAImax - CAImin;
413 double numPhotons = rFact * charge/eplus * charge/eplus *
414 (dp - ge * BetaInverse*BetaInverse);
416 LogDebug(
"EcalSim") <<
"@SUB=getAverageNumberOfPhotons" 417 <<
"CAImin = " << CAImin <<
"\n" 418 <<
"CAImax = " << CAImax <<
"\n" 419 <<
"dp = " << dp <<
", ge = " << ge <<
"\n" 420 <<
"numPhotons = " << numPhotons;
435 if ( pbWO2Name != aMaterial->GetName() ) {
437 <<
"expecting " << pbWO2Name
438 <<
", got " << aMaterial->GetName();
442 G4MaterialPropertiesTable* table =
new G4MaterialPropertiesTable();
446 const int nEntries = 14;
447 double PhotonEnergy[nEntries] = { 1.7712*eV, 1.8368*eV, 1.90745*eV, 1.98375*eV, 2.0664*eV,
448 2.15625*eV, 2.25426*eV, 2.3616*eV, 2.47968*eV, 2.61019*eV,
449 2.75521*eV, 2.91728*eV, 3.09961*eV, 3.30625*eV };
450 double RefractiveIndex[nEntries] = { 2.17728, 2.18025, 2.18357, 2.18753, 2.19285,
451 2.19813, 2.20441, 2.21337, 2.22328, 2.23619,
452 2.25203, 2.27381, 2.30282, 2.34666 };
454 table->AddProperty(
"RINDEX", PhotonEnergy, RefractiveIndex, nEntries );
455 aMaterial->SetMaterialPropertiesTable(table);
462 double currentRI = RefractiveIndex[
index];
463 double currentPM = PhotonEnergy[
index];
464 double currentCAI = 0.0;
466 double prevPM = currentPM;
467 double prevCAI = currentCAI;
468 double prevRI = currentRI;
469 while ( ++index < nEntries ) {
470 currentRI = RefractiveIndex[
index];
471 currentPM = PhotonEnergy[
index];
472 currentCAI = 0.5*(1.0/(prevRI*prevRI) + 1.0/(currentRI*currentRI));
473 currentCAI = prevCAI + (currentPM - prevPM) * currentCAI;
478 prevCAI = currentCAI;
482 LogDebug(
"EcalSim") <<
"Material properties set for " << aMaterial->GetName();
495 const G4ThreeVector&
x,
496 const G4Step* aStep )
509 G4StepPoint* stepPoint = aStep->GetPreStepPoint();
510 G4LogicalVolume* lv = stepPoint->GetTouchable()->GetVolume(0)->GetLogicalVolume();
511 G4String nameVolume= lv->GetName();
515 double dapd = 0.5 * crlength - x.x();
516 double y = p.y()/p.x()*dapd;
518 LogDebug(
"EcalSim") <<
"Distance to APD: " << dapd
519 <<
" - y at APD: " <<
y;
522 if ( fabs(y)>crwidth*0.5 ) {
527 double waveLength = p.mag()*1.239e8;
532 LogDebug(
"EcalSim") <<
"Wavelength: " << waveLength <<
" - Energy: " << energy;
T getParameter(std::string const &) const
T getUntrackedParameter(std::string const &, T const &) const
const std::vector< double > & parameters(void) const
Give the parameters of the solid.
const DDLogicalPart & logicalPart() const
The logical-part of the current node in the filtered-view.
double getPhotonEnergyDeposit_(const G4ParticleMomentum &p, const G4ThreeVector &x, const G4Step *aStep)
Returns energy deposit for a given photon.
std::pair< double, double > Doubles
Sin< T >::type sin(const T &t)
uint32_t setDetUnitId(const G4Step *) override
bool setPbWO2MaterialProperties_(G4Material *aMaterial)
Sets material properties at run-time...
T * make(const Args &...args) const
make new ROOT object
const DDSolid & solid(void) const
Returns a reference object of the solid being the shape of this LogicalPart.
Compact representation of the geometrical detector hierarchy.
The Signals That Services Can Subscribe To This is based on ActivityRegistry and is current per Services can connect to the signals distributed by the ActivityRegistry in order to monitor the activity of the application Each possible callback has some defined which we here list in angle e g
A DDSolid represents the shape of a part.
bool next()
set current node to the next node in the filtered tree
double cherenkovDeposit_(const G4Step *aStep)
Returns the total energy due to Cherenkov radiation.
Cos< T >::type cos(const T &t)
double getAverageNumberOfPhotons_(const double charge, const double beta, const G4Material *aMaterial, const G4MaterialPropertyVector *rIndex)
Returns average number of photons created by track.
DDSolidShape shape(void) const
The type of the solid.
G4MaterialPropertiesTable * materialPropertiesTable
double curve_LY(const G4Step *, int)
const double crystalWidth(G4LogicalVolume *) const
G4ThreeVector setToLocal(const G4ThreeVector &, const G4VTouchable *) const
std::unique_ptr< G4PhysicsOrderedFreeVector > chAngleIntegrals_
Table of Cherenkov angle integrals vs photon momentum.
double getEnergyDeposit(const G4Step *) override
double getAttenuation(const G4Step *aStep, double birk1, double birk2, double birk3) const
DreamSD(const std::string &, const DDCompactView &, const SensitiveDetectorCatalog &, edm::ParameterSet const &, const SimTrackManager *)
bool firstChild()
set the current node to the first child ...
const double crystalLength(G4LogicalVolume *) const
const std::string & name() const
Returns the name.
void initMap(const std::string &, const DDCompactView &)
static const double getEfficiency(const double &waveLengthNm)
Return efficiency for given photon wavelength (in nm)