source: Sophya/trunk/SophyaLib/NTools/integ.cc@ 4035

Last change on this file since 4035 was 3587, checked in by ansari, 17 years ago

Adaptation suite nettoyage/suppression TRY/CATCH... , Reza 05/03/2009

File size: 10.6 KB
Line 
1#include "sopnamsp.h"
2#include "integ.h"
3#include "generalfit.h"
4
5// A faire :
6// 1 dans GLInteg, optimiser recalcul en utilisant des poids
7// calcules sur [0,1] et chgt de variable
8// 2 dans GLInteg, distinction nStep = subdivisions de l'intervalle,
9// et on applique GL d'ordre "ordre" sur chaque subdivision, en
10// utilisant le (1)
11
12/*!
13 \ingroup NTools
14 \class SOPHYA::Integrator
15
16 \brief Classe abstraite d'intégration numérique 1D.
17
18 On fournit une fonction double f(double) au constructeur, ou
19 une classe-fonction (ClassFuc) ou
20 une GeneralFunction avec des paramètres définis.
21 L'objet Integrator est convertible en valeur double qui est la valeur
22 de l'intégrale. Diverses méthodes permettent de choisir des options
23 de calcul, et ces méthodes retournent une référence sur l'objet, pour
24 permettre une notation chaînée.
25
26 \sa TrpzInteg GLInteg
27*/
28
29//! Constructeur par défaut. L'objet n'est pas utilisable en l'état.
30Integrator::Integrator()
31: mFunc(NULL), mClFun(NULL), mGFF(NULL), mGFFParm(NULL),
32 mNStep(50), mDX(-1), mReqPrec(-1),
33 mXMin(0), mXMax(1)
34{}
35
36//! Constructeur à partir d'une classe-fonction, et des bornes d'intégration.
37Integrator::Integrator(ClassFunc & f, double xmin, double xmax)
38: mFunc(NULL), mClFun(&f), mGFF(NULL), mGFFParm(NULL),
39 mNStep(50), mDX(-1), mReqPrec(-1),
40 mXMin(xmin), mXMax(xmax)
41{}
42
43//! Constructeur à partir de la fonction double->double, et des bornes d'intégration.
44Integrator::Integrator(FUNC f, double xmin, double xmax)
45: mFunc(f), mClFun(NULL), mGFF(NULL), mGFFParm(NULL),
46 mNStep(50), mDX(-1), mReqPrec(-1),
47 mXMin(xmin), mXMax(xmax)
48{}
49
50
51/*!
52 Constructeur a partir d'une classe-fonction
53 sans spécifier les bornes. Elles sont positionnées
54 à [0,1], et on pourra les modifier plus tard.
55*/
56Integrator::Integrator(ClassFunc & f)
57: mFunc(NULL), mClFun(&f), mGFF(NULL), mGFFParm(NULL),
58 mNStep(50), mDX(-1), mReqPrec(-1),
59 mXMin(0), mXMax(1)
60{}
61
62/*!
63 Constructeur sans spécifier les bornes. Elles sont positionnées
64 à [0,1], et on pourra les modifier plus tard.
65*/
66Integrator::Integrator(FUNC f)
67: mFunc(f), mClFun(NULL), mGFF(NULL), mGFFParm(NULL),
68 mNStep(50), mDX(-1), mReqPrec(-1),
69 mXMin(0), mXMax(1)
70{}
71
72/*!
73 Constructeur à partir d'une GeneralFunction. La fonction doit être une
74 fonction de une variable, et on fournit les valeurs des paramètres ainsi
75 que les bornes d'intégration.
76*/
77Integrator::Integrator(GeneralFunction* gff, double* par, double xmin, double xmax)
78: mFunc(NULL), mClFun(NULL), mGFF(gff), mGFFParm(par),
79 mNStep(50), mDX(-1), mReqPrec(-1),
80 mXMin(xmin), mXMax(xmax)
81{
82 ASSERT(gff->NVar() == 1);
83}
84
85/*!
86 Constructeur à partir d'une GeneralFunction. La fonction doit être une
87 fonction de une variable, et on fournit les valeurs des paramètres.
88 On ne spécifie pas les bornes. Elles sont positionnées
89 à [0,1], et on pourra les modifier plus tard.
90*/
91Integrator::Integrator(GeneralFunction* gff, double* par)
92: mFunc(NULL), mClFun(NULL), mGFF(gff), mGFFParm(par),
93 mNStep(50), mDX(-1), mReqPrec(-1),
94 mXMin(0), mXMax(1)
95{
96 ASSERT(gff->NVar() == 1);
97}
98
99Integrator::~Integrator()
100{
101}
102
103
104/*!
105 \brief Spécifie le nombre de pas pour l'intégration numérique.
106
107 La signification peut dépendre de la méthode d'intégration.
108*/
109Integrator&
110Integrator::NStep(int n)
111{
112 mNStep = n;
113 mDX = mReqPrec = -1;
114 StepsChanged();
115 return *this;
116}
117
118/*!
119 \brief Spécifie le nombre de pas pour l'intégration numérique.
120
121 La signification peut dépendre de la méthode d'intégration.
122*/
123Integrator&
124Integrator::DX(double d)
125{
126 mDX = d;
127 mNStep = -1;
128 mReqPrec = -1.;
129 StepsChanged();
130 return *this;
131}
132
133/*!
134 \brief Spécifie la précision souhaitée.
135
136 La signification peut dépendre de la méthode d'intégration.
137 Non disponible dans toutes les méthodes d'intégration.
138*/
139Integrator&
140Integrator::ReqPrec(double p)
141{
142 ASSERT( !"Pas encore implemente !");
143 mReqPrec = p;
144 mDX = mNStep = -1;
145 StepsChanged();
146 return *this;
147}
148
149//! Spécifie les bornes de l'intégrale.
150Integrator&
151Integrator::Limits(double xmin, double xmax)
152{
153 mXMin = xmin;
154 mXMax = xmax;
155 LimitsChanged();
156 return *this;
157}
158
159//! Spécifie la fonction à intégrer, sous forme double f(double).
160Integrator&
161Integrator::SetFunc(ClassFunc & f)
162{
163 mFunc = NULL;
164 mClFun = &f;
165 mGFFParm = NULL;
166 mFunc = NULL;
167 FuncChanged();
168 return *this;
169}
170
171//! Spécifie la fonction à intégrer, sous forme double f(double).
172Integrator&
173Integrator::SetFunc(FUNC f)
174{
175 mFunc = f;
176 mClFun = NULL;
177 mGFFParm = NULL;
178 mFunc = NULL;
179 FuncChanged();
180 return *this;
181}
182
183/*!
184 \brief Spécifie la fonction à intégrer, sous forme de GeneralFunction
185 à une variable, et les paramètres sont fournis.
186*/
187Integrator&
188Integrator::SetFunc(GeneralFunction* gff, double* par)
189{
190 mGFF = gff;
191 mGFFParm = par;
192 mFunc = NULL;
193 ASSERT(gff->NVar() == 1);
194 FuncChanged();
195 return *this;
196}
197
198double
199Integrator::FVal(double x) const
200{
201 ASSERT( mFunc || mClFun || (mGFF && mGFFParm) );
202 if (mFunc) return mFunc(x);
203 else return mClFun ? (*mClFun)(x) : mGFF->Value(&x, mGFFParm);
204}
205
206double
207Integrator::ValueBetween(double xmin, double xmax)
208{
209 Limits(xmin,xmax);
210 return Value();
211}
212
213void
214Integrator::Print(int lp)
215{
216 cout<<"Integrator between "<<mXMin<<" and "<<mXMax
217 <<" in "<<mNStep<<" steps"<<endl;
218 if(lp>1) cout<<"mFunc="<<mFunc<<"mClFun="<<mClFun<<"mGFF="<<mGFF
219 <<"mReqPrec="<<mReqPrec<<"mDX="<<mDX<<endl;
220}
221
222/*!
223 \ingroup NTools
224 \class SOPHYA::TrpzInteg
225
226 \brief Implementation de Integrator par la methode des trapezes.
227
228 Classe d'intégration par la méthode des trapèzes.
229 Voir Integrator pour les méthodes. Le nombre de pas
230 est le nombre de trapèze, le pas d'intégration est
231 la largeur des trapèzez. Impossible de demander une
232 précision.
233
234 \sa SOPHYA::Integrator
235*/
236
237
238TrpzInteg::TrpzInteg()
239{}
240
241TrpzInteg::TrpzInteg(ClassFunc & f, double xmin, double xmax)
242: Integrator(f, xmin, xmax)
243{}
244
245TrpzInteg::TrpzInteg(FUNC f, double xmin, double xmax)
246: Integrator(f, xmin, xmax)
247{}
248
249TrpzInteg::TrpzInteg(ClassFunc & f)
250: Integrator(f)
251{}
252
253TrpzInteg::TrpzInteg(FUNC f)
254: Integrator(f)
255{}
256
257TrpzInteg::TrpzInteg(GeneralFunction* gff, double* par, double xmin, double xmax)
258: Integrator(gff, par, xmin, xmax)
259{}
260
261TrpzInteg::TrpzInteg(GeneralFunction* gff, double* par)
262: Integrator(gff, par)
263{}
264
265TrpzInteg::~TrpzInteg()
266{}
267
268//! Return the value of the integral.
269double
270TrpzInteg::Value()
271{
272 double dx = mDX;
273 double nstep = mNStep;
274
275 if (dx > 0)
276 nstep = (mXMax - mXMin)/dx;
277
278 if (nstep <= 0)
279 nstep = 10;
280
281 dx = (mXMax - mXMin) / nstep;
282
283 double s = (FVal(mXMin) + FVal(mXMax))/2;
284 double x = dx + mXMin;
285 for (int i=1; i<nstep; i++, x += dx)
286 s += FVal(x);
287
288 return s * dx;
289}
290
291
292
293/*!
294 \ingroup NTools
295 \class SOPHYA::GLInteg
296
297 \brief Implementation de Integrator par la methode de Gauss-Legendre.
298
299 Classe d'intégration par la méthode de Gauss-Legendre.
300 Voir Integrator pour les méthodes.
301 Pour le moment, nstep est l'ordre de la méthode.
302 Il est prévu un jour de spécifier l'ordre, et que NStep
303 découpe en intervalles sur chacun desquels on applique GL.
304 Le principe de la méthode est de calculer les valeurs de la
305 fonction aux zéros des polynomes de Legendre. Avec les poids
306 qui vont bien, GL d'ordre n est exacte pour des polynomes de
307 degré <= 2n+1 (monome le + haut x^(2*n-1).
308 Impossible de demander une précision donnée.
309
310 \sa SOPHYA::Integrator
311
312 \warning statut EXPERIMENTAL , NON TESTE
313*/
314
315
316
317GLInteg::GLInteg()
318: mXPos(NULL), mWeights(NULL)
319{}
320
321
322GLInteg::GLInteg(ClassFunc & f, double xmin, double xmax)
323: Integrator(f, xmin, xmax), mXPos(NULL), mWeights(NULL), mOrder(8)
324{
325 NStep(1);
326}
327
328GLInteg::GLInteg(FUNC f, double xmin, double xmax)
329: Integrator(f, xmin, xmax), mXPos(NULL), mWeights(NULL), mOrder(8)
330{
331 NStep(1);
332}
333
334GLInteg::GLInteg(ClassFunc & f)
335: Integrator(f), mXPos(NULL), mWeights(NULL), mOrder(8)
336{
337 NStep(1);
338}
339
340GLInteg::GLInteg(FUNC f)
341: Integrator(f), mXPos(NULL), mWeights(NULL), mOrder(8)
342{
343 NStep(1);
344}
345
346GLInteg::GLInteg(GeneralFunction* gff, double* par, double xmin, double xmax)
347: Integrator(gff, par, xmin, xmax), mXPos(NULL), mWeights(NULL), mOrder(8)
348{
349 NStep(1);
350}
351
352GLInteg::GLInteg(GeneralFunction* gff, double* par)
353: Integrator(gff, par), mXPos(NULL), mWeights(NULL), mOrder(8)
354{
355 NStep(1);
356}
357
358GLInteg::~GLInteg()
359{
360 if(mXPos) delete[] mXPos; mXPos = NULL;
361 if(mWeights) delete[] mWeights; mWeights = NULL;
362}
363
364void
365GLInteg::InvalWeights()
366{
367 if(mXPos) delete[] mXPos; mXPos = NULL;
368 if(mWeights) delete[] mWeights; mWeights = NULL;
369}
370
371
372void
373GLInteg::LimitsChanged()
374{
375 ComputeBounds();
376}
377
378void
379GLInteg::StepsChanged()
380{
381 ComputeBounds();
382}
383
384GLInteg&
385GLInteg::AddBound(double x)
386{
387 if (x<=mXMin || x>=mXMax) throw RangeCheckError("GLInteg::AddBound()") ;
388 // On introduira les classes d'exections apres reflexion et de maniere systematique (Rz+cmv)
389 // if (x<=mXMin || x>=mXMax) throw range_error("GLInteg::AddBound bound outside interval");
390 mBounds.insert(x);
391 return *this;
392}
393
394
395//! Definit l'ordre de la methode d'integration Gauus-Legendre
396GLInteg&
397GLInteg::SetOrder(int order)
398{
399 mOrder = order;
400 InvalWeights();
401 return *this;
402}
403
404
405//! Retourne la valeur de l'integrale
406double
407GLInteg::Value()
408{
409 if (!mXPos) ComputeWeights();
410 double s = 0;
411 set<double>::iterator i=mBounds.begin();
412 set<double>::iterator j=i; j++;
413 while (j != mBounds.end()) {
414 double s1 = 0;
415 double x1 = *i;
416 double x2 = *j;
417 for(int k=0; k<mOrder; k++)
418 s1 += mWeights[k] * FVal(x1 + (x2-x1)*mXPos[k]);
419 s += s1*(x2-x1);
420 i++; j++;
421 }
422 return s;
423}
424
425void
426GLInteg::ComputeBounds()
427{
428 mBounds.erase(mBounds.begin(), mBounds.end());
429 for (int i=0; i<=mNStep; i++)
430 mBounds.insert(mXMin + (mXMax-mXMin)*i/mNStep);
431}
432
433void
434GLInteg::ComputeWeights()
435{
436 const double EPS_gauleg = 5.0e-12;
437
438 int m=(mOrder+1)/2;
439 const double xxMin = 0;
440 const double xxMax = 1;
441
442 mXPos = new double[mOrder];
443 mWeights = new double[mOrder];
444
445 double xm=0.5*(xxMax+xxMin);
446 double xl=0.5*(xxMax-xxMin);
447 for (int i=1;i<=m;i++) {
448 double z=cos(3.141592654*(i-0.25)/(mOrder+0.5));
449 double z1, pp;
450 do {
451 double p1=1.0;
452 double p2=0.0;
453 for (int j=1;j<=mOrder;j++) {
454 double p3=p2;
455 p2=p1;
456 p1=((2.0*j-1.0)*z*p2-(j-1.0)*p3)/j;
457 }
458 pp=mOrder*(z*p1-p2)/(z*z-1.0);
459 z1=z;
460 z=z1-p1/pp;
461 } while (fabs(z-z1) > EPS_gauleg);
462 mXPos[i-1] = xm-xl*z;
463 mXPos[mOrder-i] = xm+xl*z;
464 mWeights[i-1] = 2.0*xl/((1.0-z*z)*pp*pp);
465 mWeights[mOrder-i] = mWeights[i-1];
466 }
467
468}
469
470//! Imprime l'ordre et la valeur des poids sur cout
471void
472GLInteg::Print(int lp)
473{
474 Integrator::Print(lp);
475 cout<<"GLInteg order="<<mOrder<<endl;
476 if(lp>0 && mOrder>0) {
477 for(int i=0;i<mOrder;i++)
478 cout<<" ("<<mXPos[i]<<","<<mWeights[i]<<")";
479 cout<<endl;
480 }
481}
Note: See TracBrowser for help on using the repository browser.