View Javadoc

1   package org.lcsim.geometry.compact.converter.lcdd;
2   
3   import static java.lang.Math.cos;
4   import static java.lang.Math.sin;
5   
6   import java.util.HashMap;
7   import java.util.Iterator;
8   import java.util.Map;
9   
10  import org.jdom.Element;
11  import org.jdom.JDOMException;
12  import org.lcsim.geometry.compact.converter.lcdd.util.Box;
13  import org.lcsim.geometry.compact.converter.lcdd.util.LCDD;
14  import org.lcsim.geometry.compact.converter.lcdd.util.Material;
15  import org.lcsim.geometry.compact.converter.lcdd.util.PhysVol;
16  import org.lcsim.geometry.compact.converter.lcdd.util.Position;
17  import org.lcsim.geometry.compact.converter.lcdd.util.Rotation;
18  import org.lcsim.geometry.compact.converter.lcdd.util.SensitiveDetector;
19  import org.lcsim.geometry.compact.converter.lcdd.util.Solids;
20  import org.lcsim.geometry.compact.converter.lcdd.util.Structure;
21  import org.lcsim.geometry.compact.converter.lcdd.util.Tube;
22  import org.lcsim.geometry.compact.converter.lcdd.util.VisAttributes;
23  import org.lcsim.geometry.compact.converter.lcdd.util.Volume;
24  
25  /**
26   * 
27   * Convert an SiTrackerBarrel subdetector to the LCDD format.
28   * 
29   * @author Jeremy McCormick <jeremym@slac.stanford.edu>
30   * @author Tim Nelson <tknelson@slac.stanford.edu>
31   *
32   */
33  public class SiTrackerBarrel extends LCDDSubdetector
34  {
35  	Map<String, Volume> modules = new HashMap<String, Volume>();
36  
37  	public SiTrackerBarrel(Element node) throws JDOMException
38  	{
39  		super(node);
40  	}
41  
42  	/**
43  	 * Build the LCDD for the subdetector.
44  	 * @param lcdd The LCDD file being created.
45  	 * @param sens The SD for this subdetector.
46  	 */
47  	public void addToLCDD(LCDD lcdd, SensitiveDetector sens) throws JDOMException
48  	{
49  		// ID of the detector.
50  		int id = this.node.getAttribute("id").getIntValue();
51  
52  		// Name of the detector.
53  		String detector_name = this.node.getAttributeValue("name");
54  
55  		// Get air from LCDD materials DB.
56  		Material air = lcdd.getMaterial("Air");
57  
58  		// Get solids collection from LCDD. 
59  		Solids solids = lcdd.getSolids();
60  
61  		// Get structure collection from LCDD.
62  		Structure structure = lcdd.getStructure();
63  
64  		// Pick the mother volume (tracking volume).
65  		Volume tracking_volume = lcdd.pickMotherVolume(this);
66  		
67  		VisAttributes vis = null;
68  		if (node.getAttribute("vis") != null)
69  		    vis = lcdd.getVisAttributes(node.getAttributeValue("vis"));
70  
71  		// Loop over the modules and put them into a map for lookup later.
72  		for (Iterator i = node.getChildren("module").iterator(); i.hasNext();)
73  		{
74  			Element module = (Element) i.next();
75  			String module_name = module.getAttributeValue("name");
76  			Volume module_envelope;
77  			try
78  			{
79  				module_envelope = buildModule(node, module_name, lcdd, sens, vis);
80  				modules.put(module_name, module_envelope);
81  			}
82  			catch (Exception x)
83  			{
84  				throw new RuntimeException(x);
85  			}
86  		}
87  
88  		// Build the layers.
89  		for (Iterator i = node.getChildren("layer").iterator(); i.hasNext();)
90  		{
91  			// Get the next layer element.
92  			Element layer_element = (Element) i.next();
93  			
94  			int layern = layer_element.getAttribute("id").getIntValue();
95  
96  			// Get the reference to the module from the layer.
97  			String module_name = layer_element.getAttributeValue("module");
98  
99  			// Get the logical volume for the module.
100 			Volume module_envelope = modules.get(module_name);
101 
102 			// Get the barrel_envelope for this layer.
103 			Element barrel_envelope = layer_element.getChild("barrel_envelope");
104 
105 			// Inner radius of layer.
106 			double ir = barrel_envelope.getAttribute("inner_r").getDoubleValue();
107 
108 			// Outer radius of layer.
109 			double or = barrel_envelope.getAttribute("outer_r").getDoubleValue();
110 
111 			// Full length in z of layer.
112 			double oz = barrel_envelope.getAttribute("z_length").getDoubleValue();
113 
114 			// Name of this layer including layer number.
115 			String layer_name = detector_name + "_layer" + layern;
116 
117 			//System.out.println("layer_name=" + layer_name);
118 
119 			// Create the layer tube solid.
120 			Tube layer_tube = new Tube(layer_name + "_tube");
121 			layer_tube.setRMin(ir);
122 			layer_tube.setRMax(or);
123 			layer_tube.setZ(oz);
124 			solids.addContent(layer_tube);
125 
126 			// Create the layer envelope volume.
127 			Volume layer_volume = new Volume(layer_name);
128 			layer_volume.setMaterial(air);
129 			layer_volume.setSolid(layer_tube);
130 
131 			// Get the rphi_layout element.
132 			Element rphi_layout = layer_element.getChild("rphi_layout");
133 
134 			// Starting phi of first module.
135 			double phi0 = rphi_layout.getAttribute("phi0").getDoubleValue();
136 
137 			// Number of modules in phi.
138 			int nphi = rphi_layout.getAttribute("nphi").getIntValue();
139 			assert (nphi > 0);
140 
141 			// Phi tilt of a module.
142 			double phi_tilt = rphi_layout.getAttribute("phi_tilt").getDoubleValue();
143 
144 			// Radius of the module center.
145 			double rc = rphi_layout.getAttribute("rc").getDoubleValue();
146 
147 			// The delta radius of every other module.
148 			double rphi_dr = 0.0;
149 			if (rphi_layout.getAttribute("dr") != null)
150 			{
151 				rphi_dr = rphi_layout.getAttribute("dr").getDoubleValue();
152 			}
153 
154 			// Phi increment for one module.
155 			double phi_incr = (Math.PI * 2) / nphi;
156 
157 			// Phi of the module center.
158 			double phic = 0;
159 			phic += phi0;
160 
161 			// Get the <z_layout> element.
162 			Element z_layout = layer_element.getChild("z_layout");
163 
164 			// Z position of first module in phi.
165 			double z0 = z_layout.getAttribute("z0").getDoubleValue();
166 
167 			// Number of modules to place in z.
168 			double nz = z_layout.getAttribute("nz").getIntValue();
169 			assert (nz > 0);
170 
171 			// Radial displacement parameter, of every other module.
172 			double z_dr = z_layout.getAttribute("dr").getDoubleValue();
173 
174 			// Z increment for module placement along Z axis.
175 			// Adjust for z0 at center of module rather than
176 			// the end of cylindrical envelope.
177 			double z_incr = (2.0 * z0) / (nz - 1);
178 
179 			// Starting z for module placement along Z axis.
180 			double module_z = -z0;
181 
182 			// DEBUG 
183 			//System.out.println("layer ir=" + ir);
184 			//System.out.println("layer or=" + or);
185 			//System.out.println("layer oz=" + oz);
186 			//System.out.println("phi_tilt=" + phi_tilt);
187 			//System.out.println("rc=" + rc);
188 			//System.out.println("phi0=" + phi0);
189 			//System.out.println("module z_incr=" + z_incr);
190 			//System.out.println("module z0=" + z0);
191 			//System.out.println("module nz=" + nz);
192 			//System.out.println("module dr=" + dr);
193 			//
194 
195 			//String module_lkp_name = layer.getAttributeValue("module");
196             
197             int module = 0;
198             
199 			// Loop over the number of modules in phi.
200 			for (int ii = 0; ii < nphi; ii++)
201 			{
202 				// Delta x of module position.
203 				double dx = z_dr * cos(phic + phi_tilt);
204 
205 				// Delta y of module position.
206 				double dy = z_dr * sin(phic + phi_tilt);
207 
208 				// Basic x module position.
209 				double x = rc * cos(phic);
210 
211 				// Basic y module position.
212 				double y = rc * sin(phic);
213 
214 				// Loop over the number of modules in z.
215 				for (int j = 0; j < nz; j++)
216 				{
217 					// Create a unique name for the module in this logical volume, layer, phi, and z.
218 					String module_place_name = detector_name + "_layer" + layern + "_phi" + ii + "_z" + j;
219 
220 					double z = module_z;
221 
222 					// DEBUG
223 					//System.out.println("module build...");
224 					//System.out.println("module nphi=" + ii);
225 					//System.out.println("module nz" + j);
226 					//System.out.println("module x=" + x);
227 					//System.out.println("module y=" + y);
228 					//System.out.println("module z=" + z);
229 					// DEBUG
230 
231 					// Position of module.
232 					Position module_position = new Position(module_place_name + "_position");
233 					module_position.setX(x);
234 					module_position.setY(y);
235 					module_position.setZ(z);
236 					lcdd.getDefine().addPosition(module_position);
237 
238 					// Rotation of module.
239 					Rotation module_rotation = new Rotation(module_place_name + "_rotation");
240 					double rotx = Math.PI / 2;
241 					double roty = -((Math.PI / 2) - phic - phi_tilt);
242 					double rotz = 0;
243 					module_rotation.setX(rotx);
244 					module_rotation.setY(roty);
245 					module_rotation.setZ(rotz);
246 					lcdd.getDefine().addRotation(module_rotation);
247 
248 					//System.out.println("module rotx=" + rotx);
249 					////System.out.println("module roty=" + roty);
250 					//System.out.println("module rotz=" + rotz);
251 
252 					// Module PhysicalVolume.
253 					PhysVol module_physvol = new PhysVol(module_envelope);
254 					module_physvol.setPosition(module_position);
255 					module_physvol.setRotation(module_rotation);
256 					//module_physvol.addPhysVolID("phi", ii);
257 					//module_physvol.addPhysVolID("z", j);
258                     module_physvol.addPhysVolID("module", module);
259                     ++module;
260 					layer_volume.addPhysVol(module_physvol);
261 
262 					// Adjust the x and y coordinates of the module.
263 					x += dx;
264 					y += dy;
265 
266 					// Flip sign of x and y adjustments.
267 					dx *= -1;
268 					dy *= -1;
269 
270 					// Add z increment to get next z placement pos.
271 					module_z += z_incr;
272 
273 					//System.out.println();
274 				}
275 
276 				// Increment the phi placement of module.
277 				phic += phi_incr;
278 
279 				// Increment the center radius according to dr parameter.
280 				rc += rphi_dr;
281 
282 				// Flip sign of dr parameter.
283 				rphi_dr *= -1;
284 
285 				// Reset the Z placement parameter for module.
286 				module_z = -z0;
287 			}
288 
289             setRegion(lcdd, layer_element, layer_volume);
290             setLimitSet(lcdd, layer_element, layer_volume);
291 			//setVisAttributes(lcdd, layer_element, layer_volume);
292             
293 			// Set the layer envelope to invisible to help Geant4 visualization.
294 			//if (layer_element.getAttribute("vis") == null)
295 			//{
296 			//	if (lcdd.getVisAttributes("InvisibleWithDaughters") != null)
297 			//	{
298 			//		layer_volume.setVisAttributes(lcdd.getVisAttributes("InvisibleWithDaughters"));
299 			//	}
300 			//}
301             
302 			// Add the layer volume to LCDD.
303 			structure.addVolume(layer_volume);
304 
305 			// Create the PhysicalVolume for the layer.
306 			PhysVol layer_envelope_physvol = new PhysVol(layer_volume);
307 
308 			// Set the subdetector system ID.
309 			layer_envelope_physvol.addPhysVolID("system", id);
310 
311 			// Flag this as a barrel subdetector.
312 			layer_envelope_physvol.addPhysVolID("barrel", 0);
313 
314 			// Set the layer ID.
315 			layer_envelope_physvol.addPhysVolID("layer", layern);
316 
317 			// Put the layer into the mother volume.
318 			tracking_volume.addPhysVol(layer_envelope_physvol);
319 		}
320 	}
321 
322 	/**
323 	 * Build a module logical volume.
324 	 * @param detector The detector XML node.
325 	 * @param name The name of the module for lookup.
326 	 * @param lcdd The LCDD being processed.
327 	 * @return
328 	 * @throws Exception
329 	 */
330 	Volume buildModule(Element detector, String name, LCDD lcdd, SensitiveDetector sens, VisAttributes vis) throws Exception
331 	{
332 		String detector_name = detector.getAttributeValue("name");
333 		Volume module_volume = null;
334 
335 		int sensor_number = 0;
336 
337 		VisAttributes visOff = lcdd.getVisAttributes("InvisibleNoDaughters");
338 		
339 		// Search for module.
340 		for (Iterator i = detector.getChildren("module").iterator(); i.hasNext();)
341 		{
342 			Element module_element = (Element) i.next();
343 
344 			if (module_element.getAttributeValue("name").compareTo(name) == 0)
345 			{
346 				Element module_envelope_element = module_element.getChild("module_envelope");
347 
348 				String module_name = detector_name + "_" + module_element.getAttributeValue("name");
349 
350 				// Create the module box.
351 				double module_length = module_envelope_element.getAttribute("length").getDoubleValue();
352 				double module_width = module_envelope_element.getAttribute("width").getDoubleValue();
353 				double module_thickness = module_envelope_element.getAttribute("thickness").getDoubleValue();
354 				Box module_box = new Box(module_name + "_box");
355 				module_box.setX(module_width);
356 				module_box.setY(module_length);
357 				module_box.setZ(module_thickness);
358 				lcdd.getSolids().addSolid(module_box);
359 
360 				// Create the module logical volume.
361 				module_volume = new Volume(module_name);
362 				module_volume.setMaterial(lcdd.getMaterial("Air"));
363 				module_volume.setSolid(module_box);
364 
365 				// Build module components.
366 				int ncomponents = 0;
367 				for (Iterator j = module_element.getChildren("module_component").iterator(); j.hasNext(); ++ncomponents)
368 				{
369 					Element component_element = (Element) j.next();
370 
371 					boolean sensitive = ((component_element.getAttribute("sensitive") == null) ? false : component_element.getAttribute("sensitive").getBooleanValue());
372 
373 					String component_name = module_name + "_component" + ncomponents;
374 
375 					// DEBUG
376 					//System.out.println("component_name=" + component_name);
377 					//System.out.println("build component="+ncomponents);
378 					//
379 
380 					// Create the box solid for the module component.
381 					double component_length = component_element.getAttribute("length").getDoubleValue();
382 					double component_width = component_element.getAttribute("width").getDoubleValue();
383 					double component_thickness = component_element.getAttribute("thickness").getDoubleValue();
384 					Box component_box = new Box(component_name + "_box");
385 					component_box.setX(component_width);
386 					component_box.setY(component_length);
387 					component_box.setZ(component_thickness);
388 					lcdd.getSolids().addSolid(component_box);
389 
390 					// Create the volume for the module component.
391 					Volume component_volume = new Volume(component_name);
392 					Material component_material = lcdd.getMaterial(component_element.getAttributeValue("material"));
393 					component_volume.setMaterial(component_material);
394 					component_volume.setSolid(component_box);
395 						
396 					lcdd.getStructure().addVolume(component_volume);                    
397                     
398 					PhysVol component_physvol = new PhysVol(component_volume);
399 
400 					// Set component position.
401 					// FIXME: Processing of positions should be generalized in compact description.					
402 					if (component_element.getChild("position") != null)
403 					{
404 						Element pos_elem = component_element.getChild("position");
405 
406 						Position component_position = new Position(component_name + "_position");
407 
408 						if (pos_elem.getAttribute("x") != null)
409 						{
410 							component_position.setX(pos_elem.getAttribute("x").getDoubleValue());
411 						}
412 
413 						if (pos_elem.getAttribute("y") != null)
414 						{
415 							component_position.setY(pos_elem.getAttribute("y").getDoubleValue());
416 						}
417 
418 						if (pos_elem.getAttribute("z") != null)
419 						{
420 							component_position.setZ(pos_elem.getAttribute("z").getDoubleValue());
421 						}
422 
423 						lcdd.getDefine().addPosition(component_position);
424 						component_physvol.setPosition(component_position);
425 					}
426 
427 					// Set component rotation.
428 					// FIXME: Processing of rotations should be generalized in compact description.
429 					if (component_element.getChild("rotation") != null)
430 					{
431 						Element rot_elem = component_element.getChild("rotation");
432 
433 						Rotation component_rotation = new Rotation(component_name + "_rotation");
434 
435 						if (rot_elem.getAttribute("x") != null)
436 						{
437 							component_rotation.setX(rot_elem.getAttribute("x").getDoubleValue());
438 						}
439 
440 						if (rot_elem.getAttribute("y") != null)
441 						{
442 							component_rotation.setY(rot_elem.getAttribute("y").getDoubleValue());
443 						}
444 
445 						if (rot_elem.getAttribute("z") != null)
446 						{
447 							component_rotation.setZ(rot_elem.getAttribute("z").getDoubleValue());
448 						}
449 
450 						component_physvol.setRotation(component_rotation);
451 
452 						lcdd.getDefine().addRotation(component_rotation);
453 					}
454 
455 					if (sensitive)
456 					{
457 						component_volume.setSensitiveDetector(sens);
458 						component_physvol.addPhysVolID("sensor", sensor_number);
459 						++sensor_number;
460 					}
461                     
462                     setRegion(lcdd, component_element, component_volume);
463                     setLimitSet(lcdd, component_element, component_volume);
464                     //setVisAttributes(lcdd, component_element, component_volume);
465                     component_volume.setVisAttributes(visOff);
466 
467 					module_volume.addPhysVol(component_physvol);
468 				}
469 				//setVisAttributes(lcdd, module_element, module_volume);
470 				if (vis != null)
471 				    module_volume.setVisAttributes(vis);
472 				break;
473 			}
474 		}
475 
476 		if (module_volume == null)
477 		{
478 			throw new RuntimeException("Failed to find module " + name);
479 		}
480         
481 		// Add module logical volume to LCDD.
482 		lcdd.getStructure().addVolume(module_volume);
483 
484 		return module_volume;
485 	}
486 
487 	public boolean isTracker()
488 	{
489 		return true;
490 	}
491 }