ROOT logo

From $ROOTSYS/tutorials/fit/line3Dfit.C

//Fitting of a TGraph2D with a 3D straight line
//
// run this macro by doing: 
// 
// root>.x line3Dfit.C+
//

//Author: L. Moneta
//

   
#include <TMath.h>
#include <TGraph2D.h>
#include <TRandom2.h>
#include <TStyle.h>
#include <TCanvas.h>
#include <TF2.h>
#include <TH1.h>
#include <Math/Functor.h>
#include <TPolyLine3D.h>
#include <Math/Vector3D.h>
#include <Fit/Fitter.h>

using namespace ROOT::Math;


// define the parameteric line equation 
void line(double t, const double *p, double &x, double &y, double &z) {
   // a parameteric line is define from 6 parameters but 4 are independent
   // x0,y0,z0,z1,y1,z1 which are the coordinates of two points on the line
   // can choose z0 = 0 if line not parallel to x-y plane and z1 = 1; 
   x = p[0] + p[1]*t; 
   y = p[2] + p[3]*t;
   z = t; 
} 

// calculate distance line-point 
double distance2(double x,double y,double z, const double *p) {
   // distance line point is D= | (xp-x0) cross  ux | 
   // where ux is direction of line and x0 is a point in the line (like t = 0) 
   XYZVector xp(x,y,z); 
   XYZVector x0(p[0], p[2], 0. ); 
   XYZVector x1(p[0] + p[1], p[2] + p[3], 1. ); 
   XYZVector u = (x1-x0).Unit(); 
   double d2 = ((xp-x0).Cross(u)) .Mag2(); 
   return d2; 
}
bool first = true; 


// function Object to be minimized
struct SumDistance2 {
   // the TGraph is a data member of the object
   TGraph2D * fGraph;
   
   SumDistance2(TGraph2D * g) : fGraph(g) {}
   
   // implementation of the function to be minimized
   double operator() (const double * par) {
      
      assert(fGraph    != 0);
      double * x = fGraph->GetX();
      double * y = fGraph->GetY();
      double * z = fGraph->GetZ();
      int npoints = fGraph->GetN();
      double sum = 0;
      for (int i  = 0; i < npoints; ++i) {
         double d = distance2(x[i],y[i],z[i],par);
         sum += d;
#ifdef DEBUG
         if (first) std::cout << "point " << i << "\t"
            << x[i] << "\t"
            << y[i] << "\t"
            << z[i] << "\t"
            << std::sqrt(d) << std::endl;
#endif
      }
      if (first)
         std::cout << "Total Initial distance square = " << sum << std::endl;
      first = false;
      return sum;
   }
   
};

Int_t line3Dfit()
{
   gStyle->SetOptStat(0);
   gStyle->SetOptFit();


   //double e = 0.1;
   Int_t nd = 10000;


//    double xmin = 0; double ymin = 0;
//    double xmax = 10; double ymax = 10;

   TGraph2D * gr = new TGraph2D();

   // Fill the 2D graph
   double p0[4] = {10,20,1,2};

   // generate graph with the 3d points
   for (Int_t N=0; N<nd; N++) {
      double x,y,z = 0;
      // Generate a random number 
      double t = gRandom->Uniform(0,10);
      line(t,p0,x,y,z);
      double err = 1;
    // do a gaussian smearing around the points in all coordinates
      x += gRandom->Gaus(0,err);  
      y += gRandom->Gaus(0,err);  
      z += gRandom->Gaus(0,err);  
      gr->SetPoint(N,x,y,z);
      //dt->SetPointError(N,0,0,err);
   }
   // fit the graph now 
   
   ROOT::Fit::Fitter  fitter;
   
   
   // make the functor objet
   SumDistance2 sdist(gr);
#ifdef __CINT__
   ROOT::Math::Functor fcn(&sdist,4,"SumDistance2");
#else
   ROOT::Math::Functor fcn(sdist,4);
#endif
   // set the function and the initial parameter values
   double pStart[4] = {1,1,1,1};
   fitter.SetFCN(fcn,pStart);
   // set step sizes different than default ones (0.3 times parameter values)
   for (int i = 0; i < 4; ++i) fitter.Config().ParSettings(i).SetStepSize(0.01);
  
   bool ok = fitter.FitFCN();
   if (!ok) {
      Error("line3Dfit","Line3D Fit failed");
      return 1;
   }
   
   const ROOT::Fit::FitResult & result = fitter.Result();
   
   std::cout << "Total final distance square " << result.MinFcnValue() << std::endl;
   result.Print(std::cout);
   

   gr->Draw("p0");

   // get fit parameters
   const double * parFit = result.GetParams();

   
   // draw the fitted line
   int n = 1000;
   double t0 = 0;
   double dt = 10;
   TPolyLine3D *l = new TPolyLine3D(n);
   for (int i = 0; i <n;++i) {
      double t = t0+ dt*i/n;
      double x,y,z;
      line(t,parFit,x,y,z);
      l->SetPoint(i,x,y,z);
   }
   l->SetLineColor(kRed);
   l->Draw("same");
   
   // draw original line
   TPolyLine3D *l0 = new TPolyLine3D(n);
   for (int i = 0; i <n;++i) {
      double t = t0+ dt*i/n;
      double x,y,z;
      line(t,p0,x,y,z);
      l0->SetPoint(i,x,y,z);
   }
   l0->SetLineColor(kBlue);
   l0->Draw("same");
   return 0;
}

int main() { 
   return line3Dfit();
}
 line3Dfit.C:1
 line3Dfit.C:2
 line3Dfit.C:3
 line3Dfit.C:4
 line3Dfit.C:5
 line3Dfit.C:6
 line3Dfit.C:7
 line3Dfit.C:8
 line3Dfit.C:9
 line3Dfit.C:10
 line3Dfit.C:11
 line3Dfit.C:12
 line3Dfit.C:13
 line3Dfit.C:14
 line3Dfit.C:15
 line3Dfit.C:16
 line3Dfit.C:17
 line3Dfit.C:18
 line3Dfit.C:19
 line3Dfit.C:20
 line3Dfit.C:21
 line3Dfit.C:22
 line3Dfit.C:23
 line3Dfit.C:24
 line3Dfit.C:25
 line3Dfit.C:26
 line3Dfit.C:27
 line3Dfit.C:28
 line3Dfit.C:29
 line3Dfit.C:30
 line3Dfit.C:31
 line3Dfit.C:32
 line3Dfit.C:33
 line3Dfit.C:34
 line3Dfit.C:35
 line3Dfit.C:36
 line3Dfit.C:37
 line3Dfit.C:38
 line3Dfit.C:39
 line3Dfit.C:40
 line3Dfit.C:41
 line3Dfit.C:42
 line3Dfit.C:43
 line3Dfit.C:44
 line3Dfit.C:45
 line3Dfit.C:46
 line3Dfit.C:47
 line3Dfit.C:48
 line3Dfit.C:49
 line3Dfit.C:50
 line3Dfit.C:51
 line3Dfit.C:52
 line3Dfit.C:53
 line3Dfit.C:54
 line3Dfit.C:55
 line3Dfit.C:56
 line3Dfit.C:57
 line3Dfit.C:58
 line3Dfit.C:59
 line3Dfit.C:60
 line3Dfit.C:61
 line3Dfit.C:62
 line3Dfit.C:63
 line3Dfit.C:64
 line3Dfit.C:65
 line3Dfit.C:66
 line3Dfit.C:67
 line3Dfit.C:68
 line3Dfit.C:69
 line3Dfit.C:70
 line3Dfit.C:71
 line3Dfit.C:72
 line3Dfit.C:73
 line3Dfit.C:74
 line3Dfit.C:75
 line3Dfit.C:76
 line3Dfit.C:77
 line3Dfit.C:78
 line3Dfit.C:79
 line3Dfit.C:80
 line3Dfit.C:81
 line3Dfit.C:82
 line3Dfit.C:83
 line3Dfit.C:84
 line3Dfit.C:85
 line3Dfit.C:86
 line3Dfit.C:87
 line3Dfit.C:88
 line3Dfit.C:89
 line3Dfit.C:90
 line3Dfit.C:91
 line3Dfit.C:92
 line3Dfit.C:93
 line3Dfit.C:94
 line3Dfit.C:95
 line3Dfit.C:96
 line3Dfit.C:97
 line3Dfit.C:98
 line3Dfit.C:99
 line3Dfit.C:100
 line3Dfit.C:101
 line3Dfit.C:102
 line3Dfit.C:103
 line3Dfit.C:104
 line3Dfit.C:105
 line3Dfit.C:106
 line3Dfit.C:107
 line3Dfit.C:108
 line3Dfit.C:109
 line3Dfit.C:110
 line3Dfit.C:111
 line3Dfit.C:112
 line3Dfit.C:113
 line3Dfit.C:114
 line3Dfit.C:115
 line3Dfit.C:116
 line3Dfit.C:117
 line3Dfit.C:118
 line3Dfit.C:119
 line3Dfit.C:120
 line3Dfit.C:121
 line3Dfit.C:122
 line3Dfit.C:123
 line3Dfit.C:124
 line3Dfit.C:125
 line3Dfit.C:126
 line3Dfit.C:127
 line3Dfit.C:128
 line3Dfit.C:129
 line3Dfit.C:130
 line3Dfit.C:131
 line3Dfit.C:132
 line3Dfit.C:133
 line3Dfit.C:134
 line3Dfit.C:135
 line3Dfit.C:136
 line3Dfit.C:137
 line3Dfit.C:138
 line3Dfit.C:139
 line3Dfit.C:140
 line3Dfit.C:141
 line3Dfit.C:142
 line3Dfit.C:143
 line3Dfit.C:144
 line3Dfit.C:145
 line3Dfit.C:146
 line3Dfit.C:147
 line3Dfit.C:148
 line3Dfit.C:149
 line3Dfit.C:150
 line3Dfit.C:151
 line3Dfit.C:152
 line3Dfit.C:153
 line3Dfit.C:154
 line3Dfit.C:155
 line3Dfit.C:156
 line3Dfit.C:157
 line3Dfit.C:158
 line3Dfit.C:159
 line3Dfit.C:160
 line3Dfit.C:161
 line3Dfit.C:162
 line3Dfit.C:163
 line3Dfit.C:164
 line3Dfit.C:165
 line3Dfit.C:166
 line3Dfit.C:167
 line3Dfit.C:168
 line3Dfit.C:169
 line3Dfit.C:170
 line3Dfit.C:171
 line3Dfit.C:172
 line3Dfit.C:173
 line3Dfit.C:174
 line3Dfit.C:175
 line3Dfit.C:176
 line3Dfit.C:177
 line3Dfit.C:178
 line3Dfit.C:179
 line3Dfit.C:180
 line3Dfit.C:181
 line3Dfit.C:182
 line3Dfit.C:183
 line3Dfit.C:184