880 lines
37 KiB
C++
880 lines
37 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-2021 Université Bretagne Sud (France)
|
|
// AUTHOR : Gérard Rio
|
|
// E-MAIL : gerardrio56@free.fr
|
|
//
|
|
// This program is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License,
|
|
// or (at your option) any later version.
|
|
//
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty
|
|
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
// See the GNU General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
//
|
|
// For more information, please consult: <https://herezh.irdl.fr/>.
|
|
|
|
#include "CondLim.h"
|
|
#include "ConstMath.h"
|
|
|
|
// ---------- variables globales ------------
|
|
// déclaration d'une variable de travail, utilisée par CondlineaireCHRepere
|
|
Mat_pleine CondLim::matinter(1,1);
|
|
// ---------- fin variables globales ------------
|
|
|
|
// contructeur
|
|
CondLim::CondLim() :
|
|
VImpSM(),VImpRaid()
|
|
{ };
|
|
// destructeur
|
|
CondLim::~CondLim()
|
|
{ };
|
|
// concernant les sous class
|
|
CondLim::ImpRaid::ImpRaid() : // part defaut
|
|
ligne(),colonne()
|
|
{};
|
|
CondLim::ImpRaid::ImpRaid(int i,const Vecteur& vL,const Vecteur& vC,double val) : // entree nomale
|
|
ilicol(i), ligne(vL),colonne(vC),valeur(val)
|
|
{};
|
|
CondLim::ImpRaid::ImpRaid(const ImpRaid & a) :
|
|
ilicol(a.ilicol), ligne(a.ligne),colonne(a.colonne),valeur(a.valeur)
|
|
{};
|
|
CondLim::ImpRaid& CondLim::ImpRaid::operator=(const ImpRaid& a) // assigment
|
|
{ this->ilicol = a.ilicol; this->ligne = a.ligne; this->colonne = a.colonne;
|
|
this->valeur = a.valeur;
|
|
return *this;
|
|
};
|
|
|
|
CondLim::ImpSM& CondLim::ImpSM::operator=(const ImpSM& a) // assigment
|
|
{ this->iligne = a.iligne; this->valeur = a.valeur;
|
|
return *this;
|
|
};
|
|
|
|
// valeur imposee au second membre
|
|
// vecglob : le second membre, i : la position globale du ddl impose
|
|
// val : la valeur a imposer
|
|
// vec2 : est un second vecteur éventuel (si != NULL) sur lequel on impose les mêmes CL que vecglob
|
|
// mais sans sauvegarde (correspond par exemple à une partie de vecglob)
|
|
void CondLim::Val_imposee_Sm(Vecteur& vecglob,int i,double val,Vecteur* vec2)
|
|
{ // on sauvegarde la valeur du second membre existante et on remplace
|
|
// par le ddl impose
|
|
ImpSM sauv(i,vecglob(i));
|
|
VImpSM.push_back(sauv);
|
|
vecglob(i) = val;
|
|
if (vec2 != NULL)
|
|
(*vec2)(i) = val;
|
|
};
|
|
// valeur imposee a la matrice et au second membre si la valeur est
|
|
// differente de zero
|
|
// matglob : la matrice, i : la position globale du ddl impose
|
|
// val : la valeur a imposer
|
|
// vec2 : est un second vecteur éventuel (si != NULL) sur lequel on impose les mêmes CL que vecglob
|
|
// mais sans sauvegarde (correspond par exemple à une partie de vecglob)
|
|
void CondLim::Val_imposee_Mat(Mat_abstraite & matglob,Vecteur& vecglob,
|
|
int i,double val,Vecteur* vec2)
|
|
{// on sauvegarde la ligne et la colonne de la matrice, correspondant
|
|
// au ddl impose
|
|
Vecteur vL = matglob.LigneSpe(i);
|
|
Vecteur vC = matglob.ColonneSpe(i);
|
|
ImpRaid sauv(i,vL,vC,vecglob(i)); // on sauvegarde la réaction
|
|
VImpRaid.push_back(sauv);
|
|
|
|
// on impose sur la matrice et on met les répercussions sur le second membre, mais
|
|
// on n'impose pas sur le second membre à ce stade, car en fait la valeur imposer
|
|
// pourrait éventuellement encore changer (sans doute non, car les coeff hors diag sont
|
|
// maintenant nul, mais on laisse quand même le système à deux temps)
|
|
if (val != 0.) // cas ou il faut modifier le second membre
|
|
{ vecglob -= val*matglob.Colonne(i); // recup de la colonne et modif
|
|
if (vec2 != NULL)
|
|
*vec2 -= val*matglob.Colonne(i);
|
|
|
|
// je crois que la ligne d'après est fausse, car là on applique la cl, alors que l'objet de la routine concerne uniquement la matrice
|
|
// et les répercussions sur le second membre. Si val est diff de 0, vecglob(i) va changer et la valeur sauvegardé ensuite par
|
|
// CondLim::Val_imposee_Sm( ne sera pas bonne
|
|
// vecglob(i) = val; // mais a jour le second membre
|
|
|
|
};
|
|
matglob.MetValLigne(i,0.); // mise de la ligne
|
|
matglob.MetValColonne(i,0.); // et de la colonne a zero
|
|
matglob(i,i) = 1.; // puis l'element diagonnal = 1
|
|
};
|
|
// cas particulier de valeur imposee a une matrice
|
|
// c'a-dire val sur la diagonale
|
|
// matglob : la matrice, i : la position globale du ddl impose
|
|
// dans ce cas-ci il n'y a aucune information sauvegardée, des valeurs modifiées
|
|
// cela signifie qu'après cette fonction, les appels aux routines pour la
|
|
// remontée aux réactions, n'ont aucun sens
|
|
void CondLim::Val_imposSimple_Mat(Mat_abstraite & matglob,int i,double val)
|
|
{matglob.MetValLigne(i,0.); // mise de la ligne
|
|
matglob.MetValColonne(i,0.); // et de la colonne a zero
|
|
matglob(i,i) = val; // puis l'element diagonnal = 1
|
|
};
|
|
// remontee aux efforts apres resolution
|
|
// ceci pour la ligne i, dans le cas d'un ddl bloque
|
|
double CondLim::RemonteDdlBloqueMat(Mat_abstraite & matglob,Vecteur& solution, int iligne)
|
|
{ // on boucle sur le container pour retrouver le ddl
|
|
bool cherche = false;
|
|
list <ImpRaid>::iterator ip;
|
|
for (ip = VImpRaid.begin();ip != VImpRaid.end(); ip++)
|
|
if ((*ip).ilicol == iligne)
|
|
{ matglob.RemplaceLigneSpe(iligne,(*ip).ligne);
|
|
return matglob.Prod_Ligne_vec (iligne,solution);
|
|
cherche = true;
|
|
};
|
|
if (cherche != true)
|
|
{ cout << "\n par d effort sur ce ddl nb = " << iligne;
|
|
cout << "\n double CondLim::RemonteDdlBloqueMat ( etc ..." << endl;
|
|
};
|
|
return 0.;
|
|
};
|
|
|
|
// retourne le maxi des efforts exterieurs
|
|
double CondLim::MaxEffort(int & ili)
|
|
{ double res = 0;
|
|
ili = 1;
|
|
list <ImpSM>::iterator ip;
|
|
for (ip = VImpSM.begin();ip != VImpSM.end(); ip++)
|
|
if (Abs((*ip).valeur) > res)
|
|
{res = Abs((*ip).valeur);
|
|
ili = (*ip).iligne;
|
|
}
|
|
return res;
|
|
};
|
|
|
|
// retourne la valeur initiale au second membre avant condition limite
|
|
// en fonction du pointeur d'assemblage
|
|
double CondLim::ValReact(int & ili)
|
|
{ list <ImpSM>::iterator ip;
|
|
for (ip = VImpSM.begin();ip != VImpSM.end(); ip++)
|
|
if ((*ip).iligne == ili )
|
|
{ return (*ip).valeur;
|
|
}
|
|
// on n'a rien trouver
|
|
cout << "\n erreur la ligne demandee ne correspond pas a un ddl bloque ";
|
|
cout << "\n CondLim::ValReact(int & ili) ";
|
|
Sortie (1);
|
|
|
|
return 0.; // pour pas avoir de message a la compile
|
|
|
|
};
|
|
//----- cas de conditions limites lineaires entre plusieurs ddl-----
|
|
|
|
// class qui permet d'enregistrer le changement de repere
|
|
CondLim::lineaires::lineaires () : // par defaut
|
|
val(),pt()
|
|
{ indice = 0; valeur = 0.; };
|
|
CondLim::lineaires::lineaires (int i,const Vecteur& vL,const Tableau<int> & ptt,double vale):
|
|
indice(i),val(vL),pt(ptt), valeur(vale)
|
|
{};
|
|
CondLim::lineaires::lineaires (const lineaires & a) : // constructeur de copie
|
|
indice(a.indice),val(a.val),pt(a.pt),valeur(a.valeur)
|
|
{};
|
|
CondLim::lineaires& CondLim::lineaires::operator=(const lineaires& a) // assigment
|
|
{ this->indice = a.indice; this->val = a.val;this->pt = a.pt;this->valeur = a.valeur;
|
|
return *this; };
|
|
|
|
// premier temps : on prépare la mise en place de la condition par un changement
|
|
// de repère sur la matrice et sur le second membre
|
|
// pt : tableau des pointeurs de ddl concerne, pt(i) = la position du ddl i
|
|
// dans la matrice globale
|
|
// val : tableau des coefficients de la condition lineaire
|
|
// valeur : valeur a laquelle est egale la condition lineaire
|
|
// cond lineaire -> somme des val(i) * ddl(pt(i)) = valeur
|
|
// la procedure modifie les reperes d'expression des ddl, mais sauvegarde
|
|
// les infos permettant de reconstruire les reperes initiaux
|
|
// vec2 : est un second vecteur éventuel (si != NULL) sur lequel on impose les mêmes CL que vecglob
|
|
// mais sans sauvegarde (correspond par exemple à une partie de vecglob)
|
|
void CondLim::CondlineaireCHRepere(Mat_abstraite & matglob,Vecteur& vecglob,
|
|
const Tableau<int> & pt,const Vecteur& val, double valeur,Vecteur* vec2)
|
|
{
|
|
// //--- debug
|
|
// cout << "\n CondLim::CondlineaireCHRepere ";
|
|
// cout << "\n valeur = " << valeur << " val= " << val << " pt= " << pt << endl ;
|
|
// //--- fin debug
|
|
|
|
// on commence par normer la condition limite
|
|
int tail = pt.Taille();
|
|
double norme = val.Norme();
|
|
if ( norme <= ConstMath::trespetit )
|
|
{ cout << "\n erreur , la condition lineaire est formee de coefficients nulles !! ";
|
|
cout << "\n CondLim::Condlineaire( etc ... " << endl;
|
|
Sortie(1);
|
|
};
|
|
// norme = 1. ; // pour le débug !!!
|
|
// ==->par construction le premier indice correspond a la direction a bloquer
|
|
// --ici dans la normalisation je pense qu'il y a un pb donc on supprime momentanément
|
|
// double unsurnorme = 1. / norme ;
|
|
// valeur *= unsurnorme;
|
|
// --
|
|
//norme = 1;
|
|
// ancienne méthode : calcul du vecteur V
|
|
// val *= unsurnorme ;
|
|
// Vecteur V = -val/val(1);
|
|
// V(1) = 1./val(1);
|
|
// nouvelle méthode : calcul du vecteur V
|
|
Vecteur V(val);
|
|
V /= (-val(1));
|
|
V(1) = 1 / val(1);
|
|
// V(1) = norme / val(1);
|
|
|
|
// modif du vecteur en Vprime
|
|
V(1) -= 1.;
|
|
// calcul de la matrice de raideur modifiee: pour l'instant ne fonctionne que pour des matrices carrees ou bandes
|
|
|
|
// //--- debug
|
|
// cout << "\n CondLim::CondlineaireCHRepere ";
|
|
// cout << "\n V= " << V << endl ;
|
|
// //--- fin debug
|
|
#ifdef MISE_AU_POINT
|
|
if ((matglob.Type_matrice() != CARREE) && (matglob.Type_matrice() != CARREE_SYMETRIQUE)
|
|
&& (matglob.Type_matrice() != BANDE_SYMETRIQUE) && (matglob.Type_matrice() != BANDE_NON_SYMETRIQUE)
|
|
&& (matglob.Type_matrice() != BANDE_NON_SYMETRIQUE_LAPACK)
|
|
&& (matglob.Type_matrice() != BANDE_SYMETRIQUE_LAPACK)
|
|
&& (matglob.Type_matrice() != CARREE_LAPACK) && (matglob.Type_matrice() != CARREE_SYMETRIQUE_LAPACK))
|
|
{ cout << "\n erreur: pour l'instant la mise en place de condition lineaire par rotation n'est implante "
|
|
<< " que pour les matrices carree ou bande, symetrique ou pas , alors que la matrice ici est "
|
|
<< matglob.Type_matrice() << " ";
|
|
};
|
|
#endif
|
|
|
|
// la condition est la suivante sur la matrice de raideur:
|
|
// kp(i,j) = k(i,j) + Cp(ip) * K(a, j) + K(i,a) * Cp(jp) + Cp(ip) K(a,a) Cp(jp)
|
|
// pour tout Cp(ip) non nul, on doit balayer tous les j et idemn pour jp non nul, balayer les i
|
|
// mais!!! il faut tenir compte du type de stockage, à savoir certain K(i,j) peuvent ne pas être licite
|
|
// car ils n'existent pas (cas en dehors de la bande par exemple pour un stockage bande)
|
|
// a est l'indice où est imposé la condition limite, Kp est la nouvelle valeur de la matrice de raideur
|
|
// Cp vaut C sauf pour la première composante qui vaut : Cp(1) = C(1) -1
|
|
|
|
|
|
// on commence par une matrice carrée pour les tests pour faciliter la mise au point
|
|
// ici tous les K(i,j) existent a priori
|
|
if ((matglob.Type_matrice() == CARREE)|| (matglob.Type_matrice() == CARREE_LAPACK))
|
|
{ int nbligne = matglob.Nb_ligne();
|
|
int nbcol = matglob.Nb_colonne();
|
|
int ic = pt(1); // indice du ddl imposé
|
|
|
|
//---- pour débug
|
|
// // on symétrise la matrice
|
|
// for (int ix = 1; ix <= nbligne; ix++)
|
|
// for (int iy=1;iy <= ix; iy++)
|
|
// matglob(ix,iy) = matglob(iy,ix) = 0.5*(matglob(ix,iy)+matglob(iy,ix));
|
|
// // affiche les termes non symétriques de la matrice s'il y en a
|
|
// cout << "\n disymetrie eventuelle avant CLL ";
|
|
// matglob.Symetrie();
|
|
//---- fin débug
|
|
|
|
// on récupère la ligne et la colonne qui passe par ce point
|
|
Vecteur Bpj = matglob.Ligne(ic);
|
|
Vecteur Api = matglob.Colonne(ic);
|
|
////--- debug
|
|
// cout << "\n CondLim::CondlineaireCHRepere ";
|
|
// cout << "\n Bpj = "; Bpj.Affiche();
|
|
// cout << "\n Api= "; Api.Affiche();
|
|
// cout << endl ;
|
|
////--- fin debug
|
|
|
|
double matglobii = matglob(ic,ic); // pour simplifier
|
|
// calcul des termes modiés de la matrice
|
|
// 1) termes calculées à partir du terme diagonal matglobii: K_4
|
|
for (int ilc =1; ilc <= tail; ilc++)
|
|
for (int jlc =1; jlc <= tail; jlc++)
|
|
{int l = pt(ilc);int m = pt(jlc);
|
|
matglob(l,m) += V(ilc) * matglobii * V(jlc);
|
|
};
|
|
// 2) termes non diagonaux: K_2
|
|
for (int col=1;col <= tail;col++)
|
|
for (int ix = 1; ix <= nbligne; ix++)
|
|
{ int m = pt(col);
|
|
matglob (ix,m) += Api(ix) * V(col);
|
|
};
|
|
// 3) termes non diagonaux: K_3
|
|
for (int iy=1;iy <= nbcol;iy++)
|
|
for (int lig=1; lig <= tail; lig++)
|
|
{ int l = pt(lig);
|
|
matglob (l,iy) += V(lig) * Bpj(iy);
|
|
};
|
|
//---- pour débug
|
|
// // affiche les termes non symétriques de la matrice s'il y en a
|
|
// cout << "\n disymetrie eventuelle apres CLL ";
|
|
// matglob.Symetrie();
|
|
//---- fin débug
|
|
}
|
|
else
|
|
//--- cas d'une matrice quelconque ----
|
|
{ int nbligne = matglob.Nb_ligne();
|
|
int ic = pt(1); // indice du ddl imposé
|
|
// on récupère la ligne et la colonne qui passe par ce point
|
|
Vecteur Bpj = matglob.Ligne(ic);
|
|
Vecteur Api = matglob.Colonne(ic);
|
|
double matglobii = matglob(ic,ic); // pour simplifier
|
|
////--- debug
|
|
// cout << "\n CondLim::CondlineaireCHRepere ";
|
|
// cout << "\n matglobii = "<< matglobii ;
|
|
// cout << "\n Bpj = "; Bpj.Affiche();
|
|
// cout << "\n Api= "; Api.Affiche();
|
|
// cout << endl ;
|
|
////--- fin debug
|
|
//
|
|
// calcul des termes modifiés de la matrice
|
|
// if (!matglob.Symetrie())
|
|
if (!Symetrique_Enum_matrice(matglob.Type_matrice()))
|
|
{ //$$ cas d'une matrice non symétrique
|
|
|
|
// 1) termes calculées à partir du terme diagonal matglobii: K_4
|
|
for (int ilc =1; ilc <= tail; ilc++)
|
|
for (int jlc =1; jlc <= tail; jlc++)
|
|
{int l = pt(ilc);int m = pt(jlc);
|
|
matglob(l,m) += V(ilc) * matglobii * V(jlc);
|
|
};
|
|
|
|
// 2) deuxième et troisième terme
|
|
for (int col=1;col <= tail;col++)
|
|
for (int ix = 1; ix <= nbligne; ix++) // on sait que les termes non nuls sont ceux compris dans lb
|
|
{ int m = pt(col);
|
|
double r = Api(ix) * V(col);
|
|
// normalement il n'y aura de terme non null qu'au niveau de place existant dans la matrice !!
|
|
// ce qui permet d'éviter de tester l'appartenance ou non à la bande par exemple pour une matrice bande
|
|
// NON!! ce n'est pas vrai, il faut vérifier que l'on ne sort pas des clous
|
|
// en effet on fait varier ix de 1 à nbligne donc toute la matrice !! donc forcément on sortira de la bande
|
|
// si c'est un stockage bande
|
|
// on ne fait le calcul que si le terme de la matrice K existe
|
|
if (matglob.Existe(ix,m))
|
|
{if (Dabs(r) > ConstMath::trespetit)
|
|
matglob (ix,m) += r;
|
|
};
|
|
// on fait l'inverse: au niveau des indices, pour éviter une nouvelle double boucle
|
|
r = V(col) * Bpj(ix);
|
|
if (matglob.Existe(m,ix))
|
|
{if (Dabs(r) > ConstMath::trespetit)
|
|
matglob (m,ix) += r;
|
|
};
|
|
};
|
|
}
|
|
else //$$ cas d'une matrice symétrique
|
|
{ // 1) termes calculées à partir du terme diagonal matglobii: K_4
|
|
for (int ilc =1; ilc <= tail; ilc++)
|
|
for (int jlc =1; jlc <= tail; jlc++)
|
|
{int l = pt(ilc);int m = pt(jlc);
|
|
if (m >= l)
|
|
matglob(l,m) += V(ilc) * matglobii * V(jlc);
|
|
};
|
|
// 2) deuxième et troisième terme
|
|
for (int col=1;col <= tail;col++)
|
|
for (int ix = 1; ix <= nbligne; ix++) // on sait que les termes non nuls sont ceux compris dans lb
|
|
{ int m = pt(col);
|
|
double r = Api(ix) * V(col);
|
|
// normalement il n'y aura de terme non null qu'au niveau de place existant dans la matrice !!
|
|
// ce qui permet d'éviter de tester l'appartenance ou non à la bande par exemple pour une matrice bande
|
|
// NON!! ce n'est pas vrai, il faut vérifier que l'on ne sort pas des clous
|
|
// en effet on fait varier ix de 1 à nbligne donc toute la matrice !! donc forcément on sortira de la bande
|
|
// si c'est un stockage bande
|
|
// on ne fait le calcul que si le terme de la matrice K existe
|
|
if (matglob.Existe(ix,m))
|
|
{ if ((Dabs(r) > ConstMath::trespetit) && (m >= ix ))
|
|
matglob (ix,m) += r;
|
|
};
|
|
// on fait l'inverse: au niveau des indices, pour éviter une nouvelle double boucle
|
|
r = V(col) * Bpj(ix);
|
|
if (matglob.Existe(m,ix))
|
|
{if ((Dabs(r) > ConstMath::trespetit) && (ix >= m))
|
|
matglob (m,ix) += r;
|
|
};
|
|
|
|
};
|
|
////--- debug
|
|
//{
|
|
// Vecteur Bpj_ = matglob.Ligne(ic);
|
|
// Vecteur Api_ = matglob.Colonne(ic);
|
|
// double matglobii_ = matglob(ic,ic); // pour simplifier
|
|
// cout << "\n CondLim::CondlineaireCHRepere ";
|
|
// cout << "\n matglobii = "<< matglobii_ ;
|
|
// cout << "\n Bpj_ = "; Bpj_.Affiche();
|
|
// cout << "\n Api_= "; Api_.Affiche();
|
|
// cout << endl ;
|
|
// }
|
|
////--- fin debug
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
// calcul du second membre modifie, et éventuellement d'un second vecteur
|
|
int ili = pt(1);
|
|
if (vec2 == NULL)
|
|
{double ri = vecglob(ili);
|
|
for (int lig=1; lig <= tail; lig++)
|
|
{int l = pt(lig);
|
|
vecglob (l) += ri * V(lig);
|
|
};
|
|
}
|
|
else // cas où on applique également au second vecteur
|
|
{double ri = vecglob(ili);
|
|
double ri2 = (*vec2)(ili);
|
|
for (int lig=1; lig <= tail; lig++)
|
|
{ int l = pt(lig);
|
|
vecglob (l) += ri * V(lig);
|
|
(*vec2) (l) += ri2 * V(lig);
|
|
};
|
|
};
|
|
|
|
// retour du Vprime en V et sauvegarde
|
|
V(1) += 1.;
|
|
lineaires sauv(1,V,pt,valeur);
|
|
// on sauvegarde la condition lineaire au début de la liste de manière ensuite si l'on
|
|
// parcourt la liste de commencer par la dernière entrée et de remonter vers les plus anciennes
|
|
Vlineaires.push_front(sauv);
|
|
};
|
|
|
|
// second temps : imposition des blocages correspondant aux conditions lineaires
|
|
// vec2 : est un second vecteur éventuel (si != NULL) sur lequel on impose les mêmes CL que vecglob
|
|
// mais sans sauvegarde (correspond par exemple à une partie de vecglob)
|
|
void CondLim::CondlineaireImpose (Mat_abstraite & matglob,Vecteur& vecglob,Vecteur* vec2)
|
|
{ list <lineaires>::iterator ip,ipfin = Vlineaires.end();
|
|
if (Vlineaires.size() != 0)
|
|
for (ip = Vlineaires.begin();ip != ipfin; ip++)
|
|
{ lineaires& lin = (*ip);
|
|
int ptassemb = lin.pt(lin.indice); // pointeur d'assemblage globale
|
|
// on impose la condition limite a la raideur et au second membre
|
|
// NB: a priori ici la valeur imposée est toujours nulle (vue la méthode employée
|
|
// pour tenir compte des conditions linéaires, cf. théorie)
|
|
// on impose sur la matrice et on met les répercussions sur le second membre,
|
|
// mais on n'impose pas sur le second membre à ce stade, car en fait la valeur imposer
|
|
// pourrait éventuellement encore changer (sans doute non, car les coeff hors diag sont
|
|
// maintenant nul, mais on laisse quand même le système à deux temps)
|
|
Val_imposee_Mat(matglob,vecglob,ptassemb,lin.valeur,vec2);
|
|
// là on impose définitivement les valeurs au second membre
|
|
Val_imposee_Sm(vecglob,ptassemb,lin.valeur,vec2);
|
|
}
|
|
// 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) apres blocage dus aux ";
|
|
entete += " conditions lineaires limites";
|
|
matglob.Affichage_ecran(entete);
|
|
entete = " affichage du second membre (puissance interne) apres blocage dus aux ";
|
|
entete += " conditions lineaires limites";
|
|
vecglob.Affichage_ecran(entete);
|
|
}
|
|
};
|
|
|
|
//expression du vecteur resultat dans les reperes initiaux
|
|
// sol : la solution, est modifie et retournee dans les reperes initiaux
|
|
void CondLim::RepInitiaux( Vecteur& sol)
|
|
{ // on balaie les conditions limites lineaires
|
|
// ceux-ci sont ordonnées de manière à ce que la première conditions limites est la
|
|
// dernière rentrée
|
|
list <lineaires>::iterator ip,ipfin= Vlineaires.end();
|
|
//-- debug
|
|
// Vecteur intersol(Vlineaires.size());
|
|
// int num = 1;
|
|
//-- fin debug
|
|
|
|
|
|
// on revient par rotation inverse
|
|
for (ip = Vlineaires.begin();ip != ipfin; ip++)
|
|
{ Vecteur& val = (*ip).val;
|
|
int indice = (*ip).indice;
|
|
Tableau<int> & pt = (*ip).pt;
|
|
int tail = val.Taille();
|
|
double r = 0;
|
|
//-- debug
|
|
//cout << "\n pt(indice)= " << pt(indice) ;
|
|
//-- fin debug
|
|
|
|
for (int lig=1; lig <= tail; lig++)
|
|
{ r += val(lig) * sol (pt(lig));
|
|
//-- debug
|
|
//if (val(lig) != 0.)
|
|
// cout << " val(" << lig << ")= " << val(lig) << " sol (" << pt(lig) << ")= " << sol (pt(lig)) ;
|
|
//-- fin debug
|
|
};
|
|
|
|
//-- debug
|
|
//cout << " r= " << r << endl;
|
|
//-- fin debug
|
|
|
|
|
|
sol(pt(indice)) = r; // à commenter pour le débug
|
|
// intersol(num) = r; // debug
|
|
// num++; // debug
|
|
};
|
|
|
|
//-- debug
|
|
// num = 1;
|
|
// for (ip = Vlineaires.begin();ip != ipfin; ip++)
|
|
// { int indice = (*ip).indice;
|
|
// Tableau<int> & pt = (*ip).pt;
|
|
// sol(pt(indice)) = intersol(num);
|
|
// }
|
|
//-- fin debug
|
|
|
|
|
|
// affichage éventuelle du vecteur solution : deltat_ddl
|
|
if (Vlineaires.size() != 0)
|
|
if (ParaGlob::NiveauImpression() >= 10)
|
|
{ string entete = " affichage du vecteur solution (delta_ddl) apres retour dans les reperes initiaux";
|
|
sol.Affichage_ecran(entete); };
|
|
|
|
};
|
|
|
|
|
|
// application d'une condition linéaire seule, avec en retour, la situation de la condition linéaire
|
|
// imposée, ramené dans le repère initial
|
|
void CondLim::CondiLineaireImposeComplet(Mat_abstraite & matglob,Vecteur& vecglob,
|
|
const Tableau<int> & pt,const Vecteur& val, double valeur,Vecteur* vec2)
|
|
{
|
|
// //--- debug
|
|
// cout << "\n CondLim::CondiLineaireImposeComplet ";
|
|
// // pour tester la rotation
|
|
// cout << "\n valeur = " << valeur << " val= " << val << " pt= " << pt << endl ;
|
|
// cout << "\n matrice au début: ";
|
|
// matglob.Affiche2(1,16,1,1,16,1,14);
|
|
// cout << "\n second membre au début: ";vecglob.Affiche();
|
|
//{ Vecteur vol(16);
|
|
// vol(1) = 0.1; vol(2)=0.;
|
|
// vol(3) = 0.1; vol(4)=0.015;
|
|
// vol(5) = 0.05; vol(6)=0.;
|
|
// vol(7) = 0.05; vol(8)=0.015;
|
|
// vol(9) = 0.05; vol(10)=0.;
|
|
// vol(11) = 0.05; vol(12)=0.015;
|
|
// vol(13) = 0.; vol(14)=0.;
|
|
// vol(15) = 0.; vol(16)=0.015;
|
|
// Vecteur toto = matglob.Prod_mat_vec(vol);
|
|
// cout << "\n résidu matglob*deplacement: ";toto.Affiche();
|
|
//}
|
|
//
|
|
// //--- fin debug
|
|
|
|
// I) ========= première partie : on commence par changer de repère pour l'application de la condition limite
|
|
|
|
// on commence par normer la condition limite
|
|
int tail = pt.Taille();
|
|
double norme = val.Norme();
|
|
if ( norme <= ConstMath::trespetit )
|
|
{ cout << "\n erreur , la condition lineaire est formee de coefficients nulles !! ";
|
|
cout << "\n CondLim::Condlineaire( etc ... " << endl;
|
|
Sortie(1);
|
|
};
|
|
|
|
Vecteur V(val);
|
|
V /= (-val(1));
|
|
V(1) = 1 / val(1);
|
|
|
|
// calcul de la matrice de raideur modifiee: pour l'instant ne fonctionne que pour des matrices carrees ou bandes
|
|
Rotation(matglob,vecglob,pt,V,vec2);
|
|
|
|
// on sauvegarde la condition lineaire au début de la liste de manière ensuite si l'on
|
|
// parcourt la liste de commencer par la dernière entrée et de remonter vers les plus anciennes
|
|
lineaires sauv(1,V,pt,valeur);
|
|
Vlineaires.push_front(sauv);
|
|
|
|
// II) ========= deuxième partie : on applique la condition fixée, due à la condition limite
|
|
|
|
// //--- debug
|
|
// cout << "\n CondLim::CondiLineaireImposeComplet ";
|
|
// cout << "\n matrice après retation et avant application du ddl bloqué : ";
|
|
// matglob.Affiche2(1,16,1,1,16,1,14);
|
|
// cout << "\n second membre après retation et avant application du ddl bloqué: ";vecglob.Affiche();
|
|
// //--- fin debug
|
|
|
|
int ptassemb = pt(sauv.indice);
|
|
// on impose la condition limite a la raideur et au second membre
|
|
// NB: a priori ici la valeur imposée est toujours nulle (vue la méthode employée
|
|
// pour tenir compte des conditions linéaires, cf. théorie)
|
|
// on impose sur la matrice et on met les répercussions sur le second membre,
|
|
// mais on n'impose pas sur le second membre à ce stade, car en fait la valeur imposer
|
|
// pourrait éventuellement encore changer (sans doute non, car les coeff hors diag sont
|
|
// maintenant nul, mais on laisse quand même le système à deux temps)
|
|
Val_imposee_Mat(matglob,vecglob,ptassemb,sauv.valeur,vec2);
|
|
// là on impose définitivement les valeurs au second membre
|
|
Val_imposee_Sm(vecglob,ptassemb,sauv.valeur,vec2);
|
|
|
|
// //--- debug
|
|
// cout << "\n CondLim::CondiLineaireImposeComplet ";
|
|
// cout << "\n matrice après rotation et après application du ddl bloqué : ";
|
|
// matglob.Affiche2(1,16,1,1,16,1,14);
|
|
// cout << "\n second membre après rotation et après application du ddl bloqué: ";vecglob.Affiche();
|
|
// //--- fin debug
|
|
|
|
// III) ========= troisième partie : on revient dans le repère initiale
|
|
|
|
// calcul de la matrice de raideur modifiee: pour l'instant ne fonctionne que pour des matrices carrees ou bandes
|
|
V = val; // récup de la condition initiale
|
|
Rotation(matglob,vecglob,pt,V,vec2);
|
|
// là on impose définitivement les valeurs au second membre
|
|
// Val_imposee_Sm(vecglob,ptassemb,sauv.valeur,vec2);
|
|
|
|
// //--- debug
|
|
// cout << "\n CondLim::CondiLineaireImposeComplet ";
|
|
// cout << "\n matrice à la fin: ";
|
|
// matglob.Affiche2(1,16,1,1,16,1,14);
|
|
// cout << "\n second membre à la fin: ";vecglob.Affiche();
|
|
//{ Vecteur vol(16);
|
|
// vol(1) = 0.1; vol(2)=0.;
|
|
// vol(3) = 0.1; vol(4)=0.015;
|
|
// vol(5) = 0.05; vol(6)=0.;
|
|
// vol(7) = 0.05; vol(8)=0.015;
|
|
// vol(9) = 0.05; vol(10)=0.;
|
|
// vol(11) = 0.05; vol(12)=0.015;
|
|
// vol(13) = 0.; vol(14)=0.;
|
|
// vol(15) = 0.; vol(16)=0.015;
|
|
// Vecteur toto = matglob.Prod_mat_vec(vol);
|
|
// cout << "\n résidu matglob*deplacement: ";toto.Affiche();
|
|
//}
|
|
// Sortie(1);
|
|
//--- fin debug
|
|
|
|
};
|
|
|
|
|
|
// remise a zero des sauvegardes de second membre et de matrice
|
|
void CondLim::EffaceSauvegarde()
|
|
{ // effacement des deux containers
|
|
VImpSM.erase(VImpSM.begin(),VImpSM.end());
|
|
VImpRaid.erase(VImpRaid.begin(),VImpRaid.end());
|
|
};
|
|
|
|
|
|
// remise a zero des sauvegardes de condition lineaire
|
|
void CondLim::EffaceCoLin()
|
|
{ Vlineaires.erase(Vlineaires.begin(),Vlineaires.end());
|
|
};
|
|
|
|
|
|
//---------- méthodes internes --------
|
|
|
|
// méthode pour faire une rotation de la matrice et du second membre suivant un vecteur
|
|
// vec2 : est un second vecteur éventuel (si != NULL)
|
|
void CondLim::Rotation(Mat_abstraite & matglob,Vecteur& vecglob,
|
|
const Tableau<int> & pt,const Vecteur& val,Vecteur* vec2)
|
|
{
|
|
Vecteur V(val);
|
|
int tail = pt.Taille();
|
|
|
|
V(1) -= 1.;
|
|
// calcul de la matrice de raideur modifiee: pour l'instant ne fonctionne que pour des matrices carrees ou bandes
|
|
#ifdef MISE_AU_POINT
|
|
if ((matglob.Type_matrice() != CARREE) && (matglob.Type_matrice() != CARREE_SYMETRIQUE)
|
|
&& (matglob.Type_matrice() != BANDE_SYMETRIQUE) && (matglob.Type_matrice() != BANDE_NON_SYMETRIQUE)
|
|
&& (matglob.Type_matrice() != BANDE_NON_SYMETRIQUE_LAPACK)
|
|
&& (matglob.Type_matrice() != BANDE_SYMETRIQUE_LAPACK)
|
|
&& (matglob.Type_matrice() != CARREE_LAPACK) && (matglob.Type_matrice() != CARREE_SYMETRIQUE_LAPACK))
|
|
{ cout << "\n erreur: pour l'instant la mise en place de condition lineaire par rotation n'est implante "
|
|
<< " que pour les matrices carree ou bande, symetrique ou pas , alors que la matrice ici est "
|
|
<< matglob.Type_matrice() << " ";
|
|
};
|
|
#endif
|
|
|
|
// la condition est la suivante sur la matrice de raideur:
|
|
// kp(i,j) = k(i,j) + Cp(ip) * K(a, j) + K(i,a) * Cp(jp) + Cp(ip) K(a,a) Cp(jp)
|
|
// pour tout Cp(ip) non nul, on doit balayer tous les j et idemn pour jp non nul, balayer les i
|
|
// mais!!! il faut tenir compte du type de stockage, à savoir certain K(i,j) peuvent ne pas être licite
|
|
// car ils n'existent pas (cas en dehors de la bande par exemple pour un stockage bande)
|
|
// a est l'indice où est imposé la condition limite, Kp est la nouvelle valeur de la matrice de raideur
|
|
// Cp vaut C sauf pour la première composante qui vaut : Cp(1) = C(1) -1
|
|
|
|
|
|
// on commence par une matrice carrée pour les tests pour faciliter la mise au point
|
|
// ici tous les K(i,j) existent a priori
|
|
if ((matglob.Type_matrice() == CARREE)|| (matglob.Type_matrice() == CARREE_LAPACK))
|
|
{ int nbligne = matglob.Nb_ligne();
|
|
int nbcol = matglob.Nb_colonne();
|
|
int ic = pt(1); // indice du ddl imposé
|
|
|
|
//---- pour débug
|
|
// // on symétrise la matrice
|
|
// for (int ix = 1; ix <= nbligne; ix++)
|
|
// for (int iy=1;iy <= ix; iy++)
|
|
// matglob(ix,iy) = matglob(iy,ix) = 0.5*(matglob(ix,iy)+matglob(iy,ix));
|
|
// // affiche les termes non symétriques de la matrice s'il y en a
|
|
// cout << "\n disymetrie eventuelle avant CLL ";
|
|
// matglob.Symetrie();
|
|
//---- fin débug
|
|
|
|
// on récupère la ligne et la colonne qui passe par ce point
|
|
Vecteur Bpj = matglob.Ligne(ic);
|
|
Vecteur Api = matglob.Colonne(ic);
|
|
////--- debug
|
|
// cout << "\n CondLim::CondlineaireCHRepere ";
|
|
// cout << "\n Bpj = "; Bpj.Affiche();
|
|
// cout << "\n Api= "; Api.Affiche();
|
|
// cout << endl ;
|
|
////--- fin debug
|
|
|
|
double matglobii = matglob(ic,ic); // pour simplifier
|
|
// calcul des termes modiés de la matrice
|
|
// 1) termes calculées à partir du terme diagonal matglobii: K_4
|
|
for (int ilc =1; ilc <= tail; ilc++)
|
|
for (int jlc =1; jlc <= tail; jlc++)
|
|
{int l = pt(ilc);int m = pt(jlc);
|
|
matglob(l,m) += V(ilc) * matglobii * V(jlc);
|
|
};
|
|
// 2) termes non diagonaux: K_2
|
|
for (int col=1;col <= tail;col++)
|
|
for (int ix = 1; ix <= nbligne; ix++)
|
|
{ int m = pt(col);
|
|
matglob (ix,m) += Api(ix) * V(col);
|
|
};
|
|
// 3) termes non diagonaux: K_3
|
|
for (int iy=1;iy <= nbcol;iy++)
|
|
for (int lig=1; lig <= tail; lig++)
|
|
{ int l = pt(lig);
|
|
matglob (l,iy) += V(lig) * Bpj(iy);
|
|
};
|
|
//---- pour débug
|
|
// // affiche les termes non symétriques de la matrice s'il y en a
|
|
// cout << "\n disymetrie eventuelle apres CLL ";
|
|
// matglob.Symetrie();
|
|
//---- fin débug
|
|
}
|
|
else
|
|
//--- cas d'une matrice quelconque ----
|
|
{ int nbligne = matglob.Nb_ligne();
|
|
int ic = pt(1); // indice du ddl imposé
|
|
// on récupère la ligne et la colonne qui passe par ce point
|
|
Vecteur Bpj = matglob.Ligne(ic);
|
|
Vecteur Api = matglob.Colonne(ic);
|
|
double matglobii = matglob(ic,ic); // pour simplifier
|
|
////--- debug
|
|
// cout << "\n CondLim::CondlineaireCHRepere ";
|
|
// cout << "\n matglobii = "<< matglobii ;
|
|
// cout << "\n Bpj = "; Bpj.Affiche();
|
|
// cout << "\n Api= "; Api.Affiche();
|
|
// cout << endl ;
|
|
////--- fin debug
|
|
//
|
|
// calcul des termes modifiés de la matrice
|
|
// if (!matglob.Symetrie())
|
|
if (!Symetrique_Enum_matrice(matglob.Type_matrice()))
|
|
{ //$$ cas d'une matrice non symétrique
|
|
|
|
// 1) termes calculées à partir du terme diagonal matglobii: K_4
|
|
for (int ilc =1; ilc <= tail; ilc++)
|
|
for (int jlc =1; jlc <= tail; jlc++)
|
|
{int l = pt(ilc);int m = pt(jlc);
|
|
matglob(l,m) += V(ilc) * matglobii * V(jlc);
|
|
};
|
|
|
|
// 2) deuxième et troisième terme
|
|
for (int col=1;col <= tail;col++)
|
|
for (int ix = 1; ix <= nbligne; ix++) // on sait que les termes non nuls sont ceux compris dans lb
|
|
{ int m = pt(col);
|
|
double r = Api(ix) * V(col);
|
|
// normalement il n'y aura de terme non null qu'au niveau de place existant dans la matrice !!
|
|
// ce qui permet d'éviter de tester l'appartenance ou non à la bande par exemple pour une matrice bande
|
|
// NON!! ce n'est pas vrai, il faut vérifier que l'on ne sort pas des clous
|
|
// en effet on fait varier ix de 1 à nbligne donc toute la matrice !! donc forcément on sortira de la bande
|
|
// si c'est un stockage bande
|
|
// on ne fait le calcul que si le terme de la matrice K existe
|
|
if (matglob.Existe(ix,m))
|
|
{if (Dabs(r) > ConstMath::trespetit)
|
|
matglob (ix,m) += r;
|
|
};
|
|
// on fait l'inverse: au niveau des indices, pour éviter une nouvelle double boucle
|
|
r = V(col) * Bpj(ix);
|
|
if (matglob.Existe(m,ix))
|
|
{if (Dabs(r) > ConstMath::trespetit)
|
|
matglob (m,ix) += r;
|
|
};
|
|
};
|
|
}
|
|
else //$$ cas d'une matrice symétrique
|
|
{ // 1) termes calculées à partir du terme diagonal matglobii: K_4
|
|
for (int ilc =1; ilc <= tail; ilc++)
|
|
for (int jlc =1; jlc <= tail; jlc++)
|
|
{int l = pt(ilc);int m = pt(jlc);
|
|
if (m >= l)
|
|
matglob(l,m) += V(ilc) * matglobii * V(jlc);
|
|
};
|
|
// 2) deuxième et troisième terme
|
|
for (int col=1;col <= tail;col++)
|
|
for (int ix = 1; ix <= nbligne; ix++) // on sait que les termes non nuls sont ceux compris dans lb
|
|
{ int m = pt(col);
|
|
double r = Api(ix) * V(col);
|
|
// normalement il n'y aura de terme non null qu'au niveau de place existant dans la matrice !!
|
|
// ce qui permet d'éviter de tester l'appartenance ou non à la bande par exemple pour une matrice bande
|
|
// NON!! ce n'est pas vrai, il faut vérifier que l'on ne sort pas des clous
|
|
// en effet on fait varier ix de 1 à nbligne donc toute la matrice !! donc forcément on sortira de la bande
|
|
// si c'est un stockage bande
|
|
// on ne fait le calcul que si le terme de la matrice K existe
|
|
if (matglob.Existe(ix,m))
|
|
{ if ((Dabs(r) > ConstMath::trespetit) && (m >= ix ))
|
|
matglob (ix,m) += r;
|
|
};
|
|
// on fait l'inverse: au niveau des indices, pour éviter une nouvelle double boucle
|
|
r = V(col) * Bpj(ix);
|
|
if (matglob.Existe(m,ix))
|
|
{if ((Dabs(r) > ConstMath::trespetit) && (ix >= m))
|
|
matglob (m,ix) += r;
|
|
};
|
|
|
|
};
|
|
////--- debug
|
|
//{
|
|
// Vecteur Bpj_ = matglob.Ligne(ic);
|
|
// Vecteur Api_ = matglob.Colonne(ic);
|
|
// double matglobii_ = matglob(ic,ic); // pour simplifier
|
|
// cout << "\n CondLim::CondlineaireCHRepere ";
|
|
// cout << "\n matglobii = "<< matglobii_ ;
|
|
// cout << "\n Bpj_ = "; Bpj_.Affiche();
|
|
// cout << "\n Api_= "; Api_.Affiche();
|
|
// cout << endl ;
|
|
// }
|
|
////--- fin debug
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
// calcul du second membre modifie, et éventuellement d'un second vecteur
|
|
int ili = pt(1);
|
|
if (vec2 == NULL)
|
|
{double ri = vecglob(ili);
|
|
for (int lig=1; lig <= tail; lig++)
|
|
{int l = pt(lig);
|
|
vecglob (l) += ri * V(lig);
|
|
};
|
|
}
|
|
else // cas où on applique également au second vecteur
|
|
{double ri = vecglob(ili);
|
|
double ri2 = (*vec2)(ili);
|
|
for (int lig=1; lig <= tail; lig++)
|
|
{ int l = pt(lig);
|
|
vecglob (l) += ri * V(lig);
|
|
(*vec2) (l) += ri2 * V(lig);
|
|
};
|
|
};
|
|
|
|
// retour à la situation initiale
|
|
V(1) += 1.;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|