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.Define;
14  import org.lcsim.geometry.compact.converter.lcdd.util.LCDD;
15  import org.lcsim.geometry.compact.converter.lcdd.util.Material;
16  import org.lcsim.geometry.compact.converter.lcdd.util.PhysVol;
17  import org.lcsim.geometry.compact.converter.lcdd.util.Position;
18  import org.lcsim.geometry.compact.converter.lcdd.util.Rotation;
19  import org.lcsim.geometry.compact.converter.lcdd.util.SensitiveDetector;
20  import org.lcsim.geometry.compact.converter.lcdd.util.Solids;
21  import org.lcsim.geometry.compact.converter.lcdd.util.Structure;
22  import org.lcsim.geometry.compact.converter.lcdd.util.Trapezoid;
23  import org.lcsim.geometry.compact.converter.lcdd.util.Volume;
24  import org.lcsim.geometry.layer.LayerStack;
25  import org.lcsim.geometry.layer.Layering;
26  
27  /**
28   * Convert a PolyhedraEndcapCalorimeter to the LCDD format.
29   *
30   * @author Jeremy McCormick <jeremym@slac.stanford.edu>
31   * @version $id: $
32   */
33  public class PolyhedraEndcapCalorimeter extends LCDDSubdetector
34  {
35      private Element node;
36  
37      // Subtracted from stave envelope dimensions.
38      //private final double STAVE_ENVELOPE_TOLERANCE=10.0;
39      private final double STAVE_ENVELOPE_TOLERANCE=0.0;
40      
41      // Subtracted from layer envelope dimensions.
42      //private final double LAYER_ENVELOPE_TOLERANCE=1.0;
43      private final double LAYER_ENVELOPE_TOLERANCE=0.0;
44      
45      // Subtracted from slice dimensions.
46      //private final double SLICE_ENVELOPE_TOLERANCE=1.0;
47      private final double SLICE_ENVELOPE_TOLERANCE=0.0;
48      
49      // Small gap placed in front of each layer.
50      //private final double INTER_LAYER_GAP=1.0;
51      private final double INTER_LAYER_GAP=0.0;
52      
53      // Small subtraction from given thickness of slice.  
54      //private final double SLICE_TOLERANCE=0.01;
55      private final double SLICE_TOLERANCE=0.0;
56  
57      public PolyhedraEndcapCalorimeter(Element node) throws JDOMException
58      {
59          super(node);
60          this.node = node;
61      }
62  
63      public void addToLCDD(LCDD lcdd, SensitiveDetector sens) throws JDOMException
64      {
65          if ( sens == null)
66          {
67              throw new IllegalArgumentException("PolyhedraBarrelCalorimeter <" + getName() + " has null SD.");
68          }
69  
70          // Get important LCDD objects.
71          Solids solids = lcdd.getSolids();
72          Structure structure = lcdd.getStructure();
73          Volume motherVolume = lcdd.pickMotherVolume(this);
74          Material air = lcdd.getMaterial("Air");
75          Define define = lcdd.getDefine();
76          Element staves = node.getChild("staves");
77  
78          // Subdetector name and ID.
79          String detName = node.getAttributeValue("name");
80          int id = node.getAttribute("id").getIntValue();
81  
82          // Subdetector envelope dimensions.
83          Element dimensions = node.getChild("dimensions");
84          double zmin = dimensions.getAttribute("zmin").getDoubleValue();
85          double rmin = dimensions.getAttribute("rmin").getDoubleValue();
86          double rmax = dimensions.getAttribute("rmax").getDoubleValue();
87                  
88          int numsides = dimensions.getAttribute("numsides").getIntValue();
89          
90          // Geant4 interprets rmax as the distance to the polygonal flat.
91          // we want to interpret this as the distance to the point.
92          rmax = rmax*Math.cos(Math.PI/numsides);
93  
94          LayerStack layers = Layering.makeLayering(this.node).getLayerStack();
95          
96          rmax = rmin + layers.getTotalThickness();
97          
98          // Total thickness of the subdetector.
99          double subdetectorThickness = org.lcsim.geometry.layer.LayerFromCompactCnv.computeDetectorTotalThickness(node);
100         
101         // Increase the thickness of the endcap to accomodate a gap between layers.
102         subdetectorThickness += layers.getNumberOfLayers() * INTER_LAYER_GAP;
103                 
104         // Compute the radial thickness from the user parameters. 
105         double radialThickness = rmax - rmin;        
106 
107         /*
108         // The detector envelope volume.
109          * 
110         double detZ = subdetector_thickness;
111         PolyhedraRegular polyhedra = new PolyhedraRegular(
112                 detName + "_polyhedra",
113                 numsides, rmin, rmax, detZ);
114         solids.addSolid(polyhedra);
115 
116         Volume envelopeVolume = new Volume(detName + "_envelope");
117         envelopeVolume.setSolid(polyhedra);
118         envelopeVolume.setMaterial(air);
119         */
120 
121         // The stave's trapezoid.
122         double innerAngle = Math.PI * 2 / numsides;
123         double halfInnerAngle = innerAngle/2;
124         double innerFaceLength = (rmin * tan(halfInnerAngle)) * 2;
125         double outerFaceLength = (rmax * tan(halfInnerAngle)) * 2;
126 
127         // Apply tolerances to the computed dimensions.
128         radialThickness -= STAVE_ENVELOPE_TOLERANCE;
129         innerFaceLength -= STAVE_ENVELOPE_TOLERANCE;
130         outerFaceLength -= STAVE_ENVELOPE_TOLERANCE;
131                        
132         //outerFaceLength = (innerFaceLength * outerFaceLength) / (innerFaceLength + STAVE_ENVELOPE_TOLERANCE);
133         //System.out.println("outerFaceLength="+outerFaceLength);
134         
135         Trapezoid sectTrd = new Trapezoid(detName + "_stave_trapezoid");
136         sectTrd.setY2(subdetectorThickness/2);
137         sectTrd.setY1(subdetectorThickness/2);
138         sectTrd.setZ(radialThickness/2);
139         sectTrd.setX1(innerFaceLength/2);
140         sectTrd.setX2(outerFaceLength/2);
141         
142         solids.addSolid(sectTrd);
143         Volume sectVolume = new Volume(detName + "_stave");
144         sectVolume.setMaterial(air);
145         sectVolume.setSolid(sectTrd);
146 
147         // Build the layers.
148         int layer_number = 0;
149         double layerPositionY = subdetectorThickness / 2;
150         
151         // DEBUG
152         layerPositionY -= INTER_LAYER_GAP;
153         for (Iterator i = node.getChildren("layer").iterator(); i.hasNext();)
154         {
155             Element layerElement = (Element) i.next();
156 
157             int repeat = (int)layerElement.getAttribute("repeat").getDoubleValue();
158 
159             for ( int j=0; j<repeat; j++)
160             {
161             	String layerName = detName + "_stave_layer" + layer_number;;
162 
163             	double layerThickness = layers.getLayer(layer_number).getThickness();
164 
165             	layerPositionY -= layerThickness / 2;
166 
167             	// Layer position.
168                 Position layerPosition = new Position(layerName + "_position");
169                 layerPosition.setY(layerPositionY);
170                 define.addPosition(layerPosition);
171 
172                 // Layer trapezoid.
173                 Trapezoid layerTrd = new Trapezoid(layerName + "_trapezoid");
174                 
175                 double layerInnerFaceLength=innerFaceLength-LAYER_ENVELOPE_TOLERANCE;
176                 double layerOuterFaceLength=outerFaceLength-LAYER_ENVELOPE_TOLERANCE;
177                 double layerRadialThickness=radialThickness-LAYER_ENVELOPE_TOLERANCE;
178                 
179                 layerTrd.setX1(layerInnerFaceLength/2);
180                 layerTrd.setX2(layerOuterFaceLength/2);
181                 layerTrd.setY1(layerThickness/2);
182                 layerTrd.setY2(layerThickness/2);
183                 layerTrd.setZ(layerRadialThickness/2);
184                                 
185                 solids.addSolid(layerTrd);
186 
187                 Volume layerVolume = new Volume(layerName);
188                 layerVolume.setSolid(layerTrd);
189                 layerVolume.setMaterial(lcdd.getMaterial("Air"));
190 
191                 int slice_number = 0;
192                 double slice_position_y = layerThickness / 2;
193                 for ( Iterator k = layerElement.getChildren("slice").iterator(); k.hasNext();)
194                 {
195                 	Element sliceElement = (Element)k.next();
196 
197                 	String sliceName = layerName + "_slice" + slice_number;
198 
199                 	Attribute s = sliceElement.getAttribute("sensitive");
200                     boolean sensitive = s != null && s.getBooleanValue();
201 
202                     double slice_thickness = sliceElement.getAttribute("thickness").getDoubleValue();
203                     
204                     // Apply tolerance factor to given slice thickness.
205                     //slice_thickness -= SLICE_TOLERANCE;
206                     
207                     slice_position_y -=  slice_thickness / 2;
208 
209                     Position slicePosition = new Position(sliceName + "_position");
210                     slicePosition.setY(slice_position_y);
211                     define.addPosition(slicePosition);
212 
213                     Trapezoid sliceTrd = new Trapezoid(sliceName + "_trapezoid");
214                     
215                     double sliceInnerFaceLength = layerInnerFaceLength - SLICE_ENVELOPE_TOLERANCE;
216                     double sliceOuterFaceLength = layerOuterFaceLength - SLICE_ENVELOPE_TOLERANCE;
217                     double sliceRadialThickness = layerRadialThickness - SLICE_ENVELOPE_TOLERANCE;
218                     
219                     sliceTrd.setX1(sliceInnerFaceLength/2);
220                     sliceTrd.setX2(sliceOuterFaceLength/2);
221                     sliceTrd.setY1((slice_thickness-SLICE_TOLERANCE)/2);  // Subtract tolerance from slice_thickness.
222                     sliceTrd.setY2((slice_thickness-SLICE_TOLERANCE)/2);  // Subtract tolerance from slice_thickness.
223                     sliceTrd.setZ(sliceRadialThickness/2);
224                     
225                     solids.addSolid(sliceTrd);
226 
227                     Volume sliceVolume = new Volume(sliceName);
228                     sliceVolume.setSolid(sliceTrd);
229                     sliceVolume.setMaterial(lcdd.getMaterial(sliceElement.getAttributeValue("material")));
230                     
231                     if ( sensitive ) sliceVolume.setSensitiveDetector(sens);
232                     
233                     if (sliceElement.getAttribute("vis") != null)
234                     {
235                         sliceVolume.setVisAttributes(lcdd.getVisAttributes(sliceElement.getAttributeValue("vis")));
236                     }
237 
238                     setRegion(lcdd, sliceElement, sliceVolume);
239                     setLimitSet(lcdd, sliceElement, sliceVolume);
240 
241                     //setVisAttributes(lcdd, node, sliceVolume);
242                     structure.addVolume(sliceVolume);
243 
244                     PhysVol slicePhysVol = new PhysVol(sliceVolume);
245                     slicePhysVol.setPosition(slicePosition);
246                     slicePhysVol.addPhysVolID("slice", slice_number);
247                     layerVolume.addPhysVol(slicePhysVol);
248 
249                     // The slice thickness is the original, NOT adjusted for tolerance,
250                     // so that the center of the slice is in the right place with tolerance
251                     // gaps on either side.
252                     slice_position_y -= slice_thickness / 2;
253 
254                     // Increment the slice counter.
255                     ++slice_number;
256                 }
257                                 
258                 lcdd.add(layerVolume);
259 
260                 setRegion(lcdd, layerElement, layerVolume);
261                 setLimitSet(lcdd, layerElement, layerVolume);
262                 if (layerElement.getAttribute("vis") != null)
263                 {
264                     layerVolume.setVisAttributes(lcdd.getVisAttributes(layerElement.getAttributeValue("vis")));
265                 }
266                 //setVisAttributes(lcdd, node, layerVolume);
267 
268                 PhysVol layer_physvol = new PhysVol(layerVolume);
269                 layer_physvol.setPosition(layerPosition);
270                 layer_physvol.addPhysVolID("layer", layer_number);
271                 sectVolume.addPhysVol(layer_physvol);
272 
273                 layerPositionY -= layerThickness / 2;
274                 
275                 //layerPositionY -= INTER_LAYER_GAP;
276 
277                 ++layer_number;                    
278             }
279             // DEBUG - Uncomment to build only one layer. 
280             //break;
281         }        
282 
283         // Set the vis of the section.
284         if (staves != null)
285 		{
286         	if (staves.getAttribute("vis") != null)
287         	{
288         		setVisAttributes(lcdd,staves,sectVolume);
289         	}
290 		}
291         
292         // Add the section volume after layers created.
293         //if (node.getAttribute("vis") != null)
294         //{
295         //    sectVolume.setVisAttributes(lcdd.getVisAttributes(node.getAttributeValue("vis")));
296         //}
297         
298         structure.addVolume(sectVolume);
299 
300         // Place the sections.
301         double innerRotation = innerAngle;
302         //double offsetRotation = -innerRotation / 2;
303         //double offsetRotation = 0.;
304 
305         //System.out.println("radial_thickness: " + radial_thickness);
306 
307         double sectCenterRadius = rmin + radialThickness / 2;
308         //System.out.println("sectCenterRadius: " + sectCenterRadius);
309         //double rotY = -offsetRotation;
310         double rotY = 0.;
311         //double rotY = 0.;
312         double rotX = PI / 2;
313         //double rotX = PI / 4;
314         double posX = -sectCenterRadius * sin(rotY);
315         double sectPosY = sectCenterRadius * cos(rotY);
316         //System.out.println("posX: " + posX);
317         //System.out.println("sectPosY: " + sectPosY);
318         for ( int i=0; i < numsides; i++)
319         {
320             int moduleNumber=i;
321 
322             //System.out.println("moduleNumber: " + moduleNumber);
323             //System.out.println("posX: " + posX);
324             //System.out.println("sectPosY: " + sectPosY);
325             
326             Position position = new Position(detName + "_stave0_module" + moduleNumber + "_position");
327             position.setX(posX);
328             position.setY(sectPosY);
329             position.setZ(zmin + subdetectorThickness/2);
330             
331             Rotation rotation = new Rotation(detName + "_stave0_module" + moduleNumber + "_rotation");
332             rotation.setX(rotX);
333             rotation.setY(rotY);
334 
335             define.addPosition(position);
336             define.addRotation(rotation);
337 
338             PhysVol sectPhysVol = new PhysVol(sectVolume);
339             sectPhysVol.setPosition(position);
340             sectPhysVol.setRotation(rotation);
341 
342             //envelopeVolume.addPhysVol(sectPhysVol);
343             motherVolume.addPhysVol(sectPhysVol);
344             sectPhysVol.addPhysVolID("system",id);
345             sectPhysVol.addPhysVolID("barrel",1);
346             sectPhysVol.addPhysVolID("stave",0);
347             sectPhysVol.addPhysVolID("module",moduleNumber);
348             
349             // Place the reflected subdetector envelope.
350             boolean reflect = true;
351             if (node.getAttribute("reflect") != null)
352                 reflect = node.getAttribute("reflect").getBooleanValue();
353             if (reflect)
354             {
355                 Rotation envelopeRotationReflect = new Rotation(detName + "_stave0_module" + moduleNumber + "_reflect_rotation");
356                 
357                 //envelopeRotationReflect.setX(Math.PI);
358                 //envelopeRotationReflect.setY(rotY);
359                 //envelopeRotationReflect.setZ(zrot);
360                 
361                 envelopeRotationReflect.setX(Math.PI / 2);
362                 envelopeRotationReflect.setY(rotY);
363                 envelopeRotationReflect.setZ(Math.PI);
364                 
365                 //envelopeRotationReflect.setY(Math.PI);
366                 
367                 define.addRotation(envelopeRotationReflect);
368 
369                 Position reflect_position = new Position(detName + "_stave0_module" + moduleNumber + "_reflect_position");
370                 reflect_position.setX(posX);
371                 reflect_position.setY(sectPosY);
372                 reflect_position.setZ(-zmin-subdetectorThickness/2);
373                 define.addPosition(reflect_position);
374                 
375                 PhysVol physvol2 = new PhysVol(sectVolume);
376                 physvol2.setPosition(reflect_position);
377                 physvol2.setRotation(envelopeRotationReflect);
378                 physvol2.addPhysVolID("system",id);
379                 physvol2.addPhysVolID("barrel",2);
380                 physvol2.addPhysVolID("stave",0);
381                 physvol2.addPhysVolID("module",moduleNumber);
382                 motherVolume.addPhysVol(physvol2);
383             } 
384             
385             rotY -= innerRotation;
386             posX = -sectCenterRadius * sin(rotY);
387             sectPosY = sectCenterRadius * cos(rotY);
388 
389             //System.out.println();
390             
391             // DEBUG
392             //if (i==1)
393             //	break;
394         }
395 
396         /*
397         // Place the subdetector envelope.
398         PhysVol envelopePhysvol = new PhysVol(envelopeVolume);
399         envelopePhysvol.setZ(zmin + subdetector_thickness/2);
400         envelopePhysvol.addPhysVolID("system",id);
401         envelopePhysvol.setRotation(envelopeRotation);
402         envelopePhysvol.addPhysVolID("barrel",1);
403 
404         motherVolume.addPhysVol(envelopePhysvol);
405 
406         // Place the reflected subdetector envelope.
407         boolean reflect = node.getAttribute("reflect").getBooleanValue();
408         if (reflect)
409         {
410         	Rotation envelopeRotationReflect = new Rotation(detName + "_reflect_rotation");
411             envelopeRotationReflect.setX(Math.PI);
412             envelopeRotationReflect.setZ(zrot);
413             define.addRotation(envelopeRotationReflect);
414 
415             PhysVol physvol2 = new PhysVol(envelopeVolume);
416             physvol2.setZ(-zmin-subdetector_thickness/2);
417             physvol2.setRotation(envelopeRotationReflect);
418             physvol2.addPhysVolID("system",id);
419             physvol2.addPhysVolID("barrel",2);
420             motherVolume.addPhysVol(physvol2);
421         }
422 
423         // Add the envelope volume to LCDD once staves are all created.
424         setVisAttributes(lcdd, node, envelopeVolume);
425         structure.addVolume(envelopeVolume);
426         */
427     }
428 
429     public boolean isCalorimeter()
430     {
431         return true;
432     }
433 }