View Javadoc

1   package org.lcsim.geometry.segmentation;
2   
3   import static java.lang.Math.PI;
4   import static java.lang.Math.tan;
5   
6   import org.jdom.DataConversionException;
7   import org.jdom.Element;
8   import org.lcsim.geometry.layer.Layer;
9   import org.lcsim.geometry.layer.LayerStack;
10  import org.lcsim.geometry.util.IDDescriptor;
11  import org.lcsim.geometry.util.IDEncoder;
12  
13  /**
14   * This segmentation represents a projective Z plane.  It is 
15   * most appropriately used for cylindrical endcap calorimeter components.
16   * 
17   * @author Tony Johnson <tonyj@slac.stanford.edu>
18   */
19  public class ProjectiveZPlane extends SegmentationBase
20  {
21      private int thetaBins;
22      private int phiBins;
23  
24      private int thetaIndex;
25      private int phiIndex;
26      private int systemIndex = -1;
27      private int barrelIndex = -1;
28  
29      private double thetaDim = 0;
30      private double phiDim = 0;
31      
32      private static final String fieldNames[] = {"phi", "theta"};
33      
34      ProjectiveZPlane(Element node) throws DataConversionException
35      {
36          super(node);
37          thetaBins = node.getAttribute("thetaBins").getIntValue();
38          phiBins = node.getAttribute("phiBins").getIntValue();
39      }
40      
41      public String[] getSegmentationFieldNames() {
42          return fieldNames;
43      }
44      
45      public double getCellSizeU()
46      {
47          return thetaDim;
48      }
49      
50      public double getCellSizeV()
51      {
52          return phiDim;
53      }
54  
55      public int getThetaBins()
56      {
57          return thetaBins;
58      }
59  
60      public int getPhiBins()
61      {
62          return phiBins;
63      }
64  
65      public double getPhi()
66      {
67          double phi = 2 * PI * ((getValue(phiIndex) + 0.5) / phiBins);
68          return phi;
69      }
70  
71      public double getTheta()
72      {
73          return PI * ((getValue(thetaIndex) + 0.5) / thetaBins);
74      }
75  
76      public double getX()
77      {
78          return getSphericalRadius() * Math.cos(getPhi());
79      }
80  
81      public double getY()
82      {
83          return getSphericalRadius() * Math.sin(getPhi());
84      }
85  
86      public double getZ()
87      {
88          return -Math.signum(getTheta() - PI / 2) * getDistanceToSensitive(getLayer());
89      }
90  
91      private double getSphericalRadius()
92      {
93          return getZ() * tan(getTheta());
94      }
95  
96      public void setIDDescription(IDDescriptor id)
97      {
98          super.setIDDescription(id);
99  
100         phiIndex = id.indexOf("phi");
101         thetaIndex = id.indexOf("theta");
102         barrelIndex = id.indexOf("barrel");
103         systemIndex = id.indexOf("system");
104     }
105 
106     public long[] getNeighbourIDs(int deltaLayer, int deltaTheta, int deltaPhi)
107     {
108         IDEncoder encoder = new IDEncoder(descriptor);
109         encoder.setValues(values);
110 
111         int nMax = (2 * deltaLayer + 1) * (2 * deltaTheta + 1) * (2 * deltaPhi + 1) - 1;
112         int size = 0;
113         long[] result = new long[nMax];
114         for (int i = -deltaLayer; i <= deltaLayer; i++)
115         {
116             int l = values[layerIndex] + i;
117 
118             if (l < 0 || l >= getNumberOfLayers())
119                 continue;
120             encoder.setValue(layerIndex, l);
121 
122             for (int j = -deltaTheta; j <= deltaTheta; j++)
123             {
124                 int t = values[thetaIndex] + j;
125 
126                 if (t < 0 || t >= thetaBins)
127                     continue;
128                 encoder.setValue(thetaIndex, t);
129 
130                 for (int k = -deltaPhi; k <= deltaPhi; k++)
131                 {
132                     if (i == 0 && j == 0 && k == 0)
133                         continue;
134 
135                     int p = values[phiIndex] + k;
136                     if(p<0) p+=phiBins;
137                     if(p>=phiBins) p-=phiBins;
138 
139                     result[size++] = encoder.setValue(phiIndex, p);
140                 }
141             }
142         }
143         if (size < result.length)
144         {
145             long[] temp = new long[size];
146             System.arraycopy(result, 0, temp, 0, size);
147             result = temp;
148         }
149         return result;
150     }
151 
152     public boolean supportsNeighbours()
153     {
154         return true;
155     }
156 
157     /**
158      * Return the cell which contains a given point (x,y,z), or zero.
159      *
160      * @param x Cartesian X coordinate.
161      * @param y Cartesian Y coordinate.
162      * @param z Cartesian Z coordinate.     
163      *            
164      * @return ID of cell containing the point (maybe either in absorber or live
165      *         material)
166      */
167     public long findCellContainingXYZ(double x, double y, double z)
168     {
169 
170         // validate point
171         if(Math.abs(z) < getZMin()) return 0;
172         if(Math.abs(z) > getZMax()) return 0;
173         double rho = Math.sqrt(x * x + y * y);
174         if(rho < getRMin()) return 0;
175         if(rho > getRMax()) return 0;
176 
177         // ok, point is valid, so a valid ID should be returned
178         int ilay = getLayerBin(z);
179 
180         double phi = Math.atan2(y, x);
181         if(phi < 0) phi += 2 * PI;
182         int iphi = (int) ((phi * phiBins)/(2*PI) - 0.5);
183 
184         double theta = Math.atan2(rho, z);
185         if(theta < 0)
186         {
187             // If never prints out, the whole if can be dropped
188             System.out.println("ProjCylinder: Is this really needed?!?");
189             theta += 2. * PI;
190         }
191         int itheta = (int) ((theta * thetaBins)/PI - 0.5);
192 	int ibar = ( z<0 ? 2 : 1 );
193 	int system = detector.getSystemID();
194 
195         IDEncoder enc = new IDEncoder(descriptor);
196         enc.setValue(layerIndex, ilay);
197         enc.setValue(thetaIndex, itheta);
198         enc.setValue(phiIndex, iphi);
199 	enc.setValue(barrelIndex, ibar);
200 	enc.setValue(systemIndex, system);
201         long resultID = enc.getID();
202 
203         return resultID;
204     }
205 
206     /**
207      * Return the layer number based on the z-coordinate
208      *
209      * @param z
210      *            z-coordinate
211      * @return layer number of layer corresponding to that distance (may be
212      *         either in absorber or live material)
213      * @throws RuntimeException
214      *             if abs(z)<zMin
215      */
216     public int getLayerBin(double z)
217     {
218         // In order to be general, we should not assume that all
219         // layers have the same thickness. Therefore, one has to
220         // guess the starting layer (based on average thickness), and
221         // then navigate through layers until one finds the right one
222         double depth = Math.abs(z) - getZMin();
223         if (depth < 0)
224             throw new RuntimeException("ProjectiveZPlane: Error: z < zMin, z=" + z + ", zMin=" + this.getZMin());
225 
226         double mean_t = (getZMax() - getZMin()) / getNumberOfLayers();
227 
228         int ilay = (int) Math.floor(depth / mean_t);
229         LayerStack stack = getLayering().getLayers();
230         Layer layer = stack.getLayer(ilay);
231         double depHi = stack.getThicknessToLayerBack(ilay);
232         double depLo = depHi - layer.getThickness();
233         for (;;)
234         {
235             if (depth > depLo && depth <= depHi)
236                 return ilay;
237             if (depth <= depLo)
238             {
239                 --ilay;
240                 depHi = depLo;
241                 layer = stack.getLayer(ilay);
242                 depLo -= layer.getThickness();
243             }
244             if (depth > depHi)
245             {
246                 ++ilay;
247                 depLo = depHi;
248                 layer = stack.getLayer(ilay);
249                 depHi += layer.getThickness();
250             }
251         }
252     }
253 }