// FICHIER : SfeMembT.cc // CLASSE : SfeMembT // 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-2021 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 #include using namespace std; //introduces namespace std #include #include "Sortie.h" #include "MathUtil.h" #include "SfeMembT.h" #include "TypeConsTens.h" #include "FrontPointF.h" #include "Loi_Umat.h" #include "ExceptionsElemMeca.h" #include "ExceptionsLoiComp.h" #include "CharUtil.h" // =========================== variables communes =============================== // a priori les pointeurs de fonction pointent sur rien au debut TenseurHH* SfeMembT::sig_bulk_pourSfe_HH = NULL; // variable de travail pour le bulk // =========================== fin variables communes =========================== // ---- definition du constructeur de la classe conteneur de donnees communes ------------ SfeMembT::DonnComSfe::DonnComSfe (ElemGeomC0* elCentre,const GeomSeg& seg,const DdlElement& tab ,DdlElement& tabErr,DdlElement& tab_Err1Sig,DdlElement& t_ddlXi_C ,const Met_Sfe1& met_gene, Tableau & resEr,Mat_pleine& raidEr, ElemGeomC0* elEr,GeomSeg& segEr,ElemGeomC0* elS,GeomSeg& segmS ,Vecteur& residu_int,Mat_pleine& raideur_int, Tableau & residus_extN,Tableau & raideurs_extN, Tableau & residus_extA,Tableau & raideurs_extA, Tableau & residus_extS,Tableau & raideurs_extS, Mat_pleine& mat_masse,ElemGeomC0* elMas,const GeomSeg& segMas,int nbi, Tableau const & tabTypeCL,Tableau const & vplan ,Tableau & nMetddl,const Met_abstraite& met_cent ) : eleCentre(elCentre),segment(seg),tab_ddl(tab),tab_ddlErr(tabErr),tab_Err1Sig11(tab_Err1Sig) ,tab_ddlXi_C(t_ddlXi_C),met_SfeMembT(met_gene) ,matGeom(tab.NbDdl(),tab.NbDdl()),matInit(tab.NbDdl(),tab.NbDdl()) ,d_epsBB(tab.NbDdl()),d_sigHH(tab.NbDdl()),d2_epsBB(nbi) ,resErr(resEr),raidErr(raidEr),eleEr(elEr),segmentEr(segEr),eleS(elS),segS(segmS) ,residu_interne(residu_int),raideur_interne(raideur_int) ,residus_externeN(residus_extN),raideurs_externeN(raideurs_extN) ,residus_externeA(residus_extA),raideurs_externeA(raideurs_extA) ,residus_externeS(residus_extS),raideurs_externeS(raideurs_extS) ,matrice_masse(mat_masse),eleMas(elMas),segmentMas(segMas) ,tabType_rienCL(tabTypeCL),vplan_rien(vplan) ,nMetVTab_ddl(nMetddl),met_surf_cent(met_cent) ,sfematD(NULL),sferesD(NULL),noeud_a_prendre_en_compte(NULL) { int nbddl = tab.NbDdl(); int dim_tens = met_gene.Nbvec_des_bases(); for (int ni=1;ni<=nbi;ni++) {d2_epsBB(ni).Change_taille(nbddl); for (int i1=1; i1<= nbddl; i1++) for (int i2=1; i2<= nbddl; i2++) d2_epsBB(ni)(i1,i2) = NevezTenseurBB (dim_tens); }; // int tailledeps = d_epsBB.Taille(); // for (int i=1;i<= tailledeps; i++) for (int i=1;i<= nbddl; i++) d_epsBB(i) = NevezTenseurBB (dim_tens); // int tailledsig = d_sigHH.Taille(); // for (int j=1;j<= tailledsig; j++) for (int j=1;j<= nbddl; j++) d_sigHH(j) = NevezTenseurHH (dim_tens); }; // Il ne doit exister qu'un exemplaire de la classe, donc au niveau du constructeur de copie les tableaux // de pointeurs pointes sur les mêmes entités que la valeur passée en paramètre SfeMembT::DonnComSfe::DonnComSfe(DonnComSfe& a) : eleCentre(a.eleCentre),segment(a.segment) ,tab_ddl(a.tab_ddl),tab_ddlErr(a.tab_ddlErr),tab_Err1Sig11(a.tab_Err1Sig11) ,tab_ddlXi_C(a.tab_ddlXi_C),met_SfeMembT(a.met_SfeMembT),matGeom(a.matGeom) ,matInit(a.matInit),d2_epsBB(a.d2_epsBB),resErr(a.resErr),raidErr(a.raidErr) ,eleEr(a.eleEr),segmentEr(a.segmentEr),eleS(a.eleS),segS(a.segS) ,d_epsBB(a.d_epsBB),d_sigHH(a.d_sigHH) ,residu_interne(a.residu_interne),raideur_interne(a.raideur_interne) ,residus_externeN(a.residus_externeN),raideurs_externeN(a.raideurs_externeN) ,residus_externeA(a.residus_externeA),raideurs_externeA(a.raideurs_externeA) ,residus_externeS(a.residus_externeS),raideurs_externeS(a.raideurs_externeS) ,matrice_masse(a.matrice_masse),eleMas(a.eleMas),segmentMas(a.segmentMas) ,tabType_rienCL(a.tabType_rienCL),vplan_rien(a.vplan_rien) ,nMetVTab_ddl(a.nMetVTab_ddl),met_surf_cent(a.met_surf_cent) ,sfematD(NULL),sferesD(NULL),noeud_a_prendre_en_compte(NULL) { int nbddl = tab_ddl.NbDdl(); int nbi=d2_epsBB.Taille(); for (int ni=1;ni<=nbi;ni++) for (int i1=1; i1<= nbddl; i1++) for (int i2=1; i2<= nbddl; i2++) d2_epsBB(ni)(i1,i2) = NevezTenseurBB (*(a.d2_epsBB(ni)(i1,i2))); // int tailledeps = d_epsBB.Taille(); // for (int i=1;i<= tailledeps; i++) for (int i=1;i<= nbddl; i++) d_epsBB(i) = NevezTenseurBB (*(a.d_epsBB(i))); // int tailledsig = d_sigHH.Taille(); // for (int j=1;j<= tailledsig; j++) for (int j=1;j<= nbddl; j++) d_sigHH(j) = NevezTenseurHH (*(d_sigHH(j))); // cas d'une stabilisation éventuelle if (a.sfematD != NULL) sfematD = new Mat_pleine(*a.sfematD); if (a.sferesD != NULL) sferesD = new Vecteur (*a.sferesD); if (a.noeud_a_prendre_en_compte != NULL) noeud_a_prendre_en_compte = new Tableau (*a.noeud_a_prendre_en_compte); }; // certaines grandeurs pointées qui n'exitent qu'en un seul exemplaire // ne seront supprimées que par l'ordre destruction, SfeMembT::DonnComSfe::DonnComSfe::~DonnComSfe() { int nbddl = tab_ddl.NbDdl(); int nbi=d2_epsBB.Taille(); for (int ni=1;ni<=nbi;ni++) for (int i1=1; i1<= nbddl; i1++) for (int i2=1; i2<= nbddl; i2++) delete d2_epsBB(ni)(i1,i2); int tailledeps = d_epsBB.Taille(); for (int i=1;i<= tailledeps; i++) delete d_epsBB(i); int tailledsig = d_sigHH.Taille(); for (int j=1;j<= tailledsig; j++) delete d_sigHH(j); // cas d'une stabilisation éventuelle if (sfematD != NULL) delete sfematD; if (sferesD != NULL) delete sferesD; if (noeud_a_prendre_en_compte != NULL) delete noeud_a_prendre_en_compte; }; // ---------- fin definition de la classe conteneur de donnees communes ------------ // -+-+ definition de la classe contenant tous les indicateurs qui sont modifiés une seule fois -+-+-+ SfeMembT::UneFois::UneFois () : // constructeur par défaut doCoMemb(NULL),CalResPrem_t(0),CalResPrem_tdt(0),CalimpPrem(0),dualSortSfe(0) ,CalSMlin_t(0),CalSMlin_tdt(0),CalSMRlin(0) ,CalSMsurf_t(0),CalSMsurf_tdt(0),CalSMRsurf(0) ,CalSMvol_t(0),CalSMvol_tdt(0),CalSMvol(0) ,CalDynamique(0),CalPt_0_t_tdt(0) ,nbelem_in_Prog(0) {}; SfeMembT::UneFois::~UneFois () { delete doCoMemb; }; // -+-+ fin definition de la classe contenant tous les indicateurs qui sont modifiés une seule fois -+-+-+ // CONSTRUCTEURS : // Constructeur par defaut SfeMembT::SfeMembT () : ElemMeca(),lesPtMecaInt(),donnee_specif(),areteTypeCL(NULL),vplan(NULL) ,t_N_centre(),unefois(NULL),nombre(NULL) { lesPtIntegMecaInterne = &lesPtMecaInt; // association avec le pointeur d'ElemMeca }; // Constructeur fonction d'un numero // d'identification , d'identificateur d'interpolation et de geometrie SfeMembT::SfeMembT (int num_mail,int num_id,Enum_interpol id_interp_elt,Enum_geom id_geom_elt,string info) : ElemMeca(num_mail,num_id,id_interp_elt,id_geom_elt,info),lesPtMecaInt(),donnee_specif() ,areteTypeCL(NULL),vplan(NULL),t_N_centre(),unefois(NULL),nombre(NULL) { lesPtIntegMecaInterne = &lesPtMecaInt; // association avec le pointeur d'ElemMeca }; // Constructeur fonction d'un numero de maillage et d'identification, // du tableau de connexite des noeuds, d'identificateur d'interpolation et de geometrie SfeMembT::SfeMembT (int num_mail,int num_id,Enum_interpol id_interp_elt,Enum_geom id_geom_elt, const Tableau& tab,string info) : ElemMeca(num_mail,num_id,tab,id_interp_elt,id_geom_elt,info),lesPtMecaInt(),donnee_specif() ,areteTypeCL(NULL),vplan(NULL),t_N_centre(),unefois(NULL),nombre(NULL) { lesPtIntegMecaInterne = &lesPtMecaInt; // association avec le pointeur d'ElemMeca }; // Constructeur de copie SfeMembT::SfeMembT (const SfeMembT& SfeM) : ElemMeca (SfeM) ,lesPtMecaInt(SfeM.lesPtMecaInt) ,donnee_specif(SfeM.donnee_specif),unefois(SfeM.unefois),nombre(SfeM.nombre) ,areteTypeCL(SfeM.areteTypeCL),vplan(SfeM.vplan),t_N_centre(SfeM.t_N_centre) { lesPtIntegMecaInterne = &lesPtMecaInt; // association avec le pointeur d'ElemMeca // --- cas des différentes puissances et ... --- SfeMembT::DonnComSfe* CoSfe = unefois->doCoMemb; // pour simplifier l'écriture residu = &(CoSfe->residu_interne); // residu local raideur = &(CoSfe->raideur_interne); // raideur locale // --- cas de la dynamique ----- mat_masse = &(CoSfe->matrice_masse); // --- cas des efforts externes concernant noeuds ------ res_extN = &(CoSfe->residus_externeN); // pour les résidus et second membres raid_extN= &(CoSfe->raideurs_externeN);// pour les raideurs // --- cas des efforts externes concernant les aretes ------ res_extA = &(CoSfe->residus_externeA); // pour les résidus et second membres raid_extA= &(CoSfe->raideurs_externeA);// pour les raideurs // --- cas des efforts externes concernant les faces ------ res_extS= &(CoSfe->residus_externeS); // pour les résidus et second membres raid_extS= &(CoSfe->raideurs_externeS); // pour les raideurs // pour les conditions limites on les crée si besoin if (areteTypeCL != (&(unefois->doCoMemb->tabType_rienCL))) { // si ça ne pointe pas sur la valeur par défaut, alors c'est qu'il y a // des CL particulières, on les crée donc à l'identique areteTypeCL = new Tableau (*(SfeM.areteTypeCL)); vplan = new Tableau (*(SfeM.vplan)); }; }; // DESTRUCTEUR : SfeMembT::~SfeMembT () { /* // on va libérer les déformations d'arrête et de surface qui sont un peu particulières if (defArete.Taille() != 0) if (defArete(1) != NULL) { delete defArete(1); // on remet à null les pointeurs pour un appel correcte du destructeur d'elemMeca for (int ia=1;ia<= 12; ia++) defArete(ia) = NULL; } if (defSurf.Taille() != 0) if (defSurf(1) != NULL) { delete defSurf(1); // on remet à null les pointeurs pour un appel correcte du destructeur d'elemMeca for (int ia=1;ia<= 12; ia++) defSurf(ia) = NULL; } */ // concernant tous les éléments qui sont définit qu'une seule fois, leur destruction est effectuée avec la méthode destruction // appelée par les classes descendantes LibereTenseur(); }; // Lecture des donnees de la classe sur fichier void SfeMembT::LectureDonneesParticulieres (UtilLecture * entreePrinc,Tableau * tabMaillageNoeud) { int nb;int nbnte = nombre->nbnte; tab_noeud.Change_taille(nbnte); for (int i=1; i<= nbnte; i++) { *(entreePrinc->entree) >> nb; if ((entreePrinc->entree)->rdstate() == 0) // pour mémoire ici on a /* enum io_state { badbit = 1<<0, // -> 1 dans rdstate() eofbit = 1<<1, // -> 2 failbit = 1<<2, // -> 4 goodbit = 0 // -> O };*/ tab_noeud(i) = (*tabMaillageNoeud)(nb); // lecture normale #ifdef ENLINUX else if ((entreePrinc->entree)->fail()) // on a atteind la fin de la ligne et on appelle un nouvel enregistrement { entreePrinc->NouvelleDonnee(); // lecture d'un nouvelle enregistrement *(entreePrinc->entree) >> nb; tab_noeud(i) = (*tabMaillageNoeud)(nb); // lecture normale } #else /* #ifdef SYSTEM_MAC_OS_X_unix else if ((entreePrinc->entree)->fail()) // on a atteind la fin de la ligne et on appelle un nouvel enregistrement { entreePrinc->NouvelleDonnee(); // lecture d'un nouvelle enregistrement *(entreePrinc->entree) >> nb; tab_noeud(i) = (*tabMaillageNoeud)(nb); // lecture normale } #else */ else if ((entreePrinc->entree)->eof()) // la lecture est bonne mais on a atteind la fin de la ligne { tab_noeud(i) = (*tabMaillageNoeud)(nb); // lecture // si ce n'est pas la fin de la lecture on appelle un nouvel enregistrement if (i != nbnte) entreePrinc->NouvelleDonnee(); // lecture d'un nouvelle enregistrement } // #endif #endif else // cas d'une erreur de lecture { cout << "\n erreur de lecture inconnue "; entreePrinc->MessageBuffer("** lecture des données particulières **"); cout << "SfeMembT::LecDonPart"; Affiche(2); Sortie (1); } }; // construction du tableau de ddl des noeuds de SfeMembT ConstTabDdl(); // construction du tableau des noeuds du centre t_N_centre.Change_taille(nombre->nbnce); for (int i=1;i<= nombre->nbnce;i++) t_N_centre(i)=tab_noeud(i); }; // calcul d'un point dans l'élément réel en fonction des coordonnées dans l'élément de référence associé // temps: indique si l'on veut les coordonnées à t = 0, ou t ou tdt // 1) cas où l'on utilise la place passée en argument Coordonnee & SfeMembT::Point_physique(const Coordonnee& ,Coordonnee & co,Enum_dure ) { cout << "\n methode non encore implantee !!" << "\n Coordonnee & SfeMembT::Point_physique(..."; Sortie(1); // d) retour return co; }; // 3) cas où l'on veut les coordonnées aux 1, 2 ou trois temps selon la taille du tableau t_co void SfeMembT::Point_physique(const Coordonnee& ,Tableau & ) { cout << "\n methode non encore implantee !!" << "\n void SfeMembT::Point_physique(..."; Sortie(1); }; // vérification que la courbure ne soit pas anormale au temps enu // inf_normale : indique en entrée le det mini pour la courbure en locale // retour 1: si tout est ok, // 0: une courbure trop grande a été détecté // retour = -1 : il y a un pb inconnue dans le calcul int SfeMembT::Test_courbure_anormale3(Enum_dure enu,double inf_normale) { SfeMembT::DonnComSfe* CoSfe = unefois->doCoMemb; // pour simplifier l'écriture if (unefois->CalimpPrem == 0) { unefois->CalimpPrem = 1; Tableau tab(20); tab(1) = igiB_0; tab(2) = igiB_t; tab(3) = igiB_tdt; tab(4) = igijBB_0; tab(5) = igijBB_t;tab(6) = igijBB_tdt; tab(7) = igijHH_tdt; tab(8) = id_giB_tdt; tab(9) = id_gijBB_tdt ;tab(10) = igiH_tdt;tab(11) = id_giH_tdt; tab(12) = id_gijHH_tdt;tab(13) = id_jacobien_tdt;tab(14) = id2_gijBB_tdt; tab(15) = id_gijBB_t ;tab(16) = id_gijBB_tdt ;tab(17) = idMtdt ; tab(18) = igradVBB_tdt; tab(19) = iVtdt; tab(20) = idVtdt; CoSfe->met_SfeMembT.PlusInitVariables(tab) ; }; // la variable de retour initialisée à 1 par défaut int retour = 1; // on gère les exceptions éventuelles en mettant le bloc sous surveillance try { // puis les indices de boucle int indice = 1; int nbtotsurf = CoSfe->eleCentre->Nbi(); int nbtotepais =(CoSfe->segment).Nbi(); for (int nisur =1; nisur<= nbtotsurf; nisur++) // boucle sur les pt d'integ de surface {for (int niepais =1; niepais<= nbtotepais; niepais++, indice++) // pt d'integ d'epaisseur {((DeformationSfe1*) def)->ChangeNumIntegSfe1(nisur,niepais); ((DeformationSfe1*) def)->Mise_a_jour_data_specif(tabSaveDefDon(indice)); retour *= ((DeformationSfe1*) def)->Test_courbure_anormale(enu,inf_normale); if (!retour) break; // on arrête dès qu'un pb est repéré }; // fin boucle sur les points d'intégration if (!retour) break; // on arrête dès qu'un pb est repéré }; } catch (ErrSortieFinale) // cas d'une direction voulue vers la sortie // on relance l'interuption pour le niveau supérieur { ErrSortieFinale toto; throw (toto); } catch ( ... ) { if (ParaGlob::NiveauImpression() > 3) {cout << "\n warning: erreur generee par un element lors du test de verification de la courbure "; }; retour = -1; } return retour; }; // récupération des valeurs au numéro d'ordre = iteg pour les grandeurs enu // ici il s'agit de grandeurs scalaire, // absolue: indique si oui ou non on sort les tenseurs dans la base absolue ou une base particulière Tableau SfeMembT::Valeur_a_diff_temps(bool absolue,Enum_dure enu_t,const List_io& enu,int iteg) { // appel de la procedure de elem meca int cas; if (!(unefois->dualSortSfe ) && (unefois->CalimpPrem )) { cas=1;unefois->dualSortSfe += 1; } else if ((unefois->dualSortSfe ) && (unefois->CalimpPrem )) { cas = 11;} else if (!(unefois->dualSortSfe ) && (unefois->CalResPrem_tdt )) { cas=2;unefois->dualSortSfe += 1; } else if ((unefois->dualSortSfe ) && (unefois->CalResPrem_tdt )) { cas = 12;} // sinon problème else { cout << "\n warning: les grandeurs ne sont pas calculees : il faudrait au moins un pas de calcul" << " pour inialiser les conteneurs des tenseurs resultats "; if (ParaGlob::NiveauImpression() >= 4) cout << "\n cas non prévu, unefois->dualSortSfe= " << unefois->dualSortSfe << " unefois->CalimpPrem= " << unefois->CalimpPrem << "\n SfeMembT::Valeur_a_diff_temps(Enum_dure enu_t..."; Sortie(1); }; return ElemMeca::Valeur_multi(absolue,enu_t,enu,iteg,cas); }; // récupération des valeurs au numéro d'ordre = iteg pour les grandeurs enu // ici il s'agit de grandeurs tensorielles, le retour s'effectue dans la liste // de conteneurs quelconque associée // absolue: indique si oui ou non on sort les tenseurs dans la base absolue ou une base particulière void SfeMembT::ValTensorielle_a_diff_temps(bool absolue,Enum_dure enu_t,List_io& enu,int iteg) { // appel de la procedure de elem meca int cas; if (!(unefois->dualSortSfe ) && (unefois->CalimpPrem )) { cas=1;unefois->dualSortSfe += 1; } else if ((unefois->dualSortSfe ) && (unefois->CalimpPrem )) { cas = 11;} else if (!(unefois->dualSortSfe ) && (unefois->CalResPrem_tdt )) { cas=2;unefois->dualSortSfe += 1; } else if ((unefois->dualSortSfe ) && (unefois->CalResPrem_tdt )) { cas = 12;} // sinon problème else { cout << "\n warning: les grandeurs ne sont pas calculees : il faudrait au moins un pas de calcul" << " pour inialiser les conteneurs des tenseurs resultats "; if (ParaGlob::NiveauImpression() >= 4) cout << "\n cas non prévu, unefois->dualSortSfe= " << unefois->dualSortSfe << " unefois->CalimpPrem= " << unefois->CalimpPrem << "\n SfeMembT::ValTensorielle_a_diff_temps(Enum_dure enu_t..."; Sortie(1); }; ElemMeca::Valeurs_Tensorielles(absolue,enu_t,enu,iteg,cas); }; // Calcul du residu local à t ou tdt en fonction du booleen atdt Vecteur* SfeMembT::CalculResidu (bool atdt,const ParaAlgoControle & pa) { SfeMembT::DonnComSfe* CoSfe = unefois->doCoMemb; // pour simplifier l'écriture Tableau & d_epsBB = (CoSfe->d_epsBB);// " energie_totale.Initialisation_differenciee(energie_totale_t); // init de l'énergie totale sur l'élément TenseurHH* sigHH_t_1 = (*lesPtIntegMecaInterne)(1).SigHH_t(); // simplification d'écriture if (ElemMeca::Bulk_visco_actif()) { if (sig_bulk_pourSfe_HH == NULL) {sig_bulk_pourSfe_HH = NevezTenseurHH(*sigHH_t_1);} else if (sig_bulk_pourSfe_HH->Dimension() != sigHH_t_1->Dimension()) {delete sig_bulk_pourSfe_HH; sig_bulk_pourSfe_HH = NevezTenseurHH(*sigHH_t_1);}; }; // dimensionnement de la metrique if (!atdt) {if( !(unefois->CalResPrem_t )) { unefois->CalResPrem_t += 1; Tableau tab(10); tab(1) = igiB_0; tab(2) = igiB_t; tab(3) = igijBB_0;tab(4) = igijBB_t; tab(5) = igijHH_t; tab(6) = id_giB_t; tab(7) = id_gijBB_t ; tab(8) = id_gijBB_t ;tab(9) = igradVBB_t; tab(10) = iVt; CoSfe->met_SfeMembT.PlusInitVariables(tab) ; };} else {if( !(unefois->CalResPrem_tdt )) {unefois->CalResPrem_tdt += 1; Tableau tab(11); tab(1) = igiB_0; tab(2) = igiB_tdt; tab(3) = igijBB_0;tab(4) = igijBB_tdt; tab(5) = igijHH_tdt; tab(6) = id_giB_tdt; tab(7) = id_gijBB_tdt ; tab(8) = id_gijBB_t ;tab(9) = id_gijBB_tdt ; tab(10) = igradVBB_tdt;tab(11) = iVtdt; CoSfe->met_SfeMembT.PlusInitVariables(tab) ; };}; // dimensionnement du residu int nbddl = CoSfe->tab_ddl.NbDdl(); if ( residu == NULL) residu = new Vecteur(nbddl); // cas du premier passage else for (int i =1; i<= nbddl; i++) // cas des autres passages (*residu)(i) = 0.; // on initialise a zero double jacobien; // def du jacobien int indice = 1; int nbtotsurf =CoSfe->eleCentre->Nbi(); int nbtotepais =(CoSfe->segment).Nbi(); // préparation du calcul de l'épaisseur finale (qui dépend de tous les points d'intégration) double somme_epaisseurs_finales = 0; // on utilise une épaisseur intermédiaire pour la métrique // de manière à utiliser l'épaisseur de l'incrément précédent Epai epais_pour_metrique; // on doit boucler à l'extérieur sur les pt de surface et à l'intérieur sur les pt d'épaisseurs // pour profiter du fait que une fois un pt calculer, on n'a pas à recalculer la courbure !!!!! for (int nisur =1; nisur<= nbtotsurf; nisur++) // boucle sur les pt d'integ de surface for (int niepais =1; niepais<= nbtotepais; niepais++, indice++) // pt d'integ d'epaisseur { if ((donnee_specif.epais != NULL) // on change les épaisseurs si elles sont stockées && (!Loi_rien(loiComp->Id_comport())) ) { epais_pour_metrique = *(donnee_specif.epais); epais_pour_metrique.epaisseur_tdt = epais_pour_metrique.epaisseur_t; // ((DeformationSfe1*) def)->Change_epaisseur(*donnee_specif.epais); // au niveau de l'élément ((DeformationSfe1*) def)->Change_epaisseur(epais_pour_metrique); }; ((DeformationSfe1*) def)->ChangeNumIntegSfe1(nisur,niepais); ((DeformationSfe1*) def)->Mise_a_jour_data_specif(tabSaveDefDon(indice)); PtIntegMecaInterne & ptIntegMeca = (*lesPtIntegMecaInterne)(indice); TenseurHH & sigHH = *(ptIntegMeca.SigHH()); TenseurBB & DepsBB_ = *(ptIntegMeca.DepsBB()); EnergieMeca& energ = tab_energ(indice); EnergieMeca& energ_t = tab_energ_t(indice); double poids = CoSfe->eleCentre->Wi(nisur) * (CoSfe->segment).Wi(niepais) ; CompThermoPhysiqueAbstraite::SaveResul* sTP=NULL; // les données spécifique thermo physiques if (loiTP != NULL) {sTP = tabSaveTP(indice);}; // au pt d'integ si elles existes if ((loiComp->Id_comport()==LOI_VIA_UMAT) // cas de l'utilisation d'une loi umat || (loiComp->Id_comport()==LOI_VIA_UMAT_CP)) ((Loi_Umat*) loiComp)->Mise_a_jour_nbe_nbptinteg(this->Num_elt(),indice); double epaisseur_tdt = 0.; // ne sert que pour les éléments 2D avec épaisseurs stockées à l'élément double epaisseur_pris_en_compte = 0.; // celle qui sera réellement prise en compte // -- on gère les exceptions éventuelles en mettant le bloc sous surveillance try // ce qui permet de donner les numéros d'éléments et de pti {if (atdt) { const Met_abstraite::Expli_t_tdt& ex = loiComp->Cal_explicit_tdt (tabSaveDon(indice), *def,CoSfe->tab_ddl,ptIntegMeca,d_epsBB,jacobien ,sTP,loiTP,dilatation,energ,energ_t,premier_calcul_meca_impli_expli); // examen du cas où on désire utiliser la méthode d'atténuation des hautes fréquences avec le bulk viscosity if (Bulk_visco_actif()) ModifContrainteBulk(TEMPS_tdt,*ex.gijHH_tdt,sigHH,DepsBB_ ,(*sig_bulk_pourSfe_HH)); // on tient compte de la variation d'épaisseur si l'épaisseur est stockée dans l'élément // et que l'on n'a pas une loi rien if ((donnee_specif.epais != NULL) && (!Loi_rien(loiComp->Id_comport()))) { switch (loiComp->Comportement_3D_CP_DP_1D()) { case COMP_CONTRAINTES_PLANES : // en contrainte plane on recalcule l'épaisseur { CalEpaisseurAtdtExp_et_vol_pti(donnee_specif.epais->epaisseur0,pa,donnee_specif.epais->epaisseur_t ,ptIntegMeca,epaisseur_tdt,ex); //------ le 7 nov 2016: changement car je ne veux pas utiliser la variation d'épaisseur // qui est calculée dans les lois. C'est sans doute possible, bien qu'avec les lois additives et mélange // ce n'est pas sûr que cela veuille dire quelque chose. Donc on essaie de sans passer // De plus c'est cohérent avec les éléments membranes ... // ---- remodif le 1 avril 2017 car la méthode précédente fait que l'élément converge très mal !! // je ne sais pas trop pourquoi (avec une loi de déformation plane, cela converge immédiatement !) // // en fait, on récupère la variation d'épaisseur calculée via la condition de contrainte plane // // on utilise uniquement la variation d'épaisseur calculée à la surface médiane ??? pour l'instant // epaisseur_tdt = loiComp->HsurH0(tabSaveDon(nisur)) * donnee_specif.epais->epaisseur0; // il faudrait peut-être utiliser finalement la variation d'épaisseur calculée par la loi, comme pour les éléments // membranes qui ont été modifiées pour tenir compte de la différence de def entre géométrique et la def méca // Par exemple lors de critère de rupture, on aura le même pb qu'avec les plis //*** à faire epaisseur_pris_en_compte = donnee_specif.epais->epaisseur_tdt; break; } case COMP_DEFORMATIONS_PLANES : // en deformation plane, l'épaisseur ne change pas { epaisseur_tdt = donnee_specif.epais->epaisseur0; ptIntegMeca.Volume_pti() *= donnee_specif.epais->epaisseur0; epaisseur_pris_en_compte = donnee_specif.epais->epaisseur0; break; } default : cout << "\nErreur : cas de loi de comportement : " << Nom_comp((loiComp->Id_comport())) << " non prevu pour le calcul le l'epaisseur avec l'element SFE "; cout << "\n SfeMembT::Calcul_implicit(.... \n"; Sortie(1); }; }; somme_epaisseurs_finales += epaisseur_tdt; //pour le calcul final } else { const Met_abstraite::Expli& ex = loiComp->Cal_explicit_t (tabSaveDon(indice), *def,CoSfe->tab_ddl,ptIntegMeca,d_epsBB,jacobien ,sTP,loiTP,dilatation,energ,energ_t,premier_calcul_meca_impli_expli); // examen du cas où on désire utiliser la méthode d'atténuation des hautes fréquences avec le bulk viscosity if (Bulk_visco_actif()) ModifContrainteBulk(TEMPS_t,*ex.gijHH_t,sigHH,DepsBB_ ,(*sig_bulk_pourSfe_HH)); // pour l'instant on expédie un message, car il y a des chances que cette partie disparaisse !! cout << "\n attention *** calcul non operationnelle en explicite t, on ne tient pas compte de la" << " variation d'epaisseur !! (a modifier ) "; }; } catch (ErrNonConvergence_loiDeComportement excep) // cas d'une d'une erreur survenue à cause d'une non convergence pour la résolution // d'une loi de comportement incrémentale { cout << "\n erreur de loi de comportement element= " << this->Num_elt() << " point d'integration de surface= "<= 1) { cout << "\n ********** attention on a trouve un jacobien negatif!! ("<nMetVTab_ddl(j); // adressage indirecte (*residu)(jloc) -= (sigHH && (*(d_epsBB(j)))) * jacobien * poids * epaisseur_pris_en_compte; volume += jacobien * poids * epaisseur_tdt; // là on prend la vrai épaisseur }; }; if (ElemMeca::Bulk_visco_actif()) // dans le cas du bulk on retire la contrainte du bulk, qui est non physique { sigHH -= (*sig_bulk_pourSfe_HH); } // ceci pour la sauvegarde ou autre utilisation }; // fin boucle sur les points d'intégration // on calcul éventuellement l'épaisseur moyenne finale si c'est un élément 2D if ((donnee_specif.epais != NULL)&&(!Loi_rien(loiComp->Id_comport()))) // cas 2D donnee_specif.epais->epaisseur_tdt = somme_epaisseurs_finales / (indice - 1); // liberation des tenseurs intermediaires LibereTenseur(); return residu; }; // Calcul du residu local et de la raideur locale, // pour le schema implicite Element::ResRaid SfeMembT::Calcul_implicit (const ParaAlgoControle & pa) { SfeMembT::DonnComSfe* CoSfe = unefois->doCoMemb; // pour simplifier l'écriture Tableau & d_epsBB = (CoSfe->d_epsBB);// " Tableau & d_sigHH = (CoSfe->d_sigHH);// " energie_totale.Initialisation_differenciee(energie_totale_t); // init de l'énergie totale sur l'élément E_elem_bulk_tdt = E_elem_bulk_t; P_elem_bulk = 0.; // init pour l'énergie et la puissance associées au bulk // init éventuel de la contrainte de bulk viscosity TenseurHH* sigHH_t_1 = (*lesPtIntegMecaInterne)(1).SigHH_t(); // simplification d'écriture if (ElemMeca::Bulk_visco_actif()) { if (sig_bulk_pourSfe_HH == NULL) {sig_bulk_pourSfe_HH = NevezTenseurHH(*sigHH_t_1);} else if (sig_bulk_pourSfe_HH->Dimension() != sigHH_t_1->Dimension()) {delete sig_bulk_pourSfe_HH; sig_bulk_pourSfe_HH = NevezTenseurHH(*sigHH_t_1);}; }; // init éventuel des intégrales de volume et temps Init_Integ_vol_et_temps(); // --- init pour l'init de la stabilisation de membrane-biel éventuelle const Met_abstraite::Impli* ex_final=NULL; // contiendra après les boucles la dernière métrique Mise_a_jour_A_calculer_force_stab(); // permettra ensuite de savoir où le calcul doit être fait bool cald_Dvirtuelle = false; if (unefois->CalimpPrem == 0) { unefois->CalimpPrem = 1; Tableau tab(20); tab(1) = igiB_0; tab(2) = igiB_t; tab(3) = igiB_tdt; tab(4) = igijBB_0; tab(5) = igijBB_t;tab(6) = igijBB_tdt; tab(7) = igijHH_tdt; tab(8) = id_giB_tdt; tab(9) = id_gijBB_tdt ;tab(10) = igiH_tdt;tab(11) = id_giH_tdt; tab(12) = id_gijHH_tdt;tab(13) = id_jacobien_tdt;tab(14) = id2_gijBB_tdt; tab(15) = id_gijBB_t ;tab(16) = id_gijBB_tdt ;tab(17) = idMtdt ; tab(18) = igradVBB_tdt; tab(19) = iVtdt; tab(20) = idVtdt; CoSfe->met_SfeMembT.PlusInitVariables(tab) ; // on ne calcul la dérivée de la déformation virtuelle qu'une fois // car elle est constante dans le temps et indépendante des coordonnées cald_Dvirtuelle=true; }; // dimensionnement du residu int nbddl = CoSfe->tab_ddl.NbDdl(); if ( residu == NULL) residu = new Vecteur(nbddl); // cas du premier passage else for (int i =1; i<= nbddl; i++) // cas des autres passages (*residu)(i) = 0.; // on initialise a zero // dimensionnement de la raideur if ( raideur == NULL) raideur = new Mat_pleine(nbddl,nbddl); // cas du premier passage else for (int i =1; i<= nbddl; i++) // cas des autres passages for (int j=1; j<= nbddl; j++) // (*raideur)(i,j) = 0.; // on initialise a zero double jacobien; // def du jacobien Vecteur d_jacobien_tdt; int indice = 1; int nbtotsurf = CoSfe->eleCentre->Nbi(); int nbtotepais =(CoSfe->segment).Nbi(); // préparation du calcul de l'épaisseur finale (qui dépend de tous les points d'intégration) double somme_epaisseurs_finales = 0; // on utilise une épaisseur intermédiaire pour la métrique // de manière à utiliser l'épaisseur de l'incrément précédent Epai epais_pour_metrique; //--debug //if (num_elt == 89) // { cout << "\n SfeMembT::Calcul_implicit debug "; // cout << endl; // }; // on doit boucler à l'extérieur sur les pt de surface et à l'intérieur sur les pt d'épaisseurs // pour profiter du fait que une fois un pt calculer, on n'a pas à recalculer la courbure !!!!! // ne sert plus** int nbint = nbtotsurf*nbtotepais; // nb total de pti for (int nisur =1; nisur<= nbtotsurf; nisur++) // boucle sur les pt d'integ de surface for (int niepais =1; niepais<= nbtotepais; niepais++, indice++) // pt d'integ d'epaisseur {if ((donnee_specif.epais != NULL) // on change les épaisseurs si elles sont stockées && (!Loi_rien(loiComp->Id_comport())) ) { epais_pour_metrique = *(donnee_specif.epais); epais_pour_metrique.epaisseur_tdt = epais_pour_metrique.epaisseur_t; // ((DeformationSfe1*) def)->Change_epaisseur(*donnee_specif.epais); // au niveau de l'élément ((DeformationSfe1*) def)->Change_epaisseur(epais_pour_metrique); }; ((DeformationSfe1*) def)->ChangeNumIntegSfe1(nisur,niepais); ((DeformationSfe1*) def)->Mise_a_jour_data_specif(tabSaveDefDon(indice)); PtIntegMecaInterne & ptIntegMeca = (*lesPtIntegMecaInterne)(indice); TenseurHH & sigHH = *(ptIntegMeca.SigHH()); TenseurBB & DepsBB_tdt = *(ptIntegMeca.DepsBB()); EnergieMeca& energ = tab_energ(indice); EnergieMeca& energ_t = tab_energ_t(indice); double poids = (CoSfe->eleCentre->Wi(nisur) * (CoSfe->segment).Wi(niepais)) * 0.5 ; CompThermoPhysiqueAbstraite::SaveResul* sTP=NULL; // les données spécifique thermo physiques if (loiTP != NULL) {sTP = tabSaveTP(indice);}; // au pt d'integ si elles existes if ((loiComp->Id_comport()==LOI_VIA_UMAT) // cas de l'utilisation d'une loi umat || (loiComp->Id_comport()==LOI_VIA_UMAT_CP)) ((Loi_Umat*) loiComp)->Mise_a_jour_nbe_nbptinteg(this->Num_elt(),indice); // -- on gère les exceptions éventuelles en mettant le bloc sous surveillance const Met_abstraite::Impli* ex_pointe = NULL; // c'est pour construire ex try // ce qui permet de donner les numéros d'éléments et de pti { ex_pointe = &loiComp->Cal_implicit(tabSaveDon(indice), *def,CoSfe->tab_ddl ,ptIntegMeca,d_epsBB,jacobien,d_jacobien_tdt ,d_sigHH,pa,sTP,loiTP,dilatation,energ,energ_t ,premier_calcul_meca_impli_expli); } catch (ErrNonConvergence_loiDeComportement excep) // cas d'une d'une erreur survenue à cause d'une non convergence pour la résolution // d'une loi de comportement incrémentale { cout << "\n erreur de loi de comportement element= " << this->Num_elt() << " point d'integration de surface= "<Id_comport())) << " non prevu pour le calcul le l'epaisseur avec l'element SFE "; cout << "\n SfeMembT::Calcul_implicit(.... \n"; Sortie(1); }; }; somme_epaisseurs_finales += epaisseur_tdt; //pour le calcul final //--------- pour le débug -------- // Deformation & defS = *defSurf(1); // pour simplifier l'écriture // int nbddls = ddlS.NbDdl(); //------- pour le débug fin ------- if ((jacobien <= 0.)|| (std::isinf(jacobien))||( std::isnan(jacobien))) // vérif du jacobien { if ((std::isinf(jacobien))||( std::isnan(jacobien))) // on met un message quelque soit le niveau d'impression { cout << "\n ********** attention on a trouve un jacobien infini ou nan !! = ("<= 1) { cout << "\n ********** attention on a trouve un jacobien negatif!! ("< 1.) && ( rap > pa.MaxiVarJacobien())) { if (ParaGlob::NiveauImpression() >= 3) { cout << "\n *** attention la variation maximale du jacobien est atteinte !! *** " << "\n ele= "<< Num_elt() << " ni_surf: " << nisur << " ni_ep: " << niepais << " jacobien= " << jacobien << " jacobien_0= " << (*(ex.jacobien_0)) << endl; }; // on génère une exception throw ErrVarJacobienMini_ElemMeca();break; } else { // on prend en compte toutes les variations // dans le cas d'un élément 3D, épaisseur est stockée aux noeuds, donc ici la variable // épaisseur_tdt ne devrait pas exister, en particulier le jacobien intègre déjà l'épaisseur // pour éviter des tests et une recopie du code on laisse epaisseur_tdt, avec une valeur 1 // ce qui fait qu'elle n'intervient pas if (donnee_specif.epais == NULL) epaisseur_pris_en_compte = 1.; // on continue que s'il s'agit d'une loi différente de rien if (!Loi_rien(loiComp->Id_comport())) {// il ne faut pas interpoler l'énergie à t, car elle était associée à un volume qui a changé // donc il ne faut considérer que l'accroissement d'énergie energie_totale.Ajout_differenciee(energ,energ_t,(poids * jacobien * epaisseur_pris_en_compte)); // energie_totale += (energ-energ_t) * (poids * jacobien * epaisseur_tdt); // energie_totale += energ * (poids * jacobien * epaisseur_tdt); // l'ordre des ddl vient de la métrique: tous le xi, puis les épaisseurs, par contre dans le stockage // local on doit avoir noeud1: ddlxi puis epais, noeud2: idem etc pour les noeuds centraux, puis ddl xi // pour les noeuds externes. Si pas de ddl epais, tous les noeuds sont traités de la même manière // on utilise un adressage indirecte ////--- debug //if (Dabs(epaisseur_pris_en_compte - donnee_specif.epais->epaisseur0) > 0.01) // {cout << "\n debug SfeMembT::Calcul_implicit: epai= " // << epaisseur_pris_en_compte << " epai_0= "<< donnee_specif.epais->epaisseur0 << endl; // }; //// --- fin debug for (int j =1; j<= nbddl; j++) // 1ere boucle sur les ddl { int jloc = CoSfe->nMetVTab_ddl(j); // adressage indirecte (*residu)(jloc) -= ((*(d_epsBB(j))) && sigHH ) * poids * jacobien* epaisseur_pris_en_compte; /*//--debug if ((*residu)(jloc) > 10.) { cout << "\n SfeMembT::Calcul_implicit debug "; cout << "\n (*ex.giB_0)(1): " ;(*ex.giB_0)(1).Affiche(); cout << " (*ex.giB_0)(2): " ;(*ex.giB_0)(2).Affiche(); cout << " (*ex.giH_0)(1): " ;(*ex.giH_0)(1).Affiche(); cout << " (*ex.giH_0)(2): " ;(*ex.giH_0)(2).Affiche(); cout << "\n (*ex.giBB_0): " ;(*ex.gijBB_0).Ecriture(cout); cout << "\n (*ex.giHH_0): " ;(*ex.gijHH_0).Ecriture(cout); cout << "\n (*(d_epsBB(j))): " ;(*(d_epsBB(j))).Ecriture(cout); cout << "\n sigHH: " ;sigHH.Ecriture(cout); cout << endl; ex_pointe = &loiComp->Cal_implicit(tabSaveDon(indice), *def,CoSfe->tab_ddl ,ptIntegMeca,d_epsBB,jacobien,d_jacobien_tdt ,d_sigHH,pa,sTP,loiTP,dilatation,energ,energ_t ,premier_calcul_meca_impli_expli); Sortie(1); }; //--fin debug */ //test si le jacobien due aux gi finaux est très différent du jacobien de la facette //test si le jacobien due aux gi finaux est très différent du jacobien de la facette Delta_Jacobien_anormal(tabSaveDefDon(indice),nisur,niepais); volume += jacobien * poids * epaisseur_tdt; // là on prend la vraie épaisseur for (int i =1; i<= nbddl; i++) // 2ere boucle sur les ddl { int iloc = CoSfe->nMetVTab_ddl(i); // adressage indirecte (*raideur)(jloc,iloc) += ( ((*d_sigHH(i)) && (*(d_epsBB(j)))) * jacobien + (sigHH && (*((CoSfe->d2_epsBB)(indice)(j,i)))) * jacobien + (sigHH && (*(d_epsBB(j)))) * d_jacobien_tdt(i) ) * poids * epaisseur_pris_en_compte; // on utilise toujour la variation de D, donc c'est maintenant directement intégré dans l'expression précédente, et la suite est commentée // // on intègre la variation seconde si c'est demandé // if (pa.Var_D()) // (*raideur)(jloc,iloc) += (sigHH && (*((CoSfe->d2_epsBB)(indice)(j,i)))) // * jacobien * poids * epaisseur_tdt; // ---- pour test débug // if (i < 10) // (*raideur)(j,i) += (sigHH && (*(d_epsBB(j)))) * d_jacobien_tdt(i) * poids * donnee_specif.epaisseur_tdt; }; }; }; // --- cas éventuel d'une stabilisation membrane-biel --- // ici il s'agit de la contribution précise à chaque pti if (pt_StabMembBiel != NULL) if (!(pt_StabMembBiel->Aa_calculer())) { double poids_vol = poids * epaisseur_pris_en_compte; Cal_implicit_StabMembBiel (nisur,*ex_final,nbtotsurf,poids_vol,unefois->doCoMemb->noeud_a_prendre_en_compte); }; };// fin du if sur la valeur non négative du jacobien ////--debug //for (int i = 1; i<= 18; i++) // { if ((*residu)(i) != 0. ) // { cout << "\n SfeMembT::Calcul_implicit debug "; // cout << endl; // }; ////if (num_elt == 176) //// { cout << "\n SfeMembT::Calcul_implicit debug "; //// cout << endl; // }; ////--fin debug if (ElemMeca::Bulk_visco_actif()) // dans le cas du bulk on retire la contrainte du bulk, qui est non physique { sigHH -= (*sig_bulk_pourSfe_HH); } // ceci pour la sauvegarde ou autre utilisation }; // fin boucle sur les points d'intégration #ifdef MISE_AU_POINT if (ParaGlob::NiveauImpression() > 9) { cout << "\n Raideur et second membre locaux: ? (o/n) "; string rep(" "); // procédure de lecture avec prise en charge d'un retour chariot rep = lect_return_defaut(false,"n"); if ((rep == "0")||(rep == "o")) {cout << "\n Raideur et second membre locaux: elem= " << Num_elt_const() << ", maillage= " << Num_maillage(); cout << "\n raideur: "; raideur->Affiche(); cout << "\n second membre: " << (*residu); }; }; #endif // --- intervention dans le cas d'une stabilisation d'hourglass // stabilisation pour un calcul implicit if (type_stabHourglass) Cal_implicit_hourglass(); // --- cas éventuel d'une stabilisation membrane-biel --- // ici il s'agit soit du calcul approché d'initialisation, soit de la fin du calcul après la boucle // modif: 10 janvier 2019 non c'est le calcul correct une fois la raideur calculée if (pt_StabMembBiel != NULL) {if (pt_StabMembBiel->Aa_calculer()) {Cal_implicit_StabMembBiel (0,*ex_final, nbtotsurf,volume,unefois->doCoMemb->noeud_a_prendre_en_compte);} else {Cal_implicit_StabMembBiel (-1,*ex_final, nbtotsurf,volume,unefois->doCoMemb->noeud_a_prendre_en_compte);} ; }; #ifdef MISE_AU_POINT if (ParaGlob::NiveauImpression() > 9) { if ((type_stabHourglass)||(pt_StabMembBiel != NULL)) {cout << "\n apres stabilisation: Raideur et second membre locaux: ? (o/n) "; string rep(" "); // procédure de lecture avec prise en charge d'un retour chariot rep = lect_return_defaut(false,"n"); if ((rep == "0")||(rep == "o")) {cout << "\n Raideur et second membre locaux: elem= " << Num_elt_const() << ", maillage= " << Num_maillage(); cout << "\n raideur: "; raideur->Affiche(); cout << "\n second membre: " << (*residu); }; }; }; #endif ////--debug //for (int i = 1; i<= 18; i++) // { if ((*residu)(i) != 0. ) // { cout << "\n SfeMembT::Calcul_implicit debug "; // cout << endl; // }; ////if (num_elt == 176) //// { cout << "\n SfeMembT::Calcul_implicit debug "; //// cout << endl; // }; ////--fin debug // on calcul éventuellement l'épaisseur moyenne finale si c'est un élément 2D if ((donnee_specif.epais != NULL) && (!Loi_rien(loiComp->Id_comport())) )// cas 2D donnee_specif.epais->epaisseur_tdt = somme_epaisseurs_finales / (indice - 1); // liberation des tenseurs intermediaires LibereTenseur(); Element::ResRaid el; el.res = residu; el.raid = raideur; return el; }; // Calcul de la matrice masse pour l'élément // celle-ci est calculée uniquement pour l'élément centrale et en considérant // que la masse volumique est constante dans l'épaisseur Mat_pleine * SfeMembT::CalculMatriceMasse (Enum_calcul_masse type_calcul_masse) { SfeMembT::DonnComSfe* CoSfe = unefois->doCoMemb; // pour simplifier l'écriture // dimensionement de la métrique si nécessaire if (!(unefois->CalDynamique )) { unefois->CalDynamique += 1; Tableau tab(5); tab(1) = igiB_0; tab(2) = igiB_tdt; tab(3) = igijBB_0; tab(4) = igijBB_tdt; tab(5) = igradVmoyBB_t; CoSfe->met_SfeMembT.PlusInitVariables(tab) ; // on vérifie le bon dimensionnement de la matrice if (type_calcul_masse == MASSE_CONSISTANTE) // dans le cas où la masse est consistante il faut la redimensionner { int nbddl = CoSfe->tab_ddl.NbDdl(); (CoSfe->matrice_masse).Initialise (nbddl,nbddl,0.); } }; if ((donnee_specif.epais != NULL) // on change les épaisseurs si elles sont stockées && (!Loi_rien(loiComp->Id_comport())) ) ((DeformationSfe1*) def)->Change_epaisseur(*donnee_specif.epais); // au niveau de l'élément // appel de la routine générale ////************ non, ce n'est pas correcte pour les éléments 3D, il faut revoir le calcul de la masse //// en utilisant d(OM)/d_ddl au lieu de phi^r ElemMeca::Cal_Mat_masse (CoSfe->tab_ddl,type_calcul_masse, nombre->nbisMas,CoSfe->eleMas->TaPhi(),nombre->nbnce ,CoSfe->eleMas->TaWi()); if ((donnee_specif.epais != NULL) // prise en compte de l'épaisseur finale, si elle est stockée && (!Loi_rien(loiComp->Id_comport())) ) (*mat_masse) *= donnee_specif.epais->epaisseur_tdt; // au niveau de l'élément, sinon on est en 3D, donc c'est // intégré dans le jacobien return mat_masse; }; //============= lecture écriture dans base info ========== // cas donne le niveau de la récupération // = 1 : on récupère tout // = 2 : on récupère uniquement les données variables (supposées comme telles) void SfeMembT::Lecture_base_info (ifstream& ent,const Tableau * tabMaillageNoeud,const int cas) {// tout d'abord appel de la lecture de la classe elem_meca ElemMeca::Lecture_bas_inf(ent,tabMaillageNoeud,cas); // traitement du cas particulier de l'élément centrale string nom; switch (cas) { case 1 : // ------- on récupère tout ------------------------- { // construction du tableau de ddl des noeuds de l'élément centrale ConstTabDdl(); // récup contraintes et déformation lesPtMecaInt.Lecture_base_info(ent,cas); // les données spécifiques ent >> nom; if (nom == "epaisStockeDansElement") { // cas où les épaisseurs sont stockées dans l'élément if (donnee_specif.epais == NULL) donnee_specif.epais = new Epai; ent >> nom >> donnee_specif.epais->epaisseur0 >> nom >> donnee_specif.epais->epaisseur_t >> nom >> donnee_specif.epais->epaisseur_tdt; } else // cas d'un stockage au niveau des noeuds { if (donnee_specif.epais != NULL) delete donnee_specif.epais;}; // CL éventuelles : ent >> nom ; bool existe_CL; ent >> existe_CL; if (existe_CL) {if (areteTypeCL != (&(unefois->doCoMemb->tabType_rienCL))) { // si les tableaux n'existent pas on les crée if (areteTypeCL == (&(unefois->doCoMemb->tabType_rienCL))) areteTypeCL = new Tableau (3); if (vplan == (&(unefois->doCoMemb->vplan_rien))) vplan = new Tableau (3); // et on récupère les infos ent >> nom; (*areteTypeCL)(1) = Id_nomTypeCL(nom); ent >> (*vplan)(1); ent >> nom; (*areteTypeCL)(2) = Id_nomTypeCL(nom); ent >> (*vplan)(2); ent >> nom; (*areteTypeCL)(3) = Id_nomTypeCL(nom); ent >> (*vplan)(3); } } else {// on supprime les tableaux locaux éventuels et on pointe vers les valeurs par défaut if (areteTypeCL != (&(unefois->doCoMemb->tabType_rienCL))) delete areteTypeCL; areteTypeCL = (&(unefois->doCoMemb->tabType_rienCL)); if (vplan != (&(unefois->doCoMemb->vplan_rien))) delete vplan; vplan = (&(unefois->doCoMemb->vplan_rien)); }; break; } case 2 : // ----------- lecture uniquement de se qui varie -------------------- { // récup contraintes et déformation lesPtMecaInt.Lecture_base_info(ent,cas); // les données spécifiques bool avecEpaisDansElement = true; ent >> avecEpaisDansElement; if (avecEpaisDansElement) { if (donnee_specif.epais == NULL) donnee_specif.epais = new Epai; ent >> nom >> donnee_specif.epais->epaisseur_tdt; donnee_specif.epais->epaisseur_t = donnee_specif.epais->epaisseur_tdt; }; // CL éventuelles : on ne les lit pas car elles sont généré éventuellement // à chaque fois que l'on met les CL, sinon elles ne changent pas break; } default : { cout << "\nErreur : valeur incorrecte du type de lecture !\n"; cout << "SfeMembT::::Lecture_base_info(ifstream& ent,const " << "Tableau * tabMaillageNoeud,const int cas)" << " cas= " << cas << endl; Sortie(1); } } }; // cas donne le niveau de sauvegarde // = 1 : on sauvegarde tout // = 2 : on sauvegarde uniquement les données variables (supposées comme telles) void SfeMembT::Ecriture_base_info(ofstream& sort,const int cas) {// tout d'abord appel de l'écriture de la classe elem_meca ElemMeca::Ecriture_bas_inf(sort,cas); // traitement du cas particulier de l'élément central switch (cas) { case 1 : // ------- on sauvegarde tout ------------------------- { // des tenseurs déformation et contrainte, lesPtMecaInt.Ecriture_base_info(sort,cas); // les données spécifiques if (donnee_specif.epais != NULL) { sort << "\n epaisStockeDansElement " << " epaisseur0= " << donnee_specif.epais->epaisseur0 << " epaisseur_t= " << donnee_specif.epais->epaisseur_t << " epaisseur_tdt= " << donnee_specif.epais->epaisseur_tdt; } else { sort << "\n epaisStockeAuxNoeuds "; }; // CL éventuelles : sort << " CL= "; if (areteTypeCL != (&(unefois->doCoMemb->tabType_rienCL))) { // si ça ne pointe pas sur la valeur par défaut, alors c'est qu'il y a // des CL particulières, sort << " 1 "; sort << NomTypeCL((*areteTypeCL)(1)) << " " << (*vplan)(1) << NomTypeCL((*areteTypeCL)(2)) << " " << (*vplan)(2) << NomTypeCL((*areteTypeCL)(3)) << " " << (*vplan)(3); } else {sort << " 0 "; }; break; } case 2 : // ----------- sauvegarde uniquement de se qui varie -------------------- { // des tenseurs déformation et contrainte, lesPtMecaInt.Ecriture_base_info(sort,cas); // les données spécifiques if (donnee_specif.epais != NULL) { sort << "\n 1 epaisseur_tdt= " << donnee_specif.epais->epaisseur_tdt;} else { sort << "\n 0 ";}; // CL éventuelles : on ne les sort pas car elles sont généré éventuellement // à chaque fois que l'on met les CL, sinon elles ne changent pas break; } default : { cout << "\nErreur : valeur incorrecte du type d'écriture !\n"; cout << "SfeMembT::::Ecriture_base_info(ofstream& sort,const int cas)" << " cas= " << cas << endl; Sortie(1); } }; }; //------- calcul d'erreur, remontée des contraintes ------------------- // calcul du résidu et de la matrice de raideur pour le calcul d'erreur // en fait on ne calculera l'erreur que sur la contrainte sur toute la surface // mais sur le premier pt d'integ d'épaisseur Element::Er_ResRaid SfeMembT::ContrainteAuNoeud_ResRaid() { SfeMembT::DonnComSfe* CoSfe = unefois->doCoMemb; // pour simplifier l'écriture // dimensionnement de la metrique if(!( unefois->CalResPrem_t )) {unefois->CalResPrem_t += 1; Tableau tab(10); tab(1) = igiB_0; tab(2) = igiB_t; tab(3) = igijBB_0;tab(4) = igijBB_t; tab(5) = igijHH_t; tab(6) = id_giB_t; tab(7) = id_gijBB_t ; tab(8) = id_gijBB_t ;tab(9) = igradVBB_t; tab(10) = iVt; CoSfe->met_SfeMembT.PlusInitVariables(tab) ; }; // appel du programme général int tabn_taille = tab_noeud.Taille(); ElemMeca:: SigmaAuNoeud_ResRaid(tabn_taille, CoSfe->eleCentre->TaPhi(), CoSfe->eleCentre->TaWi(), CoSfe-> resErr,CoSfe->raidErr, CoSfe->eleEr->TaPhi(), CoSfe->eleEr->TaWi()); // --- on tient compte de l'épaisseur à t, supposée déjà calculée ou récupérée // dans le cas d'un élément 3D, épaisseur est stockée aux noeuds, donc ici la variable // épaisseur_t ne devrait pas exister, en particulier le jacobien intègre déjà l'épaisseur // pour éviter des tests et une recopie du code on laisse epaisseur_t, avec une valeur 1 // ce qui fait qu'elle n'intervient pas double epaisseur = 0.; // init if (donnee_specif.epais == NULL) {epaisseur = 1.;} else {epaisseur = donnee_specif.epais->epaisseur_t;}; // on tient compte de l'épaisseur à t, supposée déjà calculée ou récupérée int taille_resErr=CoSfe->resErr.Taille(); for (int i=1;i<= taille_resErr;i++) (*CoSfe-> resErr(i)) *= epaisseur; CoSfe->raidErr *= epaisseur; return (Element::Er_ResRaid( &(CoSfe-> resErr),&(CoSfe->raidErr))); } ; // calcul du résidu pour le calcul d'erreur ramenée aux noeuds Element::Er_ResRaid SfeMembT::ErreurAuNoeud_ResRaid() { SfeMembT::DonnComSfe* CoSfe = unefois->doCoMemb; // pour simplifier l'écriture // dimensionnement de la metrique if(!( unefois->CalResPrem_t )) { unefois->CalResPrem_t += 1; Tableau tab(10); tab(1) = igiB_0; tab(2) = igiB_t; tab(3) = igijBB_0;tab(4) = igijBB_t; tab(5) = igijHH_t; tab(6) = id_giB_t; tab(7) = id_gijBB_t ; tab(8) = id_gijBB_t ;tab(9) = igradVBB_t; tab(10) = iVt; CoSfe->met_SfeMembT.PlusInitVariables(tab) ; }; // appel du programme général int tabn_taille = tab_noeud.Taille(); ElemMeca::Cal_ErrAuxNoeuds(tabn_taille, CoSfe->eleCentre->TaPhi(),CoSfe->eleCentre->TaWi() ,CoSfe-> resErr ); // --- on tient compte de l'épaisseur à t, supposée déjà calculée ou récupérée // dans le cas d'un élément 3D, épaisseur est stockée aux noeuds, donc ici la variable // épaisseur_t ne devrait pas exister, en particulier le jacobien intègre déjà l'épaisseur // pour éviter des tests et une recopie du code on laisse epaisseur_t, avec une valeur 1 // ce qui fait qu'elle n'intervient pas double epaisseur = 0.; // init if (donnee_specif.epais == NULL) {epaisseur = 1.;} else {epaisseur = donnee_specif.epais->epaisseur_t;}; int taille_resErr=CoSfe->resErr.Taille(); for (int i=1;i<= taille_resErr;i++) (*CoSfe-> resErr(i)) *= epaisseur; CoSfe->raidErr *= epaisseur; return (Element::Er_ResRaid( &(CoSfe-> resErr),&(CoSfe->raidErr))); } ; // actualisation des ddl et des grandeurs actives de t+dt vers t void SfeMembT::TdtversT() { lesPtMecaInt.TdtversT(); // contrainte if (donnee_specif.epais != NULL) donnee_specif.epais->epaisseur_t = donnee_specif.epais->epaisseur_tdt; int taille = lesPtMecaInt.NbPti(); for (int ni=1;ni<= taille; ni++) { if (tabSaveDon(ni) != NULL) tabSaveDon(ni)->TdtversT(); if (tabSaveTP(ni) != NULL) tabSaveTP(ni)->TdtversT(); if (tabSaveDefDon(ni) != NULL) tabSaveDefDon(ni)->TdtversT(); } ElemMeca::TdtversT_(); // appel de la procédure mère }; // actualisation des ddl et des grandeurs actives de t vers tdt void SfeMembT::TversTdt() { lesPtMecaInt.TversTdt(); // contrainte if (donnee_specif.epais != NULL) donnee_specif.epais->epaisseur_tdt = donnee_specif.epais->epaisseur_t; int taille = lesPtMecaInt.NbPti(); for (int ni=1;ni<= taille; ni++) { if (tabSaveDon(ni) != NULL) tabSaveDon(ni)->TversTdt(); if (tabSaveTP(ni) != NULL) tabSaveTP(ni)->TversTdt(); if (tabSaveDefDon(ni) != NULL) tabSaveDefDon(ni)->TversTdt(); } ElemMeca::TversTdt_(); // appel de la procédure mère }; // calcul de l'erreur sur l'élément. // en fait on ne calculera l'erreur que sur la contrainte sur toute la surface // mais sur le premier pt d'integ d'épaisseur void SfeMembT::ErreurElement(int type,double& errElemRelative ,double& numerateur, double& denominateur) { SfeMembT::DonnComSfe* CoSfe = unefois->doCoMemb; // pour simplifier l'écriture // dimensionnement de la metrique if(!( unefois->CalResPrem_t )) { unefois->CalResPrem_t += 1; Tableau tab(10); tab(1) = igiB_0; tab(2) = igiB_t; tab(3) = igijBB_0;tab(4) = igijBB_t; tab(5) = igijHH_t; tab(6) = id_giB_t; tab(7) = id_gijBB_t ; tab(8) = id_gijBB_t ;tab(9) = igradVBB_t; tab(10) = iVt; CoSfe->met_SfeMembT.PlusInitVariables(tab) ; }; // appel du programme général ElemMeca::Cal_ErrElem(type,errElemRelative,numerateur,denominateur, tab_noeud.Taille(),CoSfe->eleCentre->TaPhi(), CoSfe->eleCentre->TaWi(), CoSfe->eleEr->TaPhi(),CoSfe->eleEr->TaWi()); } ; // mise à jour de la boite d'encombrement de l'élément, suivant les axes I_a globales // en retour coordonnées du point mini dans retour.Premier() et du point maxi dans .Second() // la méthode est différente de la méthode générale car il faut prendre en compte l'épaisseur de l'élément const DeuxCoordonnees& SfeMembT::Boite_encombre_element(Enum_dure temps) { int tab_taille= tab_noeud.Taille(); // on commence par calculer la boite d'encombrement pour l'élément médian Element::Boite_encombre_element( temps); // ensuite on augment sytématiquement dans toutes directions d'une valeur h/2 majorée // h étant l'épaisseur maxi constatée double epais_maxi=0.; // init if (donnee_specif.epais != NULL) { // cas où les épaisseurs sont stockées sur l'élément epais_maxi = donnee_specif.epais->epaisseur_tdt; } else { // cas où les épaisseurs sont stockées aux noeuds for (int ine=1;ine<=nombre->nbnce;ine++) // balayage des noeuds epais_maxi = MaX(epais_maxi,tab_noeud(ine)->Valeur_tdt(EPAIS)); }; double hSur2maj = epais_maxi * 0.5 * (ParaGlob::param->ParaAlgoControleActifs().Extra_boite_prelocalisation()-1.); // ajout d'un extra dans toutes les directions hSur2maj += ParaGlob::param->ParaAlgoControleActifs().Ajout_extra_boite_prelocalisation(); // mise à jour boite_encombre.Premier().Ajout_meme_valeur(-hSur2maj); // le min boite_encombre.Second().Ajout_meme_valeur(hSur2maj); // le max // retour return boite_encombre; }; // ramène le nombre de points d'intégration de surface correspondant à un type énuméré // ramène 0 si l'élément n'est pas une plaque ou coque int SfeMembT::NbPtIntegSurface(Enum_ddl ddl ) const { switch (ddl) { case ERREUR : return nombre->nbisEr; break; default : return nombre->nbis; break; }; }; // ramène le nombre de points d'intégration en épaisseur correspondant à un type énuméré // ramène 0 si l'élément n'est pas une plaque ou coque int SfeMembT::NbPtIntegEpaiss(Enum_ddl ddl) const { switch (ddl) { case ERREUR : return nombre->nbieEr; break; default : return nombre->nbie; break; }; }; // ramene l'element geometrique de surface correspondant au ddl passé en paramètre // ou null si ce n'est pas définie, dans ce cas si l'élément géométrique de surface est 2D // cela signifie qu'il faut se référer à l'élément générique: ElementGeometrie(... ElemGeomC0* SfeMembT::ElementGeometrieSurface(Enum_ddl ddl ) const { switch (ddl) { case ERREUR : return (unefois->doCoMemb->eleEr); break; default : return (unefois->doCoMemb->eleCentre); break; }; }; // ramene l'element geometrique d'épaisseur correspondant au ddl passé en paramètre // ou null si ce n'est pas définie, dans ce cas si l'élément géométrique de surface est 2D // cela signifie que tout est constant (identique) dans l'épaisseur ElemGeomC0* SfeMembT::ElementGeometrieEpaiss(Enum_ddl ddl ) const { switch (ddl) { case ERREUR : return &(unefois->doCoMemb->segmentEr); break; default : return &(unefois->doCoMemb->segment); break; }; }; // retourne un numero d'ordre d'un point le plus près ou est exprimé la grandeur enum // par exemple un point d'intégration, mais n'est utilisable qu'avec des méthodes particulières // par exemple CoordPtInteg, ou Valeur_a_diff_temps // car le numéro d'ordre peut-être différent du numéro d'intégration au sens classique // temps: dit si c'est à 0 ou t ou tdt int SfeMembT::PointLePlusPres(Enum_dure temps,Enum_ddl enu, const Coordonnee& M) { int iret; // récupération des éléments géométriques correspondant à Enu ElemGeomC0* elSur = this->ElementGeometrieSurface(enu); ElemGeomC0* elEpa = this->ElementGeometrieEpaiss(enu); // récupération des tableaux des fonctions d'interpolations const Tableau & tabphiS = elSur->TaPhi(); const Tableau < Mat_pleine > & tabDphiS = elSur->TaDphi(); const Tableau & tabphiH = elEpa->TaPhi(); // on boucle sur les pt d'integ pour avoir le point le plus près int nbptSur = tabphiS.Taille(); int nbptEpa = tabphiH.Taille(); Coordonnee P; iret=1; double dist= ConstMath::tresgrand; int ipt=1; for (int iptH = 1;iptH <= nbptEpa;iptH++) for (int iptS = 1; iptS <= nbptSur;iptS++,ipt++) { switch (temps) { case TEMPS_0 : P = ((Met_Sfe1*) met)->PointSfe1M_0 (tab_noeud,tabphiS(iptS),tabDphiS(iptS),donnee_specif.epais,tabphiH(iptH)); break; case TEMPS_t : P = ((Met_Sfe1*) met)->PointSfe1M_t (tab_noeud,tabphiS(iptS),tabDphiS(iptS),donnee_specif.epais,tabphiH(iptH)); break; case TEMPS_tdt : P = ((Met_Sfe1*) met)->PointSfe1M_tdt (tab_noeud,tabphiS(iptS),tabDphiS(iptS),donnee_specif.epais,tabphiH(iptH)); break; } double di=(M-P).Norme(); if (di < dist) { dist = di; iret = ipt;}; } return iret; // retour }; // recuperation des coordonnées du point de numéro d'ordre iteg pour // la grandeur enu // temps: dit si c'est à 0 ou t ou tdt // si erreur retourne erreur à true Coordonnee SfeMembT::CoordPtInteg(Enum_dure temps,Enum_ddl enu,int iteg,bool& erreur) { Coordonnee ptret; // le retour // récupération des éléments géométriques correspondant à Enu ElemGeomC0* elSur = this->ElementGeometrieSurface(enu); ElemGeomC0* elEpa = this->ElementGeometrieEpaiss(enu); // récupération des tableaux des fonctions d'interpolations const Tableau & tabphiS = elSur->TaPhi(); const Tableau < Mat_pleine > & tabDphiS = elSur->TaDphi(); const Tableau & tabphiH = elEpa->TaPhi(); // def du numéro d'integ en surface et épaisseur int nbptSur = tabphiS.Taille(); int nbptEpa = tabphiH.Taille(); int iptS = iteg / nbptEpa +1; // division entière int iptH = iteg - (iptS-1) * nbptEpa ; // calcul du point if ((iteg < 0) || (iteg > (nbptSur*nbptEpa))) { erreur = false;} else { switch (temps) { case TEMPS_0 : ptret = ((Met_Sfe1*) met)->PointSfe1M_0 (tab_noeud,tabphiS(iptS),tabDphiS(iptS),donnee_specif.epais,tabphiH(iptH)); break; case TEMPS_t : ptret = ((Met_Sfe1*) met)->PointSfe1M_t (tab_noeud,tabphiS(iptS),tabDphiS(iptS),donnee_specif.epais,tabphiH(iptH)); break; case TEMPS_tdt : ptret = ((Met_Sfe1*) met)->PointSfe1M_tdt (tab_noeud,tabphiS(iptS),tabDphiS(iptS),donnee_specif.epais,tabphiH(iptH)); break; } } return ptret; // retour };