Author: [log in to unmask] Date: Wed Nov 25 16:55:06 2015 New Revision: 3992 Log: not working Added: java/trunk/users/src/main/java/org/hps/users/phansson/STUtils.java java/trunk/users/src/main/java/org/hps/users/phansson/StraightThroughAnalysisDriver.java Added: java/trunk/users/src/main/java/org/hps/users/phansson/STUtils.java ============================================================================= --- java/trunk/users/src/main/java/org/hps/users/phansson/STUtils.java (added) +++ java/trunk/users/src/main/java/org/hps/users/phansson/STUtils.java Wed Nov 25 16:55:06 2015 @@ -0,0 +1,806 @@ +/** + * + */ +package org.hps.users.phansson; + +import hep.physics.vec.BasicHep3Matrix; +import hep.physics.vec.BasicHep3Vector; +import hep.physics.vec.Hep3Matrix; +import hep.physics.vec.Hep3Vector; +import hep.physics.vec.VecOp; + +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.List; +import java.util.logging.Logger; + +import org.apache.commons.math3.stat.regression.SimpleRegression; +import org.hps.users.phansson.STUtils.STStereoTrack.VIEW; +import org.lcsim.detector.ITransform3D; +import org.lcsim.detector.tracker.silicon.HpsSiSensor; +import org.lcsim.event.EventHeader; +import org.lcsim.event.RawTrackerHit; +import org.lcsim.fit.helicaltrack.HelicalTrackCross; +import org.lcsim.fit.helicaltrack.HitUtils; +import org.lcsim.fit.line.SlopeInterceptLineFit; +import org.lcsim.fit.line.SlopeInterceptLineFitter; +import org.lcsim.recon.tracking.digitization.sisim.SiTrackerHitStrip1D; +import org.lcsim.recon.tracking.digitization.sisim.TrackerHitType.CoordinateSystem; + +/** + * Class with static utilities for straight through tracking. + * + * @author Per Hansson Adrian <[log in to unmask]> + * + */ +public class STUtils { + + public final static Logger logger = Logger.getLogger(STUtils.class.getSimpleName()); + + + /** + * Private constructor to avoid instantiation. + */ + private STUtils() { + } + + + abstract static class STBaseTrack { + protected List<STUtils.STTrackFit> fit = new ArrayList<STUtils.STTrackFit>(); + protected abstract double getIntercept(); + protected abstract double getSlope(); + protected abstract double getPath(double dz); + public double predict(double zHit) { + checkFit(); + return getFit().predict(zHit); + } + public STUtils.STTrackFit getFit() { + return getFit(0); + } + public STUtils.STTrackFit getFit(int i) { + if(i<fit.size()) + return fit.get(i); + else + return null; + } + public void addFit(STUtils.STTrackFit fit) { + this.fit.add(fit); + } + protected void checkFit() { + if(getFit() == null) throw new RuntimeException("This track has no fit"); + } + public abstract boolean isTop(); + public abstract String toString(); + public abstract List<double[]> getPointList(); + public void clearFit() { + fit.clear(); + } + + + } + + static class STTrack extends STBaseTrack { + private List<SiTrackerHitStrip1D> hits = new ArrayList<SiTrackerHitStrip1D>(); + + public STTrack() {} + + public void setHits(List<SiTrackerHitStrip1D> hits) { + this.hits = hits; + } + + public List<SiTrackerHitStrip1D> getHits() { + return hits; + } + + public double getIntercept() { + checkFit(); + return getFit().intercept(); + } + + public double getSlope() { + checkFit(); + return getFit().slope(); + } + + protected double getPath(double dz) { + double slope = getSlope(); + double dy = slope*dz; + return Math.sqrt( dz*dz + dy*dy ); + } + + public boolean isTop() { + if(hits.size()==0) throw new RuntimeException("need hits to determine half."); + return ((HpsSiSensor) hits.get(0).getRawHits().get(0).getDetectorElement()).isTopLayer(); + } + + public List<double[]> getPointList() { + List<double[]> l = new ArrayList<double[]>(); + for(SiTrackerHitStrip1D hit : hits) { + l.add( new double[]{hit.getPositionAsVector().z(), hit.getPositionAsVector().y()}); + } + return l; + } + + public String toString() { + String s = "STTrack: \n"; + s+= String.valueOf(hits.size()) + " hits:\n"; + for(SiTrackerHitStrip1D hit : hits) { + s += hit.getPositionAsVector().toString() + "(" + hit.getRawHits().get(0).getDetectorElement().getName() + ")\n"; + } + s += fit.toString(); + return s; + } + + } + + + + static class STStereoTrack { + protected static enum VIEW { YZ,XZ }; + private List<STUtils.StereoPair> hits = new ArrayList<STUtils.StereoPair>(); + protected STTrackFit fit[] = {null,null}; + + public STStereoTrack() { + } + + void checkView(VIEW view) { + if(!view.equals(VIEW.YZ) && !view.equals(VIEW.XZ)) throw new RuntimeException("This view is not valid."); + } + + public double[] predict(double z) { + checkFit(VIEW.XZ); + checkFit(VIEW.YZ); + double p[] = new double[2]; + double s = getSignedPathLength(this, z, VIEW.YZ); + p[VIEW.YZ.ordinal()] = predict(z, VIEW.YZ); + p[VIEW.XZ.ordinal()] = predict(s, VIEW.XZ); + return p; + } + + private double predict(double z, VIEW view) { + checkView(view); + return getFit(view).predict(z); + } + + public STTrackFit getFit(VIEW view) { + return fit[view.ordinal()]; + } + + public void setFit(STTrackFit f, VIEW view) { + fit[view.ordinal()] = f; + } + + protected void checkFit(VIEW view) { + if(getFit(view) == null) throw new RuntimeException("This track has no fit"); + } + + public void clearFit() { + clearFit(VIEW.XZ); + clearFit(VIEW.YZ); + } + + public void clearFit(VIEW view) { + fit[view.ordinal()] = null; + } + + /** + * Track direction. Assumes track moves in positive z. + * @return track direction. + */ + public Hep3Vector getDirection() { + double dxdz = getFit(VIEW.XZ).slope(); + double dydz = getFit(VIEW.YZ).slope(); + double dzdz = 1- Math.sqrt( dxdz*dxdz + dydz*dydz); + return new BasicHep3Vector(dxdz, dydz, dzdz); + } + + public List<StereoPair> getHits() { + return hits; + } + + protected double[] getIntercept() { + double[] p = new double[2]; + p[VIEW.XZ.ordinal()] = getIntercept(VIEW.XZ); + p[VIEW.YZ.ordinal()] = getIntercept(VIEW.YZ); + return p; + } + + private double getIntercept(VIEW view) { + checkView(view); + return getFit(view).intercept(); + } + + protected double[] getSlope() { + double[] p = new double[2]; + p[VIEW.XZ.ordinal()] = getSlope(VIEW.XZ); + p[VIEW.YZ.ordinal()] = getSlope(VIEW.YZ); + return p; + } + + private double getSlope(VIEW view) { + checkView(view); + return getFit(view).slope(); + } + + public void setHits(List<STUtils.StereoPair> seedHits) { + hits = seedHits; + } + + public boolean isTop() { + if(hits.size()==0) throw new RuntimeException("need hits to determine half."); + return ((HpsSiSensor) hits.get(0).getAxial().getRawHits().get(0).getDetectorElement()).isTopLayer(); + } + + /** + * Get list of points that would be used in a simple univariate regression. + * Note that one {@link VIEW} uses the path length. + * @param view - {@link VIEW} to be obtained + * @return {@link List} of points for this track. + */ + public List<double[]> getPointList(VIEW view) { + checkView(view); + List<double[]> l = new ArrayList<double[]>(); + for(StereoPair hit : hits) { + Hep3Vector p = hit.getPosition(); + // get the path length + // in one view this is simple the z-position. + double s = view.compareTo(VIEW.YZ) == 0 ? p.z() : getSignedPathLength(this, p.z(), VIEW.YZ); + double y = view.equals(VIEW.YZ) ? p.y() : p.x(); + l.add( new double[]{s, y} ); + } + return l; + } + + public String toString() { + StringBuffer sb = new StringBuffer("STStereoTrack:\n"); + sb.append(hits.size() + " stereo hits.\n"); + for(int i=0;i<2;++i) { + VIEW v = VIEW.values()[i]; + sb.append("View " + v.name() + ": \n"); + for(double[] xy : getPointList(v)) + sb.append(xy[0] + ", " + xy[1] + "\n"); + if(getFit(v)!=null) sb.append(getFit(v).toString()); + } + return sb.toString(); + } + + + + } + + static class StereoPair { + SiTrackerHitStrip1D axialCluster; + SiTrackerHitStrip1D stereoCluster; + Hep3Vector position = null; + public StereoPair(SiTrackerHitStrip1D axial, SiTrackerHitStrip1D stereo, Hep3Vector origin) { + this.axialCluster = axial; + this.stereoCluster = stereo; + this.position = STUtils.getStereoHitPositionFromReference(origin, getAxial(), getStereo()); + } + public void updatePosition(Hep3Vector trackDirection) { + position = STUtils.getPosition(trackDirection, axialCluster, stereoCluster); + + } + public SiTrackerHitStrip1D getStereo() { + return stereoCluster; + } + public SiTrackerHitStrip1D getAxial() { + return axialCluster; + } + public Hep3Vector getPosition() { + return position; + } + public static boolean passCuts(StereoPair pair) { + //find intersection with sensor + return true; + } + + } + + static class STTrackFit extends SlopeInterceptLineFit { + private String type; + public STTrackFit(String type, SlopeInterceptLineFit fit) { + super(fit.slope(), fit.intercept(), fit.slopeUncertainty(),fit.interceptUncertainty(),fit.covariance(),fit.chisquared(),fit.ndf()); + this.type = type; + } + public STTrackFit(String type, double slope, double intercept, double slopeUncertainty, double interceptUncertainty, double sigAB, double chisq, int ndf) { + super(slope, intercept,slopeUncertainty,interceptUncertainty,sigAB,chisq,ndf); + this.type = type; + } + public double predict(double zHit) { + return intercept() + slope() * zHit; + } + public String getType() { + return type; + } + public String toString() { + String s = "STTrackFit " + getType() + ": " + super.toString(); + return s; + } + } + + static abstract class STTrackFitter { + private STTrackFit fit = null; + public STTrackFitter() {} + abstract String getType(); + abstract public void fit(STTrack track); + abstract public void fit(List<double[]> xyList); + protected void setFit(STTrackFit fit) { + this.fit = fit; + } + public STTrackFit getFit() { return fit; } + void clear() { + fit = null; + } + abstract public void setErrY(double err_y); + + } + + static class RegressionFit extends STTrackFitter { + private static final String TYPE = "SimpleRegression"; + public void fit(List<double[]> xyList) { + clear(); + SimpleRegression regression = new SimpleRegression(); + for(double[] hit : xyList) { + regression.addData(hit[0], hit[1]); + } + setFit(new STTrackFit(TYPE,regression.getSlope(), regression.getIntercept(), regression.getSlopeStdErr(), regression.getInterceptStdErr(), regression.getR(), 0.0, (int) (regression.getN()-2))); + } + public void fit(STTrack track) { + fit(track.getPointList()); + } + String getType() { + return TYPE; + } + public void setErrY(double err_y) { + } + } + + private static class LineFit extends STTrackFitter { + private static final String TYPE = "LineFit"; + private double errY = 6e-3; + String getType() { + return TYPE; + } + public void setErrY(double err_y) { + this.errY = err_y; + } + public void fit(STTrack track) { + fit(track.getPointList()); + } + @Override + public void fit(List<double[]> xyList) { + int n = xyList.size(); + double[] x = new double[n]; + double[] y = new double[n]; + double[] sigma_y = new double[n]; + for(int i=0; i<n; ++i ) { + x[i] = xyList.get(i)[0]; + y[i] = xyList.get(i)[1]; + sigma_y[i] = errY; + } + SlopeInterceptLineFitter fitter = new SlopeInterceptLineFitter(); + fitter.fit(x, y, sigma_y, n); + setFit( new STTrackFit(TYPE, fitter.getFit()) ); + } + + } + + + static Hep3Vector getOrigin(SiTrackerHitStrip1D stripCluster) { + SiTrackerHitStrip1D local = stripCluster.getTransformedHit(CoordinateSystem.SENSOR); + ITransform3D trans = local.getLocalToGlobal(); + return trans.transformed(StraightThroughAnalysisDriver.origo); + } + + static Hep3Vector getNormal(SiTrackerHitStrip1D s2) { + Hep3Vector u2 = s2.getMeasuredCoordinate(); + Hep3Vector v2 = s2.getUnmeasuredCoordinate(); + return VecOp.cross(u2, v2); + } + + /** + * Basically an adaptation of what's in {@link HelicalTrackCross}. + * @param origin + * @param strip1 + * @param strip2 + * @return + */ + static Hep3Vector getStereoHitPositionFromReference(Hep3Vector origin, SiTrackerHitStrip1D strip1, SiTrackerHitStrip1D strip2) { + SiTrackerHitStrip1D s1 = strip1; + SiTrackerHitStrip1D s2 = strip2; + // sort in direction of track + // TODO do I need to sort these? + if(s1.getPositionAsVector().z() > s2.getPositionAsVector().z()) { s1 = strip2; s2 = strip1; } + + StraightThroughAnalysisDriver.logger.finest("Calculate stereo hit position assuming track from " + origin.toString()); + + // Get origin of sensors + Hep3Vector o1 = getOrigin(s1); + Hep3Vector o2 = getOrigin(s2); + + // Get sensor orientation + Hep3Vector u1 = s1.getMeasuredCoordinate(); + Hep3Vector v1 = s1.getUnmeasuredCoordinate(); + Hep3Vector w1 = getNormal(s1); + Hep3Vector u2 = s2.getMeasuredCoordinate(); + Hep3Vector v2 = s2.getUnmeasuredCoordinate(); + Hep3Vector w2 = getNormal(s2); + + // update origin calculation with displaced origin + o1 = VecOp.sub(o1, origin); + o2 = VecOp.sub(o2, origin); + + // For this to work the normal needs to point along track i.e. along z for both sensors + // so rotate coordinate system pi around u axis in this case + if(VecOp.dot(w1, o1) < 0) { + v1 = VecOp.mult(-1.0, v1); + w1 = VecOp.cross(u1, v1); + } + if(VecOp.dot(w2, o2) < 0) { + v2 = VecOp.mult(-1.0, v2); + w2 = VecOp.cross(u2, v2); + } + + + StraightThroughAnalysisDriver.logger.finest("o1 " + o1.toString()); + StraightThroughAnalysisDriver.logger.finest("u1 " + u1.toString()); + StraightThroughAnalysisDriver.logger.finest("v1 " + v1.toString()); + StraightThroughAnalysisDriver.logger.finest("w1 " + w1.toString()); + StraightThroughAnalysisDriver.logger.finest("o2 " + o2.toString()); + StraightThroughAnalysisDriver.logger.finest("u2 " + u2.toString()); + StraightThroughAnalysisDriver.logger.finest("v2 " + v2.toString()); + StraightThroughAnalysisDriver.logger.finest("w2 " + w2.toString()); + + + // Get the measured strip position on each sensor (basically origin + mult(umeas,u)) + Hep3Vector p1 = s1.getPositionAsVector(); + Hep3Vector p2 = s2.getPositionAsVector(); + StraightThroughAnalysisDriver.logger.finest("p1 " + p1.toString()); + StraightThroughAnalysisDriver.logger.finest("p2 " + p2.toString()); + + // sin(stereo angle) + double sinAlpha = VecOp.dot(v1, u2); + StraightThroughAnalysisDriver.logger.finest("sinAlpha " + sinAlpha); + + // check + if(Math.abs( VecOp.dot(o1, w1)) < 0.0001) throw new RuntimeException("o1 and w1 are orthogonal: o1 " + o1.toString() + " w1 " + w1.toString()); + + // calculate effective distance along z + double gamma = VecOp.dot(o2, w2) / VecOp.dot(o1, w1); + StraightThroughAnalysisDriver.logger.finest("gamma " + gamma); + + // Get the vector between the two strip (center) positions + Hep3Vector dp = VecOp.sub(p2, VecOp.mult(gamma, p1)); + StraightThroughAnalysisDriver.logger.finest("dp " + dp.toString()); + + // Get the projection onto u2 and scale with stereo angle to get un-measured coordinate + double p1_v = VecOp.dot(dp, u2) / (gamma * sinAlpha); + StraightThroughAnalysisDriver.logger.finest("p1_v " + p1_v); + + // calculate the position of the hit on the strip + Hep3Vector r1 = VecOp.add(p1, VecOp.mult(p1_v, v1)); + StraightThroughAnalysisDriver.logger.finest("r1 " + r1.toString()); + + // Take the final position as the half-way between the sensors + Hep3Vector p = VecOp.mult( 0.5 * ( 1 + gamma ), r1); + + StraightThroughAnalysisDriver.logger.finest("p " + p.toString()); + + + return p; + + } + + /** + * Basically the same as what's in {@link HitUtils}. + * @param origin + * @param strip1 + * @param strip2 + * @return + */ + static Hep3Vector getPosition(Hep3Vector t, SiTrackerHitStrip1D strip1, SiTrackerHitStrip1D strip2) { + SiTrackerHitStrip1D s1 = strip1; + SiTrackerHitStrip1D s2 = strip2; + // sort in direction of track + // TODO do I need to sort these? + if(s1.getPositionAsVector().z() > s2.getPositionAsVector().z()) { s1 = strip2; s2 = strip1; } + + StraightThroughAnalysisDriver.logger.finest("Calculate stereo hit position assuming track direction " + t.toString()); + + // Get origin of sensors + Hep3Vector o1 = getOrigin(s1); + Hep3Vector o2 = getOrigin(s2); + + // Get sensor orientation + Hep3Vector u1 = s1.getMeasuredCoordinate(); + Hep3Vector v1 = s1.getUnmeasuredCoordinate(); + Hep3Vector w1 = getNormal(s1); + Hep3Vector u2 = s2.getMeasuredCoordinate(); + Hep3Vector v2 = s2.getUnmeasuredCoordinate(); + Hep3Vector w2 = getNormal(s2); + + // For this to work the normal needs to point along track i.e. along z for both sensors + // so rotate coordinate system pi around u axis in this case + if(VecOp.dot(w1, o1) < 0) { + v1 = VecOp.mult(-1.0, v1); + w1 = VecOp.cross(u1, v1); + } + if(VecOp.dot(w2, o2) < 0) { + v2 = VecOp.mult(-1.0, v2); + w2 = VecOp.cross(u2, v2); + } + + + StraightThroughAnalysisDriver.logger.finest("o1 " + o1.toString()); + StraightThroughAnalysisDriver.logger.finest("u1 " + u1.toString()); + StraightThroughAnalysisDriver.logger.finest("v1 " + v1.toString()); + StraightThroughAnalysisDriver.logger.finest("w1 " + w1.toString()); + StraightThroughAnalysisDriver.logger.finest("o2 " + o2.toString()); + StraightThroughAnalysisDriver.logger.finest("u2 " + u2.toString()); + StraightThroughAnalysisDriver.logger.finest("v2 " + v2.toString()); + StraightThroughAnalysisDriver.logger.finest("w2 " + w2.toString()); + + + // Get the measured strip position on each sensor (basically origin + mult(umeas,u)) + Hep3Vector p1 = s1.getPositionAsVector(); + Hep3Vector p2 = s2.getPositionAsVector(); + StraightThroughAnalysisDriver.logger.finest("p1 " + p1.toString()); + StraightThroughAnalysisDriver.logger.finest("p2 " + p2.toString()); + + // sin(stereo angle) + double sinAlpha = VecOp.dot(v1, u2); + StraightThroughAnalysisDriver.logger.finest("sinAlpha " + sinAlpha); + + // check + if(Math.abs( VecOp.dot(o1, w1)) < 0.0001) throw new RuntimeException("o1 and w1 are orthogonal: o1 " + o1.toString() + " w1 " + w1.toString()); + + // calculate the distance between the sensors + double gamma = VecOp.dot( w1, VecOp.sub(o2, o1)) / VecOp.dot(w1, t); + StraightThroughAnalysisDriver.logger.finest("gamma " + gamma); + + // Get the vector along the track direction + Hep3Vector tgamma = VecOp.mult(gamma, t); + StraightThroughAnalysisDriver.logger.finest("tgamma " + tgamma.toString()); + + // Get the vector taking you from the midpoint of strip1 in the direction of the track + Hep3Vector p1Prime = VecOp.add(p1, tgamma); + StraightThroughAnalysisDriver.logger.finest("p1Prime " + p1Prime.toString()); + + // Get the vector between the predicted and measured center values on strip2 + Hep3Vector dp = VecOp.sub(p2, p1Prime); + StraightThroughAnalysisDriver.logger.finest("dp " + dp.toString()); + + // Get the projection onto u2 and scale with stereo angle to get un-measured coordinate + double p1_v = VecOp.dot(dp, u2) / (sinAlpha); + StraightThroughAnalysisDriver.logger.finest("p1_v " + p1_v + " (u2="+u2.toString()+")"); + + // calculate the position of the hit on the strip + Hep3Vector r1 = VecOp.add(p1, VecOp.mult(p1_v, v1)); + StraightThroughAnalysisDriver.logger.finest("r1 " + r1.toString() + "(v1="+v1.toString()+")"); + + // Take the final position as the half-way between the sensors + Hep3Vector p = VecOp.add(r1, VecOp.mult( 0.5 * gamma, t) ); + + StraightThroughAnalysisDriver.logger.finest("p " + p.toString()); + + + return p; + + } + + /** + * Fit the {@link STStereoTrack} track with the supplied {@link STTrackFitter} and add the fit to the track. + * @param regressionFitter + * @param track + */ + public static void fit(STTrackFitter regressionFitter, STStereoTrack track) { + track.clearFit(); + regressionFitter.fit(track.getPointList(STStereoTrack.VIEW.YZ)); + track.setFit(regressionFitter.getFit(), STStereoTrack.VIEW.YZ); + + regressionFitter.fit(track.getPointList(STStereoTrack.VIEW.XZ)); + track.setFit(regressionFitter.getFit(), STStereoTrack.VIEW.XZ); + + } + + public static double getSignedPathLength(STStereoTrack track, double z, STStereoTrack.VIEW view) { + double slope = track.getSlope(view); + double dy = slope*z; + return z > 0 ? Math.sqrt( z*z + dy*dy ) : -1*Math.sqrt( z*z + dy*dy ); + } + + + + + public static void printGBL(PrintWriter printWriter, EventHeader event, List<STStereoTrack> tracks) { + printWriter.printf("New Event %d %f", event.getEventNumber(), 0.0); + printWriter.println(); + for(int iTrack=0; iTrack<tracks.size(); ++iTrack) { + + STStereoTrack track = tracks.get(iTrack); + + printWriter.printf("New Track %d", iTrack); + printWriter.println(); + + double[] perPars = getPerPars(track); + printWriter.printf("Track perPar (x0 y0 dxdz dydz) %.12f %.12f %.12f %.12f", perPars[0],perPars[1],perPars[2],perPars[3]); + printWriter.println(); + + double[] clPars = getCLPars(track); + printWriter.printf("Track clPar (xT yT dxTdz dyTdz) %.12f %.12f %.12f %.12f", clPars[0],clPars[1],clPars[2],clPars[3]); + printWriter.println(); + + Hep3Matrix clPrj = curvilinearProjectionMatrix(track.getDirection()); + StringBuffer sb = new StringBuffer(); + for(int i=0;i!=3;++i) + for(int j=0;j!=3;++j) + sb.append(String.format("%.8f ", clPrj.e(i, j))); + printWriter.printf("Track clPrj %s", sb.toString()); + printWriter.println(); + + //List<SiTrackerHitStrip1D> stripHits = new ArrayList<SiTrackerHitStrip1D>(); + int iStrip = 0; + for(StereoPair pair : track.getHits()) { + SiTrackerHitStrip1D strips[] = new SiTrackerHitStrip1D[2]; + if(pair.getAxial().getPosition()[2] < pair.getStereo().getPosition()[2]) { + strips[0] = pair.getAxial(); + strips[1] = pair.getStereo(); + } else { + strips[1] = pair.getAxial(); + strips[0] = pair.getStereo(); + } + for(int i=0; i<strips.length;++i) { + SiTrackerHitStrip1D strip = strips[i]; + HpsSiSensor sensor = (HpsSiSensor) ((RawTrackerHit) strip.getRawHits().get(0)).getDetectorElement(); + printWriter.printf("New Strip id layer %d %d %s", iStrip, sensor.getMillepedeId(), sensor.getName() ); + printWriter.println(); + iStrip++; + } + } + + + } + + } + + + + + public static double[] getPerPars(STStereoTrack track) { + double intercept[] = track.getIntercept(); + double slope[] = track.getSlope(); + return new double[]{ + intercept[VIEW.XZ.ordinal()], + intercept[VIEW.YZ.ordinal()], + slope[VIEW.XZ.ordinal()], + slope[VIEW.YZ.ordinal()]}; + } + + + /** + * Computes projection matrix from the ST variables x0,y0,z0 + * to the curvilinear xT,yT,zT variables. + * + * @param track - {@link STStereoTrack} + * @return 3x3 projection matrix + */ + static Hep3Matrix curvilinearProjectionMatrix(Hep3Vector dir) { + + Hep3Vector X = new BasicHep3Vector(1, 0, 0); + Hep3Vector Y = new BasicHep3Vector(0, 1, 0); + Hep3Vector Z = new BasicHep3Vector(0, 0, 1); + + // build the curvilinear unit vectors: UVT + Hep3Vector T = dir; + Hep3Vector J = VecOp.mult(1. / VecOp.cross(T, Z).magnitude(), VecOp.cross(T, Z)); + Hep3Vector U = VecOp.mult(-1, J); + Hep3Vector V = VecOp.cross(T, U); + Hep3Vector K = Z; + Hep3Vector I = VecOp.cross(J, K); + + logger.info("U " + U.toString()); + logger.info("V " + V.toString()); + logger.info("T " + T.toString()); + logger.info("X " + X.toString()); + logger.info("Y " + Y.toString()); + logger.info("Z " + Z.toString()); + BasicHep3Matrix trans = new BasicHep3Matrix(); + trans.setElement(0, 0, VecOp.dot(X, U)); + trans.setElement(0, 1, VecOp.dot(Y, U)); + trans.setElement(0, 2, VecOp.dot(Z, U)); + trans.setElement(1, 0, VecOp.dot(X, V)); + trans.setElement(1, 1, VecOp.dot(Y, V)); + trans.setElement(1, 2, VecOp.dot(Z, V)); + trans.setElement(2, 0, VecOp.dot(X, T)); + trans.setElement(2, 1, VecOp.dot(Y, T)); + trans.setElement(2, 2, VecOp.dot(Z, T)); + + + + return trans; + + } + + + /** + * Computes projection matrix from the ST variables x0,y0,z0 + * to the curvilinear xT,yT,zT variables. + * + * @param track - {@link STStereoTrack} + * @return 3x3 projection matrix + */ + static Hep3Vector curvilinearProjection(double x0, double y0, Hep3Vector dir) { + final double z0 = 0; + Hep3Vector v = new BasicHep3Vector(x0, y0, z0); + Hep3Matrix trans = curvilinearProjectionMatrix(dir); + Hep3Vector vnew = VecOp.mult(trans, v); + + StringBuffer sb = new StringBuffer(); + sb.append("Convert v " + v.toString() + " in ST x,y,z to curvilinear frame xT,yT,zT with prjection matrix:\n"); + for(int i=0;i!=3;++i) { + sb.append("\n"); + for(int j=0;j!=3;++j) { + sb.append(trans.e(i, j) + " "); + } + } + sb.append("New vector is " + vnew.toString() + " in curvilinear frame xT,yT,zT"); + logger.info(sb.toString()); + + return vnew; + + } + + /** + * + * Get curvilinear track parameter. + */ + public static double[] getCLPars(STStereoTrack track) { + return getCLPars(track.getIntercept(VIEW.XZ), track.getIntercept(VIEW.YZ), track.getSlope(VIEW.XZ), track.getSlope(VIEW.YZ)); + } + + public static double[] getCLPars(double x0, double y0, double dxdz, double dydz) { + // track direction + Hep3Vector dir = new BasicHep3Vector(dxdz, dydz, 1 - Math.sqrt(dxdz*dxdz + dydz*dydz)); + + final double z0 = 0; + Hep3Vector v = new BasicHep3Vector(x0, y0, z0); + Hep3Matrix trans = curvilinearProjectionMatrix(dir); + Hep3Vector vnew = VecOp.mult(trans, v); + + // for readability + double xT = vnew.x(); + double yT = vnew.y(); + //double zT = vnew.z(); + + final double dzdz = 1.0; + Hep3Vector dxyz_dv = new BasicHep3Vector(dxdz, dydz, dzdz); + Hep3Vector dxyzT_dv = VecOp.mult(trans, dxyz_dv); + + // for readability + double xT_prime = dxyzT_dv.x(); + double yT_prime = dxyzT_dv.y(); + //double zT_prime = dxyzT_dv.z(); + + double clPars[] = new double[]{xT,yT,xT_prime,yT_prime}; + + logger.info("getCLPars: \n(x0,y0,z0) " + v.toString() + "\n(xT,yT,zT) " + vnew.toString() + "\nd/dz(x,y,z) " + dxyz_dv.toString() + "\nd/dz(xT,yT,zT) " + dxyzT_dv.toString() ); + StringBuffer sb = new StringBuffer(); + for(int i=0;i!=3;++i) { + sb.append("\n"); + for(int j=0;j!=3;++j) { + sb.append(trans.e(i, j) + " "); + } + } + logger.info("using CL prj matrix:\n" + sb.toString() + "\n and track direction "+ dir.toString()); + + return clPars; + } + + + + + + + +} Added: java/trunk/users/src/main/java/org/hps/users/phansson/StraightThroughAnalysisDriver.java ============================================================================= --- java/trunk/users/src/main/java/org/hps/users/phansson/StraightThroughAnalysisDriver.java (added) +++ java/trunk/users/src/main/java/org/hps/users/phansson/StraightThroughAnalysisDriver.java Wed Nov 25 16:55:06 2015 @@ -0,0 +1,853 @@ +/** + * + */ +package org.hps.users.phansson; + +import hep.aida.IAnalysisFactory; +import hep.aida.IFitResult; +import hep.aida.IHistogram1D; +import hep.aida.IHistogram2D; +import hep.aida.IHistogramFactory; +import hep.aida.IPlotter; +import hep.aida.IPlotterFactory; +import hep.aida.IPlotterStyle; +import hep.aida.ref.rootwriter.RootFileStore; +import hep.physics.vec.BasicHep3Vector; +import hep.physics.vec.Hep3Vector; +import hep.physics.vec.VecOp; + +import java.io.BufferedWriter; +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; + +import org.hps.monitoring.drivers.svt.SvtPlotUtils; +import org.hps.users.phansson.STUtils.STStereoTrack; +import org.lcsim.detector.converter.compact.subdetector.HpsTracker2; +import org.lcsim.detector.converter.compact.subdetector.SvtStereoLayer; +import org.lcsim.detector.tracker.silicon.HpsSiSensor; +import org.lcsim.event.EventHeader; +import org.lcsim.geometry.Detector; +import org.lcsim.geometry.compact.converter.HPSTrackerBuilder; +import org.lcsim.recon.tracking.digitization.sisim.SiTrackerHitStrip1D; +import org.lcsim.recon.tracking.digitization.sisim.TrackerHitType.CoordinateSystem; +import org.lcsim.util.Driver; +import org.lcsim.util.aida.AIDA; + +/** + * @author Per Hansson Adrian <[log in to unmask]> + * + */ +public class StraightThroughAnalysisDriver extends Driver { + + final static Logger logger = Logger.getLogger(StraightThroughAnalysisDriver.class.getSimpleName()); + private String stripClusterCollectionName = "StripClusterer_SiTrackerHitStrip1D"; + private List<HpsSiSensor> sensors = null; + private IHistogram1D hitCount; + private IHistogram1D topHitCount; + private IHistogram1D botHitCount; + private Map<String,IHistogram2D> stereoHitPositionsXY = new HashMap<String, IHistogram2D>(); + private Map<String,IHistogram1D> sensorHitResGlobal = new HashMap<String, IHistogram1D>(); + private Map<String,IHistogram1D> sensorStereoHitYZResGlobal = new HashMap<String, IHistogram1D>(); + private Map<String,IHistogram1D> sensorStereoHitXZResGlobal = new HashMap<String, IHistogram1D>(); + private Map<String,IHistogram1D> sensorHitPositions = new HashMap<String, IHistogram1D>(); + private Map<String,IHistogram1D> sensorHitCounts = new HashMap<String, IHistogram1D>(); + private Map<String,IHistogram1D> sensorHitTimes = new HashMap<String, IHistogram1D>(); + private Map<String,int[]> sensorHitCountMap = new HashMap<String,int[]>(); + private static AIDA aida = AIDA.defaultInstance(); + static final Hep3Vector origo = new BasicHep3Vector(0, 0, 0); + private static final Hep3Vector origoStraightThroughs = new BasicHep3Vector(0, 0, 0); + + private final IAnalysisFactory af = aida.analysisFactory(); + private final IHistogramFactory hf = af.createHistogramFactory(aida.tree()); + private final IPlotterFactory pf = af.createPlotterFactory("Factory"); + private Map<String,IPlotter> plotters = new HashMap<String, IPlotter>(); + private String rootFileName = ""; + private int runNumber = -1; + private IHistogram1D trackAxialHitCount[]; + private IHistogram1D trackAxialSlope[]; + private IHistogram1D trackAxialIntercept[]; + private IHistogram1D trackAxialCount[]; + private IHistogram2D trackAxialExtraPolation[]; + private IHistogram2D trackExtraPolationY[]; + private IHistogram2D trackExtraPolationX[]; + private IHistogram1D stereoHitCount[]; + private IHistogram1D trackHitCount[]; + private IHistogram1D trackSlope[][]; + private IHistogram1D trackIntercept[][]; + private IHistogram1D trackCount[]; + private IHistogram2D[] fitUpdateIteration; + + + private boolean selectTime = true; + private double timeMax = 8.0; + private double timeMin = -8.0; + private int minHitsAxialTrack = 6; + private int minHitsStereoTrack = 6; + private STUtils.STTrackFitter regressionFitter = new STUtils.RegressionFit(); + //private STTrackFitter regressionFitter = new LineFit(); + private final double startPointZ = 1500.0; + private final double endPointZ = -3000.0; + private final int nPointsZ = 100; + private final double[] wirePosition = {-67.23, 0.0, -2337.1}; + private String subdetectorName = "Tracker"; + private List<SvtStereoLayer> stereoLayers; + + private String outputFilename = ""; + private PrintWriter gblPrintWriter = null; + + + + /** + * + */ + public StraightThroughAnalysisDriver() { + logger.setLevel(Level.INFO); + STUtils.logger.setLevel(logger.getLevel()); + } + + + private static double getTheta0(double beta,double p,double X0) { + return 13.6/beta/p*Math.sqrt(X0)*(1 + 0.038*Math.log(X0)); + } + protected void detectorChanged(Detector detector) { + + if(!outputFilename.isEmpty()) { + try { + gblPrintWriter = new PrintWriter( new BufferedWriter(new FileWriter(outputFilename))); + } catch (IOException e) { + e.printStackTrace(); + } + logger.info("Created a GBL filewriter for to file \"" + outputFilename + "\""); + } + + // find the stereo layers for this detector + stereoLayers = ((HpsTracker2) detector.getSubdetector(subdetectorName).getDetectorElement()).getStereoPairs(); + StringBuffer sb = new StringBuffer("Found " + stereoLayers.size() + " stereo layers:"); + for(SvtStereoLayer sl : stereoLayers) sb.append(sl.getLayerNumber() + ": " + sl.getAxialSensor().getName()+ " - " + sl.getStereoSensor().getName() + "\n"); + logger.info(sb.toString()); + + // + double beta = 1.0; + double p = 1.05; + double X0 = 0.007; // per stereo pair + double theta0 = getTheta0(beta, p, X0); + double msErrY = 100.0*theta0; + regressionFitter.setErrY(msErrY); + + + // Get the HpsSiSensor objects from the geometry + sensors = detector.getSubdetector("Tracker").getDetectorElement().findDescendants(HpsSiSensor.class); + aida.tree().cd("/"); + plotters.put("Sensor hit position", af.createPlotterFactory().create("Sensor hit positions")); + plotters.get("Sensor hit position").setStyle(this.getDefaultPlotterStyle("Hit y (mm)","Entries")); + plotters.get("Sensor hit position").createRegions(6, 6); + plotters.put("Sensor hit res", af.createPlotterFactory().create("Sensor hit res")); + //plotters.get("Sensor hit res").setStyle(this.getDefaultPlotterStyle("Hit y res global (mm)","Entries")); + plotters.get("Sensor hit res").createRegions(3, 6); + plotters.put("Sensor stereo YZ hit res", af.createPlotterFactory().create("Sensor stereo YZ hit res")); + plotters.get("Sensor stereo YZ hit res").setStyle(this.getDefaultPlotterStyle("Stereo hit y res global (mm)","Entries")); + plotters.get("Sensor stereo YZ hit res").createRegions(3, 6); + plotters.put("Sensor stereo XZ hit res", af.createPlotterFactory().create("Sensor stereo XZ hit res")); + plotters.get("Sensor stereo XZ hit res").setStyle(this.getDefaultPlotterStyle("Stereo hit x res global (mm)","Entries")); + plotters.get("Sensor stereo XZ hit res").createRegions(3, 6); + plotters.put("Sensor hit times", af.createPlotterFactory().create("Sensor hit times")); + plotters.get("Sensor hit times").setStyle(this.getDefaultPlotterStyle("Hit time (ns)","Entries")); + plotters.get("Sensor hit times").createRegions(6, 6); + plotters.put("Sensor cluster counts", af.createPlotterFactory().create("Sensor cluster counts")); + plotters.get("Sensor cluster counts").setStyle(this.getDefaultPlotterStyle("Cluster multiplicity","Entries")); + plotters.get("Sensor cluster counts").createRegions(6, 6); + plotters.put("Cluster counts", af.createPlotterFactory().create("Cluster counts")); + plotters.get("Cluster counts").setStyle(this.getDefaultPlotterStyle("Cluster multiplicity","Entries")); + plotters.get("Cluster counts").createRegions(2,2); + plotters.put("Track axial extrapolation", af.createPlotterFactory().create("Track axial extrapolation")); + plotters.get("Track axial extrapolation").setStyle(this.getDefaultPlotterStyle("Z (mm)","Y (mm)")); + plotters.get("Track axial extrapolation").createRegions(2,3); + plotters.put("Track extrapolation Y", af.createPlotterFactory().create("Track extrapolation Y")); + plotters.get("Track extrapolation Y").setStyle(this.getDefaultPlotterStyle("Z (mm)","Y (mm)")); + plotters.get("Track extrapolation Y").createRegions(2,3); + plotters.put("Track extrapolation X", af.createPlotterFactory().create("Track extrapolation X")); + plotters.get("Track extrapolation X").setStyle(this.getDefaultPlotterStyle("Z (mm)","X (mm)")); + plotters.get("Track extrapolation X").createRegions(2,3); + plotters.put("Stereo hit position", af.createPlotterFactory().create("Stereo hit positions")); + plotters.get("Stereo hit position").setStyle(this.getDefaultPlotterStyle("Hit x (mm)","Hit y (mm)")); + plotters.get("Stereo hit position").createRegions(3, 6); + plotters.put("Stereo hit count", af.createPlotterFactory().create("Stereo hit count")); + plotters.get("Stereo hit count").createRegions(1, 2); + plotters.put("Fit update iterations", af.createPlotterFactory().create("Fit update iterations")); + plotters.get("Fit update iterations").setStyle(this.getDefaultPlotterStyle("Iterations","Average hit update magnitude (mm)")); + plotters.get("Fit update iterations").createRegions(1, 2); + + topHitCount = hf.createHistogram1D("Top hit count", 21,-0.5, 20.5); + botHitCount = hf.createHistogram1D("Bottom hit count", 21,-0.5, 20.5); + hitCount = hf.createHistogram1D("Hit count", 21, -0.5, 20.5); + trackAxialHitCount = new IHistogram1D[2]; + trackAxialCount = new IHistogram1D[2]; + trackAxialSlope = new IHistogram1D[2]; + trackAxialIntercept = new IHistogram1D[2]; + trackAxialExtraPolation = new IHistogram2D[5]; + trackExtraPolationY = new IHistogram2D[5]; + trackExtraPolationX = new IHistogram2D[5]; + stereoHitCount = new IHistogram1D[2]; + trackHitCount = new IHistogram1D[2]; + trackCount = new IHistogram1D[2]; + trackSlope = new IHistogram1D[2][]; + trackIntercept = new IHistogram1D[2][]; + fitUpdateIteration = new IHistogram2D[2]; + + + for(int i=0;i<2;++i) { + String half = i==0 ? "top" : "bottom"; + + trackHitCount[i]= hf.createHistogram1D("Track " + half + " hit multiplicity", 11, -0.5, 10.5); + trackCount[i] = hf.createHistogram1D("Track " + half + " multiplicity", 11, -0.5, 10.5); + trackSlope[i] = new IHistogram1D[2]; + trackIntercept[i] = new IHistogram1D[2]; + trackSlope[i][STUtils.STStereoTrack.VIEW.YZ.ordinal()] = hf.createHistogram1D("Track " + half +" " + STUtils.STStereoTrack.VIEW.YZ.name() + " slope", 50, -0.05, 0.05); + trackSlope[i][STUtils.STStereoTrack.VIEW.XZ.ordinal()] = hf.createHistogram1D("Track " + half +" " + STUtils.STStereoTrack.VIEW.XZ.name() + " slope", 50, -0.1, 0.1); + if(i==0) { + trackIntercept[i][STUtils.STStereoTrack.VIEW.YZ.ordinal()] = hf.createHistogram1D("Track " + half +" " + STUtils.STStereoTrack.VIEW.YZ.name() + " intecept", 50, 0, 50); + trackIntercept[i][STUtils.STStereoTrack.VIEW.XZ.ordinal()] = hf.createHistogram1D("Track " + half +" " + STUtils.STStereoTrack.VIEW.XZ.name() + " intecept", 50, -80, 0); + trackAxialIntercept[i] = hf.createHistogram1D("Track axial " + half +" intercept", 50, 0, 50); + } else { + trackIntercept[i][STUtils.STStereoTrack.VIEW.YZ.ordinal()] = hf.createHistogram1D("Track " + half +" " + STUtils.STStereoTrack.VIEW.YZ.name() + " intecept", 50, -50, 0); + trackIntercept[i][STUtils.STStereoTrack.VIEW.XZ.ordinal()] = hf.createHistogram1D("Track " + half +" " + STUtils.STStereoTrack.VIEW.XZ.name() + " intecept", 50, -50, 50); + trackAxialIntercept[i] = hf.createHistogram1D("Track axial " + half +" intercept", 50, -50, 0); + } + trackAxialHitCount[i] = hf.createHistogram1D("Track axial " + half +" hit multiplicity", 11, -0.5, 10.5); + trackAxialCount[i] = hf.createHistogram1D("Track axial " + half +" multiplicity", 2, -0.5, 1.5); + trackAxialSlope[i] = hf.createHistogram1D("Track axial " + half +" slope", 50, -0.05, 0.05); + trackAxialExtraPolation[i] = hf.createHistogram2D("Track axial " + half +" extrapolation", nPointsZ, endPointZ, startPointZ,50,-80,80); + trackExtraPolationY[i] = hf.createHistogram2D("Track " + half +" extrapolation Y", nPointsZ, endPointZ, startPointZ,50,-80,80); + trackExtraPolationX[i] = hf.createHistogram2D("Track " + half +" extrapolation X", nPointsZ, endPointZ, startPointZ,50,-100,60); + stereoHitCount[i] = hf.createHistogram1D("Stereo hit count " + half, 11, -0.5, 10.5); + + fitUpdateIteration[i] = hf.createHistogram2D("Fit update" + half, 6, -0.5, 6.5,50,0,20); + + plotters.get("Fit update iterations").region(i).plot(fitUpdateIteration[i]); + + plotters.put("Track " + half +" axial", af.createPlotterFactory().create("Track " + half +" axial")); + //plotters.get("Track " + half +" axial").setStyle(this.getDefaultPlotterStyle("","Entries",true)); + plotters.get("Track " + half +" axial").createRegions(2,2); + + plotters.get("Track " + half +" axial").region(0).plot(trackAxialHitCount[i]); + plotters.get("Track " + half +" axial").region(1).plot(trackAxialCount[i]); + plotters.get("Track " + half +" axial").region(2).plot(trackAxialSlope[i]); + plotters.get("Track " + half +" axial").region(3).plot(trackAxialIntercept[i]); + + + + plotters.put("Track " + half, af.createPlotterFactory().create("Track " + half)); + //plotters.get("Track " + half +" axial").setStyle(this.getDefaultPlotterStyle("","Entries",true)); + plotters.get("Track " + half).createRegions(3,2); + plotters.get("Track " + half).region(0).plot(trackHitCount[i]); + plotters.get("Track " + half).region(1).plot(trackCount[i]); + plotters.get("Track " + half).region(2).plot(trackSlope[i][STUtils.STStereoTrack.VIEW.YZ.ordinal()]); + plotters.get("Track " + half).region(3).plot(trackIntercept[i][STUtils.STStereoTrack.VIEW.YZ.ordinal()]); + plotters.get("Track " + half).region(4).plot(trackSlope[i][STUtils.STStereoTrack.VIEW.XZ.ordinal()]); + plotters.get("Track " + half).region(5).plot(trackIntercept[i][STUtils.STStereoTrack.VIEW.XZ.ordinal()]); + + plotters.get("Stereo hit count").region(i).plot(stereoHitCount[i]); + + plotters.get("Track axial extrapolation").region(i).plot(trackAxialExtraPolation[i]); + plotters.get("Track extrapolation Y").region(i).plot(trackExtraPolationY[i]); + plotters.get("Track extrapolation X").region(i).plot(trackExtraPolationX[i]); + + } + + trackAxialExtraPolation[2] = hf.createHistogram2D("Track axial extrapolation", nPointsZ, endPointZ, startPointZ,50,-80,80); + plotters.get("Track axial extrapolation").region(2).plot(trackAxialExtraPolation[2]); + trackAxialExtraPolation[3] = hf.createHistogram2D("Track axial extrapolation wires", nPointsZ, wirePosition[2]-350, wirePosition[2]+350,50,-20,20); + plotters.get("Track axial extrapolation").region(3).plot(trackAxialExtraPolation[3]); + trackAxialExtraPolation[4] = hf.createHistogram2D("Track axial extrapolation rndm", nPointsZ, -200.0, 200.0,50,-60,60); + plotters.get("Track axial extrapolation").region(4).plot(trackAxialExtraPolation[4]); + + trackExtraPolationY[2] = hf.createHistogram2D("Track extrapolation Y", nPointsZ, endPointZ, startPointZ,50,-80,80); + plotters.get("Track extrapolation Y").region(2).plot(trackExtraPolationY[2]); + trackExtraPolationY[3] = hf.createHistogram2D("Track extrapolation Y wires", nPointsZ, wirePosition[2]-350, wirePosition[2]+350,50,-20,20); + plotters.get("Track extrapolation Y").region(3).plot(trackExtraPolationY[3]); + trackExtraPolationY[4] = hf.createHistogram2D("Track extrapolation Y rndm", nPointsZ, -200.0, 200.0,50,-60,60); + plotters.get("Track extrapolation Y").region(4).plot(trackExtraPolationY[4]); + + trackExtraPolationX[2] = hf.createHistogram2D("Track extrapolation X", nPointsZ, endPointZ, startPointZ,50,-100,60); + plotters.get("Track extrapolation X").region(2).plot(trackExtraPolationX[2]); + trackExtraPolationX[3] = hf.createHistogram2D("Track extrapolation X wires", nPointsZ, wirePosition[2]-350, wirePosition[2]+350,50,-80,-20); + plotters.get("Track extrapolation X").region(3).plot(trackExtraPolationX[3]); + trackExtraPolationX[4] = hf.createHistogram2D("Track extrapolation X rndm", nPointsZ, -200.0, 200.0,50,-60,0); + plotters.get("Track extrapolation X").region(4).plot(trackExtraPolationX[4]); + + plotters.get("Cluster counts").region(0).plot(hitCount); + plotters.get("Cluster counts").region(1).plot(topHitCount); + plotters.get("Cluster counts").region(2).plot(botHitCount); + + + for(HpsSiSensor sensor : sensors) { + + if(sensor.isBottomLayer()) { + sensorHitPositions.put(sensor.getName(), hf.createHistogram1D(sensor.getName() + "_hitpos1D", 50, -60, 0)); + if(sensor.isAxial()) { + stereoHitPositionsXY.put(sensor.getName(), hf.createHistogram2D(sensor.getName() + "_stereohitpos2D", 50, -100, 1000,50,-60,0)); + plotters.get("Stereo hit position").region(SvtPlotUtils.computePlotterRegionAxialOnly(sensor)).plot(stereoHitPositionsXY.get(sensor.getName())); + } + } + else{ + sensorHitPositions.put(sensor.getName(), hf.createHistogram1D(sensor.getName() + "_hitpos1D", 50, 0, 60)); + if(sensor.isAxial()) { + stereoHitPositionsXY.put(sensor.getName(), hf.createHistogram2D(sensor.getName() + "_stereohitpos2D", 50, -100, 100,50,0,60)); + plotters.get("Stereo hit position").region(SvtPlotUtils.computePlotterRegionAxialOnly(sensor)).plot(stereoHitPositionsXY.get(sensor.getName())); + } + } + sensorHitCounts.put(sensor.getName(), hf.createHistogram1D(sensor.getName() + "_hitcount", 11, -0.5, 10.5)); + sensorHitTimes.put(sensor.getName(), hf.createHistogram1D(sensor.getName() + "_hittime", 50, -100, 100)); + sensorHitCountMap.put(sensor.getName(), new int[1]); + sensorHitCountMap.get(sensor.getName())[0] = 0; + + if(sensor.isAxial()) { + sensorHitResGlobal.put(sensor.getName(), hf.createHistogram1D(sensor.getName() + "_hitresglobal", 50, -0.7, 0.7)); + plotters.get("Sensor hit res").region(SvtPlotUtils.computePlotterRegionAxialOnly(sensor)).plot(sensorHitResGlobal.get(sensor.getName())); + plotters.get("Sensor hit res").region(0).style().dataStyle().showInStatisticsBox(true); + sensorStereoHitYZResGlobal.put(sensor.getName(), hf.createHistogram1D(sensor.getName() + "_stereohityzresglobal", 50, -1, 1)); + plotters.get("Sensor stereo YZ hit res").region(SvtPlotUtils.computePlotterRegionAxialOnly(sensor)).plot(sensorStereoHitYZResGlobal.get(sensor.getName())); + plotters.get("Sensor stereo YZ hit res").region(0).style().dataStyle().showInStatisticsBox(true); + sensorStereoHitXZResGlobal.put(sensor.getName(), hf.createHistogram1D(sensor.getName() + "_stereohitxzresglobal", 50, -1, 1)); + plotters.get("Sensor stereo XZ hit res").region(SvtPlotUtils.computePlotterRegionAxialOnly(sensor)).plot(sensorStereoHitXZResGlobal.get(sensor.getName())); + plotters.get("Sensor stereo XZ hit res").region(0).style().dataStyle().showInStatisticsBox(true); + + + } + + plotters.get("Sensor hit position").region(SvtPlotUtils.computePlotterRegion(sensor)).plot(sensorHitPositions.get(sensor.getName())); + plotters.get("Sensor hit times").region(SvtPlotUtils.computePlotterRegion(sensor)).plot(sensorHitTimes.get(sensor.getName())); + plotters.get("Sensor cluster counts").region(SvtPlotUtils.computePlotterRegion(sensor)).plot(sensorHitCounts.get(sensor.getName())); + + } + + for(IPlotter plotter : plotters.values()) + plotter.show(); + } + + + protected void resetCounts() { + //reset hit counts + for(HpsSiSensor sensor : sensors) { + sensorHitCountMap.get(sensor.getName())[0] = 0; + } + } + protected void process(EventHeader event) { + + logger.fine("Process event"); + + if (runNumber == -1) { + runNumber = event.getRunNumber(); + } + + //Find all strip clusters in the events + List<SiTrackerHitStrip1D> stripClusters = new ArrayList<SiTrackerHitStrip1D>(); + if(event.hasCollection(SiTrackerHitStrip1D.class, stripClusterCollectionName)) { + stripClusters = event.get(SiTrackerHitStrip1D.class, stripClusterCollectionName); + } + + logger.fine("Found " + stripClusters.size() + " strip clusters in the event"); + + resetCounts(); + + List<SiTrackerHitStrip1D> topHits= new ArrayList<SiTrackerHitStrip1D>(); + List<SiTrackerHitStrip1D> botHits= new ArrayList<SiTrackerHitStrip1D>(); + + // Create a map of axial hits + List<Map<Integer, List<SiTrackerHitStrip1D>>> axialHitsPerLayer = new ArrayList<Map<Integer, List<SiTrackerHitStrip1D>>>(); + axialHitsPerLayer.add(new HashMap<Integer, List<SiTrackerHitStrip1D>>()); + axialHitsPerLayer.add(new HashMap<Integer, List<SiTrackerHitStrip1D>>()); + + // Create a map of stereo hits + List<Map<Integer, List<SiTrackerHitStrip1D>>> stereoHitsPerLayer = new ArrayList<Map<Integer, List<SiTrackerHitStrip1D>>>(); + stereoHitsPerLayer.add(new HashMap<Integer, List<SiTrackerHitStrip1D>>()); + stereoHitsPerLayer.add(new HashMap<Integer, List<SiTrackerHitStrip1D>>()); + + + for(SiTrackerHitStrip1D cluster : stripClusters) { + SiTrackerHitStrip1D cluster_global = cluster.getTransformedHit(CoordinateSystem.GLOBAL); + HpsSiSensor sensor = (HpsSiSensor) cluster.getRawHits().get(0).getDetectorElement(); + int layer = HPSTrackerBuilder.getLayerFromVolumeName(sensor.getName()); + sensorHitPositions.get(sensor.getName()).fill(cluster_global.getPositionAsVector().y()); + sensorHitTimes.get(sensor.getName()).fill(cluster.getTime()); + logger.fine("cluster position " + cluster_global.getPositionAsVector().toString()); + sensorHitCountMap.get(sensor.getName())[0]++; + + if(sensor.isTopLayer()) { + topHits.add(cluster); + } else { + botHits.add(cluster); + } + //hit time selection + if(!selectTime || (cluster.getTime() < timeMax && cluster.getTime()>timeMin)) { + + // look at axials and stereo separately + if(sensor.isAxial()) { + + Map<Integer, List<SiTrackerHitStrip1D>> hitsPerLayer; + if(sensor.isTopLayer()) { + hitsPerLayer = axialHitsPerLayer.get(0); + } else { + hitsPerLayer = axialHitsPerLayer.get(1); + } + + List<SiTrackerHitStrip1D> hits; + hits = hitsPerLayer.get(layer); + if(hits == null) { + hits = new ArrayList<SiTrackerHitStrip1D>(); + hitsPerLayer.put(layer, hits); + } + hits.add(cluster); + + } else { + + // look at stereos + + Map<Integer, List<SiTrackerHitStrip1D>> hitsPerLayer; + if(sensor.isTopLayer()) { + hitsPerLayer = stereoHitsPerLayer.get(0); + } else { + hitsPerLayer = stereoHitsPerLayer.get(1); + } + + List<SiTrackerHitStrip1D> hits; + hits = hitsPerLayer.get(layer); + if(hits == null) { + hits = new ArrayList<SiTrackerHitStrip1D>(); + hitsPerLayer.put(layer, hits); + } + hits.add(cluster); + + } + + } + + } + + //count hits + hitCount.fill(stripClusters.size()); + topHitCount.fill(topHits.size()); + botHitCount.fill(botHits.size()); + + // fill hit positions + for(HpsSiSensor sensor : sensors) + sensorHitCounts.get(sensor.getName()).fill(sensorHitCountMap.get(sensor.getName())[0] ); + + + // Pattern recognition for axial hits - yeah! + List< List<SiTrackerHitStrip1D>> axialSeedHits = new ArrayList<List<SiTrackerHitStrip1D>>(); + for(int ihalf=0; ihalf<2; ++ihalf) { + List<SiTrackerHitStrip1D> seedHits = new ArrayList<SiTrackerHitStrip1D>(); + for(int layer : axialHitsPerLayer.get(ihalf).keySet()) { + // single hit on the sensor + if( axialHitsPerLayer.get(ihalf).get(layer).size() == 1 ) + seedHits.add(axialHitsPerLayer.get(ihalf).get(layer).get(0)); + } + axialSeedHits.add(seedHits); + } + + // Pattern recognition for stereo hits - yeah! + List< List<SiTrackerHitStrip1D>> stereoSeedHits = new ArrayList<List<SiTrackerHitStrip1D>>(); + for(int ihalf=0; ihalf<2; ++ihalf) { + List<SiTrackerHitStrip1D> seedHits = new ArrayList<SiTrackerHitStrip1D>(); + for(int layer : stereoHitsPerLayer.get(ihalf).keySet()) { + // single hit on the sensor + if( stereoHitsPerLayer.get(ihalf).get(layer).size() == 1 ) + seedHits.add(stereoHitsPerLayer.get(ihalf).get(layer).get(0)); + } + stereoSeedHits.add(seedHits); + } + + + // try to make stereo hits + + + List< List<STUtils.StereoPair> > stereoPairs = new ArrayList< List<STUtils.StereoPair>>(); + + + + for(int ihalf=0; ihalf<2; ++ihalf) { + List<STUtils.StereoPair> stereoPairCandidates = new ArrayList< STUtils.StereoPair>(); + List<SiTrackerHitStrip1D> aSeedHits = axialSeedHits.get(ihalf); + for(SiTrackerHitStrip1D axialSeedHit : aSeedHits) { + + // find the stereo sensor and its hit from the pre-compiled stereo pair list + HpsSiSensor stereoSensor = null; + SiTrackerHitStrip1D stereoSeedHit = null; + + HpsSiSensor axialSensor = (HpsSiSensor) axialSeedHit.getRawHits().get(0).getDetectorElement(); + logger.fine("Look for stereo sensor to \"" + axialSensor.getName() + "\""); + + for(SvtStereoLayer stereoLayer : stereoLayers) { + if(stereoLayer.getAxialSensor().getName().equals(axialSensor.getName())) { + stereoSensor = stereoLayer.getStereoSensor(); + break; + } + } + + // make sure it was found + if(stereoSensor == null) throw new RuntimeException("Couldn't find stereo sensor to \"" + axialSensor.getName() + "\""); + + logger.fine("Found stereo sensor \"" + stereoSensor.getName() + "\""); + + // find the hit + // this only works for single hits per sensor + for(List<SiTrackerHitStrip1D> sSeedHits : stereoSeedHits) { + for(SiTrackerHitStrip1D stereoSeedHitCandidate : sSeedHits) { + HpsSiSensor sensor = (HpsSiSensor) stereoSeedHitCandidate.getRawHits().get(0).getDetectorElement(); + if(sensor.getName().equals(stereoSensor.getName())) { + logger.fine("Found stereo hit at " + stereoSeedHitCandidate.getPositionAsVector().toString() + " at sensor \"" + stereoSensor.getName() + "\""); + stereoSeedHit = stereoSeedHitCandidate; + break; // ok, this only works for single hits per sensor + } + } + } + + // Check if we found a candidate pair + if(stereoSeedHit != null) { + STUtils.StereoPair pair = new STUtils.StereoPair(axialSeedHit,stereoSeedHit,origoStraightThroughs); + if(STUtils.StereoPair.passCuts(pair)) + stereoPairCandidates.add( pair ); + } + } + stereoPairs.add(stereoPairCandidates); + } + + + + // loop over the stereo pairs + for(int ihalf=0; ihalf<2; ++ihalf) { + List< STUtils.StereoPair > pairs = stereoPairs.get(ihalf); + + logger.fine("Found " + pairs.size() + " stereo candidates for " + (ihalf == 0 ? "top" : "bottom")); + + // Fill count + stereoHitCount[ihalf].fill(pairs.size()); + + // Plot the position of the hits + for(STUtils.StereoPair pair : pairs) { + Hep3Vector p = pair.getPosition(); + stereoHitPositionsXY.get(pair.getAxial().getRawHits().get(0).getDetectorElement().getName()).fill(p.x(),p.y()); + logger.fine(p.toString() + " from " + pair.getAxial().getPositionAsVector().toString() + " " + pair.getStereo().getPositionAsVector().toString() + + " ("+pair.getAxial().getRawHits().get(0).getDetectorElement().getName() +" and "+pair.getStereo().getRawHits().get(0).getDetectorElement().getName()+")"); + } + } + + + // add hits to axial tracks and fit them + List<STUtils.STTrack> axialTracks = new ArrayList<STUtils.STTrack>(); + for(List<SiTrackerHitStrip1D> seedHits : axialSeedHits) { + + if(seedHits.size() < minHitsAxialTrack) + continue; + + STUtils.STTrack track = new STUtils.STTrack(); + track.setHits(seedHits); + + logger.fine("Fit axial track"); + regressionFitter.fit(track); + track.addFit(regressionFitter.getFit()); + + axialTracks.add(track); + } + + // add stereo hits to tracks and fit them with simple regression in 1D + List<STUtils.STStereoTrack> stereoTracks = new ArrayList<STUtils.STStereoTrack>(); + for(List<STUtils.StereoPair> seedHits : stereoPairs) { + + if(seedHits.size() < minHitsStereoTrack) + continue; + + STUtils.STStereoTrack track = new STUtils.STStereoTrack(); + track.setHits(seedHits); + + STUtils.fit(regressionFitter, track); + + // logger.fine("Fit stereo track in YZ"); +// regressionFitter.fit(track.getPointList(STStereoTrack.VIEW.YZ,null)); +// track.setFit(regressionFitter.getFit(), STStereoTrack.VIEW.YZ); +// logger.fine("Fit stereo track in XZ"); +// regressionFitter.fit(track.getPointList(STStereoTrack.VIEW.XZ,STStereoTrack.VIEW.YZ)); +// track.setFit(regressionFitter.getFit(), STStereoTrack.VIEW.XZ); + + stereoTracks.add(track); + } + + + + // Loop over the axial tracks + int nTracksAxial[] = {0,0}; + for(STUtils.STTrack track : axialTracks) { + + for(SiTrackerHitStrip1D hit : track.getHits()) { + double yhit = hit.getPositionAsVector().y(); + double zHit = hit.getPositionAsVector().z(); + double yPred = track.predict(zHit); + double resGlobal = yhit - yPred; + sensorHitResGlobal.get(hit.getRawHits().get(0).getDetectorElement().getName()).fill(resGlobal); + } + + logger.fine(track.toString()); + + if(track.isTop()) { + nTracksAxial[0]++; + trackAxialHitCount[0].fill(track.getHits().size()); + trackAxialSlope[0].fill(track.getSlope()); + trackAxialIntercept[0].fill(track.getIntercept()); + } + else { + nTracksAxial[1]++; + trackAxialHitCount[1].fill(track.getHits().size()); + trackAxialSlope[1].fill(track.getSlope()); + trackAxialIntercept[1].fill(track.getIntercept()); + } + } + trackAxialCount[0].fill(nTracksAxial[0]); + trackAxialCount[1].fill(nTracksAxial[1]); + + + + // Loop over the stereo tracks + int nTracks[] = {0,0}; + for(STUtils.STStereoTrack track : stereoTracks) { + + int half = track.isTop() ? 0 : 1; + + // update the hit positions with the fit + double delta = 9999.9; + int idelta = 0; + while(delta>0.05) { + logger.fine(idelta + ": delta " + delta); + delta = 0.0; + for(STUtils.StereoPair pair : track.getHits()) { + Hep3Vector p = new BasicHep3Vector(pair.getPosition().v()); + Hep3Vector trackDirection = track.getDirection(); + logger.fine("updatePosition " + p.toString() + " with track dir " + trackDirection.toString()); + pair.updatePosition(trackDirection); + Hep3Vector pnew = pair.getPosition(); + logger.fine("new position " + pnew.toString()); + delta += VecOp.sub(p, pnew).magnitude(); + } + delta = delta / track.getHits().size(); + idelta++; + + fitUpdateIteration[half].fill(idelta,delta); + + // Re-fit the track after the update + STUtils.fit(regressionFitter,track); +// track.clearFit(); +// logger.fine("Fit stereo track in YZ"); +// regressionFitter.fit(track.getPointList(STStereoTrack.VIEW.YZ,null)); +// track.setFit(regressionFitter.getFit(), STStereoTrack.VIEW.YZ); +// logger.fine("Fit stereo track in XZ"); +// regressionFitter.fit(track.getPointList(STStereoTrack.VIEW.XZ,STStereoTrack.VIEW.YZ)); +// track.setFit(regressionFitter.getFit(), STStereoTrack.VIEW.XZ); + + } + logger.fine("finished update position after " + idelta + "iterations with delta " + delta); + + + for(STUtils.StereoPair hit : track.getHits()) { + double yhit = hit.getPosition().y(); + double xhit = hit.getPosition().x(); + double zHit = hit.getPosition().z(); + double xyPred[] = track.predict(zHit); + double resGlobalY = yhit - xyPred[STStereoTrack.VIEW.YZ.ordinal()]; + double resGlobalX = xhit - xyPred[STStereoTrack.VIEW.XZ.ordinal()];; + sensorStereoHitYZResGlobal.get(hit.getAxial().getRawHits().get(0).getDetectorElement().getName()).fill(resGlobalY); + sensorStereoHitXZResGlobal.get(hit.getAxial().getRawHits().get(0).getDetectorElement().getName()).fill(resGlobalX); + } + + logger.fine(track.toString()); + + nTracks[half]++; + trackHitCount[half].fill(track.getHits().size()); + for(int v=0;v<2;++v) { + STUtils.STStereoTrack.VIEW view = STUtils.STStereoTrack.VIEW.values()[v]; + trackSlope[half][v].fill(track.getSlope()[view.ordinal()]); + trackIntercept[half][v].fill(track.getIntercept()[view.ordinal()]); + } + } + trackCount[0].fill(nTracks[0]); + trackCount[1].fill(nTracks[1]); + + + + + //predict where these axial tracks go upstream in Y + double zIter,yIter,start,end; + for(STUtils.STTrack track : axialTracks) { + int half = track.isTop() ? 0 : 1; + for(int i = 0; i < (nPointsZ+1); ++i) { + zIter = startPointZ - i*(startPointZ - endPointZ)/(double)nPointsZ; + yIter = track.predict(zIter); + trackAxialExtraPolation[half].fill(zIter,yIter); + trackAxialExtraPolation[2].fill(zIter,yIter); + } + start = wirePosition[2] + 350.0; + end = wirePosition[2] - 350.0; + for(int i = 0; i < (nPointsZ+1); ++i) { + zIter = start - i*(start - end)/(double)nPointsZ; + yIter = track.predict(zIter); + trackAxialExtraPolation[3].fill(zIter,yIter); + } + start = 200.0; + end = -200.0; + for(int i = 0; i < (nPointsZ+1); ++i) { + zIter = start - i*(start - end)/(double)nPointsZ; + yIter = track.predict(zIter); + trackAxialExtraPolation[4].fill(zIter,yIter); + } + } + + + //predict where the stereo tracks go upstream in X-Y + double xyIter[]; + for(STStereoTrack track : stereoTracks) { + int half = track.isTop() ? 0 : 1; + for(int i = 0; i < (nPointsZ+1); ++i) { + zIter = startPointZ - i*(startPointZ - endPointZ)/(double)nPointsZ; + xyIter = track.predict(zIter); + trackExtraPolationY[half].fill(zIter,xyIter[STStereoTrack.VIEW.YZ.ordinal()]); + trackExtraPolationY[2].fill(zIter,xyIter[STStereoTrack.VIEW.YZ.ordinal()]); + trackExtraPolationX[half].fill(zIter,xyIter[STStereoTrack.VIEW.XZ.ordinal()]); + trackExtraPolationX[2].fill(zIter,xyIter[STStereoTrack.VIEW.XZ.ordinal()]); + } + start = wirePosition[2] + 350.0; + end = wirePosition[2] - 350.0; + for(int i = 0; i < (nPointsZ+1); ++i) { + zIter = start - i*(start - end)/(double)nPointsZ; + xyIter = track.predict(zIter); + trackExtraPolationY[3].fill(zIter,xyIter[STStereoTrack.VIEW.YZ.ordinal()]); + trackExtraPolationX[3].fill(zIter,xyIter[STStereoTrack.VIEW.XZ.ordinal()]); + } + start = 200.0; + end = -200.0; + for(int i = 0; i < (nPointsZ+1); ++i) { + zIter = start - i*(start - end)/(double)nPointsZ; + xyIter = track.predict(zIter); + trackExtraPolationY[4].fill(zIter,xyIter[STStereoTrack.VIEW.YZ.ordinal()]); + trackExtraPolationX[4].fill(zIter,xyIter[STStereoTrack.VIEW.XZ.ordinal()]); + } + } + + + // GBL interface + if(gblPrintWriter != null) { + STUtils.printGBL(gblPrintWriter, event, stereoTracks); + } + + + } + + + protected void endOfData() { + + rootFileName = outputFilename + "_hitrecon.root"; + RootFileStore rootFileStore = new RootFileStore(rootFileName); + try { + rootFileStore.open(); + rootFileStore.add(aida.tree()); + rootFileStore.close(); + } catch (IOException e) { + e.printStackTrace(); + } + + if(gblPrintWriter != null) gblPrintWriter.close(); + + } + + + private void updateFits() { + for(HpsSiSensor sensor : sensors) { + IHistogram1D h = sensorHitResGlobal.get(sensor.getName()); + if(h != null) { + if( h.entries() > 20) { + IFitResult f = SvtPlotUtils.performGaussianFit(h); + if(f != null) { + SvtPlotUtils.plot(plotters.get("Sensor hit res"), f.fittedFunction(), null, SvtPlotUtils.computePlotterRegionAxialOnly(sensor)); + } + } + } +// if(sensor.isAxial()) { +// sensorHitResGlobal.put(sensor.getName(), hf.createHistogram1D(sensor.getName() + "_hitresglobal", 50, -1.5, 1.5)); +// plotters.get("Sensor hit res").region(SvtPlotUtils.computePlotterRegionAxialOnly(sensor)).plot(sensorHitResGlobal.get(sensor.getName())); +// plotters.get("Sensor hit res").region(0).style().dataStyle().showInStatisticsBox(true); +// } + + } + + } + + protected IPlotterStyle getMinPlotterStyle(String xAxisTitle, String yAxisTitle) { + // Create a default style + IPlotterStyle style = this.pf.createPlotterStyle(); + + // Set the style of the X axis + if(!xAxisTitle.isEmpty()) style.xAxisStyle().setLabel(xAxisTitle); + style.xAxisStyle().labelStyle().setFontSize(14); + style.xAxisStyle().setVisible(true); + + // Set the style of the Y axis + if(!yAxisTitle.isEmpty()) style.yAxisStyle().setLabel(yAxisTitle); + style.yAxisStyle().labelStyle().setFontSize(14); + style.yAxisStyle().setVisible(true); + + // Turn off the histogram grid + style.gridStyle().setVisible(false); + + // Turn off legend + style.legendBoxStyle().setVisible(false); + + style.setParameter("hist2DStyle", "colorMap"); + style.dataStyle().fillStyle().setParameter("colorMapScheme", "rainbow"); + style.dataStyle().fillStyle().setColor("yellow"); + style.dataStyle().errorBarStyle().setVisible(false); + + return style; + } + + protected IPlotterStyle getDefaultPlotterStyle(String xAxisTitle, String yAxisTitle) { + // Create a default style + IPlotterStyle style = this.pf.createPlotterStyle(); + + style.dataBoxStyle().setVisible(true); + + // Set the style of the X axis + if(!xAxisTitle.isEmpty()) style.xAxisStyle().setLabel(xAxisTitle); + style.xAxisStyle().labelStyle().setFontSize(14); + style.xAxisStyle().setVisible(true); + + // Set the style of the Y axis + if(!yAxisTitle.isEmpty()) style.yAxisStyle().setLabel(yAxisTitle); + style.yAxisStyle().labelStyle().setFontSize(14); + style.yAxisStyle().setVisible(true); + + // Turn off the histogram grid + style.gridStyle().setVisible(false); + + style.setParameter("hist2DStyle", "colorMap"); + style.dataStyle().fillStyle().setParameter("colorMapScheme", "rainbow"); + style.dataStyle().fillStyle().setColor("yellow"); + style.dataStyle().errorBarStyle().setVisible(false); + + return style; + } + + + + public void setOutputFilename(String gblOutputFilename) { + this.outputFilename = gblOutputFilename; + } + + + + +}