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

#ifndef _GENDERIVEOP_H_
#define _GENDERIVEOP_H_

#include "genTerm.h"
#include "genTraits.h"
#include "genOperators.h"
#include "genTermApply.h"

#include "dfloat.h"

template< class scalar> class DeriveOp
{
  public :
  typedef typename scalar::FPType ValType;
  void operator ()(const scalar  &a,  ValType &r) const 
  {
    r=a.dv;
  }
};

template<class scalar,int N> class DeriveOp<genTensor0<scalar,N> >
{
public :
  typedef genTensor0<typename scalar::FPType,N> ValType;
  void operator ()( const genTensor0<scalar,N>  &a, ValType &r) const 
  {
      r()=a().dv;
  }
};

template<class scalar,int N> class DeriveOp<genTensor1<scalar,N> >
{
public :
  typedef genTensor1<typename scalar::FPType,N> ValType;
  void operator ()( const genTensor1<scalar,N>  &a, ValType &r) const 
  {
    for (int i=0;i<N;++i)
      r(i)=a(i).dv;
  }
};

template<class scalar,int N> class DeriveOp<genTensor2<scalar,N> >
{
public :
  typedef genTensor2<typename scalar::FPType,N> ValType;
  void operator ()( const genTensor2<scalar,N>  &a, ValType &r) const 
  {
    for (int i=0;i<N;++i)
      for (int j=0;j<N;++j)
        r(i,j)=a(i,j).dv;
  }
};

template<class scalar,int N> class DeriveOp<genTensor3<scalar,N> >
{
public :
  typedef genTensor3<typename scalar::FPType,N> ValType;
  void operator ()( const genTensor3<scalar,N>  &a, ValType &r) const 
  {
    for (int i=0;i<N;++i)
      for (int j=0;j<N;++j)
        for (int k=0;k<N;++k)
          r(i,j,k)=a(i,j,k).dv;
  }
};

template<class scalar,int N> class DeriveOp<genTensor4<scalar,N> >
{
public :
  typedef genTensor4<typename scalar::FPType,N> ValType;
  void operator ()( const genTensor4<scalar,N>  &a, ValType &r) const 
  {
    for (int i=0;i<N;++i)
      for (int j=0;j<N;++j)
        for (int k=0;k<N;++k)
          for (int l=0;l<N;++l)
            r(i,j,k,l)=a(i,j,k,l).dv;
  }
};


template<class GT2> std::shared_ptr<genTerm<typename DeriveOp<typename GT2::ValType>::ValType,GT2::Nsp > > Derive(const std::shared_ptr<GT2> &gt)
{
  return Apply(gt,DeriveOp<typename GT2::ValType>());
}


template< class scalar> class NominalOp
{
  public :
  typedef typename scalar::FPType ValType;
  void operator ()(const scalar  &a,  ValType &r) const 
  {
    r=a.v;
  }
};

template<class scalar,int N> class NominalOp<genTensor0<scalar,N> >
{
public :
  typedef genTensor0<typename scalar::FPType,N> ValType;
  void operator ()( const genTensor0<scalar,N>  &a, ValType &r) const 
  {
    r()=a().v;
  }
};

template<class scalar,int N> class NominalOp<genTensor1<scalar,N> >
{
public :
  typedef genTensor1<typename scalar::FPType,N> ValType;
  void operator ()( const genTensor1<scalar,N>  &a, ValType &r) const 
  {
    for (int i=0;i<N;++i)
      r(i)=a(i).v;
  }
};

template<class scalar,int N> class NominalOp<genTensor2<scalar,N> >
{
public :
  typedef genTensor2<typename scalar::FPType,N> ValType;
  void operator ()( const genTensor2<scalar,N>  &a, ValType &r) const 
  {
    for (int i=0;i<N;++i)
      for (int j=0;j<N;++j)
        r(i,j)=a(i,j).v;
  }
};

template<class scalar,int N> class NominalOp<genTensor3<scalar,N> >
{
public :
  typedef genTensor3<typename scalar::FPType,N> ValType;template< template <class TA> class OP,
          class GT1> 
  void operator ()( const genTensor3<scalar,N>  &a, ValType &r) const 
  {
    for (int i=0;i<N;++i)
      for (int j=0;j<N;++j)
        for (int k=0;k<N;++k)
          r(i,j,k)=a(i,j,k).v;
  }
};

template<class scalar,int N> class NominalOp<genTensor4<scalar,N> >
{
public :
  typedef genTensor4<typename scalar::FPType,N> ValType;
  void operator ()( const genTensor4<scalar,N>  &a, ValType &r) const 
  {
    for (int i=0;i<N;++i)
      for (int j=0;j<N;++j)
        for (int k=0;k<N;++k)
          for (int l=0;l<N;++l)
            r(i,j,k,l)=a(i,j,k,l).v;
  }
};



template<class GT2> std::shared_ptr<genTerm<typename NominalOp<typename GT2::ValType>::ValType,GT2::Nsp > > Nominal(const std::shared_ptr<GT2> &gt)
{
  return Apply(gt,NominalOp<typename GT2::ValType>());
}



#endif // _GENDERIVEOP_H_