// 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(ofstream& 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