Herezh_dev/Maillage/maillage4.cc

3098 lines
161 KiB
C++

// FICHIER : Maillage.cp
// CLASSE : Maillage
// 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) <https://www.irdl.fr/>.
//
// 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 <https://www.gnu.org/licenses/>.
//
// For more information, please consult: <https://herezh.irdl.fr/>.
#include "Maillage.h"
# include <iostream>
using namespace std; //introduces namespace std
#include <stdlib.h>
#include "Sortie.h"
#include <stdio.h>
#include <vector>
#include "List_io.h"
#include "CharUtil.h"
//#ifndef SYSTEM_MAC_OS_X_unix
// #include "Frontier.h"
//#endif
#include "ConstMath.h"
#include "ReferenceNE.h"
#include "ReferenceAF.h"
#include "Util.h"
#include "MvtSolide.h"
#include "Basiques.h"
#include "TriaSfe1.h"
#include "TriaSfe1_cm5pti.h"
#include "TriaSfe2.h"
#include "TriaSfe3.h"
#include "TriaSfe3_cm3pti.h"
#include "TriaSfe3_cm4pti.h"
#include "TriaSfe3_cm5pti.h"
#include "TriaSfe3_cm6pti.h"
#include "TriaSfe3_cm7pti.h"
#include "TriaSfe3_cm12pti.h"
#include "TriaSfe3_cm13pti.h"
#include "TriaSfe3_3D.h"
#include "TriaSfe3C.h"
#include "TriaQSfe1.h"
#include "TriaQSfe3.h"
#include <limits>
//------------------- on s'occupe de 3 classes de travail ----------------------------------
bool Maillage::NBelemEtFace::operator < (const Maillage::NBelemEtFace& c) const
{if (nbElem < c.nbElem) {return true;}
else if (nbElem > c.nbElem) {return false;}
else // ici cas ou nbElem == c.nbElem
{ return (nbFace < c.nbFace);};
};
bool Maillage::NBelemEtFace::operator > (const Maillage::NBelemEtFace& c) const
{if (nbElem > c.nbElem) {return true;}
else if (nbElem < c.nbElem) {return false;}
else // ici cas ou nbElem == c.nbElem
{ return (nbFace > c.nbFace);};
};
bool Maillage::NBelemEtArete::operator < (const Maillage::NBelemEtArete& c) const
{if (nbElem < c.nbElem) {return true;}
else if (nbElem > c.nbElem) {return false;}
else // ici cas ou nbElem == c.nbElem
{ return (nbArete < c.nbArete);};
};
bool Maillage::NBelemEtArete::operator > (const Maillage::NBelemEtArete& c) const
{if (nbElem > c.nbElem) {return true;}
else if (nbElem < c.nbElem) {return false;}
else // ici cas ou nbElem == c.nbElem
{ return (nbArete > c.nbArete);};
};
bool Maillage::NBelemEtptInteg::operator < (const Maillage::NBelemEtptInteg& c) const
{if (nbElem < c.nbElem) {return true;}
else if (nbElem > c.nbElem) {return false;}
else // ici cas ou nbElem == c.nbElem
{ return (nbPtInteg < c.nbPtInteg);};
};
bool Maillage::NBelemEtptInteg::operator > (const Maillage::NBelemEtptInteg& c) const
{if (nbElem > c.nbElem) {return true;}
else if (nbElem < c.nbElem) {return false;}
else // ici cas ou nbElem == c.nbElem
{ return (nbPtInteg > c.nbPtInteg);};
};
bool Maillage::NBelemFAEtptInteg::operator < (const Maillage::NBelemFAEtptInteg& c) const
{if (nbElem < c.nbElem) {return true;}
else if (nbElem > c.nbElem) {return false;}
else // ici cas ou nbElem == c.nbElem
{ if (nbFA < c.nbFA ) {return true;}
else if (nbFA > c.nbFA ) {return false;}
else // cas où il ne reste que le pti
{return (nbPtInteg < c.nbPtInteg);};
};
};
bool Maillage::NBelemFAEtptInteg::operator > (const Maillage::NBelemFAEtptInteg& c) const
{if (nbElem > c.nbElem) {return true;}
else if (nbElem < c.nbElem) {return false;}
else // ici cas ou nbElem == c.nbElem
{if (nbFA > c.nbFA) {return true;}
else if (nbFA < c.nbFA) {return false;}
else // cas où il ne reste que le pti
{ return (nbPtInteg > c.nbPtInteg);};
};
};
//----------------------- fin des classes de travail ------------------------------------------
// modification de l'orientation d'éléments
void Maillage::Modif_orientation_element(int cas_orientation,LesReferences* lesRef)
{
switch (cas_orientation)
{case -1: case 1:
// =-1: on sort une information s'il y a un pb d'orientation, mais on ne fait rien
// =1: on modifie automatiquement l'orientation des éléments lorsque le jacobien
// est purement négatif
{ // on va boucler sur les éléments
int nbelem = tab_element.Taille();
for (int ie=1;ie<=nbelem;ie++)
tab_element(ie)->Modif_orient_elem(cas_orientation);
break;
}
case 2: // cas d'une orientation semi-automatique des faces d'un maillage de coques ou de membranes
{cout << "\n processing of the mesh : " << nomDuMaillage << " nB= " << idmail;
cout << "\n this re-orientation of elements can be applied only for shell and membrane elements"
<< " the other elements are ignored. " ;
// initialisation des différents tableaux utilisés par Orientation_elements_mitoyens_recursif
Init_Orientation_elements_mitoyens_recursif();
// on commence par faire l'acquisition d'un élément particulier dont la direction servira de référence
bool fin_boucle_infinie = false;
bool calcul_frontiere = false; // pour le calcul une fois des frontières
int num_elem=0; // init du numéro de l'élément
bool fr = ParaGlob::Francais(); // pour simplifier
while (!fin_boucle_infinie)
{num_elem=0; // re-init du numéro de l'élément, dans le cas où on bouclerait
bool inverse = false; // init de l'indicateur permettant de savoir si l'on souhaite essayer
// d'inverser le premier élément, donc tous les éléments de la nouvelle ref
if (fr)
{cout << "\n --- choix d'un element dont l'orientation servira de reference ------- ";
cout << "\n le reperage peut se faire de differentes manieres :"
<< "\n par un numero d'element dans le maillage -> (choix : 1)"
<< "\n (rep -1 si l'on veut tenter une orientation inverse pour les elements) "
<< "\n par des coordonnees d'un point (meme approximatives), "
<< "\n l'element choisit sera celui le plus proche de ce point -> (choix : 2)"
<< "\n (rep -2 si l'on veut tenter une orientation inverse pour les elements) "
<< "\n fin -> (choix : f ou 0)";
}
else
{cout << "\n --- choise of a reference element for the orientation ------- ";
cout << "\n could be done by :"
<< "\n the number of the element in the mesh -> (choice : 1)"
<< "\n (choice -1 if an inverse orientation is tried for the elements) "
<< "\n the coordinates of a point (even approximately) "
<< "\n the choice will be the nearest element -> (choice : 2)"
<< "\n (choice -2 if an inverse orientation is tried for the elements) "
<< "\n end -> (choice : f or 0)";
};
string rep="";
if (fr)
{cout << "\n reponse ? ";}else {cout << "\n answer ? ";};
rep= lect_return_defaut(false,"f");
bool a_traiter=false; // pour gérer l'action d'orienter ou non
if ((rep == "1") || (rep == "-1"))
{if (rep =="-1") inverse = true; // on enregistre le souhait d'une orientation inverse
if (fr) { cout << "\n numero de l'element ? "; }
else { cout << "\n number of the element ? ";};
rep=lect_chaine(); num_elem = ChangeEntier(rep);
}
else if ((rep == "2") || (rep =="-2"))
{int dim = ParaGlob::Dimension();
if (rep =="-2") inverse = true; // on enregistre le souhait d'une orientation inverse
Coordonnee xi(dim);
if (fr) {cout << "\n coordonnee ("<<dim<<" nombre(s)) ? ";}
else {cout << "\n coordinate ("<<dim<<" scalar(s)) ? ";};
for(int j=1;j<=dim;j++) cin >> xi(j);
std::cin.ignore( std::numeric_limits<std::streamsize>::max(), '\n' );// purge de cin
if (fr) {cout << "\n les coordonnees sont a: t = 0 ou t ou tdt (repondre 0 ou t ou tdt) ? ";}
else {cout << "\n the coordinates are at : t = 0 or t or tdt (answer 0 or t or tdt) ? ";}
rep = lect_chaine();
bool rep_exploitable = true; Enum_dure enu_temps;
if (rep == "0")
enu_temps = TEMPS_0;
else if (rep == "t")
enu_temps = TEMPS_t;
else if (rep == "tdt")
enu_temps = TEMPS_tdt;
else
{ if (fr) {cout << "\n erreur de syntaxe, on attendait: 0, t ou tdt ";}
else {cout << "\n error, the input must be : 0, t or tdt ";}
rep_exploitable = false;
};
if (rep_exploitable)
{const Element * elem_ret = Centre_de_Gravite_Element_le_plus_proche(enu_temps,xi);
if (elem_ret == NULL) // cas où l'on ne trouve pas d'élément
{ if (fr) {cout << "\n pas d'element trouve , pour le temps "
<< rep << " recommencez ! ";}
else {cout << "\n no element founded, for the time "
<< rep << " do it again ! ";};
}
else
{ if (fr) {cout << "\n le numero de l'element contenant le point: "<< elem_ret->Num_elt_const();}
else {cout << "\n the number of the element that contains the point: "<< elem_ret->Num_elt_const();};
num_elem = elem_ret->Num_elt_const();
};
};
}
else if ((Minuscules(rep) == "fin") || (Minuscules(rep) == "f") || (Minuscules(rep) == "0"))
{fin_boucle_infinie = true; a_traiter=false;}
else
{if (fr) {cout << "\n choix non valide, recommencez !";}
else {cout << "\n the choice is not valide, starts again ! ";};
};
// on vérifie que l'élément est correcte
if (!fin_boucle_infinie) // on ne vérifie pas si c'est la fin demandée
{if ((num_elem < 1) || (num_elem > tab_element.Taille()))
{if (fr) {cout << "\n choix non valide, le numero "<<num_elem<<" est en dehors de ";
cout << "l'intervalle des elements enregistres ["<<1<<":"<<tab_element.Taille()<<"]"; }
else { cout << "\n the choice is not valide, the number "<<num_elem<<" is out of the range of recorded elements ";
cout << "["<<1<<":"<<tab_element.Taille()<<"]"; };
}
else if (Type_geom_generique(tab_element(num_elem)->Id_geometrie()) != SURFACE)
{ if (fr) {cout << "\n choix non valide, l'element "<<num_elem<<" n'est pas un element de surface !! ";
cout << " c'est un element : "<< Type_geom_generique(tab_element(num_elem)->Id_geometrie()); }
else { cout << "\n the choice is not valide, the element "<<num_elem<<" is a surface element ";
cout << " it is an element: "<< Type_geom_generique(tab_element(num_elem)->Id_geometrie()); };
}
else if (TestEnum_geom_axisymetrique(tab_element(num_elem)->Id_geometrie()))
{ if (fr) {cout << "\n choix non valide, l'element "<<num_elem<<" est un element axisymetrique !! ";}
else { cout << "\n the choice is not valide, the element "<<num_elem<<" is an axisymetric element "; };
}
else // sinon c'est ok
{ a_traiter=true;};
// maintenant on va traiter éventuellement
if (a_traiter)
{double angle_maxi=0; // angle maxi entre deux éléments, au-dessus duquel, on ne traite pas
if (fr)
{cout << "\n angle maxi (en degre) au dessus duquel on considerera "
<< "\n qu'il n'y a plus de continuite : ";
}
else
{cout << "\n angle maximun (in degree) up this angle, up this value, "
<< "\n the conitnuity is not taking into account : ";
};
angle_maxi=lect_double();
cout << "\n angle= " << angle_maxi ;
// transformation en radian
angle_maxi *= ConstMath::Pi/180.;
cout << " ("<<angle_maxi <<" rd) ";
// on s'occupe du nom des ref
string nom_ref="_"; // nom par défaut
string reponse = "n";
if (fr)
{ cout << "\n gene auto du nom des ref (par defaut rep \"o\" ) ou def d'un nom particulier (rep \"n\") ";}
else
{ cout << "\n automatic name for the ref (default rep\"o\" ) or def of a specific name (rep \"n\") ";};
reponse = lect_return_defaut(false,"o");
if (reponse == "n")
{if (fr) {cout << "\n nom de la ref ? ";}
else {cout << "\n name of the reference ? ";};
nom_ref= lect_chaine();
if (fr) {cout << "\n nom lu " << nom_ref<<endl;}
else {cout << "\n reading name " << nom_ref<<endl;};
fin_boucle_infinie = false; // pour être sûr de refaire une passe
};
// --- on appelle les programmes ad hoc
// - on définie tous les Front des éléments, et leurs Front mitoyens
if (!calcul_frontiere)
{Calcul_tous_les_front_et_leurs_mitoyens();
calcul_frontiere = true;
};
// - premier passage avec le numéro choisit et éventuellement un nom donné
bool recursif = false;
list <int> nums_non_oriente = Orientation_elements_mitoyens_recursif(recursif,nom_ref,num_elem,*lesRef
,angle_maxi,inverse);
// dans le cas où la liste de retour n'est pas vide cela signifie qu'il y a des groupes d'éléments mitoyens qui n'ont pas
// la même orientation, on demande si l'on veut les orienter
if (nums_non_oriente.size() != 0)
{ if (fr) {cout << "\n des groupes d'elements mitoyens ont ete detectes comme ayant des orientations differentes "
<< " voulez-vous les orienter (arbitrairement) par groupes mitoyens "
<< " avec des noms de ref genere automatiquement ? (rep o ou n ) ";}
else {cout << "\n we have found set of elements, that have common boundaries, but have no similar orientation,"
<< " do you want to change these orientation (arbirary) for each set "
<< " with automatic generation of ref name ? (answer y or n )";};
string answer="";answer=lect_o_n(false);
if ((fr && (Minuscules(answer) == "o")) || (!fr && (Minuscules(answer) == "y")))
{ nom_ref="_";bool recursif = true;
while (nums_non_oriente.size())
{ nums_non_oriente = Orientation_elements_mitoyens_recursif
(recursif,nom_ref,*(nums_non_oriente.begin()),*lesRef,angle_maxi,inverse);}
fin_boucle_infinie = true;
};
};
};
}; // fin du cas où on n'a pas demandé de finir la boucle infinie
}; // -- fin de la boucle infinie sur le choix noeud/élément ou arrêt
break;
}
case 3: // cas d'une orientation en fonction d'un rayon
{cout << "\n processing of the mesh : " << nomDuMaillage << " nB= " << idmail;
cout << "\n this re-orientation of elements can be applied only for shell and membrane elements"
<< " the other elements are ignored. " ;
// def des tableaux de travail initialisés à rien par défaut
int dim_espace(ParaGlob::Dimension());
if (dim_espace != 3) // pour l'instant ne fonctionne qu'en dimension 3
{ cout << "\n erreur *** pour l'instant, cette fonction d'orientation ne fonctionne qu'en dimension 3 "
<< endl;
Sortie(2);
return; // normalement ne sert à rien
};
Tableau <bool> indic_G(3,false);
Coordonnee3 A;
Tableau <bool> item_renseigne(3,false); // utilisé pour savoir si tous les items ont été renseignés
string zone_a_traiter("_");
bool inverse=false;
// on définit les paramètres de l'orientation: on va utiliser un menu
string rep("_");bool traitement_pas_pret = true;
while (traitement_pas_pret)
{ while ((Minuscules(rep) != "f")&&(Minuscules(rep) != "0"))
{
try
{
cout
<< "\n (0 ou f) (fin normal avant traitement) "
<< "\n (1) definition du point de reference "
<< "\n (2) inversion eventuelle de sens "
<< "\n (3) definition de la zone a traiter "
<< "\n (4) arret du processus (sans traitement) "
<< "\n (5) affichage de la liste des ref existantes (pour info) "
<< "\n (6) affichage min max sur x y z pour info "
<< "\n ";
rep = lect_return_defaut(false,"f");
// sortie directe si tout est ok, sinon
if ((Minuscules(rep) == "f") || (Minuscules(rep) == "0"))
{if (item_renseigne(1) && item_renseigne(3))
break; // ok on peut s'arrêter
else { cout << "\n la mise en donnee n'est pas complete ! "<<endl;
if (!item_renseigne(1)) cout << " vous devez renseigner le (1) "<<endl;
if (!item_renseigne(3)) cout << " vous devez renseigner le (3) "<<endl;
};
rep = "_"; // on réinitialise pour éviter de sortir de la boucle
}
else
{
int num = ChangeEntier(rep);
bool choix_valide=false;
if ((num >= 0)&&(num<7))
{ choix_valide=true; }
else { cout << "\n Erreur on attendait un entier entre 0 et 6 !!, "
<< "\n redonnez une bonne valeur"
<< "\n ou taper f ou 0 pour arreter le programme et valider les choix ";
choix_valide=false;
}
switch (num)
{ case 0: // sortie
{ break;} // normalement cela a déjà été filtré avant
case 1: // définition du point de référence
{ cout << "\n\n definition du point de reference \n";
{ string nom;
cout << "\n coord x du point ou XG pour utiliser le x du G de la facette ? ";
nom= lect_chaine();cout << " valeur lue "<< nom<<endl;
if (nom == "XG") {indic_G(1)=true;A(1)=0.;}
else { indic_G(1)=false;A(1)=ChangeReel(nom);};
}
{ string nom;
cout << "\n coord y du point ou YG pour utiliser le y du G de la facette ? ";
nom= lect_chaine();cout << " valeur lue "<< nom<<endl;
if (nom == "YG") {indic_G(2)=true;A(2)=0.;}
else { indic_G(2)=false;A(2)=ChangeReel(nom);};
}
{ string nom;
cout << "\n coord z du point ou ZG pour utiliser le z du G de la facette ? ";
nom= lect_chaine();cout << " valeur lue "<< nom<<endl;
if (nom == "ZG") {indic_G(3)=true;A(3)=0.;}
else { indic_G(3)=false;A(3)=ChangeReel(nom);};
}
item_renseigne(1)=true; // on valide l'item
break;
}
case 2: // inversion de sens
{ cout << "\n inversion eventuelle du sens rep o ou n ";
string nom;
nom= lect_chaine();cout << " valeur lue "<< nom<<endl; nom = Minuscules(nom);
if (nom == "o" ) inverse = true;
else if (nom == "n") inverse = false;
// sinon on laise en l'état
item_renseigne(2)=true; // on valide l'item
break;
}
case 3: // definition de la zone a traiter
{ cout << "\n definition de la zone a traiter \n";
cout << "\n donner la reference des elements a traiter ? ";
string nom;
nom= lect_chaine(); cout << " valeur lue "<< nom<<endl;
// on regarde si la référence existe
if (!lesRef->Existe(nom,idmail))
{cout << "\n *** cette reference n'existe pas !! "<<endl;
item_renseigne(3)=false;
}
else {zone_a_traiter=nom; item_renseigne(3)=true;};
break;
}
case 4: // arret du processus sans traitement
{ cout << "\n fin du processus, pas de traitement de re-orientation !! ";
return;
break;
}
case 5: // affichage de la liste des ref existantes
{ cout << "\n affichage de la liste de nom des ref existantes \n";
lesRef->Affiche(1);
break;
}
case 6: // affichage min max x y z pour info
{ cout << "\n affichage min max x y z pour info \n";
// on récupère la boite d'encombrement
Tableau <Vecteur> tab_vec = Taille_boiteMail();
cout << "\n min_x= "<<tab_vec(1)(1) << " max_x= "<< tab_vec(2)(1);
cout << "\n min_y= "<<tab_vec(1)(2) << " max_y= "<< tab_vec(2)(2);
cout << "\n min_z= "<<tab_vec(1)(3) << " max_z= "<< tab_vec(2)(3);
break;
}
default:
cout << "\n mauvais choix !! recommencez ! ";
};
};
}
catch (ErrSortieFinale)
// cas d'une direction voulue vers la sortie
// on relance l'interuption pour le niveau supérieur
{ ErrSortieFinale toto;
throw (toto);
}
catch (...)//(UtilLecture::ErrNouvelleDonnee erreur)
{ cout << "\n Erreur on attendait un des mots clés proposés !!, "
<< "\n redonnez une bonne valeur"<<endl;
};
}; //-- fin du while
// on regarde si tous les items ont été renseigné
if (item_renseigne(1) && item_renseigne(3))
{traitement_pas_pret = false;rep = "";}
else {traitement_pas_pret = true;rep = "";};
};
// arrivée ici on dispose de toutes les données ad hoc
// appel de la routine
Orientation_via_rayon(indic_G,A,zone_a_traiter,*lesRef,inverse);
break;
}
default:
cout << "\n error: case of an orientation not envisaged : cas_orientation= " << cas_orientation
<< "\n Maillage::Modif_orientation_element(... ";
Sortie(1);
};
};
// Lecture et Collapse des éléments superposés, c-a-d identiques, dans le cas où il en existe
void Maillage::LectureEtCollapse_element_superpose(UtilLecture * entreePrinc,LesReferences* lesRef)
{ if (strstr(entreePrinc->tablcar,"fusion_elements_superposes_")!=NULL)
{ if (ParaGlob::NiveauImpression() > 2) cout << "\n beginning of the process to collapse elements which are "
<< " superposed "<< endl ;
entreePrinc->NouvelleDonnee(); // on passe le mot clé
// appel de l'algo de collapse
Collapse_element_superpose(lesRef);
if (ParaGlob::NiveauImpression() > 2) cout << "\n end of the process to collapse elements which are "
<< " superposed "<< endl ;
};
};
// Collapse des éléments supperposés, c-a-d identiques, dans le cas où il en existe
void Maillage::Collapse_element_superpose(LesReferences* lesRef)
{ // création pour chaque noeud de la liste des éléments qui contiennent le noeud
Calcul_indice();
// on crée un tableau d'indicateur des éléments à supprimer
int nbelem = tab_element.Taille();
Tableau <int> elem_supprime(nbelem,0);
// on balaie les éléments, et pour chaque élément, on recherche les éléments supperposés éventuels
for (int ine = 1;ine <= nbelem;ine++)
// on ne continue que si c'est un élément qui n'a pas déjà été marqué " à supprimé "
if (elem_supprime(ine) == 0)
{Element * elem = tab_element(ine);
// on récupère uniquement le premier noeud
Noeud * noe = tab_element(ine)->Tab_noeud()(1);
// indice(i) contient la liste des éléments qui contiennent le noeud i
List_io < Element*> & li_elem = indice(noe->Num_noeud()); // pour simplifier
List_io < Element*>::iterator il,ilfin = li_elem.end();
for (il=li_elem.begin();il != ilfin;il++)
// on intervient que si le numéro de l'élément est supérieur à celui de l'élément de base
// et que ce n'est pas un élément déjà marqué à supprimé
if (((*il)->Num_elt() > ine )&&(elem_supprime((*il)->Num_elt()) == 0))
// on test si les deux éléments ont la même signature, même géométrie et appartiennent au même maillage
if (elem->Meme_signature_et_geometrie(*(*il))) // si égalité, on indique que l'élément il est à supprimer,
elem_supprime((*il)->Num_elt())=ine; // et on sauvegarde l'élément de substitution
};
// on sauvegarde les anciens numéros de noeuds, servira pour contruire nv_num
// normalement c'est directement iN mais on ne sait jamais
Tableau <int> ancien_num_ele(nbelem);
for (int ie=1;ie<=nbelem;ie++)
ancien_num_ele(ie) = tab_element(ie)->Num_elt();
// -- maintenant on va vraiment supprimer les éléments en double et mettre à jour les références
// 1- tout d'abord on s'intéresse aux éléments, dont on va mettre à jour les références
// 2- on supprime les éléments qui ne servent plus
int nb_elem_restant = nbelem; // init du nombre d'élément restant après fusion
Tableau <bool> non_referencer(nbelem,false); // un tableau intermédiaire qui servira pour les ref
for (int ine=1;ine<=nbelem;ine++)
{if (elem_supprime(ine)) // s'il est différent de 0, on doit supprimer
{ int num_nelem = elem_supprime(ine);
delete tab_element(ine); // on supprime l'élément
// -- debug
// cout << "\n Maillage::Collapse_element_superpose debug !! à remettre en service la ligne précédente "<<endl;
// -- fin debug
tab_element(ine)=NULL; // on indique qu'il n'y a plus d'élément
// non_referencer(ine)=true; // servira pour les ref
// *** modif 15 avril 2016: comme il s'agit d'éléments supperposés, cela veut dire qu'il reste un élément de substitution
// qui lui est valide donc on met false, ce qui veut dire que l'on ne veut pas supprimer l'élément dans la ref
// car sinon la ref devient différente et incomplète
non_referencer(ine)=false; // servira pour les ref
nb_elem_restant--; // on diminue le nombre d'éléments restants
if (ParaGlob::NiveauImpression() > 2)
cout << "\n collapse element " << ine << " --> " << num_nelem ;
////-- debug
//{cout << "\n debug ** Maillage::Collapse_element_superpose() ";
// Element * elem1 = tab_element(ine-1); // recup de l'element
// cout << " element " << elem1->Num_elt() << " ";
// elem1->Affiche();
//// Element * elem2 = tab_element(ine); // recup de l'element
//// cout << " element " << elem2->Num_elt() << " ";
//// elem2->Affiche();
// Element * elem3 = tab_element(ine+1); // recup de l'element
// cout << " element " << elem3->Num_elt() << " ";
// elem3->Affiche();
// cout << "\n"<<endl ;
// Sortie(1);
//
//};
////--fin debug
};
};
// maintenant on refait un nouveau tableau d'éléments avec les éléments inutiles supprimés
Tableau <Element* > tab_final(nb_elem_restant);
int nbelem_restant=0; // le nombre d'éléments restant
cout << "\n ";
for (int ijn = 1; ijn <= nbelem; ijn++)
{ if(tab_element(ijn)!=NULL)
{nbelem_restant++;
tab_final(nbelem_restant) = tab_element(ijn);
};
};
// // on redimentionne le tableau final (ses premiers restent !!)
// tab_final.Change_taille(nbn_restant);
if (ParaGlob::NiveauImpression() >= 0)
cout << "\n collapse of " << (nbelem-nbelem_restant) <<" element(s) " << endl;
// on met à jour les références
lesRef->SupprimeReference("E_tout",idmail); // on supprime la référence E_tout
Tableau <int> nv_num(nbelem,0); // nouveau num/ au ancien
for (int ia=1;ia <= nbelem_restant; ia++)
nv_num(tab_final(ia)->Num_elt()) = ia;
// *** modif 15 avril 2016: il faut tous les numéros de remplacement et pas seulement ceux
// qui restent car dans la mise à jour on commence par changer les numéros et "ensuite"
// on supprime les doublons --> donc on complète
// nv_num(num_ancien) = le nouveau numéro d'élément donc celui qui est en coincidence et qui reste
// a_fusionner(ancien_num_ele(ia)) -> le nouveau numéro dans l'ancien tableau
// qui aura comme nouveau numéro:nv_num(a_fusionner(ancien_num_ele(ia)))
for (int ia=1;ia <= nbelem; ia++)
if (nv_num(ia) == 0) // cela veut dire que c'est un numéro qui disparait
nv_num(ia) = nv_num(elem_supprime(ancien_num_ele(ia)));
// -- debug
// cout << "\n Maillage::Collapse_element_superpose debug "<<endl;
//lesRef->Affiche(); cout << endl;
// -- fin debug
lesRef->Mise_a_jour_ref_element(nv_num,idmail,non_referencer);
////-- debug
//{cout << "\n debug ** Maillage::Collapse_element_superpose() ";
// Element * elem1 = tab_final(152); // recup de l'element
// cout << " element " << elem1->Num_elt() << " ";
// elem1->Affiche();
//// Element * elem2 = tab_element(ine); // recup de l'element
//// cout << " element " << elem2->Num_elt() << " ";
//// elem2->Affiche();
// Element * elem3 = tab_final(153); // recup de l'element
// cout << " element " << elem3->Num_elt() << " ";
// elem3->Affiche();
// cout << "\n"<<endl ;
//
//};
//--fin debug
// on enregistre le nouveau tableau d'éléments
tab_element = tab_final;
// on met à jour les numéros d'éléments
for (int ia=1;ia <= nbelem_restant; ia++)
tab_element(ia)->Change_num_elt(ia);
// on recrée la référence E_tout
string Etout("E_tout");
{ // on construit le tableau des numéros de noeuds
Tableau <int> tabE(nbelem_restant); for (int i=1;i<=nbelem_restant;i++) tabE(i)=i;
ReferenceNE* rtout = new ReferenceNE(tabE,idmail,2,Etout);// construction de la référence
lesRef->Ajout_reference(rtout); // ajout de la ref, qui est maintenant géré par lesRef
};
////-- debug
//{cout << "\n debug ** Maillage::Collapse_element_superpose() ";
// Element * elem1 = tab_element(152); // recup de l'element
// cout << " element " << elem1->Num_elt() << " ";
// elem1->Affiche();
//// Element * elem2 = tab_element(ine); // recup de l'element
//// cout << " element " << elem2->Num_elt() << " ";
//// elem2->Affiche();
// Element * elem3 = tab_element(153); // recup de l'element
// cout << " element " << elem3->Num_elt() << " ";
// elem3->Affiche();
// cout << "\n"<<endl ;
//};
////--fin debug
////-- debug
//{cout << "\n debug ** Maillage::Collapse_element_superpose() ";
// int tail=tab_element.Taille();
// cout << "\n NBE= " << tail ;
// for (int ina = 1;ina <= tail;ina++)
// {Element * elem2 = tab_element(ina); // recup de l'element
// cout << " element " << elem2->Num_elt() << " ";
// elem2->Affiche();
// };
// cout << "\n"<<endl ;
// Sortie(1);
//};
//////--fin debug
};
// Lecture et collapse de noeuds très proche: appartenant à des éléments différents
void Maillage::LectureEtCollapse_noeuds_proches(UtilLecture * entreePrinc, LesReferences* lesRef)
{ if (strstr(entreePrinc->tablcar,"fusion_noeuds_proches_")!=NULL)
{ if (ParaGlob::NiveauImpression() > 2) cout << "\n beginning of the process to collapse nodes which are "
<< " nearly at the same position "<< endl ;
// on lit la distance mini
double rayon = 0;string nom;
*(entreePrinc->entree) >> nom >> rayon;
if (nom != "fusion_noeuds_proches_")
{ cout << "\n error : we expected the keyword: fusion_noeuds_proches_ but we read \""<<nom<<"\" ";
if (ParaGlob::NiveauImpression() >= 6)
cout << "\n Maillage::LectureEtCollapse_noeuds_proches(...";
Sortie(1);
};
if (ParaGlob::NiveauImpression() >= 5)
cout << "\n minimum distance = " << rayon;
entreePrinc->NouvelleDonnee(); // on passe le mot clé
// appel de l'algo de collapse
Collapse_noeuds_proches(rayon,lesRef);
if (ParaGlob::NiveauImpression() > 2) cout << "\n end of the process to collapse nodes which are "
<< " nearly at the same position "<< endl ;
};
};
// collapse de noeuds très proche: appartenant à des éléments différents
// rayon : donne la distance maxi entre les noeuds qui doivent être collapsé
void Maillage::Collapse_noeuds_proches(double rayon ,LesReferences* lesRef)
{// au niveau de l'algo on va commencer par faire un classement des noeuds pour accélérer les recherches futures
// pour cela on découpe le volume de travail en boites contenant un petit nombre de noeuds
// et on s'aide de grandeurs de référence
int NBN = tab_noeud.Taille();
int dim = ParaGlob::Dimension();
if (ParaGlob::NiveauImpression() >= 0)
cout << "\n " << NBN << " node(s) " << tab_element.Taille() << " element(s) " ;
// racine3NBN donne une idée du nombre de noeuds dans chaque direction de la dimension
int racine3NBN = (int) (exp(1./dim * log(NBN) )); // floor: extraction de la partie entière
// on veut environ 3*3*3=27 noeuds par boites en 3D par exemple
// en fait les tests on montré que c'était mieux d'avoir plus de boite, donc on ne divise pas par 3
int nb_decoupe = racine3NBN ; // 3;// on pourrait donc avoir nb_decoupe**dim cubes
// mais il faut également que la taille du cube de base soit plus grande que le rayon
// maintenant on détermine les dimensions max et min qui contiennent tous les noeuds
Tableau <Vecteur> ta_d = Taille_boiteMail();
Tableau <int> nbboite(dim); int nb_totale=1;
// on va calculer les paramètres de stockage et de calculs
Coordonnee pas_en_espace(dim); // les pas d'espace dans les différentes directions
for (int i=1;i<=dim;i++)
{double distance = ta_d(2)(i)-ta_d(1)(i);
// en générale le rayon est très petit, donc on va considérer des arêtes de boites > 5 * rayons
int nb_mini = (int)(distance / (rayon*5.));
// si nb_mini est négatif cela veut dire que l'on a dépasser la précision et que
// le nombre est trop grand on le met également à 1
if ((nb_mini == 0)
|| (nb_mini < 0)
)
nb_mini=1; // au minimum on doit avoir 1
nbboite(i) = MiN(nb_mini,nb_decoupe); // on stocke le nombre de boite dans la direction i
pas_en_espace(i) = distance / nbboite(i) + ConstMath::petit; // on stocke le pas d'espace dans la direction i
// on a ajouté un chouil pour être sur que le point le plus grand soit calculé dans les boites existantes
nb_totale *= nbboite(i); // on stocke le nombre maxi de boite
};
if (ParaGlob::NiveauImpression() >= 5)
{cout <<"\n nbboite(i)= ";for (int i=1;i<=dim;i++) cout << nbboite(i);
cout <<endl;}
// on définit des boites = listes de noeuds, qui vont nous permettre ensuite de trier rapidemment
// tout d'abord chaque noeud est associé à une boite = un élément de tab_Boite
Tableau <list <int> > tab_Boite(nb_totale); // dimensionnement des listes de noeuds principale
// pour chaque noeud de la liste , il faudra considérer tous les noeuds des boites qui l'entourent
// on comparera ce noeud avec ceux des 3 ou 9 ou 27 boites (suivant la dimension) qui entourent la boite du noeud
// étant donné que la taille de la boite est au moins plus grande que le rayon de recherche, normalement c'est ok
Tableau <list <int> > tab_BS(NBN); // les listes des numéros de boites qui seront associées à la recherche
// défini le décalage que l'on doit avoir pour le calcul des indices
Coordonnee M_ref(dim);
switch (dim)
{case 3: M_ref(3) = ta_d(1)(3);
case 2: M_ref(2) = ta_d(1)(2);
case 1: M_ref(1) = ta_d(1)(1);
};
// maintenant on va remplir les boites = listes de noeuds
for (int iN=1;iN<=NBN;iN++)
{ Noeud& no = *(tab_noeud(iN)); // pour simplifier
const Coordonnee& M0 =no.Coord0();
int indica=0; // indice de la boite
// soit i j k les indices suivants x y et z, et N1 N2 N3 les maxis de stockage suivants x y z
// le noeud est stocké dans (k-1)*N1*N2 + (j-1)*N1 + i
// - calcul de l'indice de stockage
int nb1,nb2,nb3; // les indices suivant x y z
switch (dim)
{case 3:
{nb3= ((int) ((M0(3)-M_ref(3))/pas_en_espace(3))); // le numéro -1, suivant 3
indica += nb3 * nbboite(3) * nbboite(2);
}
case 2:
{nb2= ((int) ((M0(2)-M_ref(2))/pas_en_espace(2))); // le numéro -1, suivant 2
indica += nb2 * nbboite(2);
}
case 1:
{nb1= ((int) ((M0(1)-M_ref(1))/pas_en_espace(1))); // le numéro -1, suivant 1
indica += nb1 + 1 ;
}
};
//debug
// if ((nb1 > nbboite(1)) || (nb2 > nbboite(2)) || (nb3 > nbboite(3)))
// cout << "\n nb1= "<<nb1 <<" nb2= "<<nb2 <<" nb3= "<<nb3 << endl;
//fin debug
// stockage du noeud dans la bonne boite
tab_Boite(indica).push_back(no.Num_noeud());
// def des boites qui seront associées à la recherche
list <int>& li_BS = tab_BS(no.Num_noeud()); // pour simplifier
li_BS.push_back(indica); // la boite centrale
//if (indica > nb_totale)
// cout <<"\n indica="<<indica << endl;
switch (dim)
{case 3:
{// d'abord les 8 boites du centre en plus du centre centre centre déjà entrée
int nb3_12 = nb3 * nbboite(3) * nbboite(2);
if(nb1+1 < nbboite(1)){li_BS.push_back(nb3_12+ nb2 * nbboite(2)+nb1+2);
//if (nb3_12+ nb2 * nbboite(2)+nb1+2 > nb_totale)
// cout <<"\n nb3_12+ nb2 * nbboite(2)+nb1+2="<<nb3_12+ nb2 * nbboite(2)+nb1+2<< endl;
};
if(nb1 > 0) {li_BS.push_back(nb3_12+ nb2 * nbboite(2)+nb1);
//if (nb3_12+ nb2 * nbboite(2)+nb1 > nb_totale)
// cout <<"\n nb3_12+ nb2 * nbboite(2)+nb1="<<nb3_12+ nb2 * nbboite(2)+nb1<< endl;
};
if(nb2+1 < nbboite(2))
{li_BS.push_back(nb3_12+(nb2+1) * nbboite(2)+nb1+1);
//if (nb3_12+(nb2+1) * nbboite(2)+nb1+1 > nb_totale)
// cout <<"\n nb3_12+(nb2+1) * nbboite(2)+nb1+1="<<nb3_12+(nb2+1) * nbboite(2)+nb1+1<< endl;
if(nb1+1 < nbboite(1)){li_BS.push_back(nb3_12+(nb2+1) * nbboite(2)+nb1+2);
//if (nb3_12+(nb2+1) * nbboite(2)+nb1+2 > nb_totale)
// cout <<"\n nb3_12+(nb2+1) * nbboite(2)+nb1+2="<<nb3_12+(nb2+1) * nbboite(2)+nb1+2<< endl;
};
if(nb1 > 0) {li_BS.push_back(nb3_12+(nb2+1) * nbboite(2)+nb1);
//if (nb3_12+(nb2+1) * nbboite(2)+nb1 > nb_totale)
// cout <<"\n nb3_12+(nb2+1) * nbboite(2)+nb1="<<nb3_12+(nb2+1) * nbboite(2)+nb1<< endl;
};
};
if(nb2 > 0)
{li_BS.push_back(nb3_12+(nb2-1) * nbboite(2)+nb1+1);
//if (nb3_12+(nb2-1) * nbboite(2)+nb1+1 > nb_totale)
// cout <<"\n nb3_12+(nb2-1) * nbboite(2)+nb1+1="<<nb3_12+(nb2-1) * nbboite(2)+nb1+1<< endl;
if(nb1+1 < nbboite(1)){li_BS.push_back(nb3_12+(nb2-1) * nbboite(2)+nb1+2);
//if (nb3_12+(nb2-1) * nbboite(2)+nb1+2 > nb_totale)
// cout <<"\n nb3_12+(nb2-1) * nbboite(2)+nb1+2="<<nb3_12+(nb2-1) * nbboite(2)+nb1+2<< endl;
};
if(nb1 > 0) {li_BS.push_back(nb3_12+(nb2-1) * nbboite(2)+nb1);
//if (nb3_12+(nb2-1) * nbboite(2)+nb1 > nb_totale)
// cout <<"\n nb3_12+(nb2-1) * nbboite(2)+nb1="<<nb3_12+(nb2-1) * nbboite(2)+nb1<< endl;
};
};
// les 9 au dessus dans la direction z
if(nb3+1 < nbboite(3))
{int nb3_p1_12=(nb3+1) * nbboite(3) * nbboite(2);
li_BS.push_back(nb3_p1_12+nb2 * nbboite(2)+nb1+1);
//if (nb3_p1_12+nb2 * nbboite(2)+nb1+1 > nb_totale)
// cout <<"\n nb3_p1_12+nb2 * nbboite(2)+nb1+1="<<nb3_p1_12+nb2 * nbboite(2)+nb1+1
// <<" nb3="<<nb3<<" nb2="<<nb2<<" nb1="<<nb1 << endl;
if(nb1+1 < nbboite(1)){li_BS.push_back(nb3_p1_12+ nb2 * nbboite(2)+nb1+2);
//if (nb3_p1_12+ nb2 * nbboite(2)+nb1+2 > nb_totale)
// cout <<"\n nb3_p1_12+ nb2 * nbboite(2)+nb1+2="<<nb3_p1_12+ nb2 * nbboite(2)+nb1+2
// <<" nb3="<<nb3<<" nb2="<<nb2<<" nb1="<<nb1 << endl;
};
if(nb1 > 0) {li_BS.push_back(nb3_p1_12+ nb2 * nbboite(2)+nb1);
//if (nb3_p1_12+ nb2 * nbboite(2)+nb1 > nb_totale)
// cout <<"\n nb3_p1_12+ nb2 * nbboite(2)+nb1="<<nb3_p1_12+ nb2 * nbboite(2)+nb1
// <<" nb3="<<nb3<<" nb2="<<nb2<<" nb1="<<nb1 << endl;
};
if(nb2+1 < nbboite(2))
{li_BS.push_back(nb3_p1_12+(nb2+1) * nbboite(2)+nb1+1);
//if (nb3_p1_12+(nb2+1) * nbboite(2)+nb1+1 > nb_totale)
// cout <<"\n nb3_p1_12+(nb2+1) * nbboite(2)+nb1+1="<<nb3_p1_12+(nb2+1) * nbboite(2)+nb1+1
// <<" nb3="<<nb3<<" nb2="<<nb2<<" nb1="<<nb1 << endl;
if(nb1+1 < nbboite(1)){li_BS.push_back(nb3_p1_12+(nb2+1) * nbboite(2)+nb1+2);
//if (nb3_p1_12+(nb2+1) * nbboite(2)+nb1+2 > nb_totale)
// cout <<"\n nb3_p1_12+(nb2+1) * nbboite(2)+nb1+2="<<nb3_p1_12+(nb2+1) * nbboite(2)+nb1+2
// <<" nb3="<<nb3<<" nb2="<<nb2<<" nb1="<<nb1 << endl;
};
if(nb1 > 0) {li_BS.push_back(nb3_p1_12+(nb2+1) * nbboite(2)+nb1);
//if (nb3_p1_12+(nb2+1) * nbboite(2)+nb1 > nb_totale)
// cout <<"\n nb3_p1_12+(nb2+1) * nbboite(2)+nb1="<<nb3_p1_12+(nb2+1) * nbboite(2)+nb1
// <<" nb3="<<nb3<<" nb2="<<nb2<<" nb1="<<nb1 << endl;
};
};
if(nb2 > 0)
{li_BS.push_back(nb3_p1_12+(nb2-1) * nbboite(2)+nb1+1);
//if (nb3_p1_12+(nb2-1) * nbboite(2)+nb1+1 > nb_totale)
// cout <<"\n nb3_p1_12+(nb2-1) * nbboite(2)+nb1+1="<<nb3_p1_12+(nb2-1) * nbboite(2)+nb1+1
// <<" nb3="<<nb3<<" nb2="<<nb2<<" nb1="<<nb1 << endl;
if(nb1+1 < nbboite(1)){li_BS.push_back(nb3_p1_12+(nb2-1) * nbboite(2)+nb1+2);
//if (nb3_p1_12+(nb2-1) * nbboite(2)+nb1+2 > nb_totale)
// cout <<"\n nb3_p1_12+(nb2-1) * nbboite(2)+nb1+2="<<nb3_p1_12+(nb2-1) * nbboite(2)+nb1+2
// <<" nb3="<<nb3<<" nb2="<<nb2<<" nb1="<<nb1 << endl;
};
if(nb1 > 0) {li_BS.push_back(nb3_p1_12+(nb2-1) * nbboite(2)+nb1);
//if (nb3_p1_12+(nb2-1) * nbboite(2)+nb1 > nb_totale)
// cout <<"\n nb3_p1_12+(nb2-1) * nbboite(2)+nb1="<<nb3_p1_12+(nb2-1) * nbboite(2)+nb1
// <<" nb3="<<nb3<<" nb2="<<nb2<<" nb1="<<nb1 << endl;
};
};
};
// les 9 au dessus dans la direction z
if(nb3 > 0)
{int nb3_m1_12=(nb3-1) * nbboite(3) * nbboite(2);
li_BS.push_back(nb3_m1_12+nb2 * nbboite(2)+nb1+1);
//if (nb3_m1_12+nb2 * nbboite(2)+nb1+1 > nb_totale)
// cout <<"\n nb3_m1_12+nb2 * nbboite(2)+nb1+1="<<nb3_m1_12+nb2 * nbboite(2)+nb1+1
// <<" nb3="<<nb3<<" nb2="<<nb2<<" nb1="<<nb1 << endl;
if(nb1+1 < nbboite(1)){li_BS.push_back(nb3_m1_12+ nb2 * nbboite(2)+nb1+2);
//if (nb3_m1_12+ nb2 * nbboite(2)+nb1+2 > nb_totale)
// cout <<"\n nb3_m1_12+ nb2 * nbboite(2)+nb1+2="<<nb3_m1_12+ nb2 * nbboite(2)+nb1+2
// <<" nb3="<<nb3<<" nb2="<<nb2<<" nb1="<<nb1 << endl;
};
if(nb1 > 0) {li_BS.push_back(nb3_m1_12+ nb2 * nbboite(2)+nb1);
//if (nb3_m1_12+ nb2 * nbboite(2)+nb1 > nb_totale)
// cout <<"\n nb3_m1_12+ nb2 * nbboite(2)+nb1="<<nb3_m1_12+ nb2 * nbboite(2)+nb1
// <<" nb3="<<nb3<<" nb2="<<nb2<<" nb1="<<nb1 << endl;
};
if(nb2+1 < nbboite(2))
{li_BS.push_back(nb3_m1_12+(nb2+1) * nbboite(2)+nb1+1);
//if (nb3_m1_12+(nb2+1) * nbboite(2)+nb1+1 > nb_totale)
// cout <<"\n nb3_m1_12+(nb2+1) * nbboite(2)+nb1+1="<<nb3_m1_12+(nb2+1) * nbboite(2)+nb1+1
// <<" nb3="<<nb3<<" nb2="<<nb2<<" nb1="<<nb1 << endl;
if(nb1+1 < nbboite(1)){li_BS.push_back(nb3_m1_12+(nb2+1) * nbboite(2)+nb1+2);
//if (nb3_m1_12+(nb2+1) * nbboite(2)+nb1+2 > nb_totale)
// cout <<"\n nb3_m1_12+(nb2+1) * nbboite(2)+nb1+2="<<nb3_m1_12+(nb2+1) * nbboite(2)+nb1+2
// <<" nb3="<<nb3<<" nb2="<<nb2<<" nb1="<<nb1 << endl;
};
if(nb1 > 0) {li_BS.push_back(nb3_m1_12+(nb2+1) * nbboite(2)+nb1);
//if (nb3_m1_12+(nb2+1) * nbboite(2)+nb1 > nb_totale)
// cout <<"\n nb3_m1_12+(nb2+1) * nbboite(2)+nb1="<<nb3_m1_12+(nb2+1) * nbboite(2)+nb1
// <<" nb3="<<nb3<<" nb2="<<nb2<<" nb1="<<nb1 << endl;
};
};
if(nb2 > 0)
{li_BS.push_back(nb3_m1_12+(nb2-1) * nbboite(2)+nb1+1);
//if (nb3_m1_12+(nb2-1) * nbboite(2)+nb1+1 > nb_totale)
// cout <<"\n nb3_m1_12+(nb2-1) * nbboite(2)+nb1+1="<<nb3_m1_12+(nb2-1) * nbboite(2)+nb1+1
// <<" nb3="<<nb3<<" nb2="<<nb2<<" nb1="<<nb1 << endl;
if(nb1+1 < nbboite(1)){li_BS.push_back(nb3_m1_12+(nb2-1) * nbboite(2)+nb1+2);
//if (nb3_m1_12+(nb2-1) * nbboite(2)+nb1+2 > nb_totale)
// cout <<"\n nb3_m1_12+(nb2-1) * nbboite(2)+nb1+2="<<nb3_m1_12+(nb2-1) * nbboite(2)+nb1+2
// <<" nb3="<<nb3<<" nb2="<<nb2<<" nb1="<<nb1 << endl;
};
if(nb1 > 0) {li_BS.push_back(nb3_m1_12+(nb2-1) * nbboite(2)+nb1);
//if (nb3_m1_12+(nb2-1) * nbboite(2)+nb1 > nb_totale)
// cout <<"\n nb3_m1_12+(nb2-1) * nbboite(2)+nb1="<<nb3_m1_12+(nb2-1) * nbboite(2)+nb1
// <<" nb3="<<nb3<<" nb2="<<nb2<<" nb1="<<nb1 << endl;
};
};
};
break;
}
case 2: // cas 2D, on a 9 boites à considérer, sauf si l'on est dans les extrèmes
{if(nb1+1 < nbboite(1)){li_BS.push_back((nb2) * nbboite(2)+nb1+2);};
if(nb1 > 0) {li_BS.push_back((nb2) * nbboite(2)+nb1);};
if(nb2+1 < nbboite(2))
{li_BS.push_back((nb2+1) * nbboite(2)+nb1+1);
if(nb1+1 < nbboite(1)){li_BS.push_back((nb2+1) * nbboite(2)+nb1+2);};
if(nb1 > 0) {li_BS.push_back((nb2+1) * nbboite(2)+nb1);};
};
if(nb2 > 0)
{li_BS.push_back((nb2-1) * nbboite(2)+nb1+1);
if(nb1+1 < nbboite(1)){li_BS.push_back((nb2-1) * nbboite(2)+nb1+2);};
if(nb1 > 0) {li_BS.push_back((nb2-1) * nbboite(2)+nb1);};
};
break;
}
case 1: // cas 1D, on a 3 boites à considérer, sauf si l'on est dans les extrèmes
{if(nb1+1 < nbboite(1)) {li_BS.push_back(indica+1);};
if(nb1 > 0) {li_BS.push_back(indica-1);};
}
break;
};
};
// on effectue maintenant la fusion des noeuds en s'aidant des boites pour diminuer la recherche
Tableau <int> a_fusionner(NBN,0); // tableau d'indicateurs de noeuds a fusionner
for (int ib = 1; ib<=nb_totale;ib++)
{// on parcours les boites: ib: le numéro de la boite courante
list <int>::iterator il,ilfin=tab_Boite(ib).end();
for (il=tab_Boite(ib).begin();il != ilfin; il++)
{// on parcours tous les noeuds le la boite: (*il) est le numéro du noeud courant
// on ne continue que si le noeud n'a pas été déclaré fusionable par ailleurs
if (!a_fusionner(*il))
{list <int>::iterator im,imfin=tab_BS((*il)).end(); // tab_BS = une liste de numéro de boite
for (im = tab_BS((*il)).begin();im != imfin; im++) // *im c'est un numéro de boite
{
if ((*im)>nb_totale) cout << " *il="<<(*il)<<" *im="<<(*im)<<endl;//" tab_BS.size()="<<tab_BS(*il).size();
list <int>::iterator ip,ipfin=tab_Boite(*im).end(); // *ip sera un numéro de noeud
for (ip = tab_Boite(*im).begin();ip != ipfin; ip++)
// on parcours tous les noeuds à considérer
if ((!(a_fusionner(*ip)))&&((*il)!=(*ip))) // on examine que si le noeud ne sera fusionné
if ((tab_noeud(*il)->Coord0()-tab_noeud(*ip)->Coord0()).Norme() < rayon)
{ a_fusionner(*ip)=*il; // on enregistre
if (ParaGlob::NiveauImpression()>3)
cout << "\n detail du processus de collapse de noeud proche Maillage::Collapse_noeuds_proches( "
<< "\n rayon= " << rayon << " noe_afusionner ip: " << (*ip)
<< " noeud identique il: " << *il
<< "\n coor ip: " << tab_noeud(*ip)->Coord0()
<< "\n coor il: " << tab_noeud(*il)->Coord0() << endl;
};
};
};
};
};
// création pour chaque noeud de la liste des éléments qui contiennent le noeud
Calcul_indice();
// on passe en revue les noeuds et on regarde si la fusion est possible
// elle est impossible si deux noeuds a fusionner appartiennent à un même élément
// dans ce cas on désactive l'indicateur de fusion
for (int ine=1;ine<=NBN;ine++)
{if (a_fusionner(ine)) // s'il est différent de 0, indique que ine peut-être fusionné
{// on regarde si les deux noeuds : ine et a_fusionner(ine) n'appartiennent pas à un même élément
List_io < Element*>& indic = indice(ine); // pour simplifier
List_io < Element*>::iterator ie,iefin=indic.end();
bool fusion_non_possible = false; // init par défaut
int num_maitre = a_fusionner(ine);
for (ie=indic.begin();ie!=iefin;ie++)
{ Element& ele = *(*ie); // récup d'un élément qui contient a priori le numéro ine
Tableau<Noeud *>& tn = ele.Tab_noeud(); // récup des noeuds de l'élément
// maintenant on regarde si l'élément contient également le a_fusionner(ine)
int taille_tn=tn.Taille();
for (int j=1;j<=taille_tn;j++)
if (tn(j)->Num_noeud() == num_maitre)
{fusion_non_possible=true;
break;// on sort de la première boucle sur les noeuds de l'élément
};
if (fusion_non_possible)
break; // on sort de la seconde boucle sur les éléments contenant le noeud
};
//
if (fusion_non_possible) // cas où la fusion n'est pas possible
{a_fusionner(ine)=0;};
};
};
// on sauvegarde les anciens numéros de noeuds, servira pour contruire nv_num
// normalement c'est directement iN mais on ne sait jamais
Tableau <int> ancien_num_Noe(NBN);
for (int iN=1;iN<=NBN;iN++)
ancien_num_Noe(iN) = tab_noeud(iN)->Num_noeud();
// -- maintenant on va vraiment fusionner et mettre à jour les références
// 1- tout d'abord on s'intéresse aux éléments, dont on va mettre à jour les références
// 2- on supprime les noeuds qui ne servent plus
int nb_noeud_restant = NBN; // init du nombre de noeud restant après fusion
Tableau <bool> non_referencer(NBN,false); // un tableau intermédiaire qui servira pour les ref
for (int ine=1;ine<=NBN;ine++)
{if (a_fusionner(ine)) // s'il est différent de 0, on doit fusionner
{ int num_ne = a_fusionner(ine);
//cout << "\n ine= "<<ine<<" num_ne="<<num_ne<<endl;
// on va balayer uniquement les éléments qui contiennent le noeud a fusionner
List_io < Element*>& indic = indice(ine); // pour simplifier
List_io < Element*>::iterator ie,iefin=indic.end();
for (ie=indic.begin();ie!=iefin;ie++)
{ Element& ele = *(*ie); // récup de l'élément qui contient ine
Tableau<Noeud *>& tn = ele.Tab_noeud(); // récup des noeuds de l'élément
int taille_tn=tn.Taille();
for (int j=1;j<=taille_tn;j++)
if (tn(j)->Num_noeud() == ine)
{ele.Change_noeud(j,tab_noeud(num_ne)); // on change la connexion
if (tab_noeud(num_ne) == NULL)
cout << "\n*** le noeud num_ne=" <<num_ne << " est nulle !" << endl;
};
};
// on reporte le tableau de ddl de l'élément à supprimer sur celui qui reste
tab_noeud(num_ne)->PlusTabDdl(*tab_noeud(ine));
// maintenant il n'y a plus d'élément qui utilise le noeud ine donc on le supprime
delete tab_noeud(ine); // on supprime le noeud
tab_noeud(ine)=NULL; // on indique qu'il n'y a plus de noeud
// non_referencer(ine)=true; // servira pour les ref
// *** modif 15 avril 2016: comme il s'agit de noeuds supperposés, cela veut dire qu'il reste un noeud de substitution
// qui lui est valide donc on met false, ce qui veut dire que l'on ne veut pas supprimer le noeud dans la ref
// car sinon la ref devient différente et incomplète
non_referencer(ine)=false; // servira pour les ref
nb_noeud_restant--; // on diminue le nombre de noeuds restants
if (ParaGlob::NiveauImpression() > 2)
cout << "\n collapse node " << ine << " --> "<<num_ne ;
};
};
// maintenant on refait un nouveau tableau de noeud avec les noeuds inutiles supprimés
Tableau <Noeud* > tab_final(nb_noeud_restant);
int nbn_restant=0; // le nombre de noeud restant
cout << "\n ";
for (int ijn = 1; ijn <= NBN; ijn++)
{ if(tab_noeud(ijn)!=NULL)
{nbn_restant++;
tab_final(nbn_restant) = tab_noeud(ijn);
};
};
// // on redimentionne le tableau final (ses premiers restent !!)
// tab_final.Change_taille(nbn_restant);
if (ParaGlob::NiveauImpression() >= 0)
cout << "\n collapse of " << (NBN-nbn_restant) <<" node(s) " << endl;
// on met à jour les références
lesRef->SupprimeReference("N_tout",idmail); // on supprime la référence N_tout
Tableau <int> nv_num(NBN,0); // nouveau num/ au ancien, initialisé à 0
for (int ia=1;ia <= nbn_restant; ia++)
nv_num(tab_final(ia)->Num_noeud()) = ia;
// *** modif 15 avril 2016: il faut tous les numéros de remplacement et pas seulement ceux
// qui restent car dans la mise à jour on commence par changer les numéros et "ensuite"
// on supprime les doublons --> donc on complète
// nv_num(num_ancien) = le nouveau numéro de noeud donc celui qui est en coincidence et qui reste
// a_fusionner(ancien_num_Noe(ia)) -> le nouveau numéro dans l'ancien tableau
// qui aura comme nouveau numéro:nv_num(a_fusionner(ancien_num_Noe(ia)))
for (int ia=1;ia <= NBN; ia++)
if (nv_num(ia) == 0) // cela veut dire que c'est un numéro qui disparait
nv_num(ia) = nv_num(a_fusionner(ancien_num_Noe(ia)));
lesRef->Mise_a_jour_ref_noeud(nv_num,idmail,non_referencer);
// on enregistre le nouveau tableau de noeuds
tab_noeud = tab_final;
// on met à jour les numéros de noeuds
for (int ia=1;ia <= nbn_restant; ia++)
tab_noeud(ia)->Change_num_noeud(ia);
// on recrée la référence N_tout
string ntout("N_tout");
{ // on construit le tableau des numéros de noeuds
Tableau <int> tabN(nbn_restant); for (int i=1;i<=nbn_restant;i++) tabN(i)=i;
ReferenceNE* rtout = new ReferenceNE(tabN,idmail,1,ntout);// construction de la référence
lesRef->Ajout_reference(rtout); // ajout de la ref, qui est maintenant géré par lesRef
};
};
// Lecture et suppression d'elements à 2 noeuds, de distances très proches
void Maillage::LectureEtSup_Elem_noeudsConfondu(UtilLecture * entreePrinc, LesReferences* lesRef)
{ if (strstr(entreePrinc->tablcar,"suppression_elements_2noeuds_tres_proches_")!=NULL)
{ if (ParaGlob::NiveauImpression() > 2) cout << "\n beginning of the process to collapse element with two nodes which are "
<< " nearly at the same position "<< endl ;
// on lit la distance mini
double rayon = 0;string nom;
*(entreePrinc->entree) >> nom >> rayon;
if (nom != "suppression_elements_2noeuds_tres_proches_")
{ cout << "\n error : we expected the keyword: suppression_elements_2noeuds_tres_proches_ but we read \""<<nom<<"\" ";
if (ParaGlob::NiveauImpression() >= 6)
cout << "\n Maillage::LectureEtSup_Elem_noeudsConfondu(...";
Sortie(1);
};
if (ParaGlob::NiveauImpression() >= 5)
cout << "\n minimum distance = " << rayon;
entreePrinc->NouvelleDonnee(); // on passe le mot clé
// appel de l'algo de suppression
Sup_Elem_noeudsConfondu(rayon,lesRef);
if (ParaGlob::NiveauImpression() > 2) cout << "\n end of the process to collapse element with two nodes which are "
<< " nearly at the same position "<< endl ;
};
};
// suppression d'elements à 2 noeuds, de distances très proches
// rayon : donne la distance maxi entre les noeuds
void Maillage::Sup_Elem_noeudsConfondu(double rayon, LesReferences* lesRef)
{ // on crée un tableau d'indicateur des éléments à supprimer
int nbelem = tab_element.Taille();
Tableau <int> elem_supprime(nbelem,0);
// on calcul les frontières et les mitoyens de tous les éléments
Calcul_tous_les_front_et_leurs_mitoyens();
// on balaie les éléments
for (int ine = 1;ine <= nbelem;ine++)
// on ne continue que si c'est un élément qui n'a pas déjà été marqué " à supprimé "
if (elem_supprime(ine) == 0)
{Element * elem = tab_element(ine);
// on ne continue que si c'est un éléments à 2 noeuds
if (elem->Nombre_noeud() == 2)
{ // on récupère les deux noeuds
Noeud * noe1 = tab_element(ine)->Tab_noeud()(1);
Noeud * noe2 = tab_element(ine)->Tab_noeud()(2);
// on calcule la distance entre les deux noeuds
if ((noe1->Coord0()-noe2->Coord0()).Norme() < rayon)
elem_supprime(ine)=1; // on enregistre la suppression
}
else if (elem->Nombre_noeud() == 3)
{ // un élément à 3 noeuds peut également être supprimable, mais
// pour l'instant il faut qu'il ne soit relié qu'à des éléments également à 3 ou 2 noeuds
// .. on itère sur les cotés tout d'abord pour s'assurer que les mitoyens ont au plus 3 ou 2
// noeuds: car si on a un mitoyen à 4 noeuds par exemple, il faut le convertir en
// un élément à 3 noeud, c'est possible mais pas directement dans la version actuelle
bool continou = true; // init
// pour chaque élément "i" , mitoyen_de_chaque_element(i)(j) contient l'élément Front
// qui décrit la frontière "j" de l'élément et dedans, les éléments mitoyens de cette frontière
// appartenant à d'autres éléments
for (int i=0;i<3;i++)
{Front& fron = mitoyen_de_chaque_element(ine)(i+1);
const Tableau <Front*>* t_mitoy = fron.TabMitoyen();
if (t_mitoy != NULL)
{int taille = t_mitoy->Taille();
for (int j=1;j<= taille; j++)
{ if( (*t_mitoy)(j)->PtEI()->Nombre_noeud()>3)
{continou = false; break;}; // pas bon on arrête
};
}
if (!continou) break; // arrêt car mitoyen avec plus de 3 noeuds
};
// Maintenant on regarde la distance entre les noeuds de chaque frontière
// pour l'instant ne fonctionne que pour des frontières à 2 noeuds
if (continou)
for (int i=0;i<3;i++)
{ Front& fron = mitoyen_de_chaque_element(ine)(i+1);
// on ne continue que s'il s'agit d'un élément frontière à 2 noeuds
const Tableau <Noeud *>& tlocNoe = fron.Eleme()->TabNoeud();
if (tlocNoe.Taille() == 2)
{ // on récupère les deux noeuds de l'arête
Noeud * noe1 = tlocNoe(1);
Noeud * noe2 = tlocNoe(2);
// on calcule la distance entre les deux noeuds
if ((noe1->Coord0()-noe2->Coord0()).Norme() < rayon)
{elem_supprime(ine)=1; // on enregistre la suppression
// on doit également suppimer les éléments mitoyens
const Tableau <Front*>* t_mitoy = fron.TabMitoyen();
if (t_mitoy != NULL)
{ int tail = t_mitoy->Taille();
for (int a=1;a<=tail;a++)
{Front* fr = (*t_mitoy)(a);
elem_supprime(fr->PtEI()->Num_elt())=1;
};
};
};
};
};
};
};
// -- maintenant on va vraiment supprimer les éléments et mettre à jour les références
// 1- tout d'abord on s'intéresse aux éléments, dont on va mettre à jour les références
// 2- on supprime les éléments qui ne servent plus
int nb_elem_restant = nbelem; // init du nombre d'élément restant après suppression
Tableau <bool> non_referencer(nbelem,false); // un tableau intermédiaire qui servira pour les ref
for (int ine=1;ine<=nbelem;ine++)
{if (elem_supprime(ine)) // s'il est différent de 0, on doit supprimer
{ //int num_nelem = elem_supprime(ine); // ne sert à rien ici, j'ai repris l'algo Collapse_noeuds_proches
delete tab_element(ine); // on supprime l'élément
tab_element(ine)=NULL; // on indique qu'il n'y a plus d'élément
non_referencer(ine)=true; // servira pour les ref
nb_elem_restant--; // on diminue le nombre d'éléments restants
if (ParaGlob::NiveauImpression() > 2)
cout << "\n delete element " << ine << " <-- " ;
};
};
// maintenant on refait un nouveau tableau d'éléments avec les éléments inutiles supprimés
Tableau <Element* > tab_final(nb_elem_restant);
int nbelem_restant=0; // le nombre d'éléments restant
cout << "\n ";
for (int ijn = 1; ijn <= nbelem; ijn++)
{ if(tab_element(ijn)!=NULL)
{nbelem_restant++;
tab_final(nbelem_restant) = tab_element(ijn);
};
};
// // on redimentionne le tableau final (ses premières entitées restent !!)
// tab_final.Change_taille(nbn_restant);
if (ParaGlob::NiveauImpression() >= 0)
cout << "\n delete of " << (nbelem-nbelem_restant) <<" element(s) " << endl;
// on met à jour les références
lesRef->SupprimeReference("E_tout",idmail); // on supprime la référence E_tout
Tableau <int> nv_num(nbelem,0); // nouveau num/ au ancien
for (int ia=1;ia <= nbelem_restant; ia++)
nv_num(tab_final(ia)->Num_elt()) = ia;
lesRef->Mise_a_jour_ref_element(nv_num,idmail,non_referencer);
// on enregistre le nouveau tableau d'éléments
tab_element = tab_final;
// on met à jour les numéros d'éléments
for (int ia=1;ia <= nbelem_restant; ia++)
tab_element(ia)->Change_num_elt(ia);
// on recrée la référence E_tout
string Etout("E_tout");
{ // on construit le tableau des numéros de noeuds
Tableau <int> tabE(nbelem_restant); for (int i=1;i<=nbelem_restant;i++) tabE(i)=i;
ReferenceNE* rtout = new ReferenceNE(tabE,idmail,2,Etout);// construction de la référence
lesRef->Ajout_reference(rtout); // ajout de la ref, qui est maintenant géré par lesRef
};
};
// création d'éléments SFE en fonction d'éléments classiques
void Maillage::CreationMaillageSFE()
{ // une première étape est de vérifier que tous les éléments sont des triangles, sinon
// arrêt et message d'incompétance
if (!OKPourTransSfe())
{ cout << "\n error*** the mesh " << idmail << " ( " << nomDuMaillage << " ) "
<< " does not contain only triangular elements, currently "
<< " the continuation of the processing is not possible ! --> stop ";
return;
};
// sinon c'est ok, on n'a que des éléments triangulaires
// -- on demande le choix d'éléments
bool bonne_lecture=false;Enum_interpol enuSfe=SFE1;
while (!bonne_lecture)
{ cout << "\n give the type of SFE element you want: "
<< "\n SFE1 (resp 1) SFE1_3D (resp 11) "
<< "\n SFE2 (resp 2) SFE2_3D (resp 12) "
<< "\n SFE3 (resp 3) SFE3_3D (resp 13) "
<< "\n SFE3C (resp 4) SFE3C_3D (resp 14) "
<< "\n QSFE1 (resp 5) QSFE3 (resp 6) ";
string rep; rep = lect_chaine();
if (rep == "1") {enuSfe = SFE1; bonne_lecture=true;}
else if (rep == "2") {enuSfe = SFE2; bonne_lecture=true;}
else if (rep == "3") {enuSfe = SFE3; bonne_lecture=true;}
else if (rep == "4") {enuSfe = SFE3C; bonne_lecture=true;}
else if (rep == "5") {enuSfe = QSFE1; bonne_lecture=true;}
else if (rep == "6") {enuSfe = QSFE3; bonne_lecture=true;}
else if (rep == "11") {enuSfe = SFE1_3D; bonne_lecture=true;}
else if (rep == "12") {enuSfe = SFE2_3D; bonne_lecture=true;}
else if (rep == "13") {enuSfe = SFE3_3D; bonne_lecture=true;}
else if (rep == "14") {enuSfe = SFE3C_3D; bonne_lecture=true;}
else { cout << "\n bad answer, we have read : " << rep << "! try again ";};
};
cout << "\n choice read : " << Nom_interpol(enuSfe);
// On va créer des éléments en plus que ceux qui existent déjà, puis on supprimera ceux qui
// existent, et on les remplacera par ceux que l'on vient de créer
int tabelTaille = tab_element.Taille();
Tableau< Tableau <Noeud *> > t_noe_ele(tabelTaille); // les noeuds des SFE
// on commence par remplir t_noe_ele en considérant qu'il n'y a pas de mitoyen
int nbe_C = 3; // init: nb de noeud centraux
if ((enuSfe == QSFE3) || (enuSfe == QSFE1))
nbe_C = 6; // interpolation quadratique au centre
for (int i4 = 1; i4 <= tabelTaille; i4++)
{ Tableau <Noeud *>& t_noe = t_noe_ele(i4); // pour simplifier
Element * elem = tab_element(i4); // recup de l'element
t_noe.Change_taille(nbe_C+3); // nbe_C+3 noeuds pour les sfe triangles
// les noeuds du centre
for (int i=1;i<= nbe_C;i++)
t_noe(i) = &(elem->Noeud_elt(i));
// les noeuds externes initialisés aux noeuds centraux des sommets
t_noe(nbe_C+1) = &(elem->Noeud_elt(1));
t_noe(nbe_C+2) = &(elem->Noeud_elt(2));
t_noe(nbe_C+3) = &(elem->Noeud_elt(3));
// t_noe(1) = t_noe(4) = &(elem->Noeud_elt(1));
// t_noe(2) = t_noe(5) = &(elem->Noeud_elt(2));
// t_noe(3) = t_noe(6) = &(elem->Noeud_elt(3));
};
// I-- on définit les noeuds externe de chaque triangles
// I.1- on crée des tableaux permettant d'accélérer l'algorithme final
// pour chaque noeud on regarde quel élément contiend ce noeud
int tab_noeud_taille= tab_noeud.Taille();
Tableau <List_io <Element*> > indice(tab_noeud_taille);
// indice contiend les éléments succeptibles d'avoir des arrêtes communes
// on en profite également pour calculer les normales à chaque élément
Tableau <Coordonnee > tab_Nor(tabelTaille);
for (int i22 = 1; i22 <= tabelTaille; i22++)
{ Element * elem1 = tab_element(i22); // recup de l'element
Tableau<Noeud *>& tabn = elem1->Tab_noeud(); // récup de son tableau de noeud
// int tabntaille = tabn.Taille();
int tabntaille = 3; // on n'utilise que les noeuds sommets !! : 1 mars 2021
for (int ij=1;ij<= tabntaille;ij++)
indice((tabn(ij)->Num_noeud())).push_back(elem1); // on balaie ses noeuds
// calcul de la normale
Coordonnee A=tabn(1)->Coord0();Coordonnee B=tabn(2)->Coord0();
Coordonnee C=tabn(3)->Coord0();
Coordonnee AB(B-A); Coordonnee AC(C-A);
tab_Nor(i22)=Util::ProdVec_coor(AB,AC);tab_Nor(i22).Normer();
};
// I.2 - un tableau intermédiaire t_i(i) , d'indiçage local
// l'indice i = le numéro du premier noeud de l'arrête, et t_i(i) = le num du noeud externe
Tableau <int > t_i(3);
t_i(1)=6; t_i(2)=4; t_i(3)=5; // init éléments SFE lineaires
if ((enuSfe == QSFE3) || (enuSfe == QSFE1))
{t_i(1)=9; t_i(2)=7; t_i(3)=8; }// interpolation quadratique au centre
// également un tableau pour noter les éléments dont la courbure est supérieure à un maxi
// c'est à dire qui ont deux facettes avec un produit scalaire des normales suffisamment grand
// on choisit arbitrairement 30° c-a-d cos(pi/6) = 0.86603
Tableau <int> elem_courb(tabelTaille,0); // par défaut tous sont ok
double limit_inf_prod_scal = 0.86603; // la limite inf -> servira pour les SFE3
// qui sera mesuré par
// I.3- maintenant on va de nouveau boucler sur les éléments en regardant
// pour chaque arrêtes si elle est effectivement commune
for (int i1 = 1; i1 <= tabelTaille; ++i1)
{Element * elem1 = tab_element(i1); // recup de l'element
// Tableau<Noeud *>& tabn = elem1->Tab_noeud(); // récup de son tableau de noeuds
//int nb_noe_elem1 = tabn.Taille();
// on boucle sur les 3 arrêtes
// normalement les 3 premiers noeuds sont les sommets du triangle
for (int ina=1;ina<=3;ina++)
{ int noe1 = elem1->Noeud_elt(ina).Num_noeud();// num du premier noeud de l'arrête
int noe2 = 0; // init pour le second noeud
if (ina == 3) { noe2 = elem1->Noeud_elt(1).Num_noeud();}
else { noe2 = elem1->Noeud_elt(ina+1).Num_noeud();}
List_io <Element*>& indic1 = indice(noe1); // les éléments à considérer pour noe1
List_io <Element*>& indic2 = indice(noe2); // les éléments à considérer pour noe2
// on cherche un élément de l'intersection de indic1 et indic2
// qui doit également être différent de l'élément central
List_io <Element*>::iterator il1,ilfin1=indic1.end();
List_io <Element*>::iterator il2,ilfin2=indic2.end();
list <Element *> candidats; // une liste de travail
for (il1=indic1.begin();il1 != ilfin1;il1++)
for (il2=indic2.begin();il2 != ilfin2;il2++)
if (((*il1) == (*il2)) && ((*il1) != elem1 ))
{ //ele = (*il1); break;
candidats.push_back((*il1));
};
// maintenant parmi tous les candidats on va choisir celui qui conduit à l'élément le plus plat
// NB: on considère que les éléments sont correctement orientés dans le même sens
Element* ele = NULL; // init a priori
if (candidats.size() != 0)
{ list <Element *>::iterator ilfin=candidats.end();
list <Element *>::iterator il=candidats.begin();
ele = (*il); il++; // on stocke a priori le premier élément
double prodscal = tab_Nor(ele->Num_elt()) * tab_Nor(elem1->Num_elt());
// puis on parcours les éléments suivants et on garde celui dont le prodscal est le + grand
for (;il != ilfin;il++)
{ double prod = tab_Nor((*il)->Num_elt()) * tab_Nor(elem1->Num_elt());
if (prod > prodscal)
{prodscal = prod; ele = (*il);};
};
// si le produit scalaire est inférieur à limit_inf_prod_scal, on enregistre
if (prodscal < limit_inf_prod_scal)
elem_courb(elem1->Num_elt()) = 1;
};
// si on a trouvé un candidat
if (ele != NULL)
{// on recherche le noeud qui n'est pas commun avec l'arrête
for (int j=1;j<=3;j++) // on boucle sur les 3 noeuds sommets de l'élément
{int num = ele->Noeud_elt(j).Num_noeud();
if ((num != noe1) && (num != noe2))
{ // on met à jour le tableau des noeuds externes
t_noe_ele(i1)(t_i(ina)) = &(ele->Noeud_elt(j));
break;
};
};
};
// si aucun candidat n'est trouvé, t_noe_ele reste tel_quel
};
};
// II-- on crée les éléments SFE
// bool bonne_lecture=false;Enum_interpol enuSfe=SFE1;
// while (!bonne_lecture)
// { cout << "\n give the type of SFE element you want: "
// << "\n SFE1 (resp 1) SFE1_3D (resp 11) "
// << "\n SFE2 (resp 2) SFE2_3D (resp 12) "
// << "\n SFE3 (resp 3) SFE3_3D (resp 13) "
// << "\n SFE3C (resp 4) SFE3C_3D (resp 14) ";
// string rep; rep = lect_chaine();
// if (rep == "1") {enuSfe = SFE1; bonne_lecture=true;}
// else if (rep == "2") {enuSfe = SFE2; bonne_lecture=true;}
// else if (rep == "3") {enuSfe = SFE3; bonne_lecture=true;}
// else if (rep == "4") {enuSfe = SFE3C; bonne_lecture=true;}
//
// else if (rep == "11") {enuSfe = SFE1_3D; bonne_lecture=true;}
// else if (rep == "12") {enuSfe = SFE2_3D; bonne_lecture=true;}
// else if (rep == "13") {enuSfe = SFE3_3D; bonne_lecture=true;}
// else if (rep == "14") {enuSfe = SFE3C_3D; bonne_lecture=true;}
//
//
// else { cout << "\n bad answer, we have read : " << rep << "! try again ";};
// };
// cout << "\n choice read : " << Nom_interpol(enuSfe);
Element * toto = NULL;
Tableau<Element *> tab_SFE(tabelTaille,toto); // création de pointeurs nuls
// cas d'info annexe
string str_precision(""); // stockage info annexe de choix, initié à rien par défaut
bonne_lecture=false; int num_pti=0; // init
if (enuSfe == SFE3 ) // on a des nombres de pti variables que pour les SFE3
while (!bonne_lecture)
{ cout << "\n give eventually le number of integration point : "
<< "\n 2, 3, 4, 5, 6, 7, 12, 13 : ";
string rep; rep = lect_chaine();
if (rep == "2") {str_precision="";bonne_lecture=true;num_pti=2;}
else if (rep == "3") {str_precision="_cm3pti";bonne_lecture=true;num_pti=3;}
else if (rep == "4") {str_precision="_cm4pti";bonne_lecture=true;num_pti=4;}
else if (rep == "5") {str_precision="_cm5pti";bonne_lecture=true;num_pti=5;}
else if (rep == "6") {str_precision="_cm6pti";bonne_lecture=true;num_pti=6;}
else if (rep == "7") {str_precision="_cm7pti";bonne_lecture=true;num_pti=7;}
else if (rep == "12") {str_precision="_cm12pti";bonne_lecture=true;num_pti=12;}
else if (rep == "13") {str_precision="_cm13pti";bonne_lecture=true;num_pti=13;}
else { cout << "\n bad answer, we have read : " << rep << "! try again ";};
};
if (enuSfe == SFE1 ) // idem pour les SFE1
while (!bonne_lecture)
{ cout << "\n give eventually le number of integration point : "
<< "\n 2, 5 : ";
string rep; rep = lect_chaine();
if (rep == "2") {str_precision="";bonne_lecture=true;num_pti=2;}
else if (rep == "5") {str_precision="_cm5pti";bonne_lecture=true;num_pti=5;}
else { cout << "\n bad answer, we have read : " << rep << "! try again ";};
};
for (int i5 = 1; i5 <= tabelTaille; ++i5)
{ElemMeca * el = ((ElemMeca *) tab_element(i5)); // recup de l'element
Tableau <Noeud *>& t_noe = t_noe_ele(i5); // pour simplifier
Tableau<Noeud *>& tabn = el->Tab_noeud(); // récup de son tableau de noeuds
// coordonnées du centre de gravité
Coordonnee G = (tabn(1)->Coord0()+tabn(2)->Coord0()+tabn(3)->Coord0())/3.;
double epaisseur = el->Epaisseurs(TEMPS_0,G); // épaisseur à G
switch (enuSfe)
{ case SFE1: switch (num_pti)
{ case 2: tab_SFE(i5) = new TriaSfe1(epaisseur,idmail,el->Num_elt(),t_noe); break;
case 5: tab_SFE(i5) = new TriaSfe1_cm5pti(epaisseur,idmail,el->Num_elt(),t_noe);break;
default:
cout << "*** pb, le cas "<<Nom_interpol(enuSfe)
<< " avec " << num_pti << " pti "
<< " n'est pas possible pour l'instant " << endl;
};
break;
case SFE2: tab_SFE(i5) = new TriaSfe2(epaisseur,idmail,el->Num_elt(),t_noe); break;
case SFE3:
// si la courbure de l'élément est trop grande on bascule vers un SFE1
if (elem_courb(i5))
{ if (ParaGlob::NiveauImpression() > 0)
cout << " attention l'element " << Nom_interpol(enuSfe)<< " "<<i5
<< " est remplace par un SFE1 car la courbure est sup a 30° "<< endl;
switch (num_pti)
{ case 2: tab_SFE(i5) = new TriaSfe1(epaisseur,idmail,el->Num_elt(),t_noe); break;
case 5: tab_SFE(i5) = new TriaSfe1_cm5pti(epaisseur,idmail,el->Num_elt(),t_noe);break;
default:
if (ParaGlob::NiveauImpression() > 2)
cout << " attention le cas "<<Nom_interpol(enuSfe)
<< " avec " << num_pti << " pti "
<< " sera remplace par un SFE1 avec seulement 5 pti " << endl;
tab_SFE(i5) = new TriaSfe1_cm5pti(epaisseur,idmail,el->Num_elt(),t_noe);break;
};
}
else // cas normal
{switch (num_pti)
{ case 2: tab_SFE(i5) = new TriaSfe3(epaisseur,idmail,el->Num_elt(),t_noe);break;
case 3: tab_SFE(i5) = new TriaSfe3_cm3pti(epaisseur,idmail,el->Num_elt(),t_noe);break;
case 4: tab_SFE(i5) = new TriaSfe3_cm4pti(epaisseur,idmail,el->Num_elt(),t_noe);break;
case 5: tab_SFE(i5) = new TriaSfe3_cm5pti(epaisseur,idmail,el->Num_elt(),t_noe);break;
case 6: tab_SFE(i5) = new TriaSfe3_cm6pti(epaisseur,idmail,el->Num_elt(),t_noe);break;
case 7: tab_SFE(i5) = new TriaSfe3_cm7pti(epaisseur,idmail,el->Num_elt(),t_noe);break;
case 12: tab_SFE(i5) = new TriaSfe3_cm12pti(epaisseur,idmail,el->Num_elt(),t_noe);break;
case 13: tab_SFE(i5) = new TriaSfe3_cm13pti(epaisseur,idmail,el->Num_elt(),t_noe);break;
default:
cout << "*** pb, le cas "<<Nom_interpol(enuSfe)
<< " avec " << num_pti << " pti "
<< " n'est pas possible pour l'instant " << endl;
};
}
break;
case QSFE1:
{ num_pti = 2; // pour l'instant seul le cas avec 2 pti dans l'épaisseur
// existe, on laisse le choix suivant pour mémoire mais il faudra ensuite
// modifier pour demander le nb de pti en surface et en hauteur ...
switch (num_pti)
{ case 2: tab_SFE(i5) = new TriaQSfe1(epaisseur,idmail,el->Num_elt(),t_noe);
break;
default:
cout << "*** pb, le cas "<<Nom_interpol(enuSfe)
<< " avec " << num_pti << " pti "
<< " n'est pas possible pour l'instant " << endl;
};
break;
}
case QSFE3:
// si la courbure de l'élément est trop grande on bascule vers un SFE1
if (elem_courb(i5))
{ if (ParaGlob::NiveauImpression() > 0)
cout << " attention l'element " << Nom_interpol(enuSfe)<< " "<<i5
<< " est remplace par un QSFE1 car la courbure est sup a 30° "<< endl;
switch (num_pti)
{ case 2: tab_SFE(i5) = new TriaQSfe1(epaisseur,idmail,el->Num_elt(),t_noe); break;
default:
if (ParaGlob::NiveauImpression() > 2)
cout << " attention le cas "<<Nom_interpol(enuSfe)
<< " avec " << num_pti << " pti "
<< " sera remplace par un SFE1 avec seulement Sxh = 3x2 pti " << endl;
tab_SFE(i5) = new TriaQSfe1(epaisseur,idmail,el->Num_elt(),t_noe);break;
};
}
else // cas normal
{switch (num_pti)
{ case 2: tab_SFE(i5) = new TriaQSfe3(epaisseur,idmail,el->Num_elt(),t_noe);break;
default:
cout << "*** pb, le cas "<<Nom_interpol(enuSfe)
<< " avec " << num_pti << " pti "
<< " n'est pas possible pour l'instant " << endl;
};
}
break;
case SFE3C: tab_SFE(i5) = new TriaSfe3C(epaisseur,idmail,el->Num_elt(),t_noe); break;
// case SFE1_3D: tab_SFE(i5) = new TriaSfe1(epaisseur,idmail,el->Num_elt(),t_noe); break;
// case SFE2_3D: tab_SFE(i5) = new TriaSfe2(epaisseur,idmail,el->Num_elt(),t_noe); break;
case SFE3_3D: tab_SFE(i5) = new TriaSfe3_3D(idmail,el->Num_elt(),t_noe); break;
// case SFE3C_3D: tab_SFE(i5) = new TriaSfe3C(epaisseur,idmail,el->Num_elt(),t_noe); break;
default:
cout << "*** pb, le cas "<<Nom_interpol(enuSfe)
<< " avec " << num_pti << " pti "
<< " n'est pas possible pour l'instant " << endl;
};
};
// II_bis-- maintenant que les SFE sont fabriqué, on fait un dernier passage pour voir si à l'origine
// il n'y a pas un pb de calcul de courbure
double inf_normale=0.01;
switch (enuSfe)
{ case SFE3: case SFE3C: case SFE3_3D: // cas particulier des sfe3
case QSFE3 :
{cout << "\nAssocie au choix SFE3, il y a une verification"
<< " avant le calcul de la distorsion du maillage"
<< " celle-ci est controlee par le calcul de la courbure"
<< " initiale via le determinant de la matrice des composantes de courbure"
<< " si le determinant est trop petit (inf a une limite) on bascule"
<< " automatiquement vers des elements sfe1"
<< "\n valeur de la limite inf ? (rep par defaut "<<inf_normale
<<" retour chariot ou f) "<<endl;
string rep = "_";
rep = lect_return_defaut(true,"f");
// si la taille de rep == 0 cela veut dire que c'est un retour chariot
if ((rep.size()==0)||(Minuscules(rep) == "f"))
{cout << "--> valeur par defaut : " << inf_normale << endl;}
else
{inf_normale = ChangeReel(rep);
cout << "--> valeur lue "<< inf_normale << endl;
};
break;
}
default: break;
};
// pour l'instant on se fixe une limite inf mais ensuite il faudra demander à l'utilisateur
for (int i5 = 1; i5 <= tabelTaille; ++i5)
{ SfeMembT& el = *((SfeMembT*) tab_SFE(i5)); // pour simplifier
Tableau <Noeud *>& t_noe = t_noe_ele(i5); // pour simplifier
Tableau<Noeud *>& tabn = el.Tab_noeud(); // récup de son tableau de noeuds
// coordonnées du centre de gravité
Coordonnee G = (tabn(1)->Coord0()+tabn(2)->Coord0()+tabn(3)->Coord0())/3.;
double epaisseur = el.Epaisseurs(TEMPS_0,G); // épaisseur à G
int verif_courb = el.Test_courbure_anormale3(TEMPS_0,inf_normale);
// si pb inconnue
if (verif_courb == -1)
{ cout << "\n *** pb verification de l'element "<<Nom_interpol(enuSfe)<< " "<<i5
<< "\n *** on laisse tel quel mais il y a un pb !! **** "
<< "\n info sur l'element: \n ";
if (ParaGlob::NiveauImpression() > 1)
el.Affiche(2);
}
else // sinon cas normal de vérif avec remplacement éventuel
{// si pb on modifie éventuellement les éléments, a minima on signale
if (!verif_courb)
{// on crée un nouvel element intermédiaire
Element * eleinter;
switch (enuSfe)
{ case SFE1: case SFE2: case QSFE1:
cout << "*** pb, la verification de l'element "<<Nom_interpol(enuSfe)<< " "<<i5
<< " montre que le calcul de la courbure initiale est de mauvaise qualite "
<< " il faut s'attendre a des pb dans la simulation du comportement " << endl;
break;
case SFE3: case SFE3C: case SFE3_3D:
// on va remplacer l'élément par un SFE1 qui a priori de pose pas de pb
if (ParaGlob::NiveauImpression() > 0)
cout << " attention l'element " << Nom_interpol(enuSfe)<< " "<<i5
<< " est remplace par un SFE1 (calcul de la courbure"
<< " initiale de mauvaise qualite) " << endl;
switch (num_pti)
{ case 2: eleinter = new TriaSfe1(epaisseur,idmail,el.Num_elt(),t_noe); break;
case 5: eleinter = new TriaSfe1_cm5pti(epaisseur,idmail,el.Num_elt(),t_noe);break;
default:
if (ParaGlob::NiveauImpression() > 2)
cout << " attention le cas "<<Nom_interpol(enuSfe)
<< " avec " << num_pti << " pti "
<< " sera remplace par un SFE1 avec seulement 5 pti " << endl;
eleinter = new TriaSfe1_cm5pti(epaisseur,idmail,el.Num_elt(),t_noe);break;
};
break;
case QSFE3:
// on va remplacer l'élément par un QSFE1 qui a priori de pose pas de pb
if (ParaGlob::NiveauImpression() > 0)
cout << " attention l'element " << Nom_interpol(enuSfe)<< " "<<i5
<< " est remplace par un QSFE1 (calcul de la courbure"
<< " initiale de mauvaise qualite) " << endl;
switch (num_pti)
{ case 2: eleinter = new TriaQSfe1(epaisseur,idmail,el.Num_elt(),t_noe); break;
default:
if (ParaGlob::NiveauImpression() > 2)
cout << " attention le cas "<<Nom_interpol(enuSfe)
<< " avec " << num_pti << " pti "
<< " sera remplace par un SFE1 avec seulement Sxh 3x2 pti " << endl;
eleinter = new TriaQSfe1(epaisseur,idmail,el.Num_elt(),t_noe);break;
};
break;
default:
cout << "*** pb, le cas "<<Nom_interpol(enuSfe)
<< " avec " << num_pti << " pti "
<< " n'est pas possible pour l'instant " << endl;
};
// on remplace de sfe
delete tab_SFE(i5);
tab_SFE(i5)=eleinter;
// on revérifie que le nouvel élément est correct
if (!(((SfeMembT*) tab_SFE(i5))->Test_courbure_anormale3(TEMPS_0,inf_normale)))
cout << "*** pb, la verification de l'element "<<Nom_interpol(enuSfe)<< " "<<i5
<< " montre que la courbure initiale calculee est tres grande "
<< " il faut s'attendre a des pb dans la simulation du comportement " << endl;
};
}
};
// III-- on efface les éléments triangulaires et on les remplaces par les SFE
for (int i6 = 1; i6 <= tabelTaille; ++i6)
{ delete tab_element(i6);
tab_element(i6) = tab_SFE(i6);
};
};
// test pour savoir si le maillage est ok pour être transformée en sfe
bool Maillage::OKPourTransSfe()
{ // on vérifie que tous les éléments sont des triangles, sinon
// message d'incompétance
int tabelTaille = tab_element.Taille();
bool on_continue=true; // bon par défaut
// on boucle sur les elements
for (int i2 = 1; i2 <= tabelTaille; i2++)
// if ((tab_element(i2)->Id_geometrie() != TRIANGLE)
// || (tab_element(i2)->Id_interpolation() != LINEAIRE))
// 1 mars 2021 ==> maintenant on peut avoir des triangles internes quadratique
if (tab_element(i2)->Id_geometrie() != TRIANGLE)
{on_continue = false;break;};
if (!on_continue)
{ cout << "\n Warning *** the mesh " << idmail << " ( " << nomDuMaillage << " ) "
<< " does not contain only linear triangular element, currently "
<< " the continuation of the processing is not possible ! --> stop ";
};
// retour
return on_continue;
};
// lecture et suppression éventuelle des noeuds, non référencés par les éléments et les références
void Maillage::LectureEtSuppressionNoeudNonReferencer(UtilLecture * entreePrinc,LesReferences& lesRef)
{ if (strstr(entreePrinc->tablcar,"suppression_noeud_non_references_")!=NULL) // cas d'une demande de suppression
{ if (ParaGlob::NiveauImpression() > 2) cout << "\n beginning of the process to delete nodes which are "
<< " not connected with an element "<< endl ;
entreePrinc->NouvelleDonnee(); // on passe le mot clé
// appel de l'algo de suppression
SuppressionNoeudNonReferencer(lesRef);
if (ParaGlob::NiveauImpression() > 2) cout << "\n end of the process to delete nodes which are "
<< " not connected with an element "<< endl ;
};
};
// uniquement suppression éventuelle des noeuds, non référencés par les éléments et les références
void Maillage::SuppressionNoeudNonReferencer(LesReferences& lesRef)
{ if (ParaGlob::NiveauImpression() > 2)
cout << "\n delete of nodes which are not referred in the mesh "
<< nomDuMaillage << endl;
// on commence par chercher les noeuds non référencés
int taille_tabnoeud=tab_noeud.Taille();
Tableau <bool> non_referencer(taille_tabnoeud,true);
// on passe en revue tous les éléments, pour marquer les noeuds référencés
int nbelem = tab_element.Taille();
for (int ie = 1; ie <= nbelem ; ie++)
{ Tableau<Noeud *>& tnel = tab_element(ie)->Tab_noeud();
int dim_tnel = tnel.Taille();
for (int ib = 1; ib <= dim_tnel; ib++)
non_referencer(tnel(ib)->Num_noeud())=false;
};
// idem les références
// le cas des références fonctionnent, mais en fait, ce n'est pas
// une bonne idée de garder les noeuds référencés dans les références seulement
// a priori, il vaut mieux ne garder que les noeuds référencés par les éléments
// et supprimer tous les autres, d'où la mise en commentaires du cas des références
/*
const Reference* refe = lesRef.Init_et_Premiere();
while (refe != NULL)
{ if (refe->Indic() == 1)
{ // cas d'une référence de noeud
ReferenceNE* refeN = ((ReferenceNE*) refe); // on récupère la référence
if (refeN->Nom() != "N_tout")
{int nb_el = refeN->Taille();
for (int i=1; i<= nb_el; i++)
{ int num_noeud = refeN->Numero(i);
if ((num_noeud > taille_tabnoeud ) || (num_noeud < 1))
{ cout << "\n erreur: pendant la suppression des noeuds non references, "
<< " le numero " << num_noeud << " de la reference " << refeN->Nom()
<< " n'est pas correcte, peut-etre que le noeud n'existe pas ? "
<< " on arrete la procedure ";
return;
}
else
{ non_referencer(num_noeud)=false;};
};
};
};
// on passe à la référence suivante
refe = lesRef.Reference_suivante();
}; */
// maintenant on refait un nouveau tableau de noeud avec les noeuds inutiles supprimés
Tableau <Noeud* > tab_final(taille_tabnoeud);
int nbn_restant=0; // le nombre de noeud restant
cout << "\n ";
for (int ijn = 1; ijn <= taille_tabnoeud; ijn++)
{if (non_referencer(ijn) == false)
{nbn_restant++;
tab_final(nbn_restant) = tab_noeud(ijn);
}
else
{ if (ParaGlob::NiveauImpression() > 2)
cout << "\n delete of the node " << ijn ; //<< endl;
delete tab_noeud(ijn); // suppression du noeud
};
};
if (ParaGlob::NiveauImpression() > 2)
cout << " \n " << (taille_tabnoeud-nbn_restant)
<< " nodes have been deleted " << endl;
// on redimentionne le tableau final (les premiers restent !!)
tab_final.Change_taille(nbn_restant);
// on met à jour les références
lesRef.SupprimeReference("N_tout",idmail); // on supprime la référence N_tout
Tableau <int> nv_num(taille_tabnoeud); // nouveau num/ au ancien
for (int ia=1;ia <= nbn_restant; ia++)
nv_num(tab_final(ia)->Num_noeud()) = ia;
lesRef.Mise_a_jour_ref_noeud(nv_num,idmail,non_referencer);
// on enregistre le nouveau tableau de noeud
tab_noeud = tab_final;
// on met à jour les numéros de noeuds
for (int ia=1;ia <= nbn_restant; ia++)
tab_noeud(ia)->Change_num_noeud(ia);
string ntout("N_tout");
// on recrée la référence N_tout
{ // on construit le tableau des numéros de noeuds
Tableau <int> tabN(nbn_restant); for (int i=1;i<=nbn_restant;i++) tabN(i)=i;
ReferenceNE* rtout = new ReferenceNE(tabN,idmail,1,ntout);// construction de la référence
lesRef.Ajout_reference(rtout); // ajout de la ref, qui est maintenant géré par lesRef
};
};
// Affichage des noeuds, non référencés par les éléments
void Maillage::AffichageNoeudNonReferencer()
{ //if (ParaGlob::NiveauImpression() > 2)
// cout << "\n print nodes which are not referred in the mesh "
// << nomDuMaillage << endl;
// on commence par chercher les noeuds non référencés
int taille_tabnoeud=tab_noeud.Taille();
Tableau <bool> non_referencer(taille_tabnoeud,true);
// on passe en revue tous les éléments, pour marquer les noeuds référencés
int nbelem = tab_element.Taille();
for (int ie = 1; ie <= nbelem ; ie++)
{ Tableau<Noeud *>& tnel = tab_element(ie)->Tab_noeud();
int dim_tnel = tnel.Taille();
for (int ib = 1; ib <= dim_tnel; ib++)
non_referencer(tnel(ib)->Num_noeud())=false;
};
bool existe_non_reference = false; // init par défaut
// on regarde s'il faut afficher un warning
for (int ijn = 1; ijn <= taille_tabnoeud; ijn++)
{if (non_referencer(ijn))
{existe_non_reference=true;break;};
};
if (existe_non_reference)
{for (int ijn = 1; ijn <= taille_tabnoeud; ijn++)
{if (non_referencer(ijn))
{ cout << "\n --- print nodes which are not referred in the mesh --- "
<< nomDuMaillage ;
cout << "\n ** warning: the node " << tab_noeud(ijn)->Num_noeud()
<< " is not link with an element ! ";
}
};
};
};
// lecture et création éventuelle d'une ref sur les noeuds, non référencés par les éléments
void Maillage::LectureEtCreationRefNoeudNonReferencer(UtilLecture * entreePrinc,LesReferences& lesRef)
{ if (strstr(entreePrinc->tablcar,"creation_ref_noeud_non_references_")!=NULL) // cas d'une demande de création
{ if (ParaGlob::NiveauImpression() > 2) cout << "\n beginning of the process of building a new reference on nodes which are "
<< "\n not connected with an element "<< endl ;
entreePrinc->NouvelleDonnee(); // on passe le mot clé
// appel de l'algo de suppression
CreationRefNoeudNonReferencer(lesRef);
if (ParaGlob::NiveauImpression() > 2) cout << "\n end of the process of building a new reference on nodes which are "
<< "\n not connected with an element "<< endl ;
};
};
// création éventuelle d'une référence sur les noeuds, non référencés par les éléments
void Maillage::CreationRefNoeudNonReferencer(LesReferences& lesRef)
{ if (ParaGlob::NiveauImpression() > 2)
cout << "\n new ref of nodes which are not referred by an element "
<< nomDuMaillage << endl;
// on commence par chercher les noeuds non référencés
int taille_tabnoeud=tab_noeud.Taille();
Tableau <bool> non_referencer(taille_tabnoeud,true);
// on passe en revue tous les éléments, pour marquer les noeuds référencés
int nbelem = tab_element.Taille();
for (int ie = 1; ie <= nbelem ; ie++)
{ Tableau<Noeud *>& tnel = tab_element(ie)->Tab_noeud();
int dim_tnel = tnel.Taille();
for (int ib = 1; ib <= dim_tnel; ib++)
non_referencer(tnel(ib)->Num_noeud())=false;
};
// maintenant on refait une nouvel liste de noeud avec les noeuds non référencés
list <Noeud* > list_final;
cout << "\n ";
for (int ijn = 1; ijn <= taille_tabnoeud; ijn++)
{if (non_referencer(ijn) == true)
{list_final.push_back(tab_noeud(ijn));};
};
int taille = list_final.size();
if ((ParaGlob::NiveauImpression() > 2) && (taille != 0))
cout << " \n " << taille
<< " nodes are not referred by an element "
<< " new ref = N_noeud_libre "<< endl;
string nlibre("N_noeud_libre");
// on recrée la référence N_noeud_libre
{ // on construit le tableau des numéros de noeuds
list <Noeud* >::iterator il,ilfin=list_final.end();
Tableau <int> tabN(taille);
int i=1; // init
for (il = list_final.begin(); il != ilfin;il++,i++)
{tabN(i)= (*il)->Num_noeud();}
ReferenceNE* rlibre = new ReferenceNE(tabN,idmail,1,nlibre);// construction de la référence
lesRef.Ajout_reference(rlibre); // ajout de la ref, qui est maintenant géré par lesRef
};
};
// ------------------------------ partie relative à la renumérotation --------------
// lecture et renumérotation éventuelle des noeuds
// ici la renumérotation permet d'optimiser la largeur de bande relative au maillage uniquement
// par exemple on ne tiens pas compte de relations linéaires éventuelles entre des noeuds
void Maillage::LectureEtRenumerotation(UtilLecture * entreePrinc,LesReferences& lesRef)
{ if (strstr(entreePrinc->tablcar,"renumerotation_des_noeuds_")!=NULL) // cas d'une demande de renumérotation
{ if (ParaGlob::NiveauImpression() > 2) cout << "\n beginning of the new numbering of nodes " << endl ;
entreePrinc->NouvelleDonnee(); // on passe le mot clé
// appel de l'algo de renumérotation
Tableau <Tableau <Condilineaire> > condCLL; // un tableau par défaut
bool calcul_ok = Renumerotation(lesRef,condCLL);
if (!calcul_ok) // si retour false, pas de renumerotation effectué
{ cout << "\n ** warning: no new numbering of nodes !! ";};
if (ParaGlob::NiveauImpression() > 2) cout << "\n end of the new numbering of nodes \n" << endl ;
};
};
// renumérotation des noeuds du maillage, en fonction de conditions linéaires éventuelles
// ramène false si rien n'a changé (à cause d'un pb ou parce que la renumérotation n'est pas meilleure), vrai sinon
// nv_tab est tel que : nv_tab(i) est le nouveau numéro qui avait auparavant le numéro "i"
bool Maillage::Renumerotation(LesReferences& lesRef
,const Tableau <Tableau <Condilineaire> >& condCLL)
{ bool retour = false; // par défaut pour le retour
int taille_tabnoeud=tab_noeud.Taille();
// on calcul le point de départ
Tableau < LaLIST_io <Noeud* > > t_voisin; // def du tableau des voisins
list < list < Noeud_degre > > lis_descent; // stockage des descendants
// --- suppression de la création d'éléments frontières,
// c'est fait avant, dans l'algo appelant, car certaine fois on ne veut pas que cela change
// CreeElemFront(); // on crée tous les éléments frontières
if (listFrontiere.size()==0)
CreeElemFront(); // on essaie en conditionnel
// on crée un tableau intermédiaire pour appeler les routines suivantes qui sont static
Tableau <Tableau <Noeud*> *> tt_noeud_front(1);
tt_noeud_front(1) = &tab_noeud_front;
bool calcul_ok = true; // init par défaut
Noeud* noe_dep = Point_de_depart(tab_element,tab_noeud,tt_noeud_front,t_voisin,lis_descent,condCLL,calcul_ok);
if (!calcul_ok) // il y a un pb, on sort en le signalant
{ retour = false;}
else // sinon on continue
{// on appelle l'algorithme de Cuthill Mac Kee
Tableau <Noeud* > tab_N_final = Cuthill_Mac_Kee(taille_tabnoeud,noe_dep,t_voisin,lis_descent);
// --- maintenant on regarde l'évolution de la largeur de bande en noeud
// tout d'abord la largeur initiale
int largeur_initiale = LargeurBandeEnNoeuds(tab_element);
// on change la numérotation
for (int ia=1;ia <= taille_tabnoeud; ia++)
tab_N_final(ia)->Change_num_noeud(ia);
// nouvelle largeur de bande
int largeur_Cuthill = LargeurBandeEnNoeuds(tab_element);
// on change en numérotation inverse : Cuthill Mac Kee inverse
Tableau <Noeud* > tab_N_inverse(tab_N_final);
for (int ia=1;ia <= taille_tabnoeud; ia++)
{tab_N_final(ia)->Change_num_noeud(1+taille_tabnoeud-ia);
tab_N_inverse(1+taille_tabnoeud-ia) = tab_N_final(ia);
};
int largeur_Cuthill_inverse = LargeurBandeEnNoeuds(tab_element);
if (ParaGlob::NiveauImpression() > 2)
{ cout << "\n 1/2 largeur de bande en noeud, initiale " << largeur_initiale
<< " apres l'algo de Cuthill Mac Kee " << largeur_Cuthill
<< " idem en inverse " << largeur_Cuthill_inverse ;
};
// normalement le dernier est le meilleur, en tout cas il est meilleur que le cas 2
if ( (largeur_initiale <= largeur_Cuthill_inverse)
&& (largeur_initiale <= largeur_Cuthill )
)
// bizarre, cela veut dire qu'il faut revenir à la forme initiale
{ for (int ia=1;ia <= taille_tabnoeud; ia++)
tab_noeud(ia)->Change_num_noeud(ia);
if (ParaGlob::NiveauImpression() > 2)
cout << "\n pas d'amelioration, on garde la numerotation initiale "<< endl ;
retour = false; // pour signaler que rien n'a changé
}
else if (largeur_Cuthill < largeur_Cuthill_inverse)
// bizarre, cela veut dire qu'il faut revenir à la forme de Cuthill directe
{ for (int ia=1;ia <= taille_tabnoeud; ia++)
tab_N_final(ia)->Change_num_noeud(ia);
Tableau <int> nv_num(taille_tabnoeud); // nouveau num/ au ancien
for (int ia=1;ia <= taille_tabnoeud; ia++)
nv_num(ia) = tab_noeud(ia)->Num_noeud();
lesRef.Mise_a_jour_ref_noeud(nv_num,idmail);
tab_noeud = tab_N_final;
if (ParaGlob::NiveauImpression() > 2)
cout << "\n on utilise la numerotation obtenue avec l'algo Cuthill direct "<< endl ;
retour = true; // pour signaler qu'il y a eu un changement
}
else
// c'est le cas normale
{ Tableau <int> nv_num(taille_tabnoeud); // nouveau num/ au ancien
for (int ia=1;ia <= taille_tabnoeud; ia++)
nv_num(ia) = tab_noeud(ia)->Num_noeud();
lesRef.Mise_a_jour_ref_noeud(nv_num,idmail);
tab_noeud = tab_N_inverse;
if (ParaGlob::NiveauImpression() > 2)
cout << "\n on utilise la numerotation obtenue avec l'algo Cuthill inverse "<< endl ;
retour = true; // pour signaler qu'il y a eu un changement
};
};
// retour
return retour;
};
// méthode static: c-a-d indépendante des données du maillage (elle est générale)
// calcul du point de départ, en fonction de conditions linéaires éventuelles
// il y a également calcul des voisins et de la descendance du noeud de retour
// s'il y a un pb, calcul_ok en retour est false
Noeud* Maillage::Point_de_depart(const Tableau<Element *>& tab_elem
,const Tableau<Noeud *>& tab_noe
,const Tableau <Tableau <Noeud*> *> tt_noeud_front
,Tableau < LaLIST_io <Noeud* > >& t_voisin
, list < list < Noeud_degre > > & lis_descent
,const Tableau <Tableau <Condilineaire> >& condCLL,bool& calcul_ok)
{ // début de l'algorithme de gibbs, suivant la description faite par Pironneau
// cf. Pironneau_coursWebFR.pdf page 81
// • x,y,... sont les noeuds de la triangulation Th,
// • y est voisin de x s'il existe un élément T de Th tel que x et y en soient des noeuds,
// • le degré d'un noeud x est le nombre de ses voisins, il est noté d(x),
// • les voisins de x constituent N1(x) le niveau 1 de sa descendance,
// • les voisins des noeuds de N1(x) non encore répertoriés forment N2(x),
// le niveau 2 de la descendance de x (un noeud apparaît au plus une fois
// dans Nk(x) et par suite nt peut être dans les autres niveaux),
// • l'ensemble des niveaux Nk(x) constitue la descendance, notée D(x) du noeud x,
// • la profondeur p de la descendance est le nombre de niveaux de celle-ci,
// --- on recherche un bon point de départ
// " Parmi les noeuds du contour du domaine, on sélectionne le noeud x "
// " tel que d(x) soit minimal: d(x) "
calcul_ok=false; // init par défaut
Noeud* noe_dep=NULL; // par défaut
Maillage::Voisins(tab_elem,tab_noe,t_voisin,condCLL,calcul_ok); // on crée les voisins
if (calcul_ok) // on ne continue que si Voisins s'est bien passé
{// on définit le degré de chaque noeuds
int taille_tabnoeud=tab_noe.Taille();
Tableau <int> dx(taille_tabnoeud,1000000); // un tableau de dx initialisé à très grand
for (int idx = 1; idx <= taille_tabnoeud; idx++)
{ dx(idx) = t_voisin(idx).size(); };
// maintenant on cherche le plus petit dx des noeuds frontière
int nb_front = tt_noeud_front.Taille();
int numnoeuddep = 1;
int dx_mini=dx((*(tt_noeud_front(1)))(1)->Num_noeud());
for (int ifron = 1; ifron <= nb_front; ifron++)
{ Tableau <Noeud *> & tab_noeud_front = *(tt_noeud_front(ifron)); // pour simplifier
int taille_noe_front = tab_noeud_front.Taille();
for (int io =1; io <= taille_noe_front; io++)
{int num_noe=tab_noeud_front(io)->Num_noeud();
if (dx(num_noe) < dx_mini)
{ numnoeuddep = num_noe; dx_mini = dx(num_noe);};
};
};
// Soient D(x) sa descendance et Np(x) son dernier niveau; on réalise alors l'algorithme suivant:
// • Début
// • Pour tous les noeuds y de Np(x), dans l'ordre croissant de leur degré d(y),
// on calcule D(y) et sa profondeur p(y),
// • Si p(y) est supérieur à p(x) alors y est sélectionné, on fait x=y et on va à Début,
// Sinon on teste un nouvel y.
int compt=1; // un compteur pour éviter une boucle infinie
noe_dep = tab_noe(numnoeuddep);
Descendance (taille_tabnoeud,noe_dep,t_voisin,lis_descent,calcul_ok);
if (calcul_ok) // on ne continue que si Voisins s'est bien passé
{int profondeur = lis_descent.size();
bool premier_elem_ok = true;
do
{ premier_elem_ok = true; // init dans le cas d'une nouvelle boucle
// on calcul la descendance du noeud
// récup de son Np(x)
list < Noeud_degre >& lis_Npx = *(lis_descent.begin());
lis_Npx.sort(); // classement
list < Noeud_degre >::iterator ic,icfin=lis_Npx.end();
for (ic=lis_Npx.begin();ic != icfin; ic++)
{ list < list < Noeud_degre > > lis_des_inter;
Noeud * noei = (*ic).noe; // pour simplifier
Descendance (taille_tabnoeud,noei,t_voisin,lis_des_inter,calcul_ok);
if (!calcul_ok)
break; // si pb dans le calcul de la Descendance on sort de la boucle
if (lis_des_inter.size() > profondeur)
{ // cas où on a trouvé une p(y) plus grand que p(x)
profondeur = lis_des_inter.size();
noe_dep = noei;
lis_descent = lis_des_inter;
premier_elem_ok = false; // pour que l'on refasse une boucle dans le do
break;
};
};
if (!calcul_ok)
break; // si pb dans le calcul de la Descendance on sort de la boucle
compt++; // pour éviter une boucle infinie
}
while ((compt < 1000) && (!premier_elem_ok));
if (calcul_ok) // on ne continue que si Voisins s'est bien passé
{
// normalement ici soit on a fait 1000 passages et ça n'a pas marché, ou soit c'est ok
if (compt == 1000)
{ cout << "\n Maillage::Renumerotation: on a fait 1000 passage on retiens le premier !! ";
// on repasse en revue uniquement la liste des noeuds de lis_Npx pour le premier noeud
noe_dep = tab_noe(numnoeuddep);
Descendance (taille_tabnoeud,noe_dep,t_voisin,lis_descent,calcul_ok);
if (calcul_ok) // on ne continue que si Voisins s'est bien passé
{profondeur = lis_descent.size();
bool cestLePoint_deDepart = true;
// récup de son Np(x)
list < Noeud_degre >& lis_Npx = *(lis_descent.begin());
lis_Npx.sort(); // classement
list < Noeud_degre >::iterator ic,icfin=lis_Npx.end();
list < list < Noeud_degre > > lis_des_inter;
for (ic=lis_Npx.begin();ic != icfin; ic++)
{ Noeud * noei = (*ic).noe; // pour simplifier
Descendance (taille_tabnoeud,noei,t_voisin,lis_des_inter,calcul_ok);
if (!calcul_ok)
break; // si pb dans le calcul de la Descendance on sort de la boucle
if (lis_des_inter.size() > profondeur)
{ // cas où on a trouvé une p(y) plus grande que p(x)
profondeur = lis_des_inter.size();
noe_dep = noei;
cestLePoint_deDepart=false;
};
};
if (calcul_ok)
{// si la descendance n'est pas sauvegardée
if (!cestLePoint_deDepart)
lis_descent = lis_des_inter;
// ici on est sur de sortir avec le plus petit p(x)
};
};
};
};
};
};
// retour
return noe_dep;
};
// calcul des voisins de tous les noeuds du maillage en fonction des éléments et de conditions
// linéaires éventuelles,
// la méthode est en static, c-a-d qu'elle est indépendante des données du maillage (elle est générale)
// en entrée/sortie t_voisin
// restriction: il faut que tab_noe contienne tous les noeuds référencés dans tab_elem et tt_t_condCLL
// s'il y a un pb, calcul_ok en retour est false
Tableau < LaLIST_io <Noeud* > >& Maillage::Voisins(const Tableau<Element *>& tab_elem
,const Tableau<Noeud *>& tab_noe
,Tableau < LaLIST_io <Noeud* > >& t_voisin
,const Tableau <Tableau <Condilineaire> >& t_t_condCLL,bool& calcul_ok)
{ // on efface les voisins existants
int taille_tabnoeud=tab_noe.Taille();
t_voisin.Change_taille(taille_tabnoeud);
for (int it = 1; it <= taille_tabnoeud; it++)
t_voisin(it).erase(t_voisin(it).begin(),t_voisin(it).end());
// on passe en revue tous les éléments
int nbelem = tab_elem.Taille();
for (int ie = 1; ie <= nbelem ; ie++)
{ Tableau<Noeud *>& tnel = tab_elem(ie)->Tab_noeud();
int dimtab = tnel.Taille();
LaLIST_io <Noeud* > listlocal;
for (int ine = 1; ine <= dimtab; ine++) // création d'une liste locale de tous les
{ listlocal.push_front(tnel(ine)); }; // noeud de l'élément
listlocal.sort(); // on trie la liste locale
// on remplit la liste globale
for (int ine = 1; ine <= dimtab; ine++)
{ int ne = tnel(ine)->Num_noeud(); // le numéro du noeud
LaLIST_io <Noeud* > list_inter = listlocal; // recopie, list_inter est donc également ordonnée
t_voisin(ne).merge(list_inter); // on ajoute en gardant l'ordre dans la liste résultante
};
};
// on fait de même avec toutes les conditions linéaires
int nb_gr_CLL = t_t_condCLL.Taille();
for (int ig=1;ig<=nb_gr_CLL; ig++)
{Tableau <Condilineaire>& t_condCLL = t_t_condCLL(ig); // pour simplifier
int taille_t_condCLL = t_condCLL.Taille();
for (int ic = 1; ic<= taille_t_condCLL; ic++)
{const Tableau<Noeud *>& tnel = t_condCLL(ic).TabNoeud();
int dimtab = tnel.Taille();
LaLIST_io <Noeud* > listlocal;
for (int ine = 1; ine <= dimtab; ine++) // création d'une liste locale de tous les
{ listlocal.push_front(tnel(ine)); }; // noeud de l'élément
listlocal.sort(); // on trie la liste locale
// on remplit la liste globale
for (int ine = 1; ine <= dimtab; ine++)
{ int ne = tnel(ine)->Num_noeud(); // le numéro du noeud
LaLIST_io <Noeud* > list_inter = listlocal; // recopie, list_inter est donc également ordonnée
t_voisin(ne).merge(list_inter); // on ajoute en gardant l'ordre dans la liste résultante
};
};
};
// on supprime maintenant tous les doublons dans les listes des voisins
// sachant que t_voisin(i) est déjà ordonné, because on a utilisé merge()
for (int inn = 1; inn <= taille_tabnoeud; inn++)
t_voisin(inn).unique(); // on supprime les doublons
//on vérifie que tous les noeuds ont un voisin
calcul_ok = true; // init par défaut
if (ParaGlob::NiveauImpression() > 3)
{for (int i=1;i<=taille_tabnoeud;i++)
if (t_voisin(i).size() == 0)
{cout << "\n erreur dans Voisins(.., le noeud " << i << " n'a pas de voisins ! " << endl;
calcul_ok = false; // là pb, on signale qu'il y a un pb
};
};
// retour
return t_voisin;
};
// méthode static: c-a-d indépendante des données du maillage (elle est générale)
// calcul de la descendance d'un noeud noeu,
// on considère que les voisins sont dèjà correctement définis
// en entrée la liste qui est modifiée en interne et retournée en sortie
// le premier élément de la liste c'est la dernière descendance
// s'il y a un pb, calcul_ok en retour est false
list < list < Maillage::Noeud_degre > > & Maillage::Descendance(const int& taille_tabnoeud
,Noeud * noeu, Tableau < LaLIST_io <Noeud* > >& t_voisin
,list < list < Maillage::Noeud_degre > > & lient,bool& calcul_ok)
{ //int taille_tabnoeud=tab_noeud.Taille();
int nb_noeud_restant = taille_tabnoeud; // le nombre de noeud a considérer
Tableau <bool> utiliser(taille_tabnoeud); // un tableau indiquant si le noeud est utilisé ou pas
// init du niveau 0 avec le noeud
utiliser(noeu->Num_noeud())=true;
nb_noeud_restant--;
// on vide la liste d'entrée
lient.erase(lient.begin(),lient.end());
int dxxy = t_voisin(noeu->Num_noeud()).size(); // le degre du noeud
list <Maillage::Noeud_degre > list_pere; list_pere.push_back(Maillage::Noeud_degre(noeu,dxxy));
// pour le noeud, on rempli le premier niveau
LaLIST_io <Noeud* >::iterator kl,klfin;
list <Maillage::Noeud_degre >::iterator jl,jlfin;
// on boucle
while ((nb_noeud_restant > 0) && (list_pere.size() != 0))
{ list <Noeud_degre > liste_enfant; // l'étage courant
jlfin=list_pere.end(); // init
// on balaie la liste des peres
for (jl=list_pere.begin();jl != jlfin; jl++)
{ Noeud & noe = *((*jl).noe); // pour simplifier
LaLIST_io <Noeud* >& lesvoisins = t_voisin(noe.Num_noeud());
klfin=lesvoisins.end();
for (kl=lesvoisins.begin();kl != klfin; kl++)
{ Noeud * novoi = (*kl); // pour simplifier
int num_novoi = novoi->Num_noeud(); // le numéro de novoi
if (! (utiliser(num_novoi))) // si le noeud n'a pas déjà été utilisé
{ int dxx = t_voisin(num_novoi).size(); // le degre du noeud
liste_enfant.push_back(Maillage::Noeud_degre(novoi,dxx));
utiliser(num_novoi)=true;nb_noeud_restant--;
};
};
};
// on enregistre les enfants
lient.push_front(liste_enfant);
// on init la liste des peres pour la boucle suivante
list_pere = liste_enfant;
};
// vérification
calcul_ok = true; // init par défaut
if (nb_noeud_restant != 0)
{ if (ParaGlob::NiveauImpression()>3)
{cout << "\n problem dans le calcul de la descendance (algorithme de gibbs) !!! il y a "
<< nb_noeud_restant << " noeuds, qui ne sont pas "
<< " references par les elements, l'algorithme de renumeration ne fonctionne pas "
<< " dans ce cas !! ";
for (int i=1;i<=taille_tabnoeud;i++)
if (!utiliser(i)) cout << "\n c'est le numero : " << i << endl;
};
calcul_ok = false; // là pb, on signale
};
// retour
return lient;
};
// méthode static: c-a-d indépendante des données du maillage (elle est générale)
// algorithme de Cuthill Mac Kee directe
// noeu : le noeud de départ
// lis_descent : les descendants de noeud, qui va être modifié dans le processus
// ramène une nouvelle numérotation (mais les numéros internes des noeuds ne sont pas changé
Tableau <Noeud* > Maillage::Cuthill_Mac_Kee(const int& taille_tabnoeud,Noeud * noeu
,Tableau < LaLIST_io <Noeud* > >& t_voisin
, list < list < Noeud_degre > >& lis_descent)
{ // un tableau intermédiaire qui permet de savoir si un noeud a déjà été numéroté ou pas
Tableau <bool > numeroter(taille_tabnoeud,false);
// le tableau de retour
Tableau <Noeud* > tab_N_final(taille_tabnoeud);
tab_N_final(1)=noeu; // le premier noeud
numeroter(noeu->Num_noeud())=true;
int numero_courant=2; // le numéro courant de prochain noeud à numéroter
// la boucle
// on parcourt la liste des descendants
list < list < Noeud_degre > >::reverse_iterator il,ilfin = lis_descent.rend();
list <Maillage::Noeud_degre >::iterator it,itfin;
LaLIST_io <Noeud* >::iterator kl,klfin;
int nb_couche = 1;
for (il=lis_descent.rbegin(); il != ilfin; il++,nb_couche++)
{ list <Maillage::Noeud_degre >& list_pere = (*il);
//cout << "\n couche nb " << nb_couche << endl;
// on passe en revue les noeuds des peres et on recalcule le degré en tenant compte
// des noeuds déjà numérotés, qui ne doivent pas être pris en compte
itfin = list_pere.end();
for (it= list_pere.begin();it != itfin; it++)
{ Noeud* no = (*it).noe; // pour simplifier
LaLIST_io <Noeud* >& lesvoisins = t_voisin(no->Num_noeud());
klfin=lesvoisins.end();
int& degre = (*it).degre; // pour simplifier
degre = 0;
for (kl=lesvoisins.begin();kl != klfin; kl++)
{ Noeud * novoi = (*kl); // pour simplifier
int num_novoi = novoi->Num_noeud(); // le numéro de novoi
if (! (numeroter(num_novoi))) // si le noeud n'a pas déjà été numéroté
{ degre++; }; // on incrémente le degré
};
};
// maintenant on ordonne la list_pere en fonction des degrés
list_pere.sort();
// et on numérote à partir ce ceux qui ont le plus haut degré, c'est-à-dire le plus
// de voisin non encore numéroté
list <Maillage::Noeud_degre >::reverse_iterator rit,ritfin=list_pere.rend();
//int deb_num = numero_courant; // numéro le plus bas de la couche
//cout << "\n ";
for (rit= list_pere.rbegin();rit != ritfin; rit++)
{ //cout << (*rit).degre << " ";
tab_N_final(numero_courant)=(*rit).noe;
numero_courant++;
};
//int fin_num = numero_courant; // numéro le plus haut de la couche
// la largeur de bande finale est fonction du maxi de (fin_num - deb_num)
//cout << "\n largeur en noeud de la couche = " << fin_num - deb_num << endl;
};
// retour
return tab_N_final;
};
// méthode static: c-a-d indépendante des données du maillage (elle est générale)
// calcul de la largeur de bande en noeuds
int Maillage::LargeurBandeEnNoeuds(const Tableau<Element *>& tab_elem)
{ // def du retour
int largeur = 0;
// on passe en revue tous les éléments
int nbelem = tab_elem.Taille();
for (int ie = 1; ie <= nbelem ; ie++)
{ Tableau<Noeud *>& tnel = tab_elem(ie)->Tab_noeud();
int dim_tnel = tnel.Taille();
for (int ix = 1; ix <= dim_tnel; ix++)
for (int iy = ix+1; iy <= dim_tnel; iy++)
largeur = MaX(largeur, Abs(tnel(ix)->Num_noeud() - tnel(iy)->Num_noeud()) );
};
// retour
return largeur;
};
// création automatique des références globales de frontière si demandé dans le .info
void Maillage::CreationRefFrontiere(UtilLecture * entreePrinc,LesReferences& lesRef)
{ if (strstr(entreePrinc->tablcar,"def_auto_ref_frontiere_")!=NULL)
{ entreePrinc->NouvelleDonnee(); // on passe le mot clé
// on demande de créer les références
CreationRefFrontiere(lesRef);
};
};
// demande de création automatique des références globales de frontière
void Maillage::CreationRefFrontiere(LesReferences& lesRef)
{ if (ParaGlob::NiveauImpression() > 2) cout << " automatic definition of frontier references " << endl ;
bool creationEffective=false; // pour savoir s'il y a une création effective
// on regarde si les frontières existent, si oui on ne fait rien sinon on les crées
////---- debug
// { cout << "\n listFrontiere taille: " << listFrontiere.size() ;
// LaLIST <Front>::iterator ili, ilifin = listFrontiere.end();
// // on balaie les éléments frontière, et on récupère les éléments associé
// for (ili=listFrontiere.begin();ili!=ilifin;ili++)
// (*(ili)).Affiche();
// cout << endl;
// };
////---- fin debug
if (listFrontiere.size()==0) CreeElemFront();
////---- debug
// { cout << "\n listFrontiere taille: " << listFrontiere.size() ;
// LaLIST <Front>::iterator ili, ilifin = listFrontiere.end();
// // on balaie les éléments frontière, et on récupère les éléments associé
// for (ili=listFrontiere.begin();ili!=ilifin;ili++)
// (*(ili)).Affiche();
// cout << endl;
// };
////---- fin debug
// --- maintenant on commence par définir la référence des noeuds frontières
// c-a-d de tous les noeuds contenues dans les éléments frontières
string ntoutfront("N_tout_front");
if (!lesRef.Existe(ntoutfront,idmail))
{ // on construit le tableau des numéros de noeuds
int nbNf = tab_noeud_front.Taille();
Tableau <int> tabN(nbNf); for (int i=1;i<=nbNf;i++) tabN(i)=tab_noeud_front(i)->Num_noeud();
ReferenceNE* rtoutfront = new ReferenceNE(tabN,idmail,1,ntoutfront);// construction de la référence
lesRef.Ajout_reference(rtoutfront); // ajout de la ref, qui est maintenant géré par lesRef
if (ParaGlob::NiveauImpression() >= 8) rtoutfront->Affiche();
if (ParaGlob::NiveauImpression() >= 4) cout << " N_tout_front ";
creationEffective = true;
};
// --- on continue par une référence sur les éléments de la frontière
string etoutfront("E_front");
if (!lesRef.Existe(etoutfront,idmail))
{ // on définit une liste de stockage transitoire, because plusieurs éléments frontières
// peuvent se rattacher à un même élément fini
list <int> listE;
LaLIST <Front>::iterator ili, ilifin = listFrontiere.end();
// on balaie les éléments frontière, et on récupère les éléments associé
for (ili=listFrontiere.begin();ili!=ilifin;ili++)
listE.push_back((*ili).PtEI()->Num_elt());
listE.sort();// on ordonne la listE
listE.unique();// on supprime les doublons
// on crée un tableau correspondant à la liste
// on construit le tableau des numéros des éléments
int nbEfront = listE.size();
Tableau <int> tabE(nbEfront);
list <int>::iterator ibi, ibifin = listE.end();
int i=1;
for (ibi=listE.begin();ibi!=ibifin;ibi++,i++)
tabE(i)=(*ibi);
ReferenceNE* retoutfront = new ReferenceNE(tabE,idmail,2,etoutfront);// construction de la référence
lesRef.Ajout_reference(retoutfront); // ajout de la ref, qui est maintenant géré par lesRef
if (ParaGlob::NiveauImpression() >= 8) retoutfront->Affiche();
if (ParaGlob::NiveauImpression() >= 4) cout << " ref E_front ";
creationEffective = true;
};
// ---- puis une référence sur les faces des éléments de la frontière
string ftoutfront("F_front");
if (!lesRef.Existe(ftoutfront,idmail))
{ // on construit le tableau des numéros d'éléments + numéros de face
//int nbEfront = listFrontiere.size();
// on définit une liste de stockage transitoire, because on ne connait pas a priori
// le nombre de face frontière
list <NBelemEtFace> listEface;
LaLIST <Front>::iterator ili, ilifin = listFrontiere.end();
// on balaie les éléments fronitère
NBelemEtFace nu; // une grandeur de travail
for (ili=listFrontiere.begin();ili!=ilifin;ili++)
{ Enum_type_geom type_front = (*ili).Eleme()->Type_geom_front(); // le type de frontière
// on récupère le numéro de la face (éventuellement 0)
nu.nbFace = (*ili).Num_frontiere();
// on n'intervient que si la frontière est une face
if (type_front == SURFACE)
{ nu.nbElem = (*ili).PtEI()->Num_elt(); // le numéro de l'élément
// on considère que la face existe
listEface.push_back(nu);
};
};
listEface.sort();// on ordonne la listE
listEface.unique();// on supprime les doublons
// maintenant on va s'occuper de créer la référence
int numElFace = listEface.size();
if (numElFace != 0)
{ // création des tableaux de numéros d'éléments et faces
Tableau<int> tabelem(numElFace); // éléments
Tableau<int> tabface(numElFace); // idem pour les face
list <NBelemEtFace >::iterator itn,itnfin=listEface.end();
int i=1;
for (itn=listEface.begin();itn!=itnfin;itn++,i++)
{tabelem(i)=(*itn).nbElem;tabface(i) = (*itn).nbFace;};
ReferenceAF* refAF = new ReferenceAF(tabelem,tabface,idmail,3,ftoutfront);// création de la référence
lesRef.Ajout_reference( refAF);
if (ParaGlob::NiveauImpression() >= 8) refAF->Affiche();
if (ParaGlob::NiveauImpression() >= 4) cout << " F_front ";
creationEffective = true;
};
};
// ---- et enfin une référence sur les lignes des éléments
// ainsi qu'une référence des seules noeuds des lignes frontières
string atoutfront("A_front");string nAreteFront("N_A_front");
//bool n_a_front_existe = lesRef.Existe(nAreteFront,idmail);
if (!lesRef.Existe(atoutfront,idmail))
{ // on construit le tableau des numéros d'éléments + numéros des arrêtes
//int nbEfront = listFrontiere.size();
// on définit une liste de stockage transitoire, because on ne connait pas a priori
// le nombre de face frontière
list <NBelemEtArete> listEArrete;
list <int> listN_Arrete; // idem pour les noeuds
LaLIST <Front>::iterator ili, ilifin = listFrontiere.end();
// on balaie les éléments frontières
NBelemEtArete nu; // une grandeur de travail
for (ili=listFrontiere.begin();ili!=ilifin;ili++)
{ Enum_type_geom type_front = (*ili).Eleme()->Type_geom_front(); // le type de frontière
// on récupère le numéro de l'arête (éventuellement 0)
nu.nbArete = (*ili).Num_frontiere();
// on n'intervient que si la frontière est une arête
if (type_front == LIGNE)
{ nu.nbElem = (*ili).PtEI()->Num_elt(); // le numéro de l'élément
// on considère que l'arête existe
listEArrete.push_back(nu);
// idem pour les noeuds
const Tableau <Noeud *> ttn = (*ili).Eleme()->TabNoeud_const();
int taillettn = ttn.Taille();
for (int k=1;k<=taillettn;k++)
listN_Arrete.push_back(ttn(k)->Num_noeud());
};
};
// maintenant on va s'occuper de créer la référence d'arêtes
int numElArrete = listEArrete.size();
if (numElArrete != 0)
{ // création des tableaux de numéros d'éléments et d'arêtes
Tableau<int> tabelem(numElArrete); // éléments
Tableau<int> tabArrete(numElArrete); // idem pour les arêtes
list <NBelemEtArete >::iterator itn,itnfin=listEArrete.end();
int i=1;
for (itn=listEArrete.begin();itn!=itnfin;itn++,i++)
{tabelem(i)=(*itn).nbElem;tabArrete(i) = (*itn).nbArete;};
ReferenceAF* refAF = new ReferenceAF(tabelem,tabArrete,idmail,4,atoutfront);// création de la référence
lesRef.Ajout_reference( refAF);
if (ParaGlob::NiveauImpression() >= 8) refAF->Affiche();
if (ParaGlob::NiveauImpression() >= 4) cout << " A_front ";
creationEffective = true;
};
// même chose pour la référence de noeuds
listN_Arrete.sort();// on ordonne la listE
listN_Arrete.unique();// on supprime les doublons
int numNArrete = listN_Arrete.size();
if (numNArrete != 0)
{ // création des tableaux de numéros de noeuds
Tableau<int> tabNArete(numNArrete);
list <int >::iterator itn,itnfin=listN_Arrete.end();
int i=1;
for (itn=listN_Arrete.begin();itn!=itnfin;itn++,i++)
tabNArete(i)=(*itn);
ReferenceNE* refNE = new ReferenceNE(tabNArete,idmail,1,nAreteFront);// création de la référence
lesRef.Ajout_reference( refNE);
if (ParaGlob::NiveauImpression() >= 4) refNE->Affiche();
if (ParaGlob::NiveauImpression() >= 4) cout << " N_A_front ";
creationEffective = true;
};
};
if (creationEffective) cout << endl;
if (ParaGlob::NiveauImpression() >= 4) cout << " end of automatic definition of frontier references " << endl ;
};
// vérification que toutes les références de noeuds, d'éléments, d'arêtes et de faces sont valides
// c-a-d se réfèrent à des éléments existants
void Maillage::VerifReference(LesReferences& lesRef)
{ // on va balayer toutes les références
const Reference* refi = lesRef.Init_et_Premiere(); // init du balyage
while (refi != NULL)
{ // on prend en compte que si c'est le bon maillage
if (refi->Nbmaille() == idmail)
{ // choix en fonction du type de référence
switch (refi->Indic())
{case 1: // cas de noeuds
{const ReferenceNE & refN = *((ReferenceNE *) refi);
int reftaille = refN.Taille();
int nbN = tab_noeud.Taille();
for (int nn =1; nn<= reftaille;nn++)
if ((refN.Numero(nn) < 0) || (refN.Numero(nn) > nbN))
{cout << "\n **** error, the node number " << refN.Numero(nn) << " don't belong to the range of nodes of the mesh "
<< nomDuMaillage << " [1,"<< nbN << "] "
<< "\n error of definition of the reference of nodes : " << refi->Nom() << endl;
if (ParaGlob::NiveauImpression() >= 6)
cout << "\n Maillage::VerifReference(LesReferences& lesRef) ";
Sortie(1);
}
}
break;
case 2: // cas d'éléments
{const ReferenceNE & refE = *((ReferenceNE *) refi);
int reftaille = refE.Taille();
int nbE = tab_element.Taille();
for (int nn =1; nn<= reftaille;nn++)
if ((refE.Numero(nn) < 0) || (refE.Numero(nn) > nbE))
{cout << "\n **** error, the element number " << refE.Numero(nn) << " don't belong to the range of element of the mesh "
<< nomDuMaillage << " [1,"<< nbE << "] "
<< "\n error of definition of the reference of elements : " << refi->Nom() << endl;
if (ParaGlob::NiveauImpression() >= 6)
cout << "\n Maillage::VerifReference(LesReferences& lesRef) ";
Sortie(1);
}
}
break;
case 3: // cas de surfaces d'éléments
{const ReferenceAF & refF = *((ReferenceAF *) refi);
int reftaille = refF.Taille();
int nbE = tab_element.Taille();
for (int nn =1; nn<= reftaille;nn++)
{ // récupération du numéro de face et élément
const int numE = refF.NumeroElem(nn); const int numF = refF.NumeroFA(nn);
if ((numE < 0) || (numE > nbE))
{cout << "\n **** error, the element number " << numE << " don't belong to the range of element of the mesh "
<< nomDuMaillage << " [1,"<< nbE << "] "
<< "\n error of definition of the reference of elements surfaces : " << refi->Nom() << endl;
if (ParaGlob::NiveauImpression() >= 6)
cout << "\n Maillage::VerifReference(LesReferences& lesRef) ";
Sortie(1);
};
// arrivé ici, cela signifie que l'élément existe, maintenant on regarde si la face peut exister
int nbface = tab_element(numE)->ElementGeometrique().NbFe();
if ((numF < 0) || (numF > nbface))
{cout << "\n **** error, the surface number " << numF << " of the element " << numE
<< " don't belong to the range of possible surfaces numbers of the element [1,"<< nbface << "] "
<< "\n error of definition of the reference of elements surfaces : " << refi->Nom() << endl;
if (ParaGlob::NiveauImpression() >= 6)
cout << "\n Maillage::VerifReference(LesReferences& lesRef) ";
Sortie(1);
};
};
}
break;
case 4: // cas d'arêtes d'éléments
{const ReferenceAF & refA = *((ReferenceAF *) refi);
int reftaille = refA.Taille();
int nbE = tab_element.Taille();
for (int nn =1; nn<= reftaille;nn++)
{ // récupération du numéro d'arête et élément
const int numE = refA.NumeroElem(nn); const int numA = refA.NumeroFA(nn);
if ((numE < 0) || (numE > nbE))
{cout << "\n **** error, the element number " << numE << " don't belong to the range of element of the mesh "
<< nomDuMaillage << " [1,"<< nbE << "] "
<< "\n error of definition of the reference of elements edge : " << refi->Nom() << endl;
if (ParaGlob::NiveauImpression() >= 6)
cout << "\n Maillage::VerifReference(LesReferences& lesRef) ";
Sortie(1);
};
// arrivé ici, cela signifie que l'élément existe, maintenant on regarde si l'arête peut exister
int nbArete = tab_element(numE)->ElementGeometrique().NbSe();
if ((numA < 0) || (numA > nbArete))
{cout << "\n **** error, the edge number " << numA << " of the element " << numE
<< " don't belong to the range of possible edges numbers of the element [1,"<< nbArete << "] "
<< "\n error of definition of the reference of elements edges : " << refi->Nom() << endl;
if (ParaGlob::NiveauImpression() >= 6)
cout << "\n Maillage::VerifReference(LesReferences& lesRef) ";
Sortie(1);
};
};
}
break;
default:
if (ParaGlob::NiveauImpression() >= 6)
cout << " \n indication ! no verification for reference on element node and on gauss point ";
break;
}
}
refi = lesRef.Reference_suivante();
}
};
// méthode pour initialiser les différents tableaux utilisés par Orientation_elements_mitoyens_recursif
void Maillage::Init_Orientation_elements_mitoyens_recursif()
{ // - on initialise le tableau d'indicateur, permettant de savoir si un élément a été traité ou pas
int nb_elem = tab_element.Taille();
ind_elem.Change_taille(nb_elem,false); // def et init à 0, c-à-d non traité
// --- à chaque fois que l'on va inverser le sens d'un élément, le sens de ses frontières normalement devrait également changer
// mais comme on ne les recalcule pas, on utilise un tableau pour s'en rappeler et s'en servir, au début = 1 pour tous les éléments
tab_sens_element.Change_taille(nb_elem,1.); // ensuite quand le sens change, la valeur passe à -1
};
// ** pour l'instant ne fonctionne que pour les éléments surfaces
// orientation automatique des éléments mitoyens, à l'élément num_elem, et ensuite
// récursivement à tous les éléments mitoyens des mitoyens jusqu'à ce que la chaine s'arrête
// L'ensemble des éléments est alors groupé dans une référence qui est construit
// . soit à partir du numéro num_elem
// . soit à partir d'un nom passé en paramètre (cf. nom_ref, ci dessous)
// et qui est ajouté aux refs déjà existantes
// ensuite, le programme passe en revue les éléments restants, et regarde s'ils font parti
// d'un ensemble homogène orienté, si non, ramène la liste des éléments hors ensemble orienté
// *** ne concerne que les éléments surfaces, les autres sont ignorés
// ind_elem(i) : (tableau interne) indique si l'élément i a été traité (=true) ou non (=false)
// ind_elem: est pris en compte puis mis à jour par le programme, c-a-d que les nouveaux éléments orienté
// passe de false à true, par contre tous les éléments déjà à true, ne sont pas pris en compte dans le traitement
// angle_maxi : angle maximum entre deux éléments, au dessus duquel on considère qu'il y a une rupture de la mitoyenneté
// nom_ref : s'il est différent de "_", donne le nom de base voulu à la série de référence qui va être construite
// inverse : indique si l'on souhaite partir d'une orientation inverse de celle existante avant application de l'algo
// ceci pour l'élément de départ: au premier appel, l'opération est toujours possible, ensuite cela dépend
// si l'élément trouvé a déjà été traité ou pas
// recursiv : indique si l'on se situe dans une suite récursive d'appel de la méthode
// si oui, seule les éléments non déjà pris en compte dans les appels précédents, sont examiné
// c'est ind_elem qui permet de s'en assurer
// si non: cas par exemple d'un angle_maxi qui change, on réexamine tous les éléments, cependant
// la ré_orientation éventuelle n'est faite qu'une seule fois (toujours via ind_elem)
list <int> Maillage::Orientation_elements_mitoyens_recursif(bool recursif,string& nom_base_ref,int num_elem
,LesReferences& lesRef,double& angle_maxi,bool inverse)
{ double cos_angle_maxi = cos(angle_maxi); // pour simplifier
// --- à chaque fois que l'on va inverser le sens d'un élément, le sens de ses frontières normalement devrait également changer
// mais comme on ne les recalcule pas, on utilise le tableau tab_sens_element (tableau interne)
// pour s'en rappeler et s'en servir, au début = 1 pour tous les éléments
// ensuite quand le sens change, la valeur passe à -1
int nb_elem = tab_element.Taille();
int compteur_elem_inverse=0; // pour compter le nombre d'éléments inversés
// --- def de la liste des éléments qui ont été traité
list <int> ele_oriente; // la liste des éléments qui ont été orienté, donc qui ont la même orientation
// servira à la fin pour créer les références
// --- définition et initialisation de la liste d'éléments qu'il faut traiter
list <int> ele_a_traiter; // la liste des éléments qu'il faut traiter
ele_a_traiter.push_back(num_elem); // on initialise la liste à l'aide du numéro du premier élément à traiter
// si c'est possible on change l'orientation de l'élément si c'est demandé
if (inverse && (ind_elem(num_elem)==false))
{ tab_element(num_elem)->Modif_orient_elem(0);
tab_sens_element(num_elem)=-1.;
};
#ifdef MISE_AU_POINT
if (ParaGlob::NiveauImpression() > 4)
{ cout << "\n racine element nb: "<<num_elem<<" sens:"<<tab_sens_element(num_elem)<<endl;
};
#endif
ind_elem(num_elem)=true; // on signale (dans tous les cas) que l'élément a été traité
// c'est forcément une surface, car l'algo n'est appelé que dans ce cas
ele_oriente.push_back(num_elem); // init avec le premier élément
// -- def du tableau des Front qui ont été traité: elle permet d'éviter qu'une frontière (qui est dupliqué selon
// le nombre d'éléments qui la partage) soit traité plusieurs fois dans les boucles de recherches
// t_front_deja_traite(i)(j) : indique si la frontière j de l'élément i, est traité ou non
Tableau < Tableau <bool> > t_front_deja_traite(nb_elem);
for (int i=1;i<=nb_elem;i++)
t_front_deja_traite(i).Change_taille(mitoyen_de_chaque_element(i).Taille(),false);
// --- on va passer en revue tous les éléments de manière récursive, ceci à partir du premier élément: num_elem
// on n'intervient que pour les éléments surfaces en 3D et ligne en 2D
int dim = ParaGlob::Dimension(); // la dimension de l'espace de travail
Coordonnee A,B,C,AB,AC,N; // des variables de travail
Coordonnee Ap,Bp,Dp,ApBp,ApDp,N_mitoy; // """
while (ele_a_traiter.size() != 0)
{ list <int>::iterator iter_elem_a_traiter = ele_a_traiter.begin(); // récup du premier élément
int num_elem_a_traiter = (*iter_elem_a_traiter); // récup du numéro de l'élément
ele_a_traiter.erase(iter_elem_a_traiter); // on supprime l'élément de la liste à traiter
// récup des Front de l'élément
Tableau <Front>& mtce = mitoyen_de_chaque_element(num_elem_a_traiter);
// et on ne contine que s'il s'agit d'un élément surface (ajout 15 avril 2016) en 3D
// ou une ligne en 2D
if ( (Type_geom_generique(tab_element(num_elem_a_traiter)->Id_geometrie()) == SURFACE)
|| ((dim == 2)&& (Type_geom_generique(tab_element(num_elem_a_traiter)->Id_geometrie()) == LIGNE))
)
{int dim_mtce = mtce.Taille();
// on passe en revue tous les Front
for (int i=1;i<= dim_mtce;i++)
{ // on ne va s'intéresser qu'aux frontières lignes, qui sont celles qui joignent les éléments de surface
// + aux cas où il existe des éléments mitoyens + au cas où le Front n'a pas été traité
Front& fro = mtce(i); // pour simplifier
const Tableau <Front*>* tabmitoy = fro.TabMitoyen();
if ((fro.Eleme()->Type_geom_front() == LIGNE) && (tabmitoy != NULL)
&& (!t_front_deja_traite(num_elem_a_traiter)(fro.Num_frontiere())) )
{ int tail_tabmitoy = tabmitoy->Taille();
// --- on calcul une normale à l'élément à l'aide des extrémités de la frontière ligne et d'un autre point
// ou d'un déterminant, dans le cas 2D
Tableau <Noeud *>& tab_N_fro = fro.Eleme()->TabNoeud(); // récup des noeuds de la frontière ligne
int tail_N_fro=tab_N_fro.Taille(); // récup de la taille
A=tab_N_fro(1)->Coord0(); B= tab_N_fro(tail_N_fro)->Coord0(); // def des extrémités
// on récupère les numéros de A et B
int num_A=tab_N_fro(1)->Num_noeud();int num_B=tab_N_fro(tail_N_fro)->Num_noeud();
// on cherche un troisième noeud de l'élément, différent
Tableau<Noeud *>& tab_N_elem = tab_element(num_elem_a_traiter)->Tab_noeud();
int NBN=tab_N_elem.Taille();
bool trouve_C=false;
for (int j=1;j<=NBN;j++)
{ Noeud * pt_noeud=tab_N_elem(j);
if ((pt_noeud->Num_noeud() != num_A) && (pt_noeud->Num_noeud() != num_B))
{ C=pt_noeud->Coord0(); trouve_C=true;break;};
};
if (!trouve_C)
{ cout << "\n *** erreur dans l'algo Orientation_elements_mitoyens_recursif, on n'a pas"
<< " trouve de point C ?? l'orientation automatique risque d'etre erronee " << endl;
};
// calcul des vecteurs intermédiaire
AB=B-A;AC=C-A;
double deter_centrale = 0.; // util pour le cas 2D
if (dim == 3) // dans le cas 3D on utilise la normal
{ N=Util::ProdVec_coor(AB,AC); N.Normer();} // calcul de la normale, normée
else { deter_centrale = Util::Determinant(AB,AC);}; // cas 2D: on utilise le déterminant pour déterminer le sens
Front* fro_retenu=NULL; // init du Front que l'on retiendra au final
bool mitoyen_meme_sens = true; // par défaut on initialise l'élément mitoyen comme étant de même sens
// dans le cas où on a plusieurs éléments Front mitoyen, et que l'on est en dimension 3, on choisit un seul,
// celui qui correspond à un Element qui est le plus dans le prolongement de l'élément num_elem_a_traiter
// en dimension 2, il n'y a pas de choix possible, on prend le premier élément
if ((tail_tabmitoy > 1) && (dim == 3))
{ // --- on passe en revue tous les mitoyens et on retiend celui donc la normale est le plus // avec celle de l'élément
// donc dont le produit scalaire avec la normale, est le plus important
double projection = 0.; int num_front_mitoy = 0;
for (int j=1;j<=tail_tabmitoy;j++)
{ Front& fri = *(*tabmitoy)(j); // pour simplifier
// si on est récursif, on ne continue que si l'élément associé n'a pas été traité
int num_e = fri.PtEI()->Num_elt(); // récup du numéro de l'élément
// et on ne contine que s'il s'agit d'un élément surface (ajout 15 avril 2016) en 3D
if (Type_geom_generique(tab_element(num_e)->Id_geometrie()) == SURFACE)
{if (!ind_elem(num_e) || !recursif )
{ Tableau <Noeud *>& tab_N_fri = fri.Eleme()->TabNoeud(); // récup des noeuds de la frontière ligne
int tail_N_fri=tab_N_fri.Taille(); // récup de la taille
Ap=tab_N_fri(1)->Coord0(); Bp= tab_N_fri(tail_N_fro)->Coord0(); // def des extrémités
// on récupère les numéros de Ap et Bp
int num_Ap=tab_N_fri(1)->Num_noeud();int num_Bp=tab_N_fri(tail_N_fri)->Num_noeud();
// on cherche un troisième noeud de l'élément, différent des deux noeuds centraux
Tableau <Noeud *>& tab_N_elem_mitoy = fri.PtEI()->Tab_noeud(); // récup des noeuds de l'élément mitoyen
int NBN_mitoyen=tab_N_elem_mitoy.Taille();
bool trouve_Dp = false;
for (int k=1;k<=NBN_mitoyen;k++)
{ Noeud * pt_n=tab_N_elem_mitoy(k);
if ((pt_n->Num_noeud() != num_Ap) && (pt_n->Num_noeud() != num_Bp))
{ Dp=pt_n->Coord0(); trouve_Dp = true; break;};
};
if (!trouve_Dp)
{ cout << "\n *** erreur dans l'algo Orientation_elements_mitoyens_recursif, on n'a pas"
<< " trouve de point Dp ?? l'orientation automatique risque d'etre erronee " << endl;
};
// calcul de la nouvelle normale, normée ici pour que ça soit indépendant de la surface de ABD
// (on utilise que la normale, car ici on doit être en 3D vue le test en début de block)
ApBp=Bp-Ap; ApDp=Dp-Ap; N_mitoy=Util::ProdVec_coor(ApBp,ApDp);N_mitoy.Normer();
// si l'élément de référence (num_elem_a_traiter) a eu un sens modifié, on en tient compte à l'aide de tab_sens_element
double essai_projection = tab_sens_element(num_elem_a_traiter) * N * tab_sens_element(num_e) * N_mitoy;
// fro.Affiche(); fri.Affiche();
// cout << "\n tab_sens_element(num_elem_a_traiter) " << tab_sens_element(num_elem_a_traiter) << " essai_projection "<< essai_projection;
// cout << "\n ele= "<< fro.PtEI()->Num_elt() << " elem_mitoy= " << fri.PtEI()->Num_elt()
// << "\n A:" << A << " B: " << B << " C: " << C << " N: " << N
// << "\n Ap: "<<Ap<< " Bp: " << Bp << " Dp: " << Dp << " N_mitoy: " << N_mitoy << endl;
if (Abs(essai_projection) > Abs(projection))
{projection = essai_projection; num_front_mitoy = j;};
// cout << "\n ** num_front_mitoy= " << num_front_mitoy << " projection= " << projection << endl;
};
};
};
// arrivée ici on a la projection de l'élément associé, dans le cas où l'on a trouvé un élément non déjà traité
if((num_front_mitoy != 0) && (Abs(projection) > Abs(cos_angle_maxi)))
{ fro_retenu = (*tabmitoy)(num_front_mitoy); // on enregiste le front de l'élément mitoyen
if (projection < 0) {mitoyen_meme_sens = false;} // on regarde le sens
else {mitoyen_meme_sens = true;};
};
}
else if (tail_tabmitoy != 0)
{ // si on est récursif, on ne continue que si l'élément associé n'a pas été traité
int num_e = (*tabmitoy)(1)->PtEI()->Num_elt(); // récup du numéro de l'élément
// et on ne contine que s'il s'agit d'un élément surface (ajout 15 avril 2016) en 3D
// ou une ligne en 2D
if ( (Type_geom_generique(tab_element(num_e)->Id_geometrie()) == SURFACE)
|| ((dim == 2)&& (Type_geom_generique(tab_element(num_e)->Id_geometrie()) == LIGNE))
)
{ if (!ind_elem(num_e) || !recursif )
{ fro_retenu = (*tabmitoy)(1); // enreg
// on calcul une normale, pour ensuite avec la projection, savoir si le sens des éléments mitoyens est identique ou pas
Tableau <Noeud *>& tab_N_fro_retenu = fro_retenu->Eleme()->TabNoeud(); // récup des noeuds de la frontière ligne
int tail_N_fro_retenu=tab_N_fro_retenu.Taille(); // récup de la taille
Ap=tab_N_fro_retenu(1)->Coord0(); Bp= tab_N_fro_retenu(tail_N_fro)->Coord0(); // def des extrémités
// on récupère les numéros de Ap et Bp
int num_Ap=tab_N_fro_retenu(1)->Num_noeud();int num_Bp=tab_N_fro_retenu(tail_N_fro_retenu)->Num_noeud();
// on cherche un troisième noeud de l'élément, différent des deux noeuds centraux
Tableau <Noeud *>& tab_N_elem_mitoy = fro_retenu->PtEI()->Tab_noeud(); // récup des noeuds de l'élément mitoyen
int NBN_mitoyen=tab_N_elem_mitoy.Taille();
for (int k=1;k<=NBN_mitoyen;k++)
{ Noeud * pt_n=tab_N_elem_mitoy(k);
if ((pt_n->Num_noeud() != num_Ap) && (pt_n->Num_noeud() != num_Bp))
{ Dp=pt_n->Coord0(); break;};
};
// on différencie ici les cas 2D et 3D
ApBp=Bp-Ap; ApDp=Dp-Ap;
if (dim == 3)
{ // calcul de la nouvelle normale, normée ici pour que ça soit indépendant de la surface de ABD
N_mitoy=Util::ProdVec_coor(ApBp,ApDp);N_mitoy.Normer();
// si l'élément de référence (num_elem_a_traiter) a eu un sens modifié, on en tient compte à l'aide de tab_sens_element
// idem avec l'élément considéré
double projection = tab_sens_element(num_elem_a_traiter) * N * tab_sens_element(num_e) * N_mitoy;
if ( projection < 0) {mitoyen_meme_sens = false;} // on regarde le sens
else {mitoyen_meme_sens = true;};
// si l'angle est trop grand on ne tiens pas compte de la mitoyenneté
if (Abs(projection) < Abs(cos_angle_maxi))
fro_retenu = NULL;
// fro.Affiche(); fro_retenu->Affiche();
// cout << "\n tab_sens_element(num_elem_a_traiter) " << tab_sens_element(num_elem_a_traiter) << " projection "<<projection;
// cout << "\n ele= "<< fro.PtEI()->Num_elt() << " elem_mitoy= " << fro_retenu->PtEI()->Num_elt()
// << "\n A:" << A << " B: " << B << " C: " << C << " N: " << N
// << "\n Ap: "<<Ap<< " Bp: " << Bp << " Dp: " << Dp << " N_mitoy: " << N_mitoy << endl;
}
else // cas 2D, on utilise les déterminants (ici il n'y a pas le pb de l'angle)
{ double deter_mitoy = Util::Determinant(ApBp,ApDp);
if ( (deter_centrale * deter_mitoy) < 0) {mitoyen_meme_sens = false;} // on regarde le sens
else {mitoyen_meme_sens = true;};
};
};
};
};
// on ne traite que s'il y a effectivement un candidat mitoyen recevable
if (fro_retenu != NULL)
{ int num_e = fro_retenu->PtEI()->Num_elt(); // récup du numéro de l'élément
if (!t_front_deja_traite(num_e)(fro_retenu->Num_frontiere()))
{ // si il faut un changement d'orientation et que c'est possible on change
bool suite_traitement_possible = true; // init par défaut
if (!mitoyen_meme_sens) // changement d'orientation au cas où
{ if (!ind_elem(num_e))
{tab_element(num_e)->Modif_orient_elem(0); // "
tab_sens_element(num_e)=-1.;
compteur_elem_inverse++;
}
else
{suite_traitement_possible = false;
#ifdef MISE_AU_POINT
if (ParaGlob::NiveauImpression() > 4)
{ cout << "\n ref "<<nom_base_ref<<" ele:"<<num_elem_a_traiter <<" ne peut s'associer a "<< num_e
<< " car chg de sens demande impossible "<<endl;
};
#endif
};
};
// si tout est ok on enregistre
if (suite_traitement_possible)
{ ele_oriente.push_back(num_e); // enreg pour la constitution des éléments ayant la même orientation
ind_elem(num_e)=true; // on enregistre le fait que l'élément a été traité
//--debug
//cout << "\n elem pere " << num_elem_a_traiter << " élément traité qui devient père " << num_e << endl;
//--fin debug
ele_a_traiter.push_back(num_e); // ajout dans la liste des éléments à traiter en tant que père
// on indique pour les deux éléments mitoyens que la frontière commune, a été traité
t_front_deja_traite(num_elem_a_traiter)(fro.Num_frontiere())=true; // pour l'élément père
t_front_deja_traite(num_e)(fro_retenu->Num_frontiere())=true; // pour l'élément fils
};
};
};
};
};
};
};
if (ParaGlob::NiveauImpression() > 3)
{if (ParaGlob::Francais())
{cout << "\n nombre d'element inverses " << compteur_elem_inverse;}
else {cout << "\n number of elements with change of orientation : " << compteur_elem_inverse;};
};
// --- définit une nouvelle référence qui contient tous les éléments qui ont été traité
// s'il s'agit bien de surface
// on définit un nom possible pour la référence
if ( (Type_geom_generique(tab_element(num_elem)->Id_geometrie()) == SURFACE)
|| ((dim == 2)&& (Type_geom_generique(tab_element(num_elem)->Id_geometrie()) == LIGNE))
)
{string nom_ref;
if (nom_base_ref == "_")
{ nom_ref = "E_ref_de_meme_orientation_que_ele_"+ChangeEntierSTring(num_elem);}
else // cas où l'on spécifie un nom
{ nom_ref = "E_"+nom_base_ref;};
while (lesRef.Existe(nom_ref,idmail)) // on regarde si le nom existe, si oui on ajoute un tiret
nom_ref = nom_ref+"-";
ReferenceNE* refeE = new ReferenceNE(ele_oriente,idmail,2, nom_ref); // création de la ref
lesRef.Ajout_reference(refeE); // ajout de la ref
// idem pour une référence de face
string nom_refS;
if (nom_base_ref == "_")
{ nom_refS = "F_ref_de_meme_orientation_que_ele_"+ChangeEntierSTring(num_elem);}
else // cas où l'on spécifie un nom
{ nom_refS = "F_"+nom_base_ref;};
while (lesRef.Existe(nom_refS,idmail)) // on regarde si le nom existe, si oui on ajoute un tiret
nom_refS = nom_refS+"-";
// il faut définir une deuxième liste de 1 pour définir des faces
list <int> list_face(ele_oriente.size(),1);
ReferenceAF* refeS = new ReferenceAF(ele_oriente,list_face,idmail,2, nom_refS); // création de la ref
lesRef.Ajout_reference(refeS); // ajout de la ref
if (ParaGlob::NiveauImpression() > 0)
{if (ParaGlob::Francais())
{cout << "\n creation de la reference : " << nom_ref << " ("<<refeE->Taille() <<" elements )";
cout << "\n creation de la reference : " << nom_refS << " ("<<refeS->Taille() <<" surfaces )";}
else {cout << "\n creation of the reference : " << nom_ref << " ("<<refeE->Taille() <<" elements )";
cout << "\n creation of the reference : " << nom_refS << " ("<<refeS->Taille() <<" surfaces )";};
};
};
// --- on construit la liste des éléments qui n'ont pas été orienté
list <int> list_elem_non_orient; // def de la liste des éléments non orientés
for (int i=1;i<=nb_elem;i++)
if (!ind_elem(i))
list_elem_non_orient.push_back(i);
// retour
return list_elem_non_orient;
};
// change le numéro de maillage
void Maillage::Change_numero_maillage(int new_num)
{ if (idmail != new_num)
{ idmail = new_num;
// on s'occupe des noeuds,
int nbn = tab_noeud.Taille();
for (int i=1;i<=nbn;i++)
tab_noeud(i)->Change_num_Mail(new_num);
// puis les éléments
int nbelem = tab_element.Taille();
for (int ie=1;ie<=nbelem;ie++)
tab_element(ie)->Change_num_maillage(new_num);
// la liste des noms de maillages
listeNomMail[nomDuMaillage]=idmail;
};
};
// méthode pour orienter des éléments en fonction d'un rayon: AG, A étant un point donné, G étant le centre de
// gravité d'une facette
// A : coordonnée d'un point, si indic_G(i) est true, alors A(i) est remplacé par la coordonnée G(i) du centre
// de gravité de la facette
// zone_a_traiter: le nom de la référence des éléments a traiter
// inverse : si true, l'orientation des normales des facettes est identique à celles de AG, sinon c'est l'inverse
void Maillage::Orientation_via_rayon(const Tableau <bool> & indic_G,const Coordonnee & A
,const string& zone_a_traiter, LesReferences& lesRef, bool inverse)
{ // on commence par récupérer la liste des éléments sur laquelle on va travailler
const ReferenceNE & refa = ((ReferenceNE &) lesRef.Trouve(zone_a_traiter,idmail));
const Tableau<int>& tabN_de_Ref = refa.Tab_num(); // le tableau des éléments
int dim = ParaGlob::Dimension();
if (dim != 3)
{ cout << "\n la dimension de l'espace n'est pas 3, le traitement n'est pas possible !! ";
if (ParaGlob::NiveauImpression() > 2)
cout << "\n Maillage::Orientation_via_rayon(...";
cout << endl;
return;
};
// on parcours tous les éléments
int nbn_ref = tabN_de_Ref.Taille();
for (int i = 1; i <= nbn_ref;i++)
{ int nbE = tabN_de_Ref(i); // on récupère le numéro de l'élément
// on n'effectue le traitement que s'il s'agit d'une surface
Element& ele = *(tab_element(nbE));
////--- debug
//if (ele.Num_elt()==316)
// cout << "\n debug Maillage::Orientation_via_rayon(..." << endl;
//
////--- fin debug
if (Type_geom_generique(ele.Id_geometrie()) == SURFACE)
{ //calcul du centre de gravité
Coordonnee3 G(dim);
Tableau <Noeud *> taN = ele.Tab_noeud();
int nbn = taN.Taille();
for (int inn = 1;inn<=nbn;inn++)
{Noeud* noe = taN(inn);
G += noe->Coord0();
};
G /= nbn;
// calcul du vecteur rayon
Coordonnee3 AG(dim);
for (int ia = 1;ia<=dim;ia++)
{ if (indic_G(ia))
{AG(ia)=0.; } // c'est le cas où on utilise la coordonnée du centre de gravité
else {AG(ia) = G(ia) - A(ia);};
};
AG.Normer();
// // on calcul une normale moyenne à la surface
// // tout d'abord on choisit un premier point pour un premier segment
// Coordonnee3 B = taN(1)->Coord0();
// Coordonnee3 GB(B-G);
// Coordonnee3 N;
// // on parcours tous les noeuds et on ajoute les normales
// for (int inn = 2;inn<=nbn;inn++)
// {Noeud* noe = taN(inn);
// Coordonnee3 C(noe->Coord0());
// Coordonnee3 GC(C-G);
// N += Util::ProdVec_coor(GB,GC);
// };
// N /= nbn-1;
// en fait la précédente méthode peut poser des pb,
// on choisit une méthode plus simple
// une première arête
Coordonnee3 A1A2(taN(2)->Coord0()-taN(1)->Coord0());
// une seconde
Coordonnee3 A2A3(taN(3)->Coord0()-taN(2)->Coord0());
Coordonnee3 N(Util::ProdVec_coor(A1A2,A2A3));
N.Normer();
// on test le sens
bool a_inverser = false; // init
if ( (AG * N) > 0.) // même sens
{if (inverse) a_inverser = true;
else a_inverser = false;
}
else // sens inverse
{if (inverse) a_inverser = false;
else a_inverser = true;
};
////--- debug
//{if (ele.Num_elt()==1)
// cout << "\n debug Maillage::Orientation_via_rayon(..." << endl;
// cout << "\n element: " << ele.Num_elt() <<", AG * N = " << AG * N << " a_inverser= "<< a_inverser
// << " AG= "<<AG <<" N= "<< N;
//}
//
////--- fin debug
// s'il faut inverser on inverse
if (a_inverser)
ele.Modif_orient_elem(0);
};
};
};