// FICHIER : HexaQ.cp // CLASSE : HexaQ // 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 "GeomHexaQuad.h" #include "HexaQ.h" //---------------------------------------------------------------- // def des donnees commune a tous les elements // la taille n'est pas defini ici car elle depend de la lecture //---------------------------------------------------------------- HexaMemb::DonnComHexa * HexaQ::doCoHexa = NULL; HexaMemb::UneFois HexaQ::uneFois; HexaQ::NombresConstruireHexaQ HexaQ::nombre_V; HexaQ::ConsHexaQ HexaQ::consHexaQ; // constructeur définissant les nombres (de noeud, de point d'integ ..) HexaQ::NombresConstruireHexaQ::NombresConstruireHexaQ() { nbne = 20; // le nombre de noeud de l'élément nbneS = 8; // 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 HexaQ::HexaQ () : HexaMemb(0,-3,QUADRATIQUE,HEXAEDRE) { nombre = & nombre_V; tab_noeud.Change_taille(nombre->nbne); // 20 noeuds,8 pt d'integration // calcul de doCoHexaQ 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 8 noeuds pour les éléments de surface ElemGeomC0* hexa=NULL;ElemGeomC0* hexaEr=NULL; ElemGeomC0* hexaMas=NULL; if ( doCoHexa == NULL) {hexa = new GeomHexaQuad(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 GeomHexaQuad(nombre->nbiEr); // idem pour les calculs de matrices masses consitstantes hexaMas = new GeomHexaQuad(nombre->nbiMas); } 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 "<< 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,NULL); unefois->nbelem_in_Prog++; } }; // Constructeur fonction d'un numero // d'identification HexaQ::HexaQ (int num_mail,int num_id) : HexaMemb(num_mail,num_id,QUADRATIQUE,HEXAEDRE) { nombre = & nombre_V; tab_noeud.Change_taille(nombre->nbne); // 20 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 4 noeuds pour les éléments de surface ElemGeomC0* hexa=NULL;ElemGeomC0* hexaEr=NULL; ElemGeomC0* hexaMas=NULL; if ( doCoHexa == NULL) {hexa = new GeomHexaQuad(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 GeomHexaQuad(nombre->nbiEr);} // idem pour les calculs de matrices masses consitstantes hexaMas = new GeomHexaQuad(nombre->nbiMas); #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 HexaQ, dim = " << ParaGlob::Dimension() << "\n alors que l'on doit avoir 3 !! " << endl; Sortie (1); } #endif { unefois = & uneFois; // affectation du pointeur de la classe générique triangle doCoHexa = HexaMemb::Init (hexa,hexaEr,hexaMas,NULL); unefois->nbelem_in_Prog++; } }; // Constructeur utile si le numero de l'element et // le tableau des noeuds sont connus HexaQ::HexaQ (int num_mail,int num_id,const Tableau& tab): HexaMemb(num_mail,num_id,QUADRATIQUE,HEXAEDRE,tab) { nombre = & nombre_V; if (tab_noeud.Taille() != nombre->nbne) { cout << "\n erreur de dimensionnement du tableau de noeud \n"; cout << " HexaQ::HexaQ (int num_mail,int num_id,const Tableau& tab)\n"; Sortie (1); } // 20 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 4 noeuds pour les éléments de surface ElemGeomC0* hexa=NULL;ElemGeomC0* hexaEr=NULL; ElemGeomC0* hexaMas=NULL; if ( doCoHexa == NULL) {hexa = new GeomHexaQuad(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 GeomHexaQuad(nombre->nbiEr);} // idem pour les calculs de matrices masses consitstantes hexaMas = new GeomHexaQuad(nombre->nbiMas); #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 HexaQ, dim = " << ParaGlob::Dimension() << "\n alors que l'on doit avoir 3 !! " << endl; Sortie (1); } #endif { unefois = & uneFois; // affectation du pointeur de la classe générique triangle bool sans_init_noeud = true; doCoHexa = HexaMemb::Init (hexa,hexaEr,hexaMas,NULL,sans_init_noeud); // construction du tableau de ddl spécifique à l'élément pour ses ConstTabDdl(); unefois->nbelem_in_Prog++; } }; HexaQ::HexaQ (const HexaQ& HexaQraM) : HexaMemb (HexaQraM) // Constructeur de copie { ElemGeomC0* hexa=NULL;ElemGeomC0* hexaEr=NULL; ElemGeomC0* hexaMas=NULL; 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++; }; HexaQ::~HexaQ () // Destruction effectuee dans HexaMemb { if (unefois != NULL) {unefois->nbelem_in_Prog--; Destruction(); } }; // renseignement d'un élément quadratique incomplet à partir d'un élément linéaire de même type // retourne les nouveaux noeuds construit à partir de l'interpolation linéaire. // dans le cas où 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 HexaQ::Construct_from_lineaire(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 linéaire 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'élément linéaire for (int i=1;i<=etaille;i++) tab_noeud(i)=e_tab_noeud(i); // 2) définition des noeuds milieux des différentes arrêtes // en fait il s'agit des noeuds de 9 à 20 const int num_inf=9; const int num_sup=20; 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 9 à 20 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 arrêtes par rapport a ceux de l'element Tableau > const & nons = doCoHexa->hexaed->NonS(); // initialisation de li_bornes li_bornes.erase(li_bornes.begin(),li_bornes.end()); // on boucle sur les arrêtes // par rapport au linéaire, 9 est au centre de l'arrête 1, // 10 sur l'arrête 2, etc.. donc ici on peut faire un adressage directe, néanmoins // dans le cas où les arrêtes n'ont pas le même ordre que les noeuds supplémentaires // il faut faire un adressage indirecte: voir l'exemple de HexaQcom pour la fonction // Construct_from_imcomplet int inf_nc=e_tab_noeud(1)->Num_noeud();int sup_nc=inf_nc; // init for (int ine5=num_inf,ib=1;ine5<=num_sup;ine5++,ib++) { // on cherche le maxi et le mini des numéros des noeuds de l'arrête a doc // tout d'abord initialisation const Tableau& nosa = nons(ib); int nbnoeudarrete=nosa.Taille() ; // en fait ici 2 // on regarde le premier noeud de l'arrête int inf=tab_noeud(nosa(1))->Num_noeud(); int sup = inf; // puis le dernier int num= tab_noeud(nosa(nbnoeudarrete))->Num_noeud(); if (inf > num) inf = num; if (sup < num) sup = num; li_bornes.push_back(DeuxEntiers(inf,sup)); }; // 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 HexaQ::AfficheVarDual(ofstream& sort, Tableau& nom) { // affichage de l'entête de l'element sort << "\n******************************************************************"; sort << "\n Element HexaQ (hexaedre triquadratique "<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 };