Gérard Rio
49c9e51239
Sur la branche master Votre branche est à jour avec 'origin/master'. Modifications qui seront validées : nouveau fichier : Elements/Mecanique/SFE/Met_Sfe1_struc_donnees.h nouveau fichier : Elements/Thermique/PtIntegThermiInterne.cc nouveau fichier : Elements/Thermique/PtIntegThermiInterne.h nouveau fichier : General/Distribution_CPU.cc nouveau fichier : General/Distribution_CPU.h nouveau fichier : Lecture/LectBloc_T.cc nouveau fichier : Maillage/maillage4.cc nouveau fichier : Parametres/Banniere.h nouveau fichier : Parametres/banniere.cc nouveau fichier : Util/Courbes/Courbe_1-cos.cc
3097 lines
161 KiB
C++
3097 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);
|
|
};
|
|
};
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|