BmnRoot
Loading...
Searching...
No Matches
BmnSsdSensorDssd.cxx
Go to the documentation of this file.
1
7#include "BmnSsdSensorDssd.h"
8
9#include <cassert>
10#include "BmnSsdDigitize.h"
12#include "BmnSsdModule.h"
13#include "BmnSsdPhysics.h"
14#include "BmnSsdSensorPoint.h"
15#include "BmnSsdSetup.h"
16
17
18using namespace std;
19
20
21// ----- Constructor ---------------------------------------------------
22BmnSsdSensorDssd::BmnSsdSensorDssd(Int_t address, TGeoPhysicalNode* node,
23 BmnSsdElement* mother) :
24 BmnSsdSensor(address, node, mother),
25 fDx(0.), fDy(0.), fDz(0.), fIsSet(kFALSE)
26{
27}
28// -------------------------------------------------------------------------
29
30
31
32// ----- Cross talk ----------------------------------------------------
33void BmnSsdSensorDssd::CrossTalk(Double_t ctcoeff) {
34
35 for (Int_t side = 0; side < 2; side++) { // front and back side
36
37 // Number of strips for this side
38 Int_t nStrips = GetNofStrips(side);
39
40 // First strip
41 Double_t qLeft = 0.;
42 Double_t qCurrent = fStripCharge[side][0];
43 fStripCharge[side][0] =
44 (1. - ctcoeff ) * qCurrent + ctcoeff * fStripCharge[side][1];
45
46 // Strips 1 to n-2
47 for (Int_t strip = 1; strip < nStrips - 1; strip++) {
48 qLeft = qCurrent;
49 qCurrent = fStripCharge[side][strip];
50 fStripCharge[side][strip] =
51 ctcoeff * ( qLeft + fStripCharge[side][strip+1] ) +
52 ( 1. - 2. * ctcoeff ) * qCurrent;
53 } //# strips
54
55 // Last strip
56 qLeft = qCurrent;
57 qCurrent = fStripCharge[side][nStrips-1];
58 fStripCharge[side][nStrips-1] =
59 ctcoeff * qLeft + ( 1. - ctcoeff ) * qCurrent;
60
61 } //# front and back side
62
63}
64// -------------------------------------------------------------------------
65
66
67
68// ----- Hit finding ----------------------------------------------------
69Int_t BmnSsdSensorDssd::FindHits(std::vector<BmnSsdCluster*>& clusters,
70 TClonesArray* hitArray, BmnEvent* event,
71 Double_t dTime) {
72
73 fHits = hitArray;
74 fEvent = event;
75 Int_t nHits = 0;
76
77 Int_t nClusters = clusters.size();
78
79 Int_t nClustersF = 0;
80 Int_t nClustersB = 0;
81
82 // --- Sort clusters into front and back side
83 vector<Int_t> frontClusters;
84 vector<Int_t> backClusters;
85 Int_t side = -1; // front or back side
86 for (Int_t iCluster = 0; iCluster < nClusters; iCluster++) {
87 BmnSsdCluster* cluster = clusters[iCluster];
88 side = GetSide( cluster->GetPosition() );
89
90 if ( side == 0) {
91 frontClusters.push_back(iCluster);
92 nClustersF++;
93 }
94 else if ( side == 1 ) {
95 backClusters.push_back(iCluster);
96 nClustersB++;
97 }
98 else
99 LOG(fatal) << GetName() << ": Illegal side qualifier "
100 << side;
101 } // Loop over clusters in module
102 LOG(debug3) << GetName() << ": " << nClusters << " clusters (front "
103 << frontClusters.size() << ", back " << backClusters.size()
104 << ") ";
105
106 // --- Loop over front and back side clusters
107 for (Int_t iClusterF = 0; iClusterF < nClustersF; iClusterF++) {
108 BmnSsdCluster* clusterF = clusters[frontClusters[iClusterF]];
109 for (Int_t iClusterB = 0; iClusterB < nClustersB; iClusterB++) {
110 BmnSsdCluster* clusterB = clusters[backClusters[iClusterB]];
111
112 Double_t sigma = TMath::Sqrt( clusterF->GetTimeError() * clusterF->GetTimeError()
113 + clusterB->GetTimeError() * clusterB->GetTimeError() );
114 if ( fabs(clusterF->GetTime() - clusterB->GetTime()) > 4. * sigma ) continue;
115
116 // --- Calculate intersection points
117 Int_t nOfHits = IntersectClusters(clusterF, clusterB);
118 LOG(debug4) << GetName() << ": Cluster front " << iClusterF
119 << ", cluster back " << iClusterB
120 << ", intersections " << nOfHits;
121 nHits += nOfHits;
122
123 } // back side clusters
124
125 } // front side clusters
126
127 LOG(debug3) << GetName() << ": Clusters " << nClusters << " ( "
128 << nClustersF << " / " << nClustersB << " ), hits: "
129 << nHits;
130
131
132 return nHits;
133}
134// -------------------------------------------------------------------------
135
136
137
138// ----- Get cluster position at read-out edge -------------------------
140 Double_t& xCluster,
141 Int_t& side) {
142
143 // Take integer channel
144 Int_t iChannel = Int_t(centre);
145 Double_t xDif = centre - Double_t(iChannel);
146
147 // Calculate corresponding strip on sensor
148 Int_t iStrip = -1;
149 pair<Int_t, Int_t> stripSide = GetStrip(iChannel, GetIndex());
150 iStrip = stripSide.first;
151 side = stripSide.second;
152
153 // Re-add difference to integer channel. Convert channel to
154 // coordinate
155 xCluster = (Double_t(iStrip) + xDif + 0.5 ) * GetPitch(side);
156
157 // Correct for Lorentz-Shift
158 // Simplification: The correction uses only the y component of the
159 // magnetic field. The shift is calculated using the mid-plane of the
160 // sensor, which is not correct for tracks not traversing the entire
161 // sensor thickness (i.e., are created or stopped somewhere in the sensor).
162 // However, this is the best one can do in reconstruction.
163 //Double_t mobility = (side == 0 ? 0.1650 : 0.0310 ); // in m^2/(Vs)
164 //Double_t tanLorentz = mobility * sensor->GetConditions().GetBy();
165 //xCluster -= tanLorentz * fDz / 2.;
166 assert (BmnSsdSetup::Instance()->GetDigiParameters());
167 assert ( GetConditions() );
168 if ( BmnSsdSetup::Instance()->GetDigiParameters()->GetUseLorentzShift() ) {
169 xCluster -= GetConditions()->GetMeanLorentzShift(side);
170 }
171
172 LOG(debug4) << GetName() << ": Cluster centre " << centre
173 << ", sensor index " << GetIndex() << ", side "
174 << side << ", cluster position " << xCluster
175 ;
176 return;
177}
178// -------------------------------------------------------------------------
179
180
181
182// ----- Check whether a point is inside the active area ---------------
183Bool_t BmnSsdSensorDssd::IsInside(Double_t x, Double_t y) {
184 if ( x < -fDx/2. ) return kFALSE;
185 if ( x > fDx/2. ) return kFALSE;
186 if ( y < -fDy/2. ) return kFALSE;
187 if ( y > fDy/2. ) return kFALSE;
188 return kTRUE;
189}
190// -------------------------------------------------------------------------
191
192
193
194// ----- Lorentz shift -------------------------------------------------
195Double_t BmnSsdSensorDssd::LorentzShift(Double_t z, Int_t chargeType,
196 Double_t bY) const {
197
198 // --- Drift distance to readout plane
199 // Electrons drift to the front side (z = d/2), holes to the back side (z = -d/2)
200 Double_t driftZ = 0.;
201 if ( chargeType == 0 ) driftZ = fDz / 2. - z; // electrons
202 else if ( chargeType == 1 ) driftZ = fDz / 2. + z; // holes
203 else {
204 LOG(error) << GetName() << ": illegal charge type " << chargeType
205 ;
206 return 0.;
207 }
208
209 // --- Hall mobility
210 Double_t vBias = GetConditions()->GetVbias();
211 Double_t vFd = GetConditions()->GetVfd();
212 Double_t eField = BmnSsdPhysics::ElectricField(vBias, vFd, fDz, z + fDz/2.);
213 Double_t eFieldMax = BmnSsdPhysics::ElectricField(vBias, vFd, fDz, fDz);
214 Double_t eFieldMin = BmnSsdPhysics::ElectricField(vBias, vFd, fDz, 0.);
215
216 Double_t muHall;
217 if (chargeType == 0) muHall = GetConditions()->HallMobility((eField + eFieldMax)/2., chargeType);
218 if (chargeType == 1) muHall = GetConditions()->HallMobility((eField + eFieldMin)/2., chargeType);
219
220 // --- The direction of the shift is the same for electrons and holes.
221 // --- Holes drift in negative z direction, the field is in
222 // --- positive y direction, thus the Lorentz force v x B acts in positive
223 // --- x direction. Electrons drift in the opposite (positive z) direction,
224 // --- but the have also the opposite charge sign, so the Lorentz force
225 // --- on them is also in the positive x direction.
226 Double_t shift = muHall * bY * driftZ * 1.e-4;
227 LOG(debug4) << GetName() << ": Drift " << driftZ
228 << " cm, mobility " << muHall
229 << " cm**2/(Vs), field " << bY
230 << " T, shift " << shift << " cm";
231 // The factor 1.e-4 is because bZ is in T = Vs/m**2, but muHall is in
232 // cm**2/(Vs) and z in cm.
233
234 return shift;
235}
236// -------------------------------------------------------------------------
237
238
239
240// ----- Print charge status -------------------------------------------
242 LOG(info) << GetName() << ": Charge status: \n";
243 for (Int_t side = 0; side < 2; side++) {
244 for (Int_t strip = 0; strip < GetNofStrips(side); strip++) {
245 if ( fStripCharge[side][strip] > 0. )
246 LOG(info) << " " << (side ? "Back " : "Front ") << "strip "
247 << strip << " charge " << fStripCharge[side][strip] << "\n";
248 } //# strips
249 } //# front and back side
250 LOG(info) << " Total: front side "
251 << (fStripCharge[0]).GetSum() << ", back side "
252 << (fStripCharge[1]).GetSum();
253}
254// -------------------------------------------------------------------------
255
256
257
258// ----- Process one MC Point -------------------------------------------
260
261 // --- Catch if parameters are not set
262 if ( ! fIsSet ) {
263 LOG(fatal) << fName << ": sensor is not initialised!"
264 ;
265 return -1;
266 }
267
268 // --- Debug
269 LOG(debug3) << ToString();
270 LOG(debug3) << GetName() << ": Processing point " << point->ToString()
271 ;
272
273 // --- Number of created charge signals (coded front/back side)
274 Int_t nSignals = 0;
275
276 // --- Reset the strip charge arrays
277 fStripCharge[0].Reset(); // front side
278 fStripCharge[1].Reset(); // back side
279
280 // --- Produce charge and propagate it to the readout strips
281 ProduceCharge(point);
282
283 // --- Cross talk
284 if ( BmnSsdSetup::Instance()->GetDigiParameters()->GetUseCrossTalk() ) {
285 if ( FairLogger::GetLogger()->IsLogNeeded(DEBUG4) ) {
286 LOG(debug4) << GetName() << ": Status before cross talk"
287 ;
289 }
290 Double_t ctcoeff = GetConditions()->GetCrossTalk();
291 LOG(debug4) << GetName() << ": Cross-talk coefficient is "
292 << ctcoeff;
293 CrossTalk(ctcoeff);
294 }
295
296 // --- Debug
297 if ( FairLogger::GetLogger()->IsLogNeeded(DEBUG3) )
299
300 // --- Stop here if no module is connected (e.g. for test purposes)
301 if ( ! GetModule() ) return 0;
302
303 // --- Register charges in strips to the module
304 Int_t nCharges[2] = { 0, 0 };
305 for (Int_t side = 0; side < 2; side ++) { // front and back side
306
307 for (Int_t strip = 0; strip < GetNofStrips(side); strip++) {
308 if ( fStripCharge[side][strip] > 0. ) {
309 RegisterCharge(side, strip, fStripCharge[side][strip],
310 point->GetTime());
311 nCharges[side]++;
312 } //? charge in strip
313 } //# strips
314
315 } //# front and back side
316
317 // Code number of signals
318 nSignals = 1000 * nCharges[0] + nCharges[1];
319
320 return nSignals;
321}
322// -------------------------------------------------------------------------
323
324
325
326// ----- Produce charge and propagate it to the readout strips ---------
328
329 // Total charge created in the sensor: is calculated from the energy loss
330 Double_t chargeTotal =
331 point->GetELoss() / BmnSsdPhysics::PairCreationEnergy(); // in e
332
333 // For ideal energy loss, just have all charge in the mid-point of the
334 // trajectory
335 if ( BmnSsdSetup::Instance()->GetDigitizer()->GetELossModel() == 0 ) {
336 Double_t xP = 0.5 * ( point->GetX1() + point->GetX2() );
337 Double_t yP = 0.5 * ( point->GetY1() + point->GetY2() );
338 Double_t zP = 0.5 * ( point->GetZ1() + point->GetZ2() );
339 PropagateCharge(xP, yP, zP, chargeTotal, point->GetBy(), 0); // front side (n)
340 PropagateCharge(xP, yP, zP, chargeTotal, point->GetBy(), 1); // back side (p)
341 return;
342 }
343
344 // Kinetic energy
345 Double_t mass = BmnSsdPhysics::ParticleMass(point->GetPid());
346 Double_t eKin = TMath::Sqrt( point->GetP() * point->GetP() + mass * mass )
347 - mass;
348
349 // Length of trajectory inside sensor and its projections
350 Double_t trajLx = point->GetX2() - point->GetX1();
351 Double_t trajLy = point->GetY2() - point->GetY1();
352 Double_t trajLz = point->GetZ2() - point->GetZ1();
353 Double_t trajLength = TMath::Sqrt( trajLx*trajLx +
354 trajLy*trajLy +
355 trajLz*trajLz );
356
357 // The trajectory is sub-divided into equidistant steps, with a step size
358 // close to 3 micrometer.
359 Double_t stepSizeTarget = 3.e-4; // targeted step size is 3 micrometer
360 Int_t nSteps = TMath::Nint( trajLength / stepSizeTarget );
361 if ( nSteps == 0 ) nSteps = 1; // assure at least one step
362 Double_t stepSize = trajLength / nSteps;
363 Double_t stepSizeX = trajLx / nSteps;
364 Double_t stepSizeY = trajLy / nSteps;
365 Double_t stepSizeZ = trajLz / nSteps;
366
367 // Average charge per step, used for uniform distribution
368 Double_t chargePerStep = chargeTotal / nSteps;
369 LOG(debug3) << GetName() << ": Trajectory length " << trajLength
370 << " cm, steps " << nSteps << ", step size " << stepSize * 1.e4
371 << " mu, charge per step " << chargePerStep;
372
373 // Stopping power, needed for energy loss fluctuations
374 Double_t dedx = 0.;
375 if ( BmnSsdSetup::Instance()->GetDigitizer()->GetELossModel() == 2 )
376 dedx = BmnSsdPhysics::Instance()->StoppingPower(eKin, point->GetPid());
377
378 // Stepping over the trajectory
379 Double_t chargeSum = 0.;
380 Double_t xStep = point->GetX1() - 0.5 * stepSizeX;
381 Double_t yStep = point->GetY1() - 0.5 * stepSizeY;
382 Double_t zStep = point->GetZ1() - 0.5 * stepSizeZ;
383 for (Int_t iStep = 0; iStep < nSteps; iStep++ ) {
384 xStep += stepSizeX;
385 yStep += stepSizeY;
386 zStep += stepSizeZ;
387
388 // Charge for this step
389 Double_t chargeInStep = chargePerStep; // uniform energy loss
390 if ( BmnSsdSetup::Instance()->GetDigitizer()->GetELossModel() == 2 ) // energy loss fluctuations
391 chargeInStep = BmnSsdPhysics::Instance()->EnergyLoss(stepSize, mass, eKin, dedx)
393 chargeSum += chargeInStep;
394
395 // Propagate charge to strips
396 PropagateCharge(xStep, yStep, zStep, chargeInStep,
397 point->GetBy(), 0); // front
398 PropagateCharge(xStep, yStep, zStep, chargeInStep,
399 point->GetBy(), 1); // back
400
401 } //# steps of the trajectory
402
403 // For fluctuations: normalise to the total charge from GEANT.
404 // Since the number of steps is finite (about 100), the average
405 // charge per step does not coincide with the expectation value.
406 // In order to be consistent with the transport, the charges are
407 // re-normalised.
408 if ( BmnSsdSetup::Instance()->GetDigitizer()->GetELossModel() == 2) {
409 for (Int_t side = 0; side < 2; side++) { // front and back side
410 for (Int_t strip = 0; strip < GetNofStrips(side); strip++)
411 fStripCharge[side][strip] *= ( chargeTotal / chargeSum );
412 } //# front and back side
413 } //? E loss fluctuations
414
415}
416// -------------------------------------------------------------------------
417
418
419
420// ----- Register charge to the module ----------------------------------
421void BmnSsdSensorDssd::RegisterCharge(Int_t side, Int_t strip,
422 Double_t charge,
423 Double_t time) const {
424
425 // --- Check existence of module
426 if ( ! GetModule() ) {
427 LOG(error) << GetName() << ": No module connected to sensor "
428 << GetName() << ", side " << side << ", strip "
429 << strip << ", time " << time << ", charge " << charge
430 ;
431 return;
432 }
433
434 // --- Determine module channel for given sensor strip
435 Int_t channel = GetModuleChannel(strip, side, GetSensorId() );
436
437 // --- Debug output
438 LOG(debug4) << fName << ": Registering charge: side " << side
439 << ", strip " << strip << ", time " << time
440 << ", charge " << charge
441 << " to channel " << channel
442 << " of module " << GetModule()->GetName()
443 ;
444
445 // --- Get the MC link information
446 Int_t index = -1;
447 Int_t entry = -1;
448 Int_t file = -1;
449 if ( GetCurrentLink() ) {
450 index = GetCurrentLink()->GetIndex();
451 entry = GetCurrentLink()->GetEntry();
452 file = GetCurrentLink()->GetFile();
453 }
454
455 // --- Send signal to module
456 GetModule()->AddSignal(channel, time, charge, index, entry, file);
457
458}
459// -------------------------------------------------------------------------
460
461
462
463// ----- Self test -----------------------------------------------------
465
466 for (Int_t sensorId = 0; sensorId < 3; sensorId++ ) {
467 for (Int_t side = 0; side < 2; side ++ ) {
468 for (Int_t strip = 0; strip < GetNofStrips(side); strip++ ) {
469 Int_t channel = GetModuleChannel(strip, side, sensorId);
470 pair<Int_t, Int_t> test = GetStrip(channel, sensorId);
471 if ( test.first != strip || test.second != side ) {
472 LOG(error) << fName << "Self test failed! Sensor " << sensorId
473 << " side " << side << " strip " << strip
474 << " gives channel " << channel << " gives strip "
475 << test.first << " side " << test.second
476 ;
477 return kFALSE;
478 }
479 } // strip loop
480 } // side loop
481 } // sensor loop
482
483 return kTRUE;
484}
485// -------------------------------------------------------------------------
friend F32vec4 fabs(const F32vec4 &a)
Definition P4_F32vec4.h:52
Class characterising one event by a collection of links (indices) to data objects,...
Definition BmnEvent.h:26
Data class for SSD clusters.
Double_t GetPosition() const
Cluster position @value Cluster position in channel number units.
Double_t GetTime() const
Get cluster time.
Double_t GetTimeError() const
Get error of cluster time.
Class representing an element of the SSD setup.
Int_t GetIndex() const
void AddSignal(UShort_t channel, Double_t time, Double_t charge, Int_t index=0, Int_t entry=0, Int_t file=0)
static Double_t ParticleMass(Int_t pid)
Double_t StoppingPower(Double_t eKin, Int_t pid)
static Double_t ElectricField(Double_t vBias, Double_t vFd, Double_t dZ, Double_t z)
Double_t EnergyLoss(Double_t dz, Double_t mass, Double_t eKin, Double_t dedx) const
static Double_t PairCreationEnergy()
static BmnSsdPhysics * Instance()
Double_t GetMeanLorentzShift(Int_t side) const
Double_t HallMobility(Double_t eField, Int_t chargeType) const
virtual Int_t FindHits(std::vector< BmnSsdCluster * > &clusters, TClonesArray *hitArray, BmnEvent *event, Double_t dTime)
Find hits from clusters.
Double_t fDz
Thickness in z [cm].
virtual Int_t GetNofStrips(Int_t side) const =0
Number of strips on front and back side.
void RegisterCharge(Int_t side, Int_t strip, Double_t charge, Double_t time) const
Register the produced charge in one strip to the module.
virtual Int_t IntersectClusters(BmnSsdCluster *clusterF, BmnSsdCluster *clusterB)=0
virtual Double_t GetPitch(Int_t side) const =0
Strip pitch on front and back side.
void PrintChargeStatus() const
Bool_t fIsSet
Flag whether sensor is properly initialised.
BmnSsdSensorDssd(Int_t address=0, TGeoPhysicalNode *node=nullptr, BmnSsdElement *mother=nullptr)
Double_t fDx
Dimension of active area in x [cm].
Double_t fDy
Dimension of active area in y [cm].
virtual void PropagateCharge(Double_t x, Double_t y, Double_t z, Double_t charge, Double_t bY, Int_t side)=0
Int_t GetSide(Double_t channel) const
virtual std::string ToString() const =0
virtual Int_t GetModuleChannel(Int_t strip, Int_t side, Int_t sensorId) const =0
Get the readout channel in the module for a given strip.
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)
virtual Int_t CalculateResponse(BmnSsdSensorPoint *point)
Analogue response to a track in the sensor.
void ProduceCharge(BmnSsdSensorPoint *point)
Generate charge as response to a sensor point.
virtual std::pair< Int_t, Int_t > GetStrip(Int_t channel, Int_t sensorId) const =0
void CrossTalk(Double_t ctcoeff)
Bool_t IsInside(Double_t x, Double_t y)
Container class for a local point in a SSD sensor.
Double_t GetTime() const
Time [ns].
Double_t GetZ2() const
Exit z coordinate [cm].
Double_t GetX2() const
Exit x coordinate [cm].
std::string ToString() const
Double_t GetZ1() const
Entry z coordinate [cm].
Double_t GetY2() const
Exit y coordinate [cm].
Int_t GetPid() const
Particle ID [PDG].
Double_t GetX1() const
Entry x coordinate [cm].
Double_t GetBy() const
By-Field at midpoint [T].
Double_t GetY1() const
Entry y coordinate [cm].
Double_t GetELoss() const
Energy loss [GeV].
Double_t GetP() const
Momentum magnitude.
Class representing an instance of a sensor in the BMN-SSD.
BmnLink * GetCurrentLink() const
TClonesArray * fHits
Output array for hits. Used in hit finding.
const BmnSsdSensorConditions * GetConditions() const
Int_t GetSensorId() const
BmnSsdModule * GetModule() const
BmnEvent * fEvent
static BmnSsdSetup * Instance()
STL namespace.