source: Sophya/trunk/SophyaLib/NTools/difeq.cc@ 4030

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

MAJ documentation - Reza 14/6/2005

File size: 13.9 KB
Line 
1#include "sopnamsp.h"
2#include "difeq.h"
3#include "ctimer.h"
4
5/*!
6 \ingroup NTools
7 \class SOPHYA::DiffEqSolver
8 \brief Classe abstraite de résolveur d'équation différentielles.
9
10 Beaucoup de méthodes renvoient l'objet afin de pouvoir
11 utiliser une notation chaînée du type:
12
13 s.Step(...).Start(...).Solve(...)
14
15 \warning statut EXPERIMENTAL , NON TESTE
16
17 \sa SOPHYA::DiffEqFunction
18 \sa SOPHYA::RK4DiffEq SOPHYA::RK4CDiffEq
19*/
20
21//! Constructeur vide.
22DiffEqSolver::DiffEqSolver()
23: mFunc(NULL), mOwnFunc(false),
24 mYStart(1), mXStart(0), mStep(0.01)
25{}
26
27//! Constructeur général. L'équation est donnée sous forme de DiffEqFunction
28DiffEqSolver::DiffEqSolver(DiffEqFunction* f)
29: mFunc(f), mOwnFunc(false),
30 mYStart(mFunc->NFuncReal()), mXStart(0), mStep(0.01)
31{}
32
33/*!
34 Constructeur pour le cas particulier d'une équation du premier
35 ordre. Voir DiffEqFcn1. La fonction f correspond à l'équation
36 y' = f(y).
37*/
38DiffEqSolver::DiffEqSolver(DIFEQFCN1 f)
39: mFunc(new DiffEqFcn1(f)), mOwnFunc(true),
40 mYStart(mFunc->NFuncReal()), mXStart(0), mStep(0.01)
41{}
42
43DiffEqSolver::~DiffEqSolver()
44{
45 if (mOwnFunc) delete mFunc;
46}
47
48
49/*!
50 Permet de spécifier l'équation différentielle, sous la forme
51 d'une DiffEqFunction. Retourne l'objet DiffEqSolver : notation
52 chaînée possible
53*/
54DiffEqSolver&
55DiffEqSolver::Func(DiffEqFunction* f)
56{
57 if (mFunc && mOwnFunc) delete mFunc;
58 mFunc = f;
59 mOwnFunc = false;
60 return *this;
61}
62
63/*!
64 Permet de spécifier l'équation différentielle, sous la forme
65 d'une fonction f telle que y' = f(y). Retourne l'objet DiffEqSolver :
66 notation chaînée possible.
67*/
68DiffEqSolver&
69DiffEqSolver::Func(DIFEQFCN1 f)
70{
71 if (mFunc && mOwnFunc) delete mFunc;
72 mFunc = new DiffEqFcn1(f);
73 mOwnFunc = true;
74 return *this;
75}
76
77/*!
78 Spécifie le pas d'intégration de l'équation différentielle (pour
79 les méthodes où ce pas a un sens). La valeur par défaut est 0.01.
80 Retourne l'objet DiffEqSolver : notation chaînée possible.
81*/
82DiffEqSolver&
83DiffEqSolver::Step(double step)
84{
85 mStep = step;
86 return *this;
87}
88
89
90/*!
91 Spécifie le point de départ de l'intégration de l'équadif.
92 Le vecteur \b y contient les valeurs intiales. Voir la description
93 de chaque fonction-objet-équation différentielle pour connaître
94 le rôle de chaque élément du vecteur. \b t est la valeur initiale
95 du temps.
96 La dimension de y doit correspondre au nombre apparent de fonctions.
97 Retourne l'objet DiffEqSolver : notation chaînée possible.
98*/
99DiffEqSolver&
100DiffEqSolver::StartV(Vector const& yi, double t)
101{
102 ASSERT(mFunc != NULL);
103 ASSERT(yi.NElts() == mFunc->NFunc()); // Nombre apparent
104 mYStart = yi;
105 mXStart = t;
106 mFunc->AdjustStart(mYStart,t);
107 ASSERT(mYStart.NElts() == mFunc->NFuncReal());
108 return *this;
109}
110
111/*!
112 Spécifie le point de départ de l'intégration de l'équadif,
113 pour une équation y' = f(y). On donne le temps et la valeur de y.
114 Retourne l'objet DiffEqSolver : notation chaînée possible.
115*/
116DiffEqSolver&
117DiffEqSolver::Start1(double y, double t)
118{
119 ASSERT(mFunc != NULL);
120 ASSERT(mFunc->NFunc() == 1); // Nombre apparent
121 mYStart.Realloc(1);
122 mYStart(0) = y;
123 mXStart = t;
124 mFunc->AdjustStart(mYStart,t);
125 ASSERT(mYStart.NElts() == mFunc->NFuncReal());
126 return *this;
127}
128
129
130/*!
131 Spécifie le point de départ de l'intégration de l'équadif.
132 Le tableau \b yi contient les valeurs intiales. Voir la description
133 de chaque fonction-objet-équation différentielle pour connaître
134 le rôle de chaque élément du tableau. t est la valeur initiale
135 du temps.
136 Le nombre d'éléments de yi doit correspondre au nombre apparent
137 de fonctions.
138 Retourne l'objet DiffEqSolver : notation chaînée possible.
139*/
140DiffEqSolver&
141DiffEqSolver::Start(double const* yi, double t)
142{
143 mYStart.Realloc(mFunc->NFunc());
144 for (int i=0; i<mFunc->NFunc(); i++)
145 mYStart(i) = yi[i];
146 mXStart = t;
147 mFunc->AdjustStart(mYStart,t);
148 ASSERT(mYStart.NElts() == mFunc->NFuncReal());
149 return *this;
150}
151
152/*!
153 \fn virtual void DiffEqSolver::SolveArr(Matrix& y, double* t, double tf, int n)
154
155 Lance la résolution de l'équadif, jusqu'à la valeur
156 tf du temps. N valeurs intermédiaires sont retournées dans
157 les tableaux y et t :
158 - t[i] est le temps au pas i, pour 0<=i<n
159 - y[i] sont les valeurs des fonctions au pas i.
160
161 Voir la description
162 de chaque fonction-objet-équation différentielle pour connaître
163 le rôle de chaque élément de y[i].
164 t[n-1] vaut tf.
165 Le nombre d'éléments de y[i] doit correspondre au nombre apparent
166 de fonctions.
167 Cette fonction doit être redéfinie pour chaque méthode de résolution
168 d'équations. Elle est appelée par toutes les autres fonctions de
169 résolution (autres SolveArr, et Solve).
170*/
171
172
173/*!
174 Lance la résolution de l'équadif, jusqu'à la valeur
175 tf du temps. Les valeurs finales sont retournées dans yf.
176 Voir la description
177 de chaque fonction-objet-équation différentielle pour connaître
178 le rôle de chaque élément de yf.
179 Le nombre d'éléments de yf doit correspondre au nombre apparent
180 de fonctions.
181*/
182void
183DiffEqSolver::SolveV(Vector& yf, double tf)
184{
185 double t;
186 Matrix m(1, mFunc->NFuncReal());
187 SolveArr(m, &t, tf, 1);
188 yf.Realloc(mFunc->NFunc());
189 for (int i=0; i<mFunc->NFunc(); i++)
190 yf(i) = m(0,i);
191}
192
193
194/*!
195 Lance la résolution de l'équadif, jusqu'à la valeur
196 tf du temps, pour une équation du premier ordre y' = f(y).
197 La valeur finale de y est retournée dans yf.
198*/
199void
200DiffEqSolver::Solve1(double& yf, double tf)
201{
202 ASSERT(mFunc->NFunc() == 1);
203 double t;
204 Matrix m(1,mFunc->NFuncReal());
205 SolveArr(m, &t, tf, 1);
206 yf = m(0,0);
207}
208
209
210/*!
211 Lance la résolution de l'équadif, jusqu'à la valeur
212 tf du temps. Les valeurs finales sont retournées dans yf.
213 Voir la description
214 de chaque fonction-objet-équation différentielle pour connaître
215 le rôle de chaque élément de yf.
216 Le nombre d'éléments de yf doit correspondre au nombre apparent
217 de fonctions.
218*/
219void
220DiffEqSolver::Solve(double* yf, double tf)
221{
222 double t;
223 Matrix m(1, mFunc->NFuncReal());
224 SolveArr(m, &t, tf, 1);
225 for (int i=0; i<mFunc->NFunc(); i++)
226 yf[i] = m(0,i);
227}
228
229/*!
230 Lance la résolution de l'équadif (du premier ordre), jusqu'à la valeur
231 tf du temps. N valeurs intermediaires sont retournées dans
232 les tableaux y et t :
233 t[i] est le temps au pas i, pour 0<=i<n
234 y[i] est la valeur de la fonction au pas i.
235 t[n-1] vaut tf.
236*/
237void
238DiffEqSolver::SolveArr1(double* y, double* t, double tf, int n)
239
240{
241 ASSERT(mFunc->NFunc() == 1);
242 Matrix m(n, mFunc->NFuncReal());
243 SolveArr(m, t, tf, n);
244 for (int i=0; i<n; i++)
245 y[i] = m(i,0);
246}
247
248/*!
249 Lance la résolution de l'équadif, jusqu'à la valeur
250 tf du temps. N valeurs intermédiaires sont retournées dans
251 les tableaux y et t :
252 t[i] est le temps au pas i, pour 0<=i<n
253 y[i] sont les valeurs des fonctions au pas i.
254 Voir la description
255 de chaque fonction-objet-équation différentielle pour connaître
256 le rôle de chaque élément de y[i].
257 t[n-1] vaut tf.
258 Le nombre d'éléments de y[i] doit correspondre au nombre apparent
259 de fonctions.
260*/
261void
262DiffEqSolver::SolveArr2(double** y, double* t, double tf, int n)
263{
264 Matrix m(n, mFunc->NFuncReal());
265 SolveArr(m, t, tf, n);
266 for (int i=0; i<n; i++)
267 for (int j=0; j<mFunc->NFunc(); j++)
268 y[i][j] = m(i,j);
269}
270
271
272/*!
273 \ingroup NTools
274 \class SOPHYA::DiffEqFunction
275
276 \brief Classe de fonctions pour la résolution d'équations différentielles.
277
278 On résoud de facon générale un système de n équations différentielles
279 du premier ordre, donnant les dérivées fpi de n fonctions fi.
280 Cette méthode permet de résoudre toutes les sortes d'équations :
281 pour une équation du second ordre on crée une fonction intermédiaire
282 qui est la dérivée de la fonction cherchée.
283
284 \warning statut EXPERIMENTAL , NON TESTE
285
286 \sa SOPHYA::DiffEqSolver
287*/
288
289
290
291/*!
292 \fn DiffEqFunction::DiffEqFunction(int n, int napp)
293 Constructeur. N est le nombre réel de fonctions dans le
294 système, et napp le nombre apparent (pour l'utilisateur).
295 En effet, dans certains cas, on peut avoir besoin de fonctions
296 supplémentaires masquées à l'utilisateur, par exemple la fonction
297 constante valant 1, si l'équadif fait intervenir le temps (t).
298*/
299
300/*!
301 \fn virtual void ComputeV(Vector& fpi, Vector const& fi)
302 Calcule les valeurs des dérivées fpi à partir des valeurs
303 des fonctions fi. A redéfinir.
304*/
305
306/*!
307 \fn virtual void Compute(double& fp, double f)
308 Dans le cas où il y a une seule fonction, calcule la dérivée
309 fp à partir de la valeur de la fonction f. A redéfinir.
310*/
311
312
313//++
314// virtual void AdjustStart(Vector& start, double tstart)
315// Pour ajuster le vecteur de départ quand il y a des
316// fonctions à usage interne...
317//--
318
319
320
321/*!
322 \ingroup NTools
323 \class SOPHYA::DiffEqFcn1
324
325 \brief Objet-fonction générique pour la résolution d'équations
326 différentielles de la forme y' = f(y).
327
328 On fournit une fonction de type <br>
329 <tt> typedef double(*DIFEQFCN1)(double); </tt> <br>
330 qui retourne y' en fonction de y.
331
332 \warning statut EXPERIMENTAL , NON TESTE
333*/
334
335
336//! Constructeur. On fournit la fonction f tq y'=f(y)
337DiffEqFcn1::DiffEqFcn1(DIFEQFCN1 fcn)
338: DiffEqFunction(1), mFcn(fcn)
339{}
340
341
342//! Implementation de Compute qui va utiliser la fonction fournie au constructeur.
343void
344DiffEqFcn1::Compute(double& fp, double f)
345{
346 fp = (*mFcn)(f);
347}
348
349/*!
350 \ingroup NTools
351 \class SOPHYA::DiffEqFcnT1
352
353 Objet-fonction générique pour la résolution d'équations
354 différentielles de la forme y' = f(y,t).
355 On fournit une fonction de type
356 <tt> typedef \tt double(*DIFEQFCNT1)(double, double); </tt>
357 qui retourne y' en fonction de y et t.
358
359 \verbatim
360 Note : le système résolu est alors en fait
361 y'[0] = fcn(y[0], y[1])
362 y'[1] = 1
363 \endverbatim
364
365 \warning statut EXPERIMENTAL , NON TESTE
366*/
367
368//! Constructeur. On fournit la fonction f tq y' = f(y,t)
369DiffEqFcnT1::DiffEqFcnT1(DIFEQFCNT1 fcn)
370: DiffEqFunction(2, 1), mFcn(fcn)
371{}
372
373void
374DiffEqFcnT1::ComputeV(Vector& fpi, Vector const& fi)
375{
376 fpi(0) = (*mFcn)(fi(0), fi(1));
377 fpi(1) = 1;
378}
379
380void
381DiffEqFcnT1::AdjustStart(Vector& start, double tstart)
382{
383 start.Realloc(2);
384 start(1) = tstart;
385}
386
387/*!
388 \ingroup NTools
389 \class SOPHYA::DiffEqFcn2
390
391 Objet-fonction générique pour la résolution d'équations
392 différentielles de la forme y'' = f(y',y).
393 On fournit une fonction de type
394 <tt> typedef double(*DIFEQFCN2)(double, double); </tt>
395 qui retourne y'' en fonction de y' et y.
396 \verbatim
397 Note : le système résolu est en fait
398 y'[0] = y[1]
399 y'[1] = f(y[1], y[0])
400 \endverbatim
401
402 \warning statut EXPERIMENTAL , NON TESTE
403*/
404
405//! Constructeur. On fournit la fonction f tq y''=f(y',y)
406DiffEqFcn2::DiffEqFcn2(DIFEQFCN2 fcn)
407: DiffEqFunction(2), mFcn(fcn)
408{}
409
410void
411DiffEqFcn2::ComputeV(Vector& fpi, Vector const& fi)
412{
413 fpi(0) = fi(1);
414 fpi(1) = (*mFcn)(fi(1), fi(0));
415}
416
417/*!
418 \ingroup NTools
419 \class SOPHYA::DiffEqFcnT2
420
421 Objet-fonction générique pour la résolution d'équations
422 différentielles de la forme y'' = f(y',y,t).
423 On fournit une fonction de type <br>
424 <tt> typedef double(*DIFEQFCNT2)(double, double, double); </tt> <br>
425 qui retourne y'' en fonction de y', y et t.
426 \verbatim
427 Note : le système résolu est alors en fait
428 y'[0] = y[1]
429 y'[1] = f(y[1], y[0], y[2])
430 y'[2] = 1
431 \endverbatim
432
433 \warning statut EXPERIMENTAL , NON TESTE
434*/
435
436//! Constructeur. On fournit la fonction f tq y'' = f(y',y,t)
437DiffEqFcnT2::DiffEqFcnT2(DIFEQFCNT2 fcn)
438: DiffEqFunction(3,2), mFcn(fcn)
439{}
440
441void
442DiffEqFcnT2::ComputeV(Vector& fpi, Vector const& fi)
443{
444 fpi(0) = fi(1);
445 fpi(1) = (*mFcn)(fi(1), fi(0), fi(2));
446 fpi(2) = 1;
447}
448
449void
450DiffEqFcnT2::AdjustStart(Vector& start, double tstart)
451{
452 start.Realloc(3);
453 start(2) = tstart;
454}
455
456
457/*!
458 \ingroup NTools
459 \class SOPHYA::DiffEqFcnV
460
461 Objet-fonction générique pour la résolution d'équations
462 différentielles 3D de la forme y'' = f(y',y), ou y est
463 un vecteur de dimension 3.
464 On fournit une fonction de type <br>
465 <tt> typedef void(*DIFEQFCNV)(Vector& y2, Vector const& y1, <br>
466 Vector const& y); </tt> <br>
467 qui retourne y'' en fonction de y' et y.
468 \verbatim
469 Note : le système résolu est alors en fait
470 v(0-2) = y, v(3-5) = y'
471
472 v'[0] = v[3]
473 v'[1] = v[4]
474 v'[2] = v[5]
475 v'[3-5] = f(v[3-5], v[0-2])
476 \endverbatim
477
478 \warning statut EXPERIMENTAL , NON TESTE
479*/
480
481DiffEqFcnV::DiffEqFcnV(DIFEQFCNV fcn)
482: DiffEqFunction(6), mFcn(fcn),
483 tmp1(3), tmp2(3), tmp3(3)
484{}
485
486void
487DiffEqFcnV::ComputeV(Vector& fpi, Vector const& fi)
488{
489 fpi(0) = fi(3);
490 fpi(1) = fi(4);
491 fpi(2) = fi(5);
492
493 tmp2(0) = fi(3); tmp2(1) = fi(4); tmp2(2) = fi(5);
494 tmp3(0) = fi(0); tmp3(1) = fi(1); tmp3(2) = fi(2);
495
496 (*mFcn)(tmp1, tmp2, tmp3);
497
498 fpi(3) = tmp1(0); fpi(4) = tmp1(1); fpi(5) = tmp1(2);
499}
500
501
502/*!
503 \ingroup NTools
504 \class SOPHYA::RK4DiffEq
505
506 Classe de résolution d'équadif par la méthode de
507 Runge-Kutta d'ordre 4.
508 Voir DiffEqSolver pour les méthodes.
509
510 \warning statut EXPERIMENTAL , NON TESTE
511*/
512
513RK4DiffEq::RK4DiffEq()
514: DiffEqSolver(), k1(10), k2(10), k3(10), k4(10)
515{}
516
517//! Constructeur général
518RK4DiffEq::RK4DiffEq(DiffEqFunction* f)
519: DiffEqSolver(f), k1(f->NFuncReal()),
520 k2(f->NFuncReal()), k3(f->NFuncReal()), k4(f->NFuncReal())
521{}
522
523
524//! Constructeur pour y' = f(y)
525RK4DiffEq::RK4DiffEq(DIFEQFCN1 f)
526: DiffEqSolver(f), k1(1), k2(1), k3(1), k4(1)
527{}
528
529void
530RK4DiffEq::SolveArr(Matrix& y, double* t, double tf, int n)
531{
532 //TIMEF;
533 // On calcule le nombre de sous-pas par pas
534
535 int nStep = (mStep > 0) ? int((tf - mXStart)/n/mStep) : 1;
536 if (nStep <= 1) nStep = 1;
537
538 double dx = (tf - mXStart)/(n*nStep);
539
540 Vector yt(mYStart,false);
541
542 k1.Realloc(mFunc->NFuncReal());
543 k2.Realloc(mFunc->NFuncReal());
544 k3.Realloc(mFunc->NFuncReal());
545 k4.Realloc(mFunc->NFuncReal());
546
547
548 for (int i=0; i<n; i++) {
549 for (int j=0; j<nStep; j++)
550 RKStep(yt, yt, dx);
551 for (int k=0; k<mFunc->NFunc(); k++)
552 y(i,k) = yt(k);
553 t[i] = (i+1)*dx*nStep + mXStart;
554 }
555}
556
557void
558RK4DiffEq::RKStep(Vector& newY, Vector const& y0, double dt)
559{
560 mFunc->ComputeV(k1, y0);
561 k1 *= dt;
562 mFunc->ComputeV(k2, y0 + k1/2.);
563 k2 *= dt;
564 mFunc->ComputeV(k3, y0 + k2/2.);
565 k3 *= dt;
566 mFunc->ComputeV(k4, y0 + k3);
567 k4 *= dt;
568
569 newY = y0 + (k1 + k2*2. + k3*2. + k4)/6.;
570}
571
Note: See TracBrowser for help on using the repository browser.