// FICHIER : SfeMembT.cc // CLASSE : SfeMembT // 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-2021 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 using namespace std; //introduces namespace std #include #include "Sortie.h" #include "MathUtil.h" #include "SfeMembT.h" #include "TypeConsTens.h" #include "FrontPointF.h" #include "Loi_Umat.h" #include "ExceptionsElemMeca.h" #include "TypeQuelconqueParticulier.h" #include "Coordonnee2.h" #include "Coordonnee3.h" #include "Util.h" // calcul de la nouvelle épaisseur (sans raideur) avec métrique en explicite // cas où l'épaisseur est stocké dans l'élément // mise à jour du volume au pti void SfeMembT::CalEpaisseurAtdtExp_et_vol_pti(const double& epaisseur0, const ParaAlgoControle & ,const double & epaisseur_t, PtIntegMecaInterne & ptIntegMeca ,double & epaisseur_tdt, const Met_abstraite::Expli_t_tdt& ex) { // on commence par calculer la trace du tenseur des contraintes double traceSig = (ptIntegMeca.SigHH_const() * (* ex.gijBB_tdt)).Trace(); double traceSig_t = (ptIntegMeca.SigHH_t_const() * (* ex.gijBB_t)).Trace(); const double& troisK = 3. * ptIntegMeca.ModuleCompressibilite_const(); // récup de la compressibilité // calcul de la nouvelle épaisseur //--- vérification et gestion des cas particuliers --- bool cas_particulier=false; {// on suppose un module de compressibilité positif sinon ce n'est pas normal if (troisK < 0.) {if (ParaGlob::NiveauImpression()>2) cout << "\n erreur*** on a trouve une compressibilite negative = " << troisK/3. << "\n SfeMembT::CalEpaisseurAtdtExp_et_vol_pti(..."; // on ne change pas l'épaisseur cas_particulier = true; }; // classiquement on suppose que troisK doit-être bien supérieur à traceSig: // on considère un facteur 10 arbitraire // si ce n'est pas le cas, on risque d'avoir un calcul d'épaisseur erroné if (Dabs(traceSig) > 10. * Dabs(troisK/3.)) {if (ParaGlob::NiveauImpression()>2) cout << "\n *** pb dans le calcul de la nouvelle epaisseur: " << " le coef de compressibilite = "< (troisK/3. - ConstMath::petit)) // dans le cas où delta traceSig > troisK, cela va donner une épaisseur négative !! {if (ParaGlob::NiveauImpression()>2) cout << "\n *** pb dans le calcul de la nouvelle epaisseur: " << " coef de compressibilite = "< 10. * Dabs(troisK/3.)) ) // on ne va pas pouvoir peut-être calculer une nouvelle épaisseur {if (ParaGlob::NiveauImpression()>2) cout << "\n *** pb dans le calcul de la nouvelle epaisseur: " << " coef de compressibilite = "<2) cout << "\n erreur*** on a trouve une compressibilite negative = " << troisK << "\n SfeMembT::CalEpaisseurAtdtImp_et_vol_pti...) "; // on ne change pas l'épaisseur cas_particulier = true; }; // classiquement on suppose que troisK doit-être bien supérieur à traceSig: // on considère un facteur 10 arbitraire // si ce n'est pas le cas, on risque d'avoir un calcul d'épaisseur erroné if (Dabs(traceSig) > 10. * Dabs(troisK/3.)) {if (ParaGlob::NiveauImpression()>2) cout << "\n *** pb dans le calcul de la nouvelle epaisseur: " << " le coef de compressibilite = "< (troisK/3. - ConstMath::petit)) // dans le cas où delta traceSig > troisK, cela va donner une épaisseur négative !! {if (ParaGlob::NiveauImpression()>2) cout << "\n *** pb dans le calcul de la nouvelle epaisseur: " << " coef de compressibilite = "< 10. * Dabs(troisK/3.)) ) // on ne va pas pouvoir peut-être calculer une nouvelle épaisseur {if (ParaGlob::NiveauImpression()>2) cout << "\n *** pb dans le calcul de la nouvelle epaisseur: " << " coef de compressibilite = "<doCoMemb; // pour simplifier l'écriture int nbtotsurf =CoSfe->eleCentre->Nbi(); int nbtotepais =(CoSfe->segment).Nbi(); int nbi = nbtotsurf * nbtotepais; for (int nisur =1; nisur<= nbtotsurf; nisur++) // boucle sur les pt d'integ de surface for (int niepais =1; niepais<= nbtotepais; niepais++, indice++) // pt d'integ d'epaisseur // for (int i=1;i<= nombre->nbi;i++) { // cas de la compressibilité const double& troisK = 3. * (*lesPtIntegMecaInterne)(indice).ModuleCompressibilite_const(); troisK_moy += troisK; // cas des jacobiens const double& jacobien_0 = *(tabSaveDefDon(indice)->Meti_00().jacobien_); if (atdt) { const double& jacobien_ini = *(tabSaveDefDon(indice)->Meti_t().jacobien_); jacobien_moy_ini += jacobien_ini; const double& jacobien_fin = *(tabSaveDefDon(indice)->Meti_tdt().jacobien_); jacobien_moy_fin += jacobien_fin; // cas de la trace de sigma const double traceSig = (*lesPtIntegMecaInterne)(indice).SigHH_const() && (*(tabSaveDefDon(indice)->Meti_tdt().gijBB_)); traceSig_moy += traceSig; const double traceSig_ini = (*lesPtIntegMecaInterne)(indice).SigHH_t_const() && (*(tabSaveDefDon(indice)->Meti_t().gijBB_)); traceSig_moy_ini += traceSig_ini; (*lesPtIntegMecaInterne)(indice).Volume_pti() *= (epais.epaisseur_t * jacobien_ini) / jacobien_fin * troisK / (troisK - traceSig+traceSig_ini); // la pression = - traceSig/3 !!! } else { const double& jacobien_ini = *(tabSaveDefDon(indice)->Meti_00().jacobien_); jacobien_moy_ini += jacobien_ini; const double& jacobien_fin = *(tabSaveDefDon(indice)->Meti_t().jacobien_); jacobien_moy_fin += jacobien_fin; // cas de la trace de sigma double traceSig = (*lesPtIntegMecaInterne)(indice).SigHH_const() && (*(tabSaveDefDon(indice)->Meti_t().gijBB_)); traceSig_moy += traceSig; (*lesPtIntegMecaInterne)(indice).Volume_pti() *= (epais.epaisseur0 * jacobien_ini) / jacobien_fin * troisK / (troisK - traceSig); }; }; jacobien_moy_ini /= nbi; jacobien_moy_fin /= nbi; traceSig_moy_ini /= nbi; traceSig_moy /= nbi; troisK_moy /= nbi; // d'où le calcul de la nouvelle épaisseur en utilisant la relation: // (V-V_0)/V = trace(sigma)/3 /K_moy //--- vérification et gestion des cas particuliers --- bool cas_particulier=false; {// on suppose un module de compressibilité positif sinon ce n'est pas normal if (troisK_moy < 0.) {if (ParaGlob::NiveauImpression()>2) cout << "\n erreur*** on a trouve une compressibilite moyenne negative = " << troisK_moy/3. << "\n SfeMembT::CalEpaisseurMoyenne_et_vol_pti(..."; // on ne change pas l'épaisseur cas_particulier = true; }; // classiquement on suppose que troisK_moy doit-être bien supérieur à traceSig_moy: // on considère un facteur 10 arbitraire // si ce n'est pas le cas, on risque d'avoir un calcul d'épaisseur erroné double delta_traceSig = traceSig_moy-traceSig_moy_ini; if (Dabs(delta_traceSig) > 10. * Dabs(troisK_moy)) {if (ParaGlob::NiveauImpression()>2) cout << "\n *** pb dans le calcul de la nouvelle epaisseur: " << " le coef de compressibilite moyen = "< (troisK_moy/3. - ConstMath::petit)) // dans le cas où delta_traceSig > troisK_moy, cela va donner une épaisseur négative !! {if (ParaGlob::NiveauImpression()>2) cout << "\n *** pb dans le calcul de la nouvelle epaisseur: " << " coef de compressibilite moyen = "< 10. * Dabs(troisK_moy/3.)) ) // on ne va pas pouvoir peut-être calculer une nouvelle épaisseur {if (ParaGlob::NiveauImpression()>2) cout << "\n *** pb dans le calcul de la nouvelle epaisseur: " << " coef de compressibilite moyen = "<Coord0().Norme(); double R = noe->Coord2().Norme(); //cout << "\n e0= " << epais.epaisseur_tdt<< " troisK_moy=" << troisK_moy << " traceSig_moy=" << traceSig_moy // << " J0= " << jacobien_moy_0 << " J= " << jacobien_moy_fin << " R_0 " << R_0 << " R= " << R; // }; //-- fin debug return epais.epaisseur_tdt; } else {epais.epaisseur_t = (epais.epaisseur0 * jacobien_moy_ini) / jacobien_moy_fin * troisK_moy / (troisK_moy - traceSig_moy); return epais.epaisseur_t; }; }; }; // sinon c'est une erreur cout << "\n *** erreur dans SfeMembT::CalEpaisseurMoyenne_et_vol_pti( "; Sortie(1); }; //test si le jacobien due aux gi finaux est très différent du jacobien de la facette bool SfeMembT::Delta_Jacobien_anormal(const Deformation::SaveDefResul* don ,int nisur,int niepais) {// on récupère le jacobien de la surface médiane sans courbure const DeformationSfe1::SaveDefResulSfe1* donsfe = ((DeformationSfe1::SaveDefResulSfe1*) don); #ifdef MISE_AU_POINT if (donsfe->Meti_a_tdt().jacobien_ == NULL) {cout << "\n*** erreur, le jacobien de la facette n'est pas attribue ! " << " pti de surface "<Meti_tdt().giB_ == NULL) {cout << "\n*** erreur, la bas giB_tdt n'est pas attribue ! " << " pti de surface "<Meti_a_tdt().jacobien_); // on récupère la base au pti courant const BaseB * giB_ = donsfe->Meti_tdt().giB_; // on calcule le produit mixte pour les gi finaux double jacobien_final = Util::ProduitMixte(*giB_); double ratio = jacobien_final/(jaco_init+ConstMath::pasmalpetit); double limite = ParaGlob::param->ParaAlgoControleActifs().Ratio_maxi_jacoMembrane_jacoPti(); if ((ratio > limite) || (ratio < 1./(limite+ConstMath::pasmalpetit))) cout << "\n *** attention *** le rapport entre le jacobien initial ("<< jaco_init << ") et le jacobien ("<< jacobien_final << ") calcule au pti de surface "<= 4) cout << "\n cas non pr้vu, unefois->dualSortSfe= " << unefois->dualSortSfe << " unefois->CalimpPrem= " << unefois->CalimpPrem << "\n SfeMembT::Grandeur_particuliere(List_io&..."; Sortie(1); }; // choix d'init en fonction de la valeur de "cas" if (((cas == 1) || (cas == 2))) { // cas d'une premiere initialisation Tableau tab(5); tab(1) = iM0; tab(2) = iMt; tab(3) = iMtdt; tab(4) = igiH_0; tab(5) = igijHH_0; met->PlusInitVariables(tab) ; }; //él้ments de m้trique et matrices de passage TenseurHH* gijHH;TenseurBB* gijBB; Mat_pleine jB0(dim,dim),jBfin(dim,dim); if ((cas==1) || (cas==11)) // calcul d'une ortho interessance de visualisation des tenseurs // cas de tenseur 3D -> Ia, cas 1D on prend un vecteur norme collineaire // avec g1, dans le cas 2D // la nouvelle base jB est calculee dans def par projection de "Ia" sur Galpha // le resultat est une matrice de passage utilisable pour le changement de base // jB0 a t=0, B pour les tenseurs BB, jH0 idem pour les tenseurs HH // resultat a t+dt {const Met_abstraite::InfoImp& ex = def->RemontImp(absolue,jB0,jBfin); gijHH = ex.gijHH_tdt;gijBB = ex.gijBB_tdt; } else if ((cas==2) || (cas==12)) // resultat a t {const Met_abstraite::InfoExp_tdt& ex= def->RemontExp_tdt(absolue,jB0,jBfin); gijHH = ex.gijHH_tdt;gijBB = ex.gijBB_tdt; }; // maintenant on récupère le tenseur de courbure const Met_Sfe1::Courbure_t_tdt& curb = ((DeformationSfe1*)def)->RecupCourbure0_t_tdt(); // passage en absolu si nécessaire if (besoin_tenseur_courbure) {Tenseur_ns2BB& cur_ns_bBB_tdt = *((Tenseur_ns2BB*) curb.curbBB_tdt) ; // on le symétrise curbBB_tdt = NevezTenseurBB(dim); (*curbBB_tdt).Coor(1,1) = cur_ns_bBB_tdt(1,1);(*curbBB_tdt).Coor(2,2) = cur_ns_bBB_tdt(2,2); (*curbBB_tdt).Coor(1,2) = 0.5*(cur_ns_bBB_tdt(1,2) + cur_ns_bBB_tdt(2,1)); curbBB_tdt->ChBase(jBfin); // le tenseur de courbure dans le rep่re local }; // --- bases ortho locales (du plan de la facette --- if (besoin_dir_princ_courb || besoin_rep_local_ortho) { t_ortho_local.Change_taille(3); t_ortho_local(1) = jBfin(1,1) * curb.aiB_tdt->Coordo(1) + jBfin(2,1) * curb.aiB_tdt->Coordo(2); t_ortho_local(2) = jBfin(1,2) * curb.aiB_tdt->Coordo(1) + jBfin(2,2) * curb.aiB_tdt->Coordo(2); t_ortho_local(3) = Util::ProdVec_coor(t_ortho_local(1),t_ortho_local(2)); }; // --- les directions principales et/ou les valeurs principales int ret=0; if (besoin_dir_princ_courb) { Tenseur_ns2BB& cur_ns_bBB_tdt = *((Tenseur_ns2BB*) curb.curbBB_tdt) ; // on le sym้trise Tenseur2BB curb_symBB_tdt; curb_symBB_tdt.Coor(1,1) = cur_ns_bBB_tdt(1,1);curb_symBB_tdt.Coor(2,2) = cur_ns_bBB_tdt(2,2); curb_symBB_tdt.Coor(1,2) = 0.5*(cur_ns_bBB_tdt(1,2) + cur_ns_bBB_tdt(2,1)); // on cr้e le BH correspondant Tenseur2BH curbBH = curb_symBB_tdt * (*gijHH); Mat_pleine mat(2,2); val_princ = curbBH.ValPropre(ret,mat); // // calcul des vecteurs principaux dans la base locale // Coordonnee3 V_1=mat(1,1) * curb.aiB_tdt->Coordo(1) + mat(2,1) * curb.aiB_tdt->Coordo(2); // Coordonnee3 V_2=mat(1,2) * curb.aiB_tdt->Coordo(1) + mat(2,2) * curb.aiB_tdt->Coordo(2); // t_vec_princ.Change_taille(2); // t_vec_princ(1)(1)= V_1 * t_ortho_local(1); t_vec_princ(1)(2)= V_1 * t_ortho_local(2); // t_vec_princ(2)(1)= V_2 * t_ortho_local(1); t_vec_princ(2)(2)= V_2 * t_ortho_local(2); // non finalement on les exprimes dans la base globale sinon on ne peut pas visualiser sans manip t_vec_princ.Change_taille(2); // s'il y a eu un pb dans le calcul des valeurs propres ou vecteurs propres on évite if (ret != -1) {t_vec_princ(1)=mat(1,1) * curb.aiH_tdt->Coordo(1) + mat(2,1) * curb.aiH_tdt->Coordo(2); t_vec_princ(2)=mat(1,2) * curb.aiB_tdt->Coordo(1) + mat(2,2) * curb.aiB_tdt->Coordo(2); t_vec_princ(1).Normer();t_vec_princ(2).Normer(); }; } else if (besoin_courbures_principales) // si on arrive ici c'est que l'on n'a pas besoin des directions principales mais // seulement des valeurs propres de courbure { Tenseur_ns2BB& cur_ns_bBB_tdt = *((Tenseur_ns2BB*) curb.curbBB_tdt) ; // on le sym้trise Tenseur2BB curb_symBB_tdt; curb_symBB_tdt.Coor(1,1) = cur_ns_bBB_tdt(1,1);curb_symBB_tdt.Coor(2,2) = cur_ns_bBB_tdt(2,2); curb_symBB_tdt.Coor(1,2) = 0.5*(cur_ns_bBB_tdt(1,2) + cur_ns_bBB_tdt(2,1)); // on cr้e le BH correspondant Tenseur2BH curbBH = curb_symBB_tdt * (*gijHH); val_princ = curbBH.ValPropre(ret); }; if (ret == -1) { cout << "\n pb dans le calcul de valeurs ou vecteurs propres du tenseur de courbure !"; if (ParaGlob::NiveauImpression() > 6 ) cout << "\n SfeMembT::Grandeur_particuliere (..."; }; }; // ------ maintenant on fait la sortie réelle ----- // on commence par appeler la fonction de la classe mère // il n'y aura pas de calcul des grandeurs inactivées // absolue: indique si oui ou non on sort les tenseurs dans la base absolue ou une base particulière ElemMeca::Grandeur_particuliere (absolue,liTQ,iteg); // puis les grandeurs sp้cifiques for (il=liTQ.begin();il!=ilfin;il++) {TypeQuelconque& tipParticu = (*il); // pour simplifier if (tipParticu.EnuTypeQuelconque().Nom_vide()) // veut dire que c'est un enum pur switch (tipParticu.EnuTypeQuelconque().EnumTQ()) { // 1) -----cas de l'้paisseur moyenne initiale, ici elle ne d้pend pas du point d'int้gration case EPAISSEUR_MOY_INITIALE: {if (donnee_specif.epais != NULL) { *((Grandeur_scalaire_double*) tipParticu.Grandeur_pointee())=donnee_specif.epais->epaisseur0; (*il).Active(); }; break; } // 2) -----cas de l'้paisseur moyenne finale, ici elle ne d้pend pas du point d'int้gration case EPAISSEUR_MOY_FINALE: (*il).Inactive(); break; // on inactive la grandeur quelconque { if (donnee_specif.epais != NULL) { *((Grandeur_scalaire_double*) tipParticu.Grandeur_pointee())=donnee_specif.epais->epaisseur_tdt; (*il).Active(); }; break; } // 3) ฐฐฐฐฐฐฐฐฐฐฐฐฐ cas du tenseur de courbure ฐฐฐฐฐฐฐฐฐฐ case TENSEUR_COURBURE: { ((Grandeur_TenseurBB*) tipParticu.Grandeur_pointee())->RefConteneurTenseur() = *curbBB_tdt; (*il).Active();break; } // 4) ฐฐฐฐฐฐฐฐฐฐฐฐฐ cas du vecteur contenant les courbures principales ฐฐฐฐฐฐฐฐฐฐ case COURBURES_PRINCIPALES: { (*((Tab_Grandeur_scalaire_double*) tipParticu.Grandeur_pointee()))(1) = val_princ(1); (*((Tab_Grandeur_scalaire_double*) tipParticu.Grandeur_pointee()))(2) = val_princ(2); (*il).Active();break; } // 5) ฐฐฐฐฐฐฐฐฐฐฐฐฐ cas des directions principales de courbure (dans le rep่re local ฐฐฐฐฐฐฐฐฐฐ case DIRECTIONS_PRINC_COURBURE: { (*((Tab_Grandeur_Coordonnee*) tipParticu.Grandeur_pointee()))(1) = t_vec_princ(1); (*((Tab_Grandeur_Coordonnee*) tipParticu.Grandeur_pointee()))(2) = t_vec_princ(2); (*il).Active();break; } // 6) ฐฐฐฐฐฐฐฐฐฐฐฐฐ cas du rep่re local orthonorm้ d'expression ฐฐฐฐฐฐฐฐฐฐ case REPERE_LOCAL_ORTHO: { (*((Tab_Grandeur_Coordonnee*) tipParticu.Grandeur_pointee()))(1) = t_ortho_local(1); (*((Tab_Grandeur_Coordonnee*) tipParticu.Grandeur_pointee()))(2) = t_ortho_local(2); (*((Tab_Grandeur_Coordonnee*) tipParticu.Grandeur_pointee()))(3) = t_ortho_local(3); (*il).Active();break; }; default: break; // on ne fait rien }; }; // liberation des tenseurs intermediaires LibereTenseur(); if (curbBB_tdt != NULL) delete curbBB_tdt; }; // calcul éventuel de la normale à un noeud // ce calcul existe pour les éléments 2D, 1D axi, et aussi pour les éléments 1D // qui possède un repère d'orientation // en retour coor = la normale si coor.Dimension() est = à la dimension de l'espace // si le calcul n'existe pas --> coor.Dimension() = 0 // ramène un entier : // == 1 : calcul normal // == 0 : problème de calcul -> coor.Dimension() = 0 // == 2 : indique que le calcul n'est pas licite pour le noeud passé en paramètre // c'est le cas par exemple des noeuds exterieurs pour les éléments SFE // mais il n'y a pas d'erreur, c'est seulement que l'élément n'est pas ad hoc pour // calculer la normale à ce noeud là // temps: indique à quel moment on veut le calcul // pour des éléments particulier (ex: SFE) la méthode est surchargée int SfeMembT::CalculNormale_noeud(Enum_dure temps,const Noeud& noe,Coordonnee& coor) { // === par rapport à la méthode d'ElemMeca, ici on ne s'occupe des noeuds de l'élément central int retour = 1; // on part avec l'idée que tout va être ok Enum_type_geom enutygeom = Type_geom_generique(this->Id_geometrie()); // if ((enutygeom == LIGNE) || (enutygeom == SURFACE)) if (enutygeom != SURFACE) // dans une première étape on ne s'occupe que des surfaces {coor.Libere(); // pas de calcul possible retour = 0; } else // sinon le calcul est possible { // on commence par repérer le noeud dans la numérotation locale int nuoe=0; // int borne_nb_noeud=nombre->nbnce+1; // ici on ne prend en compte que les noeuds centraux int borne_nb_noeud=tab_noeud.Taille()+1; for (int i=1;i< borne_nb_noeud;i++) {Noeud& noeloc = *tab_noeud(i); if ( (noe.Num_noeud() == noeloc.Num_noeud()) && (noe.Num_Mail() == noeloc.Num_Mail()) ) {nuoe = i; break; }; }; // on ne continue que si on a trouvé le noeud if (nuoe != 0) { // il y a deux cas: soit le noeud fait partie des noeuds centraux ou non if (nuoe <= nombre->nbnce) // cas où le noeud fait partie du centre {ElemGeomC0& elemgeom = ElementGeometrique(); // récup de la géométrie // récup des coordonnées locales du noeuds const Coordonnee& theta_noeud = elemgeom.PtelemRef()(nuoe); // récup des phi et dphi au noeud const Vecteur & phi = elemgeom.Phi(theta_noeud); const Mat_pleine& dphi = elemgeom.Dphi(theta_noeud); switch (temps) {case TEMPS_0 : {const BaseB& baseB = met->BaseNat_0(tab_noeud,dphi,phi); coor = Util::ProdVec_coor( baseB.Coordo(1), baseB.Coordo(2)); coor.Normer(); break; } case TEMPS_t : {const BaseB& baseB = met->BaseNat_t(tab_noeud,dphi,phi); coor = Util::ProdVec_coor( baseB.Coordo(1), baseB.Coordo(2)); coor.Normer(); break; } case TEMPS_tdt : {const BaseB& baseB = met->BaseNat_tdt(tab_noeud,dphi,phi); coor = Util::ProdVec_coor( baseB.Coordo(1), baseB.Coordo(2)); coor.Normer(); break; } default : cout << "\nErreur : valeur incorrecte du temps demande = " << Nom_dure(temps) << " !\n"; cout << "\n SfeMembT::CalculNormale_noeud(Enum_dure temps... \n"; retour = 0; Sortie(1); }; } else // sinon le noeud fait partie des noeuds externes // on considère que la normale n'est pas à calculer {coor.Libere(); // pas de calcul possible retour = 2; }; } else {cout << "\n *** erreur le noeud demande num= "<