15#include "CLHEP/Geometry/Point3D.h"
16#include "CLHEP/Random/RandFlat.h"
17#include "CLHEP/Random/RandGaussZiggurat.h"
18#include "CLHEP/Units/SystemOfUnits.h"
23#include "TProfile2D.h"
36 : base_class(
type, name, parent)
44 ATH_MSG_DEBUG(
"SCT_DetailedSurfaceChargesGenerator::initialize()");
58 return StatusCode::FAILURE;
61 m_h_efieldz =
new TProfile(
"efieldz",
"", 50, 0., 0.03);
65 return StatusCode::FAILURE;
71 return StatusCode::FAILURE;
77 return StatusCode::FAILURE;
83 return StatusCode::FAILURE;
89 return StatusCode::FAILURE;
112 ATH_MSG_INFO(
"\tsurface drift still not on, wrong params");
117 ATH_MSG_FATAL(
"\tCannot set both FixedTime and SubtractTime options!");
118 ATH_MSG_INFO(
"\tMake sure the two flags are not set simultaneously in jo");
119 return StatusCode::FAILURE;
132 ATH_MSG_INFO(
"\tDetailedSurfaceChargesGenerator copied");
139 return StatusCode::SUCCESS;
146 ATH_MSG_DEBUG(
"SCT_DetailedSurfaceChargesGenerator::finalize()");
147 return StatusCode::SUCCESS;
154 const double sensorThickness{element->
thickness()};
155 if ((zhit<0.0) or (zhit>sensorThickness)) {
156 ATH_MSG_DEBUG(
"DriftTime: hit coordinate zhit=" << zhit/CLHEP::micrometer <<
" out of range");
163 const double denominator{vdepl+vbias-(2.0*zhit*vdepl/sensorThickness)};
164 if (denominator<=0.0) {
167 ATH_MSG_ERROR(
"DriftTime: negative argument X for log(X) " << zhit);
177 float driftTime{
static_cast<float>(log((vdepl+vbias)/denominator))};
178 driftTime *= sensorThickness*sensorThickness/(2.0*
m_siPropertiesTool->getSiProperties(hashId, ctx).holeDriftMobility()*vdepl);
187 const float t{this->
DriftTime(zhit, element, ctx)};
189 const float diffusionSigma{
static_cast<float>(sqrt(2.*
m_siPropertiesTool->getSiProperties(hashId, ctx).holeDiffusionConstant()*t))};
190 return diffusionSigma;
200 const double sensorThickness{element->
thickness()};
201 return this->
DriftTime(sensorThickness, element, ctx);
213 const double sensorThickness{element->
thickness()};
228 float surfaceDriftTime{0.};
236 return surfaceDriftTime;
250 ATH_MSG_VERBOSE(
"SCT_DetailedSurfaceChargesGenerator::process starts");
251 const float p_eventTime{phit.
eventTime()};
252 const unsigned short p_eventId{phit.
eventId()};
253 processSiHit(element, *phit, inserter, p_eventTime, p_eventId, rndmEngine, ctx);
261 if (p_design==
nullptr) {
262 ATH_MSG_ERROR(
"SCT_DetailedSurfaceChargesGenerator::process can not get " << p_design);
270 float timeOfFlight{p_eventTime +
hitTime(phit)};
273 timeOfFlight -= (element->
center().
mag())/CLHEP::c_light;
283 const double sensorThickness{p_design->
thickness()};
296 double LargeStep{sqrt(cEta*cEta+cPhi*cPhi+cDep*cDep)};
300 double q1{e1*
m_siPropertiesTool->getSiProperties(hashId, ctx).electronHolePairsPerEnergy()};
307 double StepX{cEta/numberOfSteps};
308 double StepY{cPhi/numberOfSteps};
309 double StepZ{cDep/numberOfSteps};
327 for (
int istep{0}; istep<numberOfSteps; ++istep) {
329 double z1{zhit+StepZ*dstep};
332 double zReadout{0.5*sensorThickness - p_design->
readoutSide() * z1};
334 float tdrift{
DriftTime(zReadout, element, ctx)};
335 if (tdrift>-2.0000002 and tdrift<-1.9999998) {
336 ATH_MSG_DEBUG(
"Checking for rounding errors in compression");
337 if ((std::abs(z1)-0.5*sensorThickness)<0.000010) {
338 ATH_MSG_DEBUG(
"Rounding error found attempting to correct it. z1 = " << std::fixed << std::setprecision(8) << z1);
340 z1= 0.0000005-0.5*sensorThickness;
342 z1 = 0.5*sensorThickness-0.0000005;
344 zReadout = 0.5*sensorThickness - p_design->
readoutSide() * z1;
345 tdrift=
DriftTime(zReadout, element, ctx);
346 if (tdrift>-2.0000002 and tdrift<-1.9999998) {
349 ATH_MSG_DEBUG(
"Correction Successful! z1 = " << std::fixed << std::setprecision(8) << z1 <<
", zReadout = " << zReadout <<
", tdrift = " << tdrift);
352 ATH_MSG_DEBUG(
"No rounding error found. Making no correction.");
356 double x1{xhit+StepX*dstep};
357 double y1{yhit+StepY*dstep};
361 y1 += tanLorentz*zReadout;
364 float rx{CLHEP::RandGaussZiggurat::shoot(rndmEngine)};
365 double xd{x1+diffusionSigma*rx};
366 float ry{CLHEP::RandGaussZiggurat::shoot(rndmEngine)};
367 double yd{y1+diffusionSigma*ry};
373 float totaltime{(
m_tfix>-998.) ?
m_tfix.value() : tdrift + timeOfFlight + tsurf};
377 ATH_MSG_INFO(
"Total Time: " << totaltime <<
" tdrift " << tdrift <<
" tsurf " << tsurf <<
" sdist " << sdist <<
" charge: " << q1);
382 ATH_MSG_INFO(std::fixed << std::setprecision(8) <<
"Local position: " << position <<
" of the element is out of active area, charge = " << q1);
391 if (b_design==
nullptr) {
392 ATH_MSG_ERROR(
"SCT_DetailedSurfaceChargesGenerator::process can not get " << b_design);
398 double dstrip{(y1-stripPatternCentre)/stripPitch};
403 dstrip -=
static_cast<double>(
static_cast<int>(dstrip));
405 dstrip -=
static_cast<double>(
static_cast<int>(dstrip)-1);
407 double xtakadist{dstrip*stripPitch};
408 double x0{xtakadist/10.};
409 double y0{(sensorThickness - zReadout)/10.};
412 ATH_MSG_INFO(
"element->isBarrel(): " << element->
isBarrel() <<
" stripPitch: " << stripPitch <<
" stripPatternCentre: " << stripPatternCentre);
413 ATH_MSG_INFO(
"tanLorentz, y1, xtakadist = " << tanLorentz <<
", " << y1 <<
", " << xtakadist);
415 double Q_all[5][50]={};
418 holeTransport (x0, y0, Q_all[0], Q_all[1], Q_all[2], Q_all[3], Q_all[4], rndmEngine);
419 electronTransport(x0, y0, Q_all[0], Q_all[1], Q_all[2], Q_all[3], Q_all[4], rndmEngine);
422 double ystrip{y1 +
strip*stripPitch};
425 for (
int itq{0}; itq<50; itq++) {
427 double time{(itq+1)*0.5 + timeOfFlight};
435 ATH_MSG_INFO(std::fixed << std::setprecision(8) <<
"Local position: " << position <<
" of the element is out of active area, charge = " << q1);
440 ATH_MSG_ERROR(
"Fixed charge map model, implementation not finished yet...");
443 if (b_design==
nullptr) {
444 ATH_MSG_ERROR(
"SCT_DetailedSurfaceChargesGenerator::process can not get " << b_design);
451 double dstrip{(y1-stripPatternCentre)/stripPitch};
456 dstrip -=
static_cast<double>(
static_cast<int>(dstrip));
458 dstrip -=
static_cast<double>(
static_cast<int>(dstrip)-1);
460 double xtakadist{dstrip*stripPitch};
461 double x0{xtakadist*1000.};
462 double y0{(sensorThickness - zReadout)*1000.};
466 double ystrip{y1 +
strip*stripPitch};
472 for (
int it{0}; it<50; it++) {
473 time = 0.25 + 0.5*it;
481 ATH_MSG_INFO(std::fixed << std::setprecision(8) <<
"Local position: " << position <<
" of the element is out of active area, charge = " << q1);
511 double Ex{0.}, Ey{0.};
514 if (Ey > 0.1)
continue;
520 ATH_MSG_INFO(
"------ initialization of e-h transport ------");
530 ATH_MSG_INFO(
"----parameters for old SCT digitization model ----");
531 ATH_MSG_INFO(
"\tmean E field = " << Emean <<
" [KV/cm] ");
535 ATH_MSG_INFO(
"\tdiffusion D = " << diffusion <<
" [ ]");
541 ATH_MSG_INFO(
"-----------------------------------------------");
552 ATH_MSG_INFO(
"----------------------------------------------");
579 for (
int ix{0}; ix<17; ix++) {
580 for (
int iy{0}; iy<115; iy++) {
599 for (
int ix{0}; ix<81; ix++) {
600 for (
int iy{0}; iy<115; iy++) {
617 const double REx{-Ex};
618 const double REy{-Ey};
619 const double E{sqrt(Ex*Ex+Ey*Ey)};
620 const double mu_e{
mud_e(E)};
621 const double v_e{mu_e * E};
624 const double secLA{sqrt(1.+tanLA_e*tanLA_e)};
625 const double cosLA{1./secLA};
626 const double sinLA{tanLA_e / secLA};
627 vy_e = v_e * (REy*cosLA - REx*sinLA)/E;
628 vx_e = v_e * (REx*cosLA + REy*sinLA)/E;
648 const double E{sqrt(Ex*Ex+Ey*Ey)};
649 const double mu_h{
mud_h(E)};
650 const double v_h{mu_h * E};
653 const double secLA{sqrt(1.+tanLA_h*tanLA_h)};
654 const double cosLA{1./secLA};
655 const double sinLA{tanLA_h / secLA};
657 vy_h = v_h * (Ey*cosLA - Ex*sinLA)/E;
658 vx_h = v_h * (Ex*cosLA + Ey*sinLA)/E;
673 static const double deltax{0.0005};
674 static const double deltay{0.00025};
678 const double dx{std::abs(
x-xc)};
679 const int ix{
static_cast<int>(dx / deltax)};
680 if (ix > 79)
return 0.;
681 const int iy{
static_cast<int>(
y / deltay)};
682 const double fx{(dx - ix*deltax) / deltax};
683 const double fy{(
y - iy*deltay) / deltay};
689 ATH_MSG_DEBUG(
"induced: x,y,iy=" <<
x <<
" " <<
y <<
" " << iy <<
" istrip,xc,dx,ix="
690 << istrip <<
" " << xc <<
" " << dx <<
" " <<ix <<
" fx,fy=" << fx <<
" " << fy <<
", P=" <<
P);
706 static const double deltay{0.00025}, deltax{0.00025};
731 int iy{
static_cast<int>(
y/deltay)};
732 double fy{(
y-iy*deltay) / deltay};
738 int ix{
static_cast<int>(xxx/deltax)};
739 double fx{(xxx - ix*deltax) / deltax};
741 ATH_MSG_DEBUG(
"x,y,ix,iy,fx,fy,xx,xxx= " <<
x <<
" " <<
y <<
" " << ix <<
" " << iy <<
" " << fx <<
" " << fy <<
" " << xx <<
" " << xxx);
745 double Ex00{0.}, Ex10{0.}, Ex01{0.}, Ex11{0.};
746 double Ey00{0.}, Ey10{0.}, Ey01{0.}, Ey11{0.};
757 ATH_MSG_WARNING(
"Only +150 V bias voltage case is available. However, " << iVB <<
" V bias voltage is used. Electoric field is not extracted!!!");
761 Ex = Ex00*(1.-fx)*(1.-fy) + Ex10*fx*(1.-fy) + Ex01*(1.-fx)*fy + Ex11*fx*fy;
763 ATH_MSG_DEBUG(
"xx, xhalfpitch = " << xx <<
" " << xhalfpitch);
765 if (xx > xhalfpitch) Ex = -Ex;
766 Ey = Ey00*(1.-fx)*(1.-fy) + Ey10*fx*(1.-fy) + Ey01*(1.-fx)*fy + Ey11*fx*fy;
801 double t_current{0.};
806 static const double betaHoles{5.1E-16};
807 double trappingHoles{1./(
m_Fluence*betaHoles)};
808 double u{CLHEP::RandFlat::shoot(0., 1.)};
809 double drift_time{-TMath::Log(u)*trappingHoles};
811 for (
int istrip{-2}; istrip<=2; istrip++) {
812 qstrip[istrip+2] =
induced(istrip,
x,
y);
815 ATH_MSG_DEBUG(
"h:qstrip=" << qstrip[0] <<
" " << qstrip[1] <<
" " << qstrip[2] <<
" " << qstrip[3] <<
" " << qstrip[4]);
818 if (not isInBulk)
break;
819 if (not
hole(
x,
y, vx, vy, D))
break;
832 if (drift_time < t_current)
break;
836 double diffusion{sqrt(2.*D*dt*1.E-9)};
837 y += diffusion * CLHEP::RandGaussZiggurat::shoot(rndmEngine);
838 x += diffusion * CLHEP::RandGaussZiggurat::shoot(rndmEngine);
846 ATH_MSG_DEBUG(
"h:t,x,y=" << t_current <<
", " <<
x*1e4 <<
", " <<
y*1e4);
848 for (
int istrip{-2}; istrip<=2; istrip++) {
851 double dq{qnew - qstrip[jj]};
856 int jt{
static_cast<int>((t_current+0.001) / 0.50)};
859 case -2: Q_m2[jt] += dq;
break;
860 case -1: Q_m1[jt] += dq;
break;
861 case 0: Q_00[jt] += dq;
break;
862 case +1: Q_p1[jt] += dq;
break;
863 case +2: Q_p2[jt] += dq;
break;
869 ATH_MSG_DEBUG(
"h:qstrip=" << qstrip[0] <<
" " << qstrip[1] <<
" " << qstrip[2] <<
" " << qstrip[3] <<
" " << qstrip[4]);
873 ATH_MSG_DEBUG(
"holeTransport : x,y=(" << x0*1.e4<<
"," <<y0*1.e4<<
")->(" <<
x*1.e4<<
"," <<
y*1.e4 <<
") t=" << t_current);
897 double t_current{0.};
902 static const double betaElectrons{3.1E-16};
903 const double trappingElectrons{1./(
m_Fluence*betaElectrons)};
904 const double u{CLHEP::RandFlat::shoot(0., 1.)};
905 const double drift_time{-TMath::Log(u)*trappingElectrons};
907 for (
int istrip{-2}; istrip<=2; istrip++) {
908 qstrip[istrip+2] = -
induced(istrip,
x,
y);
913 if (not isInBulk)
break;
927 if (drift_time < t_current)
break;
931 double diffusion{sqrt(2.* D * dt*1.E-9)};
932 y += diffusion * CLHEP::RandGaussZiggurat::shoot(rndmEngine);
933 x += diffusion * CLHEP::RandGaussZiggurat::shoot(rndmEngine);
939 for (
int istrip{-2}; istrip<=2; istrip++) {
942 double dq{qnew - qstrip[jj]};
945 if (istrip==0)
ATH_MSG_DEBUG(
"e:t,x,y=" << t_current <<
" " <<
x*1e4 <<
" " <<
y*1e4 <<
" dq[0]=" << dq);
947 int jt{
static_cast<int>((t_current + 0.001) / 0.50)};
950 case -2: Q_m2[jt] += dq;
break;
951 case -1: Q_m1[jt] += dq;
break;
952 case 0: Q_00[jt] += dq;
break;
953 case +1: Q_p1[jt] += dq;
break;
954 case +2: Q_p2[jt] += dq;
break;
961 ATH_MSG_DEBUG(
"elecTransport : x,y=(" << x0*1.e4 <<
"," << y0*1.e4 <<
")->(" <<
x*1.e4 <<
"," <<
y*1.e4 <<
") t=" << t_current);
973 static const double dt{0.5};
983 ix =
static_cast<int>(fx);
987 iy =
static_cast<int>(fy);
1002 it =
static_cast<int>(ft);
1025 const double charge0{p000*(1.-fx)*(1.-fy) + p010*(1.-fx)*fy + p100*fx*(1.-fy) + p110*fx*fy};
1026 const double charge1{p001*(1.-fx)*(1.-fy) + p011*(1.-fx)*fy + p101*fx*(1.-fy) + p111*fx*fy};
1028 charge = charge0*(1.-ft) + charge1*ft;
float hitTime(const AFP_SIDSimHit &hit)
Scalar mag() const
mag method
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_WARNING(x)
double charge(const T &p)
double getPotentialValue(const int ix, const int iy)
A free function to return the SCT electric field potential internal to the silicon on a 81 * 115 arra...
constexpr int pow(int base, int exp) noexcept
a link optimized in size for a GenParticle in a McEventCollection
bool isValid() const
Validity check.
static HepMcParticleLink getRedirectedLink(const HepMcParticleLink &particleLink, uint32_t eventIndex, const EventContext &ctx)
Return a HepMcParticleLink pointing at the same particle, but in a different GenEvent.
This is a "hash" representation of an Identifier.
double thickness() const
Method which returns thickness of the silicon wafer.
int readoutSide() const
ReadoutSide.
Barrel module design description for the SCT.
double phiStripPatternCentre() const
centre of the strip pattern in phi
Base class for the SCT module side design, extended by the Forward and Barrel module design.
virtual double scaledDistanceToNearestDiode(const SiLocalPosition &chargePos) const =0
give distance to the nearest diode in units of pitch, from 0.0 to 0.5, this method should be fast as ...
virtual bool inActiveArea(const SiLocalPosition &chargePos, bool checkBondGap=true) const =0
check if the position is in active area
virtual double stripPitch(const SiLocalPosition &chargePos) const =0
give the strip pitch (dependence on position needed for forward)
Class to hold geometrical description of a silicon detector element.
virtual const SiDetectorDesign & design() const override final
access to the local description (inline):
Class to represent a position in the natural frame of a silicon sensor, for Pixel and SCT For Pixel: ...
virtual IdentifierHash identifyHash() const override final
identifier hash (inline)
virtual const Amg::Vector3D & center() const override final
Center in global coordinates.
Amg::Vector2D hitLocalToLocal(double xEta, double xPhi) const
Simulation/Hit local frame to reconstruction local frame.
ToolHandle< ISiliconConditionsTool > m_siConditionsTool
bool m_SurfaceDriftFlag
surface drift ON/OFF
bool electron(double x_e, double y_e, double &vx_e, double &vy_e, double &D_e) const
IntegerProperty m_eFieldModel
double m_PotentialValue[81][115]
FloatProperty m_tSurfaceDrift
related to the surface drift
ToolHandle< ISiLorentzAngleTool > m_lorentzAngleTool
double m_ExValue150[17][115]
void init_mud_h(double T)
virtual StatusCode finalize() override
AlgTool finalize.
virtual StatusCode initialize() override
AlgTool initialize.
double mud_e(double E) const
DoubleProperty m_sensorTemperature
float MaxDriftTime(const InDetDD::SiDetectorElement *element, const EventContext &ctx) const
max drift charge equivalent to the detector thickness
BooleanProperty m_doHistoTrap
float m_distInterStrip
Inter strip distance normalized to 1.
float MaxDiffusionSigma(const InDetDD::SiDetectorElement *element, const EventContext &ctx) const
max sigma diffusion
DoubleProperty m_transportTimeStep
void processSiHit(const InDetDD::SiDetectorElement *element, const SiHit &phit, ISiSurfaceChargesInserter &inserter, const float eventTime, const unsigned short eventID, CLHEP::HepRandomEngine *rndmEngine, const EventContext &ctx)
double mud_h(double E) const
SCT_DetailedSurfaceChargesGenerator(const std::string &type, const std::string &name, const IInterface *parent)
constructor
void EField(double x, double y, double &Ex, double &Ey) const
void initPotentialValue()
DoubleProperty m_biasVoltage
virtual void process(const InDetDD::SiDetectorElement *element, const TimedHitPtr< SiHit > &phit, ISiSurfaceChargesInserter &inserter, CLHEP::HepRandomEngine *rndmEngine, const EventContext &ctx) override
create a list of surface charges from a hit
void initTransportModel()
void init_mud_e(double T)
float m_distHalfInterStrip
Half way distance inter strip.
FloatProperty m_tsubtract
DoubleProperty m_transportTimeMax
double m_EyValue150[17][115]
ToolHandle< ISiPropertiesTool > m_siPropertiesTool
void electronTransport(double &x0, double &y0, double *Q_m2, double *Q_m1, double *Q_00, double *Q_p1, double *Q_p2, CLHEP::HepRandomEngine *rndmEngine) const
FloatProperty m_smallStepLength
max internal step along the larger G4 step
TProfile2D * m_h_yzEfield
void holeTransport(double &x0, double &y0, double *Q_m2, double *Q_m1, double *Q_00, double *Q_p1, double *Q_p2, CLHEP::HepRandomEngine *rndmEngine)
IntegerProperty m_chargeDriftModel
double induced(int istrip, double x, double y) const
float DiffusionSigma(float zhit, const InDetDD::SiDetectorElement *element, const EventContext &ctx) const
calculate diffusion sigma from a gaussian dist scattered charge
float SurfaceDriftTime(float ysurf) const
Calculate of the surface drift time.
float DriftTime(float zhit, const InDetDD::SiDetectorElement *element, const EventContext &ctx) const
calculate drift time perpandicular to the surface for a charge at distance zhit from mid gap
DoubleProperty m_magneticField
ServiceHandle< ITHistSvc > m_thistSvc
DoubleProperty m_depletionVoltage
static double ExValue150(int ix, int iy)
bool hole(double x_h, double y_h, double &vx_h, double &vy_h, double &D_h)
static double EyValue150(int ix, int iy)
static double GetPotentialValue(int ix, int iy)
BooleanProperty m_doTrapping
double inducedCharge(int &istrip, double &x, double &y, double &t) const
IntegerProperty m_numberOfCharges
number of charges
float m_tHalfwayDrift
Surface drift time.
BooleanProperty m_isOverlay
double energyLoss() const
HepGeom::Point3D< double > localStartPosition() const
const HepMcParticleLink & particleLink() const
HepGeom::Point3D< double > localEndPosition() const
a smart pointer to a hit that also provides access to the extended timing info of the host event.
unsigned short eventId() const
the index of the component event in PileUpEventInfo.
float eventTime() const
t0 offset of the bunch xing containing the hit in ns.