// FICHIER : LoiCritere.cp // CLASSE : LoiCritere // 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: . //#include "Debug.h" #include "LesLoisDeComp.h" # include using namespace std; //introduces namespace std #include #include #include "Sortie.h" #include "TypeConsTens.h" #include "TypeQuelconqueParticulier.h" #include "NevezTenseurQ.h" #include "LoiCritere.h" #include "LoiContraintesPlanesDouble.h" #include "LoiContraintesPlanes.h" #include "Util.h" // fonction critère de plissement de membrane // en entrée: // implicit : si oui on est en implicite, sinon en explicite // retour: // ** ancienne mouture // = -2 : erreur en calcul des valeurs propres de déformation, on ne tiens pas compte des plis // = -1 : erreur en calcul des valeurs propres de contrainte, on ne tiens pas compte des plis // : ou erreur en calcul des vecteurs propres de contrainte // = 1 : tout est ok, il n'y a pas d'apparition de plis, rien n'est en compression // = 2 : il y a des plis dans les deux sens, aucune raideur ni contrainte // = 3 : on a des plis dans une direction // ** nouvelle mouture // = -1 : pas de calcul de valeur propre possible en contrainte // = 1 : pas de plis (pas de calcul de nouvelle direction ) // = -2 : pas de calcul de valeur propre de déformation // = -3 : plis dans les deux sens, mais pas de calcul de direction propre valide // = 2 : plis dans les deux sens, calcul des directions de plis // = -4 : pas de calcul de vecteurs propres possible pour les contraintes // = 3 : plis dans une seule directions, calcul ok int LoiCritere::Critere_plis_membrane(bool en_base_orthonormee,TenseurHH & sigHH_t,TenseurBB& DepsBB ,TenseurBB & epsBB_tdt,TenseurBB & delta_epsBB,double& jacobien_0,double& jacobien ,TenseurHH& sigHH,TenseurHHHH& d_sigma_deps_inter ,EnergieMeca & energ,const EnergieMeca & energ_t,double& module_compressibilite ,double& module_cisaillement ,bool implicit,const Met_abstraite::Umat_cont& ex) {// on sauvegarde les modules de compressibilité et de cisaillement // car l'appel à la loi de contrainte plane annulle les valeurs stockées // et dans le cas ou il y a un pb, le mieux est de garder les anciennes valeurs // double module_compressibilite_save = module_compressibilite; // double module_cisaillement_save = module_cisaillement; // dim et vérification int dim_tens = abs(sigHH.Dimension()); // normalement le critère ne s'applique que pour des tenseurs 2D #ifdef MISE_AU_POINT if (dim_tens != 2) { cout << "\n erreur le critere de plissement de membrane ne peut s'appliquer que pour des lois 2D" << " \n LoiCritere::Critere_plis_membrane_expli(.."; Sortie(1); }; #endif SaveResul_LoiCritere & save_resul = *((SaveResul_LoiCritere*) saveResul); int retour = 0; // init par défaut // pilotage éventuelle du recalcul des directions de plis int calcul_dir_plis = 1; // initialisation // si rien n'a été auparavant calculé, on est obligé de faire un premier calcul // de direction sinon on appelle éventuellement l'indicateur // on récupère l'indicateur: qui est déterminé par une fonction nD // si cas_cal_plis == 0 cela veut dire soit qu'il n'y a pas eu déjà un calcul // soit que ce précédant calcul ne s'est pas bien passé, dans ces deux il faut // imposer de faire le calcul if ((recalcul_dir_plis != NULL) && (save_resul.cas_cal_plis != 0)) {// opération de transmission de la métrique const Met_abstraite::Impli* ex_impli = NULL; const Met_abstraite::Expli_t_tdt* ex_expli_tdt = NULL; const Met_abstraite::Umat_cont* ex_expli = &ex ; // ici on utilise les variables connues aux pti, ou calculées à partir de // on commence par récupérer les conteneurs des grandeurs à fournir List_io & li_enu_scal = recalcul_dir_plis->Li_enu_etendu_scalaire(); List_io & li_quelc = recalcul_dir_plis->Li_equi_Quel_evolue(); bool absolue = true; // on se place systématiquement en absolu // on va utiliser la méhode Valeur_multi_interpoler_ou_calculer // pour les grandeurs strictement scalaire Tableau val_ddl_enum(Valeur_multi_interpoler_ou_calculer (absolue,TEMPS_tdt,li_enu_scal,ex_impli,ex_expli_tdt,ex_expli,NULL) ); // on utilise la méthode Valeurs_Tensorielles_interpoler_ou_calculer // pour les Coordonnees et Tenseur Valeurs_Tensorielles_interpoler_ou_calculer (absolue,TEMPS_tdt,li_quelc,ex_impli,ex_expli_tdt,ex_expli,NULL); // calcul de la valeur et retour dans tab_ret Tableau & tab_val = recalcul_dir_plis->Valeur_FnD_Evoluee (&val_ddl_enum,&li_enu_scal,&li_quelc,NULL,NULL); #ifdef MISE_AU_POINT if (tab_val.Taille() != 1) { cout << "\nErreur : la fonction nD relative au recalcul de la direction des plis " << " doit calculer un scalaire or le tableau de retour est de taille " << tab_val.Taille() << " ce n'est pas normal !\n"; cout << " LoiCritere::Critere_plis_membrane(... \n"; Sortie(1); }; #endif // on récupère le premier élément du tableau uniquement calcul_dir_plis = (int) tab_val(1); }; // en fonction de l'indicateur calcul conditionnel des plis // ou utilisation des grandeurs sauvegardées Tableau V_Pr_H(2); Coordonnee2 valPropreSig; Coordonnee2 valPropreEps; switch (calcul_dir_plis) // test en fonction d'un pilotage éventuel fct de la fonction nD // recalcul_dir_plis->Valeur_FnD_Evoluee // rappel de la gestion des différents cas via la valeur de: calcul_dir_plis // si == 0 on utilise la valeur stockee actuelle, c-a-d ici à l'itération précédente // si aucun calcul de direction n'a ete effectue, il y a un premier calcul qui est fait // si == 1 on recalcule les directions des plis, // si == 2 on recalcule les directions des plis uniquement pour la zone non complètement // relâchée à l'incrément précédent, pour cette dernière on maintient le relâchement // si == -1 on utilise la valeur stockee a t (celle de l'incrément precedent qui a convergé), // si aucun calcul de direction n'a ete effectue, il y a un premier calcul qui est fait // si == -2 idem -1 , sauf que s'il n'y a pas de direction existante, on ne recalcule pas une // nouvelle direction, on continue avec un calcul sans plis // --> cela signifie que la zone de plis est totalement figée / au précédent incrément // si == -3 idem 0 , sauf que s'il n'y a pas de direction existante, on ne recalcule pas une // nouvelle direction, on continue avec un calcul sans plis // --> cela signifie que la zone de plis est totalement figée / à la précédente itération { case 2: // cas ou on doit recalculer la direction des plis uniquement pour la zone non relâché { if (save_resul.cas_cal_plis_t != 2) { int retour = Calcul_directions_plis(epsBB_tdt,sigHH,valPropreEps,V_Pr_H,ex,valPropreSig); #ifdef MISE_AU_POINT // vérif normalement inutile car le retour doit toujours être non nul if (!retour) {cout << "\n **** erreur a priori: normalement on ne devrait jamais avoir de retour nul " << " or on veut l'utiliser: ce n'est pas possible !! arret !! " << "\n LoiCritere::Critere_plis_membrane(..."; Sortie(1); }; #endif } else // sinon on maintien l'indicateur de relâchement {save_resul.cas_cal_plis = save_resul.cas_cal_plis_t; }; // retour dans le save_resul.cas_cal_plis // = -1 : pas de calcul de valeur propre possible en contrainte // = 1 : pas de plis (pas de calcul de nouvelle direction ) // = -2 : pas de calcul de valeur propre de déformation // = -3 : plis dans les deux sens, mais pas de calcul de direction propre valide // = 2 : plis dans les deux sens, calcul des directions de plis // = -4 : pas de calcul de vecteurs propres possible pour les contraintes // = 3 : plis dans une seule directions, calcul ok // si cela s'est bien passé, les résultats sont dans V_Pr_H // sinon on utilisera pas de directions: calculées ou stockées break; // fin du cas où on recalcule la direction des plis } case 1: // cas ou on doit recalculer la direction des plis { int retour = Calcul_directions_plis(epsBB_tdt,sigHH,valPropreEps,V_Pr_H,ex,valPropreSig); #ifdef MISE_AU_POINT // vérif normalement inutile car le retour doit toujours être non nul if (!retour) {cout << "\n **** erreur a priori: normalement on ne devrait jamais avoir de retour nul " << " or on veut l'utiliser: ce n'est pas possible !! arret !! " << "\n LoiCritere::Critere_plis_membrane(..."; Sortie(1); }; #endif // retour dans le save_resul.cas_cal_plis // = -1 : pas de calcul de valeur propre possible en contrainte // = 1 : pas de plis (pas de calcul de nouvelle direction ) // = -2 : pas de calcul de valeur propre de déformation // = -3 : plis dans les deux sens, mais pas de calcul de direction propre valide // = 2 : plis dans les deux sens, calcul des directions de plis // = -4 : pas de calcul de vecteurs propres possible pour les contraintes // = 3 : plis dans une seule directions, calcul ok // si cela s'est bien passé, les résultats sont dans V_Pr_H // sinon on utilisera pas de directions: calculées ou stockées break; // fin du cas où on recalcule la direction des plis } case 0: // cas où on se sert de ce qui a été sauvegardé à l'itération précédente // si aucun calcul de direction n'a ete effectue, il y a un premier calcul qui est fait { // en fait seul les cas 3 et 2 sont exploitables et seront exploités if ((save_resul.cas_cal_plis == 3)||(save_resul.cas_cal_plis == 2)) { // V_Pr_H(be)(j) correspond à la coordonnée locale ^j du vecteur be // donc V_Pr_H(be)(j) = V_Pr(be) * giH(j) // les vecteurs V_Pr_H(be) sont supposés être dans le plan des g_alpha for (int be=1;be<3;be++) // < 3 donc de 1 à 2 {for (int al=1;al<3;al++) // < 3 donc de 1 à 2 V_Pr_H(be)(al) = (*save_resul.V_P_sig)(be) * ex.giH_tdt->Coordo(al); }; } else // sinon cela veut dire que le calcul précédent n'est pas exploitable // on refait un calcul {int retour = Calcul_directions_plis(epsBB_tdt,sigHH,valPropreEps,V_Pr_H,ex,valPropreSig); #ifdef MISE_AU_POINT // vérif normalement inutile car le retour doit toujours être non nul if (!retour) {cout << "\n **** erreur a priori: normalement on ne devrait jamais avoir de retour nul " << " or on veut l'utiliser: ce n'est pas possible !! arret !! " << "\n LoiCritere::Critere_plis_membrane(..."; Sortie(1); }; #endif }; break; // fin du cas où on utilise la direction des plis sauvegardée à l'itération prec } case -1: // cas où on se sert de ce qui a été sauvegardé à l'incrément précédent // si aucun calcul de direction n'a ete effectue, il y a un premier calcul qui est fait { // en fait seul les cas 3 et 2 sont exploitables et seront exploités if ((save_resul.cas_cal_plis_t == 3)||(save_resul.cas_cal_plis_t == 2)) { // V_Pr_H(be)(j) correspond à la coordonnée locale ^j du vecteur be // donc V_Pr_H(be)(j) = V_Pr(be) * giH(j) // les vecteurs V_Pr_H(be) sont supposés être dans le plan des g_alpha // on utilise aussi les vecteurs de la base à t, ce qui permet de convecter // les vecteurs des directions de plis #ifdef MISE_AU_POINT // on vérifie que les données à t existent if (save_resul.V_P_sig_t == NULL) {cout << "\n **** erreur la direction des plis a t n'est pas encore sauvegardee " << " or on veut l'utiliser: ce n'est pas possible !! arret !! " << "\n LoiCritere::Critere_plis_membrane(..."; Sortie(1); }; #endif for (int be=1;be<3;be++) // < 3 donc de 1 à 2 {for (int al=1;al<3;al++) // < 3 donc de 1 à 2 V_Pr_H(be)(al) = (*save_resul.V_P_sig_t)(be) * ex.giH_t->Coordo(al); }; // on met à jour save_resul.cas_cal_plis en fonction save_resul.cas_cal_plis = save_resul.cas_cal_plis_t; } else // sinon cela veut dire que le calcul précédent n'est pas exploitable // on refait un calcul {int retour = Calcul_directions_plis(epsBB_tdt,sigHH,valPropreEps,V_Pr_H,ex,valPropreSig); #ifdef MISE_AU_POINT // vérif normalement inutile car le retour doit toujours être non nul if (!retour) {cout << "\n **** erreur a priori: normalement on ne devrait jamais avoir de retour nul " << " or on veut l'utiliser: ce n'est pas possible !! arret !! " << "\n LoiCritere::Critere_plis_membrane(..."; Sortie(1); }; #endif }; break; // fin du cas où on utilise la direction des plis sauvegardée à l'increment prec } case -2: // cas où la zone de plis de l'incrément précédent // est totalement figée { // en fait seul les cas 3 et 2 sont exploitables et seront exploités if ((save_resul.cas_cal_plis_t == 3)||(save_resul.cas_cal_plis_t == 2)) { // V_Pr_H(be)(j) correspond à la coordonnée locale ^j du vecteur be // donc V_Pr_H(be)(j) = V_Pr(be) * giH(j) // les vecteurs V_Pr_H(be) sont supposés être dans le plan des g_alpha // on utilise aussi les vecteurs de la base à t, ce qui permet de convecter // les vecteurs des directions de plis #ifdef MISE_AU_POINT // on vérifie que les données à t existent if (save_resul.V_P_sig_t == NULL) {cout << "\n **** erreur la direction des plis a t n'est pas encore sauvegardee " << " or on veut l'utiliser: ce n'est pas possible !! arret !! " << "\n LoiCritere::Critere_plis_membrane(..."; Sortie(1); }; #endif for (int be=1;be<3;be++) // < 3 donc de 1 à 2 {for (int al=1;al<3;al++) // < 3 donc de 1 à 2 V_Pr_H(be)(al) = (*save_resul.V_P_sig_t)(be) * ex.giH_t->Coordo(al); }; // on met à jour save_resul.cas_cal_plis en fonction save_resul.cas_cal_plis = save_resul.cas_cal_plis_t; } else // sinon on continue avec un cas sans plis { int retour = Calcul_directions_plis(epsBB_tdt,sigHH,valPropreEps,V_Pr_H,ex,valPropreSig,false); // on met à jour save_resul.cas_cal_plis en fonction save_resul.cas_cal_plis = retour; }; break; // fin du cas où on utilise la direction des plis sauvegardée à l'increment prec } case -3: // cas où on se sert de ce qui a été sauvegardé à l'itération précédente // idem 0 , sauf que s'il n'y a pas de direction existante, on ne recalcule pas une // nouvelle direction, on continue avec un calcul sans plis // --> cela signifie que la zone de plis est totalement figée / à la précédente itération { // en fait seul les cas 3 et 2 sont exploitables et seront exploités if ((save_resul.cas_cal_plis == 3)||(save_resul.cas_cal_plis == 2)) { // V_Pr_H(be)(j) correspond à la coordonnée locale ^j du vecteur be // donc V_Pr_H(be)(j) = V_Pr(be) * giH(j) // les vecteurs V_Pr_H(be) sont supposés être dans le plan des g_alpha for (int be=1;be<3;be++) // < 3 donc de 1 à 2 {for (int al=1;al<3;al++) // < 3 donc de 1 à 2 V_Pr_H(be)(al) = (*save_resul.V_P_sig)(be) * ex.giH_tdt->Coordo(al); }; } else // sinon on continue avec un cas sans plis { int retour = Calcul_directions_plis(epsBB_tdt,sigHH,valPropreEps,V_Pr_H,ex,valPropreSig,false); // on met à jour save_resul.cas_cal_plis en fonction save_resul.cas_cal_plis = retour; }; break; // fin du cas où on utilise la direction des plis sauvegardée à l'itération prec } default: cout << "\n erreur non prevu : calcul_dir_plis= "<< save_resul.cas_cal_plis << "\n LoiCritere::Critere_plis_membrane(..."; Sortie(1); }; // if ((ParaGlob::NiveauImpression() > 8) || (Permet_affichage() > 5)) // cout << "\n test3: LoiCritere::Critere_plis_membrane(... " << flush; // maintenant on fait un traitement en fonction de save_resul.cas_cal_plis // = -1 : pas de calcul de valeur propre possible en contrainte // = 1 : pas de plis (pas de calcul de nouvelle direction ) // = -2 : pas de calcul de valeur propre de déformation // = -3 : plis dans les deux sens, mais pas de calcul de direction propre valide // = 2 : plis dans les deux sens, calcul des directions de plis // = -4 : pas de calcul de vecteurs propres possible pour les contraintes // = 3 : plis dans une seule directions, calcul ok retour = save_resul.cas_cal_plis; // init switch (save_resul.cas_cal_plis) { case -1: // pas de calcul de valeur propre possible en contrainte {save_resul.eps_pli.Zero(); // pas de pli répertorié break; } case 1: // pas de plis {break; } case -2: // pas de calcul de valeur propre de déformation {save_resul.eps_pli.Zero(); // pas de pli répertorié break; } // on traite -3 et 2 en même temps, car la fin est commune case -3: // plis dans les deux sens, mais pas de calcul de direction propre valide case 2: // plis dans les deux sens, calcul des directions de plis {if (save_resul.cas_cal_plis == -3) {save_resul.eps_pli.Zero(); // pas de pli répertorié } else // -> cas: save_resul.cas_cal_plis == 2 {if (calcul_dir_plis != 2) { // calcul normal relatif à la zone relâchée // les coordonnées des vecteurs propres sont exprimées dans l'ancienne base // on a donc // Vi_B(i) = gpB(i) = beta(i,j) * gB(j), i indice de ligne, j indice de colonne Mat_pleine beta(2,2); for (int i=1;i<3;i++) // < 3 donc de 1 à 2 for (int j=1;j<3;j++) beta(i,j) = V_Pr_H(i)(j); Mat_pleine gamma(beta.Inverse().Transpose()); // on calcule la matrice inverse // la matrice gamma correspond à la matrice de changement de base des g^i au gpH // gamma est l'inverse transposée // gpH(i) = gamma(i,j) * gH(j), i indice de ligne, j indice de colonne // c-a-d= gp^i = gamma^i_j * g^j bool deux_plis = true; // on calcul les def de plis : save_resul.eps_pli Passage_3ou2_vers_1(gamma,sigHH_t,beta,DepsBB,epsBB_tdt ,delta_epsBB,deux_plis,save_resul.eps_pli); } else // sinon calcul_dir_plis == 2, cela veut dire que l'on n'a pas recalculé // dans la zône relâchée donc on utilise les déformations déjà calculées à t { save_resul.eps_pli = save_resul.eps_pli_t; // on retient les directions des plis précendentes (*save_resul.V_P_sig) = (*save_resul.V_P_sig_t); }; }; // traitement des épaisseurs et des largeurs // LoiContraintesPlanes::SaveResul_LoiContraintesPlanes * save_result_plan_inter // pour simplifier // = (LoiContraintesPlanes::SaveResul_LoiContraintesPlanes *) // (*(save_resul.liste_des_SaveResul.begin())); LoiContraintesPlanesDouble::SaveResul_LoiContraintesPlanesDouble * save_result_plan_inter // pour simplifier = (LoiContraintesPlanesDouble::SaveResul_LoiContraintesPlanesDouble *) (*(save_resul.liste_des_SaveResul.begin())); switch (choix_calcul_epaisseur_si_relachement_complet) { case 1: // cas où on impose un retour à l'épaisseur et à la largeur initiales save_result_plan_inter->hsurh0 = 1.; save_result_plan_inter->bsurb0 = 1.; break; case 2: // cas où on impose l'épaisseur et la largeur du pas précédent {if (save_result_plan_inter->h_tsurh0 != 0.) {save_result_plan_inter->hsurh0 = save_result_plan_inter->h_tsurh0;} else // sinon on remet à 1. {save_result_plan_inter->hsurh0 = 1.;}; if (save_result_plan_inter->b_tsurb0 != 0.) {save_result_plan_inter->bsurb0 = save_result_plan_inter->b_tsurb0;} else // sinon on remet à 1. {save_result_plan_inter->bsurb0 = 1.;}; break; } default: cout << "\n erreur *** la variable choix_calcul_epaisseur_si_relachement_complet= " << choix_calcul_epaisseur_si_relachement_complet << " est differente de 1= le seul choix actuellement implante " << endl; Sortie(1); break; }; // on annule la contrainte et sa contribution éventuelle à la raideur sigHH.Inita(0.); //d_sigma_deps_inter.Inita(0.); // on annule également les énergies energ.Inita(0.); break; } case -4: // pas de calcul de vecteurs propres possible pour les contraintes {save_resul.eps_pli.Zero(); // pas de pli répertorié break; } case 3: // plis dans une seule directions {// va être traité en dehors du switch car c'est le gros morceau break; } default: // normalement n'arrive jamais car Calcul_directions_plis a toujours une solution diff de 0 { cout << "\n *** cas d'erreur inconnue dans le calcul de la direction des plis " << " save_resul.cas_cal_plis= "<< save_resul.cas_cal_plis ; Sortie(1); break; } }; // if ((ParaGlob::NiveauImpression() > 8) || (Permet_affichage() > 5)) // cout << "\n test4: LoiCritere::Critere_plis_membrane(... " << flush; // le gros morceau: cas où on a une seule direction if (save_resul.cas_cal_plis == 3) {// choix entre la méthode historique et la nouvelle méthode switch (choix_methode_cal_plis_memb) {case 1: {Premie_type_calcul_en_un_pli(epsBB_tdt,delta_epsBB ,sigHH_t,jacobien_0,jacobien,energ,energ_t ,DepsBB,module_compressibilite,module_cisaillement ,V_Pr_H,sigHH,d_sigma_deps_inter ,valPropreSig,ex); break; } case 2: {Deuxieme_type_calcul_en_un_pli(epsBB_tdt,delta_epsBB ,sigHH_t,jacobien_0,jacobien,energ,energ_t ,DepsBB,module_compressibilite,module_cisaillement ,V_Pr_H,sigHH,d_sigma_deps_inter ,valPropreSig,ex); break; } default: cout << "\n cas non prevu: choix_methode_cal_plis_memb= " << choix_methode_cal_plis_memb ; Sortie(1); break; }; }; return retour; }; // calcul d'une nouvelle direction de plis // en entrée: force: = true par défaut // si == false -> pas de calcul de direction demandée, et mise en place // des indicateurs en cohérence avec le fait de ne pas faire de calcul // en retour: // = -1 : pas de calcul de valeur propre possible en contrainte // = 1 : pas de plis (pas de calcul de nouvelle direction ) // = -2 : pas de calcul de valeur propre de déformation // = -3 : plis dans les deux sens, mais pas de calcul de direction propre valide // = 2 : plis dans les deux sens, calcul des directions de plis // = -4 : pas de calcul de vecteurs propres possible pour les contraintes // = 3 : plis dans une seule directions, calcul ok // = 0 : erreur inconnue ?? int LoiCritere::Calcul_directions_plis(const TenseurBB & epsBB_tdt,const TenseurHH& sigHH ,Coordonnee2& valPropreEps ,Tableau & V_Pr_H ,const Met_abstraite::Umat_cont& ex ,Coordonnee2& valPropreSig , bool force ) {// dim et vérification int dim_tens = abs(sigHH.Dimension()); V_Pr_H.Change_taille(2); // normalement le critère ne s'applique que pour des tenseurs 2D #ifdef MISE_AU_POINT if (dim_tens != 2) { cout << "\n erreur le critere de plissement de membrane ne peut s'appliquer que pour des lois 2D" << " \n LoiCritere::Calcul_directions_plis(.."; Sortie(1); }; #endif SaveResul_LoiCritere & save_resul = *((SaveResul_LoiCritere*) saveResul); int retour = 0; // init par défaut if (!force) // cas particulier ou on ne veut pas de calcul, mais par contre on veut mettre les indicateurs // cohérence avec le fait de ne pas faire de calcul { retour = 1; //on signale save_resul.eps_pli.Zero(); // pas de pli répertorié // comme il n'y a pas de plis, donc par de variation de largeur LoiContraintesPlanesDouble::SaveResul_LoiContraintesPlanesDouble * save_result_1DCP2_inter // pour simplifier = (LoiContraintesPlanesDouble::SaveResul_LoiContraintesPlanesDouble *) (*(save_resul.liste_des_SaveResul.begin())); save_result_1DCP2_inter->Zero_var_largeur(); // mise à 0 de b_surb0 } else {// on va calculer les valeurs propres relatives au tenseur des contraintes TenseurHB* sigHB = (NevezTenseurHB(dim_tens,0.)); (*sigHB) = sigHH * (* ex.gijBB_tdt); int casSig = 0; // init par défaut // calcul des valeurs propres correspondantes à des vecteurs propres CoordonneeH valPropreSig = sigHB->ValPropre(casSig); // si le calcul n'est pas possible on ne fait rien mais on poste un message if (casSig == -1) // ==== cas d'une erreur de valeur propre sur la contrainte ==== { if (Permet_affichage() > 4) cout << "\n warning : le calcul des valeurs propres de contrainte n'a pas ete possible," << " l'application du critere de plissement n'est pas possible, et donc non effectuee " << endl; retour = -1; save_resul.eps_pli.Zero(); // pas de pli répertorié } else if (valPropreSig(dim_tens) >= save_resul.niveau_declenchement_critere) // 0.) { // on se trouve dans le cas où rien n'est en compression, donc cas normal sans plissement retour = 1; //on signale save_resul.eps_pli.Zero(); // pas de pli répertorié // comme il n'y a pas de plis, donc par de variation de largeur LoiContraintesPlanesDouble::SaveResul_LoiContraintesPlanesDouble * save_result_1DCP2_inter // pour simplifier = (LoiContraintesPlanesDouble::SaveResul_LoiContraintesPlanesDouble *) (*(save_resul.liste_des_SaveResul.begin())); save_result_1DCP2_inter->Zero_var_largeur(); // mise à 0 de b_surb0 } else { // ==== on se trouve dans le cas où potentiellement on peut avoir des plis ==== // on regarde les valeurs propres en déformation TenseurHB* epsHB = (NevezTenseurHB(dim_tens,0.)); (*epsHB) = (* ex.gijHH_tdt) * epsBB_tdt; int casEps = 0; // init par défaut // calcul des valeurs propres correspondantes à des vecteurs propres CoordonneeH valPropreEps = epsHB->ValPropre(casEps); if (casEps == -1) { if (Permet_affichage() > 4) cout << "\n warning : le calcul des valeurs propres de deformation n'a pas ete possible," << " l'application du critere de plissement n'est pas possible, et donc non effectuee " << endl; retour = -2; save_resul.eps_pli.Zero(); // pas de pli répertorié } else if (valPropreEps(1) < 0.) // ==== cas de plis dans les deux sens ==== {// si la plus grande des valeurs propres de déformation est négative, // dans ce cas il y a des plis dans les deux sens il faut que l'on récupère // les def des plis //*** il faudra grouper ce if avec le cas d'un pli de manière à éviter les erreurs de duplication *** // -- on doit définir un repère ortho dont le premier vecteur est celui selon lequel on fait du 1D // calcul des vecteurs propres int cas = 0; // init Tableau V_inter; sigHB->VecteursPropres(valPropreSig,cas, V_inter); // si cas = -1, la construction des vecteurs propres est impossible, on arrête le traitement if (cas == -1) {save_resul.eps_pli.Zero(); // on ne peut pas donner une intensité au def de pli ! // les vecteurs propres sauvegardées sont nulles Coordonnee3 zero3; // un vecteur nul save_resul.V_P_sig->Change_taille(3,zero3); // en 3D qui est obligatoire ici retour = -3; } else { #ifdef MISE_AU_POINT if (Permet_affichage() > 5) if (Dabs(V_inter(1) * V_inter(2)) > ConstMath::petit) {cout << "\n== LoiCritere::Critere_plis_membrane: plis dans les deux sens "; //cout << "\n sigma: vecteurs propres: \n "<< V_inter; cout << "\n sigma: valeurs propres: "; valPropreSig.Affiche_1(cout); // on va vérifier les vecteurs propres Coordonnee2H VpH1; VpH1.Change_val(V_inter(1)); cout << "\n vecteur propre 1 VpH1= " << VpH1; Coordonnee2H VpropreH1 = (*sigHB) * VpH1; //cout << "\n sigHH * VH1 "<< VpropreH1; // comme les valeurs peuvent être très petites on régularise VpropreH1 /= (valPropreSig(1)+ConstMath::petit); cout << "\n verif: (sigHB * VH1)/(lambda1+epsilon) = "<< VpropreH1; CoordonneeB aB; aB.Change_val(V_inter(2)); Coordonnee2H VpH2 = aB * (* ex.gijHH_tdt); cout << "\n vecteur propre 2 VpH2 "<< VpH2; Coordonnee2H VpropreH2 = (*sigHB) * VpH2; //cout << "\n sigHH * VH2 "<< VpropreH2; VpropreH2 /= (valPropreSig(2)+ConstMath::petit); cout << "\n verif: (sigHB * VH2)/(lambda2+epsilon) = "<< VpropreH2; cout << endl; }; #endif // Le premier vecteur propre s'exprime dans la base naturelle, par contre le second s'exprime // dans la base duale donc : V1^H, et V2_B // donc si on veut un changement de base de naturelle en naturelle il faut calculer V2^H V_Pr_H(1).Change_val(V_inter(1)); // le premier vecteur ok CoordonneeB aB; aB.Change_val(V_inter(2)); V_Pr_H(2)= aB * (* ex.gijHH_tdt); // pour l'instant ces vecteurs propres ne sont pas normés car les vecteurs // de base ne sont pas normés, on va donc les normer #ifdef MISE_AU_POINT if (Permet_affichage() > 5) {cout << "\n normalisation des vecteurs propres:"; }; #endif // on calcul les vecteurs propres en orthonormee // on définit l'espace de stockage des vecteurs propres si nécessaire #ifdef MISE_AU_POINT if (Permet_affichage() > 5) {cout << "\n vecteurs propres en orthonormee:"; }; #endif if (save_resul.V_P_sig == NULL) save_resul.V_P_sig = new Tableau ; Coordonnee3 zero3; // un vecteur nul save_resul.V_P_sig->Change_taille(3,zero3); // on va calculer en 3D qui est obligatoire ici for (int be=1;be<3;be++) // be < 3 donc de 1 à 2 for (int al=1;al<3;al++) (*save_resul.V_P_sig)(be) += V_Pr_H(be)(al) * ex.giB_tdt->Coordo(al); // on norme les vecteurs après le passage en absolue (modif prise en compte) for (int al=1;al<3;al++) // al < 3 erreur { #ifdef MISE_AU_POINT if (Permet_affichage() > 5) {cout << "\n vecteur propre ("< 5) {cout << "\n vecteur propre local apres normalisation " << V_Pr_H(al); cout << "\n norme VPH("< V_inter; sigHB->VecteursPropres(valPropreSig,cas, V_inter); // si cas = -1, la construction des vecteurs propres est impossible, on arrête le traitement if (cas == -1) { if (Permet_affichage() > 4) cout << "\n warning : le calcul des valeurs propres de contrainte n'a pas ete possible," << " l'application du critere de plissement n'est pas possible, et donc non effectuee " << endl; retour = -4; save_resul.eps_pli.Zero(); // pas de pli répertorié // les vecteurs propres sauvegardées sont nulles Coordonnee3 zero3; // un vecteur nul save_resul.V_P_sig->Change_taille(3,zero3); // en 3D qui est obligatoire ici } else { #ifdef MISE_AU_POINT if (Permet_affichage() > 5) {cout << "\n== LoiCritere::Critere_plis_membrane plis dans un seul sens "; //cout << "\n sigma: vecteurs propres: \n "<< V_inter; cout << "\n sigma: valeurs propres: "; valPropreSig.Affiche_1(cout); // on va vérifier les vecteurs propres Coordonnee2H VpH1; VpH1.Change_val(V_inter(1)); cout << "\n vecteur propre 1 VpH1= " << VpH1; Coordonnee2H VpropreH1 = (*sigHB) * VpH1; //cout << "\n sigHH * VH1 "<< VpropreH1; // comme les valeurs peuvent être très petites on régularise VpropreH1 /= (valPropreSig(1)+ConstMath::petit); cout << "\n verif: (sigHB * VH1)/(lambda1+epsilon) = "<< VpropreH1; CoordonneeB aB; aB.Change_val(V_inter(2)); Coordonnee2H VpH2 = aB * (* ex.gijHH_tdt); cout << "\n vecteur propre 2 VpH2 "<< VpH2; Coordonnee2H VpropreH2 = (*sigHB) * VpH2; //cout << "\n sigHH * VH2 "<< VpropreH2; VpropreH2 /= (valPropreSig(2)+ConstMath::petit); cout << "\n verif: (sigHB * VH2)/(lambda2+epsilon) = "<< VpropreH2; cout << endl; }; #endif // Le premier vecteur propre s'exprime dans la base naturelle, par contre le second s'exprime // dans la base duale donc : V1^H, et V2_B // donc si on veut un changement de base de naturelle en naturelle il faut calculer V2^H V_Pr_H(1).Change_val(V_inter(1)); // le premier vecteur ok CoordonneeB aB; aB.Change_val(V_inter(2)); V_Pr_H(2)= aB * (* ex.gijHH_tdt); // pour l'instant ces vecteurs propres ne sont pas normés car les vecteurs // de base ne sont pas normés, on va donc les normer #ifdef MISE_AU_POINT if (Permet_affichage() > 5) {cout << "\n normalisation des vecteurs propres:"; }; #endif // on calcul les vecteurs propres en orthonormee // on définit l'espace de stockage des vecteurs propres si nécessaire #ifdef MISE_AU_POINT if (Permet_affichage() >5) {cout << "\n vecteurs propres en orthonormee:"; }; #endif if (save_resul.V_P_sig == NULL) save_resul.V_P_sig = new Tableau ; Coordonnee3 zero3; // un vecteur nul save_resul.V_P_sig->Change_taille(3,zero3); // on va calculer en 3D for (int be=1;be<3;be++) // be < 3 donc de 1 à 2 for (int al=1;al<3;al++) (*save_resul.V_P_sig)(be) += V_Pr_H(be)(al) * ex.giB_tdt->Coordo(al); // on norme les vecteurs après le passage en absolue for (int al=1;al<3;al++) // al < 3 erreur { #ifdef MISE_AU_POINT if (Permet_affichage() > 5) {cout << "\n vecteur propre local avant normalisation " << V_Pr_H(al); cout << "\n vecteur propre ("< 5) {cout << "\n vecteur propre local apres normalisation " << V_Pr_H(al); cout << "\n norme VPH("< 4) {bool erreur = false; switch (retour) { case -1 : cout << "\n pas de calcul de valeur propre possible en contrainte ";erreur=true;break; case -2 : cout << "\n pas de calcul de valeur propre possible de deformation "; erreur=true;break; case -3 : cout << "\n plis dans les deux sens, mais pas de calcul de direction propre valide "; erreur=true;break; case -4 : cout << "\n pas de calcul de vecteurs propres possible pour les contraintes "; erreur=true;break; case 0 : cout << "\n erreur inconnue dans le calcul directions plis ?? "; erreur=true;break; default: break; // cas normal, aucun affichage }; if (erreur) if (ptintmeca_en_cours != NULL) cout << " mail: "<< ptintmeca_en_cours->Nb_mail() << " ele: "<< ptintmeca_en_cours->Nb_ele() << " npti: "<< ptintmeca_en_cours->Nb_pti() ; }; #endif // retour return retour; }; // création du conteneur UMAT a partir des vecteurs propres void LoiCritere::Creation_metrique_a_partir_vecteurs_propres_pour_Umat1D (const Met_abstraite::Umat_cont& ex,const Mat_pleine& beta ) { // on va se mettre en 1D dans le repère principal de contrainte SaveResul_LoiCritere & save_resul = *((SaveResul_LoiCritere*) saveResul); // la partie dépendant des vitesses: entre accolades pour pouvoir fermer // ici il est nécessaire de recalculer les gradients dans la nouvelle base // dans le cas où ils existent {if (ex.gradVmoyBB_t != NULL) {umat_cont_1D->gradVmoyBB_t= gradVmoyBB_t_1D_P = &gradVmoyBB_t_1D; // on change de base TenseurBB* t_interBB = NevezTenseurBB(*ex.gradVmoyBB_t); t_interBB->ChBase(beta); // puis on transfert en 1D umat_cont_1D->gradVmoyBB_t->Affectation_trans_dimension(*t_interBB,true); delete t_interBB; }; if (ex.gradVmoyBB_tdt != NULL) {umat_cont_1D->gradVmoyBB_tdt=gradVmoyBB_tdt_1D_P = &gradVmoyBB_tdt_1D; // on change de base TenseurBB* t_interBB = NevezTenseurBB(*ex.gradVmoyBB_tdt); t_interBB->ChBase(beta); // puis on transfert en 1D umat_cont_1D->gradVmoyBB_tdt->Affectation_trans_dimension(*t_interBB,true); delete t_interBB; }; if (ex.gradVBB_tdt != NULL) {umat_cont_1D->gradVBB_tdt=gradVBB_tdt_1D_P = &gradVBB_tdt_1D; // on change de base TenseurBB* t_interBB = NevezTenseurBB(*ex.gradVBB_tdt); t_interBB->ChBase(beta); // puis on transfert en 1D umat_cont_1D->gradVBB_tdt->Affectation_trans_dimension(*t_interBB,true); delete t_interBB; }; }; // fin de la partie dédiée à la vitesse // -- maintenant on construit les éléments de l'Umat pour le repère ortho avec 1 seul // vecteur de base, et en orthonormé // en fait on va construire un repère orthonormé à partir des vecteurs propres // **** comme on considère que la base locale est orthonormé, normalement elle ne change pas // pour l'instant on laisse sa construction, mais en fait une seule est suffisante // ***** 2 oct 2018: je commente la ligne qui suit car en fait j'ai l'impression // que la base change puisqu'elle vaut les directions propres et que ceux-ci dépendent // du calcul .... là je ne comprends pas pourquoi j'ai mis le test .... // if ((*(umat_cont_1D->gijBB_0))(1,1) == 0.) // pour savoir si la construction a été faite on non { // les vecteurs propres sont considérés normés: cf. voir leurs calculs BaseB& giB_tdt = *(umat_cont_1D->giB_tdt); // pour simplifier const Coordonnee& V_sig = (*save_resul.V_P_sig)(1); // pour simplifier giB_tdt.CoordoB(1).Change_val(V_sig); // on utilise un vecteur 3D, ici dans la base orthonormee // giB_tdt(1) = V_Pr_B(1); //.Change_val(V_sig); // giB_tdt(1)(1) = 1.; // idem pour les temps 0 et t *(umat_cont_1D->giB_0)=giB_tdt; *(umat_cont_1D->giB_t)=giB_tdt; // idem pour le contravariant BaseH& giH_tdt = *(umat_cont_1D->giH_tdt); // pour simplifier // comme la base est orthonormée, H et B sont identiques giH_tdt.CoordoH(1).Change_val(V_sig); // giH_tdt(1).Change_val(V_Pr_B(1).Coor()); // giH_tdt(1)(1) = 1.; *(umat_cont_1D->giH_0)=giH_tdt; *(umat_cont_1D->giH_t)=giH_tdt; // maintenant les métriques : ici identité (*(umat_cont_1D->gijBB_0)).Coor(1,1)=(*(umat_cont_1D->gijHH_0)).Coor(1,1)=1.; (*(umat_cont_1D->gijBB_t)).Coor(1,1)=(*(umat_cont_1D->gijHH_t)).Coor(1,1)=1.; (*(umat_cont_1D->gijBB_tdt)).Coor(1,1)=(*(umat_cont_1D->gijHH_tdt)).Coor(1,1)=1.; #ifdef MISE_AU_POINT if (Permet_affichage() > 5) {cout << "\n LoiCritere::Creation_metrique_a_partir_vecteurs_propres_pour_Umat1D( "; cout << "\n base gipB(1) "<< giB_tdt(1) << "\n base gipH(1) "<< giH_tdt(1); }; #endif }; }; // passage des grandeurs métriques de l'ordre 3 ou 2 à 1: cas implicite void LoiCritere::Passage_metrique_ordre_3_2_vers_1(const Met_abstraite::Umat_cont& ex,const Mat_pleine& gamma) {}; // chgt de repère et de dimension pour les variables de passage pour le calcul final de la loi en 1D void LoiCritere::Passage_3ou2_vers_1(const Mat_pleine& gamma,const TenseurHH & sigHH_t ,const Mat_pleine& beta ,const TenseurBB& DepsBB ,const TenseurBB & epsBB_tdt,const TenseurBB & delta_epsBB ,const bool& deux_plis,Coordonnee2& eps_pli) { // on s'occupe du changement de base int dim_tens = abs(sigHH_t.Dimension()); // on crée des nouveaux tenseurs au lieu d'utiliser les tenseurs initiaux, car on fait un changement de base // qui a pour effet de modifier le tenseur. Donc si ensuite on veut utiliser les tenseurs initiaux, ce ne sera // plus possible comme initialement if (dim_tens == 2) { Tenseur2HH sigHH_2_inter(sigHH_t); sigHH_2_inter.ChBase(gamma); sig_HH_t_1D.Affectation_trans_dimension(sigHH_2_inter,false);// passage des tenseurs résultats à l'ordre 1 Tenseur2BB DepsBB_2_inter(DepsBB); DepsBB_2_inter.ChBase(beta); Deps_BB_1D.Affectation_trans_dimension(DepsBB_2_inter,false); Tenseur2BB epsBB_tdt_2_inter(epsBB_tdt);epsBB_tdt_2_inter.ChBase(beta); /* Lorsqu'il y a un pli dans une seule direction, le premier vecteur indique la direction selon laquelle la membrane est en traction. Son intensité est égale à la déformation mécanique dans cette même direction. Le second vecteur est normal à la première direction, son intensité est égale à la déformation cinématique selon cette direction, c'est-à-dire calculée à l'aide des déplacements des noeuds du maillage. Cette déformation est différente de la déformation mécanique calculée par la loi 3D, c'est-à-dire issue de la contraction de la zone, due à la traction suivant la première direction. Cette déformation mécanique peut-être récupéré via la deformation "DEF\_LARGEUR" associée à la loi de comportement. Lorsqu'il y a des plis dans deux directions, les deux vecteurs indiquent les directions principales d'apparition de plis. L'intensité des vecteurs est égale à la déformation cinématique dans la direction associée. Lorsqu'il n'y a pas de plis, l'intensité des vecteurs est nulle. */ eps_pli(1) = epsBB_tdt_2_inter(2,2); // on sauvegarde les def de plis if (deux_plis) // cas où il y aurait des plis dans les deux sens eps_pli(2) = epsBB_tdt_2_inter(1,1); else eps_pli(2) = 0.; // cas d'un seul plis eps_BB_1D.Affectation_trans_dimension(epsBB_tdt_2_inter,false); Tenseur2BB delta_epsBB_2_inter(delta_epsBB); delta_epsBB_2_inter.ChBase(beta); delta_eps_BB_1D.Affectation_trans_dimension(delta_epsBB_2_inter,false); #ifdef MISE_AU_POINT if (Permet_affichage() > 5) {cout << "\n debug LoiCritere::Passage_3ou2_vers_1( "; cout << "\n sigHH_t= en g_i "; sigHH_t.Ecriture(cout); cout << "\n sigHH_t= en vecteurs propres "<< sigHH_2_inter; cout << "\n epsBB_tdt en gi ";epsBB_tdt.Ecriture(cout); cout << "\n epsBB_tdt en vecteurs propres "<< epsBB_tdt_2_inter; cout << "\n epsBB 1D en local vecteurs propres " << eps_BB_1D; // en orthonormee Tenseur3BB epsBB_3_inter; eps_BB_1D.BaseAbsolue(epsBB_3_inter,(giH_tdt_1D)); cout << "\n base giH_tdt_1D: "<& V_Pr_H ,const Tableau & V_P_sig) { // on s'occupe du changement de base int dim_tens = abs(sigHH.Dimension()); // if (dim_tens == 2) // { // normalement les contraintes sont nulles dans les directions autres que 11 // sigHH.Affectation_trans_dimension(sig_HH_t_1D,true); // sigHH.ChBase(beta); // on revient dans le repère naturel // } // else // cas 3D // { Tenseur3HH sigHH_3_inter(sigHH_t); sigHH_3_inter.ChBase(gamma); // sig_HH_t_1D.Affectation_trans_dimension(sigHH_3_inter,false);// passage des tenseurs résultats à l'ordre 1 // Tenseur3BB DepsBB_3_inter(DepsBB); DepsBB_3_inter.ChBase(gamma); // Deps_BB_1D.Affectation_trans_dimension(DepsBB_3_inter,false); // Tenseur3BB epsBB_tdt_3_inter(epsBB_tdt);epsBB_tdt_3_inter.ChBase(gamma); // eps_BB_1D.Affectation_trans_dimension(epsBB_tdt_3_inter,false); // Tenseur3BB delta_epsBB_3_inter(delta_epsBB); delta_epsBB_3_inter.ChBase(gamma); // delta_eps_BB_1D.Affectation_trans_dimension(delta_epsBB_3_inter,false); // }; // normalement les contraintes sont nulles dans les directions autres que 11 sigHH.Affectation_trans_dimension(sig_HH_1D,true); #ifdef MISE_AU_POINT if (Permet_affichage() > 5) {Tenseur2HH sigHH_2_inter(sigHH); cout << "\n LoiCritere::Passage_1_vers_3ou2("; cout << "\n sigHH (en VP) affecté du resultat 1D = "; sigHH.Ecriture(cout); // en base orthonormee Tenseur3HH sigHH_3_inter; sig_HH_1D.BaseAbsolue(sigHH_3_inter,(giB_tdt_1D)); cout << "\n sigHH 1D =en orthonormee "< 8) || (Permet_affichage() > 5)) // cout << "\n test2: LoiCritere::Passage_1_vers_3ou2(... " << flush; // changement de base pour la contrainte // ici il s'agit de revenir à la base initiale il faut donc utiliser // l'inverse gamma c-a-d finalement beta transposée sigHH.ChBase(beta.Transpose()); // on revient dans le repère naturel #ifdef MISE_AU_POINT if (Permet_affichage() > 5) {Tenseur2HH sigHH_2_inter(sigHH); // cout << "\n debug LoiCritere::Passage_1_vers_3ou2("; cout << "\n sigHH en g_i après changement de base "; sigHH.Ecriture(cout); // en base orthonormee Tenseur3HH sigHH_3_inter; sigHH.BaseAbsolue(sigHH_3_inter,(* ex.giB_tdt)); cout << "\n sigHH = en orthonormee "<, const BaseB &gi) if (dim_tens == 2) { // un tenseur de travail qui contient l'opérateur tangent, mais transporté en 2D // if ((ParaGlob::NiveauImpression() > 8) || (Permet_affichage() > 5)) // cout << "\n test3: LoiCritere::Passage_1_vers_3ou2(... " << flush; Tenseur2HHHH tens_travail2HHHH; bool plusZero=true; tens_travail2HHHH.Affectation_trans_dimension(*d_sigma_deps_1D_P,plusZero); // construction de la base qui permet de passer des vecteurs propres au gi // donc on veut: V_al = beta_al^be g_be // il se trouve que c'est égal à la matrice passée en paramètre : beta(al,be) // if ((ParaGlob::NiveauImpression() > 8) || (Permet_affichage() > 5)) // cout << "\n test4: LoiCritere::Passage_1_vers_3ou2(... " << flush; BaseB V_al_B(2,2,0.); V_al_B.CoordoB(1)(1) = beta(1,1);V_al_B.CoordoB(1)(2) = beta(1,2); V_al_B.CoordoB(2)(1) = beta(2,1);V_al_B.CoordoB(2)(2) = beta(2,2); #ifdef MISE_AU_POINT if (Permet_affichage() > 5) {//cout << "\n debug LoiCritere::Passage_1_vers_3ou2("; // vérif du calcul de la base // cout << "\n BaseB des gi \n "<< (* ex.giB_tdt); cout << "\n construction d'une BaseB V_al_B pour cgt base tenseurHHHH \n "<< V_al_B; // calcul long BaseB V_inter_B(2,2,0.); for (int al = 1;al < 3; al++) for (int be = 1; be < 3; be++) V_inter_B.CoordoB(al)(be) = (* ex.giH_tdt).Coordo(be) * V_P_sig(al); cout << "\n BaseB V_inter_B "<< V_inter_B; // pour voir si la base est correcte on la teste sur le tenseur des contraintes Tenseur2HH sigHH_2_inter; // on exprime sigHH dans la base des V_P qui ici est considéré comme absolue pour la vérif sig_HH_1D.BaseAbsolue(sigHH_2_inter,V_al_B); cout << "\n verif via sig_HH_1D = dans la base des gi de nouveau \n "<ChangeBase(tens_travail2HHHH,gi_al_B); tens_travail2HHHH.ChangeBase(*d_sig_deps_2HHHH,V_al_B); } else // cas 3D { //if (d_sigma_deps_inter == NULL) // d_sigma_deps_inter = NevezTenseurHHHH(3); // la suite dépendra de l'application donc du critère, donc on met un message // pour l'instant cout << "\n pour l'instant la suite n'est pas codee !! se plaindre !! " << "\n LoiCritere::Passage_1_vers_3ou2(..." << endl; Sortie(2); }; // if ((ParaGlob::NiveauImpression() > 8) || (Permet_affichage() > 5)) // cout << "\n test7: LoiCritere::Passage_1_vers_3ou2(... " << flush; }; // fonction interne utilisée par les classes dérivées de Loi_comp_abstraite // pour répercuter les modifications de la température // ici utiliser pour modifier la température des lois élémentaires // l'Enum_dure: indique quel est la température courante : 0 t ou tdt void LoiCritere::RepercuteChangeTemperature(Enum_dure temps) { list ::const_iterator ili,ilifin=lois_internes.end(); for (ili=lois_internes.begin();ili!=ilifin;ili++) {(*ili)->temperature_0 = this->temperature_0; (*ili)->temperature_t = this->temperature_t; (*ili)->temperature_tdt = this->temperature_tdt; (*ili)->dilatation=dilatation; // on répercute également les déformations thermiques, qui ne sont utilisées // telles quelles que pour certaines lois: ex: loi hyper-élastique if (dilatation) {// a- dimensionnement des tenseurs intermédiaires int dim_tens = epsBB_therm->Dimension(); // -- cas de la déformation if ((*ili)->epsBB_therm == NULL) { (*ili)->epsBB_therm = NevezTenseurBB(dim_tens);} else if ((*ili)->epsBB_therm->Dimension() != dim_tens) { delete (*ili)->epsBB_therm;(*ili)->epsBB_therm = NevezTenseurBB(dim_tens);}; // -- cas de la vitesse de déformation if ((*ili)->DepsBB_therm == NULL) { (*ili)->DepsBB_therm = NevezTenseurBB(dim_tens);} else if ((*ili)->DepsBB_therm->Dimension() != dim_tens) { delete (*ili)->DepsBB_therm;(*ili)->DepsBB_totale = NevezTenseurBB(dim_tens);}; // b- affectation des tenseurs (*(*ili)->epsBB_therm)=(*epsBB_therm); (*(*ili)->DepsBB_therm)=(*DepsBB_therm); }; (*ili)->RepercuteChangeTemperature(temps); switch (temps) { case TEMPS_0: {(*ili)->temperature = &(*ili)->temperature_0; break;} case TEMPS_t: {(*ili)->temperature = &(*ili)->temperature_t; break;} case TEMPS_tdt: {(*ili)->temperature = &(*ili)->temperature_tdt; break;} default: { cout << "\n erreur, cas de temps non prevu !! " << "\n LoiCritere::RepercuteChangeTemperature(..."; Sortie(1); }; }; }; }; // fonction surchargée dans les classes dérivée si besoin est void LoiCritere::CalculGrandeurTravail (const PtIntegMecaInterne& ptintmeca ,const Deformation & def,Enum_dure temps,const ThermoDonnee& dTP ,const Met_abstraite::Impli* ex_impli ,const Met_abstraite::Expli_t_tdt* ex_expli_tdt ,const Met_abstraite::Umat_cont* ex_umat ,const List_io* exclure_dd_etend ,const List_io* exclure_Q ) { if (avec_ponderation) { // on passe en revue les grandeurs servant au calcul des fonctions de proportion list ::iterator il,ilfin=list_ponderation.end(); list ::iterator ipfonc = fonc_ponder.begin(); for (il=list_ponderation.begin();il != ilfin;il++,ipfonc++) { Ponderation& ponder = (*il); // pour simplifier (*ipfonc)=1.; // init int taille = ponder.Type_grandeur().Taille(); for (int i=1;i<= taille; i++) { // calcul des pondérations if (ponder.Valeur_aux_noeuds()(i)) // pour l'instant que des ddl patentés ! // cas d'une proportion provenant d'une interpolation aux noeuds { double grand = def.DonneeInterpoleeScalaire(ponder.Type_grandeur()(i).Enum(),temps); double fonc = ponder.C_proport()(i)->Valeur(grand); (*ipfonc) *= fonc; // on accumule multiplicativement } else // sinon il s'agit d'une grandeur directement accessible au point d'intégration // pour l'instant il n'y a pas de procédure générale de récupération, seulement des cas particuliers { // deux cas suivant que l'on a affaire à un ddl de base ou à un vrai ddl étendu if (ponder.Type_grandeur()(i).Nom_vide()) {switch (ponder.Type_grandeur()(i).Enum()) { case PROP_CRISTA: { const double* taux_crita = dTP.TauxCrista(); if (taux_crita != NULL) { double fonc = ponder.C_proport()(i)->Valeur(*taux_crita); (*ipfonc) *= fonc; // on accumule multiplicativement } else {cout << "\n erreur, le taux de cristalinite n'est pas disponible au point d'integration " << " il n'est pas possible de calculer la proportion pour la loi des melanges " << "\n LoiCritere::CalculGrandeurTravail(.... "; }; break; } default: cout << "\n erreur, le type de proportion " << ponder.Type_grandeur()(i) << " n'est pas disponible " << " pour l'instant au point d'integration ! " << "\n LoiCritere::CalculGrandeurTravail(.... "; }; } else {// cas d'un vrai ddl étendue switch (ponder.Type_grandeur()(i).Position()-NbEnum_ddl()) {case 87: // cas de "def_equivalente" {const double def_equivalente = ptintmeca.Deformation_equi_const()(1); // recup de la def equi double fonc = ponder.C_proport()(i)->Valeur(def_equivalente); (*ipfonc) *= fonc; // on accumule multiplicativement //cout << "\n defEqui= " << def_equivalente << " fonct= " << fonc << " "; break; } case 88: // cas de "def_duale_mises_maxi" {const double def_duale_mises_maxi = ptintmeca.Deformation_equi_const()(3); // recup de la def equi double fonc = ponder.C_proport()(i)->Valeur(def_duale_mises_maxi); (*ipfonc) *= fonc; // on accumule multiplicativement break; } case 89: // cas de "vitesse_def_equivalente" {const double delta_def_equivalente = ptintmeca.Deformation_equi_const()(4); // recup du delta def equi // recup de l'incrément de temps double deltat=ParaGlob::Variables_de_temps().IncreTempsCourant(); double unSurDeltat=0; if (Abs(deltat) >= ConstMath::trespetit) {unSurDeltat = 1./deltat;} else // si l'incrément de temps est tres petit on remplace 1/deltat par un nombre tres grand { // un pas de temps doit être positif !! or certaine fois il peut y avoir des pb if (unSurDeltat < 0) { cout << "\n le pas de temps est négatif !! "; }; unSurDeltat = ConstMath::tresgrand; }; double vitesse_def_equi = delta_def_equivalente * unSurDeltat; double fonc = ponder.C_proport()(i)->Valeur(vitesse_def_equi); (*ipfonc) *= fonc; // on accumule multiplicativement //cout << "\n vit= " << vitesse_def_equi << " f= " << fonc << endl; break; } case 77: // cas de "def_duale_mises" {const double def_duale_mises = ptintmeca.Deformation_equi_const()(2); // recup de la def equi double fonc = ponder.C_proport()(i)->Valeur(def_duale_mises); (*ipfonc) *= fonc; // on accumule multiplicativement break; } case 78: // cas de "Spherique_eps" {const Vecteur & epsInvar = ptintmeca.EpsInvar_const(); // recup des invariants double spherique_eps = epsInvar(1); double fonc = ponder.C_proport()(i)->Valeur(spherique_eps); (*ipfonc) *= fonc; // on accumule multiplicativement break; } case 81: // cas de "Spherique_sig" {const Vecteur & sigInvar = ptintmeca.SigInvar_const(); // recup des invariants double spherique_sig = sigInvar(1); double fonc = ponder.C_proport()(i)->Valeur(spherique_sig); (*ipfonc) *= fonc; // on accumule multiplicativement break; } default: cout << "\n erreur, le type de proportion " << ponder.Type_grandeur()(i) << " n'est pas disponible " << " pour l'instant au point d'integration ! " << "\n LoiCritere::CalculGrandeurTravail(.... "; break; }; }; }; }; }; }; // enregistrement dans les variables spécifiques au point calculé SaveResul_LoiCritere & save_resul = *((SaveResul_LoiCritere*) saveResul); save_resul.f_ponder = fonc_ponder; // on initialise le niveau de déclanchement avec les grandeurs de la lois // si la valeur est différente de 0, sinon ce sera 1. // if (niveau_declenchement_critere != 0.) // {save_resul.niveau_declenchement_critere = niveau_declenchement_critere;} // else // {save_resul.niveau_declenchement_critere = 1.;}; // init par défaut save_resul.niveau_declenchement_critere = niveau_declenchement_critere; if (avecNiveauSigmaI_mini_pour_plis) {// on initialise le niveau de déclanchement avec les grandeurs de la lois // si la valeur est différente de 0, sinon ce sera 1. // car en multiplication, si on par de 0 cela donnera toujours 0 // if (niveau_declenchement_critere == 0.) // {save_resul.niveau_declenchement_critere = 1.;}; // non on ne fait pas cela sinon c'est compliqué à comprendre // donc si on est dans un niveau réglable, systématiquement on met 1. // ce qui fait que l'on a directement la valeur de la fonction save_resul.niveau_declenchement_critere = 1.; if (niveauF_fct_nD != NULL) { // on appel la fonction générique list list_save; // inter pour l'appel de la fonction list_save.push_back(saveResul); Tableau & tab = Loi_comp_Valeur_FnD_Evoluee (niveauF_fct_nD->C_proport(),1 ,ex_impli,ex_expli_tdt,ex_umat ,exclure_dd_etend,exclure_Q ,&list_save ); // // comme il s'agit d'une grandeur globale, on n'a pas besoin de la récupérer // double fonc = niveauF_fct_nD->C_proport()->Valeur_pour_variables_globales()(1); // save_resul.niveau_declenchement_critere *= fonc; save_resul.niveau_declenchement_critere *= tab(1); }; if (niveauF_temps != NULL) // cas d'une dépendance au temps { const VariablesTemps& var_temps = ParaGlob::Variables_de_temps(); double fonc = niveauF_temps->Valeur(var_temps.TempsCourant()); save_resul.niveau_declenchement_critere *= fonc; }; // avec une dépendance via éventuellement un ddl étendu if (niveauF_ddlEtendu != NULL) { Ponderation& ponder = *niveauF_ddlEtendu; // pour simplifier double fonc_finale = 1.; // init int taille = ponder.Type_grandeur().Taille(); for (int i=1;i<= taille; i++) { // calcul des pondérations if (ponder.Valeur_aux_noeuds()(i)) // pour l'instant que des ddl patentés ! // cas d'une proportion provenant d'une interpolation aux noeuds { double grand = def.DonneeInterpoleeScalaire(ponder.Type_grandeur()(i).Enum(),temps); double fonc = ponder.C_proport()(i)->Valeur(grand); fonc_finale *= fonc; // on accumule multiplicativement } else // sinon il s'agit d'une grandeur directement accessible au point d'intégration // pour l'instant il n'y a pas de procédure générale de récupération, seulement des cas particuliers { // deux cas suivant que l'on a affaire à un ddl de base ou à un vrai ddl étendu if (ponder.Type_grandeur()(i).Nom_vide()) {switch (ponder.Type_grandeur()(i).Enum()) { case PROP_CRISTA: { const double* taux_crita = dTP.TauxCrista(); if (taux_crita != NULL) { double fonc = ponder.C_proport()(i)->Valeur(*taux_crita); fonc_finale *= fonc; // on accumule multiplicativement } else {cout << "\n erreur, le taux de cristalinite n'est pas disponible au point d'integration " << " il n'est pas possible de calculer le niveau_declenchement_critere " << "\n LoiCritere::CalculGrandeurTravail(.... "; }; break; } default: cout << "\n erreur, le type " << ponder.Type_grandeur()(i) << " n'est pas disponible " << " pour l'instant au point d'integration ! " << "\n LoiCritere::CalculGrandeurTravail(.... "; }; } else {// cas d'un vrai ddl étendue switch (ponder.Type_grandeur()(i).Position()-NbEnum_ddl()) {case 87: // cas de "def_equivalente" {const double def_equivalente = ptintmeca.Deformation_equi_const()(1); // recup de la def equi double fonc = ponder.C_proport()(i)->Valeur(def_equivalente); fonc_finale *= fonc; // on accumule multiplicativement break; } case 88: // cas de "def_duale_mises_maxi" {const double def_duale_mises_maxi = ptintmeca.Deformation_equi_const()(3); // recup de la def equi double fonc = ponder.C_proport()(i)->Valeur(def_duale_mises_maxi); fonc_finale *= fonc; // on accumule multiplicativement break; } case 89: // cas de "vitesse_def_equivalente" {const double delta_def_equivalente = ptintmeca.Deformation_equi_const()(4); // recup du delta def equi // recup de l'incrément de temps double deltat=ParaGlob::Variables_de_temps().IncreTempsCourant(); double unSurDeltat=0; if (Abs(deltat) >= ConstMath::trespetit) {unSurDeltat = 1./deltat;} else // si l'incrément de temps est tres petit on remplace 1/deltat par un nombre tres grand { // un pas de temps doit être positif !! or certaine fois il peut y avoir des pb if (unSurDeltat < 0) { cout << "\n le pas de temps est négatif !! "; }; unSurDeltat = ConstMath::tresgrand; }; double vitesse_def_equi = delta_def_equivalente * unSurDeltat; double fonc = ponder.C_proport()(i)->Valeur(vitesse_def_equi); fonc_finale *= fonc; // on accumule multiplicativement break; } case 77: // cas de "def_duale_mises" {const double def_duale_mises = ptintmeca.Deformation_equi_const()(2); // recup de la def equi double fonc = ponder.C_proport()(i)->Valeur(def_duale_mises); fonc_finale *= fonc; // on accumule multiplicativement break; } case 78: // cas de "Spherique_eps" {const Vecteur & epsInvar = ptintmeca.EpsInvar_const(); // recup des invariants double spherique_eps = epsInvar(1); double fonc = ponder.C_proport()(i)->Valeur(spherique_eps); fonc_finale *= fonc; // on accumule multiplicativement break; } case 81: // cas de "Spherique_sig" {const Vecteur & sigInvar = ptintmeca.SigInvar_const(); // recup des invariants double spherique_sig = sigInvar(1); double fonc = ponder.C_proport()(i)->Valeur(spherique_sig); fonc_finale *= fonc; // on accumule multiplicativement break; } default: cout << "\n erreur, le type " << ponder.Type_grandeur()(i) << " n'est pas disponible " << " pour l'instant au point d'integration ! " << "\n LoiCritere::CalculGrandeurTravail(.... "; break; }; }; }; }; // on met à jour le niveau save_resul.niveau_declenchement_critere *= fonc_finale; }; }; // répercution sur les classes dérivées si besoin est list ::iterator isave=save_resul.liste_des_SaveResul.begin(); // pour les saveResul des lois list ::const_iterator ili,ilifin=lois_internes.end(); for (ili=lois_internes.begin();ili!=ilifin;ili++,isave++) {// passage des informations spécifique à la loi liste_des_SaveResul (*ili)->IndiqueSaveResult(*isave); (*ili)->IndiquePtIntegMecaInterne(ptintmeca_en_cours);// idem pour ptintmeca (*ili)->IndiqueDef_en_cours(def_en_cours); // idem pour def en cours (*ili)->CalculGrandeurTravail(ptintmeca,def,temps,dTP ,ex_impli,ex_expli_tdt,ex_umat,exclure_dd_etend,exclure_Q); }; }; // fonction critère de plissement de biel // en entrée: // implicit : si oui on est en implicite, sinon en explicite // retour: // 0 : il y a eu un pb que l'on n'a pas peu résoudre, rien n'a été modifié // 1 : le critère n'a rien modifié // 2 : l'application du critère conduit à une contrainte et un opérateur tangent nul int LoiCritere::Critere_plis_biel(bool en_base_orthonormee,TenseurHH & sigHH_t,TenseurBB& DepsBB ,TenseurBB & epsBB_tdt,TenseurBB & delta_epsBB,double& jacobien_0,double& jacobien ,TenseurHH& sigHH,TenseurHHHH& d_sigma_deps_inter ,EnergieMeca & energ,const EnergieMeca & energ_t,double& module_compressibilite ,double& module_cisaillement ,bool implicit,const Met_abstraite::Umat_cont& ex) {// dim et vérification int dim_tens = abs(sigHH.Dimension()); // normalement le critère ne s'applique que pour des tenseurs 1D #ifdef MISE_AU_POINT if (dim_tens != 1) { cout << "\n erreur le critere de plissement de biel ne peut s'appliquer que pour des lois 1D" << " \n LoiCritere::Critere_plis_biel(.."; Sortie(1); }; #endif SaveResul_LoiCritere & save_resul = *((SaveResul_LoiCritere*) saveResul); // on va utiliser la valeur de la contrainte, par contre on la ramène dans un repère normé // pour son intensité ce qui revient à calculer la trace du tenseur double sig_I = sigHH && (* ex.gijBB_tdt); int retour = 0; // init par défaut if (sig_I >= niveau_declenchement_critere) // pas de plis { // on se trouve dans le cas où rien n'est en compression, donc cas normal sans plissement retour = 1; //on signale save_resul.eps_pli.Zero(); // pas de pli répertorié } else { // on se trouve dans le cas où on a des plis // l'idée est de ce positionner au niveau du seuil de déclenchement, pour cela on va utiliser // un facteur multiplicatif de manière à pouvoir conserver un opérateur tangent cohérent avec le seuil // (si on impose dans une boucle de Newton, la contrainte on va récupérer une def méca et un opérateur // tangent par rapport à cette def méca. Du coup on ne pourra pas en déduire un opérateur tangent par // rapport à la def cinématique ...) // double rapport = niveau_declenchement_critere / (Dabs(sig_I)+ConstMath::pasmalpetit); // on annule la contrainte et sa contribution éventuelle à la raideur sigHH.Inita(0.); d_sigma_deps_inter.Inita(0.); // dans le cas explicite, ne sert à rien mais c'est rapide // comme marqueur de l'intensité des plis on utilise la def de compression save_resul.eps_pli(1) = epsBB_tdt && (* ex.gijHH_tdt); // d'autre part on définit le vecteur propre normé qui n'est autre que gi_1 normé int dim = ParaGlob::Dimension(); if (save_resul.V_P_sig == NULL) save_resul.V_P_sig = new Tableau ; Coordonnee zero(dim); // un vecteur nul save_resul.V_P_sig->Change_taille(2); // on n'a besoin que d'un vecteur // **** mais pour l'instant j'en mets 2 de manière à être cohérent avec les membranes // sinon pb en sortie des grandeurs Coordonnee inter = ex.giB_tdt->Coordo(1); (*save_resul.V_P_sig)(1)= inter.Normer(); retour = 2; }; return retour; }; // récupération de la variation relative d'épaisseur calculée: h/h0 // cette variation n'est utile que pour des lois en contraintes planes // - pour les lois 3D : retour d'un nombre très grand, indiquant que cette fonction est invalide // - pour les lois 2D def planes: retour de 0 // les infos nécessaires à la récupération , sont stockées dans saveResul // qui est le conteneur spécifique au point où a été calculé la loi double LoiCritere::HsurH0(SaveResul * saveResul) const { SaveResul_LoiCritere & save_resul = *((SaveResul_LoiCritere*) saveResul); switch (type_critere) { case PLISSEMENT_MEMBRANE: { // traitement des épaisseurs LoiContraintesPlanes::SaveResul_LoiContraintesPlanes * save_result_plan_inter // pour simplifier = (LoiContraintesPlanes::SaveResul_LoiContraintesPlanes *) (*(save_resul.liste_des_SaveResul.begin())); return save_result_plan_inter->hsurh0; break; } case PLISSEMENT_BIEL: { LoiContraintesPlanesDouble::SaveResul_LoiContraintesPlanesDouble * save_result_1DCP2_inter // pour simplifier = (LoiContraintesPlanesDouble::SaveResul_LoiContraintesPlanesDouble *) (*(save_resul.liste_des_SaveResul.begin())); return save_result_1DCP2_inter->hsurh0; break; } default : cout << "\nErreur : LoiCritere::HsurH0(.. non implante pour le critere " << Nom_Critere_Loi(type_critere) << " !\n"; Sortie(1); }; }; // premier type de calcul dans le cas d'un pli dans une seule direction void LoiCritere::Premie_type_calcul_en_un_pli(const TenseurBB & epsBB_tdt,const TenseurBB & delta_epsBB ,const TenseurHH & sigHH_t ,const double& jacobien_0,const double& jacobien ,EnergieMeca & energ,const EnergieMeca & energ_t ,const TenseurBB& DepsBB ,double& module_compressibilite,double& module_cisaillement ,const Tableau & V_Pr_H ,TenseurHH& sigHH,TenseurHHHH& d_sigma_deps_inter ,const Coordonnee2& valPropreSig ,const Met_abstraite::Umat_cont& ex) { SaveResul_LoiCritere & save_resul = *((SaveResul_LoiCritere*) saveResul); // les coordonnées des vecteurs propres sont exprimées dans l'ancienne base // on a donc // Vi_B(i) = gpB(i) = beta(i,j) * gB(j), i indice de ligne, j indice de colonne Mat_pleine beta(2,2); for (int i=1;i<3;i++) // < 3 donc de 1 à 2 for (int j=1;j<3;j++) beta(i,j) = V_Pr_H(i)(j); Mat_pleine gamma(beta.Inverse().Transpose()); // on calcule la matrice inverse // la matrice gamma correspond à la matrice de changement de base des g^i au gpH // gamma est l'inverse transposée // gpH(i) = gamma(i,j) * gH(j), i indice de ligne, j indice de colonne // c-a-d= gp^i = gamma^i_j * g^j // on va également définir une matrice de changement pour les tenseurs 3D Tableau V_Pr3D_H(3); // comme V_Pr est de dim 2, il faut transférer les coordonnées V_Pr3D_H(1)(1) = V_Pr_H(1)(1);V_Pr3D_H(1)(2) = V_Pr_H(1)(2); V_Pr3D_H(2)(1) = V_Pr_H(2)(1);V_Pr3D_H(2)(2) = V_Pr_H(2)(2); // le troisième est en local 0,0,1 V_Pr3D_H(3)(3) = 1.; Mat_pleine beta3D(3,3);// initialisée à 0 // d'abord les 2 vecteurs propres for (int i=1;i<3;i++) for (int j=1;j<4;j++) beta3D(i,j) = V_Pr3D_H(i)(j); // puis la normale beta3D(3,3) = 1.; Mat_pleine gamma3D(beta3D.Inverse().Transpose()); #ifdef MISE_AU_POINT // pour tester, on passe les contraintes dans le repère principal if (Permet_affichage() > 5) {Tenseur2HH sigHH_2_inter(sigHH); cout << "\n utilisation du repere ortho des vecteurs propres: V_P "; cout << "\n sigHH= en giB : "; sigHH.Ecriture(cout); cout << "\n base giB(1) "<< (* ex.giB_tdt)(1) << "\n base giB(2) "<< (* ex.giB_tdt)(2); // en base orthonormee Tenseur3HH sigHH_3_inter; sigHH.BaseAbsolue(sigHH_3_inter,(* ex.giB_tdt)); // TenseurHH* ptHH = NevezTenseurHH((*(*isig))); // (*(*isig)).BaseAbsolue(*ptHH,giB); cout << "\n sigHH= en absolue 3D : "< beta= ";beta.Affiche(); cout << "\n sigHH_2_inter avant chgt= "<< sigHH_2_inter; sigHH_2_inter.ChBase(gamma,false); cout << "\n sigHH= en V_P : "<< sigHH_2_inter; // on revient à la base de départ pour vérifier que l'opération inverse ne pose // pas de pb sigHH_2_inter.ChBase(beta.Transpose(),false); cout << "\n verif: sigHH après retour au repère initial giB: "; sigHH_2_inter.Ecriture(cout); //cout << "\n gamma * beta = "; (gamma * beta).Affiche(); cout << "\n vecteurs propres en 3D ortho: "; //<< (*save_resul.V_P_sig); cout << "\n VP1 "<< (*save_resul.V_P_sig)(1); cout << "\n VP2 "<< (*save_resul.V_P_sig)(2); cout << "\n VP3 "<< (*save_resul.V_P_sig)(3); // vérif des vecteurs propres Coordonnee3B VpB1; VpB1.Change_val((*save_resul.V_P_sig)(1)); Coordonnee3H VpropreH1 = sigHH_3_inter * VpB1; //cout << "\n sigHH_3_inter * VP1 "<< VpropreH1; VpropreH1 /= (valPropreSig(1)+ConstMath::petit); cout << "\n (sigHH_3_ortho * VP1) / (lambda1+epsilon)= "<< VpropreH1; Coordonnee3B VpB2; VpB2.Change_val((*save_resul.V_P_sig)(2)); Coordonnee3H VpropreH2 = sigHH_3_inter * VpB2; //cout << "\n sigHH_3_inter * VP2 "<< VpropreH2; VpropreH2 /= (valPropreSig(2)+ConstMath::petit); cout << "\n (sigHH_3_ortho * VP2) / (lambda2+epsilon)= "<< VpropreH2; }; #endif { // --il faut créer un save_result pour l'appel des contraintes doublement planes // on récupère le conteneur qui bien qu'associé à une loi CP, est également // en réalité un conteneur CP2 car c'est comme cela qu'il a été créé via // LoiCritere::LoiCritere::New_et_Initialise() //*** là il va falloir revoir cette partie, car en fait ce n'est pas sûr qui faut utiliser un conteneur intermédiaire //*** cela pose pas mal de pb, car il faut de nouveau mettre à jour les infos du conteneur initial, dans le cas des lois //*** incrémentales, or pour l'instant ce n'est pas fait, ça c'est une erreur /* *** l'idée initiale était que l'utilisation du 1D était transitoire en particulier d'une itération à l'autre. donc supposons qu'à une itération on ait un plis dans une direction, on change toutes les grandeurs tensorielles en fonction de cette direction (par exemple les tenseurs de ref) et donc à l'itération suivante on n'aura plus le même état de démarrage. Mais ... en fait on remet les choses dans le repère initial à la fin du traitement: save_resul.save_result_1DCP2->ChBase_des_grandeurs(gamma3D); donc dans ce cas là, je ne comprends pas pourquoi on utilise pas directement le conteneur initial Pour l'instant, je laisse en l'état (25 nov 2015) et après la réunion avec le CNES, je vais faire les tests en incrémental et modifier car c'est possible qu'il y a quelque chose qui m'échappe. Par contre à minima je remets les def de largeur, dans le conteneur initial */ } LoiContraintesPlanesDouble::SaveResul_LoiContraintesPlanesDouble * save_result_1DCP2_inter // pour simplifier = (LoiContraintesPlanesDouble::SaveResul_LoiContraintesPlanesDouble *) (*(save_resul.liste_des_SaveResul.begin())); // on affecte les grandeurs à un conteneur de travail if (save_resul.save_result_1DCP2 == NULL) { SaveResul * inter = save_result_1DCP2_inter->Nevez_SaveResul(); save_resul.save_result_1DCP2 = ((LoiContraintesPlanesDouble::SaveResul_LoiContraintesPlanesDouble*) inter); } else // sinon on peut affecter directement *(save_resul.save_result_1DCP2) = *((Loi_comp_abstraite::SaveResul *) save_result_1DCP2_inter); // . -- changement de repère pour venir dans le nouveau repère ortho // on change toutes les infos tensorielles contenues pour qu'elles soient exprimées dans le nouveau repère // ceci ne concerne pas les grandeurs scalaires et les grandeurs exprimées dans le repère global // là il faut utiliser une matrice 3x3 car on a systématiquement des grandeurs 3D, car la loi interne est 3D save_resul.save_result_1DCP2->ChBase_des_grandeurs(beta3D,gamma3D); // il faut initialiser les métriques en 1D à null, pour qu'elles soient recalculer systématiquement car par exemple // la métrique à 0 change d'une itération à l'autre et d'un incrément à l'autre {Deformation::Stmet met_ref_00,met_ref_t,met_ref_tdt; // def de métrique vide, qui vont être construite pendant le calcul save_resul.save_result_1DCP2->Affectation_metriques_locale(met_ref_00,met_ref_t,met_ref_tdt); }; loi_1DCP2_de_3D->IndiquePtIntegMecaInterne(ptintmeca_en_cours); // on transmet le ptintmeca global loi_1DCP2_de_3D->IndiqueDef_en_cours(def_en_cours); // idem pour def en cours loi_1DCP2_de_3D->IndiqueSaveResult(save_resul.save_result_1DCP2); // on indique à la loi le conteneur qu'il faut utiliser ////-- debug -- {//#ifdef MISE_AU_POINT //if ( save_resul.save_result_1DCP2->meti_ref_00.giB_ != NULL) // cout << "\n debug Critere_plis_membrane "; //#endif ////-- fin debug -- // -- appel du programme de contraintes doublement planes -> récup des résultats dans le nouveau repère // 7 nov 2018: ?? normalement on est en base orthonormée ! bool base_orthonormee = false; } bool base_orthonormee = true; // conditionnnement de la nouvelle métrique Creation_metrique_a_partir_vecteurs_propres_pour_Umat1D(ex,beta); // chgt de variable pour les autres variables de passage: contrainte, def, D, delta eps ... #ifdef MISE_AU_POINT if (Permet_affichage() > 5) { //cout << "\n debug LoiCritere::Critere_plis_membrane("; // for (int a=1; a<4;a++) // {cout << "\n giH_0("<giB_0))(a).Affiche(); // cout << "\n giH_0("<giB_0))(a).Affiche(); // }; cout << "\n epsBB initial en local 2D "; epsBB_tdt.Ecriture(cout); // en orthonormee Tenseur3BB epsBB_3_inter; epsBB_tdt.BaseAbsolue(epsBB_3_inter,*(ex.giH_tdt)); cout << "\n epsBB d'entrée =en orthonormee "< 5) cout << "\n LoiCritere::Critere_plis_membrane ==> calcul en 1D CP2"; #endif loi_1DCP2_de_3D->Calcul_dsigma_deps(base_orthonormee,sig_HH_t_1D,Deps_BB_1D ,eps_BB_1D,delta_eps_BB_1D,jacobien_0_1D,jacobien_tdt_1D ,sig_HH_1D,d_sigma_deps_1D,energ,energ_t,module_compressibilite, module_cisaillement ,*umat_cont_1D); #ifdef MISE_AU_POINT if (Permet_affichage() > 4) { if (Permet_affichage() > 5) {cout << "\n\n ... LoiCritere::Critere_plis_membrane apres CP2: "; cout << "\n sig_HH_1D "<< sig_HH_1D; cout << "\n d_sigma_deps_1D "<< d_sigma_deps_1D; }; if ((!isfinite(d_sigma_deps_1D(1,1,1,1))) || (isnan(d_sigma_deps_1D(1,1,1,1))) ) {cout << "\n *** attention d_sigma_deps_3D(1,1,1,1)= "<< d_sigma_deps_1D(1,1,1,1); if (Ptintmeca_en_cours() != NULL) Ptintmeca_en_cours()->Signature(); cout << "\n LoiCritere::Critere_plis_membrane ==> calcul en 1D CP2"; cout << flush; //// --- pour le débug // loi_1DCP2_de_3D->Calcul_dsigma_deps(base_orthonormee,sig_HH_t_1D,Deps_BB_1D // ,eps_BB_1D,delta_eps_BB_1D,jacobien_0_1D,jacobien_tdt_1D // ,sig_HH_1D,d_sigma_deps_1D,energ,energ_t,module_compressibilite, module_cisaillement // ,*umat_cont_1D); //// ---fin debug }; Tenseur1HH deltasigHH = (d_sigma_deps_1D && delta_eps_BB_1D); cout << "\n deltasigHH "<< deltasigHH; cout << endl; }; #endif if (Permet_affichage() > 4) if (//(sig_HH_1D(1,1) <= -1.)|| (std::isinf(sig_HH_1D(1,1)))||( std::isnan(sig_HH_1D(1,1)))) {cout << "\n *** attention sig_HH_1D(1,1) negatif ou infinie (debug LoiCritere::Critere_plis_membrane(.. \n"; cout << sig_HH_1D(1,1) << endl; cout << "\n ***** erreur detectee : on continue quand meme ... "; // Sortie(2); }; // -- passage des résultats: sig, dsig, module, énergies dans l'ancien repère // passage inverse: chgt de repère et de dimension pour les variables de passage // et stockage des infos de doublement plane pour le post-traitement pour le prochain appel Passage_1_vers_3ou2(gamma,sigHH,d_sigma_deps_1D ,beta,d_sigma_deps_inter,ex,V_Pr_H ,*(save_resul.V_P_sig)); #ifdef MISE_AU_POINT if (Permet_affichage() > 5) { cout << "\n apres Passage_1_vers_3ou2, suite LoiCritere::Critere_plis_membrane"; cout << "\n sigHH en giB: "; sigHH.Ecriture(cout); cout << "\n d_sigma_deps_inter en giB: ";d_sigma_deps_inter.Ecriture(cout); Tenseur2HH deltasigHH = (d_sigma_deps_inter && delta_epsBB); cout << "\n deltasig2HH en giB: "<< deltasigHH; cout << endl; }; #endif if (Permet_affichage() > 4) for (int al = 1; al<3;al++) for (int be=1;be<3;be++) if (//(sigHH(al,be) < 0.)|| (std::isinf(sigHH(al,be))||( std::isnan(sigHH(al,be))))) {cout << "\n *** attention (sigHH("<ChBase_des_grandeurs(beta3D,gamma3D); // on met à jour les def de largeur et d'épaisseur sur le conteneur initial save_result_1DCP2_inter->Transfert_var_hetb(*save_resul.save_result_1DCP2); }; // deuxième type de calcul dans le cas d'un pli dans une seule direction void LoiCritere::Deuxieme_type_calcul_en_un_pli (const TenseurBB & epsBB_tdt,const TenseurBB & delta_epsBB ,const TenseurHH & sigHH_t ,double& jacobien_0,double& jacobien ,EnergieMeca & energ,const EnergieMeca & energ_t ,const TenseurBB& DepsBB ,double& module_compressibilite,double& module_cisaillement ,const Tableau & V_Pr_H ,TenseurHH& sigHH,TenseurHHHH& d_sigma_deps_inter ,const Coordonnee2& valPropreSig ,const Met_abstraite::Umat_cont& ex ) { SaveResul_LoiCritere & save_resul = *((SaveResul_LoiCritere*) saveResul); // le conteneur Met_abstraite::Umat_cont& ex correspond à une métrique 2D // il nous faut l'équivalent en 3D, on se sert de la loi cp et de la méthode ad hoc const Met_abstraite::Umat_cont* ex3D = loi_2DCP_de_3D->Passage_metrique_ordre2_vers_3(ex); // en fait le repère 2D a été complété par la normale aux 2 premiers vecteurs // -- en entrée on connait la direction des vecteurs propres de contrainte // correspondant au calcul sans prise en compte de pli // on va calculer les bases associées: ViB et ViH: ici 3 vecteurs en 3D // a) ViH = les vecteurs en contravariant: c'est en fait = V_Pr_H pour // les 2 premiers vecteurs // mais on doit passer de 2D en 3D, manuellement ViH.CoordoH(1)(1) = V_Pr_H(1)(1);ViH.CoordoH(1)(2) = V_Pr_H(1)(2); ViH.CoordoH(1)(3) = 0.; // normalement pas de composante suivant la normale ViH.CoordoH(2)(1) = V_Pr_H(2)(1);ViH.CoordoH(2)(2) = V_Pr_H(2)(2); ViH.CoordoH(2)(3) = 0.; // normalement pas de composante suivant la normale // pour le 3 ième vecteur on se sert des grandeurs sauvegardées for (int i=1;i<4;i++) // < 4 donc de 1 à 3 ViH.CoordoH(3)(i) = (*save_resul.V_P_sig)(3) * ex3D->giH_tdt->Coordo(i); // b) ViB -> là il faut les calculer // on choisit d'utiliser les grandeurs stockées qui représentent les // les vecteurs orthonormées for (int j=1;j<4;j++) for (int i=1;i<4;i++) // < 4 donc de 1 à 3 ViB.CoordoB(j)(i) = (*save_resul.V_P_sig)(j) * ex3D->giB_tdt->Coordo(i); // on calcul les def de plis : save_resul.eps_pli Mat_pleine beta(2,2); for (int i=1;i<3;i++) // < 3 donc de 1 à 2 for (int j=1;j<3;j++) beta(i,j) = V_Pr_H(i)(j); Mat_pleine gamma(beta.Inverse().Transpose()); // on calcule la matrice inverse Tenseur2BB epsBB_tdt_2_inter(epsBB_tdt);epsBB_tdt_2_inter.ChBase(beta); save_resul.eps_pli(1) = epsBB_tdt_2_inter(2,2); // on sauvegarde les def de plis save_resul.eps_pli(2) = 0.; // cas d'un seul plis #ifdef MISE_AU_POINT // pour tester et afficher: calcul des matrices de changement de base if (Permet_affichage() > 5) {// les coordonnées des vecteurs propres sont exprimées dans l'ancienne base // on a donc // Vi_B(i) = gpB(i) = beta(i,j) * gB(j), i indice de ligne, j indice de colonne // Mat_pleine beta(2,2); // for (int i=1;i<3;i++) // < 3 donc de 1 à 2 // for (int j=1;j<3;j++) // beta(i,j) = V_Pr_H(i)(j); Mat_pleine gamma(beta.Inverse().Transpose()); // on calcule la matrice inverse // la matrice gamma correspond à la matrice de changement de base des g^i au gpH // gamma est l'inverse transposée // gpH(i) = gamma(i,j) * gH(j), i indice de ligne, j indice de colonne // c-a-d= gp^i = gamma^i_j * g^j // on va également définir une matrice de changement pour les tenseurs 3D Tableau V_Pr3D_H(3); // comme V_Pr est de dim 2, il faut transférer les coordonnées V_Pr3D_H(1)(1) = V_Pr_H(1)(1);V_Pr3D_H(1)(2) = V_Pr_H(1)(2); V_Pr3D_H(2)(1) = V_Pr_H(2)(1);V_Pr3D_H(2)(2) = V_Pr_H(2)(2); // le troisième est en local 0,0,1 V_Pr3D_H(3)(3) = 1.; Mat_pleine beta3D(3,3);// initialisée à 0 // d'abord les 2 vecteurs propres for (int i=1;i<3;i++) for (int j=1;j<4;j++) beta3D(i,j) = V_Pr3D_H(i)(j); // puis la normale beta3D(3,3) = 1.; Mat_pleine gamma3D(beta3D.Inverse().Transpose()); Tenseur2HH sigHH_2_inter(sigHH); cout << "\n utilisation du repere ortho des vecteurs propres: V_P "; cout << "\n sigHH= en giB : "; sigHH.Ecriture(cout); cout << "\n base giB(1) "<< (* ex3D->giB_tdt)(1) << "\n base giB(2) "<< (* ex3D->giB_tdt)(2); // en base orthonormee Tenseur3HH sigHH_3_inter; sigHH.BaseAbsolue(sigHH_3_inter,(* ex3D->giB_tdt)); cout << "\n sigHH= en absolue 3D : "< beta= ";beta.Affiche(); cout << "\n sigHH_2_inter avant chgt= "<< sigHH_2_inter; sigHH_2_inter.ChBase(gamma,false); cout << "\n sigHH= en V_P : "<< sigHH_2_inter; // on revient à la base de départ pour vérifier que l'opération inverse ne pose // pas de pb sigHH_2_inter.ChBase(beta.Transpose(),false); cout << "\n verif: sigHH après retour au repère initial giB: "; sigHH_2_inter.Ecriture(cout); //cout << "\n gamma * beta = "; (gamma * beta).Affiche(); cout << "\n vecteurs propres en 3D ortho: "; //<< (*save_resul.V_P_sig); cout << "\n VP1 "<< (*save_resul.V_P_sig)(1); cout << "\n VP2 "<< (*save_resul.V_P_sig)(2); cout << "\n VP3 "<< (*save_resul.V_P_sig)(3); // vérif des vecteurs propres Coordonnee3B VpB1; VpB1.Change_val((*save_resul.V_P_sig)(1)); Coordonnee3H VpropreH1 = sigHH_3_inter * VpB1; //cout << "\n sigHH_3_inter * VP1 "<< VpropreH1; VpropreH1 /= (valPropreSig(1)+ConstMath::petit); cout << "\n (sigHH_3_ortho * VP1) / (lambda1+epsilon)= "<< VpropreH1; Coordonnee3B VpB2; VpB2.Change_val((*save_resul.V_P_sig)(2)); Coordonnee3H VpropreH2 = sigHH_3_inter * VpB2; //cout << "\n sigHH_3_inter * VP2 "<< VpropreH2; VpropreH2 /= (valPropreSig(2)+ConstMath::petit); cout << "\n (sigHH_3_ortho * VP2) / (lambda2+epsilon)= "<< VpropreH2; }; #endif LoiContraintesPlanesDouble::SaveResul_LoiContraintesPlanesDouble * save_result_1DCP2_inter // pour simplifier = (LoiContraintesPlanesDouble::SaveResul_LoiContraintesPlanesDouble *) (*(save_resul.liste_des_SaveResul.begin())); loi_1DCP2_de_3D->IndiqueSaveResult(save_result_1DCP2_inter); // on indique à la loi le conteneur qu'il faut utiliser loi_1DCP2_de_3D->IndiquePtIntegMecaInterne(ptintmeca_en_cours); // on transmet le ptintmeca global loi_1DCP2_de_3D->IndiqueDef_en_cours(def_en_cours); // idem pour def en cours bool base_orthonormee = false; // ici on va travailler avec les gi // on utilise donc la métrique passée en paramètre #ifdef MISE_AU_POINT if (Permet_affichage() > 5) { //cout << "\n debug LoiCritere::Critere_plis_membrane("; // for (int a=1; a<4;a++) // {cout << "\n giH_0("<giB_0))(a).Affiche(); // cout << "\n giH_0("<giB_0))(a).Affiche(); // }; cout << "\n epsBB initial en local 2D "; epsBB_tdt.Ecriture(cout); // en orthonormee Tenseur3BB epsBB_3_inter; epsBB_tdt.BaseAbsolue(epsBB_3_inter,*(ex.giH_tdt)); cout << "\n epsBB d'entrée =en orthonormee "< 5) { cout << "\n LoiCritere::Critere_plis_membrane ==> calcul en 3D CP2"; } #endif loi_1DCP2_de_3D->Calcul_dsigma_deps (base_orthonormee,&ViB,&ViH,sig_HH_t_3D,Deps_BB_3D ,eps_BB_3D,delta_eps_BB_3D,jacobien_0,jacobien ,sig_HH_3D,d_sig_deps_3D_HHHH ,energ,energ_t ,module_compressibilite,module_cisaillement ,*ex3D); #ifdef MISE_AU_POINT if (Permet_affichage() > 5) { cout << "\n\n ... LoiCritere::Deuxieme_type_calcul_en_un_pli apres CP2: "; cout << "\n sigHH_3D en giB: "; sig_HH_3D.Ecriture(cout); if (Permet_affichage() > 6) {cout << "\n d_sig_deps_3D_HHHH en giB: ";d_sig_deps_3D_HHHH.Ecriture(cout);}; Tenseur3HH deltasigHH = (d_sig_deps_3D_HHHH && delta_eps_BB_3D); cout << "\n deltasig3HH en giB: "<< deltasigHH; cout << endl; }; #endif if (Permet_affichage() > 4) {bool erreur = false; for (int al = 1; al<4;al++) for (int be=1;be<4;be++) if (//(sigHH(al,be) < 0.)|| (std::isinf(sig_HH_3D(al,be))||( std::isnan(sig_HH_3D(al,be))))) {cout << "\n *** attention (sigHH_3D("< // mise à jour de save_resul.eps_pli // *** a supprimer le passage de save_resul.eps_pli // car c'est une erreur bool deux_plis = false; Passage_contrainte_et_operateur_tangent_ordre2_vers_3 (sigHH,d_sigma_deps_inter,deux_plis,save_resul.eps_pli); #ifdef MISE_AU_POINT if (Permet_affichage() > 5) { cout << "\n retour en dim 2 : "; cout << "\n sigHH en giB: "; sigHH.Ecriture(cout); cout << "\n d_sig_deps_HHHH en giB: ";d_sigma_deps_inter.Ecriture(cout); Tenseur2HH deltasigHH = (d_sigma_deps_inter && delta_epsBB); cout << "\n deltasig2HH en giB: "<< deltasigHH; cout << endl; }; #endif }; // fonction pre_critère de plissement de membrane // dans le cas d'un critère pli (plutôt seconde méthode), l'incrément de déformation // dépend de la situation précédente: avec pli ou pas // du coup on utilise un delta_eps intermédiaire au lieu du delta cinématique // ce deltat_eps doit être précalculé // en entrée: // implicit : si oui on est en implicite, sinon en explicite // retour: void LoiCritere::Pre_Critere_plis_membrane (TenseurBB & epsBB_tdt_,TenseurBB & delta_epsBB ,const Met_abstraite::Expli_t_tdt* ex_expli ,const Met_abstraite::Impli* ex_impli ,const Met_abstraite::Umat_cont* ex_umat ) { // on commence par récupérer les métriques en fonctions du conteneur ex valide const Tenseur2HH * gijHH_; // pour simplifier const Tenseur2BB * gijBB_; // " " " " const Tenseur2HH * gijHH_t_; // " " " " const Tenseur2BB * gijBB_t_; // " " " " if (ex_expli != NULL) { gijHH_ = ((Tenseur2HH*) ex_expli->gijHH_tdt); // pour simplifier gijBB_ = ((Tenseur2BB*) ex_expli->gijBB_tdt); // " " " " gijHH_t_ = ((Tenseur2HH*) ex_expli->gijHH_t); // " " " " gijBB_t_ = ((Tenseur2BB*) ex_expli->gijBB_t); // " " " " } else if (ex_impli != NULL) { gijHH_ = ((Tenseur2HH*) ex_impli->gijHH_tdt); // pour simplifier gijBB_ = ((Tenseur2BB*) ex_impli->gijBB_tdt); // " " " " gijHH_t_ = ((Tenseur2HH*) ex_impli->gijHH_t); // " " " " gijBB_t_ = ((Tenseur2BB*) ex_impli->gijBB_t); // " " " " } else if (ex_umat != NULL) { gijHH_ = ((Tenseur2HH*) ex_umat->gijHH_tdt); // pour simplifier gijBB_ = ((Tenseur2BB*) ex_umat->gijBB_tdt); // " " " " gijHH_t_ = ((Tenseur2HH*) ex_umat->gijHH_t); // " " " " gijBB_t_ = ((Tenseur2BB*) ex_umat->gijBB_t); // " " " " } else {cout << "\n **** erreur: pas de conteneur de metrique disponible ..." << "\n LoiCritere::Pre_Critere_plis_membrane(..."; Sortie(1); }; const Tenseur2HH & gijHH = *gijHH_; // pour simplifier const Tenseur2BB & gijBB = *gijBB_; // " " " " const Tenseur2HH & gijHH_t = *gijHH_t_; // " " " " const Tenseur2BB & gijBB_t = *gijBB_t_; // " " " " // et la déformation const Tenseur2BB & epsBB_tdt = *((Tenseur2BB*) &epsBB_tdt_); // " " " " SaveResul_LoiCritere & save_resul = *((SaveResul_LoiCritere*) saveResul); int retour = 0; // init par défaut LoiContraintesPlanesDouble::SaveResul_LoiContraintesPlanesDouble * save_result_1DCP2_inter // pour simplifier = (LoiContraintesPlanesDouble::SaveResul_LoiContraintesPlanesDouble *) (*(save_resul.liste_des_SaveResul.begin())); // l'objectif est de mettre à jour : delta_eps_BB_2D delta_eps_BB_2D = delta_epsBB; // initialisation par défaut // on regarde l'état précédent: sans plis, avec un pli, avec 2 plis ? int cas_cal_plis_t = save_resul.cas_cal_plis_t; // en fait seule les cas avec un deux plis, sans erreur, sont exploitables // ou le cas sans pli, pour tous les autres cas, on considèrera qu'il n'y avait pas de plis // car les infos sauvegardées (def méca) ne sont pas correctes switch (save_resul.cas_cal_plis_t) { case -1: case 1: case -2: case -3: case -4:// pas de plis {// a priori rien à faire, delta_eps_BB_2D a déjà été initialisée break; } case 2: case 3: // plis dans une seule directions ou dans deux directions { // L'incrément de déformation, entre t et t+dt est obtenu par la différence entre les // déformations t+dt et les déformations mécaniques à t, transportée de manière cohérente // avec la dérivée de Jauman à t+dt: 1/2 deux fois covariant + deux fois contra // a) on commence par récupérer les def méca à l'instant t Tenseur3BB& eps_mecaBB_t = *((Tenseur3BB*) (save_result_1DCP2_inter->eps_mecaBB_t)); // la déformation 33 est directement gérée par la loi 2D CP via les variations d'épaisseurs // sachant que l'axe 3 est indépendant des deux autres axes donc on ne s'en occupe pas eps_BB_2D_t.Affectation_3D_a_2D(eps_mecaBB_t); // b) on fait le transport cohérent avec Jauman eps_HH_2D_t = gijHH_t * eps_BB_2D_t * gijHH_t; delta_epsBB = epsBB_tdt - 0.5 * (gijBB * eps_HH_2D_t * gijBB + eps_BB_2D_t); break; } case 0: // cas où aucun calcul n'a encore été effectué on n'a rien n'a faire break; default: // normalement n'arrive jamais car Calcul_directions_plis a toujours une solution diff de 0 { cout << "\n *** cas d'erreur inconnue dans le calcul de la direction des plis " << " save_resul.cas_cal_plis= "<< save_resul.cas_cal_plis << "\n LoiCritere::Pre_Critere_plis_membrane(... "; Sortie(1); break; } }; }; // passage des informations liées à la déformation de 2 vers 3 void LoiCritere::Passage_deformation_contrainte_ordre2_vers_3 (const TenseurBB& DepsBB,const TenseurBB & epsBB_tdt ,const TenseurBB & delta_epsBB,const TenseurHH& sig_HH_t) { // on complète avec des 0 bool plusZero = true; Deps_BB_3D.Affectation_2D_a_3D(*((Tenseur2BB*) &DepsBB),plusZero); eps_BB_3D.Affectation_2D_a_3D(*((Tenseur2BB*) &epsBB_tdt),plusZero); delta_eps_BB_3D.Affectation_2D_a_3D(*((Tenseur2BB*) &delta_epsBB),plusZero); sig_HH_t_3D.Affectation_2D_a_3D(*((Tenseur2HH*) &sig_HH_t),plusZero); }; // passage des informations liées à la nouvelle contrainte de 2 vers 3 // et à l'opérateur tangent : méthode 2 void LoiCritere::Passage_contrainte_et_operateur_tangent_ordre2_vers_3 (TenseurHH& sig_HH_tdt_,TenseurHHHH& d_sig_deps_HHHH_ ,const bool& deux_plis,Coordonnee2& eps_pli) { // normalement les directions 1 et 2 sont identiques en 2D et 3D // on recopie donc simplement les grandeurs Tenseur2HH & sigHH = *((Tenseur2HH*) &sig_HH_tdt_); // " " " " sigHH.Affectation_3D_a_2D(sig_HH_3D); // idem pour l'opérateur tangent Tenseur2HHHH & d_sig_deps_HHHH = *((Tenseur2HHHH*) &d_sig_deps_HHHH_); // pour simplifier d_sig_deps_HHHH.TransfertDunTenseurGeneral(d_sig_deps_3D_HHHH); /* Lorsqu'il y a un pli dans une seule direction, le premier vecteur indique la direction selon laquelle la membrane est en traction. Son intensité est égale à la déformation mécanique dans cette même direction. Le second vecteur est normal à la première direction, son intensité est égale à la déformation cinématique selon cette direction, c'est-à-dire calculée à l'aide des déplacements des noeuds du maillage. Cette déformation est différente de la déformation mécanique calculée par la loi 3D, c'est-à-dire issue de la contraction de la zone, due à la traction suivant la première direction. Cette déformation mécanique peut-être récupéré via la deformation "DEF\_LARGEUR" associée à la loi de comportement. Lorsqu'il y a des plis dans deux directions, les deux vecteurs indiquent les directions principales d'apparition de plis. L'intensité des vecteurs est égale à la déformation cinématique dans la direction associée. Lorsqu'il n'y a pas de plis, l'intensité des vecteurs est nulle. */ //--- modif 24 sept 2020: // les def pour les plis ont déjà été calculées dans LoiCritere::Passage_3ou2_vers_1(.. // et il s'agit uniquement de def cinématique donc la suite n'est pas nécessaire et même incorrecte // SaveResul_LoiCritere & save_resul = *((SaveResul_LoiCritere*) saveResul); // LoiContraintesPlanesDouble::SaveResul_LoiContraintesPlanesDouble * save_result_1DCP2_inter // pour simplifier // = (LoiContraintesPlanesDouble::SaveResul_LoiContraintesPlanesDouble *) // (*(save_resul.liste_des_SaveResul.begin())); // Tenseur3BB& eps_mecaBB = *((Tenseur3BB*) (save_result_1DCP2_inter->eps_mecaBB)); // // eps_pli(1) = eps_mecaBB(2,2); // on sauvegarde les def de plis // if (deux_plis) // cas où il y aurait des plis dans les deux sens // eps_pli(2) = eps_mecaBB(1,1); // else eps_pli(2) = 0.; // cas d'un seul plis // Tenseur3BB& eps_P_mecaBB = *((Tenseur3BB*) (save_result_1DCP2_inter->eps_P_mecaBB)); // // eps_pli(1) = eps_P_mecaBB(2,2); // on sauvegarde les def de plis // if (deux_plis) // cas où il y aurait des plis dans les deux sens // eps_pli(2) = eps_P_mecaBB(1,1); // else eps_pli(2) = 0.; // cas d'un seul plis };