View Javadoc

1   package org.lcsim.geometry.compact.converter.lcdd;
2   
3   import org.jdom.Element;
4   import org.jdom.JDOMException;
5   import org.lcsim.geometry.compact.converter.lcdd.util.Cone;
6   import org.lcsim.geometry.compact.converter.lcdd.util.LCDD;
7   import org.lcsim.geometry.compact.converter.lcdd.util.Material;
8   import org.lcsim.geometry.compact.converter.lcdd.util.PhysVol;
9   import org.lcsim.geometry.compact.converter.lcdd.util.Rotation;
10  import org.lcsim.geometry.compact.converter.lcdd.util.SensitiveDetector;
11  import org.lcsim.geometry.compact.converter.lcdd.util.Solids;
12  import org.lcsim.geometry.compact.converter.lcdd.util.Structure;
13  import org.lcsim.geometry.compact.converter.lcdd.util.Tube;
14  import org.lcsim.geometry.compact.converter.lcdd.util.Volume;
15  import org.lcsim.geometry.layer.LayerSlice;
16  import org.lcsim.geometry.layer.LayerStack;
17  import org.lcsim.geometry.layer.Layering;
18  
19  public class CylindricalEndcapCalorimeter2 extends LCDDSubdetector
20  {
21      CylindricalEndcapCalorimeter2(Element c) throws JDOMException
22      {
23          super(c);
24      }
25  
26      void addToLCDD(LCDD lcdd, SensitiveDetector sens) throws JDOMException
27      {
28          // Get subdetector id and name.
29          int id = node.getAttribute("id").getIntValue();
30          String subdetectorName = node.getAttributeValue("name");
31  
32          // Get important references from LCDD.
33          Material air = lcdd.getMaterial("Air");
34          Solids solids = lcdd.getSolids();
35          Structure structure = lcdd.getStructure();
36          Volume motherVolume = lcdd.pickMotherVolume(this);
37  
38          // Get the subdetector dimensions.
39          Element dimensions = node.getChild("dimensions");
40          double zmin = dimensions.getAttribute("zmin").getDoubleValue();
41          double rmin = dimensions.getAttribute("rmin").getDoubleValue();
42          double rmax = dimensions.getAttribute("rmax").getDoubleValue();
43          double innerAngle = dimensions.getAttribute("angle").getDoubleValue();
44  
45          // Make layering object.
46          LayerStack layers = Layering.makeLayering(this.node).getLayerStack();
47  
48          // Get thickness of calorimeter in z dimension determined by layering.
49          double thickness = layers.getTotalThickness();
50  
51          // Compute radius at last zplane of envelope.
52          double rmin2 = rmin + (thickness * Math.tan(innerAngle));
53  
54          // Make the subdetector's envelope cone.
55          // Note: Z measurement is full length, which will be divided by two for half-length by GDML.
56          Cone envelopeCone = new Cone(subdetectorName + "_envelope_cone", rmin, rmin2, rmax, rmax, thickness);
57          solids.addSolid(envelopeCone);
58  
59          // Make the calorimeter envelope volume.
60          Volume envelopeVolume = new Volume(subdetectorName + "_volume", envelopeCone, air);
61  
62          // Set the absolute z coordinate of the layer front face for layer loop.
63          double layerZ = -thickness / 2;
64  
65          // The rmin of the layer which will decrease along z.
66          double layerRmin = rmin;
67                  
68          // Loop over and build the layers into the detector envelope.
69          for (int i = 0, l = layers.getNumberOfLayers(); i < l; i++)
70          {            
71              // Get this layer's thickness.
72              double layerThickness = layers.getLayer(i).getThickness();
73  
74              // Compute change in layer inner radius.
75              double layerdx = Math.tan(innerAngle) * layerThickness;
76  
77              // Add dx to inner radius.
78              layerRmin += layerdx;
79  
80              // Make layer tube.
81              // Note: This shape wants the z half-length instead of full z length. 
82              Tube layerTube = new Tube(subdetectorName + "_layer" + i + "_tube", layerRmin, rmax, layerThickness / 2);
83              solids.addSolid(layerTube);
84  
85              // Make layer volume.
86              Volume layerVolume = new Volume(subdetectorName + "_layer" + i + "_volume", layerTube, air);
87  
88              // Slice loop.
89              double sliceZ = -layerThickness / 2;
90              int sliceCount = 0;
91              for (LayerSlice slice : layers.getLayer(i).getSlices())
92              {                
93                  // Get slice thickness.
94                  double sliceThickness = slice.getThickness();
95  
96                  // Make slice tube.
97                  Tube sliceTube = 
98                      new Tube(subdetectorName + "_layer" + i + "_slice" + sliceCount + "_tube", layerRmin, rmax, sliceThickness / 2);
99                  solids.addSolid(sliceTube);
100                 
101                 // Make slice volume.
102                 Volume sliceVolume = new Volume(subdetectorName + "_layer" + i + "_slice" + sliceCount + "_volume", sliceTube, lcdd.getMaterial(slice.getMaterial().getName()));
103                 structure.addVolume(sliceVolume);
104                 
105                 // Set volume sensitivity.
106                 if (slice.isSensitive())
107                     sliceVolume.setSensitiveDetector(sens);
108                 
109                 // Make slice placement.
110                 PhysVol slicePhysVol = new PhysVol(sliceVolume);
111                 slicePhysVol.setZ(sliceZ + sliceThickness / 2);
112                 slicePhysVol.addPhysVolID("slice", sliceCount);
113                 layerVolume.addPhysVol(slicePhysVol);
114                 
115                 // Add slice's thickness to slice Z position.
116                 sliceZ += sliceThickness;
117                 
118                 // Increment slice count.
119                 ++sliceCount;
120             }
121              
122             // Add layer volume to structure.
123             structure.addVolume(layerVolume);
124 
125             // Make layer placement into envelope.
126             PhysVol layerPhysVol = new PhysVol(layerVolume);
127             layerPhysVol.addPhysVolID("layer", i);
128             layerPhysVol.setZ(layerZ + layerThickness / 2);  
129             envelopeVolume.addPhysVol(layerPhysVol);
130 
131             // Set z to edge of next layer.
132             layerZ += layerThickness;                
133         }
134 
135         // Add envelope's logical volume to structure.
136         structure.addVolume(envelopeVolume);
137 
138         // Positive endcap placement.
139         PhysVol endcapPositivePhysVol = new PhysVol(envelopeVolume);
140         endcapPositivePhysVol.addPhysVolID("system", id);
141         endcapPositivePhysVol.addPhysVolID("barrel", 1);        
142         endcapPositivePhysVol.setZ(zmin + thickness / 2);
143         motherVolume.addPhysVol(endcapPositivePhysVol);
144         
145         // Negative endcap placement.
146         PhysVol endcapNegativePhysVol = new PhysVol(envelopeVolume);
147         endcapNegativePhysVol.addPhysVolID("system", id);
148         endcapNegativePhysVol.addPhysVolID("barrel", 2);
149         endcapNegativePhysVol.setZ(-zmin - thickness / 2);
150         Rotation negativeEndcapRotation = new Rotation(subdetectorName + "_negative_rotation");
151         lcdd.getDefine().addRotation(negativeEndcapRotation);
152         negativeEndcapRotation.setX(Math.PI);
153         endcapNegativePhysVol.setRotation(negativeEndcapRotation);
154         motherVolume.addPhysVol(endcapNegativePhysVol);
155     }
156 
157     public boolean isCalorimeter()
158     {
159         return true;
160     }
161 }