View Javadoc

1   package org.lcsim.geometry.compact.converter.lcdd;
2   
3   import static java.lang.Math.PI;
4   import static java.lang.Math.cos;
5   import static java.lang.Math.sin;
6   import static java.lang.Math.tan;
7   
8   import java.util.Iterator;
9   
10  import org.jdom.Attribute;
11  import org.jdom.Element;
12  import org.jdom.JDOMException;
13  import org.lcsim.geometry.compact.converter.lcdd.util.Box;
14  import org.lcsim.geometry.compact.converter.lcdd.util.Define;
15  import org.lcsim.geometry.compact.converter.lcdd.util.LCDD;
16  import org.lcsim.geometry.compact.converter.lcdd.util.Material;
17  import org.lcsim.geometry.compact.converter.lcdd.util.PhysVol;
18  import org.lcsim.geometry.compact.converter.lcdd.util.PolyhedraRegular;
19  import org.lcsim.geometry.compact.converter.lcdd.util.Position;
20  import org.lcsim.geometry.compact.converter.lcdd.util.Rotation;
21  import org.lcsim.geometry.compact.converter.lcdd.util.SensitiveDetector;
22  import org.lcsim.geometry.compact.converter.lcdd.util.Solids;
23  import org.lcsim.geometry.compact.converter.lcdd.util.Structure;
24  import org.lcsim.geometry.compact.converter.lcdd.util.Trapezoid;
25  import org.lcsim.geometry.compact.converter.lcdd.util.Volume;
26  import org.lcsim.geometry.layer.Layer;
27  import org.lcsim.geometry.layer.Layering;
28  
29  /**
30   *
31   * Convert a PolyhedraBarrelCalorimeter to LCDD format.
32   *
33   * @author Jeremy McCormick <jeremym@slac.stanford.edu>
34   */
35  public class PolyhedraBarrelCalorimeter2 extends LCDDSubdetector
36  {
37      private Element node;   
38          
39      public PolyhedraBarrelCalorimeter2(Element node) throws JDOMException
40      {
41          super(node);
42          this.node = node;
43      }
44  
45      public void addToLCDD(LCDD lcdd, SensitiveDetector sens) throws JDOMException
46      {
47          // Get some important LCDD references.
48          Solids solids = lcdd.getSolids();
49          Structure structure = lcdd.getStructure();
50          Volume motherVolume = lcdd.pickMotherVolume(this);
51          Material air = lcdd.getMaterial("Air");
52          Define define = lcdd.getDefine();
53          Material gapMaterial = air;
54          if (node.getAttribute("material") != null)
55              gapMaterial = lcdd.getMaterial(node.getAttribute("material").getValue());
56  
57          // Subdetector name and ID.
58          String detName = node.getAttributeValue("name");
59          int id = node.getAttribute("id").getIntValue();
60          
61          Element staves = node.getChild("staves");
62          
63          double gap = 0.0;
64          if (node.getAttribute("gap") != null)
65          {
66              gap = node.getAttribute("gap").getDoubleValue();
67          }
68                  
69          // Subdetector envelope dimensions.
70          Element dimensions = node.getChild("dimensions");
71          double detZ = dimensions.getAttribute("z").getDoubleValue();
72          double rmin = dimensions.getAttribute("rmin").getDoubleValue();
73          int numsides = dimensions.getAttribute("numsides").getIntValue();
74  
75          // Rotation of the envelope to make flat side down.
76          double zrot = Math.PI / numsides;
77          Rotation rot = new Rotation(detName + "_rotation");
78          rot.setZ(zrot);
79          define.addRotation(rot);
80  
81          // Create layering object for this subdetector.
82          Layering layering = Layering.makeLayering(this.node);
83  
84          // Total thickness of subdetector.
85          double total_thickness = layering.getLayerStack().getTotalThickness();
86          
87          int total_repeat = 0;
88          int total_slices = 0;
89          for (Iterator i = node.getChildren("layer").iterator(); i.hasNext();)
90          {
91              Element layer_element = (Element) i.next();
92              int repeat = (int)layer_element.getAttribute("repeat").getDoubleValue();
93              total_repeat += repeat;         
94              total_slices += (layer_element.getChildren("slice").size() * total_repeat);         
95          }
96                                                                  
97          // Envelope volume for subdetector.
98          PolyhedraRegular polyhedra = new PolyhedraRegular(
99                  detName + "_polyhedra", 
100                 numsides, 
101                 rmin, 
102                 rmin + total_thickness, 
103                 detZ);
104         solids.addSolid(polyhedra);
105 
106         Volume envelopeVolume = new Volume(detName + "_envelope");
107         envelopeVolume.setSolid(polyhedra);
108         envelopeVolume.setMaterial(air);
109         
110         PhysVol envelopePhysvol = new PhysVol(envelopeVolume);
111         envelopePhysvol.setRotation(rot);
112         envelopePhysvol.addPhysVolID("system", id);
113         envelopePhysvol.addPhysVolID("barrel", 0);
114         motherVolume.addPhysVol(envelopePhysvol);
115 
116         // A trapezoid stave.
117         double innerAngle = Math.PI * 2 / numsides;
118         double halfInnerAngle = innerAngle / 2;
119         double innerFaceLength = rmin * tan(halfInnerAngle) * 2;
120         double rmax = rmin + total_thickness;
121         double outerFaceLength = rmax * tan(halfInnerAngle) * 2;        
122         double stave_thickness = total_thickness;
123         
124         // Make trap outer stave.
125         Trapezoid staveTrdOuter = new Trapezoid(detName + "_stave_trapezoid_outer");
126         staveTrdOuter.setY2(detZ/2);
127         staveTrdOuter.setY1(detZ/2);
128         staveTrdOuter.setZ(stave_thickness/2);
129         staveTrdOuter.setX1(innerFaceLength/2);
130         staveTrdOuter.setX2(outerFaceLength/2);
131         solids.addSolid(staveTrdOuter);
132                 
133         // Make trap outer volume.
134         Volume staveOuterVolume = new Volume(detName + "_stave_outer");
135         staveOuterVolume.setSolid(staveTrdOuter);
136         staveOuterVolume.setMaterial(gapMaterial);        
137         
138         // Make trap inner stave.
139         Trapezoid staveTrdInner = new Trapezoid(detName + "_stave_trapezoid_inner");
140         staveTrdInner.setY2(detZ/2);
141         staveTrdInner.setY1(detZ/2);
142         staveTrdInner.setZ(stave_thickness/2);
143         staveTrdInner.setX1(innerFaceLength/2 - gap);
144         staveTrdInner.setX2(outerFaceLength/2 - gap);
145         solids.addSolid(staveTrdInner);
146         
147         // Make trap outer volume.
148         Volume staveInnerVolume = new Volume(detName + "_stave_inner");
149         staveInnerVolume.setMaterial(air);
150         staveInnerVolume.setSolid(staveTrdInner);
151                
152         // Create layers.               
153         double layerOuterAngle = (PI - innerAngle) / 2;
154         double layerInnerAngle = (PI / 2 - layerOuterAngle);        
155         int layer_number = 0;
156         double layer_position_z = -(stave_thickness / 2);                        
157         double layer_dim_x = innerFaceLength - gap * 2;
158         
159         for (Iterator i = node.getChildren("layer").iterator(); i.hasNext();)
160         {
161             Element layer_element = (Element) i.next();
162 
163             // Get the layer from the layering engine.
164             Layer layer = layering.getLayer(layer_number);
165 
166             // Get number of times to repeat this layer.
167             int repeat = (int)layer_element.getAttribute("repeat").getDoubleValue();
168 
169             // Loop over repeats for this layer.
170             for (int j = 0; j < repeat; j++)
171             {                
172                 // Name of the layer.
173                 String layer_name = detName + "_stave_layer" + layer_number;
174 
175                 // Layer thickness.
176                 double layer_thickness = layer.getThickness();              
177 
178                 int nslices = layer_element.getChildren("slices").size();
179                                                                 
180                 // Layer position in Z within the stave.
181                 layer_position_z += layer_thickness / 2;
182                                                                                             
183                 // Position of layer.
184                 Position layer_position = new Position(layer_name + "_position");
185                 layer_position.setZ(layer_position_z);
186                 define.addPosition(layer_position);
187 
188                 // Layer box.
189                 Box layer_box = new Box(layer_name + "_box");
190                 layer_box.setX(layer_dim_x);
191                 layer_box.setY(detZ);
192                 layer_box.setZ(layer_thickness);
193                 solids.addSolid(layer_box);
194 
195                 // Layer volume. 
196                 Volume layer_volume = new Volume(layer_name);
197                 layer_volume.setSolid(layer_box);
198                 layer_volume.setMaterial(air);
199 
200                 // Create the slices (sublayers) within the layer.
201                 double slice_position_z = -(layer_thickness / 2);
202                                                                 
203                 int slice_number = 0;
204                 for (Iterator k = layer_element.getChildren("slice").iterator(); k.hasNext();)
205                 {
206                     Element slice_element = (Element) k.next();
207 
208                     String slice_name = layer_name + "_slice" + slice_number;
209 
210                     Attribute s = slice_element.getAttribute("sensitive");
211                     boolean sensitive = s != null && s.getBooleanValue();
212 
213                     double slice_thickness = slice_element.getAttribute("thickness").getDoubleValue();
214 
215                     slice_position_z += slice_thickness / 2;
216                     
217                     Material slice_material = lcdd.getMaterial(slice_element.getAttributeValue("material"));
218 
219                     // Slice Position.
220                     Position slice_position = new Position(slice_name + "_position");
221                     slice_position.setZ(slice_position_z);
222                     define.addPosition(slice_position);
223 
224                     // Slice box. 
225                     Box slice_box = new Box(slice_name + "_box");
226                     slice_box.setX(layer_dim_x);
227                     slice_box.setY(detZ);
228                     slice_box.setZ(slice_thickness);
229                     solids.addSolid(slice_box);
230 
231                     // Slice volume.
232                     Volume slice_volume = new Volume(slice_name);
233                     slice_volume.setSolid(slice_box);
234                     slice_volume.setMaterial(slice_material);
235                     if (sensitive)
236                         slice_volume.setSensitiveDetector(sens);
237                     structure.addVolume(slice_volume);
238 
239                     // Set region, limitset, and vis.
240                     setRegion(lcdd, slice_element, slice_volume);
241                     setLimitSet(lcdd, slice_element, slice_volume);
242                     setVisAttributes(lcdd, slice_element, slice_volume);
243 
244                     // slice PhysVol
245                     PhysVol slice_physvol = new PhysVol(slice_volume);
246                     slice_physvol.setPosition(slice_position);
247                     slice_physvol.addPhysVolID("slice", slice_number);
248                     layer_volume.addPhysVol(slice_physvol);
249 
250                     // Increment Z position for next slice.
251                     slice_position_z += slice_thickness / 2;
252 
253                     // Increment slice number.
254                     ++slice_number;             
255                 }
256 
257                 // Set region, limitset, and vis.
258                 setRegion(lcdd, layer_element, layer_volume);
259                 setLimitSet(lcdd, layer_element, layer_volume);
260                 setVisAttributes(lcdd, layer_element, layer_volume);
261                 
262                 // Add the layer logical volume to the structure.
263                 structure.addVolume(layer_volume);
264 
265                 // Layer physical volume.
266                 PhysVol layer_physvol = new PhysVol(layer_volume);
267                 layer_physvol.setPosition(layer_position);
268                 layer_physvol.addPhysVolID("layer", layer_number);
269                 staveInnerVolume.addPhysVol(layer_physvol);
270 
271                 // Increment the layer X dimension.
272                 layer_dim_x += layer_thickness * tan(layerInnerAngle) * 2;
273 
274                 // Increment the layer Z position.
275                 layer_position_z += layer_thickness / 2;
276 
277                 // Increment the layer number.
278                 ++layer_number;         
279             }
280         }
281                         
282         // Make stave inner physical volume.
283         PhysVol staveInnerPhysVol = new PhysVol(staveInnerVolume);
284         
285         // Add stave inner physical volume to outer stave volume.
286         staveOuterVolume.addPhysVol(staveInnerPhysVol);
287         
288         // Set the vis attributes of the outer stave section.
289         if (staves != null)
290         {
291             if (staves.getAttribute("vis") != null)
292             {
293                 setVisAttributes(lcdd,staves,staveOuterVolume);
294             }
295         }
296         
297         // Add the stave inner volume to the structure.
298         structure.addVolume(staveInnerVolume);
299         
300         // Add the stave outer volume to the structure.
301         structure.addVolume(staveOuterVolume);
302 
303         // Place the staves.
304         placeStaves(define, detName, rmin, numsides, total_thickness, envelopeVolume, innerAngle, staveOuterVolume);
305         
306         // Set envelope volume attributes.
307         setAttributes(lcdd, node, envelopeVolume);
308         
309         // Add the subdetector envelope to the structure.
310         structure.addVolume(envelopeVolume);
311     }
312 
313     private void placeStaves(Define define, String detName, double rmin, int numsides, double total_thickness, Volume envelopeVolume, double innerAngle, Volume sectVolume)
314     {
315         // Place the staves.
316         double innerRotation = innerAngle;
317         double offsetRotation= -innerRotation / 2;
318         double sectCenterRadius = rmin + total_thickness / 2;
319         double rotY = -offsetRotation;
320         double rotX = PI / 2;
321         double posX = -sectCenterRadius * sin(rotY);
322         double posY = sectCenterRadius * cos(rotY);
323         
324         for (int i = 0; i < numsides; i++)
325         {
326             int moduleNumber = i;
327 
328             Position position = new Position(detName + "_stave0_module" + moduleNumber + "_position");
329             position.setX(posX);
330             position.setY(posY);
331 
332             Rotation rotation = new Rotation(detName + "_stave0_module" + moduleNumber + "_rotation");
333             rotation.setX(rotX);
334             rotation.setY(rotY);
335 
336             define.addPosition(position);
337             define.addRotation(rotation);
338 
339             PhysVol sectPhysVol = new PhysVol(sectVolume);
340             sectPhysVol.setPosition(position);
341             sectPhysVol.setRotation(rotation);
342 
343             envelopeVolume.addPhysVol(sectPhysVol);
344             sectPhysVol.addPhysVolID("stave", 0);
345             sectPhysVol.addPhysVolID("module", moduleNumber);
346 
347             rotY -= innerRotation;
348             posX = -sectCenterRadius * sin(rotY);
349             posY = sectCenterRadius * cos(rotY);            
350         }
351     }
352 
353     public boolean isCalorimeter()
354     {
355         return true;
356     }
357 }