// 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 #include "ElemMeca.h" #include #include "ConstMath.h" #include "Util.h" #include "Coordonnee2.h" #include "Coordonnee3.h" #include "ParaAlgoControle.h" #include "ExceptionsElemMeca.h" #include "Loi_Umat.h" #include "ExceptionsLoiComp.h" #include "CharUtil.h" // =========================== variables communes =============================== // a priori les pointeurs de fonction pointent sur rien au debut const Coordonnee & (Met_abstraite::*(ElemMeca::PointM)) (const Tableau& tab_noeud,const Vecteur& Phi) ; void (Met_abstraite::*(ElemMeca::BaseND)) (const Tableau& tab_noeud,const Mat_pleine& dphi, const Vecteur& phi,BaseB& bB,BaseH& bH); int ElemMeca::bulk_viscosity = 0; // indique si oui ou non on utilise le bulk viscosity double ElemMeca::c_traceBulk = 0.; // coeff de la trace de D pour le bulk double ElemMeca::c_carreBulk = 0.; // coeff du carré de la trace de D pour le bulk TenseurHH* ElemMeca::sig_bulkHH = NULL; // variable de travail pour le bulk // ---------- pour le calcul de la masse pour la méthode de relaxation dynamique Ddl_enum_etendu ElemMeca::masse_relax_dyn; // au début rien, def à la première utilisation // pour la gestion d'hourglass: dimensionnement dans ElemMeca::Init_hourglass_comp Tableau< Vecteur> ElemMeca::vec_hourglass; // tableau de vecteurs de travail, éventuellement défini // pour la stabilisation de membrane: dimensionnement lors de l'utilisation //Tableau< Vecteur> ElemMeca::vec_StabMembBiel; // tableau de vecteurs de travail, éventuellement défini // =========================== fin variables communes =========================== // -------------------- stabilisation transversale éventuelle de membrane ou de biel ------------------- // utilisée et alimentées par les classes dérivées: ElemMeca sert de conteneur ce qui permet // d'éviter de redéfinir des conteneurs locaux aux éléments membranes et biel // par défaut ElemMeca::StabMembBiel::StabMembBiel() : type_stabMembrane(STABMEMBRANE_BIEL_NON_DEFINIE) ,gamma(0.),pt_fct_gamma(NULL),stab_ref(1.),activite_en_explicite(true) ,F_StabMembBiel(),F_StabMembBiel_t() ,E_StabMembBiel(),E_StabMembBiel_t() ,nom_fctnD(NULL),nom_fctnD_2(NULL) ,affichage_stabilisation(0),gestion_maxi_mini(false) ,beta(1.) // valeur arbitraire pour l'instant ,f_mini(ConstMath::petit) // valeur arbitraire pour l'instant ,d_maxi(1000.) // déplacement arbitraire de 1000 ,pt_fct_ponder_Ft(NULL) {}; // fonction du nombre de noeud ou de point d'interpolation ElemMeca::StabMembBiel::StabMembBiel(int nbnoe) : type_stabMembrane(STABMEMBRANE_BIEL_NON_DEFINIE) ,gamma(0.),pt_fct_gamma(NULL),stab_ref(1.),activite_en_explicite(true) ,F_StabMembBiel(nbnoe),F_StabMembBiel_t(nbnoe) ,E_StabMembBiel(nbnoe),E_StabMembBiel_t(nbnoe) ,nom_fctnD(NULL),nom_fctnD_2(NULL) ,affichage_stabilisation(0),gestion_maxi_mini(false) ,beta(1.) // valeur arbitraire pour l'instant ,f_mini(ConstMath::petit) // valeur arbitraire pour l'instant ,d_maxi(1000.) // déplacement arbitraire de 100 ,pt_fct_ponder_Ft(NULL) {}; // fonction d'une valeur numérique et des noms éventuels de fonction ElemMeca::StabMembBiel::StabMembBiel(double v,string * sgamma,string* sponder) : type_stabMembrane(STABMEMBRANE_BIEL_NON_DEFINIE) ,gamma(v),pt_fct_gamma(NULL),F_StabMembBiel() ,E_StabMembBiel(),E_StabMembBiel_t() ,nom_fctnD(NULL),nom_fctnD_2(NULL) ,stab_ref(1.),activite_en_explicite(true) ,affichage_stabilisation(0),gestion_maxi_mini(false) ,beta(1.) // valeur arbitraire pour l'instant ,f_mini(ConstMath::petit) // valeur arbitraire pour l'instant ,d_maxi(1000.) // déplacement arbitraire de 100 ,pt_fct_ponder_Ft(NULL) {if (sgamma != NULL) nom_fctnD= new string (*sgamma); if (sponder != NULL) nom_fctnD_2= new string (*sponder); }; // de copie ElemMeca::StabMembBiel::StabMembBiel(const StabMembBiel& a): type_stabMembrane(a.type_stabMembrane) ,gamma(a.gamma),pt_fct_gamma(a.pt_fct_gamma),stab_ref(a.stab_ref) ,activite_en_explicite(a.activite_en_explicite) ,F_StabMembBiel(a.F_StabMembBiel),F_StabMembBiel_t(a.F_StabMembBiel_t) ,E_StabMembBiel(a.E_StabMembBiel),E_StabMembBiel_t(a.E_StabMembBiel_t) ,nom_fctnD(NULL),nom_fctnD_2(NULL) ,affichage_stabilisation(a.affichage_stabilisation) ,gestion_maxi_mini(a.gestion_maxi_mini) ,beta(a.beta) ,f_mini(a.f_mini) ,d_maxi(a.d_maxi),pt_fct_ponder_Ft(a.pt_fct_ponder_Ft) {if (a.nom_fctnD != NULL) nom_fctnD = new string (*(a.nom_fctnD)); if (a.nom_fctnD_2 != NULL) nom_fctnD_2 = new string (*(a.nom_fctnD_2)); }; ElemMeca::StabMembBiel::~StabMembBiel() {pt_fct_gamma=NULL; // la fonction est forcément globale, donc on ne la détruie pas if (nom_fctnD != NULL) delete nom_fctnD; // idem pour la pondération if (nom_fctnD_2 != NULL) delete nom_fctnD_2; }; ElemMeca::StabMembBiel& ElemMeca::StabMembBiel::operator= (const ElemMeca::StabMembBiel& a) {type_stabMembrane = a.type_stabMembrane; gamma=a.gamma;pt_fct_gamma=a.pt_fct_gamma; stab_ref=a.stab_ref;activite_en_explicite = a.activite_en_explicite; F_StabMembBiel=a.F_StabMembBiel;F_StabMembBiel_t=a.F_StabMembBiel_t; E_StabMembBiel=a.E_StabMembBiel;E_StabMembBiel_t = a.E_StabMembBiel_t; nom_fctnD=NULL;pt_fct_ponder_Ft=a.pt_fct_ponder_Ft; affichage_stabilisation = a.affichage_stabilisation; gestion_maxi_mini=a.gestion_maxi_mini; beta=a.beta;f_mini=a.f_mini;d_maxi=a.d_maxi; if (a.nom_fctnD != NULL) nom_fctnD = new string (*(a.nom_fctnD)); if (a.nom_fctnD_2 != NULL) nom_fctnD_2 = new string (*(a.nom_fctnD_2)); return (*this); }; // énergie totale à t+dt développée sur l'élément pour la stabilisation double ElemMeca::StabMembBiel::EE_total_StabMembBiel() const { double retour = 0; // init int taille = E_StabMembBiel.Taille(); for (int i=1; i<=taille;i++) retour += E_StabMembBiel(i); return retour; }; // énergie totale à t développée sur l'élément pour la stabilisation double ElemMeca::StabMembBiel::EE_total_StabMembBiel_t() const { double retour = 0; // init int taille = E_StabMembBiel_t.Taille(); for (int i=1; i<=taille;i++) retour += E_StabMembBiel_t(i); return retour; }; // actualisation de la force de stabilisation de t+dt vers t void ElemMeca::StabMembBiel::TdtversT() {F_StabMembBiel_t = F_StabMembBiel; E_StabMembBiel_t = E_StabMembBiel; }; // actualisation de la force de stabilisation de t vers tdt void ElemMeca::StabMembBiel::TversTdt() {F_StabMembBiel = F_StabMembBiel_t; E_StabMembBiel = E_StabMembBiel_t; }; // cas donne le niveau de la récupération // = 1 : on récupère tout // = 2 : on récupère uniquement les données variables (supposées comme telles) void ElemMeca::StabMembBiel::Lecture_bas_inf(ifstream& ent,const int cas) {string toto,nom; switch (cas) { case 1 : // ------- on récupère tout ------------------------- { // récup du type de stabilisation ent >> toto; type_stabMembrane = Id_Enum_StabMembraneBiel(toto); // récup pour alpha ent >> toto; if (toto == "par_fonction_nD") { ent >> nom; if (nom_fctnD == NULL) nom_fctnD = new string(nom); else *nom_fctnD = nom; gamma = 0.; // init au cas ou pt_fct_gamma = NULL; // même si diff de NULL // il n'y a pas delete à faire car il s'agit de fonction globale // ensuite il faudra définir la fonction de stabilisation // au moment de compléter l'élément } else if (toto == "par_valeur") {ent >> gamma;} else { cout << "\n *** erreur en lecture, on attendait" << " par_fonction_nD ou par_valeur et on a lue " << toto ; Sortie(1); }; // activite_en_explicite ent >> toto >> activite_en_explicite; // pondération éventuelle ent >> toto; if (toto == "ponderation_F_t") { ent >> nom; if (nom_fctnD_2 == NULL) nom_fctnD_2 = new string(nom); else *nom_fctnD_2 = nom; pt_fct_ponder_Ft = NULL;// même si diff de NULL // il n'y a pas delete à faire car il s'agit de fonction globale // ensuite il faudra définir la fonction de pondération // au moment de compléter l'élément }; // affichage et les limitations ent >> toto >> affichage_stabilisation >> toto >> gestion_maxi_mini >> toto >> beta >> toto >> f_mini >> toto >> d_maxi; break; } case 2 : // ----------- lecture uniquement de se qui varie -------------------- { ent >> toto >> F_StabMembBiel; ent >> toto >> E_StabMembBiel; break; } default : { cout << "\nErreur : valeur incorrecte du type de lecture !\n"; cout << "ElemMeca::StabMembBiel::Lecture_bas_inf(ifstream& ent,const int cas)" << " cas= " << cas << endl; Sortie(1); }; }; }; // cas donne le niveau de sauvegarde // = 1 : on sauvegarde tout // = 2 : on sauvegarde uniquement les données variables (supposées comme telles) void ElemMeca::StabMembBiel::Ecriture_bas_inf(ofstream& sort,const int cas) {switch (cas) { case 1 : // ------- on sauvegarde tout ------------------------- { sort << " "<NomFonction()<<" ";} else {sort << " par_valeur " << gamma<< " ";}; sort << " activite_en_explicite "<< activite_en_explicite; if (pt_fct_ponder_Ft != NULL) {sort << " ponderation_F_t " << pt_fct_ponder_Ft->NomFonction()<<" ";} else {sort << " pas_de_ponderation_F_t " ;}; sort << "\n affichage_stabilisation= "<TestComplet() != 1) { cout << " \n la loi n'est pas complete dans l element " << num_elt << '\n'; ret = 0; } // dans le cas d'une loi thermo physique on vérifie qu'elle est complète if (loiTP != NULL) { if (loiTP->TestComplet() != 1) { cout << " \n la loi thermo physique n'est pas complete dans l element " << num_elt << '\n'; ret = 0; } }; // dans le cas où l'on prend en compte de la dilatation, on vérifie qu'une loi thermo plysique // a été défini if (dilatation) {if (loiTP == NULL) {cout << " \n L element " << num_elt << " prend en compte la dilatation, alors qu'aucune loi thermo physique n'est defini, " << " il faut donc en definir une ! \n "; ret = 0; } } // dans le cas d'une loi de frottement on vérifie qu'elle est complète if (loiFrot != NULL) { if (loiFrot->TestComplet() != 1) { cout << " \n la loi de frottement n'est pas complete dans l element " << num_elt << '\n'; ret = 0; } }; // suite des datas if ( masse_volumique == masse_volumique_defaut) { cout << "\n la masse volumique n'est pas defini dans l element " << num_elt << '\n'; ret = 0; } if (met == NULL) { cout << " \n la metrique n'est pas defini dans l element " << num_elt << '\n'; ret = 0; } if (def == NULL) { cout << " \n le type de deformation n'est pas defini dans l element " << num_elt << '\n'; ret = 0; } return ret; }; // test pour savoir si le calcul de contrainte en absolu est possible bool ElemMeca::ContrainteAbsoluePossible() { // il faut qu'il soit complet et il faut que les coordonnées a t =0 et t existe bool retour = true; if (TestComplet() !=0) {// on regarde la définition des coordonnées int nbmaxnoeud=tab_noeud.Taille(); for (int i=1;i<=nbmaxnoeud;i++) if((!tab_noeud(i)->ExisteCoord0())||(!tab_noeud(i)->ExisteCoord1())) { retour = false; break;} } else retour = false; return retour; }; // --------- calculs utils dans le cadre de la recherche du flambement linéaire // dans un premier temps uniquement virtuelles, ensuite se sera virtuelle pure pour éviter // les oubli de définition ----> AMODIFIER !!!!!!!! // Calcul de la matrice géométrique et initiale ElemMeca::MatGeomInit ElemMeca::MatricesGeometrique_Et_Initiale (const ParaAlgoControle & ) { cout << "\n attention le calcul de la matrice g\'eom\'etrique et de la matrice " << " initiale ne sont pas implant\'ees \n" ; this->Affiche(1); cout << "\nvoid ElemMeca::MatricesGeometrique_Et_Initiale (Mat_pleine &,Mat_pleine &)" << endl; Sortie(1); return MatGeomInit(NULL,NULL); // pour supprimer le warning }; // calcul de l'erreur sur l'élément. Ce calcul n'est disponible // qu'une fois la remontée aux contraintes effectuées sinon aucune // action. En retour la valeur de l'erreur sur l'élément // = 1 : erreur = (int (delta sigma):(delta sigma) dv)/(int sigma:sigma dv) // le numerateur et le denominateur sont tel que : // errElemRelative = numerateur / denominateur , si denominateur different de 0 // sinon denominateur = numerateur si numerateur est different de 0, sinon // tous sont nuls mais on n'effectue pas la division //!!!!!!!!!!!!! pour l'instant en virtuelle il faudra après en // virtuelle pure !!!!!!!!!!!!!!!!!!!!!!!!!!! donc le code est à virer void ElemMeca::ErreurElement(int ,double& ,double& , double& ) { cout << "\n attention le calcul de l'erreur sur l'element n'est pas implant\'e " << " pour cet element \n" ; this->Affiche(1); cout << "\nElemMeca::ErreurElement(int....." << endl; Sortie(1); }; // ajout des ddl d'erreur pour les noeuds de l'élément void ElemMeca::Plus_ddl_Erreur() {int nbne = tab_noeud.Taille(); for (int ne=1; ne<= nbne; ne++) // pour chaque noeud { Ddl ddl(ERREUR,0.,LIBRE); tab_noeud(ne)->PlusDdl(ddl); } }; // inactive les ddl d'erreur void ElemMeca::Inactive_ddl_Erreur() { int nbne = tab_noeud.Taille(); for (int ne=1; ne<= nbne; ne++) tab_noeud(ne)->Met_hors_service(ERREUR); }; // active les ddl d'erreur void ElemMeca::Active_ddl_Erreur() { int nbne = tab_noeud.Taille(); for (int ne=1; ne<= nbne; ne++) tab_noeud(ne)->Met_en_service(ERREUR); }; // retourne un tableau de ddl element, correspondant à la // composante d'erreur -> ERREUR, pour chaque noeud // -> utilisé pour l'assemblage de la raideur d'erreur //dans cette version tous les noeuds sont supposés avoi un ddl erreur // dans le cas contraire il faut redéfinir la fonction dans l'élément terminal DdlElement ElemMeca::Tableau_de_ERREUR() const { return DdlElement(tab_noeud.Taille(), DdlNoeudElement(ERREUR) ); }; // =========================== methodes protegees =============================== // calcul si un point est a l'interieur de l'element ou non // il faut que M est la dimension globale // retour : = 0 le point est externe, = 1 le point est interne , // = 2 le point est sur la frontière à la précision près // coor_locales : s'il est différent de NULL, est affecté des coordonnées locales calculées, int ElemMeca::Interne(Enum_dure temps,const Coordonnee& M,Coordonnee* coor_locales) { int dim_glob = M.Dimension(); // dim de M = dim de l'espace géométrique ElemGeomC0& elgeom = this->ElementGeometrique(); // la geometrie int dim_loc = elgeom.Dimension(); // dim de l'élément de référence #ifdef MISE_AU_POINT if (ParaGlob::Dimension() != dim_glob) { cout << "\n *** erreur, la dimension du point = (" << dim_glob << ") et de l'espace geometrique (" << ParaGlob::Dimension() << ") sont differentes! "; cout << "\nElemMeca::Interne(Coordonnee& M) " << endl; this->Affiche(); Sortie(1); }; #endif // la methode consiste tout d'abord a calculer les coordonnees locales correspondants // a M. Pour cela on utilise un processus iteratif // ---- 1 :init de la recherche const Coordonnee refL(dim_loc) ; // coordonnees locales du point de reference, initialisees a zero // - construction du point local en fonction de l'existance ou non de coor_locales Coordonnee* pt_ret=NULL; Coordonnee theta_local(refL); if (coor_locales != NULL) {pt_ret = coor_locales;} else {pt_ret = &theta_local;}; Coordonnee& theta = *pt_ret; // init de AL qui representera les coordonnes locales de M // - fin construction du point local Vecteur ph_i = elgeom.Phi_point(refL); // fonctions d'interpolation en refL Mat_pleine dph_i = elgeom.Dphi_point(refL); // derivees des fonctions d'interpolation en refL // l'image de theta par l'interpolation, de dimension : espace géométrique Coordonnee A = (met->*PointM) (tab_noeud,ph_i); // // calcul de la base naturelle et duale en refL, en fonction des coord a t BaseB bB(dim_glob,dim_loc);BaseH bH(dim_glob,dim_loc); (met->*BaseND)(tab_noeud,dph_i,ph_i,bB,bH); // calcul des coordonnees locales du point M dans le repere en refl Coordonnee AM = M - A; // en global for (int i=1;i<=dim_loc;i++) theta(i) = AM * bH(i).Coor(); // ok même si dim_loc < dim_glob -> projection sur le plan tangent Coordonnee theta_repere(theta); // le point où l'on calcul le repère Coordonnee theta_initial(theta); Coordonnee delta_theta(theta); // dans le cas où le point est externe à l'élément, on limite le repère de calcul au point externe // de l'élément dans la direction de theta if (!(elgeom.Interieur(theta))) { // calcul d'un point extreme de l'élément dans le sens de M theta_repere = elgeom.Maxi_Coor_dans_directionGM(theta); }; // calcul du point correspondant à theta dans l'element, qui remplace A ph_i = elgeom.Phi_point(theta_repere); // fonctions d'interpolation en A Coordonnee A_sauve= A; A = (met->*PointM) (tab_noeud,ph_i); AM = M-A; // nouveau gap // ---- 2 :iteration // on boucle avec un test de stabilité des coordonnées locales int compteur = 1; // contrôle du maxi d'itération int nb_exterieur=0; // contrôle du maxi de fois que l'on trouve consécutivement le point à l'extérieur // - récup des paramètres de controle double delta_thetai_maxi = ParaGlob::param->ParaAlgoControleActifs().PointInterneDeltaThetaiMaxi(); int nb_boucle_sur_delta_thetai= ParaGlob::param->ParaAlgoControleActifs().PointInterneNbBoucleSurDeltaThetai(); int nb_max_a_l_exterieur= ParaGlob::param->ParaAlgoControleActifs().PointInterneNbExterne(); double prec_tehetai_interne= ParaGlob::param->ParaAlgoControleActifs().PointInternePrecThetaiInterne(); // - boucle de recherche des thetai while (delta_theta.Norme() >= delta_thetai_maxi) {dph_i = elgeom.Dphi_point(theta_repere); // derivees des fonctions d'interpolation en theta_repere ph_i = elgeom.Phi_point(theta_repere); // fonctions d'interpolation en theta_repere (déjà calculé la première fois) // calcul de la base naturelle et duale en fonction des coord a t (met->*BaseND)(tab_noeud,dph_i,ph_i,bB,bH); // amelioration des coordonnees locales du point M dans le repere en theta for (int i=1;i<=dim_loc;i++) delta_theta(i)=AM * bH(i).Coor(); // theta += delta_theta; erreur je pense: le 11 juin 2007 // le nouveau theta = la position du repère + le deltat theta theta = theta_repere + delta_theta; theta_repere=theta; if (!(elgeom.Interieur(theta))) // si le point est à l'extérieur { // calcul d'un point extreme de l'élément dans le sens de M theta_repere = elgeom.Maxi_Coor_dans_directionGM(theta); nb_exterieur++; } else // si nb_exterieur est diff de zero, on le remet à zéro, car on est de nouveau à l'intérieur { if (nb_exterieur != 0) nb_exterieur=0; }; // si cela fait nb_max_a_l_exterieur fois que l'on est à l'extérieur on arrête if ( nb_exterieur >= nb_max_a_l_exterieur) break; // calcul du point correspondant dans l'element, qui remplace theta ph_i = elgeom.Phi_point(theta_repere); // fonctions d'interpolation en theta A = (met->*PointM) (tab_noeud,ph_i); AM = M-A; // nouveau gap compteur++; if (compteur > nb_boucle_sur_delta_thetai) { // cela signifie que l'on n'arrive pas à converger, petit message si besoin // et on choisit le point initial pour le teste if (ParaGlob::NiveauImpression() >= 4) cout << " \n ** warning, l'algorithme de recherche d'un point a l'interieur d'un " << "element ne converge pas, utilisation du repere a l'origine" << "\nElemMeca::Interne(Coordonnee& M)" << endl; if (elgeom.Interieur(theta_initial)) {theta=theta_initial; } else {theta=theta_initial; }; break; }; }; // // à la sortie de la boucle on calcul les thétas correspondants à M final // dph_i = elgeom.Dphi(theta_repere); // derivees des fonctions d'interpolation en theta // ph_i = elgeom.Phi(theta_repere); // fonctions d'interpolation en theta // // calcul de la base naturelle et duale en fonction des coord a t // (met->*BaseND)(tab_noeud,dph_i,ph_i,bB,bH); // // amelioration des coordonnees locales du point M dans le repere en theta // for (int i=1;i<=dim_glob;i++) // theta(i) += AM * bH(i).Vect(); // // -- maintenant on regarde si le point est interne ou pas a l'element int retour=0; if (elgeom.Interieur(theta)) { // on regarde si le point est intérieur d'une toute petite précision // calcul d'un point extreme de l'élément dans le sens de M theta_repere = elgeom.Maxi_Coor_dans_directionGM(theta); double diff =(theta_repere-theta).Norme(); if (diff <= prec_tehetai_interne) {retour = 2;} // !-! à l'erreur près, le point est sur la frontière else {retour = 1;}; // !-! point à l'intérieur } else {return 0;}; // !-! point à l'extérieur -> retour directe // --- cas particuliers --- // -- dans le cas où "retour" est différent de 0, on regarde les cas particuliers switch (dim_glob) {case 3: {switch (dim_loc) { case 3: break; // cas pas de pb case 2: // cas des "coques ou plaques" on regarde si le point est réellement à l'intérieur (+- 1/2 épaisseur) { double epaisseur = Epaisseurs(temps,theta); A = (met->*PointM) (tab_noeud,ph_i); // le point projeté sur la surface de l'élément AM = M-A; double delta_hauteur = 0.5 * epaisseur - AM.Norme(); if (Dabs(delta_hauteur) <= prec_tehetai_interne) {retour = 2;} // !-! à l'erreur près, le point est sur la frontière else if (delta_hauteur < 0.) {retour = 0;} // !-! point externe else {retour = 1;}; // !-! point à l'intérieur break; } default: cout << " \n *** erreur : cas non implemente pour l'instant " << " dim_glob= " << dim_glob << " dim_loc= " << dim_loc << "\n ElemMeca::Interne(... "; Sortie(1); };// -- fin du switch dim_loc pour dim_glob=3 break; } // fin dim_glob=3 case 2: {switch (dim_loc) {case 2: break; // pas de pb case 1: case 3: // cas des poutres et volume (pb non consistance) pour l'instant non traité // donc on laisse aller à la valeur par défaut default: cout << " \n *** erreur : cas non implemente pour l'instant " << " dim_glob= " << dim_glob << " dim_loc= " << dim_loc << "\n ElemMeca::Interne(... "; Sortie(1); };// -- fin du switch dim_loc pour dim_glob=3 break; } // fin dim_glob=2 case 1: // la dimension locale est forcément 1, et pas de pb {break; } default: // default pour le switch sur di_glob cout << " \n *** erreur : cas non implemente pour l'instant " << " dim_glob= " << dim_glob << " dim_loc= " << dim_loc << "\n ElemMeca::Interne(... "; Sortie(1); break; }; // -- fin du switch sur dim_glob // retour return retour; }; // Calcul du residu local et de la raideur locale, // pour le schema implicite // cald_Dvirtuelle = indique si l'on doit calculer la dérivée de la vitesse de déformation virtuelle void ElemMeca::Cal_implicit (DdlElement & tab_ddl ,Tableau & d_epsBB,Tableau < Tableau2 > d2_epsBB_ ,Tableau & d_sigHH,int nbint ,const Vecteur& poids,const ParaAlgoControle & pa,bool cald_Dvirtuelle) { int nbddl = tab_ddl.NbDdl(); double jacobien; // def du jacobien volume = 0. ; // init Vecteur d_jacobien_tdt; energie_totale.Initialisation_differenciee(energie_totale_t); // init de l'énergie totale sur l'élément E_elem_bulk_tdt = E_elem_bulk_t; P_elem_bulk = 0.; // init pour l'énergie et la puissance associées au bulk // init éventuel de la contrainte de bulk viscosity TenseurHH* sigHH_t_1 = (*lesPtIntegMecaInterne)(1).SigHH_t(); // simplification d'écriture if (bulk_viscosity) { if (sig_bulkHH == NULL) {sig_bulkHH = NevezTenseurHH(*sigHH_t_1);} else if (sig_bulkHH->Dimension() != sigHH_t_1->Dimension()) {delete sig_bulkHH; sig_bulkHH = NevezTenseurHH(*sigHH_t_1);}; }; // init éventuel des intégrales de volume et temps Init_Integ_vol_et_temps(); /* 19 nov: en fait il ne faut pas prendre en compte l'épaisseur méca: cf. doc théorique // --- init éventuel pour les épaisseurs et largeurs double epaisseur_0 = EpaisseurMoyenne(TEMPS_0 ); double epaisseur = epaisseur_0;double epaisseur_moyenne = 0.; // init */ // --- init pour l'init de la stabilisation de membrane-biel éventuelle const Met_abstraite::Impli* ex_final=NULL; // contiendra après les boucles la dernière métrique Mise_a_jour_A_calculer_force_stab(); // permettra ensuite de savoir où le calcul doit être fait for (int ni =1; ni<= nbint; ni++) // boucle sur les pt d'integ {def->ChangeNumInteg(ni);def->Mise_a_jour_data_specif(tabSaveDefDon(ni)); PtIntegMecaInterne & ptIntegMeca = (*lesPtIntegMecaInterne)(ni); TenseurHH & sigHH = *(ptIntegMeca.SigHH()); TenseurBB & DepsBB_tdt = *(ptIntegMeca.DepsBB()); EnergieMeca& energ = tab_energ(ni); EnergieMeca& energ_t = tab_energ_t(ni); CompThermoPhysiqueAbstraite::SaveResul* sTP=NULL; // les données spécifique thermo physiques if (loiTP != NULL) {sTP = tabSaveTP(ni);}; // au pt d'integ si elles existes if ((loiComp->Id_comport()==LOI_VIA_UMAT) // cas de l'utilisation d'une loi umat || (loiComp->Id_comport()==LOI_VIA_UMAT_CP)) ((Loi_Umat*) loiComp)->Mise_a_jour_nbe_nbptinteg(this->Num_elt(),ni); // -- on gère les exceptions éventuelles en mettant le bloc sous surveillance const Met_abstraite::Impli* ex_pointe = NULL; // c'est pour construire ex try // ce qui permet de donner les numéros d'éléments et de pti { ex_pointe = &loiComp->Cal_implicit(tabSaveDon(ni) , *def,tab_ddl,ptIntegMeca,d_epsBB ,jacobien,d_jacobien_tdt,d_sigHH ,pa,sTP,loiTP,dilatation,energ,energ_t ,premier_calcul_meca_impli_expli); // //---debug // {double maxsig = sigHH.MaxiComposante(); // if ((!isfinite(maxsig)) || (isnan(maxsig)) ) // cout << "\n debug ElemMeca::Cal_implicit " // << " maxsig= " // << (maxsig) // << flush; // // // } // //--- fin debug } catch (ErrNonConvergence_loiDeComportement excep) // cas d'une d'une erreur survenue à cause d'une non convergence pour la résolution // d'une loi de comportement incrémentale { cout << "\n erreur de loi de comportement element= " << this->Num_elt() << " point d'integration= "<= 1) { cout << "\n ********** attention on a trouve un jacobien negatif!! ("< 1.) && ( rap > pa.MaxiVarJacobien())) { if (ParaGlob::NiveauImpression() >= 6) {// on affiche les infos des noeuds for (int i=1;i<= tab_noeud.Taille();i++) tab_noeud(i)->Affiche(); // on affiche les vecteurs de bases à 0 et t cout << "\n gi_0: " << *(ex.giB_0)<< "\n gi_tdt: " << *(ex.giB_tdt); }; if (ParaGlob::NiveauImpression() >= 3) { cout << "\n *** attention la variation maximal du jacobien est atteinte !! *** " << "\n ele= "<< Num_elt() << " nbi= " << ni << " jacobien= " << jacobien << " jacobien_0= " << (*(ex.jacobien_0)) << endl; }; // on génère une exception throw ErrVarJacobienMini_ElemMeca();break; } else { // on prend en compte toutes les variations double poid_jacobien= poids(ni) * jacobien; // 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 Calcul_Integ_vol_et_temps(1,poid_jacobien,ni); /* 19 nov: en fait il ne faut pas prendre en compte l'épaisseur méca: cf. doc théorique //---cas éventuel de la prise en compte de la variation d'une épaisseur, ou section switch (loiComp->Comportement_3D_CP_DP_1D()) { case COMP_CONTRAINTES_PLANES : // en contrainte plane on recalcule l'épaisseur {epaisseur = epaisseur_0 * loiComp->HsurH0(tabSaveDon(ni)); epaisseur_moyenne += epaisseur; poid_jacobien *= epaisseur; break; } case COMP_DEFORMATIONS_PLANES : // en deformation plane, l'épaisseur ne change pas {epaisseur = epaisseur_0 ; epaisseur_moyenne += epaisseur; poid_jacobien *= epaisseur; break; } default : // on n'a rien à faire break; }; */ volume += poid_jacobien;ptIntegMeca.Volume_pti()=poid_jacobien; // on continue que s'il s'agit d'une loi différente de rien if (!Loi_rien(loiComp->Id_comport())) {// il ne faut pas interpoler l'énergie à t, car elle était associée à un volume qui a changé // donc il ne faut considérer que l'accroissement d'énergie energie_totale.Ajout_differenciee(energ,energ_t,poid_jacobien); // energie_totale += (energ-energ_t) * poid_jacobien; E_elem_bulk_tdt += delta_ener_bulk_vol.un * poid_jacobien; P_elem_bulk += delta_ener_bulk_vol.deux * poid_jacobien; // calcul du résidu et variation for (int j =1; j<= nbddl; j++) // 1ere boucle sur les ddl {(*residu)(j) -= ((*(d_epsBB(j))) && sigHH ) * poid_jacobien; for (int i =1; i<= nbddl; i++) // 2ere boucle sur les ddl (*raideur)(j,i) += ( ((*d_sigHH(i)) && (*(d_epsBB(j)))) * jacobien + (sigHH && (*(d2_epsBB(j,i)))) * jacobien + (sigHH && (*(d_epsBB(j)))) * d_jacobien_tdt(i) ) * poids(ni); }; }; // --- cas éventuel d'une stabilisation membrane-biel --- // ici il s'agit de la contribution précise à chaque pti if (pt_StabMembBiel != NULL) if (!(pt_StabMembBiel->Aa_calculer())) Cal_implicit_StabMembBiel(ni,*ex_final,nbint,poids(ni),NULL); ////debug //cout << "\n ElemMeca::Cal_implicit debug : "; //raideur->Affiche(); //// fin debug };// fin du if sur la valeur non négative du jacobien if (bulk_viscosity) // dans le cas du bulk on retire la contrainte du bulk, qui est non physique { sigHH -= (*sig_bulkHH); } // ceci pour la sauvegarde ou autre utilisation }; // fin boucle sur les points d'intégration #ifdef MISE_AU_POINT if (ParaGlob::NiveauImpression() > 9) { cout << "\n Raideur et second membre locaux: ? (o/n) "; string rep(" "); // procédure de lecture avec prise en charge d'un retour chariot rep = lect_return_defaut(false,"n"); if ((rep == "0")||(rep == "o")) {cout << "\n Raideur et second membre locaux: elem= " << Num_elt_const() << ", maillage= " << Num_maillage(); cout << "\n raideur: "; raideur->Affiche(); cout << "\n second membre: " << (*residu); }; }; #endif // --- intervention dans le cas d'une stabilisation d'hourglass // stabilisation pour un calcul implicit if (type_stabHourglass) Cal_implicit_hourglass(); // --- cas éventuel d'une stabilisation membrane-biel --- // ici il s'agit soit du calcul approché d'initialisation, soit de la fin du calcul après la boucle // modif: 10 janvier 2019 non c'est le calcul correct une fois la raideur calculée if (pt_StabMembBiel != NULL) {if (pt_StabMembBiel->Aa_calculer()) {Cal_implicit_StabMembBiel(0,*ex_final, nbint,volume,NULL);} else {Cal_implicit_StabMembBiel(-1,*ex_final, nbint,volume,NULL);} ; }; #ifdef MISE_AU_POINT if (ParaGlob::NiveauImpression() > 9) { if ((type_stabHourglass)||(pt_StabMembBiel != NULL)) {cout << "\n apres stabilisation: Raideur et second membre locaux: ? (o/n) "; string rep(" "); // procédure de lecture avec prise en charge d'un retour chariot rep = lect_return_defaut(false,"n"); if ((rep == "0")||(rep == "o")) {cout << "\n Raideur et second membre locaux: elem= " << Num_elt_const() << ", maillage= " << Num_maillage(); cout << "\n raideur: "; raideur->Affiche(); cout << "\n second membre: " << (*residu); }; }; }; #endif ////---- debug --- //if ((num_elt == 3)&&((integ_vol_typeQuel != NULL) || (integ_vol_t_typeQuel != NULL))) // {cout << "\n debug ElemMeca::Cal_implicit ( "; // 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++) // cout << "\n tab_integ("<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++) // cout << "\n tab_integ_et_temps("< & d_epsBB ,int nbint,const Vecteur& poids,const ParaAlgoControle & pa,bool atdt) { double jacobien; // def du jacobien int nbddl = tab_ddl.NbDdl(); energie_totale.Initialisation_differenciee(energie_totale_t); // init de l'énergie totale sur l'élément volume = 0. ; // init E_elem_bulk_tdt = E_elem_bulk_t; P_elem_bulk = 0.; // init pour l'énergie et la puissance associées au bulk // init éventuel de la contrainte de bulk viscosity TenseurHH* sigHH_t_1 = (*lesPtIntegMecaInterne)(1).SigHH_t(); // simplification d'écriture if (bulk_viscosity) { if (sig_bulkHH == NULL) {sig_bulkHH = NevezTenseurHH(*sigHH_t_1);} else if (sig_bulkHH->Dimension() != sigHH_t_1->Dimension()) {delete sig_bulkHH; sig_bulkHH = NevezTenseurHH(*sigHH_t_1);}; }; // --- init éventuel des intégrales de volume et temps Init_Integ_vol_et_temps(); /* 19 nov: en fait il ne faut pas prendre en compte l'épaisseur méca: cf. doc théorique // --- init éventuel pour les épaisseurs et largeurs double epaisseur_0 = EpaisseurMoyenne(TEMPS_0 ); double epaisseur = epaisseur_0;double epaisseur_moyenne = 0.; // init */ // --- init pour l'init de la stabilisation de membrane-biel éventuelle const Met_abstraite::Expli_t_tdt* ex_final=NULL; // contiendra après les boucles la dernière métrique Mise_a_jour_A_calculer_force_stab(); // permettra ensuite de savoir où le calcul doit être fait for (int ni =1; ni<= nbint; ni++) // boucle sur les pt d'integ { def->ChangeNumInteg(ni);def->Mise_a_jour_data_specif(tabSaveDefDon(ni)); PtIntegMecaInterne & ptIntegMeca = (*lesPtIntegMecaInterne)(ni); TenseurHH & sigHH_t = *(ptIntegMeca.SigHH_t()); TenseurHH & sigHH = *(ptIntegMeca.SigHH()); TenseurBB & epsBB = *(ptIntegMeca.EpsBB()); TenseurBB & DepsBB_ = *(ptIntegMeca.DepsBB()); EnergieMeca& energ = tab_energ(ni); EnergieMeca& energ_t = tab_energ_t(ni); CompThermoPhysiqueAbstraite::SaveResul* sTP=NULL; // les données spécifique thermo physiques if (loiTP != NULL) {sTP = tabSaveTP(ni);}; // au pt d'integ si elles existes if ((loiComp->Id_comport()==LOI_VIA_UMAT) // cas de l'utilisation d'une loi umat || (loiComp->Id_comport()==LOI_VIA_UMAT_CP)) ((Loi_Umat*) loiComp)->Mise_a_jour_nbe_nbptinteg(this->Num_elt(),ni); DeuxDoubles delta_ener_bulk_vol; // init Met_abstraite::Expli_t_tdt ex_inter; // une grandeur intermédiaire // -- on gère les exceptions éventuelles en mettant le bloc sous surveillance try // ce qui permet de donner les numéros d'éléments et de pti {if (atdt) { const Met_abstraite::Expli_t_tdt& ex = loiComp->Cal_explicit_tdt (tabSaveDon(ni), *def,tab_ddl,ptIntegMeca,d_epsBB,jacobien ,sTP,loiTP,dilatation,energ,energ_t,premier_calcul_meca_impli_expli); ex_inter= ex; ex_final = &ex_inter; // stockage pour la stabilisation éventuelle de membraneBiel // examen du cas où on désire utiliser la méthode d'atténuation des hautes fréquences avec le bulk viscosity if (bulk_viscosity) delta_ener_bulk_vol=ModifContrainteBulk(TEMPS_tdt,*ex.gijHH_tdt,sigHH,DepsBB_,(*sig_bulkHH) ); } else { const Met_abstraite::Expli& ex = loiComp->Cal_explicit_t (tabSaveDon(ni), *def,tab_ddl,ptIntegMeca,d_epsBB,jacobien ,sTP,loiTP,dilatation,energ,energ_t,premier_calcul_meca_impli_expli); ex_inter = ex.T_dans_tdt(); ex_final = &ex_inter; // stockage pour la stabilisation éventuelle de membraneBiel // examen du cas où on désire utiliser la méthode d'atténuation des hautes fréquences avec le bulk viscosity if (bulk_viscosity) delta_ener_bulk_vol=ModifContrainteBulk(TEMPS_t,*ex.gijHH_t,sigHH,DepsBB_,(*sig_bulkHH) ); }; } catch (ErrNonConvergence_loiDeComportement excep) // cas d'une d'une erreur survenue à cause d'une non convergence pour la résolution // d'une loi de comportement incrémentale { cout << "\n erreur de loi de comportement element= " << this->Num_elt() << " point d'integration= "<= 1) { cout << "\n ********** attention on a trouve un jacobien negatif!! ("< 1.) && ( rap > pa.MaxiVarJacobien())) { if (ParaGlob::NiveauImpression() >= 6) {// on affiche les infos des noeuds for (int i=1;i<= tab_noeud.Taille();i++) tab_noeud(i)->Affiche(); // on affiche les vecteurs de bases à 0 et t cout << "\n gi_0: " << *(ex_inter.giB_0)<< "\n gi_tdt: " << *(ex_inter.giB_tdt); }; if (ParaGlob::NiveauImpression() >= 3) { cout << "\n *** attention la variation maximal du jacobien est atteinte !! *** " << "\n ele= "<< Num_elt() << " nbi= " << ni << " jacobien= " << jacobien << " jacobien_0= " << (*(ex_inter.jacobien_0)) << endl; }; // on génère une exception throw ErrVarJacobienMini_ElemMeca();break; } else { double poid_jacobien= poids(ni) * jacobien; // 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 Calcul_Integ_vol_et_temps(2,poid_jacobien,ni); /* 19 nov: en fait il ne faut pas prendre en compte l'épaisseur méca: cf. doc théorique //---cas éventuel de la prise en compte de la variation d'une épaisseur, ou section switch (loiComp->Comportement_3D_CP_DP_1D()) { case COMP_CONTRAINTES_PLANES : // en contrainte plane on recalcule l'épaisseur {epaisseur = epaisseur_0 * loiComp->HsurH0(tabSaveDon(ni)); epaisseur_moyenne += epaisseur; poid_jacobien *= epaisseur; break; } case COMP_DEFORMATIONS_PLANES : // en deformation plane, l'épaisseur ne change pas {epaisseur = epaisseur_0 ; epaisseur_moyenne += epaisseur; poid_jacobien *= epaisseur; break; } default : // on n'a rien à faire break; }; */ // il ne faut pas interpoler l'énergie à t, car elle était associée à un volume qui a changé // donc il ne faut considérer que l'accroissement d'énergie energie_totale.Ajout_differenciee(energ,energ_t,poid_jacobien); // energie_totale += (energ-energ_t) * poid_jacobien; // energie_totale += energ * poid_jacobien; ////debug //cout << "\n debug: ElemMeca::Cal_explicit " // << " energ visqueux = "<< energie_totale.DissipationVisqueuse() << " brut " << energ.DissipationVisqueuse() // << " poid_jacobien = "<< poid_jacobien << endl; // ////fin debug volume += poid_jacobien; ptIntegMeca.Volume_pti()=poid_jacobien; // calcul du résidu si ce n'est pas une loi rien if (!Loi_rien(loiComp->Id_comport())) {E_elem_bulk_tdt += delta_ener_bulk_vol.un * poid_jacobien; P_elem_bulk += delta_ener_bulk_vol.deux * poid_jacobien; for (int j =1; j<= nbddl; j++) {(*residu)(j) -= (sigHH && (*(d_epsBB(j)))) * poid_jacobien; }; // --- cas éventuel d'une stabilisation membrane-biel --- // ici il s'agit de la contribution précise à chaque pti // pour une stabilisation via les normales aux pti if (pt_StabMembBiel != NULL) if (!(pt_StabMembBiel->Aa_calculer())) Cal_explicit_StabMembBiel(ni,*ex_final,nbint,poids(ni),NULL); ////---debug // #ifdef MISE_AU_POINT // if (ParaGlob::NiveauImpression() > 2) // if ((std::isinf((*residu)(j))||( std::isnan((*residu)(j))))) // { cout << "\n ********** attention on a trouve une composante ("<Aa_calculer()) // Cal_explicit_StabMembBiel(*ex_final); }; if (bulk_viscosity) // dans le cas du bulk on retire la contrainte du bulk, qui est non physique { sigHH -= (*sig_bulkHH); } // ceci pour la sauvegarde ou autre utilisation } // // fin boucle sur les points d'intégration #ifdef MISE_AU_POINT if (ParaGlob::NiveauImpression() > 9) { cout << "\n Second membre local: ? (o/n) "; string rep(" "); // procédure de lecture avec prise en charge d'un retour chariot rep = lect_return_defaut(false,"n"); if ((rep == "0")||(rep == "o")) {cout << "\n Second membre local: elem= " << Num_elt_const() << ", maillage= " << Num_maillage(); cout << "\n second membre: " << (*residu); }; }; #endif /* 19 nov: en fait il ne faut pas prendre en compte l'épaisseur méca: cf. doc théorique //---cas éventuel de la prise en compte de la variation d'une épaisseur, ou section switch (loiComp->Comportement_3D_CP_DP_1D()) { case COMP_CONTRAINTES_PLANES : // en contrainte plane on recalcule l'épaisseur {epaisseur_moyenne /= nbint; Modifie_epaisseur_moyenne_tdt(epaisseur); break; } default : // on n'a rien à faire break; }; */ // --- intervention dans le cas d'une stabilisation d'hourglass // stabilisation pour un calcul implicit if (type_stabHourglass) Cal_explicit_hourglass(atdt); // --- cas éventuel d'une stabilisation membrane-biel --- // ici il s'agit soit du calcul approché d'initialisation, soit de la fin du calcul après la boucle // modif: 10 janvier 2019 non c'est le calcul correct une fois la raideur calculée if (pt_StabMembBiel != NULL) {Cal_explicit_StabMembBiel(-1,*ex_final, nbint,volume,NULL); }; #ifdef MISE_AU_POINT if (ParaGlob::NiveauImpression() > 9) { if ((type_stabHourglass)||(pt_StabMembBiel != NULL)) {cout << "\n apres stabilisation: Second membre local: ? (o/n) "; string rep(" "); // procédure de lecture avec prise en charge d'un retour chariot rep = lect_return_defaut(false,"n"); if ((rep == "0")||(rep == "o")) {cout << "\n Second membre local: elem= " << Num_elt_const() << ", maillage= " << Num_maillage(); cout << "\n second membre: " << (*residu); }; }; }; #endif // liberation des tenseurs intermediaires LibereTenseur(); }; // Calcul de la matrice géométrique et de la matrice initiale // cette fonction est éventuellement appelée par les classes dérivées // ddl represente les degres de liberte specifiques a l'element // epsBB = deformation, sigHH = contrainte, d_epsbb = variation des def // nbint = nb de pt d'integration , poids = poids d'integration // cald_Dvirtuelle = indique si l'on doit calculer la dérivée de la vitesse de déformation virtuelle void ElemMeca::Cal_matGeom_Init (Mat_pleine & matGeom, Mat_pleine & matInit,DdlElement & tab_ddl ,Tableau & d_epsBB, Tableau < Tableau2 > d2_epsBB_ ,Tableau & d_sigHH,int nbint,const Vecteur& poids ,const ParaAlgoControle & pa,bool cald_Dvirtuelle) { // le début du programme est semblable au calcul implicit // seule la constitution des matrices finales est différente int nbddl = tab_ddl.NbDdl(); double jacobien; // def du jacobien Vecteur d_jacobien_tdt; volume = 0. ; // init for (int ni =1; ni<= nbint; ni++) // boucle sur les pt d'integ {def->ChangeNumInteg(ni);def->Mise_a_jour_data_specif(tabSaveDefDon(ni)); PtIntegMecaInterne & ptIntegMeca = (*lesPtIntegMecaInterne)(ni); TenseurHH & sigHH = *(ptIntegMeca.SigHH()); TenseurBB & DepsBB_tdt = *(ptIntegMeca.DepsBB()); EnergieMeca& energ = tab_energ(ni); EnergieMeca& energ_t = tab_energ_t(ni); CompThermoPhysiqueAbstraite::SaveResul* sTP=NULL; // les données spécifique thermo physiques if (loiTP != NULL) {sTP = tabSaveTP(ni);}; // au pt d'integ si elles existes if ((loiComp->Id_comport()==LOI_VIA_UMAT) // cas de l'utilisation d'une loi umat || (loiComp->Id_comport()==LOI_VIA_UMAT_CP)) ((Loi_Umat*) loiComp)->Mise_a_jour_nbe_nbptinteg(this->Num_elt(),ni); // -- on gère les exceptions éventuelles en mettant le bloc sous surveillance try // ce qui permet de donner les numéros d'éléments et de pti {loiComp->Cal_flamb_lin(tabSaveDon(ni), *def,tab_ddl,ptIntegMeca ,d_epsBB,jacobien,d_jacobien_tdt,d_sigHH ,pa,sTP,loiTP,dilatation,energ,energ_t ,premier_calcul_meca_impli_expli); } catch (ErrNonConvergence_loiDeComportement excep) // cas d'une d'une erreur survenue à cause d'une non convergence pour la résolution // d'une loi de comportement incrémentale { cout << "\n erreur de loi de comportement element= " << this->Num_elt() << " point d'integration= "<Zero(); }; // calcul des seconds membres suivant les chargements // cas d'un chargement surfacique de direction constante, sur les frontières des éléments // force indique la force surfacique appliquée // retourne le second membre résultant // nSurf : le numéro de la surface externe // calcul à tdt ou t suivant la variable atdt Vecteur& ElemMeca::SM_charge_surf_E (DdlElement & ,int nSurf ,const Tableau & taphi,int nbne ,const Vecteur& poids,const Coordonnee& force,Fonction_nD* pt_fonct ,const ParaAlgoControle & ,bool atdt) { // définition du vecteur de retour Vecteur& SM = *((*res_extS)(nSurf)); Deformation & defS = *defSurf(nSurf); // pour simplifier l'écriture // éventuellement dimensionnement de la sauvegarde if (lesChargeExtSurEle == NULL) lesChargeExtSurEle = new LesChargeExtSurElement; if (lesChargeExtSurEle->LesEffortsDirFixe() == NULL) {if(ParaGlob::AxiSymetrie()) {lesChargeExtSurEle->LesEffortsDirFixe_Change_taille(ElementGeometrique().NbSe());} else {lesChargeExtSurEle->LesEffortsDirFixe_Change_taille(ElementGeometrique().NbFe());} }; Tableau & tab_DirFixe= (*lesChargeExtSurEle->LesEffortsDirFixe())(nSurf); // pour simplifier if (tab_DirFixe.Taille() != defS.Phi1_Taille()) tab_DirFixe.Change_taille(defS.Phi1_Taille(),Coordonnee(ParaGlob::Dimension())); int ni; // compteur globale de point d'integration for (defS.PremierPtInteg(), ni = 1;defS.DernierPtInteg();defS.NevezPtInteg(),ni++) {// calcul des éléments de la métrique, entre autre le jacobien, on utilise le même calcul // que pour un calcul primaire en explicit mais pour un calcul autre que mécanique double jacobien; bool premier_calcul=true; // contrairement à la déformation, pas de sauvegarde // donc il faut calculer tous les éléments de la métrique const Met_abstraite::Impli* ex_impli = NULL; const Met_abstraite::Expli_t_tdt* ex_expli_tdt = NULL; const Met_abstraite::Expli* ex_expli = NULL; if (atdt) { const Met_abstraite::Expli_t_tdt& ex = defS.Cal_explicit_tdt(premier_calcul); jacobien = (*ex.jacobien_tdt); ex_expli_tdt = &ex; } else // normalement le cas à t n'est pas courant, donc on tolère une création { const Met_abstraite::Expli& ex = defS.Cal_explicit_t(premier_calcul); jacobien = (*ex.jacobien_t); ex_expli = &ex; } int ix=1; int dimf = force.Dimension(); if(ParaGlob::AxiSymetrie()) // cas d'un chargement axisymétrique, dans ce cas on ne prend en compte que les // dimf-1 coordonnées donc on décrémente dimf--; // prise en compte d'une dépendance à une fonction nD Coordonnee force_reelle(force); // init par défaut if (pt_fonct != NULL) { // ici on utilise les variables connues aux noeuds, ou calculées à partir de // on commence par récupérer les conteneurs des grandeurs à fournir List_io & li_enu_scal = pt_fonct->Li_enu_etendu_scalaire(); List_io & li_quelc = pt_fonct->Li_equi_Quel_evolue(); bool absolue = true; // on se place systématiquement en absolu // on va utiliser la méhode Valeur_multi_interpoler_ou_calculer // pour les grandeurs strictement scalaire Tableau val_ddl_enum(Valeur_multi_interpoler_ou_calculer (absolue,TEMPS_tdt,li_enu_scal,defS,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_tdt,li_quelc,defS,ex_impli,ex_expli_tdt,ex_expli); // calcul de la valeur et retour dans tab_ret Tableau & tab_val = pt_fonct->Valeur_FnD_Evoluee(&val_ddl_enum,&li_enu_scal,&li_quelc,NULL,NULL); // if (pt_fonct->Depend_M()) // {// 1) on récupère la position dans I_a du point d'intégration // const Coordonnee & M = defS.Position_tdt(); // // 2) on appel la fonction, qui ne doit dépendre que de M en var locales // Tableau tab(1); tab(1)=M; // Tableau tab_val = pt_fonct->Val_FnD_Evoluee(NULL,&tab,NULL); // deux cas: soit une fonction scalaire soit dimf composantes if (tab_val.Taille() == 1) {force_reelle *= tab_val(1);} else if (tab_val.Taille() == dimf) {switch (dimf) {case 3:force_reelle(3) *= tab_val(3); case 2:force_reelle(2) *= tab_val(2); case 1:force_reelle(1) *= tab_val(1); break; default: cout << "\n *** erreur ElemMeca::SM_charge_surf_E(.. "; Sortie(1); }; } else {cout << "\n *** erreur dans l'utilisation d'une fct nD pour un chargement" << " surfacique: la dimension de la fct nD "< implicite, // pa : permet de déterminer si oui ou non on calcul la contribution à la raideur // retourne le second membre et la matrice de raideur correspondant Element::ResRaid ElemMeca::SMR_charge_surf_I (DdlElement & ddls,int nSurf ,const Tableau & taphi,int nbne ,const Vecteur& poids,const Coordonnee& force,Fonction_nD* pt_fonct ,const ParaAlgoControle & pa) { bool avec_raid = pa.Var_charge_externe(); // récup indicateur bool premier_calcul=true; // contrairement à la déformation, pas de sauvegarde // donc il faut calculer tous les éléments de la métrique // // dans le cas où la variation sur la raideur est demandé on s'assure que la variation // // du jacobien est bien effective sinon on l'impose // ParaAlgoControle pa_nevez(pa); // if (!pa_nevez.Var_jacobien()) pa_nevez.Modif_Var_jacobien(true); int ni; // compteur globale de point d'integration Deformation & defS = *defSurf(nSurf); // pour simplifier l'écriture // éventuellement dimensionnement de la sauvegarde if (lesChargeExtSurEle == NULL) lesChargeExtSurEle = new LesChargeExtSurElement; if (lesChargeExtSurEle->LesEffortsDirFixe() == NULL) {if(ParaGlob::AxiSymetrie()) {lesChargeExtSurEle->LesEffortsDirFixe_Change_taille(ElementGeometrique().NbSe());} else {lesChargeExtSurEle->LesEffortsDirFixe_Change_taille(ElementGeometrique().NbFe());} }; Tableau & tab_DirFixe= (*lesChargeExtSurEle->LesEffortsDirFixe())(nSurf); // pour simplifier if (tab_DirFixe.Taille() != defS.Phi1_Taille()) tab_DirFixe.Change_taille(defS.Phi1_Taille(),Coordonnee(ParaGlob::Dimension())); int nbddl = ddls.NbDdl(); Vecteur& SM = (*((*res_extS)(nSurf))); // " " " Mat_pleine & KM = (*((*raid_extS)(nSurf))); // " " " for (defS.PremierPtInteg(), ni = 1;defS.DernierPtInteg();defS.NevezPtInteg(),ni++) {// calcul des éléments de la métrique, entre autre le jacobien, on utilise le même calcul // que pour un calcul primaire en implicit const Met_abstraite::Impli& ex = defS.Cal_implicit(premier_calcul); const Met_abstraite::Impli* ex_impli = &ex; const Met_abstraite::Expli_t_tdt* ex_expli_tdt = NULL; const Met_abstraite::Expli* ex_expli = NULL; int ix=1; int dimf = force.Dimension(); if(ParaGlob::AxiSymetrie()) // cas d'un chargement axisymétrique, dans ce cas on ne prend en compte que les // dimf-1 coordonnées donc on décrémente dimf--; // prise en compte d'une dépendance à une fonction nD // on ne tient pas compte de la variation du point dans la fct nD Coordonnee force_reelle(force); // init par défaut if (pt_fonct != NULL) { // ici on utilise les variables connues aux noeuds, ou calculées à partir de // on commence par récupérer les conteneurs des grandeurs à fournir List_io & li_enu_scal = pt_fonct->Li_enu_etendu_scalaire(); List_io & li_quelc = pt_fonct->Li_equi_Quel_evolue(); bool absolue = true; // on se place systématiquement en absolu // on va utiliser la méhode Valeur_multi_interpoler_ou_calculer // pour les grandeurs strictement scalaire Tableau val_ddl_enum(Valeur_multi_interpoler_ou_calculer (absolue,TEMPS_tdt,li_enu_scal,defS,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_tdt,li_quelc,defS,ex_impli,ex_expli_tdt,ex_expli); // calcul de la valeur et retour dans tab_ret Tableau & tab_val = pt_fonct->Valeur_FnD_Evoluee(&val_ddl_enum,&li_enu_scal,&li_quelc,NULL,NULL); // if (pt_fonct->Depend_M()) // {// 1) on récupère la position dans I_a du point d'intégration // const Coordonnee & M = defS.Position_tdt(); // // 2) on appel la fonction, qui ne doit dépendre que de M en var locales // Tableau tab(1); tab(1)=M; // Tableau tab_val = pt_fonct->Val_FnD_Evoluee(NULL,&tab,NULL); // deux cas: soit une fonction scalaire soit dimf composantes if (tab_val.Taille() == 1) {force_reelle *= tab_val(1);} else if (tab_val.Taille() == dimf) {switch (dimf) {case 3:force_reelle(3) *= tab_val(3); case 2:force_reelle(2) *= tab_val(2); case 1:force_reelle(1) *= tab_val(1); break; default: cout << "\n *** erreur ElemMeca::SM_charge_surf_E(.. "; Sortie(1); }; } else {cout << "\n *** erreur dans l'utilisation d'une fct nD pour un chargement" << " surfacique: la dimension de la fct nD "<& taphi,int nbne ,const Vecteur& poids,double pression,Fonction_nD* pt_fonct ,const ParaAlgoControle & ,bool atdt) { Deformation* definter=NULL; // variable de travail transitoire Vecteur* SM_P = NULL; if (!(ParaGlob::AxiSymetrie())) { definter = defSurf(nSurf); // le cas normal est non axisymétrique SM_P = ((*res_extS)(nSurf)); } else { definter = defArete(nSurf); // en axisymétrie, c'est une def d'arête SM_P = ((*res_extA)(nSurf)); }; Deformation & defS = *definter; // pour simplifier l'écriture Vecteur& SM = *SM_P; // " " " // éventuellement dimensionnement de la sauvegarde if (lesChargeExtSurEle == NULL) lesChargeExtSurEle = new LesChargeExtSurElement; if (lesChargeExtSurEle->LesPressionsExternes() == NULL) {if(ParaGlob::AxiSymetrie()) {lesChargeExtSurEle->LesPressionsExternes_Change_taille(ElementGeometrique().NbSe());} else {lesChargeExtSurEle->LesPressionsExternes_Change_taille(ElementGeometrique().NbFe());} }; Tableau & tab_Press= (*lesChargeExtSurEle->LesPressionsExternes())(nSurf); // pour simplifier if (tab_Press.Taille() != defS.Phi1_Taille()) tab_Press.Change_taille(defS.Phi1_Taille()); // définition du vecteur de retour int ni; // compteur globale de point d'integration bool premier_calcul=true; // contrairement à la déformation, pas de sauvegarde // donc il faut calculer tous les éléments de la métrique for (defS.PremierPtInteg(), ni = 1;defS.DernierPtInteg();defS.NevezPtInteg(),ni++) { // calcul des éléments de la métrique, entre autre le jacobien, on utilise le même calcul // que pour un calcul primaire en explicit mais pour un calcul autre que mécanique Met_abstraite::Expli ex; if (atdt) ex = ((defS.Cal_explicit_tdt(premier_calcul)).Tdt_dans_t()); else ex.operator=( defS.Cal_explicit_t(premier_calcul)); const Met_abstraite::Impli* ex_impli = NULL; const Met_abstraite::Expli_t_tdt* ex_expli_tdt = NULL; const Met_abstraite::Expli* ex_expli = &ex; // détermination de la normale à la surface #ifdef MISE_AU_POINT // test pour savoir si l'on a réellement affaire à une surface if ((ex.giB_t->NbVecteur() != 2) || ( ParaGlob::Dimension() != 3)) { cout << "\n erreur, il doit y avoir deux vecteurs pour la surface de dimension 3" << "\n ici on a nbvec= " << ex.giB_t->NbVecteur() <<" vecteur(s) et on est en dimension " << " dim = " << ParaGlob::Dimension(); if (ParaGlob::NiveauImpression() > 2) cout << "\n ElemMeca::SM_charge_pres (DdlElement & ...nbvec= "; Sortie(1); } #endif // la normale vaut le produit vectoriel des 2 premiers vecteurs Coordonnee normale = Util::ProdVec_coorBN( (*ex.giB_t)(1), (*ex.giB_t)(2)); // dans le cas où il y a une fonction nD, et qu'un de ces arguments // est des coordonnées Xi on l'utilise double pression_applique = pression; if (pt_fonct != NULL) { // ici on utilise les variables connues aux noeuds, ou calculées à partir de // on commence par récupérer les conteneurs des grandeurs à fournir List_io & li_enu_scal = pt_fonct->Li_enu_etendu_scalaire(); List_io & li_quelc = pt_fonct->Li_equi_Quel_evolue(); bool absolue = true; // on se place systématiquement en absolu // on va utiliser la méhode Valeur_multi_interpoler_ou_calculer // pour les grandeurs strictement scalaire Tableau val_ddl_enum(Valeur_multi_interpoler_ou_calculer (absolue,TEMPS_tdt,li_enu_scal,defS,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_tdt,li_quelc,defS,ex_impli,ex_expli_tdt,ex_expli); // calcul de la valeur et retour dans tab_ret Tableau & tab_val = pt_fonct->Valeur_FnD_Evoluee(&val_ddl_enum,&li_enu_scal,&li_quelc,NULL,NULL); // if (pt_fonct->Depend_M()) // {// calcul de la pression au niveau de la position du point d'intégration // // 1) on récupère la position dans I_a du point d'intégration // const Coordonnee & M = defS.Position_tdt(); // // 2) on appel la fonction, qui ne doit dépendre que de M en var locales // Tableau tab(1); tab(1)=M; // Tableau tab_val = pt_fonct->Val_FnD_Evoluee(NULL,&tab,NULL); // seule la première valeur est ok pression_applique *= tab_val(1); // } // else // {cout << "\n *** erreur dans l'utilisation d'une fct nD pour un chargement" // << " surfacique: dependance autre que du point "<< endl; // Sortie(1); // }; }; // calcul de la normale normée et pondérée de la pression // la pression est positive qu'en elle appuis (diminution de volume) normale.Normer();normale *= -pression_applique; tab_Press(ni).P += normale; int ix=1; int dimf = 3; // ne fonctionne qu'en dim 3 if(ParaGlob::AxiSymetrie()) // cas d'un chargement axisymétrique, dans ce cas on ne prend en compte que les // dimf-1 coordonnées donc on décrémente dimf--; for (int ne =1; ne<= nbne; ne++) for (int i=1;i<= dimf;i++,ix++) SM(ix) += taphi(ni)(ne)* normale(i) * (poids(ni) * (*ex.jacobien_t)); // sauvegarde de la pression appliquée tab_Press(ni).press += pression_applique; //debug //if (num_elt == 33839) // cout << "\n debug: ElemMeca::SM_charge_pres_E " // << " pression= " << pression << endl; //if (tab_press_appliquee(ni).press_tdt > 120) // cout << "\n debug: ElemMeca::SM_charge_pres_E "<< " on s'arrete "; //fin debug }; // retour du second membre return SM; }; // calcul des seconds membres suivant les chargements // cas d'un chargement pression, sur les frontières des éléments // pression indique la pression appliquée // retourne le second membre résultant // nSurf : le numéro de la surface externe -> implicite, // pa: permet de déterminer si oui ou non on calcul la contribution à la raideur Element::ResRaid ElemMeca::SMR_charge_pres_I(DdlElement & ddlS,int nSurf ,const Tableau & taphi,int nbne ,const Vecteur& poids,double pression,Fonction_nD* pt_fonct ,const ParaAlgoControle & pa) { int ni; // compteur globale de point d'integration Deformation* definter=NULL; // variable de travail transitoire Vecteur* SM_P = NULL; Mat_pleine* KM_P = NULL; if (!(ParaGlob::AxiSymetrie())) { definter = defSurf(nSurf); // le cas normal est non axisymétrique SM_P = ((*res_extS)(nSurf)); KM_P = ((*raid_extS)(nSurf)); } else { definter = defArete(nSurf); // en axisymétrie, c'est une def d'arête SM_P = ((*res_extA)(nSurf)); KM_P = ((*raid_extA)(nSurf)); }; Deformation & defS = *definter; // pour simplifier l'écriture Vecteur& SM = *SM_P; // " " " Mat_pleine & KM = *KM_P; // " " " // éventuellement dimensionnement de la sauvegarde if (lesChargeExtSurEle == NULL) lesChargeExtSurEle = new LesChargeExtSurElement; if (lesChargeExtSurEle->LesPressionsExternes() == NULL) {if(ParaGlob::AxiSymetrie()) {lesChargeExtSurEle->LesPressionsExternes_Change_taille(ElementGeometrique().NbSe());} else {lesChargeExtSurEle->LesPressionsExternes_Change_taille(ElementGeometrique().NbFe());} }; Tableau & tab_Press= (*lesChargeExtSurEle->LesPressionsExternes())(nSurf); // pour simplifier if (tab_Press.Taille() != defS.Phi1_Taille()) tab_Press.Change_taille(defS.Phi1_Taille()); int nbddl = ddlS.NbDdl(); // controle bool avec_raid = pa.Var_charge_externe(); // // dans le cas où la variation sur la raideur est demandé on s'assure que la variation // // du jacobien est bien effective sinon on l'impose // ParaAlgoControle pa_nevez(pa); // if (!pa_nevez.Var_jacobien()) pa_nevez.Modif_Var_jacobien(true); bool premier_calcul=true; // contrairement à la déformation, pas de sauvegarde // donc il faut calculer tous les éléments de la métrique for (defS.PremierPtInteg(), ni = 1;defS.DernierPtInteg();defS.NevezPtInteg(),ni++) { // calcul des éléments de la métrique, entre autre le jacobien, on utilise le même calcul // que pour un calcul primaire en explicit mais pour un calcul autre que mécanique const Met_abstraite::Impli& ex = defS.Cal_implicit(premier_calcul); const Met_abstraite::Impli* ex_impli = &ex; const Met_abstraite::Expli_t_tdt* ex_expli_tdt = NULL; const Met_abstraite::Expli* ex_expli = NULL; // détermination de la normale à la surface #ifdef MISE_AU_POINT // test pour savoir si l'on a réellement affaire à une surface if ((ex.giB_tdt->NbVecteur() != 2) || ( ParaGlob::Dimension() != 3)) { cout << "\n erreur, il doit y avoir deux vecteurs pour la surface de dimension 3" << " ElemMeca::SM_charge_pres (DdlElement & ...nbvec= " << ex.giB_tdt->NbVecteur() << " dim = " << ParaGlob::Dimension(); Sortie(1); } #endif // la normale vaut le produit vectoriel des 2 premiers vecteurs CoordonneeB normale = Util::ProdVec_coorB( (*ex.giB_tdt)(1), (*ex.giB_tdt)(2)); // calcul de la variation de la normale // 1) variation du produit vectoriel Tableau D_pasnormale = Util::VarProdVect_coorB( (*ex.giB_tdt)(1),(*ex.giB_tdt)(2),(*ex.d_giB_tdt)); // 2) de la normale Tableau D_normale = Util::VarUnVect_coorB(normale,D_pasnormale,normale.Norme()); // dans le cas où il y a une fonction nD, et qu'un de ces arguments // est des coordonnées Xi on l'utilise double pression_applique = pression; if (pt_fonct != NULL) { // ici on utilise les variables connues aux noeuds, ou calculées à partir de // on commence par récupérer les conteneurs des grandeurs à fournir List_io & li_enu_scal = pt_fonct->Li_enu_etendu_scalaire(); List_io & li_quelc = pt_fonct->Li_equi_Quel_evolue(); bool absolue = true; // on se place systématiquement en absolu // on va utiliser la méhode Valeur_multi_interpoler_ou_calculer // pour les grandeurs strictement scalaire Tableau val_ddl_enum(Valeur_multi_interpoler_ou_calculer (absolue,TEMPS_tdt,li_enu_scal,defS,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_tdt,li_quelc,defS,ex_impli,ex_expli_tdt,ex_expli); // //---debug // cout << "\n debug ElemMeca::SMR_charge_pres_I "; // cout << li_quelc ; // //-- fin debug // // calcul de la valeur et retour dans tab_ret Tableau & tab_val = pt_fonct->Valeur_FnD_Evoluee(&val_ddl_enum,&li_enu_scal,&li_quelc,NULL,NULL); // if (pt_fonct->Depend_M()) // {// calcul de la pression au niveau de la position du point d'intégration // // 1) on récupère la position dans I_a du point d'intégration // const Coordonnee & M = defS.Position_tdt(); // // 2) on appelle la fonction, qui ne doit dépendre que de M en var locales // Tableau tab(1); tab(1)=M; // Tableau tab_val = pt_fonct->Val_FnD_Evoluee(NULL,&tab,NULL); // seule la première valeur est ok pression_applique *= tab_val(1); // } // else // {cout << "\n *** erreur dans l'utilisation d'une fct nD pour un chargement" // << " surfacique: dependance autre que du point "<< endl; // Sortie(1); // }; }; //*** important: pour l'instant on ne calcule pas la variation de la // pression causée par la variation du point ==> ce qui est différent // du calcul hydrostatique par exemple. Du coup, la convergence est // sans doute un peu moins bonne pour des grands pas de temps ou des // grandes variation de positions // calcul de la normale normée et pondérée de la pression // la pression est positive qu'en elle appuis (diminution de volume) normale.Normer();normale *= -pression_applique; tab_Press(ni).P += normale.Coor_const(); // également pondération de la variation de la for (int ihi =1;ihi<= nbddl;ihi++) D_normale(ihi) *= -pression_applique; // sauvegarde de la pression appliquée tab_Press(ni).press += pression_applique; int ix=1; int dimf = 3; // ne fonctionne qu'en dim 3 if(ParaGlob::AxiSymetrie()) // cas d'un chargement axisymétrique, dans ce cas on ne prend en compte que les // dimf-1 coordonnées donc on décrémente dimf--; for (int ne =1; ne<= nbne; ne++) for (int i=1;i<= dimf;i++,ix++) { SM(ix) += taphi(ni)(ne)* normale(i) * (poids(ni) * (*ex.jacobien_tdt)); // dans le cas avec_raideur on calcul la contribution à la raideur if (avec_raid) for (int j =1; j<= nbddl; j++) KM(ix,j) -= taphi(ni)(ne)* normale(i) * (poids(ni) * (*ex.d_jacobien_tdt)(j)) + taphi(ni)(ne)* D_normale(j)(i) * (poids(ni) * (*ex.jacobien_tdt)) ; } } ////-------- debug //{cout << "\n debug: ElemMeca::SMR_charge_pres_I(.."; // cout << "\n effort externe de pression: Raideur et second membre : elem= " << Num_elt_const() // << ", maillage= " << Num_maillage(); // cout << "\n raideur: "; // KM.Affiche(); // cout << "\n second membre: " << SM; //}; // // ////------- fin debug // liberation des tenseurs intermediaires LibereTenseur(); Element::ResRaid el; el.res = SM_P; el.raid = KM_P; return el; }; // calcul des seconds membres suivant les chargements // cas d'un chargement lineique, sur les aretes frontières des éléments // force indique la force lineique appliquée // retourne le second membre résultant // nArete : le numéro de la surface externe // calcul à l'instant tdt ou t en fonction de la variable atdt Vecteur& ElemMeca::SM_charge_line_E (DdlElement & ,int nArete ,const Tableau & taphi,int nbne ,const Vecteur& poids,const Coordonnee& force,Fonction_nD* pt_fonct ,const ParaAlgoControle & ,bool atdt) { // définition du vecteur de retour Vecteur& SM = *((*res_extA)(nArete)); int ni; // compteur globale de point d'integration Deformation & defA = *defArete(nArete); // pour simplifier l'écriture // éventuellement dimensionnement de la sauvegarde if (lesChargeExtSurEle == NULL) lesChargeExtSurEle = new LesChargeExtSurElement; if (lesChargeExtSurEle->LesLineique() == NULL) {if(ParaGlob::AxiSymetrie()) {lesChargeExtSurEle->LesLineique_Change_taille(ElementGeometrique().Nbne());} else {lesChargeExtSurEle->LesLineique_Change_taille(ElementGeometrique().NbSe());} }; Tableau & tab_line= (*lesChargeExtSurEle->LesLineique())(nArete); // pour simplifier if (tab_line.Taille() != defA.Phi1_Taille()) tab_line.Change_taille(defA.Phi1_Taille(),Coordonnee(ParaGlob::Dimension())); for (defA.PremierPtInteg(), ni = 1;defA.DernierPtInteg();defA.NevezPtInteg(),ni++) { // calcul des éléments de la métrique, entre autre le jacobien, on utilise le même calcul // que pour un calcul primaire en explicit mais pour un calcul autre que mécanique Met_abstraite::Expli ex; bool premier_calcul=true; // contrairement à la déformation, pas de sauvegarde // donc il faut calculer tous les éléments de la métrique if (atdt) ex = (defA.Cal_explicit_tdt(premier_calcul)).Tdt_dans_t(); else ex = defA.Cal_explicit_t(premier_calcul); const Met_abstraite::Impli* ex_impli = NULL; const Met_abstraite::Expli_t_tdt* ex_expli_tdt = NULL; const Met_abstraite::Expli* ex_expli = &ex; int ix=1; int dimf = force.Dimension(); if(ParaGlob::AxiSymetrie()) // cas d'un chargement axisymétrique, dans ce cas on ne prend en compte que les // dimf-1 coordonnées donc on décrémente dimf--; // prise en compte d'une dépendance à une fonction nD Coordonnee force_reelle(force); // init par défaut if (pt_fonct != NULL) { // ici on utilise les variables connues aux noeuds, ou calculées à partir de // on commence par récupérer les conteneurs des grandeurs à fournir List_io & li_enu_scal = pt_fonct->Li_enu_etendu_scalaire(); List_io & li_quelc = pt_fonct->Li_equi_Quel_evolue(); bool absolue = true; // on se place systématiquement en absolu // on va utiliser la méhode Valeur_multi_interpoler_ou_calculer // pour les grandeurs strictement scalaire Tableau val_ddl_enum(Valeur_multi_interpoler_ou_calculer (absolue,TEMPS_tdt,li_enu_scal,defA,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_tdt,li_quelc,defA,ex_impli,ex_expli_tdt,ex_expli); // calcul de la valeur et retour dans tab_ret try { Tableau & tab_val = pt_fonct->Valeur_FnD_Evoluee(&val_ddl_enum,&li_enu_scal,&li_quelc,NULL,NULL); // deux cas: soit une fonction scalaire soit dimf composantes if (tab_val.Taille() == 1) {force_reelle *= tab_val(1);} else if (tab_val.Taille() == dimf) {switch (dimf) {case 3:force_reelle(3) *= tab_val(3); case 2:force_reelle(2) *= tab_val(2); case 1:force_reelle(1) *= tab_val(1); break; default: cout << "\n *** erreur ElemMeca::SM_charge_line_E(.. "; ErrCalculFct_nD toto; throw (toto); Sortie(1); }; } else {cout << "\n *** erreur dans l'utilisation d'une fct nD pour un chargement" << " lineique: la dimension de la fct nD "< 0) cout << "\n *** erreur ElemMeca::SM_charge_line_E(.. " << " pb dans le calcul de la fonction nD associee "; if (ParaGlob::param->ParaAlgoControleActifs().Cas_fctnD_charge() == 0) {ErrCalculFct_nD toto; throw (toto);} else // on neutralise la force force_reelle *= 0.; }; }; tab_line(ni)=force_reelle; // sauvegarde for (int ne =1; ne<= nbne; ne++) for (int i=1;i<= dimf;i++,ix++) SM(ix) += taphi(ni)(ne)* force_reelle(i) * (poids(ni) * (*ex.jacobien_t)); } // retour du second membre return SM; }; // cas d'un chargement lineique, sur les arêtes frontières des éléments // force indique la force lineique appliquée // retourne le second membre résultant // nArete : le numéro de l'arête externe -> implicite, // pa: permet de déterminer si oui ou non on calcul la contribution à la raideur Element::ResRaid ElemMeca::SMR_charge_line_I(DdlElement & ddlA,int nArete ,const Tableau & taphi,int nbne ,const Vecteur& poids,const Coordonnee& force,Fonction_nD* pt_fonct ,const ParaAlgoControle & pa) { int ni; // compteur globale de point d'integration Deformation & defA = *defArete(nArete); // pour simplifier l'écriture int nbddl = ddlA.NbDdl(); Vecteur& SM = (*((*res_extA)(nArete))); // " " " Mat_pleine & KM = (*((*raid_extA)(nArete))); // " " " // controle bool avec_raid = pa.Var_charge_externe(); // éventuellement dimensionnement de la sauvegarde if (lesChargeExtSurEle == NULL) lesChargeExtSurEle = new LesChargeExtSurElement; if (lesChargeExtSurEle->LesLineique() == NULL) {if(ParaGlob::AxiSymetrie()) {lesChargeExtSurEle->LesLineique_Change_taille(ElementGeometrique().Nbne());} else {lesChargeExtSurEle->LesLineique_Change_taille(ElementGeometrique().NbSe());} }; Tableau & tab_line= (*lesChargeExtSurEle->LesLineique())(nArete); // pour simplifier if (tab_line.Taille() != defA.Phi1_Taille()) tab_line.Change_taille(defA.Phi1_Taille(),Coordonnee(ParaGlob::Dimension())); // // dans le cas où la variation sur la raideur est demandé on s'assure que la variation // // du jacobien est bien effective sinon on l'impose // ParaAlgoControle pa_nevez(pa); // if (!pa_nevez.Var_jacobien()) pa_nevez.Modif_Var_jacobien(true); bool premier_calcul=true; // contrairement à la déformation, pas de sauvegarde // donc il faut calculer tous les éléments de la métrique for (defA.PremierPtInteg(), ni = 1;defA.DernierPtInteg();defA.NevezPtInteg(),ni++) { // calcul des éléments de la métrique, entre autre le jacobien, on utilise le même calcul // que pour un calcul primaire en implicit const Met_abstraite::Impli& ex = defA.Cal_implicit(premier_calcul); const Met_abstraite::Impli* ex_impli = &ex; const Met_abstraite::Expli_t_tdt* ex_expli_tdt = NULL; const Met_abstraite::Expli* ex_expli = NULL; int ix=1; int dimf = force.Dimension(); if(ParaGlob::AxiSymetrie()) // cas d'un chargement axisymétrique, dans ce cas on ne prend en compte que les // dimf-1 coordonnées donc on décrémente dimf--; // prise en compte d'une dépendance à une fonction nD // on ne tient pas compte de la variation du point dans la fct nD Coordonnee force_reelle(force); // init par défaut if (pt_fonct != NULL) { // ici on utilise les variables connues aux noeuds, ou calculées à partir de // on commence par récupérer les conteneurs des grandeurs à fournir List_io & li_enu_scal = pt_fonct->Li_enu_etendu_scalaire(); List_io & li_quelc = pt_fonct->Li_equi_Quel_evolue(); bool absolue = true; // on se place systématiquement en absolu // on va utiliser la méhode Valeur_multi_interpoler_ou_calculer // pour les grandeurs strictement scalaire Tableau val_ddl_enum(Valeur_multi_interpoler_ou_calculer (absolue,TEMPS_tdt,li_enu_scal,defA,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_tdt,li_quelc,defA,ex_impli,ex_expli_tdt,ex_expli); // calcul de la valeur et retour dans tab_ret Tableau & tab_val = pt_fonct->Valeur_FnD_Evoluee(&val_ddl_enum,&li_enu_scal,&li_quelc,NULL,NULL); // {if (pt_fonct->Depend_M()) // {// 1) on récupère la position dans I_a du point d'intégration // const Coordonnee & M = defA.Position_tdt(); // // 2) on appel la fonction, qui ne doit dépendre que de M en var locales // Tableau tab(1); tab(1)=M; // Tableau tab_val = pt_fonct->Val_FnD_Evoluee(NULL,&tab,NULL); // deux cas: soit une fonction scalaire soit dimf composantes if (tab_val.Taille() == 1) {force_reelle *= tab_val(1);} else if (tab_val.Taille() == dimf) {switch (dimf) {case 3:force_reelle(3) *= tab_val(3); case 2:force_reelle(2) *= tab_val(2); case 1:force_reelle(1) *= tab_val(1); break; default: cout << "\n *** erreur ElemMeca::SM_charge_line_I(.. "; Sortie(1); }; } else {cout << "\n *** erreur dans l'utilisation d'une fct nD pour un chargement" << " lineique: la dimension de la fct nD "<& taphi,int nbne ,const Vecteur& poids,const Coordonnee& force,Fonction_nD* pt_fonct ,const ParaAlgoControle & ,bool atdt) { // définition du vecteur de retour Vecteur& SM = *((*res_extA)(nArete)); int ni; // compteur globale de point d'integration Deformation & defA = *defArete(nArete); // pour simplifier l'écriture // éventuellement dimensionnement de la sauvegarde if (lesChargeExtSurEle == NULL) lesChargeExtSurEle = new LesChargeExtSurElement; if (lesChargeExtSurEle->LesLineiqueSuiveuse() == NULL) {if(ParaGlob::AxiSymetrie()) {lesChargeExtSurEle->LesLineiqueSuiveuse_Change_taille(ElementGeometrique().Nbne());} else {lesChargeExtSurEle->LesLineiqueSuiveuse_Change_taille(ElementGeometrique().NbSe());} }; Tableau & tab_line= (*lesChargeExtSurEle->LesLineiqueSuiveuse())(nArete); // pour simplifier if (tab_line.Taille() != defA.Phi1_Taille()) tab_line.Change_taille(defA.Phi1_Taille(),Coordonnee(ParaGlob::Dimension())); bool premier_calcul=true; // contrairement à la déformation, pas de sauvegarde // donc il faut calculer tous les éléments de la métrique for (defA.PremierPtInteg(), ni = 1;defA.DernierPtInteg();defA.NevezPtInteg(),ni++) { // calcul des éléments de la métrique, entre autre le jacobien, on utilise le même calcul // que pour un calcul primaire en explicit mais pour un calcul autre que mécanique Met_abstraite::Expli ex; if (atdt) ex = (defA.Cal_explicit_tdt(premier_calcul)).Tdt_dans_t(); else ex = defA.Cal_explicit_t(premier_calcul); const Met_abstraite::Impli* ex_impli = NULL; const Met_abstraite::Expli_t_tdt* ex_expli_tdt = NULL; const Met_abstraite::Expli* ex_expli = &ex; #ifdef MISE_AU_POINT // test pour savoir si l'on est en dimension 2 ou en axy sinon pas possible if ((ParaGlob::Dimension() != 2) & (!(ParaGlob::AxiSymetrie()))) { cout << "\n erreur, pour l'instant seul la dimension 2 est permise avec les forces suiveuses" << "\n si pb contacter gerard Rio ! " << " ElemMeca::SM_charge_line_Suiv_E ( ..." << " \n dim = " << ParaGlob::Dimension(); Sortie(1); } #endif // calcul du repère locale initiale orthonormée // Coordonnee2 v1((*ex.giB_0)(1).Vect()); v1.Normer(); // on récupère que les deux premières coordonnées mais on travaille en 3D pour intégrer le cas axi Coordonnee v1((*ex.giB_0).Coordo(1)); v1.Normer(); int dim = v1.Dimension(); Coordonnee v2(dim); v2(1)=-v1(2); v2(2)=v1(1); // composante du vecteur force linéique dans le repère initiale Coordonnee force_0(v1*force,v2*force); //repère locale actuel orthonormée Coordonnee giB_t = (*ex.giB_t)(1).Coor(); Coordonnee vf1(giB_t); Coordonnee vf2(dim);vf2(1)=-vf1(2);vf2(2)=vf1(1); // composantes actuelles de la force Coordonnee force_t = force_0(1)*vf1 + force_0(2)*vf2; // calcul du résidu int ix=1; int dimf = 2 ; // ici uniquement en dim 2 sinon pb // if(ParaGlob::AxiSymetrie()) // // cas d'un chargement axisymétrique, dans ce cas on ne prend en compte que les // // dimf-1 coordonnées donc on décrémente // dimf--; // prise en compte d'une dépendance à une fonction nD if (pt_fonct != NULL) { // ici on utilise les variables connues aux noeuds, ou calculées à partir de // on commence par récupérer les conteneurs des grandeurs à fournir List_io & li_enu_scal = pt_fonct->Li_enu_etendu_scalaire(); List_io & li_quelc = pt_fonct->Li_equi_Quel_evolue(); bool absolue = true; // on se place systématiquement en absolu // on va utiliser la méhode Valeur_multi_interpoler_ou_calculer // pour les grandeurs strictement scalaire Tableau val_ddl_enum(Valeur_multi_interpoler_ou_calculer (absolue,TEMPS_tdt,li_enu_scal,defA,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_tdt,li_quelc,defA,ex_impli,ex_expli_tdt,ex_expli); // calcul de la valeur et retour dans tab_ret Tableau & tab_val = pt_fonct->Valeur_FnD_Evoluee(&val_ddl_enum,&li_enu_scal,&li_quelc,NULL,NULL); // {if (pt_fonct->Depend_M()) // {// 1) on récupère la position dans I_a du point d'intégration // const Coordonnee & M = defA.Position_tdt(); // // 2) on appel la fonction, qui ne doit dépendre que de M en var locales // Tableau tab(1); tab(1)=M; // Tableau tab_val = pt_fonct->Val_FnD_Evoluee(NULL,&tab,NULL); // deux cas: soit une fonction scalaire soit dimf composantes if (tab_val.Taille() == 1) {force_t *= tab_val(1);} else if (tab_val.Taille() == dimf) {switch (dimf) {case 3:force_t(3) *= tab_val(3); case 2:force_t(2) *= tab_val(2); case 1:force_t(1) *= tab_val(1); break; default: cout << "\n *** erreur ElemMeca::SM_charge_line_E(.. "; Sortie(1); }; } else {cout << "\n *** erreur dans l'utilisation d'une fct nD pour un chargement" << " lineique suiveuse: la dimension de la fct nD "< implicite, // pa: permet de déterminer si oui ou non on calcul la contribution à la raideur Element::ResRaid ElemMeca::SMR_charge_line_Suiv_I(DdlElement & ddlA,int nArete ,const Tableau & taphi,int nbne ,const Vecteur& poids,const Coordonnee& force,Fonction_nD* pt_fonct ,const ParaAlgoControle & pa) { int ni; // compteur globale de point d'integration Deformation & defA = *defArete(nArete); // pour simplifier l'écriture int nbddl = ddlA.NbDdl(); Vecteur& SM = (*((*res_extA)(nArete))); // " " " Mat_pleine & KM = (*((*raid_extA)(nArete))); // " " " // controle bool avec_raid = pa.Var_charge_externe(); // éventuellement dimensionnement de la sauvegarde if (lesChargeExtSurEle == NULL) lesChargeExtSurEle = new LesChargeExtSurElement; if (lesChargeExtSurEle->LesLineiqueSuiveuse() == NULL) {if(ParaGlob::AxiSymetrie()) {lesChargeExtSurEle->LesLineiqueSuiveuse_Change_taille(ElementGeometrique().Nbne());} else {lesChargeExtSurEle->LesLineiqueSuiveuse_Change_taille(ElementGeometrique().NbSe());} }; Tableau & tab_line= (*lesChargeExtSurEle->LesLineiqueSuiveuse())(nArete); // pour simplifier if (tab_line.Taille() != defA.Phi1_Taille()) tab_line.Change_taille(defA.Phi1_Taille(),Coordonnee(ParaGlob::Dimension())); // // dans le cas où la variation sur la raideur est demandé on s'assure que la variation // // du jacobien est bien effective sinon on l'impose // ParaAlgoControle pa_nevez(pa); // if (!pa_nevez.Var_jacobien()) pa_nevez.Modif_Var_jacobien(true); bool premier_calcul=true; // contrairement à la déformation, pas de sauvegarde // donc il faut calculer tous les éléments de la métrique for (defA.PremierPtInteg(), ni = 1;defA.DernierPtInteg();defA.NevezPtInteg(),ni++) { // calcul des éléments de la métrique, entre autre le jacobien, on utilise le même calcul // que pour un calcul primaire en implicit const Met_abstraite::Impli& ex = defA.Cal_implicit(premier_calcul); const Met_abstraite::Impli* ex_impli = &ex; const Met_abstraite::Expli_t_tdt* ex_expli_tdt = NULL; const Met_abstraite::Expli* ex_expli = NULL; #ifdef MISE_AU_POINT // test pour savoir si l'on est en dimension 2 ou en axy sinon pas possible if ((ParaGlob::Dimension() != 2) & (!(ParaGlob::AxiSymetrie()))) { cout << "\n erreur, pour l'instant seul la dimension 2 est permise avec les forces suiveuses" << "\n si pb contacter gerard Rio ! " << " ElemMeca::SM_charge_line_Suiv_E ( ..." << " \n dim = " << ParaGlob::Dimension(); Sortie(1); } #endif // calcul du repère locale initiale orthonormée // Coordonnee2 v1((*ex.giB_0)(1).Vect()); v1.Normer(); // on récupère que les deux premières coordonnées mais on travaille en 3D pour intégrer le cas axi Coordonnee v1((*ex.giB_0).Coordo(1)); v1.Normer(); int dim = v1.Dimension(); Coordonnee v2(dim); v2(1)=-v1(2); v2(2)=v1(1); // composante du vecteur force linéique dans le repère initiale Coordonnee force_0(v1*force,v2*force); //repère locale actuel orthonormée Coordonnee giB_tdt = (*ex.giB_tdt)(1).Coor(); Coordonnee vf1(giB_tdt); double vf1Norme = vf1.Norme();vf1 /= vf1Norme; Coordonnee vf2(dim);vf2(1)=-vf1(2);vf2(2)=vf1(1); // composantes actuelles de la force Coordonnee force_t = force_0(1)*vf1 + force_0(2)*vf2; // calcul du résidu int ix=1; int dimf = 2 ; // ici uniquement en dim 2 sinon pb // prise en compte d'une dépendance à une fonction nD // on ne tient pas compte de la variation du point dans la fct nD if (pt_fonct != NULL) { // ici on utilise les variables connues aux noeuds, ou calculées à partir de // on commence par récupérer les conteneurs des grandeurs à fournir List_io & li_enu_scal = pt_fonct->Li_enu_etendu_scalaire(); List_io & li_quelc = pt_fonct->Li_equi_Quel_evolue(); bool absolue = true; // on se place systématiquement en absolu // on va utiliser la méhode Valeur_multi_interpoler_ou_calculer // pour les grandeurs strictement scalaire Tableau val_ddl_enum(Valeur_multi_interpoler_ou_calculer (absolue,TEMPS_tdt,li_enu_scal,defA,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_tdt,li_quelc,defA,ex_impli,ex_expli_tdt,ex_expli); // calcul de la valeur et retour dans tab_ret Tableau & tab_val = pt_fonct->Valeur_FnD_Evoluee(&val_ddl_enum,&li_enu_scal,&li_quelc,NULL,NULL); // {if (pt_fonct->Depend_M()) // {// 1) on récupère la position dans I_a du point d'intégration // const Coordonnee & M = defA.Position_tdt(); // // 2) on appel la fonction, qui ne doit dépendre que de M en var locales // Tableau tab(1); tab(1)=M; // Tableau tab_val = pt_fonct->Val_FnD_Evoluee(NULL,&tab,NULL); // deux cas: soit une fonction scalaire soit dimf composantes if (tab_val.Taille() == 1) {force_t *= tab_val(1);} else if (tab_val.Taille() == dimf) {switch (dimf) {case 3:force_t(3) *= tab_val(3); case 2:force_t(2) *= tab_val(2); case 1:force_t(1) *= tab_val(1); break; default: cout << "\n *** erreur ElemMeca::SM_charge_line_E(.. "; Sortie(1); }; } else {cout << "\n *** erreur dans l'utilisation d'une fct nD pour un chargement" << " lineique suiveuse: la dimension de la fct nD "<& taphi,int nbne ,const Vecteur& poids,const Coordonnee& forc,Fonction_nD* pt_fonct ,const ParaAlgoControle & ,bool atdt) { // *** dans l'ensemble du sp on utilise des vecteurs et on gére directement la variance // *** sinon c'est intractable et long // définition du vecteur de retour Vecteur& SM = *((*res_extS)(nSurf)); double module_f = forc.Norme(); // dans le cas ou la force est de module nul, on retourne sans calcul if (module_f < ConstMath::trespetit) return SM; #ifdef MISE_AU_POINT // test : a priori non valide pour les éléments axi et pour un pb autre que 3D if (( ParaGlob::Dimension() != 3) || ((ParaGlob::Dimension() == 3)&&(ParaGlob::AxiSymetrie()))) { cout << "\n erreur, ce type de chargement n'est valide que pour la dimension 3 !! et non axi" << " ElemMeca::SM_charge_line_Suiv_E ( ..." << " \n dim = " << ParaGlob::Dimension(); Sortie(1); }; #endif int ni; // compteur globale de point d'integration Deformation & defS = *defSurf(nSurf); // pour simplifier l'écriture // éventuellement dimensionnement de la sauvegarde if (lesChargeExtSurEle == NULL) lesChargeExtSurEle = new LesChargeExtSurElement; if (lesChargeExtSurEle->LesPressDir() == NULL) {if(ParaGlob::AxiSymetrie()) {lesChargeExtSurEle->LesPressDir_Change_taille(ElementGeometrique().NbSe());} else {lesChargeExtSurEle->LesPressDir_Change_taille(ElementGeometrique().NbFe());} }; Tableau & tab_Press= (*lesChargeExtSurEle->LesPressDir())(nSurf); // pour simplifier if (tab_Press.Taille() != defS.Phi1_Taille()) tab_Press.Change_taille(defS.Phi1_Taille(),Coordonnee(ParaGlob::Dimension())); bool premier_calcul=true; // contrairement à la déformation, pas de sauvegarde // donc il faut calculer tous les éléments de la métrique for (defS.PremierPtInteg(), ni = 1;defS.DernierPtInteg();defS.NevezPtInteg(),ni++) { // calcul des éléments de la métrique, entre autre le jacobien, on utilise le même calcul // que pour un calcul primaire en explicit mais pour un calcul autre que mécanique Met_abstraite::Expli ex; if (atdt) ex = (defS.Cal_explicit_tdt(premier_calcul)).Tdt_dans_t(); else ex = defS.Cal_explicit_t(premier_calcul); const Met_abstraite::Impli* ex_impli = NULL; const Met_abstraite::Expli_t_tdt* ex_expli_tdt = NULL; const Met_abstraite::Expli* ex_expli = &ex; // détermination de la normale à la surface // la normale vaut le produit vectoriel des 2 premiers vecteurs Coordonnee normale_0 = Util::ProdVec_coorBN( (*ex.giB_0)(1), (*ex.giB_0)(2)); // on passe en BN pour dire que c'est du B en normal const Coordonnee& giBN_t1 = (*ex.giB_t).Coordo(1); const Coordonnee& giBN_t2 = (*ex.giB_t).Coordo(2); const Coordonnee& giB_01 = (*ex.giB_0).Coordo(1); const Coordonnee& giB_02 = (*ex.giB_0).Coordo(2); Coordonnee normale_t = Util::ProdVec_coor( giBN_t1, giBN_t2); // calcul de la normale normée normale_0.Normer(); normale_t.Normer(); // calcul des composantes de direction de la force dans le repère local initial Coordonnee dir_forceH_0(3); // ici le fait d'utiliser la méthode .Vect() supprime la variance, mais justement // on ne veut pas de vérification de variance qui est ici incohérente dir_forceH_0(1) = giB_01 * forc; dir_forceH_0(2) = giB_02 * forc; dir_forceH_0(3) = normale_0 * forc; // calcul de la direction finale Coordonnee dir_force_t = dir_forceH_0(1) * giBN_t1 + dir_forceH_0(2) * giBN_t2 + dir_forceH_0(3) * normale_t; dir_force_t.Normer(); // calcul de la force finale Coordonnee force_t = (forc.Norme()) * dir_force_t; // calcul du second membre int ix=1; int dimf = 3; // ne fonctionne qu'en dim 3 // sauf pour les éléments axisymétriques pour lesquelles on ne considère que les deux premières composantes if(ParaGlob::AxiSymetrie()) // cas d'un chargement axisymétrique, dans ce cas on ne prend en compte que les // dimf-1 coordonnées donc on décrémente dimf--; // prise en compte d'une dépendance à une fonction nD if (pt_fonct != NULL) { // ici on utilise les variables connues aux noeuds, ou calculées à partir de // on commence par récupérer les conteneurs des grandeurs à fournir List_io & li_enu_scal = pt_fonct->Li_enu_etendu_scalaire(); List_io & li_quelc = pt_fonct->Li_equi_Quel_evolue(); bool absolue = true; // on se place systématiquement en absolu // on va utiliser la méhode Valeur_multi_interpoler_ou_calculer // pour les grandeurs strictement scalaire Tableau val_ddl_enum(Valeur_multi_interpoler_ou_calculer (absolue,TEMPS_tdt,li_enu_scal,defS,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_tdt,li_quelc,defS,ex_impli,ex_expli_tdt,ex_expli); // calcul de la valeur et retour dans tab_ret Tableau & tab_val = pt_fonct->Valeur_FnD_Evoluee(&val_ddl_enum,&li_enu_scal,&li_quelc,NULL,NULL); // {if (pt_fonct->Depend_M()) // {// 1) on récupère la position dans I_a du point d'intégration // const Coordonnee & M = defS.Position_tdt(); // // 2) on appel la fonction, qui ne doit dépendre que de M en var locales // Tableau tab(1); tab(1)=M; // Tableau tab_val = pt_fonct->Val_FnD_Evoluee(NULL,&tab,NULL); // deux cas: soit une fonction scalaire soit dimf composantes if (tab_val.Taille() == 1) {force_t *= tab_val(1);} else if (tab_val.Taille() == dimf) {switch (dimf) {case 3:force_t(3) *= tab_val(3); case 2:force_t(2) *= tab_val(2); case 1:force_t(1) *= tab_val(1); break; default: cout << "\n *** erreur ElemMeca::SM_charge_surf_Suiv_E(.. "; Sortie(1); }; } else {cout << "\n *** erreur dans l'utilisation d'une fct nD pour un chargement" << " surfacique suiveuse: la dimension de la fct nD "< implicite, // pa: permet de déterminer si oui ou non on calcul la contribution à la raideur // retourne le second membre et la matrice de raideur correspondant Element::ResRaid ElemMeca::SMR_charge_surf_Suiv_I (DdlElement & ddls,int nSurf ,const Tableau & taphi,int nbne ,const Vecteur& poids,const Coordonnee& forc,Fonction_nD* pt_fonct ,const ParaAlgoControle & pa) { // *** dans l'ensemble du sp on utilise des vecteurs et on gére directement la variance // *** sinon c'est intractable et long double module_f = forc.Norme(); // dans le cas ou la force est de module nul, on retourne sans calcul if (module_f < ConstMath::trespetit) { Element::ResRaid el; el.res = (*res_extS)(nSurf); el.raid = (*raid_extS)(nSurf); return el; } // controle bool avec_raid = pa.Var_charge_externe(); // // dans le cas où la variation sur la raideur est demandé on s'assure que la variation // // du jacobien est bien effective sinon on l'impose // ParaAlgoControle pa_nevez(pa); // if (!pa_nevez.Var_jacobien()) pa_nevez.Modif_Var_jacobien(true); int ni; // compteur globale de point d'integration Deformation & defS = *defSurf(nSurf); // pour simplifier l'écriture int nbddl = ddls.NbDdl(); Vecteur& SM = (*((*res_extS)(nSurf))); // " " " Mat_pleine & KM = (*((*raid_extS)(nSurf))); // " " " // éventuellement dimensionnement de la sauvegarde if (lesChargeExtSurEle == NULL) lesChargeExtSurEle = new LesChargeExtSurElement; if (lesChargeExtSurEle->LesPressDir() == NULL) {if(ParaGlob::AxiSymetrie()) {lesChargeExtSurEle->LesPressDir_Change_taille(ElementGeometrique().NbSe());} else {lesChargeExtSurEle->LesPressDir_Change_taille(ElementGeometrique().NbFe());} }; Tableau & tab_Press= (*lesChargeExtSurEle->LesPressDir())(nSurf); // pour simplifier if (tab_Press.Taille() != defS.Phi1_Taille()) tab_Press.Change_taille(defS.Phi1_Taille(),Coordonnee(ParaGlob::Dimension())); bool premier_calcul=true; // contrairement à la déformation, pas de sauvegarde // donc il faut calculer tous les éléments de la métrique for (defS.PremierPtInteg(), ni = 1;defS.DernierPtInteg();defS.NevezPtInteg(),ni++) { // calcul des éléments de la métrique, entre autre le jacobien, on utilise le même calcul // que pour un calcul primaire en implicit const Met_abstraite::Impli& ex = defS.Cal_implicit(premier_calcul); const Met_abstraite::Impli* ex_impli = &ex; const Met_abstraite::Expli_t_tdt* ex_expli_tdt = NULL; const Met_abstraite::Expli* ex_expli = NULL; #ifdef MISE_AU_POINT // test : a priori non valide pour les éléments axi et pour un pb autre que 3D if (( ParaGlob::Dimension() != 3) || ((ParaGlob::Dimension() == 3)&&(ParaGlob::AxiSymetrie()))) { cout << "\n erreur, ce type de chargement n'est valide pour pour la dimension 3 !! et non axi" << " ElemMeca::SM_charge_line_Suiv_E ( ..." << " \n dim = " << ParaGlob::Dimension(); Sortie(1); }; // test pour savoir si l'on a réellement affaire à une surface if (ex.giB_t->NbVecteur() != 2) { cout << "\n erreur, pb de nombre de vecteurs pour la surface !!" << " ElemMeca::SM_charge_surf_Suiv_I (.... " << ex.giB_t->NbVecteur() << " dim = " << ParaGlob::Dimension(); Sortie(1); } #endif // détermination de la normale à la surface // la normale vaut le produit vectoriel des 2 premiers vecteurs Coordonnee normale_0 = Util::ProdVec_coorBN( (*ex.giB_0)(1), (*ex.giB_0)(2)); const Coordonnee& giB_tdt1 = (*ex.giB_tdt).Coordo(1); const Coordonnee& giB_tdt2 = (*ex.giB_tdt).Coordo(2); const Coordonnee& giB_01 = (*ex.giB_0).Coordo(1); const Coordonnee& giB_02 = (*ex.giB_0).Coordo(2); Coordonnee normale_t = Util::ProdVec_coor( giB_tdt1, giB_tdt2); // calcul des normales normées normale_0.Normer(); double norme_normarle_t = normale_t.Norme();normale_t /= norme_normarle_t; // calcul des composantes de direction de la force dans le repère local initial Coordonnee dir_forceH_0(3); // on ne veut pas de vérification de variance dir_forceH_0(1) = giB_01 * forc; dir_forceH_0(2) = giB_02 * forc; dir_forceH_0(3) = normale_0 * forc; // calcul de la direction finale Coordonnee dir_f_t = dir_forceH_0(1) * giB_tdt1 + dir_forceH_0(2) * giB_tdt2 + dir_forceH_0(3) * normale_t; Coordonnee dir_f_t_normer = dir_f_t/(dir_f_t.Norme()); // calcul de la force finale Coordonnee force_t = module_f * dir_f_t_normer; // debug //cout << "\n debug Element::ResRaid ElemMeca::SMR_charge_surf_Suiv_I " // << "\n force= "<< force_t << endl; //fin debug // calcul du résidu et éventuellement de la raideur int ix=1; int dimf = forc.Dimension(); // normalement ne fonctionne qu'en 3D // sauf pour les éléments axisymétriques pour lesquelles on ne considère que les deux premières composantes if(ParaGlob::AxiSymetrie()) // cas d'un chargement axisymétrique, dans ce cas on ne prend en compte que les // dimf-1 coordonnées donc on décrémente dimf--; // prise en compte d'une dépendance à une fonction nD // on ne tient pas compte de la variation du point dans la fct nD if (pt_fonct != NULL) { // ici on utilise les variables connues aux noeuds, ou calculées à partir de // on commence par récupérer les conteneurs des grandeurs à fournir List_io & li_enu_scal = pt_fonct->Li_enu_etendu_scalaire(); List_io & li_quelc = pt_fonct->Li_equi_Quel_evolue(); bool absolue = true; // on se place systématiquement en absolu // on va utiliser la méhode Valeur_multi_interpoler_ou_calculer // pour les grandeurs strictement scalaire Tableau val_ddl_enum(Valeur_multi_interpoler_ou_calculer (absolue,TEMPS_tdt,li_enu_scal,defS,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_tdt,li_quelc,defS,ex_impli,ex_expli_tdt,ex_expli); // calcul de la valeur et retour dans tab_ret Tableau & tab_val = pt_fonct->Valeur_FnD_Evoluee(&val_ddl_enum,&li_enu_scal,&li_quelc,NULL,NULL); // {if (pt_fonct->Depend_M()) // {// 1) on récupère la position dans I_a du point d'intégration // const Coordonnee & M = defS.Position_tdt(); // // 2) on appel la fonction, qui ne doit dépendre que de M en var locales // Tableau tab(1); tab(1)=M; // Tableau tab_val = pt_fonct->Val_FnD_Evoluee(NULL,&tab,NULL); // deux cas: soit une fonction scalaire soit dimf composantes if (tab_val.Taille() == 1) {force_t *= tab_val(1);} else if (tab_val.Taille() == dimf) {switch (dimf) {case 3:force_t(3) *= tab_val(3); case 2:force_t(2) *= tab_val(2); case 1:force_t(1) *= tab_val(1); break; default: cout << "\n *** erreur ElemMeca::SM_charge_surf_Suiv_E(.. "; Sortie(1); }; } else {cout << "\n *** erreur dans l'utilisation d'une fct nD pour un chargement" << " surfacique suiveuse: la dimension de la fct nD "<& taphi,int nbne ,const Vecteur& poids,const Coordonnee& force,Fonction_nD* pt_fonct ,const ParaAlgoControle & ,bool sur_volume_finale_,bool atdt ) { // #ifdef MISE_AU_POINT // axisymétrie: a priori ce n'est pas nécessaire, on met une erreur if(ParaGlob::AxiSymetrie()) { cout << "\n erreur, les charges volumique ne sont utilisable avec les elements axisymetriques" << "\n utilisez à la place les charges surfaciques !! " << " ElemMeca::SM_charge_vol_E ( ..."; Sortie(1); }; // #endif // définition du vecteur de retour Vecteur& SM = * residu; // éventuellement dimensionnement de la sauvegarde if (lesChargeExtSurEle == NULL) lesChargeExtSurEle = new LesChargeExtSurElement; if (lesChargeExtSurEle->Force_volume() == NULL) lesChargeExtSurEle->Force_volume_Change_taille(def->Phi1_Taille()); Tableau & tab_F_vol= (*lesChargeExtSurEle->Force_volume()); // pour simplifier if (tab_F_vol.Taille() != def->Phi1_Taille()) tab_F_vol.Change_taille(def->Phi1_Taille(),Coordonnee(ParaGlob::Dimension())); int ni; // compteur globale de point d'integration bool premier_calcul=true; // contrairement à la déformation, pas de sauvegarde // donc il faut calculer tous les éléments de la métrique for (def->PremierPtInteg(), ni = 1;def->DernierPtInteg();def->NevezPtInteg(),ni++) { // calcul des éléments de la métrique, entre autre le jacobien, on utilise le même calcul // que pour un calcul primaire en explicit mais pour un calcul autre que mécanique Met_abstraite::Expli ex; if (atdt) ex = (def->Cal_explicit_tdt(premier_calcul)).Tdt_dans_t(); else ex = def->Cal_explicit_t(premier_calcul); // choix entre volume final ou initial double jacobien = (*ex.jacobien_t); if (!sur_volume_finale_) jacobien = (*ex.jacobien_0); int ix=1; int dimf = force.Dimension(); if(ParaGlob::AxiSymetrie()) // cas d'un chargement axisymétrique, dans ce cas on ne prend en compte que les // dimf-1 coordonnées donc on décrémente dimf--; // prise en compte d'une dépendance à une fonction nD Coordonnee force_reelle(force); // init par défaut if (pt_fonct != NULL) { // ici on peut utiliser toutes les variables connues de l'élément // on commence par récupérer les conteneurs des grandeurs à fournir List_io & li_enu_scal = pt_fonct->Li_enu_etendu_scalaire(); List_io & li_quelc = pt_fonct->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,ni,-1)); // on utilise la méthode des grandeurs évoluées pour les Coordonnees et Tenseur Valeurs_Tensorielles(absolue, TEMPS_tdt,li_quelc,ni,-1); // calcul de la valeur et retour dans tab_ret Tableau & tab_val = pt_fonct->Valeur_FnD_Evoluee(&val_ddl_enum,&li_enu_scal,&li_quelc,NULL,NULL); // deux cas: soit une fonction scalaire soit dimf composantes if (tab_val.Taille() == 1) {force_reelle *= tab_val(1);} else if (tab_val.Taille() == dimf) {switch (dimf) {case 3:force_reelle(3) *= tab_val(3); case 2:force_reelle(2) *= tab_val(2); case 1:force_reelle(1) *= tab_val(1); break; default: cout << "\n *** erreur ElemMeca::SM_charge_vol_E(.. "; Sortie(1); }; } else {cout << "\n *** erreur dans l'utilisation d'une fct nD pour un chargement" << " volumique: la dimension de la fct nD "<Depend_M()) // {// 1) on récupère la position dans I_a du point d'intégration // const Coordonnee * Mpt = NULL; // init // // on regarde s'il s'agit du volume final ou initial // if (sur_volume_finale_) // { Mpt = &(def->Position_0()); } // else // { Mpt = &(def->Position_tdt());}; // const Coordonnee & M = *Mpt; // // 2) on appel la fonction, qui ne doit dépendre que de M en var locales // Tableau tab(1); tab(1)=M; // Tableau tab_val = pt_fonct->Val_FnD_Evoluee(NULL,&tab,NULL); // // deux cas: soit une fonction scalaire soit dimf composantes // if (tab_val.Taille() == 1) // {force_reelle *= tab_val(1);} // else if (tab_val.Taille() == dimf) // {switch (dimf) // {case 3:force_reelle(3) *= tab_val(3); // case 2:force_reelle(2) *= tab_val(2); // case 1:force_reelle(1) *= tab_val(1); // break; // default: cout << "\n *** erreur ElemMeca::SM_charge_vol_E(.. "; // Sortie(1); // }; // } // else // {cout << "\n *** erreur dans l'utilisation d'une fct nD pour un chargement" // << " volumique: la dimension de la fct nD "< implicite, // pa: permet de déterminer si oui ou non on calcul la contribution à la raideur void ElemMeca::SMR_charge_vol_I(DdlElement & tab_ddl ,const Tableau & taphi,int nbne ,const Vecteur& poids,const Coordonnee& force,Fonction_nD* pt_fonct ,const ParaAlgoControle & pa,bool sur_volume_finale_) { // #ifdef MISE_AU_POINT // axisymétrie: a priori ce n'est pas nécessaire, on met une erreur if(ParaGlob::AxiSymetrie()) { cout << "\n erreur, les charges volumique ne sont pas utilisable avec les elements axisymetriques" << "\n utilisez à la place les charges surfaciques !! " << " ElemMeca::SMR_charge_vol_I ( ..."; Sortie(1); }; // #endif int ni; // compteur globale de point d'integration int nbddl = tab_ddl.NbDdl(); Vecteur& SM = *residu; Mat_pleine & KM = *raideur; // éventuellement dimensionnement de la sauvegarde if (lesChargeExtSurEle == NULL) lesChargeExtSurEle = new LesChargeExtSurElement; if (lesChargeExtSurEle->Force_volume() == NULL) lesChargeExtSurEle->Force_volume_Change_taille(def->Phi1_Taille()); Tableau & tab_F_vol= (*lesChargeExtSurEle->Force_volume()); // pour simplifier if (tab_F_vol.Taille() != def->Phi1_Taille()) tab_F_vol.Change_taille(def->Phi1_Taille(),Coordonnee(ParaGlob::Dimension())); // controle bool avec_raid = pa.Var_charge_externe(); // // dans le cas où la variation sur la raideur est demandé on s'assure que la variation // // du jacobien est bien effective sinon on l'impose // ParaAlgoControle pa_nevez(pa); // if (!pa_nevez.Var_jacobien()) pa_nevez.Modif_Var_jacobien(true); bool premier_calcul=true; // contrairement à la déformation, pas de sauvegarde // donc il faut calculer tous les éléments de la métrique for (def->PremierPtInteg(), ni = 1;def->DernierPtInteg();def->NevezPtInteg(),ni++) { // calcul des éléments de la métrique, entre autre le jacobien, on utilise le même calcul // que pour un calcul primaire en implicit const Met_abstraite::Impli& ex = def->Cal_implicit(premier_calcul); int ix=1; int dimf = force.Dimension(); if(ParaGlob::AxiSymetrie()) // cas d'un chargement axisymétrique, dans ce cas on ne prend en compte que les // dimf-1 coordonnées donc on décrémente dimf--; // prise en compte d'une dépendance à une fonction nD // on ne tient pas compte de la variation du point dans la fct nD Coordonnee force_reelle(force); // init par défaut if (pt_fonct != NULL) { // ici on peut utiliser toutes les variables connues de l'élément // on commence par récupérer les conteneurs des grandeurs à fournir List_io & li_enu_scal = pt_fonct->Li_enu_etendu_scalaire(); List_io & li_quelc = pt_fonct->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,ni,-1)); // on utilise la méthode des grandeurs évoluées pour les Coordonnees et Tenseur Valeurs_Tensorielles(absolue, TEMPS_tdt,li_quelc,ni,-1); // calcul de la valeur et retour dans tab_ret Tableau & tab_val = pt_fonct->Valeur_FnD_Evoluee(&val_ddl_enum,&li_enu_scal,&li_quelc,NULL,NULL); // deux cas: soit une fonction scalaire soit dimf composantes if (tab_val.Taille() == 1) {force_reelle *= tab_val(1);} else if (tab_val.Taille() == dimf) {switch (dimf) {case 3:force_reelle(3) *= tab_val(3); case 2:force_reelle(2) *= tab_val(2); case 1:force_reelle(1) *= tab_val(1); break; default: cout << "\n *** erreur ElemMeca::SM_charge_vol_E(.. "; Sortie(1); }; } else {cout << "\n *** erreur dans l'utilisation d'une fct nD pour un chargement" << " volumique: la dimension de la fct nD "<Depend_M()) // {// 1) on récupère la position dans I_a du point d'intégration // const Coordonnee * Mpt = NULL; // init // // on regarde s'il s'agit du volume final ou initial // if (sur_volume_finale_) // { Mpt = &(def->Position_0()); } // else // { Mpt = &(def->Position_tdt());}; // const Coordonnee & M = *Mpt; // // 2) on appel la fonction, qui ne doit dépendre que de M en var locales // Tableau tab(1); tab(1)=M; // Tableau tab_val = pt_fonct->Val_FnD_Evoluee(NULL,&tab,NULL); // // deux cas: soit une fonction scalaire soit dimf composantes // if (tab_val.Taille() == 1) // {force_reelle *= tab_val(1);} // else if (tab_val.Taille() == dimf) // {switch (dimf) // {case 3:force_reelle(3) *= tab_val(3); // case 2:force_reelle(2) *= tab_val(2); // case 1:force_reelle(1) *= tab_val(1); // break; // default: cout << "\n *** erreur ElemMeca::SM_charge_vol_E(.. "; // Sortie(1); // }; // } // else // {cout << "\n *** erreur dans l'utilisation d'une fct nD pour un chargement" // << " volumique: la dimension de la fct nD "<& taphi,int nbne ,const Vecteur& poids ,const Coordonnee& dir_normal_liquide,const double& poidvol ,const Coordonnee& M_liquide,bool sans_limitation ,const ParaAlgoControle & ,bool atdt) { // #ifdef MISE_AU_POINT // // axisymétrie: pour l'instant non testé a priori avec les forces hydro // if(ParaGlob::AxiSymetrie()) // { cout << "\n erreur, les charges hydro ne sont pas testees avec les elements axisymetriques" // << " ElemMeca::SM_charge_hydro_E ( ..."; // Sortie(1); // }; // #endif // *** dans l'ensemble du sp on utilise des vecteurs et on gére directement la variance // *** sinon c'est intractable et long // définition du vecteur de retour Deformation* definter=NULL; // variable de travail transitoire Vecteur* SM_P = NULL; if (!(ParaGlob::AxiSymetrie())) { definter = defSurf(nSurf); // le cas normal est non axisymétrique SM_P = ((*res_extS)(nSurf)); } else { definter = defArete(nSurf); // en axisymétrie, c'est une def d'arête SM_P = ((*res_extA)(nSurf)); }; Deformation & defS = *definter; // pour simplifier l'écriture Vecteur& SM = *SM_P; // " " " // dans le cas ou le poid volumique est nul, on retourne sans calcul if (Dabs(poidvol) < ConstMath::trespetit) return SM; int ni; // compteur globale de point d'integration // éventuellement dimensionnement de la sauvegarde if (lesChargeExtSurEle == NULL) lesChargeExtSurEle = new LesChargeExtSurElement; if (lesChargeExtSurEle->LesPressionsExternes() == NULL) {if(ParaGlob::AxiSymetrie()) {lesChargeExtSurEle->LesPressionsExternes_Change_taille(ElementGeometrique().NbSe());} else {lesChargeExtSurEle->LesPressionsExternes_Change_taille(ElementGeometrique().NbFe());} }; Tableau & tab_Press= (*lesChargeExtSurEle->LesPressionsExternes())(nSurf); // pour simplifier if (tab_Press.Taille() != defS.Phi1_Taille()) tab_Press.Change_taille(defS.Phi1_Taille()); bool premier_calcul=true; // contrairement à la déformation, pas de sauvegarde // donc il faut calculer tous les éléments de la métrique for (defS.PremierPtInteg(), ni = 1;defS.DernierPtInteg();defS.NevezPtInteg(),ni++) { // calcul de la pression au niveau de la position du point d'intégration // 1) on récupère la position dans I_a du point d'intégration const Coordonnee & M = defS.Position_tdt(); // 2) calcul de la distance à la surface libre Coordonnee MMp= M_liquide - M; double dis = dir_normal_liquide * MMp; // 3) calcul de la pression effective uniquement si le point est dans l'eau // en fait si le point est hors de l'eau il n'y a pas de pression hydrostatique // sauf si sans_limitation est true if ((dis > 0.) || sans_limitation) { double pression = -dis * poidvol; // sauvegarde de la pression appliquée tab_Press(ni).press += pression; // -- calcul des éléments de la métrique, entre autre le jacobien, on utilise le même calcul // que pour un calcul primaire en explicit mais pour un calcul autre que mécanique Met_abstraite::Expli ex; if (atdt) ex = (defS.Cal_explicit_tdt(premier_calcul)).Tdt_dans_t(); else ex = defS.Cal_explicit_t(premier_calcul); // détermination de la normale à la surface #ifdef MISE_AU_POINT // test pour savoir si l'on a réellement affaire à une surface if ((ex.giB_t->NbVecteur() != 2) || ( ParaGlob::Dimension() != 3)) { cout << "\n erreur, il doit y avoir deux vecteurs pour la surface de dimension 3" << " ElemMeca::SM_charge_hydro_E (DdlElement & ...nbvec= " << ex.giB_t->NbVecteur() << " dim = " << ParaGlob::Dimension(); Sortie(1); } #endif // la normale vaut le produit vectoriel des 2 premiers vecteurs CoordonneeB normale = Util::ProdVec_coorB( (*ex.giB_t)(1), (*ex.giB_t)(2)); // calcul de la normale normée et pondérée de la pression normale.Normer();normale *= -pression; tab_Press(ni).P += normale.Coor_const(); int ix=1; int dimf = 3; // ne fonctionne qu'en dim 3 if(ParaGlob::AxiSymetrie()) // cas d'un chargement axisymétrique, dans ce cas on ne prend en compte que les // dimf-1 coordonnées donc on décrémente dimf--; for (int ne =1; ne<= nbne; ne++) for (int i=1;i<= dimf;i++,ix++) SM(ix) += taphi(ni)(ne)* normale(i) * (poids(ni) * (*ex.jacobien_t)); }// fin test : point dans le liquide ou pas } // fin boucle sur les points d'intégrations // retour du second membre return SM; }; // idem SMR_charge_hydro_E mais // -> implicite, // pa: permet de déterminer si oui ou non on calcul la contribution à la raideur // retourne le second membre et la matrice de raideur correspondant Element::ResRaid ElemMeca::SMR_charge_hydro_I (DdlElement & ddls,int nSurf ,const Tableau & taphi,int nbne ,const Vecteur& poids ,const Coordonnee& dir_normal_liquide,const double& poidvol ,const Coordonnee& M_liquide,bool sans_limitation ,const ParaAlgoControle & pa) { // #ifdef MISE_AU_POINT // // axisymétrie: pour l'instant non testé a priori avec les forces hydro // if(ParaGlob::AxiSymetrie()) // { cout << "\n erreur, les charges hydro ne sont pas testees avec les elements axisymetriques" // << " ElemMeca::SM_charge_hydro_I ( ..."; // Sortie(1); // }; // #endif Deformation* definter=NULL; // variable de travail transitoire Vecteur* SM_P = NULL; Mat_pleine* KM_P = NULL; if (!(ParaGlob::AxiSymetrie())) { definter = defSurf(nSurf); // le cas normal est non axisymétrique SM_P = ((*res_extS)(nSurf)); KM_P = ((*raid_extS)(nSurf)); } else { definter = defArete(nSurf); // en axisymétrie, c'est une def d'arête SM_P = ((*res_extA)(nSurf)); KM_P = ((*raid_extA)(nSurf)); }; Deformation & defS = *definter; // pour simplifier l'écriture Vecteur& SM = *SM_P; // " " " Mat_pleine & KM = *KM_P; // " " " // *** dans l'ensemble du sp on utilise des vecteurs et on gére directement la variance // *** sinon c'est intractable et long // dans le cas ou le poid volumique est nul, on retourne sans calcul if (Dabs(poidvol) < ConstMath::trespetit) { Element::ResRaid el; el.res = SM_P; el.raid = KM_P; return el; } // controle bool avec_raid = pa.Var_charge_externe(); // // dans le cas où la variation sur la raideur est demandé on s'assure que la variation // // du jacobien est bien effective sinon on l'impose // ParaAlgoControle pa_nevez(pa); // if (!pa_nevez.Var_jacobien()) pa_nevez.Modif_Var_jacobien(true); int ni; // compteur globale de point d'integration // éventuellement dimensionnement de la sauvegarde if (lesChargeExtSurEle == NULL) lesChargeExtSurEle = new LesChargeExtSurElement; if (lesChargeExtSurEle->LesPressionsExternes() == NULL) {if(ParaGlob::AxiSymetrie()) {lesChargeExtSurEle->LesPressionsExternes_Change_taille(ElementGeometrique().NbSe());} else {lesChargeExtSurEle->LesPressionsExternes_Change_taille(ElementGeometrique().NbFe());} }; Tableau & tab_Press= (*lesChargeExtSurEle->LesPressionsExternes())(nSurf); // pour simplifier if (tab_Press.Taille() != defS.Phi1_Taille()) tab_Press.Change_taille(defS.Phi1_Taille()); int nbddl = ddls.NbDdl(); bool premier_calcul=true; // contrairement à la déformation, pas de sauvegarde // donc il faut calculer tous les éléments de la métrique for (defS.PremierPtInteg(), ni = 1;defS.DernierPtInteg();defS.NevezPtInteg(),ni++) { // calcul de la pression au niveau de la position du point d'intégration // 1) on récupère la position dans I_a du point d'intégration const Coordonnee & M = defS.Position_tdt(); // 2) calcul de la distance à la surface libre Coordonnee MMp= M_liquide - M; double dis = dir_normal_liquide * MMp; // 3) calcul de la pression effective uniquement si le point est dans l'eau // en fait si le point est hors de l'eau il n'y a pas de pression hydrostatique // sauf si sans_limitation est true if ((dis > 0.) || sans_limitation) { double pression = -dis * poidvol; // sauvegarde de la pression appliquée tab_Press(ni).press += pression; // dans le cas avec raideur on calcul la variation de la pression const Tableau * d_M_pointe = NULL; if (avec_raid) d_M_pointe=&(defS.Der_Posi_tdt()); // --- calcul des éléments de la métrique, entre autre le jacobien, on utilise le même calcul // que pour un calcul primaire en implicit const Met_abstraite::Impli& ex = defS.Cal_implicit(premier_calcul); #ifdef MISE_AU_POINT // test pour savoir si l'on a réellement affaire à une surface if ((ex.giB_t->NbVecteur() != 2) || ( ParaGlob::Dimension() != 3)) { cout << "\n erreur, il doit y avoir deux vecteurs pour la surface de dimension 3" << " ElemMeca::SMR_charge_hydro_I (.... " << ex.giB_t->NbVecteur() << " dim = " << ParaGlob::Dimension(); Sortie(1); } #endif // la normale vaut le produit vectoriel des 2 premiers vecteurs CoordonneeB normale = Util::ProdVec_coorB( (*ex.giB_tdt)(1), (*ex.giB_tdt)(2)); // calcul de la variation de la normale // 1) variation du produit vectoriel Tableau D_pasnormale = Util::VarProdVect_coorB( (*ex.giB_tdt)(1),(*ex.giB_tdt)(2),(*ex.d_giB_tdt)); // 2) de la normale Tableau D_normale = Util::VarUnVect_coorB(normale,D_pasnormale,normale.Norme()); // calcul de la normale normée et pondérée de la pression normale.Normer();normale *= -pression; tab_Press(ni).P += normale.Coor_const(); // également pondération de la variation de la if (avec_raid) { for (int ihi =1;ihi<= nbddl;ihi++) { double d_pression = poidvol * (dir_normal_liquide * (*d_M_pointe)(ihi)); // le - devant dis disparait avec le - devant M D_normale(ihi) = pression * D_normale(ihi) + d_pression * normale ; } } int ix=1; int dimf = 3; // ne fonctionne qu'en dim 3 if(ParaGlob::AxiSymetrie()) // cas d'un chargement axisymétrique, dans ce cas on ne prend en compte que les // dimf-1 coordonnées donc on décrémente dimf--; for (int ne =1; ne<= nbne; ne++) for (int i=1;i<= dimf;i++,ix++) { SM(ix) += taphi(ni)(ne)* normale(i) * (poids(ni) * (*ex.jacobien_tdt)); // dans le cas avec_raideur on calcul la contribution à la raideur if (avec_raid) for (int j =1; j<= nbddl; j++) KM(ix,j) -= taphi(ni)(ne)* normale(i) * (poids(ni) * (*ex.d_jacobien_tdt)(j)) + taphi(ni)(ne)* D_normale(j)(i) * (poids(ni) * (*ex.jacobien_tdt)) ; } }// fin test : point dans le liquide ou pas } // fin boucle sur les points d'intégrations // liberation des tenseurs intermediaires LibereTenseur(); Element::ResRaid el; el.res = SM_P; el.raid = KM_P; return el; };