View Javadoc

1   package org.lcsim.geometry.segmentation;
2   
3   import java.util.ArrayList;
4   import java.util.List;
5   
6   import org.jdom.DataConversionException;
7   import org.jdom.Element;
8   import org.lcsim.detector.IDetectorElement;
9   import org.lcsim.detector.IDetectorElementContainer;
10  import org.lcsim.detector.identifier.IExpandedIdentifier;
11  import org.lcsim.detector.identifier.ExpandedIdentifier;
12  import org.lcsim.detector.identifier.IIdentifier;
13  import org.lcsim.detector.identifier.IIdentifierHelper;
14  import org.lcsim.detector.identifier.Identifier;
15  import org.lcsim.detector.solids.Box;
16  import org.lcsim.geometry.util.IDDescriptor;
17  import org.lcsim.geometry.util.BaseIDDecoder;
18  import org.lcsim.geometry.util.IDEncoder;
19  import org.lcsim.geometry.subdetector.AbstractPolyhedraCalorimeter;
20  
21  /**
22   * XY Cartesian grid segmentation for overlapping staves.
23   * 
24   * @author cassell
25   */
26  public class EcalBarrelCartesianGridXY extends CartesianGridXY
27  {
28      private double gridSizeX = 0;
29      private double gridSizeY = 0;
30  
31      private int xIndex = -1;
32      private int yIndex = -1;
33      private int moduleIndex = -1;
34      private int nmodules = 12;
35  
36      private int[] validXplusG;
37      private int[] validXminusG;
38      private int[] validXplusP;
39      private int[] validXminusP;
40      private int validZplus;
41      private int validZminus;
42  
43      private double xc0 = 0.;
44      private double[] yc;
45  
46      private double sinth = 0.;
47      private double costh = 0.;
48      private double tanth = 0.;
49      private double cotth = 0.;
50      private double secth = 0.;
51      private double cscth = 0.;
52  
53      private int nlayers = 0;
54      
55      private static final String[] fieldNames = {"x", "y"};
56  
57      public EcalBarrelCartesianGridXY(Element node) throws DataConversionException
58      {
59          super(node);
60  
61          if (node.getAttribute("gridSizeX") != null)
62          {
63              gridSizeX = node.getAttribute("gridSizeX").getDoubleValue();
64              cellSizes.add(0, gridSizeX);
65          }
66          else
67          {
68              throw new RuntimeException("Missing gridSizeX parameter.");
69          }
70  
71          if (node.getAttribute("gridSizeY") != null)
72          {
73              gridSizeY = node.getAttribute("gridSizeY").getDoubleValue();
74              cellSizes.add(1, gridSizeY);
75          }
76          else
77          {
78              throw new RuntimeException("Missing gridSizeY parameter.");
79          }
80      }
81      
82      public String[] getSegmentationFieldNames() {
83          return fieldNames;
84      }
85  
86      public long[] getNeighbourIDs(int layerRange, int xRange, int yRange)
87      {
88          if (this.getDecoder().getID() == 0)
89              throw new RuntimeException("No current ID is set.");
90          if (sensitiveSlices == null)
91              initSensitiveSlices();
92          IDEncoder gnEncoder = new IDEncoder(descriptor);
93          BaseIDDecoder gnDecoder = new BaseIDDecoder(descriptor);
94          gnEncoder.setValues(values);
95          gnDecoder.setID(gnEncoder.getID());
96  
97          // Check if we need initialization
98          if (validXplusP == null)
99          {
100             initializeMappings();
101         }
102         // Set values for current id.
103         int currLayer = gnDecoder.getValue(layerIndex);
104         int currX = gnDecoder.getValue(xIndex);
105         int currY = gnDecoder.getValue(yIndex);
106         int currModule = gnDecoder.getValue(moduleIndex);
107 
108         // Find the neighbors within the current module
109         List<Long> nl = getNeighbourIDs(layerRange, xRange, yRange, gnEncoder, currLayer, currX, currY);
110         // Check for border problems
111         boolean bp1 = false;
112         boolean bp2 = false;
113         // If the layer range includes layer 0 or negative, and the
114         // X bin exceeds the maximum X bin in a "pseudo" geometry
115         // then there is possible neighbors in module +1
116         if (((currLayer - layerRange) < 1) && ((currX + xRange) > validXplusP[0]))
117             bp1 = true;
118         // If the X bin can be less than the minimum valid X bin for
119         // the minimum layer then there is possible neighbors in module
120         // -1
121         else if ((currX - xRange) <= validXminusG[Math.min(currLayer + layerRange, nlayers - 1)])
122             bp2 = true;
123         // otherwise no border problem and just return the neighbors in
124         // the current module.
125         else
126         {
127             long result[] = new long[nl.size()];
128             int i = 0;
129             for (Long id : nl)
130             {
131                 result[i] = id;
132                 i++;
133             }
134             return result;
135         }
136         if (bp1)
137         {
138             // Layer range includes l<=0, xbin large enough to overlap
139             // with module m+1. Neighbors in module m already added.
140             // Now find the neighbors in module m+1. The neighbor
141             // volume is a rectangle, so find cells is in module m+1
142             // cotained by the rectangle.
143             //
144             // Convert the corners of the rectangle layer, xbin to
145             // actual coordinates.
146             double lsep = yc[1] - yc[0];
147             // The maximum y coordinate is the layer 0 y coordinate +
148             // half the layer separation.
149             double ycmax = yc[0] + lsep / 2.;
150             // The minimum y coordinate is the layer 0 y coordinate -
151             // half the layer separation - the layer separation*# negative
152             // layers.
153             double ycmin = yc[0] - lsep / 2. + lsep * (currLayer - layerRange);
154             // The maximum/minimum X coordinate is the maximum/minimum
155             // Xbin+-.5 times the grid size, + x0
156             double xcmax = xc0 + gridSizeX * (currX + xRange + .5);
157             double xcmin = xc0 + gridSizeX * (currX - xRange - .5);
158             // rotate the coordinate system to module +1, and find the layer
159             // range in that module.
160             double minyp = ycmin * costh + xcmin * sinth;
161             double maxyp = ycmax * costh + xcmax * sinth;
162             int minl = 0;
163             int maxl = 0;
164             for (int il = 0; il < nlayers; il++)
165             {
166                 if (yc[il] < minyp)
167                     minl++;
168                 if (yc[il] > maxyp)
169                     break;
170                 maxl++;
171             }
172             // Set the module
173             int neighborModule = (currModule + 1) % nmodules;
174             gnEncoder.setValue(moduleIndex, neighborModule);
175             // Loop over the layer range
176             for (int neighborLayer = minl; neighborLayer < maxl; neighborLayer++)
177             {
178                 gnEncoder.setValue(layerIndex, neighborLayer);
179                 // In this module's coordinate system, calculate the
180                 // intersection of y=yc(layer) with the box to find the
181                 // X coordinate range inside the box.
182                 double xpmax = Math
183                         .min(xcmax * secth - yc[neighborLayer] * tanth, yc[neighborLayer] * cotth - ycmin * cscth);
184                 double xpmin = Math
185                         .max(xcmin * secth - yc[neighborLayer] * tanth, yc[neighborLayer] * cotth - ycmax * cscth);
186                 // Convert X coordinate to X bin.
187                 int xbmin = (int) ((xpmin - xc0 + gridSizeX * .5) / gridSizeX);
188                 int xbmax = (int) ((xpmax - xc0 - gridSizeX * .5) / gridSizeX);
189                 // Loop over X bins
190                 for (int neighborX = xbmin; neighborX <= xbmax; neighborX++)
191                 {
192                     gnEncoder.setValue(xIndex, neighborX);
193                     // Loop over the Z range
194                     for (int iy = -yRange; iy <= yRange; iy++)
195                     {
196                         // Compute y value.
197                         int neighborY = currY + iy;
198                         gnEncoder.setValue(yIndex, neighborY);
199                         if (sliceIndex >= 0)
200                         {
201                             // Loop over sensitive slices
202                             for (int is = 0; is < sensitiveSlices[neighborLayer].size(); is++)
203                             {
204                                 // Set the slic field.
205                                 gnEncoder.setValue(sliceIndex, ((Integer) (sensitiveSlices[neighborLayer].get(is)))
206                                         .intValue());
207                                 ;
208                                 // Add the neighbor
209                                 nl.add(gnEncoder.getID());
210                             }
211                         }
212                         else
213                             nl.add(gnEncoder.getID());
214 
215                     }
216                 }
217             }
218             long result[] = new long[nl.size()];
219             int i = 0;
220             for (Long id : nl)
221             {
222                 result[i] = id;
223                 i++;
224             }
225             return result;
226         }
227         // To get here we have overlap with module m-1. Add the
228         // neighbors in module m-1.
229         int neighborModule = (nmodules + currModule - 1) % nmodules;
230         gnEncoder.setValue(moduleIndex, neighborModule);
231         double ycmax = 0.;
232         double ycmin = 0.;
233         // The layer separation depends on where we are
234         if (currLayer - layerRange < 1)
235         {
236             double lsep = yc[1] - yc[0];
237             ycmin = yc[0] + (currLayer - layerRange) * lsep - lsep / 2.;
238         }
239         else
240         {
241             double lsep = yc[currLayer - layerRange] - yc[currLayer - layerRange - 1];
242             ycmin = yc[currLayer - layerRange] - lsep / 2.;
243         }
244         if (currLayer + layerRange > nlayers - 2)
245         {
246             double lsep = yc[nlayers - 1] - yc[nlayers - 2];
247             ycmax = yc[nlayers - 1] + lsep / 2.;
248         }
249         else
250         {
251             double lsep = yc[currLayer + layerRange + 1] - yc[currLayer + layerRange];
252             ycmax = yc[currLayer + layerRange] + lsep / 2.;
253         }
254         // Find the coordinates of the box in module m-1
255         double xcmax = xc0 + gridSizeX * (currX + xRange + .5);
256         double xcmin = xc0 + gridSizeX * (currX - xRange - .5);
257         double minyp = ycmin * costh - xcmax * sinth;
258         double maxyp = ycmax * costh - xcmin * sinth;
259         int minl = 0;
260         int maxl = 0;
261         for (int il = 0; il < nlayers; il++)
262         {
263             if (yc[il] < minyp)
264                 minl++;
265             if (yc[il] > maxyp)
266                 break;
267             maxl++;
268         }
269         // Loop over layer range
270         for (int neighborLayer = minl; neighborLayer < maxl; neighborLayer++)
271         {
272             gnEncoder.setValue(layerIndex, neighborLayer);
273             // Find intersection of y=yc[layer] with box to determine
274             // X range
275             double xpmax = Math
276                     .min(xcmax * secth + yc[neighborLayer] * tanth, -yc[neighborLayer] * cotth + ycmax * cscth);
277             double xpmin = Math
278                     .max(xcmin * secth + yc[neighborLayer] * tanth, -yc[neighborLayer] * cotth + ycmin * cscth);
279             int xbmin = (int) ((xpmin - xc0 + gridSizeX * .5) / gridSizeX);
280             int xbmax = (int) ((xpmax - xc0 - gridSizeX * .5) / gridSizeX);
281             xbmax = Math.min(xbmax, validXplusG[neighborLayer]);
282             // Loop and add neighbors
283             for (int neighborX = xbmin; neighborX <= xbmax; neighborX++)
284             {
285                 gnEncoder.setValue(xIndex, neighborX);
286                 for (int neighborY = Math.max(validZminus, currY - yRange); neighborY <= Math
287                         .min(validZplus, currY + yRange); neighborY++)
288                 {
289                     gnEncoder.setValue(yIndex, neighborY);
290                     if (sliceIndex >= 0)
291                     {
292                         // Loop over sensitive slices
293                         for (int is = 0; is < sensitiveSlices[neighborLayer].size(); is++)
294                         {
295                             // Set the slic field.
296                             gnEncoder.setValue(sliceIndex, ((Integer) (sensitiveSlices[neighborLayer].get(is)))
297                                     .intValue());
298                             ;
299                             nl.add(gnEncoder.getID());
300                         }
301                     }
302                     else
303                         nl.add(gnEncoder.getID());
304                 }
305             }
306         }
307         long result[] = new long[nl.size()];
308         int i = 0;
309         for (Long id : nl)
310         {
311             result[i] = id;
312             i++;
313         }
314         return result;
315     }
316 
317     protected List<Long> getNeighbourIDs(int layerRange, int xRange, int yRange, IDEncoder gnEncoder, int currLayer, int currX, int currY)
318     {
319         // Find neighbors within the currect module
320         List<Long> rl = new ArrayList<Long>();
321         for (int neighborLayer = Math.max(0, currLayer - layerRange); neighborLayer <= Math
322                 .min(nlayers - 1, currLayer + layerRange); neighborLayer++)
323         {
324             gnEncoder.setValue(layerIndex, neighborLayer);
325             for (int neighborX = Math.max(validXminusG[neighborLayer], currX - xRange); neighborX <= Math
326                     .min(validXplusG[neighborLayer], currX + xRange); neighborX++)
327             {
328                 gnEncoder.setValue(xIndex, neighborX);
329                 for (int neighborY = Math.max(validZminus, currY - yRange); neighborY <= Math
330                         .min(validZplus, currY + yRange); neighborY++)
331                 {
332                     gnEncoder.setValue(yIndex, neighborY);
333                     if (sliceIndex >= 0)
334                     {
335                         // Loop over sensitive slices
336                         for (int is = 0; is < sensitiveSlices[neighborLayer].size(); is++)
337                         {
338                             // Set the slic field.
339                             gnEncoder.setValue(sliceIndex, ((Integer) (sensitiveSlices[neighborLayer].get(is)))
340                                     .intValue());
341                             ;
342                             if (this.getDecoder().getID() != gnEncoder.getID())
343                                 rl.add(gnEncoder.getID());
344                         }
345                     }
346                     else if (this.getDecoder().getID() != gnEncoder.getID())
347                         rl.add(gnEncoder.getID());
348                 }
349             }
350         }
351         return rl;
352     }
353 
354     public void setupGeomFields(IDDescriptor id)
355     {
356         super.setupGeomFields(id);
357         xIndex = id.indexOf("x");
358         yIndex = id.indexOf("y");
359         moduleIndex = id.indexOf("module");
360         layerIndex = id.indexOf("layer");
361     }
362 
363     protected void initializeMappings()
364     {
365         nmodules = ((AbstractPolyhedraCalorimeter) getSubdetector()).getNumberOfSides();
366         // Initialize all the needed parameters for the neighbor
367         // finding across borders
368         // Get number of layers.
369         nlayers = this.getNumberOfLayers();
370         // The valid X bins vary by layer
371         validXplusP = new int[this.getNumberOfLayers()];
372         validXminusP = new int[this.getNumberOfLayers()];
373         validXplusG = new int[this.getNumberOfLayers()];
374         validXminusG = new int[this.getNumberOfLayers()];
375         // Calculate the trig functions needed for the rotations
376         sinth = Math.sin(2. * Math.PI / nmodules);
377         costh = Math.cos(2. * Math.PI / nmodules);
378         tanth = sinth / costh;
379         cotth = costh / sinth;
380         secth = 1. / costh;
381         cscth = 1. / sinth;
382         // Get the helper and identifiers needed to manipulate the id
383         IIdentifierHelper helper = detector.getDetectorElement().getIdentifierHelper();
384         IIdentifier currId = new Identifier(this.getDecoder().getID());
385         IExpandedIdentifier thisId = helper.unpack(currId);
386         ExpandedIdentifier pseudoId = new ExpandedIdentifier(thisId);
387         // Set the module and xbin to 0 to find pseudo-lengths and offsets
388         pseudoId.setValue(moduleIndex, 0);
389         pseudoId.setValue(xIndex, 0);
390         pseudoId.setValue(layerIndex, 0);
391         pseudoId.setValue(sliceIndex, 0);
392         // Save the current ID
393         long save = this.getDecoder().getID();
394         this.getDecoder().setID(helper.pack(pseudoId).getValue());
395         this.computeGlobalPosition();
396         // xc0 is the global x coordinate or the center of the module
397         xc0 = this.globalPosition[0] - gridSizeX / 2.;
398         // yc is the global y coordinate of each layer
399         yc = new double[nlayers];
400         // xhlp is the half length of each layer
401         double[] xhlp = new double[nlayers];
402         for (int i = 0; i < nlayers; i++)
403         {
404             // Find the half lengths per layer and convert to x index.
405             pseudoId.setValue(layerIndex, i);
406             if (i == 1)
407                 pseudoId.setValue(sliceIndex, 2);
408             this.getDecoder().setID(helper.pack(pseudoId).getValue());
409             this.computeGlobalPosition();
410             yc[i] = this.globalPosition[1];
411             // Find the box containing this cell
412             IIdentifier geomId = makeGeometryIdentifier(helper.pack(pseudoId).getValue());
413             IDetectorElementContainer deSrch = getSubdetector().getDetectorElement().findDetectorElement(geomId);
414             IDetectorElement de = deSrch.get(0);
415             if (de.getGeometry().getLogicalVolume().getSolid() instanceof Box)
416             {
417                 Box sensorBox = (Box) de.getGeometry().getLogicalVolume().getSolid();
418                 // Assume the Z extent is the same for all layers
419                 if (i == 0)
420                 {
421                     double yhl = sensorBox.getYHalfLength();
422                     // Convert half length to valid index
423                     int nvalidy = (int) (yhl / gridSizeY) + 1;
424                     validZplus = nvalidy - 1;
425                     validZminus = -nvalidy;
426                 }
427                 // Convert X half length to valid X bins
428                 double xhl = sensorBox.getXHalfLength();
429                 int nvalidx = (int) (xhl / gridSizeX) + 1;
430                 validXplusG[i] = nvalidx - 1;
431                 validXminusG[i] = -nvalidx;
432                 // Compute valid X indices contained in a pseudo
433                 // geometry of a regular N-gon
434                 xhlp[i] = yc[i] * Math.tan(Math.PI / nmodules);
435                 validXplusP[i] = (int) ((xhlp[i] - xc0) / gridSizeX);
436                 validXminusP[i] = -(int) ((xhlp[i] + xc0) / gridSizeX) - 1;
437             }
438             else
439             {
440                 throw new RuntimeException("Don't know how to bounds check solid " + de.getGeometry()
441                         .getLogicalVolume().getSolid().getName() + ".");
442             }
443         }
444         // Put back the cellID
445         this.getDecoder().setID(save);
446         this.computeGlobalPosition();
447     }
448 
449     public int getVLayer()
450     {
451         if (validXplusP == null)
452         {
453             initializeMappings();
454         }
455         // Get the helper and identifiers needed to manipulate the id
456         IIdentifierHelper helper = detector.getDetectorElement().getIdentifierHelper();
457         IIdentifier currId = new Identifier(this.getDecoder().getID());
458         IExpandedIdentifier thisId = helper.unpack(currId);
459         int xbin = thisId.getValue(xIndex);
460         int layer = thisId.getValue(layerIndex);
461         if (xbin > validXplusP[layer])
462         {
463             double xc = xc0 + gridSizeX * (xbin + .5);
464             double yp = yc[layer] * costh + xc * sinth;
465             double dely = yp - yc[layer];
466             int vl = layer;
467             for (int il = layer; il < nlayers - 1; il++)
468             {
469                 if (dely < (yc[il + 1] - yc[il]) / 2.)
470                     break;
471                 vl++;
472                 dely -= yc[il + 1] - yc[il];
473             }
474             return vl;
475         }
476         return layer;
477     }
478 }