View Javadoc

1   package org.lcsim.geometry.compact.converter.lcdd;
2   
3   import java.util.ArrayList;
4   
5   import org.jdom.Element;
6   import org.jdom.JDOMException;
7   import org.lcsim.geometry.compact.converter.lcdd.util.LCDD;
8   import org.lcsim.geometry.compact.converter.lcdd.util.Material;
9   import org.lcsim.geometry.compact.converter.lcdd.util.PhysVol;
10  import org.lcsim.geometry.compact.converter.lcdd.util.Polyhedra;
11  import org.lcsim.geometry.compact.converter.lcdd.util.Rotation;
12  import org.lcsim.geometry.compact.converter.lcdd.util.SensitiveDetector;
13  import org.lcsim.geometry.compact.converter.lcdd.util.Solids;
14  import org.lcsim.geometry.compact.converter.lcdd.util.Structure;
15  import org.lcsim.geometry.compact.converter.lcdd.util.Volume;
16  import org.lcsim.geometry.compact.converter.lcdd.util.ZPlane;
17  import org.lcsim.geometry.layer.LayerSlice;
18  import org.lcsim.geometry.layer.LayerStack;
19  import org.lcsim.geometry.layer.Layering;
20  
21  /**
22   * This class implements the LCDD binding for a calorimeter with a cone hollow section,
23   * e.g. for Muon Collider calorimeter designs.
24   */
25  public class PolyhedraEndcapCalorimeter3 extends LCDDSubdetector
26  {
27      public PolyhedraEndcapCalorimeter3(Element node) throws JDOMException
28      {
29          super(node);
30          this.node = node;
31      }
32  
33      public void addToLCDD(LCDD lcdd, SensitiveDetector sens) throws JDOMException
34      {    	
35      	// Get important references from LCDD.
36          Solids solids = lcdd.getSolids();
37          Structure structure = lcdd.getStructure();
38          Volume motherVolume = lcdd.pickMotherVolume(this);
39          Material air = lcdd.getMaterial("Air");
40          
41          // Get subdetector name and id.
42          String subdetectorName = node.getAttributeValue("name");
43          int id = node.getAttribute("id").getIntValue();        
44          
45          // Get the basic parameters from the XML.
46          Element dimensions = node.getChild("dimensions");
47          int numsides = dimensions.getAttribute("numsides").getIntValue();
48          double zmin = dimensions.getAttribute("zmin").getDoubleValue();
49          double rmin = dimensions.getAttribute("rmin").getDoubleValue();
50          double rmax = dimensions.getAttribute("rmax").getDoubleValue();
51          rmax = rmax*Math.cos(Math.PI/numsides); // Compute G4 rmax from dimension value.
52          double innerAngle = dimensions.getAttribute("angle").getDoubleValue();
53          
54          // Make layering to get thickness.
55          LayerStack layers = Layering.makeLayering(this.node).getLayerStack();
56          
57          // Get thickness of calorimeter in z dimension determined by layering.
58          double thickness = layers.getTotalThickness();
59                           
60          // Compute radius at last zplane of envelope.
61          double rmax2 = rmin + thickness * Math.tan(innerAngle);               
62          
63          // Setup envelope volume so that rmin increases along +z.
64          ArrayList<ZPlane> zplanes = new ArrayList<ZPlane>();
65          ZPlane frontZPlane = new ZPlane(rmin, rmax, -thickness/2);
66          ZPlane backZPlane = new ZPlane(rmax2, rmax, thickness/2);
67          zplanes.add(frontZPlane);
68          zplanes.add(backZPlane);
69          Polyhedra envelopePolyhedra = new Polyhedra(
70                  subdetectorName + "_envelope_polyhedra",
71                  numsides,
72                  zplanes);        
73          solids.addSolid(envelopePolyhedra);
74          
75          // Make the calorimeter envelope volume.
76          Volume envelopeVolume = new Volume(subdetectorName + "_volume", envelopePolyhedra, air);        
77          
78          // Compute z rotation for envelope with flat side down.        
79          double moduleInnerAngle = (Math.PI * 2) / numsides;
80          double leftover = (Math.PI / 2) % moduleInnerAngle;
81          double zrot = moduleInnerAngle / 2 - leftover;
82                  
83          // Set the z coordinate of the layer front face for layer loop.
84          double layerZ = -thickness/2;
85          
86          // The rmin of the layer which will decrease along z.
87          double layerRmin = rmin;
88                          
89          // Loop over and build the layers into the detector envelope.
90          for (int i=0, l=layers.getNumberOfLayers(); i<l; i++)
91          {                                   
92              // Get this layer's thickness.
93              double layerThickness = layers.getLayer(i).getThickness();
94              
95              // Compute change in layer inner radius.
96              double layerdy = Math.tan(innerAngle) * layerThickness;
97              
98              // Add dx to inner radius.
99              layerRmin += layerdy;
100                                                                            
101             // Make the layer's polyhedra.
102             ArrayList<ZPlane> layerZplanes = new ArrayList<ZPlane>();
103             ZPlane layerFrontZPlane = new ZPlane(layerRmin, rmax, -layerThickness/2);
104             ZPlane layerBackZPlane = new ZPlane(layerRmin, rmax, layerThickness/2);
105             layerZplanes.add(layerFrontZPlane);
106             layerZplanes.add(layerBackZPlane);
107             Polyhedra layerPolyhedra = new Polyhedra(
108                     subdetectorName + "_layer" + i + "_polyhedra",
109                     numsides,
110                     layerZplanes);
111             
112             // Add layer volume to solids.
113             solids.addContent(layerPolyhedra);
114             
115             // Make layer volume.            
116             Volume layerVolume = 
117                 new Volume(subdetectorName + "_layer" + i + "_volume", layerPolyhedra, air);                     
118             
119             // Build slices into the layer volume.
120             double sliceZ = -layerThickness/2;
121             int sliceCount = 0;
122             for (LayerSlice slice : layers.getLayer(i).getSlices())
123             {                
124             	// Get the slice's thickness.
125             	double sliceThickness = slice.getThickness();
126             	
127             	// Make the slice's polyhedra shape.
128             	ArrayList<ZPlane> sliceZplanes = new ArrayList<ZPlane>();
129             	ZPlane sliceFrontZPlane = new ZPlane(layerRmin, rmax, -sliceThickness/2);
130             	ZPlane sliceBackZPlane = new ZPlane(layerRmin, rmax, sliceThickness/2);
131             	sliceZplanes.add(sliceFrontZPlane);
132             	sliceZplanes.add(sliceBackZPlane);
133             	Polyhedra slicePolyhedra = new Polyhedra(
134             			subdetectorName + "_layer" + i + "_slice" + sliceCount + "_polyhedra",
135             			numsides,
136             			sliceZplanes
137             			);
138             	
139             	// Add slice volume to solids.
140             	solids.addContent(slicePolyhedra);
141             	
142             	// Make slice volume.
143             	Volume sliceVolume = 
144             		new Volume(
145             				subdetectorName + "_layer" + i + "_slice" + sliceCount + "_volume",
146             				slicePolyhedra,
147             				lcdd.getMaterial(slice.getMaterial().getName()));
148             	structure.addContent(sliceVolume);
149             	
150             	// Set slice volume's sensitive detector.
151             	if (slice.isSensitive())
152             		sliceVolume.setSensitiveDetector(sens);
153             	
154             	// Make slice physical volume.
155             	PhysVol slicePhysVol = new PhysVol(sliceVolume);
156             	slicePhysVol.setZ(sliceZ + sliceThickness/2);
157             	slicePhysVol.addPhysVolID("slice", sliceCount);
158             	
159             	// Add slice physical volume to layer.
160             	layerVolume.addPhysVol(slicePhysVol);
161             	
162             	// Increment slice count.
163             	++sliceCount;
164             	
165             	// Add thickness to get Z for next slice.
166             	sliceZ += sliceThickness;
167             }                                    
168             
169             // Add layer volume after slices are built.
170             structure.addVolume(layerVolume);
171             
172             // Make layer placement into envelope.
173             PhysVol layerPhysVol = new PhysVol(layerVolume);
174             layerPhysVol.addPhysVolID("layer", i);
175             layerPhysVol.setZ(layerZ + layerThickness/2);
176             envelopeVolume.addPhysVol(layerPhysVol);              
177             
178             // Set z to edge of next layer.
179             layerZ += layerThickness;
180         }
181         
182         // Add envelope's logical volume to structure.
183         structure.addVolume(envelopeVolume);
184         
185         // Make rotation for positive endcap.
186         Rotation positiveEndcapRotation = new Rotation(subdetectorName + "_positive");
187         positiveEndcapRotation.setZ(zrot);
188         lcdd.getDefine().addRotation(positiveEndcapRotation);        
189                 
190         // Positive endcap placement.
191         PhysVol endcapPositivePhysVol = new PhysVol(envelopeVolume);
192         endcapPositivePhysVol.setZ(zmin + thickness/2);
193         endcapPositivePhysVol.addPhysVolID("system",id);
194         endcapPositivePhysVol.addPhysVolID("barrel",1);                     
195         endcapPositivePhysVol.setRotation(positiveEndcapRotation);                       
196         motherVolume.addPhysVol(endcapPositivePhysVol);
197         
198         // Make rotation for negative endcap.        
199         Rotation negativeEndcapRotation = new Rotation(subdetectorName + "_negative");
200         negativeEndcapRotation.setZ(zrot);
201         negativeEndcapRotation.setY(Math.PI);
202         lcdd.getDefine().addRotation(negativeEndcapRotation);
203         
204         // Negative endcap placement.
205         PhysVol endcapNegativePhysVol = new PhysVol(envelopeVolume);
206         endcapNegativePhysVol.setZ(-zmin - thickness/2);
207         endcapNegativePhysVol.addPhysVolID("system",id);
208         endcapNegativePhysVol.addPhysVolID("barrel",2);                     
209         endcapNegativePhysVol.setRotation(negativeEndcapRotation);                       
210         motherVolume.addPhysVol(endcapNegativePhysVol);               
211     }   
212     
213     public boolean isCalorimeter()
214     {
215     	return true;
216     }
217 }