// This file is part of the Herezh++ application. // // The finite element software Herezh++ is dedicated to the field // of mechanics for large transformations of solid structures. // It is developed by Gérard Rio (APP: IDDN.FR.010.0106078.000.R.P.2006.035.20600) // INSTITUT DE RECHERCHE DUPUY DE LÔME (IRDL) . // // Herezh++ is distributed under GPL 3 license ou ultérieure. // // Copyright (C) 1997-2022 Université Bretagne Sud (France) // AUTHOR : Gérard Rio // E-MAIL : gerardrio56@free.fr // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // See the GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . // // For more information, please consult: . //#include "Debug.h" #include "ElemMeca.h" #include #include "ConstMath.h" #include "Util.h" #include "CharUtil.h" #include "Coordonnee2.h" #include "Coordonnee3.h" #include "TypeConsTens.h" #include "TypeQuelconqueParticulier.h" // retourne la liste de tous les types de ddl interne actuellement utilisés // par l'élément (actif ou non), sont exclu de cette liste les ddl des noeuds // reliés à l'élément (ddl implique grandeur uniquement scalaire !) // par contre sont inclus les ddl venant de l'élément, qui sont représenté directement aux noeuds // absolue: indique si oui ou non on sort les tenseurs dans la base absolue ou une base particulière List_io ElemMeca::Les_type_de_ddl_internes(bool absolue) const { List_io ret; switch (this->Dim_sig_eps()) { case 1 : {ret.push_back(SIG11); ret.push_back(EPS11);ret.push_back(DEPS11); ret.push_back(string("Green-Lagrange11"));ret.push_back(string("Almansi11"));ret.push_back(string("logarithmique11")); ret.push_back(string("Cauchy_local11")); ret.push_back(string("Almansi_local11")); ret.push_back(string("Def_principaleI"));ret.push_back(string("Sigma_principaleI")); ret.push_back(string("Vit_principaleI"));ret.push_back(string("Delta_def11")); if (dilatation) {ret.push_back(string("Almansi_totale11"));ret.push_back(string("Green_Lagrange_totale11")); ret.push_back(string("logarithmique_totale11"));}; break; } case 2 : {ret.push_back(SIG11); ret.push_back(SIG22); ret.push_back(SIG12); ret.push_back(EPS11); ret.push_back(EPS22); ret.push_back(EPS12); ret.push_back(DEPS11);ret.push_back(DEPS22);ret.push_back(DEPS12); ret.push_back(string("Green-Lagrange11")); ret.push_back(string("Green-Lagrange22")); ret.push_back(string("Green-Lagrange12")); ret.push_back(string("Almansi11")); ret.push_back(string("Almansi22")); ret.push_back(string("Almansi12")); ret.push_back(string("logarithmique11")); ret.push_back(string("logarithmique22")); ret.push_back(string("logarithmique12")); ret.push_back(string("Cauchy_local11")); ret.push_back(string("Cauchy_local22")); ret.push_back(string("Cauchy_local12")); ret.push_back(string("Almansi_local11")); ret.push_back(string("Almansi_local22")); ret.push_back(string("Almansi_local12")); ret.push_back(string("Def_principaleI"));ret.push_back(string("Def_principaleII")); ret.push_back(string("Sigma_principaleI"));ret.push_back(string("Sigma_principaleII")); ret.push_back(string("Vit_principaleI"));ret.push_back(string("Vit_principaleII")); ret.push_back(string("Delta_def11"));ret.push_back(string("Delta_def22"));ret.push_back(string("Delta_def12")); if (dilatation) {ret.push_back(string("Almansi_totale11"));ret.push_back(string("Almansi_totale12"));ret.push_back(string("Almansi_totale22")); ret.push_back(string("Green_Lagrange_totale11"));ret.push_back(string("Green_Lagrange_totale12")); ret.push_back(string("Green_Lagrange_totale22")); ret.push_back(string("logarithmique_totale11"));ret.push_back(string("logarithmique_totale12")); ret.push_back(string("logarithmique_totale22")); }; break; } case 3 : {ret.push_back(SIG11); ret.push_back(SIG22); ret.push_back(SIG33); ret.push_back(SIG12); ret.push_back(SIG23); ret.push_back(SIG13); ret.push_back(EPS11); ret.push_back(EPS22); ret.push_back(EPS33); ret.push_back(EPS12); ret.push_back(EPS23); ret.push_back(EPS13); ret.push_back(DEPS11); ret.push_back(DEPS22); ret.push_back(DEPS33); ret.push_back(DEPS12); ret.push_back(DEPS23); ret.push_back(DEPS13); ret.push_back(string("Green-Lagrange11")); ret.push_back(string("Green-Lagrange22")); ret.push_back(string("Green-Lagrange33")); ret.push_back(string("Green-Lagrange12")); ret.push_back(string("Green-Lagrange23")); ret.push_back(string("Green-Lagrange13")); ret.push_back(string("Almansi11")); ret.push_back(string("Almansi22")); ret.push_back(string("Almansi33")); ret.push_back(string("Almansi12")); ret.push_back(string("Almansi23")); ret.push_back(string("Almansi13")); ret.push_back(string("logarithmique11")); ret.push_back(string("logarithmique22")); ret.push_back(string("logarithmique33")); ret.push_back(string("logarithmique12")); ret.push_back(string("logarithmique23")); ret.push_back(string("logarithmique13")); ret.push_back(string("Cauchy_local11")); ret.push_back(string("Cauchy_local22")); ret.push_back(string("Cauchy_local33")); ret.push_back(string("Cauchy_local12")); ret.push_back(string("Cauchy_local23")); ret.push_back(string("Cauchy_local13")); ret.push_back(string("Almansi_local11")); ret.push_back(string("Almansi_local22")); ret.push_back(string("Almansi_local33")); ret.push_back(string("Almansi_local12")); ret.push_back(string("Almansi_local23")); ret.push_back(string("Almansi_local13")); ret.push_back(string("Def_principaleI"));ret.push_back(string("Def_principaleII")); ret.push_back(string("Def_principaleIII")); ret.push_back(string("Sigma_principaleI"));ret.push_back(string("Sigma_principaleII")); ret.push_back(string("Sigma_principaleIII")); ret.push_back(string("Vit_principaleI"));ret.push_back(string("Vit_principaleII"));ret.push_back(string("Vit_principaleIII")); ret.push_back(string("Delta_def11"));ret.push_back(string("Delta_def22"));ret.push_back(string("Delta_def33")); ret.push_back(string("Delta_def12"));ret.push_back(string("Delta_def13"));ret.push_back(string("Delta_def23")); if (dilatation) {ret.push_back(string("Almansi_totale11"));ret.push_back(string("Almansi_totale22")); ret.push_back(string("Almansi_totale33"));ret.push_back(string("Almansi_totale12")); ret.push_back(string("Almansi_totale23"));ret.push_back(string("Almansi_totale13")); ret.push_back(string("Green_Lagrange_totale11"));ret.push_back(string("Green_Lagrange_totale22")); ret.push_back(string("Green_Lagrange_totale33"));ret.push_back(string("Green_Lagrange_totale12")); ret.push_back(string("Green_Lagrange_totale23"));ret.push_back(string("Green_Lagrange_totale13")); ret.push_back(string("logarithmique_totale11"));ret.push_back(string("logarithmique_totale22")); ret.push_back(string("logarithmique_totale33"));ret.push_back(string("logarithmique_totale12")); ret.push_back(string("logarithmique_totale23"));ret.push_back(string("logarithmique_totale13")); }; ret.push_back(string("Spherique_eps"));ret.push_back(string("Q_eps"));ret.push_back(string("Cos3phi_eps")); ret.push_back(string("Spherique_sig"));ret.push_back(string("Q_sig"));ret.push_back(string("Cos3phi_sig")); break; } }; // cas de mises et tresca ret.push_back(string("contrainte_mises")); ret.push_back(string("contrainte_tresca")); // déformation duale de mises = sqrt(2/3 * eps_barre:eps_barre) ret.push_back(string("def_duale_mises")); // déformation cumulée: int_0^t sqrt(2./3. * ( ((*delta_epsBH) && (*delta_epsBH)) - Sqr(delta_epsBH->Trace()) /3. )) ret.push_back(string("def_equivalente")); // déformation duale de mises maxi ret.push_back(string("def_duale_mises_maxi")); // vitesse de déformation équivalente ret.push_back(string("vitesse_def_equivalente")); // cas de l'existence de l'erreur if (sigErreur != NULL) ret.push_back(ERREUR); // cas de la plasticité classique string nom_comport(loiComp->Nom_comport()); if ((strstr(nom_comport.c_str(),"PRANDTL_REUSS")!=NULL)) ret.push_back(string("def_plastique_cumulee")); // cas des énergies locales ret.push_back(string("energie_elastique")); ret.push_back(string("dissipation_plastique")); ret.push_back(string("dissipation_visqueuse")); // cas des coordonnées du points switch (ParaGlob::Dimension()) {case 3: ret.push_back(X3); case 2: ret.push_back(X2); case 1: ret.push_back(X1); }; // cas des pressions éventuellement exercées sur les faces de l'élément // modif 15 juin 2019: on sort systématiquement même s'il n'y a pas de pression enregistrée // car la pression peut ne pas être active au début puis ensuite elle devient active // et ret sert pour autoriser la sortie par la suite dans les résultats // de plus au moment de la sortie, lesChargeExtSurEle sera testé et si c'est non nul ce sera ok // si c'est nul, ce sera by passé // if (lesChargeExtSurEle != NULL) // if (lesChargeExtSurEle->LesPressionsExternes() != NULL) ret.push_back(string("pression_ext")); // dans le cas d'un élément 2D, dans un espace 3D, on peut récupérer la normale if ((Type_geom_generique(this->Id_geometrie()) == SURFACE ) && (ParaGlob::Dimension() == 3)) {ret.push_back(string("N_surf_1"));ret.push_back(string("N_surf_2"));ret.push_back(string("N_surf_3")); ret.push_back(string("N_surf_1_t0"));ret.push_back(string("N_surf_2_t0"));ret.push_back(string("N_surf_3_t0")); }; // retour return ret; }; // retourne la liste abondée de tous les données particulières interne actuellement utilisés // par l'élément (actif ou non), sont exclu de cette liste les données particulières des noeuds // reliés à l'élément // absolue: indique si oui ou non on sort les tenseurs dans la base absolue ou une base particulière List_io ElemMeca::Les_types_particuliers_internes(bool absolue) const { List_io ret; // on s'intéresse au information stockée au niveau des points d'intégration // 1° récupéreration les grandeurs // a) cas des grandeurs liées à la déformation def->ListeGrandeurs_particulieres(absolue,ret); // b) cas des grandeurs liées à la loi de comportement mécanique loiComp->ListeGrandeurs_particulieres(absolue,ret); // c) cas des grandeurs liées à la loi de comportement thermo-physique if (loiTP != NULL) loiTP->ListeGrandeurs_particulieres(absolue,ret); // d) cas des infos stockés aux points d'intégration, donc par l'élément Grandeur_scalaire_double grand_courant; // def d'une grandeur courante Tableau tab_1(1); Tab_Grandeur_scalaire_double tab_grand_courant(tab_1); // def d'un type quelconque représentatif à chaque grandeur // a priori ces grandeurs sont défini aux points d'intégration // $$$ cas de MODULE_COMPRESSIBILITE_TOTAL: intègre toutes les sous_lois par exemple TypeQuelconque typQ1(MODULE_COMPRESSIBILITE_TOTAL,SIG11,grand_courant); ret.push_back(typQ1); // $$$ cas de MODULE_CISAILLEMENT_TOTAL: intègre toutes les sous_lois par exemple TypeQuelconque typQ2(MODULE_CISAILLEMENT_TOTAL,SIG11,grand_courant); ret.push_back(typQ2); // e) cas des infos stockés à l'élément // $$$ cas du volume total : TypeQuelconque typQ3(VOLUME_ELEMENT,SIG11,grand_courant); ret.push_back(typQ3); // $$$ cas du volume élémentaire associé au pti TypeQuelconque typQ34(VOLUME_PTI,SIG11,grand_courant); ret.push_back(typQ34); // $$$ cas éventuel d'intégrale de volume: INTEG_SUR_VOLUME if (integ_vol_typeQuel != NULL) {int nb_integration = integ_vol_typeQuel->Taille(); // on va créer un conteneur particulier pour chaque intégrale Tableau & tab_integ = *integ_vol_typeQuel; //_t; // pour simplifier for (int i=1; i<= nb_integration;i++) { TypeQuelconque& tbinteg = tab_integ(i); // pour simplifier EnuTypeQuelParticulier type_interne = tbinteg.Const_Grandeur_pointee()->Type_enumGrandeurParticuliere(); const TypeQuelconque_enum_etendu& enuTQetendu = tbinteg.EnuTypeQuelconque(); {switch (type_interne) {case PARTICULIER_DDL_ETENDU: { Grandeur_Ddl_etendu& gin = *((Grandeur_Ddl_etendu*) tbinteg.Grandeur_pointee()); // pour simplifier // // on va créer (éventuellement s'il n'existe pas déjà) un nouveau : // // -- on crée le nom de référence // string nom(enuTQetendu.NomPlein()+"_"+(*(gin.Nom_ref()))+"_" // +ChangeEntierSTring((*index_Integ_vol_typeQuel)(i))); // TypeQuelconque_enum_etendu tqnevez = // TypeQuelconque_enum_etendu::Ajout_un_TypeQuelconque_enum_etendu // (INTEG_SUR_VOLUME,nom,tbinteg.EnuTypeGrandeur()); // // on enregistre pour la gestion future // (*enu_integ_vol_TQ)(i)=tqnevez; // on crée un exemplaire de conteneur pointé Grandeur_Ddl_etendu inter(gin); // création du type conteneur TypeQuelconque typQ91((*enu_integ_vol_TQ)(i),tbinteg.Enum(),inter); ret.push_back(typQ91); break; }; case PARTICULIER_VECTEUR_NOMMER: { Grandeur_Vecteur_Nommer& gin = *((Grandeur_Vecteur_Nommer*) tbinteg.Grandeur_pointee()); // pour simplifier // // on va créer (éventuellement s'il n'existe pas déjà) un nouveau : // // -- on crée le nom de référence // string nom(enuTQetendu.NomPlein()+"_"+(*(gin.Nom_ref()))+"_" // +ChangeEntierSTring((*index_Integ_vol_typeQuel)(i))); // TypeQuelconque_enum_etendu tqnevez = // TypeQuelconque_enum_etendu::Ajout_un_TypeQuelconque_enum_etendu // (INTEG_SUR_VOLUME,nom,tbinteg.EnuTypeGrandeur()); // // on enregistre pour la gestion future // (*enu_integ_vol_TQ)(i)=tqnevez; //// //----- debug //// cout << "\n ElemMeca::Les_types_particuliers_internes( " //// << "\n (*enu_integ_vol_TQ)("<Taille(); // on va créer un conteneur particulier pour chaque intégrale Tableau & tab_integ = *integ_vol_t_typeQuel; //_t; // pour simplifier for (int i=1; i<= nb_integration;i++) {TypeQuelconque& tbinteg = tab_integ(i); // pour simplifier EnuTypeQuelParticulier type_interne = tbinteg.Const_Grandeur_pointee()->Type_enumGrandeurParticuliere(); const TypeQuelconque_enum_etendu& enuTQetendu = tbinteg.EnuTypeQuelconque(); {switch (type_interne) {case PARTICULIER_DDL_ETENDU: { Grandeur_Ddl_etendu& gin = *((Grandeur_Ddl_etendu*) tbinteg.Grandeur_pointee()); // pour simplifier // // on va créer (éventuellement s'il n'existe pas déjà) un nouveau : // // -- on crée le nom de référence // string nom(enuTQetendu.NomPlein()+"_"+(*(gin.Nom_ref()))+"_" // +ChangeEntierSTring((*index_Integ_vol_typeQuel)(i))); // TypeQuelconque_enum_etendu tqnevez = // TypeQuelconque_enum_etendu::Ajout_un_TypeQuelconque_enum_etendu // (INTEG_SUR_VOLUME,nom,tbinteg.EnuTypeGrandeur()); // // on enregistre pour la gestion future // (*enu_integ_vol_t_TQ)(i)=tqnevez; // on crée un exemplaire de conteneur pointé Grandeur_Ddl_etendu inter(gin); // création du type conteneur TypeQuelconque typQ91((*enu_integ_vol_t_TQ)(i),tbinteg.Enum(),inter); ret.push_back(typQ91); break; }; case PARTICULIER_VECTEUR_NOMMER: { Grandeur_Vecteur_Nommer& gin = *((Grandeur_Vecteur_Nommer*) tbinteg.Grandeur_pointee()); // pour simplifier // // on va créer (éventuellement s'il n'existe pas déjà) un nouveau : // // -- on crée le nom de référence // string nom(enuTQetendu.NomPlein()+"_"+(*(gin.Nom_ref()))+"_" // +ChangeEntierSTring((*index_Integ_vol_typeQuel)(i))); // TypeQuelconque_enum_etendu tqnevez = // TypeQuelconque_enum_etendu::Ajout_un_TypeQuelconque_enum_etendu // (INTEG_SUR_VOLUME,nom,tbinteg.EnuTypeGrandeur()); // // on enregistre pour la gestion future // (*enu_integ_vol_t_TQ)(i)=tqnevez; // on crée un exemplaire de conteneur pointé Grandeur_Vecteur_Nommer inter(gin); // création du type conteneur TypeQuelconque typQ91((*enu_integ_vol_t_TQ)(i),tbinteg.Enum(),inter); ret.push_back(typQ91); break; } default: // pas d'intégrale ad hoc dispo ici pour la demande break; }; }; }; }; // $$$ cas de l'énergie d'hourglasse : TypeQuelconque typQ31(ENERGIE_HOURGLASS,SIG11,grand_courant); ret.push_back(typQ31); // $$$ cas de la puissance bulk : TypeQuelconque typQ32(PUISSANCE_BULK,SIG11,grand_courant); ret.push_back(typQ32); // $$$ cas de l'énergie bulk : TypeQuelconque typQ33(ENERGIE_BULK,SIG11,grand_courant); ret.push_back(typQ33); // $$$ cas de l'énergie de stabilisation membrane ou biel : TypeQuelconque typQ330(ENERGIE_STABMEMB_BIEL,SIG11,grand_courant); ret.push_back(typQ330); // $$$ cas de la force de stabilisation membrane ou biel : TypeQuelconque typQ331(FORCE_STABMEMB_BIEL,SIG11,grand_courant); ret.push_back(typQ331); // $$$ cas du temps cpu relativement à la loi de comp : TypeQuelconque typQ35(TEMPS_CPU_LOI_COMP,SIG11,grand_courant); ret.push_back(typQ35); // $$$ cas du temps cpu relativement à la métrique : TypeQuelconque typQ36(TEMPS_CPU_METRIQUE,SIG11,grand_courant); ret.push_back(typQ36); // $$$ cas des numéros Grandeur_scalaire_entier entier_courant; TypeQuelconque typQ37(NUM_ELEMENT,SIG11,entier_courant); ret.push_back(typQ37); TypeQuelconque typQ38(NUM_MAIL_ELEM,SIG11,entier_courant); ret.push_back(typQ38); TypeQuelconque typQ39(NUM_PTI,SIG11,entier_courant); ret.push_back(typQ39); // f) cas des infos calculable à la demande sur l'élément // $$$ cas des volumes entre les plans et l'élément dans le cas ou l'élément des de surface // et que le calcul est 3D : if ((ParaGlob::Dimension()==3)&&(Type_geom_generique(id_geom)==SURFACE)) {Grandeur_coordonnee grandCoordonnee(3); // un type courant TypeQuelconque typQ4(VOL_ELEM_AVEC_PLAN_REF,SIG11,grandCoordonnee); ret.push_back(typQ4); }; // liberation des tenseurs intermediaires LibereTenseur(); return ret; }; // retourne la liste des grandeurs évoluées interne actuellement utilisés // par l'élément, c'est-à-dire directement sous forme de vecteur, tenseurs .... // absolue: indique si oui ou non on sort les tenseurs dans la base absolue ou une base particulière List_io ElemMeca::Les_type_evolues_internes(bool absolue) const { List_io liTQ; // // def de la dimension des tenseurs // // il y a deux pb a gérer: 1) le fait que la dimension absolue peut-être différente de la dimension des tenseurs // // 2) le fait que l'on veut une sortie dans une base ad hoc ou pas // int dim = lesPtIntegMecaInterne->DimTens();int dim_sortie_tenseur = dim; // // dans le cas ou l'on veut une sortie en base absolue, il faut que dim_sortie_tenseur = la dimension de la base absolue // int dim_espace = ParaGlob::Dimension(); // if (absolue) // dim_sortie_tenseur = dim_espace; // // pour ne faire qu'un seul test ensuite // bool prevoir_change_dim_tenseur = false; // if ((absolue) && (dim != dim_sortie_tenseur)) // prevoir_change_dim_tenseur = true; // def des grandeurs courantes de type tenseur BB int dim_espace = ParaGlob::Dimension(); int dim_tenseur_sortie = this->Dim_sig_eps(); // la dimension a priori if (absolue) dim_tenseur_sortie = dim_espace; // si on sort en absolue, on utilise la dim globale {TenseurBB* tens = NevezTenseurBB(dim_tenseur_sortie); // un tenseur typique // maintenant on définit une grandeur typique de type tenseurBB Grandeur_TenseurBB gtBB(*tens); // def d'un type quelconque représentatif pour chaque grandeur {TypeQuelconque typQ(DEFORMATION_COURANTE,EPS11,gtBB);liTQ.push_back(typQ);}; {TypeQuelconque typQ(VITESSE_DEFORMATION_COURANTE,DEPS11,gtBB);liTQ.push_back(typQ);}; {TypeQuelconque typQ(ALMANSI,EPS11,gtBB);liTQ.push_back(typQ);}; {TypeQuelconque typQ(GREEN_LAGRANGE,EPS11,gtBB);liTQ.push_back(typQ);}; {TypeQuelconque typQ(LOGARITHMIQUE,EPS11,gtBB);liTQ.push_back(typQ);}; {TypeQuelconque typQ(DELTA_DEF,EPS11,gtBB);liTQ.push_back(typQ);}; if (dilatation) {{TypeQuelconque typQ(ALMANSI_TOTAL,EPS11,gtBB);liTQ.push_back(typQ);}; {TypeQuelconque typQ(GREEN_LAGRANGE_TOTAL,EPS11,gtBB);liTQ.push_back(typQ);}; {TypeQuelconque typQ(LOGARITHMIQUE_TOTALE,EPS11,gtBB);liTQ.push_back(typQ);}; }; delete tens; // car on n'en a plus besoin }; // def des grandeurs courantes de type tenseur HH {TenseurHH* tens = NevezTenseurHH(dim_tenseur_sortie); // un tenseur typique // maintenant on définit une grandeur typique de type tenseurHH Grandeur_TenseurHH gtHH(*tens); // def d'un type quelconque représentatif pour chaque grandeur TypeQuelconque typQ(CONTRAINTE_COURANTE,SIG11,gtHH);liTQ.push_back(typQ); delete tens; // car on n'en a plus besoin }; // def des grandeurs courantes de type coordonnee {Coordonnee coor(dim_tenseur_sortie); // un type coordonnee typique // maintenant on définit une grandeur typique de type Grandeur_coordonnee Grandeur_coordonnee gt(coor); // def d'un type quelconque représentatif pour chaque grandeur {TypeQuelconque typQ(DEF_PRINCIPALES,EPS11,gt);liTQ.push_back(typQ);}; {TypeQuelconque typQ(SIGMA_PRINCIPALES,SIG11,gt);liTQ.push_back(typQ);}; {TypeQuelconque typQ(VIT_PRINCIPALES,DEPS11,gt);liTQ.push_back(typQ);}; // pour la position il s'agit de la position du point d'intégration {TypeQuelconque typQ(POSITION_GEOMETRIQUE,SIG11,gt);liTQ.push_back(typQ);}; } {Coordonnee coor(dim_espace); // un type coordonnee typique // maintenant on définit une grandeur typique de type Grandeur_coordonnee Grandeur_coordonnee gt(coor); // *** 21 avril 2020: on change la position d'expression: du noeuds au pti // donc on passe de X1 à SIG11 , mais il s'agit d'un pti spécifique de surface ou de ligne ... // le chargement de type pression, sous forme d'un vecteur charge, exprimée aux pti surface {TypeQuelconque typQ(VECT_PRESSION,SIG11,gt);liTQ.push_back(typQ);}; // le chargement de type force volumique sous forme d'un vecteur charge, exprimée aux pti volume {TypeQuelconque typQ(VECT_FORCE_VOLUM,SIG11,gt);liTQ.push_back(typQ);}; // le chargement de type force de direction fixe sous forme d'un vecteur charge, exprimée aux pti surface {TypeQuelconque typQ(VECT_DIR_FIXE,SIG11,gt);liTQ.push_back(typQ);}; // le chargement de type force suiveuse sous forme d'un vecteur charge, exprimée aux pti surface {TypeQuelconque typQ(VECT_SURF_SUIV,SIG11,gt);liTQ.push_back(typQ);}; // le chargement de type force hydrodynamique sous forme d'un vecteur charge, exprimée aux pti surface {TypeQuelconque typQ(VECT_HYDRODYNA_Fn,SIG11,gt);liTQ.push_back(typQ);}; {TypeQuelconque typQ(VECT_HYDRODYNA_Ft,SIG11,gt);liTQ.push_back(typQ);}; {TypeQuelconque typQ(VECT_HYDRODYNA_T,SIG11,gt);liTQ.push_back(typQ);}; // le chargement de type force linéique sous forme d'un vecteur charge, exprimée aux pti ligne {TypeQuelconque typQ(VECT_LINE,SIG11,gt);liTQ.push_back(typQ);}; // le chargement de type force linéique suiveuse sous forme d'un vecteur charge, exprimée aux pti ligne {TypeQuelconque typQ(VECT_LINE_SUIV,SIG11,gt);liTQ.push_back(typQ);}; // *** fin modif avril 2020 // // les réaction sous forme d'un vecteur charge, exprimée aux noeuds // {TypeQuelconque typQ(VECT_REAC,X1,gt);liTQ.push_back(typQ);}; }; // def des grandeurs courantes de type scalaires {// on définit une grandeur typique de type Grandeur_scalaire_double Grandeur_scalaire_double scd(0.); // def d'un type quelconque représentatif pour chaque grandeur {TypeQuelconque typQ(CONTRAINTE_MISES,SIG11,scd);liTQ.push_back(typQ);}; {TypeQuelconque typQ(CONTRAINTE_TRESCA,SIG11,scd);liTQ.push_back(typQ);}; {TypeQuelconque typQ(DEF_DUALE_MISES,EPS11,scd);liTQ.push_back(typQ);}; {TypeQuelconque typQ(DEF_DUALE_MISES_MAXI,EPS11,scd);liTQ.push_back(typQ);}; {TypeQuelconque typQ(DEF_EQUIVALENTE,EPS11,scd);liTQ.push_back(typQ);}; // cas de l'existence de l'erreur // if (sigErreur != NULL) {TypeQuelconque typQ(ERREUR_Q,ERREUR,scd);liTQ.push_back(typQ);} // if (sigErreur_relative != NULL) {TypeQuelconque typQ(ERREUR_SIG_RELATIVE,ERREUR,scd);liTQ.push_back(typQ);} // cas de la plasticité classique string nom_comport(loiComp->Nom_comport()); if ((strstr(nom_comport.c_str(),"PRANDTL_REUSS")!=NULL)) {TypeQuelconque typQ(DEF_PLASTIQUE_CUMULEE,EPS11,scd);liTQ.push_back(typQ);} // les infos sur la décomposition spherique,polaire des contraintes et déformations // seulement en 3D if (ParaGlob::Dimension() == 3) {{TypeQuelconque typQ(SPHERIQUE_EPS,EPS11,scd);liTQ.push_back(typQ);}; {TypeQuelconque typQ(Q_EPS,EPS11,scd);liTQ.push_back(typQ);}; {TypeQuelconque typQ(COS3PHI_EPS,EPS11,scd);liTQ.push_back(typQ);}; {TypeQuelconque typQ(SPHERIQUE_SIG,SIG11,scd);liTQ.push_back(typQ);}; {TypeQuelconque typQ(Q_SIG,SIG11,scd);liTQ.push_back(typQ);}; {TypeQuelconque typQ(COS3PHI_SIG,SIG11,scd);liTQ.push_back(typQ);}; {TypeQuelconque typQ(SPHERIQUE_DEPS,DEPS11,scd);liTQ.push_back(typQ);}; {TypeQuelconque typQ(Q_DEPS,DEPS11,scd);liTQ.push_back(typQ);}; {TypeQuelconque typQ(COS3PHI_DEPS,DEPS11,scd);liTQ.push_back(typQ);}; }; }; // $$$ cas du repère local ad hoc orthonormé d'expression des tenseurs {Coordonnee v_rep(dim_espace); Tab_Grandeur_Coordonnee grand5(v_rep,dim_espace); // def d'une grandeur courante coordonnée TypeQuelconque typQ6(REPERE_LOCAL_ORTHO,EPS11,grand5); liTQ.push_back(typQ6); }; // $$$ cas du repère local dual exprimé dans le repère global // par défaut, on réserve dim_espace vecteurs, éventuellement certains peuvent être nuls {Coordonnee v_rep(dim_espace); Tab_Grandeur_Coordonnee grand5(v_rep,dim_espace); // def d'une grandeur courante coordonnée TypeQuelconque typQ6(REPERE_LOCAL_H,EPS11,grand5); liTQ.push_back(typQ6); }; // $$$ cas du repère local naturel exprimé dans le repère global // par défaut, on réserve dim_espace vecteurs, éventuellement certains peuvent être nuls {Coordonnee v_rep(dim_espace); Tab_Grandeur_Coordonnee grand5(v_rep,dim_espace); // def d'une grandeur courante coordonnée TypeQuelconque typQ6(REPERE_LOCAL_B,EPS11,grand5); liTQ.push_back(typQ6); }; // $$$ cas du repère principal orthonormé du tenseur des contraintes {Coordonnee v_rep(dim_espace); Tab_Grandeur_Coordonnee grand5(v_rep,dim_espace); // def d'une grandeur courante coordonnée TypeQuelconque typQ6(DIRECTIONS_PRINC_SIGMA,SIG11,grand5); liTQ.push_back(typQ6); }; // $$$ cas du repère principal orthonormé du tenseur des déformations {Coordonnee v_rep(dim_espace); Tab_Grandeur_Coordonnee grand5(v_rep,dim_espace); // def d'une grandeur courante coordonnée TypeQuelconque typQ6(DIRECTIONS_PRINC_DEF,EPS11,grand5); liTQ.push_back(typQ6); }; // $$$ cas du repère principal orthonormé du tenseur des vitesses de déformation {Coordonnee v_rep(dim_espace); Tab_Grandeur_Coordonnee grand5(v_rep,dim_espace); // def d'une grandeur courante coordonnée TypeQuelconque typQ6(DIRECTIONS_PRINC_D,DEPS11,grand5); liTQ.push_back(typQ6); }; // dans le cas d'un élément 2D, dans un espace 3D, on peut récupérer la normale if ((Type_geom_generique(this->Id_geometrie()) == SURFACE ) && (ParaGlob::Dimension() == 3)) {Grandeur_coordonnee grandCoordonnee(3); // un type courant TypeQuelconque typQ4(NN_SURF,EPS11,grandCoordonnee); liTQ.push_back(typQ4); }; // retour return liTQ; }; // retourne la liste de toutes les grandeurs quelconques relatives aux faces de // l'élément (actif ou non), // absolue: indique si oui ou non on sort les tenseurs dans la base absolue ou une base particulière List_io ElemMeca::Les_type_quelconque_de_face(bool absolue) const { List_io liTQ; // // def de la dimension des tenseurs // // il y a deux pb a gérer: 1) le fait que la dimension absolue peut-être différente de la dimension des tenseurs // // 2) le fait que l'on veut une sortie dans une base ad hoc ou pas // int dim = lesPtIntegMecaInterne->DimTens();int dim_sortie_tenseur = dim; // // dans le cas ou l'on veut une sortie en base absolue, il faut que dim_sortie_tenseur = la dimension de la base absolue // int dim_espace = ParaGlob::Dimension(); // if (absolue) // dim_sortie_tenseur = dim_espace; // // pour ne faire qu'un seul test ensuite // bool prevoir_change_dim_tenseur = false; // if ((absolue) && (dim != dim_sortie_tenseur)) // prevoir_change_dim_tenseur = true; // def des grandeurs courantes de type tenseur BB int dim_espace = ParaGlob::Dimension(); int dim_tenseur_sortie = this->Dim_sig_eps(); // la dimension a priori if (absolue) dim_tenseur_sortie = dim_espace; // si on sort en absolue, on utilise la dim globale // def des grandeurs courantes de type coordonnee {Coordonnee coor(dim_tenseur_sortie); // un type coordonnee typique // maintenant on définit une grandeur typique de type Grandeur_coordonnee Grandeur_coordonnee gt(coor); // pour la position il s'agit de la position du point d'intégration {TypeQuelconque typQ(POSITION_GEOMETRIQUE,SIG11,gt);liTQ.push_back(typQ);}; {TypeQuelconque typQ(POSITION_GEOMETRIQUE_t,SIG11,gt);liTQ.push_back(typQ);}; {TypeQuelconque typQ(POSITION_GEOMETRIQUE_t0,SIG11,gt);liTQ.push_back(typQ);}; } {Coordonnee coor(dim_espace); // un type coordonnee typique // maintenant on définit une grandeur typique de type Grandeur_coordonnee Grandeur_coordonnee gt(coor); // le chargement de type pression, sous forme d'un vecteur charge, exprimée aux pti surface {TypeQuelconque typQ(VECT_PRESSION,SIG11,gt);liTQ.push_back(typQ);}; // le chargement de type force de direction fixe sous forme d'un vecteur charge, exprimée aux pti surface {TypeQuelconque typQ(VECT_DIR_FIXE,SIG11,gt);liTQ.push_back(typQ);}; // le chargement de type force suiveuse sous forme d'un vecteur charge, exprimée aux pti surface {TypeQuelconque typQ(VECT_SURF_SUIV,SIG11,gt);liTQ.push_back(typQ);}; // le chargement de type force hydrodynamique sous forme d'un vecteur charge, exprimée aux pti surface {TypeQuelconque typQ(VECT_HYDRODYNA_Fn,SIG11,gt);liTQ.push_back(typQ);}; {TypeQuelconque typQ(VECT_HYDRODYNA_Ft,SIG11,gt);liTQ.push_back(typQ);}; {TypeQuelconque typQ(VECT_HYDRODYNA_T,SIG11,gt);liTQ.push_back(typQ);}; // // les réaction sous forme d'un vecteur charge, exprimée aux noeuds // {TypeQuelconque typQ(VECT_REAC,X1,gt);liTQ.push_back(typQ);}; }; // def des grandeurs courantes de type scalaires {// def d'un type quelconque représentatif pour chaque grandeur // // $$$ cas du repère local ad hoc orthonormé d'expression des tenseurs // {Coordonnee v_rep(dim_espace); // Tab_Grandeur_Coordonnee grand5(v_rep,dim_espace); // def d'une grandeur courante coordonnée // TypeQuelconque typQ6(REPERE_LOCAL_ORTHO,EPS11,grand5); // liTQ.push_back(typQ6); // }; // // // $$$ cas du repère local dual exprimé dans le repère global // // par défaut, on réserve dim_espace vecteurs, éventuellement certains peuvent être nuls // {Coordonnee v_rep(dim_espace); // Tab_Grandeur_Coordonnee grand5(v_rep,dim_espace); // def d'une grandeur courante coordonnée // TypeQuelconque typQ6(REPERE_LOCAL_H,EPS11,grand5); // liTQ.push_back(typQ6); // }; // // $$$ cas du repère local naturel exprimé dans le repère global // // par défaut, on réserve dim_espace vecteurs, éventuellement certains peuvent être nuls // {Coordonnee v_rep(dim_espace); // Tab_Grandeur_Coordonnee grand5(v_rep,dim_espace); // def d'une grandeur courante coordonnée // TypeQuelconque typQ6(REPERE_LOCAL_B,EPS11,grand5); // liTQ.push_back(typQ6); // }; {Grandeur_coordonnee grandCoordonnee(3); // un type courant TypeQuelconque typQ4(NN_SURF,EPS11,grandCoordonnee); liTQ.push_back(typQ4); }; {Grandeur_coordonnee grandCoordonnee(3); // un type courant TypeQuelconque typQ4(NN_SURF_t,EPS11,grandCoordonnee); liTQ.push_back(typQ4); }; {Grandeur_coordonnee grandCoordonnee(3); // un type courant TypeQuelconque typQ4(NN_SURF_t0,EPS11,grandCoordonnee); liTQ.push_back(typQ4); }; }; // $$$ cas des numéros Grandeur_scalaire_entier entier_courant; TypeQuelconque typQ37(NUM_ELEMENT,SIG11,entier_courant); liTQ.push_back(typQ37); TypeQuelconque typQ38(NUM_MAIL_ELEM,SIG11,entier_courant); liTQ.push_back(typQ38); TypeQuelconque typQ39(NUM_FACE,SIG11,entier_courant); liTQ.push_back(typQ39); TypeQuelconque typQ40(NUM_PTI,SIG11,entier_courant); liTQ.push_back(typQ40); Grandeur_scalaire_double double_courant; TypeQuelconque typQ41(PRESSION_SCALAIRE,SIG11,double_courant); liTQ.push_back(typQ41); // retour return liTQ; }; // retourne la liste de toutes les grandeurs quelconques relatives aux arêtes de // l'élément (actif ou non), // absolue: indique si oui ou non on sort les tenseurs dans la base absolue ou une base particulière List_io ElemMeca::Les_type_quelconque_de_arete(bool absolue) const { List_io liTQ; // // def de la dimension des tenseurs // // il y a deux pb a gérer: 1) le fait que la dimension absolue peut-être différente de la dimension des tenseurs // // 2) le fait que l'on veut une sortie dans une base ad hoc ou pas // int dim = lesPtIntegMecaInterne->DimTens();int dim_sortie_tenseur = dim; // // dans le cas ou l'on veut une sortie en base absolue, il faut que dim_sortie_tenseur = la dimension de la base absolue // int dim_espace = ParaGlob::Dimension(); // if (absolue) // dim_sortie_tenseur = dim_espace; // // pour ne faire qu'un seul test ensuite // bool prevoir_change_dim_tenseur = false; // if ((absolue) && (dim != dim_sortie_tenseur)) // prevoir_change_dim_tenseur = true; // def des grandeurs courantes de type tenseur BB int dim_espace = ParaGlob::Dimension(); int dim_tenseur_sortie = this->Dim_sig_eps(); // la dimension a priori if (absolue) dim_tenseur_sortie = dim_espace; // si on sort en absolue, on utilise la dim globale // def des grandeurs courantes de type coordonnee {Coordonnee coor(dim_tenseur_sortie); // un type coordonnee typique // maintenant on définit une grandeur typique de type Grandeur_coordonnee Grandeur_coordonnee gt(coor); // pour la position il s'agit de la position du point d'intégration {TypeQuelconque typQ(POSITION_GEOMETRIQUE,SIG11,gt);liTQ.push_back(typQ);}; {TypeQuelconque typQ(POSITION_GEOMETRIQUE_t,SIG11,gt);liTQ.push_back(typQ);}; {TypeQuelconque typQ(POSITION_GEOMETRIQUE_t0,SIG11,gt);liTQ.push_back(typQ);}; } {Coordonnee coor(dim_espace); // un type coordonnee typique // maintenant on définit une grandeur typique de type Grandeur_coordonnee Grandeur_coordonnee gt(coor); // le chargement de type force linéique sous forme d'un vecteur charge, exprimée aux pti ligne {TypeQuelconque typQ(VECT_LINE,SIG11,gt);liTQ.push_back(typQ);}; // le chargement de type force linéique suiveuse sous forme d'un vecteur charge, exprimée aux pti ligne {TypeQuelconque typQ(VECT_LINE_SUIV,SIG11,gt);liTQ.push_back(typQ);}; }; // $$$ cas des numéros Grandeur_scalaire_entier entier_courant; TypeQuelconque typQ37(NUM_ELEMENT,SIG11,entier_courant); liTQ.push_back(typQ37); TypeQuelconque typQ38(NUM_MAIL_ELEM,SIG11,entier_courant); liTQ.push_back(typQ38); TypeQuelconque typQ39(NUM_ARETE,SIG11,entier_courant); liTQ.push_back(typQ39); TypeQuelconque typQ40(NUM_PTI,SIG11,entier_courant); liTQ.push_back(typQ40); // retour return liTQ; }; // récupération de grandeurs particulières au numéro d'ordre = iteg // celles-ci peuvent être quelconques // en retour liTQ est modifié et contiend les infos sur les grandeurs particulières // absolue: indique si oui ou non on sort les tenseurs dans la base absolue ou une base particulière void ElemMeca::Grandeur_particuliere(bool absolue,List_io& liTQ,int iteg) { // on s'intéresse au information stockée au niveau des points d'intégration // pour tenir compte du fait qu'il peut y avoir plusieurs fois la même information, ces dernières sont systématiquement // stockées dans des tableaux, et on associe à ce tableau un indice qui indique aux méthodes appelées, à quel endroit // elles doivent écrire les infos. les indices sont stockés dans une liste de même dim que liTQ list decal(liTQ.size(),0.); // on initi tous les membres à 0 // 0° on initialise les grandeurs à 0 pour éviter d'avoir des valeurs aléatoires // -- on commence par initialiser les conteneurs car certaines données peuvent ne pas exister List_io::iterator iquefin=liTQ.end(); List_io::iterator ique,ique_deb=liTQ.begin(); for (ique=ique_deb;ique!=iquefin;ique++) (*ique).Grandeur_pointee()->InitParDefaut(); // 1° on change le numéro de point d'intégration courant def->ChangeNumInteg(iteg); // 2° on commence par récupérer les grandeurs // a) cas des grandeurs liées à la déformation // met à jour les données spécifiques du point considéré def->Mise_a_jour_data_specif(tabSaveDefDon(iteg)); def->Grandeur_particuliere(absolue,liTQ); // b) cas des grandeurs liées à la loi de comportement méca // on commence par indiquer quel saveresult de pti a utiliser loiComp->IndiquePtIntegMecaInterne(&((*lesPtIntegMecaInterne)(iteg))); // puis on récupère les grandeurs loiComp->Grandeur_particuliere(absolue,liTQ,tabSaveDon(iteg),decal); // pour le débug ---- //cout << "\n debug ElemMeca::Grandeur_particuliere " << liTQ << endl; // débug // fin pour le débug ---- // c) cas des grandeurs liées à la loi de comportement thermo-physique if (loiTP != NULL) loiTP->Grandeur_particuliere(absolue,liTQ,tabSaveTP(iteg),decal); // 3° on change éventuellement de repère (local en global) si nécessaire // a) définition des grandeurs qui sont indépendante de la boucle qui suit // dimension des vecteurs de base de la métrique int dim = met->Dim_vec_base(); // calcul des matrices de passages Mat_pleine* gamma0=NULL; Mat_pleine* gammat=NULL; Mat_pleine* gammatdt=NULL; Mat_pleine* beta0=NULL; Mat_pleine* betat=NULL; Mat_pleine* betatdt=NULL; // const Met_abstraite::Info0_t_tdt& ex = def->Remont0_t_tdt(gamma0,gammat,gammatdt); // Mat_pleine beta0(gamma0.Inverse().Transpose()); // Mat_pleine betat(gammat.Inverse().Transpose()); // Mat_pleine betatdt(gammatdt.Inverse().Transpose()); List_io::iterator il,ilfin = liTQ.end(); for (il=liTQ.begin();il!=ilfin;il++) { TypeQuelconque& tipParticu = (*il); // pour simplifier // n'intervient que si la grandeur est active: if ((*il).Activite()) { // on regarde si c'est une grandeur locale ou pas if (tipParticu.TypeExpressionGrandeur()==0) // cas d'une grandeur exprimée dans le repère locale, changement de repère { // calcul des matrices de passages, au premier passage if (gamma0 == NULL) { Mat_pleine Aa0(dim,dim),Aat(dim,dim),Aatdt(dim,dim); const Met_abstraite::Info0_t_tdt& ex = def->Remont0_t_tdt(absolue,Aa0,Aat,Aatdt); // a) ----- dans le sens: gi -> Ia // on a: g^i = A^i_{.a} * I^a ou Ip^a suivant que absolue est true ou false // si false, cela veut dire que Ip^a est un repère ad hoc // sinon cela veut dire que c'est le repère absolu donc I_a = I^a // et g_j = B_j^{.a} * I_a d'où [B_j^{.a}] = [A^i_{.a}]^{-1T} // // b) ----- dans le sens: Ia -> gi // pour les formules de passage de repère il nous faut : // Ip_a = beta_a^{.j} g_j et Ip^b = gamma^b_{.j} g^j // on a alors : [beta_a^{.j}] = [Aa^j_{.a}]^T // et [gamma^b_{.j}] = [beta_a^{.j}]^{-1T} = [Aa^j_{.a}]^{-1} // // au final: [beta_a^{.j}] = [Aa^j_{.a}]^T // [gamma^b_{.j}] = [Aa^j_{.a}]^{-1} // [B_j^{.a}] = [gamma^b_{.j}]^T gamma0 = new Mat_pleine(Aa0.Inverse()); gammat = new Mat_pleine(Aat.Inverse()); gammatdt = new Mat_pleine(Aatdt.Inverse()); // on détermine également les matrices beta beta0 = new Mat_pleine(Aa0.Transpose()); betat = new Mat_pleine(Aat.Transpose()); betatdt = new Mat_pleine(Aatdt.Transpose()); //---------- debug /* { cout << "\n debug en 3D ElemMeca::Grandeur_particuliere( "; cout << "\n -- affichage de la sauvegarde du pti "<Affiche(); cout << "\n Aatdt: "; Aatdt.Affiche(); cout << "\n betatdt: "; betatdt->Affiche(); cout << "\n gammatdt: "; gammatdt->Affiche(); Tableau gB_itdt(3),gH_itdt(3); for (int a=1; a<3;a++) { cout << "\n giB_tdt("<Transpose()); cout << "\n beta^T * gamma "; ((*gammatdt)* BB).Affiche(); // calcul des Ip_a à l'aide de betatdt for (int a=1; a<4;a++) { Vecteur V(3); for (int j=1;j<4;j++) V += (*betatdt)(a,j) * gB_itdt(j); // V += BB(a,j) * gB_itdt(j); cout << "\n Ip("<Taille();//_t->Taille(); Tableau & tab_integ = *integ_vol_typeQuel; //_t; // pour simplifier const TypeQuelconque_enum_etendu& type_externe = tipParticu.EnuTypeQuelconque(); // maintenant il faut trouver la locale qui correspond: le plus simple // mais pas le plus rapide !! est d'itérer for (int i=1; i<= nb_integration;i++) {EnuTypeQuelParticulier enuTQP = tipParticu.Grandeur_pointee()->Type_enumGrandeurParticuliere(); // //----- debug // cout << "\n ElemMeca::Grandeur_particuliere( "; // cout << "\n type_externe " << type_externe // << "\n (*enu_integ_vol_TQ)("<Valeur(); } break; }; case PARTICULIER_VECTEUR_NOMMER: { Grandeur_Vecteur_Nommer& gex = *((Grandeur_Vecteur_Nommer*) tipParticu.Grandeur_pointee()); // pour simplifier Grandeur_Vecteur_Nommer& gin = *((Grandeur_Vecteur_Nommer*) tab_integ(i).Grandeur_pointee()); // pour simplifier if ((*(gex.Nom_ref())) == (*(gin.Nom_ref()))) // là on a récupérer la même grandeur {Vecteur& V = gex.ConteneurVecteur(); V = gin.ConteneurVecteur(); // //----- debug // cout << "\n ElemMeca::Grandeur_particuliere( "; // V.Affiche(); // //----- fin debug } break; } default: // pas d'intégrale ad hoc dispo ici pour la demande break; }; }; }; }; break; } case INTEG_SUR_VOLUME_ET_TEMPS: {if (integ_vol_t_typeQuel != NULL)//_t != NULL) // cas où localement il y a une intégrale de définie {int nb_integration = integ_vol_t_typeQuel->Taille(); //_t->Taille(); Tableau & tab_integ = *integ_vol_t_typeQuel; //_t; // pour simplifier const TypeQuelconque_enum_etendu& type_externe = tipParticu.EnuTypeQuelconque(); // maintenant il faut trouver la locale qui correspond: le plus simple // mais pas le plus rapide !! est d'itérer for (int i=1; i<= nb_integration;i++) {EnuTypeQuelParticulier enuTQP = tipParticu.Grandeur_pointee()->Type_enumGrandeurParticuliere(); if (type_externe == (*enu_integ_vol_TQ)(i)) {switch (enuTQP) {case PARTICULIER_DDL_ETENDU: { Grandeur_Ddl_etendu& gex = *((Grandeur_Ddl_etendu*) tipParticu.Grandeur_pointee()); // pour simplifier Grandeur_Ddl_etendu& gin = *((Grandeur_Ddl_etendu*) tab_integ(i).Grandeur_pointee()); // pour simplifier if ((*(gex.Nom_ref())) == (*(gin.Nom_ref()))) // là on a récupérer la même grandeur {Ddl_etendu& ddl = *(gex.ConteneurDdl_etendu());// récup du ddl ddl.Valeur() = gin.ConteneurDdl_etendu()->Valeur(); } break; }; case PARTICULIER_VECTEUR_NOMMER: { Grandeur_Vecteur_Nommer& gex = *((Grandeur_Vecteur_Nommer*) tipParticu.Grandeur_pointee()); // pour simplifier Grandeur_Vecteur_Nommer& gin = *((Grandeur_Vecteur_Nommer*) tab_integ(i).Grandeur_pointee()); // pour simplifier if ((*(gex.Nom_ref())) == (*(gin.Nom_ref()))) // là on a récupérer la même grandeur {Vecteur& V = gex.ConteneurVecteur(); V = gin.ConteneurVecteur(); } break; } default: // pas d'intégrale ad hoc dispo ici pour la demande break; }; }; }; }; break; } case ENERGIE_HOURGLASS: { *((Grandeur_scalaire_double*) tipParticu.Grandeur_pointee())=ElemMeca::Energie_Hourglass();break;} case PUISSANCE_BULK: { *((Grandeur_scalaire_double*) tipParticu.Grandeur_pointee())=ElemMeca::Puissance_Bulk();break;} case ENERGIE_BULK: { *((Grandeur_scalaire_double*) tipParticu.Grandeur_pointee())=ElemMeca::Energie_Bulk();break;} case ENERGIE_STABMEMB_BIEL: { *((Grandeur_scalaire_double*) tipParticu.Grandeur_pointee())=ElemMeca::Energie_StabMembBiel(iteg);break;} case FORCE_STABMEMB_BIEL: { *((Grandeur_scalaire_double*) tipParticu.Grandeur_pointee())=ElemMeca::Force_StabMembBiel(iteg);break;} // d) cas des infos calculable à la demande sur l'élément case VOL_ELEM_AVEC_PLAN_REF: { *((Grandeur_coordonnee*) tipParticu.Grandeur_pointee())=VolumePlan();break;} // cas des temps d'exécution case TEMPS_CPU_LOI_COMP: { *((Grandeur_scalaire_double*) tipParticu.Grandeur_pointee())= (*lesPtIntegMecaInterne)(iteg).Tps_cpu_loi_comp_const().Temps_CPU_User();break;} case TEMPS_CPU_METRIQUE: { *((Grandeur_scalaire_double*) tipParticu.Grandeur_pointee())= (*lesPtIntegMecaInterne)(iteg).TpsMetrique_const().Temps_CPU_User();break;} case NUM_ELEMENT: { *((Grandeur_scalaire_entier*) tipParticu.Grandeur_pointee())= num_elt; break;} case NUM_MAIL_ELEM: { *((Grandeur_scalaire_entier*) tipParticu.Grandeur_pointee())= num_maillage; break;} case NUM_PTI: { *((Grandeur_scalaire_entier*) tipParticu.Grandeur_pointee())= iteg; break;} default: ; }; }; }; // suppression des bases de passages if (gamma0 != NULL) {delete gamma0; delete gammat; delete gammatdt; delete beta0; delete betat; delete betatdt;}; // liberation des tenseurs intermediaires LibereTenseur(); def->Retour_pti_precedant(); // on revient au pti initial }; // récupération de grandeurs particulières pour une face au numéro d'ordre = iteg // celles-ci peuvent être quelconques // en retour liTQ est modifié et contiend les infos sur les grandeurs particulières // absolue: indique si oui ou non on sort les tenseurs dans la base absolue ou une base particulière void ElemMeca::Grandeur_particuliere_face (bool absolue,List_io& liTQ,int face, int iteg) { // on s'intéresse au information stockée au niveau des points d'intégration // pour tenir compte du fait qu'il peut y avoir plusieurs fois la même information, ces dernières sont systématiquement // stockées dans des tableaux, et on associe à ce tableau un indice qui indique aux méthodes appelées, à quel endroit // elles doivent écrire les infos. les indices sont stockés dans une liste de même dim que liTQ list decal(liTQ.size(),0.); // on initi tous les membres à 0 // 0° on initialise les grandeurs à 0 pour éviter d'avoir des valeurs aléatoires // -- on commence par initialiser les conteneurs car certaines données peuvent ne pas exister List_io::iterator iquefin=liTQ.end(); List_io::iterator ique,ique_deb=liTQ.begin(); for (ique=ique_deb;ique!=iquefin;ique++) (*ique).Grandeur_pointee()->InitParDefaut(); // 1° on change le numéro de point d'intégration courant si c'est possible // on récupère l'élément frontière associée int num_face = face; // init par défaut // if(ParaGlob::AxiSymetrie()) // dans le cas d'éléments axysymétriques, les faces // {num_face += posi_tab_front_lin;}; // sont en faites les frontières lignes // if(ParaGlob::AxiSymetrie()) // dans le cas d'éléments axysymétriques, les faces // {num_face += posi_tab_front_lin;}; // sont en faites les frontières lignes // const ElemGeomC0 & elemgeom = tabb(num_face)->ElementGeometrique(); Deformation* definter=NULL; // variable de travail transitoire if (!(ParaGlob::AxiSymetrie())) { definter = defSurf(num_face); } // le cas normal est non axisymétrique else { definter = defArete(num_face);}; // en axisymétrie, c'est une def d'arête Deformation * defS = definter; // pour simplifier l'écriture if (defS != NULL) // cas où la face existe { defS->ChangeNumInteg(iteg); // 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_t_tdt ex = (defS->Cal_explicit_tdt(true)); // 3° on change éventuellement de repère (local en global) si nécessaire // a) définition des grandeurs qui sont indépendante de la boucle qui suit // dimension des vecteurs de base de la métrique int dim = met->Dim_vec_base(); // calcul des matrices de passages Mat_pleine* gamma0=NULL; Mat_pleine* gammat=NULL; Mat_pleine* gammatdt=NULL; Mat_pleine* beta0=NULL; Mat_pleine* betat=NULL; Mat_pleine* betatdt=NULL; // const Met_abstraite::Info0_t_tdt& ex = def->Remont0_t_tdt(gamma0,gammat,gammatdt); // Mat_pleine beta0(gamma0.Inverse().Transpose()); // Mat_pleine betat(gammat.Inverse().Transpose()); // Mat_pleine betatdt(gammatdt.Inverse().Transpose()); List_io::iterator il,ilfin = liTQ.end(); for (il=liTQ.begin();il!=ilfin;il++) { TypeQuelconque& tipParticu = (*il); // pour simplifier // n'intervient que si la grandeur est active: if ((*il).Activite()) { // on regarde si c'est une grandeur locale ou pas if (tipParticu.TypeExpressionGrandeur()==0) // cas d'une grandeur exprimée dans le repère locale, changement de repère { // calcul des matrices de passages, au premier passage if (gamma0 == NULL) { Mat_pleine Aa0(dim,dim),Aat(dim,dim),Aatdt(dim,dim); const Met_abstraite::Info0_t_tdt& ex = defS->Remont0_t_tdt(absolue,Aa0,Aat,Aatdt); // a) ----- dans le sens: gi -> Ia // on a: g^i = A^i_{.a} * I^a ou Ip^a suivant que absolue est true ou false // si false, cela veut dire que Ip^a est un repère ad hoc // sinon cela veut dire que c'est le repère absolu donc I_a = I^a // et g_j = B_j^{.a} * I_a d'où [B_j^{.a}] = [A^i_{.a}]^{-1T} // // b) ----- dans le sens: Ia -> gi // pour les formules de passage de repère il nous faut : // Ip_a = beta_a^{.j} g_j et Ip^b = gamma^b_{.j} g^j // on a alors : [beta_a^{.j}] = [Aa^j_{.a}]^T // et [gamma^b_{.j}] = [beta_a^{.j}]^{-1T} = [Aa^j_{.a}]^{-1} // // au final: [beta_a^{.j}] = [Aa^j_{.a}]^T // [gamma^b_{.j}] = [Aa^j_{.a}]^{-1} // [B_j^{.a}] = [gamma^b_{.j}]^T gamma0 = new Mat_pleine(Aa0.Inverse()); gammat = new Mat_pleine(Aat.Inverse()); gammatdt = new Mat_pleine(Aatdt.Inverse()); // on détermine également les matrices beta beta0 = new Mat_pleine(Aa0.Transpose()); betat = new Mat_pleine(Aat.Transpose()); betatdt = new Mat_pleine(Aatdt.Transpose()); }; tipParticu.Change_repere(*beta0,*betat,*betatdt,*gamma0,*gammat,*gammatdt); }; // on la boucle également pour mettre à jour les grandeurs quelconque liés à la face de l'élément // 1) -----cas du module de compressibilité ou de cisaillement totale switch (tipParticu.EnuTypeQuelconque().EnumTQ()) { case POSITION_GEOMETRIQUE : {Grandeur_coordonnee& gr= *((Grandeur_coordonnee*) (tipParticu.Grandeur_pointee())); (*gr.ConteneurCoordonnee())= defS->Position_tdt(); break; } case POSITION_GEOMETRIQUE_t : {Grandeur_coordonnee& gr= *((Grandeur_coordonnee*) (tipParticu.Grandeur_pointee())); (*gr.ConteneurCoordonnee())= defS->Position_t(); break; } case POSITION_GEOMETRIQUE_t0 : {Grandeur_coordonnee& gr= *((Grandeur_coordonnee*) (tipParticu.Grandeur_pointee())); (*gr.ConteneurCoordonnee())= defS->Position_0(); break; } case VECT_PRESSION: {// on récupère les infos Grandeur_coordonnee& gr= *((Grandeur_coordonnee*) (tipParticu.Grandeur_pointee())); if (lesChargeExtSurEle != NULL) {if (lesChargeExtSurEle->LesPressionsExternes() != NULL) // cas où il existe des pressions sauvegardées { Tableau >& lesPressionsExternes = *lesChargeExtSurEle->LesPressionsExternes(); // on se positionne sur la face if (lesPressionsExternes(num_face).Taille() != 0) { Tableau & tab_press_appliquee = (lesPressionsExternes(num_face)); // pour simplifier if (tab_press_appliquee.Taille()) {(*gr.ConteneurCoordonnee())=tab_press_appliquee(iteg).P; }; }; }; }; break; } case VECT_DIR_FIXE: {// on récupère les infos Grandeur_coordonnee& gr= *((Grandeur_coordonnee*) (tipParticu.Grandeur_pointee())); if (lesChargeExtSurEle != NULL) { if (lesChargeExtSurEle->LesEffortsDirFixe() != NULL) // cas où il existe des valeurs sauvegardées { Tableau >& lesForcesExternes = *lesChargeExtSurEle->LesEffortsDirFixe(); // on se positionne sur la face if (lesForcesExternes(num_face).Taille() != 0) { Tableau & tab_force_appliquee = (lesForcesExternes(num_face)); // pour simplifier if (tab_force_appliquee.Taille()) {(*gr.ConteneurCoordonnee())=tab_force_appliquee(iteg); }; }; }; }; break; } case VECT_SURF_SUIV: {// on récupère les infos Grandeur_coordonnee& gr= *((Grandeur_coordonnee*) (tipParticu.Grandeur_pointee())); if (lesChargeExtSurEle != NULL) { if (lesChargeExtSurEle->LesPressDir() != NULL) // cas où il existe des valeurs sauvegardées { Tableau >& lesForcesExternes = *lesChargeExtSurEle->LesPressDir(); // on se positionne sur la num_face if (lesForcesExternes(num_face).Taille() != 0) { Tableau & tab_force_appliquee = (lesForcesExternes(num_face)); // pour simplifier if (tab_force_appliquee.Taille()) {(*gr.ConteneurCoordonnee())=tab_force_appliquee(iteg); }; }; }; }; break; } case VECT_HYDRODYNA_Fn:case VECT_HYDRODYNA_Ft:case VECT_HYDRODYNA_T: {// on récupère les infos Grandeur_coordonnee& gr= *((Grandeur_coordonnee*) (tipParticu.Grandeur_pointee())); if (lesChargeExtSurEle != NULL) { if (lesChargeExtSurEle->LesHydroDyna() != NULL) // cas où il existe des valeurs sauvegardées { Tableau >& lesForcesExternes = *lesChargeExtSurEle->LesHydroDyna(); // on se positionne sur la face if (lesForcesExternes(num_face).Taille() != 0) { Tableau & tab_force_appliquee = (lesForcesExternes(num_face)); // pour simplifier switch (tipParticu.EnuTypeQuelconque().EnumTQ()) {case VECT_HYDRODYNA_Fn: (*gr.ConteneurCoordonnee())=tab_force_appliquee(iteg).F_n; break; case VECT_HYDRODYNA_Ft: (*gr.ConteneurCoordonnee())=tab_force_appliquee(iteg).F_t; break; case VECT_HYDRODYNA_T: (*gr.ConteneurCoordonnee())=tab_force_appliquee(iteg).T; break; default: break; }; }; }; }; break; } case NN_SURF: {// on récupère les infos Grandeur_coordonnee& gr= *((Grandeur_coordonnee*) (tipParticu.Grandeur_pointee())); // la normale vaut le produit vectoriel des 2 premiers vecteurs (*gr.ConteneurCoordonnee()) = Util::ProdVec_coorBN( (*ex.giB_tdt)(1), (*ex.giB_tdt)(2)); gr.ConteneurCoordonnee()->Normer(); // que l'on norme break; }; case NN_SURF_t: {// on récupère les infos Grandeur_coordonnee& gr= *((Grandeur_coordonnee*) (tipParticu.Grandeur_pointee())); // la normale vaut le produit vectoriel des 2 premiers vecteurs (*gr.ConteneurCoordonnee()) = Util::ProdVec_coorBN( (*ex.giB_t)(1), (*ex.giB_t)(2)); gr.ConteneurCoordonnee()->Normer(); // que l'on norme break; }; case NN_SURF_t0: {// on récupère les infos Grandeur_coordonnee& gr= *((Grandeur_coordonnee*) (tipParticu.Grandeur_pointee())); // la normale vaut le produit vectoriel des 2 premiers vecteurs (*gr.ConteneurCoordonnee()) = Util::ProdVec_coorBN( (*ex.giB_0)(1), (*ex.giB_0)(2)); gr.ConteneurCoordonnee()->Normer(); // que l'on norme break; }; case NUM_ELEMENT: { *((Grandeur_scalaire_entier*) tipParticu.Grandeur_pointee())= num_elt; break;} case NUM_MAIL_ELEM: { *((Grandeur_scalaire_entier*) tipParticu.Grandeur_pointee())= num_maillage; break;} case NUM_FACE: { *((Grandeur_scalaire_entier*) tipParticu.Grandeur_pointee())= num_face; break;} case NUM_PTI: { *((Grandeur_scalaire_entier*) tipParticu.Grandeur_pointee())= iteg; break; } case PRESSION_SCALAIRE: {// on récupère les infos Grandeur_scalaire_double& gr= *((Grandeur_scalaire_double*) (tipParticu.Grandeur_pointee())); if (lesChargeExtSurEle != NULL) {if (lesChargeExtSurEle->LesPressionsExternes() != NULL) // cas où il existe des pressions sauvegardées { Tableau >& lesPressionsExternes = *lesChargeExtSurEle->LesPressionsExternes(); // on se positionne sur la face if (lesPressionsExternes(num_face).Taille() != 0) { Tableau & tab_press_appliquee = (lesPressionsExternes(num_face)); // pour simplifier if (tab_press_appliquee.Taille()) {(*gr.ConteneurDouble())=tab_press_appliquee(iteg).press; //// --- debug //cout << "\n debug ElemMeca::Grandeur_particuliere_face ( "; //cout << "\n pression = "<< }; }; }; }; break; } default: ; }; }; }; // suppression des bases de passages if (gamma0 != NULL) {delete gamma0; delete gammat; delete gammatdt; delete beta0; delete betat; delete betatdt;}; // liberation des tenseurs intermediaires LibereTenseur(); defS->Retour_pti_precedant(); // on revient au pti initial }; }; // récupération de grandeurs particulières pour une arête au numéro d'ordre = iteg // celles-ci peuvent être quelconques // en retour liTQ est modifié et contiend les infos sur les grandeurs particulières // absolue: indique si oui ou non on sort les tenseurs dans la base absolue ou une base particulière void ElemMeca::Grandeur_particuliere_arete (bool absolue,List_io& liTQ,int arete, int iteg) { // on s'intéresse au information stockée au niveau des points d'intégration // pour tenir compte du fait qu'il peut y avoir plusieurs fois la même information, ces dernières sont systématiquement // stockées dans des tableaux, et on associe à ce tableau un indice qui indique aux méthodes appelées, à quel endroit // elles doivent écrire les infos. les indices sont stockés dans une liste de même dim que liTQ list decal(liTQ.size(),0.); // on initi tous les membres à 0 // 0° on initialise les grandeurs à 0 pour éviter d'avoir des valeurs aléatoires // -- on commence par initialiser les conteneurs car certaines données peuvent ne pas exister List_io::iterator iquefin=liTQ.end(); List_io::iterator ique,ique_deb=liTQ.begin(); for (ique=ique_deb;ique!=iquefin;ique++) (*ique).Grandeur_pointee()->InitParDefaut(); // 1° on change le numéro de point d'intégration courant si c'est possible Deformation * defA = defArete(arete); // pour simplifier l'écriture if (defA != NULL) {defA->ChangeNumInteg(iteg); // 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_t_tdt ex = (defA->Cal_explicit_tdt(true)); // 3° on change éventuellement de repère (local en global) si nécessaire // a) définition des grandeurs qui sont indépendante de la boucle qui suit // dimension des vecteurs de base de la métrique int dim = met->Dim_vec_base(); // calcul des matrices de passages Mat_pleine* gamma0=NULL; Mat_pleine* gammat=NULL; Mat_pleine* gammatdt=NULL; Mat_pleine* beta0=NULL; Mat_pleine* betat=NULL; Mat_pleine* betatdt=NULL; // const Met_abstraite::Info0_t_tdt& ex = def->Remont0_t_tdt(gamma0,gammat,gammatdt); // Mat_pleine beta0(gamma0.Inverse().Transpose()); // Mat_pleine betat(gammat.Inverse().Transpose()); // Mat_pleine betatdt(gammatdt.Inverse().Transpose()); List_io::iterator il,ilfin = liTQ.end(); for (il=liTQ.begin();il!=ilfin;il++) { TypeQuelconque& tipParticu = (*il); // pour simplifier // n'intervient que si la grandeur est active: if ((*il).Activite()) { // on regarde si c'est une grandeur locale ou pas if (tipParticu.TypeExpressionGrandeur()==0) // cas d'une grandeur exprimée dans le repère locale, changement de repère { // calcul des matrices de passages, au premier passage if (gamma0 == NULL) { Mat_pleine Aa0(dim,dim),Aat(dim,dim),Aatdt(dim,dim); const Met_abstraite::Info0_t_tdt& ex = defA->Remont0_t_tdt(absolue,Aa0,Aat,Aatdt); // a) ----- dans le sens: gi -> Ia // on a: g^i = A^i_{.a} * I^a ou Ip^a suivant que absolue est true ou false // si false, cela veut dire que Ip^a est un repère ad hoc // sinon cela veut dire que c'est le repère absolu donc I_a = I^a // et g_j = B_j^{.a} * I_a d'où [B_j^{.a}] = [A^i_{.a}]^{-1T} // // b) ----- dans le sens: Ia -> gi // pour les formules de passage de repère il nous faut : // Ip_a = beta_a^{.j} g_j et Ip^b = gamma^b_{.j} g^j // on a alors : [beta_a^{.j}] = [Aa^j_{.a}]^T // et [gamma^b_{.j}] = [beta_a^{.j}]^{-1T} = [Aa^j_{.a}]^{-1} // // au final: [beta_a^{.j}] = [Aa^j_{.a}]^T // [gamma^b_{.j}] = [Aa^j_{.a}]^{-1} // [B_j^{.a}] = [gamma^b_{.j}]^T gamma0 = new Mat_pleine(Aa0.Inverse()); gammat = new Mat_pleine(Aat.Inverse()); gammatdt = new Mat_pleine(Aatdt.Inverse()); // on détermine également les matrices beta beta0 = new Mat_pleine(Aa0.Transpose()); betat = new Mat_pleine(Aat.Transpose()); betatdt = new Mat_pleine(Aatdt.Transpose()); }; tipParticu.Change_repere(*beta0,*betat,*betatdt,*gamma0,*gammat,*gammatdt); }; // on la boucle également pour mettre à jour les grandeurs quelconque liés à la arete de l'élément // 1) -----cas du module de compressibilité ou de cisaillement totale switch (tipParticu.EnuTypeQuelconque().EnumTQ()) { case POSITION_GEOMETRIQUE : {Grandeur_coordonnee& gr= *((Grandeur_coordonnee*) (tipParticu.Grandeur_pointee())); (*gr.ConteneurCoordonnee())= defA->Position_tdt(); break; } case POSITION_GEOMETRIQUE_t : {Grandeur_coordonnee& gr= *((Grandeur_coordonnee*) (tipParticu.Grandeur_pointee())); (*gr.ConteneurCoordonnee())= defA->Position_t(); break; } case POSITION_GEOMETRIQUE_t0 : {Grandeur_coordonnee& gr= *((Grandeur_coordonnee*) (tipParticu.Grandeur_pointee())); (*gr.ConteneurCoordonnee())= defA->Position_0(); break; } case VECT_LINE: {// on récupère les infos Grandeur_coordonnee& gr= *((Grandeur_coordonnee*) (tipParticu.Grandeur_pointee())); if (lesChargeExtSurEle != NULL) { if (lesChargeExtSurEle->LesLineique() != NULL) // cas où il existe des valeurs sauvegardées { Tableau >& lesForcesExternes = *lesChargeExtSurEle->LesLineique(); // on se positionne sur la arete if (lesForcesExternes(arete).Taille() != 0) { Tableau & tab_force_appliquee = (lesForcesExternes(arete)); // pour simplifier if (tab_force_appliquee.Taille()) {(*gr.ConteneurCoordonnee())=tab_force_appliquee(iteg); }; }; }; }; break; } case VECT_LINE_SUIV: {// on récupère les infos Grandeur_coordonnee& gr= *((Grandeur_coordonnee*) (tipParticu.Grandeur_pointee())); if (lesChargeExtSurEle != NULL) { if (lesChargeExtSurEle->LesLineiqueSuiveuse() != NULL) // cas où il existe des valeurs sauvegardées { Tableau >& lesForcesExternes = *lesChargeExtSurEle->LesLineiqueSuiveuse(); // on se positionne sur la arete if (lesForcesExternes(arete).Taille() != 0) { Tableau & tab_force_appliquee = (lesForcesExternes(arete)); // pour simplifier if (tab_force_appliquee.Taille()) {(*gr.ConteneurCoordonnee())=tab_force_appliquee(iteg); }; }; }; }; break; } case NUM_ELEMENT: { *((Grandeur_scalaire_entier*) tipParticu.Grandeur_pointee())= num_elt; break;} case NUM_MAIL_ELEM: { *((Grandeur_scalaire_entier*) tipParticu.Grandeur_pointee())= num_maillage; break;} case NUM_ARETE: { *((Grandeur_scalaire_entier*) tipParticu.Grandeur_pointee())= arete; break;} case NUM_PTI: { *((Grandeur_scalaire_entier*) tipParticu.Grandeur_pointee())= iteg; break; } default: ; }; }; }; // suppression des bases de passages if (gamma0 != NULL) {delete gamma0; delete gammat; delete gammatdt; delete beta0; delete betat; delete betatdt;}; // liberation des tenseurs intermediaires LibereTenseur(); defA->Retour_pti_precedant(); // on revient au pti initial }; }; // --- transfert des grandeurs des points d'intégration aux noeuds // transfert de ddl des points d'intégrations (de tous) aux noeuds d'un éléments (on ajoute aux noeuds, on ne remplace pas) // les ddl doivent déjà exister aux noeuds sinon erreur // il doit s'agir du même type de répartition de pt d'integ pour toutes les grandeurs // tab_val(i)(j) : valeur associée au i ième pt d'integ et au j ième ddl_enum_etendu void ElemMeca::TransfertAjoutAuNoeuds(const List_io < Ddl_enum_etendu >& lietendu ,const Tableau > & tab_val,int cas) {List_io < Ddl_enum_etendu >::const_iterator ili,ilifin = lietendu.end(); // on récupère l'élément géométrique associé au ddl pur du premier ddl étendu, ili = lietendu.begin(); Enum_ddl enu = (*ili).Enum(); int indice = 1; for (ili = lietendu.begin();ili!=ilifin;ili++,indice++) { // cas normal courant // récupération des tableaux d'indiçage pour le calcul aux noeuds const ElemGeomC0& elemgeom = ElementGeometrie(enu); // on récupère le nombre de noeud de l'élément géométrique (qui peut-être différent de celui de l'élément // par ex: element sfe, donc on utilise les noeuds de l'élément géom. On considère que ce sont les premiers // du tableau des noeuds int nbn = elemgeom.Nbne(); const ElemGeomC0::ConteneurExtrapolation & contExtra = elemgeom.ExtrapolationNoeud(cas); // calcul des valeurs aux noeuds // val_au_noeud(i) = somme_(de j=indir(i)(1) à indir(i)(taille(indice(i)) )) {tab(i)(j) * val_pt_integ(j) } for (int ine=1;ine<=nbn;ine++) { Ddl_etendu& de = tab_noeud(ine)->ModifDdl_etendu(*ili); Tableau & indir = contExtra.indir(ine); // pour simplifier int nbindir = indir.Taille(); for (int j=1; j<= nbindir; j++) de.Valeur() += contExtra.tab(ine)(indir(j)) * tab_val(indir(j))(indice); }; }; }; // transfert de type quelconque des points d'intégrations (de tous) aux noeuds d'un éléments (on ajoute aux noeuds, // on ne remplace pas). Les types quelconques doivent déjà exister. // un tableau tab_liQ correspondent aux grandeurs quelconque pour tous les pt integ. tab_liQ(i) est associé au pt d'integ i // Toutes les listes sont identiques au niveau des descripteurs (types...) ce sont uniquement les valeurs numériques // c-a-dire les valeurs associées à TypeQuelconque::Grandeur qui sont différentes (elles sont associées à chaque pt d'integ) // liQ_travail: est une liste de travail qui sera utilisée dans le transfert void ElemMeca::TransfertAjoutAuNoeuds(const Tableau >& tab_liQ ,List_io < TypeQuelconque > & liQ_travail,int cas) {int nb_pt_integ = lesPtIntegMecaInterne->NbPti(); // ---- modif transitoire pour la sortie des coques !!!! // on s'occupe uniquement de la première couche d'élément if ((this->PoutrePlaqueCoque() == COQUE)||(this->PoutrePlaqueCoque() == PLAQUE)) nb_pt_integ = this->NbPtIntegSurface(SIG11); // SIG11 arbitraire car c'est les pt d'integ classique //------- fin modif transitoire -------- if (tab_liQ.Taille() == 0) return; // cas où on n'a rien à faire #ifdef MISE_AU_POINT if (nb_pt_integ != tab_liQ.Taille()) { cout << "\n erreur de dimension, la taille de tab_liQ= " << tab_liQ.Taille() << " n'est pas egale " << " au nombre de pt_d'integ de l'element : " << nb_pt_integ ; cout << "\n ElemMeca::TransfertAjoutAuNoeuds(... " << endl; Sortie(1); } #endif //---- pour le debug //cout << " \n debug ElemMeca::TransfertAjoutAuNoeuds " << tab_liQ << endl; //--- fin pour le debug // sinon on a au moins un élément, on récupère la 1ère liste qui nous servira pour les descripteurs List_io & liQ_ref = tab_liQ(1); // pour simplifier List_io < TypeQuelconque >::const_iterator ili_ref,ilifin_ref=liQ_ref.end(); // la liste de travail List_io < TypeQuelconque >::iterator ili_travail = liQ_travail.begin(); // on définit un tableau d'itérator de dimension = le nb de pt d'integ static Tableau < List_io < TypeQuelconque >::const_iterator > tab_iterator; // on le redimentionne si besoin est tab_iterator.Change_taille(nb_pt_integ); // on définit ses éléments for (int ia=1;ia<=nb_pt_integ;ia++) tab_iterator(ia) = tab_liQ(ia).begin(); // on boucle sur les éléments de la liste de référence for (ili_ref = liQ_ref.begin();ili_ref != ilifin_ref;ili_ref++,ili_travail++) { // on récupère l'élément géométrique associé au ddl pur dont les valeurs sont calculées aux mêmes // endroits que la grandeur quelconque Enum_ddl enu = (*ili_ref). Enum(); const ElemGeomC0& elemgeom = ElementGeometrie(enu); // on récupère le nombre de noeud de l'élément géométrique (qui peut-être différent de celui de l'élément // par ex: element sfe, donc on utilise les noeuds de l'élément géom. On considère que ce sont les premiers // du tableau des noeuds int nbn = elemgeom.Nbne(); // récupération des tableaux d'indiçage pour le calcul aux noeuds const ElemGeomC0::ConteneurExtrapolation & contExtra = elemgeom.ExtrapolationNoeud(cas); // on boucle sur les noeuds, ceci est due à la technique utilisée pour accumuler dans les conteneurs du noeud for (int ine=1;ine<=nbn;ine++) {TypeQuelconque& tq = tab_noeud(ine)->ModifGrandeur_quelconque((*ili_ref).EnuTypeQuelconque()); TypeQuelconque::Grandeur & grandeur_au_noeud = *(tq.Grandeur_pointee()); // on récupère une grandeur du même type que les grandeurs à manipuler, ceci pour accumuler TypeQuelconque::Grandeur & stockage_inter = *((*ili_travail).Grandeur_pointee()); // calcul des valeurs aux noeuds // val_au_noeud(i) = somme_(de j=indir(i)(1) à indir(i)(taille(indice(i)) )) {tab(i)(j) * val_pt_integ(j) } Tableau & indir = contExtra.indir(ine); // pour simplifier int nbindir = indir.Taille(); for (int j=1; j<= nbindir; j++) { stockage_inter *= 0.; // met à 0 la grandeur inter // tab_iterator(j) pointe sur la grandeur quelconque du point d'intégration voulu stockage_inter = *((*(tab_iterator(indir(j)))).Const_Grandeur_pointee()); // récup de la grandeur pointée //---- debug //cout << "\n debug ElemMeca::TransfertAjoutAuNoeuds: stockage_inter 1= " << stockage_inter; //-- fin debug stockage_inter *= contExtra.tab(ine)(indir(j)); // * par le coeff grandeur_au_noeud += stockage_inter; // stockage dans le noeud //---- debug //cout << " stockage_inter 2= "<< stockage_inter << " grandeur_au_noeud= " << grandeur_au_noeud; //if (Dabs(grandeur_au_noeud.GrandeurNumOrdre(2)) > 1.) // {cout << "\n ***** grandeur_au_noeud.GrandeurNumOrdre(2) = " << grandeur_au_noeud.GrandeurNumOrdre(2) // << "\n contExtra.tab= "<< contExtra.tab << " contExtra.indir= "<< contExtra.indir; // // }; // //-- fin debug }; }; // on incrémente les itérators de points d'intégration for (int ib=1;ib<=nb_pt_integ;ib++) (tab_iterator(ib))++; }; }; // accumulation aux noeuds de grandeurs venant des éléments vers leurs noeuds (exemple la pression appliquée) // autres que celles aux pti classiques, mais directements disponibles // le contenu du conteneur stockées dans liQ est utilisé en variable intermédiaire void ElemMeca::Accumul_aux_noeuds(const List_io < Ddl_enum_etendu >& lietendu ,List_io < TypeQuelconque > & liQ,int cas) {// ... cas des ddl étendu ... {List_io < Ddl_enum_etendu >::const_iterator ili,ilifin = lietendu.end(); ili = lietendu.begin(); for (ili = lietendu.begin();ili!=ilifin;ili++) {// on traite en fonctions des cas particuliers //debug //cout << "\n debug ElemMeca::Accumul_aux_noeuds" // << " *ili = " << *ili << endl; // fin debug switch ((*ili).Position()-NbEnum_ddl()) { case 94 : // cas des pressions externes {if (lesChargeExtSurEle != NULL) if (lesChargeExtSurEle->LesPressionsExternes() != NULL) // cas où il existe des pressions sauvegardées { Tableau >& lesPressionsExternes = *lesChargeExtSurEle->LesPressionsExternes(); int nb_face = lesPressionsExternes.Taille(); for (int n_face=1;n_face<=nb_face;n_face++) // on boucle sur les faces if (lesPressionsExternes(n_face).Taille() != 0) { Tableau & tab_press_appliquee = (lesPressionsExternes(n_face)); // pour simplifier int t_tail = tab_press_appliquee.Taille(); if (t_tail != 0) // cas où on a une face chargée { // on récupère l'élément frontière associée (on considère qu'il y en a forcément 1) int num_face = n_face; // init par défaut if(ParaGlob::AxiSymetrie()) // dans le cas d'éléments axysymétriques, les faces {num_face += posi_tab_front_lin;}; // sont en faites les frontières lignes const ElemGeomC0 & elemgeom = tabb(num_face)->ElementGeometrique(); int nbn = elemgeom.Nbne(); const ElemGeomC0::ConteneurExtrapolation & contExtra = elemgeom.ExtrapolationNoeud(cas); Tableau & tab_noe = tabb(num_face)->TabNoeud(); // récup du tableau de noeuds de la frontière for (int ine=1;ine<=nbn;ine++) { Ddl_etendu& de = tab_noe(ine)->ModifDdl_etendu(*ili); Tableau & indir = contExtra.indir(ine); // pour simplifier int nbindir = indir.Taille(); for (int j=1; j<= nbindir; j++) { de.Valeur() += contExtra.tab(ine)(indir(j)) * tab_press_appliquee(indir(j)).press; //debug //cout << "\n debug ElemMeca::Accumul_aux_noeuds" // << " de.Valeur() = " << de.Valeur() << endl; // fin debug } }; }; }; }; break; } default : break; // sinon on ne fait rien, cela signifie que ce n'est pas un ddl géré par l'élément }; }; }; // ... cas des grandeurs quelconque ... // on traite d'abord le cas où on n'a rien à faire if (liQ.size() == 0) return; //---- pour le debug //cout << " \n debug ElemMeca::TransfertAjoutAuNoeuds " << tab_liQ << endl; //--- fin pour le debug {List_io < TypeQuelconque >::const_iterator ili,ilifin=liQ.end(); // on boucle sur les grandeurs de la liste for (ili = liQ.begin();ili != ilifin;ili++) { // on récupère l'énuméré TypeQuelconque_enum_etendu enutq = (*ili).EnuTypeQuelconque(); switch (enutq.EnumTQ()) { case VECT_PRESSION: { // on récupère les infos pour extrapoler les valeurs if (lesChargeExtSurEle != NULL) if (lesChargeExtSurEle->LesPressionsExternes() != NULL) // cas où il existe des pressions sauvegardées { Tableau >& lesPressionsExternes = *lesChargeExtSurEle->LesPressionsExternes(); int nb_face = lesPressionsExternes.Taille(); for (int n_face=1;n_face<=nb_face;n_face++) // on boucle sur les faces if (lesPressionsExternes(n_face).Taille() != 0) { Tableau & tab_press_appliquee = (lesPressionsExternes(n_face)); // pour simplifier int t_tail = tab_press_appliquee.Taille(); if (t_tail != 0) // cas où on a une face chargée { // on récupère l'élément frontière associée (on considère qu'il y en a forcément 1) int num_face = n_face; // init par défaut if(ParaGlob::AxiSymetrie()) // dans le cas d'éléments axysymétriques, les faces {num_face += posi_tab_front_lin;}; // sont en faites les frontières lignes const ElemGeomC0 & elemgeom = tabb(num_face)->ElementGeometrique(); int nbn = elemgeom.Nbne(); const ElemGeomC0::ConteneurExtrapolation & contExtra = elemgeom.ExtrapolationNoeud(cas); Tableau & tab_noe = tabb(num_face)->TabNoeud(); // récup du tableau de noeuds de la frontière for (int ine=1;ine<=nbn;ine++) { TypeQuelconque& de = tab_noe(ine)->ModifGrandeur_quelconque(enutq); // récup des coordonnées Grandeur_coordonnee* gr_coor = ((Grandeur_coordonnee*) de.Const_Grandeur_pointee()); Coordonnee& coor = *(gr_coor->ConteneurCoordonnee()); Tableau & indir = contExtra.indir(ine); // pour simplifier int nbindir = indir.Taille(); for (int j=1; j<= nbindir; j++) { coor += contExtra.tab(ine)(indir(j)) * tab_press_appliquee(indir(j)).P; //debug //cout << "\n debug ElemMeca::Accumul_aux_noeuds" // << " de.Valeur() = " << de.Valeur() << endl; // fin debug } }; }; }; }; } break; case VECT_FORCE_VOLUM: { // on récupère les infos pour extrapoler les valeurs if (lesChargeExtSurEle != NULL) if (lesChargeExtSurEle->Force_volume() != NULL) // cas où il existe des F volume sauvegardées { Tableau & force_volume = *lesChargeExtSurEle->Force_volume(); int t_tail = force_volume.Taille(); if (t_tail != 0) // cas où on a des forces volumique { // on récupère l'élément géométrique associée const ElemGeomC0& elemgeom = ElementGeometrie(X1); // on récupère le nombre de noeud de l'élément géométrique (qui peut-être différent de celui de l'élément // par ex: element sfe, donc on utilise les noeuds de l'élément géom. On considère que ce sont les premiers // du tableau des noeuds int nbn = elemgeom.Nbne(); // récupération des tableaux d'indiçage pour le calcul aux noeuds const ElemGeomC0::ConteneurExtrapolation & contExtra = elemgeom.ExtrapolationNoeud(cas); // on boucle sur les noeuds, for (int ine=1;ine<=nbn;ine++) {TypeQuelconque& tq = tab_noeud(ine)->ModifGrandeur_quelconque(enutq); // récup des coordonnées Grandeur_coordonnee* gr_coor = ((Grandeur_coordonnee*) tq.Const_Grandeur_pointee()); Coordonnee& coor = *(gr_coor->ConteneurCoordonnee()); Tableau & indir = contExtra.indir(ine); // pour simplifier int nbindir = indir.Taille(); for (int j=1; j<= nbindir; j++) { coor += (contExtra.tab(ine)(indir(j))) * force_volume(indir(j)); //debug //cout << "\n debug ElemMeca::Accumul_aux_noeuds" // << " de.Valeur() = " << de.Valeur() << endl; // fin debug } }; }; }; } break; case VECT_DIR_FIXE: { // on récupère les infos pour extrapoler les valeurs if (lesChargeExtSurEle != NULL) if (lesChargeExtSurEle->LesEffortsDirFixe() != NULL) // cas où il existe des pressions sauvegardées { Tableau >& lesForcesExternes = *lesChargeExtSurEle->LesEffortsDirFixe(); int nb_face = lesForcesExternes.Taille(); for (int n_face=1;n_face<=nb_face;n_face++) // on boucle sur les faces if (lesForcesExternes(n_face).Taille() != 0) { Tableau & tab_force_appliquee = (lesForcesExternes(n_face)); // pour simplifier int t_tail = tab_force_appliquee.Taille(); if (t_tail != 0) // cas où on a une face chargée { // on récupère l'élément frontière associée (on considère qu'il y en a forcément 1) int num_face = n_face; // init par défaut if(ParaGlob::AxiSymetrie()) // dans le cas d'éléments axysymétriques, les faces {num_face += posi_tab_front_lin;}; // sont en faites les frontières lignes const ElemGeomC0 & elemgeom = tabb(num_face)->ElementGeometrique(); int nbn = elemgeom.Nbne(); const ElemGeomC0::ConteneurExtrapolation & contExtra = elemgeom.ExtrapolationNoeud(cas); Tableau & tab_noe = tabb(num_face)->TabNoeud(); // récup du tableau de noeuds de la frontière for (int ine=1;ine<=nbn;ine++) { TypeQuelconque& de = tab_noe(ine)->ModifGrandeur_quelconque(enutq); // récup des coordonnées Grandeur_coordonnee* gr_coor = ((Grandeur_coordonnee*) de.Const_Grandeur_pointee()); Coordonnee& coor = *(gr_coor->ConteneurCoordonnee()); Tableau & indir = contExtra.indir(ine); // pour simplifier int nbindir = indir.Taille(); for (int j=1; j<= nbindir; j++) { coor += contExtra.tab(ine)(indir(j)) * tab_force_appliquee(indir(j)); //debug //cout << "\n debug ElemMeca::Accumul_aux_noeuds" // << " de.Valeur() = " << de.Valeur() << endl; // fin debug } }; }; }; }; } break; case VECT_SURF_SUIV: { // on récupère les infos pour extrapoler les valeurs if (lesChargeExtSurEle != NULL) if (lesChargeExtSurEle->LesPressDir() != NULL) // cas où il existe des pressions sauvegardées { Tableau >& lesForcesExternes = *lesChargeExtSurEle->LesPressDir(); int nb_face = lesForcesExternes.Taille(); for (int n_face=1;n_face<=nb_face;n_face++) // on boucle sur les faces if (lesForcesExternes(n_face).Taille() != 0) { Tableau & tab_force_appliquee = (lesForcesExternes(n_face)); // pour simplifier int t_tail = tab_force_appliquee.Taille(); if (t_tail != 0) // cas où on a une face chargée { // on récupère l'élément frontière associée (on considère qu'il y en a forcément 1) int num_face = n_face; // init par défaut if(ParaGlob::AxiSymetrie()) // dans le cas d'éléments axysymétriques, les faces {num_face += posi_tab_front_lin;}; // sont en faites les frontières lignes const ElemGeomC0 & elemgeom = tabb(num_face)->ElementGeometrique(); int nbn = elemgeom.Nbne(); const ElemGeomC0::ConteneurExtrapolation & contExtra = elemgeom.ExtrapolationNoeud(cas); Tableau & tab_noe = tabb(num_face)->TabNoeud(); // récup du tableau de noeuds de la frontière for (int ine=1;ine<=nbn;ine++) { TypeQuelconque& de = tab_noe(ine)->ModifGrandeur_quelconque(enutq); // récup des coordonnées Grandeur_coordonnee* gr_coor = ((Grandeur_coordonnee*) de.Const_Grandeur_pointee()); Coordonnee& coor = *(gr_coor->ConteneurCoordonnee()); Tableau & indir = contExtra.indir(ine); // pour simplifier int nbindir = indir.Taille(); for (int j=1; j<= nbindir; j++) { coor += contExtra.tab(ine)(indir(j)) * tab_force_appliquee(indir(j)); //debug //cout << "\n debug ElemMeca::Accumul_aux_noeuds" // << " de.Valeur() = " << de.Valeur() << endl; // fin debug } }; }; }; }; } break; case VECT_HYDRODYNA_Fn:case VECT_HYDRODYNA_Ft:case VECT_HYDRODYNA_T: { // on récupère les infos pour extrapoler les valeurs if (lesChargeExtSurEle != NULL) if (lesChargeExtSurEle->LesHydroDyna() != NULL) // cas où il existe des pressions sauvegardées { Tableau >& lesForcesExternes = *lesChargeExtSurEle->LesHydroDyna(); int nb_face = lesForcesExternes.Taille(); for (int n_face=1;n_face<=nb_face;n_face++) // on boucle sur les faces if (lesForcesExternes(n_face).Taille() != 0) { Tableau & tab_force_appliquee = (lesForcesExternes(n_face)); // pour simplifier int t_tail = tab_force_appliquee.Taille(); if (t_tail != 0) // cas où on a une face chargée { // on récupère l'élément frontière associée (on considère qu'il y en a forcément 1) int num_face = n_face; // init par défaut if(ParaGlob::AxiSymetrie()) // dans le cas d'éléments axysymétriques, les faces {num_face += posi_tab_front_lin;}; // sont en faites les frontières lignes const ElemGeomC0 & elemgeom = tabb(num_face)->ElementGeometrique(); int nbn = elemgeom.Nbne(); const ElemGeomC0::ConteneurExtrapolation & contExtra = elemgeom.ExtrapolationNoeud(cas); Tableau & tab_noe = tabb(num_face)->TabNoeud(); // récup du tableau de noeuds de la frontière for (int ine=1;ine<=nbn;ine++) { TypeQuelconque& de = tab_noe(ine)->ModifGrandeur_quelconque(enutq); // récup des coordonnées Grandeur_coordonnee* gr_coor = ((Grandeur_coordonnee*) de.Const_Grandeur_pointee()); Coordonnee& coor = *(gr_coor->ConteneurCoordonnee()); Tableau & indir = contExtra.indir(ine); // pour simplifier int nbindir = indir.Taille(); switch (enutq.EnumTQ()) {case VECT_HYDRODYNA_Fn: for (int j=1; j<= nbindir; j++) coor += contExtra.tab(ine)(indir(j)) * tab_force_appliquee(indir(j)).F_n; break; case VECT_HYDRODYNA_Ft: for (int j=1; j<= nbindir; j++) coor += contExtra.tab(ine)(indir(j)) * tab_force_appliquee(indir(j)).F_t; break; case VECT_HYDRODYNA_T: for (int j=1; j<= nbindir; j++) coor += contExtra.tab(ine)(indir(j)) * tab_force_appliquee(indir(j)).T; break; default: break; }; }; }; }; }; } break; case VECT_LINE: { // on récupère les infos pour extrapoler les valeurs if (lesChargeExtSurEle != NULL) if (lesChargeExtSurEle->LesLineique() != NULL) // cas où il existe des pressions sauvegardées { Tableau >& lesForcesExternes = *lesChargeExtSurEle->LesLineique(); int nb_face = lesForcesExternes.Taille(); for (int n_face=1;n_face<=nb_face;n_face++) // on boucle sur les faces if (lesForcesExternes(n_face).Taille() != 0) { Tableau & tab_force_appliquee = (lesForcesExternes(n_face)); // pour simplifier int t_tail = tab_force_appliquee.Taille(); if (t_tail != 0) // cas où on a une face chargée { // on récupère l'élément frontière associée (on considère qu'il y en a forcément 1) int num_face = n_face; // init par défaut if(ParaGlob::AxiSymetrie()) // dans le cas d'éléments axysymétriques, les faces {num_face += posi_tab_front_lin;}; // sont en faites les frontières lignes const ElemGeomC0 & elemgeom = tabb(num_face)->ElementGeometrique(); int nbn = elemgeom.Nbne(); const ElemGeomC0::ConteneurExtrapolation & contExtra = elemgeom.ExtrapolationNoeud(cas); Tableau & tab_noe = tabb(num_face)->TabNoeud(); // récup du tableau de noeuds de la frontière for (int ine=1;ine<=nbn;ine++) { TypeQuelconque& de = tab_noe(ine)->ModifGrandeur_quelconque(enutq); // récup des coordonnées Grandeur_coordonnee* gr_coor = ((Grandeur_coordonnee*) de.Const_Grandeur_pointee()); Coordonnee& coor = *(gr_coor->ConteneurCoordonnee()); Tableau & indir = contExtra.indir(ine); // pour simplifier int nbindir = indir.Taille(); for (int j=1; j<= nbindir; j++) { coor += contExtra.tab(ine)(indir(j)) * tab_force_appliquee(indir(j)); //debug //cout << "\n debug ElemMeca::Accumul_aux_noeuds" // << " de.Valeur() = " << de.Valeur() << endl; // fin debug } }; }; }; }; } break; case VECT_LINE_SUIV: { // on récupère les infos pour extrapoler les valeurs if (lesChargeExtSurEle != NULL) if (lesChargeExtSurEle->LesLineiqueSuiveuse() != NULL) // cas où il existe des pressions sauvegardées { Tableau >& lesForcesExternes = *lesChargeExtSurEle->LesLineiqueSuiveuse(); int nb_ligne = lesForcesExternes.Taille(); for (int n_ligne=1;n_ligne<=nb_ligne;n_ligne++) // on boucle sur les lignes if (lesForcesExternes(n_ligne).Taille() != 0) { Tableau & tab_force_appliquee = (lesForcesExternes(n_ligne)); // pour simplifier int t_tail = tab_force_appliquee.Taille(); if (t_tail != 0) // cas où on a une ligne chargée { // on récupère l'élément frontière associée (on considère qu'il y en a forcément 1) int num_ligne = n_ligne; // init par défaut if(ParaGlob::AxiSymetrie()) // dans le cas d'éléments axysymétriques, les lignes {num_ligne += posi_tab_front_point;} // sont en faites les frontières points else {num_ligne += posi_tab_front_lin;}; // sinon c'est des lignes const ElemGeomC0 & elemgeom = tabb(num_ligne)->ElementGeometrique(); int nbn = elemgeom.Nbne(); const ElemGeomC0::ConteneurExtrapolation & contExtra = elemgeom.ExtrapolationNoeud(cas); Tableau & tab_noe = tabb(num_ligne)->TabNoeud(); // récup du tableau de noeuds de la frontière for (int ine=1;ine<=nbn;ine++) { TypeQuelconque& de = tab_noe(ine)->ModifGrandeur_quelconque(enutq); // récup des coordonnées Grandeur_coordonnee* gr_coor = ((Grandeur_coordonnee*) de.Const_Grandeur_pointee()); Coordonnee& coor = *(gr_coor->ConteneurCoordonnee()); Tableau & indir = contExtra.indir(ine); // pour simplifier int nbindir = indir.Taille(); for (int j=1; j<= nbindir; j++) { coor += contExtra.tab(ine)(indir(j)) * tab_force_appliquee(indir(j)); //debug //cout << "\n debug ElemMeca::Accumul_aux_noeuds" // << " de.Valeur() = " << de.Valeur() << endl; // fin debug } }; }; }; }; } break; // case VECT_REAC: // // là on ne fait rien car la grandeur est directement à construire via les noeuds // // et ceci est fait dans la routine: // // lesMaillages->PassageInterneDansNoeud_composantes_vers_vectorielles() // break; default: // VECT_PRESSION pour l'instant il n'y a aucune grandeur a priori qui est disponible directement // donc message d'erreur cout << "\n cas de grandeur actuellement non traité " << "\n pas de grandeur " << (*ili).EnuTypeQuelconque().NomPlein() << " dans l'element " << "\n ou cas non implante pour l'instant" << "\n ElemMeca::Accumul_aux_noeuds(...."; }; }; }; }; // procedure permettant de completer l'element, en ce qui concerne les variables gérés // par ElemMeca, apres sa creation avec les donnees du bloc transmis // peut etre appeler plusieurs fois Element* ElemMeca::Complete_ElemMeca(BlocGen & bloc,LesFonctions_nD* lesFonctionsnD) { // avant toute chose, une complétion hors bloc, concernant la stabilisation if (pt_StabMembBiel != NULL) // ne sert qu'après un démarrage initial sur un base_info // donc dans la pratique ne sert pas souvent, mais existe pour que // ElemMeca::StabMembBiel::Lecture_bas_inf soit correcte pt_StabMembBiel->Complete_StabMembBiel(lesFonctionsnD); // cas de la masse volumique if (bloc.Nom(1) == "masse_volumique") { masse_volumique = bloc.Val(1); return this; } // cas de données thermique else if (bloc.Nom(1) == "dilatation_thermique") { if (bloc.Val(1) == 1) {dilatation=1;} else {dilatation = 0;}; return this; }; // cas de la définition d'une intégrale sur le volume // on prévoit une intégrale via les pti, on utilise donc le ddl EPS11 pour la position // (*index_Integ_vol_typeQuel)(ii) contient alors le numéro de l'intégrale qui a été // demandé par l'utilisateur = le numéro d'apparition dans le .info // idem pour (*index_Integ_vol_t_typeQuel)(ii) if (bloc.Nom(1) == "integrale_sur_volume_") { if (bloc.Nom(2) == "un_ddl_etendu_") { // il s'agit d'une intégrale d'un ddl étendu de nom: bloc.Nom(3) Ddl_etendu ddl(Ddl_enum_etendu(bloc.Nom(3))) ;// on crée un ddl ad hoc Grandeur_Ddl_etendu grand_courant(ddl,bloc.Nom(4));// le conteneur ad hoc TypeQuelconque typQ(INTEG_SUR_VOLUME,EPS11,grand_courant); // on garde en mémoire le TypeQuelconque_enum_etendu associé // -- on crée le nom de référence // string nom(NomTypeQuelconque(INTEG_SUR_VOLUME)+"_"+bloc.Nom(4)+"_" // +ChangeEntierSTring(bloc.Val(1))); // modif le 29 janvier 2018 version >= 6.827, on ne met plus le chiffre du rang // de l'intégrale à la fin, car le rang peu changer après un restart par exemple // du coup c'est une complexité qui n'apporte pas d'info sup, car la rang est stocké dans l'index string nom(NomTypeQuelconque(INTEG_SUR_VOLUME)+"_"+bloc.Nom(4)+"_"); // on regarde si l'identificateur existe déjà, sinon on le crée if (!TypeQuelconque_enum_etendu::VerifExistence(nom)) TypeQuelconque_enum_etendu::Ajout_un_TypeQuelconque_enum_etendu (INTEG_SUR_VOLUME,nom,typQ.EnuTypeGrandeur()); // puis récupération TypeQuelconque_enum_etendu tqnevez = TypeQuelconque_enum_etendu::RecupTypeQuelconque_enum_etendu(nom); if (integ_vol_typeQuel == NULL) {// ici rien n'existe, donc on crée sans se poser des questions int taille = 1; integ_vol_typeQuel = new Tableau (1); integ_vol_typeQuel_t = new Tableau (1); (*integ_vol_typeQuel)(1) = typQ;(*integ_vol_typeQuel_t)(1) = typQ; index_Integ_vol_typeQuel = new Tableau (1); (*index_Integ_vol_typeQuel)(1) = (int) bloc.Val(1); enu_integ_vol_TQ = new Tableau (1); (*enu_integ_vol_TQ)(1)=tqnevez; } else {// sinon, deux cas suivant que la grandeur a déjà été enregistrée // suite à un restart par exemple , ou au contraire en n'existe pas encore // on utilise l'identificateur pour repérer l'intégrale int indic = enu_integ_vol_TQ->Contient(tqnevez); if (!indic) {// cas où l'intégrale n'existe pas déjà int taille = integ_vol_typeQuel->Taille()+1; integ_vol_typeQuel->Change_taille(taille); integ_vol_typeQuel_t->Change_taille(taille); (*integ_vol_typeQuel)(taille) = typQ; (*integ_vol_typeQuel_t)(taille) = typQ; index_Integ_vol_typeQuel->Change_taille(taille); (*index_Integ_vol_typeQuel)(taille) = (int) bloc.Val(1); enu_integ_vol_TQ->Change_taille(taille); (*enu_integ_vol_TQ)(taille)=tqnevez; } else // sinon les conteneurs existent déjà // il faut juste mettre à jour l'index { (*index_Integ_vol_typeQuel)(indic) = (int) bloc.Val(1); } ; }; } else if (bloc.Nom(2) == "une_fonction_nD_") { // il s'agit d'une intégrale d'une fonction nD de nom: bloc.Nom(3) // on récupère le pointeur de fonction correspondant: Fonction_nD * fct = lesFonctionsnD->Trouve(bloc.Nom(3)); int nb_composante = fct->NbComposante(); Grandeur_Vecteur_Nommer grand_courant(bloc.Nom(3),nb_composante,fct); TypeQuelconque typQ(INTEG_SUR_VOLUME,EPS11,grand_courant); // on garde en mémoire le TypeQuelconque_enum_etendu associé // -- on crée le nom de référence // string nom(NomTypeQuelconque(INTEG_SUR_VOLUME)+"_"+bloc.Nom(4)+"_" // +ChangeEntierSTring(bloc.Val(1))); // modif le 29 janvier 2018 version >= 6.827, on ne met plus le chiffre du rang // de l'intégrale à la fin, car le rang peu changer après un restart par exemple // du coup c'est une complexité qui n'apporte pas d'info sup, car la rang est stocké dans l'index string nom(NomTypeQuelconque(INTEG_SUR_VOLUME)+"_"+bloc.Nom(4)+"_"); // on regarde si l'identificateur existe déjà, sinon on le crée if (!TypeQuelconque_enum_etendu::VerifExistence(nom)) TypeQuelconque_enum_etendu::Ajout_un_TypeQuelconque_enum_etendu (INTEG_SUR_VOLUME,nom,typQ.EnuTypeGrandeur()); // puis récupération TypeQuelconque_enum_etendu tqnevez = TypeQuelconque_enum_etendu::RecupTypeQuelconque_enum_etendu(nom); if (integ_vol_typeQuel == NULL) { // ici rien n'existe, donc on crée sans se poser des questions int taille = 1; integ_vol_typeQuel = new Tableau (1); integ_vol_typeQuel_t = new Tableau (1); (*integ_vol_typeQuel)(1) = typQ;(*integ_vol_typeQuel_t)(1) = typQ; index_Integ_vol_typeQuel = new Tableau (1); (*index_Integ_vol_typeQuel)(1) = (int) bloc.Val(1); enu_integ_vol_TQ = new Tableau (1); (*enu_integ_vol_TQ)(1)=tqnevez; } else {// sinon, deux cas suivant que la grandeur a déjà été enregistrée // suite à un restart par exemple , ou au contraire en n'existe pas encore // on utilise l'identificateur pour repérer l'intégrale int indic = enu_integ_vol_TQ->Contient(tqnevez); if (!indic) {// cas où l'intégrale n'existe pas déjà int taille = integ_vol_typeQuel->Taille()+1; integ_vol_typeQuel->Change_taille(taille); integ_vol_typeQuel_t->Change_taille(taille); (*integ_vol_typeQuel)(taille) = typQ; (*integ_vol_typeQuel_t)(taille) = typQ; index_Integ_vol_typeQuel->Change_taille(taille); (*index_Integ_vol_typeQuel)(taille) = (int) bloc.Val(1); enu_integ_vol_TQ->Change_taille(taille); (*enu_integ_vol_TQ)(taille)=tqnevez; } else // sinon les conteneurs existent déjà // il faut juste mettre à jour l'index { (*index_Integ_vol_typeQuel)(indic) = (int) bloc.Val(1); } ; }; }; return this; } // cas de la définition d'une intégrale sur le volume et le temps else if (bloc.Nom(1) == "integrale_sur_vol_et_temps_") { if (bloc.Nom(2) == "un_ddl_etendu_") { // il s'agit d'une intégrale d'un ddl étendu de nom: bloc.Nom(3) Ddl_etendu ddl(Ddl_enum_etendu(bloc.Nom(3))) ;// on crée un ddl ad hoc Grandeur_Ddl_etendu grand_courant(ddl,bloc.Nom(4));// le conteneur ad hoc TypeQuelconque typQ(INTEG_SUR_VOLUME_ET_TEMPS,EPS11,grand_courant); // on garde en mémoire le TypeQuelconque_enum_etendu associé // -- on crée le nom de référence // string nom(NomTypeQuelconque(INTEG_SUR_VOLUME_ET_TEMPS)+"_"+bloc.Nom(4)+"_" // +ChangeEntierSTring(bloc.Val(1))); // modif le 29 janvier 2018 version >= 6.827, on ne met plus le chiffre du rang // de l'intégrale à la fin, car le rang peu changer après un restart par exemple // du coup c'est une complexité qui n'apporte pas d'info sup, car la rang est stocké dans l'index string nom(NomTypeQuelconque(INTEG_SUR_VOLUME_ET_TEMPS)+"_"+bloc.Nom(4)+"_"); // on regarde si l'identificateur existe déjà, sinon on le crée if (!TypeQuelconque_enum_etendu::VerifExistence(nom)) TypeQuelconque_enum_etendu::Ajout_un_TypeQuelconque_enum_etendu (INTEG_SUR_VOLUME_ET_TEMPS,nom,typQ.EnuTypeGrandeur()); // puis récupération TypeQuelconque_enum_etendu tqnevez = TypeQuelconque_enum_etendu::RecupTypeQuelconque_enum_etendu(nom); if (integ_vol_t_typeQuel == NULL) {// ici rien n'existe, donc on crée sans se poser des questions int taille = 1; integ_vol_t_typeQuel = new Tableau (1); integ_vol_t_typeQuel_t = new Tableau (1); (*integ_vol_t_typeQuel)(1) = typQ;(*integ_vol_t_typeQuel_t)(1) = typQ; index_Integ_vol_t_typeQuel = new Tableau (1); (*index_Integ_vol_t_typeQuel)(1) = (int) bloc.Val(1); enu_integ_vol_t_TQ = new Tableau (1); (*enu_integ_vol_t_TQ)(1)=tqnevez; } else {// sinon, deux cas suivant que la grandeur a déjà été enregistrée // suite à un restart par exemple , ou au contraire en n'existe pas encore // on utilise l'identificateur pour repérer l'intégrale int indic = enu_integ_vol_t_TQ->Contient(tqnevez); if (!indic) {int taille = integ_vol_t_typeQuel->Taille()+1; integ_vol_t_typeQuel->Change_taille(taille); integ_vol_t_typeQuel_t->Change_taille(taille); (*integ_vol_t_typeQuel)(taille) = typQ; (*integ_vol_t_typeQuel_t)(taille) = typQ; index_Integ_vol_t_typeQuel->Change_taille(taille); (*index_Integ_vol_t_typeQuel)(taille) = (int) bloc.Val(1); enu_integ_vol_t_TQ->Change_taille(taille); (*enu_integ_vol_t_TQ)(taille)=tqnevez; } else // sinon les conteneurs existent déjà // il faut juste mettre à jour l'index { (*index_Integ_vol_t_typeQuel)(indic) = (int) bloc.Val(1); } ; }; } else if (bloc.Nom(2) == "une_fonction_nD_") { // il s'agit d'une intégrale d'une fonction nD de nom: bloc.Nom(3) // on récupère le pointeur de fonction correspondant: Fonction_nD * fct = lesFonctionsnD->Trouve(bloc.Nom(3)); int nb_composante = fct->NbComposante(); Grandeur_Vecteur_Nommer grand_courant(bloc.Nom(3),nb_composante,fct); TypeQuelconque typQ(INTEG_SUR_VOLUME_ET_TEMPS,EPS11,grand_courant); // on garde en mémoire le TypeQuelconque_enum_etendu associé // -- on crée le nom de référence // string nom(NomTypeQuelconque(INTEG_SUR_VOLUME_ET_TEMPS)+"_"+bloc.Nom(4)+"_" // +ChangeEntierSTring(bloc.Val(1))); // modif le 29 janvier 2018 version >= 6.827, on ne met plus le chiffre du rang // de l'intégrale à la fin, car le rang peu changer après un restart par exemple // du coup c'est une complexité qui n'apporte pas d'info sup, car la rang est stocké dans l'index string nom(NomTypeQuelconque(INTEG_SUR_VOLUME_ET_TEMPS)+"_"+bloc.Nom(4)+"_"); if (!TypeQuelconque_enum_etendu::VerifExistence(nom)) TypeQuelconque_enum_etendu::Ajout_un_TypeQuelconque_enum_etendu (INTEG_SUR_VOLUME_ET_TEMPS,nom,typQ.EnuTypeGrandeur()); // puis récupération TypeQuelconque_enum_etendu tqnevez = TypeQuelconque_enum_etendu::RecupTypeQuelconque_enum_etendu(nom); if (integ_vol_t_typeQuel == NULL) {// ici rien n'existe, donc on crée sans se poser des questions int taille = 1; integ_vol_t_typeQuel = new Tableau (1); integ_vol_t_typeQuel_t = new Tableau (1); (*integ_vol_t_typeQuel)(1) = typQ;(*integ_vol_t_typeQuel_t)(1) = typQ; index_Integ_vol_t_typeQuel = new Tableau (1); (*index_Integ_vol_t_typeQuel)(1) = (int) bloc.Val(1); enu_integ_vol_t_TQ = new Tableau (1); (*enu_integ_vol_t_TQ)(1)=tqnevez; } else {// sinon, deux cas suivant que la grandeur a déjà été enregistrée // suite à un restart par exemple , ou au contraire en n'existe pas encore // on utilise l'identificateur pour repérer l'intégrale int indic = enu_integ_vol_t_TQ->Contient(tqnevez); if (!indic) {int taille = integ_vol_t_typeQuel->Taille()+1; integ_vol_t_typeQuel->Change_taille(taille); integ_vol_t_typeQuel_t->Change_taille(taille); (*integ_vol_t_typeQuel)(taille) = typQ; (*integ_vol_t_typeQuel_t)(taille) = typQ; index_Integ_vol_t_typeQuel->Change_taille(taille); (*index_Integ_vol_t_typeQuel)(taille) = (int) bloc.Val(1); enu_integ_vol_t_TQ->Change_taille(taille); (*enu_integ_vol_t_TQ)(taille)=tqnevez; } else // sinon les conteneurs existent déjà // il faut juste mettre à jour l'index { (*index_Integ_vol_t_typeQuel)(indic) = (int) bloc.Val(1); }; }; }; return this; } // cas de la définition d'une stabilisation transversale pour membrane ou biel else if (bloc.Nom(1) == "stabilisation_transvers_membrane_biel_") {// on vérifie qu'il s'agit d'une géométrie membrane ou biel Enum_type_geom enu_type_geom = Type_geom_generique(this->Id_geometrie()); if ((enu_type_geom != LIGNE) && (enu_type_geom != SURFACE)) {cout << "\n **** erreur, la stabilisation n'est pas prevue pour ce type d'element: "; this->Affiche(1); Sortie(1); }; // maintenant on va allouer le conteneur d'infos // pour savoir comment dimensionner le stockage // il faut prendre en compte le type de stabilisation Enum_StabMembraneBiel enu_stab = Id_Enum_StabMembraneBiel(bloc.Nom(2)); int taille_stockage = 0; // init if (!Contient_Normale_au_noeud(enu_stab)) // cas d'un stockage aux pti { // détermination de la taille en fonction du type d'élément // ** non car finalement on ne prend que les pti de surface // Enum_type_geom enu_type_geom = Type_geom_generique(this->Id_geometrie()); // switch (enu_type_geom) // { case SURFACE: // taille_stockage = NbPtIntegSurface(X1) * NbPtIntegEpaiss(X1); // break; // default: // cout << "\n *** actuellement seule les elements de surface peuvent etre stabilise ** revoir la mise en donnees ..."; // Sortie(1); // }; taille_stockage = this->ElementGeometrique().Nbi(); } else // sinon c'est un stockage aux noeuds { taille_stockage = tab_noeud.Taille();}; pt_StabMembBiel = new StabMembBiel(taille_stockage); // définition du type de stabilisation if (Type_Enum_StabMembraneBiel_existe(bloc.Nom(2))) {pt_StabMembBiel->Type_stabMembrane()= Id_Enum_StabMembraneBiel(bloc.Nom(2));} else {cout << "\n *** erreur en mise en place de la stabilisation de membrane et/ou biel: " << " le type de stabilisation "<Affiche(1); Sortie(1); }; // choix entre valeur numérique ou une fonction nD if (bloc.Nom(3) == "une_valeur_numerique_") {// dans ce cas la valeur numémrique est en string pt_StabMembBiel->Valgamma() = ChangeReel(bloc.Nom(4)); } else if (bloc.Nom(3) == "une_fonction_nD_") {// il s'agit d'une fonction nD: récupération de la fonction pt_StabMembBiel->Change_pt_fct_gamma(lesFonctionsnD->Trouve(bloc.Nom(4))); // non modif 8 mai 2022 // pour l'instant seules les variables globales sont autorisées: // if (pt_StabMembBiel->Pt_fct_gamma()->Nom_variables().Taille() == 0) // // cas où il n'y a que des variables globales {// on vérifie qu'en retour on a un scalaire // Tableau & tava = pt_StabMembBiel->Pt_fct_gamma()->Valeur_pour_variables_globales(); // pour simplifier if (pt_StabMembBiel->Pt_fct_gamma()->NbComposante() != 1) {cout << "\n *** erreur en mise en place de la stabilisation de membrane et/ou biel : " // << " la fonction nD avec grandeur(s) globale(s) ne renvoie pas un scalaire ! "; << " la fonction nD " << bloc.Nom(4) << " ne renvoie pas un unique scalaire ! "; cout << "\n element: "; this->Affiche(1); cout << "\n fonction nD : "; pt_StabMembBiel->Pt_fct_gamma()->Affiche(); Sortie(1); } } // else // {cout << "\n *** erreur en mise en place de la stabilisation: " // << " la fonction nD ne doit utiliser que des variables globales ! "; // cout << "\n element: "; this->Affiche(1); // cout << "\n fonction nD : "; pt_StabMembBiel->Pt_fct_gamma()->Affiche(); // Sortie(1); // }; } else {cout << "\n **** erreur, en mise en place de la stabilisation: " << " le mot cle: "<< bloc.Nom(3) << "n'est pas exploitable "; if (ParaGlob::NiveauImpression() > 2) cout << "\n ElemMeca::Complete_ElemMeca(.."; Sortie(1); }; // on regarde s'il y a des infos sur les limites int nb_info = (bloc.DimNom()-4)/2; // nombre de couples // on passe en revue les noms s'ils existent, > 4 // on va de 2 en 2 for (int i=1;i<= nb_info;i++) {if (bloc.Nom(3+i*2) == "affichage_stabilisation_") {pt_StabMembBiel->Change_affichage_stabilisation(ChangeEntier(bloc.Nom(4+i*2)));} else if (bloc.Nom(3+i*2) == "gestion_maxi_mini_") {pt_StabMembBiel->Change_gestion_maxi_mini(bool(ChangeEntier(bloc.Nom(4+i*2))));} else if (bloc.Nom(3+i*2) == "beta_") {pt_StabMembBiel->Change_beta(ChangeReel(bloc.Nom(4+i*2)));} else if (bloc.Nom(3+i*2) == "f_mini_") {pt_StabMembBiel->Change_f_mini(ChangeReel(bloc.Nom(4+i*2)));} else if (bloc.Nom(3+i*2) == "d_maxi_") {pt_StabMembBiel->Change_d_maxi(ChangeReel(bloc.Nom(4+i*2)));} else if (bloc.Nom(3+i*2) == "specifique_explicite_") {if (bloc.Nom(4+i*2) == "inactive_stabilisation_") pt_StabMembBiel->change_activite_en_explicite(false); else if (bloc.Nom(4+i*2) == "active_stabilisation_") pt_StabMembBiel->change_activite_en_explicite(true); } else if (bloc.Nom(3+i*2) == "ponderation_f_stab_t_") {// il s'agit d'une fonction nD: récupération de la fonction pt_StabMembBiel->Change_pt_fct_ponder_Ft(lesFonctionsnD->Trouve(bloc.Nom(4+i*2))); // on vérifie que c'est bien une fonction scalaire if (pt_StabMembBiel->Pt_fct_ponder_Ft()->NbComposante() != 1) {cout << "\n *** erreur en mise en place de la stabilisation de membrane et/ou biel : " << " la fonction nD " << bloc.Nom(4+i*2) << " n'est pas scalaire "; cout << "\n element: "; this->Affiche(1); cout << "\n fonction nD : "; pt_StabMembBiel->Pt_fct_ponder_Ft()->Affiche(); Sortie(1); }; } }; return this; } // cas de la définition d'un repère d'anisotropie else if (bloc.Nom(1) == "repere_anisotropie_") {// pour l'instant le repère d'anisotropie est éventuellement // utilisable par la loi de comportement // 1) tout d'abord on doit définir le repère au niveau de chaque point d'intégration // définition d'un repère d'anisotropie à un point d'intégration // ici on ne fait que définir les conteneurs, la définition exacte des repères // ne se fera que pendant l'initialisation de l'algo et/ou pendant le calcul int nb_pti = lesPtIntegMecaInterne->NbPti(); int dim = ParaGlob::Dimension(); Coordonnee u(dim); Tableau tab_coor(dim,u); for (int ni=1;ni<= nb_pti;ni++) {// passage des infos if (tabSaveDon(ni) != NULL) tabSaveDon(ni)->Complete_SaveResul(bloc,tab_coor,loiComp); }; return this; } // sinon rien else { return NULL;}; }; // calcul de la contrainte modifiée en fonction du bulk viscosity // ramène l'énergie par unité de volume, dépensée par le bulk DeuxDoubles ElemMeca::ModifContrainteBulk(Enum_dure temps,const TenseurHH& gijHH,TenseurHH & sigHH ,const TenseurBB & DepsBB,TenseurHH & sigbulkHH ) { DeuxDoubles ener_bulk_volumique; // pour le retour // on calcul la trace du tenseur de vitesse de déformation TenseurBH* DepsBH = NevezTenseurBH(DepsBB.Dimension()); (*DepsBH) = DepsBB * gijHH; double IDeps = DepsBH->Trace(); // on intervient que si la trace est négative dans le cas où bulk_viscosity != 2 // ou dans tous les cas si == 2 if ((bulk_viscosity == 2) || (IDeps < 0.)) { // calcul d'une longueur caractéristique de l'élément // cout << "\n c_carreBulk" << c_carreBulk << " c_traceBulk" << c_traceBulk << endl; double lon=this->LongueurGeometrique_mini(1); // cas 1 pour l'instant // on calcul la célérité double cc = sqrt(ElemMeca::Calcul_maxi_E_qui(temps)/masse_volumique); // calcul de la pression //-- double q = masse_volumique * lon * ( c_carreBulk * lon * IDeps*IDeps + c_traceBulk * cc * IDeps ); //-- modification car il y a une erreur / à la théorique concernant le signe de c_carreBulk double q = masse_volumique * lon * ( c_carreBulk * lon * IDeps*IDeps - c_traceBulk * cc * IDeps ); // calcul de la modification du tenseur sigHH //-- sigHH += q * gijHH; sigbulkHH = (-q) * gijHH; //--- debug //cout << "\n sigbulkHH= " << sigbulkHH(1,1) << " sigHH= " << sigHH(1,1) // << " lon="<PremierPtInteg(), ni = 1;def->DernierPtInteg();def->NevezPtInteg(),ni++) { def->ChangeNumInteg(ni);def->Mise_a_jour_data_specif(tabSaveDefDon(ni)); // si l'on a une thermo-dépendance il faut s'assurer que la température est mise à jour loiComp->Mise_a_jour_temperature(temps,*def); // indique également à la loi quelle valeur de saveResult il faut se référer double E_equi = loiComp->Module_young_equivalent(temps,*def,tabSaveDon(ni)); if (E_equi < mini) mini = E_equi; } return mini; }; // calcul du maxi du module d'young équivalent pour tous les points d'intégrations double ElemMeca::Calcul_maxi_E_qui(Enum_dure temps) { double maxi = 0.; // init int ni; for (def->PremierPtInteg(), ni = 1;def->DernierPtInteg();def->NevezPtInteg(),ni++) { def->ChangeNumInteg(ni);def->Mise_a_jour_data_specif(tabSaveDefDon(ni)); // si l'on a une thermo-dépendance il faut s'assurer que la température est mise à jour loiComp->Mise_a_jour_temperature(temps,*def); double E_equi = loiComp->Module_young_equivalent(temps,*def,tabSaveDon(ni)); if (E_equi > maxi) maxi = E_equi; } return maxi; }; // cas d'un chargement aero-hydrodynamique, sur les frontières de l'élément // Il y a trois forces: une suivant la direction de la vitesse: de type traînée aerodynamique // Fn = poids_volu * fn(V) * S * (normale*u) * u, u étant le vecteur directeur de V (donc unitaire) // une suivant la direction normale à la vitesse de type portance // Ft = poids_volu * ft(V) * S * (normale*u) * w, w unitaire, normal à V, et dans le plan n et V // une suivant la vitesse tangente de type frottement visqueux // T = to(Vt) * S * ut, Vt étant la vitesse tangentielle et ut étant le vecteur directeur de Vt // retourne le second membre résultant // calcul à l'instant tdt ou t en fonction de la variable atdt // coef_mul: est un coefficient multiplicateur global (de tout) Vecteur& ElemMeca::SM_charge_hydrodyn_E (const double& poidvol,const Tableau & taphi,int nbne ,Courbe1D* frot_fluid,const Vecteur& poids ,Courbe1D* coef_aero_n,int numfront,const double& coef_mul ,Courbe1D* coef_aero_t,const ParaAlgoControle & ,bool atdt) { //****************** attention voir w non normé pour les dimensions 2 et 1 **************** //****************** attention voir w non normé pour les dimensions 2 et 1 **************** //****************** attention voir w non normé pour les dimensions 2 et 1 **************** //****************** attention voir w non normé pour les dimensions 2 et 1 **************** //****************** attention voir w non normé pour les dimensions 2 et 1 **************** // *** dans l'ensemble du sp on utilise des vecteurs et on gére directement la variance // *** sinon c'est intractable et long // remarque: l'initialisation du résidu n'est pas fait ici, mais dans les routines appelants Vecteur* SM_r; int dime = 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 switch (dime) {case 3: // cas de la dimension 3 { // définition du vecteur de retour Vecteur& SM = *((*res_extS)(numfront));SM_r=&SM; // 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 Deformation & defS = *defSurf(numfront); // pour simplifier l'écriture // éventuellement dimensionnement de la sauvegarde if (lesChargeExtSurEle == NULL) lesChargeExtSurEle = new LesChargeExtSurElement; if (lesChargeExtSurEle->LesHydroDyna() == NULL) {if(ParaGlob::AxiSymetrie()) {lesChargeExtSurEle->LesHydroDyna_Change_taille(ElementGeometrique().NbSe());} else {lesChargeExtSurEle->LesHydroDyna_Change_taille(ElementGeometrique().NbFe());} }; Tableau & tab_hydrodyna= (*lesChargeExtSurEle->LesHydroDyna())(numfront); // pour simplifier if (tab_hydrodyna.Taille() != defS.Phi1_Taille()) tab_hydrodyna.Change_taille(defS.Phi1_Taille()); 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); }; // détermination de la normale à la surface qui vaut le produit vectoriel des 2 premiers vecteurs // conversion explicite en coordonnées sans variance Coordonnee normale = Util::ProdVec_coorBN( (*ex.giB_t)(1), (*ex.giB_t)(2)); // cout << "\n normale avant normalisation"; // normale.Affiche(); normale.Normer(); // on norme la normale // cout << "\n normale après normalisation"; // normale.Affiche(); Sortie(1); // récupération de la vitesse const Coordonnee* Vp; if (atdt) {Vp = &(defS.VitesseM_tdt());} else {Vp = &(defS.VitesseM_t());}; const Coordonnee& V = *Vp; double nV = V.Norme(); // dans le cas où la vitesse est trop faible, le résidu est nul if (nV < ConstMath::trespetit) return SM; Coordonnee Vt=V-(V*normale)*normale;// calcul de la vitesse tangente double nVt = Vt.Norme(); // norme de la vitesse tangente if (nVt < ConstMath::trespetit) { nVt=0.;Vt.Zero();} else {Vt /= nVt;}; // on norme la vitesse tangente Coordonnee u= V / nV; // on norme la vitesse, car ensuite on n'a besoin que de la direction unitaire de la vitesse double cos_directeur = u * normale; // permet de calculer surface normale à la vitesse Coordonnee w(3); if (coef_aero_t != NULL) {w = Util::ProdVec_coor(u,Util::ProdVec_coor( u, normale)); // si w est non nulle on le norme double norme_w = w.Norme(); if (norme_w > ConstMath::trespetit) {w /= norme_w;}; }; Force_hydroDyna& Fsauve = tab_hydrodyna(ni); // pour simplifier la sauvegarde // calcul du résidu int ix=1; int dimf = 3; // ne fonctionne qu'en dim 3 // cas de T: T = to(Vt) * S * ut, Vt étant la vitesse tangentielle et ut étant le vecteur directeur de Vt double coef_frot_fluid=0.; if (frot_fluid != NULL) { coef_frot_fluid += frot_fluid->Valeur(nVt) * poids(ni) * (*ex.jacobien_t); Fsauve.T += frot_fluid->Valeur(nVt) * Vt;}; // cas de Fn = poids_volu * fn(V) * S * (normale*u) * u, u unitaire suivant V double coef_n=0.; if (coef_aero_n != NULL) { coef_n += poidvol * coef_aero_n->Valeur(nV) * poids(ni) * (*ex.jacobien_t) * cos_directeur; Fsauve.F_n += (poidvol * coef_aero_n->Valeur(nV) * cos_directeur) * u ;}; // cas de Ft = poids_volu * ft(V) * S * (normale*u) * w, w unitaire suivant la normal à V double coef_t=0.; if (coef_aero_t != NULL) { coef_t += poidvol * coef_aero_t->Valeur(nV) * poids(ni) * (*ex.jacobien_t) * cos_directeur; Fsauve.F_t += (poidvol * coef_aero_t->Valeur(nV) * cos_directeur) * w ;}; for (int ne =1; ne<= nbne; ne++) for (int i=1;i<= dimf;i++,ix++) { SM(ix) += taphi(ni)(ne) * coef_mul * (coef_frot_fluid * Vt(i) + coef_n * u(i) + coef_t * w(i));}; } // fin boucle sur les points d'intégrations break; }; // fin du cas de la dimension 3 case 2: // cas de la dimension 2 { // définition du vecteur de retour Vecteur& SM = *((*res_extA)(numfront));SM_r=&SM; // 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 Deformation & defA = *defArete(numfront); // pour simplifier l'écriture // éventuellement dimensionnement de la sauvegarde if (lesChargeExtSurEle == NULL) lesChargeExtSurEle = new LesChargeExtSurElement; if (lesChargeExtSurEle->LesHydroDyna() == NULL) lesChargeExtSurEle->LesHydroDyna_Change_taille(ElementGeometrique().NbSe()); Tableau & tab_hydrodyna= (*lesChargeExtSurEle->LesHydroDyna())(numfront); // pour simplifier if (tab_hydrodyna.Taille() != defA.Phi1_Taille()) tab_hydrodyna.Change_taille(defA.Phi1_Taille()); 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); }; // détermination de la normale à la surface qui vaut le vecteur perpendiculaire au g1 // dans le sens directe Coordonnee normale; normale(1) = - (*ex.giB_t)(1)(2); normale(2) = (*ex.giB_t)(1)(1); normale.Normer(); // on norme la normale // récupération de la vitesse const Coordonnee* Vp; if (atdt) {Vp = &(defA.VitesseM_tdt());} else {Vp = &(defA.VitesseM_t());}; const Coordonnee& V = *Vp; double nV = V.Norme(); // dans le cas où la vitesse est trop faible, le résidu est nul if (nV < ConstMath::trespetit) return SM; Coordonnee Vt=V-(V*normale)*normale;// calcul de la vitesse tangente double nVt = Vt.Norme(); // norme de la vitesse tangente if (nVt < ConstMath::trespetit) { nVt=0.;Vt.Zero();} else {Vt /= nVt;}; // on norme la vitesse tangente Coordonnee u= V / nV; // on norme la vitesse, car ensuite on n'a besoin que de la direction unitaire de la vitesse double cos_directeur = u * normale; // permet de calculer surface normale à la vitesse Coordonnee w(dime); // comme on est en 2D w ce calcul directement avec les composantes de u if (coef_aero_t != NULL) {w(1) = -u(2); w(2)=u(1);}; Force_hydroDyna& Fsauve = tab_hydrodyna(ni); // pour simplifier la sauvegarde // calcul du résidu int ix=1; // cas de T: T = to(Vt) * S * ut, Vt étant la vitesse tangentielle et ut étant le vecteur directeur de Vt double coef_frot_fluid=0.; if (frot_fluid != NULL) { coef_frot_fluid += frot_fluid->Valeur(nVt) * poids(ni) * (*ex.jacobien_t); Fsauve.T+=frot_fluid->Valeur(nVt) * Vt;}; // cas de Fn = poids_volu * fn(V) * S * (normale*u) * u, u unitaire suivant V double coef_n=0.; if (coef_aero_n != NULL) { coef_n += poidvol * coef_aero_n->Valeur(nV) * poids(ni) * (*ex.jacobien_t) * cos_directeur; Fsauve.F_n += (poidvol * coef_aero_n->Valeur(nV) * cos_directeur) * u ;}; // cas de Ft = poids_volu * ft(V) * S * (normale*u) * w, w unitaire suivant la normal à V double coef_t=0.; if (coef_aero_t != NULL) { coef_t += poidvol * coef_aero_t->Valeur(nV) * poids(ni) * (*ex.jacobien_t) * cos_directeur; Fsauve.F_t += (poidvol * coef_aero_t->Valeur(nV) * cos_directeur) * w ;}; for (int ne =1; ne<= nbne; ne++) for (int i=1;i<= dime;i++,ix++) { SM(ix) += taphi(ni)(ne) * coef_mul * (coef_frot_fluid * Vt(i) + coef_n * u(i) + coef_t * w(i));}; } // fin boucle sur les points d'intégrations } // fin boucle sur les points d'intégrations break; case 1: // cas de la dimension 1 { // définition du vecteur de retour Vecteur& SM = *((*res_extN)(numfront));SM_r=&SM; // dans le cas ou le poid volumique est nul, on retourne sans calcul if (Dabs(poidvol) < ConstMath::trespetit) return SM; // il n'y a pas plusieurs point d'intégration // en 1D il ne peut y avoir que deux extrémités, la première à une normale = -1 , la seconde 1 Coordonnee normale(1); if (numfront == 1) {normale(1)=-1.;} else {normale(1)=1.;}; // éventuellement dimensionnement de la sauvegarde if (lesChargeExtSurEle == NULL) lesChargeExtSurEle = new LesChargeExtSurElement; if (lesChargeExtSurEle->LesHydroDyna() == NULL) lesChargeExtSurEle->LesHydroDyna_Change_taille(2); // car deux extrémités au plus Tableau & tab_hydrodyna= (*lesChargeExtSurEle->LesHydroDyna())(numfront); // pour simplifier if (tab_hydrodyna.Taille() != 1) tab_hydrodyna.Change_taille(1); // un seul point d'intégration en un point ! // récupération de la vitesse const Coordonnee* Vp; Noeud* noe = (tabb(posi_tab_front_point+numfront)->TabNoeud())(1); // on récupére tout d'abord le noeud fontière if (atdt) {Vp = &(def->VitesseM_tdt(noe));} // on utilise la déformation générale, qui convient pour un noeud else {Vp = &(def->VitesseM_t(noe));}; const Coordonnee& V = *Vp; double nV = V.Norme(); // dans le cas où la vitesse est trop faible, le résidu est nul if (nV < ConstMath::trespetit) return SM; // dans le cas 1D il n'y a qu'un effort de trainée (car pas de vitesse tangente) Coordonnee u= V / nV; // on norme la vitesse, car ensuite on n'a besoin que de la direction unitaire de la vitesse // inutile double cos_directeur = u * normale; // permet de calculer surface normale à la vitesse Force_hydroDyna& Fsauve = tab_hydrodyna(1); // pour simplifier la sauvegarde // calcul du résidu int ix=1; int dimf = dime; // cas de Fn = poids_volu * fn(V) * S * (normale*u) * u, u unitaire suivant V double coef_n=0.; if (coef_aero_n != NULL) // le poids(1) contiend la section, et il n'y a pas de jacobien, cos directeur = 1 { coef_n += poidvol * coef_aero_n->Valeur(nV) * poids(1) ; Fsauve.F_n += (poidvol * coef_aero_n->Valeur(nV) ) * u ;}; for (int ne =1; ne<= nbne; ne++) // il n'y qu'un point d'intégration le noeud lui-même for (int i=1;i<= dimf;i++,ix++) { SM(ix) += taphi(1)(ne) * coef_mul * ( coef_n * u(i) );}; break; }; // fin du cas de la dimension 1 */ }; //-- fin du switch sur la dimension // retour du second membre return *SM_r; }; // idem SM_charge_hydrodyn_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 // coef_mul: est un coefficient multiplicateur global (de tout) Element::ResRaid ElemMeca::SM_charge_hydrodyn_I (const double& poidvol,const Tableau & taphi,int nbne ,Courbe1D* frot_fluid,const Vecteur& poids,DdlElement & ddls ,Courbe1D* coef_aero_n,int numfront,const double& coef_mul ,Courbe1D* coef_aero_t,const ParaAlgoControle & pa) { //****************** attention voir w non normé pour les dimensions 2 et 1 **************** //****************** attention voir w non normé pour les dimensions 2 et 1 **************** //****************** attention voir w non normé pour les dimensions 2 et 1 **************** //****************** attention voir w non normé pour les dimensions 2 et 1 **************** //****************** attention voir w non normé pour les dimensions 2 et 1 **************** // *** dans l'ensemble du sp on utilise des vecteurs et on gére directement la variance // *** sinon c'est intractable et long // remarque: l'initialisation du résidu n'est pas fait ici, mais dans les routines appelants Element::ResRaid el; int nbddl = ddls.NbDdl(); bool avec_raid = pa.Var_charge_externe(); // controle // // 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 dime = 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 switch (dime) {case 3: // cas de la dimension 3 { // dans le cas ou le poid volumique est nul, on retourne sans calcul if (Dabs(poidvol) < ConstMath::trespetit) { el.res = (*res_extS)(numfront); el.raid = (*raid_extS)(numfront); return el; }; Vecteur& SM = (*((*res_extS)(numfront))); // pour simplifier Mat_pleine & KM = (*((*raid_extS)(numfront))); // " " " el.res = (*res_extS)(numfront); el.raid = (*raid_extS)(numfront); // pour le retour int ni; // compteur globale de point d'integration Deformation & defS = *defSurf(numfront); // pour simplifier l'écriture // éventuellement dimensionnement de la sauvegarde if (lesChargeExtSurEle == NULL) lesChargeExtSurEle = new LesChargeExtSurElement; if (lesChargeExtSurEle->LesHydroDyna() == NULL) {if(ParaGlob::AxiSymetrie()) {lesChargeExtSurEle->LesHydroDyna_Change_taille(ElementGeometrique().NbSe());} else {lesChargeExtSurEle->LesHydroDyna_Change_taille(ElementGeometrique().NbFe());} }; Tableau & tab_hydrodyna= (*lesChargeExtSurEle->LesHydroDyna())(numfront); // pour simplifier if (tab_hydrodyna.Taille() != defS.Phi1_Taille()) tab_hydrodyna.Change_taille(defS.Phi1_Taille()); 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 mais pour un calcul autre que mécanique const Met_abstraite::Impli& ex = defS.Cal_implicit(premier_calcul); // détermination de la normale à la surface qui vaut le produit vectoriel des 2 premiers vecteurs Coordonnee normale = Util::ProdVec_coorBN( (*ex.giB_tdt)(1), (*ex.giB_tdt)(2)); normale.Normer(); // on norme la normale // récupération de la vitesse const Coordonnee V = defS.VitesseM_tdt(); double nV = V.Norme(); // dans le cas où la vitesse est trop faible, le résidu est nul if (nV < ConstMath::trespetit) return el; Coordonnee Vt=V-(V*normale)*normale;// calcul de la vitesse tangente double nVt = Vt.Norme(); // norme de la vitesse tangente if (nVt < ConstMath::trespetit) { nVt=0.;Vt.Zero();} else {Vt /= nVt;}; // on norme la vitesse tangente Coordonnee u= V / nV; // on norme la vitesse, car ensuite on n'a besoin que de la direction unitaire de la vitesse double cos_directeur = u * normale; // permet de calculer surface normale à la vitesse Coordonnee w(3);double norme_w=0.; Coordonnee vecNul(3); // un vecteur nul pour l'initialisation if (coef_aero_t != NULL) {w = Util::ProdVec_coor(u,Util::ProdVec_coor( u, normale)); // si w est non nulle on le norme norme_w = w.Norme(); if (norme_w > ConstMath::trespetit) {w /= norme_w;}; }; // calcul éventuel des variations static Tableau D_Vt,D_u,D_w,D_w_non_normer; static Tableau D_coef_frot_fluid,D_coef_n,D_coef_t; if (avec_raid) { // calcul de la variation de la normale // 1) variation du produit vectoriel Tableau D_pasnormale = Util::VarProdVect_coor((*ex.giB_tdt)(1).Coor(),(*ex.giB_tdt)(2).Coor(),(*ex.d_giB_tdt)); // 2) de la normale Tableau D_normale = Util::VarUnVect_coor(normale,D_pasnormale,normale.Norme()); // récupération de la variation de vitesse bool ddl_vitesse; const Tableau D_V = defS.Der_VitesseM_tdt(ddl_vitesse); D_Vt.Change_taille(nbddl); // calcul de la variation de la vitesse tangente for (int ii=1;ii<=nbddl;ii++) {D_Vt(ii)=D_V(ii) - (D_V(ii) * normale + V * D_normale(ii)) * normale - (V*normale) * D_normale(ii);}; // variation de u D_u.Change_taille(nbddl); D_u = Util::VarUnVect_coor( V, D_V,nV); // variation de la norme de V Tableau D_nV = Util::VarNorme(D_V,V,nV); // variation de w s'il a une norme différente de 0 D_w.Change_taille(nbddl,vecNul); // !! init obligatoire car peut ne pas rentrer dans les if qui suivent if (norme_w > ConstMath::trespetit) {if (coef_aero_t != NULL) { D_w_non_normer.Change_taille(nbddl); // tout d'abord la variation du produit vectoriel Coordonnee k = Util::ProdVec_coor( u, normale); Tableau D_k = Util::VarProdVect_coor(u,normale,D_u,D_normale); D_w_non_normer=Util::VarProdVect_coor(u,k,D_u,D_k); D_w = Util::VarUnVect_coor(w,D_w_non_normer,norme_w); } }; // variation des coefficients // cas de T: T = to(Vt) * S * ut, Vt étant la vitesse tangentielle et ut étant le vecteur directeur de Vt D_coef_frot_fluid.Change_taille(nbddl); if (frot_fluid != NULL) { Courbe1D::ValDer valder = frot_fluid->Valeur_Et_derivee(nVt); for (int i=1;i<=nbddl;i++) D_coef_frot_fluid(i) = valder.derivee * D_nV(i) * poids(ni) * (*ex.jacobien_tdt) + valder.valeur * poids(ni) * (*ex.d_jacobien_tdt)(i); }; // cas de Fn = poids_volu * fn(V) * S * (normale*u) * u, u unitaire suivant V D_coef_n.Change_taille(nbddl); if (coef_aero_n != NULL) { Courbe1D::ValDer valder = coef_aero_n->Valeur_Et_derivee(nV); for (int i=1;i<=nbddl;i++) D_coef_n(i) = poidvol * poids(ni) * ( valder.derivee * D_nV(i) * (*ex.jacobien_tdt) * cos_directeur + valder.valeur * (*ex.d_jacobien_tdt)(i) * cos_directeur + valder.valeur * (*ex.jacobien_tdt) * (D_u(i) * normale + u * D_normale(i)) ); }; // cas de Ft = poids_volu * ft(V) * S * (normale*u) * w, w unitaire suivant la normal à V D_coef_t.Change_taille(nbddl); if (coef_aero_t != NULL) { Courbe1D::ValDer valder = coef_aero_t->Valeur_Et_derivee(nV); for (int i=1;i<=nbddl;i++) D_coef_t(i) = poidvol * poids(ni) * ( valder.derivee * D_nV(i) * (*ex.jacobien_tdt) * cos_directeur + valder.valeur * (*ex.d_jacobien_tdt)(i) * cos_directeur + valder.valeur * (*ex.jacobien_tdt) * (D_u(i) * normale + u * D_normale(i)) ); }; }; //-- fin du if (avec_raid) Force_hydroDyna& Fsauve = tab_hydrodyna(ni); // pour simplifier la sauvegarde // calcul du résidu int ix=1; int dimf = 3; // ne fonctionne qu'en dim 3 // cas de T: T = to(Vt) * S * ut, Vt étant la vitesse tangentielle et ut étant le vecteur directeur de Vt double coef_frot_fluid=0.; if (frot_fluid != NULL) { coef_frot_fluid += frot_fluid->Valeur(nVt) * poids(ni) * (*ex.jacobien_tdt); Fsauve.T += frot_fluid->Valeur(nVt) * Vt;}; // cas de Fn = poids_volu * fn(V) * S * (normale*u) * u, u unitaire suivant V double coef_n=0.; if (coef_aero_n != NULL) { coef_n += poidvol * coef_aero_n->Valeur(nV) * poids(ni) * (*ex.jacobien_tdt) * cos_directeur; Fsauve.F_n += (poidvol * coef_aero_n->Valeur(nV) * cos_directeur) * u ;}; // cas de Ft = poids_volu * ft(V) * S * (normale*u) * w, w unitaire suivant la normal à V double coef_t=0.; if (coef_aero_t != NULL) { coef_t += poidvol * coef_aero_t->Valeur(nV) * poids(ni) * (*ex.jacobien_tdt) * cos_directeur; Fsauve.F_t += (poidvol * coef_aero_t->Valeur(nV) * cos_directeur) * w ;}; for (int ne =1; ne<= nbne; ne++) for (int i=1;i<= dimf;i++,ix++) { SM(ix) += taphi(ni)(ne) * coef_mul * (coef_frot_fluid * Vt(i) + coef_n * u(i) + coef_t * w(i)); if (avec_raid) {for (int j =1; j<= nbddl; j++) { //cout << "\n taphi(ni)(ne)= " << taphi(ni)(ne) << endl; //cout << "\n D_coef_frot_fluid(j) " << D_coef_frot_fluid(j) << endl; //cout << "\n Vt(i) " << Vt(i) << endl; //cout << "\n D_Vt(j)(i) " << D_Vt(j)(i) << endl; //cout << "\n D_coef_n(j) " << D_coef_n(j) << endl; //cout << "\n u(i) " << u(i) << endl; //cout << "\n D_u(j)(i) " << D_u(j)(i) << endl; //cout << "\n D_coef_t(j) " << D_coef_t(j) << endl; //cout << "\n w(i) " << w(i) << endl; //cout << "\n D_w(j)(i) " << D_w(j)(i) << endl; KM(ix,j) -= taphi(ni)(ne) * coef_mul *( D_coef_frot_fluid(j) * Vt(i) + coef_frot_fluid * D_Vt(j)(i) + D_coef_n(j) * u(i) + coef_n * D_u(j)(i) + D_coef_t(j) * w(i) + coef_t * D_w(j)(i) ); }; }; }; } // fin boucle sur les points d'intégrations break; }; // fin du cas de la dimension 3 case 2: // cas de la dimension 2 { // dans le cas ou le poid volumique est nul, on retourne sans calcul if (Dabs(poidvol) < ConstMath::trespetit) { el.res = (*res_extS)(numfront); el.raid = (*raid_extS)(numfront); return el; }; Vecteur& SM = (*((*res_extA)(numfront))); // pour simplifier Mat_pleine & KM = (*((*raid_extA)(numfront))); // " " " el.res = (*res_extA)(numfront); el.raid = (*raid_extA)(numfront); // pour le retour int ni; // compteur globale de point d'integration Deformation & defA = *defArete(numfront); // pour simplifier l'écriture // éventuellement dimensionnement de la sauvegarde if (lesChargeExtSurEle == NULL) lesChargeExtSurEle = new LesChargeExtSurElement; if (lesChargeExtSurEle->LesHydroDyna() == NULL) lesChargeExtSurEle->LesHydroDyna_Change_taille(ElementGeometrique().NbSe()); Tableau & tab_hydrodyna= (*lesChargeExtSurEle->LesHydroDyna())(numfront); // pour simplifier if (tab_hydrodyna.Taille() != defA.Phi1_Taille()) tab_hydrodyna.Change_taille(defA.Phi1_Taille()); 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 const Met_abstraite::Impli& ex = defA.Cal_implicit(premier_calcul); // détermination de la normale à la surface qui vaut le vecteur perpendiculaire au g1 // dans le sens directe Coordonnee normale; normale(1) = -(*ex.giB_tdt)(1)(2); normale(2) = (*ex.giB_tdt)(1)(1); normale.Normer(); // on norme la normale // récupération de la vitesse const Coordonnee V = defA.VitesseM_tdt(); double nV = V.Norme(); // dans le cas où la vitesse est trop faible, le résidu est nul if (nV < ConstMath::trespetit) return el; Coordonnee Vt=V-(V*normale)*normale;// calcul de la vitesse tangente double nVt = Vt.Norme(); // norme de la vitesse tangente if (nVt < ConstMath::trespetit) { nVt=0.;Vt.Zero();} else {Vt /= nVt;}; // on norme la vitesse tangente Coordonnee u= V / nV; // on norme la vitesse, car ensuite on n'a besoin que de la direction unitaire de la vitesse double cos_directeur = u * normale; // permet de calculer surface normale à la vitesse Coordonnee w(dime); // comme on est en 2D, w ce calcul directement avec les composantes de u if (coef_aero_t != NULL) {w(1) = -u(2); w(2)=u(1);}; // calcul éventuel des variations static Tableau D_Vt,D_u,D_w; static Tableau D_coef_frot_fluid,D_coef_n,D_coef_t; if (avec_raid) { // calcul de la variation de la normale // 1) variation du produit vectoriel Tableau D_pasnormale(nbddl); for (int i=1;i<=nbddl;i++) {D_pasnormale(i)(1) = -(*ex.d_giB_tdt)(i)(1)(2); D_pasnormale(i)(2) = (*ex.d_giB_tdt)(i)(1)(1);}; // 2) de la normale Tableau D_normale = Util::VarUnVect_coor(normale,D_pasnormale,normale.Norme()); // récupération de la variation de vitesse bool ddl_vitesse; const Tableau D_V = defA.Der_VitesseM_tdt(ddl_vitesse); D_Vt.Change_taille(nbddl); // calcul de la variation de la vitesse tangente for (int ii=1;ii<=nbddl;ii++) {D_Vt(ii)=D_V(ii) - (D_V(ii) * normale + V * D_normale(ii)) * normale - (V*normale) * D_normale(ii);}; // variation de u D_u.Change_taille(nbddl); D_u = Util::VarUnVect_coor( V, D_V,nV); // variation de la norme de V Tableau D_nV = Util::VarNorme(D_V,V,nV); // variation de w D_w.Change_taille(nbddl); if (coef_aero_t != NULL) { for (int i=1;i<=nbddl;i++) {D_w(i)(1)=-D_u(i)(2);D_w(i)(2)=D_u(i)(1);}; } // variation des coefficients // cas de T: T = to(Vt) * S * ut, Vt étant la vitesse tangentielle et ut étant le vecteur directeur de Vt D_coef_frot_fluid.Change_taille(nbddl); if (frot_fluid != NULL) { Courbe1D::ValDer valder = frot_fluid->Valeur_Et_derivee(nVt); for (int i=1;i<=nbddl;i++) D_coef_frot_fluid(i) = valder.derivee * D_nV(i) * poids(ni) * (*ex.jacobien_tdt) + valder.valeur * poids(ni) * (*ex.d_jacobien_tdt)(i); }; // cas de Fn = poids_volu * fn(V) * S * (normale*u) * u, u unitaire suivant V D_coef_n.Change_taille(nbddl); if (coef_aero_n != NULL) { Courbe1D::ValDer valder = coef_aero_n->Valeur_Et_derivee(nV); for (int i=1;i<=nbddl;i++) D_coef_n(i) = poidvol * poids(ni) * ( valder.derivee * D_nV(i) * (*ex.jacobien_tdt) * cos_directeur + valder.valeur * (*ex.d_jacobien_tdt)(i) * cos_directeur + valder.valeur * (*ex.jacobien_tdt) * (D_u(i) * normale + u * D_normale(i)) ); }; // cas de Ft = poids_volu * ft(V) * S * (normale*u) * w, w unitaire suivant la normal à V D_coef_t.Change_taille(nbddl); if (coef_aero_t != NULL) { Courbe1D::ValDer valder = coef_aero_t->Valeur_Et_derivee(nV); for (int i=1;i<=nbddl;i++) D_coef_t(i) = poidvol * poids(ni) * ( valder.derivee * D_nV(i) * (*ex.jacobien_tdt) * cos_directeur + valder.valeur * (*ex.d_jacobien_tdt)(i) * cos_directeur + valder.valeur * (*ex.jacobien_tdt) * (D_u(i) * normale + u * D_normale(i)) ); }; }; //-- fin du if (avec_raid) Force_hydroDyna& Fsauve = tab_hydrodyna(ni); // pour simplifier la sauvegarde // calcul du résidu int ix=1; // cas de T: T = to(Vt) * S * ut, Vt étant la vitesse tangentielle et ut étant le vecteur directeur de Vt double coef_frot_fluid=0.; if (frot_fluid != NULL) { coef_frot_fluid += frot_fluid->Valeur(nVt) * poids(ni) * (*ex.jacobien_tdt); Fsauve.T+=frot_fluid->Valeur(nVt) * Vt;}; // cas de Fn = poids_volu * fn(V) * S * (normale*u) * u, u unitaire suivant V double coef_n=0.; if (coef_aero_n != NULL) { coef_n += poidvol * coef_aero_n->Valeur(nV) * poids(ni) * (*ex.jacobien_tdt) * cos_directeur; Fsauve.F_n += (poidvol * coef_aero_n->Valeur(nV) * cos_directeur) * u ;}; // cas de Ft = poids_volu * ft(V) * S * (normale*u) * w, w unitaire suivant la normal à V double coef_t=0.; if (coef_aero_t != NULL) { coef_t += poidvol * coef_aero_t->Valeur(nV) * poids(ni) * (*ex.jacobien_tdt) * cos_directeur; Fsauve.F_t += (poidvol * coef_aero_t->Valeur(nV) * cos_directeur) * w ;}; for (int ne =1; ne<= nbne; ne++) for (int i=1;i<= dime;i++,ix++) { SM(ix) += taphi(ni)(ne) * coef_mul * (coef_frot_fluid * Vt(i) + coef_n * u(i) + coef_t * w(i)); if (avec_raid) {for (int j =1; j<= nbddl; j++) {KM(ix,j) -= taphi(ni)(ne) * coef_mul * ( D_coef_frot_fluid(j) * Vt(i) + coef_frot_fluid * D_Vt(j)(i) + D_coef_n(j) * u(i) + coef_n * D_u(j)(i) + D_coef_t(j) * w(i) + coef_t * D_w(j)(i) ); }; }; }; } // fin boucle sur les points d'intégrations break; }; case 1: // cas de la dimension 1 { // dans le cas ou le poid volumique est nul, on retourne sans calcul if (Dabs(poidvol) < ConstMath::trespetit) { Element::ResRaid el; el.res = (*res_extN)(numfront); el.raid = (*raid_extN)(numfront); return el; }; Vecteur& SM = (*((*res_extN)(numfront))); // pour simplifier Mat_pleine & KM = (*((*raid_extN)(numfront))); // " " " el.res = (*res_extN)(numfront); el.raid = (*raid_extN)(numfront); // pour le retour // il n'y a pas plusieurs point d'intégration // en 1D il ne peut y avoir que deux extrémités, la première à une normale = -1 , la seconde 1 Coordonnee normale(1); if (numfront == 1) {normale(1)=-1.;} else {normale(1)=1.;}; // éventuellement dimensionnement de la sauvegarde if (lesChargeExtSurEle == NULL) lesChargeExtSurEle = new LesChargeExtSurElement; if (lesChargeExtSurEle->LesHydroDyna() == NULL) lesChargeExtSurEle->LesHydroDyna_Change_taille(2); // car deux extrémités au plus Tableau & tab_hydrodyna= (*lesChargeExtSurEle->LesHydroDyna())(numfront); // pour simplifier if (tab_hydrodyna.Taille() != 1) tab_hydrodyna.Change_taille(1); // un seul point d'intégration en un point ! // récupération de la vitesse Noeud* noe = (tabb(posi_tab_front_point+numfront)->TabNoeud())(1); // on récupére tout d'abord le noeud fontière const Coordonnee& V = def->VitesseM_tdt(noe); double nV = V.Norme(); // dans le cas où la vitesse est trop faible, le résidu est nul if (nV < ConstMath::trespetit) return el; // dans le cas 1D il n'y a qu'un effort de trainée (car pas de vitesse tangente) Coordonnee u= V / nV; // on norme la vitesse, car ensuite on n'a besoin que de la direction unitaire de la vitesse // u en fait = 1 ou -1 d'où variation = 0 // calcul éventuel des variations static Tableau D_coef_n; if (avec_raid) { // calcul de la variation de la normale // récupération de la variation de vitesse bool ddl_vitesse; const Tableau D_V = def->Der_VitesseM_tdt(ddl_vitesse,noe); // variation de la norme de V Tableau D_nV = Util::VarNorme(D_V,V,nV); // variation des coefficients // cas de Fn = poids_volu * fn(V) * S * (normale*u) * u, u unitaire suivant V D_coef_n.Change_taille(nbddl); if (coef_aero_n != NULL) { Courbe1D::ValDer valder = coef_aero_n->Valeur_Et_derivee(nV); for (int i=1;i<=nbddl;i++) D_coef_n(i) = poidvol * poids(1) * valder.derivee * D_nV(i); }; }; //-- fin du if (avec_raid) Force_hydroDyna& Fsauve = tab_hydrodyna(1); // pour simplifier la sauvegarde // calcul du résidu int ix=1; int dimf = dime; // cas de Fn = poids_volu * fn(V) * S * (normale*u) * u, u unitaire suivant V double coef_n=0.; if (coef_aero_n != NULL) // le poids(1) contiend la section, et il n'y a pas de jacobien, cos directeur = 1 { coef_n += poidvol * coef_mul * coef_aero_n->Valeur(nV) * poids(1) ; Fsauve.F_n = (poidvol * coef_aero_n->Valeur(nV) ) * u ;}; for (int ne =1; ne<= nbne; ne++) // il n'y qu'un point d'intégration le noeud lui-même for (int i=1;i<= dimf;i++,ix++) { SM(ix) += taphi(1)(ne) * ( coef_n * u(i) ); if (avec_raid) {for (int j =1; j<= nbddl; j++) {KM(ix,j) -= taphi(1)(ne) * coef_mul * (D_coef_n(j) * u(i));}; }; }; break; }; // fin du cas de la dimension 1 */ }; //-- fin du switch sur la dimension // retour return el; };