1
2
3
4
5
6
7
8
9 package org.lcsim.detector.tracker.silicon;
10
11 import hep.physics.vec.BasicHep3Vector;
12 import hep.physics.vec.Hep3Vector;
13 import hep.physics.vec.VecOp;
14 import java.util.HashSet;
15 import java.util.Set;
16 import java.util.SortedMap;
17 import java.util.TreeMap;
18 import org.lcsim.detector.IDetectorElement;
19 import org.lcsim.detector.ITransform3D;
20 import org.lcsim.detector.Transform3D;
21 import org.lcsim.detector.solids.GeomOp2D;
22 import org.lcsim.detector.solids.GeomOp3D;
23 import org.lcsim.detector.solids.Point3D;
24 import org.lcsim.detector.solids.Polygon3D;
25 import org.lcsim.util.probability.BivariateDistribution;
26
27
28
29
30
31 public class SiPixels implements SiSensorElectrodes {
32
33 private ChargeCarrier _carrier;
34 private int _nrows;
35 private int _ncols;
36 private double _row_pitch;
37 private double _col_pitch;
38 private double _window_size = 3.0;
39 private double _capacitance = 0.1;
40
41
42 private double _row_offset;
43 private double _col_offset;
44 private IDetectorElement _detector;
45 private ITransform3D _parent_to_local;
46 private ITransform3D _local_to_global;
47 private ITransform3D _global_to_local;
48 private Polygon3D _geometry;
49
50
51 public SiPixels(ChargeCarrier carrier, double row_pitch, double col_pitch,
52 IDetectorElement detector, ITransform3D parent_to_local) {
53
54
55
56
57
58 setCarrier(carrier);
59 setRowPitch(row_pitch);
60 setColumnPitch(col_pitch);
61 setGeometry(((SiSensor) detector).getBiasSurface(carrier).transformed(parent_to_local));
62 setPixelNumbering();
63 setDetectorElement(detector);
64 setParentToLocal(parent_to_local);
65 setGlobalToLocal(Transform3D.multiply(parent_to_local, detector.getGeometry().getGlobalToLocal()));
66 setLocalToGlobal(getGlobalToLocal().inverse());
67 }
68
69
70 public int getNAxes() {
71 return 2;
72 }
73
74
75 public IDetectorElement getDetectorElement() {
76 return _detector;
77 }
78
79
80 public ITransform3D getParentToLocal() {
81 return _parent_to_local;
82 }
83
84
85 public ITransform3D getLocalToGlobal() {
86 return _local_to_global;
87 }
88
89
90 public ITransform3D getGlobalToLocal() {
91 return _global_to_local;
92 }
93
94
95 public Polygon3D getGeometry() {
96 return _geometry;
97 }
98
99
100 public Hep3Vector getMeasuredCoordinate(int axis) {
101 if (axis == 0) return new BasicHep3Vector(1.0, 0.0, 0.0);
102 else if (axis == 1) return new BasicHep3Vector(0.0, 1.0, 0.0);
103 else return null;
104 }
105
106
107 public Hep3Vector getUnmeasuredCoordinate(int axis) {
108 if (axis == 0) return new BasicHep3Vector(0.0, 1.0, 0.0);
109 if (axis == 1) return new BasicHep3Vector(1.0, 0.0, 0.0);
110 else return null;
111 }
112
113
114 public int getNeighborCell(int cell_id, int ncells_row, int ncells_col) {
115
116
117 int nbrcol = getColumnNumber(cell_id) + ncells_col;
118 int nbrrow = getRowNumber(cell_id) + ncells_row;
119
120
121 int nbrcell = getCellID(nbrrow, nbrcol);
122 if (nbrcell < 0) return nbrcell;
123
124
125 if (!isValidCell(cell_id)) return -1;
126
127
128 return nbrcell;
129 }
130
131
132 public Set<Integer> getNearestNeighborCells(int cell_id) {
133 Set<Integer> neighbors = new HashSet<Integer>();
134
135
136 for (int irow = -1; irow <= 1; irow++) {
137 for (int icol = - 1; icol <= 1; icol++) {
138
139
140 if (irow == 0 && icol == 0) continue;
141
142
143 int neighbor = getNeighborCell(cell_id, irow, icol);
144 if (neighbor >= 0) neighbors.add(neighbor);
145 }
146 }
147 return neighbors;
148 }
149
150
151 public boolean isValidCell(int cell_id) {
152 return GeomOp3D.intersects(new Point3D(getCellPosition(cell_id)), _geometry);
153 }
154
155
156 public int getNCells() {
157 return _nrows * _ncols;
158 }
159
160
161 public int getNCells(int axis) {
162 if (axis == 0) return _nrows;
163 else if (axis == 1) return _ncols;
164 else return 0;
165 }
166
167
168 public double getPitch(int axis) {
169 if (axis == 0) return _row_pitch;
170 else if (axis == 1) return _col_pitch;
171 else return 0;
172 }
173
174
175 public int getCellID(Hep3Vector position) {
176 return getCellID(getRowNumber(position), getColumnNumber(position));
177 }
178
179
180 public int getRowNumber(Hep3Vector position) {
181 int row = (int) Math.round((position.x() + _row_offset) / _row_pitch);
182 if (row < 0) row = 0;
183 if (row >= _nrows) row = _nrows - 1;
184 return row;
185 }
186
187
188 public int getColumnNumber(Hep3Vector position) {
189 int col = (int) Math.round((position.y() + _col_offset) / _col_pitch);
190 if (col < 0) col = 0;
191 if (col >= _ncols) col = _ncols - 1;
192 return col;
193 }
194
195
196 public int getCellID(int row_number, int column_number) {
197 if (row_number < 0 || row_number >=_nrows) return -1;
198 if (column_number < 0 || column_number >= _ncols) return -1;
199 return row_number * _ncols + column_number;
200 }
201
202
203 public int getRowNumber(int cell_id) {
204 return cell_id / _ncols;
205 }
206
207
208 public int getColumnNumber(int cell_id) {
209 return cell_id - getRowNumber(cell_id) * _ncols;
210 }
211
212
213 public Hep3Vector getPositionInCell(Hep3Vector position) {
214 return VecOp.sub(position, getCellPosition(getCellID(position)));
215 }
216
217
218 public Hep3Vector getCellPosition(int cell_id) {
219 return new BasicHep3Vector(getRowNumber(cell_id) * _row_pitch - _row_offset, getColumnNumber(cell_id) * _col_pitch - _col_offset, 0.0);
220 }
221
222
223 public ChargeCarrier getChargeCarrier() {
224 return _carrier;
225 }
226
227
228
229
230
231
232
233
234 public double getCapacitance(int cell_id) {
235 return getCapacitance();
236 }
237
238
239
240
241
242
243 public double getCapacitance() {
244 return _capacitance;
245 }
246
247
248
249
250
251
252
253
254 public void setCapacitance(double capacitance) {
255 _capacitance = capacitance;
256 }
257
258
259
260
261
262
263
264
265
266
267
268 public void setWindowSize(double window_size) {
269 _window_size = Math.abs(window_size);
270 }
271
272
273
274
275
276
277
278
279
280
281
282
283 public SortedMap<Integer, Integer> computeElectrodeData(ChargeDistribution distribution) {
284
285
286 if (!(distribution instanceof GaussianDistribution2D))
287 throw new RuntimeException("Electrode charge distribution not recognized");
288 GaussianDistribution2D gdistribution = (GaussianDistribution2D) distribution;
289
290
291 SortedMap<Integer, Integer> electrode_data = new TreeMap<Integer, Integer>();
292
293
294 BivariateDistribution bivariate = new BivariateDistribution();
295
296
297 Hep3Vector gmean = gdistribution.getMean();
298 double x0 = gmean.x();
299 double y0 = gmean.y();
300
301
302 Hep3Vector xaxis = getMeasuredCoordinate(0);
303 Hep3Vector yaxis = getMeasuredCoordinate(1);
304
305
306 double xsig = gdistribution.sigma1D(xaxis);
307 double ysig = gdistribution.sigma1D(yaxis);
308 double rho = gdistribution.covxy(xaxis, yaxis) / (xsig * ysig);
309
310
311 double xpitch = getPitch(0);
312 double ypitch = getPitch(1);
313
314
315
316 double xmin0 = x0 - _window_size * xsig;
317 double ymin0 = y0 - _window_size * ysig;
318 int cell1 = getCellID(new BasicHep3Vector(xmin0, ymin0, 0.));
319 double xmax0 = x0 + _window_size * xsig;
320 double ymax0 = y0 + _window_size * ysig;
321 int cell2 = getCellID(new BasicHep3Vector(xmax0, ymax0, 0.));
322
323
324 int ixmin = getRowNumber(cell1);
325 int iymin = getColumnNumber(cell1);
326 int ixmax = getRowNumber(cell2);
327 int iymax = getColumnNumber(cell2);
328
329
330 Hep3Vector corner1 = getCellPosition(cell1);
331 double xmin = corner1.x() - 0.5 * xpitch;
332 double ymin = corner1.y() - 0.5 * ypitch;
333 int nxbins = ixmax - ixmin + 1;
334 int nybins = iymax - iymin + 1;
335 if (nxbins < 1) {
336 System.out.println("x binning error - ixmax: "+ixmax+" ixmin: "+ixmin+" xmin: "+xmin+" xmin0: "+xmin0+" xmax0: "+xmax0+" xsig: "+xsig);
337 nxbins = 1;
338 }
339 if (nybins < 1) {
340 System.out.println("y binning error - iymax: "+iymax+" iymin: "+iymin+" ymin: "+ymin+" ymin0: "+ymin0+" ymax0: "+ymax0+" ysig: "+ysig);
341 nybins = 1;
342 }
343
344 bivariate.xBins(nxbins, xmin, xpitch);
345 bivariate.yBins(nybins, ymin, ypitch);
346
347
348 double[][] prob = bivariate.Calculate(x0, y0, xsig, ysig, rho);
349
350
351 double normalization = gdistribution.getNormalization();
352
353
354 for (int ix = 0; ix < nxbins; ix++) {
355 for (int iy = 0; iy < nybins; iy++) {
356
357
358 int ipixel = getCellID(ixmin + ix, iymin + iy);
359
360
361 if (isValidCell(ipixel)) {
362
363
364 int pixel_charge = (int) Math.round(normalization * prob[ix][iy]);
365
366
367 if (pixel_charge != 0) {
368 electrode_data.put(ipixel, pixel_charge);
369 }
370 }
371 }
372 }
373 return electrode_data;
374 }
375
376
377
378 public void setCarrier(ChargeCarrier carrier) {
379 _carrier = carrier;
380 }
381
382 public void setGeometry(Polygon3D geometry) {
383
384
385
386
387
388
389
390
391 if (GeomOp3D.equals(geometry.getPlane(), GeomOp2D.PLANE)) {
392 _geometry = geometry;
393 } else {
394 throw new RuntimeException("Electrode geometry must be defined in x-y plane!!");
395 }
396 }
397
398 private void setPixelNumbering() {
399 double xmin = Double.MAX_VALUE;
400 double xmax = Double.MIN_VALUE;
401 double ymin = Double.MAX_VALUE;
402 double ymax = Double.MIN_VALUE;
403 for (Point3D vertex : _geometry.getVertices()) {
404 xmin = Math.min(xmin, vertex.x());
405 xmax = Math.max(xmax, vertex.x());
406 ymin = Math.min(ymin, vertex.y());
407 ymax = Math.max(ymax, vertex.y());
408 }
409
410 setNRows((int) Math.ceil((xmax - xmin) / getPitch(0)));
411 setNColumns((int) Math.ceil((ymax - ymin) / getPitch(1)));
412
413 }
414
415 private void setNRows(int nrows) {
416 _nrows = nrows;
417 setRowOffset();
418 }
419
420 private void setNColumns(int ncolumns) {
421 _ncols = ncolumns;
422 setColumnOffset();
423 }
424
425 private void setRowOffset() {
426 double xmin = Double.MAX_VALUE;
427 double xmax = Double.MIN_VALUE;
428 for (Point3D vertex : _geometry.getVertices()) {
429 xmin = Math.min(xmin, vertex.x());
430 xmax = Math.max(xmax, vertex.x());
431 }
432
433 double row_center = (xmin + xmax) / 2;
434
435 _row_offset = ((_nrows - 1) * _row_pitch) / 2 - row_center;
436
437 }
438
439 private void setColumnOffset() {
440 double ymin = Double.MAX_VALUE;
441 double ymax = Double.MIN_VALUE;
442 for (Point3D vertex : _geometry.getVertices()) {
443 ymin = Math.min(ymin, vertex.y());
444 ymax = Math.max(ymax, vertex.y());
445 }
446
447 double column_center = (ymin + ymax) / 2;
448
449 _col_offset = ((_ncols - 1) * _col_pitch) / 2 - column_center;
450
451 }
452
453 private void setRowPitch(double row_pitch) {
454 _row_pitch = row_pitch;
455 }
456
457 private void setColumnPitch(double col_pitch) {
458 _col_pitch = col_pitch;
459 }
460
461 private void setDetectorElement(IDetectorElement detector) {
462 _detector = detector;
463 }
464
465 private void setParentToLocal(ITransform3D parent_to_local) {
466 _parent_to_local = parent_to_local;
467 }
468
469 private void setLocalToGlobal(ITransform3D local_to_global) {
470 _local_to_global = local_to_global;
471 }
472
473 private void setGlobalToLocal(ITransform3D global_to_local) {
474 _global_to_local = global_to_local;
475 }
476 }