2Track fit with general broken lines.
32from gblnum
import BorderedBandMatrix
33from mille
import MilleRecord
55 def __init__(self, aMeasurement, minPrecision=0.):
72 if (aMeasurement[2].ndim == 2):
74 eigenVal, eigenVec = np.linalg.eigh(aMeasurement[2])
77 if (aMeasurement[0]
is None):
287 if (aScatterer[1].ndim == 2):
288 eigenVal, eigenVec = np.linalg.eigh(aScatterer[1])
289 scatTransformation = eigenVec.T
292 self.
__scatterer[1] = np.dot(scatTransformation, aScatterer[0])
321 scatPrec = np.zeros((4, 4))
322 scatPrec[2:, 2:] = np.linalg.inv(posCov)
324 eigenVal, eigenVec = np.linalg.eigh(scatPrec)
325 scatTransformation = eigenVec.T
326 return [scatTransformation, np.dot(scatTransformation, scatRes), eigenVal]
430 matJ = aJacobian[3:5, 3:5]
431 matS = aJacobian[3:5, 1:3]
432 vecD = aJacobian[3:5, 0:1]
435 matW = np.linalg.inv(matS)
436 return matW, np.dot(matW, matJ), np.dot(matW, vecD)
459 def __init__(self, aLabel=0, aType=0, aValue=0., aPrec=0., aMeas=0):
497 derLocal=None, labGlobal=None, derGlobal=None):
498 if (derLocal
is not None):
499 for i
in range(derLocal.shape[1]):
500 if (derLocal[iRow, i] != 0.):
504 for i
in range(len(labDer)):
505 if (labDer[i] != 0
and matDer[iRow, i] != 0.):
509 if (derGlobal
is not None):
510 for i
in range(derGlobal.shape[1]):
511 if (derGlobal[iRow, i] != 0.):
521 for i
in range(len(derExt)):
522 if (derExt[i] != 0.):
532 aMatrix = np.dot(aVector.T, aVector)
535 return self.
__parameters, aValue * aVector * aWeight, aMatrix * aWeight
568 if (scaledResidual < 4.6851):
569 aWeight = (1.0 - (scaledResidual / 4.6851) ** 2) ** 2
573 if (scaledResidual < 1.345):
576 aWeight = 1.345 / scaledResidual
578 aWeight = 1.0 / (1.0 + (scaledResidual / 2.3849) ** 2)
590 Chi2 = scaledResidual ** 2
592 if (scaledResidual < 4.6851):
593 Chi2 = 4.6851 ** 2 / 3. * (1. - (1. - (scaledResidual / 4.6851) ** 2) ** 3)
595 Chi2 = 4.6851 ** 2 / 3.
597 if (scaledResidual > 1.345):
598 Chi2 = 1.345 * (2.*scaledResidual - 1.345)
600 Chi2 = math.log(1. + (scaledResidual / 2.3849) ** 2) * 2.3849 ** 2
657 if (i < maxPar - maxBand):
659 return maxPar, maxBor
811 point.setLabel(label)
813 for m
in point.getMeasurements():
848 print "GblData blocks"
868 rec.addData(aData.toRecord())
870 rec.writeRecord(aFile)
878 rec.readRecord(aFile)
882 while (rec.moreData()):
883 aTag = rec.specialDataTag()
887 aData.fromRecord(rec.getData())
889 nPar, nBor = aData.analyzeData(mBand)
890 mPar = max(mPar, nPar)
891 mBor = max(mBor, nBor)
904 anIndex = abs(aLabel) - 1
919 nBorder = nCurv + nLocals
920 nParBRL = nBorder + 2 * nDim
921 nParLoc = nLocals + 5
922 aJacobian = np.zeros((nParLoc, nParBRL))
927 for i
in range(nLocals):
928 aJacobian[i + 5, i] = 1.0;
929 anIndex.append(i + 1);
935 anIndex.append(labDer[i]);
937 aJacobian[j, iCol] = matDer[j, i];
940 return anIndex, aJacobian
957 nOffset = aPoint.getOffset()
958 scatDim = aPoint.getScatDim()
959 anIndex = [0, 0, 0, 0, 0]
960 aJacobian = np.zeros((measDim, 5))
961 labOffset = measDim - 2
962 labSlope = measDim - 4
963 labCurv = measDim - 5
966 prevW, prevWJ, prevWd = aPoint.getDerivatives(0)
967 nextW, nextWJ, nextWd = aPoint.getDerivatives(1)
968 sumWJ = prevWJ + nextWJ
969 matN = np.linalg.inv(sumWJ)
973 prevNW = np.dot(matN, prevW)
974 nextNW = np.dot(matN, nextW)
975 prevNd = np.dot(matN, prevWd)
976 nextNd = np.dot(matN, nextWd)
977 iOff = nDim * (-nOffset - 1) + nLocals + nCurv + 1
979 aJacobian[labOffset:measDim, 0:1] = -prevNd - nextNd
980 anIndex[0] = nLocals + 1
981 aJacobian[labOffset:measDim, 1:3] = prevNW
982 aJacobian[labOffset:measDim, 3:5] = nextNW
983 for i
in range(nDim):
984 anIndex[1 + aDim[i]] = iOff + i
985 anIndex[3 + aDim[i]] = iOff + nDim + i
989 prevWPN = np.dot(nextWJ, prevNW)
990 nextWPN = np.dot(prevWJ, nextNW)
991 prevWNd = np.dot(nextWJ, prevNd)
992 nextWNd = np.dot(prevWJ, nextNd)
994 aJacobian[labSlope:labOffset, 0:1] = prevWNd - nextWNd
995 aJacobian[labSlope:labOffset, 1:3] = -prevWPN
996 aJacobian[labSlope:labOffset, 3:5] = nextWPN
1005 iOff1 = nDim * nOffset + nCurv + nLocals + 1
1006 index1 = 3 - 2 * nJacobian
1007 iOff2 = iOff1 + nDim * (nJacobian * 2 - 1)
1008 index2 = 1 + 2 * nJacobian
1010 if (labOffset >= 0):
1011 aJacobian[labOffset, index1] = 1.0
1012 aJacobian[labOffset + 1, index1 + 1] = 1.0
1013 for i
in range(nDim):
1014 anIndex[index1 + aDim[i]] = iOff1 + i
1017 matW, matWJ, vecWd = aPoint.getDerivatives(nJacobian)
1018 sign = 2 * nJacobian - 1
1020 aJacobian[labSlope:labOffset, 0:1] = -sign * vecWd
1021 anIndex[0] = nLocals + 1
1022 aJacobian[labSlope:labOffset, index1:index1 + 2] = -sign * matWJ
1023 aJacobian[labSlope:labOffset, index2:index2 + 2] = sign * matW
1024 for i
in range(nDim):
1025 anIndex[index2 + aDim[i]] = iOff2 + i
1030 aJacobian[labCurv, labCurv] = 1.0
1032 return anIndex, aJacobian
1047 nOffset = aPoint.getOffset()
1048 anIndex = [0, 0, 0, 0, 0, 0, 0]
1049 aJacobian = np.zeros((2, 7))
1051 prevW, prevWJ, prevWd = aPoint.getDerivatives(0)
1052 nextW, nextWJ, nextWd = aPoint.getDerivatives(1)
1053 sumWJ = prevWJ + nextWJ
1054 sumWd = prevWd + nextWd
1055 iOff = (nOffset - 1) * nDim + nCurv + nLocals + 1
1059 aJacobian[:, 0:1] = -sumWd
1060 anIndex[0] = nLocals + 1
1061 aJacobian[:, 1:3] = prevW
1062 aJacobian[:, 3:5] = -sumWJ
1063 aJacobian[:, 5:7] = nextW
1064 for i
in range(nDim):
1065 anIndex[1 + aDim[i]] = iOff + i
1066 anIndex[3 + aDim[i]] = iOff + nDim + i
1067 anIndex[5 + aDim[i]] = iOff + nDim * 2 + i
1069 return anIndex, aJacobian
1086 nOffset = aPoint.getOffset()
1087 anIndex = [0, 0, 0, 0]
1088 aJacobian = np.zeros((4, 4))
1090 iOff = (nOffset - 1) * nDim + nCurv + nLocals + 1
1093 aJacobian[2:,:2] = -np.eye(2)
1094 aJacobian[2:, 2:] = np.eye(2)
1096 for i
in range(nDim):
1097 anIndex[aDim[i]] = iOff + nDim + i
1098 anIndex[2 + aDim[i]] = iOff + nDim * 2 + i
1100 return anIndex, aJacobian
1117 nOffset = aPoint.getOffset()
1118 anIndex = [0, 0, 0, 0, 0, 0, 0, 0, 0]
1119 aJacobian = np.zeros((4, 9))
1121 prevW, prevWJ, prevWd = aPoint.getDerivatives(0)
1122 nextW, nextWJ, nextWd = aPoint.getDerivatives(1)
1123 iOff = (nOffset - 1) * nDim + nCurv + nLocals + 1
1127 aJacobian[:2, 0:1] = -(prevWd + nextWd)
1128 anIndex[0] = nLocals + 1
1129 aJacobian[:2, 1:3] = prevW
1130 aJacobian[:2, 3:5] = -prevWJ
1131 aJacobian[:2, 5:7] = -nextWJ
1132 aJacobian[:2, 7:9] = nextW
1134 aJacobian[2:, 3:5] = -np.eye(2)
1135 aJacobian[2:, 5:7] = np.eye(2)
1137 for i
in range(nDim):
1138 anIndex[1 + aDim[i]] = iOff + i
1139 anIndex[3 + aDim[i]] = iOff + nDim + i
1140 anIndex[5 + aDim[i]] = iOff + nDim * 2 + i
1141 anIndex[7 + aDim[i]] = iOff + nDim * 3 + i
1143 return anIndex, aJacobian
1146 aResidual, aMeasVar, aDownWeight, indLocal, derLocal = self.
__data[aData].
getResidual()
1147 aVec = np.array(derLocal)
1148 aMat = self.
__matrix.getBlockMatrix(indLocal)
1149 aFitVar = np.dot(aVec, np.dot(aMat, aVec.T))
1150 aFitVar *= aDownWeight
1151 aMeasError = math.sqrt(aMeasVar)
1153 aResError = math.sqrt(aMeasVar - aFitVar)
if aFitVar < aMeasVar
else 0.
1155 aResError = math.sqrt(aMeasVar + aFitVar)
1156 return aResidual, aMeasError, aResError, aDownWeight
1169 nParBRL = len(anIndex)
1170 aVec = np.empty(nParBRL)
1171 for i
in range(nParBRL):
1172 aVec[i] = self.
__vector[anIndex[i] - 1]
1173 aMat = self.
__matrix.getBlockMatrix(anIndex)
1174 locPar = np.dot(aJacobian, aVec)
1175 locCov = np.dot(aJacobian, np.dot(aMat, aJacobian.T))
1176 return locPar, locCov
1189 return 0,
None,
None,
None,
None
1191 aResiduals = np.empty(numData)
1192 aMeasErr = np.empty(numData)
1193 aResErr = np.empty(numData)
1194 aDownWeight = np.empty(numData)
1195 for i
in range(numData):
1197 return numData, aResiduals, aMeasErr, aResErr, aDownWeight
1210 return 0,
None,
None,
None,
None
1212 aResiduals = np.empty(numData)
1213 aMeasErr = np.empty(numData)
1214 aResErr = np.empty(numData)
1215 aDownWeight = np.empty(numData)
1216 for i
in range(numData):
1217 aResiduals[i], aMeasErr[i], aResErr[i], aDownWeight[i] = self.
__getResAndErr(firstData + i)
1218 return numData, aResiduals, aMeasErr, aResErr, aDownWeight
1233 def fit(self, optionList="", aLabel=0):
1236 def defineOffsets():
1244 scatDim = aPoint.getScatDim()
1246 aPoint.setOffset(nOffsets)
1252 aPoint.setOffset(-nOffsets)
1254 self.
__points[-1].setOffset(nOffsets)
1256 if (self.
__points[-1].getScatDim() == 4):
1264 def calcJacobians():
1265 scatJacobian = np.empty((5, 5))
1271 scatJacobian = self.
__points[iPoint].getP2pJacobian()
1273 scatJacobian = np.dot(self.
__points[iPoint].getP2pJacobian(), scatJacobian)
1275 self.
__points[iPoint].addPrevJacobian(scatJacobian)
1276 if (self.
__points[iPoint].getOffset() >= 0):
1277 self.
__points[lastPoint].addNextJacobian(scatJacobian)
1282 if (self.
__points[iPoint].getOffset() >= 0):
1283 scatJacobian = self.
__points[iPoint].getP2pJacobian()
1285 self.
__points[iPoint].addNextJacobian(scatJacobian)
1286 scatJacobian = np.dot(scatJacobian, self.
__points[iPoint].getP2pJacobian())
1294 if (aPoint.hasMeasurement()):
1295 nLabel = aPoint.getLabel()
1297 for m
in aPoint.getMeasurements():
1299 measDim = m.getMeasDim()
1300 measPrecision = m.getMeasMinPrec()
1301 localDer = m.getLocalDerivatives()
1302 globalLab = m.getGlobalLabels()
1303 globalDer = m.getGlobalDerivatives()
1304 matP, aMeas, aPrec = m.getMeasurement()
1305 nJacobian = 1
if aPoint.getOffset() < self.
__numOffsets - 1
else 0
1307 matPDer = matDer
if matP
is None else np.dot(matP, matDer)
1308 for i
in range(measDim):
1309 if (aPrec[i] > measPrecision):
1310 aData =
GblData(nLabel, 1, aMeas[i], aPrec[i], measIndex)
1311 aData.addDerivatives(i, labDer, matPDer, localDer, \
1312 globalLab, globalDer)
1313 self.
__data.append(aData)
1320 scatDim = aPoint.getScatDim()
1322 nLabel = aPoint.getLabel()
1325 if (aPoint.isLast()):
1327 matT, aMeas, aPrec = aPoint.getReducedScatterer()
1331 matT, aMeas, aPrec = aPoint.getScatterer()
1335 if (aPoint.isLast()):
1339 matT, aMeas, aPrec = aPoint.getScatterer()
1341 matTDer = matDer
if matT
is None else np.dot(matT, matDer)
1344 aData =
GblData(nLabel, 2, aMeas[i], aPrec[i])
1345 aData.addDerivatives(i, labDer, matTDer)
1346 self.
__data.append(aData)
1350 if (aPrec[i + 2] > 0.):
1351 aData =
GblData(nLabel, 2, aMeas[i + 2], aPrec[i + 2])
1352 aData.addDerivatives(i + 2, labDer, matTDer)
1353 self.
__data.append(aData)
1361 aMatrix = np.dot(eigenVec.T, aJacobian)
1362 for i
in range(len(eigenVec)):
1363 if (eigenVal[i] > 0.):
1364 externalDerivatives = []
1365 for j
in range(len(externalIndex)):
1366 externalDerivatives.append(aMatrix[i, j])
1368 aData.addExtDerivatives(externalIndex, externalDerivatives)
1369 self.
__data.append(aData)
1373 def buildLinearEquationSystem():
1377 for aData
in self.
__data:
1381 index, aVector, aMatrix = aData.getMatrices()
1382 for i
in range(len(index)):
1383 self.
__vector[ index[i] - 1 ] += aVector[0, i]
1384 self.
__matrix.addBlockMatrix(index, aMatrix)
1391 def downWeight(aMethod):
1393 for aData
in self.
__data:
1394 aLoss += (1. - aData.setDownWeighting(aMethod))
1399 for aData
in self.
__data:
1410 buildLinearEquationSystem()
1418 for o
in optionList:
1420 aMethod =
"THC".index(o.upper()) + 1
1421 lostWeight = downWeight(aMethod)
1422 buildLinearEquationSystem()
1430 for aData
in self.
__data:
1434 Chi2 += aData.getChi2()
1436 Chi2 /= [1.0, 0.8737, 0.9326, 0.8228 ][aMethod]
1437 return Chi2, Ndf, lostWeight
1439 except (ZeroDivisionError, np.linalg.linalg.LinAlgError):
Data (block) containing value, precision and derivatives for measurements, kinks and external seed.
def toRecord(self)
Get data components (for copying to MP binaty record)
__downWeight
down weighting factor (M-estimators); float
def fromRecord(self, dataList)
Set data components (from MP binaty record)
__dwMethod
down weighting method; int
def printData(self)
Print data.
def setDownWeighting(self, aMethod)
Outlier down weighting with M-estimators.
__value
value (residual or kink); float
__prediction
prediction (for value from fit); float
def getMatrices(self)
Calculate compressed matrix and right hand side from data.
def getResidual(self)
Get data for residual (and errors).
__label
label of corresponding point; int
__derivatives
derivatives (prediction vs fit parameters); list(float)
def addExtDerivatives(self, indexExt, derExt)
Add derivatives to data (block) from external seed.
def __init__(self, aLabel=0, aType=0, aValue=0., aPrec=0., aMeas=0)
Create new data.
def addDerivatives(self, iRow, labDer, matDer, derLocal=None, labGlobal=None, derGlobal=None)
Add derivatives to data (block) from measurements and kinks.
__parameters
labels of fit parameters (with non zero derivative); list(int)
def setPrediction(self, aVector)
Calculate prediction for data from fit.
def getIndex(self)
Get index.
def analyzeData(self, maxBand)
Analyze labels of fit parameters to determine number of parameters and border size with given maximal...
__type
type of data (0: none, 1: internal measurement, 2: internal kink, 3: external seed,...
__precision
precision (diagonal element of inverse covariance matrix); float
__globalLabels
labels of global parameters; list(int)
def getType(self)
Get type.
def getChi2(self)
Calculate Chi2 (contribution) from data.
__index
index for internal measurement
def getGlobalLabels(self)
Get global labels.
__globalDerivatives
derivatives (prediction vs global parameters); list(float)
def getLabel(self)
Get Label.
User supplied measurement at point on (initial) trajectory.
def getLocalDerivatives(self)
Get local derivatives.
def printMeasurement(self)
Print Measurement.
__measDim
dimension of measurement (2D, 4D or 5D); int
def getNumLocals(self)
Get number of local derivatives.
def getMeasurement(self)
Retrieve measurement of a point.
__globalDerivatives
global derivatives; matrix(float)
__measurement
measurement at point: projection (dm/du), residuals (to initial trajectory), precision; list(matrix(f...
__localDerivatives
local derivatives; matrix(float)
def getGlobalLabels(self)
Get global labels.
def getGlobalDerivatives(self)
Get global derivatives.
def addGlobals(self, labels, derivatives)
Add global derivatives.
def addLocals(self, derivatives)
Add local derivatives.
def hasMeasurement(self)
Check point for a measurement.
def getMeasDim(self)
Retrieve dimension of measurement of a point.
def __init__(self, aMeasurement, minPrecision=0.)
Create new measurement.
__measMinPrec
minimal precision to accept measurement <
__globalLabels
global labels; matrix(int)
def getMeasMinPrec(self)
Retrieve minimal precision to accept measurement.
__measTransformation
transformation (to eigen-vectors of precision matrix); matrix(float)
User supplied point on (initial) trajectory.
__jacobians
jacobians for propagation to previous or next point with offsets; pair(matrix(float))
__p2pJacobian
Point-to-point jacobian from previous point; matrix(float)
def getScatDim(self)
Get scatterer dimension.
def isFirst(self)
Is first point?
def getMeasurements(self)
Retrieve measurements of a point.
def addPrevJacobian(self, aJacobian)
Add jacobian to previous offset.
def isLast(self)
Is last point?
__scatterer
scatterer at point: (transformation or None,) initial kinks, precision (inverse covariance matrix); l...
def getScatterer(self)
Retrieve scatterer of a point.
def addGlobals(self, labels, derivatives)
Add global derivatives (to last measurement).
def printPoint(self)
Print point.
def setLabel(self, aLabel)
Define label of a point.
def getLabel(self)
Retrieve label of a point.
def hasMeasurement(self)
Check point for a measurement.
__type
type (-1: first, 0: inner, 1: last)
def getReducedScatterer(self)
Retrieve (reduced) scatterer of a point.
def __init__(self, aJacobian)
Create new point.
def addLocals(self, derivatives)
Add local derivatives (to last measurement).
def getOffset(self)
Get offset of a point.
def setOffset(self, anOffset)
Define offset of a point and references to previous and next point with offset.
def addNextJacobian(self, aJacobian)
Add jacobian to next offset.
def addScatterer(self, aScatterer)
Add a (thin or thick) scatterer to a point.
def getP2pJacobian(self)
Retrieve jacobian of a point.
__scatDim
scatterer dimension (valid 2(thin) or 4(thick))
def getDerivatives(self, index)
Get derivatives for locally linearized track model (backward or forward propagation).
def addMeasurement(self, aMeasurement, minPrecision=0.)
Add a mesurement to a point.
__measurements
measurements at point; list(GblMeasurement)
__label
label for referencing point (0,1,..,number(points)-1); int
def setType(self, aType)
Define type of a point.
__offset
>=0: offset number at point, <0: offset number at next point with offset; int
General Broken Lines Trajectory.
__externalPoint
label of point with external seed; int
def getResidual(self, iData)
Get residuals from data of trajectory.
def getNumPoints(self)
Get number of points on trajectory.
__numCurvature
'curvature' is fit parameter (=1); int
def milleOut(self, aFile, doublePrec=False)
Write (data blocks of) trajectory to MP (binary) file (as float or double values).
__skippedMeasLabel
label of point with measurements skipped in fit (for unbiased residuals)
def getNumbers(self)
Get (parameter) number of trajectory.
__dimensions
active components of offsets (both ([0,1]) or single ([0] or [1]); list(int)
def milleIn(self, aFile)
Read (data blocks of) trajectory from MP (binary) file.
def addPoint(self, point)
Add point to trajectory.
__measDataIndex
mapping points to data blocks from measurements; list(int)
def __getFitToStepJacobian(self, aPoint)
Get jacobian for transformation from (trajectory) fit to step parameters at point.
__numParameters
number fit parameters; int
def __init__(self, hasCurv=True, aDim=[0, 1])
Create new trajectory.
__numLocals
number of local parameters; int
__numPoints
number of points on trajectory; int
def printData(self)
Print data of trajectory.
__points
points on trajectory; list(GblPoint)
def getScatResults(self, aLabel)
Get residuals at point from scatterer.
def __getFitToKinkJacobian(self, aPoint)
Get jacobian for transformation from (trajectory) fit to kink parameters at point.
__externalSeed
external seed (for local, fit parameters); matrix(float)
def getData(self)
Get data of trajectory.
def __getJacobian(self, aLabel)
Get jacobian for transformation from fit to track parameters at point.
__matrix
Calculate Jacobians to previous/next scatterer from point to point ones.
def fit(self, optionList="", aLabel=0)
Perform fit of trajectory.
__numOffsets
number of (points with) offsets on trajectory; int
def printPoints(self)
Print points of trajectory.
def addExternalSeed(self, aLabel, aSeed)
Add external seed to trajectory.
__data
data (blocks) of trajectory; list(GblData)
def __getFitToKinkAndStepJacobian(self, aPoint)
Get jacobian for transformation from (trajectory) fit to kink and step parameters at point.
def __getResAndErr(self, aData, used=True)
__scatDataIndex
mapping points to data blocks from scatterers; list(int)
def getMeasResults(self, aLabel)
Get residuals at point from measurement.
def __getFitToLocalJacobian(self, aPoint, measDim, nJacobian=1)
Get (part of) jacobian for transformation from (trajectory) fit to track parameters at point.
def getResults(self, aLabel)
Get results (corrections, covarinace matrix) at point in forward or backward direction.
(Symmetric) Bordered Band Matrix.
Millepede-II (binary) record.