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

Last change on this file since 2615 was 2615, checked in by cmv, 21 years ago

using namespace sophya enleve de machdefs.h, nouveau sopnamsp.h cmv 10/09/2004

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