// FICHIER : PoutTimo.cp
// CLASSE : PoutTimo

// 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 "Debug.h"


#include <iostream>
#include <stdlib.h>
#include "Sortie.h"


#include "PoutTimo.h"
#include "FrontPointF.h"
#include "FrontSegLine.h"


//----------------------------------------------------------------
// def des donnees commune a tous les elements
// la taille n'est pas defini ici car elle depend de la lecture 
//----------------------------------------------------------------
PoutTimo::DonneeCommune * PoutTimo::doCo = NULL;                                     
int PoutTimo::CalculResidu_t_PoutTimo_met_abstraite = 0;  
int  PoutTimo::Calcul_implicit_PoutTimo_met_abstraite = 0;
int  PoutTimo::Calcul_VarDualSort = 0;
PoutTimo::ConstrucElementpoutTimo PoutTimo::construcElementpoutTimo;
// fonction privee
// dans cette fonction il ne doit y avoir que les données communes !!
void PoutTimo::Def_DonneeCommune() 
  {	 // interpollation
     GeomSeg segment(1,2) ; // element geometrique correspondant: 1 pt integ, 2 noeuds
     // degre de liberte
     int dim = ParaGlob::Dimension();
     DdlElement  tab_ddl(2,dim);
     int posi = Id_nom_ddl("X1") -1;
	 for (int i =1; i<= ParaGlob::Dimension(); i++)
	    {tab_ddl (1,i) = Enum_ddl(i+posi);
	     tab_ddl (2,i) = Enum_ddl(i+posi); } 
	// def metrique
	// on definit les variables a priori toujours utiles
    Tableau<Enum_variable_metrique> tab(15);
    tab(1) = iM0; tab(2) = iMt; tab(3) = iMtdt ;
    tab(4)=igiB_0;tab(5)=igiB_t;tab(6)=igiB_tdt;
    tab(7)=igiH_0;tab(8)=igiH_t;tab(9)=igiH_tdt ;
    tab(10)=igijBB_0;tab(11)=igijBB_t;tab(12)=igijBB_tdt;
    tab(13)=igijHH_0;tab(14)=igijHH_t;tab(15)=igijHH_tdt ;
	     // dim du pb , nb de vecteur de la base , tableau de ddl et la def de variables
	Met_biellette  metri(ParaGlob::Dimension(),tab_ddl,tab,2) ;
    // definition de la classe static contenant toute les variables communes aux biellettes
    doCo = new DonneeCommune(segment,tab_ddl,metri);
  };    
PoutTimo::PoutTimo ()  :
// Constructeur par defaut
ElemMeca()

{   id_interpol=BIE1;  //   donnees de la classe mere
	id_geom=POUT;      //
    // stockage des donnees particulieres de la loi de comportement au point d'integ
    tabSaveDon.Change_taille(1);
	section=-1.;
	tab_noeud.Change_taille(2);
	// le fait de mettre les pointeurs a null permet
	// de savoir que l'element n'est pas complet
	tab_noeud(1) = NULL;tab_noeud(2) = NULL; 
	// definition des donnees communes aux biellettes 
	// a la premiere definition d'une biellette
	if (doCo == NULL) Def_DonneeCommune();
	met = &(doCo->met_biellette); // met est defini dans elemeca
	// def pointe sur la deformation specifique a l'element    		
	def = new Deformation(*met,*this,(doCo->segment).taDphi(),(doCo->segment).taPhi());
    //dimensionnement des deformations et contraintes
    epsBB = NevezTenseurBB (1);
	sigHH = NevezTenseurHH (1);
	int nbddl = doCo->tab_ddl.NbDdl();
    d_epsBB.Change_taille(nbddl);
    for (int i=1; i<= nbddl; i++)
       d_epsBB(i) = NevezTenseurBB (1);

};  
	
PoutTimo::PoutTimo (double sect,int num_id):
// Constructeur utile si la section de l'element et
// le numero de l'element  sont connus
ElemMeca(num_id,BIE1,POUT)
{	// stockage des donnees particulieres de la loi de comportement au point d'integ
    tabSaveDon.Change_taille(1);
    section=sect;
	tab_noeud.Change_taille(2);
	// le fait de mettre les pointeurs a null permet
	// de savoir que l'element n'est pas complet
	tab_noeud(1) = NULL;tab_noeud(2) = NULL; 	
	// definition des donnees communes aux biellettes 
	// a la premiere definition d'une biellette
	if (doCo == NULL) Def_DonneeCommune();
	met = &(doCo->met_biellette);// met est defini dans elemeca
	// def pointe sur la deformation specifique a l'element    		
	def = new Deformation(*met,*this,(doCo->segment).taDphi(),(doCo->segment).taPhi());
    //dimensionnement des deformations et contraintes
    epsBB = NevezTenseurBB (1);
	sigHH = NevezTenseurHH (1);
	int nbddl = doCo->tab_ddl.NbDdl();
    d_epsBB.Change_taille(nbddl);
    for (int i=1; i<= nbddl; i++)
       d_epsBB(i) = NevezTenseurBB (1);
	
};

// Constructeur fonction  d'un numero d'identification  
PoutTimo::PoutTimo (int num_id) :
  ElemMeca(num_id,BIE1,POUT)
 {  // stockage des donnees particulieres de la loi de comportement au point d'integ
    tabSaveDon.Change_taille(1);
	section=-1.;  // c-a-d non valide
	tab_noeud.Change_taille(2);
	// le fait de mettre les pointeurs a null permet
	// de savoir que l'element n'est pas complet
	tab_noeud(1) = NULL;tab_noeud(2) = NULL; 
	// definition des donnees communes aux biellettes 
	// a la premiere definition d'une biellette
	if (doCo == NULL) Def_DonneeCommune();
	met = &(doCo->met_biellette);// met est defini dans elemeca
	// def pointe sur la deformation specifique a l'element    		
	def = new Deformation(*met,*this,(doCo->segment).taDphi(),(doCo->segment).taPhi());
    //dimensionnement des deformations et contraintes
    epsBB = NevezTenseurBB (1);
	sigHH = NevezTenseurHH (1);
	int nbddl = doCo->tab_ddl.NbDdl();
    d_epsBB.Change_taille(nbddl);
    for (int i=1; i<= nbddl; i++)
       d_epsBB(i) = NevezTenseurBB (1);

 };

PoutTimo::PoutTimo (double sect,int num_id,const Tableau<Noeud *>& tab):
// Constructeur utile si la section de l'element, le numero de l'element et
// le tableau des noeuds sont connus
ElemMeca(num_id,tab,BIE1,POUT)
{    // stockage des donnees particulieres de la loi de comportement au point d'integ
    tabSaveDon.Change_taille(1);
	section=sect;
	if (tab_noeud.Taille() != 2)
	  { cout << "\n erreur de dimensionnement du tableau de noeud \n";
	   cout << " PoutTimo::PoutTimo (double sect,int num_id,const Tableau<Noeud *>& tab)\n";
	   Sortie (1); }
	// definition des donnees communes aux biellettes 
	// a la premiere definition d'une biellette
	if (doCo == NULL) Def_DonneeCommune();
	met = &(doCo->met_biellette);// met est defini dans elemeca
	// def pointe sur la deformation specifique a l'element    		
	def = new Deformation(*met,*this,(doCo->segment).taDphi(),(doCo->segment).taPhi());
    //dimensionnement des deformations et contraintes
    epsBB = NevezTenseurBB (1);
	sigHH = NevezTenseurHH (1);
	int nbddl = doCo->tab_ddl.NbDdl();
    d_epsBB.Change_taille(nbddl);
    for (int i=1; i<= nbddl; i++)
       d_epsBB(i) = NevezTenseurBB (1);
    // construction du tableau de ddl des noeuds de biellette
    ConstTabDdl(); 
};

PoutTimo::PoutTimo (PoutTimo& poutTimo) :
 ElemMeca (poutTimo)
 
// Constructeur de copie
{   // stockage des donnees particulieres de la loi de comportement au point d'integ
    tabSaveDon.Change_taille(1);
    section=poutTimo.section;
	*(epsBB) = *(poutTimo.epsBB);
	*(sigHH) = *(poutTimo.sigHH);	
	d_epsBB=poutTimo.d_epsBB;  
	for (int i=1; i<= d_epsBB.Taille(); i++)
	  { d_epsBB(i) = NevezTenseurBB(1);
	    *d_epsBB(i) = *(poutTimo.d_epsBB(i)); }
	*(residu) = *(poutTimo.residu);
	*(raideur) = *(poutTimo.raideur);
	*met = *(poutTimo.met);
	*def = *(poutTimo.def);
};	

PoutTimo::~PoutTimo ()
// Destructeur
{ delete epsBB;
  delete sigHH;
  for (int i=1; i<= d_epsBB.Taille(); i++)
     delete d_epsBB(i);
  LibereTenseur();
  delete def; // la deformation
 };

// Lecture des donnees de la classe sur fichier
void 
PoutTimo::LectureDonneesParticulieres
    (UtilLecture * entreePrinc,Tableau<Noeud  *> * tabMaillageNoeud)
  { int nb;
    tab_noeud.Change_taille(2);
    for (int i=1; i<= 2; i++)
     { *(entreePrinc->entree) >> nb;
       tab_noeud(i) = (*tabMaillageNoeud)(nb);
     }
    // construction du tableau de ddl des noeuds de biellette
    ConstTabDdl(); 
  };
  
// Calcul du residu local 
 Vecteur* PoutTimo::CalculResidu_t ()
     { // dimensionnement de la metrique
       if( CalculResidu_t_PoutTimo_met_abstraite == 0)
        { Tableau<Enum_variable_metrique> tab(7);
         tab(1) = igiB_0; tab(2) = igiB_t; tab(3) = igijBB_0;tab(4) = igijBB_t;
         tab(5) = igijHH_t; tab(6) = id_giB_t; tab(7) = id_gijBB_t ;
         doCo->met_biellette.PlusInitVariables(tab) ;
          CalculResidu_t_PoutTimo_met_abstraite = 1;
        };  
       // dimensionnement du residu
       int nbddl = doCo->tab_ddl.NbDdl();
       if ( residu == NULL)
          residu = new Vecteur(nbddl); // cas du premier passage
       else
          for (int i =1; i<= nbddl; i++)  // cas des autres passages
             (*residu)(i) = 0.;             // on initialise a zero
       Vecteur poids =(doCo->segment).taWi();   // poids d'interpolation  = 2
       poids(1) *=  section; 
	   Tableau <TenseurHH *> tabSigHH(1); tabSigHH(1) = sigHH;
	   Tableau <TenseurBB *> tabEpsBB(1);  tabEpsBB(1) = epsBB;        
       ElemMeca::Cal_explicit ( doCo->tab_ddl,tabEpsBB,d_epsBB,tabSigHH,1,poids); 
       return residu;  
     };
// Calcul du residu local et de la raideur locale,
//  pour le schema implicite
Element::ResRaid  PoutTimo::Calcul_implicit ()
    {  if( Calcul_implicit_PoutTimo_met_abstraite == 0)
        { Tableau<Enum_variable_metrique> tab(13);
         tab(1) = igiB_0; tab(2) = igiB_t; tab(3) = igiB_tdt; tab(4) = igijBB_0;
         tab(5) = igijBB_t;tab(6) = igijBB_tdt; tab(7) = igijHH_tdt; tab(8) = id_giB_tdt;
         tab(9) = id_gijBB_tdt ;tab(10) = igiH_tdt;tab(11) =  id_giH_tdt;
         tab(12) = id_gijHH_tdt;tab(13) = id_jacobien_tdt; 
         doCo->met_biellette.PlusInitVariables(tab) ;
         Calcul_implicit_PoutTimo_met_abstraite = 1;
        };  

      // dimensionnement du residu
       int nbddl = doCo->tab_ddl.NbDdl();
       if ( residu == NULL)
          residu = new Vecteur(nbddl); // cas du premier passage
       else
          for (int i =1; i<= nbddl; i++)  // cas des autres passages
             (*residu)(i) = 0.;             // on initialise a zero
      // dimensionnement de la raideur
       if ( raideur == NULL)
          raideur = new Mat_pleine(nbddl,nbddl); // cas du premier passage
       else
          for (int i =1; i<= nbddl; i++)  // cas des autres passages
            for (int j=1; j<= nbddl; j++) //
              (*raideur)(i,j) = 0.;       // on initialise a zero
       Vecteur poids =(doCo->segment).taWi();   // poids d'interpolation  = 2
       poids(1) *=  section; 
	   Tableau <TenseurHH *> tabSigHH(1); tabSigHH(1) = sigHH;
	   Tableau <TenseurBB *> tabEpsBB(1);  tabEpsBB(1) = epsBB;        
       ElemMeca::Cal_implicit (doCo->tab_ddl,tabEpsBB, d_epsBB,tabSigHH,1,poids);
       Element::ResRaid el;
       el.res = residu; 
       el.raid = raideur;
       return el;
    };
// Calcul de la matrice géométrique et initiale
ElemMeca::MatGeomInit PoutTimo::MatricesGeometrique_Et_Initiale () 
 {  if( Calcul_implicit_PoutTimo_met_abstraite == 0)
        { Tableau<Enum_variable_metrique> tab(14);
         tab(1) = igiB_0; tab(2) = igiB_t; tab(3) = igiB_tdt; tab(4) = igijBB_0;
         tab(5) = igijBB_t;tab(6) = igijBB_tdt; tab(7) = igijHH_tdt; tab(8) = id_giB_tdt;
         tab(9) = id_gijBB_tdt ;tab(10) = igiH_tdt;tab(11) =  id_giH_tdt;
         tab(12) = id_gijHH_tdt;tab(13) = id_jacobien_tdt;tab(14) = id2_gijBB_tdt; 
         doCo->met_biellette.PlusInitVariables(tab) ;
         Calcul_implicit_PoutTimo_met_abstraite = 1;
        };
    // Par simplicité
    Mat_pleine & matGeom = doCo->matGeom;    
    Mat_pleine & matInit = doCo->matInit;    
    // mise à zéro de la matrice géométrique
    matGeom.Initialise();
    Vecteur poids =(doCo->segment).taWi();   // poids d'interpolation  = 2
    poids(1) *=  section; 
	Tableau <TenseurHH *> tabSigHH(1); tabSigHH(1) = sigHH;
	Tableau <TenseurBB *> tabEpsBB(1);  tabEpsBB(1) = epsBB;        
    ElemMeca::Cal_matGeom_Init 
          (matGeom,matInit,doCo->tab_ddl,tabEpsBB, d_epsBB,
          doCo->d2_epsBB,tabSigHH,1,poids);
    return  MatGeomInit(&matGeom,&matInit);     
  } ;
	
// retourne les tableaux de ddl gere par l'element
// ce tableau et specifique a l'element
DdlElement & PoutTimo::TableauDdl()
     { return doCo->tab_ddl; };
// liberation de la place pointee     
void PoutTimo::Libere ()
  {Element::Libere (); // liberation de residu et raideur
   LibereTenseur() ; // liberation des tenseur intermediaires
   for (int i=1; i<= d_epsBB.Taille(); i++) // a priori est locale
     delete d_epsBB(i);
  };
// acquisition ou modification d'une loi de comportement
void PoutTimo::DefLoi (LoiAbstraiteGeneral * NouvelleLoi)
    { loiComp = (Loi_comp_abstraite *) NouvelleLoi;
      // verification du type de loi
      if (loiComp->Dimension() != 1)
        { cout << "\n Erreur, la loi de comportement a utiliser avec des biellettes";
          cout << " doit etre de type 1D, \n ici est de type = " 
               << (NouvelleLoi->Dimension()) << " !!! " << endl;
          Sortie(1);     
        }
      // initialisation du stockage particulier, ici 1 pt d'integ
      tabSaveDon(1) = loiComp->Initialise();  
    };
  
// test si l'element est complet
int PoutTimo::TestComplet()
  { int res = ElemMeca::TestComplet(); // test dans la fonction mere
    if ( section == -1)
     { cout << "\n la section de la biellette n'est pas defini  \n";
       res = 0; }
    if ( tab_noeud(1) == NULL)
     { cout << "\n les noeuds de la biellette ne sont pas defini  \n";
       res = 0; }
    else 
     { int testi =1;
       int posi = Id_nom_ddl("X1") -1;    
       for (int i =1; i<= ParaGlob::Dimension(); i++)
          for (int j=1;j<=2;j++)
           if(!(tab_noeud(j)->Existe_ici(Enum_ddl(posi+i))))
              testi = 0;
       if(testi == 0)
         { cout << "\n les ddls X1,X2 etc des noeuds de la biellette ne sont pas defini  \n";
           cout << " \n utilisez PoutTimo::ConstTabDdl() pour completer " ;
           res = 0; }            
      }          
    return res;   
  };
    
// ajout du tableau de ddl des noeuds de biellette
 void PoutTimo::ConstTabDdl()
    {  
    Tableau <Ddl> ta(ParaGlob::Dimension());
    int posi = Id_nom_ddl("X1") -1;    
    for (int i =1; i<= ParaGlob::Dimension(); i++)
	    {Ddl inter((Enum_ddl(i+posi)),0.,false);
	     ta(i) = inter;
	     }
    // attribution des ddls aux noeuds    
    tab_noeud(1)->PlusTabDdl(ta); 
    tab_noeud(2)->PlusTabDdl(ta);  
    };
		
// procesure permettant de completer l'element apres
// sa creation avec les donnees du bloc transmis
// peut etre appeler plusieurs fois
 Element* PoutTimo::Complete(BlocGen & bloc,LesFonctions_nD*  lesFonctionsnD)
    { if (bloc.Nom(1) == "sections")
       { section = bloc.Val(1);
         return this;
        }
       else
         return ElemMeca::Complete_ElemMeca(bloc,lesFonctionsnD);
//return NULL;
    };       
                         
// affichage dans la sortie transmise, des variables duales "nom"
// dans le cas ou nom est vide, affichage de "toute" les variables
 void PoutTimo::AfficheVarDual(ofstream& sort, Tableau<string>& nom)
     {// affichage de l'entête de l'element
      sort << "\n******************************************************************";
      sort << "\n Element poutTimo (2 noeuds 1 point d'integration) ";
      sort << "\n******************************************************************";
      // appel de la procedure de elem meca
	  Tableau <TenseurHH *> tabSigHH(1); tabSigHH(1) = sigHH;
	  Tableau <TenseurBB *> tabEpsBB(1);  tabEpsBB(1) = epsBB;        
      if ((Calcul_VarDualSort == 0) && (Calcul_implicit_PoutTimo_met_abstraite != 0))
        { VarDualSort(sort,nom,tabSigHH,tabEpsBB,1,1);
          Calcul_VarDualSort = 1;
         } 
      else if ((Calcul_VarDualSort == 1) && (Calcul_implicit_PoutTimo_met_abstraite != 0))       
         VarDualSort(sort,nom,tabSigHH,tabEpsBB,1,11);
      else if ((Calcul_VarDualSort == 0) && (CalculResidu_t_PoutTimo_met_abstraite != 0))       
        { VarDualSort(sort,nom,tabSigHH,tabEpsBB,1,2);
          Calcul_VarDualSort = 1;
         }         
      else if ((Calcul_VarDualSort == 1) && (CalculResidu_t_PoutTimo_met_abstraite != 0))       
         VarDualSort(sort,nom,tabSigHH,tabEpsBB,1,12);
      // sinon on ne fait rien     
      };
      
// Calcul des frontieres de l'element
		//  creation des elements frontieres et retour du tableau de ces elements
Tableau <ElFrontiere*> & PoutTimo::Frontiere()
  { int cas = 6; // on veut des lignes et des points
    return Frontiere_elemeca(cas,force);
//  { // dimensionnement des tableaux intermediaires
//    Tableau <Noeud *> tab(1); // les noeuds des points frontieres
//    DdlElement ddelem(1);  // les ddlelements des points frontieres
//    int tail;
//    if (ParaGlob::Dimension() <= 2) 
//       tail = 2;  // deux points
//    else if (ParaGlob::Dimension() == 3) 
//       tail = 3;  // deux points et le segment lui-meme
//    #ifdef MISE_AU_POINT	 	 
//    else
//     { cout << "\n erreur de dimension dans PoutTimo, dim = " << ParaGlob::Dimension();
//       cout << "\n alors que l'on doit avoir 1 ou 2 ou 3 !! " << endl;
//       Sortie (1);
//      }        
//    #endif
//    tabb.Change_taille(tail); 
//    // premier point  
//    tab(1) = tab_noeud(1);
//    ddelem(1) = doCo->tab_ddl(1);
//    tabb(1) = new  FrontPointF (tab,ddelem);
//    // second point
//    tab(1) = tab_noeud(2);
//    ddelem(1) = doCo->tab_ddl(2);
//    tabb(2) = new  FrontPointF (tab,ddelem);
//    // 3 ieme cote eventuelle
//    if (tail == 3)
//     tabb(3) = new   FrontSegLine(tab_noeud,doCo->tab_ddl);
//    
//    return tabb;          
   };
   
   
   
                  	
