1 | // ESAF : Euso Simulation and Analysis Framework |
---|
2 | // $Id: MedianFit.cc 2949 2011-06-26 18:39:34Z mabl $ |
---|
3 | // R. Pesce created Jan, 29 2004 |
---|
4 | |
---|
5 | /***************************************************************************** |
---|
6 | * ESAF: Euso Simulation and Analysis Framework * |
---|
7 | * * |
---|
8 | * Id: MedianFit * |
---|
9 | * Package: Fitting * |
---|
10 | * Coordinator: <coordinator> * |
---|
11 | * * |
---|
12 | *****************************************************************************/ |
---|
13 | |
---|
14 | //_____________________________________________________________________________ |
---|
15 | // |
---|
16 | // TrackDirection2Module |
---|
17 | // |
---|
18 | // <extensive class description> |
---|
19 | |
---|
20 | #include <iostream> |
---|
21 | #include "MedianFit.hh" |
---|
22 | #include "TMath.h" |
---|
23 | |
---|
24 | using namespace TMath; |
---|
25 | |
---|
26 | ClassImp(MedianFit) |
---|
27 | |
---|
28 | //___________________________________________________________________________ |
---|
29 | MedianFit::MedianFit( Int_t numpoints, vector<Double_t> x, vector<Double_t> y ) { |
---|
30 | // |
---|
31 | // ctor |
---|
32 | // |
---|
33 | |
---|
34 | fNumPoints = numpoints; |
---|
35 | fSlope = 0; |
---|
36 | fOffset = 0; |
---|
37 | fAbsoluteDeviation = 0; |
---|
38 | fPointsX = x; |
---|
39 | fPointsY = y; |
---|
40 | Do(); |
---|
41 | } |
---|
42 | |
---|
43 | //___________________________________________________________________________ |
---|
44 | MedianFit::~MedianFit() { |
---|
45 | // |
---|
46 | // dtor |
---|
47 | // |
---|
48 | |
---|
49 | fPointsX.clear(); |
---|
50 | fPointsY.clear(); |
---|
51 | } |
---|
52 | |
---|
53 | |
---|
54 | //___________________________________________________________________________ |
---|
55 | void MedianFit::Do() { |
---|
56 | // |
---|
57 | // Median fit algorithm |
---|
58 | // Adapted from "Numerical Recipes in C" pag.704 |
---|
59 | // |
---|
60 | |
---|
61 | if ( fNumPoints < 2 ) return; |
---|
62 | |
---|
63 | Double_t XSum = 0; |
---|
64 | Double_t XSqSum = 0; |
---|
65 | Double_t YSum = 0; |
---|
66 | Double_t XYSum = 0; |
---|
67 | |
---|
68 | for( Int_t i=0; i<fNumPoints; i++ ) { |
---|
69 | XSum += fPointsX[i]; |
---|
70 | XSqSum += fPointsX[i] * fPointsX[i]; |
---|
71 | YSum += fPointsY[i]; |
---|
72 | XYSum += fPointsX[i] * fPointsY[i]; |
---|
73 | } |
---|
74 | |
---|
75 | // method of least squares for a first guess for slope and offset |
---|
76 | fOffset = (XSqSum * YSum - XSum * XYSum) / (fNumPoints * XSqSum - XSum * XSum); |
---|
77 | fSlope = (fNumPoints * XYSum - XSum * YSum) / (fNumPoints * XSqSum - XSum * XSum); |
---|
78 | Double_t chisquare = 0; |
---|
79 | for( Int_t i=0; i<fNumPoints; i++ ) { |
---|
80 | chisquare += Power((fPointsY[i] - (fOffset + fSlope * fPointsX[i] )),2); |
---|
81 | } |
---|
82 | |
---|
83 | // standard deviation: idea of how big an interaction step to take |
---|
84 | Double_t sigmaslope = Sqrt(chisquare / fNumPoints * XSqSum - XSum * XSum); |
---|
85 | |
---|
86 | Double_t b1 = fSlope; |
---|
87 | Double_t r1 = RoFunc( b1 ); |
---|
88 | |
---|
89 | if ( sigmaslope > 0 ) { |
---|
90 | Double_t b2 = fSlope + Sign(3. * sigmaslope, r1); |
---|
91 | // gues bracket as 3-sigma away, in the downhill direction known from r1 |
---|
92 | Double_t r2 = RoFunc( b2 ); |
---|
93 | if ( b2 == b1 ) { |
---|
94 | fAbsoluteDeviation /= fNumPoints; |
---|
95 | return; |
---|
96 | } |
---|
97 | // bracketing |
---|
98 | while( r1*r2 > 0 ) { |
---|
99 | fSlope = b2 + 1.6 * ( b2 - b1 ); |
---|
100 | b1 = b2; |
---|
101 | r1 = r2; |
---|
102 | b2 = fSlope; |
---|
103 | r2 = RoFunc( b2 ); |
---|
104 | } |
---|
105 | sigmaslope *= 0.01; |
---|
106 | // refine until error a negligible number of sigmas |
---|
107 | while( Abs(b2-b1) > sigmaslope ) { |
---|
108 | fSlope = b1 + 0.5 * ( b2 - b1 ); // bisection |
---|
109 | if ( ( fSlope == b1 ) || ( fSlope == b2 ) ) break; |
---|
110 | Double_t r = RoFunc( fSlope ); |
---|
111 | if ( r*r1 >= 0 ) { |
---|
112 | r1 = r; |
---|
113 | b1 = fSlope; |
---|
114 | } else { |
---|
115 | r2 = r; |
---|
116 | b2 = fSlope; |
---|
117 | } |
---|
118 | } |
---|
119 | } |
---|
120 | fAbsoluteDeviation /= fNumPoints; |
---|
121 | } |
---|
122 | |
---|
123 | //___________________________________________________________________________ |
---|
124 | Double_t MedianFit::RoFunc( Double_t b ) { |
---|
125 | // |
---|
126 | // Method used by median fit |
---|
127 | // Adapted from "Numerical Recipes in C pag.705" |
---|
128 | // |
---|
129 | |
---|
130 | vector<Double_t> dummy; |
---|
131 | |
---|
132 | for( Int_t i=0; i<fNumPoints; i++ ) { |
---|
133 | dummy.push_back( fPointsY[i]- b * fPointsX[i] ); |
---|
134 | } |
---|
135 | |
---|
136 | if ( ( fNumPoints & 1 ) == 0 ) { |
---|
137 | Int_t j = fNumPoints >> 1; |
---|
138 | fOffset = 0.5 * (Select( j, dummy ) + Select( j + 1, dummy )); |
---|
139 | } else { |
---|
140 | fOffset = Select( (fNumPoints+1)>>1, dummy); |
---|
141 | } |
---|
142 | |
---|
143 | Float_t sum = 0.; |
---|
144 | fAbsoluteDeviation = 0.; |
---|
145 | for( Int_t i=0; i<fNumPoints; i++ ) { |
---|
146 | Double_t d = fPointsY[i] - ( fOffset + b * fPointsX[i] ); |
---|
147 | fAbsoluteDeviation += Abs(d); |
---|
148 | if ( fPointsY[i] != 0 ) |
---|
149 | d /= fPointsY[i]; |
---|
150 | if ( Abs(d) > 1.0e-7) |
---|
151 | sum += ( d >= 0 ? fPointsX[i] : -fPointsX[i] ); |
---|
152 | } |
---|
153 | |
---|
154 | return sum; |
---|
155 | } |
---|
156 | |
---|
157 | //___________________________________________________________________________ |
---|
158 | Double_t MedianFit::Select( Int_t k, vector<Double_t> vec ) { |
---|
159 | // |
---|
160 | // Find the k-th smallest element in a vector; used to find the median |
---|
161 | // Adapted from "Numerical Recipes in C" pag.342 |
---|
162 | // |
---|
163 | |
---|
164 | Int_t l = 0; |
---|
165 | Int_t ir = vec.size() - 1; |
---|
166 | |
---|
167 | for( ; ; ) { |
---|
168 | if ( ir <= l + 1 ) { // active partition contains 1 or 2 elements |
---|
169 | if ( ir == l + 1 && vec[ir] < vec[l] ) { // active partition contains 2 elements |
---|
170 | Double_t temp = vec[l]; vec[l] = vec[ir]; vec[ir] = temp; |
---|
171 | } |
---|
172 | return vec[k-1]; |
---|
173 | } else { |
---|
174 | // choose median of left, center and right elements as partitioning element a |
---|
175 | // rearrange so that vec[l] <= vec[l+1] <= vec[ir] |
---|
176 | Int_t middle = ( l + ir ) >> 1; |
---|
177 | Double_t temp = vec[middle]; vec[middle] = vec[l+1]; vec[l+1] = temp; |
---|
178 | if ( vec[l] > vec[ir] ) { |
---|
179 | temp = vec[l]; vec[l] = vec[ir]; vec[ir] = temp; |
---|
180 | } |
---|
181 | if ( vec[l+1] > vec[ir] ) { |
---|
182 | temp = vec[l+1]; vec[l+1] = vec[ir]; vec[ir] = temp; |
---|
183 | } |
---|
184 | if ( vec[l] > vec[l+1] ) { |
---|
185 | temp = vec[l]; vec[l] = vec[l+1]; vec[l+1] = temp; |
---|
186 | } |
---|
187 | // initialize pointers for partitioning |
---|
188 | Int_t i = l + 1; |
---|
189 | Int_t j = ir; |
---|
190 | Double_t a = vec[l+1]; // partitioning element |
---|
191 | for( ; ; ) { |
---|
192 | do { // scan up to find element > a |
---|
193 | i++; |
---|
194 | } while( vec[i] < a ); // && i< (Int_t)vec.size() ); |
---|
195 | do { // scan down to find element < a |
---|
196 | j--; |
---|
197 | } while( vec[j] > a ); //&& j>=0 ); |
---|
198 | if ( j < i ) break; // pointers crossed; partitioning complete |
---|
199 | temp = vec[i]; vec[i] = vec[j]; vec[j] = temp; |
---|
200 | } |
---|
201 | vec[l+1] = vec[j]; // insert partitioning element |
---|
202 | vec[j] = a; |
---|
203 | if ( j >= (k-1) ) ir = j - 1; // keep active the partiction that contains the k-th element |
---|
204 | if ( j <= (k-1) ) l = i; |
---|
205 | } |
---|
206 | } |
---|
207 | } |
---|