GeomConverter/sandbox
diff -N HPSMuonCalorimeter.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ HPSMuonCalorimeter.java 4 Dec 2012 01:11:54 -0000 1.1
@@ -0,0 +1,226 @@
+package org.lcsim.geometry.compact.converter.lcdd;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.StringTokenizer;
+
+import org.jdom.Element;
+import org.jdom.JDOMException;
+import org.lcsim.geometry.compact.converter.lcdd.util.Box;
+import org.lcsim.geometry.compact.converter.lcdd.util.LCDD;
+import org.lcsim.geometry.compact.converter.lcdd.util.Material;
+import org.lcsim.geometry.compact.converter.lcdd.util.PhysVol;
+import org.lcsim.geometry.compact.converter.lcdd.util.Position;
+import org.lcsim.geometry.compact.converter.lcdd.util.Rotation;
+import org.lcsim.geometry.compact.converter.lcdd.util.SensitiveDetector;
+import org.lcsim.geometry.compact.converter.lcdd.util.Trap;
+import org.lcsim.geometry.compact.converter.lcdd.util.Volume;
+
+/**
+ *
+ * To build:
+ *
+ * cd GeomConverter
+ * mvn clean install -DskipTests=true
+ *
+ * To generate LCDD from test geometry:
+ *
+ * java -jar ./target/GeomConverter-2.5-SNAPSHOT-bin.jar -o lcdd ./testResources/org/lcsim/geometry/subdetector/HPSMuonCalorimeterTest.xml ./HPSMuonCalorimeterTest.lcdd
+ *
+ * Parameters (initially from python):
+ *
+ * vertseg_gap <= vertical gaps between hodoscopes e.g. scintillator strips
+ * vertseg_num <= number of readout strips in first layer
+ * vertseg_size <= vertical dimension of strip
+ * from_target <= distance from front face to target
+ * absorber_layers <= how many absorber layers?
+ * absorber_thicknesses <= thickness of each absorber layer
+ * gaps <= horizontal gap between each strips and absorber
+ * sensor_thickness <= thickness of absorber
+ * theta1 <= fan out angle in y of the vacuum box (?)
+ * absorber_width <= 1st layer absorber width
+ * fan_out <= make absorbers all the same width or fan them out as depth increases
+ * connecting_width <= when fan_out is false then set how far in the connecting iron piece goes (?)
+ * theta4 <= fan out angle
+ * alum_plate_width <= width of the aluminum plate
+ * alum_side_width <= width of the side wall of the vacuum system
+ * alum_airgap <= gap between alum plate and iron chunks
+ * al_extra[1-3] <= see diagram (???)
+ * vac_pullz <= how far to extend the vacuum (-z) towards ecal
+ * vac_pushz <= how far to extend the vacuum (+z) beyond muon detector
+ *
+ * Example XML:
+ * <parameters vertseg_gap="0.01*cm" vertseg_num="8" vertseg_size="3.0*cm" from_target="185.0*cm" gap="0.2*cm"
+ * sensor_thickness="1.0*cm" theta1="0.025" absorber_width="50.0*cm" fan_out="true"
+ * connecting_width="40.0*cm" theta4="0.0873" />
+ * <absorber_thicknesses>68.0 68.0 68.0 68.0 150.0 150.0 150.0</absorber_thicknesses>
+ * <vacuum alum_plate_width="1.0*cm" alum_side_width="1.0*cm" alum_airgap="0.01*cm" al_extra1="35.0*cm"
+ * al_extra2="20.0*cm" al_extra3="5.0*cm" />
+ *
+ * @author jeremym
+ * @version $Id: HPSMuonCalorimeter.java,v 1.1 2012/12/04 01:11:54 jeremy Exp $
+ */
+public class HPSMuonCalorimeter extends LCDDSubdetector {
+
+ HPSMuonCalorimeter(Element node) throws JDOMException {
+ super(node);
+ }
+
+ void addToLCDD(LCDD lcdd, SensitiveDetector sens) throws JDOMException {
+
+ String name = node.getAttributeValue("name");
+ int id = node.getAttribute("id").getIntValue();
+
+ // Get muon calorimeter parameters.
+ Element parameters = node.getChild("parameters");
+ double vertseg_gap = parameters.getAttribute("vertseg_gap").getDoubleValue();
+ int vertseg_num = parameters.getAttribute("vertseg_num").getIntValue();
+ double vertseg_size = parameters.getAttribute("vertseg_size").getDoubleValue();
+ double from_target = parameters.getAttribute("from_target").getDoubleValue();
+ double gap = parameters.getAttribute("gap").getDoubleValue();
+ double sensor_thickness = parameters.getAttribute("sensor_thickness").getDoubleValue();
+ double theta1 = parameters.getAttribute("theta1").getDoubleValue();
+ double absorber_width = parameters.getAttribute("absorber_width").getDoubleValue();
+ boolean fan_out = parameters.getAttribute("fan_out").getBooleanValue();
+ double connecting_width = parameters.getAttribute("connecting_width").getDoubleValue();
+ double theta4 = parameters.getAttribute("theta4").getDoubleValue();
+
+ // Get the absorber thicknesses. These are hard-coded to be in mm because I don't know
+ // how to convert the array on the fly to arbitrary units.
+ String s = node.getChild("absorber_thicknesses").getText();
+ StringTokenizer st = new StringTokenizer(s);
+ List<Double> depth = new ArrayList<Double>();
+ while (st.hasMoreElements()) {
+ depth.add(Double.parseDouble((String)st.nextElement()));
+ }
+
+ // Get vacuum box parameters.
+ Element vacuum = node.getChild("vacuum");
+ double alum_plate_width = vacuum.getAttribute("alum_plate_width").getDoubleValue();
+ double alum_side_width = vacuum.getAttribute("alum_side_width").getDoubleValue();
+ double alum_airgap = vacuum.getAttribute("alum_airgap").getDoubleValue();
+ double al_extra1 = vacuum.getAttribute("al_extra1").getDoubleValue();
+ double al_extra2 = vacuum.getAttribute("al_extra2").getDoubleValue();
+ double al_extra3 = vacuum.getAttribute("al_extra3").getDoubleValue();
+
+ // Computed values.
+ int nabsorbers = depth.size();
+ double absorber_total_depth = 0.;
+ for (Double a : depth) {
+ absorber_total_depth += a;
+ }
+ double gaps_total_depth = (nabsorbers)*gap;
+
+ //System.out.println("absorber_total_depth="+absorber_total_depth);
+ //System.out.println("gaps_total_depth="+gaps_total_depth);
+
+ // Total detector depth.
+ double md_depth = absorber_total_depth + 2*gaps_total_depth - gap + nabsorbers*sensor_thickness;
+ //System.out.println("md_depth="+md_depth);
+
+ // Z position of muon detector.
+ double vac_pullz = al_extra3;
+ double vac_pushz = al_extra1;
+ double muon_box_z = from_target + 0.5*md_depth - 0.5*Math.max(vac_pullz, al_extra3) + 0.5*Math.max(vac_pushz,al_extra1);
+
+ //System.out.println("muon_box_z = " + muon_box_z);
+
+ double md_mid = from_target - muon_box_z + 0.5*md_depth;
+ //System.out.println("muon_mid = " + md_mid);
+
+ double z = from_target - muon_box_z + depth.get(0)/2;
+ //System.out.println("z="+z);
+
+ double theta2 = Math.atan( (vertseg_num*vertseg_size+(vertseg_num-1)*vertseg_gap+(from_target+depth.get(0)+gap)*Math.tan(theta1) )/ (from_target+depth.get(0)+gap));
+ double theta3 = Math.atan(absorber_width/(from_target));
+ double theta = 0.5*(theta1+theta2);
+
+ //System.out.println("theta2="+theta2);
+ //System.out.println("theta3="+theta3);
+ //System.out.println("theta="+theta);
+
+ double tt1 = Math.tan(theta1);
+ double tt2 = Math.tan(theta2);
+ //System.out.println("theta3="+theta3);
+ double tt3 = Math.tan(theta3);
+ double tt4 = Math.tan(theta4);
+ double tt34 = Math.tan( (theta3+theta4)/2 );
+ double tt = Math.tan(theta);
+
+ // Place crystals in world volume.
+ Volume world = lcdd.pickMotherVolume(this);
+
+ // Position of mother volume in the world.
+ Position md_pos = new Position(name + "_pos", 0, 0, muon_box_z);
+ lcdd.add(md_pos);
+
+ // Compute dimensions of mother box.
+ double md_x, md_y, md_z;
+ double spacing = 20.;
+ //System.out.println("tt3="+tt3);
+ //System.out.println("md_x1="+((from_target+md_depth+al_extra1)*tt3+al_extra2));
+ //System.out.println("md_x2="+(from_target+md_depth+vac_pushz)*tt3);
+ md_x = Math.max((from_target+md_depth+al_extra1)*tt3+al_extra2,(from_target+md_depth+vac_pushz)*tt3)+spacing;
+ md_y = (from_target+md_depth)*tt2+spacing;
+ md_z = .5*md_depth+.5*Math.max(al_extra1,vac_pushz)+.5*Math.max(al_extra3,vac_pullz);
+
+ //System.out.println("md_x = " + md_x);
+ //System.out.println("md_y = " + md_y);
+ //System.out.println("md_z = " + md_z);
+
+ // Create mother box.
+ Box muonBox = new Box(name + "_box", md_x*2, md_y*2, md_z*2);
+ lcdd.add(muonBox);
+
+ Material air = lcdd.getMaterial("Air");
+
+ Volume md_vol = new Volume(name + "_vol", muonBox, air);
+
+ Material iron = lcdd.getMaterial("Iron");
+
+ Rotation rot = new Rotation(name+"_absorber_rot", 0, 0, Math.PI/2);
+ lcdd.add(rot);
+ for (int i=0; i<nabsorbers; i++) {
+
+ double gz = z + muon_box_z;
+ //System.out.println("gz="+gz);
+
+ String base_name = name + "_layer" + i;
+ String abs_base_name = base_name + "_abs_";
+
+ Position top_pos = new Position(abs_base_name+"top_pos", 0, gz*tt, z);
+ lcdd.add(top_pos);
+
+ Trap abs_top_trap = new Trap(abs_base_name+"top_trap",
+ .5*depth.get(i),
+ -theta,
+ 0.,
+ ((gz-depth.get(i)/2)*tt3),
+ .5*(gz-depth.get(i)/2)*(tt2-tt1),
+ .5*(gz-depth.get(i)/2)*(tt2-tt1),
+ 0.,
+ ((gz+depth.get(i)/2)*tt3),
+ .5*(gz+depth.get(i)/2)*(tt2-tt1),
+ .5*(gz+depth.get(i)/2)*(tt2-tt1),
+ 0);
+ lcdd.add(abs_top_trap);
+ Volume abs_top_vol = new Volume(abs_base_name+"vol", abs_top_trap, iron);
+ lcdd.add(abs_top_vol);
+ PhysVol abs_top_pv = new PhysVol(abs_top_vol, md_vol, top_pos, rot);
+
+ // CONTINUE CODING HERE
+
+ if (i != (nabsorbers - 1))
+ z = z + .5*depth.get(i)+.5*depth.get(i+1)+2*gap+sensor_thickness;
+ } // nabsorbers loop
+
+ lcdd.add(md_vol);
+ Rotation md_rot = new Rotation(name + "_rot");
+ lcdd.add(md_rot);
+ PhysVol md_pv = new PhysVol(md_vol, world, md_pos, md_rot);
+ }
+
+ public boolean isCalorimeter() {
+ return true;
+ }
+}
\ No newline at end of file