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

408 lines
20 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 "MatBand.h"
#include "Assemblage.h"
#include "ElemMeca.h"
// ------ fait partie de la classe Algori -----------
// initialisation du calcul de la remontée des contraintes aux noeuds
// initialisation valable également dans le cas où aucun calcul n'a précédé ce calcul
void Algori::InitRemontSigma(LesMaillages * lesMail,LesReferences* lesRef,
DiversStockage* ,Charge* ,
LesCondLim* lesCondLim,LesContacts* ,Resultats* )
{//mise en place des coordonnées à t, qui sont nécessaire pour calculer les éléments
// géométriques sur une pièce déformée, même si les ddl sont autres que les déplacements
// dans le cas où les coordonnées existent déjà, il n'y a aucune modification
lesMail->Insert_coord1();
// l'idée ici est d'initialiser la gestion d'un nouveau groupe de ddl
// ==== 1 - on commence par inactiver les ddl qui sont en cours
lesMail->Inactive_ddl();
// ==== 2 - on définit un nouveau groupe de ddl avec la gestion rapide associé
// introduction des ddl de contraintes (s'ils n'existent pas déjà sinon aucune action)
lesMail->Plus_ddl_Sigma();
////--- debug
//cout << "\n debug Algori::InitRemontSigma ";
//lesMail->Noeud_LesMaille(1,1).Affiche(1);
//cout << endl;
////--- fin debug
// mise a zero des ddl actifs et on laisse les ddl à t+dt
// mais il faut d'abord activer les ddl sigma
lesMail->Active_ddl_Sigma();
// le deuxième paramètre de ZeroDdl est false pour indiquer que les coordonnées à t
// ne sont pas à initialiser aux valeurs à t = 0, ceci permet par exemple de travailler
// sur une structure déformée si elle a été calculée auparavant
lesMail->ZeroDdl(true,false); // mise à jour de tous les ddl actifs sauf de déplacement
// ==== 3 - def de l'assemblage pour tous les ddl de type sigma
nbddl_sigeps = lesMail->NbTotalDdlActifs(); // nb total de ddl de sigma
// on définit un nouveau cas de second membre
// à travers la définition d'une instance de la classe assemblage
// si elle existe déjà on l'utilise directement
if (cas_ass_sig == NULL)
// cas où les conteneurs sont à créer
{ cas_ass_sig = new Nb_assemb(lesMail->InitNouveauCasAssemblage(1));
Ass_sig = new Assemblage(*cas_ass_sig);
}
// mise a jour des pointeurs d'assemblage
lesMail->MiseAJourPointeurAssemblage(Ass_sig->Nb_cas_assemb());
// ==== 4 - def de l'assemblage pour tous les ddl de type sigma11 uniquement (c-a-d le premier ddl)
// on rend actif le premier ddl mécanique, en fait on se servira des
//autres qui sont supposé être à la suite mais pour éviter d'avoir une
//grosse matrice de raideur le second membre est décomposé en plusieurs
//SM, chacun relatif à "un" ddl de contrainte
lesMail->Inactive_ddl_Sigma();
lesMail->Active_premier_ddl_Sigma();
// récup du nombre de composantes du tenseur de contrainte en absolu
int nbcomposante = ParaGlob::NbCompTens ();
nbddl_sigeps11 = lesMail->NbTotalDdlActifs(SIG11) / nbcomposante; // nb total de ddl de sigma11
// on définit un nouveau cas de second membre
// à travers la définition d'une instance de la classe assemblage
// si elle existe déjà on l'utilise directement
if (cas_ass_sig11 == NULL)
// cas où les conteneurs sont à créer
{ cas_ass_sig11 = new Nb_assemb(lesMail->InitNouveauCasAssemblage(1));
Ass_sig11 = new Assemblage(*cas_ass_sig11);
}
// mise a jour des pointeurs d'assemblage
lesMail->MiseAJourPointeurAssemblage(Ass_sig11->Nb_cas_assemb());
// ==== 5 - définition de la matrice pour la résolution du problème de minimisation
// dans le cas où c'est déjà fait on ne change rien
if (mat_glob_sigeps == NULL)
//on est obligé de faire une petite manipe avec un tableau, car l'appel à changé
{ Tableau < Mat_abstraite*> tab_inter(1); tab_inter(1)=NULL;
Choix_matriciel(nbddl_sigeps11,tab_inter,lesMail,lesRef
,Ass_sig11->Nb_cas_assemb(),lesCondLim);
mat_glob_sigeps = tab_inter(1);
};
// choix de la résolution
mat_glob_sigeps->Change_Choix_resolution(pa.Type_resolution(),pa.Type_preconditionnement());
// def du tableau de seconds membres globaux avec initialisation à zéro
if (vglob_sigeps == NULL)
vglob_sigeps = new Tableau <Vecteur> (nbcomposante,Vecteur(nbddl_sigeps11));
// définition du vecteur global de tous les ddl de sigma
if (vglobal_sigeps == NULL)
vglobal_sigeps = new Vecteur(nbcomposante*nbddl_sigeps11);
};
// initialisation du calcul de la remontée des déformations aux noeuds
// initialisation valable également dans le cas où aucun calcul n'a précédé ce calcul
void Algori::InitRemontEps(LesMaillages * ,LesReferences* ,
DiversStockage* ,Charge* ,
LesCondLim* ,LesContacts* ,Resultats* )
{// pour l'instant rien
};
// initialisation du calcul d'erreur aux éléments
// initialisation valable également dans le cas où aucun calcul n'a précédé ce calcul
void Algori::InitErreur(LesMaillages * lesMail,LesReferences* ,
DiversStockage* ,Charge* ,
LesCondLim* ,LesContacts* ,Resultats* )
{// pour la remontée des valeurs aux noeuds
// l'idée ici est d'initialiser la gestion d'un nouveau groupe de ddl
// ==== 1 - on commence par inactiver les ddl qui sont en cours
lesMail->Inactive_ddl();
// ==== 2 - on définit un nouveau groupe de ddl avec la gestion rapide associé
// introduction des ddl d'erreur (s'ils n'existent pas déjà sinon aucune action)
lesMail->Plus_ddl_Erreur();
// activation des ddl Erreur
lesMail->Active_ddl_Erreur();
// mise a zero des ddl actifs et on laisse les ddl à t+dt
// le deuxième paramètre de ZeroDdl est false pour indiquer que les coordonnées à t
// ne sont pas à initialiser aux valeurs à t = 0, ceci permet par exemple de travailler
// sur une structure déformée si elle a été calculée auparavant
lesMail->ZeroDdl(true,false); // mise à jour de tous les ddl actifs sauf de déplacement
// ==== 3 - def de l'assemblage pour tous les ddl de type erreur
nbddl_err= lesMail->NbTotalDdlActifs(); // nb total de ddl d'erreur
// on définit un nouveau cas de second membre
// à travers la définition d'une instance de la classe assemblage
// si elle existe déjà on l'utilise directement
if (cas_ass_err == NULL)
// cas où les conteneurs sont à créer
{ cas_ass_err = new Nb_assemb(lesMail->InitNouveauCasAssemblage(1));
Ass_err = new Assemblage(*cas_ass_err);
}
// mise a jour des pointeurs d'assemblage
lesMail->MiseAJourPointeurAssemblage(Ass_err->Nb_cas_assemb());
// ==== 4 - définition de la matrice pour la résolution du problème de minimisation
// dans le cas où c'est déjà fait on ne change rien
// ici contrairement au cas des contraintes où des déformations, on considère qu'il y a déjà eu
// la remonté des contraintes, qui est obligatoire pour calculer l'erreur aux éléments qui elle est
// obligatoire pour calculer l'erreur aux noeuds => on utilise la même matrice de raideur
if (mat_glob_sigeps == NULL)
{ cout << "\n erreur la remontee des contraintes n'a pas ete faite, on ne peut pas continuer"
<< "\n Algori::InitErreur(...";
Sortie(1);
};
// def du tableau du second membre global avec initialisation à zéro
// on utilise la place de celui utilisé pour sigma
if (vglob_sigeps == NULL)
{ cout << "\n erreur la remontee des contraintes n'a pas ete faite, on ne peut pas continuer"
<< "\n Algori::InitErreur(...";
Sortie(1);
};
};
// calcul de la remontée des contraintes aux noeuds
void Algori::RemontSigma(LesMaillages * lesMail)
{ // affichage
if (ParaGlob::NiveauImpression() >= 2 )
cout << "\n================================================================="
<< "\n REMONTEE DES CONTRAINTES AUX NOEUDS "
<< "\n=================================================================\n";
lesMail->Inactive_ddl(); // inactive les ddl en cours
// mise a zero des ddl actifs et on laisse les ddl à t+dt
// mais il faut d'abord activer les ddl sigma
lesMail->Active_ddl_Sigma();
// le deuxième paramètre de ZeroDdl est false pour indiquer que les coordonnées à t
// ne sont pas à initialiser aux valeurs à t = 0, ceci permet par exemple de travailler
// sur une structure déformée si elle a été calculée auparavant
lesMail->ZeroDdl(true,false);
// on rend actif le premier ddl mécanique, en fait on se servira des
//autres qui sont supposé être à la suite mais pour éviter d'avoir une
//grosse matrice de raideur le second membre est décomposé en plusieurs
//SM, chacun relatif à "un" ddl de contrainte
lesMail->Inactive_ddl_Sigma();
lesMail->Active_premier_ddl_Sigma();
// def du nombre de composantes du tenseur de contrainte en absolu
int nbcomposante = ParaGlob::NbCompTens ();
// pour simplifier
Mat_abstraite& matglob = *mat_glob_sigeps;
mat_glob_sigeps->Initialise(0.);
Tableau <Vecteur>& vglob = *vglob_sigeps;
Vecteur& vglobal = *vglobal_sigeps;
vglobal_sigeps->Zero();
// ----- Calcul de la raideur et des seconds membres
Tableau <Vecteur> * sol; // pointeur du vecteur solution
// boucle sur les elements
int nbMaillage = lesMail->NbMaillage();
for (int nbMail =1; nbMail<= nbMaillage; nbMail++)
{int nbelement = lesMail->Nombre_element(nbMail);
for (int ne=1; ne<= nbelement;ne++)
{
// calcul du résidu et de la matrice de raideur pour le calcul d'erreur
ElemMeca & el = *((ElemMeca*) &lesMail->Element_LesMaille(nbMail,ne)); // l'element
Element::Er_ResRaid resu = el.ContrainteAuNoeud_ResRaid();
Tableau<Noeud *>& taN = el.Tab_noeud(); // tableau de noeuds de l'el
// création du tableau d'un ddl SIG11, pour chaque noeud concerné des
// élément traité
const DdlElement& TabDdl = el.Tableau_de_Sig1() ;
// assemblage de la raideur
Ass_sig11->AssembMatSym (matglob,*(resu.raidErr),TabDdl,taN); // de la raideur
// assemblage des seconds membres
Ass_sig11->AssemSM (vglob,*(resu.resErr),TabDdl,taN); // du second membre
// cout << "numéro =" << ne << endl;
// (resu.res)->Affiche();
// (resu.raid)->Affiche();
// assemblage
};
};
// affichage éventuelle de la matrice de raideur et du second membre
if (ParaGlob::NiveauImpression() >= 10)
{ string entete = " affichage de la matrice de raideur pour le calcul d'erreur ";
matglob.Affichage_ecran(entete);
entete = " affichage du second membre nb= ";
int nbsm = vglob.Taille();
for (int i=1;i<=nbsm;i++)
vglob(i).Affichage_ecran(entete + ChangeEntierSTring(i) +" ");
};
//------------- resolution -----------------
// matglob.Affiche1(1,6,1,1,6,1);
// for (int i=1;i<= vglob.Taille();i++)
// vglob(i).Affiche();
// vglobal.Affiche();
// cout << "\n entree une lettre"; int toto; cin >> toto;
// ici sol en fait = vecglob qui est ecrase par la resolution
// la résolution se fait en deux temps pour que la même matrice de raideur puisse servir plusieur fois
matglob.Preparation_resol(); // préparation
sol = &(matglob.Simple_Resol_systID(vglob)); // résolution sans modification de la matrice de raideur
// affichage éventuelle de la solution
if (ParaGlob::NiveauImpression() >= 10)
{ string entete = " affichage de la solutions pour le calcul d'erreur ";
entete = " affichage de la composante nb= ";
int nbsm = vglob.Taille();
for (int i=1;i<=nbsm;i++)
(*sol)(i).Affichage_ecran(entete + ChangeEntierSTring(i) +" ");
};
// sol = &(matglob.Resol_systID(vglob));
// sol->Affiche();
////---debug
// cout << "\n debug Algori::RemontErreur ";
// (*sol)(1).Affiche();
// (*sol)(2).Affiche();
// (*sol)(3).Affiche();
//// (*sol)(4).Affiche();
//// (*sol)(5).Affiche();
//// (*sol)(6).Affiche();
cout << endl;
////---fin debug
// ------------- résultat transféré dans les noeuds ---------
// construction du vecteur avec tous les ddl sigma
int iposition = 1;
for (int j=1; j<= nbddl_sigeps11; j++)
for (int i=1;i<=nbcomposante;i++,iposition++)
vglobal(iposition) = vglob(i)(j);
// activation de tous les ddl sigma
lesMail->Active_ddl_Sigma();
// modif 6 nov 2014
// // actualisation de tous les sigma a t
lesMail->PlusDelta_t(vglobal,Ass_sig->Nb_cas_assemb());
// actualisation de tous les sigma a tdt, et on passe les info
// car c'est les grandeurs de tdt qui sont visualisées !
lesMail->ChangeDdla_tdt(vglobal,Ass_sig->Nb_cas_assemb());
// fin des calculs
};
// calcul de la remontée des contraintes aux
// noeuds, puis de l'erreur, après un calcul de mécanique.
// calcul de la remontée des déformations aux noeuds
void Algori::RemontEps(LesMaillages * )
{// pour l'instant rien
};
void Algori::RemontErreur(LesMaillages * lesMail)
{
if (ParaGlob::NiveauImpression() >= 2 )
cout << "\n=========================================================================="
<< "\n CALCUL D'ERREUR AUX ELEMENTS ET REMONTEE DES VALEURS AUX NOEUDS "
<< "\n=========================================================================\n ";
// 1) Calcul de l'erreur sur chaque élément
// type indique le type d'erreur retenue
// type = 1 : cas d'un calcul aux moindres carrés
// et retour de l'erreur relative totale sur les maillages en cours
int type = 1;
// Calcul de l'erreur sur l'ensemble des éléments
// type indique le type d'erreur retenue
// type = 1 : cas d'un calcul aux moindres carrés
// et retour un tableau de tableau de grandeurs sur les maillages en cours
// ret(i) : concerne le maillage i
// ret(i)(1) : somme des erreurs sur l'ensemble des éléments: est homogêne à
// un |delta contrainte| * domaine
// ret(i)(2) : somme de la grandeur de ref du calcul d'erreur sur l'ensemble des
// éléments: est homogêne à une |contrainte| * domaine
// ret(i)(3) : le maxi pour les tous les éléments de |delta contrainte| * domaine
// ret(i)(4) : le maxi pour les tous les éléments de |contrainte| * domaine
// ret(i)(5) : le maxi pour les tous les éléments de l'erreur relative
Tableau <Tableau <double > > ret(lesMail->ErreurSurChaqueElement(type));
if (ParaGlob::NiveauImpression() >= 2 )
{int nbmaillage = ret.Taille();
for (int i=1;i<=nbmaillage;i++)
{cout << "\n --- maillage: "<<i
<< "\n cumul des erreurs sur les elements: " << ret(i)(1)
<< " versus cumul de la |grandeur| observee = "<< ret(i)(2)
<< "\n ==> erreur cumulee relative= "<<ret(i)(1)/MaX(ret(i)(3), ConstMath::trespetit)
<< "\n |maxi| sur les elements de l'erreur= "<< ret(i)(3)
<< " versus |maxi| sur les element de la |grandeur| observee = "<< ret(i)(4)
<< "\n ==> maxi de l'erreur relative sur les element = "<<ret(i)(5)
<< '\n';
};
};
// 2) remontée des valeurs aux noeuds
// on inactive les ddl
lesMail->Inactive_ddl();
// activation des ddl Erreur
lesMail->Active_ddl_Erreur();
// mise a zero des ddl actifs et on laisse les ddl à t+dt
lesMail->ZeroDdl(true,false);
// mise a jour des pointeurs d'assemblage
lesMail->MiseAJourPointeurAssemblage(Ass_err->Nb_cas_assemb());
// pour le second membre on utilise le premier vecteur de second membre utilisé
// pour les contraintes : vglob(1) et localement resu.resErr(1)
// on ne recalcule pas la raideur, mais on utilise celle calculée lors de la résolution
// pour les contraintes. Il y a sauvegarde de la matrice de raideur lors de la
// résolution, on peut donc la réutiliser.
// ----- Calcul du second membre
// on commence par initialiser le second membre à zero
Vecteur & vgloberr = (*vglob_sigeps)(1);
vgloberr.Zero();
Mat_abstraite& matglob = *mat_glob_sigeps;
// boucle sur les elements
int nbMaillage = lesMail->NbMaillage();
for (int nbMail =1; nbMail<= nbMaillage; nbMail++)
{int nbelement = lesMail->Nombre_element(nbMail);
for (int ne=1; ne<= nbelement;ne++)
{
// calcul du résidu
ElemMeca & el = *((ElemMeca*) &lesMail->Element_LesMaille(nbMail,ne)); // l'element
Element::Er_ResRaid resu = el.ErreurAuNoeud_ResRaid();
Tableau<Noeud *>& taN = el.Tab_noeud(); // tableau de noeuds de l'el
// assemblage du second membre
Ass_err->AssemSM (vgloberr,*((*(resu.resErr))(1)),el.Tableau_de_ERREUR(),taN);
// cout << "numéro =" << ne << endl;
// (resu.res)->Affiche();
// (resu.raid)->Affiche();
// assemblage
}
}
//------------- resolution -----------------
// matglob.Affiche(1,4,1,1,4,1);
// for (int i=1;i<= vglob.Taille();i++)
// vglob(i).Affiche();
// matglob.Affiche(1,8,1,7,8,1);
// matglob.Affiche(1,18,1,13,18,1);
// Vecteur * solEr = &(matglob.Resol_systID_sans_triangul(vglob(1)));
Vecteur * solEr = &(matglob.Simple_Resol_systID(vgloberr)); // résolution sans modification de la matrice de raideur
////---debug
// cout << "\n debug Algori::RemontErreur ";
// solEr->Affiche();
// cout << endl;
////---fin debug
// sol->Affiche();
// ------------- résultat transféré dans les noeuds ---------
// actualisation des ddl actifs a t
lesMail->PlusDelta_t(*solEr,Ass_err->Nb_cas_assemb());
// inactivation des ddl d'erreur
lesMail->Inactive_ddl_Erreur();
// fin des calculs
};