ATLAS Offline Software
Loading...
Searching...
No Matches
HitCreatorSilicon.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
3*/
4
5// class header
6#include "HitCreatorSilicon.h"
7
8// ISF
10
11// Tracking
13#include "TrkSurfaces/Surface.h"
22// InDet
23// (0) InDet(DD)
33#include "InDetSimEvent/SiHit.h"
34// CLHEP
36#include "CLHEP/Units/SystemOfUnits.h"
37#include "CLHEP/Random/RandFlat.h"
38#include "CLHEP/Random/RandGauss.h"
39#include "CLHEP/Random/RandLandau.h"
40#include <TMath.h>
41#include <TF1.h>
42#include <vector>
43
44
45double langaufun_fast(double* x, double* par);
46//================ Constructor =================================================
47iFatras::HitCreatorSilicon::HitCreatorSilicon(const std::string& t, const std::string& n, const IInterface* p ) :
48 base_class(t,n,p)
49{
50}
51
52
53//================ Initialisation =================================================
55{
56 // Random number service
57 ATH_CHECK ( m_randomSvc.retrieve() );
58
59 //Get own engine with own seeds:
61 if (!m_randomEngine) {
62 ATH_MSG_ERROR( "[ --- ] Could not get random engine '" << m_randomEngineName << "'" );
63 return StatusCode::FAILURE;
64 }
65
66 ATH_CHECK ( m_condSummaryTool.retrieve( DisableTool{ !m_useConditionsTool } ) );
67
68 // Get the Pixel Identifier-helper:
69 if ( m_siIdHelperName == "PixelID" ) {
70 ATH_CHECK ( detStore()->retrieve(m_pixIdHelper, m_siIdHelperName) );
71 }
72 else if ( m_siIdHelperName == "SCT_ID" ) {
73 ATH_CHECK ( detStore()->retrieve(m_sctIdHelper, m_siIdHelperName) );
74 }
75
76 // Athena/Gaudi framework
77 ATH_CHECK (m_incidentSvc.retrieve());
78
79 // register to the incident service: BeginEvent for TrackCollection
80 m_incidentSvc->addListener( this, IncidentType::BeginEvent);
81 m_dEdX_function = new TF1 ("fitfunc2", langaufun_fast, 0.,10.,4);
82 ATH_MSG_VERBOSE( "[ sihit ] initialize() successful." );
83 return StatusCode::SUCCESS;
84}
85
86
88{
89 delete m_dEdX_function;
90 return StatusCode::SUCCESS;
91}
92
93
94void iFatras::HitCreatorSilicon::handle( const Incident& inc ) {
95 // check the incident type
96 if ( inc.type() == IncidentType::BeginEvent ){
97 // check if the hit collection already contains:
98 // (a) if yes ... try to retrieve it
100 if ( (evtStore()->retrieve(m_hitColl , m_collectionName)).isFailure() )
101 ATH_MSG_ERROR( "[ --- ] Unable to retrieve SiHitCollection " << m_collectionName);
102 // (b) if no ... try to create it
103 } else {
105 if ( (evtStore()->record(m_hitColl, m_collectionName, true)).isFailure() ) {
106 ATH_MSG_ERROR( "[ --- ] Unable to record SiHitCollection " << m_collectionName);
107 delete m_hitColl; m_hitColl=0;
108 }
109 }
110 }
111 return;
112}
113
114double langaufun_fast(double* x, double* par){
115 //Fit parameters:
116 //par[0]=Width (scale) parameter of Landau density
117 //par[1]=Most Probable (MP, location) parameter of Landau density
118 //par[2]=Total area (integral -inf to inf, normalization constant)
119 //par[3]=Width (sigma) of convoluted Gaussian function
120 //
121 //In the Landau distribution (represented by the CERNLIB approximation),
122 //the maximum is located at x=-0.22278298 with the location parameter=0.
123 //This shift is corrected within this function, so that the actual
124 //maximum is identical to the MP parameter.
125
126 // Numeric constants
127 float invsq2pi = 0.3989422804014; // (2 pi)^(-1/2)
128 float mpshift = -0.22278298; // Landau maximum location
129 // Gauss lookup table - let's be honest, these are always the same values...
130 // This table is specific to the following np value and needs adaptation in case np is changed
131 double gauss_lut[50] = {0.998750780887374456,0.988813043727165275,0.96923323447634413,0.940588065326561695,0.903707082721058597,
132 0.859632757966350525,0.809571661213986715,0.754839601989007347,0.696804761374882342,0.636831621583786367,
133 0.576229102522380576,0.516205688098894111,0.457833361771614267,0.402021370154990454,0.349500576034800337,
134 0.300817976590658676,0.256340161499255759,0.216265166829887306,0.180639843651333204,0.149381761360416171,
135 0.122303465302261424,0.0991372321836489212,0.0795595087182276867,0.0632127172421080297,0.0497248676032363973,
136 0.0387257750604656018,0.0298595590948963728,0.0227941808836123437,0.0172274759940137939,0.0128906873307075114,
137 0.00954965878387800497,0.00700416504525899417,0.00508606923101270064,0.00365649704823364612,0.0026025848245772071,
138 0.0018340111405293852,0.00127954549250140965,0.000883826306935049958,0.000604414925679283501,0.000409223053150731654,
139 0.000274310255595171487,0.000182046138317709796,0.000119612883581024366,7.78093008945889215e-05,5.01120454198365631e-05,
140 3.19527960443799922e-05,2.01712861314266379e-05,1.26071051770485227e-05,7.8010709105552431e-06,4.77914424437207415e-06};
141 // Control constants
142 float np = 100.0; // number of convolution steps
143 float sc = 5.0; // convolution extends to +-sc Gaussian sigmas
144
145 // Variables
146 float xx;
147 float mpc;
148 float fland;
149 float sum = 0.0;
150 float xlow,xupp;
151 float step;
152 int i;
153
154 // MP shift correction
155 mpc = par[1] - mpshift * par[0];
156
157 // Range of convolution integral
158 xlow = x[0] - sc * par[3];
159 xupp = x[0] + sc * par[3];
160
161 step = (xupp-xlow) / np;
162
163 // Convolution integral of Landau and Gaussian by sum
164 for(i=0; i < np/2; i++) {
165 xx = x[0] +(((float) i)-.5) * step; //x[0] - (((float) i)+.5) * step;
166 fland = TMath::Landau(xx,mpc,par[0]) / par[0];
167 sum += fland * gauss_lut[i];
168
169 xx = x[0] -(((float) i)-.5) * step; // x[0] + (((float) i)+.5) * step;
170 fland = TMath::Landau(xx,mpc,par[0]) / par[0];
171 sum += fland * gauss_lut[i];
172 }
173
174 return (par[2] * step * sum * invsq2pi / par[3]);
175}
176
177double iFatras::HitCreatorSilicon::energyDeposit_fast(const ISF::ISFParticle& isp, bool& isPix, bool& isSCT ) const {
178
179 int pdg_id= isp.pdgCode();
180 Amg::Vector3D mom = isp.momentum();
181 double Momentum = sqrt((mom.x()*mom.x()) +( mom.y()*mom.y())+(mom.z()*mom.z()));
182 double randLand = CLHEP::RandLandau::shoot(m_randomEngine);
183 double energyLoss=0;
184 if(abs(pdg_id)==11){ // electrons
185 energyLoss = (randLand*0.032)+0.32;
186 }
187 else{ // kaons, protons, pions, myons
188 double rest_mass= isp.mass();
189 double para0 = -1.12409e-02;
190 double para1 = 1.42786e-11;
191 // ST : TEMPORARY remove beta dependence ( fixed to 1 GeV )
192 Momentum = 1000.;
193 // ST
194 double beta = Momentum/ sqrt((Momentum*Momentum)+(rest_mass*rest_mass));
195 double MPV = (para0/pow(beta,2))*(log(para1*(pow(beta,2)/(1-pow(beta,2))))-pow(beta,2));
196
197 if( Momentum< 1000){ //momentum < 1GeV
198 if(abs(pdg_id)==211){ // Pionen
199 if(isSCT){
200 energyLoss = (randLand*0.023)+(MPV+0.008);
201 }
202 if(isPix){
203 energyLoss = (randLand*0.0225)+(MPV+0.008);
204 }
205 }
206 else if(abs(pdg_id)==321){ //Kaonen
207 if(isSCT){
208 energyLoss = (randLand*0.048)+(MPV+0.01);
209 }
210 if(isPix){
211 energyLoss = (randLand*0.0465)+(MPV+0.01);
212 }
213 }
214 else if(abs(pdg_id)==13){ // Muonen
215 if(isSCT){
216 energyLoss = (randLand*0.025)+(MPV+0.011);
217 }
218 if(isPix){
219 energyLoss = (randLand*0.048)+(MPV+0.011);
220 }
221 }
222 else if(abs(pdg_id)==2212){ // Protonen
223 if(isSCT){
224 energyLoss = (randLand*0.0458)+(MPV+0.008);
225 }
226 if(isPix){
227 energyLoss = (randLand*0.0465)+(MPV+0.008);
228 }
229 }
230
231 }//end momentum < 1GeV
232 else if(Momentum >= 1000){
233 if(isSCT){
234 energyLoss = (randLand*0.025)+(MPV+0.013);
235 }
236 if(isPix){
237 energyLoss = (randLand*0.025)+(MPV+0.014);
238 }
239 }//end Momentum >= 1GeV
240 } // End kaons, protons, pions, myons
241
242 return energyLoss;
243}
244
245double iFatras::HitCreatorSilicon::energyDeposit_exact(const ISF::ISFParticle& isp, bool& isPix, bool& isSCT ) const {
246 int pdg_id= isp.pdgCode();
247 Amg::Vector3D mom = isp.momentum();
248 double Momentum = sqrt((mom.x()*mom.x()) +( mom.y()*mom.y())+(mom.z()*mom.z()));
249 m_dEdX_function->SetNpx(4);
250 double xmin = 0;
251 double xmax = 0.;
252 if(abs(pdg_id)==11){ // electrons
253 m_dEdX_function->SetParameters(0.009807, 0.3 ,453.7,0.03733);
254 xmax = 1.;
255 }
256 else{ // Kaonen, Protonen, Pionen, Myonen
257
258 double rest_mass= isp.mass();
259 double para0 = -1.12409e-02;
260 double para1 = 1.42786e-11;
261 double beta = Momentum/ sqrt((Momentum*Momentum)+(rest_mass*rest_mass));
262 double MPV = (para0/pow(beta,2))*(log(para1*(pow(beta,2)/(1-pow(beta,2))))-pow(beta,2));
263 if(Momentum < 1000){ // momentum < 1GeV
264 if(abs(pdg_id)==211){ // Pionen
265 if(isSCT){
266 m_dEdX_function->SetParameters(0.0250, MPV ,453.7,0.0109);
267 }
268 if(isPix){
269 m_dEdX_function->SetParameters(0.0205, MPV ,453.7,0.0219);
270 }
271 }
272 else if(abs(pdg_id)==321){ //Kaonen
273 if(isSCT){
274 m_dEdX_function->SetParameters(0.0458, MPV ,453.7,0.0064);
275 }
276 if(isPix){
277 m_dEdX_function->SetParameters(0.0465, MPV,453.7,0.000);
278 }
279 }
280 else if(abs(pdg_id)==13){ // Muonen
281 if(isSCT){
282 m_dEdX_function->SetParameters(0.0140, MPV,453.7,0.0245);
283 }
284 if(isPix){
285 m_dEdX_function->SetParameters(0.0064, MPV ,453.7,0.0480);
286 }
287 }
288 else if(abs(pdg_id)==2212){ // Protonen
289 if(isSCT){
290 m_dEdX_function->SetParameters(0.0458, MPV ,453.7,0.0064);
291 }
292 if(isPix){
293 m_dEdX_function->SetParameters(0.0465, MPV ,453.7,0.000);
294 }
295 }
296
297 }
298 else if(Momentum>= 1000){
299 if(isSCT){
300 m_dEdX_function->SetParameters(0.0135, MPV ,453.7,0.0245);
301 }
302 if(isPix){
303 m_dEdX_function->SetParameters(0.0102, MPV ,453.7,0.0297);
304 }
305 }
306 xmax = MPV*10.;
307 } // Parametrisierung fuer Kaonen, Protonen, Pionen, Myonen ENDE
308
309 double ymin = 0;
310 double ymax = m_dEdX_function -> GetMaximum(xmin, xmax);
311 double energyLoss = 0;
312
313 for (int count=0; count <1000; count++) {
314 double ry = CLHEP::RandFlat::shoot(m_randomEngine)*(ymax-ymin) + ymin;
315 double rx = CLHEP::RandFlat::shoot(m_randomEngine)*(xmax-xmin) + xmin;
316 double y = m_dEdX_function->Eval(rx);
317 if ( ry <= y ){ energyLoss = rx; break;}
318 }
319
320
321
322 return energyLoss;
323}
324
325
326void iFatras::HitCreatorSilicon::createSimHit(const ISF::ISFParticle& isp, const Trk::TrackParameters& pars, double time ) const {
327
328 // get surface and DetElement base
329 const Trk::Surface &hitSurface = pars.associatedSurface();
330 const Trk::TrkDetElementBase* detElementBase = hitSurface.associatedDetectorElement();
331
332 // the detector element cast -> needed
333 const InDetDD::SiDetectorElement* SiDetElement = dynamic_cast<const InDetDD::SiDetectorElement*>((detElementBase));
334
335 // return triggered if no siDetElement or no current particle link to the stack
336 if ( !SiDetElement ){
337 ATH_MSG_WARNING("[ sihit ] No Silicon Detector element available. Ignore this one.");
338 return;
339 }
340
341 return createSimHit( isp, pars, time, *SiDetElement, 1);
342
343}
344
345void iFatras::HitCreatorSilicon::createSimHit(const ISF::ISFParticle& isp, const Trk::TrackParameters& pars, double time, const InDetDD::SiDetectorElement& hitSiDetElement, bool isSiDetElement) const {
346
347 // get surface and DetElement base
348 const Trk::Surface &hitSurface = pars.associatedSurface();
349
350 // get the identifier and hash identifier
352 IdentifierHash hitIdHash = hitSiDetElement.identifyHash();
353 // check conditions of the intersection
354 if ( m_useConditionsTool ) {
355 const EventContext& ctx = Gaudi::Hive::currentContext();
356 bool isActive = m_condSummaryTool->isActive(hitIdHash, hitId, ctx); // active = "element returns data"
357 bool isGood = isActive ? m_condSummaryTool->isGood(hitIdHash, hitId, ctx) : false; // good = "data are reliable"
358 if (!isActive)
359 ATH_MSG_VERBOSE("[ sihit ] ID " << hitId << ", hash " << hitIdHash << " is not active. ");
360 else if (!isGood)
361 ATH_MSG_VERBOSE("[ sihit ] ID " << hitId << ", hash " << hitIdHash << " is active but not good. ");
362 else
363 ATH_MSG_VERBOSE("[ sihit ] ID " << hitId << ", hash " << hitIdHash << " is active and good.");
364 if (!isActive || !isGood) return;
365 }
366
367 // intersection
368 const Amg::Vector2D& intersection = pars.localPosition();
369 double interX = intersection.x();
370 double interY = intersection.y();
371 // thickness of the module
372 const double thickness = hitSiDetElement.thickness();
373 // get the momentum direction into the local frame
374 Amg::Vector3D particleDir = pars.momentum().unit();
375 const Amg::Transform3D& sTransform = hitSurface.transform();
376 Amg::Vector3D localDirection = sTransform.inverse().linear() * particleDir;
377 localDirection *= thickness/cos(localDirection.theta());
378 // moving direction
379 int movingDirection = localDirection.z() > 0. ? 1 : -1;
380 // get he local distance of the intersection in x,y
381 double distX = localDirection.x();
382 double distY = localDirection.y();
383 // local entries in x,y
384 double localEntryX = interX-0.5*distX;
385 double localEntryY = interY-0.5*distY;
386 double localExitX = interX+0.5*distX;
387 double localExitY = interY+0.5*distY;
389 const Amg::Transform3D &hitTransform = hitSiDetElement.transformHit().inverse();
390 // transform into the hit frame
391 Amg::Vector3D localEntry(hitTransform*(sTransform*Amg::Vector3D(localEntryX,localEntryY,-0.5*movingDirection*thickness)));
392 Amg::Vector3D localExit(hitTransform*(sTransform*Amg::Vector3D(localExitX,localExitY,0.5*movingDirection*thickness)));
393
394 bool isPix = hitSiDetElement.isPixel();
395 bool isSCT = hitSiDetElement.isSCT();
396
397 // Landau approximation
398 const double dEdX = m_fastEnergyDepositionModel ?
399 energyDeposit_fast(isp,isPix,isSCT)
400 : energyDeposit_exact(isp,isPix,isSCT);
401
402 const double energyDeposit = dEdX * (localExit - localEntry).mag();
403
404 // create the silicon hit
405 const HepGeom::Point3D<double> localEntryHep( localEntry.x(), localEntry.y(), localEntry.z() );
406 const HepGeom::Point3D<double> localExitHep( localExit.x(), localExit.y(), localExit.z() );
407
408 if ( isSiDetElement )
409 ATH_MSG_VERBOSE("[ sihit ] Adding an SiHit SiDetElement to the SiHitCollection.");
410 else
411 ATH_MSG_VERBOSE("[ sihit ] SiHit SiDetElement not found to add to the SiHitCollection.");
412
413 HepMcParticleLink partLink(HepMC::uniqueID(isp), 0,
416 m_hitColl->Emplace(localEntryHep,
417 localExitHep,
418 energyDeposit,
419 time,
420 partLink,
421 m_pixIdHelper ? 0 : 1,
422 m_pixIdHelper ? m_pixIdHelper->barrel_ec(hitId) : m_sctIdHelper->barrel_ec(hitId),
423 m_pixIdHelper ? m_pixIdHelper->layer_disk(hitId) : m_sctIdHelper->layer_disk(hitId),
424 m_pixIdHelper ? m_pixIdHelper->eta_module(hitId) : m_sctIdHelper->eta_module(hitId),
425 m_pixIdHelper ? m_pixIdHelper->phi_module(hitId) : m_sctIdHelper->phi_module(hitId),
426 m_pixIdHelper ? 0 : m_sctIdHelper->side(hitId));
427
428}
Scalar mag() const
mag method
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(x)
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_WARNING(x)
double langaufun_fast(double *x, double *par)
static Double_t sc
This is an Identifier helper class for the Pixel subdetector.
This is an Identifier helper class for the SCT subdetector.
AtlasHitsVector< SiHit > SiHitCollection
#define y
#define x
constexpr int pow(int base, int exp) noexcept
The generic ISF particle definition,.
Definition ISFParticle.h:42
const Amg::Vector3D & momentum() const
The current momentum vector of the ISFParticle.
int pdgCode() const
PDG value.
double mass() const
mass of the particle
This is a "hash" representation of an Identifier.
Class to hold geometrical description of a silicon detector element.
virtual IdentifierHash identifyHash() const override final
identifier hash (inline)
const GeoTrf::Transform3D & transformHit() const
Local (simulation/hit frame) to global transform.
Abstract Base Class for tracking surfaces.
const TrkDetElementBase * associatedDetectorElement() const
return associated Detector Element
const Amg::Transform3D & transform() const
Returns HepGeom::Transform3D by reference.
Identifier associatedDetectorElementIdentifier() const
return Identifier of the associated Detector Element
This is the base class for all tracking detector elements with read-out relevant information.
StringProperty m_collectionName
name of the collection on storegate
void handle(const Incident &inc)
handle for incident service
double energyDeposit_exact(const ISF::ISFParticle &isp, bool &isPix, bool &isSCT) const
Calculate Energyloss with exact Landau*Gauss.
TF1 * m_dEdX_function
function to evaluate dEdx
HitCreatorSilicon(const std::string &, const std::string &, const IInterface *)
Constructor.
ServiceHandle< IIncidentSvc > m_incidentSvc
void createSimHit(const ISF::ISFParticle &isp, const Trk::TrackParameters &, double) const
Return nothing - store the HIT in hit collection.
CLHEP::HepRandomEngine * m_randomEngine
Random Engine.
StatusCode finalize()
AlgTool finalize method.
const PixelID * m_pixIdHelper
the Pixel ID helper
StringProperty m_siIdHelperName
where to find the Si helper
StatusCode initialize()
AlgTool initailize method.
StringProperty m_randomEngineName
Name of the random number stream.
double energyDeposit_fast(const ISF::ISFParticle &isp, bool &isPix, bool &isSCT) const
Calculate Energyloss with simple Landau approximation.
ToolHandle< IInDetConditionsTool > m_condSummaryTool
ToolHandle to ClusterMaker.
ServiceHandle< IAtRndmGenSvc > m_randomSvc
Pointer to the random number generator service.
SiHitCollection * m_hitColl
the SiHit collection
const SCT_ID * m_sctIdHelper
the SCT ID helper
BooleanProperty m_fastEnergyDepositionModel
use fast energy deposition model (landau approximation )
std::vector< std::string > intersection(std::vector< std::string > &v1, std::vector< std::string > &v2)
bool contains(const std::string &s, const std::string &regx)
does a string contain the substring
Definition hcg.cxx:114
int count(std::string s, const std::string &regx)
count how many occurances of a regx are in a string
Definition hcg.cxx:146
double xmax
Definition listroot.cxx:61
double ymin
Definition listroot.cxx:63
double xmin
Definition listroot.cxx:60
double ymax
Definition listroot.cxx:64
Eigen::Affine3d Transform3D
Eigen::Matrix< double, 2, 1 > Vector2D
Eigen::Matrix< double, 3, 1 > Vector3D
int uniqueID(const T &p)
ParametersBase< TrackParametersDim, Charged > TrackParameters