Back to home page

sPhenix code displayed by LXR

 
 

    


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

0001 //-*-mode: C++; c-basic-offset: 2; -*-
0002 /* Copyright 2013
0003  *  Authors: Sergey Yashchenko and Tadeas Bilka
0004  *
0005  *  This is an interface to General Broken Lines
0006  *
0007  *  Version: 5 (Tadeas)
0008  *  - several bug-fixes:
0009  *    - Scatterers at bad points
0010  *    - Jacobians at a point before they should be (code reorganized)
0011  *    - Change of sign of residuals
0012  *  Version: 4 (Tadeas)
0013  *  Fixed calculation of equvivalent scatterers (solution by C. Kleinwort)
0014  *  Now a scatterer is inserted at each measurement (except last) and between each two measurements.
0015  *  TrueHits/Clusters. Ghost (1D) hits ignored. With or without magnetic field.
0016  *  Version: 3 (Tadeas)
0017  *  This version now supports both TrueHits and Clusters for VXD.
0018  *  It can be used for arbitrary material distribution between
0019  *  measurements. Moments of scattering distribution are computed
0020  *  and translated into two equivalent thin GBL scatterers placed
0021  *  at computed positions between measurement points.
0022  *  Version: 2 ... never published (Tadeas)
0023  *  Scatterer at each boundary (tooo many scatterers). TrueHits/Clusters. Without global der.&MP2 output.
0024  *  Version: 1 (Sergey & Tadeas)
0025  *  Scatterers at measurement planes. TrueHits
0026  *  Version 0: (Sergey)
0027  *  Without scatterers. Genfit 1.
0028  *
0029  *  This file is part of GENFIT.
0030  *
0031  *  GENFIT is free software: you can redistribute it and/or modify
0032  *  it under the terms of the GNU Lesser General Public License as published
0033  *  by the Free Software Foundation, either version 3 of the License, or
0034  *  (at your option) any later version.
0035  *
0036  *  GENFIT is distributed in the hope that it will be useful,
0037  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
0038  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0039  *  GNU Lesser General Public License for more details.
0040  *
0041  *  You should have received a copy of the GNU Lesser General Public License
0042  *  along with GENFIT.  If not, see <http://www.gnu.org/licenses/>.
0043  */
0044 
0045 #include "GFGbl.h"
0046 #include "GblTrajectory.h"
0047 #include "GblPoint.h"
0048 #include "MyDebugTools.h"
0049 
0050 #include "AbsMeasurement.h"
0051 #include "PlanarMeasurement.h"
0052 #include "KalmanFitterInfo.h"
0053 
0054 #include "Track.h"
0055 #include <TFile.h>
0056 #include <TH1F.h>
0057 #include <TTree.h>
0058 #include <string>
0059 #include <list>
0060 #include <FieldManager.h>
0061 #include <HMatrixU.h>
0062 #include <HMatrixV.h>
0063 #include <Math/SMatrix.h>
0064 #include <TMatrixD.h>
0065 #include <TVectorDfwd.h>
0066 #include <TMatrixT.h>
0067 
0068 #include <TVector3.h>
0069 
0070 //#define DEBUG
0071 //#define OUTPUT
0072 
0073 
0074 #ifdef DEBUG
0075 //ofstream debug("gbl.debug");
0076 #endif
0077 
0078 #ifdef OUTPUT
0079 
0080 std::string rootFileName = "gbl.root";
0081 
0082 
0083 TFile* diag;
0084 TH1F* resHistosU[12];
0085 TH1F* resHistosV[12];
0086 TH1F* mhistosU[12];
0087 TH1F* mhistosV[12];
0088 TH1F* ghistosU[12];
0089 TH1F* ghistosV[12];
0090 TH1F* downWeightsHistosU[12];
0091 TH1F* downWeightsHistosV[12];
0092 TH1F* localPar1[12];
0093 TH1F* localPar2[12];
0094 TH1F* localPar3[12];
0095 TH1F* localPar4[12];
0096 TH1F* localPar5[12];
0097 TH1F* localCov1[12];
0098 TH1F* localCov2[12];
0099 TH1F* localCov3[12];
0100 TH1F* localCov4[12];
0101 TH1F* localCov5[12];
0102 TH1F* localCov12[12];
0103 TH1F* localCov13[12];
0104 TH1F* localCov14[12];
0105 TH1F* localCov15[12];
0106 TH1F* localCov23[12];
0107 TH1F* localCov24[12];
0108 TH1F* localCov25[12];
0109 TH1F* localCov34[12];
0110 TH1F* localCov35[12];
0111 TH1F* localCov45[12];
0112 TH1I* fitResHisto;
0113 TH1I* ndfHisto;
0114 TH1F* chi2OndfHisto;
0115 TH1F* pValueHisto;
0116 TH1I* stats;
0117 
0118 
0119 
0120 bool writeHistoDataForLabel(double label, TVectorD res, TVectorD measErr, TVectorD resErr, TVectorD downWeights, TVectorD localPar, TMatrixDSym localCov)
0121 {
0122   if (label < 1.) return false;
0123   
0124   unsigned int id = floor(label);
0125   // skip segment (5 bits)
0126   id = id >> 5;
0127   unsigned int sensor = id & 7;
0128   id = id >> 3;
0129   unsigned int ladder = id & 31;
0130   id = id >> 5;
0131   unsigned int layer = id & 7;
0132   if (layer == 7 && ladder == 2) {
0133     label = sensor;
0134   } else if (layer == 7 && ladder == 3) {
0135     label = sensor + 9 - 3;
0136   } else {
0137     label = layer + 3;
0138   }
0139   
0140   if (label > 12.) return false;
0141   
0142   int i = int(label);
0143   
0144   #ifdef OUTPUT
0145   resHistosU[i - 1]->Fill(res[0]);
0146   resHistosV[i - 1]->Fill(res[1]);
0147   mhistosU[i - 1]->Fill(res[0] / measErr[0]);
0148   mhistosV[i - 1]->Fill(res[1] / measErr[1]);
0149   ghistosU[i - 1]->Fill(res[0] / resErr[0]);
0150   ghistosV[i - 1]->Fill(res[1] / resErr[1]);
0151   downWeightsHistosU[i - 1]->Fill(downWeights[0]);
0152   downWeightsHistosV[i - 1]->Fill(downWeights[1]);
0153   localPar1[i - 1]->Fill(localPar(0));
0154   localPar2[i - 1]->Fill(localPar(1));
0155   localPar3[i - 1]->Fill(localPar(2));
0156   localPar4[i - 1]->Fill(localPar(3));
0157   localPar5[i - 1]->Fill(localPar(4));
0158   #endif
0159   
0160   
0161   return true;
0162 }
0163 #endif
0164 
0165 // Millepede Binary File for output of GBL trajectories for alignment
0166 gbl::MilleBinary* milleFile;
0167 // Minimum scattering sigma (will be squared and inverted...)
0168 const double scatEpsilon = 1.e-8;
0169 
0170 
0171 using namespace gbl;
0172 using namespace std;
0173 using namespace genfit;
0174 
0175 GFGbl::GFGbl() :
0176 AbsFitter(), m_milleFileName("millefile.dat"), m_gblInternalIterations("THC"), m_pValueCut(0.), m_minNdf(1),
0177 m_chi2Cut(0.),
0178 m_enableScatterers(true),
0179 m_enableIntermediateScatterer(true)
0180 {
0181   
0182 }
0183 
0184 void GFGbl::beginRun()
0185 {
0186   milleFile = new MilleBinary(m_milleFileName);
0187   
0188   #ifdef OUTPUT
0189   diag = new TFile(rootFileName.c_str(), "RECREATE");
0190   char name[20];
0191   
0192   for (int i = 0; i < 12; i++) {
0193     sprintf(name, "res_u_%i", i + 1);
0194     resHistosU[i] = new TH1F(name, "Residual (U)", 1000, -0.1, 0.1);
0195     sprintf(name, "res_v_%i", i + 1);
0196     resHistosV[i] = new TH1F(name, "Residual (V)", 1000, -0.1, 0.1);
0197     sprintf(name, "meas_pull_u_%i", i + 1);
0198     mhistosU[i] = new TH1F(name, "Res/Meas.Err. (U)", 1000, -20., 20.);
0199     sprintf(name, "meas_pull_v_%i", i + 1);
0200     mhistosV[i] = new TH1F(name, "Res/Meas.Err. (V)", 1000, -20., 20.);
0201     sprintf(name, "pull_u_%i", i + 1);
0202     ghistosU[i] = new TH1F(name, "Res/Res.Err. (U)", 1000, -20., 20.);
0203     sprintf(name, "pull_v_%i", i + 1);
0204     ghistosV[i] = new TH1F(name, "Res/Res.Err. (V)", 1000, -20., 20.);
0205     sprintf(name, "downWeights_u_%i", i + 1);
0206     downWeightsHistosU[i] = new TH1F(name, "Down-weights (U)", 1000, 0., 1.);
0207     sprintf(name, "downWeights_v_%i", i + 1);
0208     downWeightsHistosV[i] = new TH1F(name, "Down-weights (V)", 1000, 0., 1.);
0209     sprintf(name, "localPar1_%i", i + 1);
0210     
0211     localPar1[i] = new TH1F(name, "Residual (U)", 1000, -0.1, 0.1);
0212     sprintf(name, "localPar2_%i", i + 1);
0213     localPar2[i] = new TH1F(name, "Residual (U)", 1000, -0.1, 0.1);
0214     sprintf(name, "localPar3_%i", i + 1);
0215     localPar3[i] = new TH1F(name, "Residual (U)", 1000, -0.1, 0.1);
0216     sprintf(name, "localPar4_%i", i + 1);
0217     localPar4[i] = new TH1F(name, "Residual (U)", 1000, -0.1, 0.1);
0218     sprintf(name, "localPar5_%i", i + 1);
0219     localPar5[i] = new TH1F(name, "Residual (U)", 1000, -0.1, 0.1);
0220   }
0221   fitResHisto = new TH1I("fit_result", "GBL Fit Result", 21, -1, 20);
0222   ndfHisto = new TH1I("ndf", "GBL Track NDF", 41, -1, 40);
0223   chi2OndfHisto = new TH1F("chi2_ndf", "Track Chi2/NDF", 100, 0., 10.);
0224   pValueHisto = new TH1F("p_value", "Track P-value", 100, 0., 1.);
0225   
0226   stats = new TH1I("stats", "0: NDF>0 | 1: fTel&VXD | 2: all | 3: VXD | 4: SVD | 5: all - PXD | 6: fTel&SVD | 7: bTel", 10, 0, 10);
0227   
0228   #endif
0229 }
0230 
0231 void GFGbl::endRun()
0232 {
0233   #ifdef OUTPUT
0234   diag->cd();
0235   diag->Write();
0236   diag->Close();
0237   #endif
0238   // This is needed to close the file before alignment starts
0239   if (milleFile)
0240     delete milleFile;
0241 }
0242 
0243 /**
0244  * @brief Evaluates moments of radiation length distribution from list of
0245  * material steps and computes parameters describing a corresponding thick scatterer.
0246  *
0247  * Based on input from Claus Kleinwort (DESY),
0248  * adapted for continuous material distribution represented by
0249  * a sum of step functions. Returned thick scatterer can be represented by two GBL scattering points
0250  * at (s - ds) and (s + ds) with variance of theta equal to theta/sqrt(2) for both points.
0251  * Calculates variance of theta from total sum of radiation lengths
0252  * instead of summimg squares of individual deflection angle variances.
0253  *
0254  * @param length returned: Length of the track
0255  * @param theta returned: Variation of distribution of deflection angle
0256  * @param s returned: First moment of material scattering distribution
0257  * @param ds returned: Second moment (variance) of material scattering distribution
0258  * @param p Particle momentum magnitude (GeV/c)
0259  * @param mass Mass of particle (GeV/c/c)
0260  * @param steps Vector of material steps from (RKTrackRep) extrapolation
0261  * @return void
0262  */
0263 void getScattererFromMatList(double& length, double& theta, double& s, double& ds, const double p, const double mass, const double charge, const std::vector<MatStep>& steps)
0264 {
0265   theta = 0.; s = 0.; ds = 0.;
0266   if (steps.empty()) return;
0267   
0268   // sum of step lengths
0269   double len = 0.;
0270   // normalization
0271   double sumxx = 0.;
0272   // first moment (non-normalized)
0273   double sumx2x2 = 0.;
0274   // (part of) second moment / variance (non-normalized)
0275   double sumx3x3 = 0.;
0276   
0277   // cppcheck-suppress unreadVariable
0278   double xmin = 0.;
0279   double xmax = 0.;
0280   
0281   for (unsigned int i = 0; i < steps.size(); i++) {
0282     const MatStep step = steps.at(i);
0283     // inverse of material radiation length ... (in 1/cm) ... "density of scattering"
0284     double rho = 1. / step.material_.radiationLength;
0285     len += fabs(step.stepSize_);
0286     xmin = xmax;
0287     xmax = xmin + fabs(step.stepSize_);
0288     // Compute integrals
0289     
0290     // integral of rho(x)
0291     sumxx   += rho * (xmax - xmin);
0292     // integral of x*rho(x)
0293     sumx2x2 += rho * (xmax * xmax - xmin * xmin) / 2.;
0294     // integral of x*x*rho(x)
0295     sumx3x3 += rho * (xmax * xmax * xmax - xmin * xmin * xmin) / 3.;
0296   }
0297   // This ensures PDG formula still gives positive results (but sumxx should be > 1e-4 for it to hold)
0298   if (sumxx < 1.0e-10) return;
0299   // Calculate theta from total sum of radiation length
0300   // instead of summimg squares of individual deflection angle variances
0301   // PDG formula:
0302   double beta = p / sqrt(p * p + mass * mass);
0303   theta = (0.0136 / p / beta) * fabs(charge) * sqrt(sumxx) * (1. + 0.038 * log(sumxx));
0304   //theta = (0.015 / p / beta) * fabs(charge) * sqrt(sumxx);
0305   
0306   // track length
0307   length = len;
0308   // Normalization factor
0309   double N = 1. / sumxx;
0310   // First moment
0311   s  = N * sumx2x2;
0312   // Square of second moment (variance)
0313   // integral of (x - s)*(x - s)*rho(x)
0314   double ds_2 = N * (sumx3x3 - 2. * sumx2x2 * s + sumxx * s * s);
0315   ds = sqrt(ds_2);
0316   
0317   #ifdef DEBUG
0318   //cout << "Thick scatterer parameters:" << endl;
0319   //cout << "Variance of theta: " << theta << endl;
0320   //cout << "Mean s           : " << s << endl;
0321   //cout << "Variance of s    : " << ds << endl;
0322   
0323   #endif
0324 }
0325 
0326 
0327 void GFGbl::processTrackWithRep(Track* trk, const AbsTrackRep* rep, bool /*resortHits*/)
0328 {
0329   // Flag used to mark error in raw measurement combination
0330   // measurement won't be considered, but scattering yes
0331   bool skipMeasurement = false;
0332   // Chi2 of Reference Track
0333   double trkChi2 = 0.;
0334   // This flag enables/disables fitting of q/p parameter in GBL
0335   // It is switched off automatically if no B-field at (0,0,0) is detected.
0336   bool fitQoverP = true;
0337   //TODO: Use clever way to determine zero B-field
0338   double Bfield = genfit::FieldManager::getInstance()->getFieldVal(TVector3(0., 0., 0.)).Mag();
0339   if (!(Bfield > 0.))
0340     fitQoverP = false;
0341   
0342   // Dimesion of repository/state
0343   int dim = rep->getDim();
0344   // current measurement point
0345   TrackPoint* point_meas;
0346   // current raw measurement
0347   AbsMeasurement* raw_meas;
0348   
0349   // We assume no initial kinks, this will be reused several times
0350   TVectorD scatResidual(2);
0351   scatResidual.Zero();
0352   
0353   // All measurement points in ref. track
0354   int npoints_meas = trk->getNumPointsWithMeasurement();
0355   
0356   #ifdef DEBUG
0357   int npoints_all = trk->getNumPoints();
0358   
0359   if (resortHits)
0360     cout << "WARNING: Hits resorting in GBL interface not supported." << endl;
0361   
0362   cout << "-------------------------------------------------------" << endl;
0363   cout << "               GBL processing genfit::Track            " << endl;
0364   cout << "-------------------------------------------------------" << endl;
0365   cout << " # Ref. Track Points  :  " << npoints_all  << endl;
0366   cout << " # Meas. Points       :  " << npoints_meas << endl;
0367   
0368   #endif
0369   // List of prepared GBL points for GBL trajectory construction
0370   std::vector<GblPoint> listOfPoints;
0371   
0372   std::vector<double> listOfLayers;
0373   //TODO: Add internal/external seed (from CDC) option in the future
0374   // index of point with seed information (0 for none)
0375   unsigned int seedLabel = 0;
0376   // Seed covariance
0377   // TMatrixDSym clCov(dim);
0378   // Seed state
0379   TMatrixDSym clSeed(dim);
0380   
0381   // propagation Jacobian to next point from current measurement point
0382   TMatrixD jacPointToPoint(dim, dim);
0383   jacPointToPoint.UnitMatrix();
0384   
0385   int n_gbl_points = 0;
0386   int n_gbl_meas_points = 0;
0387   int Ndf = 0;
0388   double Chi2 = 0.;
0389   double lostWeight = 0.;
0390   
0391   // Momentum of track at current plane
0392   double trackMomMag = 0.;
0393   // Charge of particle at current plane :-)
0394   double particleCharge = 1.;
0395   
0396   for (int ipoint_meas = 0; ipoint_meas < npoints_meas; ipoint_meas++) {
0397     point_meas = trk->getPointWithMeasurement(ipoint_meas);
0398     
0399     if (!point_meas->hasFitterInfo(rep)) {
0400       cout << " ERROR: Measurement point does not have a fitter info. Track will be skipped." << endl;
0401       return;
0402     }
0403     // Fitter info which contains Reference state and plane
0404     KalmanFitterInfo* fi = dynamic_cast<KalmanFitterInfo*>(point_meas->getFitterInfo(rep));
0405     if (!fi) {
0406       cout << " ERROR: KalmanFitterInfo (with reference state) for measurement does not exist. Track will be skipped." << endl;
0407       return;
0408     }
0409     // Current detector plane
0410     SharedPlanePtr plane = fi->getPlane();
0411     if (!fi->hasReferenceState()) {
0412       cout << " ERROR: Fitter info does not contain reference state. Track will be skipped." << endl;
0413       return;
0414     }
0415     // Reference StateOnPlane for extrapolation
0416     ReferenceStateOnPlane* reference = new ReferenceStateOnPlane(*fi->getReferenceState());//(dynamic_cast<const genfit::ReferenceStateOnPlane&>(*fi->getReferenceState()));
0417     // Representation state at plane
0418     TVectorD state = reference->getState();
0419     // track direction at plane (in global coords)
0420     TVector3 trackDir = rep->getDir(*reference);
0421     // track momentum vector at plane (in global coords)
0422     trackMomMag = rep->getMomMag(*reference);
0423     // charge of particle
0424     particleCharge = rep->getCharge(*reference);
0425     // mass of particle
0426     double particleMass = rep->getMass(*reference);
0427     
0428     // Parameters of a thick scatterer between measurements
0429     double trackLen = 0.;
0430     double scatTheta = 0.;
0431     double scatSMean = 0.;
0432     double scatDeltaS = 0.;
0433     // Parameters of two equivalent thin scatterers
0434     double theta1 = 0.;
0435     double theta2 = 0.;
0436     double s1 = 0.;
0437     double s2 = 0.;
0438     
0439     TMatrixDSym noise;
0440     TVectorD deltaState;
0441     // jacobian from s2 to M2
0442     TMatrixD jacMeas2Scat(dim, dim);
0443     jacMeas2Scat.UnitMatrix();
0444     
0445     
0446     // Now get measurement. First have a look if we need to combine SVD clusters...
0447     // Load Jacobian from previous extrapolation
0448     // rep->getForwardJacobianAndNoise(jacPointToPoint, noise, deltaState);
0449     // Try to get VxdId of current plane
0450     int sensorId = 0;
0451     PlanarMeasurement* measPlanar = dynamic_cast<PlanarMeasurement*>(point_meas->getRawMeasurement(0));
0452     if (measPlanar) sensorId = measPlanar->getPlaneId();
0453     
0454     //WARNING: Now we only support 2D measurements. If 2 raw measurements are stored at the track
0455     // point, these are checked if they correspond to "u" and "v" measurement (for SVD clusters) and these
0456     // measurements are combined. SLANTED SENSORS NOT YET SUPPORTED!!!
0457     if (point_meas->getRawMeasurement(0)->getDim() != 2
0458       && trk->getPointWithMeasurement(ipoint_meas)->getNumRawMeasurements() == 2
0459       && point_meas->getRawMeasurement(0)->getDim() == 1
0460       && point_meas->getRawMeasurement(1)->getDim() == 1) {
0461       AbsMeasurement* raw_measU = 0;
0462       AbsMeasurement* raw_measV = 0;
0463     
0464       // cout << " Two 1D Measurements encountered. " << endl;
0465     
0466       int sensorId2 = -1;
0467       PlanarMeasurement* measPlanar2 = dynamic_cast<PlanarMeasurement*>(point_meas->getRawMeasurement(0));
0468       if (measPlanar2) sensorId2 = measPlanar->getPlaneId();
0469     
0470       // We only try to combine if at same sensor id (should be always, but who knows)
0471       // otherwise ignore this point
0472       if (sensorId != sensorId2) {
0473     skipMeasurement = true;
0474     cout << " ERROR: Incompatible sensorIDs at measurement point " << ipoint_meas << ". Measurement will be skipped." << endl;
0475       }
0476     
0477       // We have to combine two SVD 1D Clusters at the same plane into one 2D recohit
0478       AbsMeasurement* raw_meas1 = point_meas->getRawMeasurement(0);
0479       AbsMeasurement* raw_meas2 = point_meas->getRawMeasurement(1);
0480       // Decide which cluster is u and which v based on H-matrix
0481       if (raw_meas1->constructHMatrix(rep)->isEqual(genfit::HMatrixU())
0482       && raw_meas2->constructHMatrix(rep)->isEqual(genfit::HMatrixV())) {
0483     // right order U, V
0484     raw_measU = raw_meas1;
0485     raw_measV = raw_meas2;
0486       } else if (raw_meas2->constructHMatrix(rep)->isEqual(genfit::HMatrixU())
0487          && raw_meas1->constructHMatrix(rep)->isEqual(genfit::HMatrixV())) {
0488         // inversed order V, U
0489         raw_measU = raw_meas2;
0490     raw_measV = raw_meas1;
0491       } else {
0492     // Incompatible measurements ... skip track ... I saw this once and just before a segfault ...
0493     cout << " ERROR: Incompatible 1D measurements at meas. point " << ipoint_meas << ". Track will be skipped." << endl;
0494     return;
0495       }
0496       // Combine raw measurements
0497       TVectorD _raw_coor(2);
0498       _raw_coor(0) = raw_measU->getRawHitCoords()(0);
0499       _raw_coor(1) = raw_measV->getRawHitCoords()(0);
0500       // Combine covariance matrix
0501       TMatrixDSym _raw_cov(2);
0502       _raw_cov.Zero();
0503       _raw_cov(0, 0) = raw_measU->getRawHitCov()(0, 0);
0504       _raw_cov(1, 1) = raw_measV->getRawHitCov()(0, 0);
0505       // Create new combined measurement
0506       raw_meas = new PlanarMeasurement(_raw_coor, _raw_cov, raw_measU->getDetId(), raw_measU->getHitId(), point_meas);
0507     } else {
0508       // Default behavior
0509       raw_meas = point_meas->getRawMeasurement(0);
0510     }
0511     //TODO: We only support 2D measurements in GBL (ot two 1D combined above)
0512     if (raw_meas->getRawHitCoords().GetNoElements() != 2) {
0513       skipMeasurement = true;
0514       #ifdef DEBUG
0515       cout << " WARNING: Measurement " << (ipoint_meas + 1) << " is not 2D. Measurement Will be skipped. " << endl;
0516       #endif
0517     }
0518       
0519     // Now we have all necessary information, so lets insert current measurement point
0520     // if we don't want to skip it (e.g. ghost SVD hit ... just 1D information)
0521     if (!skipMeasurement) {
0522       // 2D hit coordinates
0523       TVectorD raw_coor = raw_meas->getRawHitCoords();
0524       // Covariance matrix of measurement
0525       TMatrixDSym raw_cov = raw_meas->getRawHitCov();
0526       // Projection matrix from repository state to measurement coords
0527       std::unique_ptr<const AbsHMatrix> HitHMatrix(raw_meas->constructHMatrix(rep));
0528       // Residual between measured position and reference track position
0529       TVectorD residual = -1. * (raw_coor - HitHMatrix->Hv(state));
0530 
0531       trkChi2 += residual(0) * residual(0) / raw_cov(0, 0) + residual(1) * residual(1) / raw_cov(1, 1);
0532         
0533       // Measurement point
0534       GblPoint measPoint(jacPointToPoint);
0535       // Projection from local (state) coordinates to measurement coordinates (inverted)
0536       // 2x2 matrix ... last block of H matrix (2 rows x 5 columns)
0537       //TMatrixD proL2m = HitHMatrix->getMatrix().GetSub(0, 1, 3, 4);
0538       TMatrixD proL2m(2, 2);
0539       proL2m.Zero();
0540       proL2m(0, 0) = HitHMatrix->getMatrix()(0, 3);
0541       proL2m(0, 1) = HitHMatrix->getMatrix()(0, 4);
0542       proL2m(1, 1) = HitHMatrix->getMatrix()(1, 4);
0543       proL2m(1, 0) = HitHMatrix->getMatrix()(1, 3);
0544       proL2m.Invert();
0545       //raw_cov *= 100.;
0546       //proL2m.Print();
0547       measPoint.addMeasurement(proL2m, residual, raw_cov.Invert());
0548         
0549       //Add global derivatives to the point
0550         
0551       // sensor label = sensorID * 10, then last digit is label for global derivative for the sensor
0552       int label = sensorId * 10;
0553       // values for global derivatives
0554       //TMatrixD derGlobal(2, 6);
0555       TMatrixD derGlobal(2, 12);
0556         
0557       // labels for global derivatives
0558       std::vector<int> labGlobal;
0559         
0560       // track direction in global coords
0561       TVector3 tDir = trackDir;
0562       // sensor u direction in global coords
0563       TVector3 uDir = plane->getU();
0564       // sensor v direction in global coords
0565       TVector3 vDir = plane->getV();
0566       // sensor normal direction in global coords
0567       TVector3 nDir = plane->getNormal();
0568       //file << sensorId << endl;
0569       //outputVector(uDir, "U");
0570       //outputVector(vDir, "V");
0571       //outputVector(nDir, "Normal");
0572       // track direction in local sensor system
0573       TVector3 tLoc = TVector3(uDir.Dot(tDir), vDir.Dot(tDir), nDir.Dot(tDir));
0574         
0575       // track u-slope in local sensor system
0576       double uSlope = tLoc[0] / tLoc[2];
0577       // track v-slope in local sensor system
0578       double vSlope = tLoc[1] / tLoc[2];
0579         
0580       // Measured track u-position in local sensor system
0581       double uPos = raw_coor[0];
0582       // Measured track v-position in local sensor system
0583       double vPos = raw_coor[1];
0584         
0585       //Global derivatives for alignment in sensor local coordinates
0586       derGlobal(0, 0) = 1.0;
0587       derGlobal(0, 1) = 0.0;
0588       derGlobal(0, 2) = - uSlope;
0589       derGlobal(0, 3) = vPos * uSlope;
0590       derGlobal(0, 4) = -uPos * uSlope;
0591       derGlobal(0, 5) = vPos;
0592         
0593       derGlobal(1, 0) = 0.0;
0594       derGlobal(1, 1) = 1.0;
0595       derGlobal(1, 2) = - vSlope;
0596       derGlobal(1, 3) = vPos * vSlope;
0597       derGlobal(1, 4) = -uPos * vSlope;
0598       derGlobal(1, 5) = -uPos;
0599 
0600       labGlobal.push_back(label + 1); // u
0601       labGlobal.push_back(label + 2); // v
0602       labGlobal.push_back(label + 3); // w
0603       labGlobal.push_back(label + 4); // alpha
0604       labGlobal.push_back(label + 5); // beta
0605       labGlobal.push_back(label + 6); // gamma
0606 
0607       // Global derivatives for movement of whole detector system in global coordinates
0608       //TODO: Usage of this requires Hierarchy Constraints to be provided to MP2
0609   
0610       // sensor centre position in global system
0611       TVector3 detPos = plane->getO();
0612       //cout << "detPos" << endl;
0613       //detPos.Print();
0614 
0615       // global prediction from raw measurement
0616       TVector3 pred = detPos + uPos * uDir + vPos * vDir;
0617       //cout << "pred" << endl;
0618       //pred.Print();
0619 
0620       double xPred = pred[0];
0621       double yPred = pred[1];
0622       double zPred = pred[2];
0623 
0624       // scalar product of sensor normal and track direction
0625       double tn = tDir.Dot(nDir);
0626       //cout << "tn" << endl;
0627       //cout << tn << endl;
0628 
0629       // derivatives of local residuals versus measurements
0630       TMatrixD drdm(3, 3);
0631       drdm.UnitMatrix();
0632       for (int row = 0; row < 3; row++)
0633     for (int col = 0; col < 3; col++)
0634       drdm(row, col) -= tDir[row] * nDir[col] / tn;
0635 
0636       //cout << "drdm" << endl;
0637       //drdm.Print();
0638 
0639       // derivatives of measurements versus global alignment parameters
0640       TMatrixD dmdg(3, 6);
0641       dmdg.Zero();
0642       dmdg(0, 0) = 1.; dmdg(0, 4) = -zPred; dmdg(0, 5) = yPred;
0643       dmdg(1, 1) = 1.; dmdg(1, 3) = zPred;  dmdg(1, 5) = -xPred;
0644       dmdg(2, 2) = 1.; dmdg(2, 3) = -yPred; dmdg(2, 4) = xPred;
0645 
0646       //cout << "dmdg" << endl;
0647       //dmdg.Print();
0648 
0649       // derivatives of local residuals versus global alignment parameters
0650       TMatrixD drldrg(3, 3);
0651       drldrg.Zero();
0652       drldrg(0, 0) = uDir[0]; drldrg(0, 1) = uDir[1]; drldrg(0, 2) = uDir[2];
0653       drldrg(1, 0) = vDir[0]; drldrg(1, 1) = vDir[1]; drldrg(1, 2) = vDir[2];
0654 
0655       //cout << "drldrg" << endl;
0656       //drldrg.Print();
0657 
0658       //cout << "drdm * dmdg" << endl;
0659       //(drdm * dmdg).Print();
0660 
0661       // derivatives of local residuals versus rigid body parameters
0662       TMatrixD drldg(3, 6);
0663       drldg = drldrg * (drdm * dmdg);
0664 
0665       //cout << "drldg" << endl;
0666       //drldg.Print();
0667 
0668       // offset to determine labels for sensor sets or individual layers
0669       // 0: PXD, TODO 1: SVD, or individual layers
0670       // offset 0 is for alignment of whole setup
0671       int offset = 0;
0672       //if (sensorId > 16704) offset = 20; // svd, but needs to introduce new 6 constraints: sum rot&shifts of pxd&svd = 0
0673 
0674       derGlobal(0, 6) = drldg(0, 0); labGlobal.push_back(offset + 1);
0675       derGlobal(0, 7) = drldg(0, 1); labGlobal.push_back(offset + 2);
0676       derGlobal(0, 8) = drldg(0, 2); labGlobal.push_back(offset + 3);
0677       derGlobal(0, 9) = drldg(0, 3); labGlobal.push_back(offset + 4);
0678       derGlobal(0, 10) = drldg(0, 4); labGlobal.push_back(offset + 5);
0679       derGlobal(0, 11) = drldg(0, 5); labGlobal.push_back(offset + 6);
0680 
0681       derGlobal(1, 6) = drldg(1, 0);
0682       derGlobal(1, 7) = drldg(1, 1);
0683       derGlobal(1, 8) = drldg(1, 2);
0684       derGlobal(1, 9) = drldg(1, 3);
0685       derGlobal(1, 10) = drldg(1, 4);
0686       derGlobal(1, 11) = drldg(1, 5);
0687 
0688 
0689 
0690       measPoint.addGlobals(labGlobal, derGlobal);
0691       listOfPoints.push_back(measPoint);
0692       listOfLayers.push_back((unsigned int) sensorId);
0693       n_gbl_points++;
0694       n_gbl_meas_points++;
0695     } else {
0696       // Incompatible measurement, store point without measurement
0697       GblPoint dummyPoint(jacPointToPoint);
0698       listOfPoints.push_back(dummyPoint);
0699       listOfLayers.push_back((unsigned int) sensorId);
0700       n_gbl_points++;
0701       skipMeasurement = false;
0702       #ifdef DEBUG
0703       cout << " Dummy point inserted. " << endl;
0704       #endif
0705     }
0706 
0707 
0708     //cout << " Starting extrapolation..." << endl;
0709     try {
0710 
0711       // Extrapolate to next measurement to get material distribution
0712       if (ipoint_meas < npoints_meas - 1) {
0713     // Check if fitter info is in place
0714     if (!trk->getPoint(ipoint_meas + 1)->hasFitterInfo(rep)) {
0715       cout << " ERROR: Measurement point does not have a fitter info. Track will be skipped." << endl;
0716       return;
0717     }
0718     // Fitter of next point info which is only used now to get the plane
0719     KalmanFitterInfo* fi_i_plus_1 = dynamic_cast<KalmanFitterInfo*>(trk->getPoint(ipoint_meas + 1)->getFitterInfo(rep));
0720     if (!fi_i_plus_1) {
0721       cout << " ERROR: KalmanFitterInfo (with reference state) for measurement does not exist. Track will be skipped." << endl;
0722       return;
0723     }
0724     StateOnPlane refCopy(*reference);
0725     // Extrap to point + 1, do NOT stop at boundary
0726     rep->extrapolateToPlane(refCopy, trk->getPoint(ipoint_meas + 1)->getFitterInfo(rep)->getPlane(), false, false);
0727     getScattererFromMatList(trackLen,
0728                 scatTheta,
0729                 scatSMean,
0730                 scatDeltaS,
0731                 trackMomMag,
0732                 particleMass,
0733                 particleCharge,
0734                 rep->getSteps());
0735     // Now calculate positions and scattering variance for equivalent scatterers
0736     // (Solution from Claus Kleinwort (DESY))
0737     s1 = 0.;
0738     s2 = scatSMean + scatDeltaS * scatDeltaS / (scatSMean - s1);
0739     theta1 = sqrt(scatTheta * scatTheta * scatDeltaS * scatDeltaS / (scatDeltaS * scatDeltaS + (scatSMean - s1) * (scatSMean - s1)));
0740     theta2 = sqrt(scatTheta * scatTheta * (scatSMean - s1) * (scatSMean - s1) / (scatDeltaS * scatDeltaS + (scatSMean - s1) * (scatSMean - s1)));
0741 
0742     if (m_enableScatterers && !m_enableIntermediateScatterer) {
0743       theta1 = scatTheta;
0744       theta2 = 0;
0745     } else if (!m_enableScatterers) {
0746       theta1 = 0.;
0747       theta2 = 0.;
0748     }
0749 
0750     if (s2 < 1.e-4 || s2 >= trackLen - 1.e-4 || s2 <= 1.e-4) {
0751       cout << " WARNING: GBL points will be too close. GBLTrajectory construction might fail. Let's try it..." << endl;
0752     }
0753 
0754       }
0755       // Return back to state on current plane
0756       delete reference;
0757       reference = new ReferenceStateOnPlane(*fi->getReferenceState());
0758 
0759       // If not last measurement, extrapolate and get jacobians for scattering points between this and next measurement
0760       if (ipoint_meas < npoints_meas - 1) {
0761     if (theta2 > scatEpsilon) {
0762       // First scatterer will be placed at current measurement point (see bellow)
0763 
0764       // theta2 > 0 ... we want second scatterer:
0765       // Extrapolate to s2 (remember we have s1 = 0)
0766       rep->extrapolateBy(*reference, s2, false, true);
0767       rep->getForwardJacobianAndNoise(jacMeas2Scat, noise, deltaState);
0768       // Finish extrapolation to next measurement
0769       double nextStep = rep->extrapolateToPlane(*reference, trk->getPoint(ipoint_meas + 1)->getFitterInfo(rep)->getPlane(), false, true);
0770       if (0. > nextStep) {
0771         cout << " ERROR: The extrapolation to measurement point " << (ipoint_meas + 2) << " stepped back by " << nextStep << "cm !!! Track will be skipped." << endl;
0772         return;
0773       }
0774       rep->getForwardJacobianAndNoise(jacPointToPoint, noise, deltaState);
0775 
0776     } else {
0777       // No scattering: extrapolate whole distance between measurements
0778       rep->extrapolateToPlane(*reference, trk->getPoint(ipoint_meas + 1)->getFitterInfo(rep)->getPlane(), false, true);
0779       //NOTE: we will load the jacobian from this extrapolation in next loop into measurement point
0780       //jacPointToPoint.Print();
0781       rep->getForwardJacobianAndNoise(jacPointToPoint, noise, deltaState);
0782       //jacPointToPoint.Print();
0783     }
0784       }
0785     } catch (...) {
0786       cout << " ERROR: Extrapolation failed. Track will be skipped." << endl;
0787       return;
0788     }
0789     //cout << " Extrapolation finished." << endl;
0790 
0791 
0792     // Now store scatterers if not last measurement and if we decided
0793     // there should be scatteres, otherwise the jacobian in measurement
0794     // stored above is already correct
0795     if (ipoint_meas < npoints_meas - 1) {
0796 
0797       if (theta1 > scatEpsilon) {
0798     // We have to insert first scatterer at measurement point
0799     // Therefore (because state is perpendicular to plane, NOT track)
0800     // we have non-diaonal matrix of multiple scattering covariance
0801     // We have to project scattering into plane coordinates
0802     double c1 = trackDir.Dot(plane->getU());
0803     double c2 = trackDir.Dot(plane->getV());
0804     TMatrixDSym scatCov(2);
0805     scatCov(0, 0) = 1. - c2 * c2;
0806     scatCov(1, 1) = 1. - c1 * c1;
0807     scatCov(0, 1) = c1 * c2;
0808     scatCov(1, 0) = c1 * c2;
0809     scatCov *= theta1 * theta1 / (1. - c1 * c1 - c2 * c2) / (1. - c1 * c1 - c2 * c2) ;
0810 
0811     // last point is the just inserted measurement (or dummy point)
0812     GblPoint& lastPoint = listOfPoints.at(n_gbl_points - 1);
0813     lastPoint.addScatterer(scatResidual, scatCov.Invert());
0814 
0815       }
0816 
0817       if (theta2 > scatEpsilon) {
0818     // second scatterer is somewhere between measurements
0819     // TrackRep state is perpendicular to track direction if using extrapolateBy (I asked Johannes Rauch),
0820     // therefore scattering covariance is diagonal (and both elements are equal)
0821     TMatrixDSym scatCov(2);
0822     scatCov.Zero();
0823     scatCov(0, 0) = theta2 * theta2;
0824     scatCov(1, 1) = theta2 * theta2;
0825 
0826     GblPoint scatPoint(jacMeas2Scat);
0827     scatPoint.addScatterer(scatResidual, scatCov.Invert());
0828     listOfPoints.push_back(scatPoint);
0829     listOfLayers.push_back(((unsigned int) sensorId) + 0.5);
0830     n_gbl_points++;
0831       }
0832 
0833 
0834     }
0835     // Free memory on the heap
0836     delete reference;
0837   }
0838   // We should have at least two measurement points to fit anything
0839   if (n_gbl_meas_points > 1) {
0840     int fitRes = -1;
0841     double pvalue = 0.;
0842     GblTrajectory* traj = 0;
0843     try {
0844       // Construct the GBL trajectory, seed not used
0845       traj = new GblTrajectory(listOfPoints, seedLabel, clSeed, fitQoverP);
0846       // Fit the trajectory
0847       fitRes = traj->fit(Chi2, Ndf, lostWeight, m_gblInternalIterations);
0848       if (fitRes != 0) {
0849         //#ifdef DEBUG
0850         //traj->printTrajectory(100);
0851         //traj->printData();
0852         //traj->printPoints(100);
0853         //#endif
0854       }
0855     } catch (...) {
0856       // Gbl failed critically (usually GblPoint::getDerivatives ... singular matrix inversion)
0857       return;
0858     }
0859     
0860     pvalue = TMath::Prob(Chi2, Ndf);
0861     
0862     //traj->printTrajectory(100);
0863     //traj->printData();
0864     //traj->printPoints(100);
0865     
0866     #ifdef OUTPUT
0867     // Fill histogram with fit result
0868     fitResHisto->Fill(fitRes);
0869     ndfHisto->Fill(Ndf);
0870     #endif
0871     
0872     #ifdef DEBUG
0873     cout << " Ref. Track Chi2      :  " << trkChi2 << endl;
0874     cout << " Ref. end momentum    :  " << trackMomMag << " GeV/c ";
0875     if (abs(trk->getCardinalRep()->getPDG()) == 11) {
0876       if (particleCharge < 0.)
0877         cout << "(electron)";
0878       else
0879         cout << "(positron)";
0880     }
0881     cout << endl;
0882     cout << "------------------ GBL Fit Results --------------------" << endl;
0883     cout << " Fit q/p parameter    :  " << ((fitQoverP) ? ("True") : ("False")) << endl;
0884     cout << " Valid trajectory     :  " << ((traj->isValid()) ? ("True") : ("False")) << endl;
0885     cout << " Fit result           :  " << fitRes << "    (0 for success)" << endl;
0886     cout << " # GBL meas. points   :  " << n_gbl_meas_points << endl;
0887     cout << " # GBL all points     :  " << n_gbl_points << endl;
0888     cout << " GBL track NDF        :  " << Ndf << "    (-1 for failure)" << endl;
0889     cout << " GBL track Chi2       :  " << Chi2 << endl;
0890     cout << " GBL track P-value    :  " << pvalue;
0891     if (pvalue < m_pValueCut)
0892       cout << " < p-value cut " << m_pValueCut;
0893     cout << endl;
0894     cout << "-------------------------------------------------------" << endl;
0895     #endif
0896     
0897     #ifdef OUTPUT
0898     bool hittedLayers[12];
0899     for (int hl = 0; hl < 12; hl++) {
0900       hittedLayers[hl] = false;
0901     }
0902     #endif
0903     
0904     // GBL fit succeded if Ndf >= 0, but Ndf = 0 is useless
0905     //TODO: Here should be some track quality check
0906     //    if (Ndf > 0 && fitRes == 0) {
0907     if (traj->isValid() && pvalue >= m_pValueCut && Ndf >= m_minNdf) {
0908       
0909       // In case someone forgot to use beginRun and dind't reset mille file name to ""
0910       if (!milleFile && m_milleFileName != "")
0911         milleFile = new MilleBinary(m_milleFileName);
0912       
0913       // Loop over all GBL points
0914       for (unsigned int p = 0; p < listOfPoints.size(); p++) {
0915         unsigned int label = p + 1;
0916         unsigned int numRes;
0917         TVectorD residuals(2);
0918         TVectorD measErrors(2);
0919         TVectorD resErrors(2);
0920         TVectorD downWeights(2);
0921         //TODO: now we only provide info about measurements, not kinks
0922         if (!listOfPoints.at(p).hasMeasurement())
0923           continue;
0924         
0925         #ifdef OUTPUT
0926         // Decode VxdId and get layer in TB setup
0927         unsigned int l = 0;
0928         unsigned int id = listOfLayers.at(p);
0929         // skip segment (5 bits)
0930         id = id >> 5;
0931         unsigned int sensor = id & 7;
0932         id = id >> 3;
0933         unsigned int ladder = id & 31;
0934         id = id >> 5;
0935         unsigned int layer = id & 7;
0936         
0937         if (layer == 7 && ladder == 2) {
0938           l = sensor;
0939         } else if (layer == 7 && ladder == 3) {
0940           l = sensor + 9 - 3;
0941         } else {
0942           l = layer + 3;
0943         }
0944         
0945         hittedLayers[l - 1] = true;
0946         #endif
0947         TVectorD localPar(5);
0948         TMatrixDSym localCov(5);
0949         traj->getResults(label, localPar, localCov);
0950         // Get GBL fit results
0951         traj->getMeasResults(label, numRes, residuals, measErrors, resErrors, downWeights);
0952         if (m_chi2Cut && (fabs(residuals[0] / resErrors[0]) > m_chi2Cut || fabs(residuals[1] / resErrors[1]) > m_chi2Cut))
0953           return;
0954         // Write layer-wise data
0955         #ifdef OUTPUT
0956         if (!writeHistoDataForLabel(listOfLayers.at(p), residuals, measErrors, resErrors, downWeights, localPar, localCov))
0957           return;
0958         #endif
0959         
0960       } // end for points
0961       
0962       // Write binary data to mille binary
0963       if (milleFile && m_milleFileName != "" && pvalue >= m_pValueCut && Ndf >= m_minNdf) {
0964         traj->milleOut(*milleFile);
0965         #ifdef DEBUG
0966         cout << " GBL Track written to Millepede II binary file." << endl;
0967         cout << "-------------------------------------------------------" << endl;
0968         #endif
0969       }
0970       
0971       #ifdef OUTPUT
0972       // Fill histograms
0973       chi2OndfHisto->Fill(Chi2 / Ndf);
0974       pValueHisto->Fill(TMath::Prob(Chi2, Ndf));
0975       // track counting
0976       stats->Fill(0);
0977       // hitted sensors statistics
0978       if (
0979         hittedLayers[0] &&
0980         hittedLayers[1] &&
0981         hittedLayers[2] &&
0982         hittedLayers[3] &&
0983         hittedLayers[4] &&
0984         hittedLayers[5] &&
0985         hittedLayers[6] &&
0986         hittedLayers[7] &&
0987         hittedLayers[8]
0988       ) {
0989         // front tel + pxd + svd
0990         stats->Fill(1);
0991       }
0992       
0993       if (
0994         hittedLayers[0] &&
0995         hittedLayers[1] &&
0996         hittedLayers[2] &&
0997         hittedLayers[3] &&
0998         hittedLayers[4] &&
0999         hittedLayers[5] &&
1000         hittedLayers[6] &&
1001         hittedLayers[7] &&
1002         hittedLayers[8] &&
1003         hittedLayers[9] &&
1004         hittedLayers[10] &&
1005         hittedLayers[11]
1006       ) {
1007         // all layers
1008         stats->Fill(2);
1009       }
1010       if (
1011         hittedLayers[3] &&
1012         hittedLayers[4] &&
1013         hittedLayers[5] &&
1014         hittedLayers[6] &&
1015         hittedLayers[7] &&
1016         hittedLayers[8]
1017       ) {
1018         // vxd
1019         stats->Fill(3);
1020       }
1021       if (
1022         hittedLayers[5] &&
1023         hittedLayers[6] &&
1024         hittedLayers[7] &&
1025         hittedLayers[8]
1026       ) {
1027         // svd
1028         stats->Fill(4);
1029       }
1030       if (
1031         hittedLayers[0] &&
1032         hittedLayers[1] &&
1033         hittedLayers[2] &&
1034         
1035         hittedLayers[5] &&
1036         hittedLayers[6] &&
1037         hittedLayers[7] &&
1038         hittedLayers[8] &&
1039         hittedLayers[9] &&
1040         hittedLayers[10] &&
1041         hittedLayers[11]
1042       ) {
1043         // all except pxd
1044         stats->Fill(5);
1045       }
1046       if (
1047         hittedLayers[0] &&
1048         hittedLayers[1] &&
1049         hittedLayers[2] &&
1050         
1051         hittedLayers[5] &&
1052         hittedLayers[6] &&
1053         hittedLayers[7] &&
1054         hittedLayers[8]
1055       ) {
1056         // front tel + svd
1057         stats->Fill(6);
1058       }
1059       if (
1060         hittedLayers[9] &&
1061         hittedLayers[10] &&
1062         hittedLayers[11]
1063       ) {
1064         // backward tel
1065         stats->Fill(7);
1066       }
1067       #endif
1068     }
1069     
1070     // Free memory
1071     delete traj;
1072   }
1073 }
1074