// 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: Eric Bechet (rev.1007)


#ifndef _GEN_TENSORBUILD__H_
#define _GEN_TENSORBUILD__H_

#include "genTensors.h"


template<class T1,class T2=T1> class BuildFromOneOp
{
  public :
/*  typedef scalar2 ValType;
  void operator()(const scalar &a,  ValType &r) const
  {
    r=scalar2(a);
  }*/
};

// new genTensor

template<int order,class scalar,class scalar2,int N1,int N2> class BuildFromOneOp<genTensor<order,scalar,N1>, genTensor<order,scalar2,N2> >
{
public :
  typedef genTensor<order,scalar2,N2> ValType;
  void operator()(const genTensor0<scalar,N1> &a, ValType &r) const
  {
    const int N=(N1>N2)?N2:N1;
    genIndices<order,N> ndx;
    genIndices<order,N1> ndx1;
    genIndices<order,N2> ndx2;
    for (;++ndx;!ndx.Overflow())
    {
      ndx1.copyIndices(ndx);
      ndx2.copyIndices(ndx);
      r(ndx2)=scalar2(a(ndx1));
    }
  }
};


template<class scalar,class scalar2,int N1,int N2> class BuildFromOneOp<genTensor0<scalar,N1>, genTensor0<scalar2,N2> >
{
public :
  typedef genTensor0<scalar2,N2> ValType;
  void operator()(const genTensor0<scalar,N1> &a, ValType &r) const
  {
    r()=scalar2(a());
  }
};

template<class scalar,class scalar2,int N1,int N2> class BuildFromOneOp<genTensor1<scalar,N1>, genTensor1<scalar2,N2> >
{
public :
  typedef genTensor1<scalar2,N2> ValType;
  void operator()(const genTensor1<scalar,N1> &a, ValType &r) const
  {
    int N=(N1>N2)?N2:N1;
    for (int i=0;i<N;++i)
      r(i)=scalar2(a(i));
  }
};

template<class scalar,class scalar2,int N1,int N2 > class BuildFromOneOp<genTensor2<scalar,N1>, genTensor2<scalar2,N2> >
{
public :
  typedef genTensor2<scalar2,N2> ValType;
  void operator()(const genTensor2<scalar,N1> &a, ValType &r) const
  {
    int N=(N1>N2)?N2:N1;
    for (int i=0;i<N;++i)
      for (int j=0;j<N;++j)
        r(i,j)=scalar2(a(i,j));
  }
};

template<class scalar,class scalar2,int N1,int N2> class BuildFromOneOp<genTensor3<scalar,N1>,genTensor3<scalar2,N2> >
{
public :
  typedef genTensor3<scalar2,N2> ValType;
  void operator()(const genTensor3<scalar,N1> &a, ValType &r) const
  {
    int N=(N1>N2)?N2:N1;
    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)=scalar2(a(i,j,k));
  }
};

template<class scalar,class scalar2,int N1,int N2> class BuildFromOneOp<genTensor4<scalar,N1>, genTensor4<scalar2,N2> >
{
public :
  typedef genTensor4<scalar2,N2> ValType;
  void operator()(const genTensor4<scalar,N1> &a, ValType &r) const
  {
    int N=(N1>N2)?N2:N1;
    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)=scalar2(a(i,j,k,l));
  }
};



template< class scalar,class scalar2,class scalar3> class BuildFromTwoOp
{
/*  public :
  typedef T ValType;
  void operator()(const scalar &a, const scalar2 &b, ValType &r) const
  {
    r=T(a,b);
  }*/
};


// new genTensor

template<int order, class scalar,class scalar2,class scalar3,int N> class BuildFromTwoOp<genTensor<order,scalar,N>, genTensor<order,scalar2,N>, genTensor<order,scalar3,N> >
{
public :
  typedef  genTensor<order,scalar3,N> ValType;
  void operator()(const genTensor<order,scalar,N> &a, const genTensor<order,scalar,N> &b, ValType &r) const
  {
    for (int i=0;i<ValType::Nele;++i)
    r[i]=scalar3(a[i],b[i]);
  }
};


template<class scalar,class scalar2,class scalar3,int N1,int N2,int N3> class BuildFromTwoOp<genTensor0<scalar,N1>, genTensor0<scalar2,N2>, genTensor0<scalar3,N3> >
{
public :
  typedef  genTensor0<scalar3,N3> ValType;
  void operator()(const genTensor0<scalar,N1> &a, const genTensor0<scalar2,N2> &b, ValType &r) const
  {
    r()=scalar3(a(),b());
  }
};

template<class scalar,class scalar2,class scalar3,int N> class BuildFromTwoOp<genTensor1<scalar,N>, genTensor1<scalar2,N>, genTensor1<scalar3,N> >
{
public :
  typedef genTensor1<scalar3,N>  ValType;
  void operator()(const genTensor1<scalar,N> &a, const genTensor1<scalar2,N> &b, ValType &r) const
  {
    for (int i=0;i<N;++i)
      r(i)=scalar3(a(i),b(i));
  }
};

template<class scalar,class scalar2,class scalar3,int N> class BuildFromTwoOp<genTensor2<scalar,N>,genTensor2<scalar2,N>, genTensor2<scalar3,N> >
{
public :
  typedef genTensor2<scalar3,N> ValType;
  void operator()(const genTensor2<scalar,N> &a, const genTensor2<scalar2,N> &b, ValType &r) const
  {
    for (int i=0;i<N;++i)
      for (int j=0;j<N;++j)
        r(i,j)=scalar3(a(i,j),b(i,j));
  }
};

template<class scalar,class scalar2,class scalar3,int N> class BuildFromTwoOp<genTensor3<scalar,N>,genTensor3<scalar2,N>, genTensor3<scalar3,N> >
{
public :
  typedef genTensor3<scalar3,N> ValType;
  void operator()(const genTensor3<scalar,N> &a, const genTensor3<scalar2,N> &b, 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)=scalar3(a(i,j,k),b(i,j,k));
  }
};

template<class scalar,class scalar2,class scalar3,int N> class BuildFromTwoOp<genTensor4<scalar,N>, genTensor4<scalar2,N>,genTensor4<scalar3,N> >
{
public :
  typedef genTensor4<scalar3,N> ValType;
  void operator()(const genTensor4<scalar,N> &a, const genTensor4<scalar2,N> &b, 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)=scalar3(a(i,j,k,l),b(i,j,k,l));
  }
};




#endif // _GEN_TENSORBUILD__H_