ATLAS Offline Software
Loading...
Searching...
No Matches
TRT_PAI_Process.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration
3*/
4
5#include "TRT_PAI_Process.h"
6#include "TRT_PAI_gasdata.h"
7#include "TRT_PAI_element.h"
12#include "TRT_PAI_utils.h"
13
14#include "GaudiKernel/MsgStream.h"
15#include "GaudiKernel/ServiceHandle.h"
16
17#include "CLHEP/Units/SystemOfUnits.h"
18
19// For Athena-based random numbers
20#include "CLHEP/Random/RandomEngine.h"
21#include "CLHEP/Random/RandFlat.h"
22
23// To get TRT dig. settings:
25
26#include <vector>
27#include <map>
28#include <cmath>
29#include <iostream>
30
31//__________________________________________________________________________
32
34 const std::string& name,
35 const IInterface* parent )
36 : base_class( type, name, parent )
38{
39 //Properties:
40 declareProperty( "GasType", m_gasType, "Gas Type" );
41}
42//__________________________________________________________________________
44
45 using namespace TRT_PAI_gasdata;
46 using namespace TRT_PAI_physicsConstants;
47
48 ATH_MSG_VERBOSE ( "TRT_PAI_Process::initialize()" );
49
50 // Supported gasType's are 70%/27%/03%:
51 // 1) "Xenon" - Xe/CO2/O2
52 // 2) "Argon" - Ar/CO2/O2
53 // 3) "Kryton" - Kr/CO2/O2
54 //
55 // Figure out which type of gas we are having:
56
57 ATH_MSG_DEBUG ( "Gastype read as " << m_gasType );
58
59 std::string gasType = "NotSet";
60 // Here m_gasType="Auto" was previously used to prompt a
61 // check of InDetDD::TRT_DetectorManager for whether we want
62 // the old Xenon mix: Xe/CO2/CF4 or the new one: Xe/CO2/O2
63 // Nowadays, it is always the new one, so we don't check this anymore.
64
65 if ( m_gasType == "Auto" )
66 {
67 gasType = "Xenon";
68 }
69 else if ( m_gasType == "Xenon" || m_gasType == "Argon" || m_gasType == "Krypton" )
70 {
71 ATH_MSG_DEBUG ( "Gastype is overriden from joboptions to be " << m_gasType );
72 gasType = m_gasType;
73 }
74 else
75 {
76 ATH_MSG_FATAL ( "GasType property set to '" << m_gasType
77 << "'. Must be one of 'Auto', 'Xenon', 'Argon' or 'Krypton'." );
78 return StatusCode::FAILURE;
79 };
80
81 ATH_MSG_INFO ( name() << " will use gas type = " << gasType );
82
83 // Done with "trivial" initialization.
84 // Finally we can start to construct gas
85
86 ATH_MSG_VERBOSE ( "Constructing gas mixture." );
87
88 // Need the gas temperature
89 const double tempK = 289.; // At 289. degrees, we get same densities as Nevski had
90
91 // Define elements
92 using element_type = std::map<std::string, TRT_PAI_element, std::less<std::string>>;
93
94 element_type elements;
95 elements["Xe"] = TRT_PAI_element( "Xe", EXe , SXe , NXe , ZXe, AXe);
96 elements["C"] = TRT_PAI_element( "C" , EC , SC , NC , ZC , AC );
97 elements["F"] = TRT_PAI_element( "F" , EF , SF , NF , ZF , AF );
98 elements["O"] = TRT_PAI_element( "O" , EO , SO , NO , ZO , AO );
99 elements["Ar"] = TRT_PAI_element( "Ar", EAr , SAr , NAr , ZAr, AAr);
100 elements["Kr"] = TRT_PAI_element( "Kr", EKr , SKr , NKr , ZKr, AKr);
101
102 // Print out elements
103 {
104 for (element_type::iterator ei=elements.begin(); ei!=elements.end(); ++ei) {
105 ATH_MSG_DEBUG ( ". Element " << (*ei).second.getName()
106 << ", A= " << (*ei).second.getAtomicA()
107 << ", Z= " << (*ei).second.getAtomicZ()
108 << ", rho=" << (*ei).second.getDensity(tempK)
109 << " (" << tempK << " Kelvin)"
110 );
111 }
112 }
113
114 // Define gas components
115
116 using component_type = std::map<std::string, TRT_PAI_gasComponent, std::less<std::string>>;
117
118 component_type components;
119
120 components["Xe"] = TRT_PAI_gasComponent("Xe");
121 components["Xe"].addElement(&elements["Xe"],1);
122
123 components["CO2"] = TRT_PAI_gasComponent("CO2");
124 components["CO2"].addElement(&elements["C"],1);
125 components["CO2"].addElement(&elements["O"],2);
126
127 components["CF4"] = TRT_PAI_gasComponent("CF4");
128 components["CF4"].addElement(&elements["C"],1);
129 components["CF4"].addElement(&elements["F"],4);
130
131 components["O2"] = TRT_PAI_gasComponent("O2");
132 components["O2"].addElement(&elements["O"],2);
133
134 components["Ar"] = TRT_PAI_gasComponent("Ar");
135 components["Ar"].addElement(&elements["Ar"],1);
136
137 components["Kr"] = TRT_PAI_gasComponent("Kr");
138 components["Kr"].addElement(&elements["Kr"],1);
139
140 // Print out gas components
141
142 {
143 std::vector<std::string> cnam(6);
144 cnam[0] = "Xe"; cnam[1] = "CO2"; cnam[2] = "CF4"; cnam[3] = "CO2"; cnam[4] = "Ar"; cnam[5] = "Kr";
145
146 int n;
147 for ( int ic=0; ic<6; ++ic ) {
148 n = components[cnam[ic]].getNElementTypes();
149 ATH_MSG_DEBUG ( ". Gas component " << components[cnam[ic]].getName() << " contains");
150 for ( int ie=0; ie<n; ++ie ) {
151 ATH_MSG_DEBUG ( " - " << components[cnam[ic]].getElementMultiplicity(ie)
152 << " atoms " << (components[cnam[ic]].getElement(ie))->getName()
153 << " with Z= " << (components[cnam[ic]].getElement(ie))->getAtomicZ()
154 << " and A= " << (components[cnam[ic]].getElement(ie))->getAtomicA()
155 );
156 }
157 ATH_MSG_DEBUG ( " > density: " << components[cnam[ic]].getDensity(tempK) << " (" << tempK << " Kelvin)" );
158 }
159 }
160
161 // Construct TRT gas mixture
162 std::string mixtureName="TRT Gas Mixture";
163 mixtureName.insert(4, gasType);
164 m_trtgas = new TRT_PAI_gasMixture(mixtureName);
165
166 if ( gasType == "Xenon" ) {
167 ATH_MSG_DEBUG ( "Using new Xenon gas mixture (Xe/CO2/O2 - 70/27/3)." );
168 m_trtgas->addComponent( &components["Xe"] , 0.70);
169 m_trtgas->addComponent( &components["CO2"], 0.27);
170 m_trtgas->addComponent( &components["O2"] , 0.03);
171 }
172
173 if (( gasType == "XenonOld" )){
174 ATH_MSG_DEBUG ( "Using old Xenon gas mixture (Xe/CO2/CF4 - 70/10/20)." );
175 m_trtgas->addComponent( &components["Xe"] , 0.70);
176 m_trtgas->addComponent( &components["CO2"], 0.10);
177 m_trtgas->addComponent( &components["CF4"], 0.20);
178 }
179
180 if ( gasType == "Argon" ) {
181 ATH_MSG_DEBUG ( "Using Argon gas mixture (Ar/CO2/O2 - 70/27/3)." );
182 m_trtgas->addComponent( &components["Ar"] , 0.70);
183 m_trtgas->addComponent( &components["CO2"], 0.27);
184 m_trtgas->addComponent( &components["O2"] , 0.03);
185 }
186
187 if ( gasType == "Krypton" ) {
188 ATH_MSG_DEBUG ( "Using Krypton gas mixture (Kr/CO2/O2 - 70/27/3)." );
189 m_trtgas->addComponent( &components["Kr"] , 0.70);
190 m_trtgas->addComponent( &components["CO2"], 0.27);
191 m_trtgas->addComponent( &components["O2"] , 0.03);
192 }
193
194 m_trtgas->freezeGas();
195
196 m_trtgas->showStructure();
197
198 // Create and initialize effective gas
199 // Sasha: to check: does Emin depends from Energy levels of active gas?
200 // for Xenon lowest energetic level is 12.08 eV
201 // for Argon - 15.83 eV. Does Emin should be different for Argon???
202
203 const double Emin = 12.0; // [eV]
204 const double Emax = 1e+07; // [eV]
205 // Don't change Emax from 10 MeV without
206 // talking to Pavel Nevski!
207 const double eps = 0.01; // Epsilon for numeric integration
208
209 TRT_PAI_effectiveGas effectiveGas(m_trtgas, Emin, Emax, tempK, eps);
210
211 // Now tabulate...
212
213 ATH_MSG_DEBUG ( "Making tables for various gamma factors." );
214
215 std::vector<float> gamvec(m_nTabulatedGammaValues);
216 std::vector<float> lnE;
217
218 double gamvar = m_gamExpMin - 0.5*m_deltaGamExp;
219 for ( unsigned int ig = 0; ig < m_nTabulatedGammaValues; ++ig ) {
220 gamvar += m_deltaGamExp;
221 gamvec[ig] = 1. + pow(10.,gamvar);
222 }
223
224 // Here is the real action!
225
226 effectiveGas.GasTab(gamvec, m_en_array, m_fn_array, m_dndx );
227
228 ATH_MSG_DEBUG ( "Initialization completed." );
229
230 return StatusCode::SUCCESS;
231}
232
233//__________________________________________________________________________
235 delete m_trtgas;
236 return StatusCode::SUCCESS;
237}
238
239//__________________________________________________________________________
240inline double TRT_PAI_Process::ScaledEkin2GamVarTab(double scaledKineticEnergy)
241 const {
242 using namespace TRT_PAI_physicsConstants;
243 return (log(scaledKineticEnergy/MProtonMeV)*invlog10 - m_gamExpMin)/m_deltaGamExp;
244}
245
246//__________________________________________________________________________
247double TRT_PAI_Process::GetMeanFreePath(double scaledKineticEnergy,
248 double squaredCharge) const {
249
250 if ( squaredCharge == 0. ) return 99999.0 * CLHEP::km;
251
252 double gv = ScaledEkin2GamVarTab( scaledKineticEnergy );
253 unsigned int index = 0;
254 if ( gv > 0 ) index = static_cast<unsigned int >(gv);
255
256 double d;
257 if ( gv < 0 ) d = m_dndx[0];
259 else {
260 double remain = gv-index;
261 d = (1.-remain)*m_dndx[index] + remain*m_dndx[index+1];
262 }
263
264 double freepath = 1./(d*squaredCharge);
265
266#ifndef NDEBUG
267 ATH_MSG_VERBOSE ( "Mean free path for scaledKineticEnergy = " << scaledKineticEnergy
268 << " is " << freepath/CLHEP::mm << " mm " );
269#endif
270
271 // All internal calculations are performed without initialization with
272 // CLHEP units, so we put it here instead
273
274 return freepath * CLHEP::cm;
275}
276
277//__________________________________________________________________________
278double TRT_PAI_Process::GetEnergyTransfer(double scaledKineticEnergy, CLHEP::HepRandomEngine* rndmEngine) const {
279
280 double gv = ScaledEkin2GamVarTab( scaledKineticEnergy );
281 unsigned int tabIndx = 0;
282
283 if ( gv>0 ) tabIndx = static_cast<unsigned int>( gv );
284
285 tabIndx = std::min( tabIndx, m_nTabulatedGammaValues-1 );
286
287 // Generate a random number uniformly in [0,1].
288 // CLHEP::HepRandomEngine* pHRengine = m_pAtRndmGenSvc->GetEngine("TRT_PAI");
289 double random = CLHEP::RandFlat::shoot(rndmEngine, 0., 1.);
290
291 // What we are doing next is actually to select a value of E from
292 // dN^2/dXdE considered as a function of E using the standard Monte
293 // Carlo method. The total area under the function is equal to
294 // dN/dX, and since we can not calculate the inverse antiderivative,
295 // we have tabulated the antiderivative in (m_en_array, m_fn_array)
296 // and taking the inverse is as simple as switching the roles of the
297 // two arrays.
298
299 double Etransf = TRT_PAI_utils::Interpolate (random * m_dndx[tabIndx], m_fn_array[tabIndx], m_en_array ) ;
300
301 Etransf = exp(Etransf);
302
303#ifndef NDEBUG
304 ATH_MSG_VERBOSE ( "Energy transfer for scaledKineticEnergy = "
305 << scaledKineticEnergy << " is " << Etransf << " eV"
306 );
307#endif
308
309 return Etransf * CLHEP::eV;
310}
#define ATH_MSG_FATAL(x)
#define ATH_MSG_INFO(x)
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_DEBUG(x)
constexpr int pow(int base, int exp) noexcept
const double m_deltaGamExp
TRT_PAI_gasMixture * m_trtgas
std::string m_gasType
TRT_PAI_Process(const std::string &type, const std::string &name, const IInterface *parent)
Not much action.
virtual StatusCode finalize() override final
double ScaledEkin2GamVarTab(double scaledKineticEnergy) const
Converting Lorentz gamma to table index (well, double)
virtual double GetEnergyTransfer(double scaledKineticEnergy, CLHEP::HepRandomEngine *rndmEngine) const override final
Get the energy transferred from the charged particle to the gas (CLHEP units).
std::vector< float > m_dndx
std::vector< std::vector< float > > m_fn_array
virtual StatusCode initialize() override final
Initialization of the PAI model:
virtual double GetMeanFreePath(double scaledKineticEnergy, double squaredCharge) const override final
Get the mean free path in gas (CLHEP units)
const double m_gamExpMax
std::vector< float > m_en_array
const unsigned int m_nTabulatedGammaValues
const double m_gamExpMin
Effective gas: All quantities necessary to calculate PAI ionisation for gas mixture.
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.
Chemical element.
Gas component (molecule)
Gas mixture = mixture of gas components.
Input data to PAI process:
const float EF[NF]
Energy levels for Fluor.
const float EO[NO]
Energy levels for Oxygen.
const float SO[NO]
Cross sections for Oxygen.
const float EAr[NAr]
Energy levels for Argon.
const float EXe[NXe]
Energy levels for Xenon.
const float EKr[NKr]
Energy levels for Krypton.
const int NC
Number of levels for Carbon.
const float SC[NC]
Cross sections for Carbon.
const int NAr
Number of levels for Argon.
const int NKr
Number of levels for Krypton.
const float SKr[NKr]
Cross sections for Krypton.
const float EC[NC]
Energy levels for Carbon.
const int NF
Number of levels for Fluor.
const float SF[NF]
Cross sections for Fluor.
const float SAr[NAr]
Cross sections for Argon.
const int ZXe
Atommic Z for elements.
const float AXe
Atommic A for elements.
const float SXe[NXe]
Cross sections for Xenon.
const int NO
Number of levels for Oxygen.
const int NXe
Number of levels for Xenon.
const double MProtonMeV
Proton mass in MeV.
const double invlog10
you guess...
float Interpolate(const float &xval, const std::vector< float > &xtabulated, const std::vector< float > &ytabulated)
Interpolation function.
Definition index.py:1