CbmRoot
Loading...
Searching...
No Matches
CbmStsSimSensorDssdOrtho.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], Pierre-Alain Loizeau */
4
11
12#include "CbmMatch.h"
13#include "CbmStsParSim.h"
14#include "CbmStsPhysics.h"
15#include "CbmStsSetup.h"
16
17#include "TGeoBBox.h"
18#include "TGeoMatrix.h"
19#include "TMath.h"
20#include <TGeoPhysicalNode.h>
21
22#include <cassert>
23
24
25using namespace std;
26
27
28// ----- Constructor ---------------------------------------------------
30// -------------------------------------------------------------------------
31
32
33// ----- Constructor ---------------------------------------------------
34CbmStsSimSensorDssdOrtho::CbmStsSimSensorDssdOrtho(Int_t nStripsF, Double_t pitchF, Int_t nStripsB, Double_t pitchB,
35 CbmStsElement* element)
36 : CbmStsSimSensorDssd(element)
37 , fNofStrips {nStripsF, nStripsB}
38 , fPitch {pitchF, pitchB}
39{
40}
41// -------------------------------------------------------------------------
42
43
44// ----- Diffusion -----------------------------------------------------
45void CbmStsSimSensorDssdOrtho::Diffusion(Double_t x, Double_t y, Double_t sigma, Int_t side, Double_t& fracL,
46 Double_t& fracC, Double_t& fracR)
47{
48
49 // Check side qualifier
50 assert(side == 0 || side == 1);
51
52 // Coordinate at the readout edge (y = fDy/2 ).
53 // This x is counted from the left / bottom corner.
54 Double_t aRo = (side == 0 ? x + fDx / 2. : y + fDy / 2.);
55
56 // Centre strip number
57 Int_t iStrip = TMath::FloorNint(aRo / fPitch[side]);
58
59 // Strip boundaries at the readout edge
60 Double_t aLeftRo = Double_t(iStrip) * fPitch[side];
61 Double_t aRightRo = aLeftRo + fPitch[side];
62
63 // Distance from strip boundaries across the strip
64 Double_t dLeft = aRo - aLeftRo;
65 Double_t dRight = aRightRo - aRo;
66
67 // Charge fractions
68 // The value 0.707107 is 1/sqrt(2)
69 fracL = 0.;
70 if (dLeft < 3. * sigma) fracL = 0.5 * (1. - TMath::Erf(0.707107 * dLeft / sigma));
71 fracR = 0.;
72 if (dRight < 3. * sigma) fracR = 0.5 * (1. - TMath::Erf(0.707107 * dRight / sigma));
73 fracC = 1. - fracL - fracR;
74
75 LOG(debug4) << GetName() << ": Distances to next strip " << dLeft << " / " << dRight << ", charge fractions " << fracL
76 << " / " << fracC << " / " << fracR;
77}
78// -------------------------------------------------------------------------
79
80
81// ----- Get channel number in module ----------------------------------
82Int_t CbmStsSimSensorDssdOrtho::GetModuleChannel(Int_t strip, Int_t side, Int_t) const
83{
84
85 // --- Check side
86 assert(side == 0 || side == 1);
87
88 // --- Account for front or back side
89 Int_t channel = strip;
90 if (side) channel += fNofStrips[0];
91
92 return channel;
93}
94// -------------------------------------------------------------------------
95
96
97// ----- Get strip number from coordinates -----------------------------
98Int_t CbmStsSimSensorDssdOrtho::GetStripNumber(Double_t x, Double_t y, Int_t side) const
99{
100
101 // Cave: This implementation assumes that the centre of the sensor volume
102 // is also the centre of the active area, i.e. that the inactive borders
103 // (guard ring) are symmetric both and x and y (not necessarily the same
104 // in x and y).
105
106 // Check side
107 assert(side == 0 || side == 1);
108
109 // Check whether in active area (should have been caught before)
110 assert(TMath::Abs(x) < 0.5 * fDx);
111 assert(TMath::Abs(y) < 0.5 * fDy);
112
113 // Calculate distance from lower left corner of the active area,
114 // in x for the front side, in y for the back side.
115 // Note: the coordinates are given w.r.t. the centre of the volume.
116 Double_t dist = (side == 0 ? x + 0.5 * fDx : y + 0.5 * fDy);
117
118 // Calculate corresponding strip number
119 Int_t iStrip = TMath::FloorNint(dist / fPitch[side]);
120
121 return iStrip;
122}
123// -------------------------------------------------------------------------
124
125
126// ----- Initialise ----------------------------------------------------
128{
129
130 // Check whether parameters are assigned
131 if (fNofStrips[0] <= 0) {
132 LOG(error) << GetName() << ": Parameters are not set!";
133 return kFALSE;
134 }
135
136 // Geometric shape of the sensor volume
137 assert(fElement);
138 TGeoPhysicalNode* node = fElement->GetPnode();
139 assert(node);
140 TGeoBBox* shape = dynamic_cast<TGeoBBox*>(node->GetShape());
141 assert(shape);
142
143 // Active size in x coordinate
144 fDx = Double_t(fNofStrips[0]) * fPitch[0];
145 assert(fDx < 2. * shape->GetDX()); // The strips fit into the volume
146
147 // Active size in y coordinate
148 fDy = Double_t(fNofStrips[1]) * fPitch[1];
149 assert(fDy < 2. * shape->GetDY());
150
151 // Active size in z coordinate
152 fDz = 2. * shape->GetDZ();
153
154 // Set size of charge arrays
155 fStripCharge[0].Set(fNofStrips[0]);
156 fStripCharge[1].Set(fNofStrips[1]);
157
158 // Daisy chains are not allowed. Make sure that this is the only sensor
159 // connected to the module.
160 assert(GetSensorId() == 0);
161
162 // --- Flag parameters to be set if test is OK
163 fIsSet = kTRUE;
164
165 LOG(info) << ToString();
166
167 return fIsSet;
168}
169// -------------------------------------------------------------------------
170
171
172// ----- Modify the strip pitch ----------------------------------------
174{
175
176 assert(fIsSet); // Parameters should have been set before
177
178 // Set new pitch and re-calculate number of strips on both sides
179 fPitch[0] = pitch;
180 fNofStrips[0] = Int_t(fDx / pitch);
181 fDx = Double_t(fNofStrips[0]) * pitch;
182 fPitch[1] = pitch;
183 fNofStrips[1] = Int_t(fDy / pitch);
184 fDy = Double_t(fNofStrips[1]) * pitch;
185
186 // Set size of charge arrays
187 fStripCharge[0].Set(fNofStrips[0]);
188 fStripCharge[1].Set(fNofStrips[1]);
189}
190// -------------------------------------------------------------------------
191
192
193// ----- Propagate charge to the readout strips ------------------------
194void CbmStsSimSensorDssdOrtho::PropagateCharge(Double_t x, Double_t y, Double_t z, Double_t charge, Double_t bY,
195 Int_t side)
196{
197
198 // Check side qualifier
199 assert(side == 0 || side == 1);
200
201 Double_t xCharge = x;
202 Double_t yCharge = y;
203 Double_t zCharge = z;
204
205 // Debug
206 LOG(debug4) << GetName() << ": Propagating charge " << charge << " from (" << x << ", " << y << ", " << z
207 << ") on side " << side << " of sensor " << GetName();
208
209 // Lorentz shift on the drift to the readout plane
210 if (fSettings->LorentzShift()) { xCharge += LorentzShift(z, side, bY); }
211
212 LOG(debug4) << GetName() << ": After Lorentz shift: (" << xCharge << ", " << yCharge << ", " << zCharge << ") cm";
213
214 // Stop if the charge after Lorentz shift is not in the active area.
215 // Diffusion into the active area is not treated.
216 if (!IsInside(xCharge, yCharge)) {
217 LOG(debug4) << GetName() << ": Charge outside active area";
218 return;
219 }
220
221 // No diffusion: all charge is in one strip
222 if (!fSettings->Diffusion()) {
223 Int_t iStrip = GetStripNumber(xCharge, yCharge, side);
224 fStripCharge[side][iStrip] += charge;
225 LOG(debug4) << GetName() << ": Adding charge " << charge << " to strip " << iStrip;
226 } //? Do not use diffusion
227
228 // Diffusion: charge is distributed over centre strip and neighbours
229 else {
230 // Calculate diffusion width
231 Double_t diffusionWidth = CbmStsPhysics::DiffusionWidth(z + fDz / 2., // distance from back side
232 fDz, GetConditions()->GetVbias(), GetConditions()->GetVfd(),
233 GetConditions()->GetTemperature(), side);
234 assert(diffusionWidth >= 0.);
235 LOG(debug4) << GetName() << ": Diffusion width = " << diffusionWidth << " cm";
236 // Calculate charge fractions in strips
237 Double_t fracL = 0.; // fraction of charge in left neighbour
238 Double_t fracC = 1.; // fraction of charge in centre strip
239 Double_t fracR = 0.; // fraction of charge in right neighbour
240 Diffusion(xCharge, yCharge, diffusionWidth, side, fracL, fracC, fracR);
241 // Calculate strip numbers
242 // Note: In this implementation, charge can diffuse out of the sensitive
243 // area only for vertical strips. In case of stereo angle (cross-connection
244 // of strips), all charge is assigned to some strip, so the edge effects
245 // are not treated optimally.
246 Int_t iStripC = GetStripNumber(xCharge, yCharge, side); // centre strip
247 Int_t iStripL = iStripC - 1; // left neighbour
248 Int_t iStripR = iStripC + 1; // right neighbour
249 // Collect charge on the readout strips
250 if (fracC > 0.) {
251 fStripCharge[side][iStripC] += charge * fracC; // centre strip
252 LOG(debug4) << GetName() << ": Adding charge " << charge * fracC << " to strip " << iStripC;
253 }
254 if (fracL > 0. && iStripL >= 0) {
255 fStripCharge[side][iStripL] += charge * fracL; // right neighbour
256 LOG(debug4) << GetName() << ": Adding charge " << charge * fracL << " to strip " << iStripL;
257 }
258 if (fracR > 0. && iStripR < fNofStrips[side]) {
259 fStripCharge[side][iStripR] += charge * fracR; // left neighbour
260 LOG(debug4) << GetName() << ": Adding charge " << charge * fracR << " to strip " << iStripR;
261 }
262 } //? Use diffusion
263}
264// -------------------------------------------------------------------------
265
266
267// ----- Set internal sensor parameters --------------------------------
268Bool_t CbmStsSimSensorDssdOrtho::SetParameters(Int_t nStripsF, Double_t pitchF, Int_t nStripsB, Double_t pitchB)
269{
270
271 // Geometric shape of the sensor volume
272 assert(fElement);
273 TGeoPhysicalNode* node = fElement->GetPnode();
274 TGeoBBox* shape = dynamic_cast<TGeoBBox*>(node->GetShape());
275
276 // Active size in x coordinate
277 fDx = Double_t(nStripsF) * pitchF;
278 assert(fDx < 2. * shape->GetDX()); // The strips fit into the volume
279
280 // Active size in y coordinate
281 fDy = Double_t(nStripsB) * pitchB;
282 assert(fDy < 2. * shape->GetDY());
283
284 // Active size in z coordinate
285 fDz = 2. * shape->GetDZ();
286
287 // Number of strips, pitch and stereo angles
288 fNofStrips[0] = nStripsF;
289 fPitch[0] = pitchF;
290 fNofStrips[1] = nStripsB;
291 fPitch[1] = pitchB;
292
293 // Set size of charge arrays
294 fStripCharge[0].Set(fNofStrips[0]);
295 fStripCharge[1].Set(fNofStrips[1]);
296
297 // Daisy chains are not allowed. Make sure that this is the only sensor
298 // connected to the module.
299 assert(GetSensorId() == 0);
300
301 // --- Flag parameters to be set if test is OK
302 fIsSet = kTRUE;
303
304 return fIsSet;
305}
306// -------------------------------------------------------------------------
307
308
309// ----- String output -------------------------------------------------
311{
312 stringstream ss;
313 assert(fElement);
314 ss << fElement->GetName() << " (DssdOrtho): ";
315 TGeoPhysicalNode* node = fElement->GetPnode();
316 if (!node) ss << "no node assigned; ";
317 else {
318 ss << "Dimension (" << fDx << ", " << fDy << ", " << fDz << ") cm, ";
319 ss << "# strips " << fNofStrips[0] << "/" << fNofStrips[1] << ", ";
320 ss << "pitch " << fPitch[0] << "/" << fPitch[1] << " cm, ";
321 }
322 return ss.str();
323}
324// -------------------------------------------------------------------------
325
ClassImp(CbmConverterManager)
Class representing an element of the STS setup.
TGeoPhysicalNode * GetPnode() const
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 orthogonal strips.
virtual void ModifyStripPitch(Double_t pitch)
Modify the strip pitch.
virtual void Diffusion(Double_t x, Double_t y, Double_t sigma, Int_t side, Double_t &fracL, Double_t &fracC, Double_t &fracR)
CbmStsSimSensorDssdOrtho(CbmStsElement *element=nullptr)
Standard constructor.
virtual void PropagateCharge(Double_t x, Double_t y, Double_t z, Double_t charge, Double_t bY, Int_t side)
Double_t fPitch[2]
Strip pitch front/back side [cm].
virtual Int_t GetStripNumber(Double_t x, Double_t y, Int_t side) const
Get strip number from point coordinates.
Int_t fNofStrips[2]
Number of strips on front/back side.
virtual Bool_t Init()
Initialisation @value kTRUE if parameters and node are consistent.
Bool_t SetParameters(Int_t nStripsF, Double_t pitchF, Int_t nStripsB, Double_t pitchB)
Set the internal sensor parameters.
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.
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.
Int_t GetSensorId() const
Sensor ID.
CbmStsElement * fElement
const CbmStsParSensorCond * GetConditions() const
Sensor conditions.
const CbmStsParSim * fSettings
Simulation module.
Hash for CbmL1LinkKey.