// FICHIER : HexaQComp.cc // CLASSE : HexaQComp // 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 using namespace std; //introduces namespace std #include #include "Sortie.h" #include "GeomHexaQuadComp.h" #include "HexaQComp.h" //---------------------------------------------------------------- // def des donnees commune a tous les elements // la taille n'est pas defini ici car elle depend de la lecture //---------------------------------------------------------------- HexaMemb::DonnComHexa * HexaQComp::doCoHexa = NULL; HexaMemb::UneFois HexaQComp::uneFois; HexaQComp::NombresConstruireHexaQComp HexaQComp::nombre_V; HexaQComp::ConsHexaQComp HexaQComp::consHexaQComp; // constructeur définissant les nombres (de noeud, de point d'integ ..) // utilisé dans la construction des éléments HexaQComp::NombresConstruireHexaQComp::NombresConstruireHexaQComp() { nbne = 27; // le nombre de noeud de l'élément nbneS = 9; // le nombre de noeud des facettes nbneA = 3; // le nombre de noeud des aretes nbi = 8; // le nombre de point d'intégration pour le calcul mécanique // nbi = 27; // le nombre de point d'intégration pour le calcul mécanique nbiEr = 27; // le nombre de point d'intégration pour le calcul d'erreur nbiV = 8; // le nombre de point d'intégration pour le calcul de second membre volumique nbiS = 4; // le nombre de point d'intégration pour le calcul de second membre surfacique nbiA = 2; // le nombre de point d'intégration pour le calcul de second membre linéique nbiMas = 27; // le nombre de point d'intégration pour le calcul de la matrice masse nbiHour = 27; // éventuellement, le nombre de point d'intégration un blocage d'hourglass }; // =========================== constructeurs ================== // Constructeur par defaut, le seul accepte en dimension different de 3 HexaQComp::HexaQComp () : HexaMemb(0,-3,QUADRACOMPL,HEXAEDRE) { nombre = & nombre_V; tab_noeud.Change_taille(nombre->nbne); // 27 noeuds,8 pt d'integration // calcul de doCoHexaQComp egalement si c'est le premier passage // après hexa, le nombre de point d'intégration de surface pour le second membre // ici 4 et 9 noeuds pour les éléments de surface ElemGeomC0* hexa=NULL;ElemGeomC0* hexaEr=NULL; ElemGeomC0* hexaMas=NULL; ElemGeomC0* hexaeHourg; // pour le blocage d'hourglass if ( doCoHexa == NULL) {hexa = new GeomHexaQuadComp(nombre->nbi); // pour le calcul d'erreur il faut plus de pt d'intégration pour éviter la singularité // de la matrice de raideur -> 27 hexaEr = new GeomHexaQuadComp(nombre->nbiEr); // idem pour les calculs de matrices masses consitstantes hexaMas = new GeomHexaQuadComp(nombre->nbiMas); hexaeHourg = new GeomHexaQuadComp(nombre->nbiHour); } int dim = ParaGlob::Dimension(); if (dim != 3) // cas d'une dimension autre que trois { if (ParaGlob::NiveauImpression() >= 7) cout << "\nATTENTION -> dimension " << dim <<", pas de definition d\'elements hexaedriques quadratiques complet"<< endl; delete hexa;delete hexaEr;delete hexaMas; unefois = NULL; } else { unefois = & uneFois; // affectation du pointeur de la classe générique triangle doCoHexa = HexaMemb::Init (hexa,hexaEr,hexaMas,hexaeHourg); unefois->nbelem_in_Prog++; } }; // Constructeur fonction d'un numero // d'identification HexaQComp::HexaQComp (int num_mail,int num_id) : HexaMemb(num_mail,num_id,QUADRACOMPL,HEXAEDRE) { nombre = & nombre_V; tab_noeud.Change_taille(nombre->nbne); // 27 noeuds,8 pt d'integration // calcul de doCoHexa egalement si c'est le premier passage // après hexa, le nombre de point d'intégration de surface pour le second membre // ici 4 et 9 noeuds pour les éléments de surface ElemGeomC0* hexa=NULL;ElemGeomC0* hexaEr=NULL; ElemGeomC0* hexaMas=NULL; ElemGeomC0* hexaeHourg; // pour le blocage d'hourglass if ( doCoHexa == NULL) {hexa = new GeomHexaQuadComp(nombre->nbi); // pour le calcul d'erreur il faut plus de pt d'intégration pour éviter la singularité // de la matrice de raideur -> 27 hexaEr = new GeomHexaQuadComp(nombre->nbiEr); }; // idem pour les calculs de matrices masses consitstantes hexaMas = new GeomHexaQuadComp(nombre->nbiMas); hexaeHourg = new GeomHexaQuadComp(nombre->nbiHour); // #ifdef MISE_AU_POINT if (ParaGlob::Dimension() != 3) // cas d'une dimension autre que trois { if (ParaGlob::NiveauImpression() >= 2) cout << "\n erreur de dimension dans HexaQComp, dim = " << ParaGlob::Dimension() << "\n alors que l'on doit avoir 3 !! " << endl; Sortie (1); } // #endif else {unefois = & uneFois; // affectation du pointeur de la classe générique doCoHexa = HexaMemb::Init (hexa,hexaEr,hexaMas,hexaeHourg); unefois->nbelem_in_Prog++; }; }; // Constructeur utile si le numero de l'element et // le tableau des noeuds sont connus HexaQComp::HexaQComp (int num_mail,int num_id,const Tableau& tab): HexaMemb(num_mail,num_id,QUADRACOMPL,HEXAEDRE,tab) { nombre = & nombre_V; if (tab_noeud.Taille() != nombre->nbne) { cout << "\n erreur de dimensionnement du tableau de noeud \n"; cout << " HexaQComp::HexaQComp (int num_mail,int num_id,const Tableau& tab)\n"; Sortie (1); }; // 27 noeuds,8 pt d'integration // calcul de doCoHexa egalement si c'est le premier passage // après hexa, le nombre de point d'intégration de surface pour le second membre // ici 4 et 9 noeuds pour les éléments de surface ElemGeomC0* hexa=NULL;ElemGeomC0* hexaEr=NULL; ElemGeomC0* hexaMas=NULL; ElemGeomC0* hexaeHourg; // pour le blocage d'hourglass if ( doCoHexa == NULL) {hexa = new GeomHexaQuadComp(nombre->nbi); // pour le calcul d'erreur il faut plus de pt d'intégration pour éviter la singularité // de la matrice de raideur -> nombre->nbiEr hexaEr = new GeomHexaQuadComp(nombre->nbiEr);} // idem pour les calculs de matrices masses consitstantes hexaMas = new GeomHexaQuadComp(nombre->nbiMas); hexaeHourg = new GeomHexaQuadComp(nombre->nbiHour); // #ifdef MISE_AU_POINT if (ParaGlob::Dimension() != 3) // cas d'une dimension autre que trois { if (ParaGlob::NiveauImpression() >= 2) cout << "\n erreur de dimension dans HexaQComp, dim = " << ParaGlob::Dimension() << "\n alors que l'on doit avoir 3 !! " << endl; Sortie (1); } // #endif else { unefois = & uneFois; // affectation du pointeur de la classe générique triangle bool sans_init_noeud = true; doCoHexa = HexaMemb::Init (hexa,hexaEr,hexaMas,hexaeHourg,sans_init_noeud); // construction du tableau de ddl spécifique à l'élément pour ses ConstTabDdl(); unefois->nbelem_in_Prog++; }; }; HexaQComp::HexaQComp (const HexaQComp& HexaQraM) : HexaMemb (HexaQraM) // Constructeur de copie { unefois = & uneFois; // affectation du pointeur de la classe générique // ce qui est relatif à l'initialisation est déjà effectué dans elem_meca et HexaMemb unefois->nbelem_in_Prog++; }; HexaQComp::~HexaQComp () // Destruction effectuee dans HexaMemb { if (unefois != NULL) {unefois->nbelem_in_Prog--; Destruction(); } }; // renseignement d'un élément complet à partir d'un élément incomplet de même type // retourne les nouveaux noeuds construit à partir de l'interpolation incomplète. // dans le cas l'élément n'est pas concerné, retourne une liste vide // ramène également une liste de même dimension contenant les bornes en numéros de noeuds // entre lesquelles il faut définir les nouveaux numéros de noeuds si l'on veut conserver // une largeur de bande optimisée du même type // nbnt+1: est le premier numéro de noeud utilisable pour les nouveaux noeuds list HexaQComp::Construct_from_imcomplet(const Element & elem,list & li_bornes,int nbnt) { list li_ret; // la liste de retour // ----- construction de l'élément, // 1) définition des noeuds venant de l'élément incomplet const Tableau& e_tab_noeud = elem.Tab_noeud_const(); int nbne = nombre-> nbne; int etaille=e_tab_noeud.Taille(); tab_noeud.Change_taille(nbne); // les premiers noeuds sont ceux de l'incomplet for (int i=1;i<=etaille;i++) tab_noeud(i)=e_tab_noeud(i); // 2) définition des noeuds centraux des différentes faces // en fait il s'agit des noeuds de 21 à 27 const int num_inf=21; const int num_sup=27; int idmail = tab_noeud(1)->Num_Mail(); // récup du numéro de maillage associé au noeud int dim = ParaGlob::Dimension(); HexaMemb::DonnComHexa* doCoHexa = unefois->doCoMemb; // pour simplifier l'écriture // récupération des coordonnées des noeuds locaux Tableau const & ptlocal = doCoHexa->hexaed->PtelemRef(); // on boucle sur les noeuds supplémentaires : de 21 à 27 int ib=1; // indice sup pour l'attribution d'un bon numéro for (int ine=num_inf;ine<=num_sup;ine++,ib++) { // déf d'un noeud initialisée aux coordonnées du premier noeud pour l'instant Noeud * ptr = new Noeud(*tab_noeud(1)); ptr->Change_num_noeud(nbnt+ib); // attribution d'un bon numéro tab_noeud(ine)=ptr; // enregistrement dans les noeuds de l'élément } // ajout du tableau de ddl des noeuds, ce qui permet d'activer les ddl XI à t si ce n'est // pas encore fait ConstTabDdl(); // definition des coordonnées des nouveaux noeuds Coordonnee co(dim); // les coordonnées physique Tableau t_co; // les coordonnées physique // test pour savoir si le calcul à tdt est activé ou pas if (tab_noeud(1)->Tdt()) // cas où l'on travailles à 0 t et tdt { for (int ine1=num_inf;ine1<=num_sup;ine1++) { t_co.Change_taille(3); ((HexaMemb&)elem).Point_physique(ptlocal(ine1),t_co); tab_noeud(ine1)->Change_coord0(t_co(1));tab_noeud(ine1)->Change_coord1(t_co(2)); tab_noeud(ine1)->Change_coord2(t_co(3)); } } else // on regarde si on a les coordonnées à t qui sont définis {if (tab_noeud(1)->En_service(X1)) // cas où les coordonnees à t sont définis {for (int ine2=num_inf;ine2<=num_sup;ine2++) {t_co.Change_taille(2); ((HexaMemb&)elem).Point_physique(ptlocal(ine2),t_co); tab_noeud(ine2)->Change_coord0(t_co(1));tab_noeud(ine2)->Change_coord1(t_co(2)); } } else // cas où seules les coordonnées à 0 sont définis // en fait ici n'arrive jamais !! mais mis pour pas oublier {for (int ine3=num_inf;ine3<=num_sup;ine3++) { ((HexaMemb&)elem).Point_physique(ptlocal(ine3),co,TEMPS_0); tab_noeud(ine3)->Change_coord0(t_co(1)); } } } // 3) enregistrement des noeuds for (int ine4=num_inf;ine4<=num_sup;ine4++) li_ret.push_back(tab_noeud(ine4)); // 4) remplissage de li_bornes // recup de la connection des noeuds des faces par rapport a ceux de l'element Tableau > const & nonf = doCoHexa->hexaed->Nonf(); // initialisation de li_bornes li_bornes.erase(li_bornes.begin(),li_bornes.end()); // On travaille d'abord sur les faces de l'élément // par rapport au quadratique incomplet, 21 est au centre de la face 1, // 22 sur la face 3, 23 sur la face 5, 24 sur la face 6 // 25 sur la face 2, 26 sur la face 4, 27 au centre de l'élément // on définit un adressage indirecte des faces de manière à faire ensuite une boucle sur les faces Tableau t_i(6); t_i(1)=1; t_i(2)=3;t_i(3)=5; t_i(4)=6; t_i(5)=2; t_i(6)=4; // on définit un inf et sup de numéro pour le noeud central, qui sera traité en même temps que les faces int inf_nc=e_tab_noeud(1)->Num_noeud();int sup_nc=inf_nc; for (int ine5=num_inf,ib=1;ine5& nofa = nonf(t_i(ib)); int nbnoeudface=nofa.Taille() ; // en fait ici 9 int inf=tab_noeud(nofa(1))->Num_noeud(); int sup = inf; for (int i=2;iNum_noeud(); if (inf > num) inf = num; if (sup < num) sup = num; if (inf_nc > num) inf_nc = num; if (sup_nc < num) sup_nc = num; // pour le noeud central à la fin } li_bornes.push_back(DeuxEntiers(inf,sup)); } // on s'occupe maintenant du noeud central li_bornes.push_back(DeuxEntiers(inf_nc,sup_nc)); // 5) retour return li_ret; }; // affichage dans la sortie transmise, des variables duales "nom" // aux differents points d'integration // dans le cas ou nom est vide, affichage de "toute" les variables void HexaQComp::AfficheVarDual(ofstream& sort, Tableau& nom) { // affichage de l'entête de l'element sort << "\n******************************************************************"; sort << "\n Element HexaQComp (hexaedre triquadratique complet "<nbi<<" pts d'integration) "; sort << "\n******************************************************************"; // appel de la procedure de elem meca if (!(uneFois.dualSortHexa) && (uneFois.CalimpPrem)) { VarDualSort(sort,nom,nombre->nbi,1); uneFois.dualSortHexa += 1; } else if ((uneFois.dualSortHexa) && (uneFois.CalimpPrem)) VarDualSort(sort,nom,nombre->nbi,11); else if (!(uneFois.dualSortHexa) && (uneFois.CalResPrem_tdt)) { VarDualSort(sort,nom,nombre->nbi,2); uneFois.dualSortHexa += 1; } else if ((uneFois.dualSortHexa) && (uneFois.CalResPrem_tdt)) VarDualSort(sort,nom,nombre->nbi,12); // sinon on ne fait rien };