% FUNCTION gf_asm(operation[, arg])
% 
%   General assembly function.
% 
%   Many of the functions below use more than one mesh_fem: the main
%   mesh_fem (mf_u) used for the main unknow, and data mesh_fem (mf_d)
%   used for the data. It is always assumed that the Qdim of mf_d is
%   equal to 1: if mf_d is used to describe vector or tensor data, you
%   just have to "stack" (in fortran ordering) as many scalar fields as
%   necessary.
% 
%   * V = gf_asm('volumic_source',MeshIm mim, MeshFem mf_u, MeshFem mf_d, vec fd)
%   Assembly of a volumic source term.  Output a vector `V`, assembled on the
%   MeshFem `mf_u`, using the data vector `fd` defined on the data MeshFem `mf_d`.
%   `fd` may be real or complex-valued.
%   
%     Return a vec object.
% 
%   * B = gf_asm('boundary_source',int bnum, MeshIm mim, MeshFem mf_u, MeshFem mf_d,
%   vec G)
%   Assembly of a boundary source term.  `G` should be a [Qdim x N] matrix, where
%   N is the number of dof of `mf_d`, and Qdim is the dimension of the unkown u
%   (that is set when creating the MeshFem).
%   
%     Return a vec object.
% 
%   * M = gf_asm('mass_matrix',MeshIm mim, MeshFem mf1[, MeshFem mf2])
%   Assembly of a mass matrix.  Return a Spmat object.
% 
%   * L = gf_asm('laplacian',MeshIm mim, MeshFem mf_u, MeshFem mf_d, vec a)
%   Assembly of the matrix for the Laplacian problem.  div(a(x)*grad(u)) with `a`
%   scalar.
%   
%     Return a Spmat object.
% 
%   * Le = gf_asm('linear_elasticity',MeshIm mim, MeshFem mf_u, MeshFem mf_d, vec
%   lambda_d, vec mu_d)
%   Assembles of the matrix for the linear (isotropic) elasticity problem.
%   div(C(x):grad(u)) with C defined via `lambda_d` and `mu_d`.
%   
%     Return a Spmat object.
% 
%   * TRHS = gf_asm('nonlinear_elasticity',MeshIm mim, MeshFem mf_u, vec U, string
%   law, MeshFem mf_d, mat params, {'tangent matrix'|'rhs'|'incompressible tangent
%   matrix', MeshFem mf_p, vec P|'incompressible rhs', MeshFem mf_p, vec P})
%   Assembles terms (tangent matrix and right hand side) for nonlinear elasticity.
%   The solution `U` is required at the current time-step. The `law` may be
%   choosen among:
%   
%    - 'SaintVenant Kirchhoff':
%       Linearized law, should be avoided). This law has the two usual
%       Lame coefficients as parameters, called lambda and mu.
%    - 'Mooney Rivlin':
%       Only for incompressibility. This law has two parameters,
%       called C1 and C2.
%    - 'Ciarlet Geymonat':
%       This law has 3 parameters, called lambda, mu and gamma, with
%       gamma chosen such that gamma is in ]-lambda/2-mu, -mu[.
%   
%     The parameters of the material law are described on the MeshFem `mf_d`. The
%   matrix `params` should have `nbdof(mf_d)` columns, each row correspounds to a
%   parameter.
%   
%     The last argument selects what is to be built: either the tangent matrix, or
%   the right hand side. If the incompressibility is considered, it should be
%   followed by a MeshFem `mf_p`, for the pression.
%   
%     Return a Spmat object (tangent matrix), vec object (right hand side), tuple
%   of Spmat objects (incompressible tangent matrix), or tuple of vec objects
%   (incompressible right hand side).
% 
%   * {K, B} = gf_asm('stokes',MeshIm mim, MeshFem mf_u, MeshFem mf_p, MeshFem mf_d,
%   vec nu)
%   Assembly of matrices for the Stokes problem.  `-nu(x).Delta(u) + grad(p) = 0`
%   
%    `div(u) = 0`
%   
%    with `nu`, the fluid's dynamic viscosity.
%   
%     On output, `K` is the usual linear elasticity stiffness matrix with lambda =
%   0 and 2mu = nu. `B` is a matrix corresponding to $\int p.div v$.
%   
%     `K` and `B` are Spmat object's.
% 
%   * A = gf_asm('helmholtz',MeshIm mim, MeshFem mf_u, MeshFem mf_d, vec k)
%   Assembly of the matrix for the Helmholtz problem.  `Laplacian(u) + k^2 u` = 0
%   with `k` complex scalar.
%   
%     Return a Spmat object.
% 
%   * A = gf_asm('bilaplacian',MeshIm mim, MeshFem mf_u, MeshFem mf_d, vec a)
%   Assembly of the matrix for the Bilaplacian problem.
%   `Laplacian(a(x)*Laplacian(u)) = 0` with `a` scalar.
%   
%     Return a Spmat object.
% 
%   * {HH, RR} = gf_asm('dirichlet',int bnum, MeshIm mim, MeshFem mf_u, MeshFem
%   mf_d, mat H, vec R [, threshold])
%   Assembly of Dirichlet conditions of type `h.u = r`.  Handle `h.u = r` where h
%   is a square matrix (of any rank) whose size is equal to the dimension of the
%   unkown u. This matrix is stored in `H`, one column per dof in `mf_d`, each
%   column containing the values of the matrix h stored in fortran order:
%   
%     `H(:,j) = [h11(x_j) h21(x_j) h12(x_j) h22(x_j)]`
%   
%     if u is a 2D vector field.
%   
%     Of course, if the unknown is a scalar field, you just have to set `H =
%   ones(1, N)`, where N is the number of dof of `mf_d`.
%   
%     This is basically the same than calling gf_asm('boundary_qu_term') for `H`
%   and calling gf_asm('neumann') for `R`, except that this function tries to
%   produce a 'better' (more diagonal) constraints matrix (when possible).
%   
%     See also gf_spmat_get(M,'Dirichlet_nullspace').
% 
%   * Q = gf_asm('boundary_qu_term',int boundary_num, MeshIm mim, MeshFem mf_u,
%   MeshFem mf_d, mat q)
%   Assembly of a boundary qu term.  `q` should be be a [Qdim x Qdim x N] array,
%   where N is the number of dof of `mf_d`, and Qdim is the dimension of the
%   unkown u (that is set when creating the MeshFem).
%   
%     Return a Spmat object.
% 
%   * {Q, G, H, R, F} = gf_asm('pdetool_boundary_conditions',mf_u, mf_d, b, e[,
%   f_expr])
%   Assembly of pdetool boundary conditions.  `B` is the boundary matrix exported
%   by pdetool, and `E` is the edges array. `f_expr` is an optionnal expression
%   (or vector) for the volumic term. On return `Q, G, H, R, F` contain the
%   assembled boundary conditions (`Q` and `H` are matrices), similar to the ones
%   returned by the function ASSEMB from PDETOOL.
% 
%   * {...} = gf_asm('volumic'[,CVLST], expr [, mesh_ims, mesh_fems, data...])
%   Generic assembly procedure for volumic assembly.  The expression `expr` is
%   evaluated over the MeshFem's listed in the arguments (with optional data) and
%   assigned to the output arguments. For details about the syntax of assembly
%   expressions, please refer to the getfem user manual (or look at the file
%   getfem_assembling.h in the getfem++ sources).
%   
%     For example, the L2 norm of a field can be computed with
%   
%     gf_compute(MF, U,'L2 norm') or with:
%   
%     gf_asm('volumic','u=data(#1);
%   V()+=u(i).u(j).comp(Base(#1).Base(#1))(i,j)',mim,mf,U)
%   
%     The Laplacian stiffness matrix can be evaluated with
%   
%     gf_asm('laplacian',mim, mf, A) or equivalently with:
%   
%     gf_asm('volumic','a=data(#2);M(#1,#1)+=sym(comp(Grad(#1).Grad(#1).Base(#2))(
%   :,i,:,i,j).a(j))', mim,mf, A);
% 
%   * {...} = gf_asm('boundary',int bnum, string expr [, MeshIm mim, MeshFem mf,
%   data...])
%   Generic boundary assembly.  See the help for gf_asm('volumic').
% 
%   * Mi = gf_asm('interpolation_matrix',MeshFem mf, MeshFem mfi)
%   Build the interpolation matrix from a MeshFem onto another MeshFem.  Return a
%   matrix `Mi`, such that `V = Mi.U` is equal to gf_compute(MF,
%   U,'interpolate_on',mfi). Useful for repeated interpolations. Note that this is
%   just interpolation, no elementary integrations are involved here, and `mfi`
%   has to be lagrangian. In the more general case, you would have to do a L2
%   projection via the mass matrix.
%   
%     `Mi` is a Spmat object.
% 
%   * Me = gf_asm('extrapolation_matrix',MeshFem mf, MeshFem mfe)
%   Build the extrapolation matrix from a MeshFem onto another MeshFem.  Return a
%   matrix `Me`, such that `V = Me.U` is equal to gf_compute(MF,
%   U,'extrapolate_on',mfe). Useful for repeated extrapolations.  `Me` is a Spmat
%   object.
% 
function [varargout]=gf_asm(varargin)
  if (nargin>=1 & strcmpi(varargin{1},'pdetool boundary conditions')),
    [varargout{1:nargout}]=gf_asm_pdetoolbc(varargin{[1 3:nargin]}); return;
  end;
  if (nargout),
    [varargout{1:nargout}]=gf_matlab('asm',varargin{:});
  else
    gf_matlab('asm',varargin{:});
    if (exist('ans','var') == 1), varargout{1}=ans; end;
  end;
