// GenFem - A high-level finite element library
// 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>.
//
// Initial design: Frederic Duboeuf (rev.659)


#include "savedDiffTerm.h"
#include "genFSpace.h"
#include <cassert>
#include <cstdio>

template<class T> void SavedDiffTerm<T>::get(MElement* ele, int npts, IntPt* GP, std::vector<ContainerValType> &vvals) const
{
  std::vector<Dof> D;
  fs->getKeys(ele, D);

  int nbdofs = D.size();
  typename ContainerTraits<double,1>::Container Dofvals;
  Dofvals.resize(nbdofs);
  std::map<Dof, double>::const_iterator itvals;
  for (int i=0; i<nbdofs; ++i)
  {
    itvals = mapval.find(D[i]);
    assert(itvals != mapval.end());
    Dofvals(i) = itvals->second;
  }

  std::vector< typename genFSpace<T>::ContainerValType > vFSvals(npts);
  fs->get(ele, npts, GP, vFSvals);

  int curpos = 0;
  for (unsigned int i = 0; i < npts; ++i)
  {
    vvals[i]=ContainerValType();
    for (unsigned int j = 0; j < nbdofs; ++j)
      vvals[i]() += vFSvals[i](j) * Dofvals(j);
  }
}

template<class T> void SavedDiffTerm<T>::get(MElement* ele, int npts, IntPt* GP, ContainerValType &vals) const
{
  diffTerm<T,0>::get(ele,npts,GP,vals);
}

template<class T> void SavedDiffTerm<T>::getgradf(MElement* ele, int npts, IntPt* GP, std::vector< ContainerGradType > &vgrads) const
{
  std::vector<Dof> D;
  fs->getKeys(ele, D);

  int nbdofs = D.size();
  typename ContainerTraits<double,1>::Container Dofvals;
  Dofvals.resize(nbdofs);
  std::map<Dof, double>::const_iterator itvals;
  for (int i=0; i<nbdofs; ++i)
  {
    itvals = mapval.find(D[i]);
    assert(itvals != mapval.end());
    Dofvals(i) = itvals->second;
  }

  std::vector< typename genFSpace<T>::ContainerGradType > vFSgrads(npts);
  fs->getgradf(ele, npts, GP, vFSgrads);

  int curpos = 0;
  for (unsigned int i = 0; i < npts; ++i)
  {
    vgrads[i]=ContainerGradType();
    for (unsigned int j = 0; j < nbdofs; ++j)
      vgrads[i]() += vFSgrads[i](j) * Dofvals(j);
  }
}

template<class T> void SavedDiffTerm<T>::getgradf(MElement* ele, int npts, IntPt* GP, ContainerGradType &grads) const
{
  typename genTerm<GradType,0>::ConstHandle GG(Gradient(typename diffTerm<T,0>::ConstHandle(this,NoDelete())));
  GG->get(ele,npts,GP,grads);
}

template<class T> void SavedDiffTerm<T>::getgradfuvw(MElement* ele, int npts, IntPt* GP, std::vector< ContainerGradType > &vgrads) const
{
  std::vector<Dof> D;
  fs->getKeys(ele, D);

  int nbdofs = D.size();
  typename ContainerTraits<double,1>::Container Dofvals;
  Dofvals.resize(nbdofs);
  std::map<Dof, double>::const_iterator itvals;
  for (int i=0; i<nbdofs; ++i)
  {
    itvals = mapval.find(D[i]);
    assert(itvals != mapval.end());
    Dofvals(i) = itvals->second;
  }

  std::vector< typename genFSpace<T>::ContainerGradType > vFSgrads(npts);
  fs->getgradfuvw(ele, npts, GP, vFSgrads);

  int curpos = 0;
  for (unsigned int i = 0; i < npts; ++i)
  {
    vgrads[i]=ContainerGradType();
    for (unsigned int j = 0; j < nbdofs; ++j)
      vgrads[i]() += vFSgrads[i](j) * Dofvals(j);
  }
}

template<class T> void SavedDiffTerm<T>::gethessf(MElement* ele, int npts, IntPt* GP, std::vector< ContainerHessType > &vhesss) const
{
  std::vector<Dof> D;
  fs->getKeys(ele, D);

  int nbdofs = D.size();
  typename ContainerTraits<double,1>::Container Dofvals;
  Dofvals.resize(nbdofs);
  std::map<Dof, double>::const_iterator itvals;
  for (int i=0; i<nbdofs; ++i)
  {
    itvals = mapval.find(D[i]);
    assert(itvals != mapval.end());
    Dofvals(i) = itvals->second;
  }

  std::vector< typename genFSpace<T>::ContainerHessType > vFShesss(npts);
  fs->gethessf(ele, npts, GP, vFShesss);

  int curpos = 0;
  for (unsigned int i = 0; i < npts; ++i)
  {
    vhesss[i]=ContainerHessType();
    for (unsigned int j = 0; j < nbdofs; ++j)
      vhesss[i]() += vFShesss[i](j) * Dofvals(j);
  }
}

template<class T> void SavedDiffTerm<T>::gethessf(MElement* ele, int npts, IntPt* GP, ContainerHessType &hesss) const
{
  typename genTerm<HessType,0>::ConstHandle HH(Hessian(typename diffTerm<T,0>::ConstHandle(this,NoDelete())));
  HH->get(ele,npts,GP,hesss);
}



template<class T> void SavedDiffTerm<T>::set(MElement* ele, int nbdofs, std::vector<Dof> &D, typename ContainerTraits<genTensor0<double>,1>::Container &Dofvals)
{
  for (int i=0; i<nbdofs; ++i)
  {
    mapval[D[i]] = Dofvals(i);
  }
}


template<class T> void SavedDiffTerm<T>::print(const char* name)
{
  printf("\n");
  printf("Print %s, size %d :\n", name, (int)mapval.size());
  std::map< Dof, double >::const_iterator it;
  for ( it=mapval.begin(); it!=mapval.end(); it++)
  {
    Dof d = it->first;
    long int entity = d.getEntity();
    int type = d.getType();
    double val = it->second;
    printf(" Entity : %ld, Type : %d\n", entity, type);
    PrintOp(val);
  }
}

template<class T> void SavedDiffTerm<T>::printfile(const char* name)
{
  char fileName [50];
  sprintf(fileName,"%s.txt", name);
  printf("Printfile %s\n", fileName);
  FILE* f = fopen (fileName, "w" );
  fprintf ( f,"Print %s, size %d :\n", name, (int)mapval.size());
  std::map< Dof, double >::const_iterator it;
  for ( it=mapval.begin(); it!=mapval.end(); it++)
  {
    Dof d = it->first;
    long int entity = d.getEntity();
    int type = d.getType();
    double val = it->second;
    fprintf( f," Entity : %ld, Type : %d, Value : %12.5E\n", entity, type, val);
  }
  fclose ( f );
}
