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

Last change on this file since 3002 was 2808, checked in by ansari, 20 years ago

MAJ documentation - Reza 14/6/2005

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