CbmRoot
Loading...
Searching...
No Matches
CbmStsSimSensorDssdStereo.cxx
Go to the documentation of this file.
1/* Copyright (C) 2017-2020 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
2 SPDX-License-Identifier: GPL-3.0-only
3 Authors: Volker Friese [committer] */
4
11
12#include "CbmStsElement.h"
13#include "CbmStsParSensorCond.h"
14#include "CbmStsParSim.h"
15#include "CbmStsPhysics.h"
16
17#include <Logger.h>
18
19#include <TGeoBBox.h>
20#include <TGeoPhysicalNode.h>
21#include <TMath.h>
22
23
24using std::stringstream;
25
26
27// ----- Constructor ---------------------------------------------------
29// -------------------------------------------------------------------------
30
31
32// ----- Constructor ---------------------------------------------------
33CbmStsSimSensorDssdStereo::CbmStsSimSensorDssdStereo(Double_t dy, Int_t nStrips, Double_t pitch, Double_t stereoF,
34 Double_t stereoB, CbmStsElement* element)
35 : CbmStsSimSensorDssd(element)
36 , fNofStrips(nStrips)
37 , fPitch(pitch)
38 , fStereoF(stereoF)
39 , fStereoB(stereoB)
40 , fTanStereo()
41 , fCosStereo()
42 , fStripShift()
43 , fErrorFac(0.)
44{
45 fDy = dy;
46}
47// -------------------------------------------------------------------------
48
49
50// ----- Diffusion -----------------------------------------------------
51void CbmStsSimSensorDssdStereo::Diffusion(Double_t x, Double_t y, Double_t sigma, Int_t side, Double_t& fracL,
52 Double_t& fracC, Double_t& fracR)
53{
54
55 // Check side qualifier
56 assert(side == 0 || side == 1);
57
58 // x coordinate at the readout edge (y = fDy/2 )
59 // This x is counted from the left edge.
60 Double_t xRo = x + fDx / 2. - (fDy / 2. - y) * fTanStereo[side];
61
62 // Centre strip number (w/o cross connection; may be negative or large than
63 // the number of strips)
64 Int_t iStrip = TMath::FloorNint(xRo / fPitch);
65
66 // Strip boundaries at the readout edge (y = fDy/2)
67 Double_t xLeftRo = Double_t(iStrip) * fPitch;
68 Double_t xRightRo = xLeftRo + fPitch;
69
70 // Distance from strip boundaries across the strip
71 Double_t dLeft = (xRo - xLeftRo) * fCosStereo[side];
72 Double_t dRight = (xRightRo - xRo) * fCosStereo[side];
73
74 // Charge fractions
75 // The value 0.707107 is 1/sqrt(2)
76 fracL = 0.;
77 if (dLeft < 3. * sigma) fracL = 0.5 * (1. - TMath::Erf(0.707107 * dLeft / sigma));
78 fracR = 0.;
79 if (dRight < 3. * sigma) fracR = 0.5 * (1. - TMath::Erf(0.707107 * dRight / sigma));
80 fracC = 1. - fracL - fracR;
81}
82// -------------------------------------------------------------------------
83
84
85// ----- Get channel number in module ----------------------------------
86Int_t CbmStsSimSensorDssdStereo::GetModuleChannel(Int_t strip, Int_t side, Int_t sensorId) const
87{
88
89 // --- Check side argument
90 assert(side == 0 || side == 1);
91
92 // --- Account for offset due to stereo angle
93 Int_t channel = strip - sensorId * fStripShift[side];
94
95 // --- Account for horizontal cross-connection of strips
96 while (channel < 0)
97 channel += fNofStrips;
98 while (channel >= fNofStrips)
99 channel -= fNofStrips;
100
101 // --- Account for front or back side
102 if (side) channel += fNofStrips;
103
104 return channel;
105}
106// -------------------------------------------------------------------------
107
108
109// ----- Get strip number from coordinates -----------------------------
110Int_t CbmStsSimSensorDssdStereo::GetStripNumber(Double_t x, Double_t y, Int_t side) const
111{
112
113 // Cave: This implementation assumes that the centre of the sensor volume
114 // is also the centre of the active area, i.e. that the inactive borders
115 // (guard ring) are symmetric both and x and y (not necessarily the same
116 // in x and y).
117
118 // Check side
119 assert(side == 0 || side == 1);
120
121 // Check whether in active area (should have been caught before)
122 assert(TMath::Abs(x) <= fDx / 2.);
123 assert(TMath::Abs(y) <= fDy / 2.);
124
125 // Calculate distance from lower left corner of the active area.
126 // Note: the coordinates are given w.r.t. the centre of the volume.
127 Double_t xdist = x + 0.5 * fDx;
128 Double_t ydist = y + 0.5 * fDy;
129
130 // Project coordinates to readout (top) edge
131 Double_t xro = xdist - (fDy - ydist) * fTanStereo[side];
132
133 // Calculate corresponding strip number
134 Int_t iStrip = TMath::FloorNint(xro / fPitch);
135
136 // Account for horizontal cross-connection of strips
137 // not extending to the top edge
138 while (iStrip < 0)
139 iStrip += fNofStrips;
140 while (iStrip >= fNofStrips)
141 iStrip -= fNofStrips;
142
143 return iStrip;
144}
145// -------------------------------------------------------------------------
146
147
148// ----- Initialise ----------------------------------------------------
150{
151
152 // Check presence of node
153 assert(fElement);
154 TGeoPhysicalNode* node = fElement->GetPnode();
155 assert(node);
156
157 // Check whether parameters are assigned
158 assert(fNofStrips > 0);
159
160 // Geometric shape of the sensor volume
161 TGeoBBox* shape = dynamic_cast<TGeoBBox*>(node->GetShape());
162 assert(shape);
163
164 // Active size in x coordinate
165 fDx = Double_t(fNofStrips) * fPitch;
166 assert(fDx < 2. * shape->GetDX());
167
168 // Active size in y coordinate
169 assert(fDy < 2. * shape->GetDY());
170
171 // Active size in z coordinate
172 fDz = 2. * shape->GetDZ();
173
174 // Stereo angle front side must be between -85 and 85 degrees
175 assert(TMath::Abs(fStereoF) < 85.);
176
177 // Stereo angle back side must be between -85 and 85 degrees
178 assert(TMath::Abs(fStereoB) < 85.);
179
180 // Derived variables
181 fTanStereo[0] = TMath::Tan(fStereoF * TMath::DegToRad());
182 fCosStereo[0] = TMath::Cos(fStereoF * TMath::DegToRad());
183 fStripShift[0] = TMath::Nint(fDy * fTanStereo[0] / fPitch);
184 fTanStereo[1] = TMath::Tan(fStereoB * TMath::DegToRad());
185 fCosStereo[1] = TMath::Cos(fStereoB * TMath::DegToRad());
186 fStripShift[1] = TMath::Nint(fDy * fTanStereo[1] / fPitch);
187
188 // Set size of charge arrays
189 fStripCharge[0].Set(fNofStrips);
190 fStripCharge[1].Set(fNofStrips);
191
192 // Factor for the hit position error
193 fErrorFac = 1. / (fTanStereo[1] - fTanStereo[0]) / (fTanStereo[1] - fTanStereo[0]);
194
195 // --- Flag parameters to be set if test is OK
196 fIsSet = kTRUE;
197
198 return fIsSet;
199}
200// -------------------------------------------------------------------------
201
202
203// ----- Modify the strip pitch ----------------------------------------
205{
206
207 assert(fIsSet); // Parameters should have been set before
208
209 // Set new pitch and re-calculate number of strips
210 fPitch = pitch;
211 fNofStrips = Int_t(fDx / pitch);
212 fDx = Double_t(fNofStrips) * pitch;
213
214 // Set size of charge arrays
215 fStripCharge[0].Set(fNofStrips);
216 fStripCharge[1].Set(fNofStrips);
217}
218// -------------------------------------------------------------------------
219
220
221// ----- Propagate charge to the readout strips ------------------------
222void CbmStsSimSensorDssdStereo::PropagateCharge(Double_t x, Double_t y, Double_t z, Double_t charge, Double_t bY,
223 Int_t side)
224{
225
226 // Check side qualifier
227 assert(side == 0 || side == 1);
228
229 Double_t xCharge = x;
230 Double_t yCharge = y;
231
232 // Lorentz shift on the drift to the readout plane
233 if (fSettings->LorentzShift()) { xCharge += LorentzShift(z, side, bY); }
234
235 // Stop if the charge after Lorentz shift is not in the active area.
236 // Diffusion into the active area is not treated.
237 if (!IsInside(xCharge, yCharge)) { return; }
238
239 // No diffusion: all charge is in one strip
240 if (!fSettings->Diffusion()) {
241 Int_t iStrip = GetStripNumber(xCharge, yCharge, side);
242 fStripCharge[side][iStrip] += charge;
243 } //? Do not use diffusion
244
245 // Diffusion: charge is distributed over centre strip and neighbours
246 else {
247 // Calculate diffusion width
248 Double_t diffusionWidth = CbmStsPhysics::DiffusionWidth(z + fDz / 2., // distance from back side
249 fDz, GetConditions()->GetVbias(), GetConditions()->GetVfd(),
250 GetConditions()->GetTemperature(), side);
251 assert(diffusionWidth >= 0.);
252 // Calculate charge fractions in strips
253 Double_t fracL = 0.; // fraction of charge in left neighbour
254 Double_t fracC = 1.; // fraction of charge in centre strip
255 Double_t fracR = 0.; // fraction of charge in right neighbour
256 Diffusion(xCharge, yCharge, diffusionWidth, side, fracL, fracC, fracR);
257 // Calculate strip numbers
258 // Note: In this implementation, charge can diffuse out of the sensitive
259 // area only for vertical strips. In case of stereo angle (cross-connection
260 // of strips), all charge is assigned to some strip, so the edge effects
261 // are not treated optimally.
262 Int_t iStripC = GetStripNumber(xCharge, yCharge, side); // centre strip
263 Int_t iStripL = 0; // left neighbour
264 Int_t iStripR = 0; // right neighbour
265 if (fTanStereo[side] < 0.0001) { // vertical strips, no cross connection
266 iStripL = iStripC - 1; // might be = -1
267 iStripR = iStripC + 1; // might be = nOfStrips
268 }
269 else { // stereo angle, cross connection
270 iStripL = (iStripC == 0 ? fNofStrips - 1 : iStripC - 1);
271 iStripR = (iStripC == fNofStrips - 1 ? 0 : iStripC + 1);
272 }
273 // Collect charge on the readout strips
274 if (fracC > 0.) {
275 fStripCharge[side][iStripC] += charge * fracC; // centre strip
276 }
277 if (fracL > 0. && iStripL >= 0) {
278 fStripCharge[side][iStripL] += charge * fracL; // right neighbour
279 }
280 if (fracR > 0. && iStripR < fNofStrips) {
281 fStripCharge[side][iStripR] += charge * fracR; // left neighbour
282 }
283 } //? Use diffusion
284}
285// -------------------------------------------------------------------------
286
287
288// ----- String output -------------------------------------------------
290{
291 stringstream ss;
292 assert(fElement);
293 ss << fElement->GetName() << " (DssdStereo): ";
294 TGeoPhysicalNode* node = fElement->GetPnode();
295 if (!node) ss << "no node assigned; ";
296 else {
297 TGeoBBox* shape = dynamic_cast<TGeoBBox*>(node->GetShape());
298 assert(shape);
299 ss << "Dimension (" << 2. * shape->GetDX() << ", " << 2. * shape->GetDY() << ", " << 2. * shape->GetDZ()
300 << ") cm, ";
301 }
302 ss << "dy " << fDy << " cm, ";
303 ss << "# strips " << fNofStrips << ", pitch " << fPitch << " cm, ";
304 ss << "stereo " << fStereoF << "/" << fStereoB << " degrees";
305 if (fConditions) ss << "\n\t Conditions: " << fConditions->ToString();
306 return ss.str();
307}
308// -------------------------------------------------------------------------
309
310
ClassImp(CbmConverterManager)
Class representing an element of the STS setup.
TGeoPhysicalNode * GetPnode() const
std::string ToString() const
String output.
Bool_t LorentzShift() const
Check whether Lorentz shift is applied.
Bool_t Diffusion() const
Check whether diffusion is applied.
static Double_t DiffusionWidth(Double_t z, Double_t d, Double_t vBias, Double_t vFd, Double_t temperature, Int_t chargeType)
Detector response for DSSD sensors with stereo angles and cross-connection by double metal layers.
Double_t fPitch
Strip pitch /same for front and back)
Int_t fStripShift[2]
cosine of stereo angle front/back side
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 fCosStereo[2]
tangent of stereo angle front/back side
std::string ToString() const
String output.
Double_t fErrorFac
Shift in number of strips from bottom to top.
virtual void PropagateCharge(Double_t x, Double_t y, Double_t z, Double_t charge, Double_t bY, Int_t side)
virtual Int_t GetStripNumber(Double_t x, Double_t y, Int_t side) const
Get strip number from point coordinates.
Double_t fStereoF
Stereo angle front side [degrees].
virtual void ModifyStripPitch(Double_t pitch)
Modify the strip pitch.
CbmStsSimSensorDssdStereo(CbmStsElement *element=nullptr)
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.
virtual Bool_t Init()
Initialisation @value kTRUE if parameters and node are consistent.
Int_t fNofStrips
Number of strips (same for front and back)
Double_t fStereoB
Stereo angle front back side [degrees].
Abstract class for the simulation of double-sided silicon strip sensors.
Bool_t IsInside(Double_t x, Double_t y)
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.
CbmStsElement * fElement
const CbmStsParSensorCond * GetConditions() const
Sensor conditions.
const CbmStsParSensorCond * fConditions
Simulation settings.
const CbmStsParSim * fSettings
Simulation module.