// This file is part of the Herezh++ application. // // The finite element software Herezh++ is dedicated to the field // of mechanics for large transformations of solid structures. // It is developed by Gérard Rio (APP: IDDN.FR.010.0106078.000.R.P.2006.035.20600) // INSTITUT DE RECHERCHE DUPUY DE LÔME (IRDL) . // // Herezh++ is distributed under GPL 3 license ou ultérieure. // // Copyright (C) 1997-2022 Université Bretagne Sud (France) // AUTHOR : Gérard Rio // E-MAIL : gerardrio56@free.fr // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // See the GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . // // For more information, please consult: . #ifndef Algo_edp_deja_inclus #include "Algo_edp.h" #endif // --- include pour rkf45 --- # include # include # include # include # include // --- fin include pour rkf45 --- // contient que les méthodes nécessitant les templates, qui doivent donc être //incluses dans le .h #ifndef Algo_edp_deja_inclus #include "MathUtil.h" #include "ConstMath.h" static double remin = 1.0E-12; // ----- cas d'un système d'edp du premier ordre---- , // résolution par runge kutta imbriqué --> estimation d'erreur // il y a 3 calcul de la fonction dérivée // 2 et 3 ième ordre imbriquée // calcul de la solution à t+dt en fonction de la solution à t, // en entrée: // *Ptder_fonc : pointeur de la fonction de calcul de la dérivées // en entrée: t et f : temps et la valeur de la fonction a t // en sortie: df : dérivée de la fonction a t // erreur : si diff de 0, indique qu'il y a eu une erreur // *Ptverif_fonc : pointeur de fonction, pour tester val_finale après la prédiction explicite finale // // val_initiale : valeur des fonctions en t0 // der_initiale : valeur de la dérivée pour t0 // t0 : temps initiale // deltat : incrément de temps demandé // en sortie : // val_finale : valeur des fonctions à tdt // estime_erreur : estimation d'erreur pour chaque fonction template void Algo_edp::Runge_Kutta_step23(T& instance ,Vecteur& (T::*Ptder_fonc) (const double & t,const Vecteur& f,Vecteur& df,int& erreur) ,void (T::*Ptverif_fonc) (const double & t,const Vecteur& f,int& erreur_final) ,const Vecteur& val_initiale,const Vecteur& der_initiale ,const double& t0,const double& deltat ,Vecteur& val_finale,Vecteur& estime_erreur) {// récup de la dimension int taille = val_initiale.Taille(); int erreur=0; // init de l'indicateur d'erreur dans le calcul de la fonction // vérif de la dimmension if (taille != k2.Taille()) { k2.Change_taille(taille);k3.Change_taille(taille); // val_finale.Change_taille(taille); }; // -- premier incrément val_finale = val_initiale + (deltat * bb21) * der_initiale; //// --- debug --- //cout << "\n Algo_edp::Runge_Kutta_step23(.. avant appel " // << "\n val_initiale= ";val_initiale.Affiche(); //cout << " der_initiale= "; der_initiale.Affiche(); //cout << " val_finale= "; val_finale.Affiche(); //cout << "\n t0= "<< t0 << ", deltat= "<< deltat<< ", t0+aa2*deltat= "<< (t0+aa2*deltat); //cout << endl; //// --- fin debug --- // appel de la dérivée pour le premier incrément (instance.*Ptder_fonc) (t0+aa2*deltat,val_finale,k2,erreur); k2 *= deltat; //// --- debug --- //cout << "\n Algo_edp::Runge_Kutta_step23(.. après appel " // << "\n k2= ";k2.Affiche(); //cout << endl; //// --- fin debug --- if (erreur) // cas où le calcul n'est pas licite { estime_erreur.Inita(ConstMath::tresgrand); // on indique une erreur monstrueuse val_finale = val_initiale; // on retourne la valeur initiale return; }; // -- deuxième incrément val_finale = val_initiale + (deltat*bb31) * der_initiale + bb32 * k2; // appel de la dérivée pour le deuxième incrément (aa3=1.) (instance.*Ptder_fonc) (t0+deltat,val_finale,k3,erreur); k3 *= deltat; if (erreur) // cas où le calcul n'est pas licite { estime_erreur.Inita(ConstMath::tresgrand); // on indique une erreur monstrueuse val_finale = val_initiale; // on retourne la valeur initiale return; }; // somme pondéré des incréments val_finale = val_initiale + (deltat*AB1)*der_initiale+AB2*k2+AB3*k3; // estimation de l'erreur comme différence entre les méthodes du quatrième // et cinquième ordre estime_erreur = (deltat*dA1)*der_initiale+dA2*k2+dA3*k3; // on vérifie que la solution finale est licite (instance.*Ptverif_fonc) (t0+deltat,val_finale,erreur); if (erreur) // cas où le calcul n'est pas licite { estime_erreur.Inita(ConstMath::tresgrand); // on indique une erreur monstrueuse val_finale = val_initiale; // on retourne la valeur initiale return; }; //// --- debug --- //cout << "\n Algo_edp::Runge_Kutta_step23(.. à la fin, tout c'est bien passée " // << "\n val_finale= ";val_finale.Affiche(); //cout << " estime_erreur= "; estime_erreur.Affiche(); //cout << "\n t0+deltat= "<< t0+deltat ; //cout << endl; //// --- fin debug --- } // résolution par runge kutta imbriqué --> estimation d'erreur // il y a 4 calcul de la fonction dérivée // 3 et 4 ième ordre imbriquée (Fehlberg) // calcul de la solution à t+dt en fonction de la solution à t, // en entrée: // *Ptder_fonc : pointeur de la fonction de calcul de la dérivées // en entrée: t et f : temps et la valeur de la fonction a t // en sortie: df : dérivée de la fonction a t // erreur : si diff de 0, indique qu'il y a eu une erreur // *Ptverif_fonc : pointeur de fonction, pour tester val_finale après la prédiction explicite finale // // val_initiale : valeur des fonctions en t0 // der_initiale : valeur de la dérivée pour t0 // t0 : temps initiale // deltat : incrément de temps demandé // en sortie : // val_finale : valeur des fonctions à tdt // estime_erreur : estimation d'erreur pour chaque fonction template void Algo_edp::Runge_Kutta_step34(T& instance ,Vecteur& (T::*Ptder_fonc) (const double & t,const Vecteur& f,Vecteur& df,int& erreur) ,void (T::*Ptverif_fonc) (const double & t,const Vecteur& f,int& erreur_final) ,const Vecteur& val_initiale,const Vecteur& der_initiale ,const double& t0,const double& deltat ,Vecteur& val_finale,Vecteur& estime_erreur) {// récup de la dimension int taille = val_initiale.Taille(); int erreur=0; // init de l'indicateur d'erreur dans le calcul de la fonction // vérif de la dimmension if (taille != k2.Taille()) { k2.Change_taille(taille);k3.Change_taille(taille); k4.Change_taille(taille),k5.Change_taille(taille); // val_finale.Change_taille(taille); }; // -- premier incrément val_finale = val_initiale + (deltat * b_b21) * der_initiale; // appel de la dérivée pour le premier incrément (instance.*Ptder_fonc) (t0+a_a2*deltat,val_finale,k2,erreur); k2 *= deltat; if (erreur) // cas où le calcul n'est pas licite { estime_erreur.Inita(ConstMath::tresgrand); // on indique une erreur monstrueuse val_finale = val_initiale; // on retourne la valeur initiale return; }; // -- deuxième incrément val_finale = val_initiale + (deltat * b_b31) * der_initiale + b_b32* k2; // appel de la dérivée pour le deuxième incrément (instance.*Ptder_fonc) (t0+a_a3*deltat,val_finale,k3,erreur); k3 *= deltat; if (erreur) // cas où le calcul n'est pas licite { estime_erreur.Inita(ConstMath::tresgrand); // on indique une erreur monstrueuse val_finale = val_initiale; // on retourne la valeur initiale return; }; // -- troisième incrément val_finale = val_initiale + (deltat*b_b41)*der_initiale+b_b42*k2+b_b43*k3; // appel de la dérivée pour le troisième incrément (instance.*Ptder_fonc) (t0+a_a4*deltat,val_finale,k4,erreur); k4 *= deltat; if (erreur) // cas où le calcul n'est pas licite { estime_erreur.Inita(ConstMath::tresgrand); // on indique une erreur monstrueuse val_finale = val_initiale; // on retourne la valeur initiale return; }; // -- quatrième incrément val_finale = val_initiale + (deltat*b_b51)*der_initiale+b_b53*k3+b_b54*k4; // appel de la dérivée pour le quatrième incrément (instance.*Ptder_fonc) (t0+a_a5*deltat,val_finale,k5,erreur); k5 *= deltat; if (erreur) // cas où le calcul n'est pas licite { estime_erreur.Inita(ConstMath::tresgrand); // on indique une erreur monstrueuse val_finale = val_initiale; // on retourne la valeur initiale return; }; // somme pondéré des incréments val_finale = val_initiale + (deltat*A_B1)*der_initiale+A_B3*k3+A_B4*k4+A_B5*k5; // on vérifie que la solution finale est licite (instance.*Ptverif_fonc) (t0+deltat,val_finale,erreur); if (erreur) // cas où le calcul n'est pas licite { estime_erreur.Inita(ConstMath::tresgrand); // on indique une erreur monstrueuse val_finale = val_initiale; // on retourne la valeur initiale return; }; // estimation de l'erreur comme différence entre les méthodes du quatrième // et cinquième ordre estime_erreur = (deltat*d_A1)*der_initiale+d_A3*k3+d_A4*k4+d_A5*k5; } // résolution par runge kutta imbriqué --> estimation d'erreur // il y a 5 calcul de la fonction dérivée // l'algorithme s'appuis sur la présentation de numerical recipes // fifth-order Cash-Karp Runge-Kutta // calcul de la solution à t+dt en fonction de la solution à t, // en entrée: // *Ptder_fonc : pointeur de la fonction de calcul de la dérivées // en entrée: t et f : temps et la valeur de la fonction a t // en sortie: df : dérivée de la fonction a t // erreur : si diff de 0, indique qu'il y a eu une erreur // *Ptverif_fonc : pointeur de fonction, pour tester val_finale après la prédiction explicite finale // // val_initiale : valeur des fonctions en t0 // der_initiale : valeur de la dérivée pour t0 // t0 : temps initiale // deltat : incrément de temps demandé // en sortie : // val_finale : valeur des fonctions à tdt // estime_erreur : estimation d'erreur pour chaque fonction template void Algo_edp::Runge_Kutta_step45(T& instance ,Vecteur& (T::*Ptder_fonc) (const double & t,const Vecteur& f,Vecteur& df,int& erreur) ,void (T::*Ptverif_fonc) (const double & t,const Vecteur& f,int& erreur_final) ,const Vecteur& val_initiale,const Vecteur& der_initiale ,const double& t0,const double& deltat ,Vecteur& val_finale,Vecteur& estime_erreur) {// récup de la dimension int taille = val_initiale.Taille(); int erreur=0; // init de l'indicateur d'erreur dans le calcul de la fonction // vérif de la dimmension if (taille != k2.Taille()) { k2.Change_taille(taille);k3.Change_taille(taille); k4.Change_taille(taille),k5.Change_taille(taille); k6.Change_taille(taille);//f_inter.Change_taille(taille); }; // -- premier incrément val_finale = val_initiale + (deltat * b21) * der_initiale; // appel de la dérivée pour le premier incrément (instance.*Ptder_fonc) (t0+a2*deltat,val_finale,k2,erreur); k2 *= deltat; if (erreur) // cas où le calcul n'est pas licite { estime_erreur.Inita(ConstMath::tresgrand); // on indique une erreur monstrueuse val_finale = val_initiale; // on retourne la valeur initiale return; }; // -- deuxième incrément val_finale = val_initiale + (deltat * b31) * der_initiale + b32* k2; // appel de la dérivée pour le deuxième incrément (instance.*Ptder_fonc) (t0+a3*deltat,val_finale,k3,erreur); k3 *= deltat; if (erreur) // cas où le calcul n'est pas licite { estime_erreur.Inita(ConstMath::tresgrand); // on indique une erreur monstrueuse val_finale = val_initiale; // on retourne la valeur initiale return; }; // -- troisième incrément val_finale = val_initiale + (deltat*b41)*der_initiale+b42*k2+b43*k3; // appel de la dérivée pour le troisième incrément (instance.*Ptder_fonc) (t0+a4*deltat,val_finale,k4,erreur); k4 *= deltat; if (erreur) // cas où le calcul n'est pas licite { estime_erreur.Inita(ConstMath::tresgrand); // on indique une erreur monstrueuse val_finale = val_initiale; // on retourne la valeur initiale return; }; // -- quatrième incrément val_finale = val_initiale + (deltat*b51)*der_initiale+b52*k2+b53*k3+b54*k4; // appel de la dérivée pour le quatrième incrément (instance.*Ptder_fonc) (t0+a5*deltat,val_finale,k5,erreur); k5 *= deltat; if (erreur) // cas où le calcul n'est pas licite { estime_erreur.Inita(ConstMath::tresgrand); // on indique une erreur monstrueuse val_finale = val_initiale; // on retourne la valeur initiale return; }; // -- cinquième incrément val_finale = val_initiale + (deltat*b61)*der_initiale+b62*k2+b63*k3+b64*k4+b65*k5; // appel de la dérivée pour le cinquième incrément (instance.*Ptder_fonc) (t0+a6*deltat,val_finale,k6,erreur); k6 *= deltat; if (erreur) // cas où le calcul n'est pas licite { estime_erreur.Inita(ConstMath::tresgrand); // on indique une erreur monstrueuse val_finale = val_initiale; // on retourne la valeur initiale return; }; // somme pondéré des incréments val_finale = val_initiale + (deltat*c1)*der_initiale+c3*k3+c4*k4+c6*k6; // on vérifie que la solution finale est licite (instance.*Ptverif_fonc) (t0+deltat,val_finale,erreur); if (erreur) // cas où le calcul n'est pas licite { estime_erreur.Inita(ConstMath::tresgrand); // on indique une erreur monstrueuse val_finale = val_initiale; // on retourne la valeur initiale return; }; // estimation de l'erreur comme différence entre les méthodes du quatrième // et cinquième ordre estime_erreur = (deltat*ce1)*der_initiale+ce3*k3+ce4*k4+ce5*k5+ce6*k6; } // un programme de pilotage de l'intégration d'un pas (on s'inspire du programme libre rkf45) // on distingue une erreur globale et une erreur relative // l'erreur réelle utilisée sur chaque step est: erreurRelative * |f| + erreurAbsolue // ==== en entrée: ===== // cas_kutta : donne le type de routine kutta imbriqué a employer: // =3 pour kutta23, =4 pour kutta34, =5 pour kutta45 // tdebut et tfin : temps de début et de fin du calcul, demandé // val_initiale : valeur initiale de la fonction (donc à tdebut) // der_initiale : dérivée initiale de la fonction (donc à tdebut) // erreurAbsolue : erreur absolue demandée // erreurRelative : erreur relative (à la fonction) demandée // Ptder_fonc : pointeur de fonction // en entrée: t et f : temps et la valeur de la fonction a t // en sortie: df : dérivée de la fonction a t // erreur : si diff de 0, indique qu'il y a eu une erreur // Ptverif_fonc : pointeur de fonction, pour tester l'intégrité du résultat // cela signifie que val_finale est testée avec cette fonction, systématiquement // - à la fin de chaque prédiction des kuttas imbriqués // - au retour du pilotage // ---- en sortie: ----- // dernierTemps : temps final utilisé = tfin si calcul ok, sinon = le dernier temps calculé // val_finale : valeur de la fonction à "dernierTemps" // der_finale : dérivée finale // dernierdeltat : le dernier deltat utilisé // nombreAppelF : nombre d'appel de la fonction réellement utilisé dans le programme // erreurRelative : si retour = 3 ==> erreur relative (à la fonction) minimum possible, // nb_step : nombre de step utilisé pour le calcul (non compté les steps avec trop d'erreur) // erreur_maxi_global : une approximation de l'erreur maxi global cumulant les erreurs sur tous les steps // === en retour un entier qui donne le résultat du calcul : ==== // =2 : tout est ok : seul cas où toutes les valeurs de retour sont valides // =3 : erreur: la précision relative demandée est trop petite, en retour la précision mini possible // =4 : erreur: on a dépassé le nombre maxi d'appel fixé, d'où a peu près à (nombreAppelF/6) step de calcul. // =6 : erreur: l'intégration pas possible, due aux précisions demandées, on doit augmenter ces précisions // souvent du à une solution qui varie très rapidemment --> problème potentiel // =8 : erreur: cas_kutta ne correspond pas à une routine de base existante // =9 : tout c'est bien passé, mais la dernière valeur à t, n'a pu être calculée, donc c'est la valeur à t - quelque chose qui est renvoyée // = 0 : erreur inconnue template int Algo_edp::Pilotage_kutta(int cas_kutta, T& instance ,Vecteur& (T::*Ptder_fonc) (const double & t,const Vecteur& f,Vecteur& df,int& erreur) ,void (T::*Ptverif_fonc) (const double & t,const Vecteur& f,int& erreur_final) ,const Vecteur& val_initiale,const Vecteur& der_initiale ,const double& tdebut,const double& tfin ,const double& erreurAbsolue, double& erreurRelative ,Vecteur& val_finale,Vecteur& der_finale ,double& dernierTemps, double& dernierdeltat,int& nombreAppelF,int& nb_step ,double& erreur_maxi_global) { // -- premières initialisation nb_step=0; // compteur d'incrément // double temps = tfin ; //******* modif 4 septembre: double temps = tdebut; nombreAppelF=0; // compteur global d'appel de Kutta double deltat=tfin-tdebut; erreur_maxi_global = 0.; bool increment_valide=false; // pour savoir si l'exé d'un increment est valide // -- on commence par faire quelques tests pour vérifier le contexte // 1) vérification du niveau de la précision relative demandée static double relerr_min = 2. * ConstMath::eps_machine * remin; //// --- debug --- //cout << "\n Algo_edp::Pilotage_kutta( " // << "remin = " << remin << " eps_machine = " << ConstMath::eps_machine << " relerr_min= " // << relerr_min << endl; // //// --- fin debug --- if (erreurRelative < relerr_min) { if (permet_affichage > 4 ) cout << "\n Erreur: au niveau du pilotage de Runge Kutta, la precision relative demande= " << erreurRelative << " est inferieur a celle permise= " << relerr_min << "\n Algo_edp::Pilotage_kutta(.."; erreurRelative = relerr_min; return 3; // indication au programme appelant }; // -- récup de la dimension int taille = val_initiale.Taille(); // vérif de la dimmension if (taille != val_inter.Taille()) { val_inter.Change_taille(taille);val_finale.Change_taille(taille); der_inter.Change_taille(taille);der_finale.Change_taille(taille); }; // -- initialisation // -- initialisation avec sauvegarde des valeurs initiales der_inter=der_initiale; val_inter=val_initiale; // def du minimum de step possible (cf. rkf45) double mini_delta_t = 26. * ConstMath::eps_machine * MaX(Dabs(tdebut),Dabs(tfin)); // dans cette boucle l'idée est de piloter le pas de temps while (Dabs(temps) < Dabs(tfin)) { increment_valide = true; // par défaut on est optimiste // on appel la routine de calcul de base, // (val_inter, der_inter, temps et deltat : ne sont pas modifiés par le calcul) switch (cas_kutta) { case 3: // cas kutta23 {this->Runge_Kutta_step23(instance,Ptder_fonc,Ptverif_fonc,val_inter,der_inter,temps,deltat ,val_finale,estime_erreur); break; }; case 4: // cas kutta34 {this->Runge_Kutta_step34(instance,Ptder_fonc,Ptverif_fonc,val_inter,der_inter,temps,deltat ,val_finale,estime_erreur); break; }; case 5: // cas kutta45 {this->Runge_Kutta_step45(instance,Ptder_fonc,Ptverif_fonc,val_inter,der_inter,temps,deltat ,val_finale,estime_erreur); break; }; default: { if (permet_affichage >4) cout << "\n Erreur: au niveau du pilotage de Runge Kutta, le cas kutta demande= " << cas_kutta << " est errone ! par de routine de base de ce type (cf. doc) " << "\n Algo_edp::Pilotage_kutta(.."; return 8; // indication au programme appelant }; }; nombreAppelF += cas_kutta; //5; // on incrémente le compteur d'appels // calcul de la nouvelle dérivée initiale pour l'itération éventuelle suivante // on le fait ici, pour vérifier à ce stade que la valeur finale et la dérivée est licite // si ce n'est pas le cas cela veut dire que le calcul précédent n'est finalement pas bon // cela peut-être le cas par exemple lorsque l'évolution est instable (le pas de temps deltat est trop grand) // .. dans le cas où il y a eu une erreur dans le RKij précédent, val_finale est remis à la valeur initiale // c-a-d à val_initiale (représenté par val_inter, dans l'appel de RKij) int erreur_fonc=0; // initialisation // --- debug contrôlé--- if (permet_affichage > 6) {cout << "\n Algo_edp::Pilotage_kutta(.. juste après int erreur_fonc=0 " << "\n le vecteur= ";val_finale.Affiche(); cout << "\n l'erreur estime= ";estime_erreur.Affiche(); cout << endl; }; // --- fin debug --- // calcul de la dérivée finale, car on ne dispose pour l'instant que la la valeur finale (instance.*Ptder_fonc) (temps,val_finale,der_finale,erreur_fonc); // --- debug contrôlé --- if (permet_affichage > 6) {cout << "\n Algo_edp::Pilotage_kutta(.. appel de la fct " << "\n le vecteur= ";val_finale.Affiche(); cout << " sa dérivée= "; der_finale.Affiche(); cout << "\n temps= "<< temps <<" et temps finale visee= "<<(temps+deltat); cout << endl; }; // --- fin debug --- nombreAppelF++; // incrémente le compteur d'appel de fonction dernierTemps = temps; dernierdeltat=deltat; // init et en même temps sert de sauvegarde // ... on vérifie que le nombre d'appel n'exède pas le maxi fixé if (nombreAppelF > nbMaxiAppel) { if (permet_affichage >4) cout << "\n Erreur au niveau du pilotage de Runge Kutta, le nombre maxi d'appel= " << nbMaxiAppel << " de la fonction est depasse " << "\n Algo_edp::Pilotage_kutta(.."; if (erreur_fonc) // si erreur dans le dernier calcul, cela signifie que la valeur calculée n'est pas licite // dans ce cas on renvoie la valeur précédente { dernierTemps -= dernierdeltat;val_finale = val_inter;der_finale = der_inter;} // sinon on renvoie la dernière valeur calculée, qui est licite return 4; // indication au programme appelant }; // ... si le dernier calcul a posé pb, la seule solution est de diminuer le pas de temps // dans dernier calcul: on entend le calcul de la dérivée initiale et/ou la dernière résolution // de manière arbitraire et de recommencer le calcul if ((erreur_fonc)|| (estime_erreur.Max_val_abs() > ConstMath::grand)) { deltat /= 2.; // on divise par deux de manière arbitraire //// --- debug --- //cout << "\n Algo_edp::Pilotage_kutta( debut: erreur_fonc= " << erreur_fonc << " estime_erreur.Max_val_abs()= " // << estime_erreur.Max_val_abs() << " deltat= " << deltat; //// --- fin debug --- // on test néanmoins pour savoir si l'on n'est pas en dessous du delta limite inférieur if (Dabs(deltat) < mini_delta_t ) { if (permet_affichage > 4 ) cout << "\n Erreur1 au niveau du pilotage de Runge Kutta, le nouvelle increment qu'il faudrait utiliser = " << deltat << " est plus petit que le minimum autorise: " << mini_delta_t << "\n Algo_edp::Pilotage_kutta(.."; if (permet_affichage > 5 ) {cout << " estime_erreur= "; estime_erreur.Affiche();} dernierTemps = temps - 2. * deltat;val_finale = val_inter;der_finale = der_inter; return 6; // indication au programme appelant }; } else // sinon on peu continuer { // ... on passe en revue toutes les erreurs individuelles de chaque fonction // pour avoir le maximum, comparé à l'erreur admise -> facteur double facteur=0.; // facteur fonction des erreurs: pour contrôler le pas double max_erreur_sur_step_estimee=0; //// --- debug --- //cout << "\n Algo_edp::Pilotage_kutta( "; //// --- fin debug --- for (int i=1; i<= taille; i++) { double erreur_admise = erreurAbsolue+Dabs(val_finale(i))*erreurRelative; // comme on va diviser par erreur_admise, s'il est nulle on l'augmente erreur_admise = MaX(erreur_admise,ConstMath::pasmalpetit); facteur = MaX(facteur,Dabs(estime_erreur(i))/erreur_admise); max_erreur_sur_step_estimee = MaX(max_erreur_sur_step_estimee,Dabs(estime_erreur(i))); //// --- debug --- //cout << "\n estime_erreur(i)= " << estime_erreur(i) << " erreur_admise= "<< erreur_admise // << " max_erreur_sur_step_estimee= "<< max_erreur_sur_step_estimee; //// --- fin debug --- }; // on ajuste maintenant le pas en fonction du facteur qui dépend de l'erreur calculée double AbsDeltat=Abs(deltat); if (facteur > 1.) {// signifie que l'erreur du calcul est supérieure à celle admise // on doit donc diminuer le pas et recommencer le calcul double deltat_essai=coef*AbsDeltat*pow(facteur,-0.25); // le delta essai // on limite l'affaiblissement à 1/10 cf rkf45 deltat = DSigne(deltat)*MaX(0.1*AbsDeltat,deltat_essai); increment_valide = false; //// --- debug --- //cout << "\n Algo_edp::Pilotage_kutta( " // << "facteur = " << facteur << " max_erreur_sur_step_estimee = " << max_erreur_sur_step_estimee << " deltat_essai= " // << deltat_essai << " deltat= "<< deltat << endl; // //// --- fin debug --- // on test pour savoir si l'on n'est pas en dessous du delta limite inférieur if (Dabs(deltat) < mini_delta_t ) { if (permet_affichage > 4 ) cout << "\n Erreur2 au niveau du pilotage de Runge Kutta, le nouvelle increment qu'il faudrait utiliser = " << deltat << " est plus petit que le minimum autorise: " << mini_delta_t << "\n Algo_edp::Pilotage_kutta(.."; if (permet_affichage > 5 ) cout << "\n Algo_edp::Pilotage_kutta( " << "facteur = " << facteur << " max_erreur_sur_step_estimee = " << max_erreur_sur_step_estimee << " deltat_essai= " << deltat_essai << " deltat= "<< deltat << endl; dernierTemps = temps; dernierdeltat=deltat; return 6; // indication au programme appelant }; } else // sinon tout est ok: pas de temps, erreur, nombres d'appels et valeurs finales // donc cas ou le calcul à bien fonctionné {// on met à jour le temps temps += deltat; nb_step++; erreur_maxi_global += max_erreur_sur_step_estimee; //// --- debug --- //cout << "\n Algo_edp::Pilotage_kutta( calcul validé: " // << " erreur_maxi_global= "<