

// 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 "CompThermoPhysiqueAbstraite.h"
#include "ExceptionsLoiComp.h"

		// CONSTRUCTEURS :
CompThermoPhysiqueAbstraite::CompThermoPhysiqueAbstraite () :  // Constructeur par defaut
    LoiAbstraiteGeneral(),saveResul(NULL),comp_tangent_simplifie(false)
    ,thermo_dependant(false),temperature(-1.)
		 { };
// Constructeur utile si l'identificateur du nom de la loi
// de comportement  et la dimension sont connus		
CompThermoPhysiqueAbstraite::CompThermoPhysiqueAbstraite (Enum_comp id_compor,Enum_categorie_loi_comp id_categorie
                                                          ,int dimension) :
     LoiAbstraiteGeneral(id_compor,dimension,id_categorie)
     ,saveResul(NULL),comp_tangent_simplifie(false)
     ,thermo_dependant(false),temperature(-1)
		{ };
		
// Constructeur utile si l'identificateur du nom de la loi
// de comportement et la dimension sont connus		
CompThermoPhysiqueAbstraite::CompThermoPhysiqueAbstraite (char* nom,Enum_categorie_loi_comp id_categorie
                                                          ,int dimension) :
     LoiAbstraiteGeneral(nom,dimension,id_categorie)
	 ,saveResul(NULL),comp_tangent_simplifie(false)
     ,thermo_dependant(false),temperature(-1)
	 	{ };

// Constructeur de copie
CompThermoPhysiqueAbstraite::CompThermoPhysiqueAbstraite (const CompThermoPhysiqueAbstraite & a ) :
		 LoiAbstraiteGeneral(a),comp_tangent_simplifie(false)
         ,saveResul(a.saveResul->Nevez_SaveResul())
         ,thermo_dependant(a.thermo_dependant),temperature(-1)
		   {} ;
		
// DESTRUCTEUR VIRTUEL :
CompThermoPhysiqueAbstraite::~CompThermoPhysiqueAbstraite ()
		{ 	};
		
	
// =============== methode de calcul ======================
		

// activation des données des noeuds et/ou elements nécessaires au fonctionnement de la loi
// exemple: mise en service des ddl de température aux noeuds
// méthode appelée par Activation_donnees principal, ou des classes dérivées
void CompThermoPhysiqueAbstraite::Activ_donnees(Tableau<Noeud *>& tabnoeud)
 { if (thermo_dependant)
    { // dans le cas où la loi est thermo dépendante on active les ddl de thermique
      int nbnoeud = tabnoeud.Taille();
      for (int i=1;i<=nbnoeud;i++)
        { // on vérifie que la variable TEMP existe sinon erreur
          if (tabnoeud(i)->Existe_ici(TEMP))
            {tabnoeud(i)->Met_en_service(TEMP);}
          else
            { cout << "\n erreur: la variable temperature n'existe pas "
                   << " il n'est pas possible d'utiliser une loi thermodependante "
                   << " il manque sans doute des donnees !!! "
                   << "\n CompThermoPhysiqueAbstraite::Activ_donnees(...";
              Sortie(1);
              }     
         }
     }
  };

 
// calcul de toutes les grandeurs associées à la température (mais pas le flux), qui sont stockées
// dans le point d'intégration : ptIntegThermi
void CompThermoPhysiqueAbstraite::Cal_cinematique_thermique
                                       (bool premier_calcul,PtIntegThermiInterne& ptIntegThermi
                                        ,Tableau <CoordonneeB >& d_gradTB
                                        ,Deformation & def, const Met_abstraite::Impli& ex)
{  // calcul de la température au point d'intégration
   if (premier_calcul)
       { // calcul de la température initiale interpolée
         saveResul->temperature_0 = def.DonneeInterpoleeScalaire(TEMP,TEMPS_0);
         ptIntegThermi.Temperature_t() = def.DonneeInterpoleeScalaire(TEMP,TEMPS_t);
       }
   ptIntegThermi.Temperature() = temperature = def.DonneeInterpoleeScalaire(TEMP,TEMPS_tdt);
   // calcul du gradient thermique au temps actuel et au temps t
   CoordonneeB interB(ptIntegThermi.GradTB()); // un vecteur de travail
   def.GradDonneeInterpoleeScalaire(interB,TEMP,TEMPS_t);
   def.GradDonneeInterpoleeScalaire(ptIntegThermi.GradTB(),TEMP,TEMPS_tdt);
   ptIntegThermi.DeltaGradTB() = ptIntegThermi.GradTB() - interB;
      // -- cas de la vitesse du gradient
   // recup de l'incrément de temps
	  double deltat=ParaGlob::Variables_de_temps().IncreTempsCourant();
   double unSurDeltat=0;    
	  if (Abs(deltat) >= ConstMath::trespetit)
     { unSurDeltat = 1./deltat;}
   else
       // si l'incrément de temps est tres petit on remplace 1/deltat par un nombre tres grand
     { // un pas de temps doit être positif !! or certaine fois il peut y avoir des pb
       if (unSurDeltat < 0)
        { cout << "\n le pas de temps est négatif !! "; };
       unSurDeltat = ConstMath::tresgrand;
     };
   ptIntegThermi.DgradTB() = ptIntegThermi.DeltaGradTB() * unSurDeltat;
   // la variation du gradient / au ddl de thermique
   def.DerGradDonneeInterpoleeScalaire(d_gradTB,TEMP);
 
   // les invariants:
   ptIntegThermi.Norme_gradT() = ptIntegThermi.GradTB() * (*ex.gijHH_tdt) * ptIntegThermi.GradTB();
   ptIntegThermi.Norme_DGradT() = ptIntegThermi.DgradTB() * (*ex.gijHH_tdt) * ptIntegThermi.DgradTB();

};

  // schema implicit
  // P et P_t : pression actuelle et pression à t
 const Met_abstraite::Impli& CompThermoPhysiqueAbstraite::Cal_implicit
                 (const double & P_t,CompThermoPhysiqueAbstraite::SaveResul * saveTP
                  , const double & P,Deformation & def,DdlElement & tab_ddl
	                 ,PtIntegThermiInterne& ptIntegThermi, Tableau <CoordonneeB >& d_gradTB
		  	             ,Tableau <CoordonneeH >& d_fluxH,const ParaAlgoControle & pa
		  	             ,CompThermoPhysiqueAbstraite* loiTP
		  	             ,bool dilat,EnergieThermi & energ,const EnergieThermi & energ_t,bool premier_calcul
                  )
  {
     Temps_CPU_HZpp&  temps_cpu_loi = ptIntegThermi.Tps_cpu_loi_comp();
     temps_cpu_loi.Mise_en_route_du_comptage(); // spécifique pti
     temps_loi.Mise_en_route_du_comptage(); // spécifique loi
     // passage des infos specifiques aux classes derivantes
     saveResul = saveTP  ;
	  
     // récup des flux et gradients
/*     CoordonneeH & fluxH = (ptIntegThermi.FluxH()); // ici _tdt est la grandeur finale
     CoordonneeH & fluxH_t = (ptIntegThermi.FluxH_t()); // ici _tdt est la grandeur finale
     CoordonneeB & gradTB_tdt = (ptIntegThermi.GradTB());
     CoordonneeB & DgradTB_ = (ptIntegThermi.DgradTB());
     CoordonneeB & delta_gradTB = (ptIntegThermi.DeltaGradTB());
//     dilatation=dilat; // pour l'instant je ne sais pas si c'est utile
*/
   
     // calcul de : epsBB_tdt, delta_epsBB,gijBB_tdt, gijHH_tdt, d_gijBB_tdt,
     //	        	 d_gijHH_tdt,jacobien,d_jacobien_tdt
     Temps_CPU_HZpp&  temps_cpu_metrique = ptIntegThermi.TpsMetrique();
     temps_cpu_metrique.Mise_en_route_du_comptage(); // cpu
//     bool calcul_varD_ddl = false;// a priori on ne veut pas de vitesse de def
     // appel de la métrique pour un calcul autre que mécanique
//     bool avec_var_Xi = false;
     const Met_abstraite::Impli& ex = def.Cal_implicit(premier_calcul,false);   
     temps_cpu_metrique.Arret_du_comptage(); // cpu
   
     // calcul des grandeurs associées à la température (mais pas le flux), qui sont stockées
     // dans le point d'intégration
     // calcul de toutes les grandeurs associées à la température (mais pas le flux), qui sont stockées
     // dans le point d'intégration : ptIntegThermi
     // et de la variation du gradient thermique / au ddl
     Cal_cinematique_thermique(premier_calcul,ptIntegThermi,d_gradTB,def,ex);
   

//     // demande dans les  classes dérivées du calcul de grandeurs spécifiques si besoin est
//     ThermoDonnee dTP; // init à 0 par défaut
//     loiTP->Cal_donnees_thermiques(P_t,saveTP,def,P,TEMPS_tdt,dTP);
     // demande dans les  classes dérivées du calcul de grandeurs spécifiques si besoin est
     CalculGrandeurTravail(ptIntegThermi,def,TEMPS_tdt);
     // calcul du flux et de sa variation / aux ddl, calcul également des paramètres thermiques dTP
     // ainsi que des énergies mises en jeux
     ThermoDonnee dTP; // init à 0 par défaut
     // on gère les exceptions éventuelles en mettant le bloc sous surveillance
     try 
      { Calcul_DfluxH_tdt(P_t,ptIntegThermi,P,tab_ddl,def,
                          d_gradTB, d_fluxH,dTP, energ, energ_t,ex);
      }
     catch (ErrSortieFinale)
          // cas d'une direction voulue vers la sortie
          // on relance l'interuption pour le niveau supérieur
        { ErrSortieFinale toto;
          throw (toto);
        }
     catch ( ... )  // cas d'une erreur dans la recherche de la contrainte
      { throw ErrNonConvergence_loiDeComportement();
        if (ParaGlob::NiveauImpression() >= 1)
          {cout << "\n warning: exception generee par la loi de comportement ";
           if (ParaGlob::NiveauImpression() >= 4) cout <<  "\n Loi_comp_abstraite::Cal_implicit(..";
          };
      };                	                             
     temps_cpu_loi.Arret_du_comptage(); // cpu spécifique pti
     temps_loi.Arret_du_comptage(); // cpu spécifique loi
   
     // retour
     return ex; // retour de la métrique
  };

