ATLAS Offline Software
Loading...
Searching...
No Matches
TRTTransitionRadiation.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3*/
4
5//#define ARTRU // Choice of TR generator
6
7// class header
9
10// package includes
12#include "TRRegionXMLHandler.h"
13
14// Athena includes
15#include "CLHEP/Random/RandGaussZiggurat.h"
16#include "GeoModelInterfaces/StoredMaterialManager.h" //Material Manager
17#include "GeoMaterial2G4/Geo2G4MaterialFactory.h" //Converting GeoMaterial -> G4Material
20#include "StoreGate/StoreGateSvc.h" //Detector Store
21
26
27// Geant4 includes
28#include "G4DynamicParticle.hh"
29#include "G4Gamma.hh"
30#include "G4Material.hh"
31#include "G4Element.hh"
32#include "G4EmProcessSubType.hh" // for fTransitionRadiation
33#include "G4ProcessType.hh" // for fElectromagnetic
34
35#include "Randomize.hh"
36
37// CLHEP includes
38#include "CLHEP/Random/RandPoisson.h"
39
40// STL includes
41#include <cmath>
42#include <limits>
43
45//
46// Constructor, destructor
47
48TRTTransitionRadiation::TRTTransitionRadiation( const G4String& processName, const std::string & xmlfilename) :
49 G4VDiscreteProcess(processName,fElectromagnetic),
50 AthMessaging("TRTTransitionRadiation"),
51 m_XMLhandler(nullptr),m_xmlfilename(xmlfilename),
53 m_WplasmaFoil(0.0),m_GammaMin(0.0),m_EkinMin(0.0),m_Ey(nullptr),m_Sr(nullptr),
54 m_om(nullptr),m_Omg(nullptr),m_sigmaGas(nullptr),m_sigmaFoil(nullptr)
55{
56 m_radiators.clear();
57 m_XMLhandler = new TRRegionXMLHandler( this );
58
59 SetProcessSubType( fTransitionRadiation );
60
61 ATH_MSG_DEBUG ( "##### Constructor TRTTransitionRadiation" );
62
63 Initialize();
64
65 ATH_MSG_DEBUG ( "##### Constructor TRTTransitionRadiation done" );
66
67}
68
70
72 delete [] m_Ey;
73 delete [] m_Sr;
74 delete [] m_Omg;
75 delete [] m_om;
76 delete [] m_sigmaGas;
77 delete [] m_sigmaFoil;
78}
79
82
83 ATH_MSG_DEBUG(" New Radiator parameters being defined for TR process");
84 ATH_MSG_DEBUG(" Volume " << p.GetLogicalVolume()->GetName());
85 ATH_MSG_DEBUG(" FoilThickness " << p.GetFoilThickness());
86 ATH_MSG_DEBUG(" GasThickness " << p.GetGasThickness());
87
88 m_radiators.push_back(p);
89
90 return;
91}
92
93
95 ATH_MSG_DEBUG ( "Constructor TRTTransitionRadiation::Initialize()" );
96 m_NumBins = 100; // Bins for TR generation (Nevski has 25 bins)
97 m_MinEnergyTR = 2.0*CLHEP::keV; // Minimum TR energy
98 m_MaxEnergyTR = 50.0*CLHEP::keV; // Maximum TR energy
99
100 m_GammaMin = 500.; // Min. value of Lorentz gamma for TR generation
101 m_EkinMin = (m_GammaMin-1.)*CLHEP::electron_mass_c2;
102
103 //We get the materials from GeoMaterial manager and convert them to G4Materials
104 //
105 //NB: Maybe we should control this from TRT_GeoModel instead?
106 //
107 // On a related note we should get rid of the xml files too -
108 // they are a loophole in the versioning.
109
110 G4Material* g4mat_Gas{nullptr};
111 G4Material* g4mat_FoilMaterial{nullptr};
112 std::string errorMessage;
113
114 // Get material information from storegate.
115 ISvcLocator *svcLocator = Gaudi::svcLocator(); // from Bootstrap
116 SmartIF<StoreGateSvc> detStore{svcLocator->service( "DetectorStore")};
117 if (!detStore) {
118 errorMessage = "Can not access Detector Store";
119 ATH_MSG_FATAL (errorMessage);
120 throw std::runtime_error(errorMessage);
121 }
122
123 StoredMaterialManager* materialManager = detStore->tryRetrieve<StoredMaterialManager>("MATERIALS");
124 if(materialManager) {
125 Geo2G4MaterialFactory geo2g4_material_fact;//Note - this is a very lightweight class!
126 g4mat_Gas = geo2g4_material_fact.Build(materialManager->getMaterial("trt::CO2"));
127 g4mat_FoilMaterial = geo2g4_material_fact.Build(materialManager->getMaterial("trt::CH2"));
128
129 //Note: One might wonder if we now own g4mat_Gas and
130 //g4mat_FoilMaterial, but since the elementfactory used inside
131 //Geo2G4MaterialFactory is static, we must NOT delete them!!
132 }
133 else {
134 ATH_MSG_INFO("GeoModel Material is not available. Construct TR materials using IRDBAccessSvc interface");
135 SmartIF<IGeoDbTagSvc> geoDbTagSvc{svcLocator->service("GeoDbTagSvc")};
136 if (!geoDbTagSvc) {
137 errorMessage = "Can not access GeoDbTagSvc";
138 ATH_MSG_FATAL (errorMessage);
139 throw std::runtime_error(errorMessage);
140
141 return;
142 };
143 SmartIF<IRDBAccessSvc> pAccessSvc{svcLocator->service(geoDbTagSvc->getParamSvcName())};
144 if ( !pAccessSvc) {
145 errorMessage = "Can not access " + geoDbTagSvc->getParamSvcName();
146 ATH_MSG_FATAL (errorMessage);
147 throw std::runtime_error(errorMessage);
148 }
149
150 std::map<std::string,int> materialComponentsMap; // Number of elements for each material
151 std::map<std::string,G4Material*> materialMap;
152 IRDBRecordset_ptr materialsRec = pAccessSvc->getRecordsetPtr("TRMaterials","","");
153 // Step #1. Count elements per material
154 for (const IRDBRecord_ptr& material : *materialsRec) {
155 std::string key = material->getString("NAME");
156 auto mapIt = materialComponentsMap.find(key);
157 if (mapIt == materialComponentsMap.end()) {
158 materialComponentsMap.emplace(key,1);
159 }
160 else {
161 materialComponentsMap.at(key) = mapIt->second + 1;
162 }
163 }
164 // Step #2. Build materials
165 for (const IRDBRecord_ptr& material :*materialsRec) {
166 std::string key = material->getString("NAME");
167 G4Material* g4Material{nullptr};
168 if(materialMap.find(key)==materialMap.end()) {
169 auto itNElements = materialComponentsMap.find(key);
170 if (itNElements==materialComponentsMap.end()) continue;
171 g4Material = new G4Material(key
172 ,material->getDouble("DENSITY")*(CLHEP::gram / CLHEP::cm3)
173 ,itNElements->second);
174 materialMap.emplace(key,g4Material);
175 }
176 else {
177 g4Material = materialMap.at(key);
178 }
179
180 G4Element* g4Element = G4Element::GetElement(material->getString("ELEMENT_NAME"));
181 if(!g4Element) {
182 errorMessage = "Wrong name for element " + material->getString("ELEMENT_NAME")
183 + " found in the description of material " + key;
184 ATH_MSG_FATAL (errorMessage);
185 throw std::runtime_error(errorMessage);
186 }
187 g4Material->AddElement(g4Element,(G4int)material->getInt("N"));
188 }
189 g4mat_Gas = materialMap.at("CO2");
190 g4mat_FoilMaterial = materialMap.at("CH2");
191 }
192
193 G4double PlasmaCof(4.0*M_PI*CLHEP::fine_structure_const*CLHEP::hbarc*CLHEP::hbarc*CLHEP::hbarc/CLHEP::electron_mass_c2);
194
195 // Plate and gas indicies
196 m_WplasmaFoil = sqrt( PlasmaCof * g4mat_FoilMaterial->GetElectronDensity() );
197 m_WplasmaGas = sqrt( PlasmaCof * g4mat_Gas->GetElectronDensity() );
198
199 ATH_MSG_DEBUG("Foil material : " << g4mat_FoilMaterial->GetName()
200 << "; plasma energy : " << m_WplasmaFoil/CLHEP::eV << " eV");
201 ATH_MSG_DEBUG("Gas : " << g4mat_Gas->GetName()
202 << "; plasma energy : " << m_WplasmaGas/CLHEP::eV << " eV");
203
204 m_Omg = new G4double[m_NumBins];
205 m_om = new G4double[m_NumBins];
206 m_Ey = new G4double[m_NumBins];
207 m_Sr = new G4double[m_NumBins];
208 m_sigmaGas = new G4double[m_NumBins];
209 m_sigmaFoil = new G4double[m_NumBins];
210
211 for(G4int j(0); j<m_NumBins; ++j) {
212 m_Omg[j] = log( m_MinEnergyTR ) +
214 m_om [j] = exp( m_Omg[j] );
215 m_sigmaGas[j] = ComputePhotoAbsCof( g4mat_Gas, m_om[j] );
216 m_sigmaFoil[j] = ComputePhotoAbsCof( g4mat_FoilMaterial, m_om[j] );
217 }
218
219 const std::string file=PathResolver::find_file(m_xmlfilename,"DATAPATH");
220 if (!file.empty())
221 {
222 m_XMLhandler->Process(file);
223 }
224 else ATH_MSG_WARNING("File "<<m_xmlfilename<<" not found! Expect problems.");
225
226 ATH_MSG_DEBUG ( "Constructor TRTTransitionRadiation::Initialize() DONE!" );
227 return;
228
229}
230
232//
233// Returns condition for application of the model depending on particle type
234
235
236G4bool TRTTransitionRadiation::IsApplicable(const G4ParticleDefinition& particle) {
237 //return true if PDG Charge and PDG Mass are non-zero.
238 return ( std::abs(particle.GetPDGCharge())>std::numeric_limits<double>::epsilon() && std::abs(particle.GetPDGMass())>std::numeric_limits<double>::epsilon() ) ;
239}
240
242//
243// GetContinuousStepLimit
244//
245
246G4double TRTTransitionRadiation::GetMeanFreePath(const G4Track& aTrack,
247 G4double,
248 G4ForceCondition* condition) {
249 const G4DynamicParticle *aParticle(aTrack.GetDynamicParticle());
250 if(std::abs(aParticle->GetDefinition()->GetPDGCharge())< std::numeric_limits<double>::epsilon() ||
251 std::abs(aParticle->GetDefinition()->GetPDGMass())<std::numeric_limits<double>::epsilon() ) {
252 *condition = NotForced;
253 } else {
254 *condition = Forced;
255 }
256 return DBL_MAX;
257}
258
260//
261//
262G4VParticleChange* TRTTransitionRadiation::PostStepDoIt( const G4Track& aTrack,
263 const G4Step& aStep ) {
264 aParticleChange.Initialize(aTrack);
265
266 // Obtain kinetic energy
267 const G4DynamicParticle *aParticle(aTrack.GetDynamicParticle());
268 G4double KineticEnergy(aParticle->GetKineticEnergy());
269
270 // Kinetic energy too low for TR generation for any kind of particle
271 if ( KineticEnergy < m_EkinMin )
272 return G4VDiscreteProcess::PostStepDoIt(aTrack, aStep);
273
274 // Particle properties ...
275 G4double ParticleMass(aParticle->GetDefinition()->GetPDGMass());
276 G4double Gamma(1.0 + KineticEnergy/ParticleMass);
277
278 if( Gamma < m_GammaMin ) {
279 ATH_MSG_VERBOSE ( "Leaving PostStepDoIt(): Gamma < " << m_GammaMin );
280 return G4VDiscreteProcess::PostStepDoIt(aTrack, aStep);
281 }
282
283 G4double FoilThickness(0.);
284 G4double GasThickness(0.);
285 BEflag BEflag(BARREL); //enum?
286
287 // Check whether particle is inside radiator
288 std::vector<TRTRadiatorParameters>::const_iterator currentRadiator(m_radiators.begin());
289 const std::vector<TRTRadiatorParameters>::const_iterator endOfRadiators(m_radiators.end());
290 while(currentRadiator!=endOfRadiators) {
291 if ( currentRadiator->GetLogicalVolume() ==
292 aTrack.GetVolume()->GetLogicalVolume() ) {
293 FoilThickness = currentRadiator->GetFoilThickness();
294 GasThickness = currentRadiator->GetGasThickness();
295 BEflag = currentRadiator->GetBEflag();
296 break;
297 }
298 ++currentRadiator;
299 }
300 // Particle not inside radiator - return
301 if ( currentRadiator == endOfRadiators ) {
302 return G4VDiscreteProcess::PostStepDoIt(aTrack, aStep);
303 }
304
305 ATH_MSG_VERBOSE ( "PostStepDoIt(): Inside radiator "
306 << currentRadiator->GetLogicalVolume()->GetName() );
307
308 G4ThreeVector ParticleDirection(aParticle->GetMomentumDirection());
309
310 if ( BEflag == ENDCAP ) {
311 G4double costh(std::abs(ParticleDirection[2]));
312 FoilThickness /= costh;
313 GasThickness /= costh;
314 }
315
316 G4double StepLength(aStep.GetStepLength());
317 G4int FoilsTraversed(static_cast<G4int>(StepLength/(FoilThickness+GasThickness)+0.5));
318
319 // Steplength so short, that no foils are crossed.
320 // Forget it...
321 // Actually the treatment we do is only valid for "many" foils.
322 // Should we put this requirement higher?
323 if ( FoilsTraversed == 0 ) {
324 ATH_MSG_VERBOSE ( "Leaving PostStepDoIt(): No foils traversed." );
325 return G4VDiscreteProcess::PostStepDoIt(aTrack, aStep);
326 }
327
328 G4double Gy(0.), Gmany(0.), Neff(0.);
329
330 // Generate, in the language of Artru:
331 // 1) G_y
332 // 2) N_{eff}
333 // 3) G_{many}
334 // Divide by photon energy to get photon spectrum (m_Ey)
335
336 for( G4int i(0); i<m_NumBins; ++i ) {
337
338#ifdef ARTRU // Formulas from Artru
339 Gy = XEmitanArtru( m_om[i],
340 Gamma,
341 GasThickness,
342 FoilThickness );
343 Neff = NeffArtru( m_sigmaGas[i],
344 m_sigmaFoil[i],
345 GasThickness,
346 FoilThickness,
347 FoilsTraversed );
348#else
349 Gy = XEmitanNevski( m_om[i], // Formulas from Cherry via
350 Gamma, // Pavel Nevski in G3
351 GasThickness,
352 FoilThickness );
353 Neff = NeffNevski( m_sigmaGas[i],
354 m_sigmaFoil[i],
355 GasThickness,
356 FoilThickness,
357 FoilsTraversed );
358#endif
359
360 Gmany = Neff*Gy; // Energy spectrum
361 m_Ey[i] = Gmany / m_om[i]; // Photon spectrum
362
363 }
364
365 // Integrate spectrum
366 G4double Sph(XInteg( m_Ey, m_Sr ));
367 G4double Sph_org(Sph);
368
369 if ( ( BEflag == BARREL ) && (Gamma > 0.0) ) {
370 G4double tempLog10Gamma(log10(Gamma)); //Hardcoded numbers from TestBeam study (E.Klinkby). Better to move elsewhere.
371 G4double pHT_dEdxData = -0.001 + 0.0005*tempLog10Gamma;
372 G4double pHT_TRData = 0.15/(1.0 + exp(-(tempLog10Gamma - 3.3)/0.27));
373 G4double pHT_dEdxMC = -0.0031 + 0.00016*tempLog10Gamma;
374 G4double pHT_TRMC = 0.1289/(1.0 + exp(-(tempLog10Gamma - 3.01)/0.1253));
375
376 G4double fudge = std::min(2.0,(pHT_dEdxData+pHT_TRData)/( pHT_dEdxMC+pHT_TRMC));
377
378 Sph *= fudge;
379 }
380
381 // Now how many photons are generated?
382 G4long NumberOfPhotonsGenerated(CLHEP::RandPoisson::shoot(Sph));
383
384 //reset Sph to original value.
385 Sph = Sph_org;
386
387 ATH_MSG_VERBOSE ( ">>>> FoilsTraversed = " << FoilsTraversed
388 << ", Gamma = " << Gamma
389 << ", Sph = " << Sph
390 << ", Nph = " << NumberOfPhotonsGenerated );
391 // No photons, return
392 if ( NumberOfPhotonsGenerated <= 0 ) {
393 ATH_MSG_VERBOSE ( "Leaving TRTTransitionRadiation::PostStepDoIt: "
394 << "No photons generated." );
395
396 return G4VDiscreteProcess::PostStepDoIt(aTrack, aStep);
397 }
398
399 // Now, generate the photons
400 aParticleChange.SetNumberOfSecondaries( NumberOfPhotonsGenerated );
401 G4StepPoint *pPostStepPoint(aStep.GetPostStepPoint());
402 G4ThreeVector x0(pPostStepPoint->GetPosition());
403
404 G4double Esum(0.), XRannu(0.), Ephot(0.), Theta(0.), Phi(0.),
405 X(0.), Y(0.), Z(0.);
406
407 G4ThreeVector pos(0),TRPhotonDirection(0);
408
409 for( G4int i(0); i<NumberOfPhotonsGenerated; ++i ) {
410 XRannu = CLHEP::RandFlat::shoot();
411 Ephot = exp( XFinter( XRannu*Sph, m_Sr, m_Omg ) );
412
413 Esum += Ephot;
414
415 pos = pPostStepPoint->GetPosition();
416
417 ATH_MSG_VERBOSE ( " Photon generated with energy : " << Ephot/CLHEP::keV
418 << " keV; position: ( " << pos.x()/CLHEP::cm << " cm, "
419 << pos.y()/CLHEP::cm << " cm, " << pos.z()/CLHEP::cm << " cm )" );
420
421 // Angle w.r.t. electron direction (this is not correct but anyway...)
422 Theta = std::abs( CLHEP::RandGaussZiggurat::shoot( 0.0, M_PI/Gamma ) );
423 if( Theta >= 0.1 ) Theta = 0.1;
424
425 Phi = (2.*M_PI)*CLHEP::RandFlat::shoot();
426
427 X = sin(Theta)*cos(Phi);
428 Y = sin(Theta)*sin(Phi);
429 Z = cos(Theta);
430
431 TRPhotonDirection.set(X,Y,Z);
432 TRPhotonDirection.rotateUz( ParticleDirection );
433 TRPhotonDirection.unit();
434
435 G4DynamicParticle*
436 TRPhoton = new G4DynamicParticle( G4Gamma::Gamma(),
437 TRPhotonDirection,
438 Ephot );
439 aParticleChange.AddSecondary( TRPhoton );
440
441 }
442
443 aParticleChange.ProposeEnergy( KineticEnergy-Esum );
444
445 ATH_MSG_VERBOSE ( "Leaving TRTTransitionRadiation::PostStepDoIt; "
446 << "Number of TR photons generated: " << NumberOfPhotonsGenerated );
447
448 return &aParticleChange;
449}
450
451inline G4double TRTTransitionRadiation::NeffNevski( const G4double & sigGas,
452 const G4double & sigFoil,
453 const G4double & GasThickness,
454 const G4double & FoilThickness,
455 const G4int & FoilsTraversed ) const {
456 if ( FoilsTraversed <= 0 )
457 return 0.;
458
459 G4double C1 = sigGas * GasThickness*FoilsTraversed;
460 G4double C2 = sigFoil*FoilThickness*FoilsTraversed;
461
462 G4double W1 = exp(-C1);
463 G4double W2 = exp(-C2);
464
465 return FoilsTraversed * (1-W1*W2)/(C1+C2);
466}
467
468inline G4double TRTTransitionRadiation::NeffArtru( const G4double & sigGas,
469 const G4double & sigFoil,
470 const G4double & GasThickness,
471 const G4double & FoilThickness,
472 const G4int & FoilsTraversed ) const {
473 if ( FoilsTraversed <= 0 )
474 return 0.;
475
476 G4double sigma = FoilThickness*sigFoil + GasThickness*sigGas;
477 G4double xNF = FoilsTraversed;
478 return (1.-exp(-xNF*sigma))/(1.-exp(-sigma));
479}
480
482//
483// Nevskis XEmitan-function
484//
485//inline G4double max(G4double a, G4double b) {return a>b?a:b;}
486
487inline G4double TRTTransitionRadiation::XEmitanNevski( const G4double & PhotonEnergy,
488 const G4double & Gamma,
489 const G4double & Al1,
490 const G4double & Al2 ) const {
491 //FIXME hardcoded numbers are not good.
492 G4double eps = 0.05;
493
494 G4double Al = Al1 + Al2;
495
496 G4double CK = 1/(2*M_PI*CLHEP::hbarc);
497
498 // Plasma frequencies:
499 G4double om1 = m_WplasmaGas;
500 G4double om2 = m_WplasmaFoil;
501
502 G4double om12 = (om1*om1-om2*om2)/PhotonEnergy;
503 G4double oms = (Al1*om1*om1+Al2*om2*om2)/Al;
504 G4double Ao = 0.5*Al1*om12*CK;
505 G4double Bo = 0.5*Al2*om12*CK;
506 G4double ro = sqrt(oms)/Gamma;
507 G4double co = 0.5*(PhotonEnergy/(Gamma*Gamma)+oms/PhotonEnergy);
508 G4double cc = co*Al*CK;
509 G4double cb = M_PI*Al2/Al;
510 G4int i1 = static_cast<G4int>(1.0+(ro>co?ro:co)*Al*CK);//(G4int)(1.0+max(ro,co)*Al*CK);
511 G4int i2 = static_cast<G4int>(Gamma*ro*Al*CK);
512
513 G4double Sum = 0.0;
514 G4double Smx = 0.0;
515 G4double Sm1 = 0.0;
516 G4double S = 0.0;
517 G4double So = 0.0;
518
519 G4double Sx = 0.0;
520
521 for(G4int i(i1); i<=i2; ++i) {
522 Sx = So;
523 So = S;
524 S = (static_cast<G4double>(i)-cc)*(sin(cb*(static_cast<G4double>(i)-Ao))/((static_cast<G4double>(i)-Ao)*(static_cast<G4double>(i)+Bo)))*
525 (sin(cb*(static_cast<G4double>(i)-Ao))/((static_cast<G4double>(i)-Ao)*(static_cast<G4double>(i)+Bo)));
526 Smx=Smx>S?Smx:S;//max(Smx,S);
527 Sm1=Sm1>S?Sm1:S;//max(Sm1,S);
528 Sum += S;
529
530 if( (So<Sx)&&(So<=S) ) {
531 if( Sm1<eps*Smx ) break;
532 Sm1 = 0.0;
533 }
534 }
535
536 return ( CLHEP::fine_structure_const*om12*om12*Al*Al*CK*CK*Sum/M_PI );
537}
538
540//
541// Same as above but for the Artru way of doing things
542//
543inline G4double TRTTransitionRadiation::XEmitanArtru( const G4double & omega,
544 const G4double & Gamma,
545 const G4double & d2,
546 const G4double & d1 ) const {
547 G4double phimax = 4.*M_PI;
548 G4double ginv2 = 1./(Gamma*Gamma);
549 G4double tau = d2/d1;
550
551 G4double mom = omega/CLHEP::hbarc;
552
553 G4double xi1 = m_WplasmaFoil/omega;
554 G4double xi2 = m_WplasmaGas/omega;
555
556 G4double xi1sq = xi1*xi1;
557 G4double xi2sq = xi2*xi2;
558
559 G4double Z1 = 2./(mom*(ginv2+xi1sq));
560 G4double Z2 = 2./(mom*(ginv2+xi2sq));
561
562 G4double a = d1/Z2;
563 G4double V = d1*(1./Z1-1./Z2);
564
565 G4double p0 = mom*d1*(xi1sq-xi2sq)/(4.*M_PI);
566 G4double pmin = p0 + a*(1.+tau)/(2.*M_PI);
567 G4double ymax = tau*phimax;
568 G4double pmax = p0 + ymax*(1.+tau)/(2.*M_PI);
569
570 G4int ipmin = (int)pmin+1;
571 G4int ipmax = (int)pmax;
572
573 G4double sum=0.;
574 G4double y0 = -0.5*mom*d1*(xi1sq-xi2sq)/(1+tau);
575 G4double dy = (2.*M_PI)/(1+tau);
576 G4double y;
577
578 G4double term = 0.;
579 G4double t1 = 0.;
580 G4double t2 = 0.;
581 G4double tx = 0.;
582
583 for ( G4int ip(ipmin); ip<=ipmax; ++ip ) {
584 t2 = t1;
585 t1 = term;
586
587 y = y0 + ip*dy;
588 term = (1./y-1./(y+V))*sin(0.5*(y+V));
589 term *= term;
590 term *= y-a;
591 sum += term;
592
593 //G4double theta2 = 2.*y*tau/(mom*d2) - ginv2 - xi2sq;
594 //G4double theta = sqrt(theta2);
595
596 tx = (tx>term) ? tx : term;
597
598 // Locate local maxima (previous term)
599
600 if ( t2 > 0. && t1 > term && t1 > t2 ) {
601 if ( t1 < 0.0001*sum ) break;
602 }
603 }
604
605 return ( sum*4.*2.*CLHEP::fine_structure_const/(1.+tau));
606}
607
609//
610// Nevskis XInteg function
611// Spectrum integration
612//
613
614inline G4double TRTTransitionRadiation::XInteg( const G4double * yy, G4double * ss ) const {
615 G4double S(0.);
616 ss[0] = 0.;
617
618 for( G4int i(1); i<m_NumBins; ++i ) {
619 S += 0.5*( m_Omg[i]-m_Omg[i-1] )*( yy[i-1]*m_om[i-1] + yy[i]*m_om[i] );
620 ss[i] = S;
621 }
622
623 return S;
624}
625
627//
628// Nevskis XFINTER function
629
630G4double TRTTransitionRadiation::XFinter( const G4double & X, const G4double* A, const G4double* F ) const {
631 G4int K1(0);
632 G4int K2(0);
633
634 if( (K1>=m_NumBins) || ( X < A[K1] ) ) K1 = 0; //FIXME This line has no effect?
635 if( (K2>=m_NumBins) || ( X > A[K2] ) ) K2 = m_NumBins-1;
636
637 G4int K(0);
638 while( K2-K1>1 ) {
639 K = static_cast<G4int>((K1+K2)/2);
640 if( A[K]<X ) {
641 K1 = K;
642 } else {
643 K2 = K;
644 }
645 }
646
647 G4double X1(A[K1]);
648 G4double X2(A[K1+1]);
649
650 G4double xfinter((F[K1]*(X-X2)+F[K1+1]*(X1-X))/(X1-X2));
651 return xfinter;
652}
653
655//
656// Computes Sandia photo absorption cross section coefficients for Material
657
659 const G4double & PhotonEnergy ) const {
660
661 const G4double *SandiaCof(Material->GetSandiaTable()->GetSandiaCofForMaterial(PhotonEnergy));
662
663 const G4double Energy2(PhotonEnergy*PhotonEnergy);
664 const G4double Energy3(PhotonEnergy*Energy2);
665 const G4double Energy4(Energy2*Energy2);
666
667 return ( SandiaCof[0]/PhotonEnergy +
668 SandiaCof[1]/Energy2 +
669 SandiaCof[2]/Energy3 +
670 SandiaCof[3]/Energy4 );
671}
#define M_PI
#define ATH_MSG_FATAL(x)
#define ATH_MSG_INFO(x)
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
defines an "iterator" over instances of a given type in StoreGateSvc
Definition of the abstract IRDBAccessSvc interface.
std::shared_ptr< IRDBRecordset > IRDBRecordset_ptr
Definition of the abstract IRDBRecord interface.
Definition of the abstract IRDBRecordset interface.
std::unique_ptr< IRDBRecord > IRDBRecord_ptr
static Double_t a
static Double_t ss
#define F(x, y, z)
Definition MD5.cxx:112
@ Material
@ Phi
Definition RPCdef.h:8
#define y
AthMessaging(IMessageSvc *msgSvc, const std::string &name)
Constructor.
G4Material * Build(const GeoMaterial *)
static std::string find_file(const std::string &logical_file_name, const std::string &search_path)
This class holds one or more material managers and makes them storeable, under StoreGate.
virtual const GeoMaterial * getMaterial(const std::string &name)=0
G4bool IsApplicable(const G4ParticleDefinition &)
G4double NeffNevski(const G4double &sigGas, const G4double &sigFoil, const G4double &GasThickness, const G4double &FoilThickness, const G4int &FoilsTraversed) const
void AddRadiatorParameters(const TRTRadiatorParameters &p)
G4VParticleChange * PostStepDoIt(const G4Track &aTrack, const G4Step &aStep)
G4double XFinter(const G4double &X, const G4double *A, const G4double *F) const
G4double XInteg(const G4double *yy, G4double *ss) const
std::vector< TRTRadiatorParameters > m_radiators
G4double XEmitanNevski(const G4double &PhotonEnergy, const G4double &Gamma, const G4double &GasThickness, const G4double &FoilThickness) const
G4double NeffArtru(const G4double &sigGas, const G4double &sigFoil, const G4double &GasThickness, const G4double &FoilThickness, const G4int &FoilsTraversed) const
G4double XEmitanArtru(const G4double &PhotonEnergy, const G4double &Gamma, const G4double &GasThickness, const G4double &FoilThickness) const
TRTTransitionRadiation(const G4String &processName="TransitionRadiation", const std::string &xmlfilename="TRgeomodelgeometry.xml")
TRRegionXMLHandler * m_XMLhandler
G4double GetMeanFreePath(const G4Track &aTrack, G4double, G4ForceCondition *)
G4double ComputePhotoAbsCof(const G4Material *Material, const G4double &GammaEnergy) const
double ymax
Definition listroot.cxx:64
hold the test vectors and ease the comparison
TFile * file