// This file is part of the Herezh++ application.
//
// The finite element software Herezh++ is dedicated to the field
// of mechanics for large transformations of solid structures.
// It is developed by Gérard Rio (APP: IDDN.FR.010.0106078.000.R.P.2006.035.20600)
// INSTITUT DE RECHERCHE DUPUY DE LÔME (IRDL) .
//
// Herezh++ is distributed under GPL 3 license ou ultérieure.
//
// Copyright (C) 1997-2022 Université Bretagne Sud (France)
// AUTHOR : Gérard Rio
// E-MAIL : gerardrio56@free.fr
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License,
// or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// See the GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see .
//
// For more information, please consult: .
#include "LesContacts.h"
#include
#include "ReferenceNE.h"
#include "ReferenceAF.h"
#include "CharUtil.h"
#include "Enum_TypeQuelconque.h"
#include "TypeQuelconqueParticulier.h"
#include "FrontPointF.h"
// récupération des ddl ou des grandeurs actives de tdt vers t
void LesContacts::TdtversT()
{ LaLIST ::iterator il,ilfin=listContact.end();
for (il=listContact.begin();il != ilfin; il++)
(*il).TdtversT();
// on nettoie les indicateurs transitoires
listContact_nouveau_tatdt.clear();
listContact_efface_tatdt.clear();
};
// actualisation des ddl et des grandeurs actives de t vers tdt
// dans le cas //, on ajoute dans les messages, le num du prog
void LesContacts::TversTdt()
{
#ifdef UTILISATION_MPI
int proc_en_cours = ParaGlob::Monde()->rank();
#endif
// on essaie de mettre la situation de contact comme elle était à t
// a) on supprime les nouveaux contacts
{LaLIST ::iterator>::iterator al,alfin=listContact_nouveau_tatdt.end();
for (al=listContact_nouveau_tatdt.begin();al != alfin; al++)
{ ElContact& elc = (*(*al));
Noeud* no = elc.Esclave();
int n_noee = no->Num_noeud();
int num_mail_noe_esclave = no->Num_Mail();
#ifdef MISE_AU_POINT
if (tesN_encontact(num_mail_noe_esclave).find(no)
== tesN_encontact(num_mail_noe_esclave).end() )
{
#ifdef UTILISATION_MPI
cout << "\n proc " << proc_en_cours
#else
cout << "\n"
#endif
<< "*** Erreur : on ne trouve pas la liste d'element en contact avec le noeud esclave "
<< n_noee << " du maillage " << num_mail_noe_esclave
<< " la suite n'est pas possible "
<< " LesContacts::TversTdt(.. \n";
Sortie(1);
};
#endif
LaLIST < LaLIST::iterator > & list_tesN
= tesN_encontact(num_mail_noe_esclave)[no];
list_tesN.remove(*al);
// tesN_encontact(num_mail_noe_esclave)(n_noee).remove(*al);
listContact.erase(*al);
// cout << "\n debug toto ";
};
};
// b) on rajoute les contacts supprimés
{LaLIST ::iterator al,alfin=listContact_efface_tatdt.end();
for (al=listContact_efface_tatdt.begin();al != alfin; al++)
{ ElContact& elc = (*al);
Noeud* no = elc.Esclave();
int n_noee = no->Num_noeud();
int num_mail_noe_esclave = no->Num_Mail();
// je supprime le test suivant, car on pourrait peut-être avoir en début d'incrément précédent,
// deux elements de contact avec le même noeud esclave mais pas la même frontière
// qui ensuite à cause d'un changement de frontière, deviennent identique -> un des deux est inactivé
// mais il y en a deux identiques.
// du coup si on revient en arrière c'est de ne pas tenir compte du doublon et s'il y a besoin, au niveau de Nouveau
// on aura une création d'un nouvel élément
// #ifdef MISE_AU_POINT
// if (Element_contact_deja_present(*al))
// {
// #ifdef UTILISATION_MPI
// cout << "\n proc " << proc_en_cours
// #else
// cout << "\n"
// #endif
// << "\n*** Erreur : l'element de contact existe déjà, ce n'est pas normal "
// << (*al).Esclave()->Num_noeud()
// << " du maillage " << (*al).Esclave()->Num_Mail()
// << " la suite n'est pas possible "
// << " LesContacts::TversTdt(.. \n";
// tempsContact.Arret_du_comptage(); // fin cpu
// Sortie(1);
// };
// #endif
if (!(Element_contact_deja_present(*al)))
listContact.push_front(*al);
// on met à jour le tableau tesN_encontact
#ifdef MISE_AU_POINT
if (tesN_encontact(num_mail_noe_esclave).find(no)
== tesN_encontact(num_mail_noe_esclave).end() )
{
#ifdef UTILISATION_MPI
cout << "\n proc " << proc_en_cours
#else
cout << "\n"
#endif
<< "\n*** Erreur : on ne trouve pas la liste d'element en contact avec le noeud esclave "
<< n_noee << " du maillage " << num_mail_noe_esclave
<< " la suite n'est pas possible "
<< " LesContacts::TversTdt(.. \n";
Sortie(1);
};
#endif
tesN_encontact(num_mail_noe_esclave)[no].push_front(listContact.begin());
};
};
// c) on nettoie les indicateurs transitoires
listContact_nouveau_tatdt.clear();
listContact_efface_tatdt.clear();
// d) on revient à t pour les éléments en contact
{LaLIST ::iterator il,ilfin=listContact.end();
for (il=listContact.begin();il != ilfin; il++)
(*il).TversTdt();
};
Calcul_Nb_contact_actif();
if ((ParaGlob::NiveauImpression() > 4) || (Permet_affichage() > 4 ))
#ifdef UTILISATION_MPI
cout << "\n proc " << proc_en_cours
#else
cout << "\n"
#endif
<< "\n >> LesContacts::TversTdt : nb contact actif = "<< nb_contact_actif << endl ;
};
// cas d'une méthode avec pénalisation: calcul éventuel d'un pas de temps idéal,
// si oui retour de la valeur delta_t proposé
// sinon dans tous les autres cas retour de 0.
// le calcul se fait en fonction du pas de temps courant et de la pénétration
// donc nécessite que le contact ait déjà été étudié
// Dans le cas d'un calcul parallèle, il y a transfert du résultat au cpu 0
// seules les cpu i calculent le pas de temps idéal pour leur portion et le proc 0 choisit le min
double LesContacts::Pas_de_temps_ideal()
{ tempsContact.Mise_en_route_du_comptage(); // def deb compt
double delta_optimal=ConstMath::tresgrand;
#ifdef UTILISATION_MPI
int proc_en_cours = ParaGlob::Monde()->rank();
if (proc_en_cours != 0)
{
#endif
{
// on passe en revue tous les contacts
LaLIST ::const_iterator il,ilfin=listContact.end();
for (il=listContact.begin();il != ilfin; il++)
{ double dtelem_optimal = (*il).Pas_de_temps_ideal();
if (dtelem_optimal != 0.)
delta_optimal = MiN(delta_optimal, dtelem_optimal);
};
// retour du temps proposé
if (delta_optimal==ConstMath::tresgrand)
// cela veut dire qu'il n'a pas été modifié, on le met à 0 pour indiquer que l'on a rien
// n'a proposer
delta_optimal = 0.;
tempsContact.Arret_du_comptage(); // fin cpu
}
#ifdef UTILISATION_MPI
temps_transfert_court.Mise_en_route_du_comptage(); // comptage cpu
// maintenant on va transmettre au cpu 0
mpi::request reqs1 = ParaGlob::Monde()->isend(0, 48, delta_optimal);
// on attend pas
temps_transfert_court.Arret_du_comptage(); // fin comptage cpu
}
else // cas du cpu 0
{// l'objectif ici est de récupérer les infos
tempsContact.Arret_du_comptage(); // fin cpu
int nb_proc_terminer = 0; // permettra de terminer
while (nb_proc_terminer < (ParaGlob::Monde()->size()-1)) // gérer par les valeurs de tyfront
{ // on récupère un résultat de cpu i
temps_transfert_court.Mise_en_route_du_comptage(); // comptage cpu
double dtelem_optimal ;
mpi::request reqs1 = ParaGlob::Monde()->irecv(mpi::any_source, 48, dtelem_optimal );
reqs1.wait(); // on attend que le conteneur soit rempli
delta_optimal = MiN(delta_optimal, dtelem_optimal);
nb_proc_terminer++; // on prend en compte que l'on a récupéré un conteneur
};
};
// il faut que tous les proc aient le retour global, car le retour sert dans l'algo général
broadcast(*ParaGlob::Monde(), delta_optimal, 0);
#endif
return delta_optimal;
};
// écriture base info
// cas donne le niveau de sauvegarde
void LesContacts::Ecri_base_info_LesContacts(ostream& sort)
{ // globalement on sauvegarde toujours tout, car les éléments de contact peuvent apparaître à tout moment
// tout d'abord on indique le type
sort << "\n LesContacts: taille " << listContact.size() << " " ;
// NB: le nombre de maillages esclave et en auto-contact, peut-être redéfinit lors d'un restart
// donc n'est pas sauvegardé
// ensuite on sauvegarde la liste des éléments de contact: en fait tout d'abord les infos
// qui permettent de construire un élément ad hoc, et ensuite les infos spécifiques internes à l'élément
for (LaLIST ::iterator ic = listContact.begin();ic != listContact.end(); ic++)
{// les infos permettants de contruire l'élément de contact: on considère que les numéros des noeuds, maillages, éléments
// restent identiques, par contre on peut avoir un échange des zones de restriction de contact d'une sauvegarde à un restart
sort << "\nN_es " << (*ic).Esclave()->Num_Mail() <<" " << (*ic).Esclave()->Num_noeud(); // le noeud esclave
Front * elfront = (*ic).Elfront();
sort << " El " << elfront->NumMail() << " " << elfront->PtEI()->Num_elt_const() << " "
<< elfront->Eleme()->Type_geom_front() << " "<< elfront->Num_frontiere() ; // la frontière
// les infos spécifiques éventuelles
(*ic).Ecri_base_info_ElContact(sort);
};
sort << "\n tps_rech_contact: "< important : les conteneurs sont supposés initialisés avec l'appel
void LesContacts::Mise_a_jour_Pour_Grandeur_particuliere(
List_io < TypeQuelconque >& li_restreinte_TQ
)
{
LaLIST::iterator ili_deb= listContact.begin();
LaLIST::iterator ilifin= listContact.end();
LaLIST::iterator ili;
// on passe en revue la liste de quelconque
{List_io::iterator itq,itqfin=li_restreinte_TQ.end();
for (itq=li_restreinte_TQ.begin();itq!=itqfin;itq++)
{const TypeQuelconque_enum_etendu& enuTypeQuelconque = (*itq).EnuTypeQuelconque();
if (enuTypeQuelconque.Nom_vide()) // veut dire que c'est un enum pur
switch (enuTypeQuelconque.EnumTQ())
{ case NOEUD_PROJECTILE_EN_CONTACT:
{// ----- cas des noeuds projectiles en contact
// on parcours la liste des élément en contact
for (ili=ili_deb;ili!=ilifin;ili++)
{ElContact & elcont = (*ili); // pour simplifier
// on attribue une grandeur arbitraire de 100 aux noeuds pour un contact actif
// pour les éléments de contact inactif -> -0.1
// un noeud peut être plusieurs fois en contact -> les nombres sont cumulées
// on fait l'hypothèse qu'un ne sera jamais inactif plus de 99 fois, du coup
// en regardant le nombre modulo 100 on peut en déduire le nombre d'inactivité
// et en regardant le nombre de centaine on en déduit le nombre de contact
TypeQuelconque& tyqN = elcont.Esclave()->ModifGrandeur_quelconque(enuTypeQuelconque);
Grandeur_scalaire_double& tyTQ= *((Grandeur_scalaire_double*)
tyqN.Grandeur_pointee());
if (elcont.Actif())
{*(tyTQ.ConteneurDouble()) += 100.; }
else
{*(tyTQ.ConteneurDouble()) -= 0.1; }
};
break;
}
case NOEUD_FACETTE_EN_CONTACT:
{// ----- cas des noeuds facettes en contact
// on parcours la liste des éléments de contact
for (ili=ili_deb;ili!=ilifin;ili++)
{ElContact & elcont = (*ili); // pour simplifier
// on attribue une grandeur arbitraire de 100 aux noeuds pour un contact actif
// pour les éléments de contact inactif -> -0.1
// un noeud peut être plusieurs fois en contact -> les nombres sont cumulées
// on fait l'hypothèse qu'un ne sera jamais inactif plus de 99 fois, du coup
// en regardant le nombre modulo 100 on peut en déduire le nombre d'inactivité
// et en regardant le nombre de centaine on en déduit le nombre de contact
Tableau & tablN = elcont.TabNoeud();
int NBNF=tablN.Taille();
// on boucle sur les noeuds de la facette (le premier noeud = noeud esclave)
if (elcont.Actif())
{for (int i=2;i<=NBNF;i++)
{TypeQuelconque& tyqN = tablN(i)->ModifGrandeur_quelconque(enuTypeQuelconque);
Grandeur_scalaire_double& tyTQ= *((Grandeur_scalaire_double*)
tyqN.Grandeur_pointee());
*(tyTQ.ConteneurDouble()) += 100.;
}
}
else
{for (int i=2;i<=NBNF;i++)
{TypeQuelconque& tyqN = tablN(i)->ModifGrandeur_quelconque(enuTypeQuelconque);
Grandeur_scalaire_double& tyTQ= *((Grandeur_scalaire_double*)
tyqN.Grandeur_pointee());
*(tyTQ.ConteneurDouble()) -= 0.1;
}
};
};
break;
}
case PENETRATION_CONTACT:
{// ----- cas des noeuds projectiles en contact
// on parcours la liste des élément en contact
// on cumule s'il y a plusieurs contacts
for (ili=ili_deb;ili!=ilifin;ili++)
{ElContact & elcont = (*ili); // pour simplifier
TypeQuelconque& tyqN = elcont.Esclave()->ModifGrandeur_quelconque(enuTypeQuelconque);
Grandeur_coordonnee& tyTQ= *((Grandeur_coordonnee*)
tyqN.Grandeur_pointee());
if (elcont.Actif())
{// on définit un vecteur au niveau du noeud en contact, qui part du noeud
// projectile et va au point d'impact
const Coordonnee& Mtdt = elcont.Point_intersection();
*(tyTQ.ConteneurCoordonnee()) += Mtdt - elcont.Esclave()->Coord2();
}; // sinon on ne fait rien
};
break;
}
case GLISSEMENT_CONTACT:
{// ----- cas des noeuds projectiles en contact
// on parcours la liste des élément en contact
// on cumule s'il y a plusieurs contacts
for (ili=ili_deb;ili!=ilifin;ili++)
{ElContact & elcont = (*ili); // pour simplifier
TypeQuelconque& tyqN = elcont.Esclave()->ModifGrandeur_quelconque(enuTypeQuelconque);
Grandeur_coordonnee& tyTQ= *((Grandeur_coordonnee*)
tyqN.Grandeur_pointee());
if (elcont.Actif())
{// on définit un vecteur au niveau du noeud en contact, qui part du noeud
// projectile et va au point d'impact
*(tyTQ.ConteneurCoordonnee()) += elcont.Dep_tangentiel();
}; // sinon on ne fait rien
};
break;
}
case NORMALE_CONTACT:
{// ----- cas des noeuds projectiles en contact
// on parcours la liste des élément en contact
// on cumule s'il y a plusieurs contacts
for (ili=ili_deb;ili!=ilifin;ili++)
{ElContact & elcont = (*ili); // pour simplifier
TypeQuelconque& tyqN = elcont.Esclave()->ModifGrandeur_quelconque(enuTypeQuelconque);
Grandeur_coordonnee& tyTQ= *((Grandeur_coordonnee*)
tyqN.Grandeur_pointee());
if (elcont.Actif())
{// on définit un vecteur au niveau du noeud en contact, qui part du noeud
// projectile et va au point d'impact
*(tyTQ.ConteneurCoordonnee()) += elcont.Normale_actuelle();
}; // sinon on ne fait rien
};
break;
}
// case N_FRONT:
// {// ----- cas des noeuds projectiles en contact
// // on parcours la liste des élément en contact
// // on cumule s'il y a plusieurs contacts
// for (ili=ili_deb;ili!=ilifin;ili++)
// {ElContact & elcont = (*ili); // pour simplifier
// TypeQuelconque& tyqN = elcont.Esclave()->ModifGrandeur_quelconque(enuTypeQuelconque);
// Grandeur_coordonnee& tyTQ= *((Grandeur_coordonnee*)
// tyqN.Grandeur_pointee());
// // on récupère la normale au noeud projectile
// *(tyTQ.ConteneurCoordonnee()) = elcont.Normale_actuelle();
// };
// break;
// }
case FORCE_CONTACT:
{// ----- cas des noeuds projectiles en contact
// on parcours la liste des élément en contact
for (ili=ili_deb;ili!=ilifin;ili++)
{ElContact & elcont = (*ili); // pour simplifier
TypeQuelconque& tyqN = elcont.Esclave()->ModifGrandeur_quelconque(enuTypeQuelconque);
Grandeur_coordonnee& tyTQ= *((Grandeur_coordonnee*)
tyqN.Grandeur_pointee());
if (elcont.Actif())
{// on récupère la force de contact
*(tyTQ.ConteneurCoordonnee()) += elcont.Force_contact();
}; // sinon on ne fait rien
};
break;
}
case CONTACT_PENALISATION_N:
{// ----- on attribue la pénalisation au noeud projectile
// on met la pénalisation totale s'il y a plusieurs contacts
// on parcours la liste des élément en contact
for (ili=ili_deb;ili!=ilifin;ili++)
{ElContact & elcont = (*ili); // pour simplifier
TypeQuelconque& tyqN = elcont.Esclave()->ModifGrandeur_quelconque(enuTypeQuelconque);
Grandeur_scalaire_double& tyTQ= *((Grandeur_scalaire_double*)
tyqN.Grandeur_pointee());
if (elcont.Actif())
{*(tyTQ.ConteneurDouble()) += elcont.Penalisation(); };
};
break;
}
case CONTACT_PENALISATION_T:
{// ----- on attribue la pénalisation au noeud projectile
// on met la pénalisation totale s'il y a plusieurs contacts
// on parcours la liste des élément en contact
for (ili=ili_deb;ili!=ilifin;ili++)
{ElContact & elcont = (*ili); // pour simplifier
TypeQuelconque& tyqN = elcont.Esclave()->ModifGrandeur_quelconque(enuTypeQuelconque);
Grandeur_scalaire_double& tyTQ= *((Grandeur_scalaire_double*)
tyqN.Grandeur_pointee());
if (elcont.Actif())
{*(tyTQ.ConteneurDouble()) += elcont.Penalisation_tangentielle(); };
};
break;
}
case CONTACT_ENERG_PENAL:
{// ----- on attribue l'énergie de pénalisation au noeud projectile
// on met l'énergie totale s'il y a plusieurs contacts
// on parcours la liste des élément en contact
for (ili=ili_deb;ili!=ilifin;ili++)
{ElContact & elcont = (*ili); // pour simplifier
TypeQuelconque& tyqN = elcont.Esclave()->ModifGrandeur_quelconque(enuTypeQuelconque);
Grandeur_scalaire_double& tyTQ= *((Grandeur_scalaire_double*)
tyqN.Grandeur_pointee());
if (elcont.Actif())
{*(tyTQ.ConteneurDouble()) += elcont.EnergiePenalisation(); };
};
break;
}
case CONTACT_ENERG_GLISSE_ELAS:
{// ----- on attribue l'énergie de pénalisation au noeud projectile
// on met l'énergie totale s'il y a plusieurs contacts
// on parcours la liste des élément en contact
for (ili=ili_deb;ili!=ilifin;ili++)
{ElContact & elcont = (*ili); // pour simplifier
TypeQuelconque& tyqN = elcont.Esclave()->ModifGrandeur_quelconque(enuTypeQuelconque);
Grandeur_scalaire_double& tyTQ= *((Grandeur_scalaire_double*)
tyqN.Grandeur_pointee());
if (elcont.Actif())
{*(tyTQ.ConteneurDouble()) += elcont.EnergieFrottement().EnergieElastique(); };
};
break;
}
case CONTACT_ENERG_GLISSE_PLAS:
{// ----- on attribue l'énergie de pénalisation au noeud projectile
// on met l'énergie totale s'il y a plusieurs contacts
// on parcours la liste des élément en contact
for (ili=ili_deb;ili!=ilifin;ili++)
{ElContact & elcont = (*ili); // pour simplifier
TypeQuelconque& tyqN = elcont.Esclave()->ModifGrandeur_quelconque(enuTypeQuelconque);
Grandeur_scalaire_double& tyTQ= *((Grandeur_scalaire_double*)
tyqN.Grandeur_pointee());
if (elcont.Actif())
{*(tyTQ.ConteneurDouble()) += elcont.EnergieFrottement().DissipationPlastique(); };
};
break;
}
case CONTACT_ENERG_GLISSE_VISQ:
{// ----- on attribue l'énergie de pénalisation au noeud projectile
// on met l'énergie totale s'il y a plusieurs contacts
// on parcours la liste des élément en contact
for (ili=ili_deb;ili!=ilifin;ili++)
{ElContact & elcont = (*ili); // pour simplifier
TypeQuelconque& tyqN = elcont.Esclave()->ModifGrandeur_quelconque(enuTypeQuelconque);
Grandeur_scalaire_double& tyTQ= *((Grandeur_scalaire_double*)
tyqN.Grandeur_pointee());
if (elcont.Actif())
{*(tyTQ.ConteneurDouble()) += elcont.EnergieFrottement().DissipationVisqueuse(); };
};
break;
}
case CONTACT_NB_DECOL:
{// ----- on attribue le nombre de décolement au noeud projectile
// on met le totale s'il y a plusieurs contacts
// on parcours la liste des élément en contact
for (ili=ili_deb;ili!=ilifin;ili++)
{ElContact & elcont = (*ili); // pour simplifier
TypeQuelconque& tyqN = elcont.Esclave()->ModifGrandeur_quelconque(enuTypeQuelconque);
Grandeur_scalaire_double& tyTQ= *((Grandeur_scalaire_double*)
tyqN.Grandeur_pointee());
if (elcont.Actif())
{*(tyTQ.ConteneurDouble()) += elcont.Nb_decol(); };
};
break;
}
case CONTACT_COLLANT:
{// ----- on attribue le fait d'être collant ou pas au noeud projectile
// on met le totale s'il y a plusieurs contacts
// on parcours la liste des élément en contact
for (ili=ili_deb;ili!=ilifin;ili++)
{ElContact & elcont = (*ili); // pour simplifier
TypeQuelconque& tyqN = elcont.Esclave()->ModifGrandeur_quelconque(enuTypeQuelconque);
Grandeur_scalaire_double& tyTQ= *((Grandeur_scalaire_double*)
tyqN.Grandeur_pointee());
if (elcont.Actif())
{*(tyTQ.ConteneurDouble()) += elcont.Collant(); };
};
break;
}
case NUM_ZONE_CONTACT:
{// ----- on attribue le numéro de zone de contact au noeud projectile
// on met le totale s'il y a plusieurs contacts
// on parcours la liste des élément en contact
for (ili=ili_deb;ili!=ilifin;ili++)
{ElContact & elcont = (*ili); // pour simplifier
TypeQuelconque& tyqN = elcont.Esclave()->ModifGrandeur_quelconque(enuTypeQuelconque);
Grandeur_scalaire_double& tyTQ= *((Grandeur_scalaire_double*)
tyqN.Grandeur_pointee());
if (elcont.Actif())
{*(tyTQ.ConteneurDouble()) += elcont.Num_zone_contact(); };
};
break;
}
case CONTACT_NB_PENET:
{// ----- on attribue le nombre de décolement au noeud projectile
// on met le totale s'il y a plusieurs contacts
// on parcours la liste des élément en contact
for (ili=ili_deb;ili!=ilifin;ili++)
{ElContact & elcont = (*ili); // pour simplifier
TypeQuelconque& tyqN = elcont.Esclave()->ModifGrandeur_quelconque(enuTypeQuelconque);
Grandeur_scalaire_double& tyTQ= *((Grandeur_scalaire_double*)
tyqN.Grandeur_pointee());
if (elcont.Actif())
{*(tyTQ.ConteneurDouble()) += elcont.Nb_pene(); };
};
break;
}
case CONTACT_CAS_SOLIDE:
{// ----- on attribue le nombre au noeud projectile
// =0 contact bi déformable, =1 le noeud est libre et la frontière est bloqué (solide)
// = 2 le noeud est bloqué (solide) la frontière est libre
// = 3 tout est solide
// ici on ne met pas le totale s'il y a plusieurs contacts !!
// c'est le dernier élément qui contient le noeud projectile, qui donne le résultat
// on parcours la liste des élément en contact
for (ili=ili_deb;ili!=ilifin;ili++)
{ElContact & elcont = (*ili); // pour simplifier
TypeQuelconque& tyqN = elcont.Esclave()->ModifGrandeur_quelconque(enuTypeQuelconque);
Grandeur_scalaire_double& tyTQ= *((Grandeur_scalaire_double*)
tyqN.Grandeur_pointee());
if (elcont.Actif())
{*(tyTQ.ConteneurDouble()) = elcont.Cas_solide(); };
};
break;
}
default: ;// on ne fait rien
};
};
};
};
// récupération de la liste de tous les grandeurs particulières disponibles avec le contact
// cette liste est identique quelque soit le maillage: il n'y a donc pas de tableau indicé du num de maillage
// absolue: indique si oui ou non on sort les tenseurs dans la base absolue ou une base particulière
List_io LesContacts::ListeGrandeurs_particulieres(bool absolue) const
{
// def de la liste de retour
List_io liTQ;
// on ne ramène les infos que si le contact est actif
if (ParaGlob::param->ParaAlgoControleActifs().ContactType()!= 0)
{
// grandeurs de travail
int dim = ParaGlob::Dimension();
// ici on est en 3D et les grandeurs sont par principe en absolue, donc la variable absolue ne sert pas
Grandeur_scalaire_double grand_courant(0.);
Coordonnee inter(dim);
Grandeur_coordonnee grand_coor_courant(inter);
// def d'un type quelconque représentatif à chaque grandeur
// a priori ces grandeurs sont défini aux noeuds
//on regarde si ce type d'info existe déjà: si oui on augmente la taille du tableau, si non on crée
// $$$ cas de la visualisation des noeuds projectiles en contact
{TypeQuelconque typQ1(NOEUD_PROJECTILE_EN_CONTACT,X1,grand_courant);
liTQ.push_back(typQ1);
};
// $$$ cas de la visualisation des noeuds des facettes en contact
{TypeQuelconque typQ1(NOEUD_FACETTE_EN_CONTACT,X1,grand_courant);
liTQ.push_back(typQ1);
};
// $$$ cas de la visualisation du glissement des noeuds projectiles actifs
{TypeQuelconque typQ1(GLISSEMENT_CONTACT,X1,grand_coor_courant);
liTQ.push_back(typQ1);
};
// $$$ cas de la visualisation de la normale de contact (moyenne)
{TypeQuelconque typQ1(NORMALE_CONTACT,X1,grand_coor_courant);
liTQ.push_back(typQ1);
};
// // $$$ cas de la visualisation de la normale aux noeuds frontières
// {TypeQuelconque typQ1(N_FRONT,X1,grand_coor_courant);
// liTQ.push_back(typQ1);
// };
// $$$ cas de la visualisation de la pénétration en contact
{TypeQuelconque typQ1(PENETRATION_CONTACT,X1,grand_coor_courant);
liTQ.push_back(typQ1);
};
// $$$ cas de la visualisation des forces de contact
{TypeQuelconque typQ1(FORCE_CONTACT,X1,grand_coor_courant);
liTQ.push_back(typQ1);
};
// $$$ nombre de pénétration
{TypeQuelconque typQ1(CONTACT_NB_PENET,X1,grand_courant);
liTQ.push_back(typQ1);
};
// $$$ nombre de décolement
{TypeQuelconque typQ1(CONTACT_NB_DECOL,X1,grand_courant);
liTQ.push_back(typQ1);
};
// $$$ cas_solide
{TypeQuelconque typQ1(CONTACT_CAS_SOLIDE,X1,grand_courant);
liTQ.push_back(typQ1);
};
{TypeQuelconque typQ1(CONTACT_ENERG_PENAL,X1,grand_courant);
liTQ.push_back(typQ1);
};
{TypeQuelconque typQ1(CONTACT_ENERG_GLISSE_ELAS,X1,grand_courant);
liTQ.push_back(typQ1);
};
{TypeQuelconque typQ1(CONTACT_ENERG_GLISSE_PLAS,X1,grand_courant);
liTQ.push_back(typQ1);
};
{TypeQuelconque typQ1(CONTACT_ENERG_GLISSE_VISQ,X1,grand_courant);
liTQ.push_back(typQ1);
};
{TypeQuelconque typQ1(CONTACT_PENALISATION_N,X1,grand_courant);
liTQ.push_back(typQ1);
};
{TypeQuelconque typQ1(CONTACT_PENALISATION_T,X1,grand_courant);
liTQ.push_back(typQ1);
};
{TypeQuelconque typQ1(CONTACT_COLLANT,X1,grand_courant);
liTQ.push_back(typQ1);
};
{TypeQuelconque typQ1(NUM_ZONE_CONTACT,X1,grand_courant);
liTQ.push_back(typQ1);
};
};
// retour
return liTQ;
};
// concernant les grandeurs gérées par le contact:
// ramène une liste d'enuméré correspondant aux List_io passé en paramètre
// idem pour une List_io < Ddl _enum_etendu >
void LesContacts::List_reduite_aux_contact(const List_io& liTQ
,List_io < TypeQuelconque >& li_restreinte_TQ
)
{
// initialisation des listes de retour
li_restreinte_TQ.clear();
// on passe en revue la liste
List_io::const_iterator itq,itqfin=liTQ.end();
for (itq=liTQ.begin();itq!=itqfin;itq++)
{const TypeQuelconque& tipParticu = (*itq); // pour simplifier
const TypeQuelconque_enum_etendu& enuTypeQuelconque = tipParticu.EnuTypeQuelconque();
if (enuTypeQuelconque.Nom_vide()) // veut dire que c'est un enum pur
switch (enuTypeQuelconque.EnumTQ())
{ case NOEUD_PROJECTILE_EN_CONTACT: case NOEUD_FACETTE_EN_CONTACT:
case PENETRATION_CONTACT: case FORCE_CONTACT:
case CONTACT_PENALISATION_N: case CONTACT_PENALISATION_T:
case CONTACT_ENERG_PENAL: case NORMALE_CONTACT:
case GLISSEMENT_CONTACT: case CONTACT_ENERG_GLISSE_ELAS:
case CONTACT_ENERG_GLISSE_VISQ: case CONTACT_ENERG_GLISSE_PLAS:
case CONTACT_NB_DECOL: case CONTACT_NB_PENET:
case CONTACT_CAS_SOLIDE: case CONTACT_COLLANT:
case NUM_ZONE_CONTACT: //case N_FRONT :
{// ----- cas des noeuds projectiles en contact
li_restreinte_TQ.push_front(TypeQuelconque(tipParticu));
break;
}
default: ;// on ne fait rien
};
};
};
// initialisation des listes de grandeurs qu'ils faudra transférérer aux niveaux des noeuds des élements
// de contact, on définit si besoin, les conteneurs ad hoc au niveau des noeuds
void LesContacts::Init_Grandeur_particuliere (bool absolue,List_io& liTQ)
{liQ_en_sortie = liTQ; // on récupère la liste --> sans doute que cela ne sert à rien
LaLIST::iterator ili_deb= listContact.begin();
LaLIST::iterator ilifin= listContact.end();
LaLIST::iterator ili;
// on passe en revue la liste
List_io::iterator itq,itqfin=liTQ.end();
// on part du principe qu'il y a plus de noeuds en contact que de grandeur donc on fait une
// boucle externe sur les noeuds en contact: on parcours la liste des noeuds en contact
for (ili=ili_deb;ili!=ilifin;ili++)
{ElContact& elcont = (*ili); // pour simplifier
for (itq=liTQ.begin();itq!=itqfin;itq++)
{TypeQuelconque& tipParticu = (*itq); // pour simplifier
EnumTypeQuelconque enuTQ = tipParticu.EnuTypeQuelconque().EnumTQ();
switch (enuTQ)
{ case NOEUD_PROJECTILE_EN_CONTACT: case NOEUD_FACETTE_EN_CONTACT:
case GLISSEMENT_CONTACT: case PENETRATION_CONTACT:
case FORCE_CONTACT: case CONTACT_NB_PENET:
case CONTACT_PENALISATION_N: case CONTACT_PENALISATION_T:
case CONTACT_NB_DECOL: case CONTACT_CAS_SOLIDE:
case CONTACT_ENERG_PENAL: case CONTACT_COLLANT:
case NUM_ZONE_CONTACT: //case N_FRONT :
case NORMALE_CONTACT: case CONTACT_ENERG_GLISSE_ELAS:
case CONTACT_ENERG_GLISSE_VISQ: case CONTACT_ENERG_GLISSE_PLAS:
{// ----- cas des noeuds projectiles en contact
elcont.Esclave()->AjoutUnTypeQuelconque(*itq); // ajout du conteneur
break;
}
default: ; // sinon rien
};
};
};
} ;
//========================== fonction protegee =============================
// mise à jour des boites d'encombrement pour les éléments qui contiennent une frontière
void LesContacts::Mise_a_jour_boite_encombrement_element_contenant_front()
{
list ::iterator il,ilfin = liste_elemens_front.end();
for (il = liste_elemens_front.begin();il!=ilfin;il++)
(*il)->Boite_encombre_element(TEMPS_tdt);
};
// suppression du gap de contact pour les noeuds "collant avec suppression de gap"
void LesContacts::Suppression_gap_pour_noeud_collant()
{
int niveau_commentaire_lescontacts = Permet_affichage();
#ifdef UTILISATION_MPI
int proc_en_cours = ParaGlob::Monde()->rank();
#endif
// on passe en revue les zones de contact et si nécessaire on supprime les gaps
// sinon retour
bool continuer = false; // init par défaut
// list nom_ref_zone_contact; // liste des noms de références des zones de contact
list ::iterator iu,iufin = nom_ref_zone_contact.end();
for (iu = nom_ref_zone_contact.begin();iu != iufin; iu++)
if ((*iu).n == 2)
{continuer = true; break;};
if (!continuer)
return;
// sinon il faut effectivement faire une suppression de gap
#ifdef UTILISATION_MPI
if (proc_en_cours == 0)
#endif
if (niveau_commentaire_lescontacts > 2)
cout << "\n >>>> Suppression_gap_pour_noeud_collant : ";
// on va iterer sur les noeuds esclaves collants dont on veut supprimer le gap
LaLIST_io ::iterator iM,iMfin; // des itérator de travail
int nb_zone = MaX(1,nom_ref_zone_contact.size());
double dist_max = Dabs(ParaGlob::param->ParaAlgoControleActifs().DistanceMaxiAuPtProjete());
int tout_projeter = true; // init
int boucle_maxi = 10; // 10 boucle maxi
int boucle = 1;
do
{
#ifdef UTILISATION_MPI
if (proc_en_cours == 0)
#endif
if (niveau_commentaire_lescontacts >2 )
cout << "\n boucle : "<& tesc= tesctotal(intot)(j); // pour simplifier la notation:
const Tableau tesN_col = tesN_collant(intot)(j); // pour simplifier
int tesc_taille=tesc.Taille(); // tab des noeuds esclaves à considérer
int compteur_noeuds_projecte=0; // le nombre de noeuds qui sont projetés
double le_maxi_des_distances_trouve = 0.;
for (int inesc = 1;inesc<= tesc_taille;inesc++) // boucle sur les noeuds esclaves
if (tesN_col(inesc) == 2 ) // cas noeud collant avec volonté de supprimer le gap
{ Noeud* noee = tesc(inesc); // pour simplifier
//--- debug
//if (noee->Num_noeud() == 5)
// {cout << "\n arrivée au bon element ";
// }
const Coordonnee pt_esc = noee->Coord0(); // position du noeud esclave initial
list list_P; // la liste des projetés
list ::iterator> li_pt_front_P; // liste sur les faces pour le debug
for (int jlf=1;jlf<=nbmailMaitre;jlf++) // boucle sur les maillages maitres
{//Tableau < Tableau < LaLIST_io > > t_listFront;
LaLIST_io & t_l_front = t_listFront(jlf)(j);
iMfin=t_l_front.end();
for (iM = t_l_front.begin() ; iM != iMfin; iM++) // boucle sur les front maitres
{// si c'est dans le volume de la frontière augmenté de la distance ad hoc on test
// plus précisément
if ((*iM).In_boite_emcombrement_front(pt_esc,dist_max))
{// on projete le noeud sur la frontière
Coordonnee P;
////--- debug
//if ((noee->Num_noeud() == 5) && ((*iM).PtEI()->Num_elt()==367))
// {cout << "\n arrivée au bon element ";
//
// }
//{double Ndis = (P-pt_esc).Norme();
// if (Ndis > 20)
// (*iM).Eleme()->Projection_normale(pt_esc,P);
//}
//-- fin debug
// //----debug
//{if ((noee->Num_noeud() == 12)
// && ((*iM).Num_frontiere() == 1) && ((*iM).PtEI()->Num_elt() == 3130))
// { cout << "\n debug : frontiere 1 de l'element 3130";}
//}
////----fin debug
// si la projection est valide on enregistre
if ((*iM).Eleme()->Projection_normale(pt_esc,P))
{ list_P.push_back(P);
li_pt_front_P.push_back(iM);
};
//--- debug
//{double Ndis = (P-pt_esc).Norme();
// if (Ndis > 20)
// (*iM).Eleme()->Projection_normale(pt_esc,P);
//}
//-- fin debug
};
};
};
// maintenant on va garder le plus proche
bool projection_ok = false; // init
if (list_P.size() != 0)
{list ::iterator il,ilfin=list_P.end();
#ifdef UTILISATION_MPI
if (proc_en_cours == 0)
#endif
if (niveau_commentaire_lescontacts >5 )
{cout << "\n " << list_P.size() << " proj trouvees "
<< " Noe: "<Num_noeud()
<< " mail: " << noee->Num_Mail() << " (zone"<::iterator>::iterator iface = li_pt_front_P.begin();
LaLIST_io ::iterator>::iterator iface_maxi ;
for (il=list_P.begin(); il!= ilfin;il++,iface++)
{ double Ndis = (M-(*il)).Norme();
#ifdef UTILISATION_MPI
if (proc_en_cours == 0)
#endif
if (niveau_commentaire_lescontacts >5 )
cout << " dist: " << Ndis ;
if (Ndis < distance)
{P = (*il); distance = Ndis;
projection_ok = true; // au moins un nouveau point
iface_maxi = iface;
};
};
// si la distance == 0., il n'y a pas à changer les coordonnées
// car le point projeté == le point initial
if (distance > ConstMath::petit)
{// on change les coordonnées du noeud
noee->Change_coord0(P);
noee->Change_coord1(P);
noee->Change_coord2(P);
compteur_noeuds_projecte++;
tout_projeter=false;
if (distance > le_maxi_des_distances_trouve)
le_maxi_des_distances_trouve = distance;
#ifdef UTILISATION_MPI
if (proc_en_cours == 0)
#endif
if (niveau_commentaire_lescontacts >3 )
cout << "\n suppression gap=("<Num_noeud()
<< " du maillage " << noee->Num_Mail() << " (zone "<4 )
{cout << "\n ancienne coordonnee "<< pt_esc
<< " nouvelle " << P;
// dans le cas où iface_maxi a été attribué
if (projection_ok)
(*(*iface_maxi)).Affiche();
////--- debug
//{
//const Coordonnee pt_esc = noee->Coord0();
//Coordonnee PP;
//(*(*iface_maxi)).Eleme()->Projection_normale(pt_esc,PP);
//cout << "\n $$$ nouvelle coordonnees projetee "<< PP;
//}
////-- fin debug
};
}
else if (projection_ok)
// si on n'a pas de projection avec changement de position
// mais par contre on a quand même trouvé un projeté on enregistre
{compteur_noeuds_projecte++;};
};
if ((!projection_ok) && (boucle==1)) // au premier passage
{
#ifdef UTILISATION_MPI
if (proc_en_cours == 0)
#endif
if (niveau_commentaire_lescontacts >3 )
cout << "\n pas de projection trouvee donc de suppression gap du noeud "<Num_noeud()
<< " du maillage" << noee->Num_Mail() << " (zone "<2 )
{if (compteur_noeuds_projecte)
cout << "\n zone: " << j <<", " << compteur_noeuds_projecte << " suppression(s) de gap, maxi_distance= "
<< le_maxi_des_distances_trouve << "( passage"<& tn = al.TabNoeud();
// on parcours la liste des frontières succeptibles d'entrer en contact
// pour repérer la zone
int num_zone = 0; // init
int nb_maitre = t_listFront.Taille();
int nb_esclave = tesctotal.Taille();
for (int i=1;i<=nb_maitre;i++)
{for (int j=1;j<=nb_zone;j++)
{LaLIST_io & list_fronta = t_listFront(i)(j); // pour simplifier
LaLIST_io ::iterator il,ilfin = list_fronta.end();
for (il = list_fronta.begin();il != ilfin; il++)
{if ((*il)==(*al.Elfront()))
// les deux pointeurs pointent sur la même frontière, donc
// maintenant on regarde du coté des noeuds esclaves
{ for (int ie = 1; ie<=nb_esclave;ie++)
{const Tableau & tesc= tesctotal(i)(j); // pour simplifier la notation:
int tesc_taille=tesc.Taille(); // tab des noeuds esclaves à considérer
for (int inesc = 1;inesc<= tesc_taille;inesc++) // boucle sur les noeuds esclaves
{if (tesc(inesc) == al.Esclave())
// les deux pointeurs pointent sur le même noeud, c'est ok
{num_zone = j; break;};
};
if (num_zone)
break;
};
};
if (num_zone)
break;
};
if (num_zone)
break;
};
if (num_zone)
break;
};
// retour des infos
return num_zone;
};
// création d'un tableau de condition linéaire, correspondant à tous les éléments de contact en cours
// qu'ils soient actifs ou pas (a prior cette méthode est conçu pour donner des infos relativement à la largeur
// de bandes en noeuds due aux CLL)
// chacune des condition ne contient "d'exploitable" que le tableau de noeuds associés à la CLL,
list & LesContacts::ConnectionCLL()
{
tempsContact.Mise_en_route_du_comptage(); // def deb compt
#ifdef UTILISATION_MPI
int proc_en_cours = ParaGlob::Monde()->rank();
if (proc_en_cours != 0)
{
#endif
{
// // on boucle sur le tableau et pour chaque element on crée une condition lineaire
// int tabTaille = listContact.size();
// t_connectionCLL.Change_taille(tabTaille);
t_connectionCLL.clear();
// un tableau servant à la def de la CLL
Tableau t_enu(1); t_enu(1)=X1 ;
LaLIST ::const_iterator il,ilfin=listContact.end();
int posi=1; // init pour le tableau
for (il=listContact.begin();il != ilfin;il++,posi++)
{ const Tableau < Noeud *>& t_n = (*il).Const_TabNoeud();
// on est dans le cas ou l'on connait les infos relatives uniquements aux noeuds, aux enum ddl
t_connectionCLL.push_back(Condilineaire(t_enu, t_n));
};
tempsContact.Arret_du_comptage(); // fin cpu
}
#ifdef UTILISATION_MPI
temps_transfert_long.Mise_en_route_du_comptage(); // comptage cpu
// maintenant on va les transmettres au cpu 0
// pour cela on va utiliser un conteneur intermédiaire
// on calcul la taille nécessaire pour le conteneur (a découper éventuellement ??)
int taille_conteneur=0;
list ::iterator il,ilfin = t_connectionCLL.end();
for (il = t_connectionCLL.begin();il != ilfin;il++)
taille_conteneur += (*il).Taille_Pack();
inter_transfer2.Change_taille(taille_conteneur); // le conteneur
// on rempli le conteneur
int rang = 1; // init
for (il = t_connectionCLL.begin();il != ilfin;il++)
rang = (*il).Pack_vecteur(inter_transfer2,rang);
// on transfert
mpi::request reqs1 = ParaGlob::Monde()->isend(0, 42, taille_conteneur);
// si la taille du conteneur est nulle, on ne le transfert pas
if (taille_conteneur > 0)
mpi::request reqs2 = inter_transfer2.Ienvoi_MPI(0,43);
// on attend pas
temps_transfert_long.Arret_du_comptage(); // fin comptage cpu
}
else // cas du cpu 0
{// l'objectif ici est de récupérer les conditions linéaires
tempsContact.Arret_du_comptage(); // fin cpu
temps_transfert_long.Mise_en_route_du_comptage(); // comptage cpu
int nb_proc_terminer = 0; // permettra de terminer
t_connectionCLL.clear();// Change_taille(nb_contact_actif);
while (nb_proc_terminer < (ParaGlob::Monde()->size()-1)) // gérer par les valeurs de tyfront
{ // on récupère un résultat de cpu i
int taille_transfert;
mpi::request reqs1 = ParaGlob::Monde()->irecv(mpi::any_source, 42, taille_transfert);
mpi::status stat = reqs1.wait(); // on attend que le conteneur soit rempli
nb_proc_terminer++; // on prend en compte que l'on a récupéré un conteneur
// si la taille == 0, il n'y a rien à faire
if (taille_transfert > 0)
{inter_transfer2.Change_taille(taille_transfert); // le conteneur
int source = stat.source(); // récupération du numéro de la source
// on récupère
mpi::request reqs2 = inter_transfer2.Irecup_MPI(source, 43);
reqs2.wait(); // on attend que le conteneur soit rempli
// on va remplir la liste des conditions limites
int rang = 1; // init
while (rang != 0)
{ Condilineaire condi; // une condition intermédiaire
rang = condi.UnPack_vecteur(*lesMaille,inter_transfer2,rang,
&LesMaillages::Noeud_LesMaille);
t_connectionCLL.push_back(condi);
};
};
};
temps_transfert_long.Arret_du_comptage();
};
#endif
// retour
return t_connectionCLL;
};
// récupère le nombre de contact actif et met à jour ce nombre
// normalement devrait toujours être correct mais ?? il y a quelque chose d'incorrecte quelque part
int LesContacts::Calcul_Nb_contact_actif()
{ LaLIST ::iterator il,ilfin = listContact.end();
nb_contact_actif = 0; // init
for (il = listContact.begin();il != ilfin; il++)
if ((*il).Actif())
nb_contact_actif++;
return nb_contact_actif;
};
// création du conteneur Fct_nD_contact
void LesContacts::Creation_Fct_nD_contact()
{
#ifdef UTILISATION_MPI
int proc_en_cours = ParaGlob::Monde()->rank();
#endif
{// cas de la penalisation normale
string nom_fct = ParaGlob::param->ParaAlgoControleActifs().Fct_nD_penalisationPenetration();
if (nom_fct != "_")
{// on va récupérer la fonction
if (sauve_lesFonctionsnD->Existe(nom_fct))
{ Fonction_nD * pt_fonct = sauve_lesFonctionsnD->Trouve(nom_fct);
// sauvegarde
fct_nD_contact.fct_nD_penalisationPenetration = pt_fonct;
}
else
{
#ifdef UTILISATION_MPI
cout << "\n proc " << proc_en_cours
#else
cout << "\n"
#endif
<< " *** erreur dans la definition de la fonction nD de pilotage de la penalisation normale "
<< " le nom : " << nom_fct
<< " ne correspond pas a une fonction nD existante !! ";
Sortie(1);
};
}
else
{fct_nD_contact.fct_nD_penalisationPenetration=NULL;};
};
{// cas fct_nD_penetration_contact_maxi
string nom_fct = ParaGlob::param->ParaAlgoControleActifs().Fct_nD_penetration_contact_maxi();
if (nom_fct != "_")
{// on va récupérer la fonction
if (sauve_lesFonctionsnD->Existe(nom_fct))
{ Fonction_nD * pt_fonct = sauve_lesFonctionsnD->Trouve(nom_fct);
// sauvegarde
fct_nD_contact.fct_nD_penetration_contact_maxi = pt_fonct;
}
else
{
#ifdef UTILISATION_MPI
cout << "\n proc " << proc_en_cours
#else
cout << "\n"
#endif
<< " *** erreur dans la definition de la fonction nD de pilotage de la "
<< " penetration maxi, le nom : " << nom_fct
<< " ne correspond pas a une fonction nD existante !! ";
Sortie(1);
};
}
else
{fct_nD_contact.fct_nD_penetration_contact_maxi=NULL;};
};
{// cas Fct_nD_penetration_borne_regularisation
string nom_fct = ParaGlob::param->ParaAlgoControleActifs().Fct_nD_penetration_borne_regularisation();
if (nom_fct != "_")
{// on va récupérer la fonction
if (sauve_lesFonctionsnD->Existe(nom_fct))
{ Fonction_nD * pt_fonct = sauve_lesFonctionsnD->Trouve(nom_fct);
// sauvegarde
fct_nD_contact.fct_nD_penetration_borne_regularisation = pt_fonct;
}
else
{
#ifdef UTILISATION_MPI
cout << "\n proc " << proc_en_cours
#else
cout << "\n"
#endif
<< " *** erreur dans la definition de la fonction nD de pilotage de la "
<< " borne de regularisation, le nom : " << nom_fct
<< " ne correspond pas a une fonction nD existante !! ";
Sortie(1);
};
}
else
{fct_nD_contact.fct_nD_penetration_borne_regularisation=NULL;};
};
{// cas fct_nD_force_contact_noeud_maxi
string nom_fct = ParaGlob::param->ParaAlgoControleActifs().Fct_nD_force_contact_noeud_maxi();
if (nom_fct != "_")
{// on va récupérer la fonction
if (sauve_lesFonctionsnD->Existe(nom_fct))
{ Fonction_nD * pt_fonct = sauve_lesFonctionsnD->Trouve(nom_fct);
// sauvegarde
fct_nD_contact.fct_nD_force_contact_noeud_maxi = pt_fonct;
}
else
{
#ifdef UTILISATION_MPI
cout << "\n proc " << proc_en_cours
#else
cout << "\n"
#endif
<< " *** erreur dans la definition de la fonction nD de pilotage de la "
<< " force de contact normale, le nom : " << nom_fct
<< " ne correspond pas a une fonction nD existante !! ";
Sortie(1);
};
}
else
{fct_nD_contact.fct_nD_force_contact_noeud_maxi=NULL;};
};
{// cas fct_nD_penalisationTangentielle
string nom_fct = ParaGlob::param->ParaAlgoControleActifs().Fct_nD_penalisationTangentielle();
if (nom_fct != "_")
{// on va récupérer la fonction
if (sauve_lesFonctionsnD->Existe(nom_fct))
{ Fonction_nD * pt_fonct = sauve_lesFonctionsnD->Trouve(nom_fct);
// sauvegarde
fct_nD_contact.fct_nD_penalisationTangentielle = pt_fonct;
}
else
{
#ifdef UTILISATION_MPI
cout << "\n proc " << proc_en_cours
#else
cout << "\n"
#endif
<< " *** erreur dans la definition de la fonction nD de pilotage de la penalisation tangentielle "
<< " le nom : " << nom_fct
<< " ne correspond pas a une fonction nD existante !! ";
Sortie(1);
};
}
else
{fct_nD_contact.fct_nD_penalisationTangentielle=NULL;};
};
{// cas fct_nD_tangentielle_contact_maxi
string nom_fct = ParaGlob::param->ParaAlgoControleActifs().Fct_nD_tangentielle_contact_maxi();
if (nom_fct != "_")
{// on va récupérer la fonction
if (sauve_lesFonctionsnD->Existe(nom_fct))
{ Fonction_nD * pt_fonct = sauve_lesFonctionsnD->Trouve(nom_fct);
// sauvegarde
fct_nD_contact.fct_nD_tangentielle_contact_maxi = pt_fonct;
}
else
{
#ifdef UTILISATION_MPI
cout << "\n proc " << proc_en_cours
#else
cout << "\n"
#endif
<< " *** erreur dans la definition de la fonction nD de pilotage du "
<< " deplacement tangentiel maxi, le nom : " << nom_fct
<< " ne correspond pas a une fonction nD existante !! ";
Sortie(1);
};
}
else
{fct_nD_contact.fct_nD_tangentielle_contact_maxi=NULL;};
};
{// cas fct_nD_tangentielle_borne_regularisation
string nom_fct = ParaGlob::param->ParaAlgoControleActifs().Fct_nD_tangentielle_borne_regularisation();
if (nom_fct != "_")
{// on va récupérer la fonction
if (sauve_lesFonctionsnD->Existe(nom_fct))
{ Fonction_nD * pt_fonct = sauve_lesFonctionsnD->Trouve(nom_fct);
// sauvegarde
fct_nD_contact.fct_nD_tangentielle_borne_regularisation = pt_fonct;
}
else
{
#ifdef UTILISATION_MPI
cout << "\n proc " << proc_en_cours
#else
cout << "\n"
#endif
<< " *** erreur dans la definition de la fonction nD de pilotage de la "
<< " borne de regularisation tangentielle, le nom : " << nom_fct
<< " ne correspond pas a une fonction nD existante !! ";
Sortie(1);
};
}
else
{fct_nD_contact.fct_nD_tangentielle_borne_regularisation=NULL;};
};
{// cas fct_nD_force_tangentielle_noeud_maxi
string nom_fct = ParaGlob::param->ParaAlgoControleActifs().Fct_nD_force_tangentielle_noeud_maxi();
if (nom_fct != "_")
{// on va récupérer la fonction
if (sauve_lesFonctionsnD->Existe(nom_fct))
{ Fonction_nD * pt_fonct = sauve_lesFonctionsnD->Trouve(nom_fct);
// sauvegarde
fct_nD_contact.fct_nD_force_tangentielle_noeud_maxi = pt_fonct;
}
else
{
#ifdef UTILISATION_MPI
cout << "\n proc " << proc_en_cours
#else
cout << "\n"
#endif
<< " *** erreur dans la definition de la fonction nD de pilotage de la "
<< " force tangentielle maxi, le nom : " << nom_fct
<< " ne correspond pas a une fonction nD existante !! ";
Sortie(1);
};
}
else
{fct_nD_contact.fct_nD_force_tangentielle_noeud_maxi=NULL;};
};
{// cas fct_niveau_commentaire
string nom_fct = ParaGlob::param->ParaAlgoControleActifs().Fct_niveau_commentaire_contact();
if (nom_fct != "_")
{// on va récupérer la fonction
if (sauve_lesFonctionsnD->Existe(nom_fct))
{ Fonction_nD * pt_fonct = sauve_lesFonctionsnD->Trouve(nom_fct);
// sauvegarde
fct_nD_contact.fct_niveau_commentaire = pt_fonct;
}
else
{
#ifdef UTILISATION_MPI
cout << "\n proc " << proc_en_cours
#else
cout << "\n"
#endif
<< " *** erreur dans la definition de la fonction nD de pilotage du "
<< " niveau de commentaire en contact, le nom : " << nom_fct
<< " ne correspond pas a une fonction nD existante !! ";
Sortie(1);
};
}
else
{fct_nD_contact.fct_niveau_commentaire=NULL;};
};
// initialisation des conteneurs statique des fonction nD
fct_nD_contact.Init_conteneur_statique();
};
/*// mise à jour du stockage inter, pour prendre en
// compte une nouvelle numérotation des noeuds
void LesContacts::Prise_en_compte_nouvelle_numerotation_noeud()
{ //on va reconstruire ta_inverse
int nb_zone = MaX(1,nom_ref_zone_contact.size());
// on garde en mémoire les anciens numéros pour faire le pontage
Tableau < Tableau < Tableau > > ta_inverse_old(ta_inverse);
// on recherche les maxi des numéros de noeuds esclave, pour dimensionner ta_inverse !!
Tableau < Tableau > maxi_num_noe_esclave(nb_mail_Esclave); // init à 0
for (int i=1;i<=nb_mail_Esclave;i++)
{maxi_num_noe_esclave(i).Change_taille(nb_zone);
for (int j=1;j<=nb_zone;j++)
{const Tableau & tesc= tesctotal(i)(j); // pour simplifier la notation:
int tesc_taille=tesc.Taille(); // tab des noeuds esclaves à considérer
int& max_num_esclave = maxi_num_noe_esclave(i)(j); // pour simplifier
for (int inesc = 1;inesc<= tesc_taille;inesc++) // boucle sur les noeuds esclaves
{ Noeud* noee = tesc(inesc); // pour simplifier
int num_noeud = noee->Num_noeud();
if (num_noeud > max_num_esclave)
max_num_esclave = num_noeud;
};
};
};
// Maintenant on peut dimensionner ta_inverse
for (int i=1;i<=nb_mail_Esclave;i++)
{ta_inverse(i).Change_taille(nb_zone);
for (int j=1;j<=nb_zone;j++)
ta_inverse(i)(j).Change_taille(maxi_num_noe_esclave(i)(j),0);
};
// ensuite on va remplir ta_inverse
for (int intot=1;intot<=nb_mail_Esclave;intot++)
{for (int j=1;j<=nb_zone;j++)
{const Tableau & tesc= tesctotal(intot)(j); // pour simplifier la notation:
int tesc_taille=tesc.Taille(); // tab des noeuds esclaves à considérer
for (int inesc = 1;inesc<= tesc_taille;inesc++) // boucle sur les noeuds esclaves
{ Noeud* noee = tesc(inesc); // pour simplifier
ta_inverse(intot)(j)(noee->Num_noeud()) = inesc;
};
};
};
// on va créer un tableau de changement des numéros de noeuds
Tableau < Tableau > nouveau_Noe(nb_mail_Esclave);
// on cherche la taille maxi
Tableau maxi_maxi_num_noe_esclave(nb_mail_Esclave); // les maxis pour chaque maillage
for (int i=1;i<=nb_mail_Esclave;i++)
{int& max_max_esclave = maxi_maxi_num_noe_esclave(i) = 0; // init
for (int j=1;j<=nb_zone;j++)
{int& max_num_esclave = maxi_num_noe_esclave(i)(j); // pour simplifier
if (max_num_esclave > max_max_esclave)
max_max_esclave = max_num_esclave;
};
};
// on balaie les anciens noeuds
for (int i=1;i<=nb_mail_Esclave;i++)
{nouveau_Noe(i).Change_taille(maxi_maxi_num_noe_esclave(i));
Tableau & nouveau_Noe_i = nouveau_Noe(i);
for (int j=1;j<=nb_zone;j++)
{ Tableau & ta_inverse_old_ij = ta_inverse_old(i)(j);
Tableau & ta_inverse_ij = ta_inverse(i)(j);
int nbN = ta_inverse_old_ij.Taille();
for (int k=1;k<= nbN;k++) // k c'est le numéro de l'ancien noeud
{if (ta_inverse_old_ij(k) != 0)
{for (int k2=1;k2<= nbN;k2++)
{ if (ta_inverse_old_ij(k) == ta_inverse_ij(k2))
{nouveau_Noe_i(k)=k2;break;};
};
};
};
};
};
// // maintenant on met à jour le tableau tesN_encontact
// // Tableau < Tableau < LaLIST < LaLIST::iterator > > > tesN_encontact;
// // on sauvegarde l'ancien
// Tableau < Tableau < LaLIST < LaLIST::iterator > > > tesN_encontact_old(tesN_encontact);
// // et on fait la passation
// for (int i=1;i<=nb_mail_Esclave;i++)
// {Tableau & nouveau_Noe_i = nouveau_Noe(i);
// int nbn = tesN_encontact(i).Taille();
// for (int j=1;j<=nbn;j++)
// { tesN_encontact(i)(nouveau_Noe_i(j)) = tesN_encontact_old(i)(j);
// };
// };
// on continue avec le tableau: liste pour chaque noeud, des éléments qui contient ce noeud
// indice(i)(j) : = la liste des éléments qui contiennent le noeud j, pour le maillage i
Tableau < const Tableau > *> indice_old(indice);
int nb_mail = indice_old.Taille();
for (int i=1;i<=nb_mail;i++)
{if (indice_old(i) != NULL)
{ int nbn = indice_old(i)->Taille();
// const Tableau > & indice_i = indice(i);
// for (int j=1;j<=nbn;j++)
//indice
}
}
cout << "\n LesContacts::Prise_en_compte_nouvelle_numerotation_noeud() pas terminé !!"
<< " il faut changer lesMaillages pour récupérer directement la nouvelle numérotation !!";
Sortie(1);
};
*/
// récupération via les éléments de contact des forces maxis
// et affichage éventuel
// un : le maxi en effort normal, deux: le maxi en effort tangentiel
// Dans le cas d'un calcul parallèle, il y a transfert du résultat au cpu 0
// seules les cpu i calculent
DeuxDoubles LesContacts::Forces_contact_maxi(bool affiche)
{tempsContact.Mise_en_route_du_comptage(); // def deb compt
DeuxDoubles retour_min,retour_max; // def et init à 0
int niveau_commentaire_lescontacts = Permet_affichage();
#ifdef UTILISATION_MPI
int proc_en_cours = ParaGlob::Monde()->rank();
if (proc_en_cours != 0)
{
#endif
{
LaLIST ::const_iterator iNmin,iNmax,iTmax,il,ilfin = listContact.end();
LaLIST ::const_iterator ilbegin = listContact.begin();
for (il = iNmax = iTmax = iNmin = ilbegin;il != ilfin; il++)
if ((*il).Actif())
{ const ElContact& icont = (*il); // pour simplifier
double fNmax = icont.F_N_MAX();
double fTmax = icont.F_T_MAX();
if (fNmax < retour_min.un )
{retour_min.un = fNmax;iNmin = il;
};
if (fNmax > retour_max.un )
{retour_max.un = fNmax;iNmax = il;
};
// fTmax est toujours positif, donc on ne teste que le maxi
if (fTmax > retour_max.deux)
{retour_max.deux = fTmax;iTmax = il;
};
};
// affichage si on n'est pas en //
#ifndef UTILISATION_MPI
if ((affiche && (ParaGlob::NiveauImpression() > 2))
|| (niveau_commentaire_lescontacts > 3) // spécifiquement pour le contact
)
{ cout << "\n contact: reaction ==> F_N => [" << retour_min.un << " : " << retour_max.un << "]"
<< ", F_T max = " << retour_max.deux;
};
if (niveau_commentaire_lescontacts > 6)
{if (iNmin != ilbegin ){cout << "\n mini F_N : "; (*iNmin).Affiche(0);};
if (iNmax != ilbegin ){cout << "\n maxi F_N : "; (*iNmax).Affiche(0);};
if (iTmax != ilbegin ){cout << "\n maxi F_T : "; (*iTmax).Affiche(0);};
cout << "\n ";
}
else if (niveau_commentaire_lescontacts > 3)
{if (iNmin != ilbegin ) {cout << "\n mini F_N : "; (*iNmin).Affiche(1);};
if (iNmax != ilbegin ){cout << "\n maxi F_N : "; (*iNmax).Affiche(1);};
if (iTmax != ilbegin ){cout << "\n maxi F_T : "; (*iTmax).Affiche(1);};
cout << "\n ";
}
// cout << "\n contact: reaction ==> F_N max " << retour.un << " F_T max " << retour.deux;
// if (niveau_commentaire_lescontacts > 6)
// {if (iNmax != itbegin) {cout << "\n F_N max: "; (*iNmax).Affiche(0);};
// if (iTmax != itbegin) {cout << "\n F_T max: "; (*iTmax).Affiche(0);};
// cout << "\n";
// }
// else if (niveau_commentaire_lescontacts > 3)
// {if (iNmax != itbegin) {cout << "\n F_N max: "; (*iNmax).Affiche(1);};
// if (iTmax != itbegin) {cout << "\n F_T max: "; (*iTmax).Affiche(1);};
// cout << "\n";
// };
#endif
tempsContact.Arret_du_comptage(); // fin cpu
}
#ifdef UTILISATION_MPI
temps_transfert_court.Mise_en_route_du_comptage(); // comptage cpu
// maintenant on va transmettre au cpu 0
Vecteur v_inter(3);
v_inter(1) = retour_max.un; v_inter(2) = retour_max.deux;
v_inter(3) = retour_min.un;
// envoi
v_inter.Ienvoi_MPI(0,49);
// on attend pas
temps_transfert_court.Arret_du_comptage(); // fin comptage cpu
}
else // cas du cpu 0
{// l'objectif ici est de récupérer les infos
tempsContact.Arret_du_comptage(); // fin cpu
int nb_proc_terminer = 0; // permettra de terminer
while (nb_proc_terminer < (ParaGlob::Monde()->size()-1)) // gérer par les valeurs de tyfront
{ // on récupère un résultat de cpu i
temps_transfert_court.Mise_en_route_du_comptage(); // comptage cpu
Vecteur v_inter(3);
mpi::request reqs1 = v_inter.Irecup_MPI(mpi::any_source, 49);
reqs1.wait(); // on attend que le conteneur soit rempli
if (v_inter(1) > retour_max.un)
{retour_max.un = v_inter(1);};
if (v_inter(2) > retour_max.deux)
{retour_max.deux = v_inter(2);
};
if (v_inter(3) < retour_min.un)
{retour_min.un = v_inter(3);};
temps_transfert_court.Arret_du_comptage(); // fin comptage cpu
nb_proc_terminer++; // on prend en compte que l'on a récupéré un conteneur
};
if ((affiche && (ParaGlob::NiveauImpression() > 2))
|| (niveau_commentaire_lescontacts > 3) // spécifiquement pour le contact
)
// cout << "\n contact: reaction ==> |F_N max| = " << Dabs(retour_min.un) << " |F_T max| = " << DabsMaX(retour_min.deux,retour_max.deux);
cout << "\n contact: reaction ==> F_N => [" << retour_min.un << " : " << retour_max.un << "]"
<< ", F_T max = " << retour_max.deux;
};
#endif
tempsContact.Arret_du_comptage(); // fin cpu
return retour_max;
};
// récupération via les éléments de contact des gaps maxi en négatif, donc les mini
// un : le maxi en gap normal, deux: le maxi en gap tangentiel
// Dans le cas d'un calcul parallèle, il y a transfert du résultat au cpu 0
// seules les cpu i calculent
DeuxDoubles LesContacts::Gap_contact_maxi(bool affiche)
{tempsContact.Mise_en_route_du_comptage(); // def deb compt
DeuxDoubles retour_max,retour_min;
int niveau_commentaire_lescontacts = Permet_affichage();
#ifdef UTILISATION_MPI
int proc_en_cours = ParaGlob::Monde()->rank();
if (proc_en_cours != 0)
{
#endif
{
LaLIST ::const_iterator iNmax,iTmax,iNmin,iTmin,il,ilfin = listContact.end();
LaLIST ::const_iterator ilbegin=listContact.begin();
for (il = iNmax = iTmax = iNmin = iTmin = ilbegin;il != ilfin; il++)
if ((*il).Actif())
{ const ElContact& icont = (*il); // pour simplifier
double fNmax = icont.Gaptdt();
double fTmax = icont.Dep_T_tdt();
if (fNmax > retour_max.un )
{retour_max.un = fNmax;iNmax = il;
};
if (fNmax < retour_min.un )
{retour_min.un = fNmax;iNmin = il;
};
if (fTmax > retour_max.deux )
{retour_max.deux = fTmax;iTmax = il;
};
if (fTmax < retour_min.deux )
{retour_min.deux = fTmax;iTmin = il;
};
};
// affichage si on n'est pas en //
#ifndef UTILISATION_MPI
if ((affiche && (ParaGlob::NiveauImpression() > 2))
|| (niveau_commentaire_lescontacts > 3) // spécifiquement pour le contact
)
cout << ", [" << retour_min.un << " <= gap_N <= " << retour_max.un << "], [" << retour_min.deux <<" <= gap_T <= " << retour_max.deux<<"] ";
if (niveau_commentaire_lescontacts > 6)
{if (iNmin != ilbegin ){cout << "\n mini gap_N : "; (*iNmin).Affiche(0);};
if (iNmax != ilbegin ){cout << "\n maxi gap_N : "; (*iNmax).Affiche(0);};
if (iTmin != ilbegin ){cout << "\n mini gap_T : "; (*iTmin).Affiche(0);};
if (iTmax != ilbegin ){cout << "\n maxi gap_T : "; (*iTmax).Affiche(0);};
cout << "\n ";
}
else if (niveau_commentaire_lescontacts > 3)
{if (iNmin != ilbegin ) {cout << "\n mini gap_N : "; (*iNmin).Affiche(1);};
if (iNmax != ilbegin ){cout << "\n maxi gap_N : "; (*iNmax).Affiche(1);};
if (iTmin != ilbegin ){cout << "\n mini gap_T : "; (*iTmin).Affiche(1);};
if (iTmax != ilbegin ){cout << "\n maxi gap_T : "; (*iTmax).Affiche(1);};
cout << "\n ";
}
#endif
tempsContact.Arret_du_comptage(); // fin cpu
}
#ifdef UTILISATION_MPI
temps_transfert_court.Mise_en_route_du_comptage(); // comptage cpu
// maintenant on va transmettre au cpu 0
Vecteur v_inter(4);v_inter(1) = retour_max.un; v_inter(2) = retour_max.deux;
v_inter(3) = retour_min.un;v_inter(4) = retour_min.deux;
// envoi
v_inter.Ienvoi_MPI(0,60);
// on attend pas
temps_transfert_court.Arret_du_comptage(); // fin comptage cpu
}
else // cas du cpu 0
{// l'objectif ici est de récupérer les infos
tempsContact.Arret_du_comptage(); // fin cpu
int nb_proc_terminer = 0; // permettra de terminer
while (nb_proc_terminer < (ParaGlob::Monde()->size()-1)) // gérer par les valeurs de tyfront
{ // on récupère un résultat de cpu i
temps_transfert_court.Mise_en_route_du_comptage(); // comptage cpu
Vecteur v_inter(4);
mpi::request reqs1 = v_inter.Irecup_MPI(mpi::any_source, 60);
reqs1.wait(); // on attend que le conteneur soit rempli
if (v_inter(1) > retour_max.un)
{retour_max.un = v_inter(1);};
if (v_inter(2) > retour_max.deux)
{retour_max.deux = v_inter(2);
};
if (v_inter(3) < retour_min.un)
{retour_min.un = v_inter(3);};
if (v_inter(4) < retour_min.deux)
{retour_min.deux = v_inter(4);};
temps_transfert_court.Arret_du_comptage(); // fin comptage cpu
nb_proc_terminer++; // on prend en compte que l'on a récupéré un conteneur
};
if ((affiche && (ParaGlob::NiveauImpression() > 2))
|| (niveau_commentaire_lescontacts > 3) // spécifiquement pour le contact
)
cout << ", [" << retour_min.un << " <= gap_N <= " << retour_max.un << "], [" << retour_min.deux <<" <= gap_T <= " << retour_max.deux<<"] ";
};
#endif
tempsContact.Arret_du_comptage(); // fin cpu
return retour_min;
};
// création et ajout des éléments de frontière correspondant aux angles morts
// en 2D : noeud frontière + éléments interne
// en 3D : ligne frontière + éléments interne
void LesContacts::ElementAngleMort(LesMaillages& lesMail)
{
// la liste des éléments qui contiennent des frontières, est reconstitué au démarrage avec Init_contact(..
//>>>>> list liste_elemens_front;
// la liste pour chaque noeud, des éléments qui contient ce noeud : construite avec Init_contact
// indice(i)(j) : = la liste des éléments qui contiennent le noeud j, pour le maillage i
//>>>>> Tableau < const Tableau > *> indice;
// la liste des éléments frontières succeptibles d'entrer en contact
// ces Front (qui contiennent que des pointeurs sauf une boite d'encombrement)
// sont différents de ceux des maillages, et sont donc stocké en interne
//>>>>> Tableau < Tableau < LaLIST_io > > t_listFront;
// t_listFront(i)(j)(k) : maillage maître (i)
// zone de contact (j)
// (K) = kième frontière (dans l'ordre de la liste)
// ** pour le tableaux t_listFront, le numéros dit de maillage, n'est pas le numéro
// ** intrinsèque de maillage (telle que ceux associés aux noeuds et éléments)
// ** mais uniquement un numéro locale d'ordre
// ** mais on a: les éléments de frontière de t_listFront(i) font partie du maillage
// i + (nb_mail_Esclave-nbmailautocontact)
int niveau_commentaire_lescontacts = Permet_affichage();
#ifdef UTILISATION_MPI
if (ParaGlob::Monde()->rank() == 0)
#endif
if (niveau_commentaire_lescontacts > 4)
cout << "\n ==> LesContacts::ElementAngleMort: ";
// --- à la fin du traitement on a besoin de mettre à jour les éléments mitoyens des Front
// --- on sauvegarde des infos
Tableau < Tableau < list > > t_listFront_initial; // les pointeurs de front initiaux sans les angles morts
// t_liFront_noeud(i)(j)(k) : la liste des frontières initiales qui contiennent le noeud k de la zone j du maillage i
Tableau < Tableau < Tableau < list > > > t_liFront_noeud;
t_liFront_noeud.Change_taille(lesMail.NbMaillage());
//**** à faire la même chose pour les elements segment .....
int tail1 = t_listFront.Taille(); // num ordre dans les maillages
t_listFront_initial.Change_taille(tail1);
for (int i =1;i<= tail1;i++)
{int i_mail = i + (nb_mail_Esclave-nbmailautocontact); // le num de maillage
int nb_noe_total = lesMail.Nombre_noeud(i_mail); // le nombre total de noeud du maillage
int tail2=t_listFront(i).Taille(); // nombre de zones
t_listFront_initial(i).Change_taille(tail2);
t_liFront_noeud(i).Change_taille(tail2);
for (int j=1;j<= tail2;j++) // on balaie les zones
{list & t_listFront_initial_ij = t_listFront_initial(i)(j); // pour simplifier
LaLIST_io & t_listFront_ij = t_listFront(i)(j); // pour simplifier
// on dimensionne au nombre maxi de noeud pour chaque zone ...
// ça peut faire des gros tableaux mais il faut bien que l'on sache à quelle zone on s'intéresse ...
// donc pour l'instant c'est l'idée que je retiens
t_liFront_noeud(i)(j).Change_taille(nb_noe_total);
Tableau >& t_liFront_noeud_ij = t_liFront_noeud(i)(j);
LaLIST_io ::iterator il,ilfin=t_listFront_ij.end();
for (il = t_listFront_ij.begin();il != ilfin; il++)
{t_listFront_initial_ij.push_back(&(*il));
// on va remplir t_liFront_noeud_ij
ElFrontiere* elfro = (*il).Eleme(); // pour simplifier
const Tableau & tabN = elfro->TabNoeud_const();
int nbNF = tabN.Taille();
for (int l=1;l<=nbNF;l++)
{ Noeud * noe = tabN(l);
t_liFront_noeud_ij(noe->Num_noeud()).push_back(&(*il));
};
};
};
};
// --- constitution des front d'angle mort
// l'idée est de rechercher les éléments qui sont en relation directe avec la frontière
// via une ligne ou un point, mais qui n'ont été pris en compte du fait qu'ils n'étaient pas
// reliés à une frontière de base
// on commence par les lignes ce qui conduit éventuellement à augmenter t_listFront
// ensuite on regarde les noeuds. Ainsi, si un élément nouveau est introduit via les lignes
// les noeuds de la ligne + l'élément ne vont pas s'ajouter
// 1) === cas des lignes frontières + éléments internes
// ce cas ne concerne que les espaces de travail 3D non axisymétrique
if ((ParaGlob::Dimension() == 3) && !(ParaGlob::AxiSymetrie()))
{ // on crée les frontières lignes au cas où
lesMail.CreeListFrontiere_ligne_3D();
// on récupère toutes les frontières lignes
// ramène le tableau de pointeurs de frontières ligne 3D créées par CreeListFrontiere_ligne_3D
Tableau *>& lifrLigne = lesMail.ListFront_ligne_3D();
if (nom_ref_zone_contact.size() == 0)
{ // cas d'un contact non restreint
// cela correspond finalement à une seule zone de contact (cf. Init_contact(..))
//on boucle sur les maillages maitres de t_listFront
for (int im=1;im<=nbmailMaitre;im++)
{ // ici on ne boucle pas sur les zones restreintes car il n'y en n'a pas
LaLIST_io & la_list_des_front = t_listFront(im)(1);
int nb_front_init = la_list_des_front.size(); // la taille initiale
LaLIST & lifrLigne_mail = *lifrLigne(im); // pour simplifier
// avant de balayer les lignes, on fait une liste des éléments qui contiennent des frontières déjà référencées
list li_Elem_avec_front;
LaLIST_io ::iterator il,ilfin = la_list_des_front.end();
for (il = la_list_des_front.begin(); il != ilfin; il++)
li_Elem_avec_front.push_back((*il).PtEI());
// on supprime les doublons et on ordonne, c'est pour l'opti des recherches ensuites
li_Elem_avec_front.sort(); // ordonne
li_Elem_avec_front.unique(); // supprime les doublons
// maintenant on regarde s'il faut ajouter des éléments d'angle mort
// on va boucler sur les frontières lignes 3D
LaLIST ::iterator jl,jlfin=lifrLigne_mail.end();
for (jl = lifrLigne_mail.begin(); jl != jlfin; jl++)
{ Element * el = (*jl).PtEI();// récup de l'élément
// on regarde si cet élément ne fait pas partie de la liste d'élément
// qui contient déjà une frontière
if (find(li_Elem_avec_front.begin(),li_Elem_avec_front.end(),el) == li_Elem_avec_front.end())
// on n'a pas trouvé d'élément,
//on ajoute l'élément front sauf cas particulier
{// on fait quelques tests pour écarter des cas non recevable
bool continuer = true; // par défaut
// si on est en 3D et que l'élément est lui même un élément ligne, ou un
// élément de surface, il ne constitue pas un angle mort puisqu'il n'y à pas de volume mort associé
Enum_type_geom enu_type_geom_ele = Type_geom_generique(el->Id_geometrie());
if ((enu_type_geom_ele == LIGNE) && (enu_type_geom_ele == SURFACE))
{continuer = false;}
if (continuer)
// on doit indiquer qu'il s'agit d'un élément d'angle mort
// on se sert d'un élément intermédiaire
{Front inter((*jl));
inter.Change_angle_mort(1);
la_list_des_front.push_back(inter);
};
}
};
int nb_front_fin = la_list_des_front.size(); // la taille finale
#ifdef UTILISATION_MPI
if (ParaGlob::Monde()->rank() == 0)
#endif
if (niveau_commentaire_lescontacts >2 )
cout << "\n mail. maitre "<& lifrLigne_mail = *lifrLigne(im); // pour simplifier
// ici on boucle sur les zones restreintes
int nb_zone_et1 = 1+t_listFront(im).Taille();
for (int i_zone=1;i_zone < nb_zone_et1;i_zone++)
{// la liste des front de la zone
LaLIST_io & la_list_des_front = t_listFront(im)(i_zone);
int nb_front_init = la_list_des_front.size(); // la taille initiale
// avant de balayer les lignes, on fait une liste des éléments relatifs à la zone
// qui contiennent des frontières déjà référencées
list li_Elem_avec_front;
LaLIST_io ::iterator il,ilfin = la_list_des_front.end();
for (il = la_list_des_front.begin(); il != ilfin; il++)
li_Elem_avec_front.push_back((*il).PtEI());
// on supprime les doublons et on ordonne, c'est pour l'opti des recherches ensuites
li_Elem_avec_front.sort(); // ordonne
li_Elem_avec_front.unique(); // supprime les doublons
// maintenant on regarde s'il faut ajouter des éléments d'angle mort
// on va boucler sur les frontières lignes 3D
LaLIST ::iterator jl,jlfin=lifrLigne_mail.end();
for (jl = lifrLigne_mail.begin(); jl != jlfin; jl++)
{ Element * el = (*jl).PtEI();// récup de l'élément
// on regarde si cet élément ne fait pas partie de la liste d'élément
// qui contient déjà une frontière
if (find(li_Elem_avec_front.begin(),li_Elem_avec_front.end(),el) == li_Elem_avec_front.end())
// on n'a pas trouvé d'élément,
//on ajoute l'élément front sauf cas particulier
{// on fait quelques tests pour écarter des cas non recevable
bool continuer = true; // par défaut
// si on est en 3D et que l'élément est lui même un élément ligne, ou un
// élément de surface, il ne constitue pas un angle mort puisqu'il n'y à pas de volume mort associé
Enum_type_geom enu_type_geom_ele = Type_geom_generique(el->Id_geometrie());
if ((enu_type_geom_ele == LIGNE) && (enu_type_geom_ele == SURFACE))
{continuer = false;}
if (continuer)
// on n'a pas trouvé d'élément, on ajoute l'élément front
// on doit indiquer qu'il s'agit d'un élément d'angle mort
// on se sert d'un élément intermédiaire
{Front inter((*jl));
inter.Change_angle_mort(1);
la_list_des_front.push_back(inter);
};
};
};
int nb_front_fin = la_list_des_front.size(); // la taille finale
#ifdef UTILISATION_MPI
if (ParaGlob::Monde()->rank() == 0)
#endif
if (niveau_commentaire_lescontacts >2 )
cout << "\n mail. maitre "<*>& listFrontiere = lesMail.ListFrontiere();
int ntmail = listFrontiere.Taille(); // nb maxi de maillages
// on regarde si la zone de contact est restreinte
if (nom_ref_zone_contact.size() == 0)
{ // cas d'un contact non restreint
// cela correspond finalement à une seule zone de contact (cf. Init_contact(..))
int ilistfront = 1; // compteur pour le tableau t_listFront
// on parcours les elements maitres: à cause d'un auto contact
// éventuelle on peut avoir des maillages esclaves qui jouent le rôle également de
// maillages maitres
//on boucle sur les maillages maitres de t_listFront
for (int jf=ntmail-nbmailMaitre+1;jf<=ntmail;jf++,ilistfront++)
{ // ici on ne boucle pas sur les zones restreintes car il n'y en n'a pas
LaLIST_io & la_list_des_front = t_listFront(ilistfront)(1);
int nb_front_init = la_list_des_front.size(); // la taille initiale
// pour continuer il faut: 1) qu'il y a des front, 2) que ces fronts appartiennent au maillage
if (nb_front_init > 0)
if ((*la_list_des_front.begin()).NumMail() == jf )
{
// on va créer une liste de numéro des noeuds de la zone de frontière concernée
// et en même temps
// avant de balayer les noeuds, on fait une liste des éléments relatifs à la zone
// qui contiennent des frontières déjà référencées
list num_noe_front;
list li_Elem_avec_front;
LaLIST_io ::iterator il,ilfin = la_list_des_front.end();
for (il = la_list_des_front.begin(); il != ilfin; il++)
{ const Tableau & tnoe = (*il).Eleme()->TabNoeud_const();
int nb_noe_et1 = tnoe.Taille();
for (int m =1;mNum_noeud());
li_Elem_avec_front.push_back((*il).PtEI());
};
// on ordonne et on supprime les doublons
num_noe_front.sort(); // ordonne
num_noe_front.unique(); // suppression des doublons
li_Elem_avec_front.sort(); // ordonne
li_Elem_avec_front.unique(); // supprime les doublons
// on définit une liste temporaire des nouvelles front d'angle mort créé
// c'est utilisé pour définir les mitoyens des éléments d'angle morts
// qui sont apparus avec les angles morts (== les mitoyens angle mort des éléments angle morts !!)
list front_angle_mort;
// maintenant on parcours les noeuds contenu dans num_noe_front
// et on regarde s'il faut ajouter des éléments point d'angle mort
list ::iterator ih,ih_fin=num_noe_front.end();
for (ih = num_noe_front.begin();ih != ih_fin;ih++)
{int i_noe = (*ih); // le num du noeud maître que l'on va tester
Tableau ttn(1);
ttn(1)= &(lesMail.Noeud_LesMaille(jf,i_noe)); // récup du pointeur de noeud
////------ debug
//if (ttn(1)->Num_noeud() == 37 )
// cout << "\n debug LesContacts::ElementAngleMort(...";
//// fin debug
// récup de la liste pour le noeud i_noe, des éléments qui contient ce noeud : construite avec Init_contact
const List_io < Element* >& liel = (*indice(jf))(i_noe);
// on boucle sur chaque élément qui contient le noeud
List_io < Element* >::const_iterator il,ilfin=liel.end();
for (il = liel.begin();il != ilfin;il++)
{const Element* el=(*il); // pour simplifier
// on regarde si cet élément ne fait pas partie de la liste d'élément
// qui contient déjà une frontière
bool trouver = false;
list ::const_iterator ikl,iklfin=li_Elem_avec_front.end();
for (ikl = li_Elem_avec_front.begin();ikl != iklfin; ikl++)
{if (((*ikl)->Num_elt_const() == el->Num_elt_const()) && ((*ikl)->Num_maillage() == el->Num_maillage()))
{trouver= true; break;}
};
if (!trouver)
{// on n'a pas trouvé d'élément,
// 1. on récup le num local EF du noeud
int nb_noeu_el_et_1 = 1+el->Nombre_noeud(); // le nombre de noeud de l'élément
int num_noe_local = 0;
for (int k =1;kNum_noeud(k) == ttn(1)->Num_noeud())
{num_noe_local=k; break;};
// 2. on récupère la frontière noeud correspondante en forçant une création éventuelle
// on passe par l'intermédiaire de lesMail pour pouvoir modifier l'élément
// car c'est l'élément qui stocke et gère la frontière
Element& elem_non_const = lesMail.Element_LesMaille(el->Num_maillage(), el->Num_elt_const());
// on fait quelques tests pour écarter des cas non recevable
bool continuer = true; // par défaut
// a) si on est en 2D axi et que l'élément est un élément noeud ou un élément ligne, cela veut dire
// qu'il génére par rotation en 3D : une ligne ou une surface, or lignes ou surfaces n'intègrent pas
// d'élément de contact d'angle mort puisqu'il n'y à pas de volume mort associé
Enum_type_geom enu_type_geom_ele = Type_geom_generique(elem_non_const.Id_geometrie());
if (ParaGlob::AxiSymetrie() && ((enu_type_geom_ele == POINT_G) || (enu_type_geom_ele == LIGNE)))
{continuer = false;}
// b) si on est en axi et qu'il s'agit d'un élément surface, là c'est bon
else if (ParaGlob::AxiSymetrie() && (enu_type_geom_ele == SURFACE))
{continuer = true;}
// c) si on est en 3D et que l'élément est un élément noeud, ou ligne, ou surface, même sentence
else if ((ParaGlob::Dimension() == 3)
&& ((enu_type_geom_ele == POINT_G) || (enu_type_geom_ele == LIGNE) || (enu_type_geom_ele == SURFACE))
)
{continuer = false;}
// on continue sauf cas particulier
if (continuer)
{// 3. on crée l'élément de frontière ad hoc
ElFrontiere* const elfpoint = elem_non_const.Frontiere_points(num_noe_local,true);
// ramene le numero de la frontière passée en argument si elle existe actuellement au niveau de l'élément
// sinon ramène 0
// ramene également type_front: qui indique le type de frontière: POINT_G, LIGNE ou SURFACE
// c'est une méthode très longue, a utiliser avec précaution
Enum_type_geom type_front;
int num_front = el->Num_frontiere(*elfpoint,type_front);
// 4. on crée l'élément front ad hoc et on l'ajoute à la liste
int angle_mort = 1;
la_list_des_front.push_front(Front(*elfpoint,&elem_non_const,num_front,angle_mort));
LaLIST_io ::iterator iik = la_list_des_front.begin(); // récup de l'iterator
// on met à jour les frontières mitoyennes
int num_noeud = ttn(1)->Num_noeud(); // le num global du noeud
// récup de la liste des frontières initiales contenant le noeud
list & t_liFront_noeud_ijk = t_liFront_noeud(ilistfront)(1)(num_noeud);
list ::iterator km,kmfin=t_liFront_noeud_ijk.end();
for (km=t_liFront_noeud_ijk.begin();km != kmfin;km++)
{(*km)->AjoutMitoyen(&(*iik));// ajout frontière pour la frontière initiale
(*iik).AjoutMitoyen(*km); // ajout frontière pour la nouvelle frontière d'angle mort
};
// on sauvegarde le nouvelle front dans une liste spécifique
front_angle_mort.push_front(&(*iik));
#ifdef UTILISATION_MPI
if (ParaGlob::Monde()->rank() == 0)
#endif
if (niveau_commentaire_lescontacts >4 )
{ cout << "\n ajout front point: noeud "<Num_noeud(num_noe_local)
<< " mail: " << jf //<< " zone "
<< " element: "<Num_elt_const() ;
};
};
};
};
};
int nb_front_fin = la_list_des_front.size(); // la taille finale
#ifdef UTILISATION_MPI
if (ParaGlob::Monde()->rank() == 0)
#endif
if (niveau_commentaire_lescontacts >2 )
cout << "\n ajout angle mort pour contact: mail. maitre "<< jf <<" : "<<(nb_front_fin-nb_front_init)
<< " frontieres point ";
#ifdef MISE_AU_POINT
// petite vérif en passant
#ifdef UTILISATION_MPI
if (ParaGlob::Monde()->rank() == 0)
#endif
if ((nb_front_fin-nb_front_init) != front_angle_mort.size())
{cout << "\n *** erreur dans la definition des elements point d'angle mort "
<< " on a deux listes qui les representent mais qui n'ont pas la meme taille "
<< (nb_front_fin-nb_front_init) << " et " << front_angle_mort.size()
<< "\n LesContacts::ElementAngleMort(..";
Sortie(1);
};
#endif
// on utilise front_angle_mort pour définir les mitoyens angle mort des éléments angle morts
list ::iterator ag,agfin=front_angle_mort.end();
for (ag=front_angle_mort.begin();ag != agfin; ag++)
{list ::iterator bg;
bg = ag; bg++;
// on utilise deux boucles imbriquées
for ( ; bg!= agfin ; bg++)
{const Tableau & tan = (*ag)->Eleme()->TabNoeud_const();
const Tableau & tbn = (*bg)->Eleme()->TabNoeud_const();
// normalement c'est des FrontPoinF, donc il n'y a qu'un seul noeud frontière
if (tan(1)->Num_noeud() == tbn(1)->Num_noeud())
// les deux éléments FrontPoinF partage le même noeud,
// on met à jour les mitoyens
{ (*ag)->AjoutMitoyen((*bg));
(*bg)->AjoutMitoyen((*ag));
};
};
};
}; // fin du test if (nb_front_init > 0) et if ((*la_list_des_front.begin()).NumMail() == jf )
}; // fin de la boucle sur les maillages maitres de t_listFront
}
else
{ // cas d'une zone restreinte de contact
// on va boucler sur les zones définies pour le contact
int ilistfront = 1; // compteur pour le tableau t_listFront
// on parcours les elements maitres: à cause d'un auto contact
// éventuelle on peut avoir des maillages esclaves qui jouent le rôle également de
// maillages maitres
//on boucle sur les maillages maitres de t_listFront
for (int jf=ntmail-nbmailMaitre+1;jf<=ntmail;jf++,ilistfront++)
{ // ici on boucle sur les zones restreintes
int nb_zone_et1 = 1+t_listFront(ilistfront).Taille();
for (int i_zone=1;i_zone < nb_zone_et1;i_zone++)
{// la liste des front de la zone
LaLIST_io & la_list_des_front = t_listFront(ilistfront)(i_zone);
int nb_front_init = la_list_des_front.size(); // la taille initiale
// pour continuer il faut: 1) qu'il y a des front, 2) que ces fronts appartiennent au maillage
if (nb_front_init > 0)
if ((*la_list_des_front.begin()).NumMail() == jf )
{
// on va créer une liste de numéro des noeuds de la zone de frontière concernée
// et en même temps
// avant de balayer les noeuds, on fait une liste des éléments relatifs à la zone
// qui contiennent des frontières déjà référencées
list num_noe_front;
list li_Elem_avec_front;
LaLIST_io ::iterator il,ilfin = la_list_des_front.end();
for (il = la_list_des_front.begin(); il != ilfin; il++)
{ const Tableau & tnoe = (*il).Eleme()->TabNoeud_const();
int nb_noe_et1 = tnoe.Taille();
for (int m =1;mNum_noeud());
li_Elem_avec_front.push_back((*il).PtEI());
};
// on ordonne et on supprime les doublons
num_noe_front.sort(); // ordonne
num_noe_front.unique(); // suppression des doublons
li_Elem_avec_front.sort(); // ordonne
li_Elem_avec_front.unique(); // supprime les doublons
// on définit une liste temporaire des nouvelles front d'angle mort créé
// c'est utilisé pour définir les mitoyens des éléments d'angle morts
// qui sont apparus avec les angles morts (== les mitoyens angle mort des éléments angle morts !!)
list front_angle_mort;
// maintenant on parcours les noeuds contenu dans num_noe_front
// et on regarde s'il faut ajouter des éléments point d'angle mort
list ::iterator ih,ih_fin=num_noe_front.end();
for (ih = num_noe_front.begin();ih != ih_fin;ih++)
{int i_noe = (*ih); // le num du noeud maître que l'on va tester
Tableau ttn(1);
ttn(1)= &(lesMail.Noeud_LesMaille(jf,i_noe)); // récup du pointeur de noeud
// récup de la liste pour le noeud i_noe, des éléments qui contient ce noeud : construite avec Init_contact
const List_io < Element* >& liel = (*indice(jf))(i_noe);
// on boucle sur chaque élément qui contient le noeud
List_io < Element* >::const_iterator il,ilfin=liel.end();
for (il = liel.begin();il != ilfin;il++)
{const Element* el=(*il); // pour simplifier
// on regarde si cet élément ne fait pas partie de la liste d'élément
// qui contient déjà une frontière
bool trouver = false;
list ::const_iterator ikl,iklfin=li_Elem_avec_front.end();
for (ikl = li_Elem_avec_front.begin();ikl != iklfin; ikl++)
{if (((*ikl)->Num_elt_const() == el->Num_elt_const()) && ((*ikl)->Num_maillage() == el->Num_maillage()))
{trouver= true; break;}
};
if (!trouver)
{// on n'a pas trouvé d'élément,
// 1. on récup le num local EF du noeud
int nb_noeu_el_et_1 = 1+el->Nombre_noeud(); // le nombre de noeud de l'élément
int num_noe_local = 0;
for (int k =1;kNum_noeud(k) == ttn(1)->Num_noeud())
{num_noe_local=k; break;};
// 2. on récupère la frontière noeud correspondante en forçant une création éventuelle
// on passe par l'intermédiaire de lesMail pour pouvoir modifier l'élément
// car c'est l'élément qui stocke et gère la frontière
Element& elem_non_const = lesMail.Element_LesMaille(el->Num_maillage(), el->Num_elt_const());
// on fait quelques tests pour écarter des cas non recevable
bool continuer = true; // par défaut
// a) si on est en 2D axi et que l'élément est un élément noeud ou un élément ligne, cela veut dire
// qu'il génére par rotation en 3D : une ligne ou une surface, or lignes ou surfaces n'intègrent pas
// d'élément de contact d'angle mort puisqu'il n'y à pas de volume mort associé
Enum_type_geom enu_type_geom_ele = Type_geom_generique(elem_non_const.Id_geometrie());
if (ParaGlob::AxiSymetrie() && ((enu_type_geom_ele == POINT_G) || (enu_type_geom_ele == LIGNE)))
{continuer = false;}
// b) si on est en axi et qu'il s'agit d'un élément surface, là c'est bon
else if (ParaGlob::AxiSymetrie() && (enu_type_geom_ele == SURFACE))
{continuer = true;}
// c) si on est en 3D et que l'élément est un élément noeud, ou ligne, ou surface, même sentence
else if ((ParaGlob::Dimension() == 3)
&& ((enu_type_geom_ele == POINT_G) || (enu_type_geom_ele == LIGNE) || (enu_type_geom_ele == SURFACE))
)
{continuer = false;}
// on continue sauf cas particulier
if (continuer)
{// 3. on crée l'élément de frontière ad hoc
ElFrontiere* const elfpoint = elem_non_const.Frontiere_points(num_noe_local,true);
// ramene le numero de la frontière passée en argument si elle existe actuellement au niveau de l'élément
// sinon ramène 0
// ramene également type_front: qui indique le type de frontière: POINT_G, LIGNE ou SURFACE
// c'est une méthode très longue, a utiliser avec précaution
Enum_type_geom type_front;
int num_front = el->Num_frontiere(*elfpoint,type_front);
// 4. on crée l'élément front ad hoc et on l'ajoute à la liste
int angle_mort = 1;
la_list_des_front.push_front(Front(*elfpoint,&elem_non_const,num_front,angle_mort));
LaLIST_io ::iterator iik = la_list_des_front.begin(); // récup de l'iterator
// on met à jour les frontières mitoyennes
// // t_liFront_noeud(i)(j)(k) : la liste des frontières initiales qui contiennent le noeud k de la zone j du maillage i
// Tableau < Tableau < Tableau < list > > > t_liFront_noeud;
int num_noeud = ttn(1)->Num_noeud(); // le num global du noeud
// récup de la liste des frontières initiales contenant le noeud
list & t_liFront_noeud_ijk = t_liFront_noeud(ilistfront)(i_zone)(num_noeud);
list ::iterator km,kmfin=t_liFront_noeud_ijk.end();
for (km=t_liFront_noeud_ijk.begin();km != kmfin;km++)
{(*km)->AjoutMitoyen(&(*iik));// ajout frontière pour la frontière initiale
(*iik).AjoutMitoyen(*km); // ajout frontière pour la nouvelle frontière d'angle mort
};
// on sauvegarde le nouvelle front dans une liste spécifique
front_angle_mort.push_front(&(*iik));
#ifdef UTILISATION_MPI
if (ParaGlob::Monde()->rank() == 0)
#endif
if (niveau_commentaire_lescontacts >4 )
{ cout << "\n ajout front point: noeud "<Num_noeud(num_noe_local)
<< " mail: " << jf << " zone "<< i_zone
<< " element: "<Num_elt_const() ;
};
};
};
};
};
int nb_front_fin = la_list_des_front.size(); // la taille finale
#ifdef UTILISATION_MPI
if (ParaGlob::Monde()->rank() == 0)
#endif
if (niveau_commentaire_lescontacts >2 )
cout << "\n ajout angle mort pour contact: mail. maitre "<rank() == 0)
#endif
if ((nb_front_fin-nb_front_init) != front_angle_mort.size())
{cout << "\n *** erreur dans la definition des elements point d'angle mort "
<< " on a deux listes qui les representent mais qui n'ont pas la meme taille "
<< (nb_front_fin-nb_front_init) << " et " << front_angle_mort.size()
<< "\n LesContacts::ElementAngleMort(..";
Sortie(1);
};
#endif
// on utilise front_angle_mort pour définir les mitoyens angle mort des éléments angle morts
list ::iterator ag,agfin=front_angle_mort.end();
for (ag=front_angle_mort.begin();ag != agfin; ag++)
{list ::iterator bg;
bg = ag; bg++;
// on utilise deux boucles imbriquées
for ( ; bg!= agfin ; bg++)
{const Tableau & tan = (*ag)->Eleme()->TabNoeud_const();
const Tableau & tbn = (*bg)->Eleme()->TabNoeud_const();
// normalement c'est des FrontPoinF, donc il n'y a qu'un seul noeud frontière
if (tan(1)->Num_noeud() == tbn(1)->Num_noeud())
// les deux éléments FrontPoinF partage le même noeud,
// on met à jour les mitoyens
{ (*ag)->AjoutMitoyen((*bg));
(*bg)->AjoutMitoyen((*ag));
};
};
};
#ifdef UTILISATION_MPI
if (ParaGlob::Monde()->rank() == 0)
#endif
if (niveau_commentaire_lescontacts >7 )
{ cout << "\n liste finale des elements angle mort "
<< " mail: " << jf << " zone "<< i_zone;
for (ag=front_angle_mort.begin();ag != agfin; ag++)
(*ag)->Affiche();
};
}; // fin du test if (nb_front_init > 0) et if ((*la_list_des_front.begin()).NumMail() == jf )
};// fin de la boucle sur les zones
}; // fin de la boucle sur les maillages maitres de t_listFront
}; // fin du test avec ou sans zone de contact
};
// init éventuel du pilotage par fct nD du niveau de commentaire
void LesContacts::Init_fct_niveau_commentaire()
{
#ifdef UTILISATION_MPI
int proc_en_cours = ParaGlob::Monde()->rank();
#endif
string nom_fct = ParaGlob::param->ParaAlgoControleActifs().Fct_niveau_commentaire_LesContact();
if (nom_fct != "_")
{// on va récupérer la fonction
if (sauve_lesFonctionsnD->Existe(nom_fct))
{ Fonction_nD * pt_fonct = sauve_lesFonctionsnD->Trouve(nom_fct);
// sauvegarde
fct_niveau_commentaire = pt_fonct;
}
else
{
#ifdef UTILISATION_MPI
cout << "\n proc " << proc_en_cours
#else
cout << "\n"
#endif
<< " *** erreur dans la definition de la fonction nD de pilotage du "
<< " niveau de commentaire en contact, le nom : " << nom_fct
<< " ne correspond pas a une fonction nD existante !! ";
Sortie(1);
};
}
else
{fct_niveau_commentaire=NULL;};
// initialisation des conteneurs de la fonction nD
if (fct_niveau_commentaire != NULL)
Definition_conteneurs_fctnD_TypeQuelconque
(fct_niveau_commentaire
,tqi_fct_nD_niveau_commentaire,tqi_const_fct_nD_niveau_commentaire
,t_num_ordre_fct_nD_niveau_commentaire);
};
// définition des conteneurs static des TypeQuelconque
void LesContacts::Definition_conteneurs_fctnD_TypeQuelconque
(Fonction_nD * pt_fonct,Tableau < TypeQuelconque * >& tqi,Tableau < const TypeQuelconque * >& tqii
,Tableau & t_num_ordre )
{// on commence par récupérer le conteneurs des grandeurs à fournir
const Tableau & tab_queconque = pt_fonct->Tab_enu_quelconque();
// on dimensionne
int tail_tab_queconque = tab_queconque.Taille();
tqi.Change_taille(tail_tab_queconque);
t_num_ordre.Change_taille(tail_tab_queconque);
Grandeur_scalaire_entier grand_courant_entier(0); // par défaut pour la création des conteneurs quelconques
Grandeur_scalaire_double grand_courant_double(0.); // par défaut pour la création des conteneurs quelconques
// grandeurs de travail
int dim = ParaGlob::Dimension();
Coordonnee inter(dim);
Grandeur_coordonnee grand_coor_courant(inter);
// on va balayer les grandeurs quelconques
for (int i=1;i<= tail_tab_queconque;i++)
{ bool trouver = false;
EnumTypeQuelconque enu = tab_queconque(i);
tqi(i) = NULL; // init
t_num_ordre(i) = 1; //***** pour l'instant uniquement la première coordonnée s'il s'agit d'un Coordonnee
// *** à abonder par la suite !!!!!!!!!!
// on regarde tout d'abord les grandeurs spécifiques
switch (enu)
{ // il y a des grandeurs vectorielles qui pour l'instant ne sont pas prises en compte
// cf. fct nD
// NORMALE_CONTACT, GLISSEMENT_CONTACT ,PENETRATION_CONTACT,FORCE_CONTACT,
case CONTACT_NB_DECOL:
{ tqi(i) = new TypeQuelconque(CONTACT_NB_DECOL,X1,grand_courant_entier);
trouver = true;
break;
}
case CONTACT_PENALISATION_N:
{ tqi(i) = new TypeQuelconque(CONTACT_PENALISATION_N,X1,grand_courant_double);
trouver = true;
break;
}
case CONTACT_PENALISATION_T:
{ tqi(i) = new TypeQuelconque(CONTACT_PENALISATION_T,X1,grand_courant_double);
trouver = true;
break;
}
case CONTACT_NB_PENET:
{ tqi(i) = new TypeQuelconque(CONTACT_NB_PENET,X1,grand_courant_entier);
trouver = true;
break;
}
case CONTACT_CAS_SOLIDE:
{ tqi(i) = new TypeQuelconque(CONTACT_CAS_SOLIDE,X1,grand_courant_entier);
trouver = true;
break;
}
case CONTACT_ENERG_GLISSE_ELAS:
{ tqi(i) = new TypeQuelconque(CONTACT_ENERG_GLISSE_ELAS,X1,grand_courant_double);
trouver = true;
break;
}
case CONTACT_ENERG_GLISSE_PLAS:
{ tqi(i) = new TypeQuelconque(CONTACT_ENERG_GLISSE_PLAS,X1,grand_courant_double);
trouver = true;
break;
}
case CONTACT_ENERG_GLISSE_VISQ:
{ tqi(i) = new TypeQuelconque(CONTACT_ENERG_GLISSE_VISQ,X1,grand_courant_double);
trouver = true;
break;
}
case CONTACT_ENERG_PENAL:
{ tqi(i) = new TypeQuelconque(CONTACT_ENERG_PENAL,X1,grand_courant_double);
trouver = true;
break;
}
case NOEUD_PROJECTILE_EN_CONTACT:
{ tqi(i) = new TypeQuelconque(NOEUD_PROJECTILE_EN_CONTACT,X1,grand_courant_double);
trouver = true;
break;
}
case NOEUD_FACETTE_EN_CONTACT:
{ tqi(i) = new TypeQuelconque(NOEUD_FACETTE_EN_CONTACT,X1,grand_courant_double);
// Grandeur_scalaire_double& gr= *((Grandeur_scalaire_double*) ((*tqi(i)).Grandeur_pointee()));
trouver = true;
break;
}
case NUM_NOEUD:
{ tqi(i) = new TypeQuelconque(NUM_NOEUD,X1,grand_courant_entier);
trouver = true;
break;
}
case NUM_MAIL_NOEUD:
{ tqi(i) = new TypeQuelconque(NUM_MAIL_NOEUD,X1,grand_courant_entier);
trouver = true;
break;
}
case POSITION_GEOMETRIQUE:
{tqi(i) = new TypeQuelconque(POSITION_GEOMETRIQUE,X1,grand_coor_courant);
trouver = true;
break;
}
case POSITION_GEOMETRIQUE_t:
{tqi(i) = new TypeQuelconque(POSITION_GEOMETRIQUE_t,X1,grand_coor_courant);
trouver = true;
break;
}
case POSITION_GEOMETRIQUE_t0:
{tqi(i) = new TypeQuelconque(POSITION_GEOMETRIQUE_t0,X1,grand_coor_courant);
trouver = true;
break;
}
// *** pour l'instant la suite n'est pas opérationelle car il s'agit de vecteur
// dont les composantes n'ont pas d'équivalent en ddl_enum_etendu
// il faudrait les définir si on veut pouvoir s'en servir
case PENETRATION_CONTACT:
{tqi(i) = new TypeQuelconque(PENETRATION_CONTACT,X1,grand_coor_courant);
trouver = true;
break;
}
case PENETRATION_CONTACT_T:
{tqi(i) = new TypeQuelconque(PENETRATION_CONTACT_T,X1,grand_coor_courant);
trouver = true;
break;
}
case GLISSEMENT_CONTACT:
{tqi(i) = new TypeQuelconque(GLISSEMENT_CONTACT,X1,grand_coor_courant);
trouver = true;
break;
}
case GLISSEMENT_CONTACT_T:
{tqi(i) = new TypeQuelconque(GLISSEMENT_CONTACT_T,X1,grand_coor_courant);
trouver = true;
break;
}
case NORMALE_CONTACT:
{tqi(i) = new TypeQuelconque(NORMALE_CONTACT,X1,grand_coor_courant);
trouver = true;
break;
}
case FORCE_CONTACT:
{tqi(i) = new TypeQuelconque(FORCE_CONTACT,X1,grand_coor_courant);
trouver = true;
break;
}
case FORCE_CONTACT_T:
{tqi(i) = new TypeQuelconque(POSITION_GEOMETRIQUE,X1,grand_coor_courant);
trouver = true;
break;
}
case CONTACT_COLLANT:
{ tqi(i) = new TypeQuelconque(CONTACT_COLLANT,X1,grand_courant_entier);
trouver = true;
break;
}
case NUM_ZONE_CONTACT:
{ tqi(i) = new TypeQuelconque(NUM_ZONE_CONTACT,X1,grand_courant_entier);
trouver = true;
break;
}
case NUM_ELEMENT:
{ tqi(i) = new TypeQuelconque(NUM_ELEMENT,X1,grand_courant_entier);
trouver = true;
break;
}
case NUM_MAIL_ELEM:
{ tqi(i) = new TypeQuelconque(NUM_MAIL_ELEM,X1,grand_courant_entier);
trouver = true;
break;
}
//*** fin
default:
trouver = false;
break;
};
// si on n'a rien trouvé
if (!trouver)
{cout << "\n erreur***: la grandeur " << NomTypeQuelconque(enu)
<< " n'existe pas les elements de contact "
<< " la fonction nD " << pt_fonct->NomFonction()
<< " ne peut pas etre renseignee "
<< "\n ElContact::Fct_nD_contact::Definition_conteneurs_static_TypeQuelconque(.." << flush;
pt_fonct->Affiche();
Sortie(1);
};
};
// tableau de const intermédiaire pour l'appel de la fonction
tqii.Change_taille(tail_tab_queconque);
for (int i=1;i<= tail_tab_queconque;i++)
tqii(i) = tqi(i);
};
// calcul d'une fonction nD relative à des données de LesContacts
double LesContacts::Valeur_fct_nD_LesContacts
(Fonction_nD * pt_fonct,list* li
,Tableau < TypeQuelconque * >& tqi
,Tableau < const TypeQuelconque * >& tqii
,Tableau & t_num_ordre) const
{ // on commence par récupérer les conteneurs des grandeurs à fournir
List_io & li_enu_scal = pt_fonct->Li_enu_etendu_scalaire();
List_io & li_quelc = pt_fonct->Li_equi_Quel_evolue();
const Tableau & tab_queconque = pt_fonct->Tab_enu_quelconque();
// on passe en revue les grandeurs pour les renseigner
// --- on balaie maintenant la liste des grandeurs à sortir
// 1) tout d'abord les ddl étendues
// pour l'instant cette liste doit-être vide
if (li_enu_scal.size() != 0)
{ cout << "\n *** erreur : LesContacts::Valeur_fct_nD_LesContacts "
<< " la fonction nD associe a l'affichage pour LesContacts ne doit pas "
<< " inclure des Ddl_enum_etendu !! changer la fonction ";
Sortie(1);
}
Tableau val_ddl_enum (li_enu_scal.size()); // init par défaut
// 2) puis les grandeurs quelconques évoluées
{List_io::iterator ipq,ipqfin=li_quelc.end();
for (ipq=li_quelc.begin();ipq!=ipqfin;ipq++)
{ bool trouver = false;
TypeQuelconque& enuTQ = (*ipq); // pour simplifier
const TypeQuelconque_enum_etendu& en_ET_TQ = enuTQ.EnuTypeQuelconque().EnumTQ();
// si li est non nulle, li indique spécifiquement quelle grandeur on veut sortir
if (li != NULL)
{ // on va balayer la liste et voir si une grandeur correspond
list::iterator ili,ilifin = li->end();
for (ili = li->begin();ili != ilifin; ili++)
{ TypeQuelconque& enuTQ_li = (*ili); // pour simplifier
const TypeQuelconque_enum_etendu& en_ET_TQ_li = enuTQ_li.EnuTypeQuelconque().EnumTQ();
if (en_ET_TQ_li == en_ET_TQ ) // cas ou on a trouvé la grandeur demandée
{ // pour l'instant seules les grandeurs scalaires entières sont admises
Grandeur_scalaire_entier& gr= *((Grandeur_scalaire_entier*) ((*ipq).Grandeur_pointee()));
Grandeur_scalaire_entier& gr_li= *((Grandeur_scalaire_entier*) ((*ili).Grandeur_pointee()));
(*gr.ConteneurEntier()) = (*gr_li.ConteneurEntier());
trouver = true;
};
};
};
if (!trouver) // si non existant, init par défaut
(*ipq).Grandeur_pointee()->InitParDefaut();
};
};
// 3) et enfin les grandeurs quelconques:
// >>> en fait même topo que pour la liste
// les conteneurs sont normalement déjà bien dimensionné
int tail_tab_queconque = tab_queconque.Taille();
// on va balayer les grandeurs quelconques
for (int i=1;i<= tail_tab_queconque;i++)
{ bool trouver = false;
EnumTypeQuelconque enu = tab_queconque(i);
// si li est non nulle, li indique spécifiquement quelle grandeur on veut sortir
if (li != NULL)
{ // on va balayer la liste et voir si une grandeur correspond
list::iterator ili,ilifin = li->end();
for (ili = li->begin();ili != ilifin; ili++)
{ TypeQuelconque& enuTQ_li = (*ili); // pour simplifier
EnumTypeQuelconque en_ET_TQ_li = enuTQ_li.EnuTypeQuelconque().EnumTQ();
if (en_ET_TQ_li == enu ) // cas ou on a trouvé la grandeur demandée
{ // pour l'instant seules les grandeurs scalaires entières sont admises
Grandeur_scalaire_entier& gr= *((Grandeur_scalaire_entier*) ((*tqi(i)).Grandeur_pointee()));
Grandeur_scalaire_entier& gr_li= *((Grandeur_scalaire_entier*) ((*ili).Grandeur_pointee()));
(*gr.ConteneurEntier()) = (*gr_li.ConteneurEntier());
trouver = true;
};
};
};
if (!trouver) // si non existant, init par défaut
(*tqi_fct_nD_niveau_commentaire(i)).Grandeur_pointee()->InitParDefaut();
};
// tqii pointe aux mêmes endroit que tqi mais est déclaré en const ...
// calcul de la valeur et retour dans tab_ret
Tableau & tab_val = pt_fonct->Valeur_FnD_Evoluee(&val_ddl_enum,&li_enu_scal,&li_quelc,&(tqii),&t_num_ordre);
#ifdef MISE_AU_POINT
if (tab_val.Taille() != 1)
{ cout << "\nErreur : la fonction nD " << pt_fonct->NomFonction()
<< " doit calculer un scalaire or le tableau de retour est de taille "
<< tab_val.Taille() << " ce n'est pas normal !\n" << flush;
if (Permet_affichage() > 2 )
cout << "\n LesContacts::Valeur_fct_nD_LesContacts(... \n";
Sortie(1);
};
#endif
// on récupère le premier élément du tableau uniquement
return tab_val(1);
};
// recherche dans les Front enregistrés de la zone , c-a-d dans t_listFront(i)(zone)
// un Front de même origine , c-a-d sans les mitoyens
// si aucun résultat retourne NULL
// sinon ramène l'élément de t_listFront de même origine
Front* LesContacts::Front_de_meme_origine(Front* fro, int zone) const
{ // on récupère le num de maillage associé
// récup du numero du maillage rattache
int numMail = fro->NumMail();
int i = numMail - (nb_mail_Esclave-nbmailautocontact);
// on va balayer dans la zone de contact
LaLIST_io & list_fronta = (t_listFront(i)(zone)); // pour simplifier
LaLIST_io ::iterator il,ilfin = list_fronta.end();
for (il = list_fronta.begin();il != ilfin; il++)
if ((*il).MemeOrigine(*fro))
return &((*il));
// arrivée ici, cela veut dire que l'on n'a rien trouvé
return NULL;
// la liste des éléments frontières succeptibles d'entrer en contact
// ces Front (qui contiennent que des pointeurs sauf une boite d'encombrement)
// sont différents de ceux des maillages, et sont donc stocké en interne
// Tableau < Tableau < LaLIST_io > > t_listFront;
// t_listFront(i)(j)(k) : maillage maître (i)
// zone de contact (j)
// (K) = kième frontière (dans l'ordre de la liste)
// ** pour le tableaux t_listFront, le numéros dit de maillage, n'est pas le numéro
// ** intrinsèque de maillage (telle que ceux associés aux noeuds et éléments)
// ** mais uniquement un numéro locale d'ordre
// ** mais on a: les éléments de frontière de t_listFront(i) font partie du maillage
// i + (nb_mail_Esclave-nbmailautocontact)
};
#ifdef UTILISATION_MPI
// mise à jour list contact pour proc 0:
// il s'agit des infos minimales
void LesContacts::Mise_a_jour_liste_contacts_actif_interProc()
{ temps_transfert_long.Mise_en_route_du_comptage(); // comptage cpu
// on va se servir d'un conteneur intermédiaire
union double_int
{ double x;
int n[2];
} ;
double_int xinter;
int proc_en_cours = ParaGlob::Monde()->rank();
if (proc_en_cours != 0) // seules les proc i>0 définissent des éléments de contact
// on boucle sur les elements de contact du proc i pour les transmettres à proc 0
{ int nb_contact_actif = Calcul_Nb_contact_actif();
// on a besoin de 8 entiers pour repérer un élément de contact, on va transmettre
// un vecteur contenant ces infos
////---debug
//cout << "\n LesContacts::Mise_a_jour_liste_contacts_actif_interProc "
// << " proc "<< proc_en_cours << ", nb_contact= "<< listContact.size();
////--fin debug
v_interProc_contact_actif.Change_taille(4*nb_contact_actif);
int rang=1; // init
LaLIST ::iterator il,ilfin = listContact.end();
for (il = listContact.begin();il != ilfin; il++)
if ((*il).Actif())
{xinter.n[0] = (*il).Actif(); xinter.n[1] = (*il).Cas_solide();
v_interProc_contact_actif(rang) = xinter.x;rang++;
xinter.n[0] = (*il).Esclave()->Num_Mail(); xinter.n[1] = (*il).Esclave()->Num_noeud();
v_interProc_contact_actif(rang) = xinter.x;rang++;
xinter.n[0] = (*il).Elfront()->NumUnique(); xinter.n[1] = (*il).Const_Num_zone_contact();
v_interProc_contact_actif(rang) = xinter.x;rang++;
xinter.n[0] = (*il).Lissage_normale(); xinter.n[1] = (*il).Collant();
v_interProc_contact_actif(rang) = xinter.x;rang++;
};
// on transmet à proc 0
// tout d'abord la taille
mpi::request reqs1 = ParaGlob::Monde()->isend(0, 63, 4*nb_contact_actif);
// puis le conteneur
mpi::request reqs2 = v_interProc_contact_actif.Ienvoi_MPI(0,64);
}
else
// cas du proc 0
{ int nb_proc_terminer = 0; // permettra de terminer
// on supprime la liste existante car:
// - si on teste l'existance d'un élément à chaque ajout => il faut parcourir la liste qui peut être longue
// - il faut y adjoindre une méthode pour supprimer les éléments qui ont été supprimés par un proc
// => c'est plus simple de repartir d'une liste vide,
listContact.clear(); // init
while (nb_proc_terminer < (ParaGlob::Monde()->size()-1))
{ // on récupère un résultat de cpu i
int taille_transfert;
mpi::request reqs1 = ParaGlob::Monde()->irecv(mpi::any_source, 63, taille_transfert);
mpi::status stat = reqs1.wait(); // on attend que le conteneur soit rempli
v_interProc_contact_actif.Change_taille(taille_transfert); // le conteneur
int source = stat.source(); // récupération du numéro de la source
// on récupère
mpi::request reqs2 = v_interProc_contact_actif.Irecup_MPI(source, 64);
reqs2.wait(); // on attend que le conteneur soit rempli
nb_proc_terminer++; // on prend en compte que l'on a récupéré un conteneur
// on va remplir la liste des contacts actifs
int rang = 1; // init
while (rang < taille_transfert+1)
{ // récup des infos pour le contact
xinter.x = v_interProc_contact_actif(rang);rang++;
int actif = xinter.n[0]; int casSolide = xinter.n[1];
xinter.x = v_interProc_contact_actif(rang);rang++;
int num_mail = xinter.n[0]; int num_noeud = xinter.n[1];
xinter.x = v_interProc_contact_actif(rang);rang++;
int numUnique = xinter.n[0]; int numZoneContact = xinter.n[1];
xinter.x = v_interProc_contact_actif(rang);rang++;
int lissageNormale = xinter.n[0]; int collant = xinter.n[1];
// on crée un élément de contact
ElContact elcont(pointe_t_listFront(numUnique)
,&(lesMaille->Noeud_LesMaille(num_mail,num_noeud))
,fct_nD_contact,collant);
elcont.Num_zone_contact()=numZoneContact; // affectation du numéro de zone
elcont.Change_lissage_normale(lissageNormale); // affectation du lissage
if (actif) elcont.Met_actif();
else elcont.Met_Inactif();
listContact.push_front(elcont);
};
};
// //---debug
// cout << "\n LesContacts::Mise_a_jour_liste_contacts_actif_interProc "
// << " proc "<< proc_en_cours << ", nb_contact= "<< listContact.size();
// //--fin debug
Calcul_Nb_contact_actif(); // mise à jour
};
temps_transfert_long.Arret_du_comptage();
};
#endif