// 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 "ElemThermi.h" #include #include "ConstMath.h" #include "Util.h" #include "Coordonnee2.h" #include "Coordonnee3.h" #include "TypeQuelconqueParticulier.h" #include "TypeConsTens.h" #include "Loi_iso_elas3D.h" #include "Loi_iso_elas1D.h" #include "Loi_iso_elas2D_C.h" #include "FrontPointF.h" // -------------------- stabilisation d'hourglass ------------------- // calcul d'élément de contrôle d'hourglass associée à un comportement // str_precision : donne le type particulier d'élément à construire void ElemThermi::Init_hourglass_comp(const ElemGeomC0& elgeHour, const string & str_precision ,LoiAbstraiteGeneral * loiHourglass, const BlocGen & bloc) { //!!!! en fait pour l'instant on n'utilise pas elgehour, on considère que le nombre de pti complet est celui de l'élément sans info annexe !!! // sauf pour l'hexaèdre quadratique pour lequel on a définit un str_precision particulier // on met à jour les indicateurs if (Type_Enum_StabHourglass_existe(bloc.Nom(1))) {type_stabHourglass = Id_Nom_StabHourglass(bloc.Nom(1).c_str()); coefStabHourglass = bloc.Val(1); } else { cout << "\n erreur, le type " << bloc.Nom(2) << " de gestion d'hourglass n'existe pas !!"; if (ParaGlob::NiveauImpression() > 5) cout << "\n ElemThermi::Init_hourglass_comp(..."; cout << endl; Sortie(1); }; switch (type_stabHourglass) {case STABHOURGLASS_PAR_COMPORTEMENT : { // -- choix de l'element pour le calcul de la raideur ----- // on recherche un élément de même type, // par défaut : numéro de maillage = le numéro de this, car c'est bien rattaché à ce maillage, mais l'élément est caché, donc non accessible par le maillage // numéro d'élément = 1000000 + numéro de this : a priori c'est deux numéros n'ont pas d'importance, car ils ne sont pas // rattachés à un maillage existant en tant que tel int nUmMail = this->Num_elt_const(); int nUmElem = 1000000 + this->Num_elt(); tab_elHourglass.Change_taille(1); tab_elHourglass(1) = (ElemThermi*) Element::Choix_element(nUmMail,nUmElem,Id_geometrie(),Id_interpolation(),Id_TypeProblem(),str_precision); if (tab_elHourglass(1) == NULL) { // l'operation a echouee cout << "\n Erreur dans le choix d'un element interne utilise pour le blocage d'hourglass ****** "; cout << "\n l\'element : " << Nom_interpol(id_interpol) << " " << Nom_geom(id_geom) << " " << str_precision << " n\'est pas present dans le programme ! " << endl; if (ParaGlob::NiveauImpression() > 5) cout << "\n ElemThermi::Init_hourglass_comp(..." << endl; Sortie (1); }; // --- définition des noeuds de l'élément ----- // on construit à partir des mêmes noeuds que ceux de l'élément père // affectation des noeuds au nouvel élément tab_elHourglass(1)->Tab_noeud() = this->Tab_noeud(); //--- def de la loi de comportement --- // affectation de la loi tab_elHourglass(1)->DefLoi(loiHourglass); break; } case STABHOURGLASS_PAR_COMPORTEMENT_REDUIT : { // ici on a besoin de deux éléments. Le premier sert à faire le calcul complet // le second sert à faire un calcul réduit, comme l'élément réel tab_elHourglass.Change_taille(2); // -- choix pour le calcul de la raideur ----- // on recherche un élément de même type, // par défaut : numéro de maillage = le numéro de this, car c'est bien rattaché à ce maillage, mais l'élément est caché, donc non accessible par le maillage // numéro d'élément = 1000000 + numéro de this : a priori c'est deux numéros n'ont pas d'importance, car ils ne sont pas // rattachés à un maillage existant en tant que tel //-- le premier élément: int nUmMail = this->Num_elt_const(); int nUmElem = 1000000 + this->Num_elt(); tab_elHourglass(1) = (ElemThermi*) Element::Choix_element(nUmMail,nUmElem,Id_geometrie(),Id_interpolation(),Id_TypeProblem(),str_precision); if (tab_elHourglass(1) == NULL) { // l'operation a echouee cout << "\n Erreur dans le choix d'un element interne utilise pour le blocage d'hourglass ****** "; cout << "\n l\'element : " << Nom_interpol(id_interpol) << " " << Nom_geom(id_geom) << " " << str_precision << " n\'est pas present dans le programme ! " << endl; if (ParaGlob::NiveauImpression() > 5) cout << "\n ElemThermi::Init_hourglass_comp(..." << endl; Sortie (1); }; //-- le second élément identique à this: on utilise le même numéro de maillage // même infos annexes nUmElem = 20000000 + this->Num_elt(); // on ajoute une unité pour le numéro tab_elHourglass(2) = (ElemThermi*) Element::Choix_element(nUmMail,nUmElem,Id_geometrie(),Id_interpolation(),Id_TypeProblem(),this->infos_annexes); if (tab_elHourglass(2) == NULL) { // l'operation a echouee cout << "\n Erreur dans le choix d'un element interne utilise pour le blocage d'hourglass ****** "; cout << "\n l\'element : " << Nom_interpol(id_interpol) << " " << Nom_geom(id_geom) << " " << this->infos_annexes << " n\'est pas present dans le programme ! " << endl; if (ParaGlob::NiveauImpression() > 5) cout << "\n ElemThermi::Init_hourglass_comp(..." << endl; Sortie (1); }; // --- définition des noeuds de l'élément ----- // on construit à partir des mêmes noeuds que ceux de l'élément père // affectation des noeuds au nouvel élément tab_elHourglass(1)->Tab_noeud() = this->Tab_noeud(); tab_elHourglass(2)->Tab_noeud() = this->Tab_noeud(); //--- def de la loi de comportement --- // affectation de la loi tab_elHourglass(1)->DefLoi(loiHourglass); tab_elHourglass(2)->DefLoi(loiHourglass); break; } default : cout << "\n*** Erreur : cas de gestop, d'hourglass non defini !\n"; cout << "\n ElemThermi::Cal_implicit_hourglass() \n"; Sortie(1); }; }; // stabilisation pour un calcul implicit void ElemThermi::Cal_implicit_hourglass() { switch (type_stabHourglass) {case STABHOURGLASS_PAR_COMPORTEMENT : { // --- calcul de la raideur de l'élément, dans le cas implicite --- Element::ResRaid resraid = tab_elHourglass(1)->Calcul_implicit (ParaGlob::param->ParaAlgoControleActifs()); // on tiend compte du facteur de modération (*(resraid.raid)) *= coefStabHourglass; (*(resraid.res)) *= coefStabHourglass; // on met à jour la raideur et le résidu de l'élément principal (*raideur) += (*(resraid.raid)); (*residu) += (*(resraid.res)); //---- debug //cout << "\n raideur locale après stabilisation d'hourglass "; //matRaideur.Affiche(); //---- fin debug }; break; case STABHOURGLASS_PAR_COMPORTEMENT_REDUIT : { // --- calcul de la raideur de l'élément, dans le cas implicite --- // ici on calcul la partie supposée supplémentaire à celle déjà présente dans le calcul réduit // au premier passage ou bien si on demande une grande précision de calcul, on calcul la raideur et le second membre, // ensuite on ne calcul que le second membre if ((raid_hourglass_transitoire == NULL)||(prepa_niveau_precision > 8)) {// 1) calcul de la partie complète Element::ResRaid resraid1 = tab_elHourglass(1)->Calcul_implicit (ParaGlob::param->ParaAlgoControleActifs()); // 2) calcul de la partie réduite Element::ResRaid resraid2 = tab_elHourglass(2)->Calcul_implicit (ParaGlob::param->ParaAlgoControleActifs()); // on soustrait en gardant le résultat dans resraid1 (*(resraid1.raid)) -= (*(resraid2.raid)); (*(resraid1.res)) -= (*(resraid2.res)); // on tiend compte du facteur de modération (*(resraid1.raid)) *= coefStabHourglass; (*(resraid1.res)) *= coefStabHourglass; // on sauvegarde la raideur raid_hourglass_transitoire = new Mat_pleine((*(resraid1.raid))); // on met à jour la raideur et le résidu de l'élément principal (*raideur) += (*(resraid1.raid)); (*residu) += (*(resraid1.res)); } else {// sinon on utilise la précédente raideur sauvegardée et on ne calcul que la partie résidue Vecteur* resHourglass1 = NULL; resHourglass1 = tab_elHourglass(1)->CalculResidu_tdt (ParaGlob::param->ParaAlgoControleActifs()); Vecteur* resHourglass2 = NULL; resHourglass2 = tab_elHourglass(2)->CalculResidu_tdt (ParaGlob::param->ParaAlgoControleActifs()); // on soustrait les résidus en gardant le résultat dans resraid1 (*(resHourglass1)) -= (*(resHourglass2)); // on tiend compte du facteur de modération (*(resHourglass1)) *= coefStabHourglass; // on met à jour le résidu de l'élément principal (*residu) += (*(resHourglass1)); // pour la partie raideur: on met à jour la raideur de l'élément principal (*raideur) += (*raid_hourglass_transitoire); }; //---- debug //cout << "\n raideur locale après stabilisation d'hourglass "; //matRaideur.Affiche(); //---- fin debug }; break; case STABHOURGLASS_NON_DEFINIE : // on ne fait rien break; default : cout << "\n*** Erreur : cas de gestop, d'hourglass non defini !\n"; cout << "\n ElemThermi::Cal_implicit_hourglass() \n"; Sortie(1); }; }; // stabilisation pour un calcul explicit void ElemThermi::Cal_explicit_hourglass(bool atdt) { switch (type_stabHourglass) {case STABHOURGLASS_PAR_COMPORTEMENT : { // --- calcul de la raideur de l'élément, dans le cas implicite --- Vecteur* resHourglass = NULL; if (atdt) {resHourglass = tab_elHourglass(1)->CalculResidu_tdt (ParaGlob::param->ParaAlgoControleActifs());} else {resHourglass = tab_elHourglass(1)->CalculResidu_t (ParaGlob::param->ParaAlgoControleActifs());}; // on tiend compte du facteur de modération (*resHourglass) *= coefStabHourglass; // on met à jour le résidu de l'élément principal (*residu) += (*resHourglass); //---- debug //cout << "\n raideur locale après stabilisation d'hourglass "; //matRaideur.Affiche(); //---- fin debug }; break; case STABHOURGLASS_NON_DEFINIE : // on ne fait rien break; default : cout << "\n*** Erreur : cas de gestop, d'hourglass non defini !\n"; cout << "\n ElemThermi::Cal_implicit_hourglass() \n"; Sortie(1); }; }; // récupération de l'energie d'hourglass éventuelle double ElemThermi::Energie_Hourglass() { double enerHourglass = 0.; switch (type_stabHourglass) {case STABHOURGLASS_PAR_COMPORTEMENT : { // on récupère les énergies stockées à l'élément const EnergieThermi& energieTotale = tab_elHourglass(1)->EnergieTotaleElement(); enerHourglass = coefStabHourglass * (energieTotale.EnergieElastique() + energieTotale.DissipationPlastique() + energieTotale.DissipationVisqueuse()); }; break; }; return enerHourglass; }; // fonction a renseigner par les classes dérivées, concernant les répercutions // éventuelles due à la suppression de tous les frontières // nums_i : donnent les listes de frontières supprimées void ElemThermi::Prise_en_compte_des_consequences_suppression_tous_frontieres() {// il faut supprimer toutes les déformations liés aux frontières int tail_S = defSurf.Taille(); for (int i=1;i<=tail_S;i++) { delete defSurf(i); defSurf(i)=NULL; }; int tail_A = defArete.Taille(); for (int i=1;i<=tail_A;i++) { delete defArete(i); defArete(i)=NULL; }; }; // idem pour une frontière (avant qu'elle soit supprimée) void ElemThermi::Prise_en_compte_des_consequences_suppression_une_frontiere(ElFrontiere* elemFront) { int taille = tabb.Taille(); // on choisit en fonction du type de frontière if (( elemFront->Type_geom_front() == LIGNE)&& (defArete.Taille()!=0)) {int taille_ligne = taille - posi_tab_front_lin; // a priori = cas sans les points if (posi_tab_front_point != 0) // cas où il y a des points taille_ligne = posi_tab_front_point-posi_tab_front_lin; for (int i=1; i<=taille_ligne; i++) {if ((tabb(i+posi_tab_front_lin) == elemFront)&& (defArete(i) != NULL)) {delete defArete(i);defArete(i)=NULL;break;} } } else if (( elemFront->Type_geom_front() == SURFACE) && (defSurf.Taille()!=0)) {if (posi_tab_front_lin != 0) // si == 0 cela signifie qu'il n'y a pas de surface à supprimer !! { for (int i=1; i<=posi_tab_front_lin; i++) // posi_tab_front_lin == le nombre de surfaces, qui sont obligatoirement en début de tableau if ((tabb(i) == elemFront)&& (defSurf(i) != NULL)) {delete defSurf(i);defSurf(i)=NULL;break;} }; }; }; // Calcul des frontieres de l'element // creation des elements frontieres et retour du tableau de ces elements // la création n'a lieu qu'au premier appel // ou lorsque l'on force le paramètre force a true // dans ce dernier cas seul les frontière effacées sont recréée // cas : // = 0 -> on veut toutes les frontières // = 1 -> on veut uniquement les surfaces // = 2 -> on veut uniquement les lignes // = 3 -> on veut uniquement les points // = 4 -> on veut les surfaces + les lignes // = 5 -> on veut les surfaces + les points // = 6 -> on veut les lignes + les points Tableau const & ElemThermi::Frontiere_elethermi(int cas, bool force) {// le calcul et la création ne sont effectués qu'au premier appel // ou lorsque l'on veut forcer une recréation int taille = tabb.Taille(); // la taille initiales des frontières if (force) // dans ce cas on commence par tout effacer { // on efface les surfaces (s'il y en a) for (int i=1;i<=posi_tab_front_lin;i++) {if (tabb(i) != NULL) {delete tabb(i); //on commence par supprimer tabb(i)=NULL; // on supprime également éventuellement la déformation associée if (defSurf.Taille() != 0) if (defSurf(i) != NULL) {delete defSurf(i);defSurf(i)=NULL;}; ind_front_surf = 0; // on indique qu'il ne reste plus de frontière surface }; }; // on efface les lignes (s'il y en a) for (int i=1;i<=posi_tab_front_point - posi_tab_front_lin;i++) {if (tabb(i+posi_tab_front_lin) != NULL) {delete tabb(i+posi_tab_front_lin); //on commence par supprimer tabb(i+posi_tab_front_lin)=NULL; // on supprime également éventuellement la déformation associée if (defArete.Taille() != 0) if (defArete(i) != NULL) {delete defArete(i);defArete(i)=NULL;}; ind_front_lin = 0; // on indique qu'il ne reste plus de frontière ligne }; }; // on efface les points (s'il y en a) for (int i=1;i<=taille - posi_tab_front_point;i++) {if (tabb(i+posi_tab_front_point) != NULL) {delete tabb(i+posi_tab_front_point); //on commence par supprimer tabb(i+posi_tab_front_point)=NULL; ind_front_point = 0; // on indique qu'il ne reste plus de frontière ligne }; }; }; // -- maintenant on s'occupe de la construction conditionnelle bool built_surf = false;bool built_ligne = false; bool built_point = false; switch (cas) {case 0: built_surf = built_ligne = built_point = true; break; case 1: built_surf = true; break; case 2: built_ligne = true; break; case 3: built_point = true; break; case 4: built_surf = built_ligne = true; break; case 5: built_surf = built_point = true; break; }; if ( ((ind_front_surf == 0)&& (ind_front_lin == 0) && (ind_front_point == 0)) || force ) { // récup de l'élément géométrique ElemGeomC0& el = ElementGeometrique(); int tail_ar = el.NbSe(); // nombre potentiel d'arêtes int tail_fa = el.NbFe(); // nombre potentiel de faces int tail_po = el.Nbne(); // nombre potentiel de points // récup du tableau de ddl actuel const DdlElement & tdd = TableauDdl(); // --- on va construire en fonction des indicateurs des tableaux intermédiaires int new_posi_tab_front_point = 0; //init par défaut int new_posi_tab_front_lin = 0; //init par défaut int new_ind_front_point = 0; int new_ind_front_lin = 0; int new_ind_front_surf = 0; // -- pour les surfaces Tableau tabb_surf; if ((built_surf)&& ((ind_front_surf == 0)||force)) {tabb_surf.Change_taille(tail_fa,NULL);// init par défaut for (int num=1;num<=tail_fa;num++) { int nbnoe = el.Nonf()(num).Taille(); // nb noeud de la surface Tableau tab(nbnoe); // les noeuds de la frontiere DdlElement ddelem(nbnoe); // les ddlelements des noeuds frontieres for (int i=1;i<= nbnoe;i++) { tab(i) = tab_noeud(el.Nonf()(num)(i)); ddelem.Change_un_ddlNoeudElement(i,tdd(el.Nonf()(num)(i))); }; tabb_surf(num) = new_frontiere_surf(num,tab,ddelem); }; // nouveau indicateur d'existence new_ind_front_surf = 1; // on positionne les nouvelles positions new_posi_tab_front_point += tail_fa; new_posi_tab_front_lin += tail_fa; }; // -- pour les lignes Tableau tabb_ligne; if ((built_ligne)&& ((ind_front_lin == 0)||force)) {tabb_ligne.Change_taille(tail_ar,NULL);// init par défaut for (int num=1;num<=tail_ar;num++) { int nbnoe = el.NonS()(num).Taille(); // nb noeud de l'arête Tableau tab(nbnoe); // les noeuds de l'arête frontiere DdlElement ddelem(nbnoe); // les ddlelements des noeuds frontieres for (int i=1;i<= nbnoe;i++) { tab(i) = tab_noeud(el.NonS()(num)(i)); ddelem.Change_un_ddlNoeudElement(i,tdd(el.NonS()(num)(i))); }; tabb_ligne(num) = new_frontiere_lin(num,tab,ddelem); }; // nouveau indicateur d'existence new_ind_front_lin = 1; // on positionne les nouvelles positions new_posi_tab_front_point += tail_ar; }; // -- pour les points Tableau tabb_point; if ((built_point) && ((ind_front_point == 0)||force)) {tabb_point.Change_taille(tail_po,NULL);// init par défaut // maintenant création des frontière point éventuellement Tableau tab(1); // les noeuds de la frontiere (tab de travail) DdlElement ddelem(1); // les ddlelements des points frontieres (tab de travail) for (int i=1;i<=tail_po;i++) if (tabb_point(i) == NULL) { tab(1) = tab_noeud(i); ddelem.Change_un_ddlNoeudElement(1,tdd(i)); tabb_point(i) = new FrontPointF(tab,ddelem); }; // nouveau indicateur d'existence new_ind_front_point = 1; }; // --- mise à jour du tableau globale et des indicateurs ad hoc int taille_finale = tabb_surf.Taille()+tabb_ligne.Taille()+tabb_point.Taille(); tabb.Change_taille(taille_finale); // cas des points if (new_ind_front_point) // là is s'agit de nouveaux éléments {for (int i=tail_po;i>0;i--) // transfert pour les noeuds { tabb(i+new_posi_tab_front_point) = tabb_point(i);} } else if (ind_front_point) // là il s'agit d'anciens éléments {for (int i=tail_po;i>0;i--) // transfert pour les noeuds en descendant { tabb(i+new_posi_tab_front_point) = tabb(i+posi_tab_front_point);} }; // cas des lignes if (new_ind_front_lin) // là il s'agit de nouveaux éléments {for (int i=1;i<=tail_ar;i++) // transfert { tabb(i+new_posi_tab_front_lin) = tabb_ligne(i);} } else if (ind_front_lin) // là il s'agit d'anciens éléments {for (int i=tail_ar;i>0;i--) // transfert en descendant { tabb(i+new_posi_tab_front_lin) = tabb(i+posi_tab_front_lin);} }; // cas des surfaces if (new_ind_front_surf) // là is s'agit de nouveaux éléments {for (int i=1;i<=tail_fa;i++) // transfert { tabb(i) = tabb_surf(i);} }; // dans le cas où il y avait des anciens éléments, il n'y a rien n'a faire // car le redimentionnement de tabb ne change pas les premiers éléments // mis à jour des indicateurs ind_front_surf = new_ind_front_surf; posi_tab_front_lin = new_posi_tab_front_lin; ind_front_lin = new_ind_front_lin; posi_tab_front_point = new_posi_tab_front_point; ind_front_point = new_ind_front_point; }; // retour du tableau return (Tableau &)tabb; }; // ramène la frontière point // éventuellement création des frontieres points de l'element et stockage dans l'element // si c'est la première fois sinon il y a seulement retour de l'elements // a moins que le paramètre force est mis a true // dans ce dernier cas la frontière effacéee est recréée // num indique le numéro du point à créer (numérotation EF) ElFrontiere* const ElemThermi::Frontiere_points(int num,bool force) { // -- tout d'abord on évacue le cas où il n'y a pas de frontière surfacique à calculer // récup de l'élément géométrique ElemGeomC0& el = ElementGeometrique(); int tail_po = el.Nbne(); // nombre potentiel de points if (num > tail_po) return NULL; // le calcul et la création ne sont effectués qu'au premier appel // ou lorsque l'on veut forcer une recréation // on regarde si les frontières points existent sinon on les crée if (ind_front_point == 1) {return (ElFrontiere*)tabb(posi_tab_front_point+num);} else if ( ind_front_point == 2) // cas où certaines frontières existent {if (tabb(posi_tab_front_point+num) != NULL) return (ElFrontiere*)tabb(posi_tab_front_point+num); }; // arrivée ici cela veut dire que la frontière point n'existe pas // on l'a reconstruit éventuellement // le calcul et la création ne sont effectués qu'au premier appel // ou lorsque l'on veut forcer une recréation if ((ind_front_point == 0) || force ) {// récup du tableau de ddl const DdlElement & tdd = TableauDdl(); int taille = tabb.Taille(); // la taille initiales des frontières int tail_fa = el.NbFe(); // nombre potentiel de faces int tail_ar = el.NbSe(); // nombre potentiel d'arêtes // dimensionnement du tableau de frontières ligne si nécessaire if (ind_front_point == 0) {if ((ind_front_lin > 0) && (ind_front_surf == 0)) // cas où les frontières lignes existent seules, on ajoute les points { int taille_finale = tail_ar + tail_po; tabb.Change_taille(taille_finale); for (int i=1;i<= tail_ar;i++) // transfert pour les lignes tabb(i) = tabb(i+tail_ar); posi_tab_front_point=tail_ar; posi_tab_front_lin = 0; // car on n'a pas de surface } else if ((ind_front_lin > 0) && (ind_front_surf > 0)) // cas où les frontières lignes existent et surfaces et pas de points, donc on les rajoutes { int taille_finale = tail_fa + tail_po+tail_ar; tabb.Change_taille(taille_finale);// les grandeurs pour les surfaces et les lignes sont // conservées, donc pas de transferts à prévoir posi_tab_front_point=tail_ar+tail_fa; // après les faces et les lignes posi_tab_front_lin = tail_fa; // après les surfaces } else { // cas où il n'y a pas de frontières lignes if (ind_front_surf == 0) // cas où il n'y a pas de surface {tabb.Change_taille(tail_po,NULL); // on n'a pas de ligne, pas de point et pas de surface posi_tab_front_point = posi_tab_front_lin = 0;} else {tabb.Change_taille(tail_po+tail_fa); // cas où les surfaces existent // le redimensionnement n'affecte pas les surfaces qui sont en début de tableau posi_tab_front_lin = posi_tab_front_point = tail_fa; // après les surfaces }; }; // et on met les pointeurs de points en NULL for (int i=1;i<= tail_po;i++) { tabb(i+posi_tab_front_point) = NULL;} }; // maintenant création de la frontière point Tableau tab(1); // les noeuds de la frontiere tab(1) = tab_noeud(num); DdlElement ddelem(1); // les ddlelements des points frontieres ddelem.Change_un_ddlNoeudElement(1,tdd(num)); tabb(posi_tab_front_point+num) = new FrontPointF(tab,ddelem); // on met à jour l'indicateur ind_front_point ind_front_point = 1; // a priori for (int npoint=1;npoint<=tail_po;npoint++) if (tabb(posi_tab_front_point+npoint) == NULL) { ind_front_point = 2; break;}; }; // maintenant normalement la frontière est créé on la ramène return (ElFrontiere*)tabb(posi_tab_front_point+num); }; // ramène la frontière linéique // éventuellement création des frontieres linéique de l'element et stockage dans l'element // si c'est la première fois et en 3D sinon il y a seulement retour de l'elements // a moins que le paramètre force est mis a true // dans ce dernier cas la frontière effacéee est recréée // num indique le numéro de l'arête à créer (numérotation EF) // nbneA: nombre de noeuds des segments frontières // el : l'élément ElFrontiere* const ElemThermi::Frontiere_lineique(int num,bool force) { // -- tout d'abord on évacue le cas où il n'y a pas de frontière linéique à calculer // récup de l'élément géométrique ElemGeomC0& el = ElementGeometrique(); int tail_ar = el.NbSe(); // nombre potentiel d'arêtes if (num > tail_ar) return NULL; // le calcul et la création ne sont effectués qu'au premier appel // ou lorsque l'on veut forcer une recréation // on regarde si les frontières linéiques existent sinon on les crée if (ind_front_lin == 1) {return (ElFrontiere*)tabb(posi_tab_front_lin+num);} else if ( ind_front_lin == 2) // cas où certaines frontières existent {if (tabb(posi_tab_front_lin+num) != NULL) return (ElFrontiere*)tabb(posi_tab_front_lin+num); }; // arrivée ici cela veut dire que la frontière ligne n'existe pas // on l'a reconstruit // le calcul et la création ne sont effectués qu'au premier appel // ou lorsque l'on veut forcer une recréation if ((ind_front_lin == 0) || force ) {// récup du tableau de ddl const DdlElement & tdd = TableauDdl(); int taille = tabb.Taille(); // la taille initiales des frontières int tail_fa = el.NbFe(); // nombre potentiel de faces int tail_po = el.Nbne(); // nombre potentiel de points // dimensionnement du tableau de frontières ligne si nécessaire if (ind_front_lin == 0) {if ((ind_front_point > 0) && (ind_front_surf == 0)) // cas où les frontières points existent seules, on ajoute les lignes { int taille_finale = tail_ar + tail_po; tabb.Change_taille(taille_finale); for (int i=1;i<= tail_po;i++) tabb(i+tail_ar) = tabb(i); posi_tab_front_point=tail_ar; posi_tab_front_lin = 0; // car on n'a pas de surface } else if ((ind_front_point > 0) && (ind_front_surf > 0)) // cas où les frontières points existent et surfaces et pas de ligne, donc on les rajoutes { int taille_finale = tail_fa + tail_po+tail_ar; tabb.Change_taille(taille_finale);// les grandeurs pour les surfaces sont conservées for (int i=1;i<= tail_po;i++) // transfert pour les noeuds { tabb(i+tail_ar+tail_fa) = tabb(i+tail_fa);}; posi_tab_front_point=tail_ar+tail_fa; // après les faces et les lignes posi_tab_front_lin = tail_fa; // après les surfaces } else { // cas où il n'y a pas de frontières points if (ind_front_surf == 0) // cas où il n'y a pas de surface {tabb.Change_taille(tail_ar,NULL); // on n'a pas de ligne, pas de point et pas de surface posi_tab_front_lin = posi_tab_front_point = 0;} else {tabb.Change_taille(tail_ar+tail_fa); // cas où les surfaces existent // le redimensionnement n'affecte pas les surfaces qui sont en début de tableau posi_tab_front_lin = posi_tab_front_point = tail_fa; // après les surfaces }; }; // et on met les pointeurs de lignes en NULL for (int i=1;i<= tail_ar;i++) // transfert pour les noeuds { tabb(i+posi_tab_front_lin) = NULL;} }; // maintenant création de la ligne int nbnoe = el.NonS()(num).Taille(); // nb noeud de l'arête Tableau tab(nbnoe); // les noeuds de l'arête frontiere DdlElement ddelem(nbnoe); // les ddlelements des noeuds frontieres for (int i=1;i<= nbnoe;i++) { tab(i) = tab_noeud(el.NonS()(num)(i)); ddelem.Change_un_ddlNoeudElement(i,tdd(el.NonS()(num)(i))); }; tabb(posi_tab_front_lin+num) = new_frontiere_lin(num,tab,ddelem); ind_front_lin = 1; // a priori for (int nlign=1;nlign<=tail_ar;nlign++) if (tabb(posi_tab_front_lin+nlign) == NULL) { ind_front_lin = 2; break;}; }; // maintenant normalement la frontière est créé on la ramène return (ElFrontiere*)tabb(posi_tab_front_lin+num); }; // ramène la frontière surfacique // éventuellement création des frontieres surfacique de l'element et stockage dans l'element // si c'est la première fois sinon il y a seulement retour de l'elements // a moins que le paramètre force est mis a true // dans ce dernier cas la frontière effacéee est recréée // num indique le numéro de la surface à créer (numérotation EF) ElFrontiere* const ElemThermi::Frontiere_surfacique(int num,bool force) { // -- tout d'abord on évacue le cas où il n'y a pas de frontière surfacique à calculer // récup de l'élément géométrique ElemGeomC0& el = ElementGeometrique(); int tail_fa = el.NbFe(); // nombre potentiel de faces if (num > tail_fa) return NULL; // le calcul et la création ne sont effectués qu'au premier appel // ou lorsque l'on veut forcer une recréation // on regarde si les frontières surfacique existent sinon on les crée if (ind_front_surf == 1) {return (ElFrontiere*)tabb(num);} else if ( ind_front_surf == 2) // cas où certaines frontières existent {if (tabb(num) != NULL) return (ElFrontiere*)tabb(num); }; // arrivée ici cela veut dire que la frontière surface n'existe pas // on l'a reconstruit // le calcul et la création ne sont effectués qu'au premier appel // ou lorsque l'on veut forcer une recréation if ((ind_front_surf == 0) || force ) {// récup du tableau de ddl const DdlElement & tdd = TableauDdl(); int taille = tabb.Taille(); // la taille initiales des frontières int tail_ar = el.NbSe(); // nombre potentiel d'arêtes int tail_po = el.Nbne(); // nombre potentiel de points // dimensionnement du tableau de frontières surfaces si nécessaire if (ind_front_surf == 0) {if ((ind_front_point > 0) && (ind_front_lin == 0)) // cas où les frontières points existent seules, on ajoute les surfaces { int taille_finale = tail_fa + tail_po; tabb.Change_taille(taille_finale); for (int i=1;i<= tail_po;i++) tabb(i+tail_fa) = tabb(i); posi_tab_front_lin=posi_tab_front_point=tail_fa; } else if ((ind_front_point > 0) && (ind_front_lin > 0)) // cas où les frontières points existent et lignes et pas de surfaces, donc on les rajoutes { int taille_finale = tail_fa + tail_po+tail_ar; tabb.Change_taille(taille_finale); // --transfert pour les noeuds et les lignes for (int i=1;i<= tail_po;i++) // transfert pour les noeuds { tabb(i+tail_ar+tail_fa) = tabb(i+tail_ar);}; for (int i=1;i<= tail_ar;i++) // transfert pour les lignes { tabb(i+tail_fa) = tabb(i);}; // --def des indicateurs posi_tab_front_point=tail_ar+tail_fa; // après les faces et les lignes posi_tab_front_lin = tail_fa; // après les surfaces } else { // cas où il n'y a pas de frontières points if (ind_front_lin == 0) // cas où il n'y a pas de lignes {tabb.Change_taille(tail_fa,NULL); // on n'a pas de ligne, pas de point et pas de surface posi_tab_front_lin = posi_tab_front_point = tail_fa; } // on peut tout mettre à NULL else {tabb.Change_taille(tail_ar+tail_fa); // cas où les lignes existent for (int i=1;i<= tail_ar;i++) // transfert pour les lignes tabb(i+tail_fa) = tabb(i); posi_tab_front_lin = posi_tab_front_point = tail_fa; // après les surfaces }; }; // --et on met les pointeurs de surfaces en NULL for (int i=1;i<=tail_fa;i++) tabb(i)=NULL; }; // maintenant création de la surface int nbnoe = el.Nonf()(num).Taille(); // b noeud de la surface Tableau tab(nbnoe); // les noeuds de la frontiere DdlElement ddelem(nbnoe); // les ddlelements des noeuds frontieres for (int i=1;i<= nbnoe;i++) { tab(i) = tab_noeud(el.Nonf()(num)(i)); ddelem.Change_un_ddlNoeudElement(i,tdd(el.Nonf()(num)(i))); }; tabb(num) = new_frontiere_surf(num,tab,ddelem); ind_front_surf = 1; // a priori for (int nsurf=1;nsurf<=tail_fa;nsurf++) if (tabb(nsurf) == NULL) { ind_front_surf = 2; break;}; }; // maintenant normalement la frontière est créé on la ramène return (ElFrontiere*)tabb(num); }; // calcul éventuel de la normale à un noeud // ce calcul existe pour les éléments 2D, 1D axi, et aussi pour les éléments 1D // qui possède un repère d'orientation // en retour coor = la normale si coor.Dimension() est = à la dimension de l'espace // si le calcul n'existe pas --> coor.Dimension() = 0 // ramène un entier : // == 1 : calcul normal // == 0 : problème de calcul -> coor.Dimension() = 0 // == 2 : indique que le calcul n'est pas licite pour le noeud passé en paramètre // c'est le cas par exemple des noeuds exterieurs pour les éléments SFE // mais il n'y a pas d'erreur, c'est seulement que l'élément n'est pas ad hoc pour // calculer la normale à ce noeud là // temps: indique à quel moment on veut le calcul // pour des éléments particulier (ex: SFE) la méthode est surchargée int ElemThermi::CalculNormale_noeud(Enum_dure temps,const Noeud& noe,Coordonnee& coor) { int retour = 1; // init du retour : on part d'un bon a priori Enum_type_geom enutygeom = Type_geom_generique(this->Id_geometrie()); // if ((enutygeom == LIGNE) || (enutygeom == SURFACE)) if (enutygeom != SURFACE) // dans une première étape on ne s'occupe que des surfaces {coor.Libere(); // pas de calcul possible retour = 0; } else // sinon le calcul est possible { // on commence par repérer le noeud dans la numérotation locale int nuoe=0; int borne_nb_noeud=tab_noeud.Taille()+1; for (int i=1;i< borne_nb_noeud;i++) {Noeud& noeloc = *tab_noeud(i); if ( (noe.Num_noeud() == noeloc.Num_noeud()) && (noe.Num_Mail() == noeloc.Num_Mail()) ) {nuoe = i; break; }; }; // on ne continue que si on a trouvé le noeud if (nuoe != 0) { ElemGeomC0& elemgeom = ElementGeometrique(); // récup de la géométrie // récup des coordonnées locales du noeuds const Coordonnee& theta_noeud = elemgeom.PtelemRef()(nuoe); // récup des phi et dphi au noeud const Vecteur & phi = elemgeom.Phi_point(theta_noeud); const Mat_pleine& dphi = elemgeom.Dphi_point(theta_noeud); switch (temps) {case TEMPS_0 : {const BaseB& baseB = met->BaseNat_0(tab_noeud,dphi,phi); coor = Util::ProdVec_coor( baseB.Coordo(1), baseB.Coordo(2)); coor.Normer(); break; } case TEMPS_t : {const BaseB& baseB = met->BaseNat_t(tab_noeud,dphi,phi); coor = Util::ProdVec_coor( baseB.Coordo(1), baseB.Coordo(2)); coor.Normer(); break; } case TEMPS_tdt : {const BaseB& baseB = met->BaseNat_tdt(tab_noeud,dphi,phi); coor = Util::ProdVec_coor( baseB.Coordo(1), baseB.Coordo(2)); coor.Normer(); break; } default : cout << "\nErreur : valeur incorrecte du temps demande = " << Nom_dure(temps) << " !\n"; cout << "\n ElemThermi::CalculNormale_noeud(Enum_dure temps... \n"; retour = 0; Sortie(1); }; } else {cout << "\n *** erreur le noeud demande num= "<