23 TGeoPhysicalNode* node,
26 fNofStrips(0), fPitch(0.), fStereoF(100.), fStereoB(100.),
27 fTanStereo(), fCosStereo(), fStripShift(), fErrorFac(0.)
29 SetTitle(
"DssdStereo");
50 SetTitle(
"DssdStereo");
59 Double_t sigma, Int_t side,
60 Double_t& fracL, Double_t& fracC,
64 assert( side == 0 || side == 1);
72 Int_t iStrip = TMath::FloorNint(xRo /
fPitch);
75 Double_t xLeftRo = Double_t(iStrip) *
fPitch;
76 Double_t xRightRo = xLeftRo +
fPitch;
79 Double_t dLeft = ( xRo - xLeftRo ) *
fCosStereo[side];
80 Double_t dRight = ( xRightRo - xRo ) *
fCosStereo[side];
85 if ( dLeft < 3. * sigma )
86 fracL = 0.5 * ( 1. - TMath::Erf( 0.707107 * dLeft / sigma) );
88 if ( dRight < 3. * sigma )
89 fracR = 0.5 * ( 1. - TMath::Erf( 0.707107 * dRight / sigma) );
90 fracC = 1. - fracL - fracR;
92 LOG(debug4) << GetName() <<
": Distances to next strip " << dLeft <<
" / "
93 << dRight <<
", charge fractions " << fracL <<
" / " << fracC
102 Int_t sensorId)
const {
105 assert( side == 0 || side == 1);
108 Int_t channel = strip - sensorId *
fStripShift[side];
125 Int_t sensorId)
const {
147 return ( pair<Int_t, Int_t>(stripNr, side) );
163 assert( side == 0 || side == 1);
166 if ( TMath::Abs(x) >
fDx / 2. ) {
167 LOG(error) << GetName() <<
": Outside active area : x = "
171 if ( TMath::Abs(y) >
fDy / 2. ) {
172 LOG(error) << GetName() <<
": Outside active area : y = "
179 Double_t xdist = x + 0.5 *
fDx;
180 Double_t ydist = y + 0.5 *
fDy;
186 Int_t iStrip = TMath::FloorNint( xro /
fPitch );
204 LOG(error) << GetName() <<
": No node assigned!";
210 LOG(error) << GetName() <<
": Parameters are not set!"
216 TGeoBBox* shape =
dynamic_cast<TGeoBBox*
>(
fNode->GetShape());
221 if (
fDx >= 2. * shape->GetDX() ) {
222 LOG(error) << GetName() <<
": Active size in x ( " <<
fNofStrips <<
" x "
223 <<
fPitch <<
" cm exceeds volume extension " << 2. * shape->GetDX()
229 if (
fDy >= 2. * shape->GetDY() ) {
230 LOG(error) << GetName() <<
": Active size in y ( " <<
fDy
231 <<
" cm exceeds volume extension " << 2. * shape->GetDY()
237 fDz = 2. * shape->GetDZ();
241 LOG(error) << GetName() <<
": Stereo angle front side ( " <<
fStereoF
242 <<
"° exceeds maximum 85° ";
248 LOG(error) << GetName() <<
": Stereo angle back side ( " <<
fStereoB
249 <<
"° exceeds maximum 85° ";
280 Double_t xB, Double_t exB,
281 Double_t& x, Double_t& y,
282 Double_t& varX, Double_t& varY,
304 if ( TMath::Abs(
fStereoF) < 0.001 ) {
314 if ( TMath::Abs(
fStereoB) < 0.001 ) {
329 varY =
fErrorFac * ( exF * exF + exB * exB );
350 LOG(debug3) << GetName() <<
": ideal model of Hit Finder";
352 const BmnMatch *clusterFMatch, *clusterBMatch;
354 clusterFMatch =
static_cast<const BmnMatch*
>(clusterF -> GetMatch());
356 LOG(debug4) << GetName() <<
": front cluster exists";
357 if ((clusterFMatch -> GetNofLinks()) != 1) {
358 LOG(debug4) << GetName() <<
": front cluster has more or less than 1 BmnLink";
360 }
else LOG(debug4) << GetName() <<
": front cluster has " << clusterFMatch -> GetNofLinks() <<
" BmnLink";
363 clusterBMatch =
static_cast<const BmnMatch*
> (clusterB -> GetMatch());
365 LOG(debug4) << GetName() <<
": back cluster exists";
366 if ((clusterBMatch -> GetNofLinks()) != 1){
367 LOG(debug4) << GetName() <<
": back cluster has more or less than 1 BmnLink";
369 }
else LOG(debug4) << GetName() <<
": back cluster has " << clusterBMatch -> GetNofLinks() <<
" BmnLink";
372 if (clusterBMatch -> GetLink(0).
GetIndex() != clusterFMatch -> GetLink(0).
GetIndex()){
373 LOG(debug4) << GetName() <<
": back and front clusters have different index of BmnLink";
375 }
else LOG(debug4) << GetName() <<
": back and front clusters have the same index of BmnLink";
384 LOG(fatal) << GetName() <<
": Inconsistent side qualifier " << side
385 <<
" for front side cluster! ";
387 Double_t du = exF * TMath::Cos(TMath::DegToRad() *
fStereoF);
390 LOG(fatal) << GetName() <<
": Inconsistent side qualifier " << side
391 <<
" for back side cluster! ";
393 Double_t dv = exB * TMath::Cos(TMath::DegToRad() *
fStereoB);
396 if ( ! ( xF >= 0. || xF <=
fDx) )
return 0;
397 if ( ! ( xB >= 0. || xB <=
fDx) )
return 0;
415 Int_t nF1 = TMath::Min(0, nF);
416 Int_t nF2 = TMath::Max(0, nF);
417 Int_t nB1 = TMath::Min(0, nB);
418 Int_t nB2 = TMath::Max(0, nB);
426 for (Int_t iF = nF1; iF <= nF2; iF++) {
427 Double_t xFi = xF - Double_t(iF) *
fDx;
428 for (Int_t iB = nB1; iB <= nB2; iB++) {
429 Double_t xBi = xB - Double_t(iB) *
fDx;
432 Bool_t found =
Intersect(xFi, exF, xBi, exB, xC, yC, varX, varY, varXY);
433 LOG(debug4) << GetName() <<
": Trying " << xFi <<
", " << xBi
434 <<
", intersection ( " << xC <<
", " << yC
435 <<
" ) " << ( found ?
"TRUE" :
"FALSE" )
443 CreateHit(xC, yC, varX, varY, varXY, clusterF, clusterB, du, dv);
477 Double_t z, Double_t charge,
478 Double_t bY, Int_t side) {
481 assert( side == 0 || side == 1);
483 Double_t xCharge = x;
484 Double_t yCharge = y;
485 Double_t zCharge = z;
488 LOG(debug4) << GetName() <<
": Propagating charge " << charge
489 <<
" from (" << x <<
", " << y <<
", " << z
490 <<
") on side " << side <<
" of sensor " << GetName()
496 LOG(debug4) << GetName() <<
": After Lorentz shift: (" << xCharge <<
", "
497 << yCharge <<
", " << zCharge <<
") cm";
502 if ( !
IsInside(xCharge, yCharge) ) {
503 LOG(debug4) << GetName() <<
": Charge outside active area"
512 LOG(debug4) << GetName() <<
": Adding charge " << charge <<
" to strip "
519 Double_t diffusionWidth =
526 assert (diffusionWidth >= 0.);
527 LOG(debug4) << GetName() <<
": Diffusion width = " << diffusionWidth
533 Diffusion(xCharge, yCharge, diffusionWidth, side, fracL, fracC, fracR);
543 iStripL = iStripC - 1;
544 iStripR = iStripC + 1;
547 iStripL = ( iStripC == 0 ?
fNofStrips - 1 : iStripC - 1);
548 iStripR = ( iStripC ==
fNofStrips - 1 ? 0 : iStripC + 1);
553 LOG(debug4) << GetName() <<
": Adding charge " << charge * fracC
554 <<
" to strip " << iStripC;
556 if ( fracL > 0. && iStripL >= 0 ) {
558 LOG(debug4) << GetName() <<
": Adding charge " << charge * fracL
559 <<
" to strip " << iStripL;
563 LOG(debug4) << GetName() <<
": Adding charge " << charge * fracR
564 <<
" to strip " << iStripR;
576 ss <<
"Sensor " << fName <<
" (" << GetTitle() <<
"): ";
577 if ( !
GetPnode() ) ss <<
"no node assigned; ";
579 TGeoBBox* shape =
dynamic_cast<TGeoBBox*
>(
GetPnode()->GetShape());
581 ss <<
"Dimension (" << 2. * shape->GetDX() <<
", "
582 << 2. * shape->GetDY() <<
", " << 2. * shape->GetDZ() <<
") cm, ";
584 ss <<
"dy " <<
fDy <<
" cm, ";
Data class for SSD clusters.
Double_t GetPosition() const
Cluster position @value Cluster position in channel number units.
Double_t GetPositionError() const
Cluster position error @value Error (r.m.s.) of cluster position in channel number units.
Class representing an element of the SSD setup.
TGeoPhysicalNode * fNode
Pointer to geometry.
TGeoPhysicalNode * GetPnode() const
static Double_t DiffusionWidth(Double_t z, Double_t d, Double_t vBias, Double_t vFd, Double_t temperature, Int_t chargeType)
std::string ToString() const
Int_t fNofStrips
Number of strips (same for front and back)
virtual Int_t GetModuleChannel(Int_t strip, Int_t side, Int_t sensorId) const
Get the readout channel in the module for a given strip.
Double_t fErrorFac
Shift in number of strips from bottom to top.
Double_t fCosStereo[2]
tangent of stereo angle front/back side
virtual std::pair< Int_t, Int_t > GetStrip(Int_t channel, Int_t sensorId) const
Double_t fStereoF
Stereo angle front side [degrees].
Bool_t Intersect(Double_t xF, Double_t exF, Double_t xB, Double_t exB, Double_t &x, Double_t &y, Double_t &varX, Double_t &varY, Double_t &varXY)
virtual Int_t IntersectClusters(BmnSsdCluster *clusterF, BmnSsdCluster *clusterB)
virtual void Diffusion(Double_t x, Double_t y, Double_t sigma, Int_t side, Double_t &fracL, Double_t &fracC, Double_t &fracR)
Used for calculation of hit errors.
Int_t fStripShift[2]
cosine of stereo angle front/back side
std::string ToString() const
Set the internal sensor parameters.
BmnSsdSensorDssdStereo(UInt_t address=0, TGeoPhysicalNode *node=nullptr, BmnSsdElement *mother=nullptr)
virtual Int_t GetStripNumber(Double_t x, Double_t y, Int_t side) const
Get strip number from point coordinates.
Double_t fPitch
Strip pitch /same for front and back)
Double_t fStereoB
Stereo angle front back side [degrees].
virtual void ModifyStripPitch(Double_t pitch)
Modify the strip pitch.
virtual Bool_t Init()
Initialisation @value kTRUE if parameters and node are consistent.
virtual void PropagateCharge(Double_t x, Double_t y, Double_t z, Double_t charge, Double_t bY, Int_t side)
Class describing double-sided silicon strip sensors.
Double_t fDz
Thickness in z [cm].
Bool_t fIsSet
Flag whether sensor is properly initialised.
Double_t fDx
Dimension of active area in x [cm].
Double_t fDy
Dimension of active area in y [cm].
Double_t LorentzShift(Double_t z, Int_t chargeType, Double_t bY) const
Lorentz shift in the x coordinate.
void GetClusterPosition(Double_t ClusterCentre, Double_t &xCluster, Int_t &side)
Bool_t IsInside(Double_t x, Double_t y)
void CreateHit(Double_t xLocal, Double_t yLocal, Double_t varX, Double_t varY, Double_t varXY, BmnSsdCluster *clusterF, BmnSsdCluster *clusterB, Double_t du=0., Double_t dv=0.)
const BmnSsdSensorConditions * GetConditions() const
BmnSsdSensorConditions * fConditions
Operating conditions.
static BmnSsdSetup * Instance()