// 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 "Front.h" #include "ParaAlgoControle.h" // constructeur //par defaut Front::Front() : boite_Front(),num_frontiere(0),elem(NULL),angle_mort(0) #ifdef UTILISATION_MPI ,num_unique(0) #endif {ptEl = NULL; tabmitoyen=NULL; }; // normal Front::Front ( const ElFrontiere& el, Element * pt, int num_front ,int ang_mort) : boite_Front(ParaGlob::Dimension()),num_frontiere(num_front) ,angle_mort(ang_mort) #ifdef UTILISATION_MPI ,num_unique(0) #endif ,elem(el.NevezElemFront()) { ptEl =(Element *) pt; tabmitoyen=NULL; // construction de la boite d'encombrement pour l'element Enum_dure temps=TEMPS_0; // temps par défaut if ((ptEl->Tab_noeud())(1)->ExisteCoord1()) temps = TEMPS_t; // construction de la boite d'encombrement pour la frontière Boite_encombrement_frontiere(temps,0.); }; // de copie Front::Front ( const Front& a) : boite_Front(a.boite_Front),num_frontiere(a.num_frontiere) ,elem(a.elem->NevezElemFront()),angle_mort(a.angle_mort) #ifdef UTILISATION_MPI ,num_unique(a.num_unique) #endif { ptEl = (Element *) a.ptEl; if (a.tabmitoyen != NULL) { int tabtaille = (a.tabmitoyen)->Taille(); if (tabtaille != 0) { tabmitoyen= new Tableau ; *tabmitoyen = *(a.tabmitoyen); } else tabmitoyen = NULL; } else tabmitoyen = NULL; }; // destructeur Front::~Front() { if (elem != NULL) delete elem; // on efface le tableau mais pas les objets pointés if (tabmitoyen != NULL) delete tabmitoyen; }; // ============= METHODES ========== // affichage à l'écran des informations liées au contact // cas = 0 : affichage en fonction du niveau de commentaire voulu // cas = 1 : affichage minimal nécessaire pour repérer l'élément void Front::Affiche(int cas) const { if (elem != NULL) {if (cas == 1) { cout << " front " ; if (angle_mort) cout << "(angle mort) "; cout << num_frontiere << " de l'EF " << ptEl->Num_elt() << " du mail. " << ptEl->Num_maillage() << flush; } else {cout << "\n element de frontiere du maillage " << ptEl->Num_maillage() <<" , cree par l'element " << ptEl->Num_elt() << " de numero " << num_frontiere << " , de type de geometrie: " << Nom_type_geom(elem->Type_geom_front()) << " , avec une interpolation:" << Nom_interpol(elem->ElementGeometrique().TypeInterpolation()); if (angle_mort) cout << " ( represente un angle mort) , "; cout << " , constitue des noeuds: " ; const Tableau & tabnoeud = elem->TabNoeud_const(); int tabtaille = tabnoeud.Taille(); for (int i=1;i<=tabtaille;i++) cout << tabnoeud(i)->Num_noeud() << " , "; cout << " , et contiend les degres de liberte suivants: " << elem->DdlElem_const(); if (this->tabmitoyen != NULL) {int tai = this->tabmitoyen->Taille(); cout << "\n " << tai << " elements mitoyens: ( "; for (int i=1;i<=tai;i++) cout << (*tabmitoyen)(i)->PtEI()->Num_elt() << " , "; cout << ") "; } else cout << "\n *** aucun element mitoyen !!!! *** "; }; } else { cout << "\n element de frontiere associe a un element fini: FRONTIERE NON DEFINIE !! "; }; // cout << "\n "; }; // affectation de toute les donnees Front& Front::operator = ( const Front& a) { if (elem != NULL) { if (a.elem == NULL) {delete elem;} else {*elem = *a.elem;}; } else { if (a.elem != NULL) {elem = a.elem->NevezElemFront();}; //sinon les deux sont nuls on n'à rien à faire }; num_frontiere = a.num_frontiere; ptEl = (Element *) a.ptEl; if (a.tabmitoyen != NULL) { if (tabmitoyen == NULL) tabmitoyen= new Tableau ; *tabmitoyen = *(a.tabmitoyen); } else {if (tabmitoyen != NULL) {delete tabmitoyen; tabmitoyen = NULL; }; }; // boite d'encombrement boite_Front = a.boite_Front; // angle mort angle_mort = a.angle_mort; #ifdef UTILISATION_MPI num_unique = a.num_unique; #endif return *this; }; // definition des elements mitoyens void Front::DefMitoyen(const Tableau & tab) { int tabtaille = tab.Taille(); if (tabtaille != 0) {if (tabmitoyen == NULL) tabmitoyen= new Tableau ; *tabmitoyen = tab; } else {if (tabmitoyen != NULL) {delete tabmitoyen; tabmitoyen = NULL; }; }; }; // ajout d'un élément mitoyens (l'ajout est effectif uniquement s'il n'existe pas déjà) void Front::AjoutMitoyen(Front * mitoyen) { if (tabmitoyen == NULL) // si le tableau n'existe pas, on le dimensionne à 1 et on ajoute l'unique élément {tabmitoyen= new Tableau ; tabmitoyen->Change_taille(1); (*tabmitoyen)(1) = mitoyen; } else // sinon on commence par regarder si mitoyen existe déjà {int tail = tabmitoyen->Taille(); bool trouver = false; for (int i=1;i<= tail; i++ ) if (*(*tabmitoyen)(i) == *mitoyen) {trouver = true; break;} // s'il n'existe pas on l'ajoute if (!trouver) // on augmente la taille et on ajoute {tabmitoyen->Change_taille(tail+1); (*tabmitoyen)(tail+1)= mitoyen; }; }; }; // test si le point passé en argument appartient à la boite d'encombrement de la frontière // tous les points sont supposées avoir la même dimension bool Front::In_boite_emcombrement_front(const Coordonnee& M) const { // on va essayer de faire efficace, pour cela on test le minimum const Coordonnee& co_min = boite_Front.Premier(); // par commodité const Coordonnee& co_max = boite_Front.Second(); // par commodité #ifdef MISE_AU_POINT if ((M.Dimension() != ParaGlob::Dimension())|| (M.Dimension() != co_min.Dimension())) { cout << "\n *** pb de dimensions non coherente !! " << "\n Front::In_boite_emcombrement_front(..."; Sortie(1); }; #endif switch (ParaGlob::Dimension()) { case 3: if ((M(3) co_max(3))) return false; case 2: if ((M(2) co_max(2))) return false; case 1: if ((M(1) co_max(1))) return false; }; // si on arrive ici c'est que le point est interne return true; }; // test si le point passé en argument appartient à la boite d'encombrement de la frontière // tous les points sont supposées avoir la même dimension // ici la boite est augmentée de extra dans tous les sens bool Front::In_boite_emcombrement_front(const Coordonnee& M,double extra) const { // on va essayer de faire efficace, pour cela on test le minimum const Coordonnee& co_min = boite_Front.Premier(); // par commodité const Coordonnee& co_max = boite_Front.Second(); // par commodité #ifdef MISE_AU_POINT if ((M.Dimension() != ParaGlob::Dimension())|| (M.Dimension() != co_min.Dimension())) { cout << "\n *** pb de dimensions non coherente !! " << "\n Front::In_boite_emcombrement_front(..."; Sortie(1); }; #endif switch (ParaGlob::Dimension()) { case 3: if ((M(3)<(co_min(3)-extra)) || (M(3) > (co_max(3)+extra))) return false; case 2: if ((M(2)<(co_min(2)-extra)) || (M(2) > (co_max(2)+extra))) return false; case 1: if ((M(1)<(co_min(1)-extra)) || (M(1) > (co_max(1)+extra))) return false; }; // si on arrive ici c'est que le point est interne à l'extra près return true; }; //----- lecture écriture base info ----- // lecture base info // ici la lecture n'est pas complète il faut ensuite changer l'élément // frontière et changer le pointeur de l'élément finis // -> utilisation de : Change_elem_frontiere, Change_PtEI void Front::Lecture_base_info_front(istream& ent) { // lecture et vérification du type string nom_type; ent >> nom_type; if (nom_type != "Front") Sortie(1); // lecture des infos string toto; // les éléments spécifiques à l'élément frontière int test = 0; ent >> test; if (test) {elem->Lecture_base_info_ElFrontiere_pour_projection(ent);} // on réutilise nom_type pour lire la chaine: am= ent >> nom_type >> angle_mort; // // la boite d'encombrement de la frontière // ent >> nom_type >> boite_Front.Premier() >> boite_Front.Second() ; }; // écriture base info // on ne sauvegarde ici que les grandeurs spécifiques à ce niveau // concernant les infos relatives à l'élément, la frontière, etc, ce n'est pas traité ici, mais au niveau de la classe LesContats void Front::Ecriture_base_info_front(ostream& sort) { // écriture du type sort << "Front "; // les données // sort << "mail= " << ptEl->Num_maillage() << " NE= " << ptEl->Num_elt() << " fron= " << num_frontiere ; // les éléments spécifiques à l'élément frontière if (elem != NULL) { sort << " 1 "; elem->Ecriture_base_info_ElFrontiere_pour_projection(sort);} else { sort << " 0 ";}; sort << " am= " << angle_mort << " "; // la boite d'encombrement // sort << "encombrements_surf " << boite_Front.Premier() << " " << boite_Front.Second() << " \n"; }; //====================================== fonctions internes ============================ // fonctions internes // mise à jour de la boite d'encombrement de la frontière // dep_max : déplacement maxi des noeuds du maillage // , sert pour def des boites d'encombrement maxi des frontières void Front::Boite_encombrement_frontiere(Enum_dure temps,double dep_max) { #ifdef MISE_AU_POINT if (elem == NULL) {cout << "\n *** erreur, la frontiere n'est pas definie " << "\n Front::Boite_encombrement_frontiere(... " << endl; Sortie(1); }; #endif Tableau & tab = elem->TabNoeud(); int tab_taille= tab.Taille(); Coordonnee& encomb_min_fr=boite_Front.Premier(); Coordonnee& encomb_max_fr=boite_Front.Second(); switch (temps) { case TEMPS_0: {encomb_min_fr=tab(1)->Coord0();encomb_max_fr=encomb_min_fr; // init for (int i=2;i<=tab_taille;i++) // balayage des autres noeuds { Coordonnee co=tab(i)->Coord0(); encomb_min_fr.Modif_en_min(co); encomb_max_fr.Modif_en_max(co); }; break; } case TEMPS_t: {encomb_min_fr=tab(1)->Coord1();encomb_max_fr=encomb_min_fr; // init for (int i=2;i<=tab_taille;i++) // balayage des autres noeuds { Coordonnee co=tab(i)->Coord1(); encomb_min_fr.Modif_en_min(co); encomb_max_fr.Modif_en_max(co); }; break; } case TEMPS_tdt: {encomb_min_fr=tab(1)->Coord2();encomb_max_fr=encomb_min_fr; // init for (int i=2;i<=tab_taille;i++) // balayage des autres noeuds { Coordonnee co=tab(i)->Coord2(); encomb_min_fr.Modif_en_min(co); encomb_max_fr.Modif_en_max(co); }; break; } }; // fin du switch // maintenant on tiend compte d'un facteur majorant pour incertitude Coordonnee delta=(encomb_max_fr- encomb_min_fr) * (ParaGlob::param->ParaAlgoControleActifs().Extra_boite_prelocalisation()-1.); // dans le cas de surface plane on peut avoir une boite avec une épaisseur nulle, // comme il s'agit d'une boite d'encombrement assez grossière on ajoute une valeur par défaut // par défaut on prend une valeur par défaut du max de delta double miniajout = (ParaGlob::param->ParaAlgoControleActifs().Rapport_Extra_boite_mini_prelocalisation()) * delta.Max_val_abs(); // dans le cas d'un espace 3D et d'une frontière provenant d'un élément 2D avec une épaisseur, // on prend le maxi de l'épaisseur et du miniajout déjà calculé if ((ParaGlob::Dimension() == 3) && (Type_geom_generique(ptEl->ElementGeometrique().TypeGeometrie()) == SURFACE)) // ((ptEl->PoutrePlaqueCoque() == PLAQUE) || (ptEl->PoutrePlaqueCoque() == COQUE)) // ) { // on récupère l'épaisseur ElemMeca* elemmeca = (ElemMeca *) ptEl ; miniajout = MaX(miniajout, elemmeca->EpaisseurMoyenne(temps)); }; delta.Ajout_meme_valeur(miniajout); // ajout d'un extra dans toutes les directions delta.Ajout_meme_valeur(ParaGlob::param->ParaAlgoControleActifs().Ajout_extra_boite_prelocalisation()); encomb_min_fr -= delta; encomb_max_fr += delta; // on tiend enfin compte d'une majoration de 2 fois le déplacement maxi des noeuds du maillage if (dep_max != 0.) {encomb_min_fr.Ajout_meme_valeur(-2.*dep_max); encomb_max_fr.Ajout_meme_valeur(2.*dep_max); }; // -- debug //if( ptEl->Num_elt() == 9) // { cout << "\n elem " << ptEl->Num_elt() << " maillage " << ptEl->Num_maillage() << " frontiere N= " ; // for (int i=1;i<= (elem->TabNoeud()).Taille();i++) cout << (elem->TabNoeud())(i)->Num_noeud() << " "; // cout << "\n boite "; encomb_min_fr.Affiche(); encomb_max_fr.Affiche(); // cout << " Front::Boite_encombrement_frontiere( " << endl; // }; //-- fin débug };