getfem-commits
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Getfem-commits] (no subject)


From: Yves Renard
Subject: [Getfem-commits] (no subject)
Date: Tue, 27 Aug 2019 14:37:03 -0400 (EDT)

branch: master
commit bb28ea4115758c7de43f1b80790a1851de41d22f
Author: Yves Renard <address@hidden>
Date:   Thu Aug 15 13:38:17 2019 +0200

    Allowing elementary transformations between two different fems
---
 doc/sphinx/source/userdoc/gasm_high.rst            |  23 +-
 .../source/userdoc/model_generic_assembly.rst      |   2 +-
 interface/tests/matlab/Makefile.am                 |   1 +
 interface/tests/matlab/check_all.m                 |   8 +
 interface/tests/matlab/check_mitc.m                | 121 +++
 src/getfem/getfem_generic_assembly.h               |   4 +-
 .../getfem_generic_assembly_compile_and_exec.h     |   6 +-
 src/getfem/getfem_generic_assembly_tree.h          |   4 +-
 src/getfem_generic_assembly_compile_and_exec.cc    | 810 +++++++++++----------
 src/getfem_generic_assembly_semantic.cc            |  21 +-
 src/getfem_generic_assembly_tree.cc                |  25 +-
 src/getfem_linearized_plates.cc                    |  16 +-
 12 files changed, 626 insertions(+), 415 deletions(-)

diff --git a/doc/sphinx/source/userdoc/gasm_high.rst 
b/doc/sphinx/source/userdoc/gasm_high.rst
index 24c52d9..526115f 100644
--- a/doc/sphinx/source/userdoc/gasm_high.rst
+++ b/doc/sphinx/source/userdoc/gasm_high.rst
@@ -70,7 +70,7 @@ A specific weak form language has been developed to describe 
the weak formulatio
 
   - ``Interpolate(variable, transformation)``: Powerful operation which allows 
to interpolate the variables, or test functions either on the same mesh on 
other elements or on another mesh. ``transformation`` is an object stored by 
the workspace or model object which describes the map from the current point to 
the point where to perform the interpolation. This functionality can be used 
for instance to prescribe periodic conditions or to compute mortar matrices for 
two finite element space [...]
 
-  - ``Elementary_transformation(variable, transformation)``: Allow a linear 
tranformation defined at the element level (i.e. not possible to define at the 
gauss point level). This feature has been added mostly for defining a reduction 
for plate elements (projection onto low-level vector element such as rotated 
RT0). ``transformation`` is an object stored by the workspace or model object 
which describes the trasformation for a particular element.
+  - ``Elementary_transformation(variable, transformation, dest)``: Allow a 
linear tranformation defined at the element level (i.e. not possible to define 
at the gauss point level). This feature has been added mostly for defining a 
reduction for plate elements (projection onto low-level vector element such as 
rotated RT0). ``transformation`` is an object stored by the workspace or model 
object which describes the trasformation for a particular element. ``dest`` is 
an optional argument ref [...]
 
   - Possibility of integration on the direct product of two-domains for double 
integral computation or coupling of two variables with a Kernel / convolution / 
exchange integral. This allows terms like 
:math:`\displaystyle\int_{\Omega_1}\int_{\Omega_2}k(x,y)u(x)v(y)dydx` with 
:math:`\Omega_1` and :math:`\Omega_2` two domains, different or not, having 
their own meshes, integration methods and with :math:`u` a variable defined on 
:math:`\Omega_1` and :math:`v` a variable defined on :math:`\ [...]
 
@@ -918,16 +918,19 @@ the method::
 
 where ``pelementary_transformation`` is a pointer to an object deriving from 
``virtual_elementary_transformation``. Once it is added to the model/workspace, 
it is possible to use the following expressions in the weak form language::
 
-  Elementary_transformation(u, transname)
-  Elementary_transformation(Grad_u, transname)
-  Elementary_transformation(Div_u, transname)
-  Elementary_transformation(Hess_u, transname)
-  Elementary_transformation(Test_u, transname)
-  Elementary_transformation(Grad_Test_u, transname)
-  Elementary_transformation(Div_Test_u, transname)
-  Elementary_transformation(Hess_Test_u, transname)
+  Elementary_transformation(u, transname[, dest])
+  Elementary_transformation(Grad_u, transname[, dest])
+  Elementary_transformation(Div_u, transname[, dest])
+  Elementary_transformation(Hess_u, transname[, dest])
+  Elementary_transformation(Test_u, transname[, dest])
+  Elementary_transformation(Grad_Test_u, transname[, dest])
+  Elementary_transformation(Div_Test_u, transname[, dest])
+  Elementary_transformation(Hess_Test_u, transname[, dest])
 
-where ``u`` is one of the FEM variables of the model/workspace. For the 
moment, the only available elementary transformation is the the one for the 
projection on rotated RT0 element for two-dimensional elements which can be 
added thanks to the function (defined in 
:file:`src/getfem/getfem_linearized_plates.h`)::
+where ``u`` is one of the FEM variables of the model/workspace, and ``dest`` 
is an optional parameter which should be a variable or data name of the model 
and will correspond to the target fem of the transformation. If omitted, by 
default, the transformation is from the fem of the first variable to itself. 
+
+
+For the moment, the only available elementary transformation is the the one 
for the projection on rotated RT0 element for two-dimensional elements which 
can be added thanks to the function (defined in 
:file:`src/getfem/getfem_linearized_plates.h`)::
 
   add_2D_rotated_RT0_projection(model, transname)
 
diff --git a/doc/sphinx/source/userdoc/model_generic_assembly.rst 
b/doc/sphinx/source/userdoc/model_generic_assembly.rst
index 64af4fe..82db0a4 100644
--- a/doc/sphinx/source/userdoc/model_generic_assembly.rst
+++ b/doc/sphinx/source/userdoc/model_generic_assembly.rst
@@ -1,4 +1,4 @@
-.. $Id: model_generic_assembly.rst 3655 2010-07-17 20:42:08Z renard $
+.. $Id: model_generic_assembly.rst 3655 2010-07-19 20:42:08Z renard $
 
 .. include:: ../replaces.txt
 
diff --git a/interface/tests/matlab/Makefile.am 
b/interface/tests/matlab/Makefile.am
index 442c69a..b25a141 100644
--- a/interface/tests/matlab/Makefile.am
+++ b/interface/tests/matlab/Makefile.am
@@ -37,6 +37,7 @@ EXTRA_DIST=                                           \
        check_plot.m                                    \
        check_slices.m                                  \
        check_spmat.m                                   \
+       check_mitc.m                                    \
        check_workspace.m                               \
        check_plasticity.m                              \
        demo_elasticity.m                               \
diff --git a/interface/tests/matlab/check_all.m 
b/interface/tests/matlab/check_all.m
index 17764aa..cd80a8c 100644
--- a/interface/tests/matlab/check_all.m
+++ b/interface/tests/matlab/check_all.m
@@ -96,6 +96,14 @@ catch
   errcnt=errcnt+1; disp(['== ' t ' : FAILURE']);
 end;
 
+t = 'check_mitc [check mitc4 element and elementary transformations] ';
+try
+  check_mitc;
+  disp(['== ' t ': SUCCESS']);
+catch
+  errcnt=errcnt+1; disp(['== ' t ' : FAILURE']);
+end;
+
 t = 'demo_laplacian [model use for solving a Poisson problem] ';
 try
   automatic_var654 = 1;
diff --git a/interface/tests/matlab/check_mitc.m 
b/interface/tests/matlab/check_mitc.m
new file mode 100644
index 0000000..f03c4a7
--- /dev/null
+++ b/interface/tests/matlab/check_mitc.m
@@ -0,0 +1,121 @@
+% Copyright (C) 2015-2017 FABRE Mathieu, SECK Mamadou, DALLERIT Valentin,
+%
+% This file is a part of GetFEM++
+%
+% GetFEM++  is  free software;  you  can  redistribute  it  and/or modify it
+% under  the  terms  of the  GNU  Lesser General Public License as published
+% by  the  Free Software Foundation;  either version 3 of the License,  or
+% (at your option) any later version along with the GCC Runtime Library
+% Exception either version 3.1 or (at your option) any later version.
+% This program  is  distributed  in  the  hope  that it will be useful,  but
+% WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+% or  FITNESS  FOR  A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+% License and GCC Runtime Library Exception for more details.
+% You  should  have received a copy of the GNU Lesser General Public License
+% along  with  this program;  if not, write to the Free Software Foundation,
+% Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA.
+
+% Check on a simple supported Mindlin-Reissner plate
+
+function check_mitc(iverbose,idebug)
+  global gverbose;
+  global gdebug;  
+  if (nargin >= 1),
+    gverbose = iverbose;
+    if (nargin == 2),
+      gdebug = idebug;
+    else 
+      gdebug = 0;
+    end;
+  else 
+    gverbose = 0; gdebug = 0;
+  end;
+
+                                
+
+
+Emodulus = 1;          % Young Modulus
+nu       = 0.5;        % Poisson Coefficient
+epsilon  = 0.001;      % Plate thickness
+kappa     = 5/6;       % Shear correction factor
+f = -5*epsilon^3;      % Prescribed force on the top of the plate
+
+variant = 2;           % 0 : not reduced, 1 : with reduced integration,
+                       % 2 : MITC reduction
+quadrangles = true;    % Locking free only on quadrangle for the moment
+K = 1;                 % Degree of the finite element method
+with_Mindlin_brick = true; % Uses the Reissner-Mindlin predefined brick or not
+dirichlet_version = 1; % 0 = simplification, 1 = with multipliers
+                       % 2 = penalization
+r = 1E8;               % Penalization parameter.
+
+% trace on;
+gf_workspace('clear all');
+NX = 80;
+if (quadrangles)
+  m = gf_mesh('cartesian',[0:1/NX:1],[0:1/NX:1]);
+else
+  
m=gf_mesh('import','structured',sprintf('GT="GT_PK(2,1)";SIZES=[1,1];NOISED=0;NSUBDIV=[%d,%d];',
 NX, NX));
+end
+
+% Create a mesh_fem  for a 2D vector field
+mftheta = gf_mesh_fem(m,2);
+mfu = gf_mesh_fem(m,1);
+if (quadrangles)
+  gf_mesh_fem_set(mftheta,'fem',gf_fem(sprintf('FEM_QK(2,%d)', K)));
+  gf_mesh_fem_set(mfu,'fem',gf_fem(sprintf('FEM_QK(2,%d)', K)));
+  mim = gf_mesh_im(m, gf_integ('IM_GAUSS_PARALLELEPIPED(2,6)'));
+  mim_reduced = gf_mesh_im(m, gf_integ('IM_GAUSS_PARALLELEPIPED(2,1)'));
+else
+  gf_mesh_fem_set(mftheta,'fem',gf_fem(sprintf('FEM_PK(2,%d)', K)));
+  gf_mesh_fem_set(mfu,'fem',gf_fem(sprintf('FEM_PK(2,%d)', K)));
+  mim = gf_mesh_im(m, gf_integ('IM_TRIANGLE(6)'));
+  mim_reduced = gf_mesh_im(m, gf_integ('IM_TRIANGLE(1)'));
+end
+
+% Detect the border of the mesh and  assign it the boundary number 1
+border = gf_mesh_get(m,'outer faces');
+gf_mesh_set(m, 'boundary', 1, border);
+
+% Build the model
+md=gf_model('real');
+gf_model_set(md, 'add fem variable', 'u', mfu);
+gf_model_set(md, 'add fem variable', 'theta', mftheta);
+gf_model_set(md, 'add initialized data', 'E', Emodulus);
+gf_model_set(md, 'add initialized data', 'nu', nu);
+gf_model_set(md, 'add initialized data', 'epsilon', epsilon);
+gf_model_set(md, 'add initialized data', 'kappa', kappa);
+
+
+if (with_Mindlin_brick)
+  gf_model_set(md, 'add Mindlin Reissner plate brick', mim, mim_reduced, 'u', 
'theta', 'E', 'nu', 'epsilon', 'kappa', variant);
+else
+  gf_model_set(md, 'add elementary rotated RT0 projection', 'RT0_projection');
+  gf_model_set(md, 'add linear term', mim, 
'(E*epsilon*epsilon*epsilon*(1-nu)/(48 * (1 - nu*nu))) * 
((Grad_theta+Grad_theta''):(Grad_Test_theta+Grad_Test_theta''))');
+  gf_model_set(md, 'add linear term', mim, '(E*epsilon*epsilon*epsilon*nu/(12 
* (1 - nu*nu))) * (Div_theta*Div_Test_theta)');
+  if (variant == 0)
+    gf_model_set(md, 'add linear term', mim, '(E*kappa*epsilon/(1 + nu)) * 
((Grad_u + theta).Grad_Test_u) + (E*kappa*epsilon/(1 + nu)) * ((Grad_u + 
theta).Test_theta)');
+  elseif (variant == 1)
+    gf_model_set(md, 'add linear term', mim_reduced, '(E*kappa*epsilon/(1 + 
nu)) * ((Grad_u + theta).Grad_Test_u) + (E*kappa*epsilon/(1 + nu)) * ((Grad_u + 
theta).Test_theta)');
+  else
+    gf_model_set(md, 'add linear term', mim, '(E*kappa*epsilon/(1 + nu)) * 
((Grad_u + Elementary_transformation(theta,RT0_projection)).Grad_Test_u) + 
(E*kappa*epsilon/(1 + nu)) * ((Grad_u + Elementary_transformation(theta, 
RT0_projection)).(Elementary_transformation(Test_theta, RT0_projection)))');  
+  end
+end
+
+gf_model_set(md, 'add initialized data', 'VolumicData', f);
+
+gf_model_set(md, 'add source term brick', mim, 'u', 'VolumicData');
+gf_model_set(md, 'add initialized data', 'DirichletData', 0);
+switch (dirichlet_version)
+  case 0,
+    gf_model_set(md, 'add Dirichlet condition with simplification', 'u', 1, 
'DirichletData');   
+  case 1, 
+    gf_model_set(md, 'add Dirichlet condition with multipliers', mim, 'u', 
mfu, 1, 'DirichletData');
+  case 2,
+    gf_model_set(md, 'add Dirichlet condition with penalization', mim, 'u', r, 
1, 'DirichletData');
+end
+gf_model_get(md, 'solve');
+U = gf_model_get(md, 'variable', 'u');
+
+gfassert('abs(min(U) + 0.1828) < 0.001');
+
diff --git a/src/getfem/getfem_generic_assembly.h 
b/src/getfem/getfem_generic_assembly.h
index 3a05caa..68ea575 100644
--- a/src/getfem/getfem_generic_assembly.h
+++ b/src/getfem/getfem_generic_assembly.h
@@ -124,8 +124,8 @@ namespace getfem {
 
   public:
     
-    virtual void give_transformation(const mesh_fem &mf, size_type cv,
-                                     base_matrix &M) const = 0;
+    virtual void give_transformation(const mesh_fem &mf1, const mesh_fem &mf2,
+                                     size_type cv, base_matrix &M) const = 0;
     virtual ~virtual_elementary_transformation() {}
   };
 
diff --git a/src/getfem/getfem_generic_assembly_compile_and_exec.h 
b/src/getfem/getfem_generic_assembly_compile_and_exec.h
index 5c7ef03..ba49d6b 100644
--- a/src/getfem/getfem_generic_assembly_compile_and_exec.h
+++ b/src/getfem/getfem_generic_assembly_compile_and_exec.h
@@ -1,6 +1,6 @@
 /*===========================================================================
 
- Copyright (C) 2013-2018 Yves Renard
+ Copyright (C) 2013-2019 Yves Renard
 
  This file is a part of GetFEM++
 
@@ -146,7 +146,6 @@ namespace getfem {
 
     struct elementary_trans_info {
       base_matrix M;
-      const mesh_fem *mf;
       size_type icv;
     };
 
@@ -178,7 +177,8 @@ namespace getfem {
       std::map<std::string, std::set<std::string>> transformations;
       std::set<std::string> transformations_der;
       std::map<std::string, interpolate_info> interpolate_infos;
-      std::map<std::string, elementary_trans_info> elementary_trans_infos;
+      std::map<std::tuple<std::string, const mesh_fem *, const mesh_fem *>,
+        elementary_trans_info> elementary_trans_infos;
       secondary_domain_info secondary_domain_infos;
 
       std::vector<pga_instruction>
diff --git a/src/getfem/getfem_generic_assembly_tree.h 
b/src/getfem/getfem_generic_assembly_tree.h
index 6a9ae7f..7715299 100644
--- a/src/getfem/getfem_generic_assembly_tree.h
+++ b/src/getfem/getfem_generic_assembly_tree.h
@@ -1,6 +1,6 @@
 /*===========================================================================
 
- Copyright (C) 2013-2018 Yves Renard
+ Copyright (C) 2013-2019 Yves Renard
 
  This file is a part of GetFEM++
 
@@ -327,6 +327,8 @@ namespace getfem {
                                       // name of transformation
     std::string elementary_name;  // For Elementary_transformation :
                                   // name of transformation
+    std::string elementary_target;// For Elementary_transformation :
+                                  // target variable (for its mesh_fem) 
     size_type der1, der2;         // For functions and nonlinear operators,
                                   // optional derivative or second derivative.
     bool symmetric_op;
diff --git a/src/getfem_generic_assembly_compile_and_exec.cc 
b/src/getfem_generic_assembly_compile_and_exec.cc
index cbf0637..3614cd9 100644
--- a/src/getfem_generic_assembly_compile_and_exec.cc
+++ b/src/getfem_generic_assembly_compile_and_exec.cc
@@ -1,6 +1,6 @@
 /*===========================================================================
 
- Copyright (C) 2013-2018 Yves Renard
+ Copyright (C) 2013-2019 Yves Renard
 
  This file is a part of GetFEM++
 
@@ -1105,111 +1105,110 @@ namespace getfem {
       : ga_instruction_copy_val_base(tt, Z_, q) {}
   };
 
-  struct ga_instruction_elementary_transformation {
+  struct ga_instruction_elementary_trans {
     const base_vector &coeff_in;
     base_vector coeff_out;
     pelementary_transformation elemtrans;
-    const mesh_fem &mf;
+    const mesh_fem &mf1, &mf2;
     const fem_interpolation_context &ctx;
     base_matrix &M;
-    const mesh_fem **mf_M;
     size_type &icv;
 
-    void do_transformation() {
-      size_type nn = gmm::vect_size(coeff_in);
-      if (M.size() == 0 || icv != ctx.convex_num() || &mf != *mf_M) {
-        M.base_resize(nn, nn);
-        *mf_M = &mf; icv = ctx.convex_num();
-        elemtrans->give_transformation(mf, icv, M);
+    void do_transformation(size_type n, size_type m) {
+      if (icv != ctx.convex_num() || M.size() == 0) {
+        M.base_resize(m, n);
+        icv = ctx.convex_num();
+        elemtrans->give_transformation(mf1, mf2, icv, M);
       }
-      coeff_out.resize(nn);
+      coeff_out.resize(gmm::mat_nrows(M));
       gmm::mult(M, coeff_in, coeff_out); // remember: coeff == coeff_out
     }
 
-    ga_instruction_elementary_transformation
+    ga_instruction_elementary_trans
     (const base_vector &co, pelementary_transformation e,
-     const mesh_fem &mf_, const fem_interpolation_context &ctx_,
-     base_matrix &M_, const mesh_fem **mf_M_, size_type &icv_)
-      : coeff_in(co), elemtrans(e), mf(mf_), ctx(ctx_),
-        M(M_), mf_M(mf_M_), icv(icv_) {}
-    ~ga_instruction_elementary_transformation() {};
+     const mesh_fem &mf1_, const mesh_fem &mf2_,
+     const fem_interpolation_context &ctx_, base_matrix &M_,
+     size_type &icv_)
+      : coeff_in(co), elemtrans(e), mf1(mf1_), mf2(mf2_), ctx(ctx_),
+        M(M_), icv(icv_) {}
+    ~ga_instruction_elementary_trans() {};
   };
 
-  struct ga_instruction_elementary_transformation_val
-    : public ga_instruction_val, ga_instruction_elementary_transformation {
+  struct ga_instruction_elementary_trans_val
+    : public ga_instruction_val, ga_instruction_elementary_trans {
     // Z(ndof,target_dim), coeff_in(Qmult,ndof) --> t(target_dim*Qmult)
     virtual int exec() {
       GA_DEBUG_INFO("Instruction: variable value with elementary "
                     "transformation");
-      do_transformation();
+      size_type ndof = Z.sizes()[0];
+      size_type Qmult = qdim / Z.sizes()[1];
+      do_transformation(ndof*Qmult, t.sizes()[0]);
       return ga_instruction_val::exec();
     }
 
-    ga_instruction_elementary_transformation_val
+    ga_instruction_elementary_trans_val
     (base_tensor &tt, const base_tensor &Z_, const base_vector &co, size_type 
q,
-     pelementary_transformation e, const mesh_fem &mf_,
-     fem_interpolation_context &ctx_, base_matrix &M_,
-     const mesh_fem **mf_M_, size_type &icv_)
+     pelementary_transformation e, const mesh_fem &mf1_, const mesh_fem &mf2_,
+     fem_interpolation_context &ctx_, base_matrix &M_, size_type &icv_)
       : ga_instruction_val(tt, Z_, coeff_out, q),
-        ga_instruction_elementary_transformation(co, e, mf_, ctx_, M_,
-                                                 mf_M_, icv_) {}
+        ga_instruction_elementary_trans(co, e, mf1_, mf2_, ctx_, M_, icv_) {}
   };
 
-  struct ga_instruction_elementary_transformation_grad
-    : public ga_instruction_grad, ga_instruction_elementary_transformation {
+  struct ga_instruction_elementary_trans_grad
+    : public ga_instruction_grad, ga_instruction_elementary_trans {
     // Z(ndof,target_dim,N), coeff_in(Qmult,ndof) --> t(target_dim*Qmult,N)
     virtual int exec() {
       GA_DEBUG_INFO("Instruction: gradient with elementary transformation");
-      do_transformation();
+      size_type ndof = Z.sizes()[0];
+      size_type Qmult = qdim / Z.sizes()[1];
+      do_transformation(ndof*Qmult, t.sizes()[0]);
       return ga_instruction_grad::exec();
     }
 
-    ga_instruction_elementary_transformation_grad
+    ga_instruction_elementary_trans_grad
     (base_tensor &tt, const base_tensor &Z_, const base_vector &co, size_type 
q,
-     pelementary_transformation e, const mesh_fem &mf_,
-     fem_interpolation_context &ctx_, base_matrix &M_,
-     const mesh_fem **mf_M_, size_type &icv_)
+     pelementary_transformation e, const mesh_fem &mf1_, const mesh_fem &mf2_,
+     fem_interpolation_context &ctx_, base_matrix &M_, size_type &icv_)
       : ga_instruction_grad(tt, Z_, coeff_out, q),
-        ga_instruction_elementary_transformation(co, e, mf_, ctx_, M_,
-                                                 mf_M_, icv_) {}
+        ga_instruction_elementary_trans(co, e, mf1_, mf2_, ctx_, M_, icv_) {}
   };
 
-  struct ga_instruction_elementary_transformation_hess
-    : public ga_instruction_hess, ga_instruction_elementary_transformation {
+  struct ga_instruction_elementary_trans_hess
+    : public ga_instruction_hess, ga_instruction_elementary_trans {
     // Z(ndof,target_dim,N,N), coeff_in(Qmult,ndof) --> t(target_dim*Qmult,N,N)
     virtual int exec() {
       GA_DEBUG_INFO("Instruction: Hessian with elementary transformation");
-      do_transformation();
+      size_type ndof = Z.sizes()[0];
+      size_type Qmult = qdim / Z.sizes()[1];
+      do_transformation(ndof*Qmult, t.sizes()[0]);
       return ga_instruction_hess::exec();
     }
 
-    ga_instruction_elementary_transformation_hess
+    ga_instruction_elementary_trans_hess
     (base_tensor &tt, const base_tensor &Z_, const base_vector &co, size_type 
q,
-     pelementary_transformation e, const mesh_fem &mf_,
-     fem_interpolation_context &ctx_, base_matrix &M_,
-     const mesh_fem **mf_M_, size_type &icv_)
+     pelementary_transformation e, const mesh_fem &mf1_, const mesh_fem &mf2_,
+     fem_interpolation_context &ctx_, base_matrix &M_, size_type &icv_)
       : ga_instruction_hess(tt, Z_, coeff_out, q),
-        ga_instruction_elementary_transformation(co, e, mf_, ctx_, M_,
-                                                 mf_M_, icv_) {}
+        ga_instruction_elementary_trans(co, e, mf1_, mf2_, ctx_, M_, icv_) {}
   };
 
-  struct ga_instruction_elementary_transformation_diverg
-    : public ga_instruction_diverg, ga_instruction_elementary_transformation {
+  struct ga_instruction_elementary_trans_diverg
+    : public ga_instruction_diverg, ga_instruction_elementary_trans {
     // Z(ndof,target_dim,N), coeff_in(Qmult,ndof) --> t(1)
     virtual int exec() {
       GA_DEBUG_INFO("Instruction: divergence with elementary transformation");
-      do_transformation();
+      size_type ndof = Z.sizes()[0];
+      size_type Qmult = qdim / Z.sizes()[1];
+      do_transformation(ndof*Qmult, t.sizes()[0]);
       return ga_instruction_diverg::exec();
     }
 
-    ga_instruction_elementary_transformation_diverg
+    ga_instruction_elementary_trans_diverg
     (base_tensor &tt, const base_tensor &Z_, const base_vector &co, size_type 
q,
-     pelementary_transformation e, const mesh_fem &mf_,
-     fem_interpolation_context &ctx_, base_matrix &M_,
-     const mesh_fem **mf_M_, size_type &icv_)
+     pelementary_transformation e, const mesh_fem &mf1_, const mesh_fem &mf2_,
+     fem_interpolation_context &ctx_, base_matrix &M_, size_type &icv_)
       : ga_instruction_diverg(tt, Z_, coeff_out, q),
-        ga_instruction_elementary_transformation(co, e, mf_, ctx_, M_,
-                                                 mf_M_, icv_) {}
+        ga_instruction_elementary_trans(co, e, mf1_, mf2_, ctx_, M_, icv_) {}
   };
 
   struct ga_instruction_update_group_info : public ga_instruction {
@@ -1528,131 +1527,126 @@ namespace getfem {
   };
 
 
-  struct ga_instruction_elementary_transformation_base {
+  struct ga_instruction_elementary_trans_base {
     base_tensor t_in;
     base_tensor &t_out;
     pelementary_transformation elemtrans;
-    const mesh_fem &mf;
+    const mesh_fem &mf1, &mf2;
     const fem_interpolation_context &ctx;
     base_matrix &M;
-    const mesh_fem **mf_M;
     size_type &icv;
 
-    void do_transformation(size_type n) {
-      if (M.size() == 0 || icv != ctx.convex_num() || &mf != *mf_M) {
-        M.base_resize(n, n);
-        *mf_M = &mf; icv = ctx.convex_num();
-        elemtrans->give_transformation(mf, icv, M);
+    void do_transformation(size_type n, size_type m) {
+      if (icv != ctx.convex_num() || M.size() == 0) {
+        M.base_resize(m, n);
+        icv = ctx.convex_num();
+        elemtrans->give_transformation(mf1, mf2, icv, M);
       }
       t_out.mat_reduction(t_in, M, 0);
     }
 
-    ga_instruction_elementary_transformation_base
-    (base_tensor &t_, pelementary_transformation e, const mesh_fem &mf_,
-     const fem_interpolation_context &ctx_, base_matrix &M_,
-     const mesh_fem **mf_M_, size_type &icv_)
-      : t_out(t_), elemtrans(e), mf(mf_), ctx(ctx_),
-        M(M_), mf_M(mf_M_), icv(icv_) {}
+    ga_instruction_elementary_trans_base
+    (base_tensor &t_, pelementary_transformation e, const mesh_fem &mf1_,
+     const mesh_fem &mf2_,
+     const fem_interpolation_context &ctx_, base_matrix &M_, size_type &icv_)
+      : t_out(t_), elemtrans(e), mf1(mf1_), mf2(mf2_), ctx(ctx_),
+        M(M_), icv(icv_) {}
   };
 
-  struct ga_instruction_elementary_transformation_val_base
+  struct ga_instruction_elementary_trans_val_base
     : public ga_instruction_copy_val_base,
-             ga_instruction_elementary_transformation_base {
+             ga_instruction_elementary_trans_base {
     // Z(ndof,target_dim) --> t_in --> t_out(Qmult*ndof,Qmult*target_dim)
     virtual int exec() {
       GA_DEBUG_INFO("Instruction: value of test functions with elementary "
                     "transformation");
       size_type ndof = Z.sizes()[0];
       size_type Qmult = qdim / Z.sizes()[1];
-      t_in.adjust_sizes(t_out.sizes());
+      t_in.adjust_sizes(Qmult*ndof, Qmult*Z.sizes()[1]);
       ga_instruction_copy_val_base::exec();
-      do_transformation(ndof*Qmult);
+      do_transformation(ndof*Qmult, t_out.sizes()[0]);
       return 0;
     }
 
-    ga_instruction_elementary_transformation_val_base
+    ga_instruction_elementary_trans_val_base
     (base_tensor &t_, const base_tensor &Z_, size_type q,
-     pelementary_transformation e, const mesh_fem &mf_,
-     fem_interpolation_context &ctx_, base_matrix &M_,
-     const mesh_fem **mf_M_, size_type &icv_)
+     pelementary_transformation e, const mesh_fem &mf1_, const mesh_fem &mf2_,
+     fem_interpolation_context &ctx_, base_matrix &M_, size_type &icv_)
       : ga_instruction_copy_val_base(t_in, Z_, q),
-        ga_instruction_elementary_transformation_base(t_, e, mf_, ctx_, M_,
-                                                      mf_M_, icv_) {}
+        ga_instruction_elementary_trans_base(t_, e, mf1_, mf2_, ctx_,
+                                             M_, icv_) {}
   };
 
-  struct ga_instruction_elementary_transformation_grad_base
+  struct ga_instruction_elementary_trans_grad_base
     : public ga_instruction_copy_grad_base,
-             ga_instruction_elementary_transformation_base {
+             ga_instruction_elementary_trans_base {
     // Z(ndof,target_dim,N) --> t_in --> t_out(Qmult*ndof,Qmult*target_dim,N)
     virtual int exec() {
       GA_DEBUG_INFO("Instruction: gradient of test functions with elementary "
                     "transformation");
       size_type ndof = Z.sizes()[0];
       size_type Qmult = qdim / Z.sizes()[1];
-      t_in.adjust_sizes(t_out.sizes());
+      t_in.adjust_sizes(Qmult*ndof, Qmult*Z.sizes()[1], Z.sizes()[2]);
       ga_instruction_copy_grad_base::exec();
-      do_transformation(ndof*Qmult);
+      do_transformation(ndof*Qmult, t_out.sizes()[0]);
       return 0;
     }
 
-    ga_instruction_elementary_transformation_grad_base
+    ga_instruction_elementary_trans_grad_base
     (base_tensor &t_, const base_tensor &Z_, size_type q,
-     pelementary_transformation e, const mesh_fem &mf_,
-     fem_interpolation_context &ctx_, base_matrix &M_,
-     const mesh_fem **mf_M_, size_type &icv_)
+     pelementary_transformation e, const mesh_fem &mf1_, const mesh_fem &mf2_,
+     fem_interpolation_context &ctx_, base_matrix &M_, size_type &icv_)
       : ga_instruction_copy_grad_base(t_in, Z_, q),
-        ga_instruction_elementary_transformation_base(t_, e, mf_, ctx_, M_,
-                                                      mf_M_, icv_) {}
+        ga_instruction_elementary_trans_base(t_, e, mf1_, mf2_, ctx_,
+                                             M_,  icv_) {}
   };
 
-  struct ga_instruction_elementary_transformation_hess_base
+  struct ga_instruction_elementary_trans_hess_base
     : public ga_instruction_copy_hess_base,
-             ga_instruction_elementary_transformation_base {
+             ga_instruction_elementary_trans_base {
     // Z(ndof,target_dim,N*N) --> t_out(Qmult*ndof,Qmult*target_dim,N,N)
     virtual int exec() {
       GA_DEBUG_INFO("Instruction: Hessian of test functions with elementary "
                     "transformation");
       size_type ndof = Z.sizes()[0];
       size_type Qmult = qdim / Z.sizes()[1];
-      t_in.adjust_sizes(t_out.sizes());
+      t_in.adjust_sizes(Qmult*ndof, Qmult*Z.sizes()[1], Z.sizes()[2]);
       ga_instruction_copy_hess_base::exec();
-      do_transformation(ndof*Qmult);
+      do_transformation(ndof*Qmult, t_out.sizes()[0]);
       return 0;
     }
 
-    ga_instruction_elementary_transformation_hess_base
+    ga_instruction_elementary_trans_hess_base
     (base_tensor &t_, const base_tensor &Z_, size_type q,
-     pelementary_transformation e, const mesh_fem &mf_,
-     fem_interpolation_context &ctx_, base_matrix &M_,
-     const mesh_fem **mf_M_, size_type &icv_)
+     pelementary_transformation e, const mesh_fem &mf1_, const mesh_fem &mf2_,
+     fem_interpolation_context &ctx_, base_matrix &M_, size_type &icv_)
       : ga_instruction_copy_hess_base(t_in, Z_, q),
-        ga_instruction_elementary_transformation_base(t_, e, mf_, ctx_, M_,
-                                                      mf_M_, icv_) {}
+        ga_instruction_elementary_trans_base(t_, e, mf1_, mf2_, ctx_,
+                                             M_, icv_) {}
   };
 
-  struct ga_instruction_elementary_transformation_diverg_base
+  struct ga_instruction_elementary_trans_diverg_base
     : public ga_instruction_copy_diverg_base,
-             ga_instruction_elementary_transformation_base {
+             ga_instruction_elementary_trans_base {
     // Z(ndof,target_dim,N) --> t_out(Qmult*ndof)
     virtual int exec() {
       GA_DEBUG_INFO("Instruction: divergence of test functions with elementary 
"
                     "transformation");
       size_type ndof = Z.sizes()[0];
       size_type Qmult = qdim / Z.sizes()[1];
-      t_in.adjust_sizes(t_out.sizes());
+      t_in.adjust_sizes(Qmult*ndof);
       ga_instruction_copy_diverg_base::exec();
-      do_transformation(ndof*Qmult);
+      do_transformation(ndof*Qmult, t_out.sizes()[0]);
       return 0;
     }
 
-    ga_instruction_elementary_transformation_diverg_base
+    ga_instruction_elementary_trans_diverg_base
     (base_tensor &t_, const base_tensor &Z_, size_type q,
-     pelementary_transformation e, const mesh_fem &mf_,
-     fem_interpolation_context &ctx_, base_matrix &M_,
-     const mesh_fem **mf_M_, size_type &icv_)
+     pelementary_transformation e, const mesh_fem &mf1_, const mesh_fem &mf2_,
+     fem_interpolation_context &ctx_, base_matrix &M_, size_type &icv_)
       : ga_instruction_copy_diverg_base(t_in, Z_, q),
-        ga_instruction_elementary_transformation_base(t_, e, mf_, ctx_, M_,
-                                                      mf_M_, icv_) {}
+        ga_instruction_elementary_trans_base(t_, e, mf1_, mf2_, ctx_,
+                                             M_, icv_) {}
   };
 
 
@@ -5063,287 +5057,310 @@ namespace getfem {
     case GA_NODE_XFEM_PLUS_HESS: case GA_NODE_XFEM_PLUS_DIVERG:
     case GA_NODE_XFEM_MINUS_VAL: case GA_NODE_XFEM_MINUS_GRAD:
     case GA_NODE_XFEM_MINUS_HESS: case GA_NODE_XFEM_MINUS_DIVERG:
-      if (function_case) {
-        GMM_ASSERT1(pnode->node_type != GA_NODE_ELEMENTARY_VAL &&
-                    pnode->node_type != GA_NODE_ELEMENTARY_GRAD &&
-                    pnode->node_type != GA_NODE_ELEMENTARY_HESS &&
-                    pnode->node_type != GA_NODE_ELEMENTARY_DIVERG,
-                    "No elementary transformation is allowed in functions");
-        GMM_ASSERT1(pnode->node_type != GA_NODE_XFEM_PLUS_VAL &&
-                    pnode->node_type != GA_NODE_XFEM_PLUS_GRAD &&
-                    pnode->node_type != GA_NODE_XFEM_PLUS_HESS &&
-                    pnode->node_type != GA_NODE_XFEM_PLUS_DIVERG,
-                    "Xfem_plus not allowed in functions");
-        GMM_ASSERT1(pnode->node_type != GA_NODE_XFEM_MINUS_VAL &&
-                    pnode->node_type != GA_NODE_XFEM_MINUS_GRAD &&
-                    pnode->node_type != GA_NODE_XFEM_MINUS_HESS &&
-                    pnode->node_type != GA_NODE_XFEM_MINUS_DIVERG,
-                    "Xfem_plus not allowed in functions");
-        const mesh_fem *mf = workspace.associated_mf(pnode->name);
-        const im_data *imd = workspace.associated_im_data(pnode->name);
-        GMM_ASSERT1(!mf,"No fem expression is allowed in function expression");
-        GMM_ASSERT1(!imd, "No integration method data is allowed in "
-                    "function expression");
-        if (gmm::vect_size(workspace.value(pnode->name)) == 1)
-          pgai = std::make_shared<ga_instruction_copy_scalar>
-            (pnode->tensor()[0], (workspace.value(pnode->name))[0]);
-        else
-          pgai = std::make_shared<ga_instruction_copy_vect>
-            (pnode->tensor().as_vector(), workspace.value(pnode->name));
-        rmi.instructions.push_back(std::move(pgai));
-      } else {
-        const mesh_fem *mf = workspace.associated_mf(pnode->name);
-        const im_data *imd = workspace.associated_im_data(pnode->name);
-
-        if (imd) {
-          pgai = std::make_shared<ga_instruction_extract_local_im_data>
-            (pnode->tensor(), *imd, workspace.value(pnode->name),
-             gis.pai, gis.ctx, workspace.qdim(pnode->name));
+      {
+        bool is_elementary = (pnode->node_type == GA_NODE_ELEMENTARY_VAL ||
+                              pnode->node_type == GA_NODE_ELEMENTARY_GRAD ||
+                              pnode->node_type == GA_NODE_ELEMENTARY_HESS ||
+                              pnode->node_type == GA_NODE_ELEMENTARY_DIVERG);
+        if (function_case) {
+          GMM_ASSERT1(!is_elementary,
+                      "No elementary transformation is allowed in functions");
+          GMM_ASSERT1(pnode->node_type != GA_NODE_XFEM_PLUS_VAL &&
+                      pnode->node_type != GA_NODE_XFEM_PLUS_GRAD &&
+                      pnode->node_type != GA_NODE_XFEM_PLUS_HESS &&
+                      pnode->node_type != GA_NODE_XFEM_PLUS_DIVERG,
+                      "Xfem_plus not allowed in functions");
+          GMM_ASSERT1(pnode->node_type != GA_NODE_XFEM_MINUS_VAL &&
+                      pnode->node_type != GA_NODE_XFEM_MINUS_GRAD &&
+                      pnode->node_type != GA_NODE_XFEM_MINUS_HESS &&
+                      pnode->node_type != GA_NODE_XFEM_MINUS_DIVERG,
+                      "Xfem_plus not allowed in functions");
+          const mesh_fem *mf = workspace.associated_mf(pnode->name);
+          const im_data *imd = workspace.associated_im_data(pnode->name);
+          GMM_ASSERT1(!mf, "No fem expression is allowed in "
+                      "function expression");
+          GMM_ASSERT1(!imd, "No integration method data is allowed in "
+                      "function expression");
+          if (gmm::vect_size(workspace.value(pnode->name)) == 1)
+            pgai = std::make_shared<ga_instruction_copy_scalar>
+              (pnode->tensor()[0], (workspace.value(pnode->name))[0]);
+          else
+            pgai = std::make_shared<ga_instruction_copy_vect>
+              (pnode->tensor().as_vector(), workspace.value(pnode->name));
           rmi.instructions.push_back(std::move(pgai));
         } else {
-          GMM_ASSERT1(mf, "Internal error");
-
-          GMM_ASSERT1(&(mf->linked_mesh()) == &(m),
-                      "The finite element of variable " << pnode->name <<
-                      " has to be defined on the same mesh than the "
-                      "integration method or interpolation used");
-
-          // An instruction for extracting local dofs of the variable.
-          if (rmi.local_dofs.count(pnode->name) == 0) {
-            rmi.local_dofs[pnode->name] = base_vector(1);
-            extend_variable_in_gis(workspace, pnode->name, gis);
-            // cout << "local dof of " << pnode->name << endl;
-            size_type qmult2 = mf->get_qdim();
-            if (qmult2 > 1 && !(mf->is_uniformly_vectorized()))
-              qmult2 = size_type(-1);
-            pgai = std::make_shared<ga_instruction_slice_local_dofs>
-              (*mf, *(gis.extended_vars[pnode->name]), gis.ctx,
-               rmi.local_dofs[pnode->name],
-               workspace.qdim(pnode->name) / mf->get_qdim(), qmult2);
-            rmi.elt_instructions.push_back(std::move(pgai));
+          const mesh_fem *mf = workspace.associated_mf(pnode->name), *mfo=mf;
+          const im_data *imd = workspace.associated_im_data(pnode->name);
+          
+          if (is_elementary) {
+            mf = workspace.associated_mf(pnode->elementary_target);
+            GMM_ASSERT1(mf && mfo,
+                        "Wrong context for elementary transformation");
+            GMM_ASSERT1(&(mfo->linked_mesh()) == &(m),
+                        "The finite element of variable " << pnode->name
+                        << " has to be defined on the same mesh than the "
+                        << "integration method or interpolation used");
           }
-
-          // An instruction for pfp update
-          if (mf->is_uniform()) {
-            if (rmi.pfps.count(mf) == 0) {
+          
+          if (imd) {
+            pgai = std::make_shared<ga_instruction_extract_local_im_data>
+              (pnode->tensor(), *imd, workspace.value(pnode->name),
+               gis.pai, gis.ctx, workspace.qdim(pnode->name));
+            rmi.instructions.push_back(std::move(pgai));
+          } else {
+            GMM_ASSERT1(mf, "Internal error");
+            
+            GMM_ASSERT1(&(mf->linked_mesh()) == &(m),
+                        "The finite element of variable " <<
+                        (is_elementary ? pnode->elementary_target : 
pnode->name)
+                        << " has to be defined on the same mesh than the "
+                        << "integration method or interpolation used");
+            
+            // An instruction for extracting local dofs of the variable.
+            if (rmi.local_dofs.count(pnode->name) == 0) {
+              rmi.local_dofs[pnode->name] = base_vector(1);
+              extend_variable_in_gis(workspace, pnode->name, gis);
+              // cout << "local dof of " << pnode->name << endl;
+              size_type qmult2 = mfo->get_qdim();
+              if (qmult2 > 1 && !(mfo->is_uniformly_vectorized()))
+                qmult2 = size_type(-1);
+              pgai = std::make_shared<ga_instruction_slice_local_dofs>
+                (*mfo, *(gis.extended_vars[pnode->name]), gis.ctx,
+                 rmi.local_dofs[pnode->name],
+                 workspace.qdim(pnode->name) / mfo->get_qdim(), qmult2);
+              rmi.elt_instructions.push_back(std::move(pgai));
+            }
+            
+            // An instruction for pfp update
+            if (mf->is_uniform()) {
+              if (rmi.pfps.count(mf) == 0) {
+                rmi.pfps[mf] = 0;
+                pgai = std::make_shared<ga_instruction_update_pfp>
+                  (*mf, rmi.pfps[mf], gis.ctx, gis.fp_pool);
+                rmi.begin_instructions.push_back(std::move(pgai));
+              }
+            } else if (rmi.pfps.count(mf) == 0 ||
+                       !if_hierarchy.is_compatible(rmi.pfp_hierarchy[mf])) {
+              rmi.pfp_hierarchy[mf].push_back(if_hierarchy);
               rmi.pfps[mf] = 0;
               pgai = std::make_shared<ga_instruction_update_pfp>
                 (*mf, rmi.pfps[mf], gis.ctx, gis.fp_pool);
-              rmi.begin_instructions.push_back(std::move(pgai));
-            }
-          } else if (rmi.pfps.count(mf) == 0 ||
-                     !if_hierarchy.is_compatible(rmi.pfp_hierarchy[mf])) {
-            rmi.pfp_hierarchy[mf].push_back(if_hierarchy);
-            rmi.pfps[mf] = 0;
-            pgai = std::make_shared<ga_instruction_update_pfp>
-              (*mf, rmi.pfps[mf], gis.ctx, gis.fp_pool);
-            rmi.instructions.push_back(std::move(pgai));
-          }
-
-          // An instruction for the base value
-          pgai = pga_instruction();
-          switch (pnode->node_type) {
-          case GA_NODE_VAL: case GA_NODE_ELEMENTARY_VAL:
-            if (rmi.base.count(mf) == 0 ||
-                !if_hierarchy.is_compatible(rmi.base_hierarchy[mf])) {
-              rmi.base_hierarchy[mf].push_back(if_hierarchy);
-              pgai = std::make_shared<ga_instruction_val_base>
-                (rmi.base[mf], gis.ctx, *mf, rmi.pfps[mf]);
-            }
-            break;
-          case GA_NODE_XFEM_PLUS_VAL:
-            if (rmi.xfem_plus_base.count(mf) == 0 ||
-                !if_hierarchy.is_compatible(rmi.xfem_plus_base_hierarchy[mf]))
-            {
-              rmi.xfem_plus_base_hierarchy[mf].push_back(if_hierarchy);
-              pgai = std::make_shared<ga_instruction_xfem_plus_val_base>
-                (rmi.xfem_plus_base[mf], gis.ctx, *mf, rmi.pfps[mf]);
-            }
-            break;
-          case GA_NODE_XFEM_MINUS_VAL:
-            if (rmi.xfem_minus_base.count(mf) == 0 ||
-                !if_hierarchy.is_compatible(rmi.xfem_minus_base_hierarchy[mf]))
-            {
-              rmi.xfem_minus_base_hierarchy[mf].push_back(if_hierarchy);
-              pgai = std::make_shared<ga_instruction_xfem_minus_val_base>
-                (rmi.xfem_minus_base[mf], gis.ctx, *mf, rmi.pfps[mf]);
-            }
-            break;
-          case GA_NODE_GRAD: case GA_NODE_DIVERG:
-          case GA_NODE_ELEMENTARY_GRAD: case GA_NODE_ELEMENTARY_DIVERG:
-            if (rmi.grad.count(mf) == 0 ||
-                !if_hierarchy.is_compatible(rmi.grad_hierarchy[mf])) {
-              rmi.grad_hierarchy[mf].push_back(if_hierarchy);
-              pgai = std::make_shared<ga_instruction_grad_base>
-                (rmi.grad[mf], gis.ctx, *mf, rmi.pfps[mf]);
-            }
-            break;
-          case GA_NODE_XFEM_PLUS_GRAD: case GA_NODE_XFEM_PLUS_DIVERG:
-            if (rmi.xfem_plus_grad.count(mf) == 0 ||
-                !if_hierarchy.is_compatible(rmi.xfem_plus_grad_hierarchy[mf]))
-            {
-              rmi.xfem_plus_grad_hierarchy[mf].push_back(if_hierarchy);
-              pgai = std::make_shared<ga_instruction_xfem_plus_grad_base>
-                (rmi.xfem_plus_grad[mf], gis.ctx, *mf, rmi.pfps[mf]);
-            }
-            break;
-          case GA_NODE_XFEM_MINUS_GRAD: case GA_NODE_XFEM_MINUS_DIVERG:
-            if (rmi.xfem_minus_grad.count(mf) == 0 ||
-                !if_hierarchy.is_compatible(rmi.xfem_minus_grad_hierarchy[mf]))
-            {
-              rmi.xfem_minus_grad_hierarchy[mf].push_back(if_hierarchy);
-              pgai = std::make_shared<ga_instruction_xfem_minus_grad_base>
-                (rmi.xfem_minus_grad[mf], gis.ctx, *mf, rmi.pfps[mf]);
+              rmi.instructions.push_back(std::move(pgai));
             }
-            break;
-          case GA_NODE_HESS: case GA_NODE_ELEMENTARY_HESS:
-            if (rmi.hess.count(mf) == 0 ||
-                !if_hierarchy.is_compatible(rmi.hess_hierarchy[mf])) {
-              rmi.hess_hierarchy[mf].push_back(if_hierarchy);
-              pgai = std::make_shared<ga_instruction_hess_base>
-                (rmi.hess[mf], gis.ctx, *mf, rmi.pfps[mf]);
-            }
-            break;
-          case GA_NODE_XFEM_PLUS_HESS:
-            if (rmi.xfem_plus_hess.count(mf) == 0 ||
-                !if_hierarchy.is_compatible(rmi.xfem_plus_hess_hierarchy[mf]))
-            {
-              rmi.xfem_plus_hess_hierarchy[mf].push_back(if_hierarchy);
-              pgai = std::make_shared<ga_instruction_xfem_plus_hess_base>
-                (rmi.xfem_plus_hess[mf], gis.ctx, *mf, rmi.pfps[mf]);
-            }
-            break;
-          case GA_NODE_XFEM_MINUS_HESS:
-            if (rmi.xfem_minus_hess.count(mf) == 0 ||
-                !if_hierarchy.is_compatible(rmi.xfem_minus_hess_hierarchy[mf]))
-            {
-              rmi.xfem_minus_hess_hierarchy[mf].push_back(if_hierarchy);
-              pgai = std::make_shared<ga_instruction_xfem_minus_hess_base>
-                (rmi.xfem_minus_hess[mf], gis.ctx, *mf, rmi.pfps[mf]);
-            }
-            break;
-
-          default : GMM_ASSERT1(false, "Internal error");
-          }
-          if (pgai) rmi.instructions.push_back(std::move(pgai));
-
-          // The eval instruction
-          switch (pnode->node_type) {
-          case GA_NODE_VAL: // --> t(target_dim*Qmult)
-            pgai = std::make_shared<ga_instruction_val>
-              (pnode->tensor(), rmi.base[mf], rmi.local_dofs[pnode->name],
-               workspace.qdim(pnode->name));
-            break;
-          case GA_NODE_GRAD: // --> t(target_dim*Qmult,N)
-            pgai = std::make_shared<ga_instruction_grad>
-              (pnode->tensor(), rmi.grad[mf],
-               rmi.local_dofs[pnode->name], workspace.qdim(pnode->name));
-            break;
-          case GA_NODE_HESS: // --> t(target_dim*Qmult,N,N)
-            pgai = std::make_shared<ga_instruction_hess>
-              (pnode->tensor(), rmi.hess[mf],
-               rmi.local_dofs[pnode->name], workspace.qdim(pnode->name));
-            break;
-          case GA_NODE_DIVERG: // --> t(1)
-            pgai = std::make_shared<ga_instruction_diverg>
-              (pnode->tensor(), rmi.grad[mf],
-               rmi.local_dofs[pnode->name], workspace.qdim(pnode->name));
-            break;
-          case GA_NODE_XFEM_PLUS_VAL: // --> t(target_dim*Qmult)
-            pgai = std::make_shared<ga_instruction_val>
-              (pnode->tensor(), rmi.xfem_plus_base[mf],
-               rmi.local_dofs[pnode->name], workspace.qdim(pnode->name));
-            break;
-          case GA_NODE_XFEM_PLUS_GRAD: // --> t(target_dim*Qmult,N)
-            pgai = std::make_shared<ga_instruction_grad>
-              (pnode->tensor(), rmi.xfem_plus_grad[mf],
-               rmi.local_dofs[pnode->name], workspace.qdim(pnode->name));
-            break;
-          case GA_NODE_XFEM_PLUS_HESS: // --> t(target_dim*Qmult,N,N)
-            pgai = std::make_shared<ga_instruction_hess>
-              (pnode->tensor(), rmi.xfem_plus_hess[mf],
-               rmi.local_dofs[pnode->name], workspace.qdim(pnode->name));
-            break;
-          case GA_NODE_XFEM_PLUS_DIVERG: // --> t(1)
-            pgai = std::make_shared<ga_instruction_diverg>
-              (pnode->tensor(), rmi.xfem_plus_grad[mf],
-               rmi.local_dofs[pnode->name], workspace.qdim(pnode->name));
-            break;
-          case GA_NODE_XFEM_MINUS_VAL: // --> t(target_dim*Qmult)
-            pgai = std::make_shared<ga_instruction_val>
-              (pnode->tensor(), rmi.xfem_minus_base[mf],
-               rmi.local_dofs[pnode->name], workspace.qdim(pnode->name));
-            break;
-          case GA_NODE_XFEM_MINUS_GRAD: // --> t(target_dim*Qmult,N)
-            pgai = std::make_shared<ga_instruction_grad>
-              (pnode->tensor(), rmi.xfem_minus_grad[mf],
-               rmi.local_dofs[pnode->name], workspace.qdim(pnode->name));
-            break;
-          case GA_NODE_XFEM_MINUS_HESS: // --> t(target_dim*Qmult,N,N)
-            pgai = std::make_shared<ga_instruction_hess>
-              (pnode->tensor(), rmi.xfem_minus_hess[mf],
-               rmi.local_dofs[pnode->name], workspace.qdim(pnode->name));
-            break;
-          case GA_NODE_XFEM_MINUS_DIVERG: // --> t(1)
-            pgai = std::make_shared<ga_instruction_diverg>
-              (pnode->tensor(), rmi.xfem_minus_grad[mf],
-               rmi.local_dofs[pnode->name], workspace.qdim(pnode->name));
-            break;
-          case GA_NODE_ELEMENTARY_VAL:
-            { // --> t(target_dim*Qmult)
-              ga_instruction_set::elementary_trans_info &eti
-                = rmi.elementary_trans_infos[pnode->elementary_name];
-              pgai =
-                std::make_shared<ga_instruction_elementary_transformation_val>
-                (pnode->tensor(), rmi.base[mf],
-                 rmi.local_dofs[pnode->name], workspace.qdim(pnode->name),
-                 workspace.elementary_transformation(pnode->elementary_name),
-                 *mf, gis.ctx, eti.M, &(eti.mf), eti.icv);
+            
+            // An instruction for the base value
+            pgai = pga_instruction();
+            switch (pnode->node_type) {
+            case GA_NODE_VAL: case GA_NODE_ELEMENTARY_VAL:
+              if (rmi.base.count(mf) == 0 ||
+                  !if_hierarchy.is_compatible(rmi.base_hierarchy[mf])) {
+                rmi.base_hierarchy[mf].push_back(if_hierarchy);
+                pgai = std::make_shared<ga_instruction_val_base>
+                  (rmi.base[mf], gis.ctx, *mf, rmi.pfps[mf]);
+              }
+              break;
+            case GA_NODE_XFEM_PLUS_VAL:
+              if (rmi.xfem_plus_base.count(mf) == 0 ||
+                  
!if_hierarchy.is_compatible(rmi.xfem_plus_base_hierarchy[mf]))
+                {
+                  rmi.xfem_plus_base_hierarchy[mf].push_back(if_hierarchy);
+                  pgai = std::make_shared<ga_instruction_xfem_plus_val_base>
+                    (rmi.xfem_plus_base[mf], gis.ctx, *mf, rmi.pfps[mf]);
+                }
+              break;
+            case GA_NODE_XFEM_MINUS_VAL:
+              if (rmi.xfem_minus_base.count(mf) == 0 ||
+                  
!if_hierarchy.is_compatible(rmi.xfem_minus_base_hierarchy[mf]))
+                {
+                  rmi.xfem_minus_base_hierarchy[mf].push_back(if_hierarchy);
+                  pgai = std::make_shared<ga_instruction_xfem_minus_val_base>
+                    (rmi.xfem_minus_base[mf], gis.ctx, *mf, rmi.pfps[mf]);
+                }
+              break;
+            case GA_NODE_GRAD: case GA_NODE_DIVERG:
+            case GA_NODE_ELEMENTARY_GRAD: case GA_NODE_ELEMENTARY_DIVERG:
+              if (rmi.grad.count(mf) == 0 ||
+                  !if_hierarchy.is_compatible(rmi.grad_hierarchy[mf])) {
+                rmi.grad_hierarchy[mf].push_back(if_hierarchy);
+                pgai = std::make_shared<ga_instruction_grad_base>
+                  (rmi.grad[mf], gis.ctx, *mf, rmi.pfps[mf]);
+              }
+              break;
+            case GA_NODE_XFEM_PLUS_GRAD: case GA_NODE_XFEM_PLUS_DIVERG:
+              if (rmi.xfem_plus_grad.count(mf) == 0 ||
+                  
!if_hierarchy.is_compatible(rmi.xfem_plus_grad_hierarchy[mf]))
+                {
+                  rmi.xfem_plus_grad_hierarchy[mf].push_back(if_hierarchy);
+                  pgai = std::make_shared<ga_instruction_xfem_plus_grad_base>
+                    (rmi.xfem_plus_grad[mf], gis.ctx, *mf, rmi.pfps[mf]);
+                }
+              break;
+            case GA_NODE_XFEM_MINUS_GRAD: case GA_NODE_XFEM_MINUS_DIVERG:
+              if (rmi.xfem_minus_grad.count(mf) == 0 ||
+                  
!if_hierarchy.is_compatible(rmi.xfem_minus_grad_hierarchy[mf]))
+                {
+                  rmi.xfem_minus_grad_hierarchy[mf].push_back(if_hierarchy);
+                  pgai = std::make_shared<ga_instruction_xfem_minus_grad_base>
+                    (rmi.xfem_minus_grad[mf], gis.ctx, *mf, rmi.pfps[mf]);
+                }
+              break;
+            case GA_NODE_HESS: case GA_NODE_ELEMENTARY_HESS:
+              if (rmi.hess.count(mf) == 0 ||
+                  !if_hierarchy.is_compatible(rmi.hess_hierarchy[mf])) {
+                rmi.hess_hierarchy[mf].push_back(if_hierarchy);
+                pgai = std::make_shared<ga_instruction_hess_base>
+                  (rmi.hess[mf], gis.ctx, *mf, rmi.pfps[mf]);
+              }
+              break;
+            case GA_NODE_XFEM_PLUS_HESS:
+              if (rmi.xfem_plus_hess.count(mf) == 0 ||
+                  
!if_hierarchy.is_compatible(rmi.xfem_plus_hess_hierarchy[mf]))
+                {
+                  rmi.xfem_plus_hess_hierarchy[mf].push_back(if_hierarchy);
+                  pgai = std::make_shared<ga_instruction_xfem_plus_hess_base>
+                    (rmi.xfem_plus_hess[mf], gis.ctx, *mf, rmi.pfps[mf]);
+                }
+              break;
+            case GA_NODE_XFEM_MINUS_HESS:
+              if (rmi.xfem_minus_hess.count(mf) == 0 ||
+                  
!if_hierarchy.is_compatible(rmi.xfem_minus_hess_hierarchy[mf]))
+                {
+                  rmi.xfem_minus_hess_hierarchy[mf].push_back(if_hierarchy);
+                  pgai = std::make_shared<ga_instruction_xfem_minus_hess_base>
+                    (rmi.xfem_minus_hess[mf], gis.ctx, *mf, rmi.pfps[mf]);
+                }
+              break;
+              
+            default : GMM_ASSERT1(false, "Internal error");
             }
-            break;
-          case GA_NODE_ELEMENTARY_GRAD:
-            { // --> t(target_dim*Qmult,N)
-              ga_instruction_set::elementary_trans_info &eti
-                = rmi.elementary_trans_infos[pnode->elementary_name];
-              pgai =
-                std::make_shared<ga_instruction_elementary_transformation_grad>
+            if (pgai) rmi.instructions.push_back(std::move(pgai));
+            
+            // The eval instruction
+            switch (pnode->node_type) {
+            case GA_NODE_VAL: // --> t(target_dim*Qmult)
+              pgai = std::make_shared<ga_instruction_val>
+                (pnode->tensor(), rmi.base[mf], rmi.local_dofs[pnode->name],
+                 workspace.qdim(pnode->name));
+              break;
+            case GA_NODE_GRAD: // --> t(target_dim*Qmult,N)
+              pgai = std::make_shared<ga_instruction_grad>
                 (pnode->tensor(), rmi.grad[mf],
-                 rmi.local_dofs[pnode->name], workspace.qdim(pnode->name),
-                 workspace.elementary_transformation(pnode->elementary_name),
-                 *mf, gis.ctx, eti.M, &(eti.mf), eti.icv);
-            }
-            break;
-          case GA_NODE_ELEMENTARY_HESS:
-            { // --> t(target_dim*Qmult,N,N)
-              ga_instruction_set::elementary_trans_info &eti
-                = rmi.elementary_trans_infos[pnode->elementary_name];
-              pgai =
-                std::make_shared<ga_instruction_elementary_transformation_hess>
+                 rmi.local_dofs[pnode->name], workspace.qdim(pnode->name));
+              break;
+            case GA_NODE_HESS: // --> t(target_dim*Qmult,N,N)
+              pgai = std::make_shared<ga_instruction_hess>
                 (pnode->tensor(), rmi.hess[mf],
-                 rmi.local_dofs[pnode->name], workspace.qdim(pnode->name),
-                 workspace.elementary_transformation(pnode->elementary_name),
-                 *mf, gis.ctx, eti.M, &(eti.mf), eti.icv);
-            }
-            break;
-          case GA_NODE_ELEMENTARY_DIVERG:
-            { // --> t(1)
-              ga_instruction_set::elementary_trans_info &eti
-                = rmi.elementary_trans_infos[pnode->elementary_name];
-              pgai =
-               
std::make_shared<ga_instruction_elementary_transformation_diverg>
+                 rmi.local_dofs[pnode->name], workspace.qdim(pnode->name));
+              break;
+            case GA_NODE_DIVERG: // --> t(1)
+              pgai = std::make_shared<ga_instruction_diverg>
                 (pnode->tensor(), rmi.grad[mf],
-                 rmi.local_dofs[pnode->name], workspace.qdim(pnode->name),
-                 workspace.elementary_transformation(pnode->elementary_name),
-                 *mf, gis.ctx, eti.M, &(eti.mf), eti.icv);
+                 rmi.local_dofs[pnode->name], workspace.qdim(pnode->name));
+              break;
+            case GA_NODE_XFEM_PLUS_VAL: // --> t(target_dim*Qmult)
+              pgai = std::make_shared<ga_instruction_val>
+                (pnode->tensor(), rmi.xfem_plus_base[mf],
+                 rmi.local_dofs[pnode->name], workspace.qdim(pnode->name));
+              break;
+            case GA_NODE_XFEM_PLUS_GRAD: // --> t(target_dim*Qmult,N)
+              pgai = std::make_shared<ga_instruction_grad>
+                (pnode->tensor(), rmi.xfem_plus_grad[mf],
+                 rmi.local_dofs[pnode->name], workspace.qdim(pnode->name));
+              break;
+            case GA_NODE_XFEM_PLUS_HESS: // --> t(target_dim*Qmult,N,N)
+              pgai = std::make_shared<ga_instruction_hess>
+                (pnode->tensor(), rmi.xfem_plus_hess[mf],
+                 rmi.local_dofs[pnode->name], workspace.qdim(pnode->name));
+              break;
+            case GA_NODE_XFEM_PLUS_DIVERG: // --> t(1)
+              pgai = std::make_shared<ga_instruction_diverg>
+                (pnode->tensor(), rmi.xfem_plus_grad[mf],
+                 rmi.local_dofs[pnode->name], workspace.qdim(pnode->name));
+              break;
+            case GA_NODE_XFEM_MINUS_VAL: // --> t(target_dim*Qmult)
+              pgai = std::make_shared<ga_instruction_val>
+                (pnode->tensor(), rmi.xfem_minus_base[mf],
+                 rmi.local_dofs[pnode->name], workspace.qdim(pnode->name));
+              break;
+            case GA_NODE_XFEM_MINUS_GRAD: // --> t(target_dim*Qmult,N)
+              pgai = std::make_shared<ga_instruction_grad>
+                (pnode->tensor(), rmi.xfem_minus_grad[mf],
+                 rmi.local_dofs[pnode->name], workspace.qdim(pnode->name));
+              break;
+            case GA_NODE_XFEM_MINUS_HESS: // --> t(target_dim*Qmult,N,N)
+              pgai = std::make_shared<ga_instruction_hess>
+                (pnode->tensor(), rmi.xfem_minus_hess[mf],
+                 rmi.local_dofs[pnode->name], workspace.qdim(pnode->name));
+              break;
+            case GA_NODE_XFEM_MINUS_DIVERG: // --> t(1)
+              pgai = std::make_shared<ga_instruction_diverg>
+                (pnode->tensor(), rmi.xfem_minus_grad[mf],
+                 rmi.local_dofs[pnode->name], workspace.qdim(pnode->name));
+              break;
+            case GA_NODE_ELEMENTARY_VAL:
+              { // --> t(target_dim*Qmult)
+                ga_instruction_set::elementary_trans_info &eti
+                  = rmi.elementary_trans_infos
+                  [std::make_tuple(pnode->elementary_name, mfo, mf)];
+                pgai =
+                  std::make_shared<ga_instruction_elementary_trans_val>
+                  (pnode->tensor(), rmi.base[mf],
+                   rmi.local_dofs[pnode->name],
+                   workspace.qdim(pnode->elementary_target),
+                   workspace.elementary_transformation(pnode->elementary_name),
+                   *mfo, *mf, gis.ctx, eti.M, eti.icv);
+              }
+              break;
+            case GA_NODE_ELEMENTARY_GRAD:
+              { // --> t(target_dim*Qmult,N)
+                ga_instruction_set::elementary_trans_info &eti
+                  = rmi.elementary_trans_infos
+                  [std::make_tuple(pnode->elementary_name, mfo, mf)];
+                pgai =
+                  std::make_shared<ga_instruction_elementary_trans_grad>
+                  (pnode->tensor(), rmi.grad[mf],
+                   rmi.local_dofs[pnode->name],
+                   workspace.qdim(pnode->elementary_target),
+                   workspace.elementary_transformation(pnode->elementary_name),
+                   *mfo, *mf, gis.ctx, eti.M, eti.icv);
+              }
+              break;
+            case GA_NODE_ELEMENTARY_HESS:
+              { // --> t(target_dim*Qmult,N,N)
+                ga_instruction_set::elementary_trans_info &eti
+                  = rmi.elementary_trans_infos
+                  [std::make_tuple(pnode->elementary_name, mfo, mf)];
+                pgai =
+                  std::make_shared<ga_instruction_elementary_trans_hess>
+                  (pnode->tensor(), rmi.hess[mf],
+                   rmi.local_dofs[pnode->name],
+                   workspace.qdim(pnode->elementary_target),
+                   workspace.elementary_transformation(pnode->elementary_name),
+                   *mfo, *mf, gis.ctx, eti.M, eti.icv);
+              }
+              break;
+            case GA_NODE_ELEMENTARY_DIVERG:
+              { // --> t(1)
+                ga_instruction_set::elementary_trans_info &eti
+                  = rmi.elementary_trans_infos
+                  [std::make_tuple(pnode->elementary_name, mfo, mf)];
+                pgai =
+                  std::make_shared<ga_instruction_elementary_trans_diverg>
+                  (pnode->tensor(), rmi.grad[mf],
+                   rmi.local_dofs[pnode->name],
+                   workspace.qdim(pnode->elementary_target),
+                   workspace.elementary_transformation(pnode->elementary_name),
+                   *mfo, *mf, gis.ctx, eti.M, eti.icv);
+              }
+              break;
+            default: break;
             }
-            break;
-          default: break;
+            rmi.instructions.push_back(std::move(pgai));
           }
-          rmi.instructions.push_back(std::move(pgai));
         }
       }
       break;
-
+      
     case GA_NODE_SECONDARY_DOMAIN_VAL: case GA_NODE_SECONDARY_DOMAIN_GRAD:
     case GA_NODE_SECONDARY_DOMAIN_HESS: case GA_NODE_SECONDARY_DOMAIN_DIVERG:
       {
@@ -5527,12 +5544,27 @@ namespace getfem {
       // GMM_ASSERT1(!function_case,
       //            "Test functions not allowed in functions");
       {
-        const mesh_fem *mf = workspace.associated_mf(pnode->name);
+        bool is_elementary = (pnode->node_type==GA_NODE_ELEMENTARY_VAL_TEST ||
+                              pnode->node_type==GA_NODE_ELEMENTARY_GRAD_TEST ||
+                              pnode->node_type==GA_NODE_ELEMENTARY_HESS_TEST ||
+                              
pnode->node_type==GA_NODE_ELEMENTARY_DIVERG_TEST);
+        const mesh_fem *mf = workspace.associated_mf(pnode->name), *mfo=mf;
+        if (is_elementary) {
+          mf = workspace.associated_mf(pnode->elementary_target);
+          GMM_ASSERT1(mf && mfo,
+                      "Wrong context for elementary transformation");
+          GMM_ASSERT1(&(mfo->linked_mesh()) == &(m),
+                      "The finite element of variable " << pnode->name
+                      << " has to be defined on the same mesh than the "
+                      << "integration method or interpolation used");
+        }
+        
         if (mf) {
           GMM_ASSERT1(&(mf->linked_mesh()) == &(m),
                       "The finite element of variable " << pnode->name <<
-                      " and the applied integration method have to be"
-                      " defined on the same mesh");
+                      (is_elementary ? pnode->elementary_target : pnode->name)
+                      << " and the applied integration method have to be"
+                      << " defined on the same mesh");
 
           // An instruction for pfp update
           if (is_uniform) {
@@ -5733,45 +5765,49 @@ namespace getfem {
           case GA_NODE_ELEMENTARY_VAL_TEST:
             { // --> t(Qmult*ndof,Qmult*target_dim)
               ga_instruction_set::elementary_trans_info &eti
-                = rmi.elementary_trans_infos[pnode->elementary_name];
+                = rmi.elementary_trans_infos
+                [std::make_tuple(pnode->elementary_name, mfo, mf)];
               pgai =
-             
std::make_shared<ga_instruction_elementary_transformation_val_base>
+             std::make_shared<ga_instruction_elementary_trans_val_base>
                 (pnode->tensor(), rmi.base[mf], mf->get_qdim(),
                  workspace.elementary_transformation(pnode->elementary_name),
-                 *mf, gis.ctx, eti.M, &(eti.mf), eti.icv);
+                 *mfo, *mf, gis.ctx, eti.M, eti.icv);
             }
             break;
           case GA_NODE_ELEMENTARY_GRAD_TEST:
             { // --> t(Qmult*ndof,Qmult*target_dim,N)
               ga_instruction_set::elementary_trans_info &eti
-                = rmi.elementary_trans_infos[pnode->elementary_name];
+                = rmi.elementary_trans_infos
+                [std::make_tuple(pnode->elementary_name, mfo, mf)];
               pgai =
-            
std::make_shared<ga_instruction_elementary_transformation_grad_base>
+            std::make_shared<ga_instruction_elementary_trans_grad_base>
                 (pnode->tensor(), rmi.grad[mf], mf->get_qdim(),
                  workspace.elementary_transformation(pnode->elementary_name),
-                 *mf, gis.ctx, eti.M, &(eti.mf), eti.icv);
+                 *mfo, *mf, gis.ctx, eti.M, eti.icv);
             }
             break;
           case GA_NODE_ELEMENTARY_HESS_TEST:
             { // --> t(Qmult*ndof,Qmult*target_dim,N,N)
               ga_instruction_set::elementary_trans_info &eti
-                = rmi.elementary_trans_infos[pnode->elementary_name];
+                = rmi.elementary_trans_infos
+                [std::make_tuple(pnode->elementary_name, mfo, mf)];
               pgai =
-            
std::make_shared<ga_instruction_elementary_transformation_hess_base>
+            std::make_shared<ga_instruction_elementary_trans_hess_base>
                 (pnode->tensor(), rmi.hess[mf], mf->get_qdim(),
                  workspace.elementary_transformation(pnode->elementary_name),
-                 *mf, gis.ctx, eti.M, &(eti.mf), eti.icv);
+                 *mfo, *mf, gis.ctx, eti.M, eti.icv);
             }
             break;
           case GA_NODE_ELEMENTARY_DIVERG_TEST:
             { // --> t(Qmult*ndof)
               ga_instruction_set::elementary_trans_info &eti
-                = rmi.elementary_trans_infos[pnode->elementary_name];
+                = rmi.elementary_trans_infos
+                [std::make_tuple(pnode->elementary_name, mfo, mf)];
               pgai =
-          
std::make_shared<ga_instruction_elementary_transformation_diverg_base>
+          std::make_shared<ga_instruction_elementary_trans_diverg_base>
                 (pnode->tensor(), rmi.grad[mf], mf->get_qdim(),
                  workspace.elementary_transformation(pnode->elementary_name),
-                 *mf, gis.ctx, eti.M, &(eti.mf), eti.icv);
+                 *mfo, *mf, gis.ctx, eti.M, eti.icv);
             }
             break;
           default: break;
diff --git a/src/getfem_generic_assembly_semantic.cc 
b/src/getfem_generic_assembly_semantic.cc
index cf27450..719d4da 100644
--- a/src/getfem_generic_assembly_semantic.cc
+++ b/src/getfem_generic_assembly_semantic.cc
@@ -1,6 +1,6 @@
 /*===========================================================================
 
- Copyright (C) 2013-2018 Yves Renard
+ Copyright (C) 2013-2019 Yves Renard
 
  This file is a part of GetFEM++
 
@@ -349,7 +349,8 @@ namespace getfem {
     case GA_NODE_ELEMENTARY_VAL_TEST: case GA_NODE_ELEMENTARY_GRAD_TEST:
     case GA_NODE_ELEMENTARY_HESS_TEST: case GA_NODE_ELEMENTARY_DIVERG_TEST:
       c += 1.33*(1.22+ga_hash_code(pnode->name))
-        + 2.63*ga_hash_code(pnode->elementary_name);
+        + 2.63*ga_hash_code(pnode->elementary_name)
+        + 3.47*ga_hash_code(pnode->elementary_target);
       break;
     case GA_NODE_XFEM_PLUS_VAL: case GA_NODE_XFEM_PLUS_GRAD:
     case GA_NODE_XFEM_PLUS_HESS: case GA_NODE_XFEM_PLUS_DIVERG:
@@ -585,6 +586,13 @@ namespace getfem {
         size_type test = ga_parse_prefix_test(name);
         pnode->name = name;
 
+        if (ndt == 2) {
+          std::string target_name = pnode->elementary_target;
+          ga_parse_prefix_operator(target_name);
+          ga_parse_prefix_test(target_name);
+          pnode->elementary_target = target_name;
+        }
+
         // Group must be tested and it should be a fem variable
         if (!(workspace.variable_or_group_exists(name)))
           ga_throw_error(pnode->expr, pnode->pos,
@@ -763,6 +771,15 @@ namespace getfem {
             ga_throw_error(pnode->expr, pnode->pos,
                            "Unknown elementary transformation");
           }
+          if (!(workspace.variable_or_group_exists(pnode->elementary_target))) 
{
+            ga_throw_error(pnode->expr, pnode->pos, "Unknown data or variable "
+                           << pnode->elementary_target);
+          }
+          const mesh_fem *mft = workspace.associated_mf(name);
+          if (!mft)
+            ga_throw_error(pnode->expr, pnode->pos,
+                           "Thir argument of the elementary transformation "
+                           "should be a finite element variables/data");
         } else if (ndt == 3) {
           if (!(workspace.secondary_domain_exists
                 (pnode->interpolate_name))) {
diff --git a/src/getfem_generic_assembly_tree.cc 
b/src/getfem_generic_assembly_tree.cc
index 3617964..a9d1364 100644
--- a/src/getfem_generic_assembly_tree.cc
+++ b/src/getfem_generic_assembly_tree.cc
@@ -1,6 +1,6 @@
 /*===========================================================================
 
- Copyright (C) 2013-2018 Yves Renard
+ Copyright (C) 2013-2019 Yves Renard
 
  This file is a part of GetFEM++
 
@@ -1216,9 +1216,12 @@ namespace getfem {
 
     if (is_interpolate)
       str << "," << pnode->interpolate_name << ")";
-    else if (is_elementary)
-      str << "," << pnode->elementary_name << ")";
-    else if (is_secondary)
+    else if (is_elementary) {
+      str << "," << pnode->elementary_name;
+      if (pnode->name.compare(pnode->elementary_target) != 0)
+        str << "," << pnode->elementary_target;
+      str << ")";
+    } else if (is_secondary)
       str << ")";    
     else if (is_xfem_plus || is_xfem_minus)
       str << ")";
@@ -1738,6 +1741,7 @@ namespace getfem {
                              "should be a variable or a test function.");
             tree.current_node->name = std::string(&((*expr)[token_pos]),
                                                   token_length);
+            tree.current_node->elementary_target = tree.current_node->name;
 
             t_type = ga_get_token(*expr, pos, token_pos, token_length);
             if (t_type != GA_COMMA)
@@ -1751,6 +1755,19 @@ namespace getfem {
             tree.current_node->elementary_name
               = std::string(&((*expr)[token_pos]), token_length);
             t_type = ga_get_token(*expr, pos, token_pos, token_length);
+
+            if (t_type == GA_COMMA) {
+              t_type = ga_get_token(*expr, pos, token_pos, token_length);
+              if (t_type != GA_NAME)
+              ga_throw_error(expr, pos,
+                             "Third argument of Elementary_transformation "
+                             "should be a variable or data name.");
+              
+              tree.current_node->elementary_target =
+                std::string(&((*expr)[token_pos]), token_length);
+              t_type = ga_get_token(*expr, pos, token_pos, token_length);
+            }
+            
             if (t_type != GA_RPAR)
               ga_throw_error(expr, pos-1, "Missing a parenthesis after "
                              "Elementary_transformation arguments.");
diff --git a/src/getfem_linearized_plates.cc b/src/getfem_linearized_plates.cc
index 3252757..a984f35 100644
--- a/src/getfem_linearized_plates.cc
+++ b/src/getfem_linearized_plates.cc
@@ -195,12 +195,15 @@ namespace getfem {
 
   public:
 
-    virtual void give_transformation(const mesh_fem &mf, size_type cv,
-                                     base_matrix &M) const{
+    virtual void give_transformation(const mesh_fem &mf, const mesh_fem &mf2,
+                                     size_type cv, base_matrix &M) const{
 
       THREAD_SAFE_STATIC base_matrix M_old;
       THREAD_SAFE_STATIC pfem pf_old = nullptr;
-        
+
+      GMM_ASSERT1(&mf == &mf2,
+                  "This transformation works on identical fems only");
+      
       // Obtaining the fem descriptors
       pfem pf1 = mf.fem_of_element(cv);
       size_type N = 2;
@@ -296,11 +299,14 @@ namespace getfem {
 
   public:
 
-    virtual void give_transformation(const mesh_fem &mf, size_type cv,
-                                     base_matrix &M) const{
+    virtual void give_transformation(const mesh_fem &mf, const mesh_fem &mf2,
+                                     size_type cv, base_matrix &M) const{
 
       THREAD_SAFE_STATIC base_matrix M_old;
       THREAD_SAFE_STATIC pfem pf_old = nullptr;
+
+      GMM_ASSERT1(&mf == &mf2,
+                  "This transformation works on identical fems only");
         
       // Obtaining the fem descriptors
       pfem pf1 = mf.fem_of_element(cv);



reply via email to

[Prev in Thread] Current Thread [Next in Thread]