Herezh_dev/Algo/AlgoRef/Algori.cc
2023-05-03 17:23:49 +02:00

4156 lines
219 KiB
C++

// This file is part of the Herezh++ application.
//
// The finite element software Herezh++ is dedicated to the field
// of mechanics for large transformations of solid structures.
// It is developed by Gérard Rio (APP: IDDN.FR.010.0106078.000.R.P.2006.035.20600)
// INSTITUT DE RECHERCHE DUPUY DE LÔME (IRDL) <https://www.irdl.fr/>.
//
// Herezh++ is distributed under GPL 3 license ou ultérieure.
//
// Copyright (C) 1997-2022 Université Bretagne Sud (France)
// AUTHOR : Gérard Rio
// E-MAIL : gerardrio56@free.fr
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License,
// or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// See the GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//
// For more information, please consult: <https://herezh.irdl.fr/>.
#include "Algori.h"
#include "string"
#include "MathUtil.h"
#include <iostream> // pour utiliser la classe istrstream
#include <strstream> // nouveau dans CW5.3
// les différents types de stockage matriciel
#include <complex>
#include "MatLapack.h"
#include "Mat_pleine.h"
#include "MatBand.h"
#include "Mat_creuse_CompCol.h"
#include "MatDiag.h"
#include "ReferenceNE.h"
#include "ReferenceAF.h"
#include "ExceptionsElemMeca.h"
#include "ExceptionsLoiComp.h"
#include "TypeQuelconqueParticulier.h"
//---------- class DeuxString ---------
// surcharge de l'operator de lecture /écriture
istream & operator >> (istream & ent, Algori::DeuxString & a)
{ //lecture du type et vérification
string nom_type; ent >> nom_type;
if (nom_type != "Algori::DeuxString") Sortie(1);
// les deux strings
ent >> a.nomFichier >> a.nomMaillage;
return ent;
};
ostream & operator << (ostream & sort, const Algori::DeuxString & a)
{ // le type puis les deux strings
sort << "Algori::DeuxString " << a.nomFichier << " " << a.nomMaillage <<"\n";
return sort;
};
istream & operator >> (istream & ent , Algori::ListDeuxString & a)
{ ent >> a.infos; return ent;};
ostream & operator << (ostream & sort , const Algori::ListDeuxString &a)
{ sort << a.infos; return sort;};
//---------- fin class DeuxString ---------
// CONSTRUCTEURS :
Algori::Algori () : // par defaut
paraTypeCalcul(),pa(),temps_derniere_sauvegarde(0.),mode_debug(0),permet_affichage(0)
,list_incre_temps_sauvegarder(),list_incre_temps_calculer()
,tempsDerniereSortieFilCalcul(0.),noms_fichier(),typeFlotExterne()
,entreePrinc(NULL),debut_increment(0),visualise(),visualise_maple()
,visualise_geomview(),visualise_Gid(),visualise_Gmsh(),toto_masse(NULL)
,icharge(0)
,phase_de_convergence(0),nombre_de_bonnes_convergences(0),a_converge(false) // variables de travail
,a_converge_iterMoins1(false)
,nombre_de_mauvaises_convergences(0)
,max_var_residu(),nb_cycle_test_max_var_residu(0),v_int() // variables de travail
,tab_para_stockage() //,pt_icharge(NULL)
,E_cin_0(0.),E_cin_t(0.),E_cin_tdt(0),E_int_t(0),E_int_tdt(0),E_ext_t(0),E_ext_tdt(0),bilan_E(0) // différentes énergies et bilan
,q_mov_t(0.),q_mov_tdt(0.)
,P_acc_tdt(0.),P_int_tdt(0.),P_ext_tdt(0.),bilan_P_tdt(0.),P_acc_t(0.),P_int_t(0.),P_ext_t(0.),bilan_P_t(0.)
,E_visco_numerique_t(0.),E_visco_numerique_tdt(0.),E_bulk(0.),P_bulk(0.)
,F_int_t(),F_ext_t(),F_int_tdt(),F_ext_tdt(),F_totale_tdt() // forces généralisées int et ext à t et t+dt
,residu_final()
,E_cin_ind_t(),E_cin_ind_tdt(),E_int_ind_t(),E_int_ind_tdt(),E_ext_ind_t(),E_ext_ind_tdt(),bilan_ind_E()
,q_mov_ind_t(),q_mov_ind_tdt()
,P_acc_ind_tdt(),P_int_ind_tdt(),P_ext_ind_tdt(),bilan_P_ind_tdt()
,P_acc_ind_t(),P_int_ind_t(),P_ext_ind_t(),bilan_P_ind_t()
,E_visco_numerique_ind_t(),E_visco_numerique_ind_tdt()
,F_int_ind_t(),F_ext_ind_t(),F_int_ind_tdt(),F_ext_ind_tdt()
,X_t(),X_tdt(),delta_X(),var_delta_X(),delta_t_precedent_a_convergence(0.)
,vitesse_t(),vitesse_tdt(),acceleration_t(),acceleration_tdt()
,E_bulk_ind()
,P_bulk_ind()
,cas_ass_eps(NULL),Ass_eps(NULL),cas_ass_eps11(NULL),Ass_eps11(NULL)
,cas_ass_sig(NULL),Ass_sig(NULL),cas_ass_sig11(NULL),Ass_sig11(NULL)
,mat_glob_sigeps(NULL),vglob_sigeps(NULL),vglobal_sigeps(NULL)
,nbddl_sigeps11(0),nbddl_sigeps(0)
,cas_ass_err(NULL),Ass_err(NULL),nbddl_err(0)
,avec_remont_sigma(false),avec_remont_eps(false),avec_erreur(false)
,energTotal(),energHourglass(0.),energFrottement(),energPenalisation(0.)
,energStabiliMembBiel(0.)
,deja_lue_entete_parametre(0)
//-------- amortissement cinétique
,amortissement_cinetique(false),max_nb_decroit_pourRelaxDyn(1),compteur_decroit_pourRelaxDyn(0)
,inter_nb_entre_relax(1),fct_nD_inter_nb_entre_relax(NULL),nom_fct_nD_inter_nb_entre_relax("")
,nb_depuis_derniere_relax(0)
,taille_moyenne_glissante(1),moyenne_glissante(ConstMath::tresgrand), moy_gliss_t(0.)
,sauve_E_cin(),indice_EC1(0),nb_Ecin_stocker(0),test_fraction_energie(0.),X_EcinMax()
,coef_arret_pourRelaxDyn(0.5),dernier_pic(-1),pic_E_cint_t(-1.)
,max_pic_E_cin(-1.),coef_redemarrage_pourRelaxDyn(0.05)
,max_deltaX_pourRelaxDyn(0.1)
,nb_max_dX_OK_pourRelaxDyn(5),nb_dX_OK_pourRelaxDyn(0)
,nb_deb_testfin_pourRelaxDyn(100),nb_deb_test_amort_cinetique(1)
,compteur_test_pourRelaxDyn(0),compteur_pic_energie(0)
// ...... the same pour l'amortissement local
,amortissement_cinetique_au_noeud(0),nb_deb_test_amort_cinetique_noe(100)
,E_cinNoe_tdt(),E_cinNoe_t(),max_nb_decroit_pourRelaxDyn_noe(1),compteur_decroit_pourRelaxDyn_noe()
,coef_arret_pourRelaxDyn_noe(0.5),dernier_pic_noe()
,pic_E_cint_t_noe(),max_pic_E_cin_noe(),coef_redemarrage_pourRelaxDyn_noe(0.05)
,compteur_pic_energie_noe(0)
//------- amortissement visqueux critique
,opt_cal_C_critique(-1),f_(0.9),ampli_visco(1.)
,C_inter(NULL),type_calcul_visqu_critique(0)
,F_int_tdt_prec(),F_ext_tdt_prec()
,listeVarGlob(),listeVecGlob()
//----- fin des amortissements ---
,arret_a_equilibre_statique(0),vglob_stat(NULL)
,volume_total_matiere(0.),vol_total2D_avec_plan_ref(1,Coordonnee(ParaGlob::Dimension()))
// -- controle précision convergence
,nom_modulation_precision(""),modulation_precision(NULL),fct_norme(NULL)
//---- grandeurs de travail privées ------
,vec_trav()
//------- temps cpu -----
,tempsInitialisation(),tempsMiseAjourAlgo(),tempsCalEquilibre()
,tempsRaidSmEner(),tempsSecondMembreEnerg(),tempsResolSystemLineaire()
,tempsSauvegarde(),tempsSortieFilCalcul(),tempsRaidSmEnerContact()
,tempsSecondMembreEnergContact(),temps_CL(),temps_CLL()
,temps_lois_comportement(),temps_metrique_K_SM(),temps_chargement()
,temps_rech_contact()
,ptalgocombi(NULL)
#ifndef UTILISATION_MPI
,lesTempsCpu(16)
#else
,lesTempsCpu(19),distribution_CPU_algo()
,temps_transfert_court(),temps_transfert_long(),temps_attente()
#endif
//---------- stockage pour la transmission des grandeurs consultables -----
// ,stock_compteur(GENERIQUE_UNE_GRANDEUR_GLOBALE),val_stock_compteur(NULL)
// ,stock_icharge(GENERIQUE_UNE_GRANDEUR_GLOBALE),val_stock_icharge(NULL)
{ cout << "\n ce constructeur ne doit pas etre utilise !! \n" ;
cout << " Algo::Algo () // par defaut " << endl;
Sortie(1);
};
// constructeur en fonction du type de calcul
// il y a ici lecture des parametres attaches au type
Algori::Algori (EnumTypeCalcul type,const bool avec_typeDeCal
,const list <EnumSousTypeCalcul>& soustype
,const list <bool>& avec_soustypeDeCal
,UtilLecture& entreePrincipal
):
typeCalcul(type),avec_typeDeCalcul(avec_typeDeCal)
,soustypeDeCalcul(&soustype),avec_soustypeDeCalcul(&avec_soustypeDeCal)
,paraTypeCalcul()
,pa(),temps_derniere_sauvegarde(0.),mode_debug(0),permet_affichage(0)
,list_incre_temps_sauvegarder(),list_incre_temps_calculer()
,tempsDerniereSortieFilCalcul(0.),noms_fichier(),typeFlotExterne()
,entreePrinc(&entreePrincipal),debut_increment(0)
,visualise(&entreePrincipal),visualise_maple(&entreePrincipal)
,visualise_geomview(&entreePrincipal),visualise_Gid(&entreePrincipal)
,visualise_Gmsh(&entreePrincipal),toto_masse(NULL)
,icharge(0)
,phase_de_convergence(0),nombre_de_bonnes_convergences(0),a_converge(false) // variables de travail
,a_converge_iterMoins1(false)
,nombre_de_mauvaises_convergences(0)
,max_var_residu(),nb_cycle_test_max_var_residu(0),v_int() // variables de travail
,tab_para_stockage()//,pt_icharge(NULL)
,E_cin_0(0.),E_cin_t(0),E_cin_tdt(0),E_int_t(0),E_int_tdt(0),E_ext_t(0),E_ext_tdt(0),bilan_E(0) // différentes énergies et bilan
,q_mov_t(0.),q_mov_tdt(0.)
,P_acc_tdt(0.),P_int_tdt(0.),P_ext_tdt(0.),bilan_P_tdt(0.),P_acc_t(0.),P_int_t(0.),P_ext_t(0.),bilan_P_t(0.)
,E_visco_numerique_t(0.),E_visco_numerique_tdt(0.),E_bulk(0.),P_bulk(0.)
,F_int_t(),F_ext_t(),F_int_tdt(),F_ext_tdt(),F_totale_tdt() // forces généralisées int et ext à t et t+dt
,residu_final()
,X_t(),X_tdt(),delta_X(),var_delta_X(),delta_t_precedent_a_convergence(0.)
,vitesse_t(),vitesse_tdt(),acceleration_t(),acceleration_tdt()
,cas_ass_eps(NULL),Ass_eps(NULL),cas_ass_eps11(NULL),Ass_eps11(NULL)
,cas_ass_sig(NULL),Ass_sig(NULL),cas_ass_sig11(NULL),Ass_sig11(NULL)
,mat_glob_sigeps(NULL),vglob_sigeps(NULL),vglobal_sigeps(NULL)
,nbddl_sigeps11(0),nbddl_sigeps(0)
,cas_ass_err(NULL),Ass_err(NULL),nbddl_err(0)
,avec_remont_sigma(false),avec_remont_eps(false),avec_erreur(false)
,energTotal(),energHourglass(0.),energFrottement(),energPenalisation(0.),energStabiliMembBiel(0.)
,deja_lue_entete_parametre(0)
//-------- amortissement cinétique
,amortissement_cinetique(false),max_nb_decroit_pourRelaxDyn(1),compteur_decroit_pourRelaxDyn(0)
,inter_nb_entre_relax(1),fct_nD_inter_nb_entre_relax(NULL),nom_fct_nD_inter_nb_entre_relax("")
,nb_depuis_derniere_relax(0)
,taille_moyenne_glissante(1),moyenne_glissante(ConstMath::tresgrand), moy_gliss_t(0.)
,sauve_E_cin(),indice_EC1(0),nb_Ecin_stocker(0),test_fraction_energie(0.),X_EcinMax()
,coef_arret_pourRelaxDyn(0.5),dernier_pic(-1.),pic_E_cint_t(-1.),max_pic_E_cin(-1.),coef_redemarrage_pourRelaxDyn(0.05)
,max_deltaX_pourRelaxDyn(0.1),nb_max_dX_OK_pourRelaxDyn(5),nb_dX_OK_pourRelaxDyn(0)
,nb_deb_testfin_pourRelaxDyn(100),nb_deb_test_amort_cinetique(1)
,compteur_test_pourRelaxDyn(0),compteur_pic_energie(0)
// ...... the same pour l'amortissement local
,amortissement_cinetique_au_noeud(0),nb_deb_test_amort_cinetique_noe(100)
,E_cinNoe_tdt(),E_cinNoe_t(),max_nb_decroit_pourRelaxDyn_noe(1),compteur_decroit_pourRelaxDyn_noe()
,coef_arret_pourRelaxDyn_noe(0.5),dernier_pic_noe()
,pic_E_cint_t_noe(),max_pic_E_cin_noe(),coef_redemarrage_pourRelaxDyn_noe(0.05)
,compteur_pic_energie_noe(0)
//------- amortissement visqueux critique
,opt_cal_C_critique(-1),f_(0.9),ampli_visco(1.)
,C_inter(NULL),type_calcul_visqu_critique(0)
,F_int_tdt_prec(),F_ext_tdt_prec()
,listeVarGlob(),listeVecGlob()
//----- fin des amortissements ---
,arret_a_equilibre_statique(0),vglob_stat(NULL)
,volume_total_matiere(0.),vol_total2D_avec_plan_ref(1,Coordonnee(ParaGlob::Dimension()))
// -- controle précision convergence
,nom_modulation_precision(""),modulation_precision(NULL),fct_norme(NULL)
//---- grandeurs de travail privées ------
,vec_trav()
//------- temps cpu -----
,tempsInitialisation(),tempsMiseAjourAlgo(),tempsCalEquilibre()
,tempsRaidSmEner(),tempsSecondMembreEnerg(),tempsResolSystemLineaire()
,tempsSauvegarde(),tempsSortieFilCalcul(),tempsRaidSmEnerContact()
,tempsSecondMembreEnergContact(),temps_CL(),temps_CLL()
,temps_lois_comportement(),temps_metrique_K_SM(),temps_chargement()
,temps_rech_contact()
,ptalgocombi(NULL)
#ifndef UTILISATION_MPI
,lesTempsCpu(16)
#else
,lesTempsCpu(19),distribution_CPU_algo()
,temps_transfert_court(),temps_transfert_long(),temps_attente()
#endif
//---------- stockage pour la transmission des grandeurs consultables -----
// ,stock_compteur(GENERIQUE_UNE_GRANDEUR_GLOBALE),val_stock_compteur(NULL)
// ,stock_icharge(GENERIQUE_UNE_GRANDEUR_GLOBALE),val_stock_icharge(NULL)
{ // on met à jour ParaGlob
ParaGlob::param->ChangeParaAlgoControleActifs(&pa);
// stockage pour la transmission des grandeurs consultables
// 1) on définie un type quelconque adapté comme conteneur
{int toto=0;
Grandeur_scalaire_entier grand_courant(toto);
TypeQuelconque typQ1(GENERIQUE_UNE_GRANDEUR_GLOBALE,NU_DDL,grand_courant);
// // 2) on adapte le stockage
// stock_compteur.ChangeGrandeur(typQ1);
// val_stock_compteur = (Grandeur_scalaire_entier*) stock_compteur.Grandeur_pointee();
// stock_icharge.ChangeGrandeur(typQ1);
// val_stock_icharge = (Grandeur_scalaire_entier*) stock_icharge.Grandeur_pointee();
// 3) on ajoute en global les grandeurs consultables
ParaGlob::param->Ajout_grandeur_consultable(&typQ1,COMPTEUR_ITERATION_ALGO_GLOBAL);
ParaGlob::param->Ajout_grandeur_consultable(&typQ1,COMPTEUR_INCREMENT_CHARGE_ALGO_GLOBAL);
ParaGlob::param->Ajout_grandeur_consultable(&typQ1,ALGO_GLOBAL_ACTUEL);
};
// --- maintenant les énergies
{double titi=0.; // les énergies sont des doubles
Grandeur_scalaire_double grand_courant(titi);
TypeQuelconque typQ1(GENERIQUE_UNE_GRANDEUR_GLOBALE,NU_DDL,grand_courant);
// et on ajoute
ParaGlob::param->Ajout_grandeur_consultable(&typQ1,ENERGIE_CINETIQUE);
ParaGlob::param->Ajout_grandeur_consultable(&typQ1,ENERGIE_EXTERNE);
ParaGlob::param->Ajout_grandeur_consultable(&typQ1,ENERGIE_INTERNE);
ParaGlob::param->Ajout_grandeur_consultable(&typQ1,PUISSANCE_ACCELERATION);
ParaGlob::param->Ajout_grandeur_consultable(&typQ1,PUISSANCE_INTERNE);
ParaGlob::param->Ajout_grandeur_consultable(&typQ1,PUISSANCE_EXTERNE);
ParaGlob::param->Ajout_grandeur_consultable(&typQ1,PUISSANCE_BILAN);
ParaGlob::param->Ajout_grandeur_consultable(&typQ1,ENERGIE_ELASTIQUE);
ParaGlob::param->Ajout_grandeur_consultable(&typQ1,ENERGIE_PLASTIQUE);
ParaGlob::param->Ajout_grandeur_consultable(&typQ1,ENERGIE_VISQUEUSE);
ParaGlob::param->Ajout_grandeur_consultable(&typQ1,ENERGIE_BILAN);
ParaGlob::param->Ajout_grandeur_consultable(&typQ1,QUANTITE_MOUVEMENT);
ParaGlob::param->Ajout_grandeur_consultable(&typQ1,ENERGIE_PENALISATION);
ParaGlob::param->Ajout_grandeur_consultable(&typQ1,ENERGIE_FROT_ELAST);
ParaGlob::param->Ajout_grandeur_consultable(&typQ1,ENERGIE_FROT_PLAST);
ParaGlob::param->Ajout_grandeur_consultable(&typQ1,ENERGIE_FROT_VISQ);
ParaGlob::param->Ajout_grandeur_consultable(&typQ1,ENERGIE_VISCO_NUMERIQUE);
ParaGlob::param->Ajout_grandeur_consultable(&typQ1,ENERGIE_BULK_VISCOSITY);
ParaGlob::param->Ajout_grandeur_consultable(&typQ1,ENERGIE_HOURGLASS_);
ParaGlob::param->Ajout_grandeur_consultable(&typQ1,ENERGIE_STABILISATION_MEMB_BIEL);
ParaGlob::param->Ajout_grandeur_consultable(&typQ1,VOLUME_TOTAL_MATIERE);
ParaGlob::param->Ajout_grandeur_consultable(&typQ1,MAXPUISSEXT);
ParaGlob::param->Ajout_grandeur_consultable(&typQ1,MAXPUISSINT);
ParaGlob::param->Ajout_grandeur_consultable(&typQ1,MAXREACTION);
ParaGlob::param->Ajout_grandeur_consultable(&typQ1,MAXRESIDUGLOBAL);
ParaGlob::param->Ajout_grandeur_consultable(&typQ1,MAXdeltaX);
ParaGlob::param->Ajout_grandeur_consultable(&typQ1,MAXvarDeltaX);
ParaGlob::param->Ajout_grandeur_consultable(&typQ1,MAXvarDdl);
// //------- debug
// {void* pt_void = ParaGlob::param->Mise_a_jour_grandeur_consultable(ENERGIE_PENALISATION);
// TypeQuelconque* pt_quelc = (TypeQuelconque*) pt_void;
// Grandeur_scalaire_double& gr
// = *((Grandeur_scalaire_double*) pt_quelc->Grandeur_pointee()); // pour simplifier
// cout << "\n debug*** Algori::Algori "
// << "\n pt_void= " << pt_void << " gr.ContDouble()= " << gr.ContDouble()
// << " (*(gr.ConteneurDouble())) = " << (*(gr.ConteneurDouble()))
// << flush;
// }
// // --- fin debug
switch (ParaGlob::Dimension())
{ case 3: ParaGlob::param->Ajout_grandeur_consultable(&typQ1,VOL_TOTAL2D_AVEC_PLAN_XY);
case 2: ParaGlob::param->Ajout_grandeur_consultable(&typQ1,VOL_TOTAL2D_AVEC_PLAN_XZ);
case 1: ParaGlob::param->Ajout_grandeur_consultable(&typQ1,VOL_TOTAL2D_AVEC_PLAN_YZ);
default: break;
};
// au début on met une norme très grande, car a priori on n'a absolument pas convergé !
Grandeur_scalaire_double& gr
= *((Grandeur_scalaire_double*) typQ1.Grandeur_pointee()); // pour simplifier
*(gr.ConteneurDouble()) = ConstMath::grand;
ParaGlob::param->Ajout_grandeur_consultable(&typQ1,NORME_CONVERGENCE);
};
};
// constructeur de copie
Algori::Algori (const Algori& algo) :
typeCalcul(algo.typeCalcul)
,avec_typeDeCalcul(algo.avec_typeDeCalcul)
,soustypeDeCalcul(algo.soustypeDeCalcul)
,avec_soustypeDeCalcul(algo.avec_soustypeDeCalcul)
,paraTypeCalcul(algo.paraTypeCalcul),mode_debug(algo.mode_debug)
,permet_affichage(algo.permet_affichage)
,pa(algo.pa),temps_derniere_sauvegarde(algo.temps_derniere_sauvegarde)
,list_incre_temps_sauvegarder(algo.list_incre_temps_sauvegarder)
,list_incre_temps_calculer(algo.list_incre_temps_calculer)
,tempsDerniereSortieFilCalcul(algo.tempsDerniereSortieFilCalcul)
,noms_fichier(algo.noms_fichier)
,typeFlotExterne(algo.typeFlotExterne)
,entreePrinc(algo.entreePrinc),debut_increment(algo.debut_increment)
,visualise(),visualise_maple(),visualise_geomview(),visualise_Gid(),visualise_Gmsh()
,toto_masse(NULL),icharge(algo.icharge)
,phase_de_convergence(algo.phase_de_convergence) // variables de travail
,nombre_de_bonnes_convergences(algo.nombre_de_bonnes_convergences) // "
,nombre_de_mauvaises_convergences(algo.nombre_de_mauvaises_convergences) // "
,a_converge(algo.a_converge),a_converge_iterMoins1(algo.a_converge_iterMoins1) // "
,max_var_residu(algo.max_var_residu) // variables de travail
,nb_cycle_test_max_var_residu(algo.nb_cycle_test_max_var_residu) // variables de travail
,v_int(algo.v_int) // "
,tab_para_stockage(algo.tab_para_stockage) //,pt_icharge(algo.pt_icharge)
,E_cin_0(algo.E_cin_0),E_cin_t(algo.E_cin_t),E_cin_tdt(algo.E_cin_tdt)
,E_int_t(algo.E_int_t),E_int_tdt(algo.E_int_tdt) // différentes énergies et bilan
,E_ext_t(algo.E_ext_t),E_ext_tdt(algo.E_ext_tdt),bilan_E(algo.bilan_E) // "
,q_mov_t(algo.q_mov_t),q_mov_tdt(algo.q_mov_tdt)
,P_acc_tdt(algo.P_acc_tdt),P_int_tdt(algo.P_int_tdt),P_ext_tdt(algo.P_ext_tdt),bilan_P_tdt(algo.bilan_P_tdt)
,P_acc_t(algo.P_acc_t),P_int_t(algo.P_int_t),P_ext_t(algo.P_ext_t),bilan_P_t(algo.bilan_P_t)
,E_visco_numerique_t(algo.E_visco_numerique_t),E_visco_numerique_tdt(algo.E_visco_numerique_tdt)
,E_bulk(algo.E_bulk),P_bulk(algo.P_bulk)
,F_int_t(algo.F_int_t),F_ext_t(algo.F_ext_t) // forces généralisées int et ext à t et t+dt
,F_int_tdt(algo.F_int_tdt),F_ext_tdt(algo.F_ext_tdt) // "
,F_totale_tdt(algo.F_totale_tdt),residu_final(algo.residu_final)
,X_t(algo.X_t),X_tdt(algo.X_tdt),delta_X(algo.delta_X),var_delta_X(algo.var_delta_X)
,delta_t_precedent_a_convergence(algo.delta_t_precedent_a_convergence)
,vitesse_t(algo.vitesse_t),vitesse_tdt(algo.vitesse_tdt)
,acceleration_t(algo.acceleration_t),acceleration_tdt(algo.acceleration_tdt)
,cas_ass_eps(NULL),Ass_eps(NULL),cas_ass_eps11(NULL),Ass_eps11(NULL)
,cas_ass_sig(NULL),Ass_sig(NULL),cas_ass_sig11(NULL),Ass_sig11(NULL)
,mat_glob_sigeps(NULL),vglob_sigeps(NULL),vglobal_sigeps(NULL)
,nbddl_sigeps11(0),nbddl_sigeps(0)
,cas_ass_err(NULL),Ass_err(NULL),nbddl_err(0)
,avec_remont_sigma(false),avec_remont_eps(false),avec_erreur(false)
,energTotal(algo.energTotal),energHourglass(algo.energHourglass)
,energFrottement(algo.energFrottement),energPenalisation(algo.energPenalisation)
,energStabiliMembBiel(algo.energStabiliMembBiel)
,deja_lue_entete_parametre(algo.deja_lue_entete_parametre)
//------- amortissement visqueux critique
,amortissement_cinetique(algo.amortissement_cinetique)
,taille_moyenne_glissante(algo.taille_moyenne_glissante)
,moyenne_glissante(algo.moyenne_glissante), moy_gliss_t(algo.moy_gliss_t)
,sauve_E_cin(algo.sauve_E_cin),indice_EC1(algo.indice_EC1),nb_Ecin_stocker(algo.nb_Ecin_stocker)
,test_fraction_energie(algo.test_fraction_energie),X_EcinMax(algo.X_EcinMax)
,max_nb_decroit_pourRelaxDyn(algo.max_nb_decroit_pourRelaxDyn)
,inter_nb_entre_relax(1),fct_nD_inter_nb_entre_relax(algo.fct_nD_inter_nb_entre_relax)
,nom_fct_nD_inter_nb_entre_relax(algo.nom_fct_nD_inter_nb_entre_relax)
,nb_depuis_derniere_relax(0)
,compteur_decroit_pourRelaxDyn(algo.compteur_decroit_pourRelaxDyn)
,coef_arret_pourRelaxDyn(algo.coef_arret_pourRelaxDyn),pic_E_cint_t(algo.pic_E_cint_t)
,dernier_pic(algo.dernier_pic)
,max_pic_E_cin(algo.max_pic_E_cin),coef_redemarrage_pourRelaxDyn(algo.coef_redemarrage_pourRelaxDyn)
,max_deltaX_pourRelaxDyn(algo.max_deltaX_pourRelaxDyn),nb_max_dX_OK_pourRelaxDyn(algo.nb_max_dX_OK_pourRelaxDyn)
,nb_dX_OK_pourRelaxDyn(0),nb_deb_testfin_pourRelaxDyn(algo.nb_deb_testfin_pourRelaxDyn)
,nb_deb_test_amort_cinetique(algo.nb_deb_test_amort_cinetique)
,compteur_test_pourRelaxDyn(algo.compteur_test_pourRelaxDyn),compteur_pic_energie(algo.compteur_pic_energie)
// ...... the same pour l'amortissement local
,amortissement_cinetique_au_noeud(algo.amortissement_cinetique_au_noeud)
,nb_deb_test_amort_cinetique_noe(algo.nb_deb_test_amort_cinetique_noe)
,E_cinNoe_tdt(algo.E_cinNoe_tdt),E_cinNoe_t(algo.E_cinNoe_t)
,max_nb_decroit_pourRelaxDyn_noe(algo.max_nb_decroit_pourRelaxDyn_noe)
,compteur_decroit_pourRelaxDyn_noe(algo.compteur_decroit_pourRelaxDyn_noe)
,coef_arret_pourRelaxDyn_noe(algo.coef_arret_pourRelaxDyn_noe),dernier_pic_noe(algo.dernier_pic_noe)
,pic_E_cint_t_noe(algo.pic_E_cint_t_noe),max_pic_E_cin_noe(algo.max_pic_E_cin_noe)
,coef_redemarrage_pourRelaxDyn_noe(algo.coef_redemarrage_pourRelaxDyn_noe)
,compteur_pic_energie_noe(algo.compteur_pic_energie_noe)
//------- amortissement visqueux critique
,opt_cal_C_critique(algo.opt_cal_C_critique),f_(algo.f_)
,ampli_visco(algo.ampli_visco),C_inter(NULL)
,type_calcul_visqu_critique(algo.type_calcul_visqu_critique)
,F_int_tdt_prec(algo.F_int_tdt_prec),F_ext_tdt_prec(algo.F_int_tdt_prec)
,listeVarGlob(algo.listeVarGlob),listeVecGlob(algo.listeVecGlob)
//----- fin des amortissements ---
,arret_a_equilibre_statique(algo.arret_a_equilibre_statique),vglob_stat(algo.vglob_stat)
,volume_total_matiere(algo.volume_total_matiere),vol_total2D_avec_plan_ref(algo.vol_total2D_avec_plan_ref)
// -- controle précision convergence
,nom_modulation_precision(algo.nom_modulation_precision),modulation_precision(NULL),fct_norme(NULL)
//---- grandeurs de travail privées ------
,vec_trav()
//------- temps cpu -----
,tempsInitialisation(algo.tempsInitialisation),tempsMiseAjourAlgo(algo.tempsMiseAjourAlgo)
,tempsCalEquilibre(algo.tempsCalEquilibre),tempsRaidSmEner(algo.tempsRaidSmEner)
,tempsSecondMembreEnerg(algo.tempsSecondMembreEnerg),tempsResolSystemLineaire(algo.tempsResolSystemLineaire)
,tempsSauvegarde(algo.tempsSauvegarde),tempsSortieFilCalcul(algo.tempsSortieFilCalcul)
,tempsRaidSmEnerContact(algo.tempsRaidSmEnerContact)
,tempsSecondMembreEnergContact(algo.tempsSecondMembreEnergContact)
,temps_CL(algo.temps_CL),temps_CLL(algo.temps_CLL)
,temps_lois_comportement(algo.temps_lois_comportement),temps_metrique_K_SM(algo.temps_metrique_K_SM)
,temps_chargement(algo.temps_chargement),temps_rech_contact(algo.temps_rech_contact)
,ptalgocombi(NULL)
#ifndef UTILISATION_MPI
,lesTempsCpu(16)
#else
,lesTempsCpu(18),distribution_CPU_algo(algo.distribution_CPU_algo) // distribution de charge sur les CPU
,temps_transfert_court(algo.temps_transfert_court),temps_transfert_long(algo.temps_transfert_long)
,temps_attente(algo.temps_attente)
#endif
//---------- stockage pour la transmission des grandeurs consultables -----
// ,stock_compteur(algo.stock_compteur),val_stock_compteur(NULL)
// ,stock_icharge(algo.stock_icharge),val_stock_icharge(NULL)
{ // on met à jour ParaGlob
ParaGlob::param->ChangeParaAlgoControleActifs(&pa);
if (vglob_stat != NULL)
vglob_stat = new Vecteur(*vglob_stat);
// // 2) on adapte le stockage
// val_stock_compteur = (Grandeur_scalaire_entier*) stock_compteur.Grandeur_pointee();
// val_stock_icharge = (Grandeur_scalaire_entier*) stock_icharge.Grandeur_pointee();
};
// destructeur
Algori::~Algori ()
{ if (toto_masse != NULL)
delete toto_masse;
if (cas_ass_eps != NULL) {delete cas_ass_eps;cas_ass_eps=NULL;}
if (Ass_eps != NULL) {delete Ass_eps;Ass_eps=NULL;}
if (cas_ass_eps11 != NULL) {delete cas_ass_eps11;cas_ass_eps11=NULL;}
if (Ass_eps11 != NULL) {delete Ass_eps11;Ass_eps11=NULL;}
if (cas_ass_sig != NULL) {delete cas_ass_sig;cas_ass_sig=NULL;}
if (Ass_sig != NULL) {delete Ass_sig;Ass_sig=NULL;}
if (cas_ass_sig11 != NULL) {delete cas_ass_sig11;cas_ass_sig11=NULL;}
if (Ass_sig11 != NULL) {delete Ass_sig11;Ass_sig11=NULL;}
if (cas_ass_err != NULL) {delete cas_ass_err;cas_ass_err=NULL;}
if (Ass_err != NULL) {delete Ass_err;Ass_err=NULL;}
if (mat_glob_sigeps != NULL) {delete mat_glob_sigeps;mat_glob_sigeps=NULL;}
if (vglob_sigeps != NULL) {delete vglob_sigeps;vglob_sigeps=NULL;}
if (vglobal_sigeps != NULL) {delete vglobal_sigeps;vglobal_sigeps=NULL;}
if (vglob_stat != NULL) delete vglob_stat;
};
//lecture des parametres de controle
// et préparation de la sortie des paramètres globaux
void Algori::Lecture(UtilLecture & entreePrinc,ParaGlob & paraglob,LesMaillages& lesMail)
{ // lecture des paramètres
pa.Lecture_paraAlgoControle(entreePrinc);
// mise à jour des paramètres globaux
paraglob.Change_Nb_diggit_double(1,pa.Nb_diggit_double_calcul());
paraglob.Change_Nb_diggit_double(2,pa.Nb_diggit_double_graphique());
paraglob.Change_Nb_diggit_double(3,pa.Nb_diggit_double_ecran());
if (paraglob.EtatDeLaLecturePointInfo() <= 0) // cas de la première lecture dans le .info
Preparation_conteneurs_interne(lesMail);
// // -- modif concernant le stockage global pour volume déplacé: cas d'élément 2D dans un calcul 3D
// // on met à jour le tableau de volume déplacé en fonction du nombre de maillage effectif
// int nbMailMax = lesMail.NbMaillage();
// // normalement ne fait rien si la taille n'est pas changé
// if (vol_total2D_avec_plan_ref.Taille() != nbMailMax)
// {vol_total2D_avec_plan_ref.Change_taille(nbMailMax,Coordonnee(ParaGlob::Dimension()));
// // on remet à jour le stockage des grandeurs globales
// if ( pa.CalVolTotalEntreSurfaceEtPlansRef())
// { listeVarGlob["vol_total2D_avec_plan_yz"]=&(vol_total2D_avec_plan_ref(1)(1));
// listeVarGlob["vol_total2D_avec_plan_xz"]=&(vol_total2D_avec_plan_ref(1)(2));
// listeVarGlob["vol_total2D_avec_plan_xy"]=&(vol_total2D_avec_plan_ref(1)(3));
// };
// // s'il y a plus de 1 maillage, on définit de nouvelles variables globales
// if (pa.CalVolTotalEntreSurfaceEtPlansRef())
// for (int nbMail =2; nbMail<= nbMailMax; nbMail++)
// { // l'ordre des string est fait pour que le switch ensuite soit ok
// string nom1("vol_total2D_avec_plan_xy_"+ChangeEntierSTring(nbMail));
// listeVarGlob[nom1]=&(vol_total2D_avec_plan_ref(nbMail)(3));
// TypeQuelconque_enum_etendu::Ajout_un_TypeQuelconque_enum_etendu
// (VOL_ELEM_AVEC_PLAN_REF,nom1,SCALAIRE_DOUBLE);
// string nom2("vol_total2D_avec_plan_yz_"+ChangeEntierSTring(nbMail));
// listeVarGlob[nom2]=&(vol_total2D_avec_plan_ref(nbMail)(1));
// TypeQuelconque_enum_etendu::Ajout_un_TypeQuelconque_enum_etendu
// (VOL_ELEM_AVEC_PLAN_REF,nom2,SCALAIRE_DOUBLE);
// string nom3("vol_total2D_avec_plan_xz_"+ChangeEntierSTring(nbMail));
// listeVarGlob[nom3]=&(vol_total2D_avec_plan_ref(nbMail)(2));
// TypeQuelconque_enum_etendu::Ajout_un_TypeQuelconque_enum_etendu
// (VOL_ELEM_AVEC_PLAN_REF,nom3,SCALAIRE_DOUBLE);
//
// // --- on ajoute les grandeurs au niveau de paraglob
// // si elles n'existent pas
// double titi; // une grandeur de travail
// Grandeur_scalaire_double grand_courant(titi); // idem
// TypeQuelconque typQ1(GENERIQUE_UNE_GRANDEUR_GLOBALE,NU_DDL,grand_courant); // idem
// switch (ParaGlob::Dimension())
// { case 3: if (ParaGlob::param->GrandeurGlobal(nom1) == NULL)
// ParaGlob::param->Ajout_grandeur_consultable(&typQ1,nom1);
// case 2: if (ParaGlob::param->GrandeurGlobal(nom2) == NULL)
// ParaGlob::param->Ajout_grandeur_consultable(&typQ1,nom2);
// case 1: if (ParaGlob::param->GrandeurGlobal(nom3) == NULL)
// ParaGlob::param->Ajout_grandeur_consultable(&typQ1,nom1);
// default: break;
// };
// };
// };
};
// préparation des conteneurs interne, utilisés après la lecture
// où dans le cas où il n'y a pas de lecture directe
// (pour un sous algo via un algo combiné par exemple)
void Algori::Preparation_conteneurs_interne(LesMaillages& lesMail)
{ // on teste la présence d'un élément , si oui on considère que tous les autres sont présents
map < string, const double * , std::less <string> >::iterator imap;
imap = listeVarGlob.find("energie_cinetique");
if (imap == listeVarGlob.end()) // la map ne contient pas "energie_cinetique"
{
// remplissage de la liste des variables scalaires globales
// tout d'abord pour les énergies globales
listeVarGlob["energie_cinetique"]=&E_cin_tdt; listeVarGlob["energie_interne"]=&E_int_tdt;
listeVarGlob["energie_externe"]=&E_ext_tdt; listeVarGlob["energie_bilan"]=&bilan_E;
// la quantité de mouvement totale
listeVarGlob["quantite_mouvement"]=&q_mov_tdt;
// puis pour les puissances
listeVarGlob["puissance_acceleration"]=&P_acc_tdt; listeVarGlob["puissance_interne"]=&P_int_tdt;
listeVarGlob["puissance_externe"]=&P_ext_tdt; listeVarGlob["puissance_bilan"]=&bilan_P_tdt;
// // puis les énergies globales pour chaque maillage
// listeVarGlob["ener_cin_par_maillage"]=&E_cin_t; listeVarGlob["energie_interne"]=&E_int_t;
// listeVarGlob["energie_externe"]=&E_ext_t; listeVarGlob["energie_bilan"]=&bilan_E;
// // la quantité de mouvement totale
// listeVarGlob["quantite_mouvement"]=&q_mov_t; listeVarGlob["energie_bilan"]=&bilan_E;
// // puis pour les puissances
// listeVarGlob["puissance_acceleration"]=&P_acc_t; listeVarGlob["puissance_interne"]=&P_int_t;
// listeVarGlob["puissance_externe"]=&P_ext_t; listeVarGlob["puissance_bilan"]=&bilan_P_t;
// pour les énergies internes, elles sont systématiquement calculées
listeVarGlob["energie_elastique"]=&energTotal.EnergieElastique();
listeVarGlob["energie_plastique"]=&energTotal.DissipationPlastique();
listeVarGlob["energie_visqueuse"]=&energTotal.DissipationVisqueuse();
listeVarGlob["energie_hourglass"]=&energHourglass;
listeVarGlob["energie_penalisation"]=&energPenalisation;
listeVarGlob["energie_stabilisation_membrane_biel"]=&energStabiliMembBiel;
listeVarGlob["energie_frot_elast"]=&energFrottement.EnergieElastique();
listeVarGlob["energie_frot_plast"]=&energFrottement.DissipationPlastique();
listeVarGlob["energie_frot_visq"]=&energFrottement.DissipationVisqueuse();
// cas d'une viscosité numérique on l'a sort systématiquement même si elle est nulle
// ce qui permet une vérif éventuelle
listeVarGlob["energie_visco_numerique"]=&E_visco_numerique_tdt;
// idem pour le bulk viscosity
listeVarGlob["energie_bulk_viscosity"]=&E_bulk;listeVarGlob["puissance_bulk_viscosity"]=&P_bulk;
// volume totale de la matière
listeVarGlob["volume_total_matiere"]=&volume_total_matiere;
// -- volume déplacé: cas d'élément 2D dans un calcul 3D
// vol_total2D_avec_plan_ref; // volume total entre la surface et : yz, xz,xy
// dans une première étape on considère uniquement un seul maillage, ce sera changé éventuellement
// aprés
if ( pa.CalVolTotalEntreSurfaceEtPlansRef())
{ listeVarGlob["vol_total2D_avec_plan_yz"]=&(vol_total2D_avec_plan_ref(1)(1));
listeVarGlob["vol_total2D_avec_plan_xz"]=&(vol_total2D_avec_plan_ref(1)(2));
listeVarGlob["vol_total2D_avec_plan_xy"]=&(vol_total2D_avec_plan_ref(1)(3));
};
// -- cas des temps cpu
// //------- temps cpu -----
// Temps_CPU_HZpp tempsInitialisation; // lesTempsCpu(1)
// Temps_CPU_HZpp tempsMiseAjourAlgo; // lesTempsCpu(2)
// Temps_CPU_HZpp tempsCalEquilibre; // lesTempsCpu(3)
// Temps_CPU_HZpp tempsRaidSmEner; // lesTempsCpu(4)
// Temps_CPU_HZpp tempsSecondMembreEnerg; // lesTempsCpu(5)
// Temps_CPU_HZpp tempsResolSystemLineaire; // lesTempsCpu(6)
// Temps_CPU_HZpp tempsSauvegarde; // lesTempsCpu(7)
// Temps_CPU_HZpp tempsSortieFilCalcul; // lesTempsCpu(8)
// Temps_CPU_HZpp tempsRaidSmEnerContact; // lesTempsCpu(9)
// Temps_CPU_HZpp tempsSecondMembreEnergContact; // lesTempsCpu(10)
// Temps_CPU_HZpp temps_CL; // lesTempsCpu(11)
// Temps_CPU_HZpp temps_CLL; // lesTempsCpu(12)
// Temps_CPU_HZpp temps_lois_comportement; // lesTempsCpu(13)
// Temps_CPU_HZpp temps_metrique_K_SM; // lesTempsCpu(14)
// Temps_CPU_HZpp temps_chargement; // lesTempsCpu(15)
// Temps_CPU_HZpp temps_rech_contact; // lesTempsCpu(16)
// si calcul //:
// Temps_CPU_HZpp temps_transfert_court; // lesTempsCpu(17)
// Temps_CPU_HZpp temps_transfert_long ; // lesTempsCpu(19)
// Temps_CPU_HZpp temps_attente ; // lesTempsCpu(18)
// Tableau <Coordonnee3> lesTempsCpu; // un tableau intermédiaire qui récupère et globalise les temps pour les sorties
// // via listeVarGlob, mais c'est les variables Temps_CPU_HZpp qui stockent
// // réellement les temps
listeVarGlob["tpsU_InitAlgo"]=&lesTempsCpu(1)(1);
// listeVarGlob["tps_Syst_InitAlgo"]=&lesTempsCpu(1)(2);
// listeVarGlob["tps_Reel_InitAlgo"]=&lesTempsCpu(1)(3);
listeVarGlob["tpsU_MiseAJourAlgo"]=&lesTempsCpu(2)(1);
// listeVarGlob["tps_Syst_MiseAJourAlgo"]=&lesTempsCpu(2)(2);
// listeVarGlob["tps_Reel_MiseAJourAlgo"]=&lesTempsCpu(2)(3);
listeVarGlob["tpsU_CalEquilibre"]=&lesTempsCpu(3)(1);
// listeVarGlob["tps_Syst_CalEquilibre"]=&lesTempsCpu(3)(2);
// listeVarGlob["tps_Reel_CalEquilibre"]=&lesTempsCpu(3)(3);
listeVarGlob["tpsU_MatSmLoc"]=&lesTempsCpu(4)(1);
// listeVarGlob["tps_Syst_MatSmLoc"]=&lesTempsCpu(4)(2);
// listeVarGlob["tps_Reel_MatSmLoc"]=&lesTempsCpu(4)(3);
listeVarGlob["tpsU_SmLoc"]=&lesTempsCpu(5)(1);
// listeVarGlob["tps_Syst_SmLoc"]=&lesTempsCpu(5)(2);
// listeVarGlob["tps_Reel_SmLoc"]=&lesTempsCpu(5)(3);
listeVarGlob["tpsU_ResSystLineaire"]=&lesTempsCpu(6)(1);
// listeVarGlob["tps_Syst_ResSystLineaire"]=&lesTempsCpu(6)(2);
// listeVarGlob["tps_Reel_ResSystLineaire"]=&lesTempsCpu(6)(3);
listeVarGlob["tpsU_Sauvegarde"]=&lesTempsCpu(7)(1);
// listeVarGlob["tps_Syst_Sauvegarde"]=&lesTempsCpu(7)(2);
// listeVarGlob["tps_Reel_Sauvegarde"]=&lesTempsCpu(7)(3);
listeVarGlob["tpsU_SortieFilCalcul"]=&lesTempsCpu(8)(1);
// listeVarGlob["tps_Syst_SortieFilCalcul"]=&lesTempsCpu(8)(2);
// listeVarGlob["tps_Reel_SortieFilCalcul"]=&lesTempsCpu(8)(3);
listeVarGlob["tpsU_contactMatSmLoc"]=&lesTempsCpu(9)(1);
// listeVarGlob["tps_Syst_contactMatSmLoc"]=&lesTempsCpu(9)(2);
// listeVarGlob["tps_Reel_contactMatSmLoc"]=&lesTempsCpu(9)(3);
listeVarGlob["tpsU_contactSmLoc"]=&lesTempsCpu(10)(1);
// listeVarGlob["tps_Syst_contactSmLoc"]=&lesTempsCpu(10)(2);
// listeVarGlob["tps_Reel_contactSmLoc"]=&lesTempsCpu(10)(3);
// le tableau sert également aux temps pour la mise en place des CL et CLL
// car la classe LesCondLim n'a pas vocation a gérer les I/O des tps de cpu
// par contre les temps sont stocké dans LesCondLim, lesTempsCpu sert d'intermédiaire
listeVarGlob["tpsU_CL"]=&lesTempsCpu(11)(1);
// listeVarGlob["tps_Syst_CL"]=&lesTempsCpu(11)(2);
// listeVarGlob["tps_Reel_CL"]=&lesTempsCpu(11)(3);
listeVarGlob["tpsU_CLL"]=&lesTempsCpu(12)(1);
// listeVarGlob["tps_Syst_CLL"]=&lesTempsCpu(12)(2);
// listeVarGlob["tps_Reel_CLL"]=&lesTempsCpu(12)(3);
listeVarGlob["tpsU_Lois_comp"]=&lesTempsCpu(13)(1);
listeVarGlob["tpsU_Metriques"]=&lesTempsCpu(14)(1);
listeVarGlob["tpsU_chargement"]=&lesTempsCpu(15)(1);
listeVarGlob["tpsU_rech_contact"]=&lesTempsCpu(16)(1);
#ifdef UTILISATION_MPI
// cas d'un calcul parallèle
listeVarGlob["tpsU_transfert_inter_cpu"]=&lesTempsCpu(17)(1);
listeVarGlob["tpsU_attente_inter_cpu"]=&lesTempsCpu(18)(1);
#endif
// cas des vecteurs globaux
int dim = ParaGlob::Dimension();
if (ParaGlob::AxiSymetrie())
dim--;
// def des grandeurs courantes de type coordonnee
Coordonnee coor(dim); // un type coordonnee typique
// maintenant on définit une grandeur typique de type Grandeur_coordonnee
Grandeur_coordonnee gt(coor);
// def d'un type quelconque représentatif pour un vecteur force à chaque noeud
{ // pour les forces externes
TypeQuelconque typQ(FORCE_GENE_EXT,X1,gt);
listeVecGlob.push_back(typQ);
};
{ // pour les forces internes
TypeQuelconque typQ(FORCE_GENE_INT,X1,gt);
listeVecGlob.push_back(typQ);
};
{ // pour les forces totales = internes + externes
TypeQuelconque typQ(FORCE_GENE_TOT,X1,gt);
listeVecGlob.push_back(typQ);
};
{ // pour les forces résidu d'équilibre
TypeQuelconque typQ(RESIDU_GLOBAL,X1,gt);
listeVecGlob.push_back(typQ);
};
{ // pour les variations de positions
TypeQuelconque typQ(DELTA_XI,X1,gt);
listeVecGlob.push_back(typQ);
};
listeVecGlob.sort(); // on ordonne la liste
listeVecGlob.unique(); // suppression des doublons
// -- modif concernant le stockage global pour volume déplacé: cas d'élément 2D dans un calcul 3D
// on met à jour le tableau de volume déplacé en fonction du nombre de maillage effectif
int nbMailMax = lesMail.NbMaillage();
// normalement ne fait rien si la taille n'est pas changé
if (vol_total2D_avec_plan_ref.Taille() != nbMailMax)
{vol_total2D_avec_plan_ref.Change_taille(nbMailMax,Coordonnee(ParaGlob::Dimension()));
// on remet à jour le stockage des grandeurs globales
if ( pa.CalVolTotalEntreSurfaceEtPlansRef())
{ listeVarGlob["vol_total2D_avec_plan_yz"]=&(vol_total2D_avec_plan_ref(1)(1));
listeVarGlob["vol_total2D_avec_plan_xz"]=&(vol_total2D_avec_plan_ref(1)(2));
listeVarGlob["vol_total2D_avec_plan_xy"]=&(vol_total2D_avec_plan_ref(1)(3));
};
// s'il y a plus de 1 maillage, on définit de nouvelles variables globales
if (pa.CalVolTotalEntreSurfaceEtPlansRef())
for (int nbMail =2; nbMail<= nbMailMax; nbMail++)
{ // l'ordre des string est fait pour que le switch ensuite soit ok
string nom1("vol_total2D_avec_plan_xy_"+ChangeEntierSTring(nbMail));
listeVarGlob[nom1]=&(vol_total2D_avec_plan_ref(nbMail)(3));
TypeQuelconque_enum_etendu::Ajout_un_TypeQuelconque_enum_etendu
(VOL_ELEM_AVEC_PLAN_REF,nom1,SCALAIRE_DOUBLE);
string nom2("vol_total2D_avec_plan_yz_"+ChangeEntierSTring(nbMail));
listeVarGlob[nom2]=&(vol_total2D_avec_plan_ref(nbMail)(1));
TypeQuelconque_enum_etendu::Ajout_un_TypeQuelconque_enum_etendu
(VOL_ELEM_AVEC_PLAN_REF,nom2,SCALAIRE_DOUBLE);
string nom3("vol_total2D_avec_plan_xz_"+ChangeEntierSTring(nbMail));
listeVarGlob[nom3]=&(vol_total2D_avec_plan_ref(nbMail)(2));
TypeQuelconque_enum_etendu::Ajout_un_TypeQuelconque_enum_etendu
(VOL_ELEM_AVEC_PLAN_REF,nom3,SCALAIRE_DOUBLE);
// --- on ajoute les grandeurs au niveau de paraglob
// si elles n'existent pas
double titi=0.; // une grandeur de travail
Grandeur_scalaire_double grand_courant(titi); // idem
TypeQuelconque typQ1(GENERIQUE_UNE_GRANDEUR_GLOBALE,NU_DDL,grand_courant); // idem
switch (ParaGlob::Dimension())
{ case 3: if (ParaGlob::param->GrandeurGlobal(nom1) == NULL)
ParaGlob::param->Ajout_grandeur_consultable(&typQ1,nom1);
case 2: if (ParaGlob::param->GrandeurGlobal(nom2) == NULL)
ParaGlob::param->Ajout_grandeur_consultable(&typQ1,nom2);
case 1: if (ParaGlob::param->GrandeurGlobal(nom3) == NULL)
ParaGlob::param->Ajout_grandeur_consultable(&typQ1,nom1);
default: break;
};
};
};
};
};
// affichage des parametres
void Algori::Affiche() const// affichage de tous les parametres
{ Affiche1();
Affiche2();
};
void Algori::Affiche1() const// affichage du type de calcul
{ cout << "--> type de calcul = " << Nom_TypeCalcul(typeCalcul) << '\n';
cout << paraTypeCalcul.Taille() << " parametre(s) = ";
int nbcar = ParaGlob::NbdigdoEC();
for (int i=1; i<= paraTypeCalcul.Taille(); i++)
cout << setw(nbcar) << setprecision(nbcar) << paraTypeCalcul(i) << " , ";
cout << endl;
};
void Algori::Affiche2() const// affichage des parametres de controle
{ pa.Affiche();
};
// examine s'il y a convergence ou pas en fonction des parametres
// de controle et du resultat du systeme lineaire
// affiche: indique si l'on veut l'affichage ou non des infos
// itera : correspond au compteur d'itération dans un cas d'équilibre itératif (cal implicite par exemple)
// arrêt: indique qu'il vaut mieux arrêter le calcul
bool Algori::Convergence
(bool affiche,double last_var_ddl_max,Vecteur& residu,double maxPuissExt,double maxPuissInt,double maxReaction
,int itera,bool& arret)
{ string type_norme = pa.Norme().nom1; // pour simplifier
arret = false; // a priori on ne s'arrête pas
double maxresidu = residu.Max_val_abs();
// --- on passe les infos au niveau global
{ParaGlob::param->Mise_a_jour_grandeur_consultable_Scalaire_double(MAXPUISSEXT,maxPuissExt);
ParaGlob::param->Mise_a_jour_grandeur_consultable_Scalaire_double(MAXPUISSINT,maxPuissInt);
ParaGlob::param->Mise_a_jour_grandeur_consultable_Scalaire_double(MAXREACTION,maxReaction);
ParaGlob::param->Mise_a_jour_grandeur_consultable_Scalaire_double(MAXRESIDUGLOBAL,maxresidu);
};
////debug ------
// int iddl=0;
// maxresidu = residu.Max_val_abs(iddl);
// cout << "\n iddl= "<<iddl << " residu_total(iddl)= "<<residu(iddl) ;
////fin debug ------
double pa_precision = pa.Precision(); // initialisation de la précision demandé
if (modulation_precision != NULL) // cas où en plus on fait une modulation de précision
{pa_precision *= (modulation_precision->Valeur_pour_variables_globales())(1);}
double prec_res_mini = 4; // 1 mini
// dans le cas où on veut un test de convergence uniquement sur la partie statique
if ( (arret_a_equilibre_statique ) // le dimensionnement se fera à l'affectation (=)
&& (type_calcul_visqu_critique || pa.Amort_visco_artificielle()))
{
#ifdef MISE_AU_POINT
if (vglob_stat == NULL)
{ cout << "\n erreur le vecteur vglob_stat n'est pas attribue (=NULL) "
<< " on ne peut pas effectuer la convergence avec arret en equilibre statique uniquement "
<< " revoir les parametres (ou se plaindre officiellement !! ) ";
cout << "\n Algori::Convergence(..";
Sortie(1);
};
#endif
// if (vglob_stat->Taille() != 0) // si la taille est non nulle
// // cela veut dire que le vecteur a été affecté, donc on peut l'utiliser
maxresidu = vglob_stat->Max_val_abs();
};
int nbcar = ParaGlob::NbdigdoEC();
// 1) --- affichage des maxis de puissances virtuelles
if (affiche && (ParaGlob::NiveauImpression() > 1))
{ cout << "\n max puissance exterieure = " << setprecision(nbcar)<< maxPuissExt ;
cout << "\n max puissance interieurs = " << setprecision(nbcar)<< maxPuissInt ;
cout << "\n max des reactions = " << setprecision(nbcar)<< maxReaction ;
cout << "\n max du residu total = " << setprecision(nbcar)<< maxresidu ;
};
// 2) --- affichage de la norme
double laNorme = 0.; // valeur par défaut
if (strstr(type_norme.c_str(),"Residu/Reaction_et_Residu"))
{cout << "\n *** norme exploratoire: ";
// on initialise le cas "Residu"
laNorme = maxresidu; //init
double maxpuissance =MaX(maxReaction,MaX(maxPuissExt,maxPuissInt));
if (maxpuissance > prec_res_mini)
// cas de la norme Residu/Reaction
{if (maxReaction < 1.e-8)
laNorme = maxresidu;
else
laNorme = maxresidu/maxpuissance;
if (affiche &&(ParaGlob::NiveauImpression() > 1))
cout << "\n**** Norme Residu/Reaction --> " << setprecision(nbcar)<< laNorme ;
}
else // cas d'un résidu très faible
{pa_precision = prec_res_mini/50.;
if (affiche&&(ParaGlob::NiveauImpression() > 1))
cout << "\n**** Norme Residu --> " << setprecision(nbcar)<< laNorme ;
cout << "\n: pa_precision est mis au mini de la force admise: "
<< setprecision(nbcar)<< pa_precision << endl;
};
}
else if (strstr(type_norme.c_str(),"Residu/Reaction"))
{if (maxReaction < 1.e-8)
laNorme = maxresidu;
else
laNorme = maxresidu/maxReaction;
if (affiche &&(ParaGlob::NiveauImpression() > 1))
cout << "\n**** Norme Residu/Reaction --> " << setprecision(nbcar)<< laNorme ;
}
else if (strstr(type_norme.c_str(),"Residu/PVExterne"))
{ if (maxPuissExt < 1.e-8)
laNorme = maxresidu;
else
laNorme = maxresidu/maxPuissExt;
if (affiche&&(ParaGlob::NiveauImpression() > 1))
cout << "\n*** Norme Residu/PVExterne --> " << setprecision(nbcar)<< laNorme ;
}
else if (strstr(type_norme.c_str(),"Residu/PVInterne"))
{ if (maxPuissInt < 1.e-8)
laNorme = maxresidu;
else
laNorme = maxresidu/maxPuissInt;
if (affiche&&(ParaGlob::NiveauImpression() > 1))
cout << "\n*** Norme Residu/PVInterne --> " << setprecision(nbcar)<< laNorme ;
}
else if (strstr(type_norme.c_str(),"Residu/maxPVI"))
{ // détermination du maximum des puissances
double maxpuissance =MaX(maxReaction,MaX(maxPuissExt,maxPuissInt));
if (maxpuissance < 1.e-8)
laNorme = maxresidu;
else
laNorme = maxresidu/maxpuissance;
if (affiche&&(ParaGlob::NiveauImpression() > 1))
cout << "\n*** Norme Residu/maxPVI --> " << setprecision(nbcar)<< laNorme ;
}
else if (strstr(type_norme.c_str(),"Residu"))
{laNorme = maxresidu;
if (affiche&&(ParaGlob::NiveauImpression() > 1))
cout << "\n**** Norme Residu --> " << setprecision(nbcar)<< laNorme ;
}
else if (strstr(type_norme.c_str(),"min(Res,Res/Reaction)"))
{if (maxReaction < 1.e-8)
laNorme = maxresidu;
else
laNorme = MiN(maxresidu,maxresidu/maxReaction);
if (affiche &&(ParaGlob::NiveauImpression() > 1))
cout << "\n**** Norme min(Res,Res/Reaction) --> " << setprecision(nbcar)<< laNorme ;
}
else if (strstr(type_norme.c_str(),"min(Res,Res/MaX(Reaction_et_PVExterne))"))
{if (MaX(maxReaction,maxPuissExt) < 1.e-8)
laNorme = maxresidu;
else
laNorme = MiN(maxresidu,maxresidu/MaX(maxReaction,maxPuissExt));
if (affiche &&(ParaGlob::NiveauImpression() > 1))
cout << "\n**** Norme min(Res,Res/MaX(Reaction_et_PVExterne)) --> "
<< setprecision(nbcar)<< laNorme ;
}
else if (strstr(type_norme.c_str(),"E_cinetique/E_statique_ET_ResSurReact"))
{if (affiche && (ParaGlob::NiveauImpression() > 1))
{ cout << "\n E_cinetique = " << setprecision(nbcar)<< E_cin_tdt ;
cout << "\n E_ext = " << setprecision(nbcar)<< -E_ext_tdt ;
cout << "\n E_int = " << setprecision(nbcar)<< E_int_tdt ;
};
double max_abs_eners = MaX(Dabs(E_int_tdt),Dabs(E_ext_tdt));
if (MaX(max_abs_eners,maxReaction) < 1.e-8)
laNorme = MaX(E_cin_tdt,maxresidu);
else if (maxReaction < 1.e-8)
laNorme = MaX(E_cin_tdt/max_abs_eners,maxresidu);
else
laNorme = MaX(E_cin_tdt/max_abs_eners,maxresidu/maxReaction);
if (affiche &&(ParaGlob::NiveauImpression() > 1))
cout << "\n**** Norme E_cinetique/E_statique_ET_ResSurReact --> " << setprecision(nbcar)<< laNorme ;
}
else if (strstr(type_norme.c_str(),"E_cinetique/E_statique_ET_Res/Reac_et_Fext"))
{if (affiche && (ParaGlob::NiveauImpression() > 1))
{ cout << "\n E_cinetique = " << setprecision(nbcar)<< E_cin_tdt ;
cout << "\n E_ext = " << setprecision(nbcar)<< -E_ext_tdt ;
cout << "\n E_int = " << setprecision(nbcar)<< E_int_tdt ;
};
double max_abs_eners = MaX(Dabs(E_int_tdt),Dabs(E_ext_tdt));
double maxpuiss_reac =MaX(maxReaction,MaX(maxPuissExt,maxPuissInt));
if (MaX(max_abs_eners,maxReaction) < 1.e-8)
laNorme = MaX(E_cin_tdt,maxresidu);
else if (maxpuiss_reac < 1.e-8)
laNorme = MaX(E_cin_tdt/max_abs_eners,maxresidu);
else
laNorme = MaX(E_cin_tdt/max_abs_eners,maxresidu/maxpuiss_reac);
if (affiche &&(ParaGlob::NiveauImpression() > 1))
cout << "\n**** E_cinetique/E_statique_ET_Res/Reac_et_Fext --> " << setprecision(nbcar)<< laNorme ;
}
else if (strstr(type_norme.c_str(),"E_cin/E_stat_ET_min(Res,Res/Reac_et_Fext)"))
{if (affiche && (ParaGlob::NiveauImpression() > 1))
{ cout << "\n E_cinetique = " << setprecision(nbcar)<< E_cin_tdt ;
cout << "\n E_ext = " << setprecision(nbcar)<< -E_ext_tdt ;
cout << "\n E_int = " << setprecision(nbcar)<< E_int_tdt ;
};
double max_abs_eners = MaX(Dabs(E_int_tdt),Dabs(E_ext_tdt));
double maxpuiss_reac =MaX(maxReaction,MaX(maxPuissExt,maxPuissInt));
if (MaX(max_abs_eners,maxReaction) < 1.e-8)
laNorme = MaX(E_cin_tdt,maxresidu);
else if (maxpuiss_reac < 1.e-8)
laNorme = MaX(E_cin_tdt/max_abs_eners,maxresidu);
else
laNorme = MaX(E_cin_tdt/max_abs_eners, MiN(maxresidu,maxresidu/maxpuiss_reac));
if (affiche &&(ParaGlob::NiveauImpression() > 1))
cout << "\n**** E_cin/E_stat_ET_min(Res,Res/Reac_et_Fext) --> "
<< setprecision(nbcar)<< laNorme ;
}
else if (strstr(type_norme.c_str(),"E_cinetique"))
{if (affiche && (ParaGlob::NiveauImpression() > 1))
{ cout << "\n E_cinetique = " << setprecision(nbcar)<< E_cin_tdt ;
cout << "\n E_ext = " << setprecision(nbcar)<< -E_ext_tdt ;
cout << "\n E_int = " << setprecision(nbcar)<< E_int_tdt ;
};
laNorme = E_cin_tdt;
if (affiche &&(ParaGlob::NiveauImpression() > 1))
cout << "\n**** Norme E_cinetique --> " << setprecision(nbcar)<< laNorme ;
}
else if (strstr(type_norme.c_str(),"Bilan_puissance/Max(puiss)"))
{// si on est en statique, la puissance d'accélération = 0. normalement donc n'intervient pas
if (MaX(MaX(Dabs(P_acc_tdt),Dabs(P_int_tdt)),Dabs(P_ext_tdt)) < 1.e-8)
laNorme = bilan_P_tdt;
else
laNorme = MaX(bilan_P_tdt,bilan_P_tdt/MaX(MaX(Dabs(P_acc_tdt),Dabs(P_int_tdt)),Dabs(P_ext_tdt)));
if (affiche &&(ParaGlob::NiveauImpression() > 1))
cout << "\n**** Norme Bilan_puissance/Max(puiss) --> "
<< setprecision(nbcar)<< laNorme ;
}
else if (strstr(type_norme.c_str(),"fonction_nD:"))
{ // il s'agit ici de l'utilisation d'une fonction nD
laNorme = (fct_norme->Valeur_pour_variables_globales())(1);
if (affiche && (ParaGlob::NiveauImpression() > 1))
{ cout << "\n E_cinetique = " << setprecision(nbcar)<< E_cin_tdt ;
cout << "\n E_ext = " << setprecision(nbcar)<< -E_ext_tdt ;
cout << "\n E_int = " << setprecision(nbcar)<< E_int_tdt ;
};
if (affiche &&(ParaGlob::NiveauImpression() > 1))
cout << "\n**** Norme "<< setprecision(nbcar)<<pa.Norme().nom2<<" --> "
<< setprecision(nbcar)<< laNorme ;
}
if (affiche && (modulation_precision != NULL)) // cas où en plus on fait une modulation de précision
cout << "\n (precision= "<< setprecision(nbcar)<<pa_precision<<" ) ";
if (affiche&&(ParaGlob::NiveauImpression() > 1)) cout << endl;
//---- debug
// if (E_cin_tdt == 0)
// { cout << "\n énergie nulle !! : \n Algori::Convergence(... ";
// Sortie(1);};
//---- fin debug
// 3) --- premier test brut de la convergence
if ((laNorme <= pa_precision) && (itera != 0))
{a_converge = true;} // cas courant de convergence
else if ((laNorme <= pa_precision) && (itera == 0))
// cas particulier de la première itération
{ if (maxPuissInt == 0.)
// si la puissance interne est strictement nulle, là il n'y a rien qui bouge, donc cela veut-dire
// que tout est bloqué, et on peut dire que cela a convergé car rien ne bougera après
{a_converge = true;}
else if ((maxPuissInt <= ConstMath::trespetit) && (maxPuissExt > ConstMath::petit))
// on a théoriquement convergé, mais on a une puissance externe non nulle et une puissance interne nulle
// donc on est dans des petits nombres, il vaut mieux refaire un passage avec un calcul de delta ddl
{a_converge = false;}
else {a_converge = true;};
}
else
{a_converge = false;};
// une partie exploratoire
int nbcoup = 1;
if ((strstr(type_norme.c_str(),"Residu/Reaction_et_Residu")) && (!(laNorme <= pa_precision)) && (itera > nbcoup)
&& (nombre_de_mauvaises_convergences > nbcoup))
{ cout << "\n norme transitoire = " << setprecision(nbcar)
<< pa_precision * PUISSN(10.,nombre_de_mauvaises_convergences-nbcoup )
<< endl;
if (laNorme < pa_precision * PUISSN(10.,nombre_de_mauvaises_convergences-nbcoup ))
{a_converge = true;};
};
// fin de la partie exploratoire
// on met à jour le tableau de l'historique de l'évolution des résidus
// au minimum on sauvegarde le résidu actuel et le précédent
int nb_cycle_controle = MaX(2,pa.NbCycleControleResidu());
bool cycle_controle = false; // variable de pilotage: a priori le cycle est hors service
if (itera > 0)
{if (itera == 1)
// dimensionnement le premier incrément, puis mise en place pour les autres incréments
{ max_var_residu.Change_taille(nb_cycle_controle,ConstMath::tresgrand);};
if (itera <= nb_cycle_controle)
// cas ou on rempli le tableau max_var_residu sans s'en servir
{ max_var_residu(itera)=maxresidu;}
else
{ // cas où on rempli les tableaux et on fait une rotation
cycle_controle = true; // le cycle est en service
for (int i=1;i<nb_cycle_controle;i++)
{max_var_residu(i)=max_var_residu(i+1);}
max_var_residu(nb_cycle_controle)= maxresidu;
};
};
// cas où l'on prend en compte l'évolution des var ddl et/ou des max résidu
double var_mini_ddl = pa.VarMiniDdl();
// double var_maxi_ddl = pa.VarMaxiDdl();
int nbmax_cycle_test_var_residu= pa.PlageControleResidu();
// traitement initial dans le cas iteratif
if (itera > 0)
{ if ((pa.TypeDePilotage() == PILOT_GRADIENT)
||(strstr(type_norme.c_str(),"et_miniVarDdl")) || (strstr(type_norme.c_str(),"et_maxiVarDdl"))
|| (strstr(type_norme.c_str(),"et_VarRes")))
{ // initialisation éventuelle
if (itera == 1)
{nb_cycle_test_max_var_residu=0;}
if (itera > nb_cycle_controle)
{ //contrôle de la convergence que si ça n'a pas convergé
if (!a_converge)
{ // on signale qu'il vaut mieux arrêter car il n'y a pas de décroissance du résidu
if (((pa.TypeDePilotage() == PILOT_GRADIENT)||(strstr(type_norme.c_str(),"et_VarRes"))) &&
(max_var_residu(nb_cycle_controle) >= max_var_residu(1)))
{if(nb_cycle_test_max_var_residu > nbmax_cycle_test_var_residu)
{arret = true; phase_de_convergence =-2;}
else nb_cycle_test_max_var_residu++; }
// on signale qu'il vaut mieux arrêter car la variation de ddl est trop faible
if (((pa.TypeDePilotage() == PILOT_GRADIENT)||(strstr(type_norme.c_str(),"et_miniVarDdl"))) &&
(last_var_ddl_max <= var_mini_ddl)) {
arret = true; phase_de_convergence =-3;}
// on signale qu'il vaut mieux arrêter car la variation de ddl est trop grande
if (((pa.TypeDePilotage() == PILOT_GRADIENT)||(strstr(type_norme.c_str(),"et_maxiVarDdl"))) &&
(last_var_ddl_max <= var_mini_ddl)) {
arret = true; phase_de_convergence =-4;}
};
};
};
}; //- fin test sur itera
// cas où on demande de vérifier deux fois le résidu
if (strstr(type_norme.c_str(),"et_verification_ddouble"))
{// tout d'abord on ne peut pas s'arrêter si le cycle de convergence
if (itera > 0) // on n'intervient que pour les itérations > 0
{if (itera == 1) // on ne peut rien contrôler, donc par principe on repasse
{a_converge_iterMoins1 = a_converge; // on sauvegarde pour l'itération qui suie
a_converge = false;}
else // on est sup à 1
// on applique l'algo
{if (a_converge_iterMoins1 && a_converge)
{} // c'est ok on ne fait rien
else if (a_converge) // mais a_converge_iterMoins1 n'est pas vrai
{a_converge_iterMoins1 = a_converge; // on le met à vrai
a_converge = false; // on signal que la convergence n'est pas finie
};
};
}
else {a_converge = false;} ; // si itera = 0 on refait systématiquement une passe
};
// --- on passe les infos au niveau global
Transfert_ParaGlob_NORME_CONVERGENCE(laNorme);
//en dernier lieu on regarde si les puissances sont infinies ou nan
// si oui on signale une divergence associée
// maxPuissExt,double maxPuissInt,double maxReaction
if ((std::isinf(maxPuissExt))||( std::isnan(maxPuissExt)))
{if ((ParaGlob::NiveauImpression() > 2) || (permet_affichage> 0))
cout << "\n *** maxPuissExt inifni ou nan : divergence imposee *** ";
a_converge = false; phase_de_convergence=-11;arret = true;
};
if ((std::isinf(maxPuissInt))||( std::isnan(maxPuissInt)))
{if ((ParaGlob::NiveauImpression() > 2) || (permet_affichage> 0))
cout << "\n *** maxPuissInt inifni ou nan : divergence imposee *** ";
a_converge = false; phase_de_convergence=-11;arret = true;
};
if ((std::isinf(maxReaction))||( std::isnan(maxReaction)))
{if ((ParaGlob::NiveauImpression() > 2) || (permet_affichage> 0))
cout << "\n *** maxReaction inifni ou nan : divergence imposee *** ";
a_converge = false; phase_de_convergence=-11;arret = true;
};
// retour
return a_converge;
};
// sortie d'info sur un increment de calcul pour les ddl
// nb_casAssemb : donne le numéro du cas d'assemblage
void Algori::InfoIncrementDdl(LesMaillages * lesMail,
int inSol,double maxDeltaDdl,const Nb_assemb& nb_casAssemb)
{ // la variation maxi de ddl
// recherche des Ddl concernes
int nbNoeud1,nbMaillage1; double val0;
Ddl ddl1 = lesMail->NoeudIndice(inSol,nbNoeud1,nbMaillage1,val0,nb_casAssemb.n);
int nbcar = ParaGlob::NbdigdoEC();
// ecriture des infos
cout << "\n(assemblage " << nb_casAssemb.n << ") "
<< "delta maxi: " << setprecision(nbcar)<< maxDeltaDdl
<<", ddl " << ddl1.Nom()
<<", noeud/mail "<< nbNoeud1 << "/" << nbMaillage1
<<" , var total:"<< setprecision(nbcar)<< ddl1.Valeur() - val0
<< ", sur:" << setprecision(nbcar)<< ddl1.Valeur();
// passage en global
ParaGlob::param->Mise_a_jour_grandeur_consultable_Scalaire_double(MAXvarDdl,maxDeltaDdl);
// on affiche les autres informations du même noeud si elles existent
Noeud& noe=lesMail->Noeud_LesMaille(nbMaillage1,nbNoeud1); // récup du noeud
Enum_ddl enumax=ddl1.Id_nom();
int inci= enumax - PremierDdlFamille(enumax) ; // incice de composante du ddl -1
bool absolue = true; // a priori on sort les infos en absolu
List_io <Enum_ddl> lienu = noe.Les_type_de_ddl(absolue); // récup de tous les types de ddl du noeud
List_io <Enum_ddl>::iterator il,ilfin=lienu.end(); bool autres_valeurs = false;
for (il=lienu.begin();il!=ilfin;il++)
{ Enum_ddl enu = *il;
if ( (enu!=ddl1.Id_nom()) && (noe.En_service(enu)) && ( (enu-PremierDdlFamille(enu))==inci))
{ if(!autres_valeurs) {cout << "\n autres ddl ";};
cout << Nom_ddl(enu) << " " ;
if (noe.Tdt())
{cout << setprecision(nbcar)<< noe.Valeur_tdt(enu)
<< " var " << setprecision(nbcar)<< noe.Valeur_tdt(enu)-noe.Valeur_t(enu);
}
else
{cout << setprecision(nbcar)<< noe.Valeur_t(enu)
<< " var " << setprecision(nbcar)<< noe.Valeur_t(enu)-noe.Valeur_0(enu);};
cout << "; ";
autres_valeurs=true;
};
};
cout << endl;
};
// sortie d'info sur un increment de calcul pour les réaction
// dans le cas d'un compteur, par exemple dans le cas implicite
// nb_casAssemb : donne le numéro du cas d'assemblage
void Algori::InfoIncrementReac(LesMaillages * lesMail,int compteur,
int inreaction,double maxreaction,const Nb_assemb& nb_casAssemb)
{ int nbNoeud2,nbMaillage2;
#ifdef UTILISATION_MPI
// cas d'un calcul //, pour l'instant seule la (ou les) matrices du CPU 0 sont concernées
if (ParaGlob::Monde()->rank() != 0)
return ;
#endif
Ddl ddl2 = lesMail->NoeudIndice(inreaction,nbNoeud2,nbMaillage2,nb_casAssemb.n);
int nbcar = ParaGlob::NbdigdoEC();
// ecriture des infos
cout << "\n ITERATION : " << compteur;
if (ParaGlob::NiveauImpression() > 1)
{cout << "\n(assemblage " << nb_casAssemb.n << ") "
<< " reaction maxi : " << setprecision(nbcar)<< maxreaction <<", du ddl " << ddl2.Nom()
<<", du noeud/maillage "<< nbNoeud2 << "/" << nbMaillage2 ;
};
cout << endl;
};
// sortie d'info sur un increment de calcul pour les réaction
// dans le cas explicite par exemple (pas de compteur par rapport
// au cas précédent)
// nb_casAssemb : donne le numéro du cas d'assemblage
void Algori::InfoIncrementReac(LesMaillages * lesMail,
int inreaction,double maxreaction,const Nb_assemb& nb_casAssemb)
{ int nbNoeud2,nbMaillage2;
#ifdef UTILISATION_MPI
// cas d'un calcul //, pour l'instant seule la (ou les) matrices du CPU 0 sont concernées
if (ParaGlob::Monde()->rank() != 0)
return ;
#endif
Ddl ddl2 = lesMail->NoeudIndice(inreaction,nbNoeud2,nbMaillage2,nb_casAssemb.n);
int nbcar = ParaGlob::NbdigdoEC();
// ecriture des infos
if (ParaGlob::NiveauImpression() > 1)
{cout << "\n(assemblage " << nb_casAssemb.n << ") "
<< " reaction maxi : " << setprecision(nbcar)<< maxreaction <<", du ddl " << ddl2.Nom()
<<", du noeud/maillage "<< nbNoeud2 << "/" << nbMaillage2 ;
cout << endl;
};
};
// calcul une approximation des différences énergie en jeux
// affichage éventuelle des ces énergies et du bilan
// V : ddl de vitesse
// coef_mass : en fait il faut utiliser 1/coef_mass * mat_mass pour la matrice masse, ceci due à la spécificité de l'algo
// les différentes énergie et efforts généralisées sont des variables internes à l'algo
// en sortie: énergie cinétique : E_cin_tdt, énergie interne : E_int_tdt, énergie externe = E_ext_tdt, bilan : bilan_E
// idem avec les puissances
// énergie visqueuse due aux forces visqueuses numériques
// icharge : compteur d'increment
// brestart : booleen qui indique si l'on est en restart ou pas
void Algori::CalEnergieAffichage(const double& coef_mass,const Vecteur & V,const Mat_abstraite& mat_mass
,const Vecteur & delta_X,int icharge,bool brestart,const Vecteur & gamma
,const Vecteur & forces_vis_num)
{
#ifdef UTILISATION_MPI
// cas d'un calcul //, pour l'instant seule le CPU 0 est concerné
if (ParaGlob::Monde()->rank() != 0)
return ;
#endif
// -- le calcul est conditionnelle
if (icharge >= pa.NbIncrCalEnergie())
{int nbcar = ParaGlob::NbdigdoEC();
// --- cas des énergies ------
// initialisation
v_int.Change_taille(V.Taille()); v_int.Zero();
// calcul de l'énergie cinétique et de la quantité de mouvement
// v_int contient les quantités de mouvement locales à chaque ddl
E_cin_tdt = (0.5/coef_mass) * (V * (mat_mass.Prod_vec_mat(V,v_int)));
//---- debug
// if (E_cin_tdt == 0)
// { cout << "\n énergie nulle !! : \n Algori::CalEnergieAffichage(... ";
// Sortie(1);};
//---- fin debug
// calcul de la quantité de mouvement globale
q_mov_tdt = v_int.Somme();
// calcul de l'énergie interne dépensée
v_int.Zero(); // init à 0
if (!brestart)
{ // cas normal
v_int += F_int_t; v_int += F_int_tdt; E_int_tdt = E_int_t - 0.5 * (delta_X * v_int); }
else // cas d'un restart, F_int_t n'est pas défini, on utilise la formule des rectangles plutôt que des trapèzes
{ v_int += F_int_tdt; E_int_tdt = E_int_t - delta_X * v_int; }
// calcul de l'énergie externe dépensée
v_int.Zero(); // init à 0
if (!brestart)
{ // cas normal
v_int += F_ext_t; v_int += F_ext_tdt; E_ext_tdt = E_ext_t + 0.5 * (delta_X * v_int);}
else // cas d'un restart, F_int_t n'est pas défini, on utilise la formule des rectangles plutôt que des trapèzes
{ v_int += F_ext_tdt; E_ext_tdt = E_ext_t + delta_X * v_int;}
// bilan des énergies (on retire l'énergie cinétique initiale si elle exite)
bilan_E = E_cin_tdt - E_cin_0 + E_int_tdt - E_ext_tdt;
// --- cas des puissances ------
// calcul de la puissance d'accélération
v_int.Zero();
P_acc_tdt = (1./coef_mass) * (V * (mat_mass.Prod_vec_mat(gamma,v_int)));
// calcul de la puissance interne
P_int_tdt = V * F_int_tdt;
// calcul de la puissance externe
P_ext_tdt = V * F_ext_tdt;
// bilan des puissances
bilan_P_tdt = P_acc_tdt - P_int_tdt - P_ext_tdt;
// cas des forces visqueuses numériques
double puissance_visco_num = 0.;
if (pa.Amort_visco_artificielle())
{E_visco_numerique_tdt = E_visco_numerique_t + delta_X * forces_vis_num;
puissance_visco_num = V * forces_vis_num;
bilan_P_tdt += puissance_visco_num;
bilan_E += E_visco_numerique_tdt;
};
// --- affichage ----
if (( pa.Vrai_commande_sortie(icharge,temps_derniere_sauvegarde))
&&(pa.AfficheIncrEnergie()))
{// cas des énergies
cout << "\n energies: cin= "<< setprecision(nbcar)<< E_cin_tdt
<<" int= " << setprecision(nbcar)<< E_int_tdt
<< " ext= "<< setprecision(nbcar)<< E_ext_tdt
<< " bilan= " << setprecision(nbcar)<< bilan_E
<< " qmv= " << setprecision(nbcar)<< q_mov_tdt;
// cas des puissances
cout << "\n puissances: acc= "<< setprecision(nbcar)<< P_acc_tdt
<<" int= " << setprecision(nbcar)<< P_int_tdt
<< " ext= " << setprecision(nbcar)<< P_ext_tdt
<< " bilan= " << setprecision(nbcar)<< bilan_P_tdt;
if (pa.Amort_visco_artificielle())
cout << "\n energie d'amortissement numerique: "
<< setprecision(nbcar)<< E_visco_numerique_tdt
<< " puissance d'amortissement numerique: "
<< setprecision(nbcar)<< puissance_visco_num;
};
// --- on passe les infos au niveau global
{ParaGlob::param->Mise_a_jour_grandeur_consultable_Scalaire_double(ENERGIE_CINETIQUE,E_cin_tdt);
ParaGlob::param->Mise_a_jour_grandeur_consultable_Scalaire_double(ENERGIE_EXTERNE,E_ext_tdt);
ParaGlob::param->Mise_a_jour_grandeur_consultable_Scalaire_double(ENERGIE_INTERNE,E_int_tdt);
ParaGlob::param->Mise_a_jour_grandeur_consultable_Scalaire_double(ENERGIE_VISCO_NUMERIQUE,E_visco_numerique_t);
ParaGlob::param->Mise_a_jour_grandeur_consultable_Scalaire_double(ENERGIE_BILAN,bilan_E);
ParaGlob::param->Mise_a_jour_grandeur_consultable_Scalaire_double(QUANTITE_MOUVEMENT,q_mov_tdt);
ParaGlob::param->Mise_a_jour_grandeur_consultable_Scalaire_double(PUISSANCE_ACCELERATION,P_acc_tdt);
ParaGlob::param->Mise_a_jour_grandeur_consultable_Scalaire_double(PUISSANCE_INTERNE,P_int_tdt);
ParaGlob::param->Mise_a_jour_grandeur_consultable_Scalaire_double(PUISSANCE_EXTERNE,P_ext_tdt);
ParaGlob::param->Mise_a_jour_grandeur_consultable_Scalaire_double(PUISSANCE_BILAN,bilan_P_tdt);
}
};
};
// idem pour un calcul statique, c'est-à-dire sans énergie cinématique
// affichage éventuelle des ces énergies et du bilan
// icharge : compteur d'increment
// brestart : booleen qui indique si l'on est en restart ou pas
void Algori::CalEnergieAffichage(const Vecteur & delta_X,int icharge,bool brestart,const Vecteur & forces_vis_num)
{ // le calcul est conditionnelle
if (icharge >= pa.NbIncrCalEnergie())
{int nbcar = ParaGlob::NbdigdoEC();
// initialisation
v_int.Change_taille(delta_X.Taille()); v_int.Zero();
// calcul de l'énergie interne dépensée
if (!brestart)
{ // cas normal
v_int += F_int_t; v_int += F_int_tdt; E_int_tdt = E_int_t - 0.5 * (delta_X * v_int); }
else // cas d'un restart, F_int_t n'est pas défini, on utilise la formule des rectangles plutôt que des trapèzes
{ v_int += F_int_tdt; E_int_tdt = E_int_t - delta_X * v_int; }
// calcul de l'énergie externe dépensée
v_int.Zero(); // init à 0
if (!brestart)
{ // cas normal
v_int += F_ext_t; v_int += F_ext_tdt; E_ext_tdt = E_ext_t + 0.5 * (delta_X * v_int);}
else // cas d'un restart, F_ext_t n'est pas défini, on utilise la formule des rectangles plutôt que des trapèzes
{ v_int += F_ext_tdt; E_ext_tdt = E_ext_t + delta_X * v_int;}
// bilan des énergies (on retire l'énergie cinétique initiale si elle exite)
bilan_E = E_int_tdt - E_ext_tdt;
// --- cas des puissances ------
// recup de l'incrément de temps
double deltat=ParaGlob::Variables_de_temps().IncreTempsCourant();
double unSurDeltat=0;
if (Abs(deltat) >= ConstMath::trespetit)
{unSurDeltat = 1./deltat;}
else
// si l'incrément de temps est tres petit on remplace 1/deltat par un nombre tres grand
{ // non un pas de temps doit être positif !! or certaine fois il peut y avoir des pb
if (unSurDeltat < 0)
{ cout << "\n le pas de temps est négatif !! "; };
unSurDeltat = ConstMath::tresgrand;
};
// calcul de la puissance interne
P_int_tdt = unSurDeltat * delta_X * F_int_tdt;
// calcul de la puissance externe
P_ext_tdt = unSurDeltat * delta_X * F_ext_tdt;
// bilan des puissances
bilan_P_tdt = P_int_tdt + P_ext_tdt;
// cas des forces visqueuses numériques
double puissance_visco_num = 0.;
if (pa.Amort_visco_artificielle())
{E_visco_numerique_tdt = E_visco_numerique_t + delta_X * forces_vis_num;
puissance_visco_num = unSurDeltat * delta_X * forces_vis_num;
bilan_P_tdt += puissance_visco_num;
bilan_E += E_visco_numerique_tdt;
};
// --- affichage ----
if (( pa.Vrai_commande_sortie(icharge,temps_derniere_sauvegarde))
&&(pa.AfficheIncrEnergie()))
{// cas des énergies
cout << "\n energies: int= " << setprecision(nbcar)<< E_int_tdt
<< " ext= " << setprecision(nbcar)<< E_ext_tdt
<< " bilan= " << setprecision(nbcar)<< bilan_E;
if (pa.Amort_visco_artificielle())
cout << " energie numerique: "<< setprecision(nbcar)<< E_visco_numerique_tdt;
if (pa.BulkViscosity())
cout << " ener_bulk: " << setprecision(nbcar)<< E_bulk
<< " P_bulk: "<< setprecision(nbcar)<< P_bulk;
// cas des puissances
cout << "\n puissances(V=delta X): int= " << setprecision(nbcar)<< P_int_tdt
<< " ext= "<< setprecision(nbcar)<< P_ext_tdt
<< " bilan= " << setprecision(nbcar)<< bilan_P_tdt;
};
// --- on passe les infos au niveau global
{ParaGlob::param->Mise_a_jour_grandeur_consultable_Scalaire_double(ENERGIE_EXTERNE,E_ext_tdt);
ParaGlob::param->Mise_a_jour_grandeur_consultable_Scalaire_double(ENERGIE_INTERNE,E_int_tdt);
ParaGlob::param->Mise_a_jour_grandeur_consultable_Scalaire_double(ENERGIE_BILAN,bilan_E);
ParaGlob::param->Mise_a_jour_grandeur_consultable_Scalaire_double(PUISSANCE_INTERNE,P_int_tdt);
ParaGlob::param->Mise_a_jour_grandeur_consultable_Scalaire_double(PUISSANCE_EXTERNE,P_ext_tdt);
ParaGlob::param->Mise_a_jour_grandeur_consultable_Scalaire_double(ENERGIE_VISCO_NUMERIQUE,E_visco_numerique_t);
}
};
};
// dans le cas où un grand nombre d'information nécessaire pour l'algorithme
// est stocké de manière externe sur un fichier
// exemple : calcul d'erreur a partir
// d'un champ d'information stocké de manière externe sur un fichier
// l'acquisition du (ou des) lieu(s) (flot) où sont stocké ces infos est effectuée
// ce lieu fait parti des paramètres de l'algorithme
void Algori::DefFlotExterne(UtilLecture* entreePrinc)
{if (ParaGlob::NiveauImpression() >= 4)
cout << " debut de la lecture eventuelle de fichiers types flotExterne " << endl;
// il y a lecture si le mot clé : flotExterne est rencontré
if (strstr(entreePrinc->tablcar,"flotExterne")!=NULL)
{ // on passe en revue tous les cas possibles
// la lecture s'effectue jusqu'à un nouveau mot clé
MotCle motCle; // ref aux mots cle
// 1. preparation du flot
entreePrinc->NouvelleDonnee();
do
{
// 2. lecture du type de données à lire
int type;
*(entreePrinc->entree) >> type ;
// ------- cas d'un calcul d'erreur sans calcul d'équilibre -------
// fichier des contraintes
if (type==1)
// on balaie la liste des sous_types
{ list <EnumSousTypeCalcul>::const_iterator ili;
list <EnumSousTypeCalcul>::const_iterator ili_fin = soustypeDeCalcul->end();
for (ili = soustypeDeCalcul->begin();ili!= ili_fin;ili++)
if(!(Avec_in(*ili)) && Remonte_in(*ili))
LectureUnTypeExterne(entreePrinc,type);
};
// ------- cas d'un calcul d'erreur sans calcul d'équilibre -------
// fichier des déplacements
if (type==2)
// on balaie la liste des sous_types
{ list <EnumSousTypeCalcul>::const_iterator ili;
list <EnumSousTypeCalcul>::const_iterator ili_fin = soustypeDeCalcul->end();
for (ili = soustypeDeCalcul->begin();ili!= ili_fin;ili++)
if(!(Avec_in(*ili)) && Remonte_in(*ili))
LectureUnTypeExterne(entreePrinc,type);
}
// ------ autre cas à rajouter par la suite -------
// 3. preparation du flot pour la sortie ou la prochaine lecture
entreePrinc->NouvelleDonnee();
}
while ( !motCle.SimotCle(entreePrinc->tablcar)) ;
}
if (ParaGlob::NiveauImpression() >= 4)
cout << " fin de la lecture eventuelle de fichiers types flotExterne " << endl;
};
// lecture d'un type externe
void Algori::LectureUnTypeExterne(UtilLecture* entreePrinc,const int type)
{ // on incrémente la taille des tableaux
int taille = typeFlotExterne.Taille(); taille++;
typeFlotExterne.Change_taille(taille);
noms_fichier.Change_taille(taille);
// sauvegarde du type
typeFlotExterne(taille) = type;
// on crée une liste intermédiaire
ListDeuxString la_list; list<DeuxString > & lalist = la_list.infos;
// deux strings
DeuxString nom;
// lecture tant qu'il n'y a pas d'erreur
while (!entreePrinc->entree->rdstate())
{ // lecture du nom du fichier
*(entreePrinc->entree) >> nom.nomFichier;
*(entreePrinc->entree) >> nom.nomMaillage;
// stockage
lalist.push_back(nom);
}
// stokage de la liste
noms_fichier(taille) = la_list;
};
// ------------METHODES PROTEGEES ----------------:
// calcul de la raideur et du second membre pour tous les maillages
// ainsi que des énergies
// si pb retour false: indique que le calcul c'est mal passé, il y a une erreur
// généré, les résultats: raideur et second membres calculées sont inexploitable
bool Algori::RaidSmEner(LesMaillages * lesMail,Assemblage& Ass,Vecteur & vglobin
,Mat_abstraite& matglob )
{
tempsRaidSmEner.Mise_en_route_du_comptage(); // comptage cpu
// on doit initialiser les temps globaux de loi de comp et de métrique car
// on va ajouter ensuite des temps qui eux mêmes globalisent ce qui se passe à chaque pti
// Temps_CPU_HZpp tps_zero; // un temps d'initialisation
// temps_lois_comportement = tps_zero;
Temps_CPU_HZpp temps_debut_lois_comportement; // temps initial
// temps_metrique_K_SM = tps_zero;
Temps_CPU_HZpp temps_debut_metrique_K_SM; // temps initial
if (permet_affichage >3) cout << "\n -- debut calcul second membre et raideur " << flush;
energTotal.Inita(0.); // initialisation des énergies à 0
energHourglass=0.;energStabiliMembBiel=0.;
volume_total_matiere = 0.; // init
E_bulk = 0.; // init
P_bulk=0.; // init
if (pa.CalVolTotalEntreSurfaceEtPlansRef())
{vol_total2D_avec_plan_ref.Inita(Coordonnee(ParaGlob::Dimension()));
};
#ifdef UTILISATION_MPI
mpi::request reqs1;
mpi::request reqs2;
mpi::request reqs3;
bool premier_passage = true;
#endif
// on gère les exceptions éventuelles en mettant le bloc sous surveillance
try
{// boucle sur les elements
int nbMailMax = lesMail->NbMaillage();
#ifndef UTILISATION_MPI
// cas d'un calcul mono CPU
for (int nbMail =1; nbMail<= nbMailMax; nbMail++)
{int nemax = lesMail->Nombre_element(nbMail);
for (int ne=1; ne<= nemax;ne++)
{
#else
// cas d'un calcul multi-CPU
// on va parcourir les éléments associés au cpu
// on récupère la distribution d'éléments concernant le cpu en cours
const Tableau < list <int > > tab_list_elem_cpu = distribution_CPU_algo.List_element_CPU_en_cours();
// la taille est identique à nbMailMax, sauf si c'est le cpu 0, là le tableau est vide et il n'y
// aura pas de boucle, (ou plutôt on sortira directement de la boucle
// le cas CPU 0 est traité à part
int nb_mail_distrib = tab_list_elem_cpu.Taille();
for (int nbMail =1; nbMail<= nb_mail_distrib; nbMail++)
{const list <int >& list_elem_cpu= tab_list_elem_cpu(nbMail); // pour simplifier
// on balaie les éléments nécessaires
list <int >::const_iterator il,ilfin=list_elem_cpu.end();
for (il = list_elem_cpu.begin();il != ilfin;il++)
{ int ne = (*il);
// on récupère un signal du process 0
temps_attente.Mise_en_route_du_comptage(); // comptage cpu
if (premier_passage) {premier_passage = false;}
else // on attend que les transferts soient finis
{reqs1.wait();
reqs2.wait();
reqs3.wait();
};
temps_attente.Arret_du_comptage(); // fin comptage cpu
#endif
//calcul de la raideur local et du residu local
ElemMeca & el = *((ElemMeca*) &lesMail->Element_LesMaille(nbMail,ne)); // l'element
Tableau<Noeud *>& taN = el.Tab_noeud(); // tableau de noeuds de l'el
temps_debut_lois_comportement=el.Temps_lois_comportement(); // init
temps_debut_metrique_K_SM = el.Temps_metrique_K_SM(); // init
Element::ResRaid resu = el.Calcul_implicit(pa);
////---- débug
//{
//cout << "\n Algori::RaidSmEner debug : ";
//string entete = " affichage de la matrice de raideur avant assemblage";
//matglob.Affichage_ecran(entete);
//entete = " affichage du second membre (puissance interne) avant assemblage ";
//vglobin.Affichage_ecran(entete);
//}
// cout << "\n affichage des matrices locales : element numéro =" << ne << endl;
// (resu.res)->Affiche();
// (resu.raid)->Affiche();
// on test la symétrie des matrices locales
//if (!(resu.raid->Symetrie()))
// resu.raid->AfficheNonSymetries();
//-- fin débug
#ifndef UTILISATION_MPI
// --- assemblage et calcul de grandeur globale, pour mono-CPU
// assemblage
Ass.AssemSM (vglobin,*(resu.res),el.TableauDdl(),taN); // du second membre
////---debug---
//double maxPuissInt = vglobin.Max_val_abs();
//if (Dabs(maxPuissInt) > ConstMath::petit)
// {cout << "\n debug Algori::RaidSmEner maxPuissInt= "<<maxPuissInt<<endl
// << "\n residu interne= "<<*(resu.res) << endl ;
// };
////---fin debug ---
if (pa.Symetrie_matrice())
Ass.AssembMatSym (matglob,*(resu.raid),el.TableauDdl(),taN); // de la raideur
else
Ass.AssembMatnonSym (matglob,*(resu.raid),el.TableauDdl(),taN); // de la raideur
// globalisation des énergies
energTotal += el.EnergieTotaleElement();
energHourglass += el.Energie_Hourglass();
energStabiliMembBiel += el.Energie_stab_membBiel();
E_bulk += el.Energie_Bulk();
P_bulk += el.Puissance_Bulk();
// globalisation des volumes
volume_total_matiere += el.Volume();
if (pa.CalVolTotalEntreSurfaceEtPlansRef())
{ const Coordonnee& volPlan = el.VolumePlan();
if (volPlan.Dimension())
vol_total2D_avec_plan_ref(nbMail) += volPlan;
//--- debug
// cout << "\n calcul des volumes balayés";
// vol_total2D_avec_plan_ref.Affiche();
// cout << "\n " << *(listeVarGlob["vol_total2D_avec_plan_yz"]) << " " << *(listeVarGlob["vol_total2D_avec_plan_xz"])
// << " " << *(listeVarGlob["vol_total2D_avec_plan_xy"]) << endl;
// fin débug
};
#else
// cas d'un calcul parallèle, et CPU != 0
int num_process = ParaGlob::Monde()->rank();
if (num_process != 0)
{tempsRaidSmEner.Arret_du_comptage();
temps_transfert_court.Mise_en_route_du_comptage(); // comptage cpu
DeuxEntiers num_el_et_mail(el.Num_elt(),el.Num_maillage());
// on transmet les numéros d'élément et de maillage
reqs1 = ParaGlob::Monde()->isend(0, 24, num_el_et_mail);
// puis on transmets le vecteur résidu
reqs2 = resu.res->Ienvoi_MPI(0,25);
//puis la matrice
reqs3 = resu.raid->Ienvoi_MPI(0, 26);
temps_transfert_court.Arret_du_comptage(); // fin comptage cpu
tempsRaidSmEner.Mise_en_route_du_comptage();
};
#endif
// globalisation des temps cpu loi de comp et métrique
temps_lois_comportement += el.Temps_lois_comportement();
temps_lois_comportement -= temps_debut_lois_comportement;
temps_metrique_K_SM += el.Temps_metrique_K_SM();
temps_metrique_K_SM -= temps_debut_metrique_K_SM;
////--- debug
//{
//cout << "\n Algori::RaidSmEner debug : ";
//string entete = " affichage de la matrice de raideur (puissance interne) après assemblage";
//matglob.Affichage_ecran(entete);
//entete = " affichage du second membre (puissance interne) après assemblage ";
//vglobin.Affichage_ecran(entete);
//}
//// fin debug
};
};
}
catch (ErrJacobienNegatif_ElemMeca excep)
// cas d'un jacobien négatif "a prendre en compte"
{ phase_de_convergence = -5; a_converge = false; return false; }
catch (ErrVarJacobienMini_ElemMeca excep)
// cas d'une variation de jacobien trop importante
{ phase_de_convergence = -6; a_converge = false; return false; }
catch (ErrNonConvergence_loiDeComportement excep)
// cas d'une erreur survenue à cause d'une non convergence pour la résolution
// d'une loi de comportement incrémentale
{ switch (excep.cas)
{case 1: phase_de_convergence = -8; break;
case 0: default : phase_de_convergence = -7; break;
};
a_converge = false; return false;
}
catch (ErrCalculFct_nD)
// cas d'une d'une erreur survenue à cause d'une erreur sur le calcul d'une fct nD
// au niveau du chargement
{ phase_de_convergence = -10; a_converge = false;
cout << "\n *** erreur exception genere par une fonction nD utilisee en chargement ";
return false;
}
catch (ErrSortie)
// cas d'une direction voulue vers la sortie
// on relance l'interuption pour le niveau supérieur
{ ErrSortie toto;
throw (toto);
}
catch (ErrSortieFinale)
// cas d'une direction voulue vers la sortie
// on relance l'interuption pour le niveau supérieur
{ ErrSortieFinale toto;
tempsRaidSmEner.Arret_du_comptage(); // fin comptage cpu
throw (toto);
}
catch ( ... )
{ if (ParaGlob::NiveauImpression() >= 1)
{cout << "\n warning: exception generee par un element mais dont la prise en compte "
<< " n'est pas prevu !, on ne fait rien et on continue le calcul";
if (ParaGlob::NiveauImpression() >= 4) cout << "\n Algori::RaidSmEner(..";
};
}
// affichage éventuelle de la matrice de raideur et du second membre
if (ParaGlob::NiveauImpression() >= 10)
{ string entete = " affichage de la matrice de raideur (puissance interne) avant conditions limites";
matglob.Affichage_ecran(entete);
entete = " affichage du second membre (puissance interne) avant condition limites ";
vglobin.Affichage_ecran(entete);
};
// -- on transfert en global les énergies internes
Transfert_ParaGlob_energies_internesLoisComp();
Transfert_ParaGlob_energies_hourglass_bulk_stab();
// idem pour les volumes entre plans
Transfert_ParaGlob_volume_entre_plans();
// -- calcul des intégrales éventuelles avec transfert en global
lesMail->Integration();
// --- debug ------- essai ----
// cout << "\n *** ener_bulk " << E_bulk;
// --- fin debug ------- essai ----
// if ((permet_affichage > 6) || (ParaGlob::NiveauImpression() < 10))
// {string entete = " affichage du second membre (puissance interne) avant condition limites ";
// vglobin.Affiche();
// };
if (permet_affichage >3) cout << "\n -- fin calcul second membre et raideur " << flush;
tempsRaidSmEner.Arret_du_comptage(); // fin comptage cpu
// --- debug ------- essai ----
// cout << "\temps cpu raid SM energ " << tempsRaidSmEner;
// --- fin debug ------- essai ----
#ifdef UTILISATION_MPI
if (ParaGlob::Monde()->rank() == 0)
{ tempsRaidSmEner.Mise_en_route_du_comptage(); // comptage cpu
// récup du nombre total d'éléments, cumul sur tous les maillages
int total_elem = distribution_CPU_algo.NB_total_element();
// on va boucler sur les éléments récupérés des différents process
// jusqu'au nombre maxi d'élément
int nb_elem_deja_calcule = 0; // init
while (nb_elem_deja_calcule < total_elem)
{ // on récupère un résultat de calcul
temps_transfert_court.Mise_en_route_du_comptage(); // comptage cpu
DeuxEntiers num_el_et_mail;
mpi::request reqs1 = ParaGlob::Monde()->irecv(mpi::any_source, 24, num_el_et_mail);
temps_transfert_court.Arret_du_comptage(); // fin comptage cpu
temps_attente.Mise_en_route_du_comptage(); // comptage cpu
mpi::status stat = reqs1.wait(); // on attend que le conteneur soit rempli
temps_attente.Arret_du_comptage(); // fin comptage cpu
int ne = num_el_et_mail.un; // numero d'identification de l'element
int nbMail = num_el_et_mail.deux; // numéro de maillage
// d'où l'élément
ElemMeca & el = *((ElemMeca*) &lesMail->Element_LesMaille(nbMail,ne));
// récupération des conteneurs ad hoc vecteur et raideur
int source = stat.source(); // récupération du numéro de la source
Vecteur * residu = el.Conteneur_Residu();
temps_transfert_court.Mise_en_route_du_comptage(); // comptage cpu
mpi::request reqs2 = residu->Irecup_MPI(source, 25);
Mat_pleine* raideur = el.Conteneur_raideur();
mpi::request reqs3 = raideur->Irecup_MPI(source, 26);
temps_transfert_court.Arret_du_comptage(); // fin comptage cpu
temps_attente.Mise_en_route_du_comptage(); // comptage cpu
reqs2.wait(); // on attend que le conteneur soit rempli
reqs3.wait(); // on attend que le conteneur soit rempli
temps_attente.Arret_du_comptage(); // fin comptage cpu
Tableau<Noeud *>& taN = el.Tab_noeud(); // tableau de noeuds de l'el
// --- assemblage
Ass.AssemSM (vglobin,*residu,el.TableauDdl(),taN); // du second membre
if (pa.Symetrie_matrice())
Ass.AssembMatSym (matglob,*raideur,el.TableauDdl(),taN); // de la raideur
else
Ass.AssembMatnonSym (matglob,*raideur,el.TableauDdl(),taN); // de la raideur
// on incrémente le nombre d'élément traité
nb_elem_deja_calcule++;
};
tempsRaidSmEner.Arret_du_comptage(); // fin comptage cpu
}
// else
// {// on récupère le dernier signal du process 0
//// std::string msg;
//// ParaGlob::Monde()->recv(0, 12, msg);
// // synchronisation ici de tous les process
// ParaGlob::Monde()->barrier();
// };
// synchronisation ici de tous les process
// ParaGlob::Monde()->barrier();
#endif
// retour indiquant que tout c'est bien passé
return true ;
};
// calcul du second membre pour tous les maillages ainsi que des énergies totales
bool Algori::SecondMembreEnerg(LesMaillages * lesMail,Assemblage& Ass,Vecteur & vglobin)
{tempsSecondMembreEnerg.Mise_en_route_du_comptage(); // comptage cpu
// on doit initialiser les temps globaux de loi de comp et de métrique car
// on va ajouter ensuite des temps qui eux mêmes globalisent ce qui se passe à chaque pti
// Temps_CPU_HZpp tps_zero; // un temps d'initialisation
// temps_lois_comportement = tps_zero;
Temps_CPU_HZpp temps_debut_lois_comportement; // temps initial
// temps_metrique_K_SM = tps_zero;
Temps_CPU_HZpp temps_debut_metrique_K_SM; // temps initial
if (permet_affichage >3) cout << "\n -- debut calcul second membre " << flush;
energTotal.Inita(0.); // initialisation des énergies à 0
energHourglass=0.;energStabiliMembBiel=0.;
E_bulk = 0.; // init
P_bulk=0.; // init
volume_total_matiere = 0.; // init
if (pa.CalVolTotalEntreSurfaceEtPlansRef())
vol_total2D_avec_plan_ref.Inita(Coordonnee(ParaGlob::Dimension()));
// on gère les exceptions éventuelles en mettant le bloc sous surveillance
try
{for (int nbMail =1; nbMail<= lesMail->NbMaillage(); nbMail++)
for (int ne=1; ne<= lesMail->Nombre_element(nbMail);ne++)
{ //calcul du residu local
ElemMeca & el = *((ElemMeca*) &lesMail->Element_LesMaille(nbMail,ne)); // l'element
Tableau<Noeud *>& taN = el.Tab_noeud(); // tableau de noeuds de l'el
Temps_CPU_HZpp temps_debut_lois_comportement=el.Temps_lois_comportement(); // init
Temps_CPU_HZpp temps_debut_metrique_K_SM = el.Temps_metrique_K_SM(); // init
Vecteur* res = el.CalculResidu_tdt(pa);
////--- debug
//if (res->Max_val_abs() > 10)
// { cout << "\n debug .... Algori::SecondMembreEnerg( "
// << "\n **** res->Max_val_abs() > 10 ";
// // on recalcule pour le debug le vecteur résidu
// res = el.CalculResidu_tdt(pa);
// };
//
////--- fin debug
// assemblage
Ass.AssemSM (vglobin,*res,el.TableauDdl(),taN); // du second membre
// globalisation des énergies
energTotal += el.EnergieTotaleElement();
energHourglass += el.Energie_Hourglass();
energStabiliMembBiel += el.Energie_stab_membBiel();
E_bulk += el.Energie_Bulk();
P_bulk += el.Puissance_Bulk();
// globalisation des volumes
volume_total_matiere += el.Volume();
// globalisation des temps cpu loi de comp et métrique
temps_lois_comportement += el.Temps_lois_comportement();
temps_lois_comportement -= temps_debut_lois_comportement;
temps_metrique_K_SM += el.Temps_metrique_K_SM();
temps_metrique_K_SM -= temps_debut_metrique_K_SM;
if (pa.CalVolTotalEntreSurfaceEtPlansRef())
{ const Coordonnee& volPlan = el.VolumePlan();
if (volPlan.Dimension())
vol_total2D_avec_plan_ref(nbMail) += volPlan;
};
};
}
catch (ErrJacobienNegatif_ElemMeca excep)
// cas d'un jacobien négatif "a prendre en compte"
{ phase_de_convergence = -5; a_converge = false; return false; }
catch (ErrVarJacobienMini_ElemMeca excep)
// cas d'une variation de jacobien trop importante
{ phase_de_convergence = -6; a_converge = false; return false; }
catch (ErrNonConvergence_loiDeComportement excep)
// cas d'une d'une erreur survenue à cause d'une non convergence pour la résolution
// d'une loi de comportement incrémentale
{ phase_de_convergence = -7; a_converge = false;
cout << "\n non convergence sur une loi de comportement ";
return false;
}
catch (ErrCalculFct_nD)
// cas d'une d'une erreur survenue à cause d'une erreur sur le calcul d'une fct nD
// au niveau du chargement
{ phase_de_convergence = -10; a_converge = false;
cout << "\n *** erreur exception genere par une fonction nD utilisee en chargement ";
return false;
}
catch (ErrSortie)
// cas d'une direction voulue vers la sortie
// on relance l'interuption pour le niveau supérieur
{ ErrSortie toto;
throw (toto);
}
catch (ErrSortieFinale)
// cas d'une direction voulue vers la sortie
// on relance l'interuption pour le niveau supérieur
{ ErrSortieFinale toto;
tempsSecondMembreEnerg.Arret_du_comptage(); // fin comptage cpu
throw (toto);
}
catch ( ... )
{ if (ParaGlob::NiveauImpression() >= 1)
{cout << "\n warning: exception generee par un element mais dont la prise en compte "
<< " n'est pas prevu !, on ne fait rien et on continue le calcul";
if (ParaGlob::NiveauImpression() >= 4) cout << "\n Algori::SecondMembreEnerg(..";
};
}
// affichage éventuelle du second membre
if (ParaGlob::NiveauImpression() >= 10)
{ string entete = " affichage du second membre (puissance interne) avant conditions limites ";
vglobin.Affichage_ecran(entete);
};
if (permet_affichage >3) cout << "\n -- fin calcul second membre " << flush;
// -- on transfert en global les énergies internes
Transfert_ParaGlob_energies_internesLoisComp();
Transfert_ParaGlob_energies_hourglass_bulk_stab();
// idem pour les volumes entre plans
//---- debug
// if (pa.CalVolTotalEntreSurfaceEtPlansRef())
// { //Tableau <Coordonnee> vol_total2D_avec_plan_ref; // volume total entre la surface et : yz, xz,xy
// cout << "\n debug Algo::SecondMembreEnerg ";
// cout << "\n vol_total2D_avec_plan_ref "
// << vol_total2D_avec_plan_ref(1) << flush;
// };
//---- fin debug
Transfert_ParaGlob_volume_entre_plans();
// -- calcul des intégrales éventuelles avec transfert en global
lesMail->Integration();
tempsSecondMembreEnerg.Arret_du_comptage(); // fin comptage cpu
// retour indiquant que tout c'est bien passé
return true ;
};
// Mise à jour de la raideur et du second membre pour le contact
// calcul des énergies spécifiques au contact
// si pb retour false: indique que le calcul c'est mal passé, il y a une erreur
// généré, les résultats: raideur et second membres calculées sont inexploitables
bool Algori::RaidSmEnerContact(LesContacts * lesCont,Assemblage& Ass,Vecteur & vglobin
,Mat_abstraite& matglob )
{
tempsRaidSmEnerContact.Mise_en_route_du_comptage(); // temps cpu
energFrottement.Inita(0.); // initialisation des énergies de frottement à 0
energPenalisation = 0.;
if (permet_affichage >3) cout << "\n -- debut calcul second membre et raideur pour le contact " << flush;
// on récupère la liste des éléments de contact
LaLIST <ElContact>& listElContact = lesCont->LesElementsDeContact();
LaLIST <ElContact>::iterator il,ilfin=listElContact.end();
// on gère les exceptions éventuelles en mettant le bloc sous surveillance
try
{// boucle sur les elements de contact
for (il=listElContact.begin();il != ilfin; il++)
{
////------ debug
// cout << "\n debug Algori::RaidSmEnerContact ";
//// ------ fin debug
if ((*il).Actif()) // on n'intervient que si le contact est actif
{ //calcul de la raideur locale et du residu local
//------ debug
// (*il).Affiche();
// ------ fin debug
ElContact& elcontact = (*il); // pour simplifier
Tableau<Noeud *>& taN = elcontact.TabNoeud_pour_assemblage(); // tableau de noeuds
// calcul effectif de la raideur et résidu locals
Element::ResRaid resu = elcontact.SM_K_charge_contact();
// cout << "numéro =" << ne << endl;
//------ debug
// (resu.res)->Affiche();
// (resu.raid)->Affiche(); //1,8,1,1,8,1);
// (resu.raid)->Affiche1(1,6,1,1,6,1);
// (int min_i,int max_i,int pas_i,int min_j,int max_j,int pas_j,int nd)
// ------ fin debug
// assemblage
// dans le cas où le retour est un pointeur nul, cela signifie qu'il n'y a pas de second membre et raideur calculés
if (resu.res != NULL)
{ Ass.AssemSM (vglobin,*(resu.res),elcontact.TableauDdlCont(),taN); // du second membre
if (pa.Symetrie_matrice())
Ass.AssembMatSym (matglob,*(resu.raid),elcontact.TableauDdlCont(),taN); // de la raideur
else
Ass.AssembMatnonSym (matglob,*(resu.raid),elcontact.TableauDdlCont(),taN); // de la raideur
};
// globalisation des énergies dues aux frottements
energFrottement += elcontact.EnergieFrottement();
energPenalisation += elcontact.EnergiePenalisation();
}; //-- fin du test sur l'activité
}; //-- fin de la boucle sur les éléments de contact
} //-- fin du try
catch (ErrSortie)
// cas d'une direction voulue vers la sortie
// on relance l'interuption pour le niveau supérieur
{ ErrSortie toto;
throw (toto);
}
catch (ErrSortieFinale)
// cas d'une direction voulue vers la sortie
// on relance l'interuption pour le niveau supérieur
{ ErrSortieFinale toto;
tempsRaidSmEnerContact.Arret_du_comptage(); // temps cpu
throw (toto);
}
catch ( ... )
{ if (ParaGlob::NiveauImpression() >= 1)
{cout << "\n warning: exception generee par un element de contact mais dont la prise en compte "
<< " n'est pas prevu !, on ne fait rien et on continue le calcul";
if (ParaGlob::NiveauImpression() >= 4) cout << "\n Algori::RaidSmEnerContact(..";
};
}
// affichage éventuelle de la matrice de raideur et du second membre
//------ debug
// cout << "\n debug Algori::RaidSmEnerContact ";
// string entete = " affichage du second membre uniquement du au contact ";
// vglobin.Affichage_ecran(entete);
// ------ fin debug
if (ParaGlob::NiveauImpression() >= 10)
{ string entete = " affichage de la matrice de raideur (puissance interne) apres le contact ";
matglob.Affichage_ecran(entete);
entete = " affichage du second membre uniquement du au contact ";
vglobin.Affichage_ecran(entete);
}
// -- on transfert en global les énergies
Transfert_ParaGlob_energies_contact();
if (permet_affichage >3) cout << "\n -- fin calcul second membre et raideur pour le contact " << flush;
tempsRaidSmEnerContact.Arret_du_comptage(); // temps cpu
// retour indiquant que tout c'est bien passé
return true ;
};
// cas du contact: calcul et mise à jour du second membre ainsi que des énergies spécifiques
bool Algori::SecondMembreEnergContact(LesContacts * lesCont,Assemblage& Ass,Vecteur & vglobin
,bool aff_iteration)
{ tempsSecondMembreEnergContact.Mise_en_route_du_comptage(); // temps cpu
energFrottement.Inita(0.); // initialisation des énergies de frottement à 0
energPenalisation = 0.;
volume_total_matiere = 0.; // init
if (permet_affichage >3) cout << "\n -- debut calcul second membre pour le contact " << flush;
// on récupère la liste des éléments de contact
LaLIST <ElContact>& listElContact = lesCont->LesElementsDeContact();
LaLIST <ElContact>::iterator il,ilfin=listElContact.end();
// on gère les exceptions éventuelles en mettant le bloc sous surveillance
try
{// boucle sur les elements de contact
for (il=listElContact.begin();il != ilfin; il++)
{ if ((*il).Actif()) // on n'intervient que si le contact est actif
{ //calcul du residu local
ElContact& elcontact = (*il); // pour simplifier
Tableau<Noeud *>& taN = elcontact.TabNoeud_pour_assemblage(); // tableau de noeuds
//calcul du residu local
Vecteur* res = elcontact.SM_charge_contact();
// assemblage
Ass.AssemSM (vglobin,*res,elcontact.TableauDdlCont(),taN); // du second membre
// globalisation des énergies dues aux frottements
energFrottement += elcontact.EnergieFrottement();
energPenalisation += elcontact.EnergiePenalisation();
}; //-- fin du test sur l'activité
}; //-- fin de la boucle sur les éléments de contact
} //-- fin du try
catch (ErrSortie)
// cas d'une direction voulue vers la sortie
// on relance l'interuption pour le niveau supérieur
{ ErrSortie toto;
throw (toto);
}
catch (ErrSortieFinale)
// cas d'une direction voulue vers la sortie
// on relance l'interuption pour le niveau supérieur
{ ErrSortieFinale toto;
tempsSecondMembreEnergContact.Arret_du_comptage(); // temps cpu
throw (toto);
}
catch ( ... )
{ if (ParaGlob::NiveauImpression() >= 1)
{cout << "\n warning: exception generee par un element de contact mais dont la prise en compte "
<< " n'est pas prevu !, on ne fait rien et on continue le calcul";
if (ParaGlob::NiveauImpression() >= 4) cout << "\n Algori::SecondMembreEnergContact(..";
};
}
// affichage éventuelle du second membre
if (ParaGlob::NiveauImpression() >= 10)
{ string entete = " affichage du second membre uniquement du au contact ";
vglobin.Affichage_ecran(entete);
};
//cout << vglobin << endl;
// affichage éventuelle de la force maxi de contact
lesCont->Forces_contact_maxi(aff_iteration);
// idem pour les gap N et tangentiel
lesCont->Gap_contact_maxi(aff_iteration);
if (permet_affichage >3) cout << "\n -- fin calcul second mmembre pour le contact " << flush;
tempsSecondMembreEnergContact.Arret_du_comptage(); // temps cpu
// retour indiquant que tout c'est bien passé
return true ;
};
// choix de la matrice de raideur du système linéaire:
// 1) Si le pointeur est non null, on vérifie les tailles, si c'est différent
// la matrice est reconstruite
// 2) Si le pointeur est null, il y a création d'une matrice
// lesCondLim est utilisé pour modifier la largeur de bande par exemple
// en fonction des conditions limites linéaire
// lescontacts: si différent de NULL indique qu'il y a du contact
// NB: la dimension du tableau dépend du paramétrage lu dans ParaAlgoGlobal
Tableau <Mat_abstraite* > Algori::Choix_matriciel
(int nbddl,Tableau <Mat_abstraite* >& tab_matglob,LesMaillages * lesMail
,LesReferences* lesRef,const Nb_assemb& nb_casAssemb,LesCondLim* lesCondLim
, LesContacts* lescontacts )
{ // tout d'abord le choix de la matrice de stockage
Tableau<Enum_matrice> tab_enu_matrice_sec; // init
tab_enu_matrice_sec.Init_from_list(pa.Type_matrice_secondaire());
Tableau<Enum_type_resolution_matri> tab_enu_type_resolution_matri;
tab_enu_type_resolution_matri.Init_from_list(pa.Type_resolution_secondaire());
Tableau<Enum_preconditionnement> tab_enu_preconditionnement;
tab_enu_preconditionnement.Init_from_list(pa.Type_preconditionnement_secondaire());
Tableau<int> tab_nb_iter_nondirecte_secondaire;
tab_nb_iter_nondirecte_secondaire.Init_from_list(pa.Nb_iter_nondirecte_secondaire());
Tableau<double> tab_tolerance_secondaire;
tab_tolerance_secondaire.Init_from_list(pa.Tolerance_secondaire());
int nb_mat = 1+tab_enu_matrice_sec.Taille(); // nombre de matrices
// dans le cas où le tableau serait non nulle on regarde s'il a la bonne dimension
if (tab_matglob.Taille() > nb_mat)
// là il faut supprimer les matrices pointées en trop
{int taille = tab_matglob.Taille();
for (int i=nb_mat+1;i<=taille;i++)
if (tab_matglob(i)!= NULL)
delete tab_matglob(i);
// maintenant on peut changer la taille, en moins donc normalement
// on ne modifie pas les pointeurs déjà existants
tab_matglob.Change_taille(nb_mat);
}
else if (tab_matglob.Taille() < nb_mat)
// s'il est trop petit il faut augmenter la taille: on met les nouveaux pointeurs à NULL
tab_matglob.Change_taille(nb_mat,NULL);
// sinon il a la bonne taille et le traitement sera fait en fonction
// de l'existence ou non d'une matrice associée au pointeur
// on va boucler sur le nombre de matrice
for (int inum_mat = 1; inum_mat <= nb_mat; inum_mat++)
{ // init des valeurs par défaut de la première matrice
Enum_matrice enumatrice = pa.Type_Matrice(); // init
Enum_type_resolution_matri enumResolutionMatri = pa.Type_resolution();
Enum_preconditionnement enumPreconditionnement = pa.Type_preconditionnement();
// modif au cas où il y a des matrices secondaire
if (inum_mat > 1)
{enumatrice = tab_enu_matrice_sec(inum_mat-1);
if (tab_enu_type_resolution_matri.Taille() >= (inum_mat-1))
enumResolutionMatri = tab_enu_type_resolution_matri(inum_mat-1);
if (tab_enu_preconditionnement.Taille() >= (inum_mat-1))
enumPreconditionnement = tab_enu_preconditionnement(inum_mat-1);
};
int nbddl_MPI = nbddl; // init
bool cal_parallele_et_rang_non_nul = false;
#ifdef UTILISATION_MPI
// cas d'un calcul //, seule la matrice du CPU 0 est initialisée
// à la taille nécessaire pour une résolution globale
// pour les autres CPU on définit une matrice de taille unitaire
// qui ne sera pas utilisée mais qui sera valide
if (ParaGlob::Monde()->rank() != 0)
{nbddl_MPI = 1;
cal_parallele_et_rang_non_nul = true;
};
#endif
switch (enumatrice)
{ case CARREE : case RECTANGLE : // ici comme les tailles sont identiques rectangle
// et CARRE -> même traitement
{// cas s'une matrice carrée
if (tab_matglob(inum_mat) == NULL)
{tab_matglob(inum_mat) = new Mat_pleine (nbddl_MPI,nbddl_MPI);}
// sinon on regarde si la taille est bonne
else if ((tab_matglob(inum_mat)->Nb_ligne()!= nbddl_MPI) || (tab_matglob(inum_mat)->Nb_colonne()!= nbddl_MPI))
// dans ce cas on change de matrice
{ delete tab_matglob(inum_mat);
tab_matglob(inum_mat) = new Mat_pleine (nbddl_MPI,nbddl_MPI);
};
tab_matglob(inum_mat)->Change_Choix_resolution
(enumResolutionMatri,enumPreconditionnement);
// sinon il n'y a rien n'a faire au niveau des tailles
break;
}
case CARREE_LAPACK :
{// cas s'une matrice carrée a priori quelconque
if (tab_matglob(inum_mat) == NULL)
{tab_matglob(inum_mat) = new MatLapack (nbddl_MPI,nbddl_MPI,false,0.
,enumResolutionMatri,enumPreconditionnement);
}
// sinon on regarde si la taille est bonne
else if ((tab_matglob(inum_mat)->Nb_ligne()!= nbddl_MPI) || (tab_matglob(inum_mat)->Nb_colonne()!= nbddl_MPI))
// dans ce cas on change de matrice
{ delete tab_matglob(inum_mat);
tab_matglob(inum_mat) = new MatLapack (nbddl_MPI,nbddl_MPI,false,0.
,enumResolutionMatri,enumPreconditionnement);
};
// sinon il n'y a rien n'a faire au niveau des tailles
break;
}
case CARREE_SYMETRIQUE_LAPACK :
{// cas s'une matrice carrée symétrique
bool symetrique = true;
if (tab_matglob(inum_mat) == NULL)
{tab_matglob(inum_mat) = new MatLapack (nbddl_MPI,nbddl_MPI,symetrique,0.
,enumResolutionMatri,enumPreconditionnement);
}
// sinon on regarde si la taille est bonne
else if ((tab_matglob(inum_mat)->Nb_ligne()!= nbddl_MPI) || (tab_matglob(inum_mat)->Nb_colonne()!= nbddl_MPI))
// dans ce cas on change de matrice
{ delete tab_matglob(inum_mat);
tab_matglob(inum_mat) = new MatLapack (nbddl_MPI,nbddl_MPI,symetrique,0.
,enumResolutionMatri,enumPreconditionnement);
};
// sinon il n'y a rien n'a faire au niveau des tailles
break;
}
case RECTANGLE_LAPACK :
{// cas s'une matrice rectangulaire
if (tab_matglob(inum_mat) == NULL)
{tab_matglob(inum_mat) = new MatLapack (nbddl_MPI,nbddl_MPI,false,0.
,enumResolutionMatri,enumPreconditionnement);
}
// sinon on regarde si la taille est bonne
else if ((tab_matglob(inum_mat)->Nb_ligne()!= nbddl_MPI) || (tab_matglob(inum_mat)->Nb_colonne()!= nbddl_MPI))
// dans ce cas on change de matrice
{ delete tab_matglob(inum_mat);
tab_matglob(inum_mat) = new MatLapack (nbddl_MPI,nbddl_MPI,false,0.
,enumResolutionMatri,enumPreconditionnement);
};
// sinon il n'y a rien n'a faire au niveau des tailles
break;
}
case BANDE_SYMETRIQUE :
{ // calcul de la largeur de bande effective
int demi=0,total=0;
lesMail->Largeur_Bande(demi,total,nb_casAssemb);
total = std::min(total,nbddl_MPI);
demi = std::min(demi,nbddl_MPI);
// --- on stocke les largeurs initiales de ddl
{ // on redimensionne si nécessaire
int nombre_cas_assemb = tab_para_stockage.Taille();
if (nb_casAssemb.n > nombre_cas_assemb)
tab_para_stockage.Change_taille(nb_casAssemb.n);
// maintenant on stocke
ParaStockage & parstock = (tab_para_stockage(nb_casAssemb.n));
parstock.nbass = nb_casAssemb;
parstock.demi = demi;
parstock.total = total;
};
// dans le cas non // ou // pour le CPU 0, on précise la dim
// ici on garde nbddl au lien de nbddl_MPI: ils sont identiques
if (!cal_parallele_et_rang_non_nul)
{ if (ParaGlob::NiveauImpression() >= 5)
cout << "\n raideur: largeur de bande initiale pour les elements (en ddl) " << total << " ";
if (lescontacts!= NULL)
{// calcul de la largeur de bande effective en tenant compte du contact
int demic=0,totalc=0,cumule=0;
// on n'intervient que si la largeur en noeud augmente
if (lescontacts->Largeur_Bande(demic,totalc,nb_casAssemb,cumule))
{totalc = std::min(totalc,nbddl);
demic = std::min(demic,nbddl);
cumule = std::min(cumule,nbddl);
if (ParaGlob::NiveauImpression() >= 5)
cout << "\n augmentation de la largeur de bande pour les conditions de contact (en ddl) " << cumule << " ";
demi += cumule; // c'est donc toute la largeur hors diag que l'on ajoute
total += 2 * cumule;
// on limite au nombres total de ddl
total = std::min(total,nbddl);
demi = std::min(demi,nbddl);
}
};
// cas de l'influence des conditions linéaires d'entrée
int demic=0,totalc=0,cumule=0;
// on n'intervient que si la largeur en noeud augmente
if (lesCondLim->Largeur_Bande(demic,totalc,nb_casAssemb,lesMail,lesRef,cumule))
{totalc = std::min(totalc,nbddl);
demic = std::min(demic,nbddl);
cumule = std::min(cumule,nbddl);
if (ParaGlob::NiveauImpression() >= 5)
cout << "\n augmentation de la largeur de bande pour les conditions lineaires (en ddl) " << cumule << " ";
// ---- les deux lignes qui suivent sont fausses, car dans le cas du produit de deux matrices bandes la largeur de bande du produit
// = non pas le max, mais la "somme" des deux largeurs de bandes (parties hors diagonales),
// d'une manière plus précise cf. J Chevalier 1993, soit une matrice bande avec deux bandes de part et autre de la diagonale, différentes
// A_ij (a,b) telle que A_ij = 0 si j<i-a ou j>i+b, donc a est la bande inf (hors diag) et b est la bande sup (hors diag)
// soient A(a,b) et B(c,d) alors A*B est de type (a+B,b+d)
// or pour mettre en place les CL (actuellement)
// on utilise une matrice de rotation et on fait S^T * K * S , tel S est de type (a,b) et donc S^T est de type (b,a) donc
// si on suppose que K est de type (l,l) et bien S^T * K * S sera de type (l+a+b,l+a+b) donc c'est a+b qui compte (hors diag)
// demi = MaX(demi,demic);
// total = MaX(total,totalc);
demi += cumule; // c'est donc toute la largeur hors diag que l'on ajoute
total += 2 * cumule;
// on limite au nombres total de ddl
total = std::min(total,nbddl);
demi = std::min(demi,nbddl);
};
if (ParaGlob::NiveauImpression() >= 5)
cout << "\n largeur de bande finale (en ddl) " << total << " "
<< "\n stockage symetrique d'ou utilisation de la demi largeur= " << demi << " ";
};
// création éventuelle et initialisation a zero
if (tab_matglob(inum_mat) == NULL)
{tab_matglob(inum_mat) = new MatBand (BANDE_SYMETRIQUE,demi,nbddl_MPI,0);
}
// sinon on regarde si la taille est bonne
else if ((tab_matglob(inum_mat)->Nb_ligne()!= nbddl_MPI) || (tab_matglob(inum_mat)->Nb_colonne()!= nbddl_MPI))
// dans ce cas on change de matrice
{ delete tab_matglob(inum_mat);
tab_matglob(inum_mat) = new MatBand (BANDE_SYMETRIQUE,demi,nbddl_MPI,0);
}
else // sinon on se contente d'initialiser à 0.
tab_matglob(inum_mat)->Initialise(0.);
// on spécifie le type de résolution
tab_matglob(inum_mat)->Change_Choix_resolution
(enumResolutionMatri,enumPreconditionnement);
// on vérifie que l'assemblage choisit est bien de type symétrique
if (pa.Symetrie_matrice() != true)
{ cout << "Erreur de type d'assemblage, le type de matrice choisit est symetrique"
<< " alors que l'assemblage n'est pas symetrique !! \n";
cout << " Algori::Choix_matriciel(..)";
// dans le cas où un comptage du calcul est en cours on l'arrête
if (tempsCalEquilibre.Comptage_en_cours()) tempsCalEquilibre.Arret_du_comptage();
if (tempsInitialisation.Comptage_en_cours()) tempsInitialisation.Arret_du_comptage();
if (tempsMiseAjourAlgo.Comptage_en_cours()) tempsMiseAjourAlgo.Arret_du_comptage();
Sortie(1);
};
}
break;
case BANDE_NON_SYMETRIQUE_LAPACK : case BANDE_SYMETRIQUE_LAPACK: // le choix est fait au moment de l'allocation
{ // calcul de la largeur de bande effective
int demi=0,total=0;
lesMail->Largeur_Bande(demi,total,nb_casAssemb);
total = std::min(total,2*nbddl_MPI-1);
demi = std::min(demi,nbddl_MPI);
// --- on stocke les largeurs initiales de ddl
{ // on redimensionne si nécessaire
int nombre_cas_assemb = tab_para_stockage.Taille();
if (nb_casAssemb.n > nombre_cas_assemb)
tab_para_stockage.Change_taille(nb_casAssemb.n);
// maintenant on stocke
ParaStockage & parstock = (tab_para_stockage(nb_casAssemb.n));
parstock.nbass = nb_casAssemb;
parstock.demi = demi;
parstock.total = total;
};
// dans le cas non // ou // pour le CPU 0, on précise la dim
// ici on garde nbddl au lien de nbddl_MPI: ils sont identiques
if (!cal_parallele_et_rang_non_nul)
{if (ParaGlob::NiveauImpression() >= 5)
cout << "\n raideur: largeur de bande initiale pour les elements (en ddl) " << total << " ";
if (lescontacts!= NULL)
{// calcul de la largeur de bande effective en tenant compte du contact
int demic=0,totalc=0,cumule=0;
// on n'intervient que si la largeur en noeud augmente
if (lescontacts->Largeur_Bande(demic,totalc,nb_casAssemb,cumule))
{totalc = std::min(totalc,2*nbddl-1);
demic = std::min(demic,nbddl);
cumule = std::min(cumule,nbddl);
if (ParaGlob::NiveauImpression() >= 5)
cout << "\n augmentation de la largeur de bande pour les conditions de contact (en ddl) " << cumule << " ";
demi += cumule; // c'est donc toute la largeur hors diag que l'on ajoute
total += 2 * cumule;
// on limite au nombres total de ddl
total = std::min(total,2*nbddl-1);
demi = std::min(demi,nbddl);
};
};
// cas de l'influence des conditions linéaires d'entrée
int demic=0,totalc=0,cumule=0;
// on n'intervient que si la largeur en noeud augmente
if (lesCondLim->Largeur_Bande(demic,totalc,nb_casAssemb,lesMail,lesRef,cumule))
{totalc = std::min(totalc,2*nbddl-1);
demic = std::min(demic,nbddl);
cumule = std::min(cumule,nbddl);
if (ParaGlob::NiveauImpression() >= 5)
cout << "\n augmentation de largeur de bande pour les conditions lineaires (en ddl) " << totalc << " ";
// ---- les deux lignes qui suivent sont faussent, car dans le cas du produit de deux matrices bandes la largeur de bande du produit
// = non pas le max, mais la "somme" des deux largeurs de bandes (parties hors diagonales),
// d'une manière plus précise cf. J Chevalier 1993, soit une matrice bande avec deux bandes de part et autre de la diagonale, différentes
// A_ij (a,b) telle que A_ij = 0 si j<i-a ou j>i+b, donc a est la bande inf (hors diag) et b est la bande sup (hors diag)
// soient A(a,b) et B(c,d) alors A*B est de type (a+c,b+d)
// or pour mettre en place les CL (actuellement)
// on utilise une matrice de rotation et on fait S^T * K * S , tel S est de type (a,b) et donc S^T est de type (b,a) donc
// si on suppose que K est de type (l,l) et bien S^T * K * S sera de type (l+a+b,l+a+b) donc c'est a+b qui compte (hors diag)
// demi = MaX(demi,demic);
// total = MaX(total,totalc);
demi += cumule; // c'est donc toute la largeur hors diag que l'on ajoute
total += 2 * cumule;
// on limite au nombres total de ddl
total = std::min(total,2*nbddl-1);
demi = std::min(demi,nbddl);
};
if (ParaGlob::NiveauImpression() >= 5)
cout << "\n largeur de bande finale (en ddl) " << total << " ";
};
// création éventuelle et initialisation a zero
if (tab_matglob(inum_mat) == NULL)
{ if (enumatrice == BANDE_SYMETRIQUE_LAPACK)
{ tab_matglob(inum_mat) = new MatLapack (enumatrice,demi,nbddl_MPI,true,0.0
,enumResolutionMatri,enumPreconditionnement);}
else
{ tab_matglob(inum_mat) = new MatLapack (enumatrice,total,nbddl_MPI,false,0.0
,enumResolutionMatri,enumPreconditionnement);};
}
// sinon on regarde si la taille est bonne
else if ((tab_matglob(inum_mat)->Nb_ligne()!= nbddl_MPI) || (tab_matglob(inum_mat)->Nb_colonne()!= nbddl_MPI))
// dans ce cas on change de matrice
{ delete tab_matglob(inum_mat);
if (enumatrice == BANDE_SYMETRIQUE_LAPACK)
{ tab_matglob(inum_mat) = new MatLapack (enumatrice,demi,nbddl_MPI,true,0.0
,enumResolutionMatri,enumPreconditionnement);}
else
{ tab_matglob(inum_mat) = new MatLapack (enumatrice,total,nbddl_MPI,false,0.0
,enumResolutionMatri,enumPreconditionnement);};
}
else // sinon on se contente d'initialiser à 0.
tab_matglob(inum_mat)->Initialise(0.);
if (enumatrice == BANDE_SYMETRIQUE_LAPACK) // si on a choisit un stockage symétrique
// on vérifie que l'assemblage choisit est bien de type symétrique
if (pa.Symetrie_matrice() != true)
{ cout << "Erreur de type d'assemblage, le type de matrice choisit est symetrique"
<< " alors que l'assemblage n'est pas symetrique !! \n";
cout << " Algori::Choix_matriciel(..)";
// dans le cas où un comptage du calcul est en cours on l'arrête
if (tempsCalEquilibre.Comptage_en_cours()) tempsCalEquilibre.Arret_du_comptage();
if (tempsInitialisation.Comptage_en_cours()) tempsInitialisation.Arret_du_comptage();
if (tempsMiseAjourAlgo.Comptage_en_cours()) tempsMiseAjourAlgo.Arret_du_comptage();
Sortie(1);
};
}
break;
case CREUSE_COMPRESSEE_COLONNE :
{ // cas d'une matrice creuse compressée par colonne
// tout d'abord on demande l'ensemble des tables de connexion
// pour les éléments
Tableau < Tableau <int> > petites_matrices;
lesMail->Table_connexion(petites_matrices,nb_casAssemb);
// pour l'instant le cas avec contact n'est pas traité
if (lescontacts!= NULL)
{ cout << "\n *** cas avec contact non actuellement traite "
<< "\n Algori::Choix_matriciel(... ) \n";
// dans le cas où un comptage du calcul est en cours on l'arrête
if (tempsCalEquilibre.Comptage_en_cours()) tempsCalEquilibre.Arret_du_comptage();
if (tempsInitialisation.Comptage_en_cours()) tempsInitialisation.Arret_du_comptage();
if (tempsMiseAjourAlgo.Comptage_en_cours()) tempsMiseAjourAlgo.Arret_du_comptage();
Sortie(1);
};
// !!! pour l'instant on ne prend pas en compte les conditions linéaires initiales
// on vérifie
if (lesCondLim->ExisteCondiLimite())
{ cout << "\n*** Erreur de choix de matrice de masse, il y a des conditions lineaires intiales, ce qui conduit "
<< " a intervenir sur le stockage. Or le cas CREUSE_COMPRESSEE_COLONNE ne prend pas en compte pour l'instant "
<< " la presence de conditions limites !! \n";
if (ParaGlob::NiveauImpression() >= 5)
cout << "\n Algori::Choix_matriciel(... ) \n";
// dans le cas où un comptage du calcul est en cours on l'arrête
if (tempsCalEquilibre.Comptage_en_cours()) tempsCalEquilibre.Arret_du_comptage();
if (tempsInitialisation.Comptage_en_cours()) tempsInitialisation.Arret_du_comptage();
if (tempsMiseAjourAlgo.Comptage_en_cours()) tempsMiseAjourAlgo.Arret_du_comptage();
Sortie(1);
};
// puis on définit la matrice en conséquence
if (tab_matglob(inum_mat) == NULL)
{tab_matglob(inum_mat) = new Mat_creuse_CompCol(nbddl_MPI,nbddl_MPI, petites_matrices);
}
// sinon on regarde si la taille est bonne
else if ((tab_matglob(inum_mat)->Nb_ligne()!= nbddl_MPI) || (tab_matglob(inum_mat)->Nb_colonne()!= nbddl_MPI))
// dans ce cas on change de matrice
{ delete tab_matglob(inum_mat);
tab_matglob(inum_mat) = new Mat_creuse_CompCol(nbddl_MPI,nbddl_MPI, petites_matrices);
};
// on spécifie le type de résolution
tab_matglob(inum_mat)->Change_Choix_resolution
(enumResolutionMatri,enumPreconditionnement);
// sinon il n'y a rien n'a faire au niveau des tailles
}
break;
default :
cout << "\nErreur : valeur incorrecte ou non implanté du type de matrice retenue, type !\n"
<< " = " << enumatrice ;
cout << "\n Algori::Choix_matriciel(... ) \n";
// dans le cas où un comptage du calcul est en cours on l'arrête
if (tempsCalEquilibre.Comptage_en_cours()) tempsCalEquilibre.Arret_du_comptage();
if (tempsInitialisation.Comptage_en_cours()) tempsInitialisation.Arret_du_comptage();
if (tempsMiseAjourAlgo.Comptage_en_cours()) tempsMiseAjourAlgo.Arret_du_comptage();
Sortie(1);
};
if (ParaGlob::NiveauImpression() >= 5)
cout << "\n stockage raideur" << enumatrice << " taille (entiers) :" << tab_matglob(inum_mat)->Place() << endl;
};
return tab_matglob;
};
// Mise à jour éventuelle de la taille de la matrice de raideur ou masse du système linéaire
// en fonction du contact ou en fonction de "nouvelle_largeur_imposee" dans ce cas, lescontacts
// n'est pas utilisé ! donc la méthode peut servir dans ce cas sans le contact
//
// la matrice *matglob: doit déjà existée
// en retour le pointeur désigne toujours la même matrice qu'en entrée
// avec les même caractéristique de fonctionnement que l'ancienne (mêm résolution, stockage ...)
// NB: la dimension du tableau dépend du paramétrage lu dans ParaAlgoGlobal
// 1) si niveau_substitution =0 : -> mise à jour de toutes les matrices
// 2) si niveau_substitution = i : -> uniquement mise à jour de la matrices i
// par contre la dimension de tab_matglob est toujours mis à jour si c'est nécessaire
// si nouvelle_largeur_imposee : n'est pas nulle, cela veut-dire qu'il y a eu une nouvelle numérotation
// et une nouvelle mise en place des pointeurs d'assemblage
// alors c'est directement cette valeur de ddl (et non de noeud) qui est imposée sur la matrice
// nouvelle_largeur_imposee.un = la largeur totale
// nouvelle_largeur_imposee.deux = la demie largeur
// nouvelles_largeur_en_ddl.trois = la demie largeur maximale pour la partie éléments finis
// uniquement (sans les CLL)
void Algori::Mise_a_jour_Choix_matriciel_contact
(Tableau <Mat_abstraite* >& tab_matglob,const Nb_assemb& nb_casAssemb
, LesContacts* lescontacts
,int niveau_substitution ,TroisEntiers* nouvelle_largeur_imposee)
{
#ifdef UTILISATION_MPI
// cas d'un calcul //, seule la (ou les) matrices du CPU 0 sont concernées
if (ParaGlob::Monde()->rank() != 0)
return ;
#endif
// tout d'abord le choix de la matrice de stockage
Tableau<Enum_matrice> tab_enu_matrice_sec; // init
tab_enu_matrice_sec.Init_from_list(pa.Type_matrice_secondaire());
Tableau<Enum_type_resolution_matri> tab_enu_type_resolution_matri;
tab_enu_type_resolution_matri.Init_from_list(pa.Type_resolution_secondaire());
Tableau<Enum_preconditionnement> tab_enu_preconditionnement;
tab_enu_preconditionnement.Init_from_list(pa.Type_preconditionnement_secondaire());
Tableau<int> tab_nb_iter_nondirecte_secondaire;
tab_nb_iter_nondirecte_secondaire.Init_from_list(pa.Nb_iter_nondirecte_secondaire());
Tableau<double> tab_tolerance_secondaire;
tab_tolerance_secondaire.Init_from_list(pa.Tolerance_secondaire());
int nb_mat = 1+tab_enu_matrice_sec.Taille(); // nombre de matrices
// dans le cas où le tableau serait non nulle on regarde s'il a la bonne dimension
if (tab_matglob.Taille() > nb_mat)
// là il faut supprimer les matrices pointées en trop
{int taille = tab_matglob.Taille();
for (int i=nb_mat+1;i<=taille;i++)
if (tab_matglob(i)!= NULL)
delete tab_matglob(i);
// maintenant on peut changer la taille, en moins donc normalement
// on ne modifie pas les pointeurs déjà existants
tab_matglob.Change_taille(nb_mat);
}
else if (tab_matglob.Taille() < nb_mat)
// s'il est trop petit il faut augmenter la taille: on met les nouveaux pointeurs à NULL
tab_matglob.Change_taille(nb_mat,NULL);
// sinon il a la bonne taille on suppose que les matrices pointées sont de bonnes dimensions
int i_deb = 1; int i_fin = nb_mat+1; // initi par défaut des bornes
if (niveau_substitution != 0)
{ i_deb = niveau_substitution; i_fin = i_deb+1;};
// on va boucler sur le nombre de matrice
for (int inum_mat = i_deb; inum_mat < i_fin; inum_mat++)
{ // init des valeurs par défaut de la première matrice
Mat_abstraite* matglob = tab_matglob(inum_mat);
Enum_matrice enumatrice = pa.Type_Matrice(); // init
Enum_type_resolution_matri enumResolutionMatri = pa.Type_resolution();
Enum_preconditionnement enumPreconditionnement = pa.Type_preconditionnement();
// modif au cas où il y a des matrices secondaire
if (inum_mat > 1)
{enumatrice = tab_enu_matrice_sec(inum_mat-1);
if (tab_enu_type_resolution_matri.Taille() > (inum_mat-1))
enumResolutionMatri = tab_enu_type_resolution_matri(inum_mat-1);
if (tab_enu_preconditionnement.Taille() > (inum_mat-1))
enumPreconditionnement = tab_enu_preconditionnement(inum_mat-1);
};
switch (enumatrice)
{ case CARREE : break; // pas de modification
case RECTANGLE : break; // pas de modification
case CARREE_LAPACK : break; // pas de modification
case CARREE_SYMETRIQUE_LAPACK : break; // pas de modification
case RECTANGLE_LAPACK : break; // pas de modification
case BANDE_SYMETRIQUE : case BANDE_SYMETRIQUE_LAPACK:
{ // -- récup des anciennes tailles
int nbddl = matglob->Nb_ligne();
ParaStockage & parstock = (tab_para_stockage(nb_casAssemb.n));
int ancien_demi = matglob->Nb_colonne();
// calcul de la largeur de bande effective en tenant compte du contact
int demic=0,totalc=0,cumule=0;
int demi = parstock.demi; // init
if (nouvelle_largeur_imposee == NULL) // cas où il faut calculer
{// on n'intervient que si la largeur en noeud augmente
if (lescontacts->Largeur_Bande(demic,totalc,nb_casAssemb,cumule))
{// la mise à jour dépend du type de contact
if (pa.ContactType() == 1) // contact cinématique, sans multiplicateur ni pénalisation
// on doit augmenter la lb en fonction de cumule, si la largeur en noeud est différente
// de 1
{cumule = std::min(cumule,nbddl);
demi = parstock.demi + cumule; // c'est donc toute la largeur hors diag que l'on ajoute
if (demi > ancien_demi)
if (ParaGlob::NiveauImpression() >= 5)
cout << "\n propositon d'augmentation de la largeur de bande pour les conditions de contact (en ddl) " << cumule << "old_1/2lb: "<<ancien_demi << " new_1/2lb: "<< demi <<" ";
}
else if ((pa.ContactType() == 2)|| (pa.ContactType() == 3)
||(pa.ContactType() == 4) )// cas d'un contact par pénalisation ou type 3 *** exploratoire
// dans ce cas on considère uniquement le LB maxi
{ demic = std::min(demic,nbddl);
int demi_inter = std::max(parstock.demi, demic);
if (demi_inter > ancien_demi)
if ((ParaGlob::NiveauImpression() >= 5) && (demic > demi))
cout << "\n propositon d'augmentation de la largeur de bande pour les conditions de contact (en ddl) " << (demic-demi) << "old_1/2lb: "<<ancien_demi << " new_1/2lb: "<< demi_inter <<" ";
demi = demi_inter;
};
};
}
else // sinon on applique la demande
{ demi = nouvelle_largeur_imposee->deux;
// et on met à jour : uniquement la partie relative aux maillages
ParaStockage & parstock = (tab_para_stockage(nb_casAssemb.n));
parstock.nbass = nb_casAssemb;
parstock.demi = nouvelle_largeur_imposee->trois;
parstock.total = 2 * nouvelle_largeur_imposee->trois -1;
};
// on limite au nombres total de ddl
demi = std::min(demi,nbddl);
// on change la taille, si elle doit augmenter, ou si elle est inférieur d'au moins 5% par rapport à la taille actuelle
if ( (demi > matglob->Nb_colonne()) ||
(demi < 0.95 * matglob->Nb_colonne()))
// on change la taille
{ if (ParaGlob::NiveauImpression() >= 5)
cout << "\n augmentation effective: LB/2+1 finale(en ddl) " << demi << " ";
switch (enumatrice)
{ case BANDE_SYMETRIQUE:
((MatBand*)matglob)->Change_taille(demi,nbddl );
break;
case BANDE_SYMETRIQUE_LAPACK:
((MatLapack*)matglob)->Change_taille(nbddl,demi);
break;
default:
cout << "\n erreur non prevue Algori::Mise_a_jour_Choix_matriciel_contact "<<endl;
// dans le cas où un comptage du calcul est en cours on l'arrête
if (tempsCalEquilibre.Comptage_en_cours()) tempsCalEquilibre.Arret_du_comptage();
if (tempsInitialisation.Comptage_en_cours()) tempsInitialisation.Arret_du_comptage();
if (tempsMiseAjourAlgo.Comptage_en_cours()) tempsMiseAjourAlgo.Arret_du_comptage();
Sortie(1);
};
};
break;
}
case BANDE_NON_SYMETRIQUE : case BANDE_NON_SYMETRIQUE_LAPACK :
{ // -- récup des anciennes tailles
int nbddl = matglob->Nb_ligne();
int ancien_lb = matglob->Nb_colonne();
ParaStockage & parstock = (tab_para_stockage(nb_casAssemb.n));
//int demi = matglob->Nb_colonne();
// calcul de la largeur de bande effective en tenant compte du contact
int demic=0,totalc=0,cumule=0;
int total = parstock.total; // init
if (nouvelle_largeur_imposee == NULL) // cas où il faut calculer
{// on n'intervient que si la largeur en noeud augmente
if (lescontacts->Largeur_Bande(demic,totalc,nb_casAssemb,cumule))
{// la mise à jour dépend du type de contact
if (pa.ContactType() == 1) // contact cinématique, sans multiplicateur ni pénalisation
// on doit augmenter la lb en fonction de cumule
{ cumule = std::min(cumule,nbddl);
int total_inter = parstock.total + 2 * cumule;
if (total_inter > ancien_lb)
if (ParaGlob::NiveauImpression() >= 5)
cout << "\n propositon d'augmentation de la largeur de bande pour les conditions de contact (en ddl) " << cumule << "old_lb: "<<ancien_lb << " new_lb: "<< total_inter <<" ";
total = total_inter;
}
else if ((pa.ContactType() == 2)|| (pa.ContactType() == 3)
|| (pa.ContactType() == 4))// cas d'un contact par pénalisation ou type 3 *** exploratoire
// dans ce cas on considère uniquement le LB maxi
{ totalc = std::min(totalc,2*nbddl-1);
int total_inter = std::max(parstock.total, totalc);
if (total_inter > ancien_lb)
if ((ParaGlob::NiveauImpression() >= 5) && (totalc > total))
cout << "\n propositon d'augmentation de la largeur de bande pour les conditions de contact (en ddl) " << (totalc-total) << "old_lb: "<<ancien_lb << " new_lb: "<< total_inter << " ";
total = total_inter;
};
};
}
else // sinon on applique la demande
{ total = nouvelle_largeur_imposee->un;
// et on met à jour : uniquement la partie relative aux maillages
ParaStockage & parstock = (tab_para_stockage(nb_casAssemb.n));
parstock.nbass = nb_casAssemb;
parstock.demi = nouvelle_largeur_imposee->trois;
parstock.total = 2 * nouvelle_largeur_imposee->trois -1;
};
// on limite au nombres total de ddl
total = std::min(total,2*nbddl-1);
// on change la taille, si elle doit augmenter, ou si elle est inférieur d'au moins 5% par rapport à la taille actuelle
if ( (total > matglob->Nb_colonne()) ||
(total < 0.95 * matglob->Nb_colonne()))
// on change la taille
{ if (ParaGlob::NiveauImpression() >= 5)
cout << "\n augmentation effective: LB finale(en ddl) " << total << " ";
switch (enumatrice)
{ case BANDE_NON_SYMETRIQUE:
((MatBand*)matglob)->Change_taille(total,nbddl );
break;
case BANDE_NON_SYMETRIQUE_LAPACK:
((MatLapack*)matglob)->Change_taille(nbddl,total);
break;
default:
cout << "\n erreur2 non prevue Algori::Mise_a_jour_Choix_matriciel_contact "<<endl;
// dans le cas où un comptage du calcul est en cours on l'arrête
if (tempsCalEquilibre.Comptage_en_cours()) tempsCalEquilibre.Arret_du_comptage();
if (tempsInitialisation.Comptage_en_cours()) tempsInitialisation.Arret_du_comptage();
if (tempsMiseAjourAlgo.Comptage_en_cours()) tempsMiseAjourAlgo.Arret_du_comptage();
Sortie(1);
};
};
break;
}
case CREUSE_COMPRESSEE_COLONNE :
{ cout << "\n *** cas avec contact non actuellement traite "
<< "\n Algori::Mise_a_jour_Choix_matriciel_contact(... ) \n";
// dans le cas où un comptage du calcul est en cours on l'arrête
if (tempsCalEquilibre.Comptage_en_cours()) tempsCalEquilibre.Arret_du_comptage();
if (tempsInitialisation.Comptage_en_cours()) tempsInitialisation.Arret_du_comptage();
if (tempsMiseAjourAlgo.Comptage_en_cours()) tempsMiseAjourAlgo.Arret_du_comptage();
Sortie(1);
break;
}
default :
cout << "\nErreur : valeur incorrecte ou non implante du type de matrice retenue, type !\n"
<< " = " << enumatrice ;
cout << "\n Algori::Mise_a_jour_Choix_matriciel_contact(... ) \n";
// dans le cas où un comptage du calcul est en cours on l'arrête
if (tempsCalEquilibre.Comptage_en_cours()) tempsCalEquilibre.Arret_du_comptage();
if (tempsInitialisation.Comptage_en_cours()) tempsInitialisation.Arret_du_comptage();
if (tempsMiseAjourAlgo.Comptage_en_cours()) tempsMiseAjourAlgo.Arret_du_comptage();
Sortie(1);
};
if (ParaGlob::NiveauImpression() >= 5)
cout << "\n stockage raideur " << enumatrice << " taille (entiers) :"
<< matglob->Place() << endl;
};
};
// choix de la matrice de la matrice de masse globale
// ou mise à jour de la matrice masse si elle existe
Mat_abstraite* Algori::Choix_matrice_masse
(int nbddl,Mat_abstraite* mat_mass,LesMaillages * lesMail,LesReferences* lesRef
,const Nb_assemb& nb_casAssemb,LesContacts* ,LesCondLim* lesCondLim)
{
int nbddl_MPI = nbddl; // init
bool cal_parallele_et_rang_non_nul = false;
#ifdef UTILISATION_MPI
// cas d'un calcul //, seule la matrice du CPU 0 est initialisée
// à la taille nécessaire pour une résolution globale
// pour les autres CPU on définit une matrice de taille unitaire
// qui ne sera pas utilisée mais qui sera valide
if (ParaGlob::Monde()->rank() != 0)
{nbddl_MPI = 1;
cal_parallele_et_rang_non_nul = true;
};
#endif
// tout d'abord le choix de la matrice de stockage
// s'il n'y a pas de condition linéaires classiques, la largeur de bande ne doit pas changer
if ( ((pa.Type_calcul_masse() == MASSE_DIAG_COEF_EGAUX) || (pa.Type_calcul_masse() == MASSE_DIAG_COEF_VAR))
&& (!(lesCondLim->ExisteCondiLimite()))
// && (pa.ContactType() != 1) // non ce sera géré dans la mise à jour, pour éviter
// // un stockage en bande systématique
)
{ // on utilise une matrice diagonale
if (mat_mass == NULL)
{ mat_mass = new MatDiag (nbddl_MPI);
if ((ParaGlob::NiveauImpression() > 2)&&(!cal_parallele_et_rang_non_nul))
cout << "\n stockage initial matrice masse --> diagonal, nbddl= " << nbddl_MPI ;
}
else // sinon on redimentionne ou on change si nécessaire
{ if (mat_mass->Type_matrice() != DIAGONALE)
{ delete mat_mass; mat_mass = new MatDiag (nbddl_MPI);} // cas où on change de matrice
else { MatDiag * mat_mass_diag = (MatDiag*) mat_mass; // cas où on redimentionne la matrice
mat_mass_diag->Change_taille(nbddl_MPI);
};
if ((ParaGlob::NiveauImpression() > 2)&&(!cal_parallele_et_rang_non_nul))
cout << "\n changement stockage matrice masse --> diagonal, nbddl= " << nbddl_MPI ;
};
// --- on stocke les largeurs initiales de ddl
// on redimensionne si nécessaire
int nombre_cas_assemb = tab_para_stockage.Taille();
if (nb_casAssemb.n > nombre_cas_assemb)
tab_para_stockage.Change_taille(nb_casAssemb.n);
// maintenant on stocke
ParaStockage & parstock = (tab_para_stockage(nb_casAssemb.n));
parstock.nbass = nb_casAssemb;
parstock.demi = parstock.total = 1; // tout est diagonal
}
else if ( ((pa.Type_calcul_masse() == MASSE_DIAG_COEF_EGAUX) ||
(pa.Type_calcul_masse() == MASSE_DIAG_COEF_VAR))
&&
((lesCondLim->ExisteCondiLimite())
|| (pa.ContactType() == 1) // on part avec l'idée d'une largeur de 1 en noeud
// ce qui est le cas d'un contact solide - déformable
// sera ensuite éventuellement augmenté
// || contact_type_1_et_maitre_deformable
)
// && (pa.Type_Matrice() == DIAGONALE)
)
{ // dans le cas ou on devrait utiliser une matrice diagonale, on va arbitrairement utiliser une matrice bande
// mais avec une largeur uniquement déterminé par les conditions linéaires
// en particulier, si les CLL => un stockage diagonale en noeuds, on utilise une matrice de bande = dim espace
// calcul de la largeur de bande effective due à l'influence des conditions linéaires d'entrée
// --- on stocke les largeurs initiales de ddl
// on redimensionne si nécessaire
int nombre_cas_assemb = tab_para_stockage.Taille();
if (nb_casAssemb.n > nombre_cas_assemb)
tab_para_stockage.Change_taille(nb_casAssemb.n);
// maintenant on stocke
ParaStockage & parstock = (tab_para_stockage(nb_casAssemb.n));
parstock.nbass = nb_casAssemb;
parstock.demi = parstock.total = 1; // tout est diagonal
int demic=0,totalc=0,cumule=0;
int demi=0,total=0;
// on n'intervient que si la largeur en noeud augmente
// et que l'on est sur le CPU 0
if ( (lesCondLim->Largeur_Bande(demic,totalc,nb_casAssemb,lesMail,lesRef,cumule))
&& (!cal_parallele_et_rang_non_nul)
)
{ demi = 1 + cumule; // c'est donc toute la largeur hors diag que l'on ajoute
total = 1 + 2 * cumule;
}
else // sinon on est dans le cas où on peut utiliser une matrice bande = dim espace (ex: si dim 3: tridiagonale)
{ int dim_espace = ParaGlob::Dimension();
demi = dim_espace;
total = 1 + 2 * (dim_espace-1);
};
// on limite au nombres total de ddl
total = std::min(total,nbddl_MPI);
demi = std::min(demi,nbddl_MPI);
// si la matrice actuelle est de type diagonale il faut la supprimer et définir une
// matrice bande
bool change_stockage = false;
if (mat_mass != NULL)
if (mat_mass->Type_matrice() == DIAGONALE)
{ delete mat_mass; mat_mass = NULL;change_stockage = true;}; // cas où on change de stockage
// maintenant on crée une matrice en fonction de la demande
switch (pa.Type_Matrice())
{ case CARREE :
{// cas d'une matrice carrée, là a priori on n'a pas besoin d'augmenter la largeur, on est au maxi
if (mat_mass == NULL)
{ mat_mass = new Mat_pleine (nbddl_MPI,nbddl_MPI);}
else // sinon on redimentionne ou on change si nécessaire
{ Mat_pleine * mat_mass_d = (Mat_pleine*) mat_mass; // cas où on redimentionne la matrice
mat_mass_d->Initialise (nbddl_MPI,nbddl_MPI,0.);
};
break;
}
case RECTANGLE :
{// cas s'une matrice rectangulaire, pour l'instant idem que le cas précédent
// car pour l'instant on ne voit pas très bien à quoi cela servirait d'être différent
if (mat_mass == NULL)
{ mat_mass = new Mat_pleine (nbddl_MPI,nbddl_MPI);}
else // sinon on redimentionne ou on change si nécessaire
{ Mat_pleine * mat_mass_d = (Mat_pleine*) mat_mass; // cas où on redimentionne la matrice
mat_mass_d->Initialise (nbddl_MPI,nbddl_MPI,0.);
};
break;
}
case CARREE_LAPACK :
{// cas s'une matrice carrée
if (mat_mass == NULL)
{ mat_mass = new MatLapack (nbddl_MPI,nbddl_MPI,false,0.,pa.Type_resolution(),pa.Type_preconditionnement());}
else // sinon on redimentionne ou on change si nécessaire
{ MatLapack * mat_mass_d = (MatLapack*) mat_mass; // cas où on redimentionne la matrice
mat_mass_d->Change_taille(nbddl_MPI,nbddl_MPI,0.);
};
break;
}
case CARREE_SYMETRIQUE_LAPACK :
{// cas s'une matrice carrée symétrique
if (mat_mass == NULL)
{ mat_mass = new MatLapack (nbddl_MPI,nbddl_MPI,true,0.,pa.Type_resolution(),pa.Type_preconditionnement());}
else // sinon on redimentionne ou on change si nécessaire
{ MatLapack * mat_mass_d = (MatLapack*) mat_mass; // cas où on redimentionne la matrice
mat_mass_d->Change_taille(nbddl_MPI,nbddl_MPI,0.);
};
break;
}
case RECTANGLE_LAPACK :
{// cas s'une matrice rectangulaire, pour l'instant idem que le cas précédent
if (mat_mass == NULL)
{ mat_mass = new MatLapack (nbddl_MPI,nbddl_MPI,false,0.,pa.Type_resolution(),pa.Type_preconditionnement());}
else // sinon on redimentionne ou on change si nécessaire
{ MatLapack * mat_mass_d = (MatLapack*) mat_mass; // cas où on redimentionne la matrice
mat_mass_d->Change_taille(nbddl_MPI,nbddl_MPI,0.);
};
break;
}
case BANDE_SYMETRIQUE :
{// initialisation a zero
if (mat_mass == NULL)
{ mat_mass = new MatBand (BANDE_SYMETRIQUE,demi,nbddl_MPI,0);}
else // sinon on redimentionne ou on change si nécessaire
{ MatBand * mat_mass_d = (MatBand*) mat_mass; // cas où on redimentionne la matrice
mat_mass_d->Change_taille(demi,nbddl_MPI);
mat_mass_d->Initialise (0.);
};
break;
}
case BANDE_NON_SYMETRIQUE_LAPACK : case BANDE_SYMETRIQUE_LAPACK: // le choix est fait au moment de l'allocation
{// initialisation a zero
if (pa.Type_Matrice() == BANDE_SYMETRIQUE_LAPACK)
{ if (mat_mass == NULL)
{ mat_mass = new MatLapack(pa.Type_Matrice(),demi,nbddl_MPI,true,0.0
,pa.Type_resolution(),pa.Type_preconditionnement());}
else // sinon on redimentionne si nécessaire
{ MatLapack * mat_mass_d = (MatLapack*) mat_mass; // cas où on redimentionne la matrice
mat_mass_d->Change_taille(demi,nbddl_MPI,0.0);
};
}
else
{ if (mat_mass == NULL)
{ mat_mass = new MatLapack(pa.Type_Matrice(),total,nbddl_MPI,false,0.0
,pa.Type_resolution(),pa.Type_preconditionnement());}
else // sinon on redimentionne si nécessaire
{ MatLapack * mat_mass_d = (MatLapack*) mat_mass; // cas où on redimentionne la matrice
mat_mass_d->Change_taille(total,nbddl_MPI,0.0);
};
};
break;
}
case CREUSE_COMPRESSEE_COLONNE :
{ // cas d'une matrice creuse compressée par colonne
// tout d'abord on demande l'ensemble des tables de connexion
// pour les éléments
Tableau < Tableau <int> > petites_matrices;
lesMail->Table_connexion(petites_matrices,nb_casAssemb);
// puis on définit la matrice en conséquence
if (mat_mass == NULL)
{ mat_mass = new Mat_creuse_CompCol(nbddl_MPI,nbddl_MPI, petites_matrices);}
else // sinon on redimentionne ou on change si nécessaire
{ if (mat_mass->Type_matrice() != CREUSE_COMPRESSEE_COLONNE)
{ delete mat_mass; mat_mass = new Mat_creuse_CompCol(nbddl_MPI,nbddl_MPI, petites_matrices);} // cas où on change de matrice
else {Mat_creuse_CompCol * mat_mass_d = (Mat_creuse_CompCol*) mat_mass; // cas où on redimentionne la matrice
mat_mass_d->Change_taille(nbddl_MPI,nbddl_MPI, petites_matrices);
};
};
// pour l'instant on ne prend pas en compte les conditions linéaires initiales qui augmente la largeur
// diagonale par bloc de dim
// par contre on considère que par défaut la diagonale par bloc existe !!
if (change_stockage)
{ cout << "\n*** Erreur de choix de matrice de masse, il y a des conditions lineaires intiales,"
<< " qui vont changer le stockage a l'execution. Or le cas CREUSE_COMPRESSEE_COLONNE ne "
<< " prend pas en compte pour l'instant ce cas de changement !! \n";
if (ParaGlob::NiveauImpression() >= 5)
cout << " Algori::Choix_matrice_masse(..)";
// dans le cas où un comptage du calcul est en cours on l'arrête
if (tempsCalEquilibre.Comptage_en_cours()) tempsCalEquilibre.Arret_du_comptage();
if (tempsInitialisation.Comptage_en_cours()) tempsInitialisation.Arret_du_comptage();
if (tempsMiseAjourAlgo.Comptage_en_cours()) tempsMiseAjourAlgo.Arret_du_comptage();
Sortie(1);
};
break;
}
default :
cout << "\nErreur : valeur incorrecte ou non implante du type de matrice retenue, type !\n"
<< " = " << pa.Type_Matrice() ;
cout << "\n Algori::Algori::Choix_matrice_masse(... ) \n";
// dans le cas où un comptage du calcul est en cours on l'arrête
if (tempsCalEquilibre.Comptage_en_cours()) tempsCalEquilibre.Arret_du_comptage();
if (tempsInitialisation.Comptage_en_cours()) tempsInitialisation.Arret_du_comptage();
if (tempsMiseAjourAlgo.Comptage_en_cours()) tempsMiseAjourAlgo.Arret_du_comptage();
Sortie(1);
};
if ((ParaGlob::NiveauImpression() > 2)&&(!cal_parallele_et_rang_non_nul))
{ cout << "\n"; if (change_stockage) cout << " changement de ";
cout << " stockage matrice masse -->" << Nom_matrice(mat_mass->Type_matrice())
<< " nb_ligne= "<< mat_mass->Nb_ligne() <<" nb_col= "<< mat_mass->Nb_colonne() << endl;
};
}
else
// sinon on se trouve dans le cas de matrice voulue non diagonale car dont le calcul des coefs ne conduit pas
// à une matrice a priori diagonale (exemple: matrice consistante)
{switch (pa.Type_Matrice())
{ case CARREE :
{// cas d'une matrice carrée, là a priori on n'a pas besoin d'augmenter la largeur, on est au maxi
if (mat_mass == NULL)
{ mat_mass = new Mat_pleine (nbddl_MPI,nbddl_MPI);}
else // sinon on redimentionne ou on change si nécessaire
{ Mat_pleine * mat_mass_d = (Mat_pleine*) mat_mass; // cas où on redimentionne la matrice
mat_mass_d->Initialise (nbddl_MPI,nbddl_MPI,0.);
};
break;
}
case RECTANGLE :
{// cas s'une matrice rectangulaire, pour l'instant idem que le cas précédent
// car pour l'instant on ne voit pas très bien à quoi cela servirait d'être différent
if (mat_mass == NULL)
{ mat_mass = new Mat_pleine (nbddl_MPI,nbddl_MPI);}
else // sinon on redimentionne ou on change si nécessaire
{ Mat_pleine * mat_mass_d = (Mat_pleine*) mat_mass; // cas où on redimentionne la matrice
mat_mass_d->Initialise (nbddl_MPI,nbddl_MPI,0.);
};
break;
}
case CARREE_LAPACK :
{// cas s'une matrice carrée
if (mat_mass == NULL)
{ mat_mass = new MatLapack (nbddl_MPI,nbddl_MPI,false,0.,pa.Type_resolution(),pa.Type_preconditionnement());}
else // sinon on redimentionne ou on change si nécessaire
{ MatLapack * mat_mass_d = (MatLapack*) mat_mass; // cas où on redimentionne la matrice
mat_mass_d->Change_taille(nbddl_MPI,nbddl_MPI,0.);
};
break;
}
case CARREE_SYMETRIQUE_LAPACK :
{// cas s'une matrice carrée symétrique
if (mat_mass == NULL)
{ mat_mass = new MatLapack (nbddl_MPI,nbddl_MPI,true,0.,pa.Type_resolution(),pa.Type_preconditionnement());}
else // sinon on redimentionne ou on change si nécessaire
{ MatLapack * mat_mass_d = (MatLapack*) mat_mass; // cas où on redimentionne la matrice
mat_mass_d->Change_taille(nbddl_MPI,nbddl_MPI,0.);
};
break;
}
case RECTANGLE_LAPACK :
{// cas s'une matrice rectangulaire, pour l'instant idem que le cas précédent
if (mat_mass == NULL)
{ mat_mass = new MatLapack (nbddl_MPI,nbddl_MPI,false,0.,pa.Type_resolution(),pa.Type_preconditionnement());}
else // sinon on redimentionne ou on change si nécessaire
{ MatLapack * mat_mass_d = (MatLapack*) mat_mass; // cas où on redimentionne la matrice
mat_mass_d->Change_taille(nbddl_MPI,nbddl_MPI,0.);
};
break;
}
case BANDE_SYMETRIQUE :
{// calcul de la largeur de bande effective
int demi=0,total=0;
lesMail->Largeur_Bande(demi,total,nb_casAssemb);
total = std::min(total,nbddl_MPI);
demi = std::min(demi,nbddl_MPI);
// --- on stocke les largeurs initiales de ddl
// on redimensionne si nécessaire
int nombre_cas_assemb = tab_para_stockage.Taille();
if (nb_casAssemb.n > nombre_cas_assemb)
tab_para_stockage.Change_taille(nb_casAssemb.n);
// maintenant on stocke
ParaStockage & parstock = (tab_para_stockage(nb_casAssemb.n));
parstock.nbass = nb_casAssemb;
parstock.demi = demi;
parstock.total = total;
// l'influence des CLL n'intervient que sur le CPU 0
if (!cal_parallele_et_rang_non_nul)
{if (ParaGlob::NiveauImpression() >= 5)
cout << "\n matrice masse: largeur de bande pour les elements (en ddl) " << total << " ";
// cas de l'influence des conditions linéaires d'entrée
int demic=0,totalc=0,cumule=0;
// on n'intervient que si la largeur en noeud augmente
if (lesCondLim->Largeur_Bande(demic,totalc,nb_casAssemb,lesMail,lesRef,cumule))
{totalc = std::min(totalc,nbddl_MPI);
demic = std::min(demic,nbddl_MPI);
cumule = std::min(cumule,nbddl_MPI);
if (ParaGlob::NiveauImpression() >= 5)
cout << "\n matrice masse: largeur de bande pour les conditions lineaires (en ddl) " << totalc << " ";
demi += cumule; // c'est donc toute la largeur hors diag que l'on ajoute
total += 2 * cumule;
// on limite au nombres total de ddl
total = std::min(total,nbddl_MPI);
demi = std::min(demi,nbddl_MPI);
};
if (ParaGlob::NiveauImpression() >= 5)
cout << "\n matrice masse: largeur de bande finale (en ddl) " << total << " "
<< "\n stockage symetrique d'ou utilisation de la demi largeur= " << demi << " ";
};
// initialisation a zero
if (mat_mass == NULL)
{ mat_mass = new MatBand (BANDE_SYMETRIQUE,demi,nbddl_MPI,0);}
else // sinon on redimentionne ou on change si nécessaire
{ MatBand * mat_mass_d = (MatBand*) mat_mass; // cas où on redimentionne la matrice
mat_mass_d->Change_taille(demi,nbddl_MPI);
mat_mass_d->Initialise (0.);
};
// // on vérifie que l'assemblage choisit est bien de type symétrique
// if (pa.Symetrie_matrice() != true)
// { cout << "Erreur de type d'assemblage, le type de matrice choisit est non symetrique"
// << " alors que l'assemblage n'est pas symetrique !! \n";
// cout << " Algori::Choix_matrice_masse(..)";
// Sortie(1);
// };
break;
}
case BANDE_NON_SYMETRIQUE_LAPACK : case BANDE_SYMETRIQUE_LAPACK: // le choix est fait au moment de l'allocation
{// calcul de la largeur de bande effective
int demi=0,total=0;
lesMail->Largeur_Bande(demi,total,nb_casAssemb);
total = std::min(total,2*nbddl_MPI-1);
demi = std::min(demi,nbddl_MPI);
// --- on stocke les largeurs initiales de ddl
// on redimensionne si nécessaire
int nombre_cas_assemb = tab_para_stockage.Taille();
if (nb_casAssemb.n > nombre_cas_assemb)
tab_para_stockage.Change_taille(nb_casAssemb.n);
// maintenant on stocke
ParaStockage & parstock = (tab_para_stockage(nb_casAssemb.n));
parstock.nbass = nb_casAssemb;
parstock.demi = demi;
parstock.total = total;
// cas de l'influence des conditions linéaires d'entrée
int demic=0,totalc=0,cumule=0;
// on n'intervient que si la largeur en noeud augmente
// et que l'on est sur le CPU 0
if ( (lesCondLim->Largeur_Bande(demic,totalc,nb_casAssemb,lesMail,lesRef,cumule))
&& (!cal_parallele_et_rang_non_nul)
)
{totalc = std::min(totalc,2*nbddl_MPI-1);
demic = std::min(demic,nbddl_MPI);
cumule = std::min(cumule,nbddl_MPI);
demi += cumule; // c'est donc toute la largeur hors diag que l'on ajoute
total += 2 * cumule;
if (ParaGlob::NiveauImpression() >= 5)
cout << "\n matrice masse: augmentation de la largeur de bande pour les conditions lineaires (en ddl) " << cumule << " ";
// on limite au nombres total de ddl
total = std::min(total,2*nbddl_MPI-1);
demi = std::min(demi,nbddl_MPI);
};
if ((ParaGlob::NiveauImpression() >= 5)&& (!cal_parallele_et_rang_non_nul))
cout << "\n matrice masse: largeur de bande finale (en ddl) " << total << " ";
// initialisation a zero
if (pa.Type_Matrice() == BANDE_SYMETRIQUE_LAPACK)
{ if (mat_mass == NULL)
{ mat_mass = new MatLapack(pa.Type_Matrice(),demi,nbddl_MPI,true,0.0
,pa.Type_resolution(),pa.Type_preconditionnement());}
else // sinon on redimentionne si nécessaire
{ MatLapack * mat_mass_d = (MatLapack*) mat_mass; // cas où on redimentionne la matrice
mat_mass_d->Change_taille(demi,nbddl_MPI,0.0);
};
}
else
{ if (mat_mass == NULL)
{ mat_mass = new MatLapack(pa.Type_Matrice(),total,nbddl_MPI,false,0.0
,pa.Type_resolution(),pa.Type_preconditionnement());}
else // sinon on redimentionne si nécessaire
{ MatLapack * mat_mass_d = (MatLapack*) mat_mass; // cas où on redimentionne la matrice
mat_mass_d->Change_taille(total,nbddl_MPI,0.0);
};
};
break;
}
case CREUSE_COMPRESSEE_COLONNE :
{ // cas d'une matrice creuse compressée par colonne
// tout d'abord on demande l'ensemble des tables de connexion
// pour les éléments
Tableau < Tableau <int> > petites_matrices;
lesMail->Table_connexion(petites_matrices,nb_casAssemb);
// puis on définit la matrice en conséquence
if (mat_mass == NULL)
{ mat_mass = new Mat_creuse_CompCol(nbddl_MPI,nbddl_MPI, petites_matrices);}
else // sinon on redimentionne ou on change si nécessaire
{ if (mat_mass->Type_matrice() != CREUSE_COMPRESSEE_COLONNE)
{ delete mat_mass; mat_mass = new Mat_creuse_CompCol(nbddl_MPI,nbddl_MPI, petites_matrices);} // cas où on change de matrice
else {Mat_creuse_CompCol * mat_mass_d = (Mat_creuse_CompCol*) mat_mass; // cas où on redimentionne la matrice
mat_mass_d->Change_taille(nbddl_MPI,nbddl_MPI, petites_matrices);
};
};
// !!! pour l'instant on ne prend pas en compte les conditions linéaires initiales
// on vérifie
if (lesCondLim->ExisteCondiLimite())
{ cout << "\n*** Erreur de choix de matrice de masse, il y a des conditions lineaires intiales, ce qui conduit "
<< " a intervenir sur le stockage. Or le cas CREUSE_COMPRESSEE_COLONNE ne prend pas en compte pour l'instant "
<< " la presence de conditions limites !! \n";
if (ParaGlob::NiveauImpression() >= 5)
cout << " Algori::Choix_matrice_masse(..)";
// dans le cas où un comptage du calcul est en cours on l'arrête
if (tempsCalEquilibre.Comptage_en_cours()) tempsCalEquilibre.Arret_du_comptage();
if (tempsInitialisation.Comptage_en_cours()) tempsInitialisation.Arret_du_comptage();
if (tempsMiseAjourAlgo.Comptage_en_cours()) tempsMiseAjourAlgo.Arret_du_comptage();
Sortie(1);
};
break;
}
default :
cout << "\nErreur : valeur incorrecte ou non implante du type de matrice retenue, type !\n"
<< " = " << pa.Type_Matrice() ;
cout << "\n Algori::Algori::Choix_matrice_masse(... ) \n";
// dans le cas où un comptage du calcul est en cours on l'arrête
if (tempsCalEquilibre.Comptage_en_cours()) tempsCalEquilibre.Arret_du_comptage();
if (tempsInitialisation.Comptage_en_cours()) tempsInitialisation.Arret_du_comptage();
if (tempsMiseAjourAlgo.Comptage_en_cours()) tempsMiseAjourAlgo.Arret_du_comptage();
Sortie(1);
};
};
if ((ParaGlob::NiveauImpression() >= 5)&& (!cal_parallele_et_rang_non_nul))
cout << "\n Taille du stockage masse " << mat_mass->Type_matrice() << " (taille en entiers) :"
<< mat_mass->Place() << endl;
return mat_mass;
};
// mise à jour éventuelle du type et/ou de la taille de la matrice de masse
// retourne un pointeur sur la nouvelle matrice, s'il y a eu une modification
// l'ancienne est supprimée
// sinon retour d'un pointeur NULL
Mat_abstraite* Algori::Mise_a_jour_type_et_taille_matrice_masse_en_explicite
(int nbddl,Mat_abstraite* mat_mass,LesMaillages * lesMail,LesReferences* lesRef
,const Nb_assemb& nb_casAssemb, LesContacts* lescontacts)
{
#ifdef UTILISATION_MPI
// cas d'un calcul //, seule la matrice du CPU 0 est concernée
if (ParaGlob::Monde()->rank() != 0)
return NULL;
#endif
//// préparation pour le cas particulier : pa.ContactType() == 1
// int contact_type_1_et_maitre_deformable = false;
// if (pa.ContactType() == 1)
// {// on veut savoir s'il y a des contacts autres que solide-déformables
// if (lescontacts->Maitres_avec_deplacement_imposer())
// // cas où tous les surfaces maîtres sont fixées
// {contact_type_1_et_maitre_deformable = true;};
// // dans ce cas on peut utiliser une tridiagonale !
// };
bool change_stockage = false; // init pour le retour
if (( pa.ContactType() == 2) || (pa.ContactType() == 0)
|| (pa.ContactType() == 3)|| (pa.ContactType() == 4))
// cas sans contact ou d'une pénalisation en explicite
// il n'y a rien n'a faire
{return NULL;}
else // sinon on statut en fonction du type existant de matrice
{ // en fait il n'y a que deux cas très différents:
// soit on est en diagonal, et on doit peut-être passer dans un autre type
// de stockage
// soit ce n'est pas du diagonal, et on regarde s'il faut agrandir
if (mat_mass->Type_matrice() == DIAGONALE)
{// si on a un contact de
// type 1 c-a-d qui induit des conditions linéaires, on va analyser
if (pa.ContactType() == 1)
{ // dans le cas ou on devrait utiliser une matrice diagonale, on va utiliser la matrice demandée
// mais avec une largeur uniquement déterminé par les conditions linéaires éventuelles de contact
// en particulier, si les CLL => un stockage diagonale en noeuds, on utilise une matrice de bande = dim espace
// calcul de la largeur de bande effective due à l'influence des conditions linéaires de contact
// --- on stocke les largeurs initiales de ddl
// on redimensionne si nécessaire
int nombre_cas_assemb = tab_para_stockage.Taille();
if (nb_casAssemb.n > nombre_cas_assemb)
tab_para_stockage.Change_taille(nb_casAssemb.n);
// maintenant on stocke
ParaStockage & parstock = (tab_para_stockage(nb_casAssemb.n));
parstock.nbass = nb_casAssemb;
parstock.demi = parstock.total = 1; // tout est diagonal
int demic=0,totalc=0,cumule=0;
int demi=0,total=0;
// int ancien_lb = mat_mass->Nb_colonne();
//-- dans tous les cas, à minima il faut passer en tridiagonale
if (lescontacts->Largeur_Bande(demic,totalc,nb_casAssemb,cumule))
{ demi = 1 + cumule; // c'est donc toute la largeur hors diag que l'on ajoute
total = 1 + 2 * cumule;
}
else // sinon on est dans le cas où on peut utiliser une matrice bande = dim espace (ex: si dim 3: tridiagonale)
{ int dim_espace = ParaGlob::Dimension();
demi = dim_espace;
total = 1 + 2 * (dim_espace-1);
};
// on limite au nombres total de ddl
total = std::min(total,nbddl);
demi = std::min(demi,nbddl);
if (ParaGlob::NiveauImpression() >= 2)
cout << "\n augmentation de la largeur de bande pour les conditions de contact (en ddl) " << cumule << " new_lb: "<< total <<" ";
// comme la matrice actuelle est de type diagonale il faut la supprimer et définir une autre
if (mat_mass != NULL)
if (mat_mass->Type_matrice() == DIAGONALE)
{ delete mat_mass; mat_mass = NULL;change_stockage = true;}; // cas où on change de stockage
// maintenant on crée une matrice en fonction de la demande
switch (pa.Type_Matrice())
{ case CARREE :
{// cas d'une matrice carrée, là a priori on n'a pas besoin d'augmenter la largeur, on est au maxi
if (mat_mass == NULL)
{ mat_mass = new Mat_pleine (nbddl,nbddl);}
else // sinon on redimentionne ou on change si nécessaire
{ Mat_pleine * mat_mass_d = (Mat_pleine*) mat_mass; // cas où on redimentionne la matrice
mat_mass_d->Initialise (nbddl,nbddl,0.);
};
break;
}
case RECTANGLE :
{// cas s'une matrice rectangulaire, pour l'instant idem que le cas précédent
// car pour l'instant on ne voit pas très bien à quoi cela servirait d'être différent
if (mat_mass == NULL)
{ mat_mass = new Mat_pleine (nbddl,nbddl);}
else // sinon on redimentionne ou on change si nécessaire
{ Mat_pleine * mat_mass_d = (Mat_pleine*) mat_mass; // cas où on redimentionne la matrice
mat_mass_d->Initialise (nbddl,nbddl,0.);
};
break;
}
case CARREE_LAPACK :
{// cas s'une matrice carrée
if (mat_mass == NULL)
{ mat_mass = new MatLapack (nbddl,nbddl,false,0.,pa.Type_resolution(),pa.Type_preconditionnement());}
else // sinon on redimentionne ou on change si nécessaire
{ MatLapack * mat_mass_d = (MatLapack*) mat_mass; // cas où on redimentionne la matrice
mat_mass_d->Change_taille(nbddl,nbddl,0.);
};
break;
}
case CARREE_SYMETRIQUE_LAPACK :
{// cas s'une matrice carrée symétrique
if (mat_mass == NULL)
{ mat_mass = new MatLapack (nbddl,nbddl,true,0.,pa.Type_resolution(),pa.Type_preconditionnement());}
else // sinon on redimentionne ou on change si nécessaire
{ MatLapack * mat_mass_d = (MatLapack*) mat_mass; // cas où on redimentionne la matrice
mat_mass_d->Change_taille(nbddl,nbddl,0.);
};
break;
}
case RECTANGLE_LAPACK :
{// cas s'une matrice rectangulaire, pour l'instant idem que le cas précédent
if (mat_mass == NULL)
{ mat_mass = new MatLapack (nbddl,nbddl,false,0.,pa.Type_resolution(),pa.Type_preconditionnement());}
else // sinon on redimentionne ou on change si nécessaire
{ MatLapack * mat_mass_d = (MatLapack*) mat_mass; // cas où on redimentionne la matrice
mat_mass_d->Change_taille(nbddl,nbddl,0.);
};
break;
}
case BANDE_SYMETRIQUE :
{// initialisation a zero
if (mat_mass == NULL)
{ mat_mass = new MatBand (BANDE_SYMETRIQUE,demi,nbddl,0);}
else // sinon on redimentionne ou on change si nécessaire
{ MatBand * mat_mass_d = (MatBand*) mat_mass; // cas où on redimentionne la matrice
mat_mass_d->Change_taille(demi,nbddl);
mat_mass_d->Initialise (0.);
};
break;
}
case BANDE_NON_SYMETRIQUE_LAPACK : case BANDE_SYMETRIQUE_LAPACK: // le choix est fait au moment de l'allocation
{// initialisation a zero
if (pa.Type_Matrice() == BANDE_SYMETRIQUE_LAPACK)
{ if (mat_mass == NULL)
{ mat_mass = new MatLapack(pa.Type_Matrice(),demi,nbddl,true,0.0
,pa.Type_resolution(),pa.Type_preconditionnement());}
else // sinon on redimentionne si nécessaire
{ MatLapack * mat_mass_d = (MatLapack*) mat_mass; // cas où on redimentionne la matrice
mat_mass_d->Change_taille(demi,nbddl,0.0);
};
}
else
{ if (mat_mass == NULL)
{ mat_mass = new MatLapack(pa.Type_Matrice(),total,nbddl,false,0.0
,pa.Type_resolution(),pa.Type_preconditionnement());}
else // sinon on redimentionne si nécessaire
{ MatLapack * mat_mass_d = (MatLapack*) mat_mass; // cas où on redimentionne la matrice
mat_mass_d->Change_taille(total,nbddl,0.0);
};
};
break;
}
case CREUSE_COMPRESSEE_COLONNE :
{ // cas d'une matrice creuse compressée par colonne
// tout d'abord on demande l'ensemble des tables de connexion
// pour les éléments
Tableau < Tableau <int> > petites_matrices;
lesMail->Table_connexion(petites_matrices,nb_casAssemb);
// puis on définit la matrice en conséquence
if (mat_mass == NULL)
{ mat_mass = new Mat_creuse_CompCol(nbddl,nbddl, petites_matrices);}
else // sinon on redimentionne ou on change si nécessaire
{ if (mat_mass->Type_matrice() != CREUSE_COMPRESSEE_COLONNE)
{ delete mat_mass; mat_mass = new Mat_creuse_CompCol(nbddl,nbddl, petites_matrices);} // cas où on change de matrice
else {Mat_creuse_CompCol * mat_mass_d = (Mat_creuse_CompCol*) mat_mass; // cas où on redimentionne la matrice
mat_mass_d->Change_taille(nbddl,nbddl, petites_matrices);
};
};
// pour l'instant on ne prend pas en compte les conditions linéaires initiales qui augmente la largeur
// diagonale par bloc de dim
// par contre on considère que par défaut la diagonale par bloc existe !!
if (change_stockage)
{ cout << "\n*** Erreur de choix de matrice de masse, il y a des conditions lineaires intiales,"
<< " qui vont changer le stockage a l'execution. Or le cas CREUSE_COMPRESSEE_COLONNE ne "
<< " prend pas en compte pour l'instant ce cas de changement !! \n";
if (ParaGlob::NiveauImpression() >= 2)
cout << " Algori::Mise_a_jour_type_et_taille_matrice_masse_en_explicite(..)";
// dans le cas où un comptage du calcul est en cours on l'arrête
if (tempsCalEquilibre.Comptage_en_cours()) tempsCalEquilibre.Arret_du_comptage();
if (tempsInitialisation.Comptage_en_cours()) tempsInitialisation.Arret_du_comptage();
if (tempsMiseAjourAlgo.Comptage_en_cours()) tempsMiseAjourAlgo.Arret_du_comptage();
Sortie(1);
};
break;
}
default :
cout << "\nErreur : valeur incorrecte ou non implante du type de matrice retenue, type !\n"
<< " = " << pa.Type_Matrice() ;
cout << "\n Algori::Algori::Choix_matrice_masse(... ) \n";
// dans le cas où un comptage du calcul est en cours on l'arrête
if (tempsCalEquilibre.Comptage_en_cours()) tempsCalEquilibre.Arret_du_comptage();
if (tempsInitialisation.Comptage_en_cours()) tempsInitialisation.Arret_du_comptage();
if (tempsMiseAjourAlgo.Comptage_en_cours()) tempsMiseAjourAlgo.Arret_du_comptage();
Sortie(1);
};
if (ParaGlob::NiveauImpression() > 2)
{ cout << "\n"; if (change_stockage) cout << " changement de ";
cout << " stockage matrice masse -->" << Nom_matrice(mat_mass->Type_matrice())
<< " nb_ligne= "<< mat_mass->Nb_ligne() <<" nb_col= "<< mat_mass->Nb_colonne() << endl;
};
}
else // sinon pour l'instant les autres cas de contact ne sont pas traités
{cout << "\n*** Erreur pour la mise a jour de la matrice de masse "
<< " avec du contact, le type de contact = " <<pa.ContactType()
<< " n'est pas pris en compte \n";
if (ParaGlob::NiveauImpression() >= 5)
cout << " Algori::Mise_a_jour_type_et_taille_matrice_masse_en_explicite(..)";
};
}
else // sinon on peut augmenter la taille directement
{Enum_matrice enumatrice = mat_mass->Type_matrice();// init
switch (enumatrice)
{ case CARREE : break; // pas de modification
case RECTANGLE : break; // pas de modification
case CARREE_LAPACK : break; // pas de modification
case CARREE_SYMETRIQUE_LAPACK : break; // pas de modification
case RECTANGLE_LAPACK : break; // pas de modification
case BANDE_SYMETRIQUE : case BANDE_SYMETRIQUE_LAPACK:
{ // -- récup des anciennes tailles
int nbddl = mat_mass->Nb_ligne();
ParaStockage & parstock = (tab_para_stockage(nb_casAssemb.n));
int ancien_demi = mat_mass->Nb_colonne();
// calcul de la largeur de bande effective en tenant compte du contact
int demic=0,totalc=0,cumule=0;
int demi = parstock.demi; // init
// on n'intervient que si la largeur en noeud augmente
if (lescontacts->Largeur_Bande(demic,totalc,nb_casAssemb,cumule))
{// la mise à jour dépend du type de contact
if (pa.ContactType() == 1) // contact cinématique, sans multiplicateur ni pénalisation
// on doit augmenter la lb en fonction de cumule, si la largeur en noeud est différente
// de 1
{cumule = std::min(cumule,nbddl);
demi = parstock.demi + cumule; // c'est donc toute la largeur hors diag que l'on ajoute
if (demi > ancien_demi)
if (ParaGlob::NiveauImpression() >= 5)
cout << "\n propositon d'augmentation de la largeur de bande pour les conditions de contact (en ddl) " << cumule << "old_1/2lb: "<<ancien_demi << " new_1/2lb: "<< demi <<" ";
}
else if ((pa.ContactType() == 2) // cas d'un contact par pénalisation
|| (pa.ContactType() == 3)|| (pa.ContactType() == 4)
)
// dans ce cas on considère uniquement le LB maxi
{ demic = std::min(demic,nbddl);
int demi_inter = std::max(parstock.demi, demic);
if (demi_inter > ancien_demi)
if ((ParaGlob::NiveauImpression() >= 5) && (demic > demi))
cout << "\n propositon d'augmentation de la largeur de bande pour les conditions de contact (en ddl) " << (demic-demi) << "old_1/2lb: "<<ancien_demi << " new_1/2lb: "<< demi_inter <<" ";
demi = demi_inter;
};
};
// on limite au nombres total de ddl et pas inférieur à la dimension de l'espace
// car on a au minimum une largeur de 1 noeud donc 3 ddl
// ( à moins qu'il n'y ait plus de contact) mais pour l'instant on n'en tient pas compte ....
demi = std::max(std::min(demi,nbddl),ParaGlob::Dimension());
// on change la taille, si elle doit augmenter, ou si elle est inférieur d'au moins 5% par rapport à la taille actuelle
if ( (demi > mat_mass->Nb_colonne()) ||
(demi < 0.95 * mat_mass->Nb_colonne()))
// on change la taille
{ if (ParaGlob::NiveauImpression() >= 5)
cout << "\n augmentation effective: LB/2+1 finale(en ddl) " << demi << " ";
switch (enumatrice)
{ case BANDE_SYMETRIQUE:
((MatBand*)mat_mass)->Change_taille(demi,nbddl );
break;
case BANDE_SYMETRIQUE_LAPACK:
((MatLapack*)mat_mass)->Change_taille(nbddl,demi);
break;
default:
cout << "\n erreur non prevue Algori::Mise_a_jour_type_et_taille_matrice_masse_en_explicite "<<endl;
// dans le cas où un comptage du calcul est en cours on l'arrête
if (tempsCalEquilibre.Comptage_en_cours()) tempsCalEquilibre.Arret_du_comptage();
if (tempsInitialisation.Comptage_en_cours()) tempsInitialisation.Arret_du_comptage();
if (tempsMiseAjourAlgo.Comptage_en_cours()) tempsMiseAjourAlgo.Arret_du_comptage();
Sortie(1);
};
};
break;
}
case BANDE_NON_SYMETRIQUE : case BANDE_NON_SYMETRIQUE_LAPACK :
{ // -- récup des anciennes tailles
int nbddl = mat_mass->Nb_ligne();
int ancien_lb = mat_mass->Nb_colonne();
ParaStockage & parstock = (tab_para_stockage(nb_casAssemb.n));
//int demi = matglob->Nb_colonne();
// calcul de la largeur de bande effective en tenant compte du contact
int demic=0,totalc=0,cumule=0;
int total = parstock.total; // init
// on n'intervient que si la largeur en noeud augmente
if (lescontacts->Largeur_Bande(demic,totalc,nb_casAssemb,cumule))
{// la mise à jour dépend du type de contact
if (pa.ContactType() == 1) // contact cinématique, sans multiplicateur ni pénalisation
// on doit augmenter la lb en fonction de cumule
{ cumule = std::min(cumule,nbddl);
int total_inter = parstock.total + 2 * cumule;
if (total_inter > ancien_lb)
if (ParaGlob::NiveauImpression() >= 5)
cout << "\n propositon d'augmentation de la largeur de bande pour les conditions de contact (en ddl) " << cumule << "old_lb: "<<ancien_lb << " new_lb: "<< total_inter <<" ";
total = total_inter;
}
else if ((pa.ContactType() == 2) // cas d'un contact par pénalisation
|| (pa.ContactType() == 3)|| (pa.ContactType() == 4)
)
// dans ce cas on considère uniquement le LB maxi
{ totalc = std::min(totalc,2*nbddl-1);
int total_inter = std::max(parstock.total, totalc);
if (total_inter > ancien_lb)
if ((ParaGlob::NiveauImpression() >= 5) && (totalc > total))
cout << "\n propositon d'augmentation de la largeur de bande pour les conditions de contact (en ddl) " << (totalc-total) << "old_lb: "<<ancien_lb << " new_lb: "<< total_inter << " ";
total = total_inter;
};
};
// on limite au nombres total de ddl
total = std::min(total,2*nbddl-1);
// on change la taille, si elle doit augmenter, ou si elle est inférieur d'au moins 5% par rapport à la taille actuelle
if ( (total > mat_mass->Nb_colonne()) ||
(total < 0.95 * mat_mass->Nb_colonne()))
// on change la taille
{ if (ParaGlob::NiveauImpression() >= 5)
cout << "\n augmentation effective: LB finale(en ddl) " << total << " ";
switch (enumatrice)
{ case BANDE_NON_SYMETRIQUE:
((MatBand*)mat_mass)->Change_taille(total,nbddl );
break;
case BANDE_NON_SYMETRIQUE_LAPACK:
((MatLapack*)mat_mass)->Change_taille(nbddl,total);
break;
default:
cout << "\n erreur2 non prevue Algori::Mise_a_jour_type_et_taille_matrice_masse_en_explicite "<<endl;
// dans le cas où un comptage du calcul est en cours on l'arrête
if (tempsCalEquilibre.Comptage_en_cours()) tempsCalEquilibre.Arret_du_comptage();
if (tempsInitialisation.Comptage_en_cours()) tempsInitialisation.Arret_du_comptage();
if (tempsMiseAjourAlgo.Comptage_en_cours()) tempsMiseAjourAlgo.Arret_du_comptage();
Sortie(1);
};
};
break;
}
case CREUSE_COMPRESSEE_COLONNE :
{ cout << "\n *** cas avec contact non actuellement traite "
<< "\n Algori::Mise_a_jour_type_et_taille_matrice_masse_en_explicite(... ) \n";
// dans le cas où un comptage du calcul est en cours on l'arrête
if (tempsCalEquilibre.Comptage_en_cours()) tempsCalEquilibre.Arret_du_comptage();
if (tempsInitialisation.Comptage_en_cours()) tempsInitialisation.Arret_du_comptage();
if (tempsMiseAjourAlgo.Comptage_en_cours()) tempsMiseAjourAlgo.Arret_du_comptage();
Sortie(1);
break;
}
default :
cout << "\nErreur : valeur incorrecte ou non implante du type de matrice retenue, type !\n"
<< " = " << enumatrice ;
cout << "\n Algori::Mise_a_jour_type_et_taille_matrice_masse_en_explicite(... ) \n";
// dans le cas où un comptage du calcul est en cours on l'arrête
if (tempsCalEquilibre.Comptage_en_cours()) tempsCalEquilibre.Arret_du_comptage();
if (tempsInitialisation.Comptage_en_cours()) tempsInitialisation.Arret_du_comptage();
if (tempsMiseAjourAlgo.Comptage_en_cours()) tempsMiseAjourAlgo.Arret_du_comptage();
Sortie(1);
};
if (ParaGlob::NiveauImpression() >= 5)
cout << "\n stockage matrice masse " << enumatrice << " taille (entiers) :"
<< mat_mass->Place() << endl;
}; // fin changement matrice
};
if (ParaGlob::NiveauImpression() >= 7)
cout << "\n Taille du stockage masse " << mat_mass->Type_matrice() << " (taille en entiers) :"
<< mat_mass->Place() << endl;
// retour
if (change_stockage)
{return mat_mass;}
else {return NULL;};
};
// calcul la matrice de masse
// N_ddl : donne le ddl où doit être mis la masse
void Algori::Cal_matrice_masse(LesMaillages * lesMail,Assemblage& Ass
,Mat_abstraite& mat_mass
,const DiversStockage* divStoc,LesReferences* lesRef
,const Enum_ddl & N_ddl ,LesFonctions_nD* lesFonctionsnD)
{ bool use_diagonale = false; // par défaut on n'utilise pas de stockage diagonal
if ( (mat_mass.Type_matrice() == DIAGONALE)
|| (pa.Type_calcul_masse() == MASSE_DIAG_COEF_EGAUX)
|| (pa.Type_calcul_masse() == MASSE_DIAG_COEF_VAR)
)
{use_diagonale = true;}
else if ( (mat_mass.Type_matrice() == DIAGONALE)
&& (pa.Type_calcul_masse() == MASSE_CONSISTANTE)
)
{ cout << "\n *** erreur, le stockage globale est diagonale et on veut "
<< " egalement une matrice masse consistante !! c'est incoherent. ";
if (ParaGlob::NiveauImpression() > 5)
cout << "\n Algori::Cal_matrice_masse( ";
Sortie(1);
// dans le cas où un comptage du calcul est en cours on l'arrête
if (tempsCalEquilibre.Comptage_en_cours()) tempsCalEquilibre.Arret_du_comptage();
if (tempsInitialisation.Comptage_en_cours()) tempsInitialisation.Arret_du_comptage();
if (tempsMiseAjourAlgo.Comptage_en_cours()) tempsMiseAjourAlgo.Arret_du_comptage();
};
if (use_diagonale)
// on définit un vecteur identique à la diagonale si c'est la première fois
{ if (toto_masse == NULL)
toto_masse = new Vecteur(mat_mass.Nb_ligne());
else
// on initialise le vecteur
toto_masse->Zero();
};
// on initialise la matrice masse à 0
mat_mass.Initialise(0.);
// boucle sur les elements
for (int nbMail =1; nbMail<= lesMail->NbMaillage(); nbMail++)
for (int ne=1; ne<= lesMail->Nombre_element(nbMail);ne++)
{
//calcul de la matrice masse local
Element & el = lesMail->Element_LesMaille(nbMail,ne); // l'element
Tableau<Noeud *>& taN = el.Tab_noeud(); // tableau de noeuds de l'el
Mat_pleine * mat_mass_loc = el.CalculMatriceMasse (pa.Type_calcul_masse());
// cout << "numéro =" << ne << endl;
// mat_mass_loc->Affiche();
// mat_mass_loc->Affiche1(1,8,1,1,8,1);
// assemblage
// il faut distinguer si l'on a une matrice globale diagonale ou si l'on a une matrice pleine
// et ... il faut tenir compte du type de calcul de matrice masse locale
if (use_diagonale)
// if (mat_mass.Type_matrice() == DIAGONALE)
{ // récupération de la première ligne
Vecteur* vectloc = &(mat_mass_loc->Ligne_set(1)) ;
// ensuite on fait l'assemblage suivant un vecteur comme pour le second membre
Ass.AssemSM (*toto_masse,*vectloc,el.TableauDdl(),taN);
}
else // cas d'une matrice pleine, donc consistante
{ if (pa.Symetrie_matrice())
Ass.AssembMatSym (mat_mass,*mat_mass_loc,el.TableauDdl(),taN); // de la masse
else
Ass.AssembMatnonSym (mat_mass,*mat_mass_loc,el.TableauDdl(),taN); // de la masse
};
};
// ---- cas des masses concentrées -----
Ajout_masses_ponctuelles(lesMail,Ass,mat_mass,divStoc,lesRef,N_ddl,lesFonctionsnD);
// ---- fin cas des masses concentrées -----
// dans le cas où la masse est diagonale on transfert du vecteur assemblé à la matrice
// diagonale
if ((use_diagonale) && (mat_mass.Type_matrice() == DIAGONALE))
{ MatDiag & mat_d = *((MatDiag*) & mat_mass);
mat_d += (*toto_masse);
}
else if (use_diagonale)
{ // cas d'une matrice masse concentrée sur la diagonale, mais d'un stockage non diagonale
MatDiag mat_inter(mat_mass.Nb_ligne());
mat_inter = (*toto_masse);
mat_mass += mat_inter;
};
// sinon l'assemblage est déjà ok
// affichage éventuelle de la matrice de masse
if (ParaGlob::NiveauImpression() >= 10)
{ string entete = " affichage de la matrice masse ";
mat_mass.Affichage_ecran(entete);
};
};
// uniquement ajout dans la matrice de masse des masses ponctuelles si elles existent
// N_ddl : donne le ddl où doit être mis la masse
// par exemple, sert pour la relaxation dynamique
void Algori::Ajout_masses_ponctuelles(LesMaillages * lesMail,Assemblage& Ass,Mat_abstraite& mat_masse
,const DiversStockage* divStoc,LesReferences* lesRef
,const Enum_ddl & N_ddl,LesFonctions_nD* lesFonctionsnD)
{
#ifdef UTILISATION_MPI
// cas d'un calcul //, seule la matrice du CPU 0 est concernée
if (ParaGlob::Monde()->rank() != 0)
return ;
#endif
// prise en compte de masses ponctuelles
int dima = ParaGlob::Dimension();
// dans le cas où on est en axisymétrie il faut diminuer de 1
if (ParaGlob::AxiSymetrie())
dima--;
// int nbddl_X = mat_masse.Nb_ligne();
// ---- cas des masses concentrées -----
// on récupère les masses concentrées
const Tableau < BlocDdlLim<BlocScal_ou_fctnD> > & Tab_M_A = divStoc->TabMasseAddi();
int cas_assemblage = (Ass.Nb_cas_assemb()).n; // récup du cas d'assemblage
int posi = N_ddl -1;
// on balaie le tableau
int Tab_M_ATaille = Tab_M_A.Taille();
for (int i=1;i<= Tab_M_ATaille;i++)
{ // on récup la référence
const ReferenceNE & ref =
((ReferenceNE &) lesRef->Trouve(Tab_M_A(i).NomRef(),Tab_M_A(i).NomMaillage()));
// recup de la masse: soit c'est une valeur fixe soit une fonction nD
double val_mass = 0; // init par défaut
Fonction_nD * pt_fonct = NULL; // init
Coordonnee mass_noeu_differencie(dima);
int cas_masse = 0; // = 1 -> masse fixe sur tous les axes
// = 2 -> masse différenciée sur chaque axe
// = 0 -> n'a pas encore de valeur
string nom_fct_nD("_"); // ""
if ((Tab_M_A(i)).Val() != NULL) // cas d'une valeur fixe
{ val_mass = *((Tab_M_A(i)).Val()); // recup de la valeur
cas_masse = 1;
}
else if ((Tab_M_A(i)).Fct_nD() != NULL) // cas d'une fonction nD
{ nom_fct_nD = *((Tab_M_A(i)).Fct_nD());
// on récupère la fonction
if (lesFonctionsnD->Existe(nom_fct_nD))
{pt_fonct = lesFonctionsnD->Trouve(nom_fct_nD);
if (pt_fonct->Nom_variables().Taille() == 0) // cas où il n'y a que des variables globales
{ // on vérifie qu'en retour on a un scalaire ou un vecteur de dima = la dima de l'espace
Tableau <double> & tava = pt_fonct->Valeur_pour_variables_globales(); // pour simplifier
if (pt_fonct->NbComposante() == 1)
{val_mass = tava(1);cas_masse=1;}
else if (pt_fonct->NbComposante() == dima)
{switch (dima)
{ case 3 : mass_noeu_differencie(3) = tava(3);
case 2 : mass_noeu_differencie(2) = tava(2);
case 1 : mass_noeu_differencie(1) = tava(1);
cas_masse=2;
};
}
else
{cout << "\n *** erreur en retour de l'utilisation d'une fonction nD avec grandeur(s) globale(s)"
<< " cas des masses ponctuelles sur la ref: "<< Tab_M_A(i).NomRef()
<< " en retour, le nombre de composante est different de 1 et la dimension de l'espace : "
<< dima << endl;
Sortie(1);
};
}; // fin du cas où la fonction ne dépend que de variables globales
}
else // sinon c'est un problème
{ cout << "\n *** erreur dans la definition des masses ponctuelles via la fonction nD "
<< nom_fct_nD << ", a priori cette fonction n'est pas disponible!! ";
Sortie(1);
};
}
else // sinon il y a un pb
{ cout << "\n *** erreur de definition des masses ponctuelles aux noeuds"
<< " les infos lues ne sont pas correctes: ";
(Tab_M_A(i)).Affiche();
Sortie(1);
};
// maintenant on va balayer les noeuds de la ref
int reftaille = ref.Taille();
// on boucle sur les noeuds de la référence
for (int nn =1; nn<= reftaille;nn++) // nn = position des num de noeud
{ Noeud & noe=lesMail->Noeud_LesMaille(ref.Nbmaille(),ref.Numero(nn));
if ((noe.Pointeur_assemblage(N_ddl,cas_assemblage) != -1)
&& (noe.En_service(N_ddl)) && (noe.UneVariable(N_ddl)))
{// les masses ponctuelles correspondent aux ddl N_ddl N_ddl+1 ...
switch (cas_masse)
{case 0: // il s'agit de l'utilisation d'une fonction nD qui ne doit dépendre que de M
{if ((pt_fonct->Depend_M() < 0) || (pt_fonct->Depend_Mt() < 0)
|| (pt_fonct->Depend_M0() < 0)
) // signifie que la fonction dépend exclusivement d'un des 3 temps: tdt, t ou 0
{ Coordonnee M(dima); // init
// on vérifie également qu'en retour on a un scalaire ou un vecteur de dimension = la dimension de l'espace
if ((pt_fonct->Depend_M()<0) && pt_fonct->Nom_variables().Taille() == dima)
M = noe.Coord2();
if ((pt_fonct->Depend_Mt()<0) && pt_fonct->Nom_variables().Taille() == dima)
M = noe.Coord1();
if ((pt_fonct->Depend_M0()<0) && pt_fonct->Nom_variables().Taille() == dima)
M = noe.Coord0();
// comme pt_fonct->Depend_M()<0, cela signifie que la fonction dépend que de M
// donc dans les paramètres d'appel on ne transmet que M
Tableau <Coordonnee> tab_M(1,M);
Tableau <double> & tava = pt_fonct->Val_FnD_Evoluee(NULL,&tab_M,NULL); // pour simplifier
if (pt_fonct->NbComposante() == 1)
{ double& val_masse_fct = tava(1);
for (int di=1;di<= dima;di++)
{ int pt_adres = noe.Pointeur_assemblage(Enum_ddl(posi+di),cas_assemblage);
mat_masse (pt_adres,pt_adres) += val_masse_fct;
};
}
else if (pt_fonct->NbComposante() == dima)
{ int pt_adres = noe.Pointeur_assemblage(Enum_ddl(posi),cas_assemblage);
switch (dima)
{ case 3 : mat_masse(pt_adres+3,pt_adres+3) += tava(3);
case 2 : mat_masse(pt_adres+2,pt_adres+2) += tava(2);
case 1 : mat_masse(pt_adres+1,pt_adres+1) += tava(1);
};
}
else
{cout << "\n *** erreur en retour de l'utilisation d'une fonction nD "
<< " cas des masses ponctuelles sur la ref: "<< Tab_M_A(i).NomRef()
<< " en retour, le nombre de composante: " << pt_fonct->NbComposante()
<< " est different de 1 ou de la dimension de l'espace : "
<< dima << endl;
Sortie(1);
};
}
else
{cout << "\n *** erreur en retour de l'utilisation d'une fonction nD "
<< " cas des masses ponctuelles sur la ref: "<< Tab_M_A(i).NomRef()
<< " la fonction ne doit dependre que de M : valeur courante, ou a t "
<< " ou au temps initial "
<< dima ;
cout << "\n fonction nD: "; pt_fonct->Affiche();
Sortie(1);
};
}
break;
case 1: // la masse a déjà été déterminé, et elle est identique sur tous les axes
for (int di=1;di<= dima;di++)
{ int pt_adres = noe.Pointeur_assemblage(Enum_ddl(posi+di),cas_assemblage);
mat_masse(pt_adres,pt_adres) += val_mass;
};
break;
case 2: // la masse a déjà été déterminé, et elle est différentes sur tous les axes
for (int di=1;di<= dima;di++)
{ int pt_adres = noe.Pointeur_assemblage(Enum_ddl(posi+di),cas_assemblage);
mat_masse(pt_adres,pt_adres) += mass_noeu_differencie(di);
};
break;
default:
cout << "\n *** erreur dans l'ajout de masses ponctuelles "
<< " cas non prevu \n Algori::Ajout_masses_ponctuelles(...";
Sortie(1);
break;
};
};
};
};
// ---- fin cas des masses concentrées -----
};
// définition de la matrice de viscosité numérique, dans le cas d'une approximation
// diagonale de la raideur, dans un calcul explicit
// la matrice masse doit être diagonale
// inita indique si l'on est dans une phase d'initialisation (creation de la matrice) ou non
// dans ce dernier cas il y a modification éventuelle des valeurs de C
// ramène un pointeur sur la matrice visqueuse instancié ou nul si aucune instantiation
Mat_abstraite* Algori::Cal_mat_visqueux_num_expli(const Mat_abstraite& mat_mass,Mat_abstraite* mat_C_pt
,const Vecteur & delta_X,bool inita, const Vecteur & vitesse)
{
#ifdef UTILISATION_MPI
// cas d'un calcul //, seule la matrice du CPU 0 est concernée
if (ParaGlob::Monde()->rank() != 0)
return mat_C_pt;
#endif
// on regarde s'il ne faut pas redimentionner la matrice:
// si inadéquation: on supprime la matrice C existante
if (inita)
{if (mat_C_pt != NULL)
{ if ((mat_mass.Type_matrice() != mat_C_pt->Type_matrice()) ||
(mat_mass.Nb_ligne() != mat_C_pt->Nb_ligne()))
delete mat_C_pt;
};
// maintenant création éventuelle
if (mat_C_pt == NULL)
{mat_C_pt = mat_mass.NouvelElement();}; // amortissement du même type que la masse
//idem avec la matrice de travail C_inter
if (C_inter != NULL)
{ if ((mat_mass.Type_matrice() != C_inter->Type_matrice()) ||
(mat_mass.Nb_ligne() != C_inter->Nb_ligne()))
delete C_inter;
};
// maintenant création éventuelle
if (C_inter == NULL)
C_inter = mat_mass.NouvelElement(); // amortissement du même type et de même valeur que la masse
// dimensionnement des forces int et ext mémorisée à l'itération précédente
F_int_tdt_prec.Change_taille(mat_C_pt->Nb_ligne());
F_ext_tdt_prec.Change_taille(mat_C_pt->Nb_ligne());
};
// on s'occupe maintenant des valeurs
switch (pa.Amort_visco_artificielle())
{case 1 : // cas d'un amortissement de Rayleigh classique
{if (inita)
{if ((ParaGlob::NiveauImpression() >= 0)&&((pa.CoefRayleighMasse()!= 1.)
||(pa.CoefRayleighRaideur()!=0.)))
{ cout << "\n ** ATTENTION : dans le cas d'un algorithme explicite avec un amortissement "
<< " de Rayleigh classique la matrice d'amortissement numerique [C] n'est construite"
<< " qu'avec la matrice masse selon : [C] = nu [M], ainsi le coefficient de"
<< " Rayleigh sur la raideur est impose a 0 et sur la masse a 1";
};
// on définit la matrice visqueuse en multipliant par la viscosité
(*mat_C_pt) = mat_mass; // assignation à la valeur de la masse
(*mat_C_pt) *= pa.Visco_artificielle();
};
break;
}
case 2 : // cas d'un amortissement en fonction de l'amortissement critique approché
// première méthode
{ if (inita)
{if (mat_mass.Type_matrice() != DIAGONALE)
{ cout << "\n erreur, la matrice masse doit etre diagonale ";
if (ParaGlob::NiveauImpression()>5)
cout << "\n Algori::Cal_mat_visqueux_num(...";
// dans le cas où un comptage du calcul est en cours on l'arrête
if (tempsCalEquilibre.Comptage_en_cours()) tempsCalEquilibre.Arret_du_comptage();
if (tempsInitialisation.Comptage_en_cours()) tempsInitialisation.Arret_du_comptage();
if (tempsMiseAjourAlgo.Comptage_en_cours()) tempsMiseAjourAlgo.Arret_du_comptage();
Sortie(1);
};
}; // fin initialisation
// calcul des termes de la matrice visqueuse
MatDiag & m_masse = *((MatDiag*) & mat_mass);
MatDiag & m_C = *((MatDiag*) mat_C_pt);
int mtaille = m_masse.Nb_ligne();
double eta = pa.Visco_artificielle();
double coef_limite_C = pa.BorneMaxiSurCfonctionDeLaMasse();
for (int i=1;i<=mtaille;i++)
{ double deltaxi=delta_X(i);
if (Dabs(deltaxi) <= ConstMath::petit) deltaxi = ConstMath::petit;
double m_masseii=m_masse(i,i);
double m_Cii =2.*sqrt(Dabs(m_masseii *(F_int_tdt(i)-F_int_t(i)+F_ext_tdt(i)-F_ext_t(i))/deltaxi));
// on limite la valeur
if (m_Cii > coef_limite_C * m_masseii)
m_Cii = coef_limite_C * m_masseii;
m_C(i,i)=eta * m_Cii; // on définit directement chaque terme
};
break;
}
case 3 : // cas d'un amortissement en fonction de l'amortissement critique approché
// deuxième méthode à l'aide du quotient de Rayleight sur les forces internes
// C = eta * 2. sqrt(lambda_0) * M, avec lambda_0 = DX^T * (delta_F_int) / DX^T M DX
// le delta_F_int est supposé = K_tangent DX
{
// --- calcul des termes de la matrice visqueuse
// on ne modifie la valeur de la matrice visqueuse, que s'il y a eu un déplacement, sinon on garde la valeur précédament stockée
if (delta_X.Norme() > ConstMath::trespetit)
{ double lambda_0 = ((delta_X * F_int_tdt) - (delta_X * F_int_t)) / mat_mass.vectT_mat_vec(delta_X , delta_X );
(*mat_C_pt) = mat_mass; // assignation à la valeur de la masse
// prise en compte des limitations
double coef = 2. * sqrt(lambda_0);
double coef_limite_C = pa.BorneMaxiSurCfonctionDeLaMasse();
if (coef > coef_limite_C)
coef = coef_limite_C;
(*mat_C_pt) *= (pa.Visco_artificielle() * coef);
};
break;
}
// ----------------- cas de l'amortissement critique utilisé par exemple avec les algo de relaxation dynamique ----------------
case 4 :
CalculEnContinuMatriceViscositeCritique(mat_mass,*mat_C_pt,delta_X,vitesse);
break;
// dans les autres cas on ne fait rien
};
return mat_C_pt; // retour de la matrice
};
// mise à jour du calcul de la viscosité critique en continu
// on ajoute la viscosité critique ce qui permet de cumuler avec de la viscosité numérique
void Algori::CalculEnContinuMatriceViscositeCritique(const Mat_abstraite& mat_mass,Mat_abstraite& mat_C_pt
,const Vecteur & delta_X, const Vecteur & vitesse)
{
#ifdef UTILISATION_MPI
// cas d'un calcul //, seule la matrice du CPU 0 est concernée
if (ParaGlob::Monde()->rank() != 0)
return ;
#endif
// ---- on commence par calculer (omega_0)^2 qui représente la plus basse fréquence
double omega02=0.; // init
switch (opt_cal_C_critique)
{case -1 : // version test : c= 0
{ omega02 = 0.; // pas de prise en compte de viscosité
break;
};
case 0 : // utilisation d'une approximation d'un quotient de Rayleigh
// (omega_0)^2 \approx (dot X^T Delta R_{i(statique)}^n) / (dot X^T M dot X)
{ // on ne calcule que s'il y a eu une vitesse non nulle, sinon on ne fait rien
if (vitesse.Norme() > ConstMath::trespetit)
omega02 = -((vitesse * F_int_tdt) - (vitesse * F_int_t)
+ (vitesse * F_ext_tdt) - (vitesse * F_ext_t)) / mat_mass.vectT_mat_vec(vitesse , vitesse );
break;
};
case 1 : // utilisation d'une approximation d'un quotient de Rayleigh
// (omega_0)^2 \approx (Delta X^T Delta R_{i(statique)}^n) / (Delta X^T M Delta X)
{ // on ne calcule que s'il y a eu un déplacement, sinon on ne fait rien
if (delta_X.Norme() > ConstMath::trespetit)
omega02 = -((delta_X * F_int_tdt) - (delta_X * F_int_t)
+ (delta_X * F_ext_tdt) - (delta_X * F_ext_t)) / mat_mass.vectT_mat_vec(delta_X , delta_X );
break;
};
case 2 : // utilisation d'une approximation d'un quotient de Rayleigh
// (omega_0)^2 \approx (dot X^T Delta R_{i(statique)}^n) / (dot X^T M dot X)
{ // on ne calcule que s'il y a eu une vitesse non nulle, sinon on ne fait rien
if (vitesse.Norme() > ConstMath::trespetit)
omega02 = -((vitesse * F_int_tdt) - (vitesse * F_int_tdt_prec)
+ (vitesse * F_ext_tdt) - (vitesse * F_ext_tdt_prec)) / mat_mass.vectT_mat_vec(vitesse , vitesse );
break;
};
default :
cout << "*** erreur le cas du coefficient opt_cal_C_critique= " << opt_cal_C_critique
<< " n'est pas pris actuellement en compte car cela signifie qu'il n'est pas defini !!, "
<< "\n *** peut-etre revoir les pararametres de l'algorithme *** , "
<< "\n Algori::CalculEnContinuMatriceViscositeCritique(..." << endl;
// dans le cas où un comptage du calcul est en cours on l'arrête
if (tempsCalEquilibre.Comptage_en_cours()) tempsCalEquilibre.Arret_du_comptage();
if (tempsInitialisation.Comptage_en_cours()) tempsInitialisation.Arret_du_comptage();
if (tempsMiseAjourAlgo.Comptage_en_cours()) tempsMiseAjourAlgo.Arret_du_comptage();
Sortie(1);
};
// on regarde pour les limitations de la valeur de omega_0^2 et on en déduit la valeur d'omega0
double omega0 = 0.;
int nbcar = ParaGlob::NbdigdoEC();
//.... debug
if (ParaGlob::NiveauImpression() >= 8)
cout << "\n omega02= " << setprecision(nbcar)<< omega02
<< " llF_int_tdtll= " << setprecision(nbcar)<< F_int_tdt.Norme()
<< " llF_int_tll= " << setprecision(nbcar)<< F_int_t.Norme() << endl;
//.... fin debug
if (omega02 < 0.)
{ omega0 = 0.; }
else if (omega02 > (f_ * f_ * 4.))
{ omega0 = f_ * 2.; }
else { omega0 = sqrt(omega02);};
// ---- maintenant on calcul une viscosité critique globale
double viscosite = 0.;
switch (type_calcul_visqu_critique)
{ case 1: // cas de la méthode historique d'Underwood C_{ii} += c * M_{ii} et c = 2 * omega_0
{ viscosite = (omega0 * 2.);
break;
}
case 2: // Pajand: la matrice C est calculee selon: C_{ii} = c * M_{ii}, avec c = sqrt( 4*omega_0^2 - omega_0^4)
{ double coef = 4.* PUISSN(omega0, 2) - PUISSN(omega0, 4);
if (coef < 0.)
{ if (ParaGlob::NiveauImpression() > 7)
cout << "\n *** attention la grandeur ( 4*omega_0^2 - omega_0^4)= "
<< coef << " est negative, on la met a 0 ";
coef = 0.;
};
viscosite = sqrt(coef);
break;
}
case 3: // la matrice C est calculee selon: C_{ii} = c * M_{ii}, avec c = 2*sqrt(omega_0/(1+omega_0))
{ double coef = omega0/(1.+ omega0);
if (coef < 0.)
{ if (ParaGlob::NiveauImpression() > 7)
cout << "\n *** attention la grandeur omega_0/(1+omega_0)= "
<< coef << " est negative, on la met a 0 ";
coef = 0.;
}
viscosite = sqrt(coef);
break;
}
default:
{ cout << "\n **** erreur le cas type_calcul_visqu_critique= " << type_calcul_visqu_critique
<< " n'est pas pris actuellement en compte car cela signifie qu'il n'est pas defini !!, "
<< "\n *** peut-etre revoir les pararametres de l'algorithme *** , "
<< "\n Algori::CalculEnContinuMatriceViscositeCritique( ... ";
// dans le cas où un comptage du calcul est en cours on l'arrête
if (tempsCalEquilibre.Comptage_en_cours()) tempsCalEquilibre.Arret_du_comptage();
if (tempsInitialisation.Comptage_en_cours()) tempsInitialisation.Arret_du_comptage();
if (tempsMiseAjourAlgo.Comptage_en_cours()) tempsMiseAjourAlgo.Arret_du_comptage();
Sortie(1);
};
};
// affichage éventuelle de la viscosité
if (ParaGlob::NiveauImpression() >= 7)
{ cout << "\n viscosite c= " << setprecision(nbcar)<< viscosite << endl ;
cout << endl;
};
// ---- maintenant on va calculer la matrice visqueuse: C_{ii} += c * M_{ii}
//-- cas ou on cumulait, abandonné actuellement
// (*C_inter) = mat_mass;
// (*C_inter) *= viscosite * ampli_visco;
// mat_C_pt += (*C_inter);
//-- cas ou on cumulait, abandonné actuellement
mat_C_pt = mat_mass;
mat_C_pt *= viscosite * ampli_visco;
};
// calcul de l'impact d'une viscosité artificielle sur la raideur et sur le second membre
// l'algo travaille avec les vecteurs: delta_X, var_delta_X, et vitesse stockés dans Algori
// l'algo modifie mat_glob et calcul les forces visqueuses
void Algori::Cal_mat_visqueux_num_stat(Mat_abstraite& mat_glob,Vecteur& forces_vis_num)
{
#ifdef UTILISATION_MPI
// cas d'un calcul //, seule la matrice du CPU 0 est concernée
if (ParaGlob::Monde()->rank() != 0)
return ;
#endif
// le fonctionnement n'est pas identique au cas explicite
switch (pa.Amort_visco_artificielle())
{case 1 : // cas d'un amortissement de Rayleigh classique
{// ici on n'utilise que la matrice de raideur qui est la seule connue en statique
// K -> K*(1.-nu/delta_t)
// recup de l'incrément de temps
double deltat=ParaGlob::Variables_de_temps().IncreTempsCourant();
double unSurDeltat=0;
if (Abs(deltat) >= ConstMath::trespetit)
{unSurDeltat = 1./deltat;}
else
// si l'incrément de temps est tres petit on remplace 1/deltat par un nombre tres grand
{ // un pas de temps doit être positif !! or certaine fois il peut y avoir des pb
if (unSurDeltat < 0)
{ cout << "\n le pas de temps est négatif !! "; };
unSurDeltat = ConstMath::tresgrand;
};
//CoefRayleighRaideur()
// on calcul les forces visqueuses
// ici il s'agit de force qui dépendent de la variation de delta_X d'une itération à l'autre
// cela ne doit pas être très stable mais ... à voir
// mais à convergence, les forces ne sont plus actives puisque var_delta_X = 0
mat_glob.Prod_mat_vec(
// ((-pa.Visco_artificielle()*unSurDeltat)*var_delta_X + (-pa.CoefRayleighRaideur()*unSurDeltat)*delta_X)
((pa.Visco_artificielle()*var_delta_X )+ (pa.CoefRayleighRaideur()*unSurDeltat)*delta_X)
,forces_vis_num);
// calcul de la nouvelle matrice de raideur qui tient compte des forces visqueuse
// mat_glob *= (1.+pa.Visco_artificielle()*unSurDeltat+pa.CoefRayleighRaideur()*unSurDeltat);
mat_glob *= (1.-pa.Visco_artificielle()-pa.CoefRayleighRaideur()*unSurDeltat);
break;
}
// dans les autres cas on ne fait rien
default:
if (ParaGlob::NiveauImpression()>0)
cout << "\n attention on cherche a utiliser de l'amortissement visqueux de type "
<< pa.Amort_visco_artificielle()
<< " celui-ci n'est pas disponible en statique, on n'en tient pas compte ! " << flush;
};
};