// FICHIER : PoutSimple1.h
// CLASSE : PoutSimple1

// 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/>.

/************************************************************************
 *     DATE:        23/01/97                                            *
 *                                                                $     *
 *     AUTEUR:      G RIO   (mailto:gerardrio56@free.fr)                *
 *                                                                $     *
 *     PROJET:      Herezh++                                            *
 *                                                                $     *
 ************************************************************************
 *     BUT:  // La classe PoutSimple1 permet de declarer des elements   *
 *  de flexion très simple, qui à priori, sont prévus pour fonctionner  *
 *  seul, c'est à dire un seul élément, ceci pour tester le flambage .  *
 *  La classe permet de realiser le calcul du residu local et de la     *
 *  raideur locale pour une loi de comportement donnee. La dimension de *
 *  l'espace de référence pour un tel element est 1, celle de l'espace  *
 *  physique est uniquement 2. Les déplacements prévus sont U dans l'axe*
 *  et W transversalement.                                              *
 *  La section de la poutre est rectangulaire, épaisseur x largeur.     *
 *                                                                      *
 *     ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''     *                                                                      *
 *     VERIFICATION:                                                    *
 *                                                                      *
 *     !  date  !   auteur   !       but                          !     *
 *     ------------------------------------------------------------     *
 *     !        !            !                                    !     *
 *                                                                $     *
 *     ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''     *
 *     MODIFICATIONS:                                                   *
 *     !  date  !   auteur   !       but                          !     *
 *     ------------------------------------------------------------     *
 *                                                                $     *
 ************************************************************************/
// -----------classe pour un calcul de mecanique---------



#ifndef POUTSIMPLE1_H
#define POUTSIMPLE1_H

#include "ParaGlob.h"
#include "ElemMeca.h"
//#include "Loi_comp_abstraite.h"
#include "Met_abstraite.h"
#include "Met_pout2D.h"
#include "Noeud.h"
#include "UtilLecture.h"
#include "ElFrontiere.h"
#include "GeomSeg.h"
#include "PiPoCo.h"
#include "ParaAlgoControle.h"
#include "FrontSegLine.h"

class ConstrucElementbiel;

/// @addtogroup groupe_des_elements_finis
///  @{
///


class PoutSimple1 : public PiPoCo
{
		
	public :
	
		// CONSTRUCTEURS :
		// Constructeur par defaut
		PoutSimple1 ();  
		
		// Constructeur fonction de la hauteur, la largeur et eventuellement d'un numero
		// d'identification 
		PoutSimple1 (double epais,double larg,int num_mail=0,int num_id=-3);
		
		// Constructeur fonction  d'un numero de maillage et d'identification  
		PoutSimple1 (int num_mail,int num_id);
		
		// Constructeur fonction de la hauteur, la largeur, d'un numero d'identification,
		// du tableau de connexite des noeuds 
		PoutSimple1 (double epais,double larg,int num_mail,int num_id,const Tableau<Noeud *>& tab);
		
		// Constructeur de copie
		PoutSimple1 (const PoutSimple1& biel);
		
		
		// DESTRUCTEUR :
		~PoutSimple1 ();
				
		// création d'un élément de copie: utilisation de l'opérateur new et du constructeur de copie 
		// méthode virtuelle
  Element* Nevez_copie() const { Element * el= new PoutSimple1(*this); return el;};

		// Surcharge de l'operateur = : realise l'egalite entre deux instances de PoutSimple1
		PoutSimple1& operator= (PoutSimple1& pout);
		
		// METHODES :
  // 1) derivant des virtuelles pures
		// Lecture des donnees de la classe sur fichier
		void LectureDonneesParticulieres (UtilLecture *,Tableau<Noeud  *> * );
		        
	 // affichage d'info en fonction de ordre
	 // ordre = "commande" : affichage d'un exemple d'entree pour l'élément
  void Info_com_Element(UtilLecture * entreePrinc,string& ordre,Tableau<Noeud  *> * tabMaillageNoeud)
       { return Element::Info_com_El(2,entreePrinc,ordre,tabMaillageNoeud);};
        
		// Calcul du residu local et de la raideur locale,
		//  pour le schema implicite
		Element::ResRaid  Calcul_implicit (const ParaAlgoControle & pa);
		
		// Calcul du residu local a t
		// pour le schema explicit par exemple 
		Vecteur* CalculResidu_t (const ParaAlgoControle & pa)
		  { return PoutSimple1::CalculResidu(false,pa);};
		
		// Calcul du residu local a tdt
		// pour le schema explicit par exemple 
		Vecteur* CalculResidu_tdt (const ParaAlgoControle & pa)
		  { return PoutSimple1::CalculResidu(true,pa);};
		
  // Calcul de la matrice masse pour l'élément
  Mat_pleine * CalculMatriceMasse (Enum_calcul_masse id_calcul_masse) ;

  // --------- calcul dynamique ---------
  // calcul  de la longueur d'arrête de l'élément minimal
  // divisé par la célérité  la plus rapide dans le matériau
  double Long_arrete_mini_sur_c(Enum_dure temps)
       { return ElemMeca::Interne_Long_arrete_mini_sur_c(temps);};

		// retourne les tableaux de ddl associés aux noeuds, gere par l'element
		// ce tableau et specifique a l'element
		const DdlElement & TableauDdl() const ;

                         
  // actualisation des ddl et des grandeurs actives de t+dt vers t
  void TdtversT();
  // actualisation des ddl et des grandeurs actives de t vers tdt
  void TversTdt();

		// Libere la place occupee par le residu et eventuellement la raideur
		// par l'appel de Libere de la classe mere et libere les differents tenseurs
		// intermediaires cree pour le calcul et les grandeurs pointee
		// de la raideur et du residu
		void Libere ();
		
		// acquisition  d'une loi de comportement
		void DefLoi (LoiAbstraiteGeneral * NouvelleLoi);

       // test si l'element est complet
       // = 1 tout est ok, =0 element incomplet
		int TestComplet();
		
		// procesure permettant de completer l'element apres
		// sa creation avec les donnees du bloc transmis
		// peut etre appeler plusieurs fois
		Element* Complete(BlocGen & bloc,LesFonctions_nD*  lesFonctionsnD);                         
		// Compléter pour la mise en place de la gestion de l'hourglass
		Element* Complet_Hourglass(LoiAbstraiteGeneral * NouvelleLoi, const BlocGen & bloc) {return this;};

		// ramene l'element geometrique 
		ElemGeomC0& ElementGeometrique() const { return doCoPS1->segmentL;};
		// ramene l'element geometrique en constant
		const ElemGeomC0& ElementGeometrique_const() const { return doCoPS1->segmentL;}; 
		
		// calcul d'un point dans l'élément réel en fonction des coordonnées dans l'élément de référence associé
		// temps: indique si l'on veut les coordonnées à t = 0, ou t ou tdt
		// 1) cas où l'on utilise la place passée en argument
		Coordonnee & Point_physique(const Coordonnee& c_int,Coordonnee & co,Enum_dure temps);
		// 3) cas où l'on veut les coordonnées aux trois temps
		void Point_physique(const Coordonnee& c_int,Tableau <Coordonnee> & t_co);

  // affichage dans la sortie transmise, des variables duales "nom"
  // dans le cas ou nom est vide, affichage de "toute" les variables
  void AfficheVarDual(ostream& sort, Tableau<string>& nom);

	//============= lecture écriture dans base info ==========
	
	 // cas donne le niveau de la récupération
     // = 1 : on récupère tout
     // = 2 : on récupère uniquement les données variables (supposées comme telles)
	 void Lecture_base_info
	     (istream& ent,const Tableau<Noeud  *> * tabMaillageNoeud,const int cas) ;
     // cas donne le niveau de sauvegarde
     // = 1 : on sauvegarde tout
     // = 2 : on sauvegarde uniquement les données variables (supposées comme telles)
	 void Ecriture_base_info(ostream& sort,const int cas) ;
 
  // définition du nombre maxi de point d'intégration dans l'épaisseur
  inline int Nb_pt_int_epai()
    { return doCoPS1->segmentL.Nbi();};
  // définition du nombre maxi de point d'intégration sur la surface ou
  // dans l'axe de la poutre
  inline int Nb_pt_int_surf()
    { return doCoPS1->segmentH.Nbi();};
  // récupération de l'épaisseur
  inline double H()
    { return donnee_specif.epaisseur;};
	    
// --------- calculs utils dans le cadre de la recherche du flambement linéaire		
		// Calcul de la matrice géométrique et initiale
		ElemMeca::MatGeomInit MatricesGeometrique_Et_Initiale (const ParaAlgoControle & pa) ;

  // inactive les ddl du problème primaire de mécanique
  inline void Inactive_ddl_primaire()
    {ElemMeca::Inact_ddl_primaire(doCoPS1->tab_ddl);};
  // active les ddl du problème primaire de mécanique
  inline void Active_ddl_primaire()
    {ElemMeca::Act_ddl_primaire(doCoPS1->tab_ddl);};
  // ajout des ddl de contraintes pour les noeuds de l'élément
  inline void Plus_ddl_Sigma()
    {ElemMeca::Ad_ddl_Sigma(doCoPS1->tab_ddlErr);};
  // inactive les ddl du problème de recherche d'erreur : les contraintes
  inline void Inactive_ddl_Sigma()
    {ElemMeca::Inact_ddl_Sigma(doCoPS1->tab_ddlErr);};
  // active les ddl du problème de recherche d'erreur : les contraintes
  inline void Active_ddl_Sigma()
    {ElemMeca::Act_ddl_Sigma(doCoPS1->tab_ddlErr);};
  // active le premier ddl du problème de recherche d'erreur : SIGMA11
  inline void Active_premier_ddl_Sigma()
    {ElemMeca::Act_premier_ddl_Sigma();};

  // lecture de données diverses sur le flot d'entrée
  void LectureContraintes(UtilLecture * entreePrinc)
   { if (CalculResidu_t_PoutSimple1_met_abstraite == 1)
       ElemMeca::LectureDesContraintes (false,entreePrinc,lesPtMecaInt.TabSigHH_t());
     else
       { ElemMeca::LectureDesContraintes (true,entreePrinc,lesPtMecaInt.TabSigHH_t());
         CalculResidu_t_PoutSimple1_met_abstraite = 1;
        }
    };
 
  // retour des contraintes en absolu retour true si elle existe sinon false
  bool ContraintesAbsolues(Tableau <Vecteur>& tabSig)
  { if (CalculResidu_t_PoutSimple1_met_abstraite == 1)
        ElemMeca::ContraintesEnAbsolues(false,lesPtMecaInt.TabSigHH_t(),tabSig);
    else
       { ElemMeca::ContraintesEnAbsolues(true,lesPtMecaInt.TabSigHH_t(),tabSig);
         CalculResidu_t_PoutSimple1_met_abstraite = 1;
        }
    return true; }
		
     // ========= définition et/ou construction des frontières ===============
     			
		// Calcul des frontieres de l'element
		//  creation des elements frontieres et retour du tableau de ces elements
		// la création n'a lieu qu'au premier appel
		// ou lorsque l'on force le paramètre force a true
		// dans ce dernier cas seul les frontière effacées sont recréée
		Tableau <ElFrontiere*> const & Frontiere(bool force = false);
		

		// Retourne la section de l'element
		double Section (Enum_dure , const Coordonnee& )
		       {	return donnee_specif.epaisseur * donnee_specif.largeur; 	};
        // ramène  la section moyenne de l'élément (indépendante du point)
        double SectionMoyenne(Enum_dure ) 
		       {	return donnee_specif.epaisseur * donnee_specif.largeur; 	};

// 2) methodes propres a l'element
		
		// Retourne la largeur de l'element
		inline double Largeur ()
		       {	return donnee_specif.largeur; 	};
		// Retourne la hauteur de l'element
		inline double Hauteur ()
		       {	return donnee_specif.epaisseur; 	};
	 // les coordonnees des points d'integration dans l'epaisseur
	 inline  double KSIepais(int i) { return doCoPS1->segmentH.KSI(i);};
		
		
  // ajout du tableau specific de ddl des noeuds de la  poutre
  // la procedure met a jour les ddl(relatif a l'element, c-a-d Xi)
  // des noeuds constituants l'element
  void ConstTabDdl();
        
protected:
    		
	  // ==== >>>> methodes virtuelles dérivant d'ElemMeca ============  
		 // ramene la dimension des tenseurs contraintes et déformations de l'élément
		 int Dim_sig_eps() const {return 1;}; 
	         
 // -------------------- calcul de frontières en protected -------------------
    
    //  --- fonction nécessaire pour la construction des Frontières linéiques ou surfaciques particulière à l'élément
    // adressage des frontières linéiques et surfacique
    // définit dans les classes dérivées, et utilisées pour la construction des frontières
    virtual ElFrontiere* new_frontiere_lin(int ,Tableau <Noeud *> & tab, DdlElement& ddelem)
      { return ((ElFrontiere*) (new FrontSegLine(tab,ddelem)));};
    virtual ElFrontiere* new_frontiere_surf(int ,Tableau <Noeud *> & tab, DdlElement& ddelem)
      {return NULL;} // il n'y a pas de surface possible
    
    
	private :

      // VARIABLES PRIVEES :
	    // les données spécifiques sont grouppées dans une structure pour sécuriser
	    // le passage de paramètre dans init par exemple 
	    class Donnee_specif{ public :
	    Donnee_specif() : 
	        epaisseur(epaisseur_defaut),largeur(largeur_defaut)
	           {};
	    Donnee_specif(double epaiss,double large) : 
	        epaisseur(epaiss),largeur(large) {};
	    Donnee_specif(const Donnee_specif& a) : 
	        epaisseur(a.epaisseur),largeur(a.largeur) {};
	    Donnee_specif & operator = ( const Donnee_specif& a)  
	        { epaisseur = a.epaisseur;largeur = a.largeur;
	          return *this;};
	    // data
     double epaisseur; // épaisseur de la poutre
     double largeur; // largeur de la poutre
	                        };
	    Donnee_specif donnee_specif; 
	    
	    // grandeurs aux points d'intégration: contraintes, déformations, vitesses de def etc.
	    LesPtIntegMecaInterne  lesPtMecaInt;
	    		
     static Tableau <TenseurBB *> d_epsBB;  // place de travail pour la variation des def
     static Tableau <TenseurHH *> d_sigHH;  // place pour la variation des contraintes

	    class DonnCommunPS1
	      { public :
	        DonnCommunPS1 (GeomSeg& segL,GeomSeg& segH,DdlElement& tab,
	                       Met_Pout2D&  met_bie,
	                       Tableau <Vecteur *> & resEr,Mat_pleine& raidEr,
	                       Mat_pleine&  mat_masse,int nbi);
	        DonnCommunPS1(DonnCommunPS1& a);
	        ~DonnCommunPS1();               
         // variables
         GeomSeg segmentL ; // element geometrique correspondant a l'axe
         GeomSeg segmentH ; // element geometrique correspondant a l'épaisseur
        
	        DdlElement  tab_ddl; // tableau des degres
                  //de liberte des noeuds de l'element commun a tous les
                  // elements
         Met_Pout2D  met_pout;
		       Mat_pleine  matGeom ; // matrice géométrique
         Mat_pleine  matInit  ; // matrice initiale
         Tableau < Tableau2 <TenseurBB *> > d2_epsBB; // variation seconde des déformations
              // calcul d'erreur
	        DdlElement  tab_ddlErr; // tableau des degres servant pour le calcul
	        // d'erreur : contraintes
        
         Tableau <Vecteur *>  resErr;  // residu pour le calcul d'erreur
         Mat_pleine  raidErr; // raideur pour le calcul d'erreur
         // ------ données concernant la dynamique --------
         Mat_pleine matrice_masse;
         // ------ blocage éventuel d'hourglass
         // utiliser dans ElemMeca::Cal_mat_hourglass_comp, Cal_implicit_hourglass, Cal_explici_hourglass
         GeomSeg* segmentHourg; // contiend les fonctions d'interpolation
      };
         
     // place memoire commune a tous les elements PoutSimple1
     static int nbNoeud ; // nombre de noeud
     static int nbintL ; // nombre de point d'intégration selon l'axe
     static int nbintH ; // nombre de point d'intégration selon l'épaisseur
     static Tableau <Vecteur>  tabD2phi; // par commodité
 
     static DonnCommunPS1 * doCoPS1;
     static int CalculResidu_t_PoutSimple1_met_abstraite;  // pour dim met_pout à t
     static int CalculResidu_tdt_PoutSimple1_met_abstraite;  // pour dim met_pout à tdt
     static int  Calcul_implicit_PoutSimple1_met_abstraite; //      "
     static int Calcul_VarDualSort; // pour la sortie des valeurs au pt d'integ
     static int  CalDynamique; // pour le calcul de la matrice de masse
     static int  CalPt_0_t_tdt; // pour le calcul de point à 0 t et tdt
     // pour l'ajout d'element dans la liste : listTypeElemen, geree par la class Element
     class ConstrucElementPoutSimple1 : public ConstrucElement
       { public :  ConstrucElementPoutSimple1 ()
            { NouvelleTypeElement nouv(PS1,CUBIQUE,MECA_SOLIDE_DEFORMABLE,this);
              if (ParaGlob::NiveauImpression() >= 4)
                 cout << "\n initialisation PoutSimple1" << endl;
              Element::listTypeElement.push_back(nouv);
             };
         Element * NouvelElement(int num_maill,int num) // un nouvel élément sans rien
            {Element * pt;
             pt  = new PoutSimple1 (num_maill,num) ;
             return pt;};
         // ramene true si la construction de l'element est possible en fonction
         // des variables globales actuelles: ex en fonction de la dimension
         bool Element_possible() { if (ParaGlob::Dimension() == 2) return true; else return false;};
       };
     static ConstrucElementPoutSimple1 construcElementPoutSimple1;
     // fonction privee
     void Def_DonnCommunPS1();
     // Calcul du residu local a t ou tdt en fonction du booleen
	    Vecteur* CalculResidu (bool atdt,const ParaAlgoControle & pa);
};
/// @}  // end of group
#endif
	
	
		

