Commit in lcsim/src/org/lcsim/recon/tracking/seedtracker on MAIN
ConfirmerExtender.java+1-11.1 -> 1.2
HelixFitter.java+54-351.2 -> 1.3
MaterialManager.java+192-1731.1 -> 1.2
MultipleScattering.java+64-881.2 -> 1.3
ScatterAngle.java+8-11.1 -> 1.2
SeedCandidate.java+51-41.1 -> 1.2
SeedTracker.java+1-11.2 -> 1.3
+371-303
7 modified files
Optimize multiple scattering calculations

lcsim/src/org/lcsim/recon/tracking/seedtracker
ConfirmerExtender.java 1.1 -> 1.2
diff -u -r1.1 -r1.2
--- ConfirmerExtender.java	27 Aug 2008 17:59:01 -0000	1.1
+++ ConfirmerExtender.java	13 Oct 2008 01:05:27 -0000	1.2
@@ -9,9 +9,9 @@
 import java.util.Collections;
 import java.util.List;
 
-import org.lcsim.recon.tracking.seedtracker.diagnostic.ISeedTrackerDiagnostics;
 import org.lcsim.fit.helicaltrack.HelicalTrackFitter.FitStatus;
 import org.lcsim.fit.helicaltrack.HelicalTrackHit;
+import org.lcsim.recon.tracking.seedtracker.diagnostic.ISeedTrackerDiagnostics;
 
 /**
  *

lcsim/src/org/lcsim/recon/tracking/seedtracker
HelixFitter.java 1.2 -> 1.3
diff -u -r1.2 -r1.3
--- HelixFitter.java	9 Oct 2008 17:47:30 -0000	1.2
+++ HelixFitter.java	13 Oct 2008 01:05:27 -0000	1.3
@@ -23,6 +23,7 @@
 import org.lcsim.fit.line.SlopeInterceptLineFit;
 import org.lcsim.recon.tracking.seedtracker.diagnostic.ISeedTrackerDiagnostics;
 import org.lcsim.fit.zsegment.ZSegmentFit;
+import org.omg.PortableServer._ServantActivatorStub;
 
 /**
  *
@@ -35,7 +36,6 @@
     private HelicalTrackFit _helix;
     private MaterialManager _materialmanager;
     private ConstrainHelix _constrain;
-    private HelixUtils _helixutils;
     private double _bfield = 0.;
     private CircleFit _circlefit;
     private SlopeInterceptLineFit _linefit;
@@ -47,7 +47,6 @@
      */
     public HelixFitter(MaterialManager materialmanager) {
         _materialmanager = materialmanager;
-        _helixutils = new HelixUtils();
         _scattering = new MultipleScattering(_materialmanager);
         _constrain = new ConstrainHelix();
     }
@@ -56,7 +55,7 @@
         
         //  Initialize fit results to null objects
         _helix = null;
-
+        
         //  Check that we have set the magnetic field
         if (_bfield == 0.) throw new RuntimeException("B Field must be set before calling the Helix fitter");
         
@@ -66,11 +65,8 @@
         //  Retrieve list of hits to be fit
         List<HelicalTrackHit> hitlist = seed.getHits();
         
-        //  Retrieve the last helix fit (if any) for the MS error calculation
-        HelicalTrackFit oldhelix = seed.getHelix();
-        
         //  If this is the candidate's first helix fit, first do a fit without MS errors
-        if (oldhelix == null) {
+        if (seed.getHelix() == null) {
             
             //  Reset the stereo hit positions to their nominal value
             for (HelicalTrackHit hit : hitlist) {
@@ -78,31 +74,29 @@
             }
             //  Do the fit
             _status = _fitter.fit(hitlist);
-            checkfit();
+            SaveFit();
+            
+            //  Check for unrecoverable fit errors and call appropriate diagnostic
             if (_status != FitStatus.Success) {
                 if(_diag!=null) _diag.fireFitterFitMade(seed, null,_circlefit,_linefit,_zsegmentfit, _status, false);
                 return false;
             }
             
             //  Retrieve the helix parameters from this fit
-            oldhelix = _fitter.getFit();
+            seed.setHelix(_fitter.getFit());
+            
+            //  Calculate the multiple scattering angles for this helix
+            seed.setScatterAngles(_scattering.FindScatters(seed.getHelix()));
         }
         
-        //  Calculate the MS errors
-        Map<HelicalTrackHit, MultipleScatter> msmap = _scattering.HelixScatters(oldhelix, hitlist);
-        
-        //  Adjust stereo hit positions and covariance matrices for cross hits
-        Map<HelicalTrackHit, Double> pathmap = oldhelix.PathMap();
-        for (HelicalTrackHit hit : hitlist) {
-            if (hit instanceof HelicalTrackCross) {
-                TrackDirection trkdir = _helixutils.CalculateTrackDirection(oldhelix, pathmap.get(hit));
-                ((HelicalTrackCross) hit).setTrackDirection(trkdir, oldhelix.covariance());
-            }
-        }
+        //  Update the stereo hit positions and covariance matrices
+        CorrectStereoHits(hitlist, seed.getHelix());
         
         //  Do a helix fit including MS errors
-        _status = _fitter.fit(hitlist, msmap, oldhelix);
-        checkfit();
+        _status = _fitter.fit(hitlist, seed.getMSMap(), seed.getHelix());
+        SaveFit();
+        
+        //  Check for unrecoverable fit errors and call appropriate diagnostic
         if (_status != FitStatus.Success) {
             if(_diag!=null) _diag.fireFitterFitMade(seed, null,_circlefit,_linefit,_zsegmentfit, _status, false);
             return false;
@@ -113,8 +107,14 @@
         
         //  Set the non-holonomic constraint chi square
         _constrain.setConstraintChisq(strategy, _helix, hitlist);
+        
+        //  If the total chi square is below the cut, we have a successful fit
         boolean success = _helix.chisqtot() <= strategy.getMaxChisq();
         if(_diag!=null) _diag.fireFitterFitMade(seed, _helix, _circlefit, _linefit, _zsegmentfit, _status, success);
+        
+        //  If fit was successful, set the new multiple scattering angles
+        if (success) seed.setScatterAngles(_scattering.FindScatters(_helix));
+        
         return success;
     }
     
@@ -123,15 +123,6 @@
         return;
     }
     
-    public void setBField(double bfield) {
-        
-        //  Save b field and pass it to the multiple scattering and chisq constraint classes
-        _bfield = bfield;
-        _scattering.setBField(_bfield);
-        _constrain.setBField(_bfield);
-        return;
-    }
-    
     public HelicalTrackFit getHelix() {
         return _helix;
     }
@@ -152,14 +143,25 @@
         return _zsegmentfit;
     }
     
-    private void checkfit() {
+    public void setBField(double bfield) {
+        _bfield = bfield;
+        _scattering.setBField(_bfield);
+        _constrain.setBField(_bfield);
+        return;
+    }
+    
+    private void SaveFit() {
+        
+        //  Default to no fit results when circle fit fails
         _circlefit = null;
         _linefit = null;
         _zsegmentfit = null;
+        
+        //  Save the circle fit results if they exist
         if (_status == FitStatus.CircleFitFailed) return;
-        else {
-            _circlefit = _fitter.getCircleFit();
-        }
+        _circlefit = _fitter.getCircleFit();
+        
+        //  If we have a circle fit, try to save the line fit / zsegment fit results
         if (_status == FitStatus.LineFitFailed) return;
         if (_status == FitStatus.ZSegmentFitFailed) return;
         _linefit = _fitter.getLineFit();
@@ -167,4 +169,21 @@
         
         return;
     }
+    
+    private void CorrectStereoHits(List<HelicalTrackHit> hitlist, HelicalTrackFit helix) {
+        
+        //  Get the PathMap - used to find the track direction at the hit location
+        Map<HelicalTrackHit, Double> pathmap = helix.PathMap();
+        
+        //  Loop over the hits and look for stereo hits
+        for (HelicalTrackHit hit : hitlist) {
+            if (hit instanceof HelicalTrackCross) {
+                
+                //  Found a stereo hit - calculate the track direction and pass it to the hit
+                TrackDirection trkdir = HelixUtils.CalculateTrackDirection(helix, pathmap.get(hit));
+                ((HelicalTrackCross) hit).setTrackDirection(trkdir, helix.covariance());
+            }
+        }
+        return;
+    }
 }
\ No newline at end of file

lcsim/src/org/lcsim/recon/tracking/seedtracker
MaterialManager.java 1.1 -> 1.2
diff -u -r1.1 -r1.2
--- MaterialManager.java	27 Aug 2008 17:59:02 -0000	1.1
+++ MaterialManager.java	13 Oct 2008 01:05:27 -0000	1.2
@@ -41,14 +41,15 @@
 public class MaterialManager {
     
     private static final boolean DEBUG = false; //enable debug output
-    private static final boolean TUBE_ONLY = true; //only use Tube elements for calculating volume. 
+    private static final boolean TUBE_ONLY = true; //only use Tube elements for calculating volume.
     
-    private List<MaterialPolyconeSegment> _matpc = new ArrayList<MaterialPolyconeSegment>(); 
+    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 HashMap<ISolid,Double> solid_vol_map = new HashMap<ISolid,Double>(400);
     private double _rmax;
-      
+    private double _zmax = 1800.;
+    
     /** Creates a new instance of MaterialManager */
     public MaterialManager() {
     }
@@ -62,32 +63,32 @@
         //
         //  First find the logical volume associated with the tracker
         
-        IPhysicalVolumeNavigator nav = det.getNavigator(); 
+        IPhysicalVolumeNavigator nav = det.getNavigator();
         ILogicalVolume ltrkr = det.getTrackingVolume().getLogicalVolume();
         //  Loop over the volumes defined at the compact.xml level
         for (IPhysicalVolume pvtree : ltrkr.getDaughters()) {
             //  Flatten the geometry tree to get all daughters with material
             //List<IPhysicalVolume> pvflat = Flatten(pvtree);
-            List<UniquePV> pvflat = Flatten(pvtree,nav); 
+            List<UniquePV> pvflat = Flatten(pvtree,nav);
+            
+//           System.out.println(pvflat.size());
+            //  Calculate the total volume of material, skip this object if 0
+            VolumeGroupInfo vgi = performVolumeGroupCalculations(pvflat);
+            
+            double vtot;
+            if (TUBE_ONLY)  vtot = vgi.vtot_tube_only;
+            else vtot = vgi.vtot;
             
-//           System.out.println(pvflat.size()); 
-           //  Calculate the total volume of material, skip this object if 0
-            VolumeGroupInfo vgi = performVolumeGroupCalculations(pvflat); 
-            
-           double vtot; 
-           if (TUBE_ONLY)  vtot = vgi.vtot_tube_only;
-           else vtot = vgi.vtot; 
-          
-           
-           if (pvtree.getLogicalVolume().getSolid() instanceof Polycone){
-               handlePolycone(pvtree); 
-               continue; 
-           }
+            
+            if (pvtree.getLogicalVolume().getSolid() instanceof Polycone){
+                handlePolycone(pvtree);
+                continue;
+            }
             
             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)) {
@@ -96,22 +97,22 @@
                     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(); 
+                        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(pvtree, 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(); 
+                        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(pvtree, vgi.rmin, vgi.rmax, vgi.weighted_z, thickness));
@@ -119,9 +120,9 @@
             }
         }
         
-        solid_vol_map.clear(); 
+        solid_vol_map.clear();
         
-        //  Find the outer radius of the tracking volume
+        //  Find the envelope of the tracking volume
         //  First loop over all the subdetector elements
         IDetectorElement de = det.getDetectorElement();
         for (IDetectorElement child : de.getChildren()) {
@@ -133,7 +134,7 @@
                 IIdentifier id = child.getIdentifier();
                 
                 //  Check if this is the ECalBarrel
-                if (dehelper.isEcalBarrel(id)) {
+                if (dehelper.isEcal(id)) {
                     
                     //  Check for geometry info to make sure we don't have an ECal endcap
                     if (child.hasGeometryInfo()) {
@@ -145,11 +146,27 @@
                             
                             //  Take the inner ECal radius was the outer tracker radius
                             _rmax = tube.getInnerRadius();
+                            System.out.println("Ecal radius = "+_rmax);
                         }
+                    } else {
+                        //  Have the ECal Endcap volume - loop over the endcaps
+                        for (IDetectorElement grandchild : child.getChildren()) {
+                            if (dehelper.isEcalEndcapPositive(grandchild.getIdentifier())) {
+                                if (grandchild.hasGeometryInfo()) {
+                                    ISolid solid = grandchild.getGeometry().getLogicalVolume().getSolid();
+                                    if (solid instanceof Tube) {
+                                        Tube tube = (Tube) solid;
+                                        _zmax = grandchild.getGeometry().getPosition().z() - tube.getZHalfLength();
+                                        System.out.println("ECal inner Z = "+_zmax);
+                                    }
+                                }
+                            }
+                        } 
                     }
                 }
             }
         }
+        return;
     }
     
     public List<MaterialCylinder> getMaterialCylinders() {
@@ -161,37 +178,40 @@
     }
     
     public List<MaterialPolyconeSegment> getMaterialPolyconeSegments() {
-        return _matpc; 
+        return _matpc;
     }
     
     public double getRMax() {
         return _rmax;
     }
     
+    public 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)); 
+        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(); 
+            UniquePV upv = pvtree.poll();
+            IPhysicalVolume pv = upv.getPV();
             
             if (pv.getLogicalVolume().getNumberOfDaughters()==0) {
-                pvflat.add(upv); 
+                pvflat.add(upv);
             }
- 
+            
             else {
                 for(IPhysicalVolume p : pv.getLogicalVolume().getDaughters()) {
-                   pvtree.add(upv.createDaughterUniquePV(p));      
+                    pvtree.add(upv.createDaughterUniquePV(p));
                 }
             }
         }
         
-        return pvflat; 
+        return pvflat;
     }
     
     
@@ -201,39 +221,39 @@
     
     // special handling for Polycone...
     private void handlePolycone(IPhysicalVolume pv){
-        Polycone pc = (Polycone) pv.getLogicalVolume().getSolid(); 
-        IMaterial mat = pv.getLogicalVolume().getMaterial(); 
+        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); 
+            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); 
+            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); 
+                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 
+            //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); 
+                _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);
                 }
             }
         }
@@ -243,185 +263,184 @@
      * A "struct" holding geometry information about a single physical volume
      */
     class VolumeInfo {
-        double rmax = 0.0; 
-        double rmin = 1.e10; 
+        double rmax = 0.0;
+        double rmin = 1.e10;
         double zmin = 1.e10;
-        double zmax = -1.e10; 
+        double zmax = -1.e10;
     }
     
     
     /**
-    *  A "struct" holding geometry information about lists of physical volumes
-    */
+     *  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; 
+        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(); 
-
+        
+        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; 
+            return vgi;
         }
-
+        
         //The normal case
-        double totwgt = 0.0; 
-        if (DEBUG && volgroup.isEmpty()) System.out.println("Empty volume group..."); 
+        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; 
+            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) 
+            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); 
-
+            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; 
+            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(); 
+            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; 
+            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(); 
+        
+        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(); 
+            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; 
+            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()); 
+                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); 
+                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). 
+        
+        //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. 
+        // 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();                 
-
+            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.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 
+            
+            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; 
+                double temp = vi.zmin;
                 vi.zmin = vi.zmax;
-                vi.zmax = temp; 
+                vi.zmax = temp;
             }
         }
-
-        return vi; 
+        
+        return vi;
     }
     
     
     
- 
+    
     /**
-     * A UniquePV is a wrapper around IPhysicalVolumePath which provides 
-     * some convenience methods and caches transformations. 
+     * A UniquePV is a wrapper around IPhysicalVolumePath which provides
+     * some convenience methods and caches transformations.
      */
     class UniquePV{
         
-        IPhysicalVolumePath path; 
-        IPhysicalVolumeNavigator nav; 
-        ITransform3D transform = null; 
+        IPhysicalVolumePath path;
+        IPhysicalVolumeNavigator nav;
+        ITransform3D transform = null;
         
         /**
-         * Generates a top-level UniquePV. 
+         * 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); 
+            path = new PhysicalVolumePath();
+            nav = navigator;
+            path.add(root);
         }
         
         /**
          * Generates a UniquePV from a path. (Shallow copy of path)
-         * @param path 
+         * @param path
          * @param navigator
          */
         public UniquePV(IPhysicalVolumePath path, IPhysicalVolumeNavigator navigator){
-            this.path = path; 
-            nav = navigator; 
+            this.path = path;
+            nav = navigator;
         }
         
         /**
-         * Returns the IPhysicalVolume (the last element of the path) 
+         * Returns the IPhysicalVolume (the last element of the path)
          */
         public IPhysicalVolume getPV(){
             return path.getLeafVolume();
@@ -433,10 +452,10 @@
          * @return
          */
         public UniquePV createDaughterUniquePV(IPhysicalVolume daughter){
-            IPhysicalVolumePath np = new PhysicalVolumePath();  
-            np.addAll(path); 
-            np.add(daughter);        
-            return new UniquePV(np,nav); 
+            IPhysicalVolumePath np = new PhysicalVolumePath();
+            np.addAll(path);
+            np.add(daughter);
+            return new UniquePV(np,nav);
         }
         
         
@@ -447,34 +466,34 @@
          */
         public Hep3Vector localToGlobal(Hep3Vector v) {
             
-            return getLtoGTransform().transformed(v);       
+            return getLtoGTransform().transformed(v);
         }
         
         /**
-         * Returns the solid associated with the physical volume. 
+         * Returns the solid associated with the physical volume.
          * @return
          */
         public ISolid getSolid(){
-            return this.getPV().getLogicalVolume().getSolid(); 
+            return this.getPV().getLogicalVolume().getSolid();
         }
         
         /**
          * Returns the local-to-global transform
-         * @return an ITransform3D from local coordinates to global coordinates. 
+         * @return an ITransform3D from local coordinates to global coordinates.
          */
         public ITransform3D getLtoGTransform() {
             if (transform == null) {
-                transform = nav.getTransform(path); 
+                transform = nav.getTransform(path);
             }
-            return transform; 
+            return transform;
         }
         
-        @Override 
+        @Override
         public String toString(){
-            return path.toString(); 
+            return path.toString();
         }
     }
-            
-            
-            
+    
+    
+    
 }

lcsim/src/org/lcsim/recon/tracking/seedtracker
MultipleScattering.java 1.2 -> 1.3
diff -u -r1.2 -r1.3
--- MultipleScattering.java	9 Oct 2008 17:47:30 -0000	1.2
+++ MultipleScattering.java	13 Oct 2008 01:05:28 -0000	1.3
@@ -12,6 +12,7 @@
 import hep.physics.vec.VecOp;
 
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -28,7 +29,6 @@
  * @version 1.0
  */
 public class MultipleScattering {
-    private HelixUtils _hutil = new HelixUtils();
     private MaterialManager _materialmanager;
     private double _bfield = 0.;
     private int _mxint = 10;
@@ -41,77 +41,7 @@
     public MultipleScattering(MaterialManager materialmanager) {
         _materialmanager = materialmanager;
     }
-    
-    /**
-     * Calculate the multiple scattering errors for a given helix.
-     * The Helix PathMap is used to determine the x-y path length
-     * from the DCA to the hits on the helix.
-     * 
-     * 
-     * @param helix HelicalTrackFit that we want the ms errors for
-     * @return map containing the MultipleScatter objects for each hit
-     */
-    public Map<HelicalTrackHit, MultipleScatter> HelixScatters(HelicalTrackFit helix, List<HelicalTrackHit> hitlist) {
-        
-        //  Create an empty map to hold the multiple scattering errors
-        Map<HelicalTrackHit, MultipleScatter> msmap = new HashMap<HelicalTrackHit, MultipleScatter>();
-        
-        //  Retreive the x-y path lengths and calculate sin^2(theta) for this helix
-        Map<HelicalTrackHit, Double> pathmap = helix.PathMap();
-        double sth2 = Math.pow(helix.sth(), 2);
-        
-        //  Make sure all hits have x-y path lengths.  Hits added since the last fit
-        //  won't have path lengths, so estimate the path length measured from the DCA
-        for (HelicalTrackHit hit : hitlist) {
-            if (!pathmap.containsKey(hit)) {
-                pathmap.put(hit, (Double) _hutil.PathLength(helix, hit));
-            }
-        }
-        
-        //  Construct a list of material scatterings for this helix
-        List<ScatterAngle> scatters = FindScatters(helix);
-        
-        //  Loop over the hits on the helix and calculate the multiple scattering errors
-        for (HelicalTrackHit hit : hitlist) {
-            double hitpath = pathmap.get(hit);
-            
-            //  Loop over scattering points and sum in quadrature ms errors for this hit.
-            //  It is assumed that we can ignore ms correlations during the track-finding stage.
-            double rphi_ms2 = 0.;
-            double z_ms2 = 0.;
-            for (ScatterAngle scat : scatters) {
-                
-                //  Find the x-y path length to this scatter
-                double scatpath = scat.PathLen();
-                
-                //  If the scatter is before the hit, calculate the ms errors for this scatter
-                if (scatpath < hitpath) {
-                    
-                    //  Get the multiple scattering plane angle for this scatter
-                    double angle = scat.Angle();
-                    
-                    //  Sum in quadrature the r-phi ms errors.  It is assumed that we
-                    //  can ignore track curvature in calculating these errors during
-                    //  the track-finding stage.
-                    rphi_ms2 += Math.pow((hitpath - scatpath) * angle, 2);
-                    
-                    //  Sum in quadrature the z ms errors assuming a barrel geometry where
-                    //  the path length is fixed.  While z is fixed for disk detectors, we
-                    //  still do a z vs s fit by assuming the track direction is reasonably
-                    //  well known and converting the radial measurement error into an effective
-                    //  z coordinate error.
-                    z_ms2 += Math.pow((hitpath - scatpath) * angle / sth2, 2);
-                }
-            }
-            
-            //  Create a new MultipleScatter object and store it in the map of ms errors
-            MultipleScatter ms = new MultipleScatter(Math.sqrt(rphi_ms2), Math.sqrt(z_ms2));
-            msmap.put(hit, ms);
-        }
-        
-        return msmap;
-    }
-    
+     
     /**
      * Find the path lengths and multiple scattering angles for each
      * intersection of the helix with tracker material
@@ -131,22 +61,19 @@
         List<MaterialDisk> matdsk = _materialmanager.getMaterialDisks();
         
         //  Find the largest path length to a hit
-        double smax = 0.;
-        for (Map.Entry<HelicalTrackHit, Double> mapentry : helix.PathMap().entrySet()) {
-            smax = Math.max(smax, mapentry.getValue());
-        }
+        double smax = 9999.;
         
         //  We can't go further than the ECal, however
         double rmax = _materialmanager.getRMax();
-        List<Double> slist = _hutil.PathToCylinder(helix, rmax, smax, 1);
-        for (Double s : slist) {
-            smax = Math.min(smax, s);
-        }
+        List<Double> slist = HelixUtils.PathToCylinder(helix, rmax, smax, 1);
+        if (slist.size() > 0) smax = Math.min(smax, slist.get(0));
+        double zmax = _materialmanager.getZMax();
+        smax = Math.min(smax, HelixUtils.PathToZPlane(helix, zmax));
         
         for (MaterialDisk disk : matdsk) {
-            double s = _hutil.PathToZPlane(helix, disk.z());
+            double s = HelixUtils.PathToZPlane(helix, disk.z());
             if (s > 0. && s < smax) {
-                Hep3Vector pos = _hutil.PointOnHelix(helix, s);
+                Hep3Vector pos = HelixUtils.PointOnHelix(helix, s);
                 double r = Math.sqrt(Math.pow(pos.x(), 2) + Math.pow(pos.y(),2));
                 if (r >= disk.rmin() && r <= disk.rmax()) {
                     double cth = Math.abs(helix.cth());
@@ -159,18 +86,18 @@
         
         for (MaterialCylinder cyl : matcyl) {
             double r = cyl.radius();
-            double scmin = _hutil.PathToZPlane(helix, cyl.zmin());
-            double scmax = _hutil.PathToZPlane(helix, cyl.zmax());
+            double scmin = HelixUtils.PathToZPlane(helix, cyl.zmin());
+            double scmax = HelixUtils.PathToZPlane(helix, cyl.zmax());
             if (scmin > scmax) {
                 double temp = scmin;
                 scmin = scmax;
                 scmax = temp;
             }
-            List<Double> pathlist = _hutil.PathToCylinder(helix, r, smax, _mxint);
+            List<Double> pathlist = HelixUtils.PathToCylinder(helix, r, smax, _mxint);
             for (Double s : pathlist) {
                 if (s > scmin && s < scmax) {
-                    Hep3Vector dir = _hutil.Direction(helix, s);
-                    Hep3Vector pos = _hutil.PointOnHelix(helix, s);
+                    Hep3Vector dir = HelixUtils.Direction(helix, s);
+                    Hep3Vector pos = HelixUtils.PointOnHelix(helix, s);
                     Hep3Vector rhat = VecOp.unit(new BasicHep3Vector(pos.x(), pos.y(), 0.));
                     double cth = Math.abs(VecOp.dot(dir, rhat));
                     double radlen = cyl.ThicknessInRL() / Math.max(cth, 0.001);
@@ -179,9 +106,58 @@
                 }
             }
         }
+       
+        //  Sort the multiple scatters by their path length
+        Collections.sort(scatters);
         return scatters;
     }
     
+    public static MultipleScatter CalculateScatter(HelicalTrackHit hit, HelicalTrackFit helix, List<ScatterAngle> scatters) {
+        
+        //  Retreive the x-y path length and calculate sin^2(theta) for this helix
+        double sth2 = Math.pow(helix.sth(), 2);
+        
+        //  Make sure the hit has an x-y path lengths.  Hits added since the last fit
+        //  won't have path lengths, so estimate the path length measured from the DCA
+        Map<HelicalTrackHit, Double> pathmap = helix.PathMap();
+        if (!pathmap.containsKey(hit)) {
+            pathmap.put(hit, (Double) HelixUtils.PathLength(helix, hit));
+        }
+        
+        double hitpath = pathmap.get(hit);
+        
+        //  Loop over scattering points and sum in quadrature ms errors for this hit.
+        //  It is assumed that we can ignore ms correlations during the track-finding stage.
+        double rphi_ms2 = 0.;
+        double z_ms2 = 0.;
+        for (ScatterAngle scat : scatters) {
+            
+            //  Find the x-y path length to this scatter
+            double scatpath = scat.PathLen();
+            
+            //  If the scatter is before the hit, calculate the ms errors for this scatter
+            if (scatpath > hitpath) break;
+            
+            //  Get the multiple scattering plane angle for this scatter
+            double angle = scat.Angle();
+            
+            //  Sum in quadrature the r-phi ms errors.  It is assumed that we
+            //  can ignore track curvature in calculating these errors during
+            //  the track-finding stage.
+            rphi_ms2 += Math.pow((hitpath - scatpath) * angle, 2);
+            
+            //  Sum in quadrature the z ms errors assuming a barrel geometry where
+            //  the path length is fixed.  While z is fixed for disk detectors, we
+            //  still do a z vs s fit by assuming the track direction is reasonably
+            //  well known and converting the radial measurement error into an effective
+            //  z coordinate error.
+            z_ms2 += Math.pow((hitpath - scatpath) * angle / sth2, 2);
+        }
+        
+        //  Return the requested MultipleScatter
+        return new MultipleScatter(Math.sqrt(rphi_ms2), Math.sqrt(z_ms2));
+    }
+      
     public void setBField(double bfield) {
         _bfield = bfield;
         return;
@@ -192,4 +168,4 @@
         double angle = (0.0136 / p) * Math.sqrt(radlength) * (1.0 + 0.038 * Math.log(radlength));
         return angle;
     }
-}
+}
\ No newline at end of file

lcsim/src/org/lcsim/recon/tracking/seedtracker
ScatterAngle.java 1.1 -> 1.2
diff -u -r1.1 -r1.2
--- ScatterAngle.java	27 Aug 2008 17:59:02 -0000	1.1
+++ ScatterAngle.java	13 Oct 2008 01:05:28 -0000	1.2
@@ -12,7 +12,7 @@
  * @author Richard Partridge
  * @version 1.0
  */
-public class ScatterAngle {
+public class ScatterAngle implements Comparable {
     private double _pathlen;
     private double _angle;
     
@@ -29,4 +29,11 @@
     public double Angle() {
         return _angle;
     }
+    
+    public int compareTo(Object scatter2) {
+        double s2 = ((ScatterAngle) scatter2).PathLen();
+        if (_pathlen < s2) return -1;
+        if (_pathlen == s2) return 0;
+        return 1;
+    }    
 }
\ No newline at end of file

lcsim/src/org/lcsim/recon/tracking/seedtracker
SeedCandidate.java 1.1 -> 1.2
diff -u -r1.1 -r1.2
--- SeedCandidate.java	27 Aug 2008 17:59:02 -0000	1.1
+++ SeedCandidate.java	13 Oct 2008 01:05:28 -0000	1.2
@@ -9,11 +9,14 @@
 
 package org.lcsim.recon.tracking.seedtracker;
 
+import java.util.HashMap;
 import java.util.LinkedList;
 import java.util.List;
+import java.util.Map;
 
 import org.lcsim.fit.helicaltrack.HelicalTrackFit;
 import org.lcsim.fit.helicaltrack.HelicalTrackHit;
+import org.lcsim.fit.helicaltrack.MultipleScatter;
 
 /**
  * The SeedCandidate class encapsulates information about a track seed as it
@@ -23,16 +26,20 @@
  */
 public class SeedCandidate {
     
-    private List<HelicalTrackHit> _hits = new LinkedList<HelicalTrackHit>();
+    private List<HelicalTrackHit> _hits;
     private HelicalTrackFit _helix;
     private SeedStrategy _strategy;
+    private Map<HelicalTrackHit, MultipleScatter> _msmap;
+    private List<ScatterAngle> _scatters;
     
     /**
      * Create an empty SeedCandidate.
      */
     public SeedCandidate(SeedStrategy strategy) {
         _strategy = strategy;
-    }
+        _hits = new LinkedList<HelicalTrackHit>();
+        _msmap = new HashMap<HelicalTrackHit, MultipleScatter>();
+     }
     
     /**
      * Create a new SeedCandidate from a list of hits.
@@ -61,6 +68,8 @@
      */
     public SeedCandidate(SeedCandidate seed) {
         this(seed.getHits(), seed.getSeedStrategy(), seed.getHelix());
+        _msmap.putAll(seed.getMSMap());
+        _scatters = seed.getScatterAngles();
     }
     
     /**
@@ -78,7 +87,11 @@
      * @param hit TrackerHit to be added to the SeedCandidate
      */
     public void addHit(HelicalTrackHit hit) {
-        if (!_hits.contains(hit)) _hits.add(hit);
+        //  If this is a new hit, add it to the list of hits and calculate the multiple scattering error
+        if (!_hits.contains(hit)) {
+            _hits.add(hit);
+            UpdateMSMap(hit);
+        }
         return;
     }
     
@@ -114,7 +127,7 @@
      */
     public void setHelix(HelicalTrackFit helix) {
         _helix = helix;
-        return;
+       return;
     }
     
     /**
@@ -124,4 +137,38 @@
     public HelicalTrackFit getHelix() {
         return _helix;
     }
+    
+    public void setMSMap(Map<HelicalTrackHit, MultipleScatter> msmap) {
+        _msmap = msmap;
+        return;
+    }
+
+    public Map<HelicalTrackHit, MultipleScatter> getMSMap() {
+        return _msmap;
+    }
+        
+    public void setScatterAngles(List<ScatterAngle> scatters) {
+        
+        //  Save the list of MS scattering angles
+        _scatters = scatters;
+        
+        //  Calculate the multiple scattering error for each hit
+        for (HelicalTrackHit hit : _hits) {
+            UpdateMSMap(hit);
+        }
+        
+        return;
+    }
+    
+    public List<ScatterAngle> getScatterAngles() {
+        return _scatters;
+    }
+    
+    private void UpdateMSMap(HelicalTrackHit hit) {
+        if (_helix == null) return;
+        if (_scatters == null) return;
+        _msmap.put(hit, MultipleScattering.CalculateScatter(hit, _helix, _scatters));
+        return;
+    }
+    
 }
\ No newline at end of file

lcsim/src/org/lcsim/recon/tracking/seedtracker
SeedTracker.java 1.2 -> 1.3
diff -u -r1.2 -r1.3
--- SeedTracker.java	9 Oct 2008 17:47:30 -0000	1.2
+++ SeedTracker.java	13 Oct 2008 01:05:28 -0000	1.3
@@ -106,8 +106,8 @@
         
         //  Find the bfield and pass it to the helix fitter and diagnostic package
         _bfield = detector.getFieldMap().getField(_IP).z();
-        _helixfitter.setBField(_bfield);
         if (_diag!=null) _diag.setBField(_bfield);
+        _helixfitter.setBField(_bfield);
     }
     
     /**
CVSspam 0.2.8