// Nonlinear_genTerm - A solver for nonlinear problems using FEM
// Copyright (C) 2010-2026 Eric Bechet, Frederic Duboeuf
//
// See the LICENSE file for license information and contributions.
// Please report all bugs and problems to <bechet@cadxfem.org> or <duboeuf@outlook.com>.

#ifndef _NONLINEAR_SOLVER_H_
#define _NONLINEAR_SOLVER_H_

#include <memory>
#include "dofManager.h"
#include "genTerm.h"
#include "genSolver.h"
#include "nonLinearDomain.h"
#include "genCache.h"
#include "savedGenTermManager.h"
#include "genFSpace.h"
#include "genSField.h"


//#define LARGE_STRAIN
//#define PRINT_DATA

template<class GT> void printData(const std::shared_ptr<GT> &term, const std::string &name, int i=-1)
{
#if defined(PRINT_DATA)
  std::ostringstream o_name;
  if (i!=-1) o_name << "data_" << name << "_" << i << ".txt";
  else o_name << "data_" << name << ".txt";
  term->printfile(o_name.str());
#endif
}


class NonLinearSolver : public genSolver
{
protected :
  dofManager<double>* pAssembler;
  // function spaces
  std::vector<genFSpace<genTensor1<double> >::Handle> FSpaceDisps;
//   genFSpace<genTensor1<double> >::Handle FSpaceDisp;
  std::vector<genTerm<genTensor2<double>,1>::Handle> dEpsilonDisps;
//   genTerm<genTensor2<double> ,1>::Handle dEpsilonDisp;
  std::vector<genTerm<genTensor2<double>,2>::Handle> dEpsilonNLDisps;
//   genTerm<genTensor2<double> ,2>::Handle dEpsilonNLDisp;

  // supports for elastic
  std::vector<NLElasticDomain*> EDomains;
  std::vector<genBoundaryCondition*> FinalBCs;
  std::vector<std::vector<genGroupOfElements*> > CombineBCatDomain;
  
  // model name
  std::string modelname;

  // genTerm manager
  SavedGenTermManager savedGenTermManager;

  int _step;
  int _iter;

public :
  NonLinearSolver() : genSolver(), pAssembler(0) { }
  virtual ~NonLinearSolver();
  //read data file
  virtual void readInputFile(const std::string &fileName);
  // builds local supports
  virtual void CheckProperties();
  // init and update SavedField
  virtual void InitField();
  virtual void CopyField();
  virtual void SaveField();
  // build the problem boundary conditions
  virtual void BuildDirichlet(double facDirichlet);
  virtual void BuildNeumann(double facNeumann);
  // build the initial problem function spaces
  virtual void BuildInitialFunctionSpaces();
  // assemble the initial problem
  virtual void AssembleInitialRHS();
  virtual void AssembleInitialLHS();
  virtual void BuildInitialLinearSystem();
  // build the problem function spaces
  virtual void BuildFunctionSpaces();
  // assemble the problem
  virtual void AssembleRHS();
  virtual void AssembleLHS();
  virtual void BuildLinearSystem();
  // precision
  virtual void InitCriteria();
  virtual void MaxCriterion(const genSField<genTensor1<double> > &SField, double &retnorm);
  virtual bool ValidateCriterion(const genSField<genTensor1<double> > &SField, genSupport &Domain, const double &criterion, double &retnorm);
  virtual bool ValidateCriterion(const dofManager<double>* assembler, const double &criterion, double &retnorm);
  virtual void NormDispIncr(double &normDisp);
  virtual bool DispIncrCriterion(const double &criter, double &normDispIncr);
  virtual void NormResidualForce(double &normForce);
  virtual bool ResidualForceCriterion(const double &criter, double &normResidual);
  virtual bool StoppingCriteria();
  // assemble the residu
  virtual void AssembleInitDisp();
  virtual void AssembleResidual();
  virtual void AssembleEnergy();
  // export K.txt b.txt in file
  virtual void exportKb();
  virtual void exportKb(int step,int iter);
  // export x.txt in file
  virtual void exportx();
  virtual void exportx(int step,int iter);
  virtual void solve();
  virtual void postprocessing(int step);
  virtual PView* buildDisplacementView(const std::string &postFileName);
  virtual PView* buildElasticEnergyView(const std::string &postFileName);
  virtual PView* buildStressView(const std::string &postFileName);
  virtual PView* buildStrainView(const std::string &postFileName);
};


#endif //_NONLINEAR_SOLVER_H_
