Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions common-tools/clas-tracking/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@
</parent>

<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-math3</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ public abstract class AKFitter {
private double resiCut = 50;//residual cut for the measurements

// return variables
/** Temporary A/B switch for the former behaviour, where a null intermediate
* smoothed state made the whole chi2 NaN and failed the track. */
protected static final boolean LEGACY_NULL_SMOOTH_FAIL =
Boolean.getBoolean("kf.legacyNullSmoothFail");

public boolean setFitFailed = false;
public double chi2;
public int NDF;
Expand Down Expand Up @@ -180,12 +185,16 @@ public void setTrajectory(AStateVecs sv, AMeasVecs mv) {
int index = mv.measurements.get(k).layer;
int layer = mv.measurements.get(k).surface.getLayer();
int sector = mv.measurements.get(k).surface.getSector();
// A null smoothed state means the swim from the smoothed helix could not reach
// this surface, so there is no smoothed residual to report. Use -999, the same
// convention as a passive surface below, rather than the NaN dh() returns.
boolean nullSmooth = sv.smoothed().get(k)==null && !LEGACY_NULL_SMOOTH_FAIL;
double tRes = mv.dh(k, sv.transported().get(k));
double fRes = mv.dh(k, sv.filtered(false).get(k));
double sRes = mv.dh(k, sv.smoothed().get(k));
double sRes = nullSmooth ? -999 : mv.dh(k, sv.smoothed().get(k));
if(!mv.measurements.get(k).surface.passive) {
trajPoints.put(index, new HitOnTrack(layer, sector, sv.transported().get(k), tRes, fRes, sRes));
if(mv.measurements.get(k).skip)
if(mv.measurements.get(k).skip || nullSmooth)
trajPoints.get(index).isUsed = false;
} else {
trajPoints.put(index, new HitOnTrack(layer, sector, sv.transported().get(k), -999, -999, -999));
Expand All @@ -211,7 +220,14 @@ public double calc_chi2(AStateVecs sv, AMeasVecs mv) {
sv.transported().put(0, sv.smoothed().get(0).clone());

for(int k = 0; k< mv.measurements.size(); k++) {
if(!mv.measurements.get(k).skip) {
if(!mv.measurements.get(k).skip && sv.smoothed().get(k)==null
&& !LEGACY_NULL_SMOOTH_FAIL) {
// smooth() returns null when the swim from the smoothed helix cannot reach
// this surface. dh() returns NaN by contract for a null state, which would
// make the whole chi2 NaN and fail a track whose other measurements are
// fine. Treat it like a skipped measurement: excluded from chi2 and NDF.
}
else if(!mv.measurements.get(k).skip) {
double dh = mv.dh(k, sv.smoothed().get(k));
double error = mv.measurements.get(k).error;
chisq += dh*dh / error/error;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,11 +96,13 @@ public double getChi2(int mode) {
if(mode==1) {
double chi2 = 0;
for(int k = 1; k< mv.measurements.size(); k++) {
if(!mv.measurements.get(k).skip) {
double dh = mv.dh(k, sv.smoothed().get(k));
double error = mv.measurements.get(k).error;
chi2 += dh*dh / error/error;
}
if(mv.measurements.get(k).skip) continue;
// same rule as AKFitter.calc_chi2: a null smoothed state contributes nothing,
// rather than the NaN dh() returns for it, which would make this chi2 NaN
if(sv.smoothed().get(k)==null && !LEGACY_NULL_SMOOTH_FAIL) continue;
double dh = mv.dh(k, sv.smoothed().get(k));
double error = mv.measurements.get(k).error;
chi2 += dh*dh / error/error;
}
return chi2;
}
Expand Down Expand Up @@ -223,6 +225,14 @@ public StateVec filter(int k, StateVec vec, AMeasVecs mv) {
// System.out.println(dh);
//get the projector Matrix
double[] H = mv.H(fVec, sv, mv.measurements.get(k), this.getSwimmer());
if (H == null) {
// A perturbed state could not be placed on the measurement surface. A
// nominal-surface substitute would make the derivative geometrically
// inconsistent, so exclude this measurement and retain the incoming state.
this.NDF--;
mv.measurements.get(k).skip = true;
return fVec;
}
// System.out.println(k + " " + mv.measurements.get(k).layer + " " + H[0] + " " + H[1] + " " + H[2] + " " + H[3] + " " + H[4] + " " +dh );

double[][] CaInv = this.getMatrixOps().filterCovMat(H, fVec.covMat, V);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,9 @@ public double[] H(AStateVecs.StateVec stateVec, AStateVecs sv, MeasVec mv, Swim

//SVplus.updateFromHelix();
//SVminus.updateFromHelix();
sv.setStateVecPosAtMeasSite(SVplus, mv, null);
sv.setStateVecPosAtMeasSite(SVminus, mv, null);
boolean plusOK = sv.setStateVecPosAtMeasSite(SVplus, mv, null);
boolean minusOK = sv.setStateVecPosAtMeasSite(SVminus, mv, null);
if (!plusOK || !minusOK) return null;
// sv.printlnStateVec(SVplus);
// sv.printlnStateVec(SVminus);
Hval[i] = (this.h(stateVec.k, SVplus) - this.h(stateVec.k, SVminus)) / getDelta_d_a()[i] ;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
*/
public class StateVecs extends AStateVecs {


@Override
public boolean getStateVecPosAtMeasSite(StateVec sv, AMeasVecs.MeasVec mv, Swim swim) {
double[] swimPars = new double[7];
Expand Down Expand Up @@ -73,30 +72,48 @@ else if(mv.surface.cylinder!=null) {
if(swim==null) { // applicable only to planes parallel to the z -axis
Helix helix = sv.getHelix(xref, yref);
if(mv.surface.plane!=null) {
Point3D pos = helix.getHelixPointAtPlane(mv.surface.finitePlaneCorner1.x(), mv.surface.finitePlaneCorner1.y(),
mv.surface.finitePlaneCorner2.x(), mv.surface.finitePlaneCorner2.y(), 10);
Vector3D mom = helix.getMomentumAtPlane(mv.surface.finitePlaneCorner1.x(), mv.surface.finitePlaneCorner1.y(),
mv.surface.finitePlaneCorner2.x(), mv.surface.finitePlaneCorner2.y(), 10);
sv.path = helix.getLAtPlane(mv.surface.finitePlaneCorner1.x(), mv.surface.finitePlaneCorner1.y(),
mv.surface.finitePlaneCorner2.x(), mv.surface.finitePlaneCorner2.y(), 10);
sv.x = pos.x();
sv.y = pos.y();
sv.z = pos.z();
sv.px = mom.x();
sv.py = mom.y();
sv.pz = mom.z();
Vector3D normal = mv.surface.plane.normal();
Point3D point = mv.surface.plane.point();
double l = helix.getLAtPlane3D(point.x(), point.y(), point.z(),
normal.x(), normal.y(), normal.z(),
point.x(), point.y());
if(!Double.isFinite(l)) return false;
sv.path = l;
sv.x = helix.getX(l);
sv.y = helix.getY(l);
sv.z = helix.getZ(l);
sv.px = helix.getPx(helix.getB(), l);
sv.py = helix.getPy(helix.getB(), l);
sv.pz = helix.getPz(helix.getB());
}
else {
double r = mv.surface.cylinder.baseArc().radius();
Point3D pos = helix.getHelixPointAtR(r);
Vector3D mom = helix.getMomentumAtR(r);
sv.path = helix.getLAtR(r);
sv.x = pos.x();
sv.y = pos.y();
sv.z = pos.z();
sv.px = mom.x();
sv.py = mom.y();
sv.pz = mom.z();
double l = helix.getLAtR(r);
Point3D axisStart = mv.surface.cylinder.getAxis().origin();
Point3D axisEnd = mv.surface.cylinder.getAxis().end();

// Preserve the exact closed-form result for an ideal beam-axis cylinder.
// Alignment may displace or tilt the BMT axis; in that case intersect the
// same cylinder used by the measurement surface.
boolean beamAxis = Math.abs(axisStart.x()) < 1.0e-9
&& Math.abs(axisStart.y()) < 1.0e-9
&& Math.abs(axisEnd.x()) < 1.0e-9
&& Math.abs(axisEnd.y()) < 1.0e-9;
if (!beamAxis) {
l = helix.getLAtCylinder3D(
axisStart.x(), axisStart.y(), axisStart.z(),
axisEnd.x() - axisStart.x(),
axisEnd.y() - axisStart.y(),
axisEnd.z() - axisStart.z(), r, l);
if (!Double.isFinite(l)) return false;
}
sv.path = l;
sv.x = helix.getX(l);
sv.y = helix.getY(l);
sv.z = helix.getZ(l);
sv.px = helix.getPx(helix.getB(), l);
sv.py = helix.getPy(helix.getB(), l);
sv.pz = helix.getPz(helix.getB());
}
}
else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,161 @@ public double getPz() {
return this.getPz(this.getB());
}

/** Intersect the helix with the complete plane n.(r-p)=0, including nz. */
public double getLAtPlane3D(double px, double py, double pz,
double nx, double ny, double nz,
double xNear, double yNear) {
// Start at the point on the helix circle nearest the module. The projected trace of a
// nearly tangential plane can miss the circle even when the full 3-D plane intersects it.
double phi0 = Math.atan2(_yd - getYc(), _xd - getXc());
double phiNear = Math.atan2(yNear - getYc(), xNear - getXc());
double dphi = phiNear - phi0;
if (dphi > Math.PI) dphi -= 2.0 * Math.PI;
if (dphi < -Math.PI) dphi += 2.0 * Math.PI;
double l = dphi / getOmega();
if (!Double.isFinite(l)) return Double.NaN;

final double dl = 1.0e-3;
for (int i = 0; i < 12; i++) {
double f = nx * (getX(l) - px) + ny * (getY(l) - py)
+ nz * (getZ(l) - pz);
if (Math.abs(f) < 1.0e-7) return l;
double derivative = nx * (getX(l + dl) - getX(l - dl)) / (2 * dl)
+ ny * (getY(l + dl) - getY(l - dl)) / (2 * dl)
+ nz * (getZ(l + dl) - getZ(l - dl)) / (2 * dl);
if (!Double.isFinite(derivative) || Math.abs(derivative) < 1.0e-10)
return Double.NaN;
double step = f / derivative;
if (Math.abs(step) > 100) step = Math.copySign(100, step);
l -= step;
if (!Double.isFinite(l)) return Double.NaN;
}
double residual = nx * (getX(l) - px) + ny * (getY(l) - py)
+ nz * (getZ(l) - pz);
return Math.abs(residual) < 1.0e-5 ? l : Double.NaN;
}

/**
* Intersect this helix with a cylinder of radius {@code radius} about an arbitrary axis.
* The supplied starting value normally comes from the closed-form beam-axis solution.
*
* @return the local root nearest {@code lStart}, or NaN when no root can be established
*/
public double getLAtCylinder3D(double ax, double ay, double az,
double ux, double uy, double uz,
double radius, double lStart) {
double un = Math.sqrt(ux * ux + uy * uy + uz * uz);
if (!(un > 0) || !Double.isFinite(lStart)) return Double.NaN;
ux /= un;
uy /= un;
uz /= un;

double l = lStart;
for (int i = 0; i < 12; i++) {
double f = radialMiss(l, ax, ay, az, ux, uy, uz, radius);
if (!Double.isFinite(f)) break;
if (Math.abs(f) < 1.0e-7) return l;

double derivative = radialMissDerivative(l, ax, ay, az, ux, uy, uz);
if (!Double.isFinite(derivative) || Math.abs(derivative) < 1.0e-10) break;
double step = f / derivative;
if (Math.abs(step) > 100.0) step = Math.copySign(100.0, step);
l -= step;
if (!Double.isFinite(l)) break;
}
double residual = radialMiss(l, ax, ay, az, ux, uy, uz, radius);
if (Double.isFinite(residual) && Math.abs(residual) < 1.0e-5) return l;

// Safeguard Newton near tangencies by bracketing the first local root on each side.
// The quarter-turn limit prevents a failure from selecting the opposite crossing.
double maxSpan = Math.min(200.0, Math.PI / (2.0 * Math.abs(getOmega())));
double left = lStart;
double right = lStart;
double fLeft = radialMiss(left, ax, ay, az, ux, uy, uz, radius);
double fRight = fLeft;
double span = 0.5;
while (Double.isFinite(fLeft) && Double.isFinite(fRight)
&& Math.abs(right - lStart) < maxSpan) {
double nextSpan = Math.min(span, maxSpan);
double nextLeft = lStart - nextSpan;
double nextRight = lStart + nextSpan;
double nextFLeft = radialMiss(nextLeft, ax, ay, az, ux, uy, uz, radius);
double nextFRight = radialMiss(nextRight, ax, ay, az, ux, uy, uz, radius);

double rootLeft = bracketedCylinderRoot(nextLeft, left, nextFLeft, fLeft,
ax, ay, az, ux, uy, uz, radius);
double rootRight = bracketedCylinderRoot(right, nextRight, fRight, nextFRight,
ax, ay, az, ux, uy, uz, radius);
if (Double.isFinite(rootLeft) || Double.isFinite(rootRight)) {
if (!Double.isFinite(rootLeft)) return rootRight;
if (!Double.isFinite(rootRight)) return rootLeft;
return Math.abs(rootLeft - lStart) <= Math.abs(rootRight - lStart)
? rootLeft : rootRight;
}
left = nextLeft;
right = nextRight;
fLeft = nextFLeft;
fRight = nextFRight;
span *= 2.0;
}
return Double.NaN;
}

private double radialMissDerivative(double l, double ax, double ay, double az,
double ux, double uy, double uz) {
double wx = getX(l) - ax;
double wy = getY(l) - ay;
double wz = getZ(l) - az;
double along = wx * ux + wy * uy + wz * uz;
double qx = wx - along * ux;
double qy = wy - along * uy;
double qz = wz - along * uz;
double distance = Math.sqrt(qx * qx + qy * qy + qz * qz);
if (!(distance > 0)) return Double.NaN;

double s = -KFitter.polarity;
double phi = getPhi(l);
double vx = s * getTurningSign() * getR() * getOmega() * Math.cos(phi);
double vy = s * getTurningSign() * getR() * getOmega() * Math.sin(phi);
double vz = -getTanL();
return (qx * vx + qy * vy + qz * vz) / distance;
}

private double bracketedCylinderRoot(double lo, double hi, double flo, double fhi,
double ax, double ay, double az,
double ux, double uy, double uz, double radius) {
if (!Double.isFinite(flo) || !Double.isFinite(fhi) || flo * fhi > 0) {
return Double.NaN;
}
if (Math.abs(flo) < 1.0e-7) return lo;
if (Math.abs(fhi) < 1.0e-7) return hi;
for (int i = 0; i < 80; i++) {
double mid = 0.5 * (lo + hi);
double fm = radialMiss(mid, ax, ay, az, ux, uy, uz, radius);
if (!Double.isFinite(fm)) return Double.NaN;
if (Math.abs(fm) < 1.0e-7 || Math.abs(hi - lo) < 1.0e-9) return mid;
if (flo * fm <= 0) {
hi = mid;
} else {
lo = mid;
flo = fm;
}
}
return Double.NaN;
}

private double radialMiss(double l, double ax, double ay, double az,
double ux, double uy, double uz, double radius) {
double wx = getX(l) - ax;
double wy = getY(l) - ay;
double wz = getZ(l) - az;
double along = wx * ux + wy * uy + wz * uz;
double dx = wx - along * ux;
double dy = wy - along * uy;
double dz = wz - along * uz;
return Math.sqrt(dx * dx + dy * dy + dz * dz) - radius;
}

public double getLAtPlane(double X1, double Y1, double X2, double Y2,
double tolerance) {
// Find the intersection of the helix circle with the module plane projection in XY which is a line
Expand Down
Loading
Loading