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