// This file is part of the Herezh++ application. // // The finite element software Herezh++ is dedicated to the field // of mechanics for large transformations of solid structures. // It is developed by Gérard Rio (APP: IDDN.FR.010.0106078.000.R.P.2006.035.20600) // INSTITUT DE RECHERCHE DUPUY DE LÔME (IRDL) . // // Herezh++ is distributed under GPL 3 license ou ultérieure. // // Copyright (C) 1997-2022 Université Bretagne Sud (France) // AUTHOR : Gérard Rio // E-MAIL : gerardrio56@free.fr // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // See the GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . // // For more information, please consult: . #include "CondLim.h" #include "ConstMath.h" #include "ParaGlob.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 ::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 ::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 ::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 & 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 & 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 ::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 ::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 & 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 & 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 & 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 & 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.; };