Back to home page

sPhenix code displayed by LXR

 
 

    


File indexing completed on 2025-08-05 08:18:26

0001 /*
0002  * GblTrajectory.cpp
0003  *
0004  *  Created on: Aug 18, 2011
0005  *      Author: kleinwrt
0006  */
0007 
0008 /** \file
0009  *  GblTrajectory methods.
0010  *
0011  *  \author Claus Kleinwort, DESY, 2011 (Claus.Kleinwort@desy.de)
0012  *
0013  *  \copyright
0014  *  Copyright (c) 2011 - 2016 Deutsches Elektronen-Synchroton,
0015  *  Member of the Helmholtz Association, (DESY), HAMBURG, GERMANY \n\n
0016  *  This library is free software; you can redistribute it and/or modify
0017  *  it under the terms of the GNU Library General Public License as
0018  *  published by the Free Software Foundation; either version 2 of the
0019  *  License, or (at your option) any later version. \n\n
0020  *  This library is distributed in the hope that it will be useful,
0021  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
0022  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0023  *  GNU Library General Public License for more details. \n\n
0024  *  You should have received a copy of the GNU Library General Public
0025  *  License along with this program (see the file COPYING.LIB for more
0026  *  details); if not, write to the Free Software Foundation, Inc.,
0027  *  675 Mass Ave, Cambridge, MA 02139, USA.
0028  *
0029  *  
0030  *  General information
0031  *
0032  *  Introduction
0033  *
0034  *  For a track with an initial trajectory from a prefit of the
0035  *  measurements (internal seed) or an external prediction
0036  *  (external seed) the description of multiple scattering is
0037  *  added by offsets in a local system. Along the initial
0038  *  trajectory points are defined with can describe a measurement
0039  *  or a (thin) scatterer or both. Measurements are arbitrary
0040  *  functions of the local track parameters at a point (e.g. 2D:
0041  *  position, 4D: direction+position). The refit provides corrections
0042  *  to the local track parameters (in the local system) and the
0043  *  corresponding covariance matrix at any of those points.
0044  *  Non-diagonal covariance matrices of
0045  *  measurements will be diagonalized internally.
0046  *  Outliers can be down-weighted by use of M-estimators.
0047  *
0048  *  A position measurement is in a plane defined by two directions.
0049  *  Along one direction the measurement precision may be zero,
0050  *  defining a 1D measurement in the other direction.
0051  *
0052  *  The broken lines trajectory is defined by (2D) offsets at the
0053  *  first and last point and all points with a scatterer. The
0054  *  prediction for a measurement is obtained by interpolation of
0055  *  the enclosing offsets and for triplets of adjacent offsets
0056  *  kink angles are determined. This requires for all points the
0057  *  jacobians for propagation to the previous and next offset.
0058  *  These are calculated from the point-to-point jacobians along
0059  *  the initial trajectory. The sequence of points has to be
0060  *  strictly monotonic in arc-length.
0061  *
0062  *  Additional local or global parameters can be added and the
0063  *  trajectories can be written to special binary files for
0064  *  calibration and alignment with Millepede-II.
0065  *  (V. Blobel, NIM A, 566 (2006), pp. 5-13).
0066  *
0067  *  Besides simple trajectories describing the path of a single
0068  *  particle composed trajectories are supported. These are
0069  *  constructed from the trajectories of multiple particles and
0070  *  some external parameters (like those describing a decay)
0071  *  and transformations at the first points from the external
0072  *  to the local track parameters.
0073  *
0074  *  The conventions for the coordinate systems follow:
0075  *  Derivation of Jacobians for the propagation of covariance
0076  *  matrices of track parameters in homogeneous magnetic fields
0077  *  A. Strandlie, W. Wittek, NIM A, 566 (2006) 687-698.
0078  *
0079  *  Calling sequence
0080  *
0081  *    -# Create list of points on initial trajectory:\n
0082  *            <tt>std::vector<GblPoint> list</tt>
0083  *    -# For all points on initial trajectory:
0084  *        - Create points and add appropriate attributes:\n
0085  *           - <tt>point = gbl::GblPoint(..)</tt>
0086  *           - <tt>point.addMeasurement(..)</tt>
0087  *           - Add additional local or global parameters to measurement:\n
0088  *             - <tt>point.addLocals(..)</tt>
0089  *             - <tt>point.addGlobals(..)</tt>
0090  *           - <tt>point.addScatterer(..)</tt>
0091  *        - Add point (ordered by arc length) to list:\n
0092  *            <tt>list.push_back(point)</tt>
0093  *    -# Create (simple) trajectory from list of points:\n
0094  *            <tt>traj = gbl::GblTrajectory (list)</tt>
0095  *    -# Optionally with external seed:\n
0096  *            <tt>traj = gbl::GblTrajectory (list,seed)</tt>
0097  *    -# Optionally check validity of trajectory:\n
0098  *            <tt>if (not traj.isValid()) .. //abort</tt>
0099  *    -# Fit trajectory, return error code,
0100  *       get Chi2, Ndf (and weight lost by M-estimators):\n
0101  *            <tt>ierr = traj.fit(..)</tt>
0102  *    -# For any point on initial trajectory:
0103  *        - Get corrections and covariance matrix for track parameters:\n
0104  *            <tt>[..] = traj.getResults(label)</tt>
0105  *        - Optionally get residuals with errors for measurements:\n
0106  *            <tt>[..] = traj.getMeasResults(label) </tt>
0107  *        - Optionally get residuals with errors for scatterers:\n
0108  *            <tt>[..] = traj.getScatResults(label) </tt>
0109  *    -# Optionally write trajectory to MP binary file (doesn't needs to be fitted):\n
0110  *            <tt>traj.milleOut(..)</tt>
0111  *
0112  *  Local system and local parameters
0113  *  At each point on the trajectory a local coordinate system with local track
0114  *  parameters has to be defined. The first of the five parameters describes
0115  *  the bending, the next two the direction and the last two the position (offsets).
0116  *  The curvilinear system (T,U,V) with parameters (q/p, lambda, phi, x_t, y_t)
0117  *  is well suited.
0118  *
0119  *  Implementation
0120  *
0121  *  Matrices are implemented with ROOT (root.cern.ch). User input or output is in the
0122  *  form of TMatrices. Internally SMatrices are used for fixes sized and simple matrices
0123  *  based on std::vector<> for variable sized matrices.
0124  *
0125  *  References
0126  *    - V. Blobel, C. Kleinwort, F. Meier,
0127  *      Fast alignment of a complex tracking detector using advanced track models,
0128  *      Computer Phys. Communications (2011), doi:10.1016/j.cpc.2011.03.017
0129  *    - C. Kleinwort, General Broken Lines as advanced track fitting method,
0130  *      NIM A, 673 (2012), 107-110, doi:10.1016/j.nima.2012.01.024
0131  */
0132 
0133 #include "GblTrajectory.h"
0134 
0135 //! Namespace for the general broken lines package
0136 namespace gbl {
0137 
0138 /// Create new (simple) trajectory from list of points.
0139 /**
0140  * Curved trajectory in space (default) or without curvature (q/p) or in one
0141  * plane (u-direction) only.
0142  * \param [in] aPointList List of points
0143  * \param [in] flagCurv Use q/p
0144  * \param [in] flagU1dir Use in u1 direction
0145  * \param [in] flagU2dir Use in u2 direction
0146  */
0147 GblTrajectory::GblTrajectory(const std::vector<GblPoint> &aPointList,
0148         bool flagCurv, bool flagU1dir, bool flagU2dir) :
0149         numAllPoints(aPointList.size()), numPoints(), numOffsets(0), numInnerTrans(
0150                 0), numCurvature(flagCurv ? 1 : 0), numParameters(0), numLocals(
0151                 0), numMeasurements(0), externalPoint(0), theDimension(0), thePoints(), theData(), measDataIndex(), scatDataIndex(), externalSeed(), innerTransformations(), externalDerivatives(), externalMeasurements(), externalPrecisions() {
0152 
0153     if (flagU1dir)
0154         theDimension.push_back(0);
0155     if (flagU2dir)
0156         theDimension.push_back(1);
0157     // simple (single) trajectory
0158     thePoints.push_back(aPointList);
0159     numPoints.push_back(numAllPoints);
0160     construct(); // construct trajectory
0161 }
0162 
0163 /// Create new (simple) trajectory from list of points with external seed.
0164 /**
0165  * Curved trajectory in space (default) or without curvature (q/p) or in one
0166  * plane (u-direction) only.
0167  * \param [in] aPointList List of points
0168  * \param [in] aLabel (Signed) label of point for external seed
0169  * (<0: in front, >0: after point, slope changes at scatterer!)
0170  * \param [in] aSeed Precision matrix of external seed
0171  * \param [in] flagCurv Use q/p
0172  * \param [in] flagU1dir Use in u1 direction
0173  * \param [in] flagU2dir Use in u2 direction
0174  */
0175 GblTrajectory::GblTrajectory(const std::vector<GblPoint> &aPointList,
0176         unsigned int aLabel, const TMatrixDSym &aSeed, bool flagCurv,
0177         bool flagU1dir, bool flagU2dir) :
0178         numAllPoints(aPointList.size()), numPoints(), numOffsets(0), numInnerTrans(
0179                 0), numCurvature(flagCurv ? 1 : 0), numParameters(0), numLocals(
0180                 0), numMeasurements(0), externalPoint(aLabel), theDimension(0), thePoints(), theData(), measDataIndex(), scatDataIndex(), externalSeed(
0181                 aSeed), innerTransformations(), externalDerivatives(), externalMeasurements(), externalPrecisions() {
0182 
0183     if (flagU1dir)
0184         theDimension.push_back(0);
0185     if (flagU2dir)
0186         theDimension.push_back(1);
0187     // simple (single) trajectory
0188     thePoints.push_back(aPointList);
0189     numPoints.push_back(numAllPoints);
0190     construct(); // construct trajectory
0191 }
0192 
0193 /// Create new composed trajectory from list of points and transformations.
0194 /**
0195  * Composed of curved trajectory in space.
0196  * \param [in] aPointsAndTransList List containing pairs with list of points and transformation (at inner (first) point)
0197  */
0198 GblTrajectory::GblTrajectory(
0199         const std::vector<std::pair<std::vector<GblPoint>, TMatrixD> > &aPointsAndTransList) :
0200         numAllPoints(), numPoints(), numOffsets(0), numInnerTrans(
0201                 aPointsAndTransList.size()), numParameters(0), numLocals(0), numMeasurements(
0202                 0), externalPoint(0), theDimension(0), thePoints(), theData(), measDataIndex(), scatDataIndex(), externalSeed(), innerTransformations(), externalDerivatives(), externalMeasurements(), externalPrecisions() {
0203 
0204     for (unsigned int iTraj = 0; iTraj < aPointsAndTransList.size(); ++iTraj) {
0205         thePoints.push_back(aPointsAndTransList[iTraj].first);
0206         numPoints.push_back(thePoints.back().size());
0207         numAllPoints += numPoints.back();
0208         innerTransformations.push_back(aPointsAndTransList[iTraj].second);
0209     }
0210     theDimension.push_back(0);
0211     theDimension.push_back(1);
0212     numCurvature = innerTransformations[0].GetNcols();
0213     construct(); // construct (composed) trajectory
0214 }
0215 
0216 /// Create new composed trajectory from list of points and transformations with (independent) external measurements.
0217 /**
0218  * Composed of curved trajectory in space.
0219  * \param [in] aPointsAndTransList List containing pairs with list of points and transformation (at inner (first) point)
0220  * \param [in] extDerivatives Derivatives of external measurements vs external parameters
0221  * \param [in] extMeasurements External measurements (residuals)
0222  * \param [in] extPrecisions Precision of external measurements
0223  */
0224 GblTrajectory::GblTrajectory(
0225         const std::vector<std::pair<std::vector<GblPoint>, TMatrixD> > &aPointsAndTransList,
0226         const TMatrixD &extDerivatives, const TVectorD &extMeasurements,
0227         const TVectorD &extPrecisions) :
0228         numAllPoints(), numPoints(), numOffsets(0), numInnerTrans(
0229                 aPointsAndTransList.size()), numParameters(0), numLocals(0), numMeasurements(
0230                 0), externalPoint(0), theDimension(0), thePoints(), theData(), measDataIndex(), scatDataIndex(), externalSeed(), innerTransformations(), externalDerivatives(
0231                 extDerivatives), externalMeasurements(extMeasurements), externalPrecisions(
0232                 extPrecisions) {
0233 
0234     for (unsigned int iTraj = 0; iTraj < aPointsAndTransList.size(); ++iTraj) {
0235         thePoints.push_back(aPointsAndTransList[iTraj].first);
0236         numPoints.push_back(thePoints.back().size());
0237         numAllPoints += numPoints.back();
0238         innerTransformations.push_back(aPointsAndTransList[iTraj].second);
0239     }
0240     theDimension.push_back(0);
0241     theDimension.push_back(1);
0242     numCurvature = innerTransformations[0].GetNcols();
0243     construct(); // construct (composed) trajectory
0244 }
0245 
0246 /// Create new composed trajectory from list of points and transformations with (correlated) external measurements.
0247 /**
0248  * Composed of curved trajectory in space.
0249  * \param [in] aPointsAndTransList List containing pairs with list of points and transformation (at inner (first) point)
0250  * \param [in] extDerivatives Derivatives of external measurements vs external parameters
0251  * \param [in] extMeasurements External measurements (residuals)
0252  * \param [in] extPrecisions Precision of external measurements
0253  */
0254 GblTrajectory::GblTrajectory(
0255         const std::vector<std::pair<std::vector<GblPoint>, TMatrixD> > &aPointsAndTransList,
0256         const TMatrixD &extDerivatives, const TVectorD &extMeasurements,
0257         const TMatrixDSym &extPrecisions) :
0258         numAllPoints(), numPoints(), numOffsets(0), numInnerTrans(
0259                 aPointsAndTransList.size()), numParameters(0), numLocals(0), numMeasurements(
0260                 0), externalPoint(0), theDimension(0), thePoints(), theData(), measDataIndex(), scatDataIndex(), externalSeed(), innerTransformations() {
0261 
0262     // diagonalize external measurement
0263     TMatrixDSymEigen extEigen(extPrecisions);
0264     TMatrixD extTransformation = extEigen.GetEigenVectors();
0265     extTransformation.T();
0266     externalDerivatives.ResizeTo(extDerivatives);
0267     externalDerivatives = extTransformation * extDerivatives;
0268     externalMeasurements.ResizeTo(extMeasurements);
0269     externalMeasurements = extTransformation * extMeasurements;
0270     externalPrecisions.ResizeTo(extMeasurements);
0271     externalPrecisions = extEigen.GetEigenValues();
0272 
0273     for (unsigned int iTraj = 0; iTraj < aPointsAndTransList.size(); ++iTraj) {
0274         thePoints.push_back(aPointsAndTransList[iTraj].first);
0275         numPoints.push_back(thePoints.back().size());
0276         numAllPoints += numPoints.back();
0277         innerTransformations.push_back(aPointsAndTransList[iTraj].second);
0278     }
0279     theDimension.push_back(0);
0280     theDimension.push_back(1);
0281     numCurvature = innerTransformations[0].GetNcols();
0282     construct(); // construct (composed) trajectory
0283 }
0284 
0285 GblTrajectory::~GblTrajectory() {
0286 }
0287 
0288 /// Retrieve validity of trajectory
0289 bool GblTrajectory::isValid() const {
0290     return constructOK;
0291 }
0292 
0293 /// Retrieve number of point from trajectory
0294 unsigned int GblTrajectory::getNumPoints() const {
0295     return numAllPoints;
0296 }
0297 
0298 /// Construct trajectory from list of points.
0299 /**
0300  * Trajectory is prepared for fit or output to binary file, may consists of sub-trajectories.
0301  */
0302 void GblTrajectory::construct() {
0303 
0304     constructOK = false;
0305     fitOK = false;
0306     unsigned int aLabel = 0;
0307     if (numAllPoints < 2) {
0308         std::cout << " GblTrajectory construction failed: too few GblPoints "
0309                 << std::endl;
0310         return;
0311     }
0312     // loop over trajectories
0313     numTrajectories = thePoints.size();
0314     //std::cout << " numTrajectories: " << numTrajectories << ", " << innerTransformations.size() << std::endl;
0315     for (unsigned int iTraj = 0; iTraj < numTrajectories; ++iTraj) {
0316         std::vector<GblPoint>::iterator itPoint;
0317         for (itPoint = thePoints[iTraj].begin();
0318                 itPoint < thePoints[iTraj].end(); ++itPoint) {
0319             numLocals = std::max(numLocals, itPoint->getNumLocals());
0320             numMeasurements += itPoint->hasMeasurement();
0321             itPoint->setLabel(++aLabel);
0322         }
0323     }
0324     defineOffsets();
0325     calcJacobians();
0326     try {
0327         prepare();
0328     } catch (std::overflow_error &e) {
0329         std::cout << " GblTrajectory construction failed: " << e.what()
0330                 << std::endl;
0331         return;
0332     }
0333     constructOK = true;
0334     // number of fit parameters
0335     numParameters = (numOffsets - 2 * numInnerTrans) * theDimension.size()
0336             + numCurvature + numLocals;
0337 }
0338 
0339 /// Define offsets from list of points.
0340 /**
0341  * Define offsets at points with scatterers and first and last point.
0342  * All other points need interpolation from adjacent points with offsets.
0343  */
0344 void GblTrajectory::defineOffsets() {
0345 
0346     // loop over trajectories
0347     for (unsigned int iTraj = 0; iTraj < numTrajectories; ++iTraj) {
0348         // first point is offset
0349         thePoints[iTraj].front().setOffset(numOffsets++);
0350         // intermediate scatterers are offsets
0351         std::vector<GblPoint>::iterator itPoint;
0352         for (itPoint = thePoints[iTraj].begin() + 1;
0353                 itPoint < thePoints[iTraj].end() - 1; ++itPoint) {
0354             if (itPoint->hasScatterer()) {
0355                 itPoint->setOffset(numOffsets++);
0356             } else {
0357                 itPoint->setOffset(-numOffsets);
0358             }
0359         }
0360         // last point is offset
0361         thePoints[iTraj].back().setOffset(numOffsets++);
0362     }
0363 }
0364 
0365 /// Calculate Jacobians to previous/next scatterer from point to point ones.
0366 void GblTrajectory::calcJacobians() {
0367 
0368     SMatrix55 scatJacobian;
0369     // loop over trajectories
0370     for (unsigned int iTraj = 0; iTraj < numTrajectories; ++iTraj) {
0371         // forward propagation (all)
0372         GblPoint* previousPoint = &thePoints[iTraj].front();
0373         unsigned int numStep = 0;
0374         std::vector<GblPoint>::iterator itPoint;
0375         for (itPoint = thePoints[iTraj].begin() + 1;
0376                 itPoint < thePoints[iTraj].end(); ++itPoint) {
0377             if (numStep == 0) {
0378                 scatJacobian = itPoint->getP2pJacobian();
0379             } else {
0380                 scatJacobian = itPoint->getP2pJacobian() * scatJacobian;
0381             }
0382             numStep++;
0383             itPoint->addPrevJacobian(scatJacobian); // iPoint -> previous scatterer
0384             if (itPoint->getOffset() >= 0) {
0385                 previousPoint->addNextJacobian(scatJacobian); // lastPoint -> next scatterer
0386                 numStep = 0;
0387                 previousPoint = &(*itPoint);
0388             }
0389         }
0390         // backward propagation (without scatterers)
0391         for (itPoint = thePoints[iTraj].end() - 1;
0392                 itPoint > thePoints[iTraj].begin(); --itPoint) {
0393             if (itPoint->getOffset() >= 0) {
0394                 scatJacobian = itPoint->getP2pJacobian();
0395                 continue; // skip offsets
0396             }
0397             itPoint->addNextJacobian(scatJacobian); // iPoint -> next scatterer
0398             scatJacobian = scatJacobian * itPoint->getP2pJacobian();
0399         }
0400     }
0401 }
0402 
0403 /// Get jacobian for transformation from fit to track parameters at point.
0404 /**
0405  * Jacobian broken lines (q/p,..,u_i,u_i+1..) to track (q/p,u',u) parameters
0406  * including additional local parameters.
0407  * \param [in] aSignedLabel (Signed) label of point for external seed
0408  * (<0: in front, >0: after point, slope changes at scatterer!)
0409  * \return List of fit parameters with non zero derivatives and
0410  * corresponding transformation matrix
0411  */
0412 std::pair<std::vector<unsigned int>, TMatrixD> GblTrajectory::getJacobian(
0413         int aSignedLabel) const {
0414 
0415     unsigned int nDim = theDimension.size();
0416     unsigned int nCurv = numCurvature;
0417     unsigned int nLocals = numLocals;
0418     unsigned int nBorder = nCurv + nLocals;
0419     unsigned int nParBRL = nBorder + 2 * nDim;
0420     unsigned int nParLoc = nLocals + 5;
0421     std::vector<unsigned int> anIndex;
0422     anIndex.reserve(nParBRL);
0423     TMatrixD aJacobian(nParLoc, nParBRL);
0424     aJacobian.Zero();
0425 
0426     unsigned int aLabel = abs(aSignedLabel);
0427     unsigned int firstLabel = 1;
0428     unsigned int lastLabel = 0;
0429     unsigned int aTrajectory = 0;
0430     // loop over trajectories
0431     for (unsigned int iTraj = 0; iTraj < numTrajectories; ++iTraj) {
0432         aTrajectory = iTraj;
0433         lastLabel += numPoints[iTraj];
0434         if (aLabel <= lastLabel)
0435             break;
0436         if (iTraj < numTrajectories - 1)
0437             firstLabel += numPoints[iTraj];
0438     }
0439     int nJacobian; // 0: prev, 1: next
0440     // check consistency of (index, direction)
0441     if (aSignedLabel > 0) {
0442         nJacobian = 1;
0443         if (aLabel >= lastLabel) {
0444             aLabel = lastLabel;
0445             nJacobian = 0;
0446         }
0447     } else {
0448         nJacobian = 0;
0449         if (aLabel <= firstLabel) {
0450             aLabel = firstLabel;
0451             nJacobian = 1;
0452         }
0453     }
0454     const GblPoint aPoint = thePoints[aTrajectory][aLabel - firstLabel];
0455     std::vector<unsigned int> labDer(5);
0456     SMatrix55 matDer;
0457     getFitToLocalJacobian(labDer, matDer, aPoint, 5, nJacobian);
0458 
0459     // from local parameters
0460     for (unsigned int i = 0; i < nLocals; ++i) {
0461         aJacobian(i + 5, i) = 1.0;
0462         anIndex.push_back(i + 1);
0463     }
0464     // from trajectory parameters
0465     unsigned int iCol = nLocals;
0466     for (unsigned int i = 0; i < 5; ++i) {
0467         if (labDer[i] > 0) {
0468             anIndex.push_back(labDer[i]);
0469             for (unsigned int j = 0; j < 5; ++j) {
0470                 aJacobian(j, iCol) = matDer(j, i);
0471             }
0472             ++iCol;
0473         }
0474     }
0475     return std::make_pair(anIndex, aJacobian);
0476 }
0477 
0478 /// Get (part of) jacobian for transformation from (trajectory) fit to track parameters at point.
0479 /**
0480  * Jacobian broken lines (q/p,..,u_i,u_i+1..) to local (q/p,u',u) parameters.
0481  * \param [out] anIndex List of fit parameters with non zero derivatives
0482  * \param [out] aJacobian Corresponding transformation matrix
0483  * \param [in] aPoint Point to use
0484  * \param [in] measDim Dimension of 'measurement'
0485  * (<=2: calculate only offset part, >2: complete matrix)
0486  * \param [in] nJacobian Direction (0: to previous offset, 1: to next offset)
0487  */
0488 void GblTrajectory::getFitToLocalJacobian(std::vector<unsigned int> &anIndex,
0489         SMatrix55 &aJacobian, const GblPoint &aPoint, unsigned int measDim,
0490         unsigned int nJacobian) const {
0491 
0492     unsigned int nDim = theDimension.size();
0493     unsigned int nCurv = numCurvature;
0494     unsigned int nLocals = numLocals;
0495 
0496     int nOffset = aPoint.getOffset();
0497 
0498     if (nOffset < 0) // need interpolation
0499             {
0500         SMatrix22 prevW, prevWJ, nextW, nextWJ, matN;
0501         SVector2 prevWd, nextWd;
0502         int ierr;
0503         aPoint.getDerivatives(0, prevW, prevWJ, prevWd); // W-, W- * J-, W- * d-
0504         aPoint.getDerivatives(1, nextW, nextWJ, nextWd); // W-, W- * J-, W- * d-
0505         const SMatrix22 sumWJ(prevWJ + nextWJ);
0506         matN = sumWJ.Inverse(ierr); // N = (W- * J- + W+ * J+)^-1
0507         // derivatives for u_int
0508         const SMatrix22 prevNW(matN * prevW); // N * W-
0509         const SMatrix22 nextNW(matN * nextW); // N * W+
0510         const SVector2 prevNd(matN * prevWd); // N * W- * d-
0511         const SVector2 nextNd(matN * nextWd); // N * W+ * d+
0512 
0513         unsigned int iOff = nDim * (-nOffset - 1) + nLocals + nCurv + 1; // first offset ('i' in u_i)
0514 
0515         // local offset
0516         if (nCurv > 0) {
0517             aJacobian.Place_in_col(-prevNd - nextNd, 3, 0); // from curvature
0518             anIndex[0] = nLocals + 1;
0519         }
0520         aJacobian.Place_at(prevNW, 3, 1); // from 1st Offset
0521         aJacobian.Place_at(nextNW, 3, 3); // from 2nd Offset
0522         for (unsigned int i = 0; i < nDim; ++i) {
0523             anIndex[1 + theDimension[i]] = iOff + i;
0524             anIndex[3 + theDimension[i]] = iOff + nDim + i;
0525         }
0526 
0527         // local slope and curvature
0528         if (measDim > 2) {
0529             // derivatives for u'_int
0530             const SMatrix22 prevWPN(nextWJ * prevNW); // W+ * J+ * N * W-
0531             const SMatrix22 nextWPN(prevWJ * nextNW); // W- * J- * N * W+
0532             const SVector2 prevWNd(nextWJ * prevNd); // W+ * J+ * N * W- * d-
0533             const SVector2 nextWNd(prevWJ * nextNd); // W- * J- * N * W+ * d+
0534             if (nCurv > 0) {
0535                 aJacobian(0, 0) = 1.0;
0536                 aJacobian.Place_in_col(prevWNd - nextWNd, 1, 0); // from curvature
0537             }
0538             aJacobian.Place_at(-prevWPN, 1, 1); // from 1st Offset
0539             aJacobian.Place_at(nextWPN, 1, 3); // from 2nd Offset
0540         }
0541     } else { // at point
0542         // anIndex must be sorted
0543         // forward : iOff2 = iOff1 + nDim, index1 = 1, index2 = 3
0544         // backward: iOff2 = iOff1 - nDim, index1 = 3, index2 = 1
0545         unsigned int iOff1 = nDim * nOffset + nCurv + nLocals + 1; // first offset ('i' in u_i)
0546         unsigned int index1 = 3 - 2 * nJacobian; // index of first offset
0547         unsigned int iOff2 = iOff1 + nDim * (nJacobian * 2 - 1); // second offset ('i' in u_i)
0548         unsigned int index2 = 1 + 2 * nJacobian; // index of second offset
0549         // local offset
0550         aJacobian(3, index1) = 1.0; // from 1st Offset
0551         aJacobian(4, index1 + 1) = 1.0;
0552         for (unsigned int i = 0; i < nDim; ++i) {
0553             anIndex[index1 + theDimension[i]] = iOff1 + i;
0554         }
0555 
0556         // local slope and curvature
0557         if (measDim > 2) {
0558             SMatrix22 matW, matWJ;
0559             SVector2 vecWd;
0560             aPoint.getDerivatives(nJacobian, matW, matWJ, vecWd); // W, W * J, W * d
0561             double sign = (nJacobian > 0) ? 1. : -1.;
0562             if (nCurv > 0) {
0563                 aJacobian(0, 0) = 1.0;
0564                 aJacobian.Place_in_col(-sign * vecWd, 1, 0); // from curvature
0565                 anIndex[0] = nLocals + 1;
0566             }
0567             aJacobian.Place_at(-sign * matWJ, 1, index1); // from 1st Offset
0568             aJacobian.Place_at(sign * matW, 1, index2); // from 2nd Offset
0569             for (unsigned int i = 0; i < nDim; ++i) {
0570                 anIndex[index2 + theDimension[i]] = iOff2 + i;
0571             }
0572         }
0573     }
0574 }
0575 
0576 /// Get jacobian for transformation from (trajectory) fit to kink parameters at point.
0577 /**
0578  * Jacobian broken lines (q/p,..,u_i-1,u_i,u_i+1..) to kink (du') parameters.
0579  * \param [out] anIndex List of fit parameters with non zero derivatives
0580  * \param [out] aJacobian Corresponding transformation matrix
0581  * \param [in] aPoint Point to use
0582  */
0583 void GblTrajectory::getFitToKinkJacobian(std::vector<unsigned int> &anIndex,
0584         SMatrix27 &aJacobian, const GblPoint &aPoint) const {
0585 
0586     unsigned int nDim = theDimension.size();
0587     unsigned int nCurv = numCurvature;
0588     unsigned int nLocals = numLocals;
0589 
0590     int nOffset = aPoint.getOffset();
0591 
0592     SMatrix22 prevW, prevWJ, nextW, nextWJ;
0593     SVector2 prevWd, nextWd;
0594     aPoint.getDerivatives(0, prevW, prevWJ, prevWd); // W-, W- * J-, W- * d-
0595     aPoint.getDerivatives(1, nextW, nextWJ, nextWd); // W-, W- * J-, W- * d-
0596     const SMatrix22 sumWJ(prevWJ + nextWJ); // W- * J- + W+ * J+
0597     const SVector2 sumWd(prevWd + nextWd); // W+ * d+ + W- * d-
0598 
0599     unsigned int iOff = (nOffset - 1) * nDim + nCurv + nLocals + 1; // first offset ('i' in u_i)
0600 
0601     // local offset
0602     if (nCurv > 0) {
0603         aJacobian.Place_in_col(-sumWd, 0, 0); // from curvature
0604         anIndex[0] = nLocals + 1;
0605     }
0606     aJacobian.Place_at(prevW, 0, 1); // from 1st Offset
0607     aJacobian.Place_at(-sumWJ, 0, 3); // from 2nd Offset
0608     aJacobian.Place_at(nextW, 0, 5); // from 1st Offset
0609     for (unsigned int i = 0; i < nDim; ++i) {
0610         anIndex[1 + theDimension[i]] = iOff + i;
0611         anIndex[3 + theDimension[i]] = iOff + nDim + i;
0612         anIndex[5 + theDimension[i]] = iOff + nDim * 2 + i;
0613     }
0614 }
0615 
0616 /// Get fit results at point.
0617 /**
0618  * Get corrections and covariance matrix for local track and additional parameters
0619  * in forward or backward direction.
0620  *
0621  * The point is identified by its label (1..number(points)), the sign distinguishes the
0622  * backward (facing previous point) and forward 'side' (facing next point).
0623  * For scatterers the track direction may change in between.
0624  *
0625  * \param [in] aSignedLabel (Signed) label of point on trajectory
0626  * (<0: in front, >0: after point, slope changes at scatterer!)
0627  * \param [out] localPar Corrections for local parameters
0628  * \param [out] localCov Covariance for local parameters
0629  * \return error code (non-zero if trajectory not fitted successfully)
0630  */
0631 unsigned int GblTrajectory::getResults(int aSignedLabel, TVectorD &localPar,
0632         TMatrixDSym &localCov) const {
0633     if (not fitOK)
0634         return 1;
0635     std::pair<std::vector<unsigned int>, TMatrixD> indexAndJacobian =
0636             getJacobian(aSignedLabel);
0637     unsigned int nParBrl = indexAndJacobian.first.size();
0638     TVectorD aVec(nParBrl); // compressed vector
0639     for (unsigned int i = 0; i < nParBrl; ++i) {
0640         aVec[i] = theVector(indexAndJacobian.first[i] - 1);
0641     }
0642     TMatrixDSym aMat = theMatrix.getBlockMatrix(indexAndJacobian.first); // compressed matrix
0643     localPar = indexAndJacobian.second * aVec;
0644     localCov = aMat.Similarity(indexAndJacobian.second);
0645     return 0;
0646 }
0647 
0648 /// Get residuals from fit at point for measurement.
0649 /**
0650  * Get (diagonalized) residual, error of measurement and residual and down-weighting
0651  * factor for measurement at point
0652  *
0653  * \param [in]  aLabel Label of point on trajectory
0654  * \param [out] numData Number of data blocks from measurement at point
0655  * \param [out] aResiduals Measurements-Predictions
0656  * \param [out] aMeasErrors Errors of Measurements
0657  * \param [out] aResErrors Errors of Residuals (including correlations from track fit)
0658  * \param [out] aDownWeights Down-Weighting factors
0659  * \return error code (non-zero if trajectory not fitted successfully)
0660  */
0661 unsigned int GblTrajectory::getMeasResults(unsigned int aLabel,
0662         unsigned int &numData, TVectorD &aResiduals, TVectorD &aMeasErrors,
0663         TVectorD &aResErrors, TVectorD &aDownWeights) {
0664     numData = 0;
0665     if (not fitOK)
0666         return 1;
0667 
0668     unsigned int firstData = measDataIndex[aLabel - 1]; // first data block with measurement
0669     numData = measDataIndex[aLabel] - firstData; // number of data blocks
0670     for (unsigned int i = 0; i < numData; ++i) {
0671         getResAndErr(firstData + i, aResiduals[i], aMeasErrors[i],
0672                 aResErrors[i], aDownWeights[i]);
0673     }
0674     return 0;
0675 }
0676 
0677 /// Get (kink) residuals from fit at point for scatterer.
0678 /**
0679  * Get (diagonalized) residual, error of measurement and residual and down-weighting
0680  * factor for scatterering kinks at point
0681  *
0682  * \param [in]  aLabel Label of point on trajectory
0683  * \param [out] numData Number of data blocks from scatterer at point
0684  * \param [out] aResiduals (kink)Measurements-(kink)Predictions
0685  * \param [out] aMeasErrors Errors of (kink)Measurements
0686  * \param [out] aResErrors Errors of Residuals (including correlations from track fit)
0687  * \param [out] aDownWeights Down-Weighting factors
0688  * \return error code (non-zero if trajectory not fitted successfully)
0689  */
0690 unsigned int GblTrajectory::getScatResults(unsigned int aLabel,
0691         unsigned int &numData, TVectorD &aResiduals, TVectorD &aMeasErrors,
0692         TVectorD &aResErrors, TVectorD &aDownWeights) {
0693     numData = 0;
0694     if (not fitOK)
0695         return 1;
0696 
0697     unsigned int firstData = scatDataIndex[aLabel - 1]; // first data block with scatterer
0698     numData = scatDataIndex[aLabel] - firstData; // number of data blocks
0699     for (unsigned int i = 0; i < numData; ++i) {
0700         getResAndErr(firstData + i, aResiduals[i], aMeasErrors[i],
0701                 aResErrors[i], aDownWeights[i]);
0702     }
0703     return 0;
0704 }
0705 
0706 /// Get (list of) labels of points on (simple) valid trajectory
0707 /**
0708  * \param [out] aLabelList List of labels (aLabelList[i] = i+1)
0709  * \return error code (non-zero if trajectory not valid (constructed successfully))
0710  */
0711 unsigned int GblTrajectory::getLabels(std::vector<unsigned int> &aLabelList) {
0712     if (not constructOK)
0713         return 1;
0714 
0715     unsigned int aLabel = 0;
0716     unsigned int nPoint = thePoints[0].size();
0717     aLabelList.resize(nPoint);
0718     for (unsigned i = 0; i < nPoint; ++i) {
0719         aLabelList[i] = ++aLabel;
0720     }
0721     return 0;
0722 }
0723 
0724 /// Get (list of lists of) labels of points on (composed) valid trajectory
0725 /**
0726  * \param [out] aLabelList List of of lists of labels
0727  * \return error code (non-zero if trajectory not valid (constructed successfully))
0728  */
0729 unsigned int GblTrajectory::getLabels(
0730         std::vector<std::vector<unsigned int> > &aLabelList) {
0731     if (not constructOK)
0732         return 1;
0733 
0734     unsigned int aLabel = 0;
0735     aLabelList.resize(numTrajectories);
0736     for (unsigned int iTraj = 0; iTraj < numTrajectories; ++iTraj) {
0737         unsigned int nPoint = thePoints[iTraj].size();
0738         aLabelList[iTraj].resize(nPoint);
0739         for (unsigned i = 0; i < nPoint; ++i) {
0740             aLabelList[iTraj][i] = ++aLabel;
0741         }
0742     }
0743     return 0;
0744 }
0745 
0746 /// Get residual and errors from data block.
0747 /**
0748  * Get residual, error of measurement and residual and down-weighting
0749  * factor for (single) data block
0750  * \param [in]  aData Label of data block
0751  * \param [out] aResidual Measurement-Prediction
0752  * \param [out] aMeasError Error of Measurement
0753  * \param [out] aResError Error of Residual (including correlations from track fit)
0754  * \param [out] aDownWeight Down-Weighting factor
0755  */
0756 void GblTrajectory::getResAndErr(unsigned int aData, double &aResidual,
0757         double &aMeasError, double &aResError, double &aDownWeight) {
0758 
0759     double aMeasVar;
0760     std::vector<unsigned int>* indLocal;
0761     std::vector<double>* derLocal;
0762     theData[aData].getResidual(aResidual, aMeasVar, aDownWeight, indLocal,
0763             derLocal);
0764     unsigned int nParBrl = (*indLocal).size();
0765     TVectorD aVec(nParBrl); // compressed vector of derivatives
0766     for (unsigned int j = 0; j < nParBrl; ++j) {
0767         aVec[j] = (*derLocal)[j];
0768     }
0769     TMatrixDSym aMat = theMatrix.getBlockMatrix(*indLocal); // compressed (covariance) matrix
0770     double aFitVar = aMat.Similarity(aVec); // variance from track fit
0771     aMeasError = sqrt(aMeasVar); // error of measurement
0772     aResError = (aFitVar < aMeasVar ? sqrt(aMeasVar - aFitVar) : 0.); // error of residual
0773 }
0774 
0775 /// Build linear equation system from data (blocks).
0776 void GblTrajectory::buildLinearEquationSystem() {
0777     unsigned int nBorder = numCurvature + numLocals;
0778     theVector.resize(numParameters);
0779     theMatrix.resize(numParameters, nBorder);
0780     double aValue, aWeight;
0781     std::vector<unsigned int>* indLocal;
0782     std::vector<double>* derLocal;
0783     std::vector<GblData>::iterator itData;
0784     for (itData = theData.begin(); itData < theData.end(); ++itData) {
0785         itData->getLocalData(aValue, aWeight, indLocal, derLocal);
0786         for (unsigned int j = 0; j < indLocal->size(); ++j) {
0787             theVector((*indLocal)[j] - 1) += (*derLocal)[j] * aWeight * aValue;
0788         }
0789         theMatrix.addBlockMatrix(aWeight, indLocal, derLocal);
0790     }
0791 }
0792 
0793 /// Prepare fit for simple or composed trajectory
0794 /**
0795  * Generate data (blocks) from measurements, kinks, external seed and measurements.
0796  */
0797 void GblTrajectory::prepare() {
0798     unsigned int nDim = theDimension.size();
0799     // upper limit
0800     unsigned int maxData = numMeasurements + nDim * (numOffsets - 2)
0801             + externalSeed.GetNrows();
0802     theData.reserve(maxData);
0803     measDataIndex.resize(numAllPoints + 3); // include external seed and measurements
0804     scatDataIndex.resize(numAllPoints + 1);
0805     unsigned int nData = 0;
0806     std::vector<TMatrixD> innerTransDer;
0807     std::vector<std::vector<unsigned int> > innerTransLab;
0808     // composed trajectory ?
0809     if (numInnerTrans > 0) {
0810         //std::cout << "composed trajectory" << std::endl;
0811         for (unsigned int iTraj = 0; iTraj < numTrajectories; ++iTraj) {
0812             // innermost point
0813             GblPoint* innerPoint = &thePoints[iTraj].front();
0814             // transformation fit to local track parameters
0815             std::vector<unsigned int> firstLabels(5);
0816             SMatrix55 matFitToLocal, matLocalToFit;
0817             getFitToLocalJacobian(firstLabels, matFitToLocal, *innerPoint, 5);
0818             // transformation local track to fit parameters
0819             int ierr;
0820             matLocalToFit = matFitToLocal.Inverse(ierr);
0821             TMatrixD localToFit(5, 5);
0822             for (unsigned int i = 0; i < 5; ++i) {
0823                 for (unsigned int j = 0; j < 5; ++j) {
0824                     localToFit(i, j) = matLocalToFit(i, j);
0825                 }
0826             }
0827             // transformation external to fit parameters at inner (first) point
0828             innerTransDer.push_back(localToFit * innerTransformations[iTraj]);
0829             innerTransLab.push_back(firstLabels);
0830         }
0831     }
0832     // measurements
0833     SMatrix55 matP;
0834     // loop over trajectories
0835     std::vector<GblPoint>::iterator itPoint;
0836     for (unsigned int iTraj = 0; iTraj < numTrajectories; ++iTraj) {
0837         for (itPoint = thePoints[iTraj].begin();
0838                 itPoint < thePoints[iTraj].end(); ++itPoint) {
0839             SVector5 aMeas, aPrec;
0840             unsigned int nLabel = itPoint->getLabel();
0841             unsigned int measDim = itPoint->hasMeasurement();
0842             if (measDim) {
0843                 const TMatrixD localDer = itPoint->getLocalDerivatives();
0844                 const std::vector<int> globalLab = itPoint->getGlobalLabels();
0845                 const TMatrixD globalDer = itPoint->getGlobalDerivatives();
0846                 TMatrixD transDer;
0847                 itPoint->getMeasurement(matP, aMeas, aPrec);
0848                 unsigned int iOff = 5 - measDim; // first active component
0849                 std::vector<unsigned int> labDer(5);
0850                 SMatrix55 matDer, matPDer;
0851                 unsigned int nJacobian =
0852                         (itPoint < thePoints[iTraj].end() - 1) ? 1 : 0; // last point needs backward propagation
0853                 getFitToLocalJacobian(labDer, matDer, *itPoint, measDim,
0854                         nJacobian);
0855                 if (measDim > 2) {
0856                     matPDer = matP * matDer;
0857                 } else { // 'shortcut' for position measurements
0858                     matPDer.Place_at(
0859                             matP.Sub<SMatrix22>(3, 3)
0860                                     * matDer.Sub<SMatrix25>(3, 0), 3, 0);
0861                 }
0862 
0863                 if (numInnerTrans > 0) {
0864                     // transform for external parameters
0865                     TMatrixD proDer(measDim, 5);
0866                     // match parameters
0867                     unsigned int ifirst = 0;
0868                     unsigned int ilabel = 0;
0869                     while (ilabel < 5) {
0870                         if (labDer[ilabel] > 0) {
0871                             while (innerTransLab[iTraj][ifirst]
0872                                     != labDer[ilabel] and ifirst < 5) {
0873                                 ++ifirst;
0874                             }
0875                             if (ifirst >= 5) {
0876                                 labDer[ilabel] -= 2 * nDim * (iTraj + 1); // adjust label
0877                             } else {
0878                                 // match
0879                                 labDer[ilabel] = 0; // mark as related to external parameters
0880                                 for (unsigned int k = iOff; k < 5; ++k) {
0881                                     proDer(k - iOff, ifirst) = matPDer(k,
0882                                             ilabel);
0883                                 }
0884                             }
0885                         }
0886                         ++ilabel;
0887                     }
0888                     transDer.ResizeTo(measDim, numCurvature);
0889                     transDer = proDer * innerTransDer[iTraj];
0890                 }
0891                 for (unsigned int i = iOff; i < 5; ++i) {
0892                     if (aPrec(i) > 0.) {
0893                         GblData aData(nLabel, aMeas(i), aPrec(i));
0894                         aData.addDerivatives(i, labDer, matPDer, iOff, localDer,
0895                                 globalLab, globalDer, numLocals, transDer);
0896                         theData.push_back(aData);
0897                         nData++;
0898                     }
0899                 }
0900 
0901             }
0902             measDataIndex[nLabel] = nData;
0903         }
0904     }
0905 
0906     // pseudo measurements from kinks
0907     SMatrix22 matT;
0908     scatDataIndex[0] = nData;
0909     scatDataIndex[1] = nData;
0910     // loop over trajectories
0911     for (unsigned int iTraj = 0; iTraj < numTrajectories; ++iTraj) {
0912         for (itPoint = thePoints[iTraj].begin() + 1;
0913                 itPoint < thePoints[iTraj].end() - 1; ++itPoint) {
0914             SVector2 aMeas, aPrec;
0915             unsigned int nLabel = itPoint->getLabel();
0916             if (itPoint->hasScatterer()) {
0917                 itPoint->getScatterer(matT, aMeas, aPrec);
0918                 TMatrixD transDer;
0919                 std::vector<unsigned int> labDer(7);
0920                 SMatrix27 matDer, matTDer;
0921                 getFitToKinkJacobian(labDer, matDer, *itPoint);
0922                 matTDer = matT * matDer;
0923                 if (numInnerTrans > 0) {
0924                     // transform for external parameters
0925                     TMatrixD proDer(nDim, 5);
0926                     // match parameters
0927                     unsigned int ifirst = 0;
0928                     unsigned int ilabel = 0;
0929                     while (ilabel < 7) {
0930                         if (labDer[ilabel] > 0) {
0931                             while (innerTransLab[iTraj][ifirst]
0932                                     != labDer[ilabel] and ifirst < 5) {
0933                                 ++ifirst;
0934                             }
0935                             if (ifirst >= 5) {
0936                                 labDer[ilabel] -= 2 * nDim * (iTraj + 1); // adjust label
0937                             } else {
0938                                 // match
0939                                 labDer[ilabel] = 0; // mark as related to external parameters
0940                                 for (unsigned int k = 0; k < nDim; ++k) {
0941                                     proDer(k, ifirst) = matTDer(k, ilabel);
0942                                 }
0943                             }
0944                         }
0945                         ++ilabel;
0946                     }
0947                     transDer.ResizeTo(nDim, numCurvature);
0948                     transDer = proDer * innerTransDer[iTraj];
0949                 }
0950                 for (unsigned int i = 0; i < nDim; ++i) {
0951                     unsigned int iDim = theDimension[i];
0952                     if (aPrec(iDim) > 0.) {
0953                         GblData aData(nLabel, aMeas(iDim), aPrec(iDim));
0954                         aData.addDerivatives(iDim, labDer, matTDer, numLocals,
0955                                 transDer);
0956                         theData.push_back(aData);
0957                         nData++;
0958                     }
0959                 }
0960             }
0961             scatDataIndex[nLabel] = nData;
0962         }
0963         scatDataIndex[thePoints[iTraj].back().getLabel()] = nData;
0964     }
0965 
0966     // external seed
0967     if (externalPoint > 0) {
0968         std::pair<std::vector<unsigned int>, TMatrixD> indexAndJacobian =
0969                 getJacobian(externalPoint);
0970         std::vector<unsigned int> externalSeedIndex = indexAndJacobian.first;
0971         std::vector<double> externalSeedDerivatives(externalSeedIndex.size());
0972         const TMatrixDSymEigen externalSeedEigen(externalSeed);
0973         const TVectorD valEigen = externalSeedEigen.GetEigenValues();
0974         TMatrixD vecEigen = externalSeedEigen.GetEigenVectors();
0975         vecEigen = vecEigen.T() * indexAndJacobian.second;
0976         for (int i = 0; i < externalSeed.GetNrows(); ++i) {
0977             if (valEigen(i) > 0.) {
0978                 for (int j = 0; j < externalSeed.GetNcols(); ++j) {
0979                     externalSeedDerivatives[j] = vecEigen(i, j);
0980                 }
0981                 GblData aData(externalPoint, 0., valEigen(i));
0982                 aData.addDerivatives(externalSeedIndex,
0983                         externalSeedDerivatives);
0984                 theData.push_back(aData);
0985                 nData++;
0986             }
0987         }
0988     }
0989     measDataIndex[numAllPoints + 1] = nData;
0990     // external measurements
0991     unsigned int nExt = externalMeasurements.GetNrows();
0992     if (nExt > 0) {
0993         std::vector<unsigned int> index(numCurvature);
0994         std::vector<double> derivatives(numCurvature);
0995         for (unsigned int iExt = 0; iExt < nExt; ++iExt) {
0996             for (unsigned int iCol = 0; iCol < numCurvature; ++iCol) {
0997                 index[iCol] = numLocals + iCol + 1;
0998                 derivatives[iCol] = externalDerivatives(iExt, iCol);
0999             }
1000             GblData aData(1U, externalMeasurements(iExt),
1001                     externalPrecisions(iExt));
1002             aData.addDerivatives(index, derivatives);
1003             theData.push_back(aData);
1004             nData++;
1005         }
1006     }
1007     measDataIndex[numAllPoints + 2] = nData;
1008 }
1009 
1010 /// Calculate predictions for all points.
1011 void GblTrajectory::predict() {
1012     std::vector<GblData>::iterator itData;
1013     for (itData = theData.begin(); itData < theData.end(); ++itData) {
1014         itData->setPrediction(theVector);
1015     }
1016 }
1017 
1018 /// Down-weight all points.
1019 /**
1020  * \param [in] aMethod M-estimator (1: Tukey, 2:Huber, 3:Cauchy)
1021  */
1022 double GblTrajectory::downWeight(unsigned int aMethod) {
1023     double aLoss = 0.;
1024     std::vector<GblData>::iterator itData;
1025     for (itData = theData.begin(); itData < theData.end(); ++itData) {
1026         aLoss += (1. - itData->setDownWeighting(aMethod));
1027     }
1028     return aLoss;
1029 }
1030 
1031 /// Perform fit of (valid) trajectory.
1032 /**
1033  * Optionally iterate for outlier down-weighting.
1034  * Fit may fail due to singular or not positive definite matrices (internal exceptions 1-3).
1035  *
1036  * \param [out] Chi2 Chi2 sum (corrected for down-weighting)
1037  * \param [out] Ndf  Number of degrees of freedom
1038  * \param [out] lostWeight Sum of weights lost due to down-weighting
1039  * \param [in] optionList Iterations for down-weighting
1040  * (One character per iteration: t,h,c (or T,H,C) for Tukey, Huber or Cauchy function)
1041  * \return Error code (non zero value indicates failure of fit)
1042  */
1043 unsigned int GblTrajectory::fit(double &Chi2, int &Ndf, double &lostWeight,
1044         std::string optionList) {
1045     const double normChi2[4] = { 1.0, 0.8737, 0.9326, 0.8228 };
1046     const std::string methodList = "TtHhCc";
1047 
1048     Chi2 = 0.;
1049     Ndf = -1;
1050     lostWeight = 0.;
1051     if (not constructOK)
1052         return 10;
1053 
1054     unsigned int aMethod = 0;
1055 
1056     buildLinearEquationSystem();
1057     lostWeight = 0.;
1058     unsigned int ierr = 0;
1059     try {
1060 
1061         theMatrix.solveAndInvertBorderedBand(theVector, theVector);
1062         predict();
1063 
1064         for (unsigned int i = 0; i < optionList.size(); ++i) // down weighting iterations
1065                 {
1066             size_t aPosition = methodList.find(optionList[i]);
1067             if (aPosition != std::string::npos) {
1068                 aMethod = aPosition / 2 + 1;
1069                 lostWeight = downWeight(aMethod);
1070                 buildLinearEquationSystem();
1071                 theMatrix.solveAndInvertBorderedBand(theVector, theVector);
1072                 predict();
1073             }
1074         }
1075         Ndf = theData.size() - numParameters;
1076         Chi2 = 0.;
1077         for (unsigned int i = 0; i < theData.size(); ++i) {
1078             Chi2 += theData[i].getChi2();
1079         }
1080         Chi2 /= normChi2[aMethod];
1081         fitOK = true;
1082 
1083     } catch (int e) {
1084         std::cout << " GblTrajectory::fit exception " << e << std::endl;
1085         ierr = e;
1086     }
1087     return ierr;
1088 }
1089 
1090 /// Write valid trajectory to Millepede-II binary file.
1091 void GblTrajectory::milleOut(MilleBinary &aMille) {
1092     double aValue;
1093     double aErr;
1094     std::vector<unsigned int>* indLocal;
1095     std::vector<double>* derLocal;
1096     std::vector<int>* labGlobal;
1097     std::vector<double>* derGlobal;
1098 
1099     if (not constructOK)
1100         return;
1101 
1102 //   data: measurements, kinks and external seed
1103     std::vector<GblData>::iterator itData;
1104     for (itData = theData.begin(); itData != theData.end(); ++itData) {
1105         itData->getAllData(aValue, aErr, indLocal, derLocal, labGlobal,
1106                 derGlobal);
1107         aMille.addData(aValue, aErr, *indLocal, *derLocal, *labGlobal,
1108                 *derGlobal);
1109     }
1110     aMille.writeRecord();
1111 }
1112 
1113 /// Print GblTrajectory
1114 /**
1115  * \param [in] level print level (0: minimum, >0: more)
1116  */
1117 void GblTrajectory::printTrajectory(unsigned int level) {
1118     if (numInnerTrans) {
1119         std::cout << "Composed GblTrajectory, " << numInnerTrans
1120                 << " subtrajectories" << std::endl;
1121     } else {
1122         std::cout << "Simple GblTrajectory" << std::endl;
1123     }
1124     if (theDimension.size() < 2) {
1125         std::cout << " 2D-trajectory" << std::endl;
1126     }
1127     std::cout << " Number of GblPoints          : " << numAllPoints
1128             << std::endl;
1129     std::cout << " Number of points with offsets: " << numOffsets << std::endl;
1130     std::cout << " Number of fit parameters     : " << numParameters
1131             << std::endl;
1132     std::cout << " Number of measurements       : " << numMeasurements
1133             << std::endl;
1134     if (externalMeasurements.GetNrows()) {
1135         std::cout << " Number of ext. measurements  : "
1136                 << externalMeasurements.GetNrows() << std::endl;
1137     }
1138     if (externalPoint) {
1139         std::cout << " Label of point with ext. seed: " << externalPoint
1140                 << std::endl;
1141     }
1142     if (constructOK) {
1143         std::cout << " Constructed OK " << std::endl;
1144     }
1145     if (fitOK) {
1146         std::cout << " Fitted OK " << std::endl;
1147     }
1148     if (level > 0) {
1149         if (numInnerTrans) {
1150             std::cout << " Inner transformations" << std::endl;
1151             for (unsigned int i = 0; i < numInnerTrans; ++i) {
1152                 innerTransformations[i].Print();
1153             }
1154         }
1155         if (externalMeasurements.GetNrows()) {
1156             std::cout << " External measurements" << std::endl;
1157             std::cout << "  Measurements:" << std::endl;
1158             externalMeasurements.Print();
1159             std::cout << "  Precisions:" << std::endl;
1160             externalPrecisions.Print();
1161             std::cout << "  Derivatives:" << std::endl;
1162             externalDerivatives.Print();
1163         }
1164         if (externalPoint) {
1165             std::cout << " External seed:" << std::endl;
1166             externalSeed.Print();
1167         }
1168         if (fitOK) {
1169             std::cout << " Fit results" << std::endl;
1170             std::cout << "  Parameters:" << std::endl;
1171             theVector.print();
1172             std::cout << "  Covariance matrix (bordered band part):"
1173                     << std::endl;
1174             theMatrix.printMatrix();
1175         }
1176     }
1177 }
1178 
1179 /// Print \link GblPoint GblPoints \endlink on trajectory
1180 /**
1181  * \param [in] level print level (0: minimum, >0: more)
1182  */
1183 void GblTrajectory::printPoints(unsigned int level) {
1184     std::cout << "GblPoints " << std::endl;
1185     for (unsigned int iTraj = 0; iTraj < numTrajectories; ++iTraj) {
1186         std::vector<GblPoint>::iterator itPoint;
1187         for (itPoint = thePoints[iTraj].begin();
1188                 itPoint < thePoints[iTraj].end(); ++itPoint) {
1189             itPoint->printPoint(level);
1190         }
1191     }
1192 }
1193 
1194 /// Print GblData blocks for trajectory
1195 void GblTrajectory::printData() {
1196     std::cout << "GblData blocks " << std::endl;
1197     std::vector<GblData>::iterator itData;
1198     for (itData = theData.begin(); itData < theData.end(); ++itData) {
1199         itData->printData();
1200     }
1201 }
1202 
1203 }