View Javadoc

1   package org.lcsim.detector.converter.compact;
2   
3   import static java.lang.Math.PI;
4   import static java.lang.Math.tan;
5   
6   import java.util.Iterator;
7   
8   import org.jdom.Attribute;
9   import org.jdom.DataConversionException;
10  import org.jdom.Element;
11  import org.lcsim.detector.DetectorElement;
12  import org.lcsim.detector.IDetectorElement;
13  import org.lcsim.detector.ILogicalVolume;
14  import org.lcsim.detector.IPhysicalVolume;
15  import org.lcsim.detector.IRotation3D;
16  import org.lcsim.detector.ITransform3D;
17  import org.lcsim.detector.ITranslation3D;
18  import org.lcsim.detector.LogicalVolume;
19  import org.lcsim.detector.PhysicalVolume;
20  import org.lcsim.detector.RotationPassiveXYZ;
21  import org.lcsim.detector.Transform3D;
22  import org.lcsim.detector.Translation3D;
23  import org.lcsim.detector.identifier.ExpandedIdentifier;
24  import org.lcsim.detector.identifier.IExpandedIdentifier;
25  import org.lcsim.detector.identifier.IIdentifier;
26  import org.lcsim.detector.identifier.IIdentifierHelper;
27  import org.lcsim.detector.material.IMaterial;
28  import org.lcsim.detector.material.MaterialStore;
29  import org.lcsim.detector.solids.Box;
30  import org.lcsim.detector.solids.Trd;
31  import org.lcsim.geometry.compact.Detector;
32  import org.lcsim.geometry.compact.Subdetector;
33  import org.lcsim.geometry.layer.Layer;
34  import org.lcsim.geometry.layer.Layering;
35  import org.lcsim.geometry.subdetector.PolyhedraBarrelCalorimeter2;
36  
37  /**
38   * 
39   * This converter makes a detailed geometry for the
40   * {@link org.lcsim.geometry.subdetector.PolyhedraBarrelCalorimeter2} subdetector type.
41   * 
42   * @author Jeremy McCormick <jeremym@slac.stanford.edu>
43   * @version $Id: PolyhedraBarrelCalorimeter2Converter.java,v 1.1 2010/05/03 18:01:40
44   *          jeremy Exp $
45   */
46  public class PolyhedraBarrelCalorimeter2Converter extends AbstractSubdetectorConverter
47  {
48      public void convert( Subdetector subdet, Detector detector )
49      {
50          // Subdetector parameters.
51          int sysId = subdet.getSystemID();
52          String subdetName = subdet.getName();
53          PolyhedraBarrelCalorimeter2 cal = ( PolyhedraBarrelCalorimeter2 ) subdet;
54          int nsides = cal.getNumberOfSides();
55          double innerR = cal.getInnerRadius();
56          Layering layering = cal.getLayering();
57          double thickness = layering.getThickness();
58          double z = cal.getZLength();
59  
60          // Gap size.
61          double gap = 0;
62          if ( subdet.getNode().getAttribute( "gap" ) != null )
63          {
64              try
65              {
66                  gap = subdet.getNode().getAttribute( "gap" ).getDoubleValue();
67              }
68              catch ( DataConversionException e )
69              {
70                  throw new RuntimeException( e );
71              }
72          }
73  
74          // Get the gap material or use air as the default.
75          IMaterial air = MaterialStore.getInstance().get( "Air" );
76          IMaterial gapMaterial = air;
77          if ( subdet.getNode().getAttribute( "material" ) != null )
78          {
79              gapMaterial = MaterialStore.getInstance().get( subdet.getNode().getAttributeValue( "material" ) );
80          }
81  
82          // Parameters for trd stave.
83          double innerAngle = Math.PI * 2 / nsides;
84          double halfInnerAngle = innerAngle / 2;
85          double innerFaceLength = innerR * tan( halfInnerAngle ) * 2;
86          double rmax = innerR + thickness;
87          double outerFaceLength = rmax * tan( halfInnerAngle ) * 2;
88          double sectCenter = innerR + thickness / 2;
89          double layerOuterAngle = ( PI - innerAngle ) / 2;
90          double layerInnerAngle = ( PI / 2 - layerOuterAngle );
91  
92          // Make outer stave trd.
93          Trd staveTrdOuter = new Trd( subdet.getName() + "_stave_trap_outer",
94                                       innerFaceLength / 2,
95                                       outerFaceLength / 2,
96                                       z / 2,
97                                       z / 2,
98                                       thickness / 2 );
99  
100         // Make outer stave volume.
101         ILogicalVolume staveOuterLogicalVolume = new LogicalVolume( subdetName + "_stave_outer",
102                                                                     staveTrdOuter,
103                                                                     gapMaterial );
104 
105         // Make inner stave trd.
106         Trd staveTrdInner = new Trd( subdet.getName() + "_stave_trap_inner",
107                                      innerFaceLength / 2 - gap,
108                                      outerFaceLength / 2 - gap,
109                                      z / 2,
110                                      z / 2,
111                                      thickness / 2 );
112 
113         // Make inner stave volume.
114         ILogicalVolume staveInnerLogicalVolume = new LogicalVolume( subdetName + "_stave_inner", staveTrdInner, air );
115 
116         // Place inner stave inside of outer.
117         new PhysicalVolume( new Transform3D(), subdetName, staveInnerLogicalVolume, staveOuterLogicalVolume, 0 );
118 
119         // Layer parameters.
120         double staveThickness = thickness;
121         int layerNumber = 0;
122         double layerZ = -( staveThickness / 2 );
123         double layerX = staveTrdInner.getXHalfLength1() * 2;
124 
125         // Loop over layer elements.
126         for ( Iterator i = subdet.getNode().getChildren( "layer" ).iterator(); i.hasNext(); )
127         {
128             Element layer_element = ( Element ) i.next();
129 
130             // Get the layer from the layering engine.
131             Layer layer = layering.getLayer( layerNumber );
132 
133             // Get number of times to repeat this layer.
134             int repeat;
135             try
136             {
137                 repeat = ( int ) layer_element.getAttribute( "repeat" ).getDoubleValue();
138             }
139             catch ( Exception x )
140             {
141                 throw new RuntimeException( x );
142             }
143 
144             // Loop over repeats for this layer.
145             for ( int j = 0; j < repeat; j++ )
146             {
147                 // Name of the layer.
148                 String layerName = subdetName + "_stave_layer" + layerNumber;
149 
150                 // Layer thickness, which is Z in the trd coordinate system.
151                 double layerThickness = layer.getThickness();
152 
153                 // Layer position in Z within the stave.
154                 layerZ += layerThickness / 2;
155 
156                 // Position of layer.
157                 ITranslation3D layer_position = new Translation3D( 0, 0, layerZ );
158 
159                 // Layer box.
160                 Box layerBox = new Box( layerName + "_box", layerX / 2, z / 2, layerThickness / 2 );
161 
162                 // Layer volume.
163                 ILogicalVolume layerVolume = new LogicalVolume( layerName, layerBox, air );
164 
165                 // Starting Z of slice.
166                 double sliceZ = -( layerThickness / 2 );
167 
168                 // Slice ID.
169                 int sliceNumber = 0;
170 
171                 // Create the slices within the layer.
172                 for ( Iterator k = layer_element.getChildren( "slice" ).iterator(); k.hasNext(); )
173                 {
174                     Element sliceElement = ( Element ) k.next();
175 
176                     String sliceName = layerName + "_slice" + sliceNumber;
177 
178                     // Sensitivity.
179                     boolean sensitive = false;
180                     try
181                     {
182                         if ( sliceElement.getAttribute( "sensitive" ) != null )
183                         {
184                             Attribute s = sliceElement.getAttribute( "sensitive" );
185                             sensitive = s != null && s.getBooleanValue();
186                         }
187                     }
188                     catch ( Exception x )
189                     {
190                         throw new RuntimeException( x );
191                     }
192 
193                     // Thickness of slice.
194                     double sliceThickness;
195                     try
196                     {
197                         sliceThickness = sliceElement.getAttribute( "thickness" ).getDoubleValue();
198                     }
199                     catch ( Exception x )
200                     {
201                         throw new RuntimeException( x );
202                     }
203 
204                     // Increment Z position to place next slice.
205                     sliceZ += sliceThickness / 2;
206 
207                     // Get the slice material.
208                     IMaterial sliceMaterial = MaterialStore.getInstance().get(
209                             sliceElement.getAttributeValue( "material" ) );
210 
211                     // Slice position.
212                     ITranslation3D slicePosition = new Translation3D( 0, 0, sliceZ );
213                     ITransform3D sliceTrans = new Transform3D( slicePosition );
214 
215                     // Slice box.
216                     Box sliceBox = new Box( sliceName + "_box", layerX / 2, z / 2, sliceThickness / 2 );
217 
218                     // Slice volume.
219                     ILogicalVolume sliceVolume = new LogicalVolume( sliceName, sliceBox, sliceMaterial );
220 
221                     // Slice placement.
222                     PhysicalVolume slicePlacement = new PhysicalVolume( sliceTrans,
223                                                                         sliceName,
224                                                                         sliceVolume,
225                                                                         layerVolume,
226                                                                         sliceNumber );
227 
228                     // Set sensitivity.
229                     if ( sensitive )
230                         slicePlacement.setSensitive( true );
231 
232                     // Increment z position.
233                     sliceZ += sliceThickness / 2;
234 
235                     // Increment slice ID.
236                     ++sliceNumber;
237                 }
238 
239                 // Layer PhysicalVolume.
240                 new PhysicalVolume( new Transform3D( layer_position ),
241                                     layerName,
242                                     layerVolume,
243                                     staveInnerLogicalVolume,
244                                     layerNumber );
245 
246                 // Increment the layer X dimension.
247                 layerX += layerThickness * tan( layerInnerAngle ) * 2;
248 
249                 // Increment the layer Z position.
250                 layerZ += layerThickness / 2;
251 
252                 // Increment the layer number.
253                 ++layerNumber;
254             }
255         }
256 
257         // Place staves and make DetectorElements for them.
258         for ( int i = 0; i < nsides; i++ )
259         {
260             // Compute stave position and rotation parameters.
261             double phi = -( 2 * Math.PI * ( ( double ) i ) / nsides - Math.PI / 2 );
262             double zc = -phi + Math.PI / 2;
263             double x = sectCenter * Math.cos( phi );
264             double y = sectCenter * Math.sin( phi );
265 
266             // Make stave position and rotation.
267             ITranslation3D trans = new Translation3D( x, y, 0 );
268             IRotation3D rotate = new RotationPassiveXYZ( Math.PI / 2, 0, zc );
269             ITransform3D transform = new Transform3D( trans, rotate );
270 
271             // Stave placement.
272             String name = subdetName + "_module" + i;
273             new PhysicalVolume( transform, name, staveOuterLogicalVolume, detector.getDetectorElement().getGeometry()
274                     .getLogicalVolume(), i );
275 
276             // Stave DetectorElement.
277             new DetectorElement( subdet.getName() + "_module" + i, subdet.getDetectorElement(), "/" + name );
278         }
279 
280         // Get the identifier helper for the subdetector for ID packing.
281         IIdentifierHelper helper = cal.getDetectorElement().getIdentifierHelper();
282 
283         // Create DetectorElements for sensitive slices.
284 
285         // Loop over outer staves.
286         for ( IDetectorElement outerStave : subdet.getDetectorElement().getChildren() )
287         {
288             // Loop over inner staves (just one per outer stave).
289             for ( IPhysicalVolume innerStave : outerStave.getGeometry().getLogicalVolume().getDaughters() )
290             {
291                 // Get the stave number.
292                 int staveNum = outerStave.getGeometry().getPhysicalVolume().getCopyNumber();
293 
294                 // Loop over the layer placements.
295                 for ( IPhysicalVolume layer : innerStave.getLogicalVolume().getDaughters() )
296                 {
297                     // Loop over the slice placements.
298                     for ( IPhysicalVolume slice : layer.getLogicalVolume().getDaughters() )
299                     {
300                         // Create a new expanded identifier with correct number of fields.
301                         IExpandedIdentifier expId = new ExpandedIdentifier( helper.getIdentifierDictionary()
302                                 .getNumberOfFields() );
303 
304                         // Fill in the identifier field values from the geometry values.
305                         expId.setValue( helper.getFieldIndex( "system" ), sysId );
306                         expId.setValue( helper.getFieldIndex( "barrel" ), 0 );
307                         expId.setValue( helper.getFieldIndex( "module" ), outerStave.getGeometry().getPhysicalVolume()
308                                 .getCopyNumber() );
309                         expId.setValue( helper.getFieldIndex( "layer" ), layer.getCopyNumber() );
310                         expId.setValue( helper.getFieldIndex( "slice" ), slice.getCopyNumber() );
311 
312                         // Pack the identifier.
313                         IIdentifier id = helper.pack( expId );
314 
315                         // Make a DetectorElement if the slice is sensitive.
316                         if ( slice.isSensitive() )
317                         {
318                             new DetectorElement( subdetName + "_module" + staveNum + "_layer" + layer.getCopyNumber() + "_slice" + slice
319                                                          .getCopyNumber(),
320                                                  outerStave,
321                                                  "/" + outerStave.getGeometry().getPhysicalVolume().getName() + "/" + innerStave
322                                                          .getName() + "/" + layer.getName() + "/" + slice.getName(),
323                                                  id );
324                         }
325                     }
326                 }
327             }
328         }
329 
330     }
331 
332     public Class getSubdetectorType()
333     {
334         return PolyhedraBarrelCalorimeter2.class;
335     }
336 }