// FICHIER : PentaQComp.cp // CLASSE : PentaQComp // 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 "FrontSegQuad.h" #include "FrontQuadQuad.h" #include "FrontTriaQuad.h" #include "GeomPentaQComp.h" #include "PentaQComp.h" //---------------------------------------------------------------- // def des donnees commune a tous les elements // la taille n'est pas defini ici car elle depend de la lecture //---------------------------------------------------------------- //---------------------------------------------------------------- PentaMemb::DonnComPenta * PentaQComp::doCoPentaQComp = NULL; PentaMemb::UneFois PentaQComp::uneFois; PentaQComp::NombresConstruirePentaQComp PentaQComp::nombre_V; PentaQComp::ConsPentaQComp PentaQComp::consPentaQComp; // constructeur définissant les nombres (de noeud, de point d'integ ..) // utilisé dans la construction des éléments PentaQComp::NombresConstruirePentaQComp::NombresConstruirePentaQComp() { nbne = 18; // le nombre de noeud de l'élément nbneSQ = 9; // le nombre de noeud des facettes quadrangulaires nbneST = 6; // le nombre de noeud des facettes triangulaires nbneAQ = 3; // le nombre de noeud des aretes entres les faces triangulaires nbneAT = 3; // le nombre de noeud des aretes des facettes triangulaires nbI = 6; // nombre point d'intég pour le calcul méca pour l'élément nbiQ = 3; // nombre point d'intég pour le calcul méca pour les triangles nbiT = 4; // nombre point d'intég pour le calcul méca pour les quadrangles nbiEr =18; // le nombre de point d'intégration pour le calcul d'erreur nbiV = 6; // le nombre de point d'intégration pour le calcul de second membre volumique nbiSQ = 4; // nombre point d'intég pour le calcul de second membre surfacique quadrangulaire nbiST = 3; // nombre point d'intég pour le calcul de second membre surfacique triangulaire nbiAQ = 2; // nB pt integ pour calcul second membre linéique des arête entre faces triangles nbiAT = 2; // nB pt integ pour calcul second membre linéique des arête des triangles nbiMas = 18; // le nombre de point d'intégration pour le calcul de la matrice masse nbiHour = 9; // éventuellement, le nombre de point d'intégration un blocage d'hourglass }; // =========================== constructeurs ================== // Constructeur par defaut, le seul accepte en dimension different de 3 PentaQComp::PentaQComp () : PentaMemb(0,-3,QUADRACOMPL,PENTAEDRE) {// on intervient seulement à partir du deuxième élément, if (uneFois.nbelem_in_Prog == 0) { uneFois.nbelem_in_Prog++; // au premier passage on se contente d'incrémenter } else // sinon on construit {nombre = & nombre_V; tab_noeud.Change_taille(nombre->nbne); // calcul de doCoPentaQComp si c'est le premier passage ElemGeomC0* penta=NULL;ElemGeomC0* pentaEr=NULL; ElemGeomC0* pentaMas=NULL; ElemGeomC0* pentaeHourg=NULL; // pour le blocage d'hourglass if ( doCoPentaQComp == NULL) {penta = new GeomPentaQComp(nombre->nbI); // pour le calcul d'erreur il faut au moins autant de points d'intégration que de noeuds pentaEr = new GeomPentaQComp(nombre->nbiEr); // idem pour le calcul de la matrice masse consistante pentaMas = new GeomPentaQComp(nombre->nbiMas); pentaeHourg = new GeomPentaQComp(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 pentaedriques lineaires "<< endl; delete penta;delete pentaEr;delete pentaMas;delete pentaeHourg; unefois = NULL; } else // après penta on défini les données relatives aux surfaces externes (frontières) { unefois = & uneFois; // affectation du pointeur de la classe générique triangle doCoPentaQComp = PentaMemb::Init (penta,pentaEr,pentaMas,pentaeHourg); unefois->nbelem_in_Prog++; } }; }; // Constructeur fonction d'un numero // d'identification PentaQComp::PentaQComp (int num_mail,int num_id) : PentaMemb(num_mail,num_id,QUADRACOMPL,PENTAEDRE) {// on intervient seulement à partir du deuxième élément, if (uneFois.nbelem_in_Prog == 0) { uneFois.nbelem_in_Prog++; // au premier passage on se contente d'incrémenter } else // sinon on construit {nombre = & nombre_V; tab_noeud.Change_taille(nombre->nbne); // calcul de doCoPentaQComp si c'est le premier passage ElemGeomC0* penta=NULL;ElemGeomC0* pentaEr=NULL; ElemGeomC0* pentaMas=NULL; ElemGeomC0* pentaeHourg=NULL; // pour le blocage d'hourglass if ( doCoPentaQComp == NULL) {penta = new GeomPentaQComp(nombre->nbI); // pour le calcul d'erreur il faut au moins autant de points d'intégration que de noeuds pentaEr = new GeomPentaQComp(nombre->nbiEr); // idem pour le calcul de la matrice masse consistante pentaMas = new GeomPentaQComp(nombre->nbiMas); pentaeHourg = new GeomPentaQComp(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 PentaQComp, dim = " << ParaGlob::Dimension() << "\n alors que l'on doit avoir 3 !! " << endl; Sortie (1); } #endif // après penta on défini les données relatives aux surfaces externes (frontières) { unefois = & uneFois; // affectation du pointeur de la classe générique triangle doCoPentaQComp = PentaMemb::Init (penta,pentaEr,pentaMas,pentaeHourg); unefois->nbelem_in_Prog++; } }; }; // Constructeur utile si le numero de l'element et // le tableau des noeuds sont connus PentaQComp::PentaQComp (int num_mail,int num_id,const Tableau& tab): PentaMemb(num_mail,num_id,QUADRACOMPL,PENTAEDRE,tab) {// on intervient seulement à partir du deuxième élément, if (uneFois.nbelem_in_Prog == 0) { uneFois.nbelem_in_Prog++; // au premier passage on se contente d'incrémenter } else // sinon on construit {nombre = & nombre_V; if (tab_noeud.Taille() != nombre->nbne) { cout << "\n erreur de dimensionnement du tableau de noeud \n"; cout << " PentaQComp::PentaQComp (double epaiss,int num_mail,int num_id,const Tableau& tab)\n"; Sortie (1); } // calcul de doCoPentaQComp si c'est le premier passage ElemGeomC0* penta=NULL;ElemGeomC0* pentaEr=NULL; ElemGeomC0* pentaMas=NULL; ElemGeomC0* pentaeHourg=NULL; // pour le blocage d'hourglass if ( doCoPentaQComp == NULL) {penta = new GeomPentaQComp(nombre->nbI); // pour le calcul d'erreur il faut au moins autant de points d'intégration que de noeuds pentaEr = new GeomPentaQComp(nombre->nbiEr); // idem pour le calcul de la matrice masse consistante pentaMas = new GeomPentaQComp(nombre->nbiMas); pentaeHourg = new GeomPentaQComp(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 PentaQComp, dim = " << ParaGlob::Dimension() << "\n alors que l'on doit avoir 3 !! " << endl; Sortie (1); } #endif // après penta on défini les données relatives aux surfaces externes (frontières) { unefois = & uneFois; // affectation du pointeur de la classe générique triangle bool sans_init_noeud = true; doCoPentaQComp = PentaMemb::Init (penta,pentaEr,pentaMas,pentaeHourg,sans_init_noeud); // construction du tableau de ddl spécifique à l'élément pour ses ConstTabDdl(); unefois->nbelem_in_Prog++; } }; }; PentaQComp::PentaQComp (const PentaQComp& PentaQraM) : PentaMemb (PentaQraM) // Constructeur de copie // a priori si on utilise le constructeur de copie, donc il y a déjà un élément // par contre a priori on ne doit pas faire une copie du premier élément { if (uneFois.nbelem_in_Prog == 1) { cout << "\n **** erreur pour l'element PentaQComp, le constructeur de copie ne doit pas etre utilise" << " pour le premier element !! " << endl; Sortie (1); } else { 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 PentaMemb unefois->nbelem_in_Prog++; }; }; PentaQComp::~PentaQComp () // Destruction effectuee dans PentaMemb { 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 PentaQComp::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 16 à 18 const int num_inf=16; const int num_sup=18; int idmail = tab_noeud(1)->Num_Mail(); // récup du numéro de maillage associé au noeud int dim = ParaGlob::Dimension(); PentaMemb::DonnComPenta* doCoPenta = unefois->doCoMemb; // pour simplifier l'écriture // récupération des coordonnées des noeuds locaux Tableau const & ptlocal = doCoPenta->pentaed->PtelemRef(); // on boucle sur les noeuds supplémentaires : de 16 à 18 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); ((PentaMemb&)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); ((PentaMemb&)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++) { ((PentaMemb&)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 = doCoPenta->pentaed->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, le noeud 16 est sur la face 3, 17 sur la face 5 // et 18 sur la face 2 // 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(3); t_i(1)=3; t_i(2)=5;t_i(3)=2; // // 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<=num_sup;ine5++,ib++) { // on cherche le maxi et le mini des numéros des noeuds de la face adoc // tout d'abord initialisation const Tableau& 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; } 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 PentaQComp::AfficheVarDual(ofstream& sort, Tableau& nom) { // affichage de l'entête de l'element sort << "\n********************************************************************************"; sort << "\n Element PentaQComp (pentaedre trilquadratique complet " << nombre->nbI << " pt d'integration) "; sort << "\n********************************************************************************"; // appel de la procedure de elem meca if (!(uneFois.dualSortPenta) && (uneFois.CalimpPrem)) { VarDualSort(sort,nom,nombre->nbI,1); uneFois.dualSortPenta += 1; } else if ((uneFois.dualSortPenta) && (uneFois.CalimpPrem)) VarDualSort(sort,nom,nombre->nbI,11); else if (!(uneFois.dualSortPenta) && (uneFois.CalResPrem_tdt)) { VarDualSort(sort,nom,nombre->nbI,2); uneFois.dualSortPenta += 1; } else if ((uneFois.dualSortPenta) && (uneFois.CalResPrem_tdt)) VarDualSort(sort,nom,nombre->nbI,12); // sinon on ne fait rien };