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

Last change on this file since 852 was 514, checked in by ansari, 26 years ago

elimination des OVector/OMatrix au profit des TVector/TMatrix cmv 25/10/99

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