source: branches/AddingGoogleTestEnvironment/mtools/MCubicCoeff.cc@ 18147

Last change on this file since 18147 was 3148, checked in by tbretz, 21 years ago
*** empty log message ***
File size: 5.8 KB
Line 
1/* ======================================================================== *\
2!
3! *
4! * This file is part of MARS, the MAGIC Analysis and Reconstruction
5! * Software. It is distributed to you in the hope that it can be a useful
6! * and timesaving tool in analysing Data of imaging Cerenkov telescopes.
7! * It is distributed WITHOUT ANY WARRANTY.
8! *
9! * Permission to use, copy, modify and distribute this software and its
10! * documentation for any purpose is hereby granted without fee,
11! * provided that the above copyright notice appear in all copies and
12! * that both that copyright notice and this permission notice appear
13! * in supporting documentation. It is provided "as is" without express
14! * or implied warranty.
15! *
16!
17!
18! Author(s): Sebastian Raducci 01/2004 <mailto:raducci@fisica.uniud.it>
19!
20! Copyright: MAGIC Software Development, 2001-2004
21!
22!
23\* ======================================================================== */
24
25//////////////////////////////////////////////////////////////////////////////
26//
27// Cubic Spline Interpolation
28//
29//////////////////////////////////////////////////////////////////////////////
30#include "MCubicCoeff.h"
31
32#include <TMath.h>
33
34#include "MLog.h"
35#include "MLogManip.h"
36
37ClassImp(MCubicCoeff);
38
39using namespace std;
40
41//----------------------------------------------------------------------------
42//
43// Constructor (The spline is: fA(x-fX)3+fB(x-fX)2+fC(x-fX)+fY
44// where x is the independent variable, 2 and 3 are exponents
45//
46MCubicCoeff::MCubicCoeff(Double_t x, Double_t xNext, Double_t y, Double_t yNext,
47 Double_t a, Double_t b, Double_t c) :
48 fX(x), fXNext(xNext), fA(a), fB(b), fC(c), fY(y), fYNext(yNext)
49{
50 fH = fXNext - fX;
51 if (EvalMinMax())
52 return;
53
54 gLog << warn << "Failed to eval interval Minimum and Maximum, returning zeros" << endl;
55 fMin = 0;
56 fMax = 0;
57}
58
59//----------------------------------------------------------------------------
60//
61// Evaluate the spline at a given point
62//
63
64Double_t MCubicCoeff::Eval(Double_t x)
65{
66 const Double_t dx = x - fX;
67 return fY + dx*(fC + dx*(fB + dx*fA));
68}
69
70//----------------------------------------------------------------------------
71//
72// Find min and max using derivatives. The min and max could be at the begin
73// or at the end of the interval or somewhere inside the interval (in this case
74// a comparison between the first derivative and zero is made)
75// The first derivative coefficients are obviously: 3*fA, 2*fB, fC
76//
77Bool_t MCubicCoeff::EvalMinMax()
78{
79 fMin = fY;
80 fMax = fY;
81
82 fAbMin = fX;
83 fAbMax = fX;
84
85 if (fYNext < fMin)
86 {
87 fMin = fYNext;
88 fAbMin = fXNext;
89 }
90 if (fYNext > fMax)
91 {
92 fMax = fYNext;
93 fAbMax = fXNext;
94 }
95
96 const Double_t delta = fB*fB*4 - fA*fC*12;
97 if (delta >= 0 && fA != 0)
98 {
99 const Double_t sqrtDelta = TMath::Sqrt(delta);
100
101 const Double_t xPlus = (-fB*2 + sqrtDelta)/(fA*6);
102 const Double_t xMinus = (-fB*2 - sqrtDelta)/(fA*6);
103
104 if (xPlus >= 0 && xPlus <= fH)
105 {
106 const Double_t tempMinMax = Eval(fX+xPlus);
107 if (tempMinMax < fMin)
108 {
109 fMin = tempMinMax;
110 fAbMin = fX + xPlus;
111 }
112 if (tempMinMax > fMax)
113 {
114 fMax = tempMinMax;
115 fAbMax = fX + xPlus;
116 }
117 }
118 if (xMinus >= 0 && xMinus <= fH)
119 {
120 const Double_t tempMinMax = Eval(fX+xMinus);
121 if (tempMinMax < fMin)
122 {
123 fMin = tempMinMax;
124 fAbMin = fX + xMinus;
125 }
126 if (tempMinMax > fMax)
127 {
128 fMax = tempMinMax;
129 fAbMax = fX + xMinus;
130 }
131 }
132 return kTRUE;
133 }
134
135 /* if fA is zero then we have only one possible solution */
136 if (fA == 0 && fB != 0)
137 {
138 const Double_t xSolo = -fC/(fB*2);
139
140 if (xSolo < 0 || xSolo > fH)
141 return kTRUE;
142
143 const Double_t tempMinMax = Eval(fX+xSolo);
144 if (tempMinMax < fMin)
145 {
146 fMin = tempMinMax;
147 fAbMin = fX + xSolo;
148 }
149 if (tempMinMax > fMax)
150 {
151 fMax = tempMinMax;
152 fAbMax = fX + xSolo;
153 }
154 return kTRUE;
155 }
156
157 return kTRUE;
158}
159//-------------------------------------------------------------------------
160//
161// Given y finds x using the cubic (cardan) formula.
162//
163// we consider the following form: x3 + ax2 + bx + c = 0 where
164// a = fB/fA, b = fC/fA, c = (fY - y)/fA
165//
166// There could be three or one real solutions
167//
168Short_t MCubicCoeff::FindCardanRoot(Double_t y, Double_t *x)
169{
170 const Double_t a = fB/fA;
171 const Double_t b = fC/fA;
172 const Double_t c = (fY - y)/fA;
173
174 const Double_t q = (a*a - b*3)/9;
175 const Double_t r = (a*a*a*2 - a*b*9 + c*27)/54;
176
177 const Double_t aOver3 = a/3;
178 const Double_t r2 = r*r;
179 const Double_t q3 = q*q*q;
180
181 if (r2 < q3) //3 real sol
182 {
183 const Double_t sqrtQ = TMath::Sqrt(q);
184 const Double_t min2SqQ = -sqrtQ*2;
185 const Double_t theta = TMath::ACos(r/(sqrtQ*sqrtQ*sqrtQ));
186
187 x[0] = min2SqQ * TMath::Cos(theta/3) - aOver3;
188 x[1] = min2SqQ * TMath::Cos((theta+TMath::TwoPi())/3) - aOver3;
189 x[2] = min2SqQ * TMath::Cos((theta-TMath::TwoPi())/3) - aOver3;
190
191 for (Int_t i = 0; i < 3; i++)
192 if (x[i] >= 0 && x[i] <= fH)
193 {
194 x[i] += fX;
195 return i;
196 }
197 return -1;
198 }
199
200 const Double_t s = r==0 ? 0 : -TMath::Sign(TMath::Power(TMath::Abs(r) + TMath::Sqrt(r2 - q3), 1./3), r);
201
202 x[0] = s==0 ? - aOver3 : (s + q/s) - aOver3;
203
204 if (x[0] < 0 || x[0] > fH)
205 return -1;
206
207 x[0] += fX;
208 return 0;
209}
210
211//------------------------------------------------------------------------------------
212//
213// return true if x is in this interval
214//
215
216Bool_t MCubicCoeff :: IsIn(Double_t x)
217{
218 return x >= fX && x <= fXNext;
219}
Note: See TracBrowser for help on using the repository browser.