// elastic_genTerm - A linear solver for elastic problems using FEM & new genTensors
// Copyright (C) 2010-2026 Eric Bechet
//
// See the LICENSE file for license information and contributions.
// Please report all bugs and problems to <bechet@cadxfem.org>.

#ifndef _ELASTIC_SOLVER_NGT_H_
#define _ELASTIC_SOLVER_NGT_H_

#include <memory>
#include "dofManager.h"
#include "genTerm.h"
#include "genSolver.h"
#include "elasticDomain_ngt.h"
#include "genFSpace.h"


class ElasticSolver_ngt : public genSolver
{
protected :
  dofManager<double>* pAssembler;
  genDataIONG *Data;
  // function spaces
  genFSpace<genTensor<1,double> >::Handle FSpaceDisp;
  genTerm<genTensor<2,double>,1>::Handle EpsilonDisp;

  // supports for elastic
  std::vector<ElasticDomain_ngt*> EDomains;

  // model name
  std::string modelname;

public :
  ElasticSolver_ngt() : genSolver(), pAssembler(0),Data(0) {initData();}
  virtual void initData() {if (!Data) Data = new genDataIONG;}
  virtual ~ElasticSolver_ngt();
  //read data file
  virtual void readInputFile(const std::string &fileName);
  // builds local supports
  virtual void CheckProperties();
  // build the problem function spaces
  virtual void CreateFunctionSpaces();
  virtual void BuildFunctionSpaces();
  // assemble the problem
  virtual void AssembleRHS();
  virtual void AssembleLHS();
  virtual void BuildLinearSystem();

  // export K.txt b.txt in file
  virtual void exportKb();
  virtual void exportKbCompressed();
  virtual void exportKbToMatrixMarketFormat();
  virtual void solve();
  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);
  
 #if defined(HAVE_POST)
template<class T,class S> PView* buildViewNodal(const std::vector<std::shared_ptr<const genTerm<T,0> > > &Fields, const std::vector<S*> &sup, const std::string &postFileName)
{
  assert(Fields.size()==sup.size());

  // store the field values <vertex,value>
  std::map<int, std::vector<double> > data;
  buildDataNodal(Fields, sup, data);

  int numComp = vectorize(T()).size();
  PView* pv = new PView (postFileName, "NodeData", Data->Model, data, 0., numComp);

  return pv;
}

template<class T,class S> PView* buildViewElement(const std::vector<std::shared_ptr<const genTerm<T,0> > > &Fields, const std::vector<S*> &sup, const std::string &postFileName)
{
  assert(Fields.size()==sup.size());

  std::map<int, std::vector<double> > data;
  buildDataElement(Fields, sup, data);

  int numComp = vectorize(T()).size();
  PView* pv = new PView (postFileName, "ElementData", Data->Model, data, 0., numComp);

  return pv;
}

template<class T,class S> PView* buildViewElementNode(const std::vector<std::shared_ptr<const genTerm<T,0> > > &Fields, const std::vector<S*> &sup, const std::string &postFileName)
{
  assert(Fields.size()==sup.size());

  std::map<int, std::vector<double> > data;
  buildDataElementNode(Fields, sup, data);

  int numComp = vectorize(T()).size();
  PView* pv = new PView (postFileName, "ElementNodeData", Data->Model, data, 0., numComp);

  return pv;
}


template<class T,class S> PView* buildViewNodalStep(const std::vector<std::shared_ptr<const genTerm<T,0> > > &Fields, const std::vector<S*> &sup, const std::string &postFileName, PView* pv, double step)
{
  assert(Fields.size()==sup.size());

  // store the field values <vertex,value>
  std::map<int, std::vector<double> > data;
  buildDataNodal(Fields, sup, data);

  int numComp = vectorize(T()).size();
  if (!pv)
    pv = new PView (postFileName, "NodeData", Data->Model, data, step, numComp);
  else
    pv->addStep(Data->Model, data, step, numComp);

  return pv;
}

template<class T,class S> PView* buildViewElementStep(const std::vector<std::shared_ptr<const genTerm<T,0> > > &Fields, const std::vector<S*> &sup, const std::string &postFileName, PView* pv, double step)
{
  assert(Fields.size()==sup.size());

  std::map<int, std::vector<double> > data;
  buildDataElement(Fields, sup, data);

  int numComp = vectorize(T()).size();
  if (!pv)
    pv = new PView (postFileName, "ElementData", Data->Model, data, step, numComp);
  else
    pv->addStep(Data->Model, data, step, numComp);

  return pv;
}

template<class T,class S> PView* buildViewElementNodeStep(const std::vector<std::shared_ptr<const genTerm<T,0> > > &Fields, const std::vector<S*> &sup, const std::string &postFileName, PView* pv, double step)
{
  assert(Fields.size()==sup.size());

  std::map<int, std::vector<double> > data;
  buildDataElementNode(Fields, sup, data);

  int numComp = vectorize(T()).size();
  if (!pv)
    pv = new PView (postFileName, "ElementNodeData", Data->Model, data, step, numComp);
  else
    pv->addStep(Data->Model, data, step, numComp);

  return pv;
}

#else
template<class T,class S> PView* buildViewNodal(const std::vector<std::shared_ptr<const genTerm<T,0> > > &Fields, const std::vector<S*> &sup, const std::string &postFileName)
{
  Msg::Error ( "Post-pro module not available" );
  return 0;
}

template<class T,class S> PView* buildViewElement(const std::vector<std::shared_ptr<const genTerm<T,0> > > &Fields, const std::vector<S*> &sup, const std::string &postFileName)
{
  Msg::Error ( "Post-pro module not available" );
  return 0;
}

template<class T,class S> PView* buildViewElementNode(const std::vector<std::shared_ptr<const genTerm<T,0> > > &Fields, const std::vector<S*> &sup, const std::string &postFileName)
{
  Msg::Error ( "Post-pro module not available" );
  return 0;
}


template<class T,class S> PView* buildViewNodalStep(const std::vector<std::shared_ptr<const genTerm<T,0> > > &Fields, const std::vector<S*> &sup, const std::string &postFileName, PView* pv, double step)
{
  Msg::Error ( "Post-pro module not available" );
  return 0;
}

template<class T,class S> PView* buildViewElementStep(const std::vector<std::shared_ptr<const genTerm<T,0> > > &Fields, const std::vector<S*> &sup, const std::string &postFileName, PView* pv, double step)
{
  Msg::Error ( "Post-pro module not available" );
  return 0;
}

template<class T,class S> PView* buildViewElementNodeStep(const std::vector<std::shared_ptr<const genTerm<T,0> > > &Fields, const std::vector<S*> &sup, const std::string &postFileName, PView* pv, double step)
{
  Msg::Error ( "Post-pro module not available" );
  return 0;
}
#endif


  // one Field version
template<class T,class S> PView* buildViewNodal(const std::shared_ptr<const genTerm<T,0> > &Field, const std::vector<S*> &sup, const std::string &postFileName)
{
  std::vector<std::shared_ptr<const genTerm<T,0> > > Fields(sup.size(),Field);
  return buildViewNodal(Fields, sup, postFileName);
}

template<class T,class S> PView* buildViewElement(const std::shared_ptr<const genTerm<T,0> > &Field, const std::vector<S*> &sup, const std::string &postFileName)
{
  std::vector<std::shared_ptr<const genTerm<T,0> > > Fields(sup.size(),Field);
  return buildViewElement(Fields, sup, postFileName);
}

template<class T,class S> PView* buildViewElementNode(const std::shared_ptr<const genTerm<T,0> > &Field, const std::vector<S*> &sup, const std::string &postFileName)
{
  std::vector<std::shared_ptr<const genTerm<T,0> > > Fields(sup.size(),Field);
  return buildViewElementNode(Fields, sup, postFileName);
}

  
};

#endif //_ELASTIC_SOLVER_NGT_H_
