ATLAS Offline Software
Loading...
Searching...
No Matches
TRT_PAI_effectiveGas.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#include "TRT_PAI_Process.h"
9#include "TRT_PAI_element.h"
10#include "TRT_PAI_utils.h"
13
14#include <vector>
15#include <iostream>
16#include <complex>
17#include <cmath>
18#include <algorithm> //for std::max, std::clamp
19
20#include "CLHEP/Units/SystemOfUnits.h"
21
22//____________________________________________________________________________
23
25 double Emin,
26 double Emax,
27 double tempK,
28 double eps)
29 : AthMessaging("TRT_PAI_effectiveGas"),
30 m_lnEmin(std::log(Emin)),
31 m_lnEmax(std::log(Emax)),
32 m_eps(eps)
33{
34 // Tell clang to optimize assuming that FP may trap.
36
37 using namespace TRT_PAI_physicsConstants;
38
40 double rho = 0.;
41 double Zeff = 0.;
42 double Aeff = 0.;
43 double w = 0.;
44 double wtot = 0.;
45 int Nelem = gm->getNElements();
46
47 for ( int k=0; k<Nelem; k++ ) {
48 pe = gm->getElement(k);
49 w = gm->getElemWeight(k);
50 wtot += w;
51 rho += w * pe->getDensity(tempK);
52 Aeff += w * pe->getAtomicA();
53 Zeff += w * pe->getAtomicZ();
54 }
55 if (wtot == 0.)[[unlikely]]{
56 ATH_MSG_ERROR("TRT_PAI_effectiveGas::TRT_PAI_effectiveGas: wtot is zero.");
57 return;
58 }
59 Aeff /= wtot;
60 Zeff /= wtot;
61
62 m_ne = Nav*rho*Zeff/Aeff; // Electron density
63 m_Wp2 = 4.*M_PI*r0*m_ne*he*he; // plasma freq**2 {ev}
64 m_S1 = mb/(2.*M_PI*M_PI*r0*he*Zeff); // x-section to F.osc
65 m_S2 = 2.*M_PI*r0*m_ne*Qe*Qe/erg; // dN/dx scale
66
67 ATH_MSG_DEBUG ( "effectiveGas: Electron density " << m_ne );
68 ATH_MSG_DEBUG ( "effectiveGas: Plasma freq**2 {eV} " << m_Wp2 );
69 ATH_MSG_DEBUG ( "effectiveGas: x-section to F.osc " << m_S1 );
70 ATH_MSG_DEBUG ( "effectiveGas: dN/dx scale " << m_S2 );
71
72 // Merge all energy levels into ELvls
73 std::vector<float> tempv;
74 for ( int k=0; k<Nelem; k++ ) {
75 pe = gm->getElement(k);
76 tempv = pe->getLnELvls();
77 m_lnELvls.insert( m_lnELvls.end(), tempv.begin(), tempv.end() );
78 }
79
80 // Insert also Emin and Emax into ELvls, then sort
81 m_lnELvls.push_back(m_lnEmin);
82 m_lnELvls.push_back(m_lnEmax);
83 sort(m_lnELvls.begin(),m_lnELvls.end());
84
85 std::vector<float>::iterator vit;
86
87 // Remove duplicate energies
88 vit = unique(m_lnELvls.begin(), m_lnELvls.end());
89 m_lnELvls.erase(vit, m_lnELvls.end());
90
91 // Remove everything below Emin
92 vit = lower_bound(m_lnELvls.begin(), m_lnELvls.end(), m_lnEmin);
93 m_lnELvls.erase(m_lnELvls.begin(), vit);
94
95 // Remove everything above Emax
96 vit = upper_bound(m_lnELvls.begin(), m_lnELvls.end(), m_lnEmax)-1;
97 m_lnELvls.erase(vit, m_lnELvls.end());
98
99 int NLvls = m_lnELvls.size();
100
101
102 // Expand vectors to correct dimension
103 m_lnFosc.resize(NLvls);
104 m_lnIntegratedSigmas.resize(NLvls);
105 m_lnEpsI.resize(NLvls);
106 m_lnEpsR.resize(NLvls);
107
108 // create array of effective cross sections (Fosc).
109
110 for ( int i=0; i<NLvls; i++ ) {
111 double fosc = 0.;
112 // all atoms with an absorbtion energylevel low enough contribute.
113 for ( int k=0; k<Nelem; k++ ) {
114 pe = gm->getElement(k);
115 if ( m_lnELvls[i] >= pe->getLnELvls()[0] ) {
116 double lnSig = TRT_PAI_utils::Interpolate( m_lnELvls[i],
117 pe->getLnELvls(),
118 pe->getLnSigmas() );
119 fosc += std::exp(lnSig) * gm->getElemWeight(k);
120 }
121 }
122 //clamp, just in case
123 fosc = std::clamp(fosc, 1e-300,1e+300);
124 m_lnFosc[i] = std::log(fosc);
125 }
126
127 // Create array of integrated cross-sections
128 double sigma = 0.;
129 double lnSigma = 0.;
130 double lnEHigh;
131 double lnELow = m_lnEmax;
132 double dsigma;
133
134 for ( int i=NLvls-1; i>=0; --i) {
135 lnEHigh = lnELow;
136 lnELow = m_lnELvls[i];
138 lnELow,
139 lnEHigh,
140 m_eps,
141 0.);
142 sigma += dsigma;
143 lnSigma = std::log(sigma);
144 m_lnIntegratedSigmas[i] = lnSigma;
145 }
146
147 // Normalize
148 for ( int i=0; i<NLvls; i++) {
149 m_lnFosc[i] -= lnSigma;
150 m_lnIntegratedSigmas[i] -= lnSigma;
151 }
152
153 double cnst = std::log(M_PI_2*m_Wp2);
154 for (int i=0; i<NLvls; i++) {
155 m_lnEpsI[i] = cnst - m_lnELvls[i] + m_lnFosc[i];
157 0.,
158 m_lnEmax,
159 m_eps,
160 m_lnELvls[i] );
161 m_lnEpsR[i] = m_Wp2 * std::exp(m_lnELvls[i]) * xint;
162 }
163 return;
164}
165
166//____________________________________________________________________________
167
168double TRT_PAI_effectiveGas::XSigma (double lnE, double dummy) {
169 double xsig = dummy;
170 xsig = TRT_PAI_utils::Interpolate(std::max(lnE,m_lnEmin),
171 m_lnELvls,
172 m_lnFosc);
173 xsig = std::max(xsig,-99.);
174 xsig = std::exp( xsig + lnE );
175 return xsig;
176}
177
178//____________________________________________________________________________
179
180double TRT_PAI_effectiveGas::XFReal (double lnD, double lnE) {
181
182 double fp = 0.;
183 if ( lnE+lnD > m_lnEmin ) {
185 fp = std::exp(std::max(fp, -99.0));
186 }
187
188 double fm = 0.;
189 if (lnE-lnD > m_lnEmin ) {
191 fm = std::exp(std::max(fm, -99.0));
192 }
193
194 double x = std::exp(lnD);
195 return x/(x*x-1.)*(fp-fm);
196}
197
198//____________________________________________________________________________
199
200double TRT_PAI_effectiveGas::XGInt( double (TRT_PAI_effectiveGas::*pt2Func)(double,double),
201 double lnLo,
202 double lnHi,
203 const double eps,
204 double extraParameter ) {
205 //
206 // Pavel Nevskis "famous integration procedure"
207 //
208 // Applies the Gauss-Legendre Quadrature method with n=4
209
210 // These constants belong to the Gauss-Legendre quadrature method:
211 const int M = 4; // 4 points
212 const double U[M]={-.8611363,-.3399810, .3399810 ,.8611363}; // abscissas
213 const double W[M]={ .3478548, .6521452, .6521452, .3478548}; // weights
214
215 int N=10;
216 double OTB=0,Y,D,result;
217
218 double Dt = 0.5*(lnHi-lnLo);
219
220 do {
221 Y = OTB;
222 OTB = 0.;
223 D = Dt/N;
224 for (int i=1; i<=N; i++) {
225 for (int k=0; k<M; k++) {
226 double arg = lnLo + D*(2*i-1+U[k]);
227 OTB += W[k] * (this->*pt2Func)(arg, extraParameter );
228 }
229 }
230 OTB *= D;
231 result = OTB;
232 N *= 2;
233 if ( N>100000 ) {
234 ATH_MSG_WARNING( "effectiveGas::XGInt: integrate Divergence! " << std::abs(OTB-Y) << " " << std::abs(eps*OTB) );
235 break;
236 }
237 } while ( (std::abs(OTB-Y) > std::abs(eps*OTB)) && (eps>0) );
238
239 return result;
240}
241
242//____________________________________________________________________________
243
244double TRT_PAI_effectiveGas::dndedx(double lnE, double gamma) {
245
246 using namespace TRT_PAI_physicsConstants;
247 using namespace TRT_PAI_utils;
248
249 double E = std::exp(lnE);
250 double gammaSq = gamma*gamma;
251 double betaSq = 1.-1./gammaSq;
252
253 double er = Interpolate(lnE, m_lnELvls, m_lnEpsR);
254 double ei = Interpolate(lnE, m_lnELvls, m_lnEpsI);
255
256 std::complex<double> Ceps1(er/(E*E), std::exp(ei));
257 std::complex<double> C1 = 1./gammaSq - Ceps1*betaSq;
258 std::complex<double> C2 = C1/(1.+Ceps1) * std::log(2.*betaSq*MeeV/(E*C1));
259
260 double x;
262 x = m_S2/betaSq * E * ( -2.*imag(C2)/(m_Wp2*M_PI) + (1.-std::exp(x))/(E*E) );
263
264 return x;
265}
266
267//____________________________________________________________________________
268
269void TRT_PAI_effectiveGas::GasTab(const std::vector<float> & gamvec,
270 std::vector<float>& lnEarray,
271 std::vector< std::vector<float> >& fnArray,
272 std::vector<float>& dndx)
273{
274 // For a given gamma factor, return dn/dx
275 // (by integrating dn^2/dEdx with respect to E)
276 // and tabulated values of dn^2/dEdx(?)....
277
278 double Rener = 0.05;
279
280 int NLvls = m_lnELvls.size();
281 int nGamVals = gamvec.size();
282
283 double lnEi = m_lnEmax;
284 double lnEo;
285 double lnEs = -99999999.;
286
287 fnArray.resize(nGamVals);
288 int nEVals = 0;
289
290 // Initialize
291 for ( int ig=0; ig<nGamVals; ++ig ) {
292 fnArray[ig].push_back(0.);
293 }
294
295 // Calculate integral from above and store the cumulative values in fnArray
296
297 for ( int ie=NLvls-1; ie>=0; --ie ) {
298 lnEo = lnEi;
299 lnEi = m_lnELvls[ie];
300 for ( int ig=0; ig<nGamVals; ++ig ) {
301 double ds =
302 XGInt( &TRT_PAI_effectiveGas::dndedx, lnEi, lnEo, m_eps, gamvec[ig]);
303 fnArray[ig][nEVals] += ds;
304 }
305 if ( std::abs(lnEs-lnEi) > Rener || ie==0 ) {
306 lnEs = lnEi;
307 lnEarray.push_back( lnEs );
308 if ( ie>0 ) {
309 for ( int ig=0; ig<nGamVals; ++ig ) {
310 fnArray[ig].push_back( fnArray[ig][nEVals] );
311 }
312 }
313 nEVals++;
314 }
315 }
316
317 // Copy the total integral into auxillary vector
318 dndx.resize(nGamVals);
319 for ( int ig = 0; ig < nGamVals; ++ig ) {
320 dndx[ig] = fnArray[ig][nEVals-1];
321 }
322
323 return;
324}
325
#define M_PI
#define ATH_MSG_ERROR(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
void sort(typename DataModel_detail::iterator< DVL > beg, typename DataModel_detail::iterator< DVL > end)
Specialization of sort for DataVector/List.
#define x
AthMessaging(IMessageSvc *msgSvc, const std::string &name)
Constructor.
std::vector< float > m_lnEpsI
double XFReal(double lnD, double lnE)
double XGInt(double(TRT_PAI_effectiveGas::*pt2Func)(double, double), double lnLo, double lnHi, const double eps, double extraParameter)
std::vector< float > m_lnELvls
double XSigma(double lnE, double dummy)
std::vector< float > m_lnIntegratedSigmas
void GasTab(const std::vector< float > &gamvec, std::vector< float > &EArray, std::vector< std::vector< float > > &fnArray, std::vector< float > &dndx)
Tabulate double differential distribution.
std::vector< float > m_lnEpsR
std::vector< float > m_lnFosc
double dndedx(double lgE, double gamma)
TRT_PAI_effectiveGas(TRT_PAI_gasMixture *gm, double Emin, double Emax, double tempK, double eps)
Chemical element.
Gas mixture = mixture of gas components.
TRT_PAI_element * getElement(unsigned int n)
Get element no.
double getElemWeight(unsigned int n)
Get weight of element no.
int getNElements()
Get number of different element in this gas mixture.
#define unlikely(x)
Definition dictionary.h:41
const double erg
1 ev to erg {erg}
const double Nav
Avagadro constant.
const double Qe
Electron charge{ESU}.
const double r0
electron radius{cm}
Utilities.
float Interpolate(const float &xval, const std::vector< float > &xtabulated, const std::vector< float > &ytabulated)
Interpolation function.
STL namespace.
Tell the compiler to optimize assuming that FP may trap.
#define CXXUTILS_TRAPPING_FP
Definition trapping_fp.h:24