Print

Print


Commit in lcsim on MAIN
src/org/lcsim/recon/tracking/seedtracker/MaterialManagerNew.java+671added 1.1
test/org/lcsim/MaterialManagerNewTest.java+43added 1.1
+714
2 added files
refactor and partial rewrite of seedtracker.MaterialManager to properly handle different Subdetector types and TestCase

lcsim/src/org/lcsim/recon/tracking/seedtracker
MaterialManagerNew.java added at 1.1
diff -N MaterialManagerNew.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ MaterialManagerNew.java	9 Feb 2011 01:31:38 -0000	1.1
@@ -0,0 +1,671 @@
+package org.lcsim.recon.tracking.seedtracker;
+
+import hep.physics.vec.Hep3Vector;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import org.lcsim.detector.IDetectorElement;
+import org.lcsim.detector.IPhysicalVolume;
+import org.lcsim.detector.IPhysicalVolumeNavigator;
+import org.lcsim.detector.IPhysicalVolumePath;
+import org.lcsim.detector.ITransform3D;
+import org.lcsim.detector.PhysicalVolumeNavigator;
+import org.lcsim.detector.PhysicalVolumeNavigatorStore;
+import org.lcsim.detector.PhysicalVolumePath;
+import org.lcsim.detector.material.IMaterial;
+import org.lcsim.detector.solids.Box;
+import org.lcsim.detector.solids.ISolid;
+import org.lcsim.detector.solids.Point3D;
+import org.lcsim.detector.solids.Polycone;
+import org.lcsim.detector.solids.Trd;
+import org.lcsim.detector.solids.Tube;
+import org.lcsim.detector.solids.Polycone.ZPlane;
+import org.lcsim.geometry.Detector;
+import org.lcsim.geometry.Subdetector;
+import org.lcsim.geometry.subdetector.MultiLayerTracker;
+import org.lcsim.geometry.subdetector.PolyconeSupport;
+import org.lcsim.geometry.subdetector.SiTrackerBarrel;
+import org.lcsim.geometry.subdetector.SiTrackerEndcap2;
+
+/**
+ * Rewrite and refactor of Rich's {@link MaterialManager} class to handle Subdetector types.
+ * This class should now group together SiTrackerEndcap2 layers correctly. 
+ *
+ * @author Jeremy McCormick
+ * @version $Id: MaterialManagerNew.java,v 1.1 2011/02/09 01:31:38 jeremy Exp $
+ */
+// FIXME Bracket style is mixed.  Eclipse formatting tool borked atm.
+public class MaterialManagerNew 
+{
+    // Variables from original MaterialManager class.
+    private static final boolean DEBUG = true; //enable debug output
+    private static final boolean TUBE_ONLY = false; //only use Tube elements for calculating volume.
+    private List<MaterialPolyconeSegment> _matpc = new ArrayList<MaterialPolyconeSegment>();
+    private List<MaterialCylinder> _matcyl = new ArrayList<MaterialCylinder>();
+    private List<MaterialDisk> _matdsk = new ArrayList<MaterialDisk>();
+    private HashMap<ISolid, Double> solid_vol_map = new HashMap<ISolid, Double>(400);
+    private static double _rmax;
+    private static double _zmax = 1800.;
+    
+    /** 
+     * VolumeGroup handlers for Subdetector types. 
+     */
+    private Map<Class, SubdetectorVolumeGrouper> subdetGroups = new HashMap<Class, SubdetectorVolumeGrouper>();
+    
+    /** 
+     * Creates a new instance of MaterialManager 
+     */
+    public MaterialManagerNew() 
+    {
+        // Barrel VolumeGrouper.       
+        SubdetectorVolumeGrouper barrelGroup = new BarrelLayerVolumeGroup();
+                
+        // Add VolumeGrouper for tracker barrel types.
+        subdetGroups.put(SiTrackerBarrel.class, barrelGroup);
+        subdetGroups.put(MultiLayerTracker.class, barrelGroup);
+        
+        // Add VolumeGrouper for SiTrackerEndcap2.
+        subdetGroups.put(SiTrackerEndcap2.class, new SiTrackerEndap2VolumeGrouper());
+        
+        // Add VolumeGrouper for PolyconeSupport.
+        subdetGroups.put(PolyconeSupport.class, new PolyconeSupportVolumeGrouper());
+        
+        // FIXME Need VolumeGrouper for SiTrackerEndcap.
+    }         
+    
+    /** 
+     * Interface for getting the path groupings for different Subdetector types. 
+     */
+    private interface SubdetectorVolumeGrouper
+    {
+        List<List<String>> getPathGroups(Subdetector subdet, IPhysicalVolume topVol);
+    }
+    
+    /** 
+     * Get the path groupings for barrel Subdetectors with physical layers one level below top. 
+     * This will handle SiTrackerBarrel and MultiLayerTracker Subdetector types.
+     */
+    static private class BarrelLayerVolumeGroup implements SubdetectorVolumeGrouper
+    {        
+        public List<List<String>> getPathGroups(Subdetector subdet, IPhysicalVolume topVol)
+        {
+            List<List<String>> pathGroups = new ArrayList<List<String>>();
+            for (IDetectorElement layer : subdet.getDetectorElement().getChildren())
+            {
+                List<String> layerPaths = new ArrayList<String>();
+                String path = "";
+                PhysicalVolumeNavigator.getLeafPaths(layerPaths, layer.getGeometry().getPhysicalVolume(), path);
+                pathGroups.add(layerPaths);
+            }
+            return pathGroups;
+        }
+    }
+    
+    /**
+     * Get the path groups for a PolyconeSupport, which is a single path.
+     */
+    static private class PolyconeSupportVolumeGrouper implements SubdetectorVolumeGrouper
+    {
+        public List<List<String>> getPathGroups(Subdetector subdet, IPhysicalVolume topVol)
+        {
+            List<List<String>> pathGroups = new ArrayList<List<String>>();
+            String path = "";
+            List<String> supportPath = new ArrayList<String>();
+            IPhysicalVolume supportPV = subdet.getDetectorElement().getChildren().get(0).getGeometry().getPhysicalVolume();
+            PhysicalVolumeNavigator.getLeafPaths(supportPath, supportPV, path);
+            pathGroups.add(supportPath);
+            return pathGroups;
+        }
+    }
+    
+    /**
+     * Get the path groups for SiTrackerEndcap2, which has modules placed directly 
+     * in the tracking volume.
+     */
+    static private class SiTrackerEndap2VolumeGrouper implements SubdetectorVolumeGrouper
+    {        
+        public List<List<String>> getPathGroups(Subdetector subdet, IPhysicalVolume topVol)
+        {
+            List<List<String>> pathGroups = new ArrayList<List<String>>();
+            // Positive and negative endcap loop.
+            for (IDetectorElement endcaps : subdet.getDetectorElement().getChildren())
+            {
+                // Layer loop.
+                for (IDetectorElement layer : endcaps.getChildren())
+                {
+                    List<String> modulePaths = new ArrayList<String>();
+                    //System.out.println(layer.getName());
+                    
+                    // Module loop.                    
+                    for (IDetectorElement module : layer.getChildren())
+                    {                                     
+                        String path = "";
+                        PhysicalVolumeNavigator.getLeafPaths(modulePaths, module.getGeometry().getPhysicalVolume(), path);
+                        modulePaths.add(path);
+                    }
+                    // Add module.
+                    pathGroups.add(modulePaths);
+                }
+            }
+            return pathGroups;
+        }
+    }       
+    
+    /**
+     * Setup tracking volume parameters.
+     * @param det The Detector.
+     */
+    private void setupTrackingVolume(Detector det)
+    {
+        //  Find the envelope of the tracking volume
+        ISolid trkvol = det.getTrackingVolume().getLogicalVolume().getSolid();
+        if (trkvol instanceof Tube) {
+            Tube trktube = (Tube) trkvol;
+            _rmax = trktube.getOuterRadius();
+            _zmax = trktube.getZHalfLength();
+            if (DEBUG) {
+                System.out.println("Ecal radius = " + _rmax);
+                System.out.println("ECal inner Z = " + _zmax);
+            }
+        }
+    }    
+    
+    /** 
+     * Build model using new VolumeGroup interface for each Subdetector type.  
+     */   
+    public void buildModel(Detector det)
+    {
+        // Get the default navigator.
+        IPhysicalVolumeNavigator nav = PhysicalVolumeNavigatorStore.getInstance().getDefaultNavigator();
+        
+        // Get the tracking volume.
+        IPhysicalVolume trackingVol = det.getTrackingVolume();
+        
+        // Loop over subdetectors.
+        for (Subdetector subdet : det.getSubdetectorList())
+        {            
+            // Only look at Subdetectors in the tracking region.
+            if (subdet.isInsideTrackingVolume())
+            {
+                if (DEBUG)
+                {
+                    System.out.println();
+                    System.out.println(">>>> " + subdet.getName() + " >>>>");
+                }
+                
+                // Get the VolumeGrouper for this type.
+                SubdetectorVolumeGrouper subdetGroup = subdetGroups.get(subdet.getClass());
+                
+                // Can't handle.
+                if (subdetGroup == null)
+                {
+                    System.out.println("WARNING: Can't handle Subdetector of type <" + subdet.getClass().getCanonicalName() + ">.");
+                }                
+                else
+                {
+                    // Make the list of path groups for this Subdetector.
+                    List<List<String>> pathGroups = subdetGroup.getPathGroups(subdet, trackingVol);
+                    
+                    if (DEBUG)
+                    {
+                        System.out.println("Got " + pathGroups.size() + " path groups.");
+                    }
+                    
+                    for (List<String> pathGroup : pathGroups)
+                    {
+                        if (DEBUG)
+                        {
+                            System.out.println("Adding next " + pathGroup.size() + " paths.");
+                        }
+                        
+                        // Make the UniquePV list expected by MaterialManager.
+                        List<UniquePV> uniqPVs = makeUniquePVList(nav, trackingVol, pathGroup);
+                        
+                        // Calculate VolumeGroupInfo for this.
+                        VolumeGroupInfo vgi = performVolumeGroupCalculations(uniqPVs);
+                        
+                        // Debug print.
+                        if (DEBUG)
+                        {
+                            System.out.println("VolumeGroupInfo ...");
+                            System.out.println("    rmax = " + vgi.rmax);
+                            System.out.println("    rmin = " + vgi.rmin);
+                            System.out.println("    zmin = " + vgi.zmin);
+                            System.out.println("    zmax = " + vgi.zmax);
+                            System.out.println("    X0 = " + vgi.X0);
+                            System.out.println("    weighted_r = " + vgi.weighted_r);
+                            System.out.println("    weighted_z = " + vgi.weighted_z);
+                            System.out.println("    vtot_tube_only = " + vgi.vtot_tube_only);
+                            System.out.println("    vtot = " + vgi.vtot);
+                        }
+                        
+                        // Add the VolumeGroupInfo, which will setup the material representation.
+                        addVolumeGroupInfo(uniqPVs, vgi);
+                    }
+                }
+            }
+        }
+        
+        // Setup the tracking volume.
+        setupTrackingVolume(det);
+    }
+    
+    private void addVolumeGroupInfo(List<UniquePV> uniqPVs, VolumeGroupInfo vgi)
+    {
+        double vtot;
+        if (TUBE_ONLY) {
+            vtot = vgi.vtot_tube_only;
+        } else {
+            vtot = vgi.vtot;
+        }
+
+        // Handle Polycone.        
+        if (uniqPVs.get(0).getPV().getLogicalVolume().getSolid() instanceof Polycone) 
+        {
+            handlePolycone(uniqPVs.get(0).getPV());            
+        }       
+
+        if (vtot > 0.) {
+
+            //  Calculate the average radiation length for this volume
+
+
+            //  Determine if this volume should be modeled as barrel or disk
+            if (isCylinder(vgi.rmin, vgi.rmax, vgi.zmin, vgi.zmax)) {
+                // Calculate the weighted radius of the elements
+                double zlen = vgi.zmax - vgi.zmin;
+                double thickness = vtot / (2. * Math.PI * vgi.weighted_r * zlen * vgi.X0);
+
+                /*
+                if (DEBUG) {
+                    System.out.println(pvtree.getName());
+                    System.out.println("x0: " + vgi.X0 + "| zmin: " + vgi.zmin + "| zmax: " + vgi.zmax + "| vtot: " + vtot + "| thickness: " + thickness +
+                            "| rmin: " + vgi.rmin + "| rmax: " + vgi.rmax);
+                    System.out.println();
+                }
+                */
+
+                _matcyl.add(new MaterialCylinder(null, vgi.weighted_r, vgi.zmin, vgi.zmax, thickness));
+            } else {
+
+                double thickness = vtot / (Math.PI * (vgi.rmax * vgi.rmax - vgi.rmin * vgi.rmin) * vgi.X0);
+
+                /*
+                if (DEBUG) {
+                    System.out.println(pvtree.getName());
+                    System.out.println("x0: " + vgi.X0 + "| zmin: " + vgi.zmin + "| zmax: " + vgi.zmax + "| vtot: " + vtot + "| thickness: " + thickness +
+                            "| rmin: " + vgi.rmin + "| rmax: " + vgi.rmax);
+                    System.out.println();
+                }
+                */
+
+                _matdsk.add(new MaterialDisk(null, vgi.rmin, vgi.rmax, vgi.weighted_z, thickness));
+            }
+        }
+    }
+    
+    private static List<UniquePV> makeUniquePVList(IPhysicalVolumeNavigator nav, IPhysicalVolume trackingVol, List<String> paths)
+    {
+        List<UniquePV> uniqPVs = new ArrayList<UniquePV>();
+        for (String path : paths)
+        {                   
+            /**
+             * Create the path object, prepending tracking volume name, as the paths are 
+             * relative to Subdetector. 
+             */
+            IPhysicalVolumePath pvPath = nav.getPath("/" + trackingVol.getName() + path);
+            
+            /** 
+             * Create the UniquePV for MaterialManager.
+             */
+            uniqPVs.add(new UniquePV(pvPath, nav));
+        }        
+        return uniqPVs;
+    }   
+
+    public List<MaterialCylinder> getMaterialCylinders() {
+        return _matcyl;
+    }
+
+    public List<MaterialDisk> getMaterialDisks() {
+        return _matdsk;
+    }
+
+    public List<MaterialPolyconeSegment> getMaterialPolyconeSegments() {
+        return _matpc;
+    }
+
+    public static double getRMax() {
+        return _rmax;
+    }
+
+    public static double getZMax() {
+        return _zmax;
+    }
+
+    /*
+    private List<UniquePV> Flatten(IPhysicalVolume vol, IPhysicalVolumeNavigator nav) {
+
+        LinkedList<UniquePV> pvtree = new LinkedList<UniquePV>();
+        List<UniquePV> pvflat = new ArrayList<UniquePV>();
+        pvtree.add(new UniquePV(vol, nav));
+
+        while (pvtree.size() > 0) {
+
+            UniquePV upv = pvtree.poll();
+            IPhysicalVolume pv = upv.getPV();
+
+            if (pv.getLogicalVolume().getNumberOfDaughters() == 0) {
+                pvflat.add(upv);
+            } else {
+                for (IPhysicalVolume p : pv.getLogicalVolume().getDaughters()) {
+                    pvtree.add(upv.createDaughterUniquePV(p));
+                }
+
+            }
+        }
+
+        return pvflat;
+    }
+    */
+
+    private boolean isCylinder(double rmin, double rmax, double zmin, double zmax) {
+        return (rmax - rmin) * Math.abs(zmax + zmin) < (zmax - zmin) * (rmax + rmin);
+    }
+
+// special handling for Polycone...
+    private void handlePolycone(IPhysicalVolume pv) {
+        Polycone pc = (Polycone) pv.getLogicalVolume().getSolid();
+        IMaterial mat = pv.getLogicalVolume().getMaterial();
+
+        //Loop through each segment
+        for (int i = 0; i <
+                pc.getNumberOfZPlanes() - 1; i++) {
+            ZPlane zp1 = pc.getZPlane(i);
+            ZPlane zp2 = pc.getZPlane(i + 1);
+
+            double z1 = zp1.getZ();
+            double z2 = zp2.getZ();
+            double vol = Polycone.getSegmentVolume(zp1, zp2);
+            double zlen = Math.abs(z2 - z1);
+            double ravg = 0.25 * (zp1.getRMax() + zp1.getRMin() + zp2.getRMax() + zp2.getRMin());
+            double ang = Math.atan2(0.5 * (zp1.getRMax() + zp1.getRMin() - zp2.getRMax() - zp2.getRMin()), zlen);
+            double X0 = 10 * mat.getRadiationLength() / mat.getDensity();
+            double thickness = Math.cos(ang) * vol / (2 * Math.PI * ravg * zlen * X0);
+
+            //This is a cylinder
+            if (zp1.getRMax() == zp2.getRMax() && zp1.getRMin() == zp2.getRMin()) {
+                _matcyl.add(new MaterialCylinder(pv, ravg, Math.min(z1, z2), Math.max(z1, z2), thickness));
+                if (DEBUG) {
+                    System.out.println("Cylindrical segment of " + pv.getName());
+                    System.out.println("zmin = " + z1 + "| zmax = " + z2 + "| ravg = " + ravg + "| thickness = " + thickness);
+                }
+
+            } //Otherwise this is a non-cylindrical polycone segment
+            else {
+                _matpc.add(new MaterialPolyconeSegment(pv, zp1, zp2, thickness, ang));
+                if (DEBUG) {
+                    System.out.println("Non-Cylindrical segment of " + pv.getName());
+                    System.out.println("ZPlane 1: " + zp1.toString() + "| ZPlane 2: " + zp2.toString() + "| thickness = " + thickness);
+                }
+
+
+
+            }
+        }
+    }
+
+    /**
+     * A "struct" holding geometry information about a single physical volume
+     */
+    class VolumeInfo {
+
+        double rmax = 0.0;
+        double rmin = 1.e10;
+        double zmin = 1.e10;
+        double zmax = -1.e10;
+    }
+
+    /**
+     *  A "struct" holding geometry information about lists of physical volumes
+     */
+    class VolumeGroupInfo {
+
+        double rmax = 0.0;
+        double rmin = 1.e10;
+        double zmin = 1.e10;
+        double zmax = -1.e10;
+        double X0 = 0.0;
+        double weighted_r = 0.0;
+        double weighted_z = 0.0;
+        double vtot_tube_only = 0.;
+        double vtot = 0.0;
+    }
+
+//This function performs all the calculations on lists of physical volumes
+    private VolumeGroupInfo performVolumeGroupCalculations(
+            List<UniquePV> volgroup) {
+
+        VolumeGroupInfo vgi = new VolumeGroupInfo();
+
+        //If we have a top-level polycone, don't bother doing anything, because it'll be handled specially
+        if (volgroup.size() == 1 && volgroup.get(0).getSolid() instanceof Polycone) {
+            return vgi;
+        }
+
+//The normal case
+        double totwgt = 0.0;
+        if (DEBUG && volgroup.isEmpty()) {
+            System.out.println("Empty volume group...");
+        }
+        for (UniquePV pv : volgroup) {
+
+            //increment total volume
+            double vol = this.getVolumeOfSolid(pv.getSolid());
+            if (pv.getSolid() instanceof Tube) {
+                vgi.vtot_tube_only += vol;
+            }
+            vgi.vtot += vol;
+            //calculate weighted R / Z / Radiation Length
+            VolumeInfo vi = performVolumeCalculations(pv);
+            IMaterial mat = pv.getPV().getLogicalVolume().getMaterial();
+            double matX0 = 10.0 * mat.getRadiationLength() / mat.getDensity();
+            double wgt = vol / matX0;
+            double z0 = pv.getLtoGTransform().getTranslation().z();
+            vgi.weighted_r += 0.5 * (vi.rmin + vi.rmax) * wgt;
+            vgi.weighted_z += z0 * wgt;
+            totwgt +=
+                    wgt;
+
+            //grab (z/r)(mins/maxes)
+            vgi.zmin = Math.min(vi.zmin, vgi.zmin);
+            vgi.zmax = Math.max(vi.zmax, vgi.zmax);
+            vgi.rmin = Math.min(vi.rmin, vgi.rmin);
+            vgi.rmax = Math.max(vi.rmax, vgi.rmax);
+
+        }
+
+//finish weighted R/Z calculations + perform X0 calculation
+        if (totwgt > 0.) {
+            vgi.weighted_r /= totwgt;
+            vgi.weighted_z /= totwgt;
+            vgi.X0 = vgi.vtot / totwgt;
+        }
+
+        return vgi;
+    }
+
+    private double getVolumeOfSolid(ISolid solid) {
+        if (solid_vol_map.containsKey(solid)) {
+            return solid_vol_map.get(solid).doubleValue();
+        } else {
+            double vol;
+            try {
+                vol = solid.getCubicVolume();
+            } catch (Exception e) {
+                vol = 0.0;
+            }
+
+            solid_vol_map.put(solid, vol);
+            return vol;
+        }
+
+    }
+
+    private VolumeInfo performVolumeCalculations(UniquePV pv) {
+
+        VolumeInfo vi = new VolumeInfo();
+        ISolid solid = pv.getSolid();
+
+        //ASSUMPTION: tube is along z-axis and has center at r = 0
+        if (solid instanceof Tube) {
+            Tube tube = (Tube) solid;
+            double z0 = pv.getLtoGTransform().getTranslation().z();
+            vi.zmax = z0 + tube.getZHalfLength();
+            vi.zmin = z0 - tube.getZHalfLength();
+            vi.rmin = tube.getInnerRadius();
+            vi.rmax = tube.getOuterRadius();
+        } else if (solid instanceof Box) {
+            Box box = (Box) solid;
+            for (Point3D p : box.getVertices()) {
+                Hep3Vector transformed = pv.localToGlobal(p.getHep3Vector());
+                vi.zmin = Math.min(transformed.z(), vi.zmin);
+                vi.zmax = Math.max(transformed.z(), vi.zmax);
+                double r = Math.sqrt(transformed.x() * transformed.x() + transformed.y() * transformed.y());
+                vi.rmin = Math.min(vi.rmin, r);
+                vi.rmax = Math.max(vi.rmax, r);
+            }
+
+        }else if (solid instanceof Trd) {
+            Trd box = (Trd) solid;
+            for (Point3D p : box.getVertices()) {
+                Hep3Vector transformed = pv.localToGlobal(p.getHep3Vector());
+                vi.zmin = Math.min(transformed.z(), vi.zmin);
+                vi.zmax = Math.max(transformed.z(), vi.zmax);
+                double r = Math.sqrt(transformed.x() * transformed.x() + transformed.y() * transformed.y());
+                vi.rmin = Math.min(vi.rmin, r);
+                vi.rmax = Math.max(vi.rmax, r);
+            }
+        } //Note: this information will NOT be used most of the time...
+        // Polycones that are top-level elements (e.g. the beampipe) are
+        // handled specially (since the radiation length is a function of z).
+        // The information here will only be used in case a top-level element
+        // has a subelement that is a Polycone, in which case it'll be
+        // approximated as the smallest possible cylinder.
+        else if (solid instanceof Polycone) {
+            Polycone pc = (Polycone) solid;
+            List<Polycone.ZPlane> zplanes = pc.getZPlanes();
+
+            //For now, just take the minimum rmin and rmax of the polycone
+            for (Polycone.ZPlane z : zplanes) {
+                if (z.getRMax() > 0 && z.getRMin() > 0) {
+                    vi.rmin = Math.min(vi.rmin, z.getRMin());
+                    vi.rmax = vi.rmax > 0. ? Math.min(vi.rmax, z.getRMax()) : z.getRMax();
+                }
+
+            }
+
+            vi.zmin = pc.getZPlanes().get(0).getZ();
+            vi.zmax = pc.getZPlanes().get(pc.getZPlanes().size() - 1).getZ();
+
+            //check for wrong order
+            if (vi.zmin > vi.zmax) {
+                double temp = vi.zmin;
+                vi.zmin = vi.zmax;
+                vi.zmax = temp;
+            }
+
+        }
+
+        return vi;
+    }
+
+    /**
+     * A UniquePV is a wrapper around IPhysicalVolumePath which provides
+     * some convenience methods and caches transformations.
+     */
+    static class UniquePV {
+
+        IPhysicalVolumePath path;
+        IPhysicalVolumeNavigator nav;
+        ITransform3D transform = null;
+
+        /**
+         * Generates a top-level UniquePV.
+         * @param root The top-level IPhysicalVolume
+         * @param navigator The IPhysicalVolumeNavigator associated with the detector
+         */
+        public UniquePV(IPhysicalVolume root, IPhysicalVolumeNavigator navigator) {
+            path = new PhysicalVolumePath();
+            nav = navigator;
+            path.add(root);
+        }
+
+        /**
+         * Generates a UniquePV from a path. (Shallow copy of path)
+         * @param path
+         * @param navigator
+         */
+        public UniquePV(IPhysicalVolumePath path, IPhysicalVolumeNavigator navigator) {
+            this.path = path;
+            nav = navigator;
+        }
+
+        /**
+         * Returns the IPhysicalVolume (the last element of the path)
+         */
+        public IPhysicalVolume getPV() {
+            return path.getLeafVolume();
+        }
+
+        /**
+         * Creates a UniquePV that is a daughter of the current UniquePV (deep copy made)
+         * @param daughter
+         * @return
+         */
+        public UniquePV createDaughterUniquePV(IPhysicalVolume daughter) {
+            IPhysicalVolumePath np = new PhysicalVolumePath();
+            np.addAll(path);
+            np.add(daughter);
+            return new UniquePV(np, nav);
+        }
+
+        /**
+         * Transforms the given vector from local to global coords.
+         * @param v the untransformed local Hep3Vector
+         * @return the transformed global Hep3Vector
+         */
+        public Hep3Vector localToGlobal(Hep3Vector v) {
+
+            return getLtoGTransform().transformed(v);
+        }
+
+        /**
+         * Returns the solid associated with the physical volume.
+         * @return
+         */
+        public ISolid getSolid() {
+            return this.getPV().getLogicalVolume().getSolid();
+        }
+
+        /**
+         * Returns the local-to-global transform
+         * @return an ITransform3D from local coordinates to global coordinates.
+         */
+        public ITransform3D getLtoGTransform() {
+            if (transform == null) {
+                transform = nav.getTransform(path);
+            }
+            return transform;
+        }
+
+        @Override
+        public String toString() {
+            return path.toString();
+        }
+    }
+}

lcsim/test/org/lcsim
MaterialManagerNewTest.java added at 1.1
diff -N MaterialManagerNewTest.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ MaterialManagerNewTest.java	9 Feb 2011 01:31:38 -0000	1.1
@@ -0,0 +1,43 @@
+/**
+ * @author Jeremy McCormick <[log in to unmask]>
+ * @version $Id: MaterialManagerNewTest.java,v 1.1 2011/02/09 01:31:38 jeremy Exp $
+ */
+package org.lcsim;
+
+import java.io.File;
+import java.net.URL;
+
+import junit.framework.TestCase;
+
+import org.lcsim.geometry.Detector;
+import org.lcsim.recon.tracking.seedtracker.MaterialManagerNew;
+import org.lcsim.util.Driver;
+import org.lcsim.util.cache.FileCache;
+import org.lcsim.util.loop.LCSimLoop;
+
+/**
+ * @author jeremym
+ */
+public class MaterialManagerNewTest extends TestCase 
+{
+    public void testMaterialManagerNew() throws Exception
+    {
+        URL url = new URL("http://www.lcsim.org/test/lcio/muon_Theta1-179_20GeV_SLIC-v2r8p0_geant4-v9r2p2_QGSP_BERT_sidloi3-0-10.slcio");
+        FileCache cache = new FileCache();
+        File file = cache.getCachedFile(url);
+        
+        LCSimLoop loop = new LCSimLoop();
+        loop.add(new MaterialManagerNewTestDriver());
+        loop.setLCIORecordSource(file);
+        loop.loop(1);
+    }
+    
+    static class MaterialManagerNewTestDriver extends Driver
+    {
+        public void detectorChanged(Detector detector)
+        {
+            MaterialManagerNew mgr = new MaterialManagerNew();
+            mgr.buildModel(detector);
+        }        
+    }
+}
\ No newline at end of file
CVSspam 0.2.8