// 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)
{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)
,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)
{ 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;
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(ifstream& 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(ofstream& 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
};