Skip to content
Snippets Groups Projects
Select Git revision
  • d3841df3ed94f3f804c0c56f2528cb809eb3c8f8
  • master default
  • cgnsUnstructured
  • partitioning
  • poppler
  • HighOrderBLCurving
  • gmsh_3_0_4
  • gmsh_3_0_3
  • gmsh_3_0_2
  • gmsh_3_0_1
  • gmsh_3_0_0
  • gmsh_2_16_0
  • gmsh_2_15_0
  • gmsh_2_14_1
  • gmsh_2_14_0
  • gmsh_2_13_2
  • gmsh_2_13_1
  • gmsh_2_12_0
  • gmsh_2_11_0
  • gmsh_2_10_1
  • gmsh_2_10_0
  • gmsh_2_9_3
  • gmsh_2_9_2
  • gmsh_2_9_1
  • gmsh_2_9_0
  • gmsh_2_8_6
26 results

TetReferenceSpace.h

Blame
  • Forked from gmsh / gmsh
    Source project has a limited visibility.
    functionSpace.h 26.66 KiB
    // Gmsh - Copyright (C) 1997-2016 C. Geuzaine, J.-F. Remacle
    //
    // See the LICENSE.txt file for license information. Please report all
    // bugs and problems to the public mailing list <gmsh@onelab.info>.
    
    #ifndef _FUNCTION_SPACE_H_
    #define _FUNCTION_SPACE_H_
    
    #include "SVector3.h"
    #include "STensor3.h"
    #include "STensor33.h"
    #include "STensor43.h"
    #include <vector>
    #include <iterator>
    #include <iostream>
    #include "Numeric.h"
    #include "MElement.h"
    #include "dofManager.h"
    #include "simpleFunction.h"
    
    //class SVoid{};
    template<class T> struct TensorialTraits
    {
      typedef T ValType;
      typedef T GradType[3];
      typedef T HessType[3][3];
      typedef T ThirdDevType[3][3][3];
    /*  typedef SVoid DivType;
      typedef SVoid CurlType;*/
    };
    
    template<> struct TensorialTraits<double>
    {
      typedef double ValType;
      typedef SVector3 GradType;
      typedef STensor3 HessType;
      typedef double TensProdType;
      typedef STensor33 ThirdDevType;
    /*  typedef SVoid DivType;
      typedef SVoid CurlType;*/
    };
    
    template<> struct TensorialTraits<SVector3>
    {
      typedef SVector3 ValType;
      typedef STensor3 GradType;
      typedef STensor3 HessType;
      typedef STensor3 TensProdType;
      typedef STensor3 ThirdDevType;
    //  typedef double DivType;
    //  typedef SVector3 CurlType;
    };
    
    template<> struct TensorialTraits<STensor3>
    {
      typedef STensor3 ValType;
    //  typedef STensor3 GradType;
    //  typedef STensor3 HessType;
    //  typedef STensor3 TensProdType;
      typedef STensor43 TensProdType;
    //  typedef double DivType;
    //  typedef SVector3 CurlType;
    };
    
    
    class FunctionSpaceBase
    {
     public:
      virtual ~FunctionSpaceBase(){}
    	virtual int getId(void) const =0;
      virtual int getNumKeys(MElement *ele) = 0; // if one needs the number of dofs
      virtual void getKeys(MElement *ele, std::vector<Dof> &keys) = 0;
      virtual void getKeysOnVertex(MElement* ele, MVertex* v, const std::vector<int>& comp, std::vector<Dof>& keys){
        Msg::Warning("this function is defined to get Dofs of vertex %d on element %d",v->getNum(),ele->getNum());
      }
    	virtual FunctionSpaceBase* clone(const int id) const {return NULL;}; // copy space with new Id
    };
    
    template<class T>
    class FunctionSpace : public FunctionSpaceBase
    {
     protected:
      int _iField; // field number (used to build dof keys)
     public:
      typedef typename TensorialTraits<T>::ValType ValType;
      typedef typename TensorialTraits<T>::GradType GradType;
      typedef typename TensorialTraits<T>::HessType HessType;
      typedef typename TensorialTraits<T>::ThirdDevType ThirdDevType;
      virtual int getId(void) const {return _iField;}
      virtual void f(MElement *ele, double u, double v, double w, std::vector<ValType> &vals) = 0;
      virtual void fuvw(MElement *ele, double u, double v, double w, std::vector<ValType> &vals) {} // should return to pure virtual once all is done.
      virtual void gradf(MElement *ele, double u, double v, double w, std::vector<GradType> &grads) = 0;
      virtual void gradfuvw(MElement *ele, double u, double v, double w, std::vector<GradType> &grads) {} // should return to pure virtual once all is done.
      virtual void hessfuvw(MElement *ele, double u, double v, double w, std::vector<HessType> &hess) = 0;
      virtual void hessf(MElement *ele, double u, double v, double w,std::vector<HessType> &hess) {} //need to high order fem
      virtual void thirdDevfuvw(MElement *ele, double u, double v, double w,std::vector<ThirdDevType> &third){}; //need to high order fem
      virtual void thirdDevf(MElement *ele, double u, double v, double w,std::vector<ThirdDevType> &third){}; //need to high order fem
    
      virtual int getNumKeys(MElement *ele) = 0; // if one needs the number of dofs
      virtual void getKeys(MElement *ele, std::vector<Dof> &keys) = 0;
    };
    
    class ScalarLagrangeFunctionSpaceOfElement : public FunctionSpace<double>
    {
     public:
      typedef TensorialTraits<double>::ValType ValType;
      typedef TensorialTraits<double>::GradType GradType;
      typedef TensorialTraits<double>::HessType HessType;
    
     private:
      virtual void getKeys(MVertex *ver, std::vector<Dof> &keys)
      {
        keys.push_back(Dof(ver->getNum(), _iField));
      }
    
     public:
      ScalarLagrangeFunctionSpaceOfElement(int i = 0) { _iField = i; }
      virtual void f(MElement *ele, double u, double v, double w, std::vector<ValType> &vals)
      {
        if(ele->getParent()) {
          if(ele->getTypeForMSH() == MSH_LIN_B || ele->getTypeForMSH() == MSH_TRI_B ||
             ele->getTypeForMSH() == MSH_POLYG_B) { //FIXME MPolygonBorders...
            ele->movePointFromParentSpaceToElementSpace(u, v, w);
          }
        }
        int ndofs = ele->getNumShapeFunctions();
        int curpos = vals.size();
        vals.resize(curpos + ndofs);
        ele->getShapeFunctions(u, v, w, &(vals[curpos]));
      }
      // Fonction renvoyant un vecteur contenant le grandient de chaque FF
      virtual void gradf(MElement *ele, double u, double v, double w, std::vector<GradType> &grads)
      {
        if(ele->getParent()) {
          if(ele->getTypeForMSH() == MSH_LIN_B || ele->getTypeForMSH() == MSH_TRI_B ||
             ele->getTypeForMSH() == MSH_POLYG_B) { //FIXME MPolygonBorders...
            ele->movePointFromParentSpaceToElementSpace(u, v, w);
          }
        }
        int ndofs = ele->getNumShapeFunctions();
        grads.reserve(grads.size() + ndofs);
        double gradsuvw[256][3];
        ele->getGradShapeFunctions(u, v, w, gradsuvw);
        double jac[3][3];
        double invjac[3][3];
        ele->getJacobian(u, v, w, jac); // redondant : on fait cet appel a l'exterieur
        inv3x3(jac, invjac);
        for(int i = 0; i < ndofs; ++i)
          grads.push_back(GradType(
          invjac[0][0] * gradsuvw[i][0] + invjac[0][1] * gradsuvw[i][1] + invjac[0][2] * gradsuvw[i][2],
          invjac[1][0] * gradsuvw[i][0] + invjac[1][1] * gradsuvw[i][1] + invjac[1][2] * gradsuvw[i][2],
          invjac[2][0] * gradsuvw[i][0] + invjac[2][1] * gradsuvw[i][1] + invjac[2][2] * gradsuvw[i][2]));
      }
      // Fonction renvoyant un vecteur contenant le hessien [][] de chaque FF dans l'espace ISOPARAMETRIQUE
      virtual void hessfuvw(MElement *ele, double u, double v, double w, std::vector<HessType> &hess)
      {
        if(ele->getParent()) {
          if(ele->getTypeForMSH() == MSH_LIN_B || ele->getTypeForMSH() == MSH_TRI_B ||
             ele->getTypeForMSH() == MSH_POLYG_B) { //FIXME MPolygonBorders...
            ele->movePointFromParentSpaceToElementSpace(u, v, w);
          }
        }
        int ndofs = ele->getNumShapeFunctions();
        hess.reserve(hess.size() + ndofs);   // permet de mettre les composantes suivantes à la suite du vecteur
        double hessuvw[256][3][3];
        ele->getHessShapeFunctions(u, v, w, hessuvw);
        HessType hesst;
        for(int i = 0; i < ndofs; ++i){
          hesst(0,0) = hessuvw[i][0][0]; hesst(0,1) = hessuvw[i][0][1]; hesst(0,2) = hessuvw[i][0][2];
          hesst(1,0) = hessuvw[i][1][0]; hesst(1,1) = hessuvw[i][1][1]; hesst(1,2) = hessuvw[i][1][2];
          hesst(2,0) = hessuvw[i][2][0]; hesst(2,1) = hessuvw[i][2][1]; hesst(2,2) = hessuvw[i][2][2];
          hess.push_back(hesst);
        }
      }
      virtual void gradfuvw(MElement *ele, double u, double v, double w, std::vector<GradType> &grads)
      {
        if(ele->getParent()) {
          if(ele->getTypeForMSH() == MSH_LIN_B || ele->getTypeForMSH() == MSH_TRI_B ||
             ele->getTypeForMSH() == MSH_POLYG_B) { //FIXME MPolygonBorders...
            ele->movePointFromParentSpaceToElementSpace(u, v, w);
          }
        }
        int ndofs = ele->getNumShapeFunctions();
        grads.reserve(grads.size() + ndofs);
        double gradsuvw[256][3];
        ele->getGradShapeFunctions(u, v, w, gradsuvw);
        for(int i = 0; i < ndofs; ++i)
          grads.push_back(GradType(gradsuvw[i][0], gradsuvw[i][1], gradsuvw[i][2]));
      }
      virtual int getNumKeys(MElement *ele)
      {
        return ele->getNumShapeFunctions();
      }
      virtual void getKeys(MElement *ele, std::vector<Dof> &keys) // appends ...
      {
        int ndofs = ele->getNumShapeFunctions();
        keys.reserve(keys.size() + ndofs);
        for(int i = 0; i < ndofs; ++i)
          getKeys(ele->getShapeFunctionNode(i), keys);
      }
    };
    
    class ScalarLagrangeFunctionSpace : public FunctionSpace<double>
    {
     public:
      typedef TensorialTraits<double>::ValType ValType;
      typedef TensorialTraits<double>::GradType GradType;
      typedef TensorialTraits<double>::HessType HessType;
    
     private:
      virtual void getKeys(MVertex *ver, std::vector<Dof> &keys)
      {
        keys.push_back(Dof(ver->getNum(), _iField));
      }
     public:
      ScalarLagrangeFunctionSpace(int i = 0) { _iField = i; }
      virtual void f(MElement *ele, double u, double v, double w, std::vector<ValType> &vals)
      {
        if(ele->getParent()) ele = ele->getParent();
        int ndofs = ele->getNumShapeFunctions();
        int curpos = vals.size();
        vals.resize(curpos + ndofs);
        ele->getShapeFunctions(u, v, w, &(vals[curpos]));
      }
      // Fonction renvoyant un vecteur contenant le grandient de chaque FF
      virtual void gradf(MElement *ele, double u, double v, double w, std::vector<GradType> &grads)
      {
        if(ele->getParent()) ele = ele->getParent();
        int ndofs = ele->getNumShapeFunctions();
        grads.reserve(grads.size() + ndofs);
        double gradsuvw[256][3];
        ele->getGradShapeFunctions(u, v, w, gradsuvw);
        double jac[3][3];
        double invjac[3][3];
        ele->getJacobian(u, v, w, jac); // redondant : on fait cet appel a l'exterieur
        inv3x3(jac, invjac);
        for(int i = 0; i < ndofs; ++i)
          grads.push_back(GradType(
          invjac[0][0] * gradsuvw[i][0] + invjac[0][1] * gradsuvw[i][1] + invjac[0][2] * gradsuvw[i][2],
          invjac[1][0] * gradsuvw[i][0] + invjac[1][1] * gradsuvw[i][1] + invjac[1][2] * gradsuvw[i][2],
          invjac[2][0] * gradsuvw[i][0] + invjac[2][1] * gradsuvw[i][1] + invjac[2][2] * gradsuvw[i][2]));
      }
      // Fonction renvoyant un vecteur contenant le hessien [][] de chaque FF dans l'espace ISOPARAMETRIQUE
      virtual void hessfuvw(MElement *ele, double u, double v, double w, std::vector<HessType> &hess)
      {
        if(ele->getParent()) ele = ele->getParent();
        int ndofs = ele->getNumShapeFunctions();
        hess.reserve(hess.size() + ndofs);   // permet de mettre les composantes suivantes à la suite du vecteur
        double hessuvw[256][3][3];
        ele->getHessShapeFunctions(u, v, w, hessuvw);
        HessType hesst;
        for(int i = 0; i < ndofs; ++i){
          hesst(0,0) = hessuvw[i][0][0]; hesst(0,1) = hessuvw[i][0][1]; hesst(0,2) = hessuvw[i][0][2];
          hesst(1,0) = hessuvw[i][1][0]; hesst(1,1) = hessuvw[i][1][1]; hesst(1,2) = hessuvw[i][1][2];
          hesst(2,0) = hessuvw[i][2][0]; hesst(2,1) = hessuvw[i][2][1]; hesst(2,2) = hessuvw[i][2][2];
          hess.push_back(hesst);
        }
      }
      virtual void gradfuvw(MElement *ele, double u, double v, double w, std::vector<GradType> &grads)
      {
        if(ele->getParent()) ele = ele->getParent();
        int ndofs = ele->getNumShapeFunctions();
        grads.reserve(grads.size() + ndofs);
        double gradsuvw[256][3];
        ele->getGradShapeFunctions(u, v, w, gradsuvw);
        for(int i = 0; i < ndofs; ++i)
          grads.push_back(GradType(gradsuvw[i][0], gradsuvw[i][1], gradsuvw[i][2]));
      }
      virtual void fuvw(MElement *ele, double u, double v, double w,std::vector<ValType> &vals)
      {
        if(ele->getParent()) ele = ele->getParent();
        int ndofs= ele->getNumShapeFunctions();
        vals.reserve(vals.size()+ndofs);
        double valsuvw[1256];
        ele->getShapeFunctions(u, v, w, valsuvw);
        for(int i = 0; i < ndofs; ++i)
          vals.push_back(valsuvw[i]);
      }
      virtual int getNumKeys(MElement *ele)
      {
        if(ele->getParent()) ele = ele->getParent();
        return ele->getNumShapeFunctions();
      }
      virtual void getKeys(MElement *ele, std::vector<Dof> &keys) // appends ...
      {
        if(ele->getParent()) ele = ele->getParent();
        int ndofs = ele->getNumShapeFunctions();
        keys.reserve(keys.size() + ndofs);
        for(int i = 0; i < ndofs; ++i)
          getKeys(ele->getShapeFunctionNode(i), keys);
      }
    };
    
    template <class T> class ScalarToAnyFunctionSpace : public FunctionSpace<T>
    {
    public :
      typedef typename TensorialTraits<T>::ValType ValType;
      typedef typename TensorialTraits<T>::GradType GradType;
      typedef typename TensorialTraits<T>::HessType HessType;
    protected :
      std::vector<T> multipliers;
      std::vector<int> comp;
      FunctionSpace<double> *ScalarFS;
    public :
      template <class T2> ScalarToAnyFunctionSpace(const T2 &SFS, const T& mult, int comp_): ScalarFS(new T2(SFS))
      {
        multipliers.push_back(mult); comp.push_back(comp_);
      }
    
      template <class T2> ScalarToAnyFunctionSpace(const T2 &SFS, const T& mult1, int comp1_,
                              const T& mult2, int comp2_): ScalarFS(new T2(SFS))
      {
        multipliers.push_back(mult1); multipliers.push_back(mult2);
        comp.push_back(comp1_); comp.push_back(comp2_);
      }
    
      template <class T2> ScalarToAnyFunctionSpace(const T2 &SFS, const T& mult1, int comp1_,
                              const T& mult2, int comp2_, const T& mult3, int comp3_): ScalarFS(new T2(SFS))
      {
        multipliers.push_back(mult1); multipliers.push_back(mult2); multipliers.push_back(mult3);
        comp.push_back(comp1_); comp.push_back(comp2_); comp.push_back(comp3_);
      }
    
      virtual ~ScalarToAnyFunctionSpace() {delete ScalarFS;}
    
      virtual void f(MElement *ele, double u, double v, double w, std::vector<ValType> &vals)
      {
        std::vector<double> valsd;
        ScalarFS->f(ele, u, v, w, valsd);
        int nbdofs = valsd.size();
        int nbcomp = comp.size();
        int curpos = vals.size();
        vals.reserve(curpos + nbcomp * nbdofs);
        for(int j = 0; j < nbcomp; ++j){
          for(int i = 0; i < nbdofs; ++i)
            vals.push_back(multipliers[j] * valsd[i]);
        }
      }
    
      virtual void gradf(MElement *ele, double u, double v, double w, std::vector<GradType> &grads)
      {
        std::vector<SVector3> gradsd;
        ScalarFS->gradf(ele, u, v, w, gradsd);
        int nbdofs = gradsd.size();
        int nbcomp = comp.size();
        int curpos = grads.size();
        grads.reserve(curpos + nbcomp * nbdofs);
        GradType val;
        for(int j = 0; j < nbcomp; ++j){
          for(int i = 0; i < nbdofs; ++i){
            tensprod(multipliers[j], gradsd[i], val);
            grads.push_back(val);
          }
        }
      }
      virtual void hessfuvw(MElement *ele, double u, double v, double w, std::vector<HessType> &hess)
      {
        ScalarFS->hessfuvw(ele, u, v, w, hess);
      }
      virtual void gradfuvw(MElement *ele, double u, double v, double w, std::vector<GradType> &grads)
      {
        std::vector<SVector3> gradsd;
        ScalarFS->gradfuvw(ele, u, v, w, gradsd);
        int nbdofs = gradsd.size();
        int nbcomp = comp.size();
        int curpos = grads.size();
        grads.reserve(curpos + nbcomp * nbdofs);
        GradType val;
        for(int j = 0; j < nbcomp; ++j){
          for(int i = 0; i < nbdofs; ++i){
            tensprod(multipliers[j], gradsd[i], val);
            grads.push_back(val);
          }
        }
      }
    
      virtual int getNumKeys(MElement *ele) {return ScalarFS->getNumKeys(ele) * comp.size();}
    
      virtual void getKeys(MElement *ele, std::vector<Dof> &keys)
      {
        int nk = ScalarFS->getNumKeys(ele);
        std::vector<Dof> bufk;
        bufk.reserve(nk);
        ScalarFS->getKeys(ele, bufk);
        int nbdofs = bufk.size();
        int nbcomp = comp.size();
        int curpos = keys.size();
        keys.reserve(curpos + nbcomp * nbdofs);
        for(int j = 0; j < nbcomp; ++j){
          for(int i = 0; i < nk; ++i){
            int i1, i2;
            Dof::getTwoIntsFromType(bufk[i].getType(), i1, i2);
            keys.push_back(Dof(bufk[i].getEntity(), Dof::createTypeWithTwoInts(comp[j], i1)));
          }
        }
      }
    };
    
    class VectorLagrangeFunctionSpaceOfElement : public ScalarToAnyFunctionSpace<SVector3>
    {
     protected:
      static const SVector3 BasisVectors[3];
     public:
      enum Along { VECTOR_X = 0, VECTOR_Y = 1, VECTOR_Z = 2 };
      typedef TensorialTraits<SVector3>::ValType ValType;
      typedef TensorialTraits<SVector3>::GradType GradType;
      VectorLagrangeFunctionSpaceOfElement(int id) :
              ScalarToAnyFunctionSpace<SVector3>::ScalarToAnyFunctionSpace(ScalarLagrangeFunctionSpaceOfElement(id),
              SVector3(1.,0.,0.), VECTOR_X, SVector3(0.,1.,0.), VECTOR_Y, SVector3(0.,0.,1.), VECTOR_Z)
      {}
      VectorLagrangeFunctionSpaceOfElement(int id, Along comp1) :
              ScalarToAnyFunctionSpace<SVector3>::ScalarToAnyFunctionSpace(ScalarLagrangeFunctionSpaceOfElement(id),
              BasisVectors[comp1], comp1)
      {}
      VectorLagrangeFunctionSpaceOfElement(int id, Along comp1, Along comp2) :
              ScalarToAnyFunctionSpace<SVector3>::ScalarToAnyFunctionSpace(ScalarLagrangeFunctionSpaceOfElement(id),
              BasisVectors[comp1], comp1, BasisVectors[comp2], comp2)
      {}
      VectorLagrangeFunctionSpaceOfElement(int id, Along comp1, Along comp2, Along comp3) :
              ScalarToAnyFunctionSpace<SVector3>::ScalarToAnyFunctionSpace(ScalarLagrangeFunctionSpaceOfElement(id),
              BasisVectors[comp1], comp1, BasisVectors[comp2], comp2, BasisVectors[comp3], comp3)
      {}
    };
    
    class VectorLagrangeFunctionSpace : public ScalarToAnyFunctionSpace<SVector3>
    {
     protected:
      static const SVector3 BasisVectors[3];
     public:
      enum Along { VECTOR_X = 0, VECTOR_Y = 1, VECTOR_Z = 2 };
      typedef TensorialTraits<SVector3>::ValType ValType;
      typedef TensorialTraits<SVector3>::GradType GradType;
      VectorLagrangeFunctionSpace(int id) :
              ScalarToAnyFunctionSpace<SVector3>::ScalarToAnyFunctionSpace(ScalarLagrangeFunctionSpace(id),
              SVector3(1.,0.,0.), VECTOR_X, SVector3(0.,1.,0.), VECTOR_Y, SVector3(0.,0.,1.), VECTOR_Z)
      {}
      VectorLagrangeFunctionSpace(int id, Along comp1) :
              ScalarToAnyFunctionSpace<SVector3>::ScalarToAnyFunctionSpace(ScalarLagrangeFunctionSpace(id),
              BasisVectors[comp1], comp1)
      {}
      VectorLagrangeFunctionSpace(int id, Along comp1, Along comp2) :
              ScalarToAnyFunctionSpace<SVector3>::ScalarToAnyFunctionSpace(ScalarLagrangeFunctionSpace(id),
              BasisVectors[comp1], comp1, BasisVectors[comp2], comp2)
      {}
      VectorLagrangeFunctionSpace(int id, Along comp1, Along comp2, Along comp3) :
              ScalarToAnyFunctionSpace<SVector3>::ScalarToAnyFunctionSpace(ScalarLagrangeFunctionSpace(id),
              BasisVectors[comp1], comp1, BasisVectors[comp2], comp2, BasisVectors[comp3], comp3)
      {}
    };
    
    template<class T>
    class CompositeFunctionSpace : public FunctionSpace<T>
    {
     public:
      typedef typename TensorialTraits<T>::ValType ValType;
      typedef typename TensorialTraits<T>::GradType GradType;
      typedef typename TensorialTraits<T>::HessType HessType;
      typedef typename std::vector<FunctionSpace<T>* >::iterator iterFS;
     protected:
    
      std::vector<FunctionSpace<T>* > _spaces;
     public:
      template <class T1> CompositeFunctionSpace(const T1& t) { _spaces.push_back(new T1(t));}
      template <class T1, class T2> CompositeFunctionSpace(const T1& t1, const T2& t2)
      { _spaces.push_back(new T1(t1));
        _spaces.push_back(new T2(t2)); }
      template <class T1, class T2, class T3> CompositeFunctionSpace(const T1& t1, const T2& t2, const T3& t3)
      { _spaces.push_back(new T1(t1));
        _spaces.push_back(new T2(t2));
        _spaces.push_back(new T3(t3)); }
      template <class T1, class T2, class T3, class T4> CompositeFunctionSpace(const T1& t1, const T2& t2, const T3& t3, const T4& t4)
      { _spaces.push_back(new T1(t1));
        _spaces.push_back(new T2(t2));
        _spaces.push_back(new T3(t3));
        _spaces.push_back(new T4(t4)); }
      template <class T1> void insert(const T1& t)
      {
        _spaces.push_back(new T(t));
      }
      ~CompositeFunctionSpace(void)
      {
        for (iterFS it = _spaces.begin(); it != _spaces.end(); ++it)
          delete (*it);
      }
      virtual void f(MElement *ele, double u, double v, double w, std::vector<ValType> &vals)
      {
        for (iterFS it = _spaces.begin(); it != _spaces.end(); ++it)
          (*it)->f(ele, u, v, w, vals);
      }
    
      virtual void gradf(MElement *ele, double u, double v, double w, std::vector<GradType> &grads)
      {
        for (iterFS it = _spaces.begin(); it != _spaces.end(); ++it)
          (*it)->gradf(ele, u, v, w, grads);
      }
    
      virtual void hessfuvw(MElement *ele, double u, double v, double w, std::vector<HessType> &hess)
      {
        for (iterFS it = _spaces.begin(); it != _spaces.end(); ++it)
          (*it)->hessfuvw(ele, u, v, w, hess);
      }
    
      virtual int getNumKeys(MElement *ele)
      {
        int ndofs = 0;
        for (iterFS it = _spaces.begin(); it != _spaces.end(); ++it)
          ndofs += (*it)->getNumKeys(ele);
        return ndofs;
      }
    
      virtual void getKeys(MElement *ele, std::vector<Dof> &keys)
      {
        for (iterFS it = _spaces.begin(); it != _spaces.end(); ++it)
          (*it)->getKeys(ele, keys);
      }
    };
    
    template<class T>
    class xFemFunctionSpace : public FunctionSpace<T>
    {
     public:
      typedef typename TensorialTraits<T>::ValType ValType;
      typedef typename TensorialTraits<T>::GradType GradType;
      typedef typename TensorialTraits<T>::HessType HessType;
     protected:
       FunctionSpace<T>* _spacebase;
       simpleFunctionOnElement<double> *_funcEnrichment;
    
     public:
      virtual void hessfuvw(MElement *ele, double u, double v, double w,std::vector<HessType> &hess){}
      xFemFunctionSpace(FunctionSpace<T>* spacebase,simpleFunctionOnElement<double> *funcEnrichment) :
        _spacebase(spacebase),_funcEnrichment(funcEnrichment){}
      virtual void f(MElement *ele, double u, double v, double w,std::vector<ValType> &vals);
      virtual void gradf(MElement *ele, double u, double v, double w,std::vector<GradType> &grads);
      virtual int getNumKeys(MElement *ele);
      virtual void getKeys(MElement *ele, std::vector<Dof> &keys);
    };
    
    
    template<class T, class F>
    class FilteredFunctionSpace : public FunctionSpace<T>
    {
     public :
      typedef typename TensorialTraits<T>::ValType ValType;
      typedef typename TensorialTraits<T>::GradType GradType;
      typedef typename TensorialTraits<T>::HessType HessType;
     protected:
      FunctionSpace<T>* _spacebase;
      F *_filter;
     public:
      virtual void hessfuvw(MElement *ele, double u, double v, double w, std::vector<HessType> &hess){}
      FilteredFunctionSpace<T,F>(FunctionSpace<T>* spacebase,F * filter) : _spacebase(spacebase), _filter(filter){}
      virtual void f(MElement *ele, double u, double v, double w, std::vector<ValType> &vals);
      virtual void gradf(MElement *ele, double u, double v, double w, std::vector<GradType> &grads);
      virtual int getNumKeys(MElement *ele);
      virtual void getKeys(MElement *ele, std::vector<Dof> &keys);
    };
    
    
    template <class T> void xFemFunctionSpace<T>::f(MElement *ele, double u, double v, double w, std::vector<ValType> &vals)
    {
       // We need parent parameters
      MElement * elep;
      if (ele->getParent()) elep = ele->getParent();
      else elep = ele;
    
        // Get the spacebase valsd
      std::vector<ValType> valsd;
      xFemFunctionSpace<T>::_spacebase->f(elep, u, v, w, valsd);
    
      int nbdofs = valsd.size();
      int curpos = vals.size();  // if in composite function space
      vals.reserve(curpos + nbdofs);
    
      // then enriched dofs so the order is ex:(a2x,a2y,a3x,a3y)
      if (nbdofs > 0){ // if enriched
        // Enrichment function calcul
        SPoint3 p;
        elep->pnt(u, v, w, p); // parametric to cartesian coordinates
        double func;
        _funcEnrichment->setElement(elep);
        func = (*_funcEnrichment)(p.x(), p.y(), p.z());
        for (int i = 0 ; i < nbdofs; i++){
          vals.push_back(valsd[i] * func);
        }
      }
    }
    
    template <class T> void xFemFunctionSpace<T>::gradf(MElement *ele, double u, double v, double w, std::vector<GradType> &grads)
    {
    
        // We need parent parameters
      MElement *elep;
      if (ele->getParent()) elep = ele->getParent();
      else elep = ele;
    
        // Get the spacebase gradsd
      std::vector<GradType> gradsd;
      xFemFunctionSpace<T>::_spacebase->gradf(elep, u, v, w, gradsd);
    
      int nbdofs=gradsd.size();
    
        // We need spacebase valsd to compute total gradient
      std::vector<ValType> valsd;
      xFemFunctionSpace<T>::_spacebase->f(elep, u, v, w, valsd);
    
      int curpos = grads.size();  // if in composite function space
      grads.reserve(curpos + nbdofs);
    
        // then enriched dofs so the order is ex:(a2x,a2y,a3x,a3y)
      if (nbdofs > 0){ // if enriched
        double df[3];
        SPoint3 p;
        elep->pnt(u, v, w, p);
        _funcEnrichment->setElement(elep);
        _funcEnrichment->gradient (p.x(), p.y(), p.z(), df[0], df[1], df[2]);
        ValType gradfuncenrich(df[0], df[1], df[2]);
    
            // Enrichment function calcul
        double func;
        _funcEnrichment->setElement(elep);
        func = (*_funcEnrichment)(p.x(), p.y(), p.z());
    
        for (int i = 0 ; i < nbdofs; i++){
          GradType GradFunc;
          tensprod(valsd[i], gradfuncenrich, GradFunc);
          grads.push_back(gradsd[i] * func + GradFunc);
        }
      }
    }
    
    template <class T> int xFemFunctionSpace<T>::getNumKeys(MElement *ele)
    {
      MElement *elep;
      if (ele->getParent()) elep = ele->getParent();
      else elep = ele;
      int nbdofs = xFemFunctionSpace<T>::_spacebase->getNumKeys(elep);
      return nbdofs;
    }
    
    template <class T> void xFemFunctionSpace<T>::getKeys(MElement *ele, std::vector<Dof> &keys)
    {
      MElement *elep;
      if (ele->getParent()) elep = ele->getParent();
      else elep = ele;
    
      int normalk = xFemFunctionSpace<T>::_spacebase->getNumKeys(elep);
    
      std::vector<Dof> bufk;
      bufk.reserve(normalk);
      xFemFunctionSpace<T>::_spacebase->getKeys(elep, bufk);
      int normaldofs = bufk.size();
      int nbdofs = normaldofs;
    
      int curpos = keys.size();
      keys.reserve(curpos + nbdofs);
    
        // get keys so the order is ex:(a2x,a2y,a3x,a3y)
        // enriched dof tagged with ( i2 -> i2 + 1 )
      for (int i = 0 ;i < nbdofs; i++){
        int i1, i2;
        Dof::getTwoIntsFromType(bufk[i].getType(), i1, i2);
        keys.push_back(Dof(bufk[i].getEntity(), Dof::createTypeWithTwoInts(i1, i2 + 1)));
      }
    }
    
    
    // Filtered function space
    //
    
    template <class T,class F> void FilteredFunctionSpace<T,F>::f(MElement *ele, double u, double v, double w, std::vector<ValType> &vals)
    {
        // We need parent parameters
      MElement *elep;
      if (ele->getParent()) elep = ele->getParent();
      else elep = ele;
    
      std::vector<ValType> valsd;
    
      _spacebase->f(elep, u, v, w, valsd);
    
      int normalk = _spacebase->getNumKeys(elep);
      std::vector<Dof> bufk;
      bufk.reserve(normalk);
      _spacebase->getKeys(elep, bufk);
    
      for (int i = 0; i < bufk.size(); i++){
        if ((*_filter)(bufk[i]))
          vals.push_back(valsd[i]);
      }
    }
    
    
    template <class T,class F> void FilteredFunctionSpace<T,F>::gradf(MElement *ele, double u, double v, double w, std::vector<GradType> &grads)
    {
        // We need parent parameters
      MElement *elep;
      if (ele->getParent()) elep = ele->getParent();
      else elep = ele;
    
        // Get space base gradsd
      std::vector<GradType> gradsd;
      _spacebase->gradf(elep, u, v, w, gradsd);
    
        // Get numkeys
      int normalk = _spacebase->getNumKeys(elep);
      std::vector<Dof> bufk;
      bufk.reserve(normalk);
      _spacebase->getKeys(elep, bufk);
    
      for (int i = 0; i < bufk.size(); i++){
        if ((*_filter)(bufk[i]))
          grads.push_back(gradsd[i]);
      }
    }
    
    template <class T,class F> int FilteredFunctionSpace<T,F>::getNumKeys(MElement *ele)
    {
      MElement *elep;
      if (ele->getParent()) elep = ele->getParent();
      else elep = ele;
    
      int nbdofs = 0;
    
      int normalk = _spacebase->getNumKeys(elep);
      std::vector<Dof> bufk;
      bufk.reserve(normalk);
      _spacebase->getKeys(elep, bufk);
    
      for (int i = 0; i < bufk.size(); i++){
        if ((*_filter)(bufk[i]))
          nbdofs = nbdofs + 1;
      }
      return nbdofs;
    }
    
    template <class T, class F> void FilteredFunctionSpace<T, F>::getKeys(MElement *ele, std::vector<Dof> &keys)
    {
      MElement *elep;
      if (ele->getParent()) elep = ele->getParent();
      else elep = ele;
    
      int normalk = _spacebase->getNumKeys(elep);
    
      std::vector<Dof> bufk;
      bufk.reserve(normalk);
      _spacebase->getKeys(elep, bufk);
    
      for (int i = 0; i < bufk.size(); i++){
        if ((*_filter)(bufk[i]))
          keys.push_back(bufk[i]);
      }
    }
    
    
    #endif