1 package org.lcsim.detector.tracker.silicon;
2
3 import hep.physics.matrix.BasicMatrix;
4 import hep.physics.vec.BasicHep3Vector;
5 import hep.physics.vec.VecOp;
6
7 import java.util.HashMap;
8 import java.util.HashSet;
9 import java.util.List;
10 import java.util.Map;
11 import java.util.Set;
12
13 import org.lcsim.detector.IDetectorElement;
14 import org.lcsim.detector.IRotation3D;
15 import org.lcsim.detector.ITranslation3D;
16 import org.lcsim.detector.RotationPassiveXYZ;
17 import org.lcsim.detector.Transform3D;
18 import org.lcsim.detector.Translation3D;
19 import org.lcsim.detector.identifier.IIdentifier;
20 import org.lcsim.detector.solids.Box;
21 import org.lcsim.detector.solids.LineSegment3D;
22 import org.lcsim.detector.solids.Polygon3D;
23
24
25
26
27
28
29
30
31
32 public class HpsSiSensor extends SiSensor {
33
34
35
36
37
38 public final static int NUMBER_OF_SAMPLES = 6;
39 private final static int NUMBER_OF_SHAPE_FIT_PARAMETERS = 4;
40
41 public final static int AMPLITUDE_INDEX = 0;
42 public final static int T0_INDEX = 1;
43 public final static int TP_INDEX = 2;
44
45 public final static String ELECTRON_SIDE = "ELECTRON";
46 public final static String POSITRON_SIDE = "POSITRON";
47
48
49
50
51
52 protected int febID;
53 protected int febHybridID;
54 protected double t0Shift = 0;
55 protected boolean isAxial = false;
56 protected boolean isStereo = false;
57
58 private final double readoutStripCapacitanceIntercept = 0;
59 private final double readoutStripCapacitanceSlope = 0.16;
60 private final double senseStripCapacitanceIntercept = 0;
61 private final double senseStripCapacitanceSlope = 0.16;
62
63
64
65
66
67
68
69
70 protected double longSensorLengthThreshold = 190.0;
71 protected double readoutLongStripCapacitanceSlope = 0.39;
72 protected double senseLongStripCapacitanceSlope = 0.39;
73
74
75
76
77 protected Map<Integer, double[]> pedestalMap = new HashMap<Integer, double[]>();
78 protected Map<Integer, double[]> noiseMap = new HashMap<Integer, double[]>();
79 protected Map<Integer, Double> gainMap = new HashMap<Integer, Double>();
80 protected Map<Integer, Double> offsetMap = new HashMap<Integer, Double>();
81 protected Map<Integer, double[]> shapeFitParametersMap = new HashMap<Integer, double[]>();
82 protected Set<Integer> badChannels = new HashSet<Integer>();
83 protected int millepedeId = -1;
84
85
86
87
88
89
90
91
92
93
94 public HpsSiSensor(final int sensorid, final String name, final IDetectorElement parent, final String support,
95 final IIdentifier id) {
96 super(sensorid, name, parent, support, id);
97
98
99
100
101 if (this.isTopLayer() && this.getLayerNumber() % 2 == 1) {
102 this.setAxial(true);
103 } else if (this.isBottomLayer() && this.getLayerNumber() % 2 == 0) {
104 this.setAxial(true);
105 } else {
106 this.setStereo(true);
107 }
108
109 this.initialize();
110 }
111
112
113
114
115
116
117
118 public boolean isTopLayer() {
119 return getModuleNumber() % 2 == 0;
120 }
121
122
123
124
125
126
127
128 public boolean isBottomLayer() {
129 return getModuleNumber() % 2 != 0;
130 }
131
132
133
134
135
136
137 public int getModuleNumber() {
138 return getTrackerIdHelper().getModuleValue(getIdentifier());
139 }
140
141
142
143
144
145
146 public SiTrackerIdentifierHelper getTrackerIdHelper() {
147 return (SiTrackerIdentifierHelper) getIdentifierHelper();
148 }
149
150
151
152
153
154
155 public boolean isAxial() {
156 return this.isAxial;
157 }
158
159
160
161
162
163
164 public boolean isStereo() {
165 return this.isStereo;
166 }
167
168
169
170
171
172
173
174
175 public Double getPedestal(final int channel, final int sample) {
176 if (sample >= NUMBER_OF_SAMPLES) {
177 throw new RuntimeException("The sample number must be less than " + NUMBER_OF_SAMPLES);
178 }
179 return this.pedestalMap.get(channel)[sample];
180 }
181
182
183
184
185
186
187
188
189 public Double getNoise(final int channel, final int sample) {
190 if (sample >= NUMBER_OF_SAMPLES) {
191 throw new RuntimeException("The sample number must be less than " + NUMBER_OF_SAMPLES);
192 }
193 return this.noiseMap.get(channel)[sample];
194 }
195
196
197
198
199
200
201
202 public Double getGain(final int channel) {
203 return this.gainMap.get(channel);
204 }
205
206
207
208
209
210
211
212 public Double getOffset(final int channel) {
213 return this.offsetMap.get(channel);
214 }
215
216
217 public double getReadoutTransferEfficiency() {
218 return 0.986;
219 }
220
221
222 public double getSenseTransferEfficiency() {
223 return 0.419;
224 }
225
226
227
228
229
230
231
232 public double[] getShapeFitParameters(final int channel) {
233 return this.shapeFitParametersMap.get(channel);
234 }
235
236
237
238
239
240
241
242 public boolean isBadChannel(final int channel) {
243 return this.badChannels.contains(channel);
244 }
245
246
247
248
249
250
251 public int getNumberOfChannels() {
252 return this.getReadoutElectrodes(ChargeCarrier.HOLE).getNCells();
253 }
254
255
256 public int getNumberOfSenseStrips() {
257 return 1277;
258 }
259
260
261
262
263
264
265
266 public boolean isValidChannel(final int channel) {
267 return this.getNumberOfChannels() >= 0 && channel < this.getNumberOfChannels();
268 }
269
270
271
272
273
274
275 public int getFebID() {
276 return this.febID;
277 }
278
279
280
281
282
283
284 public int getFebHybridID() {
285 return this.febHybridID;
286 }
287
288
289
290
291
292
293 public int getLayerNumber() {
294 return getIdentifierHelper().getValue(getIdentifier(), "layer");
295 }
296
297
298
299
300
301
302 public double getT0Shift() {
303 return this.t0Shift;
304 }
305
306
307
308
309
310
311 public String getSide() {
312 return this.getModuleNumber() < 2 ? ELECTRON_SIDE : POSITRON_SIDE;
313 }
314
315
316 public double getReadoutStripPitch() {
317 return 0.060;
318 }
319
320
321 public double getSenseStripPitch() {
322 return 0.030;
323 }
324
325
326
327
328
329
330
331 public long makeChannelID(final int channel) {
332 final int sideNumber = this.hasElectrodesOnSide(ChargeCarrier.HOLE) ? ChargeCarrier.HOLE.charge()
333 : ChargeCarrier.ELECTRON.charge();
334 return this.makeStripId(channel, sideNumber).getValue();
335 }
336
337
338
339
340
341
342
343 public void setPedestal(final int channel, final double[] pedestal) {
344 if (pedestal.length > NUMBER_OF_SAMPLES) {
345 throw new RuntimeException("The number of pedestal samples must be equal to" + NUMBER_OF_SAMPLES);
346 }
347 this.pedestalMap.put(channel, pedestal);
348 }
349
350
351
352
353
354
355
356 public void setNoise(final int channel, final double[] noise) {
357 if (noise.length > NUMBER_OF_SAMPLES) {
358 throw new RuntimeException("The number of pedestal samples must be equal to" + NUMBER_OF_SAMPLES);
359 }
360 this.noiseMap.put(channel, noise);
361 }
362
363
364
365
366
367
368
369 public void setGain(final int channel, final double gain) {
370 this.gainMap.put(channel, gain);
371 }
372
373
374
375
376
377
378
379 public void setOffset(final int channel, final double offset) {
380 this.offsetMap.put(channel, offset);
381 }
382
383
384
385
386
387
388
389 public void setShapeFitParameters(final int channel, final double[] shapeFitParameters) {
390 if (shapeFitParameters.length != NUMBER_OF_SHAPE_FIT_PARAMETERS) {
391 throw new IllegalArgumentException("Number of shape fit parameters is incorrect: "
392 + shapeFitParameters.length);
393 }
394 this.shapeFitParametersMap.put(channel, shapeFitParameters);
395 }
396
397
398
399
400
401
402 public void setBadChannel(final int channel) {
403 this.badChannels.add(channel);
404 }
405
406
407
408
409
410
411 public void setFebID(final int febID) {
412 this.febID = febID;
413 }
414
415
416
417
418
419
420 public void setFebHybridID(final int febHybridID) {
421 this.febHybridID = febHybridID;
422 }
423
424
425
426
427
428
429 public void setT0Shift(final double t0Shift) {
430 this.t0Shift = t0Shift;
431 }
432
433
434
435
436
437
438 public void setAxial(final boolean isAxial) {
439 this.isAxial = isAxial;
440 }
441
442
443
444
445
446
447 public void setStereo(final boolean isStereo) {
448 this.isStereo = isStereo;
449 }
450
451
452
453
454
455 public void reset() {
456 this.pedestalMap.clear();
457 this.noiseMap.clear();
458 this.offsetMap.clear();
459 this.shapeFitParametersMap.clear();
460 this.badChannels.clear();
461 this.gainMap.clear();
462 this.t0Shift = 0;
463 }
464
465 @Override
466 public String toString() {
467
468 final StringBuffer buffer = new StringBuffer();
469 buffer.append("HpsSiSensor: " + this.getName());
470 buffer.append("\n");
471 buffer.append("----------------------------------");
472 buffer.append("\n");
473 buffer.append("Feb ID: " + this.getFebID() + "\n");
474 buffer.append("Feb Hybrid ID: " + this.getFebHybridID() + "\n");
475 buffer.append("Layer: " + this.getLayerNumber() + "\n");
476 buffer.append("Module: " + this.getModuleNumber() + "\n");
477 buffer.append("Number of readout strips: " + this.getReadoutElectrodes(ChargeCarrier.HOLE).getNCells() + "\n");
478 buffer.append("Number of sense strips: " + this.getSenseElectrodes(ChargeCarrier.HOLE).getNCells() + "\n");
479 buffer.append("Strip length: " + this.getStripLength() + "\n");
480 buffer.append("----------------------------------");
481
482 return buffer.toString();
483 }
484
485
486
487
488 @Override
489 public void initialize() {
490
491
492 final Box sensorSolid = (Box) this.getGeometry().getLogicalVolume().getSolid();
493
494
495 final Polygon3D pSide = sensorSolid.getFacesNormalTo(new BasicHep3Vector(0, 0, 1)).get(0);
496 final Polygon3D nSide = sensorSolid.getFacesNormalTo(new BasicHep3Vector(0, 0, -1)).get(0);
497
498
499 this.setBiasSurface(ChargeCarrier.HOLE, pSide);
500
501
502 this.setBiasSurface(ChargeCarrier.ELECTRON, nSide);
503
504
505 final ITranslation3D electrodesPosition = new Translation3D(VecOp.mult(-pSide.getDistance(), pSide.getNormal()));
506
507
508 final IRotation3D electrodesRotation = new RotationPassiveXYZ(0, 0, 0);
509 final Transform3D electrodesTransform = new Transform3D(electrodesPosition, electrodesRotation);
510
511
512 final SiStrips readoutElectrodes = new SiStrips(ChargeCarrier.HOLE, getReadoutStripPitch(), this,
513 electrodesTransform);
514 final SiStrips senseElectrodes = new SiStrips(ChargeCarrier.HOLE, getSenseStripPitch(),
515 this.getNumberOfSenseStrips(), this, electrodesTransform);
516
517 final double readoutCapacitance = this.getStripLength() > this.longSensorLengthThreshold ? this.readoutLongStripCapacitanceSlope
518 : this.readoutStripCapacitanceSlope;
519 final double senseCapacitance = this.getStripLength() > this.longSensorLengthThreshold ? this.senseLongStripCapacitanceSlope
520 : this.senseStripCapacitanceSlope;
521
522
523 readoutElectrodes.setCapacitanceIntercept(this.readoutStripCapacitanceIntercept);
524 readoutElectrodes.setCapacitanceSlope(readoutCapacitance);
525 senseElectrodes.setCapacitanceIntercept(this.senseStripCapacitanceIntercept);
526 senseElectrodes.setCapacitanceSlope(senseCapacitance);
527
528
529 this.setSenseElectrodes(senseElectrodes);
530 this.setReadoutElectrodes(readoutElectrodes);
531
532
533
534 final double[][] transferEfficiencies = {{this.getReadoutTransferEfficiency(), this.getSenseTransferEfficiency()}};
535 this.setTransferEfficiencies(ChargeCarrier.HOLE, new BasicMatrix(transferEfficiencies));
536
537 }
538
539
540
541
542
543
544
545 protected double getStripLength() {
546
547 double length = 0;
548
549
550 final List<Polygon3D> faces = ((Box) this.getGeometry().getLogicalVolume().getSolid())
551 .getFacesNormalTo(new BasicHep3Vector(0, 0, 1));
552 for (final Polygon3D face : faces) {
553
554
555
556 final List<LineSegment3D> edges = face.getEdges();
557 for (final LineSegment3D edge : edges) {
558 if (edge.getLength() > length) {
559 length = edge.getLength();
560 }
561 }
562 }
563 return length;
564 }
565
566
567
568
569
570
571 public void setMillepedeId(final int id) {
572 this.millepedeId = id;
573 }
574
575
576
577
578
579
580 public int getMillepedeId() {
581 return this.millepedeId;
582 }
583 }