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