Print

Print


Commit in GeomConverter/src/org/lcsim/geometry/compact/converter/lcdd on MAIN
HPSEcal3.java+268added 1.1
work in progress on new HPS Ecal converter

GeomConverter/src/org/lcsim/geometry/compact/converter/lcdd
HPSEcal3.java added at 1.1
diff -N HPSEcal3.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ HPSEcal3.java	24 Aug 2011 22:10:16 -0000	1.1
@@ -0,0 +1,268 @@
+package org.lcsim.geometry.compact.converter.lcdd;
+
+import static java.lang.Math.atan;
+import static java.lang.Math.cos;
+import static java.lang.Math.sin;
+import static java.lang.Math.tan;
+
+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.Define;
+import org.lcsim.geometry.compact.converter.lcdd.util.LCDD;
+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.Trapezoid;
+import org.lcsim.geometry.compact.converter.lcdd.util.Volume;
+
+/**
+ * LCDD model for the HPS inner ECal.
+ * 
+ * Coordinate System Notes:
+ * 
+ * Beam travels in +X direction.
+ * Magnetic field is -Z.
+ * Y is the beam bend plane.
+ * 
+ * The dimensions element defines the crystal HALF dimensions: x1, x2, y1, y2, and z.
+ * 
+ * The layout element defines the placement of the crystals.
+ * 
+ * <ul>
+ * <li>beamgap - offset from the beamline in the Y coordinate</li>
+ * <li>nx - number of crystals in X</li>
+ * <li>ny - number of crystals in Y along each side of beam</li>
+ * <li>dface - distance from origin to the face of the calorimeter along X</li>
+ * </ul>
+ * 
+ * @author Jeremy McCormick
+ * @author Tim Nelson
+ * 
+ * @version $Id: HPSEcal3.java,v 1.1 2011/08/24 22:10:16 jeremy Exp $
+ */
+public class HPSEcal3 extends LCDDSubdetector
+{
+    // Tolerance factor for moving crystals to appropriate place in mom volume.
+    static final double tolerance = 0.1;
+    
+    // Tolerance factor for separating crystals to avoid overlaps.
+    static final double crystalTolerance = 0.1;
+    
+    // Margin for mother volume.
+    static final double margin = 1.1;
+    
+    HPSEcal3(Element node) throws JDOMException
+    {
+        super(node); 
+    }
+    
+    void addToLCDD(LCDD lcdd, SensitiveDetector sens) throws JDOMException
+    {
+        if (sens == null)
+            throw new RuntimeException("SensitiveDetector is null!");
+        
+        // Crystal dimensions.
+        Element dimensions = node.getChild("dimensions");
+        double dx1 = dimensions.getAttribute("x1").getDoubleValue();
+        double dx2 = dimensions.getAttribute("x2").getDoubleValue();
+        double dy1 = dimensions.getAttribute("y1").getDoubleValue();
+        double dy2 = dimensions.getAttribute("y2").getDoubleValue();
+        double dz = dimensions.getAttribute("z").getDoubleValue();
+                
+        // Crystal material.
+        Element mat = node.getChild("material");
+        String materialName = mat.getAttributeValue("name");
+        
+        // Layout parameters.
+        Element layout = node.getChild("layout");
+        double beamgap = layout.getAttribute("beamgap").getDoubleValue();
+        int nx = layout.getAttribute("nx").getIntValue();
+        int ny = layout.getAttribute("ny").getIntValue();
+        double dface = layout.getAttribute("dface").getDoubleValue();
+                
+        // Setup crystal logical volume.
+        Trapezoid crystalTrap = new Trapezoid("crystal_trap", dx1, dx2, dy1, dy2, dz);
+        Volume crystalLogVol = new Volume("crystal_volume", crystalTrap, lcdd.getMaterial(materialName));
+        crystalLogVol.setSensitiveDetector(sens);
+        
+        lcdd.add(crystalTrap);
+        lcdd.add(crystalLogVol);
+                      
+        // Mother volume dimensions.
+        double mx, my, mz;
+        mx = nx*Math.max(dx2, dx1)*margin;
+        my = ny*Math.max(dy2, dy1)*margin;
+        my *= 2;
+        my += beamgap;
+        mz = dz*margin;
+        
+        // Get mother volume for envelope.
+        Volume world = lcdd.pickMotherVolume(this);
+
+        // Envelope box and logical volume for one section of ECal.
+        Box momBox = new Box("ecal_env_box", mx*2, my*2, mz*2);
+        Volume momVol = new Volume("ecal_env_volume", momBox, lcdd.getMaterial("Air"));       
+        
+        lcdd.add(momBox);
+        lcdd.add(momVol);
+        
+        // Slope of the trapezoid side in X.
+        double sx = (dx2-dx1)/(2*dz);
+        
+        // Angle of the side of the trapezoid w.r.t. center line in X.  Rotation about Y axis.
+        double dthetay = atan(sx);        
+        
+        // Slope of the trapezoid side in Y.
+        double sy = (dy2-dy1)/(2*dz);      
+        
+        // Angle of the side of the trapezoid w.r.t. center line in Y.  Rotation about X axis.        
+        double dthetax = atan(sx);
+        
+        // Distance between (virtual) angular origin and center of trapezoid in X.
+        double z0x = dx1/sx+dz;
+        
+        // Distance between (virtual) angular origin and center of trapezoid in Y.
+        double z0y = dy1/sy+dz;
+                
+        // Odd or even number of crystals in X.
+        boolean oddx = (nx % 2 != 0);
+        
+        // Calculate number of X for loop.
+        if (oddx)
+        {
+            nx -= 1;
+            nx /= 2;
+        }
+        else
+        {
+            nx /= 2;
+        }
+
+        double ycorrtot = 0;
+        double zcorrtoty = 0;
+        
+        Define define = lcdd.getDefine();
+
+        for (int iy=1; iy<=ny; iy++)
+        {
+            double zcorrtotx = 0;
+            double xcorrtot = 0;
+            
+            int coeffy = 2*iy-1;
+            double thetax = coeffy*dthetax;
+            double zcorry = dy1*(2*sin(coeffy*dthetax));
+            double ycorr = zcorry*tan((coeffy-1)*dthetax);
+            double ycenter = z0y*sin(coeffy*dthetax)+ycorr+ycorrtot+(crystalTolerance*iy);
+            
+            for (int ix=0; ix<=nx; ix++)
+            {                             
+                // Coefficient for even/odd crystal
+                int coeffx = 2*ix;
+                if (!oddx)
+                {
+                    coeffx -= 1;
+                    // For even number of crystals, the 0th is skipped.
+                    if (ix==0)
+                        continue;
+                }
+                
+                // Set parameters for next crystal placement.
+                // FIXME Need documentation here.
+                double thetay = coeffx*dthetay;
+                double zcorrx = dx1*(2*sin(coeffx*dthetay));
+                double xcorr = zcorrx*tan((coeffx-1)*dthetay);
+                double xcenter = z0x*sin(coeffx*dthetay)+xcorr+xcorrtot+(crystalTolerance*ix);
+                double zcenter = z0y*(cos(coeffy*dthetax)-1)+z0x*(cos(coeffx*dthetay)-1)+zcorrx+zcorrtotx+zcorry+zcorrtoty;
+                zcenter += dz;
+                                
+                double thetaz = 0;
+                                
+                String baseName = "crystal"+ix+"-"+iy;
+                
+                // Transform of positive.
+                Position ipos = 
+                    new Position(baseName+"_pos_pos", xcenter, -(beamgap+ycenter+tolerance), zcenter+tolerance+dface);
+                Rotation irot = 
+                    new Rotation(baseName+"_rot_pos", -thetax, -thetay, thetaz);
+
+                define.addPosition(ipos);
+                define.addRotation(irot);            
+
+                // Place positive crystal.
+                PhysVol posCrystalPlacement = new PhysVol(crystalLogVol, world, ipos, irot);
+                
+                // Add volume IDs.
+                posCrystalPlacement.addPhysVolID("ix", ix);
+                posCrystalPlacement.addPhysVolID("iy", iy);                               
+
+                // Reflection to negative.
+                if (ix != 0)
+                {
+                    // Transform of negative.
+                    Position iposneg = 
+                        new Position(baseName+"_pos_neg", -xcenter, -(beamgap+ycenter+tolerance), zcenter+tolerance+dface);
+                    Rotation irotneg =                 
+                        new Rotation(baseName+"_rot_neg", -thetax, thetay, thetaz);
+
+                    define.addPosition(iposneg);
+                    define.addRotation(irotneg);
+
+                    // Place negative crystal.
+                    PhysVol negCrystalPlacement = new PhysVol(crystalLogVol, world, iposneg, irotneg);
+                    
+                    // Add volume IDs.
+                    negCrystalPlacement.addPhysVolID("ix", -ix);
+                    negCrystalPlacement.addPhysVolID("iy", iy);
+                }
+                
+                // Transform of positive.
+                Position iposBot = 
+                    new Position(baseName+"_pos_pos", xcenter, -(ycenter-my+tolerance), zcenter-mz+tolerance);
+                Rotation irotBot = 
+                    new Rotation(baseName+"_rot_pos", -thetax, -thetay, thetaz);
+                                
+
+                // Increment running X and Z totals and include tolerance to avoid overlaps.
+                xcorrtot += xcorr;
+                zcorrtotx += zcorrx;
+            }        
+                        
+            // Increment running Y totals.
+            ycorrtot += ycorr;
+            zcorrtoty += zcorry;
+        }
+                        
+        // Place the top section.
+        /*
+        Position mpostop = new Position(momVol.getVolumeName() + "_top_pos", 0, 0, 0);
+        //Rotation mrottop = new Rotation(momVol.getVolumeName() + "_top_rot", 0, -Math.PI/2, (3*Math.PI)/2);
+        Rotation mrottop = new Rotation(momVol.getVolumeName() + "_top_rot", 0, 0, 0);
+        define.addPosition(mpostop);
+        define.addRotation(mrottop);
+        PhysVol topSide = new PhysVol(momVol, world, mpostop, mrottop);
+        topSide.addPhysVolID("system", this.getSystemID());
+        topSide.addPhysVolID("side", 1);
+        */
+                
+        // Place the bottom section.
+        /*
+        Position mposbot = new Position(momVol.getVolumeName() + "_bot_pos", 0, -my-beamgap, dface+mz);
+        Rotation mrotbot = new Rotation(momVol.getVolumeName() + "_bot_rot", 0, 0, Math.PI);
+        define.addPosition(mposbot);
+        define.addRotation(mrotbot);
+        PhysVol botSide = new PhysVol(momVol, world, mposbot, mrotbot);        
+        botSide.addPhysVolID("system", this.getSystemID());
+        botSide.addPhysVolID("side", -1);
+        */        
+        
+        // Make the section box invisible.
+        momVol.setVisAttributes(lcdd.getVisAttributes("InvisibleWithDaughters"));
+    }
+    
+    public boolean isCalorimeter()
+    {
+        return true;
+    }
+}
\ No newline at end of file
CVSspam 0.2.8