// 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 "ElemMeca.h" #include #include "ConstMath.h" #include "Util.h" #include "Coordonnee2.h" #include "Coordonnee3.h" #include "TypeQuelconqueParticulier.h" #include "TypeConsTens.h" #include "Loi_iso_elas3D.h" #include "Loi_iso_elas1D.h" #include "Loi_iso_elas2D_C.h" #include "FrontPointF.h" #include "MathUtil2.h" #include "Enum_StabMembrane.h" // -------------------- stabilisation d'hourglass ------------------- // calcul d'élément de contrôle d'hourglass associée à un comportement // str_precision : donne le type particulier d'élément à construire void ElemMeca::Init_hourglass_comp(const ElemGeomC0& elgeHour, const string & str_precision ,LoiAbstraiteGeneral * loiHourglass, const BlocGen & bloc) { //!!!! en fait pour l'instant on n'utilise pas elgehour, on considère que le nombre de pti complet est celui de l'élément sans info annexe !!! // sauf pour l'hexaèdre quadratique pour lequel on a définit un str_precision particulier // on met à jour les indicateurs if (Type_Enum_StabHourglass_existe(bloc.Nom(1))) { type_stabHourglass = Id_Nom_StabHourglass(bloc.Nom(1).c_str()); coefStabHourglass = bloc.Val(1); } else { cout << "\n erreur, le type " << bloc.Nom(2) << " de gestion d'hourglass n'existe pas !!"; if (ParaGlob::NiveauImpression() > 5) cout << "\n ElemMeca::Init_hourglass_comp(..."; cout << endl; Sortie(1); }; switch (type_stabHourglass) {case STABHOURGLASS_PAR_COMPORTEMENT : { // -- choix de l'element pour le calcul de la raideur ----- // on recherche un élément de même type, // par défaut : numéro de maillage = le numéro de this, car c'est bien rattaché à ce maillage, mais l'élément est caché, donc non accessible par le maillage // numéro d'élément = 1000000 + numéro de this : a priori c'est deux numéros n'ont pas d'importance, car ils ne sont pas // rattachés à un maillage existant en tant que tel int nUmMail = this->Num_elt_const(); int nUmElem = 1000000 + this->Num_elt(); tab_elHourglass.Change_taille(1); tab_elHourglass(1) = (ElemMeca*) Element::Choix_element(nUmMail,nUmElem,Id_geometrie(),Id_interpolation(),Id_TypeProblem(),str_precision); if (tab_elHourglass(1) == NULL) { // l'operation a echouee cout << "\n Erreur dans le choix d'un element interne utilise pour le blocage d'hourglass ****** "; cout << "\n l\'element : " << Nom_interpol(id_interpol) << " " << Nom_geom(id_geom) << " " << str_precision << " n\'est pas present dans le programme ! " << endl; if (ParaGlob::NiveauImpression() > 5) cout << "\n ElemMeca::Init_hourglass_comp(..." << endl; Sortie (1); }; // --- définition des noeuds de l'élément ----- // on construit à partir des mêmes noeuds que ceux de l'élément père // affectation des noeuds au nouvel élément tab_elHourglass(1)->Tab_noeud() = this->Tab_noeud(); //--- def de la loi de comportement --- // affectation de la loi tab_elHourglass(1)->DefLoi(loiHourglass); break; } case STABHOURGLASS_PAR_COMPORTEMENT_REDUIT : { // ici on a besoin de deux éléments. Le premier sert à faire le calcul complet // le second sert à faire un calcul réduit, comme l'élément réel tab_elHourglass.Change_taille(2); // -- choix pour le calcul de la raideur ----- // on recherche un élément de même type, // par défaut : numéro de maillage = le numéro de this, car c'est bien rattaché à ce maillage, mais l'élément est caché, donc non accessible par le maillage // numéro d'élément = 1000000 + numéro de this : a priori c'est deux numéros n'ont pas d'importance, car ils ne sont pas // rattachés à un maillage existant en tant que tel //-- le premier élément: int nUmMail = this->Num_elt_const(); int nUmElem = 1000000 + this->Num_elt(); tab_elHourglass(1) = (ElemMeca*) Element::Choix_element(nUmMail,nUmElem,Id_geometrie(),Id_interpolation(),Id_TypeProblem(),str_precision); if (tab_elHourglass(1) == NULL) { // l'operation a echouee cout << "\n Erreur dans le choix d'un element interne utilise pour le blocage d'hourglass ****** "; cout << "\n l\'element : " << Nom_interpol(id_interpol) << " " << Nom_geom(id_geom) << " " << str_precision << " n\'est pas present dans le programme ! " << endl; if (ParaGlob::NiveauImpression() > 5) cout << "\n ElemMeca::Init_hourglass_comp(..." << endl; Sortie (1); }; //-- le second élément identique à this: on utilise le même numéro de maillage // même infos annexes nUmElem = 20000000 + this->Num_elt(); // on ajoute une unité pour le numéro tab_elHourglass(2) = (ElemMeca*) Element::Choix_element(nUmMail,nUmElem,Id_geometrie(),Id_interpolation(),Id_TypeProblem(),this->infos_annexes); if (tab_elHourglass(2) == NULL) { // l'operation a echouee cout << "\n Erreur dans le choix d'un element interne utilise pour le blocage d'hourglass ****** "; cout << "\n l\'element : " << Nom_interpol(id_interpol) << " " << Nom_geom(id_geom) << " " << this->infos_annexes << " n\'est pas present dans le programme ! " << endl; if (ParaGlob::NiveauImpression() > 5) cout << "\n ElemMeca::Init_hourglass_comp(..." << endl; Sortie (1); }; // --- définition des noeuds de l'élément ----- // on construit à partir des mêmes noeuds que ceux de l'élément père // affectation des noeuds au nouvel élément tab_elHourglass(1)->Tab_noeud() = this->Tab_noeud(); tab_elHourglass(2)->Tab_noeud() = this->Tab_noeud(); //--- def de la loi de comportement --- // affectation de la loi tab_elHourglass(1)->DefLoi(loiHourglass); tab_elHourglass(2)->DefLoi(loiHourglass); // def de trois vecteurs de travail s'ils ne sont pas encore définit if (vec_hourglass.Taille() < 3) vec_hourglass.Change_taille(3); break; } default : cout << "\n*** Erreur : cas de gestop, d'hourglass non defini !\n"; cout << "\n ElemMeca::Cal_implicit_hourglass() \n"; Sortie(1); }; }; // stabilisation pour un calcul implicit void ElemMeca::Cal_implicit_hourglass() {E_Hourglass=0.; // init par défaut switch (type_stabHourglass) {case STABHOURGLASS_PAR_COMPORTEMENT : { // --- calcul de la raideur de l'élément, dans le cas implicite --- Element::ResRaid resraid = tab_elHourglass(1)->Calcul_implicit (ParaGlob::param->ParaAlgoControleActifs()); // on tiend compte du facteur de modération (*(resraid.raid)) *= coefStabHourglass; (*(resraid.res)) *= coefStabHourglass; // on met à jour la raideur et le résidu de l'élément principal (*raideur) += (*(resraid.raid)); (*residu) += (*(resraid.res)); // on récupère les énergies stockées à l'élément const EnergieMeca& energieTotale = tab_elHourglass(1)->EnergieTotaleElement(); E_Hourglass = coefStabHourglass * (energieTotale.EnergieElastique() + energieTotale.DissipationPlastique() + energieTotale.DissipationVisqueuse()); //---- debug //cout << "\n raideur locale après stabilisation d'hourglass "; //matRaideur.Affiche(); //---- fin debug }; break; case STABHOURGLASS_PAR_COMPORTEMENT_REDUIT : { // --- calcul de la raideur de l'élément, dans le cas implicite --- // ici on calcul la partie supposée supplémentaire à celle déjà présente dans le calcul réduit // au premier passage ou bien si on demande une grande précision de calcul, on calcul la raideur et le second membre, // ensuite on ne calcul que le second membre // if ((raid_hourglass_transitoire == NULL)||(prepa_niveau_precision > 8)) // en l'expérience prouve que c'est la forme des éléments du début qui est la moins tordu donc vaut mieux // ne pas recalculer la raideur sur des éléments tordus, c'est dans ce cas que ça marche le mieux if (raid_hourglass_transitoire == NULL) {// 1) calcul de la partie complète Element::ResRaid resraid1 = tab_elHourglass(1)->Calcul_implicit (ParaGlob::param->ParaAlgoControleActifs()); // 2) calcul de la partie réduite Element::ResRaid resraid2 = tab_elHourglass(2)->Calcul_implicit (ParaGlob::param->ParaAlgoControleActifs()); // on soustrait en gardant le résultat dans resraid1 // **** non ce n'est pas une bonne idée, lorsque l'on fait certain test de stabilité: lorsque le facteur est très grand // si on ne fait pas la soustraction cela converge, avec la soustraction cela ne converge pas donc il ne faut pas soustraire // (*(resraid1.raid)) -= (*(resraid2.raid)); // (*(resraid1.res)) -= (*(resraid2.res)); // ---nouvelle idée: // on commence par récupérer dans le vecteur résidu les incréments de ddl correspondant à l'élément int NBN = tab_noeud.Taille(); int dim = ParaGlob::Dimension(); if(ParaGlob::AxiSymetrie()) dim--; // on passe à une dimension 2 ! et il y a uniquement les x et les y qui sont concernés Vecteur& D_X = vec_hourglass(1); // pour simplier Vecteur& X = vec_hourglass(2); // pour simplier D_X.Change_taille(NBN*dim); // changement de la taille au cas où X.Change_taille(NBN*dim); // changement de la taille au cas où for (int ine=1;ine<=NBN;ine++) { Noeud& noe = *(tab_noeud(ine)); // pour simplifier Coordonnee delta_X = noe.Coord2() - noe.Coord1(); Coordonnee Xnoeud = noe.Coord2(); int ipos = (ine-1)*dim; switch (dim) { case 3: {D_X(ipos+1)=delta_X(1);D_X(ipos+2)=delta_X(2);D_X(ipos+3)=delta_X(3); X(ipos+1)=Xnoeud(1);X(ipos+2)=Xnoeud(2);X(ipos+3)=Xnoeud(3);break;} case 2: {D_X(ipos+1)=delta_X(1);D_X(ipos+2)=delta_X(2); X(ipos+1)=Xnoeud(1);X(ipos+2)=Xnoeud(2);break;} case 1: {D_X(ipos+1)=delta_X(1); X(ipos+1)=Xnoeud(1);break;} }; }; // on multiplie la matrice par le vecteur delta_X (*(resraid1.res)) = resraid1.raid->Prod_mat_vec(D_X); // on sauvegarde la raideur initiale if (raid_hourglass_transitoire == NULL) raid_hourglass_transitoire = new Mat_pleine((*(resraid1.raid))); // premier calcul de l'accroissement de l'énergie E_Hourglass = 0.5 * (D_X * (*(resraid1.res))); // on tiend compte du facteur de modération double coefMultiplicatif = coefStabHourglass; if (E_Hourglass < 0.) // on veut un accroissement d'énergie positive (1/2 k deltaX ^2) { coefMultiplicatif = -coefStabHourglass;}; // grandeurs finales avec le bon signe (*(resraid1.raid)) *= coefMultiplicatif; (*(resraid1.res)) *= coefMultiplicatif; // calcul définitif: correspond à une grandeur qui peut être comparée avec l'énergie élastique totale E_Hourglass = 0.5 * (X * (*(resraid1.res))); //debug //cout << "\n premier passage, "; //res.Affiche(); (resraid1.raid)->Affiche(); //fin debug // on met à jour la raideur et le résidu de l'élément principal (*raideur) += (*(resraid1.raid)); (*residu) -= (*(resraid1.res)); } else {// sinon on utilise la précédente raideur sauvegardée et on ne calcul que la partie résidue // dans la nouvelle idée le vecteur doit exister à la bonne dimension, mais CalculResidu_tdt n'a pas besoin // d'être appeler **** a améliorer // Vecteur* resHourglass1 = NULL; // resHourglass1 = tab_elHourglass(1)->CalculResidu_tdt (ParaGlob::param->ParaAlgoControleActifs()); /* Vecteur* resHourglass2 = NULL; resHourglass2 = tab_elHourglass(2)->CalculResidu_tdt (ParaGlob::param->ParaAlgoControleActifs()); // on soustrait les résidus en gardant le résultat dans resraid1 (*(resHourglass1)) -= (*(resHourglass2));*/ // ---nouvelle idée: // on commence par récupérer dans le vecteur résidu les incréments de ddl correspondant à l'élément int NBN = tab_noeud.Taille(); int dim = ParaGlob::Dimension(); if(ParaGlob::AxiSymetrie()) dim--; // on passe à une dimension 2 ! et il y a uniquement les x et les y qui sont concernés Vecteur& D_X = vec_hourglass(1); // pour simplier Vecteur& X = vec_hourglass(2); // pour simplier D_X.Change_taille(NBN*dim); // changement de la taille au cas où X.Change_taille(NBN*dim); // changement de la taille au cas où for (int ine=1;ine<=NBN;ine++) { Noeud& noe = *(tab_noeud(ine)); // pour simplifier Coordonnee delta_X = noe.Coord2() - noe.Coord1(); Coordonnee Xnoeud = noe.Coord2(); int ipos = (ine-1)*dim; switch (dim) { case 3: {D_X(ipos+1)=delta_X(1);D_X(ipos+2)=delta_X(2);D_X(ipos+3)=delta_X(3); X(ipos+1)=Xnoeud(1);X(ipos+2)=Xnoeud(2);X(ipos+3)=Xnoeud(3);break;} case 2: {D_X(ipos+1)=delta_X(1);D_X(ipos+2)=delta_X(2); X(ipos+1)=Xnoeud(1);X(ipos+2)=Xnoeud(2);break;} case 1: {D_X(ipos+1)=delta_X(1); X(ipos+1)=Xnoeud(1);break;} }; }; //debug //cout << " res ddl, "; //res.Affiche(); //fin debug Vecteur& res = vec_hourglass(2); // pour simplier res.Change_taille(NBN*dim); // changement de la taille au cas où // on multiplie le vecteur delta_X par la matrice res = raid_hourglass_transitoire->Prod_mat_vec(D_X); // on définit un facteur de modération qui est fondé sur le ratio des énergies // --- essai d'adaptation du coef, mais ça ne marche pas du tout, il n'y a que quand c'est fixe que c'est ok /* double energieHourglassDeBase = 0.5 * (D_X * res); const EnergieMeca& energieActuelle = this->EnergieTotaleElement(); // récup de l'énergie actuelle double val_ref_energie = (Dabs(energieActuelle.EnergieElastique()) + Dabs(energieActuelle.DissipationPlastique()) + Dabs(energieActuelle.DissipationVisqueuse())); double coef_a_appliquer = coefStabHourglass; if (Dabs(energieHourglassDeBase*coefStabHourglass) > MaX(ConstMath::petit,val_ref_energie)) coef_a_appliquer *= val_ref_energie / energieHourglassDeBase; // on tiend compte du facteur de modération res *= coef_a_appliquer; // on met à jour le résidu de l'élément principal (*residu) -= res; // pour la partie raideur: on met à jour la raideur de l'élément principal (*raideur) += coef_a_appliquer * (*raid_hourglass_transitoire); // calcul de l'énergie E_Hourglass = energieHourglassDeBase * coef_a_appliquer; //0.5 * (D_X * res); */ // premier calcul de l'accroissement de l'énergie E_Hourglass = 0.5 * (D_X * res); // on tiend compte du facteur de modération double coefMultiplicatif = coefStabHourglass; if (E_Hourglass < 0.) // on veut un accroissement d'énergie positive (1/2 k deltaX ^2) { coefMultiplicatif = -coefStabHourglass;}; // grandeurs finales avec le bon signe res *= coefMultiplicatif; // calcul définitif: correspond à une grandeur qui peut être comparée avec l'énergie élastique totale E_Hourglass = 0.5 * (X * (res)); // on met à jour le résidu de l'élément principal (*residu) -= res; // pour la partie raideur: on met à jour la raideur de l'élément principal (*raideur) += coefMultiplicatif * (*raid_hourglass_transitoire); //debug //if (E_Hourglass < 0.) // { D_X.Affiche(); // res.Affiche(); // raid_hourglass_transitoire->Affiche(); // cout << "\n E_Hourglass= "<< E_Hourglass << endl ; // // }; //res.Affiche(); (raid_hourglass_transitoire)->Affiche(); //fin debug }; //---- debug //cout << "\n raideur locale après stabilisation d'hourglass "; //matRaideur.Affiche(); //---- fin debug }; break; case STABHOURGLASS_NON_DEFINIE : // on ne fait rien break; default : cout << "\n*** Erreur : cas de gestop, d'hourglass non defini !\n"; cout << "\n ElemMeca::Cal_implicit_hourglass() \n"; Sortie(1); }; }; // stabilisation pour un calcul explicit void ElemMeca::Cal_explicit_hourglass(bool atdt) { switch (type_stabHourglass) {case STABHOURGLASS_PAR_COMPORTEMENT : { // --- calcul de la raideur de l'élément, dans le cas implicite --- Vecteur* resHourglass = NULL; if (atdt) {resHourglass = tab_elHourglass(1)->CalculResidu_tdt (ParaGlob::param->ParaAlgoControleActifs());} else {resHourglass = tab_elHourglass(1)->CalculResidu_t (ParaGlob::param->ParaAlgoControleActifs());}; // on tiend compte du facteur de modération (*resHourglass) *= coefStabHourglass; // on met à jour le résidu de l'élément principal (*residu) += (*resHourglass); //---- debug //cout << "\n raideur locale après stabilisation d'hourglass "; //matRaideur.Affiche(); //---- fin debug }; break; case STABHOURGLASS_PAR_COMPORTEMENT_REDUIT : { // --- on calcul la raideur de l'élément juste à la définition --- if ((raid_hourglass_transitoire == NULL)||(prepa_niveau_precision > 18)) // pour le debug { // 1) calcul de la partie complète Element::ResRaid resraid1 = tab_elHourglass(1)->Calcul_implicit (ParaGlob::param->ParaAlgoControleActifs()); // on sauvegarde la raideur initiale if (raid_hourglass_transitoire == NULL) raid_hourglass_transitoire = new Mat_pleine((*(resraid1.raid))); // on commence par récupérer dans le vecteur résidu les incréments de ddl correspondant à l'élément int NBN = tab_noeud.Taille(); int dim = ParaGlob::Dimension(); if(ParaGlob::AxiSymetrie()) dim--; // on passe à une dimension 2 ! et il y a uniquement les x et les y qui sont concernés Vecteur& D_X = vec_hourglass(1); // pour simplier Vecteur& X = vec_hourglass(2); // pour simplier D_X.Change_taille(NBN*dim); // changement de la taille au cas où X.Change_taille(NBN*dim); // changement de la taille au cas où for (int ine=1;ine<=NBN;ine++) { Noeud& noe = *(tab_noeud(ine)); // pour simplifier Coordonnee delta_X = noe.Coord2() - noe.Coord1(); Coordonnee Xnoeud = noe.Coord2(); int ipos = (ine-1)*dim; switch (dim) { case 3: {D_X(ipos+1)=delta_X(1);D_X(ipos+2)=delta_X(2);D_X(ipos+3)=delta_X(3); X(ipos+1)=Xnoeud(1);X(ipos+2)=Xnoeud(2);X(ipos+3)=Xnoeud(3);break;} case 2: {D_X(ipos+1)=delta_X(1);D_X(ipos+2)=delta_X(2); X(ipos+1)=Xnoeud(1);X(ipos+2)=Xnoeud(2);break;} case 1: {D_X(ipos+1)=delta_X(1); X(ipos+1)=Xnoeud(1);break;} }; }; // on multiplie la matrice par le vecteur delta_X (*(resraid1.res)) = resraid1.raid->Prod_mat_vec(D_X); // premier calcul de l'accroissement de l'énergie E_Hourglass = 0.5 * (D_X * (*(resraid1.res))); // on tiend compte du facteur de modération double coefMultiplicatif = coefStabHourglass; if (E_Hourglass < 0.) // on veut un accroissement d'énergie positive (1/2 k deltaX ^2) { coefMultiplicatif = -coefStabHourglass;}; // grandeurs finales avec le bon signe (*(resraid1.raid)) *= coefMultiplicatif; (*(resraid1.res)) *= coefMultiplicatif; // calcul définitif: correspond à une grandeur qui peut être comparée avec l'énergie élastique totale E_Hourglass = 0.5 * (X * (*(resraid1.res))); // on met à jour le résidu de l'élément principal (*residu) -= (*(resraid1.res)); // calcul de l'énergie E_Hourglass = 0.5 * (D_X * (*(resraid1.res))); } else // cas courant {// on utilise la précédente raideur sauvegardée et on ne calcul qu'une partie résidue linéaire // on commence par récupérer dans le vecteur résidu les incréments de ddl correspondant à l'élément int NBN = tab_noeud.Taille(); int dim = ParaGlob::Dimension(); if(ParaGlob::AxiSymetrie()) dim--; // on passe à une dimension 2 ! et il y a uniquement les x et les y qui sont concernés Vecteur& D_X = vec_hourglass(1); // pour simplier Vecteur& X = vec_hourglass(2); // pour simplier D_X.Change_taille(NBN*dim); // changement de la taille au cas où X.Change_taille(NBN*dim); // changement de la taille au cas où for (int ine=1;ine<=NBN;ine++) { Noeud& noe = *(tab_noeud(ine)); // pour simplifier Coordonnee delta_X = noe.Coord2() - noe.Coord1(); Coordonnee Xnoeud = noe.Coord2(); int ipos = (ine-1)*dim; switch (dim) { case 3: {D_X(ipos+1)=delta_X(1);D_X(ipos+2)=delta_X(2);D_X(ipos+3)=delta_X(3); X(ipos+1)=Xnoeud(1);X(ipos+2)=Xnoeud(2);X(ipos+3)=Xnoeud(3);break;} case 2: {D_X(ipos+1)=delta_X(1);D_X(ipos+2)=delta_X(2); X(ipos+1)=Xnoeud(1);X(ipos+2)=Xnoeud(2);break;} case 1: {D_X(ipos+1)=delta_X(1); X(ipos+1)=Xnoeud(1);break;} }; }; Vecteur& res = vec_hourglass(2); // pour simplier res.Change_taille(NBN*dim); // changement de la taille au cas où // on multiplie le vecteur delta_X par la matrice res = raid_hourglass_transitoire->Prod_mat_vec(D_X); // premier calcul de l'accroissement de l'énergie E_Hourglass = 0.5 * (D_X * res); // on tiend compte du facteur de modération double coefMultiplicatif = coefStabHourglass; if (E_Hourglass < 0.) // on veut un accroissement d'énergie positive (1/2 k deltaX ^2) { coefMultiplicatif = -coefStabHourglass;}; // grandeurs finales avec le bon signe res *= coefMultiplicatif; // calcul définitif: correspond à une grandeur qui peut être comparée avec l'énergie élastique totale E_Hourglass = 0.5 * (X * (res)); // on met à jour le résidu de l'élément principal (*residu) -= res; }; }; break; case STABHOURGLASS_NON_DEFINIE : // on ne fait rien break; default : cout << "\n*** Erreur : cas de gestop, d'hourglass non defini !\n"; cout << "\n ElemMeca::Cal_implicit_hourglass() \n"; Sortie(1); }; }; /* // récupération de l'energie d'hourglass éventuelle double ElemMeca::Energie_Hourglass() {double enerHourglass = 0.; switch (type_stabHourglass) {case STABHOURGLASS_PAR_COMPORTEMENT : { // on récupère les énergies stockées à l'élément const EnergieMeca& energieTotale = tab_elHourglass(1)->EnergieTotaleElement(); enerHourglass = coefStabHourglass * (energieTotale.EnergieElastique() + energieTotale.DissipationPlastique() + energieTotale.DissipationVisqueuse()); break; } case STABHOURGLASS_PAR_COMPORTEMENT_REDUIT : {// --- l'énergie est purement une énergie élastique du type 0.5 [K] (D_X) --- if (raid_hourglass_transitoire == NULL) { enerHourglass = 0.;} // car rien n'a été calculé else { int NBN = tab_noeud.Taille(); // récup du nombre de noeuds int dim = ParaGlob::Dimension(); Vecteur& D_X = vec_hourglass(1); // pour simplier D_X.Change_taille(NBN*dim); // changement de la taille au cas où for (int ine=1;ine<=NBN;ine++) { Noeud& noe = *(tab_noeud(ine)); // pour simplifier Coordonnee delta_X = noe.Coord2() - noe.Coord1(); int ipos = (ine-1)*dim; switch (dim) { case 3: {D_X(ipos+1)=delta_X(1);D_X(ipos+2)=delta_X(2);D_X(ipos+3)=delta_X(3);break;} case 2: {D_X(ipos+1)=delta_X(1);D_X(ipos+2)=delta_X(2);break;} case 1: {D_X(ipos+1)=delta_X(1);break;} }; }; Vecteur& res = vec_hourglass(2); // pour simplier res.Change_taille(NBN*dim); // changement de la taille au cas où // on multiplie la matrice par le vecteur delta_X res = raid_hourglass_transitoire->Prod_mat_vec(D_X); enerHourglass = 0.5 * (D_X * res); //debug //cout << " , " << enerHourglass; //fin debug }; break; case STABHOURGLASS_NON_DEFINIE : // on ne fait rien break; } }; return enerHourglass; };*/ // -------------------- stabilisation transversale de membrane ou biel ------------------- // mise à jour de "a_calculer" en fonction du contexte // NB: pour l'instant ne concerne que le calcul en implicite void ElemMeca::Mise_a_jour_A_calculer_force_stab() {if (pt_StabMembBiel != NULL) {pt_StabMembBiel->Aa_calculer() = true; // on init par défaut Enum_StabMembraneBiel enu_stab = pt_StabMembBiel->Type_stabMembrane(); switch (enu_stab) { case STABMEMBRANE_BIEL_PREMIER_ITER: case STABMEMBRANE_BIEL_Gerschgorin_PREMIER_ITER: case STABMEMBRANE_BIEL_PREMIER_ITER_NORMALE_AU_NOEUD: case STABMEMBRANE_BIEL_Gerschgorin_PREMIER_ITER_NORMALE_AU_NOEUD: {// on récupère le pointeur correspondant aux iteration const void* pointe = (ParaGlob::param->GrandeurGlobal(COMPTEUR_ITERATION_ALGO_GLOBAL)); if (pointe == NULL) { cout << "\n *** pb dans la stabilisation de membrane et/ou biel " << " le type de stabilisation est " << Nom_StabMembraneBiel(enu_stab) << "et la variable globale COMPTEUR_ITERATION_ALGO_GLOBAL n'est pas disponible" << " on ne peut pas continuer " << "\nElemMeca::Mise_a_jour_A_calculer_force_stab(..."<Grandeur_pointee()); // pour simplifier int compteur_iter = *(gr.ConteneurEntier()); if (compteur_iter > 1) // cela veut dire que la force de stabilisation a déjà été calculé {pt_StabMembBiel->Aa_calculer() = false;} else // sinon il faut la calculer {pt_StabMembBiel->Aa_calculer() = true;}; break; } case STABMEMBRANE_BIEL_PREMIER_ITER_INCR: case STABMEMBRANE_BIEL_Gerschgorin_PREMIER_ITER_INCR: case STABMEMBRANE_BIEL_PREMIER_ITER_INCR_NORMALE_AU_NOEUD: case STABMEMBRANE_BIEL_Gerschgorin_PREMIER_ITER_INCR_NORMALE_AU_NOEUD: {int compteur_iter = 0;// init {// on récupère le pointeur correspondant aux iteration const void* pointe = (ParaGlob::param->GrandeurGlobal(COMPTEUR_ITERATION_ALGO_GLOBAL)); if (pointe == NULL) { cout << "\n *** pb dans la stabilisation de membrane et/ou biel " << " le type de stabilisation est " << Nom_StabMembraneBiel(enu_stab) << "et la variable globale COMPTEUR_ITERATION_ALGO_GLOBAL n'est pas disponible" << " on ne peut pas continuer " << "\nElemMeca::Cal_implicit_StabMembBiel(..."<Grandeur_pointee()); // pour simplifier compteur_iter = *(gr.ConteneurEntier()); } // on récupère le pointeur correspondant aux incréments int compteur_incr = 0; // init {const void* pointe = (ParaGlob::param->GrandeurGlobal(COMPTEUR_INCREMENT_CHARGE_ALGO_GLOBAL)); if (pointe == NULL) { cout << "\n *** pb dans la stabilisation de membrane et/ou biel " << " le type de stabilisation est STABMEMBRANE_BIEL_PREMIER_ITER_INCR " << "et la variable globale COMPTEUR_INCREMENT_CHARGE_ALGO_GLOBAL n'est pas disponible" << " on ne peut pas continuer " << "\nElemMeca::Cal_implicit_StabMembBiel(..."<Grandeur_pointee()); // pour simplifier compteur_iter = *(gr.ConteneurEntier()); } if ((compteur_incr > 1) && (compteur_iter > 1)) // cela veut dire que la force de stabilisation a déjà été calculé {pt_StabMembBiel->Aa_calculer() = false;} else // sinon il faut la calculer {pt_StabMembBiel->Aa_calculer() = true;}; break; } default: cout << "\n *** erreur le type de stabilisation de membrane et/ou biel n'est pas definie " << " on ne peut pas continuer " << "\nElemMeca::Mise_a_jour_A_calculer_force_stab(..."< donne le numéro du dernier pti sur lequel on a travaillé, auquel met est associé // iteg == 0 : un seul calcul global, et on est à la suite d'une boucle // iteg == -1 : fin d'un calcul avec boucle sur tous les pti, et on est à la suite de la boucle // correspond au calcul d'alpha: == stab_ref // iteg entre 1 et nbint: on est dans une boucle de pti // nbint : le nombre maxi de pti // poids_volume : si iteg > 0 : le poids d'intégration // si iteg <= 0 : l'intégrale de l'élément (ici la surface totale) void ElemMeca::Cal_implicit_StabMembBiel(int iteg,const Met_abstraite::Impli& ex, const int& nbint ,const double& poids_volume ,Tableau * noeud_a_prendre_en_compte) {// l'idée est de bloquer la direction normale à l'élément pour une plaque et // les deux directions transverses pour une biel int niveau_affichage = ParaGlob::NiveauImpression(); if (pt_StabMembBiel->Affichage_stabilisation() > 0) niveau_affichage = pt_StabMembBiel->Affichage_stabilisation(); //---- détermination de l'intensité de stabilisation // celle-ci n'est calculé que dans le cas ou iteg == 0 // c'est à dire que l'on n'est pas dans une boucle sur les pti, dans la méthode appelant double alpha = 0.; // init bool stab_utilisable = false; // init // bool alpha_vient_etre_calculee = false; Enum_StabMembraneBiel enu_stab = pt_StabMembBiel->Type_stabMembrane(); switch (enu_stab) { case STABMEMBRANE_BIEL_PREMIER_ITER: case STABMEMBRANE_BIEL_Gerschgorin_PREMIER_ITER: case STABMEMBRANE_BIEL_PREMIER_ITER_NORMALE_AU_NOEUD : case STABMEMBRANE_BIEL_Gerschgorin_PREMIER_ITER_NORMALE_AU_NOEUD: {// on récupère le pointeur correspondant aux iteration const void* pointe = (ParaGlob::param->GrandeurGlobal(COMPTEUR_ITERATION_ALGO_GLOBAL)); if (pointe == NULL) { cout << "\n *** pb dans la stabilisation de membrane et/ou biel " << " le type de stabilisation est " << Nom_StabMembraneBiel(enu_stab) << "et la variable globale COMPTEUR_ITERATION_ALGO_GLOBAL n'est pas disponible" << " on ne peut pas continuer " << "\nElemMeca::Cal_implicit_StabMembBiel(..."<Grandeur_pointee()); // pour simplifier int compteur_iter = *(gr.ConteneurEntier()); if ((iteg > 0) && (compteur_iter > 1)) // cela veut dire que la la référence de stabilisation a déjà été calculée {alpha = pt_StabMembBiel->Stab_ref(); // récup de l'intensité de stabilisation // ce n'est pas un pointeur, alpha est une variable locale // dans le cas d'une fonction multiplicatrice , // et il faut appeler la fonction qui peut varier pendant les itérations if (pt_StabMembBiel->Pt_fct_gamma() != NULL) // cas où il y a une fonction nD {Fonction_nD* fct = pt_StabMembBiel->Pt_fct_gamma(); // récupération de la fonction nD // on commence par récupérer les conteneurs des grandeurs à fournir List_io & li_enu_scal = fct->Li_enu_etendu_scalaire(); List_io & li_quelc = fct->Li_equi_Quel_evolue(); bool absolue = true; // on se place systématiquement en absolu // on va utiliser la méhode Valeur_multi pour les grandeurs strictement scalaire int cas = -1; // signifie que l'on utilise la métrique qui vient juste d'être calculée Tableau val_ddl_enum(ElemMeca::Valeur_multi(absolue,TEMPS_tdt,li_enu_scal,iteg,-cas)); // on utilise la méthode des grandeurs évoluées pour les Coordonnees et Tenseur Valeurs_Tensorielles(absolue, TEMPS_tdt,li_quelc,iteg,-cas); // calcul de la valeur et retour dans tab_ret Tableau & tab_ret = fct->Valeur_FnD_Evoluee(&val_ddl_enum,&li_enu_scal,&li_quelc,NULL,NULL); // seule la première valeur est ok alpha *= tab_ret(1) ; pt_StabMembBiel->Valgamma() = alpha; // on sauvegarde la valeur d'alpha } else // sinon cela veut dire que l'intensité de stabilisation est fixe {alpha *= pt_StabMembBiel->Valgamma();} stab_utilisable=true; } else if ((pt_StabMembBiel->Aa_calculer()) && (iteg == 0) ) // cas ou il faut calculer la référence de stabilisation, mais on ne le fait qu'ici car // on est sortie de la boucle sur des pti, de manière à utiliser la raideur totale {// on récupère la valeur maxi de la raideur int i,j; // def double& maxival = pt_StabMembBiel->Stab_ref(); // init // là il s'agit d'un pointeur donc on travaille directement sur la grandeur stockée if ( (enu_stab == STABMEMBRANE_BIEL_PREMIER_ITER) ||(enu_stab == STABMEMBRANE_BIEL_PREMIER_ITER_NORMALE_AU_NOEUD)) {maxival = (*raideur).MaxiValAbs(i,j) / poids_volume; // alpha_vient_etre_calculee = true; } else if ( (enu_stab == STABMEMBRANE_BIEL_Gerschgorin_PREMIER_ITER) ||(enu_stab == STABMEMBRANE_BIEL_Gerschgorin_PREMIER_ITER_NORMALE_AU_NOEUD)) {maxival = (*raideur).Maxi_ligne_ValAbs(i) / poids_volume; // alpha_vient_etre_calculee = true; } else { cout << "\n *** pb dans la stabilisation de membrane et/ou biel " << " le type de stabilisation est " << Nom_StabMembraneBiel(enu_stab) << " pas pris en compte pour l'instant .... " << " on ne peut pas continuer " << "\nElemMeca::Cal_implicit_StabMembBiel(..."<Pt_fct_gamma() != NULL) // cas où il y a une fonction nD {Fonction_nD* fct = pt_StabMembBiel->Pt_fct_gamma(); // récupération de la fonction nD // on commence par récupérer les conteneurs des grandeurs à fournir List_io & li_enu_scal = fct->Li_enu_etendu_scalaire(); List_io & li_quelc = fct->Li_equi_Quel_evolue(); bool absolue = true; // on se place systématiquement en absolu // on va utiliser la méhode Valeur_multi pour les grandeurs strictement scalaire int cas = -1; // signifie que l'on utilise la métrique qui vient juste d'être calculée // ici c'est la métrique correspondante au dernier pti // comme iteg == 0 on est donc sortie de la boucle sur les pti, le dernier pti c'est nbint Tableau val_ddl_enum(ElemMeca::Valeur_multi(absolue,TEMPS_tdt,li_enu_scal,nbint,-cas)); // on utilise la méthode des grandeurs évoluées pour les Coordonnees et Tenseur Valeurs_Tensorielles(absolue, TEMPS_tdt,li_quelc,nbint,-cas); // calcul de la valeur et retour dans tab_ret Tableau & tab_ret = fct->Valeur_FnD_Evoluee(&val_ddl_enum,&li_enu_scal,&li_quelc,NULL,NULL); // seule la première valeur est ok alpha = tab_ret(1) * maxival; pt_StabMembBiel->Valgamma() = alpha; // on sauvegarde la valeur d'alpha } else // sinon cela veut dire que l'intensité de stabilisation est fixe ; {alpha = pt_StabMembBiel->Valgamma() * maxival; // on prend une proportion du maxi }; stab_utilisable = true; } else if (iteg == -1)// cas de la fin d'une boucle, on passe car il n'y a rien à faire {if (pt_StabMembBiel->Pt_fct_gamma() != NULL) {alpha = pt_StabMembBiel->Valgamma();} // on récupère la dernière valeur d'alpha calculée else // sinon il s'agit d'une valeur fixe, on recalcule alpha {alpha = pt_StabMembBiel->Valgamma() * pt_StabMembBiel->Stab_ref();}; stab_utilisable = true; } else // ce n'est pas prévu { cout << "\n *** erreur, iteg = "<< iteg //<< " local= "<< local << " cas non prevu dans la stabilisation " << "\n ElemMeca::Cal_implicit_StabMembBiel(.."; Sortie(1); }; break; } case STABMEMBRANE_BIEL_PREMIER_ITER_INCR: case STABMEMBRANE_BIEL_Gerschgorin_PREMIER_ITER_INCR: case STABMEMBRANE_BIEL_PREMIER_ITER_INCR_NORMALE_AU_NOEUD: case STABMEMBRANE_BIEL_Gerschgorin_PREMIER_ITER_INCR_NORMALE_AU_NOEUD: {int compteur_iter = 0;// init // on récupère le pointeur correspondant aux iteration {const void* pointe = (ParaGlob::param->GrandeurGlobal(COMPTEUR_ITERATION_ALGO_GLOBAL)); if (pointe == NULL) { cout << "\n *** pb dans la stabilisation de membrane et/ou biel " << " le type de stabilisation est " << Nom_StabMembraneBiel(enu_stab) << "et la variable globale COMPTEUR_ITERATION_ALGO_GLOBAL n'est pas disponible" << " on ne peut pas continuer " << "\nElemMeca::Cal_implicit_StabMembBiel(..."<Grandeur_pointee()); // pour simplifier compteur_iter = *(gr.ConteneurEntier()); } // on récupère le pointeur correspondant aux incréments int compteur_incr = 0; // init {const void* pointe = (ParaGlob::param->GrandeurGlobal(COMPTEUR_INCREMENT_CHARGE_ALGO_GLOBAL)); if (pointe == NULL) { cout << "\n *** pb dans la stabilisation de membrane et/ou biel " << " le type de stabilisation est " << Nom_StabMembraneBiel(enu_stab) << "et la variable globale COMPTEUR_INCREMENT_CHARGE_ALGO_GLOBAL n'est pas disponible" << " on ne peut pas continuer " << "\nElemMeca::Cal_implicit_StabMembBiel(..."<Grandeur_pointee()); // pour simplifier compteur_iter = *(gr.ConteneurEntier()); } if ((iteg != 0) && (compteur_incr > 1) && (compteur_iter > 1)) // cela veut dire que la la référence de stabilisation a déjà été calculée {alpha = pt_StabMembBiel->Stab_ref(); // init de l'intensité de stabilisation // dans le cas d'une fonction, la partie liée à la raideur est stockée dans Valgamma() // et il faut appeler la fonction qui peut varier pendant les itérations if (pt_StabMembBiel->Pt_fct_gamma() != NULL) // cas où il y a une fonction nD {Fonction_nD* fct = pt_StabMembBiel->Pt_fct_gamma(); // récupération de la fonction nD // on commence par récupérer les conteneurs des grandeurs à fournir List_io & li_enu_scal = fct->Li_enu_etendu_scalaire(); List_io & li_quelc = fct->Li_equi_Quel_evolue(); bool absolue = true; // on se place systématiquement en absolu // on va utiliser la méhode Valeur_multi pour les grandeurs strictement scalaire int cas = -1; // signifie que l'on utilise la métrique qui vient juste d'être calculée Tableau val_ddl_enum(ElemMeca::Valeur_multi(absolue,TEMPS_tdt,li_enu_scal,iteg,-cas)); // on utilise la méthode des grandeurs évoluées pour les Coordonnees et Tenseur Valeurs_Tensorielles(absolue, TEMPS_tdt,li_quelc,iteg,-cas); // calcul de la valeur et retour dans tab_ret Tableau & tab_ret = fct->Valeur_FnD_Evoluee(&val_ddl_enum,&li_enu_scal,&li_quelc,NULL,NULL); // seule la première valeur est ok alpha *= tab_ret(1); pt_StabMembBiel->Valgamma() = alpha; // on sauvegarde la valeur d'alpha } else // sinon cela veut dire que l'intensité de stabilisation est fixe {alpha *= pt_StabMembBiel->Valgamma();} stab_utilisable=true; } else if ((pt_StabMembBiel->Aa_calculer()) && (iteg == 0) ) // cas ou il faut calculer la référence de stabilisation, mais on ne le fait qu'ici car // on est sortie de la boucle sur des pti, de manière à utiliser la raideur totale {// on récupère la valeur maxi de la raideur int i,j; // def double& maxival = pt_StabMembBiel->Stab_ref(); // init if ( (enu_stab == STABMEMBRANE_BIEL_PREMIER_ITER_INCR) || (enu_stab == STABMEMBRANE_BIEL_PREMIER_ITER_INCR_NORMALE_AU_NOEUD)) {maxival = (*raideur).MaxiValAbs(i,j); // alpha_vient_etre_calculee = true; } else if ( (enu_stab == STABMEMBRANE_BIEL_Gerschgorin_PREMIER_ITER_INCR) ||(enu_stab == STABMEMBRANE_BIEL_Gerschgorin_PREMIER_ITER_INCR_NORMALE_AU_NOEUD)) {maxival = (*raideur).Maxi_ligne_ValAbs(i); // alpha_vient_etre_calculee = true; } else { cout << "\n *** pb dans la stabilisation de membrane et/ou biel " << " le type de stabilisation est " << Nom_StabMembraneBiel(enu_stab) << " pas pris en compte pour l'instant .... " << " on ne peut pas continuer " << "\nElemMeca::Cal_implicit_StabMembBiel(..."<Pt_fct_gamma() != NULL) // cas où il y a une fonction nD {Fonction_nD* fct = pt_StabMembBiel->Pt_fct_gamma(); // récupération de la fonction nD // on commence par récupérer les conteneurs des grandeurs à fournir List_io & li_enu_scal = fct->Li_enu_etendu_scalaire(); List_io & li_quelc = fct->Li_equi_Quel_evolue(); bool absolue = true; // on se place systématiquement en absolu // on va utiliser la méhode Valeur_multi pour les grandeurs strictement scalaire int cas = -1; // signifie que l'on utilise la métrique qui vient juste d'être calculée // ici c'est la métrique correspondante au dernier pti // comme iteg == 0 on est donc sortie de la boucle sur les pti, le dernier pti c'est nbint Tableau val_ddl_enum(ElemMeca::Valeur_multi(absolue,TEMPS_tdt,li_enu_scal,nbint,-cas)); // on utilise la méthode des grandeurs évoluées pour les Coordonnees et Tenseur Valeurs_Tensorielles(absolue, TEMPS_tdt,li_quelc,nbint,-cas); // calcul de la valeur et retour dans tab_ret Tableau & tab_ret = fct->Valeur_FnD_Evoluee(&val_ddl_enum,&li_enu_scal,&li_quelc,NULL,NULL); // seule la première valeur est ok alpha = tab_ret(1) * maxival; pt_StabMembBiel->Valgamma() = alpha; // on sauvegarde la valeur d'alpha } else // sinon cela veut dire que l'intensité de stabilisation est fixe ; {alpha = pt_StabMembBiel->Valgamma() * maxival; // on prend une proportion du maxi }; stab_utilisable = true; } else if (iteg == -1)// cas de la fin d'une boucle, on passe car il n'y a rien à faire {if (pt_StabMembBiel->Pt_fct_gamma() != NULL) {alpha = pt_StabMembBiel->Valgamma();} // on récupère la dernière valeur d'alpha calculée else // sinon il s'agit d'une valeur fixe, on recalcule alpha {alpha = pt_StabMembBiel->Valgamma() * pt_StabMembBiel->Stab_ref();}; stab_utilisable = true; } else // ce n'est pas prévu { cout << "\n *** erreur, iteg = "<< iteg //<< " local= "<< local << " cas non prevu dans la stabilisation " << "\n ElemMeca::Cal_implicit_StabMembBiel(.."; Sortie(1); }; break; } /* // case STAB_M_B_ITER_1_VIA_F_EXT: case STAB_M_B_ITER_1_VIA_F_EXT_NORMALE_AU_NOEUD: // {// on récupère le pointeur correspondant aux iteration // const void* pointe = (ParaGlob::param->GrandeurGlobal(COMPTEUR_ITERATION_ALGO_GLOBAL)); // if (pointe == NULL) // { cout << "\n *** pb dans la stabilisation de membrane et/ou biel " // << " le type de stabilisation est " << Nom_StabMembraneBiel(enu_stab) // << "et la variable globale COMPTEUR_ITERATION_ALGO_GLOBAL n'est pas disponible" // << " on ne peut pas continuer " // << "\nElemMeca::Cal_implicit_StabMembBiel(..."<Grandeur_pointee()); // pour simplifier // int compteur_iter = *(gr.ConteneurEntier()); // if (compteur_iter > 1) // cela veut dire que la force de stabilisation a déjà été calculé // {// dans le cas d'une fonction, la partie liée à la raiseur est stockée dans Valgamma() // // et il faut appeler la fonction qui peut varier pendant les itérations // if (pt_StabMembBiel->Pt_fct_gamma() != NULL) // // cas où il y a une fonction nD // { Tableau & tab_val = pt_StabMembBiel->Pt_fct_gamma()->Valeur_pour_variables_globales(); // // seule la première valeur est ok // alpha = tab_val(1) * pt_StabMembBiel->Valgamma(); // pt_StabMembBiel->FF_StabMembBiel() = alpha; // on sauvegarde // } // else // sinon cela veut dire que l'intensité de stabilisation est fixe // {alpha = pt_StabMembBiel->FF_StabMembBiel();} // alpha_utilisable=true; // } // else if (!local) // sinon il faut la calculer, mais on ne le fait que // // si on est sortie de la boucle sur des pti, // {// ***** à faire ***** on récupère la valeur maxi de la raideur // { cout << "\n *** pb dans la stabilisation de membrane et/ou biel " // << " partie pas operationnelle pour l'instant !! " // << " on ne peut pas continuer " // << "\nElemMeca::Cal_implicit_StabMembBiel(..."<Pt_fct_gamma() != NULL) // // cas où il y a une fonction nD // { Tableau & tab_val = pt_StabMembBiel->Pt_fct_gamma()->Valeur_pour_variables_globales(); // // seule la première valeur est ok // alpha = tab_val(1) * maxival; // pt_StabMembBiel->Valgamma() = maxival; // sauvegarde // } // else // sinon cela veut dire que l'intensité de stabilisation est fixe ; // {alpha = pt_StabMembBiel->Valgamma() * maxival; // on prend une proportion du maxi // }; // pt_StabMembBiel->FF_StabMembBiel() = alpha; // on sauvegarde // alpha_utilisable = true; // }; // break; // } */ default: cout << "\n *** erreur le type de stabilisation de membrane et/ou biel n'est pas definie " << " on ne peut pas continuer " << endl; Sortie(1); break; }; // si la stabilisation est utilisable on s'en sert if (stab_utilisable) // if ( (alpha_utilisable) // // et soit la stabilisation vient juste d'être calculée, donc on est en dehors de la boucle sur les pti // // donc on calcule globalement l'impact sur la raideur // // ou soit on est en local : et on calcul localement l'impact sur la raideur, mais à la sortie de la boucle // // on ne recalculera pas en globa // && (alpha_vient_etre_calculee || local) // ) {// choix en fonction de la géométrie Enum_type_geom enu_type_geom = Type_geom_generique(this->Id_geometrie()); switch (enu_type_geom) { case SURFACE: //#ifdef MISE_AU_POINT // if (num_elt==25) // -----debug à virer // {cout << "\n ElemMeca::Cal_implicit_StabMembBiel(.."; // cout << "\n iteg= "<< iteg << flush; // }; //#endif if (!Contient_Normale_au_noeud(enu_stab)) // cas où on utilise la normale au pti {// la normale vaut le produit vectoriel des 2 premiers vecteurs Coordonnee normale = Util::ProdVec_coor( (*ex.giB_tdt).Coordo(1), (*ex.giB_tdt).Coordo(2)); // calcul de la variation de la normale // 1) variation du produit vectoriel Tableau D_pasnormale = Util::VarProdVect_coor( (*ex.giB_tdt).Coordo(1),(*ex.giB_tdt).Coordo(2),(*ex.d_giB_tdt)); // 2) de la normale Tableau D_normale = Util::VarUnVect_coor(normale,D_pasnormale,normale.Norme()); // calcul de la normale normée et pondérée par la stabilisation normale.Normer(); int nbddl = (*residu).Taille(); int dimf = 3; // ne fonctionne qu'en dim 3 if(ParaGlob::AxiSymetrie()) // cas axisymétrique, dans ce cas on ne prend en compte que les // dimf-1 coordonnées donc on décrémente dimf--; int nbne = tab_noeud.Taille(); double ponder_F_t = 1.; // init // si iteg == 0 ==> un seul calcul, global: correspond au calcul d'alpha: == stab_ref // si teg == 1 ==> premier calcul correspondant au premier pti if ((iteg == 0) || (iteg == 1)) { matD->Initialise(0.); resD->Inita(0.); maxi_F_t = 0.; // on initialise les forces et énergie int taille = pt_StabMembBiel->Taille(); for (int i=1;i<=taille;i++) {pt_StabMembBiel->FF_StabMembBiel(i) = 0.; pt_StabMembBiel->EE_StabMembBiel(i) = pt_StabMembBiel->EE_StabMembBiel_t(i); } }; // on récupère l'élément géométrique ElemGeomC0& elemGeom = this->ElementGeometrique(); // récup des fonctions d'interpolation const Tableau & taphi = elemGeom.TaPhi(); int nb_noeud_pris_en_compte = 0; //pour faire la moyenne dans le cas iteg == 0 // on applique une force de stabilisation // uniquement suivant la direction de la normale int num_pti=iteg; // init if (iteg <= 0) num_pti = nbint; // la force est proportionelle au déplacement suivant la normale if (iteg > -1) // c-a-d == 0 ou plus { int ix=1; for (int ne =1; ne<= nbne; ne++) {bool continuer = true; if (noeud_a_prendre_en_compte != NULL) if (!(*noeud_a_prendre_en_compte)(ne)) continuer = false; if (continuer) {Noeud& noe = *(tab_noeud(ne)); // pour simplifier nb_noeud_pris_en_compte++; // on va bloquer le déplacement dans la direction de la normale calculée au pti //dans un calcul implicit on utilise la position à l'itération 0 // celle-ci peut-être différente de celle à t=0, lorsque l'on a une succession d'algo sur le même incrément // on commence par récupérer les coordonnées pour l'itération 0 TypeQuelconque_enum_etendu enu(XI_ITER_0); // récupération du conteneur pour lecture uniquement const TypeQuelconque& typquel = noe.Grandeur_quelconque(enu); const Grandeur_coordonnee& cofo = *((Grandeur_coordonnee*) typquel.Const_Grandeur_pointee()); Coordonnee delta_X = noe.Coord2() - cofo.ConteneurCoordonnee_const(); double normal_fois_delta_X = normale * delta_X; // le déplacement au noeud suivant la normale au pti // dans le cas où on veut pondérer F_t, on calcule la fonction if (pt_StabMembBiel->Pt_fct_ponder_Ft() != NULL) {Fonction_nD* fct = pt_StabMembBiel->Pt_fct_ponder_Ft(); // récupération de la fonction nD // on commence par récupérer les conteneurs des grandeurs à fournir List_io & li_enu_scal = fct->Li_enu_etendu_scalaire(); List_io & li_quelc = fct->Li_equi_Quel_evolue(); bool absolue = true; // on se place systématiquement en absolu // on va utiliser la méhode Valeur_multi pour les grandeurs strictement scalaire int cas = -1; // signifie que l'on utilise la métrique qui vient juste d'être calculée Tableau val_ddl_enum(ElemMeca::Valeur_multi (absolue,TEMPS_tdt,li_enu_scal,num_pti,-cas)); // on utilise la méthode des grandeurs évoluées pour les Coordonnees et Tenseur Valeurs_Tensorielles(absolue, TEMPS_tdt,li_quelc,num_pti,-cas); // calcul de la valeur et retour dans tab_ret Tableau & tab_ret = fct->Valeur_FnD_Evoluee(&val_ddl_enum,&li_enu_scal,&li_quelc,NULL,NULL); // seule la première valeur est ok ponder_F_t = tab_ret(1) ; } // un - car la force doit s'opposer au déplacement double intensite = -alpha * normal_fois_delta_X + ponder_F_t * pt_StabMembBiel->FF_StabMembBiel_t(num_pti); // on enregistre le maxi de la force à t maxi_F_t = DabsMaX(maxi_F_t, pt_StabMembBiel->FF_StabMembBiel_t(num_pti)); // d'où une variation réelle d'intensité double delta_intensite = intensite - ponder_F_t * pt_StabMembBiel->FF_StabMembBiel_t(num_pti); pt_StabMembBiel->EE_StabMembBiel(num_pti) += 0.5 * delta_intensite * normal_fois_delta_X; #ifdef MISE_AU_POINT if (niveau_affichage>5) // if (num_elt==25) // -----debug à virer {cout << "\n ElemMeca::Cal_implicit_StabMembBiel(.."; cout << "\n noeud ("<Gestion_maxi_mini()) { #ifdef MISE_AU_POINT if (niveau_affichage>9) // if (num_elt==1) // -----debug à virer {cout << "\n residu de stabilisation avant limitation: "<< (*resD) << "\n residu initial (sans stabilisation): "<< (*residu) << "\n maxi_F_t= " << maxi_F_t; }; if (niveau_affichage > 5) // if (num_elt==25) // -----debug à virer {int nb_pti = pt_StabMembBiel->Taille(); for (int i=1;i<=nb_pti;i++) cout << "\n F_stab("<FF_StabMembBiel(i)<< " "; }; #endif // 1) ---- on regarde s'il faut limiter la valeur de la stabilisation // et on prend en compte dans la raideur globale et le résidu global // la stabilisation bool limitation = false; double coef=1.; // coef de limitation éventuelle si limitation devient true // récup des limitations éventuelles double beta = pt_StabMembBiel->Beta(); double F_mini = pt_StabMembBiel->F_mini(); double d_maxi = pt_StabMembBiel->D_maxi(); // on fait une boucle sur les noeuds int ix=1; for (int ne =1; ne<= nbne; ne++) {bool continuer = true; if (noeud_a_prendre_en_compte != NULL) if (!(*noeud_a_prendre_en_compte)(ne)) continuer = false; if (continuer) {Noeud& noe = *(tab_noeud(ne)); // pour simplifier // récup de la force de stabilisation généralisée au noeud // c'est différent de celle au pti car elle inclue la surface de l'élément Coordonnee force_stab(dimf); // init for (int i=1;i<= dimf;i++,ix++) force_stab(i) = (*resD)(ix); double intensite_generalise = force_stab.Norme(); // on récupère la force externe au noeud à l'instant t TypeQuelconque_enum_etendu enu_ext(FORCE_GENE_EXT_t); // récupération du conteneur pour lecture uniquement const TypeQuelconque& typquel_ext = noe.Grandeur_quelconque(enu_ext); const Grandeur_coordonnee& cofo_ext = *((Grandeur_coordonnee*) typquel_ext.Const_Grandeur_pointee()); // on calcule l'intensité de la force externe selon la normale double intensite_Fext = Dabs(cofo_ext.ConteneurCoordonnee_const() * normale); // si l'intensité de la stabilisation est supérieure à beta * intensite_Fext // on limite double maxi_intensite = beta * intensite_Fext; double max_intens_via_Fext = maxi_intensite; // on sauve pour le cas où on est dep max // on applique l'algo théorique cf. doc théorique // erreur, maxi_intensité est une limitation, mais ce que l'on cherche à voir c'est // est-ce que les forces externes sont non-nulles, donc c'est intensite_Fext qu'il faut tester // if (maxi_intensite >= F_mini) if (intensite_Fext >= F_mini) // on est dans le cas où les forces externes sont à prendre en compte {if ((intensite_generalise > maxi_intensite) && (intensite_generalise > ConstMath::petit) // au cas où maxi_intensite et intensite très petites ) {limitation = true; if (niveau_affichage>3) {cout << "\n limitation stabilisation due aux forces externes, F_stab gene= "<< intensite_generalise << " ==> " << maxi_intensite; if (niveau_affichage > 5) cout << "\n F_mini= "<< F_mini << " intensite_Fext= "<< intensite_Fext; }; coef = DabsMiN(coef, maxi_intensite/intensite_generalise); }; // sinon pas de pb donc on ne fait rien } else // cas où l'intensité dans la direction normale, des forces externes n'existent pas // la limitation va s'exercée via un déplacement maxi {maxi_intensite = Dabs(-alpha*d_maxi + maxi_F_t); {if ((intensite_generalise > maxi_intensite) && (intensite_generalise > ConstMath::petit) // au cas où maxi_intensite et intensite très petites && (Dabs(alpha) > ConstMath::pasmalpetit) // il faut qu'alpha ne soit pas nul ) {limitation = true; if ((niveau_affichage > 3)) {cout << "\n limitation stabilisation due deplace maxi acceptable, F_stab gene= "<< intensite_generalise << " ==> " << maxi_intensite << " (max_intens_via_Fext= "< 4)) cout << "\n maxi_F_t= "<< maxi_F_t << " alpha*d_maxi= " << (alpha*d_maxi) << " alpha= " << alpha << " d_maxi= " << d_maxi; }; coef = DabsMiN(coef, maxi_intensite/intensite_generalise); }; }; }; }; // fin du test sur les noeuds à considérer };// fin de la boucle sur les noeuds if (limitation) { (*resD) *= coef; // mise à jour de la force de stabilisation // idem au niveau des pti int taille = pt_StabMembBiel->Taille(); for (int i=1;i<=taille;i++) {pt_StabMembBiel->FF_StabMembBiel(i) *=coef; // cas des énergies double delta_energie_initiale = pt_StabMembBiel->EE_StabMembBiel(i) - pt_StabMembBiel->EE_StabMembBiel_t(i); // on coefficiente le delta double delta_energie = delta_energie_initiale * coef; //ce qui donne au final: pt_StabMembBiel->EE_StabMembBiel(i) = delta_energie + pt_StabMembBiel->EE_StabMembBiel_t(i); }; }; }; // 2) ---- on met à jour la raideur et résidu global // en tenant compte de la stabilisation (*residu) += (*resD); (*raideur) += (*matD); //et du coup on ne boucle pas sur les pti et on peut limiter la force sauf qu'une fois le calcul des forces //aux noeuds fait, il faut ramener par interpolation, la force au pti pour la sauvegarder... bordel //non... on sauvegarde dans un tableau indicé par les num de noeud, et seulement pour le post-traitement //on calcul la valeur aux pti // #ifdef MISE_AU_POINT if ((niveau_affichage > 9)) // if (num_elt==1) // -----debug à virer {cout << "\n residu de stabilisation: "<< (*resD); cout << "\n raideur de stabilisation: "; matD->Affiche(); cout << "\n fin ElemMeca::Cal_implicit_StabMembBiel(.."; }; #endif }; // fin du cas iteg == 0 ou -1 } // fin du cas où on utilise la normale aux pti else {if (iteg < 1) // on ne calcul que si iteg < 1, c-a-d qu'on est sortie // de la boucle sur les pti // sinon cas où on utilise la normale aux noeuds {int nbddl = (*residu).Taille(); int dimf = 3; // ne fonctionne qu'en dim 3 if(ParaGlob::AxiSymetrie()) // cas axisymétrique, dans ce cas on ne prend en compte que les // dimf-1 coordonnées donc on décrémente dimf--; int nbne = tab_noeud.Taille(); matD->Initialise(0.); resD->Inita(0.); maxi_F_t = 0.; #ifdef MISE_AU_POINT // on vérifie le bon dimensionnement int taille = pt_StabMembBiel->Taille(); if (taille != nbne) {cout << "\n erreur** ElemMeca::Cal_implicit_StabMembBiel(.." << " le stockage est mal dimensionne: taille = " << taille << " alors qu'il devrait etre : nbe = " << nbne << flush ; Sortie(1); }; #endif // on applique une force de stabilisation aux noeuds // uniquement suivant la direction de la normale // la force est proportionelle au déplacement suivant la normale au noeud int ix=1; for (int ne =1; ne<= nbne; ne++) {Noeud& noe = *(tab_noeud(ne)); // pour simplifier // on initialise les forces et énergie pt_StabMembBiel->FF_StabMembBiel(ne) = 0.; pt_StabMembBiel->EE_StabMembBiel(ne) = pt_StabMembBiel->EE_StabMembBiel_t(ne); // pour chaque noeud on va bloquer le déplacement dans la direction de la normale au noeud à t // on récupère la normale au noeud const TypeQuelconque& tiq = noe.Grandeur_quelconque(NN_SURF_t); const Grandeur_coordonnee& gr= *((const Grandeur_coordonnee*) (tiq.Const_Grandeur_pointee())); const Coordonnee& normale = gr.ConteneurCoordonnee_const(); //dans un calcul implicit on utilise la position à l'itération 0 // celle-ci peut-être différente de celle à t=0, lorsque l'on a une succession d'algo sur le même incrément // on commence par récupérer les coordonnées pour l'itération 0 TypeQuelconque_enum_etendu enu(XI_ITER_0); // récupération du conteneur pour lecture uniquement const TypeQuelconque& typquel = noe.Grandeur_quelconque(enu); const Grandeur_coordonnee& cofo = *((Grandeur_coordonnee*) typquel.Const_Grandeur_pointee()); Coordonnee delta_X = noe.Coord2() - cofo.ConteneurCoordonnee_const(); double normal_fois_delta_X = normale * delta_X; double ponder_F_t = 1.; // init // dans le cas où on veut pondérer F_t, on calcule la fonction if (pt_StabMembBiel->Pt_fct_ponder_Ft() != NULL) {Fonction_nD* fct = pt_StabMembBiel->Pt_fct_ponder_Ft(); // récupération de la fonction nD // on commence par récupérer les conteneurs des grandeurs à fournir List_io & li_enu_scal = fct->Li_enu_etendu_scalaire(); List_io & li_quelc = fct->Li_equi_Quel_evolue(); bool absolue = true; // on se place systématiquement en absolu // on va utiliser la méhode Valeur_multi pour les grandeurs strictement scalaire int cas = -1; // signifie que l'on utilise la métrique qui vient juste d'être calculée // au dernier pti ! Tableau val_ddl_enum(ElemMeca::Valeur_multi (absolue,TEMPS_tdt,li_enu_scal,nbint,-cas)); // on utilise la méthode des grandeurs évoluées pour les Coordonnees et Tenseur Valeurs_Tensorielles(absolue, TEMPS_tdt,li_quelc,nbint,-cas); // calcul de la valeur et retour dans tab_ret Tableau & tab_ret = fct->Valeur_FnD_Evoluee(&val_ddl_enum,&li_enu_scal,&li_quelc,NULL,NULL); // seule la première valeur est ok ponder_F_t = tab_ret(1) ; } // un - car la force doit s'opposer au déplacement double intensite = -alpha * normal_fois_delta_X + ponder_F_t * pt_StabMembBiel->FF_StabMembBiel_t(ne); // on enregistre le maxi de la force à t maxi_F_t = DabsMaX(maxi_F_t, pt_StabMembBiel->FF_StabMembBiel_t(ne)); // d'où une variation réelle d'intensité double delta_intensite = intensite - ponder_F_t * pt_StabMembBiel->FF_StabMembBiel_t(ne); pt_StabMembBiel->EE_StabMembBiel(ne) += 0.5 * delta_intensite * normal_fois_delta_X; #ifdef MISE_AU_POINT if ((niveau_affichage > 5)) {cout << "\n ElemMeca::Cal_implicit_StabMembBiel(.."; cout << "\n alpha= "<Beta(); double F_mini = pt_StabMembBiel->F_mini(); double d_maxi = pt_StabMembBiel->D_maxi(); // on refait une boucle sur les noeuds int ix=1; for (int ne =1; ne<= nbne; ne++) {bool continuer = true; if (noeud_a_prendre_en_compte != NULL) if (!(*noeud_a_prendre_en_compte)(ne)) continuer = false; if (continuer) {Noeud& noe = *(tab_noeud(ne)); // pour simplifier // récup de la force de stabilisation généralisée au noeud // c'est différent de celle au pti car elle inclue la surface de l'élément Coordonnee force_stab(dimf); // init for (int i=1;i<= dimf;i++,ix++) force_stab(i) = (*resD)(ix); double intensite_generalise = force_stab.Norme(); // on récupère la force externe au noeud à l'instant t TypeQuelconque_enum_etendu enu_ext(FORCE_GENE_EXT_t); // récupération du conteneur pour lecture uniquement const TypeQuelconque& typquel_ext = noe.Grandeur_quelconque(enu_ext); const Grandeur_coordonnee& cofo_ext = *((Grandeur_coordonnee*) typquel_ext.Const_Grandeur_pointee()); // on récupère la normale au noeud const TypeQuelconque& tiq = noe.Grandeur_quelconque(NN_SURF_t); const Grandeur_coordonnee& gr= *((const Grandeur_coordonnee*) (tiq.Const_Grandeur_pointee())); const Coordonnee& normale = gr.ConteneurCoordonnee_const(); // on calcule l'intensité de la force externe selon la normale double intensite_Fext = Dabs(cofo_ext.ConteneurCoordonnee_const() * normale); // si l'intensité de la stabilisation est supérieure à beta * intensite_Fext // on limite double maxi_intensite = beta * intensite_Fext; double max_intens_via_Fext = maxi_intensite; // on sauve pour le cas où on est dep max // on applique l'algo théorique cf. doc théorique if (intensite_Fext >= F_mini) // on est dans le cas où les forces externes existent {if ((intensite_generalise > maxi_intensite) && (intensite_generalise > ConstMath::petit) // au cas où maxi_intintensite très petites ) {limitation = true; if ((niveau_affichage > 3)) {cout << "\n limitation stabilisation due aux forces externes, F_stab gene= "<< intensite_generalise << " ==> " << maxi_intensite; if ((niveau_affichage>4) || (pt_StabMembBiel->Affichage_stabilisation() > 4)) cout << "\n F_mini= "<< F_mini << " intensite_Fext= "<< intensite_Fext; }; coef = DabsMiN(coef, maxi_intensite/intensite_generalise); }; // sinon pas de pb donc on ne fait rien } else // cas où les forces externes n'existent pas // la limitation va s'exercée via un déplacement maxi {maxi_intensite = Dabs(-alpha*d_maxi + maxi_F_t); {if ((intensite_generalise > maxi_intensite) && (intensite_generalise > ConstMath::petit) // au cas où maxi_intintensite très petites && (Dabs(alpha) > ConstMath::pasmalpetit) // il faut qu'alpha ne soit pas nul ) {limitation = true; if ((niveau_affichage > 3)) {cout << "\n limitation stabilisation due deplace maxi acceptable, F_s"<< intensite_generalise << " ==> " << maxi_intensite << " (max_intens_via_Fext= "< 4)) cout << "\n maxi_F_t= "<< maxi_F_t << " alpha*d_maxi= " << (alpha*d_maxi) << " alpha= " << alpha << " d_maxi= " << d_maxi; }; coef = DabsMiN(coef, maxi_intensite/intensite_generalise); }; }; }; }; // fin du test sur les noeuds à considérer };// fin de la boucle sur les noeuds if (limitation) { (*resD) *= coef; // mise à jour de la force de stabilisation // idem au niveau des noeuds int taille = pt_StabMembBiel->Taille(); for (int i=1;i<=taille;i++) {pt_StabMembBiel->FF_StabMembBiel(i) *=coef; // cas des énergies double delta_energie_initiale = pt_StabMembBiel->EE_StabMembBiel(i) - pt_StabMembBiel->EE_StabMembBiel_t(i); // on coefficiente le delta double delta_energie = delta_energie_initiale * coef; //ce qui donne au final: pt_StabMembBiel->EE_StabMembBiel(i) = delta_energie + pt_StabMembBiel->EE_StabMembBiel_t(i); }; // 2) ---- on met à jour la raideur et résidu global // en tenant compte de la stabilisation (*residu) += (*resD); (*raideur) += (*matD); }; // fin du cas if (limitation) }; // fin du cas ou on applique éventuellement une limitation #ifdef MISE_AU_POINT if ((niveau_affichage > 9)) {cout << "\n residu de stabilisation: "<< (*resD); cout << "\n raideur de stabilisation: "; matD->Affiche(); cout << "\n fin debug ElemMeca::Cal_implicit_StabMembBiel(.."; }; #endif } // fin du cas où on utilise la normale aux noeuds }; break; case LIGNE: break; default: // on ne fait rien pour l'instant pour les autres types break; }; }; }; // stabilisation pour un calcul explicit void ElemMeca::Cal_explicit_StabMembBiel(int iteg,const Met_abstraite::Expli_t_tdt ex , const int& nbint,const double& poids_volume ,Tableau * noeud_a_prendre_en_compte) { // la stabilisation en explicite n'est possible que s'il existe soit: // - une force de stabilisation déjà enregistrée // - un coefficient alpha non nulle que l'on peut calculer avec les données déjà enregistrées // l'idée est de bloquer la direction normale à l'élément pour une plaque et // les deux directions transverses pour une biel int niveau_affichage = ParaGlob::NiveauImpression(); if (pt_StabMembBiel->Affichage_stabilisation() > 0) niveau_affichage = pt_StabMembBiel->Affichage_stabilisation(); //---- détermination de l'intensité de stabilisation // ici on ne s'occupe pas de l'itération ni de l'incrément, dans tous les cas // on utilise les grandeurs déjà stockées // ceci quelque soit le type de stabilisation double alpha = 0.; // init bool stab_utilisable = false; // init Enum_StabMembraneBiel enu_stab = pt_StabMembBiel->Type_stabMembrane(); if (pt_StabMembBiel != NULL) if (pt_StabMembBiel->Activite_en_explicite()) { //alpha = pt_StabMembBiel->Stab_ref(); // récup de l'intensité de stabilisation // ce n'est pas un pointeur, alpha est une variable locale // stab_ref, par défaut == 1, mais dans le cas d'un passage // implicit -> explicite : vaut la dernière valeur implicite calculée // cela permet de profiter du passage en implicite, en récupérant l'intensité // de raideur réelle alpha = pt_StabMembBiel->Stab_ref(); // init // dans le cas d'une fonction multiplicatrice , // et il faut appeler la fonction qui peut varier if (pt_StabMembBiel->Pt_fct_gamma() != NULL) // cas où il y a une fonction nD {Fonction_nD* fct = pt_StabMembBiel->Pt_fct_gamma(); // récupération de la fonction nD // on commence par récupérer les conteneurs des grandeurs à fournir List_io & li_enu_scal = fct->Li_enu_etendu_scalaire(); List_io & li_quelc = fct->Li_equi_Quel_evolue(); bool absolue = true; // on se place systématiquement en absolu // on va utiliser la méhode Valeur_multi pour les grandeurs strictement scalaire int cas = -1; // signifie que l'on utilise la métrique qui vient juste d'être calculée int num_iteg_a_considerer; // init if (iteg > 0) // on est dans la boucle num_iteg_a_considerer = iteg; else // sinon on est à la sortie de la boucle num_iteg_a_considerer = nbint; Tableau val_ddl_enum(ElemMeca::Valeur_multi (absolue,TEMPS_tdt,li_enu_scal,num_iteg_a_considerer,-cas)); // on utilise la méthode des grandeurs évoluées pour les Coordonnees et Tenseur Valeurs_Tensorielles(absolue, TEMPS_tdt,li_quelc,num_iteg_a_considerer,-cas); // calcul de la valeur et retour dans tab_ret Tableau & tab_ret = fct->Valeur_FnD_Evoluee(&val_ddl_enum,&li_enu_scal,&li_quelc,NULL,NULL); // seule la première valeur est ok alpha *= tab_ret(1) ; pt_StabMembBiel->Valgamma() = alpha; // on sauvegarde la valeur d'alpha } else // sinon cela veut dire que l'intensité de stabilisation est fixe // en explicite c'est directement la valeur lue {alpha *= pt_StabMembBiel->Valgamma() ;} stab_utilisable=true; }; // si la stabilisation est utilisable on s'en sert if (stab_utilisable) {// choix en fonction de la géométrie Enum_type_geom enu_type_geom = Type_geom_generique(this->Id_geometrie()); switch (enu_type_geom) { case SURFACE: if (!Contient_Normale_au_noeud(enu_stab)) // --- cas où on utilise la normale au pti {// la normale vaut le produit vectoriel des 2 premiers vecteurs Coordonnee normale = Util::ProdVec_coor( (*ex.giB_tdt).Coordo(1), (*ex.giB_tdt).Coordo(2)); // calcul de la normale normée et pondérée par la stabilisation normale.Normer(); int nbddl = (*residu).Taille(); int dimf = 3; // ne fonctionne qu'en dim 3 if(ParaGlob::AxiSymetrie()) // cas axisymétrique, dans ce cas on ne prend en compte que les // dimf-1 coordonnées donc on décrémente dimf--; int nbne = tab_noeud.Taille(); double ponder_F_t = 1.; // init // si iteg == 1 ==> premier calcul correspondant au premier pti if (iteg == 1) { resD->Inita(0.); maxi_F_t = 0.; // on initialise les forces et énergie int taille = pt_StabMembBiel->Taille(); for (int i=1;i<=taille;i++) {pt_StabMembBiel->FF_StabMembBiel(i) = 0.; pt_StabMembBiel->EE_StabMembBiel(i) = pt_StabMembBiel->EE_StabMembBiel_t(i); } }; // on récupère l'élément géométrique ElemGeomC0& elemGeom = this->ElementGeometrique(); // récup des fonctions d'interpolation const Tableau & taphi = elemGeom.TaPhi(); // on applique une force de stabilisation // uniquement suivant la direction de la normale // ici iteg peut soit == -1 : on est sortie de la boucle sur les pti // soit > 0 : on et dans la boucle des pti int num_pti=iteg; // init if (iteg == -1) num_pti = nbint; // la force est proportionelle au déplacement suivant la normale if (iteg > 0) { int ix=1; for (int ne =1; ne<= nbne; ne++) {bool continuer = true; if (noeud_a_prendre_en_compte != NULL) if (!(*noeud_a_prendre_en_compte)(ne)) continuer = false; if (continuer) {Noeud& noe = *(tab_noeud(ne)); // pour simplifier // pour chaque noeud on va rectifier la normale par rapport à celle calculée au pti // on va bloquer le déplacement dans la direction de la normale au noeud à t // celle-ci peut-être différente de celle à t=0, lorsque l'on a une succession d'algo sur le même incrément // on commence par récupérer les coordonnées pour l'itération 0 TypeQuelconque_enum_etendu enu(XI_ITER_0); // récupération du conteneur pour lecture uniquement const TypeQuelconque& typquel = noe.Grandeur_quelconque(enu); const Grandeur_coordonnee& cofo = *((Grandeur_coordonnee*) typquel.Const_Grandeur_pointee()); Coordonnee delta_X = noe.Coord2() - cofo.ConteneurCoordonnee_const(); double normal_fois_delta_X = normale * delta_X; // le déplacement suivant la normale // dans le cas où on veut pondérer F_t, on calcule la fonction if (pt_StabMembBiel->Pt_fct_ponder_Ft() != NULL) {Fonction_nD* fct = pt_StabMembBiel->Pt_fct_ponder_Ft(); // récupération de la fonction nD // on commence par récupérer les conteneurs des grandeurs à fournir List_io & li_enu_scal = fct->Li_enu_etendu_scalaire(); List_io & li_quelc = fct->Li_equi_Quel_evolue(); bool absolue = true; // on se place systématiquement en absolu // on va utiliser la méhode Valeur_multi pour les grandeurs strictement scalaire int cas = -1; // signifie que l'on utilise la métrique qui vient juste d'être calculée Tableau val_ddl_enum(ElemMeca::Valeur_multi (absolue,TEMPS_tdt,li_enu_scal,num_pti,-cas)); // on utilise la méthode des grandeurs évoluées pour les Coordonnees et Tenseur Valeurs_Tensorielles(absolue, TEMPS_tdt,li_quelc,num_pti,-cas); // calcul de la valeur et retour dans tab_ret Tableau & tab_ret = fct->Valeur_FnD_Evoluee(&val_ddl_enum,&li_enu_scal,&li_quelc,NULL,NULL); // seule la première valeur est ok ponder_F_t = tab_ret(1) ; } // un - car la force doit s'opposer au déplacement double intensite = -alpha * normal_fois_delta_X + ponder_F_t * pt_StabMembBiel->FF_StabMembBiel_t(num_pti); // on enregistre le maxi de la force à t maxi_F_t = DabsMaX(maxi_F_t, pt_StabMembBiel->FF_StabMembBiel_t(num_pti)); // d'où une variation réelle d'intensité double delta_intensite = intensite - ponder_F_t * pt_StabMembBiel->FF_StabMembBiel_t(num_pti); pt_StabMembBiel->EE_StabMembBiel(num_pti) += 0.5 * delta_intensite * normal_fois_delta_X; #ifdef MISE_AU_POINT if ((niveau_affichage > 5)) {cout << "\n ElemMeca::Cal_explicit_StabMembBiel(.."; cout << "\n alpha= "<Beta(); double F_mini = pt_StabMembBiel->F_mini(); double d_maxi = pt_StabMembBiel->D_maxi(); // on refait une boucle sur les pti int ix=1; for (int ne =1; ne<= nbne; ne++) {bool continuer = true; if (noeud_a_prendre_en_compte != NULL) if (!(*noeud_a_prendre_en_compte)(ne)) continuer = false; if (continuer) {Noeud& noe = *(tab_noeud(ne)); // pour simplifier // récup de la force de stabilisation généralisée au noeud // c'est différent de celle au pti car elle inclue la surface de l'élément Coordonnee force_stab(dimf); // init for (int i=1;i<= dimf;i++,ix++) force_stab(i) = (*resD)(ix); double intensite_generalise = force_stab.Norme(); // on récupère la force externe au noeud à l'instant t TypeQuelconque_enum_etendu enu_ext(FORCE_GENE_EXT_t); // récupération du conteneur pour lecture uniquement const TypeQuelconque& typquel_ext = noe.Grandeur_quelconque(enu_ext); const Grandeur_coordonnee& cofo_ext = *((Grandeur_coordonnee*) typquel_ext.Const_Grandeur_pointee()); // on calcule l'intensité de la force externe selon la normale double intensite_Fext = Dabs(cofo_ext.ConteneurCoordonnee_const() * normale); // si l'intensité de la stabilisation est supérieure à beta * intensite_Fext // on limite double maxi_intensite = beta * intensite_Fext; double max_intens_via_Fext = maxi_intensite; // on sauve pour le cas où on est dep max // on applique l'algo théorique cf. doc théorique if (intensite_Fext >= F_mini) // on est dans le cas où les forces externes existent {if ((intensite_generalise > maxi_intensite) && (intensite_generalise > ConstMath::petit) // au cas où maxi_intensite et intensite très petites ) {limitation = true; if ((niveau_affichage > 3)) {cout << "\n limitation stabilisation due aux forces externes, F_stab gene= "<< intensite_generalise << " ==> " << maxi_intensite; if ((niveau_affichage > 5)) cout << "\n F_mini= "<< F_mini << " intensite_Fext= "<< intensite_Fext; }; coef = DabsMiN(coef, maxi_intensite/intensite_generalise); }; // sinon pas de pb donc on ne fait rien } else // cas où les forces externes n'existent pas // la limitation va s'exercée via un déplacement maxi {maxi_intensite = Dabs(-alpha*d_maxi + maxi_F_t); {if ((intensite_generalise > maxi_intensite) && (intensite_generalise > ConstMath::petit) // au cas où maxi_intensite et intensite très petites && (Dabs(alpha) > ConstMath::pasmalpetit) // il faut qu'alpha ne soit pas nul ) {limitation = true; if ((niveau_affichage > 3)) {cout << "\n limitation stabilisation due deplace maxi acceptable, F_stab gene= "<< intensite_generalise << " ==> " << maxi_intensite << " (max_intens_via_Fext= "< 4)) cout << "\n maxi_F_t= "<< maxi_F_t << " alpha*d_maxi= " << (alpha*d_maxi) << " alpha= " << alpha << " d_maxi= " << d_maxi; }; coef = DabsMiN(coef, maxi_intensite/intensite_generalise); }; }; }; }; // fin du test sur les noeuds à considérer };// fin de la boucle sur les noeuds if (limitation) { (*resD) *= coef; // mise à jour de la force de stabilisation // idem au niveau des pti int taille = pt_StabMembBiel->Taille(); for (int i=1;i<=taille;i++) {pt_StabMembBiel->FF_StabMembBiel(i) *=coef; // cas des énergies double delta_energie_initiale = pt_StabMembBiel->EE_StabMembBiel(i) - pt_StabMembBiel->EE_StabMembBiel_t(i); // on coefficiente le delta double delta_energie = delta_energie_initiale * coef; //ce qui donne au final: pt_StabMembBiel->EE_StabMembBiel(i) = delta_energie + pt_StabMembBiel->EE_StabMembBiel_t(i); }; }; }; // fin mise en place d'une limitation éventuelle // 2) ---- on met à jour le résidu global // en tenant compte de la stabilisation (*residu) += (*resD); #ifdef MISE_AU_POINT if ((niveau_affichage > 9)) {cout << "\n residu de stabilisation: "<< (*resD); cout << "\n fin ElemMeca::Cal_explicit_StabMembBiel(.."; }; #endif }; // fin du cas iteg == -1 } // fin du cas où on utilise la normale aux pti else //--- cas où on utilise la normale au noeud {if (iteg == -1) // on ne calcul que si iteg == -1, c-a-d qu'on est sortie // de la boucle sur les pti // sinon cas où on utilise la normale aux noeuds {int nbddl = (*residu).Taille(); int dimf = 3; // ne fonctionne qu'en dim 3 if(ParaGlob::AxiSymetrie()) // cas axisymétrique, dans ce cas on ne prend en compte que les // dimf-1 coordonnées donc on décrémente dimf--; int nbne = tab_noeud.Taille(); resD->Inita(0.); maxi_F_t = 0.; #ifdef MISE_AU_POINT // on vérifie le bon dimensionnement int taille = pt_StabMembBiel->Taille(); if (taille != nbne) {cout << "\n erreur** ElemMeca::Cal_explicit_StabMembBiel(.." << " le stockage est mal dimensionne: taille = " << taille << " alors qu'il devrait etre : nbe = " << nbne << flush ; Sortie(1); }; #endif // on applique une force de stabilisation aux noeuds // uniquement suivant la direction de la normale // la force est proportionelle au déplacement suivant la normale au noeud int ix=1; for (int ne =1; ne<= nbne; ne++) {Noeud& noe = *(tab_noeud(ne)); // pour simplifier // on initialise les forces et énergie pt_StabMembBiel->FF_StabMembBiel(ne) = 0.; pt_StabMembBiel->EE_StabMembBiel(ne) = pt_StabMembBiel->EE_StabMembBiel_t(ne); // pour chaque noeud on va bloquer le déplacement dans la direction de la normale au noeud à t // on récupère la normale au noeud const TypeQuelconque& tiq = noe.Grandeur_quelconque(NN_SURF_t); const Grandeur_coordonnee& gr= *((const Grandeur_coordonnee*) (tiq.Const_Grandeur_pointee())); const Coordonnee& normale = gr.ConteneurCoordonnee_const(); //dans un calcul implicit on utilise la position à l'itération 0 // celle-ci peut-être différente de celle à t=0, lorsque l'on a une succession d'algo sur le même incrément // on commence par récupérer les coordonnées pour l'itération 0 TypeQuelconque_enum_etendu enu(XI_ITER_0); // récupération du conteneur pour lecture uniquement const TypeQuelconque& typquel = noe.Grandeur_quelconque(enu); const Grandeur_coordonnee& cofo = *((Grandeur_coordonnee*) typquel.Const_Grandeur_pointee()); Coordonnee delta_X = noe.Coord2() - cofo.ConteneurCoordonnee_const(); double normal_fois_delta_X = normale * delta_X; double ponder_F_t = 1.; // init // dans le cas où on veut pondérer F_t, on calcule la fonction if (pt_StabMembBiel->Pt_fct_ponder_Ft() != NULL) {Fonction_nD* fct = pt_StabMembBiel->Pt_fct_ponder_Ft(); // récupération de la fonction nD // on commence par récupérer les conteneurs des grandeurs à fournir List_io & li_enu_scal = fct->Li_enu_etendu_scalaire(); List_io & li_quelc = fct->Li_equi_Quel_evolue(); bool absolue = true; // on se place systématiquement en absolu // on va utiliser la méhode Valeur_multi pour les grandeurs strictement scalaire int cas = -1; // signifie que l'on utilise la métrique qui vient juste d'être calculée // au dernier pti ! Tableau val_ddl_enum(ElemMeca::Valeur_multi (absolue,TEMPS_tdt,li_enu_scal,nbint,-cas)); // on utilise la méthode des grandeurs évoluées pour les Coordonnees et Tenseur Valeurs_Tensorielles(absolue, TEMPS_tdt,li_quelc,nbint,-cas); // calcul de la valeur et retour dans tab_ret Tableau & tab_ret = fct->Valeur_FnD_Evoluee(&val_ddl_enum,&li_enu_scal,&li_quelc,NULL,NULL); // seule la première valeur est ok ponder_F_t = tab_ret(1) ; } // un - car la force doit s'opposer au déplacement double intensite = -alpha * normal_fois_delta_X + ponder_F_t * pt_StabMembBiel->FF_StabMembBiel_t(ne); // on enregistre le maxi de la force à t maxi_F_t = DabsMaX(maxi_F_t, pt_StabMembBiel->FF_StabMembBiel_t(ne)); // d'où une variation réelle d'intensité double delta_intensite = intensite - ponder_F_t * pt_StabMembBiel->FF_StabMembBiel_t(ne); pt_StabMembBiel->EE_StabMembBiel(ne) += 0.5 * delta_intensite * normal_fois_delta_X; #ifdef MISE_AU_POINT if ((niveau_affichage > 5)) {cout << "\n ElemMeca::Cal_explicit_StabMembBiel(.."; cout << "\n alpha= "<Beta(); double F_mini = pt_StabMembBiel->F_mini(); double d_maxi = pt_StabMembBiel->D_maxi(); // on refait une boucle sur les noeuds int ix=1; for (int ne =1; ne<= nbne; ne++) {bool continuer = true; if (noeud_a_prendre_en_compte != NULL) if (!(*noeud_a_prendre_en_compte)(ne)) continuer = false; if (continuer) {Noeud& noe = *(tab_noeud(ne)); // pour simplifier // récup de la force de stabilisation généralisée au noeud // c'est différent de celle au pti car elle inclue la surface de l'élément Coordonnee force_stab(dimf); // init for (int i=1;i<= dimf;i++,ix++) force_stab(i) = (*resD)(ix); double intensite_generalise = force_stab.Norme(); // on récupère la force externe au noeud à l'instant t TypeQuelconque_enum_etendu enu_ext(FORCE_GENE_EXT_t); // récupération du conteneur pour lecture uniquement const TypeQuelconque& typquel_ext = noe.Grandeur_quelconque(enu_ext); const Grandeur_coordonnee& cofo_ext = *((Grandeur_coordonnee*) typquel_ext.Const_Grandeur_pointee()); // on récupère la normale au noeud const TypeQuelconque& tiq = noe.Grandeur_quelconque(NN_SURF_t); const Grandeur_coordonnee& gr= *((const Grandeur_coordonnee*) (tiq.Const_Grandeur_pointee())); const Coordonnee& normale = gr.ConteneurCoordonnee_const(); // on calcule l'intensité de la force externe selon la normale double intensite_Fext = Dabs(cofo_ext.ConteneurCoordonnee_const() * normale); // si l'intensité de la stabilisation est supérieure à beta * intensite_Fext // on limite double maxi_intensite = beta * intensite_Fext; double max_intens_via_Fext = maxi_intensite; // on sauve pour le cas où on est en dep max // on applique l'algo théorique cf. doc théorique if (intensite_Fext >= F_mini) // on est dans le cas où les forces externes existent {if ((intensite_generalise > maxi_intensite) && (intensite_generalise > ConstMath::petit) // au cas où maxi_intintensite très petites ) {limitation = true; if ((niveau_affichage > 3)) {cout << "\n limitation stabilisation due aux forces externes, F_stab gene= "<< intensite_generalise << " ==> " << maxi_intensite; if ((niveau_affichage > 4)) cout << "\n F_mini= "<< F_mini << " intensite_Fext= "<< intensite_Fext; }; coef = DabsMiN(coef, maxi_intensite/intensite_generalise); }; // sinon pas de pb donc on ne fait rien } else // cas où les forces externes n'existent pas // la limitation va s'exercée via un déplacement maxi {maxi_intensite = Dabs(-alpha*d_maxi + maxi_F_t); {if ((intensite_generalise > maxi_intensite) && (intensite_generalise > ConstMath::petit) // au cas où maxi_intintensite très petites && (Dabs(alpha) > ConstMath::pasmalpetit) // il faut qu'alpha ne soit pas nul ) {limitation = true; if ((niveau_affichage > 3)) {cout << "\n limitation stabilisation due deplace maxi acceptable, F_s"<< intensite_generalise << " ==> " << maxi_intensite << " (max_intens_via_Fext= "< 4)) cout << "\n maxi_F_t= "<< maxi_F_t << " alpha*d_maxi= " << (alpha*d_maxi) << " alpha= " << alpha << " d_maxi= " << d_maxi; }; coef = DabsMiN(coef, maxi_intensite/intensite_generalise); }; }; }; }; // fin du test sur les noeuds à considérer };// fin de la boucle sur les noeuds if (limitation) { (*resD) *= coef; // mise à jour de la force de stabilisation // idem au niveau des noeuds int taille = pt_StabMembBiel->Taille(); for (int i=1;i<=taille;i++) {pt_StabMembBiel->FF_StabMembBiel(i) *=coef; // cas des énergies double delta_energie_initiale = pt_StabMembBiel->EE_StabMembBiel(i) - pt_StabMembBiel->EE_StabMembBiel_t(i); // on coefficiente le delta double delta_energie = delta_energie_initiale * coef; //ce qui donne au final: pt_StabMembBiel->EE_StabMembBiel(i) = delta_energie + pt_StabMembBiel->EE_StabMembBiel_t(i); }; }; // fin du cas if (limitation) }; // fin du cas ou on applique éventuellement une limitation // 2) ---- on met à jour la raideur et résidu global // en tenant compte de la stabilisation (*residu) += (*resD); #ifdef MISE_AU_POINT if ((niveau_affichage > 9)) {cout << "\n residu de stabilisation: "<< (*resD); cout << "\n fin debug ElemMeca::Cal_explicit_StabMembBiel(.."; }; #endif } // fin du cas où on utilise la normale aux noeuds }; break; case LIGNE: break; default: // on ne fait rien pour l'instant pour les autres types break; }; }; }; // fonction a renseigner par les classes dérivées, concernant les répercutions // éventuelles due à la suppression de tous les frontières // nums_i : donnent les listes de frontières supprimées void ElemMeca::Prise_en_compte_des_consequences_suppression_tous_frontieres() {// il faut supprimer toutes les déformations liés aux frontières int tail_S = defSurf.Taille(); for (int i=1;i<=tail_S;i++) { delete defSurf(i); defSurf(i)=NULL; }; int tail_A = defArete.Taille(); for (int i=1;i<=tail_A;i++) { delete defArete(i); defArete(i)=NULL; }; }; // idem pour une frontière (avant qu'elle soit supprimée) void ElemMeca::Prise_en_compte_des_consequences_suppression_une_frontiere(ElFrontiere* elemFront) { int taille = tabb.Taille(); // on choisit en fonction du type de frontière if (( elemFront->Type_geom_front() == LIGNE)&& (defArete.Taille()!=0)) {int taille_ligne = taille - posi_tab_front_lin; // a priori = cas sans les points if (posi_tab_front_point != 0) // cas où il y a des points taille_ligne = posi_tab_front_point-posi_tab_front_lin; for (int i=1; i<=taille_ligne; i++) {if ((tabb(i+posi_tab_front_lin) == elemFront)&& (defArete(i) != NULL)) {delete defArete(i);defArete(i)=NULL;break;} } } else if (( elemFront->Type_geom_front() == SURFACE) && (defSurf.Taille()!=0)) {if (posi_tab_front_lin != 0) // si == 0 cela signifie qu'il n'y a pas de surface à supprimer !! { for (int i=1; i<=posi_tab_front_lin; i++) // posi_tab_front_lin == le nombre de surfaces, qui sont obligatoirement en début de tableau if ((tabb(i) == elemFront)&& (defSurf(i) != NULL)) {delete defSurf(i);defSurf(i)=NULL;break;} }; }; }; // Calcul des frontieres de l'element // creation des elements frontieres et retour du tableau de ces elements // la création n'a lieu qu'au premier appel // ou lorsque l'on force le paramètre force a true // dans ce dernier cas seul les frontière effacées sont recréée // cas : // = 0 -> on veut toutes les frontières // = 1 -> on veut uniquement les surfaces // = 2 -> on veut uniquement les lignes // = 3 -> on veut uniquement les points // = 4 -> on veut les surfaces + les lignes // = 5 -> on veut les surfaces + les points // = 6 -> on veut les lignes + les points Tableau const & ElemMeca::Frontiere_elemeca(int cas, bool force) {// le calcul et la création ne sont effectués qu'au premier appel // ou lorsque l'on veut forcer une recréation int taille = tabb.Taille(); // la taille initiales des frontières if (force) // dans ce cas on commence par tout effacer { // on efface les surfaces (s'il y en a) for (int i=1;i<=posi_tab_front_lin;i++) {if (tabb(i) != NULL) {delete tabb(i); //on commence par supprimer tabb(i)=NULL; // on supprime également éventuellement la déformation associée if (defSurf.Taille() != 0) if (defSurf(i) != NULL) {delete defSurf(i);defSurf(i)=NULL;}; ind_front_surf = 0; // on indique qu'il ne reste plus de frontière surface }; }; // on efface les lignes (s'il y en a) for (int i=1;i<=posi_tab_front_point - posi_tab_front_lin;i++) {if (tabb(i+posi_tab_front_lin) != NULL) {delete tabb(i+posi_tab_front_lin); //on commence par supprimer tabb(i+posi_tab_front_lin)=NULL; // on supprime également éventuellement la déformation associée if (defArete.Taille() != 0) if (defArete(i) != NULL) {delete defArete(i);defArete(i)=NULL;}; ind_front_lin = 0; // on indique qu'il ne reste plus de frontière ligne }; }; // on efface les points (s'il y en a) for (int i=1;i<=taille - posi_tab_front_point;i++) {if (tabb(i+posi_tab_front_point) != NULL) {delete tabb(i+posi_tab_front_point); //on commence par supprimer tabb(i+posi_tab_front_point)=NULL; ind_front_point = 0; // on indique qu'il ne reste plus de frontière ligne }; }; }; // -- maintenant on s'occupe de la construction conditionnelle bool built_surf = false;bool built_ligne = false; bool built_point = false; switch (cas) {case 0: built_surf = built_ligne = built_point = true; break; case 1: built_surf = true; break; case 2: built_ligne = true; break; case 3: built_point = true; break; case 4: built_surf = built_ligne = true; break; case 5: built_surf = built_point = true; break; case 6: built_ligne = built_point = true; break; }; if ( ((ind_front_surf == 0)&& (ind_front_lin == 0) && (ind_front_point == 0)) || force ) { // récup de l'élément géométrique ElemGeomC0& el = ElementGeometrique(); int tail_ar = el.NbSe(); // nombre potentiel d'arêtes int tail_fa = el.NbFe(); // nombre potentiel de faces int tail_po = el.Nbne(); // nombre potentiel de points // récup du tableau de ddl actuel const DdlElement & tdd = TableauDdl(); // --- on va construire en fonction des indicateurs des tableaux intermédiaires int new_posi_tab_front_point = 0; //init par défaut int new_posi_tab_front_lin = 0; //init par défaut int new_ind_front_point = 0; int new_ind_front_lin = 0; int new_ind_front_surf = 0; // -- pour les surfaces Tableau tabb_surf; if ((built_surf)&& ((ind_front_surf == 0)||force)) {tabb_surf.Change_taille(tail_fa,NULL);// init par défaut for (int num=1;num<=tail_fa;num++) { int nbnoe = el.Nonf()(num).Taille(); // nb noeud de la surface Tableau tab(nbnoe); // les noeuds de la frontiere DdlElement ddelem(nbnoe); // les ddlelements des noeuds frontieres for (int i=1;i<= nbnoe;i++) { tab(i) = tab_noeud(el.Nonf()(num)(i)); ddelem.Change_un_ddlNoeudElement(i,tdd(el.Nonf()(num)(i))); }; tabb_surf(num) = new_frontiere_surf(num,tab,ddelem); }; // nouveau indicateur d'existence new_ind_front_surf = 1; // on positionne les nouvelles positions new_posi_tab_front_point += tail_fa; new_posi_tab_front_lin += tail_fa; }; // -- pour les lignes Tableau tabb_ligne; if ((built_ligne)&& ((ind_front_lin == 0)||force)) {tabb_ligne.Change_taille(tail_ar,NULL);// init par défaut for (int num=1;num<=tail_ar;num++) { int nbnoe = el.NonS()(num).Taille(); // nb noeud de l'arête Tableau tab(nbnoe); // les noeuds de l'arête frontiere DdlElement ddelem(nbnoe); // les ddlelements des noeuds frontieres for (int i=1;i<= nbnoe;i++) { tab(i) = tab_noeud(el.NonS()(num)(i)); ddelem.Change_un_ddlNoeudElement(i,tdd(el.NonS()(num)(i))); }; tabb_ligne(num) = new_frontiere_lin(num,tab,ddelem); }; // nouveau indicateur d'existence new_ind_front_lin = 1; // on positionne les nouvelles positions new_posi_tab_front_point += tail_ar; }; // -- pour les points Tableau tabb_point; if ((built_point) && ((ind_front_point == 0)||force)) {tabb_point.Change_taille(tail_po,NULL);// init par défaut // maintenant création des frontière point éventuellement Tableau tab(1); // les noeuds de la frontiere (tab de travail) DdlElement ddelem(1); // les ddlelements des points frontieres (tab de travail) for (int i=1;i<=tail_po;i++) if (tabb_point(i) == NULL) { tab(1) = tab_noeud(i); ddelem.Change_un_ddlNoeudElement(1,tdd(i)); tabb_point(i) = new FrontPointF(tab,ddelem); }; // nouveau indicateur d'existence new_ind_front_point = 1; }; // --- mise à jour du tableau globale et des indicateurs ad hoc int taille_finale = tabb_surf.Taille()+tabb_ligne.Taille()+tabb_point.Taille(); tabb.Change_taille(taille_finale); // cas des points if (new_ind_front_point) // là is s'agit de nouveaux éléments {for (int i=tail_po;i>0;i--) // transfert pour les noeuds { tabb(i+new_posi_tab_front_point) = tabb_point(i);} } else if (ind_front_point) // là il s'agit d'anciens éléments {for (int i=tail_po;i>0;i--) // transfert pour les noeuds en descendant { tabb(i+new_posi_tab_front_point) = tabb(i+posi_tab_front_point);} }; // cas des lignes if (new_ind_front_lin) // là il s'agit de nouveaux éléments {for (int i=1;i<=tail_ar;i++) // transfert { tabb(i+new_posi_tab_front_lin) = tabb_ligne(i);} } else if (ind_front_lin) // là il s'agit d'anciens éléments {for (int i=tail_ar;i>0;i--) // transfert en descendant { tabb(i+new_posi_tab_front_lin) = tabb(i+posi_tab_front_lin);} }; // cas des surfaces if (new_ind_front_surf) // là is s'agit de nouveaux éléments {for (int i=1;i<=tail_fa;i++) // transfert { tabb(i) = tabb_surf(i);} }; // dans le cas où il y avait des anciens éléments, il n'y a rien n'a faire // car le redimentionnement de tabb ne change pas les premiers éléments // mis à jour des indicateurs ind_front_surf = new_ind_front_surf; posi_tab_front_lin = new_posi_tab_front_lin; ind_front_lin = new_ind_front_lin; posi_tab_front_point = new_posi_tab_front_point; ind_front_point = new_ind_front_point; }; // retour du tableau return (Tableau &)tabb; }; // ramène la frontière point // éventuellement création des frontieres points de l'element et stockage dans l'element // si c'est la première fois sinon il y a seulement retour de l'elements // a moins que le paramètre force est mis a true // dans ce dernier cas la frontière effacéee est recréée // num indique le numéro du point à créer (numérotation EF) ElFrontiere* const ElemMeca::Frontiere_points(int num,bool force) { // -- tout d'abord on évacue le cas où il n'y a pas de frontière point à calculer // récup de l'élément géométrique ElemGeomC0& el = ElementGeometrique(); int tail_po = el.Nbne(); // nombre potentiel de points if (num > tail_po) return NULL; // le calcul et la création ne sont effectués qu'au premier appel // ou lorsque l'on veut forcer une recréation // on regarde si les frontières points existent sinon on les crée if (ind_front_point == 1) {return (ElFrontiere*)tabb(posi_tab_front_point+num);} else if ( ind_front_point == 2) // cas où certaines frontières existent {if (tabb(posi_tab_front_point+num) != NULL) return (ElFrontiere*)tabb(posi_tab_front_point+num); }; // arrivée ici cela veut dire que la frontière point n'existe pas // on l'a reconstruit éventuellement // le calcul et la création ne sont effectués qu'au premier appel // ou lorsque l'on veut forcer une recréation if ((ind_front_point == 0) || force ) {// récup du tableau de ddl const DdlElement & tdd = TableauDdl(); int taille = tabb.Taille(); // la taille initiales des frontières int tail_fa = el.NbFe(); // nombre potentiel de faces int tail_ar = el.NbSe(); // nombre potentiel d'arêtes // dimensionnement du tableau de frontières ligne si nécessaire if (ind_front_point == 0) {if ((ind_front_lin > 0) && (ind_front_surf == 0)) // cas où les frontières lignes existent seules, on ajoute les points { int taille_finale = tail_ar + tail_po; tabb.Change_taille(taille_finale); for (int i=1;i<= tail_ar;i++) // transfert pour les lignes tabb(i) = tabb(i+tail_ar); posi_tab_front_point=tail_ar; posi_tab_front_lin = 0; // car on n'a pas de surface } else if ((ind_front_lin > 0) && (ind_front_surf > 0)) // cas où les frontières lignes existent et surfaces et pas de points, donc on les rajoutes { int taille_finale = tail_fa + tail_po+tail_ar; tabb.Change_taille(taille_finale);// les grandeurs pour les surfaces et les lignes sont // conservées, donc pas de transferts à prévoir posi_tab_front_point=tail_ar+tail_fa; // après les faces et les lignes posi_tab_front_lin = tail_fa; // après les surfaces } else { // cas où il n'y a pas de frontières lignes if (ind_front_surf == 0) // cas où il n'y a pas de surface {tabb.Change_taille(tail_po,NULL); // on n'a pas de ligne, pas de point et pas de surface posi_tab_front_point = posi_tab_front_lin = 0;} else {tabb.Change_taille(tail_po+tail_fa); // cas où les surfaces existent // le redimensionnement n'affecte pas les surfaces qui sont en début de tableau posi_tab_front_lin = posi_tab_front_point = tail_fa; // après les surfaces }; }; // et on met les pointeurs de points en NULL for (int i=1;i<= tail_po;i++) { tabb(i+posi_tab_front_point) = NULL;} }; // maintenant création de la frontière point Tableau tab(1); // les noeuds de la frontiere tab(1) = tab_noeud(num); DdlElement ddelem(1); // les ddlelements des points frontieres ddelem.Change_un_ddlNoeudElement(1,tdd(num)); tabb(posi_tab_front_point+num) = new FrontPointF(tab,ddelem); // on met à jour l'indicateur ind_front_point ind_front_point = 1; // a priori for (int npoint=1;npoint<=tail_po;npoint++) if (tabb(posi_tab_front_point+npoint) == NULL) { ind_front_point = 2; break;}; }; // maintenant normalement la frontière est créé on la ramène return (ElFrontiere*)tabb(posi_tab_front_point+num); }; // ramène la frontière linéique // éventuellement création des frontieres linéique de l'element et stockage dans l'element // si c'est la première fois et en 3D sinon il y a seulement retour de l'elements // a moins que le paramètre force est mis a true // dans ce dernier cas la frontière effacéee est recréée // num indique le numéro de l'arête à créer (numérotation EF) // nbneA: nombre de noeuds des segments frontières // el : l'élément ElFrontiere* const ElemMeca::Frontiere_lineique(int num,bool force) { // -- tout d'abord on évacue le cas où il n'y a pas de frontière linéique à calculer // récup de l'élément géométrique ElemGeomC0& el = ElementGeometrique(); int tail_ar = el.NbSe(); // nombre potentiel d'arêtes if (num > tail_ar) return NULL; // le calcul et la création ne sont effectués qu'au premier appel // ou lorsque l'on veut forcer une recréation // on regarde si les frontières linéiques existent sinon on les crée if (ind_front_lin == 1) {return (ElFrontiere*)tabb(posi_tab_front_lin+num);} else if ( ind_front_lin == 2) // cas où certaines frontières existent {if (tabb(posi_tab_front_lin+num) != NULL) return (ElFrontiere*)tabb(posi_tab_front_lin+num); }; // arrivée ici cela veut dire que la frontière ligne n'existe pas // on l'a reconstruit // le calcul et la création ne sont effectués qu'au premier appel // ou lorsque l'on veut forcer une recréation if ((ind_front_lin == 0) || force ) {// récup du tableau de ddl const DdlElement & tdd = TableauDdl(); int taille = tabb.Taille(); // la taille initiales des frontières int tail_fa = el.NbFe(); // nombre potentiel de faces int tail_po = el.Nbne(); // nombre potentiel de points // dimensionnement du tableau de frontières ligne si nécessaire if (ind_front_lin == 0) {if ((ind_front_point > 0) && (ind_front_surf == 0)) // cas où les frontières points existent seules, on ajoute les lignes { int taille_finale = tail_ar + tail_po; tabb.Change_taille(taille_finale); for (int i=1;i<= tail_po;i++) tabb(i+tail_ar) = tabb(i); posi_tab_front_point=tail_ar; posi_tab_front_lin = 0; // car on n'a pas de surface } else if ((ind_front_point > 0) && (ind_front_surf > 0)) // cas où les frontières points existent et surfaces et pas de ligne, donc on les rajoutes { int taille_finale = tail_fa + tail_po+tail_ar; tabb.Change_taille(taille_finale);// les grandeurs pour les surfaces sont conservées for (int i=1;i<= tail_po;i++) // transfert pour les noeuds { tabb(i+tail_ar+tail_fa) = tabb(i+tail_fa);}; posi_tab_front_point=tail_ar+tail_fa; // après les faces et les lignes posi_tab_front_lin = tail_fa; // après les surfaces } else { // cas où il n'y a pas de frontières points if (ind_front_surf == 0) // cas où il n'y a pas de surface {tabb.Change_taille(tail_ar,NULL); // on n'a pas de ligne, pas de point et pas de surface posi_tab_front_lin = 0; posi_tab_front_point = tail_ar; } else {tabb.Change_taille(tail_ar+tail_fa); // cas où les surfaces existent // le redimensionnement n'affecte pas les surfaces qui sont en début de tableau posi_tab_front_lin = tail_fa; // après les surfaces posi_tab_front_point = tail_fa+tail_ar; }; }; // et on met les pointeurs de lignes en NULL for (int i=1;i<= tail_ar;i++) // transfert pour les noeuds { tabb(i+posi_tab_front_lin) = NULL;} }; // maintenant création de la ligne int nbnoe = el.NonS()(num).Taille(); // nb noeud de l'arête Tableau tab(nbnoe); // les noeuds de l'arête frontiere DdlElement ddelem(nbnoe); // les ddlelements des noeuds frontieres for (int i=1;i<= nbnoe;i++) { tab(i) = tab_noeud(el.NonS()(num)(i)); ddelem.Change_un_ddlNoeudElement(i,tdd(el.NonS()(num)(i))); }; tabb(posi_tab_front_lin+num) = new_frontiere_lin(num,tab,ddelem); ind_front_lin = 1; // a priori for (int nlign=1;nlign<=tail_ar;nlign++) if (tabb(posi_tab_front_lin+nlign) == NULL) { ind_front_lin = 2; break;}; }; // maintenant normalement la frontière est créé on la ramène return (ElFrontiere*)tabb(posi_tab_front_lin+num); }; // ramène la frontière surfacique // éventuellement création des frontieres surfacique de l'element et stockage dans l'element // si c'est la première fois sinon il y a seulement retour de l'elements // a moins que le paramètre force est mis a true // dans ce dernier cas la frontière effacéee est recréée // num indique le numéro de la surface à créer (numérotation EF) ElFrontiere* const ElemMeca::Frontiere_surfacique(int num,bool force) { // -- tout d'abord on évacue le cas où il n'y a pas de frontière surfacique à calculer // récup de l'élément géométrique ElemGeomC0& el = ElementGeometrique(); int tail_fa = 0; // init // test --- retour rapide si l'existance n'est pas possible if (ParaGlob::AxiSymetrie()) // dans le cas axiSymétrique, le test est un peu différent car les surfaces sont générées // par les lignes, {tail_fa = el.NbSe(); // nombre potentiel de segments if (num > tail_fa) return NULL; } else // dans le cas où on n'est pas en axi, test simple {tail_fa = el.NbFe(); // nombre potentiel de faces if (num > tail_fa) return NULL; }; // --- la suite concerne le cas où on peut faire des surfaces (non axi ou axi !) // le calcul et la création ne sont effectués qu'au premier appel // ou lorsque l'on veut forcer une recréation // on regarde si les frontières surfacique existent sinon on les crée if (ind_front_surf == 1) {return (ElFrontiere*)tabb(num);} else if ( ind_front_surf == 2) // cas où certaines frontières existent {if (tabb(num) != NULL) return (ElFrontiere*)tabb(num); }; // arrivée ici cela veut dire que la frontière surface n'existe pas // on l'a reconstruit // le calcul et la création ne sont effectués qu'au premier appel // ou lorsque l'on veut forcer une recréation if ((ind_front_surf == 0) || force ) {// récup du tableau de ddl const DdlElement & tdd = TableauDdl(); int taille = tabb.Taille(); // la taille initiales des frontières int tail_ar = el.NbSe(); // nombre potentiel d'arêtes int tail_po = el.Nbne(); // nombre potentiel de points // dimensionnement du tableau de frontières surfaces si nécessaire if (ind_front_surf == 0) {if ((ind_front_point > 0) && (ind_front_lin == 0)) // cas où les frontières points existent seules, on ajoute les surfaces { int taille_finale = tail_fa + tail_po; tabb.Change_taille(taille_finale); for (int i=1;i<= tail_po;i++) tabb(i+tail_fa) = tabb(i); posi_tab_front_lin=posi_tab_front_point=tail_fa; } else if ((ind_front_point > 0) && (ind_front_lin > 0)) // cas où les frontières points existent et lignes et pas de surfaces, donc on les rajoutes { int taille_finale = tail_fa + tail_po+tail_ar; tabb.Change_taille(taille_finale); // --transfert pour les noeuds et les lignes for (int i=1;i<= tail_po;i++) // transfert pour les noeuds { tabb(i+tail_ar+tail_fa) = tabb(i+tail_ar);}; for (int i=1;i<= tail_ar;i++) // transfert pour les lignes { tabb(i+tail_fa) = tabb(i);}; // --def des indicateurs posi_tab_front_point=tail_ar+tail_fa; // après les faces et les lignes posi_tab_front_lin = tail_fa; // après les surfaces } else { // cas où il n'y a pas de frontières points if (ind_front_lin == 0) // cas où il n'y a pas de lignes {tabb.Change_taille(tail_fa,NULL); // on n'a pas de ligne, pas de point et pas de surface posi_tab_front_lin = posi_tab_front_point = tail_fa; } // on peut tout mettre à NULL else {tabb.Change_taille(tail_ar+tail_fa); // cas où les lignes existent for (int i=1;i<= tail_ar;i++) // transfert pour les lignes tabb(i+tail_fa) = tabb(i); posi_tab_front_lin = tail_fa; // après les surfaces posi_tab_front_point = tail_fa + tail_ar; }; }; // --et on met les pointeurs de surfaces en NULL for (int i=1;i<=tail_fa;i++) tabb(i)=NULL; }; // maintenant création de la surface int nbnoe = el.Nonf()(num).Taille(); // b noeud de la surface Tableau tab(nbnoe); // les noeuds de la frontiere DdlElement ddelem(nbnoe); // les ddlelements des noeuds frontieres for (int i=1;i<= nbnoe;i++) { tab(i) = tab_noeud(el.Nonf()(num)(i)); ddelem.Change_un_ddlNoeudElement(i,tdd(el.Nonf()(num)(i))); }; tabb(num) = new_frontiere_surf(num,tab,ddelem); ind_front_surf = 1; // a priori for (int nsurf=1;nsurf<=tail_fa;nsurf++) if (tabb(nsurf) == NULL) { ind_front_surf = 2; break;}; }; // maintenant normalement la frontière est créé on la ramène return (ElFrontiere*)tabb(num); }; // calcul des intégrales de volume et de volume + temps // cas = 1 : pour un appel après un calcul implicit // cas = 2 : pour un appel après un calcul explicit void ElemMeca::Calcul_Integ_vol_et_temps(int cas,const double& poid_jacobien,int iteg) { // 1) intégration de volume uniquement //List_io integ_vol_typeQuel,integ_vol_typeQuel_t; if (integ_vol_typeQuel != NULL) // on balaie les conteneurs { int taille = integ_vol_typeQuel->Taille(); Tableau & tab_integ = *integ_vol_typeQuel; // pour simplifier for (int il =1;il <= taille ;il++) // l'intégrale n'est effectuée que si l'index est positif, sinon, il s'agit // d'une valeur figée if ((*index_Integ_vol_typeQuel)(il)) {// différent choix switch (tab_integ(il).Const_Grandeur_pointee()->Type_enumGrandeurParticuliere()) {case PARTICULIER_DDL_ETENDU: { Grandeur_Ddl_etendu& gr = *((Grandeur_Ddl_etendu*) tab_integ(il).Grandeur_pointee()); // pour simplifier Ddl_etendu& ddl = *(gr.ConteneurDdl_etendu());// récup du ddl // on va utiliser la méthode Valeur_multi ce qui n'est pas optimal en vitesse // mais 1) c'est cohérent avec l'implantation existante // 2) identique avec les ddl déjà accessibles List_io inter; // une liste intermédiaire inter.push_back(ddl.DdlEnumEtendu()); bool absolue = true; // on se place systématiquement en absolu // calcul de la valeur et retour dans tab_d Tableau tab_d(ElemMeca::Valeur_multi(absolue,TEMPS_tdt,inter,iteg,-cas)); // on cumule l'intégrale ddl.Valeur() += tab_d(1) * poid_jacobien; ////---- debug //cout << "\n debug: ElemMeca::Calcul_Integ_vol_et_temps("; //cout << " tab_d(1)= "<< tab_d(1) << " ";ddl.Affiche(); //tab_noeud(1)->Affiche(); ////---- fin debug break; } case PARTICULIER_VECTEUR_NOMMER: { Grandeur_Vecteur_Nommer& gr = *((Grandeur_Vecteur_Nommer*) tab_integ(il).Grandeur_pointee()); // pour simplifier Fonction_nD* fct = gr.Fct(); // récupération de la fonction nD // on commence par récupérer les conteneurs des grandeurs à fournir List_io & li_enu_scal = fct->Li_enu_etendu_scalaire(); List_io & li_quelc = fct->Li_equi_Quel_evolue(); bool absolue = true; // on se place systématiquement en absolu // on va utiliser la méhode Valeur_multi pour les grandeurs strictement scalaire Tableau val_ddl_enum(ElemMeca::Valeur_multi(absolue,TEMPS_tdt,li_enu_scal,iteg,-cas)); // on utilise la méthode des grandeurs évoluées pour les Coordonnees et Tenseur Valeurs_Tensorielles(absolue, TEMPS_tdt,li_quelc,iteg,-cas); // calcul de la valeur et retour dans tab_ret Tableau & tab_ret = fct->Valeur_FnD_Evoluee(&val_ddl_enum,&li_enu_scal,&li_quelc,NULL,NULL); // on cumule l'intégrale Vecteur& V = gr.ConteneurVecteur(); int taille = V.Taille(); for (int i=1;i<=taille;i++) V(i) += tab_ret(i) * poid_jacobien; ////----- debug //cout << "\n debug *** ElemMeca::Grandeur_particuliere( "; //cout << "\n li_enu_scal= "<< li_enu_scal << ", val_ddl_enum= " << val_ddl_enum; //cout << "\n li_quelc= "<< li_quelc; //V.Affiche();cout << " tab_ret= " << tab_ret << endl;; ////----- fin debug break; } break; default: cout << " \n *** pas d'integration prevu pour la grandeur " << tab_integ(il); if (ParaGlob::NiveauImpression() > 0) cout << "\n ElemMeca::Calcul_Integ_vol_et_temps(..." << endl; }; }; }; // 2) intégration de volume et en temps //List_io integ_vol_t_typeQuel,integ_vol_t_typeQuel_t; if (integ_vol_t_typeQuel != NULL) // on balaie les conteneurs { int taille = integ_vol_t_typeQuel->Taille(); Tableau & tab_integ = *integ_vol_t_typeQuel; // pour simplifier // recup de l'incrément de temps double deltat=ParaGlob::Variables_de_temps().IncreTempsCourant(); for (int il =1;il <= taille ;il++) // l'intégrale n'est effectuée que si l'index est positif, sinon, il s'agit // d'une valeur figée if ((*index_Integ_vol_t_typeQuel)(il)) {// différent choix switch (tab_integ(il).Const_Grandeur_pointee()->Type_enumGrandeurParticuliere()) {case PARTICULIER_DDL_ETENDU: { Grandeur_Ddl_etendu& gr = *((Grandeur_Ddl_etendu*) tab_integ(il).Grandeur_pointee()); // pour simplifier Ddl_etendu& ddl = *(gr.ConteneurDdl_etendu());// récup du ddl // on va utiliser la méthode Valeur_multi ce qui n'est pas optimal en vitesse // mais 1) c'est cohérent avec l'implantation existante // 2) identique avec les ddl déjà accessibles List_io inter; // une liste intermédiaire inter.push_back(ddl.DdlEnumEtendu()); bool absolue = true; // on se place systématiquement en absolu // calcul de la valeur et retour dans tab_d Tableau tab_d(ElemMeca::Valeur_multi(absolue,TEMPS_tdt,inter,iteg,-cas)); // on cumule l'intégrale ddl.Valeur() += deltat * tab_d(1) * poid_jacobien; break; } case PARTICULIER_VECTEUR_NOMMER: { Grandeur_Vecteur_Nommer& gr = *((Grandeur_Vecteur_Nommer*) tab_integ(il).Grandeur_pointee()); // pour simplifier Fonction_nD* fct = gr.Fct(); // récupération de la fonction nD // on commence par récupérer les conteneurs des grandeurs à fournir List_io & li_enu_scal = fct->Li_enu_etendu_scalaire(); List_io & li_quelc = fct->Li_equi_Quel_evolue(); bool absolue = true; // on se place systématiquement en absolu // on va utiliser la méhode Valeur_multi pour les grandeurs strictement scalaire Tableau val_ddl_enum(ElemMeca::Valeur_multi(absolue,TEMPS_tdt,li_enu_scal,iteg,-cas)); // on utilise la méthode des grandeurs évoluées pour les Coordonnees et Tenseur Valeurs_Tensorielles(absolue, TEMPS_tdt,li_quelc,iteg,-cas); // calcul de la valeur et retour dans tab_ret Tableau & tab_ret = fct->Valeur_FnD_Evoluee(&val_ddl_enum,&li_enu_scal,&li_quelc,NULL,NULL); // on cumule l'intégrale Vecteur& V = gr.ConteneurVecteur(); int taille = V.Taille(); for (int i=1;i<=taille;i++) V(i) += deltat * tab_ret(i) * poid_jacobien; break; } break; default: cout << " \n *** pas d'integration prevu pour la grandeur " << tab_integ(il); if (ParaGlob::NiveauImpression() > 0) cout << "\n ElemMeca::Calcul_Integ_vol_et_temps(..." << endl; }; }; }; }; // au premier pti init éventuel des intégrales de volume et temps void ElemMeca::Init_Integ_vol_et_temps() { // 1) intégration de volume uniquement if (integ_vol_typeQuel != NULL) {int taille = integ_vol_typeQuel->Taille(); Tableau & tab_integ = *integ_vol_typeQuel; // pour simplifier for (int il =1;il <= taille ;il++) // l'intégrale n'est effectuée que si l'index est positif, sinon, il s'agit // d'une valeur figée if ((*index_Integ_vol_typeQuel)(il)) {tab_integ(il).Grandeur_pointee()->InitParDefaut(); // on initialise le conteneur }; }; // 2) intégration de volume et en temps if (integ_vol_t_typeQuel != NULL) {int taille = integ_vol_t_typeQuel->Taille(); Tableau & tab_integ = *integ_vol_t_typeQuel; // pour simplifier Tableau & tab_integ_t = *integ_vol_t_typeQuel_t; // "" for (int il =1;il <= taille ;il++) // l'intégrale n'est effectuée que si l'index est positif, sinon, il s'agit // d'une valeur figée if ((*index_Integ_vol_t_typeQuel)(il)) {(*tab_integ(il).Grandeur_pointee()) = (*tab_integ_t(il).Grandeur_pointee()); }; }; }; // définition d'un repère d'anisotropie à un point d'intégration BaseH ElemMeca::DefRepereAnisotropie (int iteg,LesFonctions_nD* lesFonctionsnD,const BlocGen & bloc) { // la définition du repère dépend du type de définition // (cf. la def du bloc dans LesMaillages::Completer .... dans LesMaillages.cc) if (bloc.Nom(4) == "par_fonction_nD_") {// on doit simplement appeler la fonction nD // Nom(5) est le nom de la fonction nD Fonction_nD * fct = lesFonctionsnD->Trouve(bloc.Nom(5)); // on commence par récupérer les conteneurs des grandeurs à fournir List_io & li_enu_scal = fct->Li_enu_etendu_scalaire(); List_io & li_quelc = fct->Li_equi_Quel_evolue(); bool absolue = true; // on se place systématiquement en absolu const Met_abstraite::Impli* ex_impli = NULL; const Met_abstraite::Expli_t_tdt* ex_expli_tdt = NULL; const Met_abstraite::Expli* ex_expli = NULL; // pour l'instant on ne peut s'occuper que des grandeurs à t au maximum: mais pas // à tdt bool premier_calcul = true; // def->ChangeNumInteg(iteg); // const Met_abstraite::Expli& ex = def->Cal_explicit_t(premier_calcul); // ex_expli = &ex; // // 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_t,li_enu_scal,*def,ex_impli,ex_expli_tdt,ex_expli) // ); // // on utilise la méthode Valeurs_Tensorielles_interpoler_ou_calculer // // pour les Coordonnees et Tenseur // Valeurs_Tensorielles_interpoler_ou_calculer // (absolue,TEMPS_t,li_quelc,*def,ex_impli,ex_expli_tdt,ex_expli); // on va utiliser la méhode Valeur_multi pour les grandeurs strictement scalaire int cas = 1; // on se met dans un cas normal avec utilisation de certaine partie de la métrique implicite // a priori ce serait idem avec l'explicite Tableau val_ddl_enum(ElemMeca::Valeur_multi(absolue,TEMPS_t,li_enu_scal,iteg,cas)); // on utilise la méthode des grandeurs évoluées pour les Coordonnees et Tenseur Valeurs_Tensorielles(absolue, TEMPS_t,li_quelc,iteg,cas); // calcul de la valeur et retour dans tab_ret Tableau & tab_ret = fct->Valeur_FnD_Evoluee(&val_ddl_enum,&li_enu_scal,&li_quelc,NULL,NULL); // on doit récupérer 6 composantes en 3D (pour le reste c'est actuellement en attente) int dim = ParaGlob::Dimension(); if (dim != 3) { cout << "\n arret: le type de construction de repere: par_fonction_nD_ " << " n'est implante que pour la dimension 3 pour l'instant !!! " << " affaire a suivre ....(et se plaindre! ) "; Sortie(1); }; int nb_composante = tab_ret.Taille(); if (nb_composante != 6) { cout << "\n erreur dans la construction d'un repere d'orthotropie par_fonction_nD_ " << " la fonction nD ramene "<ChangeNumInteg(iteg); const Met_abstraite::InfoExp_t & ex_infoExp_t = def->RemontExp_t(); int nb_vec = ex_infoExp_t.giB_0->NbVecteur(); // nb vecteur local BaseH base_ret_H(3,3); // les coordonnées locales : théta^te = V * g^te // soit O_a la base d'anisotropie: O_a = beta_a^{.i} g_i // ona beta_a^{.i} = O_a . g^i // et on stocke dans base_ret_H de la manière suivante // base_ret_H(a)(i) = beta_a^{.i} for (int a = 1;a <= 3; a++) {CoordonneeH& inter = base_ret_H.CoordoH(a); for (int i=1;i coor.Dimension() = 0 // ramène un entier : // == 1 : calcul normal // == 0 : problème de calcul -> coor.Dimension() = 0 // == 2 : indique que le calcul n'est pas licite pour le noeud passé en paramètre // c'est le cas par exemple des noeuds exterieurs pour les éléments SFE // mais il n'y a pas d'erreur, c'est seulement que l'élément n'est pas ad hoc pour // calculer la normale à ce noeud là // temps: indique à quel moment on veut le calcul // pour des éléments particulier (ex: SFE) la méthode est surchargée int ElemMeca::CalculNormale_noeud(Enum_dure temps,const Noeud& noe,Coordonnee& coor) { int retour = 1; // init du retour : on part d'un bon a priori Enum_type_geom enutygeom = Type_geom_generique(this->Id_geometrie()); // if ((enutygeom == LIGNE) || (enutygeom == SURFACE)) if (enutygeom != SURFACE) // dans une première étape on ne s'occupe que des surfaces {coor.Libere(); // pas de calcul possible retour = 0; } else // sinon le calcul est possible { // on commence par repérer le noeud dans la numérotation locale int nuoe=0; int borne_nb_noeud=tab_noeud.Taille()+1; for (int i=1;i< borne_nb_noeud;i++) {Noeud& noeloc = *tab_noeud(i); if ( (noe.Num_noeud() == noeloc.Num_noeud()) && (noe.Num_Mail() == noeloc.Num_Mail()) ) {nuoe = i; break; }; }; // on ne continue que si on a trouvé le noeud if (nuoe != 0) { ElemGeomC0& elemgeom = ElementGeometrique(); // récup de la géométrie // récup des coordonnées locales du noeuds const Coordonnee& theta_noeud = elemgeom.PtelemRef()(nuoe); // récup des phi et dphi au noeud const Vecteur & phi = elemgeom.Phi_point(theta_noeud); const Mat_pleine& dphi = elemgeom.Dphi_point(theta_noeud); switch (temps) {case TEMPS_0 : {const BaseB& baseB = met->BaseNat_0(tab_noeud,dphi,phi); coor = Util::ProdVec_coor( baseB.Coordo(1), baseB.Coordo(2)); coor.Normer(); break; } case TEMPS_t : {const BaseB& baseB = met->BaseNat_t(tab_noeud,dphi,phi); coor = Util::ProdVec_coor( baseB.Coordo(1), baseB.Coordo(2)); coor.Normer(); break; } case TEMPS_tdt : {const BaseB& baseB = met->BaseNat_tdt(tab_noeud,dphi,phi); coor = Util::ProdVec_coor( baseB.Coordo(1), baseB.Coordo(2)); coor.Normer(); break; } default : cout << "\nErreur : valeur incorrecte du temps demande = " << Nom_dure(temps) << " !\n"; cout << "\n ElemMeca::CalculNormale_noeud(Enum_dure temps... \n"; retour = 0; Sortie(1); }; } else {cout << "\n *** erreur le noeud demande num= "<