View Javadoc

1   package org.lcsim.detector.converter.compact;
2   
3   import static java.lang.Math.PI;
4   import static java.lang.Math.acos;
5   import static java.lang.Math.cos;
6   import static java.lang.Math.sin;
7   import static java.lang.Math.sqrt;
8   import static java.lang.Math.tan;
9   
10  import java.util.Iterator;
11  
12  import org.jdom.Attribute;
13  import org.jdom.Element;
14  import org.lcsim.detector.DetectorElement;
15  import org.lcsim.detector.IDetectorElement;
16  import org.lcsim.detector.IPhysicalVolume;
17  import org.lcsim.detector.ITransform3D;
18  import org.lcsim.detector.ITranslation3D;
19  import org.lcsim.detector.LogicalVolume;
20  import org.lcsim.detector.PhysicalVolume;
21  import org.lcsim.detector.RotationGeant;
22  import org.lcsim.detector.Transform3D;
23  import org.lcsim.detector.Translation3D;
24  import org.lcsim.detector.identifier.ExpandedIdentifier;
25  import org.lcsim.detector.identifier.IExpandedIdentifier;
26  import org.lcsim.detector.identifier.IIdentifier;
27  import org.lcsim.detector.identifier.IIdentifierHelper;
28  import org.lcsim.detector.material.IMaterial;
29  import org.lcsim.detector.material.MaterialStore;
30  import org.lcsim.detector.solids.Box;
31  import org.lcsim.detector.solids.Trd;
32  import org.lcsim.geometry.compact.Detector;
33  import org.lcsim.geometry.compact.Subdetector;
34  import org.lcsim.geometry.layer.LayerFromCompactCnv;
35  import org.lcsim.geometry.layer.LayerStack;
36  import org.lcsim.geometry.layer.Layering;
37  import org.lcsim.geometry.subdetector.EcalBarrel;
38  import org.lcsim.geometry.subdetector.PolyhedraBarrelCalorimeter;
39  
40  /**
41   * Implementation of the EcalBarrel detailed geometry.
42   * 
43   * @author jeremym
44   */
45  public class EcalBarrelConverter extends AbstractSubdetectorConverter implements ISubdetectorConverter
46  {
47      public void convert( Subdetector subdet, Detector detector )
48      {
49          Element node = subdet.getNode();
50          int sysId = subdet.getSystemID();
51          PolyhedraBarrelCalorimeter cal = ( PolyhedraBarrelCalorimeter ) subdet;
52          int nsides = cal.getNumberOfSides();
53          double innerR = cal.getInnerRadius();
54          Layering layering = cal.getLayering();
55          LayerStack layers = layering.getLayerStack();
56          double z = cal.getZLength();
57          String name = subdet.getName();
58  
59          // Compute the delta phi per section.
60          double dphiModule = PI * 2.0 / nsides;
61          double hphi = dphiModule / 2;
62  
63          double moduleY1 = z;
64          double moduleY2 = moduleY1;
65  
66          // Compute the total thickness of the subdetector.
67          double moduleZ = 0.;
68          try
69          {
70              moduleZ = LayerFromCompactCnv.computeDetectorTotalThickness( node );
71          }
72          catch ( Exception x )
73          {
74              throw new RuntimeException( x );
75          }
76  
77          // Compute the center Y offset of a single module.
78          double moduleYOffset = innerR + moduleZ / 2;
79  
80          // Compute the outer radius.
81          double outerR = innerR + moduleZ;
82  
83          // Compute trapezoid measurements.
84          double bo = tan( hphi ) * outerR;
85          double bi = tan( hphi ) * innerR;
86  
87          // Compute the dx per layer, using side
88          // triangle calculations (from Norman Graf).
89          double gamma = ( PI * 2 ) / nsides;
90          double dx = moduleZ / sin( gamma );
91  
92          // The offset of a stave, derived from the dx term.
93          double moduleXOffset = dx / 2.0;
94  
95          // Compute the top and bottom face measurements.
96          double moduleX2 = 2 * bo - dx;
97          double moduleX1 = 2 * bi + dx;
98  
99          // Create the trapezoid for the stave.
100         Trd moduleTrd = new Trd( name + "_module_trd", moduleX1 / 2, // Outer side, i.e.
101                                  // the "short" X
102                                  // side.
103                                  moduleX2 / 2, // Inner side, i.e. the "long" X side.
104                                  moduleY1 / 2, // Corresponds to subdetector (or module)
105                                  // Z.
106                                  moduleY2 / 2, // "
107                                  moduleZ / 2 ); // Thickness, in Y for top stave, when
108         // rotated.
109 
110         LogicalVolume moduleVolume = new LogicalVolume( name + "_module", moduleTrd, MaterialStore.getInstance().get(
111                 "Air" ) );
112         //
113         // Build module.
114         //
115 
116         // double layerZ = moduleTrd.getYHalfLength1();
117         double trdZ = moduleTrd.getZHalfLength();
118 
119         //
120         // Parameters for computing the layer X dimension,
121         // e.g. trapezoid's X1 value.
122         //
123 
124         // Adjacent angle of triangle.
125         double adj = ( moduleTrd.getXHalfLength1() - moduleTrd.getXHalfLength2() ) / 2;
126 
127         // Hypotenuse of triangle.
128         double hyp = sqrt( trdZ * trdZ + adj * adj );
129 
130         // Lower-right angle of triangle.
131         double beta = acos( adj / hyp );
132 
133         // Primary coefficient for figuring X.
134         double tan_beta = tan( beta );
135 
136         double subdetectorThickness = 0;
137         try
138         {
139             subdetectorThickness = LayerFromCompactCnv.computeDetectorTotalThickness( node );
140         }
141         catch ( Exception x )
142         {
143             throw new RuntimeException( x );
144         }
145 
146         double layerPositionZ = -( subdetectorThickness / 2 );
147 
148         // Delta phi.
149         double dphiLayer = PI * 2.0 / nsides;
150 
151         // Half delta phi.
152         // double hphiLayer = dphiLayer / 2;
153 
154         // Starting X dimension for the layer.
155         double layerDimX = moduleTrd.getXHalfLength1();
156 
157         int layerNumber = 0;
158         for ( Iterator i = node.getChildren( "layer" ).iterator(); i.hasNext(); )
159         {
160             Element layer_element = ( Element ) i.next();
161             int repeat = 0;
162             try
163             {
164                 repeat = ( int ) layer_element.getAttribute( "repeat" ).getDoubleValue();
165             }
166             catch ( Exception x )
167             {
168                 throw new RuntimeException( x );
169             }
170 
171             // Loop over number of repeats for this layer.
172             for ( int j = 0; j < repeat; j++ )
173             {
174                 // Compute this layer's thickness.
175                 double layerThickness = layers.getLayer( layerNumber ).getThickness();
176 
177                 // Increment the Z position to place this layer.
178                 layerPositionZ += layerThickness / 2;
179 
180                 // Name of the layer.
181                 String layerName = name + "_layer" + layerNumber;
182 
183                 // Position of the layer.
184                 Translation3D layerPosition = new Translation3D( 0, 0, layerPositionZ );
185 
186                 layerPositionZ += layerThickness / 2;
187 
188                 // Compute the X dimension for this layer.
189                 double xcut = ( layerThickness / tan_beta );
190                 layerDimX -= xcut;
191 
192                 Box layerBox = new Box( layerName + "_box", layerDimX, z / 2, layerThickness / 2 );
193 
194                 LogicalVolume layerVolume = new LogicalVolume( layerName, layerBox, MaterialStore.getInstance().get(
195                         "Air" ) );
196 
197                 int sliceNumber = 0;
198                 double slicePositionZ = -( layerThickness / 2 );
199                 for ( Iterator k = layer_element.getChildren( "slice" ).iterator(); k.hasNext(); )
200                 {
201                     Element sliceElement = ( Element ) k.next();
202 
203                     // Name of the slice.
204                     String sliceName = layerName + "_slice" + sliceNumber;
205 
206                     // Sensitivity.
207                     Attribute s = sliceElement.getAttribute( "sensitive" );
208                     boolean sensitive = false;
209                     try
210                     {
211                         sensitive = s != null && s.getBooleanValue();
212                     }
213                     catch ( Exception x )
214                     {
215                         throw new RuntimeException( x );
216                     }
217 
218                     // Thickness of slice.
219                     double sliceThickness = 0;
220 
221                     try
222                     {
223                         sliceThickness = sliceElement.getAttribute( "thickness" ).getDoubleValue();
224                     }
225                     catch ( Exception x )
226                     {
227                         throw new RuntimeException( x );
228                     }
229 
230                     // Increment Z position of slice.
231                     slicePositionZ += sliceThickness / 2;
232 
233                     Translation3D slicePosition = new Translation3D( 0, 0, slicePositionZ );
234 
235                     slicePositionZ += sliceThickness / 2;
236 
237                     Box sliceBox = new Box( sliceName + "_box", layerDimX, z / 2, sliceThickness / 2 );
238 
239                     IMaterial sliceMaterial = MaterialStore.getInstance().get(
240                             sliceElement.getAttributeValue( "material" ) );
241 
242                     LogicalVolume sliceVolume = new LogicalVolume( sliceName, sliceBox, sliceMaterial );
243 
244                     PhysicalVolume slicePhysVol = new PhysicalVolume( new Transform3D( slicePosition,
245                                                                                        new RotationGeant( 0, 0, 0 ) ),
246                                                                       sliceName,
247                                                                       sliceVolume,
248                                                                       layerVolume,
249                                                                       sliceNumber );
250                     if ( sensitive )
251                     {
252                         slicePhysVol.setSensitive( true );
253                     }
254 
255                     ++sliceNumber;
256                 }
257 
258                 ITransform3D layerTransform = new Transform3D( layerPosition, new RotationGeant( 0, 0, 0 ) );
259 
260                 PhysicalVolume layerPhysVol = new PhysicalVolume( layerTransform,
261                                                                   layerName,
262                                                                   layerVolume,
263                                                                   moduleVolume,
264                                                                   layerNumber );
265 
266                 ++layerNumber;
267             }
268 
269         }
270 
271         //
272         // End build module.
273         //
274 
275         // 
276         // Start place modules.
277         //
278 
279         // Phi start for a stave.
280         double phi = 0;
281 
282         // Create DetectorElements for modules.
283         for ( int i = 0; i < nsides; i++ )
284         {
285             int moduleNumber = i;
286 
287             RotationGeant rotation = new RotationGeant( PI * 0.5, phi, 0 );
288 
289             double modulePositionX = moduleXOffset * cos( phi ) - moduleYOffset * sin( phi );
290             double modulePositionY = moduleXOffset * sin( phi ) + moduleYOffset * cos( phi );
291             double modulePositionZ = 0;
292 
293             ITranslation3D trans = new Translation3D( modulePositionX, modulePositionY, modulePositionZ );
294             ITransform3D transform = new Transform3D( trans, rotation );
295             String moduleName = name + "_module" + i;
296             new PhysicalVolume( transform, moduleName, moduleVolume, detector.getDetectorElement().getGeometry()
297                     .getLogicalVolume(), moduleNumber );
298             new DetectorElement( moduleName, subdet.getDetectorElement(), "/" + moduleName );
299 
300             // increment phi
301             phi -= dphiLayer;
302         }
303 
304         //
305         // End place modules.
306         //
307 
308         //
309         // Start build DetectorElements.
310         //
311         IIdentifierHelper helper = cal.getDetectorElement().getIdentifierHelper();
312         for ( IDetectorElement module : subdet.getDetectorElement().getChildren() )
313         {
314             int sensorNum = 0;
315             for ( IPhysicalVolume layer : module.getGeometry().getLogicalVolume().getDaughters() )
316             {
317                 IDetectorElement deLayer = new DetectorElement( name + "_module" + module.getGeometry()
318                         .getPhysicalVolume().getCopyNumber() + "_layer" + layer.getCopyNumber(), module, "/" + module
319                         .getGeometry().getPhysicalVolume().getName() + "/" + layer.getName() );
320                 for ( IPhysicalVolume slice : layer.getLogicalVolume().getDaughters() )
321                 {
322                     if ( slice.isSensitive() )
323                     {
324                         IExpandedIdentifier expId = new ExpandedIdentifier( helper.getIdentifierDictionary()
325                                 .getNumberOfFields() );
326 
327                         expId.setValue( helper.getFieldIndex( "system" ), sysId );
328                         expId.setValue( helper.getFieldIndex( "barrel" ), 0 );
329                         expId.setValue( helper.getFieldIndex( "module" ), module.getGeometry().getPhysicalVolume()
330                                 .getCopyNumber() );
331                         expId.setValue( helper.getFieldIndex( "layer" ), layer.getCopyNumber() );
332                         expId.setValue( helper.getFieldIndex( "slice" ), slice.getCopyNumber() );
333 
334                         IIdentifier sensorId = helper.pack( expId );
335                         String sliceName = module.getName() + "_layer" + layer.getCopyNumber() + "_sensor" + sensorNum;
336                         IDetectorElement sensor = new DetectorElement( sliceName,
337                                                                        deLayer,
338                                                                        "/" + module.getName() + "/" + layer.getName() + "/" + slice
339                                                                                .getName(),
340                                                                        sensorId );
341                         ++sensorNum;
342                     }
343                 }
344 
345             }
346         }
347         //
348         // End build DetectorElements.
349         //
350     }
351 
352     public Class getSubdetectorType()
353     {
354         return EcalBarrel.class;
355     }
356 }