#!/usr/bin/env python
# -*- coding: iso-8859-1 -*-
#
# Python GetFEM++ interface
#
# Copyright (C) 2004-2010 Yves Renard, Julien Pommier.
#
# 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.
#
# File autogenerated by bin/extract_doc. Do not edit it.

"""GetFEM-interface classes.
  Provides access to the pseudo-objects exported by the python-getfem
  interface.
"""

import sys
import numpy

try:
  import numbers
except ImportError:
  numbers = numpy
  numbers.Number = (int,float,complex)

from numpy import *

from _getfem import *
obj_count = {}
getfem('workspace', 'clear all')

def generic_constructor(self, clname, *args):
    """Internal function -- acts as a constructor for all getfem objects."""
    #print 'generic_constructor.'+clname+'('+str(args)+')'
    if (len(args)==1 and type(args[0]) is GetfemObject):
      if hasattr(self,'id'):
        print "warning: hasattr(self,'id')!"
        print "self.id: ",self.id
        print "args[0]: ",args[0]
      else:
        self.id = args[0]
        if obj_count.get(self.id,0)==0:
          #print "Reviviendo objeto..."
          #print "self: ",self
          #print "self.id: ",self.id
          #if hasattr(self.id,'classid'):
          #  print "self.id.classid: ",self.id.classid
          #else:
          #  print "self.id.classid not found!"
          getfem("undelete",self.id)
          #print "self.id: ",self.id
          #pass
    else:
      self.id = getfem_from_constructor(clname,*args)
    obj_count[self.id] = obj_count.get(self.id,0)+1

def generic_destructor(self, destructible=True):
    """Internal function -- acts as a destructor for all getfem objects."""
    if (not hasattr(self,'id')):
      return
    #print "Mesh.__del__       ",self.id,'count=',obj_count[self.id]
    if (obj_count.has_key(self.id)):
      obj_count[self.id] = obj_count[self.id]-1
      if (destructible and obj_count[self.id] == 0):
        getfem('delete',self.id)
        #print "effective deletion"



#
# GetFEM class ContStruct definition.
#

class ContStruct:
  """GetFEM ContStruct object

  This object serves for storing parameters and data used in numerical
  continuation (for more details about the continuation see the Getfem++ user
  documentation).

  """
  def __init__(self, *args):
    """General constructor for ContStruct objects

  * ``S = ContStruct(Model md, string dataname_parameter[,string dataname_init, string dataname_final, string dataname_current], scalar sc_fac[, ...])``
    The variable `dataname_parameter` should parametrise the model given by
    `md`. If the parametrisation is done via some vector datum,
    `dataname_init` and `dataname_final` should store two given values of
    this datum determining the parametrisation, and `dataname_current`
    serves for actual values of this datum. `sc_fac` is a scale factor
    involved in the norm used in the continuation.
    
    Additional options:
    
    - 'lsolver', string SOLVER_NAME
       name of the solver to be used for the incorporated linear systems
       (the default value is 'auto', which lets getfem choose itself);
       possible values are 'superlu', 'mumps' (if supported), 'cg/ildlt',
       'gmres/ilu' and 'gmres/ilut';
    - 'max_iter', int NIT
       maximum number of iterations allowed in the correction (the default
       value is 10);
    - 'thr_iter', int TIT
       threshold number of iterations of the correction for enlarging the
       step size (the default value is 8);
    - 'max_res', scalar RES
       target residual value of the new point (the default value is 1e-6);
    - 'max_diff', scalar DIFF
       determines a convergence criterion to the new tangent vector (the
       default value is 1e-9);
    - 'min_ang', scalar ANG
       minimal value of the cosine of the angle between tangents to the
       solution curve at the old point and the new one (the default value
       is 0.9);
    - 'h_init', scalar HIN
       initial step size (the default value is 1e-2);
    - 'h_max', scalar HMAX
       maximal step size (the default value is 1e-1);
    - 'h_min', scalar HMIN
       minimal step size (the default value is 1e-5);
    - 'h_inc', scalar HINC
       factor for enlarging the step size (the default value is 1.3);
    - 'h_dec', scalar HDEC
       factor for diminishing the step size (the default value is 0.5);
    - 'epsilon', scalar EPS
       increment to be used to compute the incorporated finite
       differences (the default value is 1e-8);
    - 'max_res_solve', scalar RES_SOLVE
       target residual value for the linear systems to be solved (the
       default value is 1e-7);
    - 'nb_test', int NTEST
       number of evaluations of the test function when passing through
       a boundary between different smooth pieces;
    - 'noisy' or 'very_noisy'
       determines how detailed information has to be displayed during the
       process (residual values etc.).

    """
    generic_constructor(self,'cont_struct',*args)
  def __del__(self):
    generic_destructor(self, destructible=True)
  def get(self, *args):
    return getfem('cont_struct_get',self.id, *args)
  def __repr__(self):
    getfem('cont_struct_get',self.id, 'display')
    return ''
  def __str__(self):
    return self.char()

  def init_test_function(self, tangent, tangent_parameter):
    """Initialise the border of the bordered system that serves for calculating
    the test function. Return the value of test function for the solution
    and the value of the parameter saved in the corresponding model object
    and the tangent given by `tangent` and `tangent_parameter`."""
    return self.get("init_test_function", tangent, tangent_parameter)


  def init_Moore_Penrose_continuation(self, init_dir):
    """Initialise the Moore-Penrose continuation: Return a unit tangent
    corresponding to the solution branch at the solution and the
    value of the parameter saved in the corresponding model object,
    and an initial step size for the continuation. Direction of the
    computed tangent with respect to the parameter is determined by the
    sign of `init_dir`."""
    return self.get("init_Moore_Penrose_continuation", init_dir)


  def Moore_Penrose_continuation(self, tangent, tangent_parameter, h):
    """Compute one step of the Moore-Penrose continuation: Take the solution
    and the value of the parameter saved in the corresponding model object,
    the tangent given by `tangent` and `tangent_parameter`, and the step
    size `h`, save a new point on the solution curve into the model object,
    and return a new tangent and a step size for the next step. If the
    returned step size equals zero, the continuation has failed."""
    return self.get("Moore_Penrose_continuation", tangent, tangent_parameter, h)


  def test_function(self):
    """Return the last value of the test function and eventaully all the
    values calculated when passing through a boundary between different
    smooth pieces."""
    return self.get("test_function")


  def char(self):
    """Output a (unique) string representation of the ContStruct.
    
    This can be used to perform comparisons between two
    different ContStruct objects.
    This function is to be completed.
    """
    return self.get("char")


  def display(self):
    """Display a short summary for a ContStruct object."""
    return self.get("display")


#
# GetFEM class CvStruct definition.
#

class CvStruct:
  """GetFEM CvStruct object


  """
  def __init__(self, *args):
    """General constructor for CvStruct objects

    """
    generic_constructor(self,'cvstruct',*args)
  def __del__(self):
    generic_destructor(self, destructible=False)
  def get(self, *args):
    return getfem('cvstruct_get',self.id, *args)
  def __repr__(self):
    getfem('cvstruct_get',self.id, 'display')
    return ''
  def __str__(self):
    return self.char()

  def nbpts(self):
    """Get the number of points of the convex structure."""
    return self.get("nbpts")


  def dim(self):
    """Get the dimension of the convex structure."""
    return self.get("dim")


  def basic_structure(self):
    """Get the simplest convex structure.
    
    For example, the 'basic structure' of the 6-node triangle, is the
    canonical 3-noded triangle."""
    return self.get("basic_structure")


  def face(self, F):
    """Return the convex structure of the face `F`."""
    return self.get("face", F)


  def facepts(self, F):
    """Return the list of point indices for the face `F`."""
    return self.get("facepts", F)


  def char(self):
    """Output a string description of the CvStruct."""
    return self.get("char")


  def display(self):
    """displays a short summary for a CvStruct object."""
    return self.get("display")


#
# GetFEM class Eltm definition.
#

class Eltm:
  """GetFEM Eltm object


  This object represents a type of elementary matrix. In order to obtain a
  numerical value of these matrices, see MeshIm.eltm().

  If you have very particular assembling needs, or if you just want to check
  the content of an elementary matrix, this function might be useful. But
  the generic assembly abilities of gf_asm(...) should suit most needs.
  """
  def __init__(self, *args):
    """General constructor for Eltm objects

  * ``E = Eltm('base', Fem FEM)``
    return a descriptor for the integration of shape functions on
    elements, using the Fem `FEM`. 

  * ``E = Eltm('grad', Fem FEM)``
    return a descriptor for the integration of the gradient of shape
    functions on elements, using the Fem `FEM`.

  * ``E = Eltm('hessian', Fem FEM)``
    return a descriptor for the integration of the hessian of shape
    functions on elements, using the Fem `FEM`.

  * ``E = Eltm('normal')``
    return a descriptor for the unit normal of convex faces.

  * ``E = Eltm('grad_geotrans')``
    return a descriptor to the gradient matrix of the geometric
    transformation.

  * ``E = Eltm('grad_geotrans_inv')``
    return a descriptor to the inverse of the gradient matrix of the
    geometric transformation (this is rarely used).

  * ``E = Eltm('product', Eltm A, Eltm B)``
    return a descriptor for the integration of the tensorial product of
    elementary matrices `A` and `B`.

    """
    generic_constructor(self,'eltm',*args)
  def __del__(self):
    generic_destructor(self, destructible=False)
  def __str__(self):
    return self.char()

#
# GetFEM class Fem definition.
#

class Fem:
  """GetFEM Fem object

    This object represents a finite element method on a reference element.

  """
  def __init__(self, *args):
    """General constructor for Fem objects

  * ``F = Fem('interpolated_fem', MeshFem mf, MeshIm mim, [ivec blocked_dof])``
    Build a special Fem which is interpolated from another MeshFem.
    
    Using this special finite element, it is possible to interpolate a given
    MeshFem `mf` on another mesh, given the integration method `mim` that will
    be used on this mesh.
    
    Note that this finite element may be quite slow, and eats much
    memory.

  * ``F = Fem(string fem_name)``
    The `fem_name` should contain a description of the finite element
    method. Please refer to the getfem++ manual (especially the
    description of finite element and integration methods) for a complete
    reference. Here is a list of some of them:
    
    - FEM_PK(n,k) :
      classical Lagrange element Pk on a simplex of dimension `n`.
    - FEM_PK_DISCONTINUOUS(n,k[,alpha]) :
      discontinuous Lagrange element Pk on a simplex of dimension `n`.
    - FEM_QK(n,k) :
      classical Lagrange element Qk on quadrangles, hexahedrons etc.
    - FEM_QK_DISCONTINUOUS(n,k[,alpha]) :
      discontinuous Lagrange element Qk on quadrangles, hexahedrons etc.
    - FEM_Q2_INCOMPLETE :
      incomplete 2D Q2 element with 8 dof (serendipity Quad 8 element).
    - FEM_PK_PRISM(n,k) :
      classical Lagrange element Pk on a prism of dimension `n`.
    - FEM_PK_PRISM_DISCONTINUOUS(n,k[,alpha]) :
      classical discontinuous Lagrange element Pk on a prism.
    - FEM_PK_WITH_CUBIC_BUBBLE(n,k) :
      classical Lagrange element Pk on a simplex with an additional
      volumic bubble function.
    - FEM_P1_NONCONFORMING :
      non-conforming P1 method on a triangle.
    - FEM_P1_BUBBLE_FACE(n) :
      P1 method on a simplex with an additional bubble function on face 0.
    - FEM_P1_BUBBLE_FACE_LAG :
      P1 method on a simplex with an additional lagrange dof on face 0.
    - FEM_PK_HIERARCHICAL(n,k) :
      PK element with a hierarchical basis.
    - FEM_QK_HIERARCHICAL(n,k) :
      QK element with a hierarchical basis
    - FEM_PK_PRISM_HIERARCHICAL(n,k) :
      PK element on a prism with a hierarchical basis.
    - FEM_STRUCTURED_COMPOSITE(Fem f,k) :
      Composite Fem `f` on a grid with `k` divisions.
    - FEM_PK_HIERARCHICAL_COMPOSITE(n,k,s) :
      Pk composite element on a grid with `s` subdivisions and with a
      hierarchical basis.
    - FEM_PK_FULL_HIERARCHICAL_COMPOSITE(n,k,s) :
      Pk composite element with `s` subdivisions and a hierarchical basis
      on both degree and subdivision.
    - FEM_PRODUCT(A,B) :
      tensorial product of two polynomial elements.
    - FEM_HERMITE(n) :
      Hermite element P3 on a simplex of dimension `n = 1, 2, 3`.
    - FEM_ARGYRIS :
      Argyris element P5 on the triangle.
    - FEM_HCT_TRIANGLE :
      Hsieh-Clough-Tocher element on the triangle (composite P3 element
      which is C1), should be used with IM_HCT_COMPOSITE() integration
      method.
    - FEM_QUADC1_COMPOSITE :
      Quadrilateral element, composite P3 element and C1 (16 dof).
    - FEM_REDUCED_QUADC1_COMPOSITE :
      Quadrilateral element, composite P3 element and C1 (12 dof).
    - FEM_RT0(n) :
      Raviart-Thomas element of order 0 on a simplex of dimension `n`.
    - FEM_NEDELEC(n) :
      Nedelec edge element of order 0 on a simplex of dimension `n`.
    
    Of course, you have to ensure that the selected fem is compatible with
    the geometric transformation: a Pk fem has no meaning on a quadrangle.
    

    """
    generic_constructor(self,'fem',*args)
  def __del__(self):
    generic_destructor(self, destructible=False)
  def get(self, *args):
    return getfem('fem_get',self.id, *args)
  def __repr__(self):
    getfem('fem_get',self.id, 'display')
    return ''
  def __str__(self):
    return self.char()

  def nbdof(self, cv=None):
    """Return the number of dof for the Fem.
    
    Some specific Fem (for example 'interpolated_fem') may require a
    convex number `cv` to give their result. In most of the case, you
    can omit this convex number."""
    return self.get("nbdof", cv)


  def dim(self):
    """Return the dimension (dimension of the reference convex) of the Fem."""
    return self.get("dim")


  def target_dim(self):
    """Return the dimension of the target space.
    
    The target space dimension is usually 1, except for vector Fem. """
    return self.get("target_dim")


  def pts(self, cv=None):
    """Get the location of the dof on the reference element.
    
    Some specific Fem may require a convex number `cv` to give their
    result (for example 'interpolated_fem'). In most of the case, you
    can omit this convex number. """
    return self.get("pts", cv)


  def is_equivalent(self):
    """Return 0 if the Fem is not equivalent.
    
    Equivalent Fem are evaluated on the reference convex. This is
    the case of most classical Fem's."""
    return self.get("is_equivalent")


  def is_lagrange(self):
    """Return 0 if the Fem is not of Lagrange type."""
    return self.get("is_lagrange")


  def is_polynomial(self):
    """Return 0 if the basis functions are not polynomials."""
    return self.get("is_polynomial")


  def estimated_degree(self):
    """Return an estimation of the polynomial degree of the Fem.
    
    This is an estimation for fem which are not polynomials."""
    return self.get("estimated_degree")


  def base_value(self, p):
    """Evaluate all basis functions of the FEM at point `p`.
    
    `p` is supposed to be in the reference convex!"""
    return self.get("base_value", p)


  def grad_base_value(self, p):
    """Evaluate the gradient of all base functions of the Fem at point `p`.
    
    `p` is supposed to be in the reference convex!"""
    return self.get("grad_base_value", p)


  def hess_base_value(self, p):
    """Evaluate the Hessian of all base functions of the Fem at point `p`.
    
    `p` is supposed to be in the reference convex!."""
    return self.get("hess_base_value", p)


  def poly_str(self):
    """Return the polynomial expressions of its basis functions in
    the reference convex.
    
    The result is expressed as a tuple of
    strings. Of course this will fail on non-polynomial Fem's. """
    return self.get("poly_str")


  def char(self):
    """Ouput a (unique) string representation of the Fem.
    
    This can be used to perform comparisons between two different Fem
    objects."""
    return self.get("char")


  def display(self):
    """displays a short summary for a Fem object."""
    return self.get("display")


#
# GetFEM class GeoTrans definition.
#

class GeoTrans:
  """GetFEM GeoTrans object

   The geometric transformation must be used when you are building a custom
   mesh convex by convex (see the add_convex() function of Mesh): it also
   defines the kind of convex (triangle, hexahedron, prism, etc..)
  
  """
  def __init__(self, *args):
    """General constructor for GeoTrans objects

  * ``GT = GeoTrans(string name)``
    The name argument contains the specification of the geometric transformation
    as a string, which may be:
    
      - GT_PK(n,k) :
        Transformation on simplexes, dim `n`, degree `k`.
      - GT_QK(n,k) :
        Transformation on parallelepipeds, dim `n`, degree `k`.
      - GT_PRISM(n,k) :
        Transformation on prisms, dim `n`, degree `k`.
      - GT_PRODUCT(A,B) :
        Tensorial product of two transformations.
      - GT_LINEAR_PRODUCT(GeoTrans gt1,GeoTrans gt2) :
        Linear tensorial product of two transformations
    

    """
    generic_constructor(self,'geotrans',*args)
  def __del__(self):
    generic_destructor(self, destructible=False)
  def get(self, *args):
    return getfem('geotrans_get',self.id, *args)
  def __repr__(self):
    getfem('geotrans_get',self.id, 'display')
    return ''
  def __str__(self):
    return self.char()

  def dim(self):
    """Get the dimension of the GeoTrans.
    
    This is the dimension of the source space, i.e. the dimension of
    the reference convex."""
    return self.get("dim")


  def is_linear(self):
    """Return 0 if the GeoTrans is not linear."""
    return self.get("is_linear")


  def nbpts(self):
    """Return the number of points of the GeoTrans."""
    return self.get("nbpts")


  def pts(self):
    """Return the reference convex points of the GeoTrans.
    
    The points are stored in the columns of the output matrix."""
    return self.get("pts")


  def normals(self):
    """Get the normals for each face of the reference convex of the GeoTrans.
    
    The normals are stored in the columns of the output matrix."""
    return self.get("normals")


  def transform(self, G, Pr):
    """Apply the GeoTrans to a set of points.
    
    `G` is the set of vertices of the real convex, `Pr` is the set
    of points (in the reference convex) that are to be transformed.
    The corresponding set of points in the real convex is returned."""
    return self.get("transform", G, Pr)


  def char(self):
    """Output a (unique) string representation of the GeoTrans.
    
    This can be used to perform comparisons between two
    different GeoTrans objects. """
    return self.get("char")


  def display(self):
    """displays a short summary for a GeoTrans object."""
    return self.get("display")


#
# GetFEM class GlobalFunction definition.
#

class GlobalFunction:
  """GetFEM GlobalFunction object

  Global function object is represented by three functions:

   * The function `val`.
   * The function gradient `grad`.
   * The function Hessian `hess`.

  this type of function is used as local and global enrichment function. The
  global function Hessian is an optional parameter (only for fourth order
  derivative problems). 
  """
  def __init__(self, *args):
    """General constructor for GlobalFunction objects

  * ``GF = GlobalFunction('cutoff', int fn, scalar r, scalar r1, scalar r0)``
    Create a cutoff global function.

  * ``GF = GlobalFunction('crack', int fn)``
    Create a near-tip asymptotic global function for modelling cracks.

  * ``GF = GlobalFunction('parser', string val[, string grad[, string hess]])``
    Create a global function from strings `val`, `grad` and `hess`.

  * ``GF = GlobalFunction('product', GlobalFunction F, GlobalFunction G)``
    Create a product of two global functions.

  * ``GF = GlobalFunction('add', GlobalFunction gf1, GlobalFunction gf2)``
    Create a add of two global functions.

    """
    generic_constructor(self,'global_function',*args)
  def __del__(self):
    generic_destructor(self, destructible=False)
  def get(self, *args):
    return getfem('global_function_get',self.id, *args)
  def __repr__(self):
    getfem('global_function_get',self.id, 'display')
    return ''
  def __str__(self):
    return self.char()

  def __mul__(self,other):
    if isinstance(other,numbers.Number):
      return GlobalFunction('product',self,GlobalFunction('parser',"%e"%(other)))
    return GlobalFunction('product',self,other)
  def __add__(self,other):
    if isinstance(other,numbers.Number):
      return GlobalFunction('add',self,GlobalFunction('parser',"%e"%(other)))
    return GlobalFunction('add',self,other)
  def __call__(self,Pts):
    return getfem('global_function_get',self.id, 'val', Pts)


  def val(self, PTs):
    """Return `val` function evaluation in `PTs` (column points)."""
    return self.get("val", PTs)


  def grad(self, PTs):
    """Return `grad` function evaluation in `PTs` (column points).
    
    On return, each column of `GRADs` is of the
    form [Gx,Gy]."""
    return self.get("grad", PTs)


  def hess(self, PTs):
    """Return `hess` function evaluation in `PTs` (column points).
    
    On return, each column of `HESSs` is of the
    form [Hxx,Hxy,Hyx,Hyy]."""
    return self.get("hess", PTs)


  def char(self):
    """Output a (unique) string representation of the GlobalFunction.
    
    This can be used to perform comparisons between two
    different GlobalFunction objects.
    This function is to be completed.
    """
    return self.get("char")


  def display(self):
    """displays a short summary for a GlobalFunction object."""
    return self.get("display")


#
# GetFEM class Integ definition.
#

class Integ:
  """GetFEM Integ object

  General object for obtaining handles to various integrations methods on
  convexes (used when the elementary matrices are built).

  """
  def __init__(self, *args):
    """General constructor for Integ objects

  * ``I = Integ(string method)``
    Here is a list of some integration methods defined in getfem++ (see the
    description of finite element and integration methods for a complete
    reference):
    
     - IM_EXACT_SIMPLEX(n) :
       Exact integration on simplices (works only with linear geometric
       transformations and PK Fem's).
     - IM_PRODUCT(A,B) :
       Product of two integration methods.
     - IM_EXACT_PARALLELEPIPED(n) :
       Exact integration on parallelepipeds.
     - IM_EXACT_PRISM(n) :
       Exact integration on prisms.
     - IM_GAUSS1D(k) :
       Gauss method on the segment, order `k=1,3,...,99`.
     - IM_NC(n,k) :
       Newton-Cotes approximative integration on simplexes, order `k`.
     - IM_NC_PARALLELEPIPED(n,k) :
       Product of Newton-Cotes integration on parallelepipeds.
     - IM_NC_PRISM(n,k) :
       Product of Newton-Cotes integration on prisms.
     - IM_GAUSS_PARALLELEPIPED(n,k) :
       Product of Gauss1D integration on parallelepipeds.
     - IM_TRIANGLE(k) :
       Gauss methods on triangles `k=1,3,5,6,7,8,9,10,13,17,19`.
     - IM_QUAD(k) :
       Gauss methods on quadrilaterons `k=2,3,5, ...,17`. Note that
       IM_GAUSS_PARALLELEPIPED should be prefered for QK Fem's.
     - IM_TETRAHEDRON(k) :
       Gauss methods on tetrahedrons `k=1,2,3,5,6 or 8`.
     - IM_SIMPLEX4D(3) :
       Gauss method on a 4-dimensional simplex.
     - IM_STRUCTURED_COMPOSITE(im,k) :
       Composite method on a grid with `k` divisions.
     - IM_HCT_COMPOSITE(im) :
       Composite integration suited to the HCT composite finite element.
    
    Example:
    
     - I = Integ('IM_PRODUCT(IM_GAUSS1D(5),IM_GAUSS1D(5))')
    
    is the same as:
    
     - I = Integ('IM_GAUSS_PARALLELEPIPED(2,5)')
    
    Note that 'exact integration' should be avoided in general, since they
    only apply to linear geometric transformations, are quite slow, and
    subject to numerical stability problems for high degree Fem's. 

    """
    generic_constructor(self,'integ',*args)
  def __del__(self):
    generic_destructor(self, destructible=False)
  def get(self, *args):
    return getfem('integ_get',self.id, *args)
  def __repr__(self):
    getfem('integ_get',self.id, 'display')
    return ''
  def __str__(self):
    return self.char()

  def is_exact(self):
    """Return 0 if the integration is an approximate one."""
    return self.get("is_exact")


  def dim(self):
    """Return the dimension of the reference convex of
    the method."""
    return self.get("dim")


  def nbpts(self):
    """Return the total number of integration points.
    
    Count the points for the volume integration, and points for
    surface integration on each face of the reference convex.
    
    Only for approximate methods, this has no meaning for exact
    integration methods!"""
    return self.get("nbpts")


  def pts(self):
    """Return the list of integration points
    
    Only for approximate methods, this has no meaning for exact
    integration methods!"""
    return self.get("pts")


  def face_pts(self, F):
    """Return the list of integration points for a face.
    
    Only for approximate methods, this has no meaning for exact
    integration methods!"""
    return self.get("face_pts", F)


  def coeffs(self):
    """Returns the coefficients associated to each integration point.
    
    Only for approximate methods, this has no meaning for exact
    integration methods!"""
    return self.get("coeffs")


  def face_coeffs(self, F):
    """Returns the coefficients associated to each integration of a face.
    
    Only for approximate methods, this has no meaning for exact
    integration methods!"""
    return self.get("face_coeffs", F)


  def char(self):
    """Ouput a (unique) string representation of the integration method.
    
    This can be used to  comparisons between two different Integ
    objects."""
    return self.get("char")


  def display(self):
    """displays a short summary for a Integ object."""
    return self.get("display")


#
# GetFEM class LevelSet definition.
#

class LevelSet:
  """GetFEM LevelSet object


   The level-set object is represented by a primary level-set and optionally
   a secondary level-set used to represent fractures (if p(x) is the primary
   level-set function and s(x) is the secondary level-set, the crack is
   defined by :math:`p(x)=0` and :math:`s(x)\\leq0` : the role of the secondary is to determine
   the crack front/tip).

   note:

      All tools listed below need the package qhull installed on your
      system. This package is widely available. It computes convex hull and
      delaunay triangulations in arbitrary dimension.


  """
  def __init__(self, *args):
    """General constructor for LevelSet objects

  * ``LS = LevelSet(Mesh m, int d[, string 'ws'| string f1[, string f2 | string 'ws']])``
    Create a LevelSet object on a Mesh represented by a primary function
    (and optional secondary function, both) defined on a lagrange MeshFem of
    degree `d`.
    
    If `ws` (with secondary) is set; this levelset is represented by a
    primary function and a secondary function. If `f1` is set; the primary
    function is defined by that expression. If `f2` is set; this levelset
    is represented by a primary function and a secondary function defined
    by these expressions. 

    """
    generic_constructor(self,'levelset',*args)
  def __del__(self):
    generic_destructor(self, destructible=True)
  def get(self, *args):
    return getfem('levelset_get',self.id, *args)
  def __repr__(self):
    getfem('levelset_get',self.id, 'display')
    return ''
  def set(self, *args):
    return getfem('levelset_set',self.id, *args)
  def __str__(self):
    return self.char()

  def values(self, nls):
    """Return the vector of dof for `nls` funtion.
    
    If `nls` is 0, the method return the vector of dof for the primary
    level-set funtion. If `nls` is 1, the method return the vector of
    dof for the secondary level-set function (if any)."""
    return self.get("values", nls)


  def degree(self):
    """Return the degree of lagrange representation."""
    return self.get("degree")


  def mf(self):
    """Return a reference on the MeshFem object."""
    return self.get("mf")


  def memsize(self):
    """Return the amount of memory (in bytes) used by the level-set."""
    return self.get("memsize")


  def char(self):
    """Output a (unique) string representation of the LevelSet.
    
    This can be used to perform comparisons between two
    different LevelSet objects.
    This function is to be completed.
    """
    return self.get("char")


  def display(self):
    """displays a short summary for a LevelSet."""
    return self.get("display")


  def set_values(self, *args):
    """Synopsis: LevelSet.set_values(self, {mat v1|string func_1}[, mat v2|string func_2])

    Set values of the vector of dof for the level-set functions.
    
    Set the primary function with the vector of dof `v1` (or the expression
    `func_1`) and the secondary function (if any) with  the vector of dof
    `v2` (or the expression `func_2`)"""
    return self.set("values", *args)


  def simplify(self, eps=0.01):
    """Simplify dof of level-set optionally with the parameter `eps`."""
    return self.set("simplify", eps)


#
# GetFEM class MdBrick definition.
#

class MdBrick:
  """GetFEM MdBrick object


  """
  def __init__(self, *args):
    """General constructor for MdBrick objects

  * ``B = MdBrick('constraint', MdBrick pb, string CTYPE[, int nfem])``
    Build a generic constraint brick.
    
    It may be useful in some situations, such as the Stokes problem
    where the pressure is defined modulo a constant. In such a
    situation, this brick can be used to add an additional constraint
    on the pressure value.
    `CTYPE` has to be chosen among 'augmented', 'penalized', and
    'eliminated'. The constraint can be specified with
    MdBrick.constraints(). Note that Dirichlet bricks (except
    the 'generalized Dirichlet' one) are also specializations of
    the 'constraint' brick.

  * ``B = MdBrick('dirichlet', MdBrick pb, int bnum, MeshFem mf_m, string CTYPE[, int nfem])``
    Build a Dirichlet condition brick which impose the value of a field along a mesh boundary.
    
    The `bnum` parameter selects on which mesh region the Dirichlet
    condition is imposed. `CTYPE` has to be chosen among 'augmented',
    'penalized', and 'eliminated'. The `mf_m` may generally be taken
    as the MeshFem of the unknown, but for 'augmented' Dirichlet
    conditions, you may have to respect the Inf-Sup condition and
    choose an adequate MeshFem.

  * ``B = MdBrick('dirichlet on normal component', MdBrick pb, int bnum, MeshFem mf_m, string CTYPE[, int nfem])``
    Build a Dirichlet condition brick which imposes the value of the normal component of a vector field.

  * ``B = MdBrick('dirichlet on normal derivative', MdBrick pb, int bnum, MeshFem mf_m, string CTYPE[, int nfem])``
    Build a Dirichlet condition brick which imposes the value of the normal derivative of the unknown.

  * ``B = MdBrick('generalized dirichlet', MdBrick pb, int bnum[, int nfem])``
    This is the "old" Dirichlet brick of getfem.
    
    This brick can be used to impose general Dirichlet conditions
    `h(x)u(x) = r(x)`, however it may have some issues with elaborated
    Fem's (such as Argyris, etc). It should be avoided when possible.

  * ``B = MdBrick('source term', MdBrick pb[, int bnum=-1[, int nfem]])``
    Add a boundary or volumic source term ( \\int B.v ).
    
    If `bnum` is omitted (or set to -1) , the brick adds a volumic
    source term on the whole mesh. For `bnum` >= 0, the source term is
    imposed on the mesh region `bnum`. Use MdBrick.set_param('source
    term',mf,B) to set the source term field. The source term is
    expected as a vector field of size Q (with Q = qdim).

  * ``B = MdBrick('normal source term', MdBrick pb, int bnum[, int nfem])``
    Add a boundary source term ( \\int (Bn).v ).
    
    The source term is imposed on the mesh region `bnum` (which of course
    is not allowed to be a volumic region, only boundary regions are
    allowed). Use MdBrick.set_param('source term',mf,B) to set the
    source term field. The source term B is expected as tensor field
    of size QxN (with Q = qdim, N = mesh dim). For example, if you
    consider an elasticity problem, this brick may be used to impose
    a force on the boundary with B as the stress tensor.

  * ``B = MdBrick('normal derivative source term', MdBrick parent, int bnum[, int nfem])``
    Add a boundary source term ( \\int (\\partial_n B).v ).
    
    The source term is imposed on the mesh region `bnum`. Use
    MdBrick.set_param('source term',mf,B) to set the source term
    field, which is expected as a vector field of size Q (with Q =
    qdim).

  * ``B = MdBrick('neumann KirchhoffLove source term', MdBrick pb, int bnum[, int nfem])``
    Add a boundary source term for neumann Kirchhoff-Love plate problems.
    
    Should be used with the Kirchhoff-Love flavour of the bilaplacian
    brick.

  * ``B = MdBrick('qu term', MdBrick pb[, int bnum[, int nfem]])``
    Update the tangent matrix with a \\int (Qu).v term.
    
    The Q(x) parameter is a matrix field of size qdim x qdim. An example
    of use is for the "iku" part of Robin boundary conditions
    \\partial_n u + iku = ...

  * ``B = MdBrick('mass matrix', MeshIm mim, MeshFem mf_u[, 'real'|'complex'])``
    Build a mass-matrix brick.

  * ``B = MdBrick('generic elliptic', MeshIm mim, MeshFem mfu[, 'scalar'|'matrix'|'tensor'][, 'real'|'complex'])``
    Setup a generic elliptic problem.
    
    a(x)*grad(U).grad(V)
    
    The brick parameter `a` may be a scalar field, a matrix field, or
    a tensor field (default is scalar).

  * ``B = MdBrick('helmholtz', MeshIm mim, MeshFem mfu[, 'real'|'complex'])``
    Setup a Helmholtz problem.
    
    The brick has one parameter, 'wave_number'.

  * ``B = MdBrick('isotropic linearized elasticity', MeshIm mim, MeshFem mfu)``
    Setup a linear elasticity problem.
    
    The brick has two scalar parameter, 'lambda' and 'mu' (the Lame
    coefficients).

  * ``B = MdBrick('linear incompressibility term', MdBrick pb, MeshFem mfp[, int nfem])``
    Add an incompressibily constraint (div u = 0).

  * ``B = MdBrick('nonlinear elasticity', MeshIm mim, MeshFem mfu, string law)``
    Setup a nonlinear elasticity (large deformations) problem.
    
    The material `law` can be chosen among:
    
    - 'SaintVenant Kirchhoff' :
      Linearized material law.
    - 'Mooney Rivlin' :
      To be used with the nonlinear incompressibily term.
    - 'Ciarlet Geymonat'

  * ``B = MdBrick('nonlinear elasticity incompressibility term', MdBrick pb, MeshFem mfp[, int nfem])``
    Add an incompressibily constraint to a large strain elasticity problem.

  * ``B = MdBrick('small deformations plasticity', MeshIm mim, MeshFem mfu, scalar THRESHOLD)``
    Setup a plasticity problem (with small deformations).
    
    The `THRESHOLD` parameter is the maximum value of the Von Mises
    stress before 'plastification' of the material.

  * ``B = MdBrick('dynamic', MdBrick pb, scalar rho[, int numfem])``
    Dynamic brick. This brick is not fully working.

  * ``B = MdBrick('bilaplacian', MeshIm mim, MeshFem mfu[, 'Kirchhoff-Love'])``
    Setup a bilaplacian problem.
    
    If the 'Kirchhoff-Love' option is specified, the Kirchhoff-Love
    plate model is used.

  * ``B = MdBrick('navier stokes', MeshIm mim, MeshFem mfu, MeshFem mfp)``
    Setup a Navier-Stokes problem (this brick is not ready, do not use it).

  * ``B = MdBrick('isotropic_linearized_plate', MeshIm mim, MeshIm mims, MeshFem mfut, MeshFem mfu3, MeshFem mftheta, scalar eps)``
    Setup a linear plate model brick.
    
    For moderately thick plates, using the Reissner-Mindlin model.
    `eps` is the plate thinkness, the MeshFem `mfut` and `mfu3` are used
    respectively for the membrane displacement and the transverse
    displacement of the plate. The MeshFem `mftheta` is the rotation of
    the normal ("section rotations").
    
    The second integration method `mims` can be chosen equal to
    `mim`, or different if you want to perform sub-integration on
    the transverse shear term (mitc4 projection).
    
    This brick has two parameters "lambda" and "mu" (the Lame
    coefficients)

  * ``B = MdBrick('mixed_isotropic_linearized_plate', MeshIm mim, MeshFem mfut, MeshFem mfu3, MeshFem mftheta, scalar eps)``
    Setup a mixed linear plate model brick.
    
    For thin plates, using Kirchhoff-Love model. For a non-mixed version,
    use the bilaplacian brick.

  * ``B = MdBrick('plate_source_term', MdBrick pb[, int bnum=-1[, int nfem]])``
    Add a boundary or a volumic source term to a plate problem.
    
    This brick has two parameters: "B" is the displacement (ut and u3)
    source term, "M" is the moment source term (i.e. the source term
    on the rotation of the normal).

  * ``B = MdBrick('plate_simple_support', MdBrick pb, int bnum, string CTYPE[, int nfem])``
    Add a "simple support" boundary condition to a plate problem.
    
    Homogeneous Dirichlet condition on the displacement, free rotation.
    `CTYPE` specifies how the constraint is enforced ('penalized',
    'augmented' or 'eliminated').

  * ``B = MdBrick('plate_clamped_support', MdBrick pb, int bnum, string CTYPE[, int nfem])``
    Add a "clamped support" boundary condition to a plate problem.
    
    Homogeneous Dirichlet condition on the displacement and on the
    rotation. `CTYPE` specifies how the constraint is enforced
    ('penalized', 'augmented' or 'eliminated').

  * ``B = MdBrick('plate_closing', MdBrick pb[, int nfem])``
    Add a free edges condition for the mixed plate model brick.
    
    This brick is required when the mixed linearized plate brick is
    used. It must be inserted after all other boundary conditions
    (the reason is that the brick has to inspect all other boundary
    conditions to determine the number of disconnected boundary parts
    which are free edges). 

    """
    generic_constructor(self,'mdbrick',*args)
  def __del__(self):
    generic_destructor(self, destructible=True)
  def get(self, *args):
    return getfem('mdbrick_get',self.id, *args)
  def __repr__(self):
    getfem('mdbrick_get',self.id, 'display')
    return ''
  def set(self, *args):
    return getfem('mdbrick_set',self.id, *args)
  def __str__(self):
    return self.char()

  def nbdof(self):
    """Get the total number of dof of the current problem.
    
    This is the sum of the brick specific dof plus the dof of the
    parent bricks."""
    return self.get("nbdof")


  def dim(self):
    """Get the dimension of the main mesh (2 for a 2D mesh, etc)."""
    return self.get("dim")


  def nb_constraints(self):
    """Get the total number of dof constraints of the current problem.
    
    This is the sum of the brick specific dof constraints plus the
    dof constraints of the parent bricks."""
    return self.get("nb_constraints")


  def is_linear(self):
    """Return true if the problem is linear."""
    return self.get("is_linear")


  def is_symmetric(self):
    """Return true if the problem is symmetric."""
    return self.get("is_symmetric")


  def is_coercive(self):
    """Return true if the problem is coercive."""
    return self.get("is_coercive")


  def is_complex(self):
    """Return true if the problem uses complex numbers."""
    return self.get("is_complex")


  def mixed_variables(self):
    """Identify the indices of mixed variables (typically the pressure,
    etc.) in the tangent matrix."""
    return self.get("mixed_variables")


  def subclass(self):
    """Get the typename of the brick."""
    return self.get("subclass")


  def param_list(self):
    """Get the list of parameters names.
    
    Each brick embeds a number of parameters (the Lame coefficients
    for the linearized elasticity brick, the wave number for the
    Helmholtz brick,...), described as a (scalar, or vector, tensor
    etc) field on a mesh_fem. You can read/change the parameter values
    with MdBrick.param() and MdBrick.param()."""
    return self.get("param_list")


  def param(self, parameter_name):
    """Get the parameter value.
    
    When the parameter has been assigned a specific MeshFem, it is returned
    as a large array (the last dimension being the MeshFem dof). When no
    MeshFem has been assigned, the parameter is considered to be constant
    over the mesh."""
    return self.get("param", parameter_name)


  def solve(self, mds, *args):
    """Synopsis: MdBrick.solve(self,MdState mds[,...])

    Run the standard getfem solver.
    
    Note that you should be able to use your own solver if you want
    (it is possible to obtain the tangent matrix and its right hand
    side with the MdState.tangent_matrix() etc.).
    
    Various options can be specified:
    
    - 'noisy' or 'very noisy'
       the solver will display some information showing the progress
       (residual values etc.).
    - 'max_iter', NIT
       set the maximum iterations numbers.
    - 'max_res', RES
       set the target residual value.
    - 'lsolver', SOLVERNAME
       select explicitely the solver used for the linear systems (the
       default value is 'auto', which lets getfem choose itself).
       Possible values are 'superlu', 'mumps' (if supported),
       'cg/ildlt', 'gmres/ilu' and 'gmres/ilut'."""
    return self.get("solve", mds, *args)


  def von_mises(self, mds, mfvm):
    """Compute the Von Mises stress on the MeshFem `mfvm`.
    
    Only available on bricks where it has a meaning: linearized
    elasticity, plasticity, nonlinear elasticity. Note that in 2D
    it is not the "real" Von Mises (which should take into account
    the 'plane stress' or 'plane strain' aspect), but a pure 2D Von
    Mises."""
    return self.get("von_mises", mds, mfvm)


  def tresca(self, mds, mft):
    """Compute the Tresca stress criterion on the MeshFem `mft`.
    
    Only available on bricks where it has a meaning: linearized
    elasticity, plasticity, nonlinear elasticity."""
    return self.get("tresca", mds, mft)


  def memsize(self):
    """Return the amount of memory (in bytes) used by the model brick."""
    return self.get("memsize")


  def char(self):
    """Output a (unique) string representation of the MdBrick.
    
    This can be used to perform comparisons between two
    different MdBrick objects.
    This function is to be completed.
    """
    return self.get("char")


  def display(self):
    """displays a short summary for a MdBrick."""
    return self.get("display")


  def set_param(self, name, *args):
    """Synopsis: MdBrick.set_param(self, string name, {MeshFem mf,V | V})

    Change the value of a brick parameter.
    
    `name` is the name of the parameter. `V` should contain the
    new parameter value (vector or float). If a MeshFem is given,
    `V` should hold the field values over that MeshFem (i.e. its
    last dimension should be MeshFem.nbdof() or 1 for
    constant field)."""
    return self.set("param", name, *args)


  def penalization_epsilon(self, eps):
    """Change the penalization coefficient of a constraint brick.
    
    This is only applicable to the bricks which inherit from the
    constraint brick, such as the Dirichlet ones. And of course it
    is not effective when the constraint is enforced via direct
    elimination or via Lagrange multipliers. The default value of
    `eps` is 1e-9."""
    return self.set("penalization_epsilon", eps)


  def constraints(self, H, R):
    """Set the constraints imposed by a constraint brick.
    
    This is only applicable to the bricks which inherit from the
    constraint brick, such as the Dirichlet ones. Imposes `H.U=R`."""
    return self.set("constraints", H, R)


  def constraints_rhs(self, H, R):
    """Set the right hand side of the constraints imposed by a constraint brick.
    
    This is only applicable to the bricks which inherit from the
    constraint brick, such as the Dirichlet ones."""
    return self.set("constraints_rhs", H, R)


#
# GetFEM class MdState definition.
#

class MdState:
  """GetFEM MdState object

  A model state is an object which store the state data for a chain of model
  bricks. This includes the global tangent matrix, the right hand side and
  the constraints.

  This object is now deprecated and replaced by the Model object.

  There are two sorts of model states, the `real` and the `complex` models
  states.

  """
  def __init__(self, *args):
    """General constructor for MdState objects

  * ``MDS = MdState('real')``
    Build a model state for real unknowns.

  * ``MDS = MdState('complex')``
    Build a model state for complex unknowns.

  * ``MDS = MdState(MdBrick B)``
    Build a modelstate for the brick `B`.
    
    Selects the real or complex state from the complexity of `B`.

    """
    generic_constructor(self,'mdstate',*args)
  def __del__(self):
    generic_destructor(self, destructible=True)
  def get(self, *args):
    return getfem('mdstate_get',self.id, *args)
  def __repr__(self):
    getfem('mdstate_get',self.id, 'display')
    return ''
  def set(self, *args):
    return getfem('mdstate_set',self.id, *args)
  def __str__(self):
    return self.char()

  def is_complex(self):
    """Return 0 is the model state is real, 1 if it is complex."""
    return self.get("is_complex")


  def tangent_matrix(self):
    """Return the tangent matrix stored in the model state."""
    return self.get("tangent_matrix")


  def constraints_matrix(self):
    """Return the constraints matrix stored in the model state."""
    return self.get("constraints_matrix")


  def reduced_tangent_matrix(self):
    """Return the reduced tangent matrix (i.e. the tangent matrix after
    elimination of the constraints)."""
    return self.get("reduced_tangent_matrix")


  def constraints_nullspace(self):
    """Return the nullspace of the constraints matrix."""
    return self.get("constraints_nullspace")


  def state(self):
    """Return the vector of unknowns, which contains the solution after MdBrick.solve()."""
    return self.get("state")


  def residual(self):
    """Return the residual."""
    return self.get("residual")


  def reduced_residual(self):
    """Return the residual on the reduced system."""
    return self.get("reduced_residual")


  def unreduce(self, U):
    """Reinsert the constraint eliminated from the system."""
    return self.get("unreduce", U)


  def memsize(self):
    """Return the amount of memory (in bytes) used by the model state."""
    return self.get("memsize")


  def char(self):
    """Output a (unique) string representation of the MdState.
    
    This can be used to perform comparisons between two
    different MdState objects.
    This function is to be completed.
    """
    return self.get("char")


  def display(self):
    """displays a short summary for a MdState."""
    return self.get("display")


  def compute_reduced_system(self):
    """Compute the reduced system from the tangent matrix and constraints."""
    return self.set("compute_reduced_system")


  def compute_reduced_residual(self):
    """Compute the reduced residual from the residual and constraints."""
    return self.set("compute_reduced_residual")


  def compute_residual(self, B):
    """Compute the residual for the brick `B`."""
    return self.set("compute_residual", B)


  def compute_tangent_matrix(self, B):
    """Update the tangent matrix from the brick `B`."""
    return self.set("compute_tangent_matrix", B)


  def set_state(self, U):
    """Update the internal state with the vector `U`."""
    return self.set("state", U)


  def clear(self):
    """Clear the model state."""
    return self.set("clear")


#
# GetFEM class Mesh definition.
#

class Mesh:
  """GetFEM Mesh object

  This object is able to store any element in any dimension even if you mix
  elements with different dimensions.

  

  """
  def __init__(self, *args):
    """General constructor for Mesh objects

  * ``M = Mesh('empty', int dim)``
    Create a new empty mesh.

  * ``M = Mesh('cartesian', vec X[, vec Y[, vec Z,..]])``
    Build quickly a regular mesh of quadrangles, cubes, etc.

  * ``M = Mesh('cartesian Q1', vec X, vec Y[, vec Z,..])``
    Build quickly a regular mesh of quadrangles, cubes, etc. with
    Q1 elements.

  * ``M = Mesh('triangles grid', vec X, vec Y)``
    Build quickly a regular mesh of triangles.
    
    This is a very limited and somehow deprecated function (See also
    ``Mesh('ptND')``, ``Mesh('regular simplices')`` and
    ``Mesh('cartesian')``).

  * ``M = Mesh('regular simplices', vec X[, vec Y[, vec Z,...]]['degree', int k]['noised'])``
    Mesh a n-dimensionnal parallelepipeded with simplices (triangles,
    tetrahedrons etc) .
    
    The optional degree may be used to build meshes with non linear
    geometric transformations.

  * ``M = Mesh('curved', Mesh m, vec F)``
    Build a curved (n+1)-dimensions mesh from a n-dimensions mesh `m`.
    
    The points of the new mesh have one additional coordinate, given by
    the vector `F`. This can be used to obtain meshes for shells. `m` may
    be a MeshFem object, in that case its linked mesh will be used.

  * ``M = Mesh('prismatic', Mesh m, int nl)``
    Extrude a prismatic Mesh `M` from a Mesh `m`.
    
    In the additional dimension there are `nl` layers of elements built
    from ``0`` to ``1``.

  * ``M = Mesh('pt2D', mat P, imat T[, int n])``
    Build a mesh from a 2D triangulation.
    
    Each column of `P` contains a point coordinate, and each column of `T`
    contains the point indices of a triangle. `n` is optional and is a
    zone number. If `n` is specified then only the zone number `n` is
    converted (in that case, `T` is expected to have 4 rows, the fourth
    containing these zone numbers).
    
    

  * ``M = Mesh('ptND', mat P, imat T)``
    Build a mesh from a n-dimensional "triangulation".
    
    Similar function to 'pt2D', for building simplexes meshes from a
    triangulation given in `T`, and a list of points given in `P`. The
    dimension of the mesh will be the number of rows of `P`, and the
    dimension of the simplexes will be the number of rows of `T`.

  * ``M = Mesh('load', string filename)``
    Load a mesh from a getfem++ ascii mesh file.
    
    See also ``Mesh.save(string filename)``.

  * ``M = Mesh('from string', string s)``
    Load a mesh from a string description.
    
    For example, a string returned by ``Mesh.char()``.

  * ``M = Mesh('import', string format, string filename)``
    Import a mesh.
    
    `format` may be:
    
    - 'gmsh' for a mesh created with `Gmsh`
    - 'gid' for a mesh created with `GiD`
    - 'am_fmt' for a mesh created with `EMC2`

  * ``M = Mesh('clone', Mesh m2)``
    Create a copy of a mesh.

  * ``M = Mesh('generate', MesherObject mo, scalar h[, int K = 1[, mat vertices]])``
    Call the (very) experimental mesher of Getfem on the geometry
    represented by `mo`. please control the conformity of the produced mesh.
    You can add the mesher by adding a priori vertices in the array
    `vertices` which should be of size ``n x m`` where ``n`` n is the
    dimension of the mesh and ``m`` the number of points. `h` is
    approximate diameter of the elements. `K` is the degree of the
    mesh ( > 1 for curved boundaries).  The mesher try to optimize the
    quality of the elements. This operation may be time consuming.
    Note that if the mesh generation fails, because of some random
    procedure used, it will not give necessarily the same result due
    to random procedures used.
    The messages send to the console by the mesh generation can be
    desactivated using `gf_util('trace level', 2)`. More information
    can be obtained by `gf_util('trace level', 4)`.
    

    """
    generic_constructor(self,'mesh',*args)
  def __del__(self):
    generic_destructor(self, destructible=True)
  def get(self, *args):
    return getfem('mesh_get',self.id, *args)
  def __repr__(self):
    getfem('mesh_get',self.id, 'display')
    return ''
  def set(self, *args):
    return getfem('mesh_set',self.id, *args)
  def __str__(self):
    return self.char()

  def dim(self):
    """Get the dimension of the mesh (2 for a 2D mesh, etc)."""
    return self.get("dim")


  def nbpts(self):
    """Get the number of points of the mesh."""
    return self.get("nbpts")


  def nbcvs(self):
    """Get the number of convexes of the mesh."""
    return self.get("nbcvs")


  def pts(self, PIDs=None):
    """Return the list of point coordinates of the mesh.
    
    Each column of the returned matrix contains the coordinates of one
    point. If the optional argument `PIDs` was given, only the points
    whose #id is listed in this vector are returned. Otherwise, the
    returned matrix will have Mesh.max_pid() columns, which might
    be greater than Mesh.nbpts() (if some points of the mesh have
    been destroyed and no call to Mesh.optimize_structure() have
    been issued). The columns corresponding to deleted points will be
    filled with NaN. You can use Mesh.pid() to filter such invalid
    points."""
    return self.get("pts", PIDs)


  def pid(self):
    """Return the list of points #id of the mesh.
    
    Note that their numbering is not supposed to be contiguous from
    0 to Mesh.nbpts()-1,
    especially if some points have been removed from the mesh. You
    can use Mesh.optimize_structure() to enforce a contiguous
    numbering."""
    return self.get("pid")


  def pid_in_faces(self, CVFIDs):
    """Search point #id listed in `CVFIDs`.
    
    `CVFIDs` is a two-rows matrix, the first row lists convex #ids,
    and the second lists face numbers. On return, `PIDs` is a
    vector containing points #id."""
    return self.get("pid_in_faces", CVFIDs)


  def pid_in_cvids(self, CVIDs):
    """Search point #id listed in `CVIDs`.
    
    `PIDs` is a vector containing points #id."""
    return self.get("pid_in_cvids", CVIDs)


  def pid_in_regions(self, RIDs):
    """Search point #id listed in `RIDs`.
    
    `PIDs` is a vector containing points #id."""
    return self.get("pid_in_regions", RIDs)


  def pid_from_coords(self, PTS, radius=0):
    """Search point #id whose coordinates are listed in `PTS`.
    
    `PTS` is an array containing a list of point coordinates. On
    return, `PIDs` is a vector containing points
    #id for each point found in `eps` range, and -1 for those
    which where not found in the mesh."""
    return self.get("pid_from_coords", PTS, radius)


  def pid_from_cvid(self, CVIDs=None):
    """Return the points attached to each convex of the mesh.
    
    If `CVIDs` is omitted, all the convexes will be considered
    (equivalent to `CVIDs = Mesh.max_cvid()`). `IDx` is a
    vector, length(IDx) = length(CVIDs)+1. `Pid` is a
    vector containing the concatenated list of #id of
    points of each convex in `CVIDs`. Each entry of `IDx` is the
    position of the corresponding convex point list in `Pid`. Hence,
    for example, the list of #id of points of the second convex is
    Pid[IDx(2):IDx(3)].
    
    If `CVIDs` contains convex #id which do not exist in the mesh,
    their point list will be empty."""
    return self.get("pid_from_cvid", CVIDs)


  def pts_from_cvid(self, CVIDs=None):
    """Search point listed in `CVID`.
    
    If `CVIDs` is omitted, all the convexes will be considered
    (equivalent to `CVIDs = Mesh.max_cvid()`). `IDx` is a
    vector, length(IDx) = length(CVIDs)+1. `Pts` is a
    vector containing the concatenated list of points
    of each convex in `CVIDs`. Each entry of `IDx` is the position
    of the corresponding convex point list in `Pts`. Hence, for
    example, the list of points of the second convex is
    Pts[:,IDx[2]:IDx[3]].
    
    If `CVIDs` contains convex #id which do not exist in the mesh,
    their point list will be empty."""
    return self.get("pts_from_cvid", CVIDs)


  def cvid(self):
    """Return the list of all convex #id.
    
    Note that their numbering is not supposed to be contiguous from
    0 to Mesh.nbcvs()-1,
    especially if some points have been removed from the mesh. You
    can use Mesh.optimize_structure() to enforce a contiguous
    numbering."""
    return self.get("cvid")


  def max_pid(self):
    """Return the maximum #id of all points in the mesh (see 'max cvid')."""
    return self.get("max_pid")


  def max_cvid(self):
    """Return the maximum #id of all convexes in the mesh (see 'max pid')."""
    return self.get("max_cvid")


  def edges(self, CVLST=None, *args):
    """Synopsis: [E,C] = Mesh.edges(self [, CVLST][, 'merge'])

    [OBSOLETE FUNCTION! will be removed in a future release]
    
    Return the list of edges of mesh M for the convexes listed in the
    row vector CVLST. E is a 2 x nb_edges matrix containing point
    indices. If CVLST is omitted, then the edges of all convexes are
    returned. If CVLST has two rows then the first row is supposed to
    contain convex numbers, and the second face numbers, of which the
    edges will be returned.  If 'merge' is indicated, all common
    edges of convexes are merged in a single edge.  If the optional
    output argument C is specified, it will contain the convex number
    associated with each edge."""
    return self.get("edges", CVLST, *args)


  def curved_edges(self, N, CVLST=None):
    """[OBSOLETE FUNCTION! will be removed in a future release]
    
    More sophisticated version of Mesh.edges() designed for
    curved elements. This one will return N (N>=2) points of the
    (curved) edges. With N==2, this is equivalent to
    Mesh.edges(). Since the points are no more always part of
    the mesh, their coordinates are returned instead of points
    number, in the array E which is a [ mesh_dim x 2 x nb_edges ]
    array.  If the optional output argument C is specified, it will
    contain the convex number associated with each edge."""
    return self.get("curved_edges", N, CVLST)


  def orphaned_pid(self):
    """Search point #id which are not linked to a convex."""
    return self.get("orphaned_pid")


  def cvid_from_pid(self, PIDs, share=False):
    """Search convex #ids related with the point #ids given in `PIDs`.
    
    If `share=False`, search convex whose vertex #ids are in `PIDs`.
    If `share=True`, search convex #ids that share the point #ids
    given in `PIDs`. `CVIDs` is a  vector (possibly
    empty)."""
    return self.get("cvid_from_pid", PIDs, share)


  def faces_from_pid(self, PIDs):
    """Return the convex faces whose vertex #ids are in `PIDs`.
    
    `CVFIDs` is a two-rows matrix, the first row lists convex #ids,
    and the second lists face numbers (local number in the convex).
    For a convex face to be returned, EACH of its points have to be
    listed in `PIDs`."""
    return self.get("faces_from_pid", PIDs)


  def outer_faces(self, CVIDs=None):
    """Return the faces which are not shared by two convexes.
    
    `CVFIDs` is a two-rows matrix, the first row lists convex #ids,
    and the second lists face numbers (local number in the convex).
    If `CVIDs` is not given, all convexes are considered, and it
    basically returns the mesh boundary. If `CVIDs` is given, it
    returns the boundary of the convex set whose #ids are listed
    in `CVIDs`."""
    return self.get("outer_faces", CVIDs)


  def faces_from_cvid(self, CVIDs=None, *args):
    """Synopsis: CVFIDs = Mesh.faces_from_cvid(self[, ivec CVIDs][, 'merge'])

    Return a list of convexes faces from a list of convex #id.
    
    `CVFIDs` is a two-rows matrix, the first row lists convex #ids,
    and the second lists face numbers (local number in the convex).
    If `CVIDs` is not given, all convexes are considered. The optional
    argument 'merge' merges faces shared by the convex of `CVIDs`."""
    return self.get("faces_from_cvid", CVIDs, *args)


  def triangulated_surface(self, Nrefine, CVLIST=None):
    """[DEPRECATED FUNCTION! will be removed in a future release]
    
    Similar function to Mesh.curved_edges() : split (if
    necessary, i.e. if the geometric transformation if non-linear)
    each face into sub-triangles and return their coordinates in T
    (see also gf_compute('eval on P1 tri mesh'))"""
    return self.get("triangulated_surface", Nrefine, CVLIST)


  def normal_of_face(self, cv, f, nfpt=None):
    """Evaluates the normal of convex `cv`, face `f` at the `nfpt` point of the face.
    
    If `nfpt` is not specified, then the normal is evaluated at each
    geometrical node of the face."""
    return self.get("normal_of_face", cv, f, nfpt)


  def normal_of_faces(self, CVFIDs):
    """Evaluates (at face centers) the normals of convexes.
    
    `CVFIDs` is supposed a two-rows matrix, the first row lists convex
    #ids, and the second lists face numbers (local number in the convex)."""
    return self.get("normal_of_faces", CVFIDs)


  def quality(self, CVIDs=None):
    """Return an estimation of the quality of each convex (:math:`0 \\leq Q \\leq 1`)."""
    return self.get("quality", CVIDs)


  def convex_area(self, CVIDs=None):
    """Return an estimate of the area of each convex."""
    return self.get("convex_area", CVIDs)


  def convex_radius(self, CVIDs=None):
    """Return an estimate of the radius of each convex."""
    return self.get("convex_radius", CVIDs)


  def cvstruct(self, CVIDs=None):
    """Return an array of the convex structures.
    
    If `CVIDs` is not given, all convexes are considered. Each convex
    structure is listed once in `S`, and `CV2S` maps the convexes
    indice in `CVIDs` to the indice of its structure in `S`."""
    return self.get("cvstruct", CVIDs)


  def geotrans(self, CVIDs=None):
    """Returns an array of the geometric transformations.
    
    See also Mesh.cvstruct()."""
    return self.get("geotrans", CVIDs)


  def boundaries(self):
    """DEPRECATED FUNCTION. Use 'regions' instead."""
    return self.get("boundaries")


  def regions(self):
    """Return the list of valid regions stored in the mesh."""
    return self.get("regions")


  def boundary(self):
    """DEPRECATED FUNCTION. Use 'region' instead."""
    return self.get("boundary")


  def region(self, RIDs):
    """Return the list of convexes/faces on the regions `RIDs`.
    
    `CVFIDs` is a two-rows matrix, the first row lists convex #ids,
    and the second lists face numbers (local number in the convex).
    (and -1 when the whole convex is in the
    regions)."""
    return self.get("region", RIDs)


  def save(self, filename):
    """Save the mesh object to an ascii file.
    
    This mesh can be restored with Mesh('load', filename)."""
    return self.get("save", filename)


  def char(self):
    """Output a string description of the mesh."""
    return self.get("char")


  def export_to_vtk(self, filename, *args):
    """Synopsis: Mesh.export_to_vtk(self, string filename, ... [,'ascii'][,'quality'])

    Exports a mesh to a VTK file .
    
    If 'quality' is specified, an estimation of the quality of each
    convex will be written to the file.
    
    See also MeshFem.export_to_vtk(), Slice.export_to_vtk()."""
    return self.get("export_to_vtk", filename, *args)


  def export_to_dx(self, filename, *args):
    """Synopsis: Mesh.export_to_dx(self, string filename, ... [,'ascii'][,'append'][,'as',string name,[,'serie',string serie_name]][,'edges'])

    Exports a mesh to an OpenDX file.
    
    See also MeshFem.export_to_dx(), Slice.export_to_dx()."""
    return self.get("export_to_dx", filename, *args)


  def export_to_pos(self, filename, name=None):
    """Exports a mesh to a POS file .
    
    See also MeshFem.export_to_pos(), Slice.export_to_pos()."""
    return self.get("export_to_pos", filename, name)


  def memsize(self):
    """Return the amount of memory (in bytes) used by the mesh."""
    return self.get("memsize")


  def display(self):
    """displays a short summary for a Mesh object."""
    return self.get("display")


  def set_pts(self, PTS):
    """Replace the coordinates of the mesh points with those given in `PTS`."""
    return self.set("pts", PTS)


  def add_point(self, PTS):
    """Insert new points in the mesh and return their #ids.
    
    `PTS` should be an ``nxm`` matrix , where ``n`` is the mesh
    dimension, and ``m`` is the number of points that will be
    added to the mesh. On output, `PIDs` contains the point #ids
    of these new points.
    
    Remark: if some points are already part of the mesh (with a small
    tolerance of approximately ``1e-8``), they won't be inserted again,
    and `PIDs` will contain the previously assigned #ids of these
    points."""
    return self.set("add_point", PTS)


  def del_point(self, PIDs):
    """Removes one or more points from the mesh.
    
    `PIDs` should contain the point #ids, such as the one returned by
    the 'add point' command."""
    return self.set("del_point", PIDs)


  def add_convex(self, GT, PTS):
    """Add a new convex into the mesh.
    
    The convex structure (triangle, prism,...) is given by `GT`
    (obtained with GeoTrans('...')), and its points are given by
    the columns of `PTS`. On return, `CVIDs` contains the convex #ids.
    `PTS` might be a 3-dimensional array in order to insert more than
    one convex (or a two dimensional array correctly shaped according
    to Fortran ordering)."""
    return self.set("add_convex", GT, PTS)


  def del_convex(self, CVIDs):
    """Remove one or more convexes from the mesh.
    
    `CVIDs` should contain the convexes #ids, such as the ones
    returned by the 'add convex' command."""
    return self.set("del_convex", CVIDs)


  def del_convex_of_dim(self, DIMs):
    """Remove all convexes of dimension listed in `DIMs`.
    
    For example; ``Mesh.del_convex_of_dim([1,2])`` remove
    all line segments, triangles and quadrangles."""
    return self.set("del_convex_of_dim", DIMs)


  def translate(self, V):
    """Translates each point of the mesh from `V`."""
    return self.set("translate", V)


  def transform(self, T):
    """Applies the matrix `T` to each point of the mesh.
    
    Note that `T` is not required to be a ``NxN`` matrix (with
    ``N = Mesh.dim()``). Hence it is possible to transform
    a 2D mesh into a 3D one (and reciprocally)."""
    return self.set("transform", T)


  def set_boundary(self, rnum, CVFIDs):
    """DEPRECATED FUNCTION. Use 'region' instead."""
    return self.set("boundary", rnum, CVFIDs)


  def set_region(self, rnum, CVFIDs):
    """Assigns the region number `rnum` to the convex faces (or convexes)
    stored in each column of the matrix `CVFIDs`.
    
    The first row of `CVFIDs` contains a convex #ids, and the second row
    contains a face number in the convex (or ``-1``
    for the whole convex (regions are usually used to store a list of
    convex faces, but you may also use them to store a list of convexes).
    
    If a vector is provided (or a one row matrix) the region will represent
    the corresponding set of convex."""
    return self.set("region", rnum, CVFIDs)


  def region_intersect(self, r1, r2):
    """Replace the region number `r1` with its intersection with region number `r2`."""
    return self.set("region_intersect", r1, r2)


  def region_merge(self, r1, r2):
    """Merge region number `r2` into region number `r1`."""
    return self.set("region_merge", r1, r2)


  def region_substract(self, r1, r2):
    """Replace the region number `r1` with its difference with region
    number `r2`."""
    return self.set("region_substract", r1, r2)


  def delete_boundary(self, rnum, CVFIDs):
    """DEPRECATED FUNCTION. Use 'delete region' instead."""
    return self.set("delete_boundary", rnum, CVFIDs)


  def delete_region(self, RIDs):
    """Remove the regions whose #ids are listed in `RIDs`"""
    return self.set("delete_region", RIDs)


  def merge(self, m2):
    """Merge with the Mesh `m2`.
    
    Overlapping points won't be duplicated. If `m2` is a MeshFem object,
    its linked mesh will be used."""
    return self.set("merge", m2)


  def optimize_structure(self):
    """Reset point and convex numbering.
    
    After optimisation, the points (resp. convexes) will
    be consecutively numbered from ``0`` to
    ``Mesh.max_pid()-1`` (resp. ``Mesh.max_cvid()-1``)."""
    return self.set("optimize_structure")


  def refine(self, CVIDs=None):
    """Use a Bank strategy for mesh refinement.
    
    If `CVIDs` is not given, the whole mesh is refined. Note
    that the regions, and the finite element methods and
    integration methods of the MeshFem and MeshIm objects linked
    to this mesh will be automagically refined."""
    return self.set("refine", CVIDs)


#
# GetFEM class MeshFem definition.
#

class MeshFem:
  """GetFEM MeshFem object

  This object represents a finite element method defined on a whole mesh.

  """
  def __init__(self, *args):
    """General constructor for MeshFem objects

  * ``MF = MeshFem('load', string fname[, Mesh m])``
    Load a MeshFem from a file.
    
    If the mesh `m` is not supplied (this kind of file does not store the
    mesh), then it is read from the file `fname` and its descriptor is
    returned as the second output argument.

  * ``MF = MeshFem('from string', string s[, Mesh m])``
    Create a MeshFem object from its string description.
    
    See also ``MeshFem.char()``

  * ``MF = MeshFem('clone', MeshFem mf)``
    Create a copy of a MeshFem.

  * ``MF = MeshFem('sum', MeshFem mf1, MeshFem mf2[, MeshFem mf3[, ...]])``
    Create a MeshFem that combines two (or more) MeshFem's.
    
    All MeshFem must share the same mesh (see
    ``Fem('interpolated_fem')`` to map a MeshFem onto another).
    
    After that, you should not modify the FEM of `mf1`, `mf2` etc.

  * ``MF = MeshFem('levelset', MeshLevelSet mls, MeshFem mf)``
    Create a MeshFem that is conformal to implicit surfaces defined in
    MeshLevelSet.

  * ``MF = MeshFem('global function', Mesh m, LevelSet ls, (GlobalFunction GF1,...)[, int Qdim_m])``
    Create a MeshFem whose base functions are global function given by the
    user in the system of coordinate defined by the iso-values of the two
    level-set function of `ls`. 

  * ``MF = MeshFem('partial', MeshFem mf, ivec DOFs[, ivec RCVs])``
    Build a restricted MeshFem by keeping only a subset of the degrees of
    freedom of `mf`.
    
    If `RCVs` is given, no FEM will be put on the convexes listed in
    `RCVs`.

  * ``MF = MeshFem(Mesh m[, int Qdim_m=1[, int Qdim_n=1]])``
    Build a new MeshFem object.
    
    `Qdim_m` and `Qdim_n` parameters are optionals. Returns the handle of
    the created object. 

    """
    generic_constructor(self,'mesh_fem',*args)
  def __del__(self):
    generic_destructor(self, destructible=True)
  def get(self, *args):
    return getfem('mesh_fem_get',self.id, *args)
  def __repr__(self):
    getfem('mesh_fem_get',self.id, 'display')
    return ''
  def set(self, *args):
    return getfem('mesh_fem_set',self.id, *args)
  def __str__(self):
    return self.char()

  def nbdof(self):
    """Return the number of degrees of freedom (dof) of the MeshFem."""
    return self.get("nbdof")


  def nb_basic_dof(self):
    """Return the number of basic degrees of freedom (dof) of the MeshFem."""
    return self.get("nb_basic_dof")


  def dof_from_cv(self, CVids):
    """Deprecated function. Use MeshFem.basic_dof_from_cv() instead."""
    return self.get("dof_from_cv", CVids)


  def basic_dof_from_cv(self, CVids):
    """Return the dof of the convexes listed in `CVids`.
    
    WARNING: the Degree of Freedom might be returned in ANY order, do
    not use this function in your assembly routines. Use 'basic dof from cvid'
    instead, if you want to be able to map a convex number with its
    associated degrees of freedom.
    
    One can also get the list of basic dof on a set on convex faces, by
    indicating on the second row of `CVids` the faces numbers (with
    respect to the convex number on the first row)."""
    return self.get("basic_dof_from_cv", CVids)


  def dof_from_cvid(self, CVids=None):
    """Deprecated function. Use MeshFem.basic_dof_from_cvid() instead."""
    return self.get("dof_from_cvid", CVids)


  def basic_dof_from_cvid(self, CVids=None):
    """Return the degrees of freedom attached to each convex of the mesh.
    
    If `CVids` is omitted, all the convexes will be considered (equivalent
    to `CVids = 1 ... Mesh.max_cvid()`).
    
    `IDx` is a vector, `length(IDx) = length(CVids)+1`.
    `DOFs` is a vector containing the concatenated list
    of dof of each convex in `CVids`. Each entry of `IDx` is the position
    of the corresponding convex point list in `DOFs`. Hence, for example,
    the list of points of the second convex is DOFs[IDx(2):IDx(3)].
    
    If `CVids` contains convex #id which do not exist in the mesh, their
    point list will be empty."""
    return self.get("basic_dof_from_cvid", CVids)


  def non_conformal_dof(self, CVids=None):
    """Deprecated function. Use MeshFem.non_conformal_basic_dof() instead."""
    return self.get("non_conformal_dof", CVids)


  def non_conformal_basic_dof(self, CVids=None):
    """Return partially linked degrees of freedom.
    
    Return the basic dof located on the border of a convex and which belong
    to only one convex, except the ones which are located on the border
    of the mesh.  For example, if the convex 'a' and 'b' share a common
    face, 'a' has a P1 FEM, and 'b' has a P2 FEM, then the basic dof on the
    middle of the face will be returned by this function (this can be
    useful when searching the interfaces between classical FEM and
    hierarchical FEM)."""
    return self.get("non_conformal_basic_dof", CVids)


  def qdim(self):
    """Return the dimension Q of the field interpolated by the MeshFem.
    
    By default, Q=1 (scalar field). This has an impact on the dof numbering."""
    return self.get("qdim")


  def fem(self, CVids=None):
    """Return a list of FEM used by the MeshFem.
    
    `FEMs` is an array of all Fem objects found in the convexes
    given in `CVids`. If `CV2F` was supplied as an output argument,
    it contains, for each convex listed in `CVids`, the index of its
    correspounding FEM in `FEMs`.
    
    Convexes which are not part of the mesh, or convexes which do not
    have any FEM have their correspounding entry in `CV2F` set to -1.
    
    """
    return self.get("fem", CVids)


  def convex_index(self):
    """Return the list of convexes who have a FEM."""
    return self.get("convex_index")


  def is_lagrangian(self, CVids=None):
    """Test if the MeshFem is Lagrangian.
    
    Lagrangian means that each base function Phi[i] is such that
    Phi[i](P[j]) = delta(i,j), where P[j] is the dof location of
    the jth base function, and delta(i,j) = 1 if i==j, else 0.
    
    If `CVids` is omitted, it returns 1 if all convexes in the mesh
    are Lagrangian. If `CVids` is used, it returns the convex indices
    (with respect to `CVids`) which are Lagrangian."""
    return self.get("is_lagrangian", CVids)


  def is_equivalent(self, CVids=None):
    """Test if the MeshFem is equivalent.
    
    See MeshFem.is_lagrangian()"""
    return self.get("is_equivalent", CVids)


  def is_polynomial(self, CVids=None):
    """Test if all base functions are polynomials.
    
    See MeshFem.is_lagrangian()"""
    return self.get("is_polynomial", CVids)


  def is_reduced(self):
    """Return 1 if the optional reduction matrix is applied to the dofs."""
    return self.get("is_reduced")


  def reduction_matrix(self):
    """Return the optional reduction matrix."""
    return self.get("reduction_matrix")


  def extension_matrix(self):
    """Return the optional extension matrix."""
    return self.get("extension_matrix")


  def basic_dof_on_region(self, Rs):
    """Return the list of basic dof (before the optional reduction) lying on one
    of the mesh regions listed in `Rs`.
    
    More precisely, this function returns the basic dof whose support is
    non-null on one of regions whose #ids are listed in `Rs` (note
    that for boundary regions, some dof nodes may not lie exactly
    on the boundary, for example the dof of Pk(n,0) lies on the center
    of the convex, but the base function in not null on the convex
    border)."""
    return self.get("basic_dof_on_region", Rs)


  def dof_on_region(self, Rs):
    """Return the list of dof (after the optional reduction) lying on one
    of the mesh regions listed in `Rs`.
    
    More precisely, this function returns the basic dof whose support is
    non-null on one of regions whose #ids are listed in `Rs` (note
    that for boundary regions, some dof nodes may not lie exactly
    on the boundary, for example the dof of Pk(n,0) lies on the center
    of the convex, but the base function in not null on the convex
    border).
    
    For a reduced mesh_fem
    a dof is lying on a region if its potential corresponding shape
    function is nonzero on this region. The extension matrix is used
    to make the correspondance between basic and reduced dofs."""
    return self.get("dof_on_region", Rs)


  def dof_nodes(self, DOFids=None):
    """Deprecated function. Use MeshFem.basic_dof_nodes() instead."""
    return self.get("dof_nodes", DOFids)


  def basic_dof_nodes(self, DOFids=None):
    """Get location of basic degrees of freedom.
    
    Return the list of interpolation points for the specified
    dof #IDs in `DOFids` (if `DOFids` is omitted, all basic dof are
    considered)."""
    return self.get("basic_dof_nodes", DOFids)


  def dof_partition(self):
    """Get the 'dof_partition' array.
    
    Return the array which associates an integer (the partition number)
    to each convex of the MeshFem. By default, it is an all-zero array.
    The degrees of freedom of each convex of the MeshFem are connected
    only to the dof of neighbouring convexes which have the same
    partition number, hence it is possible to create partially
    discontinuous MeshFem very easily."""
    return self.get("dof_partition")


  def save(self, filename, opt=None):
    """Save a MeshFem in a text file (and optionaly its linked mesh object
    if `opt` is the string 'with_mesh')."""
    return self.get("save", filename, opt)


  def char(self, opt=None):
    """Output a string description of the MeshFem.
    
    By default, it does not include the description of the linked mesh
    object, except if `opt` is 'with_mesh'."""
    return self.get("char", opt)


  def display(self):
    """displays a short summary for a MeshFem object."""
    return self.get("display")


  def linked_mesh(self):
    """Return a reference to the Mesh object linked to `mf`."""
    return self.get("linked_mesh")


  def mesh(self):
    """Return a reference to the Mesh object linked to `mf`.
    (identical to Mesh.linked_mesh())"""
    return self.get("mesh")


  def export_to_vtk(self, filename, *args):
    """Synopsis: MeshFem.export_to_vtk(self,string filename, ... ['ascii'], U, 'name'...)

    Export a MeshFem and some fields to a vtk file.
    
    The FEM and geometric transformations will be mapped to order 1
    or 2 isoparametric Pk (or Qk) FEMs (as VTK does not handle higher
    order elements). If you need to represent high-order FEMs or
    high-order geometric transformations, you should consider
    Slice.export_to_vtk()."""
    return self.get("export_to_vtk", filename, *args)


  def export_to_dx(self, filename, *args):
    """Synopsis: MeshFem.export_to_dx(self,string filename, ...['as', string mesh_name][,'edges']['serie',string serie_name][,'ascii'][,'append'], U, 'name'...)

    Export a MeshFem and some fields to an OpenDX file.
    
    This function will fail if the MeshFem mixes different convex types
    (i.e. quads and triangles), or if OpenDX does not handle a specific
    element type (i.e. prism connections are not known by OpenDX).
    
    The FEM will be mapped to order 1 Pk (or Qk) FEMs. If you need to
    represent high-order FEMs or high-order geometric transformations,
    you should consider Slice.export_to_dx()."""
    return self.get("export_to_dx", filename, *args)


  def export_to_pos(self, filename, name=None, *args):
    """Synopsis: MeshFem.export_to_pos(self,string filename[, string name][[,MeshFem mf1], mat U1, string nameU1[[,MeshFem mf2], mat U2, string nameU2,...]])

    Export a MeshFem and some fields to a pos file.
    
    The FEM and geometric transformations will be mapped to order 1
    isoparametric Pk (or Qk) FEMs (as GMSH does not handle higher
    order elements)."""
    return self.get("export_to_pos", filename, name, *args)


  def dof_from_im(self, mim, p=None):
    """Return a selection of dof who contribute significantly to the
    mass-matrix that would be computed with `mf` and the integration
    method `mim`.
    
    `p` represents the dimension on what the integration method
    operates (default `p = mesh dimension`).
    
    IMPORTANT: you still have to set a valid integration method on
    the convexes which are not crosses by the levelset!"""
    return self.get("dof_from_im", mim, p)


  def interpolate_convex_data(self, Ucv):
    """Interpolate data given on each convex of the mesh to the MeshFem dof.
    The MeshFem has to be lagrangian, and should be discontinuous (typically
    a FEM_PK(N,0) or FEM_QK(N,0) should be used).
    
    The last dimension of the input vector Ucv should have
    Mesh.max_cvid() elements.
    
    Example of use: MeshFem.interpolate_convex_data(Mesh.quality())"""
    return self.get("interpolate_convex_data", Ucv)


  def memsize(self):
    """Return the amount of memory (in bytes) used by the mesh_fem object.
    
    The result does not take into account the linked mesh object."""
    return self.get("memsize")


  def has_linked_mesh_levelset(self):
    """Is a mesh_fem_level_set or not."""
    return self.get("has_linked_mesh_levelset")


  def linked_mesh_levelset(self):
    """if it is a mesh_fem_level_set gives the linked mesh_level_set."""
    return self.get("linked_mesh_levelset")


  def eval(self, expression, gl={}, lo={}):
    """interpolate an expression on the (lagrangian) MeshFem.

    Examples::

      mf.eval('x*y') # interpolates the function 'x*y'
      mf.eval('[x,y]') # interpolates the vector field '[x,y]'

      import numpy as np
      mf.eval('np.sin(x)',globals(),locals()) # interpolates the function sin(x)
    """
    P = self.basic_dof_nodes()
    nbd = P.shape[1]

    if not self.is_lagrangian:
      raise RuntimeError('cannot eval on a non-Lagragian MeshFem')
    if self.qdim() != 1:
      Ind = numpy.arange(0,nbd,self.qdim()) # = sdof
      P   = P[:,Ind]
      nbd = P.shape[1] # = nb_sdof
    vars = ('x','y','z','u','v','w')
    nbvars = min(P.shape[0],len(vars))
    for i in xrange(0,nbvars):
      gl[vars[i]] = P[i,0]
      lo[vars[i]] = P[i,0]
    r = numpy.array(eval(expression,gl,lo))
    Z = numpy.zeros(r.shape + (nbd,), r.dtype)
    for j in xrange(0,nbd):
      for i in xrange(0,nbvars):
        gl[vars[i]] = P[i,j]
        lo[vars[i]] = P[i,j]
      Z[...,j] = eval(expression,gl,lo)
    return Z
  

  def set_fem(self, f, CVids=None):
    """Set the Finite Element Method.
    
    Assign a FEM `f` to all convexes whose #ids are listed in `CVids`.
    If `CVids` is not given, the integration is assigned to all convexes.
    
    See the help of Fem to obtain a list of available FEM methods."""
    return self.set("fem", f, CVids)


  def set_classical_fem(self, k, CVids=None):
    """Assign a classical (Lagrange polynomial) fem of order `k` to the MeshFem.
    
    Uses FEM_PK for simplexes, FEM_QK for parallelepipeds etc."""
    return self.set("classical_fem", k, CVids)


  def set_classical_discontinuous_fem(self, K, alpha=None, *args):
    """Synopsis: MeshFem.set_classical_discontinuous_fem(self, int K[, @tscalar alpha[, ivec CVIDX]])

    Assigns a classical (Lagrange polynomial) discontinuous fem or order K.
    
    Similar to MeshFem.classical_fem() except that
    FEM_PK_DISCONTINUOUS is used. Param `alpha` the node inset,
    :math:`0 \\leq alpha < 1`, where 0 implies usual dof nodes, greater values
    move the nodes toward the center of gravity, and 1 means that all
    degrees of freedom collapse on the center of gravity."""
    return self.set("classical_discontinuous_fem", K, alpha, *args)


  def set_qdim(self, Q):
    """Change the `Q` dimension of the field that is interpolated by the MeshFem.
    
    `Q = 1` means that the MeshFem describes a scalar field, `Q = N` means
    that the MeshFem describes a vector field of dimension N."""
    return self.set("qdim", Q)


  def reduction_matrices(self, R, E):
    """Set the reduction and extension matrices and valid their use."""
    return self.set("reduction_matrices", R, E)


  def reduction(self, s):
    """Set or unset the use of the reduction/extension matrices."""
    return self.set("reduction", s)


  def reduce_meshfem(self, RM):
    """Set reduction mesh fem
    This function selects the degrees of freedom of the finite element
    method by selecting a set of independent vectors of the matrix RM.
    The numer of columns of RM should corresponds to the number of degrees
    of fredoom of the finite element method.  """
    return self.set("reduce_meshfem", RM)


  def set_dof_partition(self, DOFP):
    """Change the 'dof_partition' array.
    
    `DOFP` is a vector holding a integer value for each convex of the MeshFem.
    See MeshFem.dof_partition() for a description of "dof partition"."""
    return self.set("dof_partition", DOFP)


  def set_partial(self, DOFs, RCVs=None):
    """Can only be applied to a partial MeshFem. Change the subset of the
    degrees of freedom of `mf`.
    
    If `RCVs` is given, no FEM will be put on the convexes listed
    in `RCVs`."""
    return self.set("set_partial", DOFs, RCVs)


#
# GetFEM class MeshIm definition.
#

class MeshIm:
  """GetFEM MeshIm object

  This object represents an integration method defined on a whole mesh (an 
  potentialy on its boundaries).

  """
  def __init__(self, *args):
    """General constructor for MeshIm objects

  * ``MIM = MeshIm('load', string fname[, Mesh m])``
    Load a MeshIm from a file.
    
    If the mesh `m` is not supplied (this kind of file does not store the
    mesh), then it is read from the file and its descriptor is returned as
    the second output argument.

  * ``MIM = MeshIm('from string', string s[, Mesh m])``
    Create a MeshIm object from its string description.
    
    See also ``MeshIm.char()``

  * ``MIM = MeshIm('clone', MeshIm mim)``
    Create a copy of a MeshIm.

  * ``MIM = MeshIm('levelset', MeshLevelSet mls, string where, Integ im[, Integ im_tip[, Integ im_set]])``
    Build an integration method conformal to a partition defined
    implicitely by a levelset.
    
    The `where` argument define the domain of integration with respect to
    the levelset, it has to be chosen among 'ALL', 'INSIDE', 'OUTSIDE' and
    'BOUNDARY'.
    
    CAUTION: this integration method will be defined only on the element
    cut by the level-set. For the 'ALL', 'INSIDE' and 'OUTSIDE' options
    it is mandatory to use the method ``MeshIm.set_integ()`` to define
    the integration method on the remaining elements.

  * ``MIM = MeshIm(Mesh m, [{Integ im|int im_degree}])``
    Build a new MeshIm object.
    
    For convenience, optional arguments (`im` or `im_degree`) can be
    provided, in that case a call to ``MeshIm.integ()`` is issued
    with these arguments.

    """
    generic_constructor(self,'mesh_im',*args)
  def __del__(self):
    generic_destructor(self, destructible=True)
  def get(self, *args):
    return getfem('mesh_im_get',self.id, *args)
  def __repr__(self):
    getfem('mesh_im_get',self.id, 'display')
    return ''
  def set(self, *args):
    return getfem('mesh_im_set',self.id, *args)
  def __str__(self):
    return self.char()

  def integ(self, CVids=None):
    """Return a list of integration methods used by the MeshIm.
    
    `I` is an array of all Integ objects found in the convexes
    given in `CVids`. If `CV2I` was supplied as an output argument, it
    contains, for each convex listed in `CVids`, the index of its
    correspounding integration method in `I`.
    
    Convexes which are not part of the mesh, or convexes which do
    not have any integration method have their correspounding entry
    in `CV2I` set to -1.
    
    """
    return self.get("integ", CVids)


  def convex_index(self):
    """Return the list of convexes who have a integration method.
    
    Convexes who have the dummy IM_NONE method are not listed."""
    return self.get("convex_index")


  def eltm(self, em, cv, f=None):
    """Return the elementary matrix (or tensor) integrated on the convex `cv`.
    
    **WARNING**
    
    Be sure that the fem used for the construction of `em` is compatible
    with the fem assigned to element `cv` ! This is not checked by the
    function ! If the argument `f` is given, then the elementary tensor
    is integrated on the face `f` of `cv` instead of the whole convex."""
    return self.get("eltm", em, cv, f)


  def im_nodes(self, CVids=None):
    """Return the coordinates of the integration points, with their weights.
    
    `CVids` may be a list of convexes, or a list of convex faces, such
    as returned by Mesh.region()
    
    **WARNING**
    
    Convexes which are not part of the mesh, or convexes which
    do not have an approximate integration method don't have
    their correspounding entry (this has no meaning for exact
    integration methods!)."""
    return self.get("im_nodes", CVids)


  def save(self, filename):
    """Saves a MeshIm in a text file (and optionaly its linked mesh object)."""
    return self.get("save", filename)


  def char(self):
    """Output a string description of the MeshIm.
    
    By default, it does not include the description of the linked
    Mesh object."""
    return self.get("char")


  def display(self):
    """displays a short summary for a MeshIm object."""
    return self.get("display")


  def linked_mesh(self):
    """Returns a reference to the Mesh object linked to `mim`."""
    return self.get("linked_mesh")


  def memsize(self):
    """Return the amount of memory (in bytes) used by the MeshIm object.
    
    The result does not take into account the linked Mesh object."""
    return self.get("memsize")


  def set_integ(self, *args):
    """Synopsis: MeshIm.set_integ(self,{Integ im|int im_degree}[, ivec CVids])

    Set the integration method.
    
    Assign an integration method to all convexes whose #ids are
    listed in `CVids`. If `CVids` is not given, the integration is
    assigned to all convexes. It is possible to assign a specific
    integration method with an integration method handle `im` obtained
    via Integ('IM_SOMETHING'), or to let getfem choose a suitable
    integration method with `im_degree` (choosen such that polynomials
    of :math:`\\text{degree} \\leq \\text{im\\_degree}` are exactly integrated.
    If `im_degree=-1`, then the dummy integration method IM_NONE will 
    be used.)"""
    return self.set("integ", *args)


  def adapt(self):
    """For a MeshIm levelset object only. Adapt the integration methods to a
    change of the levelset function."""
    return self.set("adapt")


#
# GetFEM class MeshLevelSet definition.
#

class MeshLevelSet:
  """GetFEM MeshLevelSet object

  General constructor for mesh_levelset objects. The role of this object is
  to provide a mesh cut by a certain number of level_set. This object is
  used to build conformal integration method (object mim and enriched finite
  element methods (Xfem)).
  
  """
  def __init__(self, *args):
    """General constructor for MeshLevelSet objects

  * ``MLS = MeshLevelSet(Mesh m)``
    Build a new MeshLevelSet object from a Mesh and returns its handle. 

    """
    generic_constructor(self,'mesh_levelset',*args)
  def __del__(self):
    generic_destructor(self, destructible=True)
  def get(self, *args):
    return getfem('mesh_levelset_get',self.id, *args)
  def __repr__(self):
    getfem('mesh_levelset_get',self.id, 'display')
    return ''
  def set(self, *args):
    return getfem('mesh_levelset_set',self.id, *args)
  def __str__(self):
    return self.char()

  def cut_mesh(self):
    """Return a Mesh cut by the linked LevelSet's."""
    return self.get("cut_mesh")


  def linked_mesh(self):
    """Return a reference to the linked Mesh."""
    return self.get("linked_mesh")


  def nb_ls(self):
    """Return the number of linked LevelSet's."""
    return self.get("nb_ls")


  def levelsets(self):
    """Return a list of references to the linked LevelSet's."""
    return self.get("levelsets")


  def crack_tip_convexes(self):
    """Return the list of convex #id's of the linked Mesh on
    which have a tip of any linked LevelSet's."""
    return self.get("crack_tip_convexes")


  def memsize(self):
    """Return the amount of memory (in bytes) used by the MeshLevelSet."""
    return self.get("memsize")


  def char(self):
    """Output a (unique) string representation of the MeshLevelSetn.
    
    This can be used to perform comparisons between two
    different MeshLevelSet objects.
    This function is to be completed.
    """
    return self.get("char")


  def display(self):
    """displays a short summary for a MeshLevelSet object."""
    return self.get("display")


  def add(self, ls):
    """Add a link to the LevelSet `ls`.
    
    Only a reference is kept, no copy is done. In order to indicate
    that the linked Mesh is cut by a LevelSet one has to call this
    method, where `ls` is an LevelSet object. An arbitrary number of
    LevelSet can be added.
    
    **WARNING**
    
    The Mesh of `ls` and the linked Mesh must be the same."""
    return self.set("add", ls)


  def sup(self, ls):
    """Remove a link to the LevelSet `ls`."""
    return self.set("sup", ls)


  def adapt(self):
    """Do all the work (cut the convexes with the levelsets).
    
    To initialice the MeshLevelSet object or to actualize it when the
    value of any levelset function is modified, one has to call
    this method."""
    return self.set("adapt")


#
# GetFEM class MesherObject definition.
#

class MesherObject:
  """GetFEM MesherObject object

  This object represents a geometric object to be meshed by the (very)
  experimental meshing procedure of Getfem.

  """
  def __init__(self, *args):
    """General constructor for MesherObject objects

  * ``MF = MesherObject('ball', vec center, scalar radius)``
    Represents a ball of corresponding center and radius.
    

  * ``MF = MesherObject('half space', vec origin, vec normal_vector)``
    Represents an half space delimited by the plane which contains the
    origin and normal to `normal_vector`. The selected part is the part
    in the direction of the normal vector. This allows to cut a geometry
    with a plane for instance to build a polygon or a polyhedron.
    

  * ``MF = MesherObject('cylinder', vec origin, vec n, scalar length, scalar radius)``
    Represents a cylinder (in any dimension) of a certain radius whose axis is determined by the origin, a vector `n` and a certain length.
    

  * ``MF = MesherObject('cone', vec origin, vec n, scalar length, scalar half_angle)``
    Represents a cone (in any dimension) of a certain half-angle (in radians) whose axis is determined by the origin, a vector `n` and a certain length.
    

  * ``MF = MesherObject('torus', scalar R, scalar r)``
    Represents a torus in 3d of axis along the z axis with a great radius
    equal to `R` and small radius equal to `r`. For the moment, the
    possibility to change the axis is not given.
    

  * ``MF = MesherObject('rectangle', vec rmin, vec rmax)``
    Represents a rectangle (or parallelepiped in 3D) parallel to the axes.
    

  * ``MF = MesherObject('intersect', MesherObject object1 , MesherObject object2, ...)``
    Intersection of several objects.
    

  * ``MF = MesherObject('union', MesherObject object1 , MesherObject object2, ...)``
    Union of several objects.
    

  * ``MF = MesherObject('set minus', MesherObject object1 , MesherObject object2)``
    Geometric object being object1 minus object2.
    

    """
    generic_constructor(self,'mesher_object',*args)
  def __del__(self):
    generic_destructor(self, destructible=False)
  def get(self, *args):
    return getfem('mesher_object_get',self.id, *args)
  def __repr__(self):
    getfem('mesher_object_get',self.id, 'display')
    return ''
  def __str__(self):
    return self.char()

  def char(self):
    """Output a (unique) string representation of the MesherObject.
    
    This can be used to perform comparisons between two
    different MesherObject objects.
    This function is to be completed.
    """
    return self.get("char")


  def display(self):
    """displays a short summary for a MesherObject object."""
    return self.get("display")


#
# GetFEM class Model definition.
#

class Model:
  """GetFEM Model object

  Model variables store the variables and the state data and the
  description of a model. This includes the global tangent matrix, the right
  hand side and the constraints. There are two kinds of models, the `real`
  and the `complex` models.

  Model object is the evolution for getfem++ 4.0 of the MdState object.

  """
  def __init__(self, *args):
    """General constructor for Model objects

  * ``MD = Model('real')``
    Build a model for real unknowns.

  * ``MD = Model('complex')``
    Build a model for complex unknowns.

    """
    generic_constructor(self,'model',*args)
  def __del__(self):
    generic_destructor(self, destructible=True)
  def get(self, *args):
    return getfem('model_get',self.id, *args)
  def __repr__(self):
    getfem('model_get',self.id, 'display')
    return ''
  def set(self, *args):
    return getfem('model_set',self.id, *args)
  def __str__(self):
    return self.char()

  def is_complex(self):
    """Return 0 is the model is real, 1 if it is complex."""
    return self.get("is_complex")


  def nbdof(self):
    """Return the total number of degrees of freedom of the model."""
    return self.get("nbdof")


  def tangent_matrix(self):
    """Return the tangent matrix stored in the model ."""
    return self.get("tangent_matrix")


  def rhs(self):
    """Return the right hand side of the tangent problem."""
    return self.get("rhs")


  def brick_term_rhs(self, ind_brick, ind_term=None, sym=None, ind_iter=None):
    """Gives the access to the part of the right hand side of a term
    of a particular nonlinear brick. Does not account of the eventual
    time dispatcher. An assembly of the rhs has to be done first.
    `ind_brick` is the brick index. `ind_term` is the index of the
    term inside the brick (default value : 0).
    `sym` is to access to the second right hand side of for symmetric
    terms acting on two different variables (default is 0).
    `ind_iter` is the iteration number when time dispatchers are
    used (default is 0).
    """
    return self.get("brick_term_rhs", ind_brick, ind_term, sym, ind_iter)


  def memsize(self):
    """Return a rough approximation of the amount of memory (in bytes) used by
    the model."""
    return self.get("memsize")


  def listvar(self):
    """print to the output the list of variables and constants of the model."""
    return self.get("listvar")


  def listbricks(self):
    """print to the output the list of bricks of the model."""
    return self.get("listbricks")


  def variable(self, name, niter=None):
    """Gives the value of a variable or data."""
    return self.get("variable", name, niter)


  def mesh_fem_of_variable(self, name):
    """Gives access to the `mesh_fem` of a variable or data."""
    return self.get("mesh_fem_of_variable", name)


  def mult_varname_Dirichlet(self, ind_brick):
    """Gives the name of the multiplier variable for a Dirichlet brick.
    If the brick is not a Dirichlet condition with multiplier brick,
    this function has an undefined behavior"""
    return self.get("mult_varname_Dirichlet", ind_brick)


  def interval_of_variable(self, varname):
    """Gives the interval of the variable `varname` in the linear system of
    the model."""
    return self.get("interval_of_variable", varname)


  def from_variables(self):
    """Return the vector of all the degrees of freedom of the model consisting
    of the concatenation of the variables of the model (useful
    to solve your problem with you own solver). """
    return self.get("from_variables")


  def assembly(self, option=None):
    """Assembly of the tangent system taking into account the terms
    from all bricks. `option`, if specified, should be 'build_all',
    'build_rhs', 'build_matrix' or 'pseudo_potential' (in that case,
    the pseudo_potential is returned).
    The default is to build the whole
    tangent linear system (matrix and rhs). This function is useful
    to solve your problem with you own solver. """
    return self.get("assembly", option)


  def solve(self, *args):
    """Synopsis: (nbit, converged) = Model.solve(self[, ...])

    Run the standard getfem solver.
    
    Note that you should be able to use your own solver if you want
    (it is possible to obtain the tangent matrix and its right hand
    side with the Model.tangent_matrix() etc.).
    
    Various options can be specified:
    
    - 'noisy' or 'very_noisy'
       the solver will display some information showing the progress
       (residual values etc.).
    - 'max_iter', int NIT
       set the maximum iterations numbers.
    - 'max_res', @float RES
       set the target residual value.
    - 'diverged_res', @float RES
       set the threshold value of the residual beyond which the iterative
       method is considered to diverge (default is 1e200).
    - 'lsolver', string SOLVER_NAME
       select explicitely the solver used for the linear systems (the
       default value is 'auto', which lets getfem choose itself).
       Possible values are 'superlu', 'mumps' (if supported),
       'cg/ildlt', 'gmres/ilu' and 'gmres/ilut'.
    - 'lsearch', string LINE_SEARCH_NAME
       select explicitely the line search method used for the linear systems (the
       default value is 'default').
       Possible values are 'simplest', 'systematic', 'quadratic' or 'basic'.
    - 'with pseudo potential'
      for nonlinear problems, the criterion of the line search will
      be a pseudo potential instead of the residual. Still experimental since
      not all bricks define a pseudo potential.
    
      Return the number of iterations, if a iterative method is used.
      
      Note that it is possible to disable some variables
      (see Model.disable_variable() ) in order to
      solve the problem only with respect to a subset of variables (the
      disabled variables are the considered as data) for instance to
      replace the global Newton strategy with a fixed point one."""
    return self.get("solve", *args)


  def test_tangent_matrix(self, EPS=None, *args):
    """Synopsis: Model.test_tangent_matrix(self[, scalar EPS[, int NB[, scalar scale]]])

    Test the consistency of the tangent matrix in some random positions
    and random directions (useful to test newly created bricks).
    `EPS` is the value of the small parameter for the finite difference
    computation of the derivative is the random direction (default is 1E-6).
    `NN` is the number of tests (default is 100). `scale` is a parameter
    for the random position (default is 1). Each dof od the random
    position is chosen in the range [-scale, scale].
    """
    return self.get("test_tangent_matrix", EPS, *args)


  def compute_isotropic_linearized_Von_Mises_or_Tresca(self, varname, dataname_lambda, dataname_mu, mf_vm, version=None):
    """Compute the Von-Mises stress or the Tresca stress of a field (only
    valid for isotropic linearized elasticity in 3D). `version` should
    be  'Von_Mises' or 'Tresca' ('Von_Mises' is the default). """
    return self.get("compute_isotropic_linearized_Von_Mises_or_Tresca", varname, dataname_lambda, dataname_mu, mf_vm, version)


  def compute_Von_Mises_or_Tresca(self, varname, lawname, dataname, mf_vm, version=None):
    """Compute on `mf_vm` the Von-Mises stress or the Tresca stress of a field
    for nonlinear elasticity in 3D. `lawname` is the constitutive law which
    could be 'SaintVenant Kirchhoff', 'Mooney Rivlin' or 'Ciarlet Geymonat'.
    `dataname` is a vector of parameters for the constitutive law. Its length
    depends on the law. It could be a short vector of constant values or a
    vector field described on a finite element method for variable coefficients.
    `version` should be  'Von_Mises' or 'Tresca' ('Von_Mises' is the default). """
    return self.get("compute_Von_Mises_or_Tresca", varname, lawname, dataname, mf_vm, version)


  def compute_second_Piola_Kirchhoff_tensor(self, varname, lawname, dataname, mf_sigma):
    """Compute on `mf_sigma` the second Piola Kirchhoff stress tensor of a field
    for nonlinear elasticity in 3D. `lawname` is the constitutive law which
    could be 'SaintVenant Kirchhoff', 'Mooney Rivlin' or 'Ciarlet Geymonat'.
    `dataname` is a vector of parameters for the constitutive law. Its length
    depends on the law. It could be a short vector of constant values or a
    vector field described on a finite element method for variable
    coefficients.
    """
    return self.get("compute_second_Piola_Kirchhoff_tensor", varname, lawname, dataname, mf_sigma)


  def compute_plasticity_Von_Mises_or_Tresca(self, datasigma, mf_vm, version=None):
    """Compute on `mf_vm` the Von-Mises or the Tresca stress of a field for plasticity and return it into the vector V.
    `datasigma` is a vector which contains the stress constraints values supported by the mesh.
    `version` should be  'Von_Mises' or 'Tresca' ('Von_Mises' is the default)."""
    return self.get("compute_plasticity_Von_Mises_or_Tresca", datasigma, mf_vm, version)


  def compute_plasticity_constraints(self, mim, varname, projname, datalambda, datamu, datathreshold, datasigma):
    """Compute and save the stress constraints sigma for other hypothetical iterations.
    'mim' is the integration method to use for the computation.
    'varname' is the main variable of the problem.
    'projname' is the type of projection to use. For the moment it could only be 'Von Mises' or 'VM'.
    'datalambda' and 'datamu' are the Lame coefficients of the material.
    'datasigma' is a vector which will contains the new stress constraints values."""
    return self.get("compute_plasticity_constraints", mim, varname, projname, datalambda, datamu, datathreshold, datasigma)


  def compute_plastic_part(self, mim, mf_pl, varname, projname, datalambda, datamu, datathreshold, datasigma):
    """Compute on `mf_pl` the plastic part and return it into the vector V.
    `datasigma` is a vector which contains the stress constraints values supported by the mesh."""
    return self.get("compute_plastic_part", mim, mf_pl, varname, projname, datalambda, datamu, datathreshold, datasigma)


  def matrix_term(self, ind_brick, ind_term):
    """Gives the matrix term ind_term of the brick ind_brick if it exists
    """
    return self.get("matrix_term", ind_brick, ind_term)


  def char(self):
    """Output a (unique) string representation of the Model.
    
    This can be used to perform comparisons between two
    different Model objects.
    This function is to be completed.
    """
    return self.get("char")


  def display(self):
    """displays a short summary for a Model object."""
    return self.get("display")


  def clear(self):
    """Clear the model."""
    return self.set("clear")


  def add_fem_variable(self, name, mf, niter=None):
    """Add a variable to the model linked to a MeshFem. `name` is the variable
    name and `niter` is the optional number of version of the data stored,
    for time integration schemes."""
    return self.set("add_fem_variable", name, mf, niter)


  def add_filtered_fem_variable(self, name, mf, region, niter=None):
    """Add a variable to the model linked to a MeshFem. The variable is filtered
    in the sense that only the dof on the region are considered.
    `name` is the variable name and `niter` is the optional number of
    version of the data stored, for time integration schemes."""
    return self.set("add_filtered_fem_variable", name, mf, region, niter)


  def add_variable(self, name, size, niter=None):
    """Add a variable to the model of constant size. `name` is the variable
    name and `niter` is the optional number of version of the data stored,
    for time integration schemes. """
    return self.set("add_variable", name, size, niter)


  def resize_variable(self, name, size):
    """Resize a  constant size variable of the model. `name` is the variable
    name. """
    return self.set("resize_variable", name, size)


  def add_multiplier(self, name, mf, primalname, mim=None, region=None, *args):
    """Synopsis: Model.add_multiplier(self, string name, MeshFem mf, string primalname[, MeshIm mim, int region][, int niter])

    Add a particular variable linked to a fem being a multiplier with
    respect to a primal variable. The dof will be filtered with the
    ``gmm::range_basis`` function applied on the terms of the model
    which link the multiplier and the primal variable. This in order to
    retain only linearly independant constraints on the primal variable.
    Optimized for boundary multipliers. `niter` is the optional number
    of version of the data stored, for time integration schemes. """
    return self.set("add_multiplier", name, mf, primalname, mim, region, *args)


  def add_fem_data(self, name, mf, qdim=None, *args):
    """Synopsis: Model.add_fem_data(self, string name, MeshFem mf[, int qdim[, int niter]])

    Add a data to the model linked to a MeshFem. `name` is the data name,
    `qdim` is the optional dimension of the data over the MeshFem and
    `niter` is the optional number of version of the data stored,
    for time integration schemes. """
    return self.set("add_fem_data", name, mf, qdim, *args)


  def add_initialized_fem_data(self, name, mf, V):
    """Add a data to the model linked to a MeshFem. `name` is the data name.
    The data is initiakized with `V`. The data can be a scalar or vector
    field."""
    return self.set("add_initialized_fem_data", name, mf, V)


  def add_data(self, name, size, niter=None):
    """Add a data to the model of constant size. `name` is the data name
    and `niter` is the optional number of version of the data stored,
    for time integration schemes. """
    return self.set("add_data", name, size, niter)


  def add_initialized_data(self, name, V):
    """Add a fixed size data to the model linked to a MeshFem.
    `name` is the data name and `V` is the value of the data."""
    return self.set("add_initialized_data", name, V)


  def set_variable(self, name, V, niter=None):
    """Set the value of a variable or data. `name` is the data name
    and `niter` is the optional number of version of the data stored,
    for time integration schemes."""
    return self.set("variable", name, V, niter)


  def to_variables(self, V):
    """Set the value of the variables of the model with the vector `V`.
    Typically, the vector `V` results of the solve of the tangent
    linear system (useful to solve your problem with you own solver)."""
    return self.set("to_variables", V)


  def add_Laplacian_brick(self, mim, varname, region=None):
    """Add a Laplacian term to the model relatively to the variable `varname`
    (in fact with a minus : :math:`-\\text{div}(\\nabla u)`).
    If this is a vector valued variable, the Laplacian term is added
    componentwise. `region` is an optional mesh region on which the term
    is added. If it is not specified, it is added on the whole mesh. Return
    the brick index in the model."""
    return self.set("add_Laplacian_brick", mim, varname, region)


  def add_generic_elliptic_brick(self, mim, varname, dataname, region=None):
    """Add a generic elliptic term to the model relatively to the variable `varname`.
    The shape of the elliptic term depends both on the variable and the data.
    This corresponds to a term
    :math:`-\\text{div}(a\\nabla u)`
    where :math:`a` is the data and :math:`u` the variable. The data can be a scalar,
    a matrix or an order four tensor. The variable can be vector valued or
    not. If the data is a scalar or a matrix and the variable is vector
    valued then the term is added componentwise. An order four tensor data
    is allowed for vector valued variable only. The data can be constant or
    describbed on a fem. Of course, when the data is a tensor describe on a
    finite element method (a tensor field) the data can be a huge vector.
    The components of the matrix/tensor have to be stored with the fortran
    order (columnwise) in the data vector (compatibility with blas). The
    symmetry of the given matrix/tensor is not verified (but assumed). If
    this is a vector valued variable, the elliptic term is added
    componentwise. `region` is an optional mesh region on which the term is
    added. If it is not specified, it is added on the whole mesh. Return the
    brick index in the model."""
    return self.set("add_generic_elliptic_brick", mim, varname, dataname, region)


  def add_source_term_brick(self, mim, varname, dataname, region=None, *args):
    """Synopsis: ind = Model.add_source_term_brick(self, MeshIm mim, string varname, string dataname[, int region[, string directdataname]])

    Add a source term to the model relatively to the variable `varname`.
    The source term is represented by the data `dataname` which could be
    constant or described on a fem. `region` is an optional mesh region
    on which the term is added. An additional optional data `directdataname`
    can be provided. The corresponding data vector will be directly added
    to the right hand side without assembly. Return the brick index in the
    model."""
    return self.set("add_source_term_brick", mim, varname, dataname, region, *args)


  def add_normal_source_term_brick(self, mim, varname, dataname, region):
    """Add a source term on the variable `varname` on a boundary `region`.
    This region should be a boundary. The source term is represented by the
    data `dataname` which could be constant or described on a fem. A scalar
    product with the outward normal unit vector to the boundary is performed.
    The main aim of this brick is to represent a Neumann condition with a
    vector data without performing the scalar product with the normal as a
    pre-processing. Return the brick index in the model."""
    return self.set("add_normal_source_term_brick", mim, varname, dataname, region)


  def add_Dirichlet_condition_with_multipliers(self, mim, varname, mult_description, region, dataname=None):
    """Add a Dirichlet condition on the variable `varname` and the mesh
    region `region`. This region should be a boundary. The Dirichlet
    condition is prescribed with a multiplier variable described by
    `mult_description`. If `mult_description` is a string this is assumed
    to be the variable name corresponding to the multiplier (which should be
    first declared as a multiplier variable on the mesh region in the model).
    If it is a finite element method (mesh_fem object) then a multiplier
    variable will be added to the model and build on this finite element
    method (it will be restricted to the mesh region `region` and eventually
    some conflicting dofs with some other multiplier variables will be
    suppressed). If it is an integer, then a  multiplier variable will be
    added to the model and build on a classical finite element of degree
    that integer. `dataname` is the optional right hand side of  the
    Dirichlet condition. It could be constant or described on a fem; scalar
    or vector valued, depending on the variable on which the Dirichlet
    condition is prescribed. Return the brick index in the model."""
    return self.set("add_Dirichlet_condition_with_multipliers", mim, varname, mult_description, region, dataname)


  def add_Dirichlet_condition_with_penalization(self, mim, varname, coeff, region, dataname=None, mf_mult=None):
    """Add a Dirichlet condition on the variable `varname` and the mesh
    region `region`. This region should be a boundary. The Dirichlet
    condition is prescribed with penalization. The penalization coefficient
    is initially `coeff` and will be added to the data of the model.
    `dataname` is the optional right hand side of the Dirichlet condition.
    It could be constant or described on a fem; scalar or vector valued,
    depending on the variable on which the Dirichlet condition is prescribed.
    `mf_mult` is an optional parameter which allows to weaken the
    Dirichlet condition specifying a multiplier space.
    Return the brick index in the model."""
    return self.set("add_Dirichlet_condition_with_penalization", mim, varname, coeff, region, dataname, mf_mult)


  def add_normal_Dirichlet_condition_with_multipliers(self, mim, varname, mult_description, region, dataname=None):
    """Add a Dirichlet condition to the normal component of the vector
    or tensor) valued variable `varname` and the mesh
    region `region`. This region should be a boundary. The Dirichlet
    condition is prescribed with a multiplier variable described by
    `mult_description`. If `mult_description` is a string this is assumed
    to be the variable name corresponding to the multiplier (which should be
    first declared as a multiplier variable on the mesh region in the model).
    If it is a finite element method (mesh_fem object) then a multiplier
    variable will be added to the model and build on this finite element
    method (it will be restricted to the mesh region `region` and eventually
    some conflicting dofs with some other multiplier variables will be
    suppressed). If it is an integer, then a  multiplier variable will be
    added to the model and build on a classical finite element of degree
    that integer. `dataname` is the optional right hand side of  the
    Dirichlet condition. It could be constant or described on a fem; scalar
    or vector valued, depending on the variable on which the Dirichlet
    condition is prescribed (scalar if the variable
    is vector valued, vector if the variable is tensor valued).
    Returns the brick index in the model."""
    return self.set("add_normal_Dirichlet_condition_with_multipliers", mim, varname, mult_description, region, dataname)


  def add_normal_Dirichlet_condition_with_penalization(self, mim, varname, coeff, region, dataname=None, mf_mult=None):
    """Add a Dirichlet condition to the normal component of the vector
    (or tensor) valued variable `varname` and the mesh
    region `region`. This region should be a boundary. The Dirichlet
    condition is prescribed with penalization. The penalization coefficient
    is initially `coeff` and will be added to the data of the model.
    `dataname` is the optional right hand side of the Dirichlet condition.
    It could be constant or described on a fem; scalar or vector valued,
    depending on the variable on which the Dirichlet condition is prescribed
    (scalar if the variable
    is vector valued, vector if the variable is tensor valued).
    `mf_mult` is an optional parameter which allows to weaken the
    Dirichlet condition specifying a multiplier space.
    Returns the brick index in the model."""
    return self.set("add_normal_Dirichlet_condition_with_penalization", mim, varname, coeff, region, dataname, mf_mult)


  def add_generalized_Dirichlet_condition_with_multipliers(self, mim, varname, mult_description, region, dataname, Hname):
    """Add a Dirichlet condition on the variable `varname` and the mesh
    region `region`.  This version is for vector field.
    It prescribes a condition :math:`Hu = r`
    where `H` is a matrix field. The region should be a boundary. The Dirichlet
    condition is prescribed with a multiplier variable described by
    `mult_description`. If `mult_description` is a string this is assumed
    to be the variable name corresponding to the multiplier (which should be
    first declared as a multiplier variable on the mesh region in the model).
    If it is a finite element method (mesh_fem object) then a multiplier
    variable will be added to the model and build on this finite element
    method (it will be restricted to the mesh region `region` and eventually
    some conflicting dofs with some other multiplier variables will be
    suppressed). If it is an integer, then a  multiplier variable will be
    added to the model and build on a classical finite element of degree
    that integer. `dataname` is the right hand side of  the
    Dirichlet condition. It could be constant or described on a fem; scalar
    or vector valued, depending on the variable on which the Dirichlet
    condition is prescribed. `Hname` is the data
    corresponding to the matrix field `H`.
    Returns the brick index in the model."""
    return self.set("add_generalized_Dirichlet_condition_with_multipliers", mim, varname, mult_description, region, dataname, Hname)


  def add_generalized_Dirichlet_condition_with_penalization(self, mim, varname, coeff, region, dataname, Hname, mf_mult=None):
    """Add a Dirichlet condition on the variable `varname` and the mesh
    region `region`. This version is for vector field.
    It prescribes a condition :math:`Hu = r`
    where `H` is a matrix field.
    The region should be a boundary. The Dirichlet
    condition is prescribed with penalization. The penalization coefficient
    is intially `coeff` and will be added to the data of the model.
    `dataname` is the right hand side of the Dirichlet condition.
    It could be constant or described on a fem; scalar or vector valued,
    depending on the variable on which the Dirichlet condition is prescribed.
    `Hname` is the data
    corresponding to the matrix field `H`. It has to be a constant matrix
    or described on a scalar fem.
    `mf_mult` is an optional parameter which allows to weaken the
    Dirichlet condition specifying a multiplier space.
    Return the brick index in the model."""
    return self.set("add_generalized_Dirichlet_condition_with_penalization", mim, varname, coeff, region, dataname, Hname, mf_mult)


  def add_pointwise_constraints_with_multipliers(self, varname, dataname_pt, dataname_unitv=None, *args):
    """Synopsis: ind = Model.add_pointwise_constraints_with_multipliers(self, string varname, string dataname_pt[, string dataname_unitv] [, string dataname_val])

    Add some pointwise constraints on the variable `varname` using
    multiplier. The multiplier variable is automatically added to the model.
    The conditions are prescribed on a set of points given in the data
    `dataname_pt` whose dimension is the number of points times the dimension
    of the mesh.
    If the variable represents a vector field, one has to give the data
    `dataname_unitv` which represents a vector of dimension the number of
    points times the dimension of the vector field which should store some
    unit vectors. In that case the prescribed constraint is the scalar
    product of the variable at the corresponding point with the corresponding
    unit vector.
    The optional data `dataname_val` is the vector of values to be prescribed
    at the different points.
    This brick is specifically designed to kill rigid displacement
    in a Neumann problem.
    Returns the brick index in the model."""
    return self.set("add_pointwise_constraints_with_multipliers", varname, dataname_pt, dataname_unitv, *args)


  def add_pointwise_constraints_with_given_multipliers(self, varname, multname, dataname_pt, dataname_unitv=None, *args):
    """Synopsis: ind = Model.add_pointwise_constraints_with_given_multipliers(self, string varname, string multname, string dataname_pt[, string dataname_unitv] [, string dataname_val])

    Add some pointwise constraints on the variable `varname` using a given
    multiplier `multname`.
    The conditions are prescribed on a set of points given in the data
    `dataname_pt` whose dimension is the number of points times the dimension
    of the mesh.
    The multiplier variable should be a fixed size variable of size the
    number of points.
    If the variable represents a vector field, one has to give the data
    `dataname_unitv` which represents a vector of dimension the number of
    points times the dimension of the vector field which should store some
    unit vectors. In that case the prescribed constraint is the scalar
    product of the variable at the corresponding point with the corresponding
    unit vector.
    The optional data `dataname_val` is the vector of values to be prescribed
    at the different points.
    This brick is specifically designed to kill rigid displacement
    in a Neumann problem.
    Returns the brick index in the model."""
    return self.set("add_pointwise_constraints_with_given_multipliers", varname, multname, dataname_pt, dataname_unitv, *args)


  def add_pointwise_constraints_with_penalization(self, varname, coeff, dataname_pt, dataname_unitv=None, *args):
    """Synopsis: ind = Model.add_pointwise_constraints_with_penalization(self, string varname, scalar coeff, string dataname_pt[, string dataname_unitv] [, string dataname_val])

    Add some pointwise constraints on the variable `varname` thanks to
    a penalization. The penalization coefficient is initially
    `penalization_coeff` and will be added to the data of the model.
    The conditions are prescribed on a set of points given in the data
    `dataname_pt` whose dimension is the number of points times the dimension
    of the mesh.
    If the variable represents a vector field, one has to give the data
    `dataname_unitv` which represents a vector of dimension the number of
    points times the dimension of the vector field which should store some
    unit vectors. In that case the prescribed constraint is the scalar
    product of the variable at the corresponding point with the corresponding
    unit vector.
    The optional data `dataname_val` is the vector of values to be prescribed
    at the different points.
    This brick is specifically designed to kill rigid displacement
    in a Neumann problem.
    Returns the brick index in the model."""
    return self.set("add_pointwise_constraints_with_penalization", varname, coeff, dataname_pt, dataname_unitv, *args)


  def change_penalization_coeff(self, ind_brick, coeff):
    """Change the penalization coefficient of a Dirichlet condition with
    penalization brick. If the brick is not of this kind, this
    function has an undefined behavior."""
    return self.set("change_penalization_coeff", ind_brick, coeff)


  def add_Helmholtz_brick(self, mim, varname, dataname, region=None):
    """Add a Helmholtz term to the model relatively to the variable `varname`.
    `dataname` should contain the wave number. `region` is an optional mesh
    region on which the term is added. If it is not specified, it is added
    on the whole mesh. Return the brick index in the model."""
    return self.set("add_Helmholtz_brick", mim, varname, dataname, region)


  def add_Fourier_Robin_brick(self, mim, varname, dataname, region):
    """Add a Fourier-Robin term to the model relatively to the variable
    `varname`. This corresponds to a weak term of the form
    :math:`\\int (qu).v`. `dataname`
    should contain the parameter :math:`q` of
    the Fourier-Robin condition. `region` is the mesh region on which
    the term is added. Return the brick index in the model."""
    return self.set("add_Fourier_Robin_brick", mim, varname, dataname, region)


  def add_basic_nonlinear_brick(self, mim, varname, f, dfdu, dataname=None, region=None):
    """Add a brick representing a scalar term :math:`f(u)` to the left-hand
    side of the model. In the weak form, one adds :math:`+\\int f(u)v`.
    The function :math:`f` may optionally depend on :math:`\\lambda`, i.e.,
    :math:`f(u)=f(u,\\lambda)`.
    `f` and `dfdu` should contain the expressions for
    :math:`f(u)` and :math:`\\frac{df}{du}(u)`, respectively.
    `dataname` represents the optional real scalar parameter :math:`\\lambda`
    in the model. `region` is an optional mesh region on which the term is
    added. If it is not specified, the term is added on the whole mesh.
    Return the brick index in the model."""
    return self.set("add_basic_nonlinear_brick", mim, varname, f, dfdu, dataname, region)


  def add_constraint_with_multipliers(self, varname, multname, B, L):
    """Add an additional explicit constraint on the variable `varname` thank to
    a multiplier `multname` peviously added to the model (should be a fixed
    size variable). The constraint is :math:`BU=L`
    with `B` being a rectangular sparse matrix. It is possible to change
    the constraint at any time whith the methods Model.set_private_matrix()
    and Model.set_private_rhs(). Return the brick index in the model."""
    return self.set("add_constraint_with_multipliers", varname, multname, B, L)


  def add_constraint_with_penalization(self, varname, coeff, B, L):
    """Add an additional explicit penalized constraint on the variable `varname`.
    The constraint is :math`BU=L` with `B` being a rectangular sparse matrix.
    Be aware that `B` should not contain a palin row, otherwise the whole
    tangent matrix will be plain. It is possible to change the constraint
    at any time whith the methods Model.set_private_matrix()
    and Model.set_private_rhs(). The method
    Model.change_penalization_coeff() can be used. Return the brick
    index in the model."""
    return self.set("add_constraint_with_penalization", varname, coeff, B, L)


  def add_explicit_matrix(self, varname1, varname2, B, issymmetric=None, *args):
    """Synopsis: ind = Model.add_explicit_matrix(self, string varname1, string varname2, Spmat B[, int issymmetric[, int iscoercive]])

    Add a brick representing an explicit matrix to be added to the tangent
    linear system relatively to the variables `varname1` and `varname2`.
    The given matrix should have has many rows as the dimension of
    `varname1` and as many columns as the dimension of `varname2`.
    If the two variables are different and if `issymmetric` is set to 1
    then the transpose of the matrix is also added to the tangent system
    (default is 0). Set `iscoercive` to 1 if the term does not affect the
    coercivity of the tangent system (default is 0). The matrix can be
    changed by the command Model.set_private_matrix(). Return the
    brick index in the model."""
    return self.set("add_explicit_matrix", varname1, varname2, B, issymmetric, *args)


  def add_explicit_rhs(self, varname, L):
    """Add a brick representing an explicit right hand side to be added to
    the right hand side of the tangent linear system relatively to the
    variable `varname`. The given rhs should have the same size than the
    dimension of `varname`. The rhs can be changed by the command
    Model.set_private_rhs(). Return the brick index in the model."""
    return self.set("add_explicit_rhs", varname, L)


  def set_private_matrix(self, indbrick, B):
    """For some specific bricks having an internal sparse matrix
    (explicit bricks: 'constraint brick' and 'explicit matrix brick'),
    set this matrix. """
    return self.set("set_private_matrix", indbrick, B)


  def set_private_rhs(self, indbrick, B):
    """For some specific bricks having an internal right hand side vector
    (explicit bricks: 'constraint brick' and 'explicit rhs brick'),
    set this rhs. """
    return self.set("set_private_rhs", indbrick, B)


  def add_isotropic_linearized_elasticity_brick(self, mim, varname, dataname_lambda, dataname_mu, region=None):
    """Add an isotropic linearized elasticity term to the model relatively to
    the variable `varname`. `dataname_lambda` and `dataname_mu` should
    contain the Lame coefficients. `region` is an optional mesh region
    on which the term is added. If it is not specified, it is added
    on the whole mesh. Return the brick index in the model."""
    return self.set("add_isotropic_linearized_elasticity_brick", mim, varname, dataname_lambda, dataname_mu, region)


  def add_linear_incompressibility_brick(self, mim, varname, multname_pressure, region=None, *args):
    """Synopsis: ind = Model.add_linear_incompressibility_brick(self, MeshIm mim, string varname, string multname_pressure[, int region[, string dataname_coeff]])

    Add an linear incompressibility condition on `variable`. `multname_pressure`
    is a variable which represent the pressure. Be aware that an inf-sup
    condition between the finite element method describing the pressure and the
    primal variable has to be satisfied. `region` is an optional mesh region on
    which the term is added. If it is not specified, it is added on the whole mesh.
    `dataname_coeff` is an optional penalization coefficient for nearly
    incompressible elasticity for instance. In this case, it is the inverse
    of the Lame coefficient :math:`\\lambda`. Return the brick index in the model."""
    return self.set("add_linear_incompressibility_brick", mim, varname, multname_pressure, region, *args)


  def add_nonlinear_elasticity_brick(self, mim, varname, constitutive_law, dataname, region=None):
    """Add a nonlinear elasticity term to the model relatively to the
    variable `varname`. `lawname` is the constitutive law which
    could be 'SaintVenant Kirchhoff', 'Mooney Rivlin', 'Ciarlet Geymonat'
    or 'generalized Blatz Ko'.
    IMPORTANT : if the variable is defined on a 2D mesh, the plane strain
    approximation is automatically used.
    `dataname` is a vector of parameters for the constitutive law. Its length
    depends on the law. It could be a short vector of constant values or a
    vector field described on a finite element method for variable
    coefficients. `region` is an optional mesh region on which the term
    is added. If it is not specified, it is added on the whole mesh. Return the
    brick index in the model."""
    return self.set("add_nonlinear_elasticity_brick", mim, varname, constitutive_law, dataname, region)


  def add_elastoplasticity_brick(self, mim, projname, varname, datalambda, datamu, datathreshold, datasigma, region=None):
    """Add a nonlinear elastoplastic term to the model relatively to the
    variable `varname`, in small deformations, for an isotropic material
    and for a quasistatic model. `projname` is the type of projection that
    we want to use. For the moment, only the Von Mises projection is
    computing that we could entering 'VM' or 'Von Mises'.
    `datasigma` is the variable representing the constraints on the material.
    Be carefull that `varname` and `datasigma` are composed of two iterates
    for the time scheme needed for the Newton algorithm used.
    Moreover, the finite element method on which `varname` is described
    is an K ordered mesh_fem, the `datasigma` one have to be at least
    an K-1 ordered mesh_fem.
    `datalambda` and `datamu` are the Lame coefficients of the studied
    material.
    `datathreshold` is the plasticity threshold of the material.
    The three last variable could be constants or described on the
    same finite element method.
    `region` is an optional mesh region on which the term is added.
    If it is not specified, it is added on the whole mesh.
    Return the brick index in the model."""
    return self.set("add_elastoplasticity_brick", mim, projname, varname, datalambda, datamu, datathreshold, datasigma, region)


  def add_nonlinear_incompressibility_brick(self, mim, varname, multname_pressure, region=None):
    """Add an nonlinear incompressibility condition on `variable` (for large
    strain elasticity). `multname_pressure`
    is a variable which represent the pressure. Be aware that an inf-sup
    condition between the finite element method describing the pressure and the
    primal variable has to be satisfied. `region` is an optional mesh region on
    which the term is added. If it is not specified, it is added on the
    whole mesh. Return the brick index in the model."""
    return self.set("add_nonlinear_incompressibility_brick", mim, varname, multname_pressure, region)


  def add_bilaplacian_brick(self, mim, varname, dataname, region=None):
    """Add a bilaplacian brick on the variable
    `varname` and on the mesh region `region`.
    This represent a term :math:`\\Delta(D \\Delta u)`.
    where :math:`D(x)` is a coefficient determined by `dataname` which
    could be constant or described on a f.e.m. The corresponding weak form
    is :math:`\\int D(x)\\Delta u(x) \\Delta v(x) dx`.
    Return the brick index in the model."""
    return self.set("add_bilaplacian_brick", mim, varname, dataname, region)


  def add_Kirchhoff_Love_plate_brick(self, mim, varname, dataname_D, dataname_nu, region=None):
    """Add a bilaplacian brick on the variable
    `varname` and on the mesh region `region`.
    This represent a term :math:`\\Delta(D \\Delta u)` where :math:`D(x)`
    is a the flexion modulus determined by `dataname_D`. The term is
    integrated by part following a Kirchhoff-Love plate model
    with `dataname_nu` the poisson ratio.
    Return the brick index in the model."""
    return self.set("add_Kirchhoff_Love_plate_brick", mim, varname, dataname_D, dataname_nu, region)


  def add_normal_derivative_source_term_brick(self, mim, varname, dataname, region):
    """Add a normal derivative source term brick
    :math:`F = \\int b.\\partial_n v` on the variable `varname` and the
    mesh region `region`.
    
    Update the right hand side of the linear system.
    `dataname` represents `b` and `varname` represents `v`.
    Return the brick index in the model."""
    return self.set("add_normal_derivative_source_term_brick", mim, varname, dataname, region)


  def add_Kirchhoff_Love_Neumann_term_brick(self, mim, varname, dataname_M, dataname_divM, region):
    """Add a Neumann term brick for Kirchhoff-Love model
    n the variable `varname` and the mesh region `region`.
    dataname_M` represents the bending moment tensor and  `dataname_divM`
    ts divergence.
    eturn the brick index in the model."""
    return self.set("add_Kirchhoff_Love_Neumann_term_brick", mim, varname, dataname_M, dataname_divM, region)


  def add_normal_derivative_Dirichlet_condition_with_multipliers(self, mim, varname, mult_description, region, dataname=None, R_must_be_derivated=None):
    """Add a Dirichlet condition on the normal derivative of the variable
    varname` and on the mesh region `region` (which should be a boundary.
    he general form is
    math:`\\int \\partial_n u(x)v(x) = \\int r(x)v(x) \\forall v`
    here :math:`r(x)` is
    he right hand side for the Dirichlet condition (0 for
    omogeneous conditions) and :math:`v` is in a space of multipliers
    efined by `mult_description`.
    f `mult_description` is a string this is assumed
    o be the variable name corresponding to the multiplier (which should be
    irst declared as a multiplier variable on the mesh region in the model).
    f it is a finite element method (mesh_fem object) then a multiplier
    ariable will be added to the model and build on this finite element
    ethod (it will be restricted to the mesh region `region` and eventually
    ome conflicting dofs with some other multiplier variables will be
    uppressed). If it is an integer, then a  multiplier variable will be
    dded to the model and build on a classical finite element of degree
    hat integer. `dataname` is an optional parameter which represents
    he right hand side of the Dirichlet condition.
    f `R_must_be_derivated` is set to `true` then the normal
    erivative of `dataname` is considered.
    eturn the brick index in the model."""
    return self.set("add_normal_derivative_Dirichlet_condition_with_multipliers", mim, varname, mult_description, region, dataname, R_must_be_derivated)


  def add_normal_derivative_Dirichlet_condition_with_penalization(self, mim, varname, coeff, region, dataname=None, R_must_be_derivated=None):
    """Add a Dirichlet condition on the normal derivative of the variable
    varname` and on the mesh region `region` (which should be a boundary.
    he general form is
    math:`\\int \\partial_n u(x)v(x) = \\int r(x)v(x) \\forall v`
    here :math:`r(x)` is
    he right hand side for the Dirichlet condition (0 for
    omogeneous conditions).
    he penalization coefficient
    s initially `coeff` and will be added to the data of the model.
    t can be changed with the command Model.change_penalization_coeff().
    dataname` is an optional parameter which represents
    he right hand side of the Dirichlet condition.
    f `R_must_be_derivated` is set to `true` then the normal
    erivative of `dataname` is considered.
    eturn the brick index in the model."""
    return self.set("add_normal_derivative_Dirichlet_condition_with_penalization", mim, varname, coeff, region, dataname, R_must_be_derivated)


  def add_mass_brick(self, mim, varname, dataname_rho=None, *args):
    """Synopsis: ind = Model.add_mass_brick(self, MeshIm mim, string varname[, string dataname_rho[, int region]])

    Add mass term to the model relatively to the variable `varname`.
    If specified, the data `dataname_rho` should contain the
    density (1 if omitted). `region` is an optional mesh region on
    which the term is added. If it is not specified, it
    is added on the whole mesh. Return the brick index in the model."""
    return self.set("add_mass_brick", mim, varname, dataname_rho, *args)


  def add_basic_d_on_dt_brick(self, mim, varnameU, dataname_dt, dataname_rho=None, *args):
    """Synopsis: ind = Model.add_basic_d_on_dt_brick(self, MeshIm mim, string varnameU, string dataname_dt[, string dataname_rho[, int region]])

    Add the standard discretization of a first order time derivative on
    `varnameU`. The parameter `dataname_rho` is the density which could
    be omitted (the defaul value is 1). This brick should be used in
    addition to a time dispatcher for the other terms. Return the brick
    index in the model."""
    return self.set("add_basic_d_on_dt_brick", mim, varnameU, dataname_dt, dataname_rho, *args)


  def add_basic_d2_on_dt2_brick(self, mim, varnameU, datanameV, dataname_dt, dataname_alpha, dataname_rho=None, *args):
    """Synopsis: ind = Model.add_basic_d2_on_dt2_brick(self, MeshIm mim, string varnameU,  string datanameV, string dataname_dt, string dataname_alpha,[, string dataname_rho[, int region]])

    Add the standard discretization of a second order time derivative
    on `varnameU`. `datanameV` is a data represented on the same finite
    element method as U which represents the time derivative of U. The
    parameter `dataname_rho` is the density which could be omitted (the defaul
    value is 1). This brick should be used in addition to a time dispatcher for
    the other terms. The time derivative :math:`v` of the
    variable :math:`u` is preferably computed as a
    post-traitement which depends on each scheme. The parameter `dataname_alpha`
    depends on the time integration scheme. Return the brick index in the model."""
    return self.set("add_basic_d2_on_dt2_brick", mim, varnameU, datanameV, dataname_dt, dataname_alpha, dataname_rho, *args)


  def add_theta_method_dispatcher(self, bricks_indices, theta):
    """Add a theta-method time dispatcher to a list of bricks. For instance,
    a matrix term :math:`K` will be replaced by
    :math:`\\theta K U^{n+1} + (1-\\theta) K U^{n}`.
    """
    return self.set("add_theta_method_dispatcher", bricks_indices, theta)


  def add_midpoint_dispatcher(self, bricks_indices):
    """Add a midpoint time dispatcher to a list of bricks. For instance, a
    nonlinear term :math:`K(U)` will be replaced by
    :math:`K((U^{n+1} +  U^{n})/2)`."""
    return self.set("add_midpoint_dispatcher", bricks_indices)


  def velocity_update_for_order_two_theta_method(self, varnameU, datanameV, dataname_dt, dataname_theta):
    """Function which udpate the velocity :math:`v^{n+1}` after
    the computation of the displacement :math:`u^{n+1}` and
    before the next iteration. Specific for theta-method and when the velocity is
    included in the data of the model. """
    return self.set("velocity_update_for_order_two_theta_method", varnameU, datanameV, dataname_dt, dataname_theta)


  def velocity_update_for_Newmark_scheme(self, id2dt2_brick, varnameU, datanameV, dataname_dt, dataname_twobeta, dataname_alpha):
    """Function which udpate the velocity
    :math:`v^{n+1}` after
    the computation of the displacement
    :math:`u^{n+1}` and
    before the next iteration. Specific for Newmark scheme
    and when the velocity is
    included in the data of the model.*
    This version inverts the mass matrix by a
    conjugate gradient."""
    return self.set("velocity_update_for_Newmark_scheme", id2dt2_brick, varnameU, datanameV, dataname_dt, dataname_twobeta, dataname_alpha)


  def disable_bricks(self, bricks_indices):
    """Disable a brick (the brick will no longer participate to the
    building of the tangent linear system)."""
    return self.set("disable_bricks", bricks_indices)


  def enable_bricks(self, bricks_indices):
    """Enable a disabled brick."""
    return self.set("enable_bricks", bricks_indices)


  def disable_variable(self, varname):
    """Disable a variable for a solve. The next solve will operate only on
    the remaining variables. This allows to solve separately different
    parts of a model. If there is a strong coupling of the variables,
    a fixed point strategy can the be used. """
    return self.set("disable_variable", varname)


  def enable_variable(self, varname):
    """Enable a disabled variable."""
    return self.set("enable_variable", varname)


  def first_iter(self):
    """To be executed before the first iteration of a time integration
    scheme. """
    return self.set("first_iter")


  def next_iter(self):
    """To be executed at the end of each iteration of a time
    integration scheme. """
    return self.set("next_iter")


  def add_basic_contact_brick(self, varname_u, multname_n, multname_t=None, *args):
    """Synopsis: ind = Model.add_basic_contact_brick(self, string varname_u, string multname_n[, string multname_t], string dataname_r, Spmat BN[, Spmat BT, string dataname_friction_coeff][, string dataname_gap[, string dataname_alpha[, int augmented_version]])

    Add a contact with  or without friction brick to the model.
    If U is the vector
    of degrees of freedom on which the unilateral constraint is applied,
    the matrix `BN` have to be such that this constraint is defined by
    :math:`B_N U \\le 0`. A friction condition can be considered by adding
    the three parameters `multname_t`, `BT` and `dataname_friction_coeff`.
    In this case, the tangential displacement is :math:`B_T U` and
    the matrix `BT` should have as many rows as `BN` multiplied by
    :math:`d-1` where :math:`d` is the domain dimension.
    In this case also, `dataname_friction_coeff` is a data which represents
    the coefficient of friction. It can be a scalar or a vector representing a
    value on each contact condition.  The unilateral constraint is prescribed
    thank to a multiplier
    `multname_n` whose dimension should be equal to the number of rows of
    `BN`. If a friction condition is added, it is prescribed with a
    multiplier `multname_t` whose dimension should be equal to the number
    of rows of `BT`. The augmentation parameter `r` should be chosen in
    a range of
    acceptabe values (see Getfem user documentation). `dataname_gap` is an
    optional parameter representing the initial gap. It can be a single value
    or a vector of value. `dataname_alpha` is an optional homogenization
    parameter for the augmentation parameter
    (see Getfem user documentation).  The parameter `augmented_version`
    indicates the augmentation strategy : 1 for the non-symmetric
    Alart-Curnier augmented Lagrangian, 2 for the symmetric one (except for
    the coupling between contact and Coulomb friction), 3 for the
    unsymmetric method with augmented multipliers, 4 for the unsymmetric
    method with augmented multipliers and De Saxce projection. """
    return self.set("add_basic_contact_brick", varname_u, multname_n, multname_t, *args)


  def contact_brick_set_BN(self, indbrick, BN):
    """Can be used to set the BN matrix of a basic contact/friction brick."""
    return self.set("contact_brick_set_BN", indbrick, BN)


  def contact_brick_set_BT(self, indbrick, BT):
    """Can be used to set the BT matrix of a basic contact with
    friction brick. """
    return self.set("contact_brick_set_BT", indbrick, BT)


  def add_nodal_contact_with_rigid_obstacle_brick(self, mim, varname_u, multname_n, multname_t=None, *args):
    """Synopsis: ind = Model.add_nodal_contact_with_rigid_obstacle_brick(self,  MeshIm mim, string varname_u, string multname_n[, string multname_t], string dataname_r[, string dataname_friction_coeff], int region, string obstacle[,  int augmented_version])

    Add a contact with or without friction condition with a rigid obstacle
    to the model. The condition is applied on the variable `varname_u`
    on the boundary corresponding to `region`. The rigid obstacle should
    be described with the string `obstacle` being a signed distance to
    the obstacle. This string should be an expression where the coordinates
    are 'x', 'y' in 2D and 'x', 'y', 'z' in 3D. For instance, if the rigid
    obstacle correspond to :math:`z \\le 0`, the corresponding signed distance
    will be simply "z". `multname_n` should be a fixed size variable whose size
    is the number of degrees of freedom on boundary `region`. It represents the
    contact equivalent nodal forces. In order to add a friction condition
    one has to add the `multname_t` and `dataname_friction_coeff` parameters.
    `multname_t` should be a fixed size variable whose size is
    the number of degrees of freedom on boundary `region` multiplied by
    :math:`d-1` where :math:`d` is the domain dimension. It represents
    the friction equivalent nodal forces.
    The augmentation parameter `r` should be chosen in a
    range of acceptabe values (close to the Young modulus of the elastic
    body, see Getfem user documentation).  `dataname_friction_coeff` is
    the friction coefficient. It could be a scalar or a vector of values
    representing the friction coefficient on each contact node. 
    The parameter `augmented_version`
    indicates the augmentation strategy : 1 for the non-symmetric
    Alart-Curnier augmented Lagrangian, 2 for the symmetric one (except for
    the coupling between contact and Coulomb friction),
    3 for the new unsymmetric method.
    Basically, this brick compute the matrix BN
    and the vectors gap and alpha and calls the basic contact brick. """
    return self.set("add_nodal_contact_with_rigid_obstacle_brick", mim, varname_u, multname_n, multname_t, *args)


  def add_contact_with_rigid_obstacle_brick(self, mim, varname_u, multname_n, multname_t=None, *args):
    """Synopsis: ind = Model.add_contact_with_rigid_obstacle_brick(self,  MeshIm mim, string varname_u, string multname_n[, string multname_t], string dataname_r[, string dataname_friction_coeff], int region, string obstacle[,  int augmented_version])

    DEPRECATED FUNCTION. Use 'add nodal contact with rigid obstacle brick' instead."""
    return self.set("add_contact_with_rigid_obstacle_brick", mim, varname_u, multname_n, multname_t, *args)


  def add_integral_contact_with_rigid_obstacle_brick(self, mim, varname_u, multname, dataname_obstacle, dataname_r, dataname_friction_coeff=None, *args):
    """Synopsis: ind = Model.add_integral_contact_with_rigid_obstacle_brick(self,  MeshIm mim, string varname_u, string multname, string dataname_obstacle, string dataname_r [, string dataname_friction_coeff], int region [, int option [, string dataname_alpha [, string dataname_wt [, string dataname_gamma [, string dataname_vt]]]]])

    Add a contact with or without friction condition with a rigid obstacle
    to the model. This brick adds a contact which is defined
    in an integral way. It is the direct approximation of an augmented
    Lagrangian formulation (see Getfem user documentation) defined at the
    continuous level. The advantage is a better scalability: the number of
    Newton iterations should be more or less independent of the mesh size.
    The contact condition is applied on the variable `varname_u`
    on the boundary corresponding to `region`. The rigid obstacle should
    be described with the data `dataname_obstacle` being a signed distance to
    the obstacle (interpolated on a finite element method).
    `multname` should be a fem variable representing the contact stress.
    An inf-sup condition beetween `multname` and `varname_u` is required.
    The augmentation parameter `dataname_r` should be chosen in a
    range of acceptabe values.
    The optional parameter `dataname_friction_coeff` is the friction
    coefficient which could be constant or defined on a finite element method.
    Possible values for `option` is 1 for the non-symmetric Alart-Curnier
    augmented Lagrangian method, 2 for the symmetric one, 3 for the
    non-symmetric Alart-Curnier method with an additional augmentation
    and 4 for a new unsymmetric method. The default value is 1.
    In case of contact with friction, `dataname_alpha` and `dataname_wt`
    are optional parameters to solve evolutionary friction problems.
    `dataname_gamma` and `dataname_vt` represent optional data for adding
    a parameter-dependent sliding velocity to the friction condition.
    """
    return self.set("add_integral_contact_with_rigid_obstacle_brick", mim, varname_u, multname, dataname_obstacle, dataname_r, dataname_friction_coeff, *args)


  def add_penalized_contact_with_rigid_obstacle_brick(self, mim, varname_u, dataname_obstacle, dataname_r, dataname_coeff=None, *args):
    """Synopsis: ind = Model.add_penalized_contact_with_rigid_obstacle_brick(self,  MeshIm mim, string varname_u, string dataname_obstacle, string dataname_r [, string dataname_coeff], int region [, int option, string dataname_lambda, [, string dataname_alpha [, string dataname_wt]]])

    Add a penalized contact with or without friction condition with a
    rigid obstacle to the model.
    The condition is applied on the variable `varname_u`
    on the boundary corresponding to `region`. The rigid obstacle should
    be described with the data `dataname_obstacle` being a signed distance to
    the obstacle (interpolated on a finite element method).
    The penalization parameter `dataname_r` should be chosen
    large enough to prescribe approximate non-penetration and friction
    conditions but not too large not to deteriorate too much the
    conditionning of the tangent system.
    `dataname_lambda` is an optional parameter used if option
    is 2. In that case, the penalization term is shifted by lambda (this
    allows the use of an Uzawa algorithm on the corresponding augmented
    Lagrangian formulation)
    """
    return self.set("add_penalized_contact_with_rigid_obstacle_brick", mim, varname_u, dataname_obstacle, dataname_r, dataname_coeff, *args)


  def add_Nitsche_contact_with_rigid_obstacle_brick(self, mim, varname_u, dataname_obstacle, dataname_r, dataname_friction_coeff, dataname_lambda, dataname_mu, region):
    """Add a contact with friction condition with a rigid obstacle
    to the model with  Nitsche strategy (no multiplier) in an integral way.
    This is an experimental brick, which works only for linear homogeneous
    isotropic elasticity.
    The condition is applied on the variable `varname_u`
    on the boundary corresponding to `region`. The rigid obstacle should
    be described with the data `dataname_obstacle` being a signed distance
    to the obstacle (interpolated on a finite element method).
    The Nitsche parameter `dataname_r` should be chosen in a
    range of acceptable values. `dataname_friction_coeff` is the friction
    coefficient which could be constant or defined on a finite element
    method. `dataname_lambda` and `dataname_mu` are the Lame coefficients.
    """
    return self.set("add_Nitsche_contact_with_rigid_obstacle_brick", mim, varname_u, dataname_obstacle, dataname_r, dataname_friction_coeff, dataname_lambda, dataname_mu, region)


  def add_nodal_contact_between_nonmatching_meshes_brick(self, mim1, mim2=None, *args):
    """Synopsis: ind = Model.add_nodal_contact_between_nonmatching_meshes_brick(self,  MeshIm mim1[, MeshIm mim2], string varname_u1[, string varname_u2], string multname_n[, string multname_t], string dataname_r[, string dataname_fr], int rg1, int rg2[, int slave1, int slave2,  int augmented_version])

    Add a contact with or without friction condition between two faces of
    one or two elastic bodies. The condition is applied on the variable
    `varname_u1` or the variables `varname_u1` and `varname_u2` depending
    if a single or two distinct displacement fields are given. Integers
    `rg1` and `rg2` represent the regions expected to come in contact with
    each other. In the single displacement variable case the regions defined
    in both `rg1` and `rg2` refer to the variable `varname_u1`. In the case
    of two displacement variables, `rg1` refers to `varname_u1` and `rg2`
    refers to `varname_u2`. `multname_n` should be a fixed size variable
    whose size is the number of degrees of freedom on those regions among
    the ones defined in `rg1` and `rg2` which are characterized as "slaves".
    It represents the contact equivalent nodal normal forces. `multname_t`
    should be a fixed size variable whose size corresponds to the size of
    `multname_n` multiplied by qdim - 1 . It represents the contact
    equivalent nodal tangent (frictional) forces. The augmentation parameter
    `r` should be chosen in a range of acceptabe values (close to the Young
    modulus of the elastic body, see Getfem user documentation). The
    friction coefficient stored in the parameter `fr` is either a single
    value or a vector of the same size as `multname_n`. The optional
    parameters `slave1` and `slave2` declare if the regions defined in `rg1`
    and `rg2` are correspondingly considered as "slaves". By default
    `slave1` is true and `slave2` is false, i.e. `rg1` contains the slave
    surfaces, while 'rg2' the master surfaces. Preferrably only one of
    `slave1` and `slave2` is set to true.  The parameter `augmented_version`
    indicates the augmentation strategy : 1 for the non-symmetric
    Alart-Curnier augmented Lagrangian, 2 for the symmetric one (except for
    the coupling between contact and Coulomb friction),
    3 for the new unsymmetric method.
    Basically, this brick computes the matrices BN and BT and the vectors
    gap and alpha and calls the basic contact brick. """
    return self.set("add_nodal_contact_between_nonmatching_meshes_brick", mim1, mim2, *args)


  def add_nonmatching_meshes_contact_brick(self, mim1, mim2=None, *args):
    """Synopsis: ind = Model.add_nonmatching_meshes_contact_brick(self,  MeshIm mim1[, MeshIm mim2], string varname_u1[, string varname_u2], string multname_n[, string multname_t], string dataname_r[, string dataname_fr], int rg1, int rg2[, int slave1, int slave2,  int augmented_version])

    DEPRECATED FUNCTION. Use 'add nodal contact between nonmatching meshes brick' instead."""
    return self.set("add_nonmatching_meshes_contact_brick", mim1, mim2, *args)


  def add_integral_contact_between_nonmatching_meshes_brick(self, mim, varname_u1, varname_u2, multname, dataname_r, dataname_friction_coeff=None, *args):
    """Synopsis: ind = Model.add_integral_contact_between_nonmatching_meshes_brick(self,  MeshIm mim, string varname_u1, string varname_u2, string multname, string dataname_r [, string dataname_friction_coeff], int region1, int region2 [, int option [, string dataname_alpha [, string dataname_wt1 , string dataname_wt2]]])

    Add a contact with or without friction condition between nonmatching
    meshes to the model. This brick adds a contact which is defined
    in an integral way. It is the direct approximation of an augmented
    agrangian formulation (see Getfem user documentation) defined at the
    continuous level. The advantage should be a better scalability:
    the number of Newton iterations should be more or less independent
    of the mesh size.
    The condition is applied on the variables `varname_u1` and `varname_u2`
    on the boundaries corresponding to `region1` and `region2`.
    `multname` should be a fem variable representing the contact stress
    for the frictionless case and the contact and friction stress for the
    case with friction. An inf-sup condition between `multname` and
    `varname_u1` and `varname_u2` is required.
    The augmentation parameter `dataname_r` should be chosen in a
    range of acceptable values.
    The optional parameter `dataname_friction_coeff` is the friction
    coefficient which could be constant or defined on a finite element
    method on the same mesh as `varname_u1`.
    Possible values for `option` is 1 for the non-symmetric Alart-Curnier
    augmented Lagrangian method, 2 for the symmetric one, 3 for the
    non-symmetric Alart-Curnier method with an additional augmentation
    and 4 for a new unsymmetric method. The default value is 1.
    In case of contact with friction, `dataname_alpha`, `dataname_wt1` and
    `dataname_wt2` are optional parameters to solve evolutionary friction
    problems.
    """
    return self.set("add_integral_contact_between_nonmatching_meshes_brick", mim, varname_u1, varname_u2, multname, dataname_r, dataname_friction_coeff, *args)


  def add_penalized_contact_between_nonmatching_meshes_brick(self, mim, varname_u1, varname_u2, dataname_r, dataname_coeff=None, *args):
    """Synopsis: ind = Model.add_penalized_contact_between_nonmatching_meshes_brick(self,  MeshIm mim, string varname_u1, string varname_u2, string dataname_r [, string dataname_coeff], int region1, int region2 [, int option [, string dataname_lambda, [, string dataname_alpha [, string dataname_wt1, string dataname_wt2]]]])

    Add a penalized contact condition with or without friction between
    nonmatching meshes to the model.
    The condition is applied on the variables `varname_u1` and  `varname_u2`
    on the boundaries corresponding to `region1` and `region2`.
    The penalization parameter `dataname_r` should be chosen
    large enough to prescribe approximate non-penetration and friction
    conditions but not too large not to deteriorate too much the
    conditionning of the tangent system.
    The optional parameter `dataname_friction_coeff` is the friction
    coefficient which could be constant or defined on a finite element
    method on the same mesh as `varname_u1`.
    `dataname_lambda` is an optional parameter used if option
    is 2. In that case, the penalization term is shifted by lambda (this
    allows the use of an Uzawa algorithm on the corresponding augmented
    Lagrangian formulation)
    In case of contact with friction, `dataname_alpha`, `dataname_wt1` and
    `dataname_wt2` are optional parameters to solve evolutionary friction
    problems.
    """
    return self.set("add_penalized_contact_between_nonmatching_meshes_brick", mim, varname_u1, varname_u2, dataname_r, dataname_coeff, *args)


  def add_integral_large_sliding_contact_brick(self, mim, varname_u, multname, dataname_r, dataname_fr, rg):
    """(still experimental brick)
    Add a large sliding contact with friction brick to the model.
    This brick is able to deal with auto-contact, contact between
    several deformable bodies and contact with rigid obstacles.
    The condition is applied on the variable `varname_u` on the
    boundary corresponding to `region`. `dataname_r` is the augmentation
    parameter of the augmented Lagrangian. `dataname_friction_coeff`
    is the friction coefficient. `mim` is an integration method on the
    boundary. `varname_u` is the variable on which the contact condition 
    will be prescribed (should be of displacement type). `multname` is 
    a multiplier defined on the boundary which will represent the contact
    force. If no additional boundary or rigid
    obstacle is added, only auto-contact will be detected. Use
    `add_boundary_to_large_sliding_contact_brick` and
    `add_rigid_obstacle_to_large_sliding_contact_brick` to add contact
    boundaries and rigid obstacles. """
    return self.set("add_integral_large_sliding_contact_brick", mim, varname_u, multname, dataname_r, dataname_fr, rg)


  def add_boundary_to_large_sliding_contact_brick(self, indbrick, mim, varname_u, multname, rg):
    """Add a contact boundary to an existing large sliding contact brick.
    indbrick` is the brick index. """
    return self.set("add_boundary_to_large_sliding_contact_brick", indbrick, mim, varname_u, multname, rg)


  def add_rigid_obstacle_to_large_sliding_contact_brick(self, indbrick, obs):
    """Add a rigid obstacle to an existing large sliding contact brick.
    indbrick` is the brick index, `obs` is the expression of a
    unction which should be closed to a signed distance to the obstacle. """
    return self.set("add_rigid_obstacle_to_large_sliding_contact_brick", indbrick, obs)


#
# GetFEM class Precond definition.
#

class Precond:
  """GetFEM Precond object

  The preconditioners may store REAL or COMPLEX values. They accept getfem
  sparse matrices and Matlab sparse matrices.

  """
  def __init__(self, *args):
    """General constructor for Precond objects

  * ``PC = Precond('identity')``
    Create a REAL identity precondioner.

  * ``PC = Precond('cidentity')``
    Create a COMPLEX identity precondioner.

  * ``PC = Precond('diagonal', vec D)``
    Create a diagonal precondioner.

  * ``PC = Precond('ildlt', SpMat m)``
    Create an ILDLT (Cholesky) preconditioner for the (symmetric) sparse
    matrix `m`. This preconditioner has the same sparsity pattern than `m`
    (no fill-in).

  * ``PC = Precond('ilu', SpMat m)``
    Create an ILU (Incomplete LU) preconditioner for the sparse
    matrix `m`. This preconditioner has the same sparsity pattern
    than `m` (no fill-in).  

  * ``PC = Precond('ildltt', SpMat m[, int fillin[, scalar threshold]])``
    Create an ILDLTT (Cholesky with filling) preconditioner for the
    (symmetric) sparse matrix `m`. The preconditioner may add at most
    `fillin` additional non-zero entries on each line. The default value
    for `fillin` is 10, and the default threshold is1e-7.

  * ``PC = Precond('ilut', SpMat m[, int fillin[, scalar threshold]])``
    Create an ILUT (Incomplete LU with filling) preconditioner for the
    sparse matrix `m`. The preconditioner may add at most `fillin`
    additional non-zero entries on each line. The default value for
    `fillin` is 10, and the default threshold is 1e-7.

  * ``PC = Precond('superlu', SpMat m)``
    Uses SuperLU to build an exact factorization of the sparse matrix `m`.
    This preconditioner is only available if the getfem-interface was
    built with SuperLU support. Note that LU factorization is likely to
    eat all your memory for 3D problems.

  * ``PC = Precond('spmat', SpMat m)``
    Preconditionner given explicitely by a sparse matrix.

    """
    generic_constructor(self,'precond',*args)
  def __del__(self):
    generic_destructor(self, destructible=True)
  def get(self, *args):
    return getfem('precond_get',self.id, *args)
  def __repr__(self):
    getfem('precond_get',self.id, 'display')
    return ''
  def __str__(self):
    return self.char()

  def mult(self, V):
    """Apply the preconditioner to the supplied vector."""
    return self.get("mult", V)


  def tmult(self, V):
    """Apply the transposed preconditioner to the supplied vector."""
    return self.get("tmult", V)


  def type(self):
    """Return a string describing the type of the preconditioner ('ilu', 'ildlt',..)."""
    return self.get("type")


  def size(self):
    """Return the dimensions of the preconditioner."""
    return self.get("size")


  def is_complex(self):
    """Return 1 if the preconditioner stores complex values."""
    return self.get("is_complex")


  def char(self):
    """Output a (unique) string representation of the Precond.
    
    This can be used to perform comparisons between two
    different Precond objects.
    This function is to be completed.
    """
    return self.get("char")


  def display(self):
    """displays a short summary for a Precond object."""
    return self.get("display")


#
# GetFEM class Slice definition.
#

class Slice:
  """GetFEM Slice object

  Creation of a mesh slice. Mesh slices are very similar to a
  P1-discontinuous MeshFem on which interpolation is very fast. The slice is
  built from a mesh object, and a description of the slicing operation, for
  example::

    sl = Slice(('planar',+1,[[0],[0]],[[0],[1]]), m, 5)

  cuts the original mesh with the half space {y>0}. Each convex of the
  original Mesh `m` is simplexified (for example a quadrangle is splitted
  into 2 triangles), and each simplex is refined 5 times.

  Slicing operations can be:

  * cutting with a plane, a sphere or a cylinder
  * intersection or union of slices
  * isovalues surfaces/volumes
  * "points", "streamlines" (see below)

  If the first argument is a MeshFem `mf` instead of a Mesh, and if it is
  followed by a `mf`-field `u`, then the deformation `u` will be applied to the
  mesh before the slicing operation.

  The first argument can also be a slice.

  """
  def __init__(self, *args):
    """General constructor for Slice objects

  * ``sl = Slice(sliceop, {Slice sl|{Mesh m| MeshFem mf, vec U}, int refine}[, mat CVfids])``
    Create a Slice using `sliceop` operation.
    
    `sliceop` operation is specified with  Tuple
    or List, do not forget the extra parentheses!. The first element is the
    name of the operation, followed the slicing options:
    
    * ('none') :
      Does not cut the mesh.
    
    * ('planar', int orient, vec p, vec n) :
      Planar cut. `p` and `n` define a half-space, `p` being a point belong to
      the boundary of the half-space, and `n` being its normal. If `orient` is
      equal to -1 (resp. 0, +1), then the slicing operation will cut the mesh
      with the "interior" (resp. "boundary", "exterior") of the half-space.
      `orient` may also be set to +2 which means that the mesh will be sliced,
      but both the outer and inner parts will be kept.
    
    * ('ball', int orient, vec c, scalar r) :
      Cut with a ball of center `c` and radius `r`.
    
    * ('cylinder', int orient, vec p1, vec p2, scalar r) :
      Cut with a cylinder whose axis is the line `(p1, p2)` and whose radius
      is `r`.
    
    * ('isovalues', int orient, MeshFem mf, vec U, scalar s) :
      Cut using the isosurface of the field `U` (defined on the MeshFem `mf`).
      The result is the set `{x such that :math:`U(x) \\leq s`}` or `{x such that
      `U`(x)=`s`}` or `{x such that `U`(x) >= `s`}` depending on the value of
      `orient`.
    
    * ('boundary'[, SLICEOP]) :
      Return the boundary of the result of SLICEOP, where SLICEOP is any
      slicing operation. If SLICEOP is not specified, then the whole mesh is
      considered (i.e. it is equivalent to ('boundary',{'none'})).
    
    * ('explode', mat Coef) :
      Build an 'exploded' view of the mesh: each convex is shrinked (:math:`0 <
      \\text{Coef} \\leq 1`). In the case of 3D convexes, only their faces are kept.
    
    * ('union', SLICEOP1, SLICEOP2) :
      Returns the union of slicing operations.
    
    * ('intersection', SLICEOP1, SLICEOP2) :
      Returns the intersection of slicing operations, for example::
    
        sl = Slice((intersection',('planar',+1,[[0],[0],[0]],[[0],[0],[1]]),
                                   ('isovalues',-1,mf2,u2,0)),mf,u,5)
    
    * ('comp', SLICEOP) :
      Returns the complementary of slicing operations.
    
    * ('diff', SLICEOP1, SLICEOP2) :
      Returns the difference of slicing operations.
    
    * ('mesh', Mesh m) :
      Build a slice which is the intersection of the sliced mesh with another
      mesh. The slice is such that all of its simplexes are stricly contained
      into a convex of each mesh.
    

  * ``sl = Slice('streamlines', MeshFem mf, mat U, mat S)``
    Compute streamlines of the (vector) field `U`, with seed points given
    by the columns of `S`.

  * ``sl = Slice('points', Mesh m, mat Pts)``
    Return the "slice" composed of points given by the columns of `Pts`
    (useful for interpolation on a given set of sparse points, see
    ``gf_compute('interpolate on',sl)``.

  * ``sl = Slice('load', string filename[, Mesh m])``
    Load the slice (and its linked mesh if it is not given as an argument)
    from a text file.

    """
    generic_constructor(self,'slice',*args)
  def __del__(self):
    generic_destructor(self, destructible=True)
  def get(self, *args):
    return getfem('slice_get',self.id, *args)
  def __repr__(self):
    getfem('slice_get',self.id, 'display')
    return ''
  def set(self, *args):
    return getfem('slice_set',self.id, *args)
  def __str__(self):
    return self.char()

  def dim(self):
    """Return the dimension of the slice (2 for a 2D mesh, etc..)."""
    return self.get("dim")


  def area(self):
    """Return the area of the slice."""
    return self.get("area")


  def cvs(self):
    """Return the list of convexes of the original mesh contained in the slice."""
    return self.get("cvs")


  def nbpts(self):
    """Return the number of points in the slice."""
    return self.get("nbpts")


  def nbsplxs(self, dim=None):
    """Return the number of simplexes in the slice.
    
    Since the slice may contain points (simplexes of dim 0), segments
    (simplexes of dimension 1), triangles etc., the result is a vector
    of size Slice.dim()+1, except if the optional argument `dim`
    is used."""
    return self.get("nbsplxs", dim)


  def pts(self):
    """Return the list of point coordinates."""
    return self.get("pts")


  def splxs(self, dim):
    """Return the list of simplexes of dimension `dim`.
    
    On output, S has 'dim+1' rows, each column contains the point
    numbers of a simplex.  The vector `CV2S` can be used to find the
    list of simplexes for any convex stored in the slice. For example
    'S[:,CV2S[4]:CV2S[5]]'
    gives the list of simplexes for the fourth convex."""
    return self.get("splxs", dim)


  def edges(self):
    """Return the edges of the linked mesh contained in the slice.
    
    `P` contains the list of all edge vertices, `E1` contains
    the indices of each mesh edge in `P`, and `E2` contains the
    indices of each "edges" which is on the border of the slice.
    This function is useless except for post-processing purposes."""
    return self.get("edges")


  def interpolate_convex_data(self, Ucv):
    """Interpolate data given on each convex of the mesh to the slice nodes.
    
    The input array `Ucv` may have any number of dimensions, but its
    last dimension should be equal to Mesh.max_cvid().
    
    Example of use: Slice.interpolate_convex_data(Mesh.quality())."""
    return self.get("interpolate_convex_data", Ucv)


  def linked_mesh(self):
    """Return the mesh on which the slice was taken."""
    return self.get("linked_mesh")


  def mesh(self):
    """Return the mesh on which the slice was taken
    (identical to 'linked mesh')"""
    return self.get("mesh")


  def memsize(self):
    """Return the amount of memory (in bytes) used by the slice object."""
    return self.get("memsize")


  def export_to_vtk(self, filename, *args):
    """Synopsis: Slice.export_to_vtk(self, string filename, ...)

    Export a slice to VTK.
    
    Following the `filename`, you may use any of the following options:
    
    - if 'ascii' is not used, the file will contain binary data
      (non portable, but fast).
    - if 'edges' is used, the edges of the original mesh will be
      written instead of the slice content.
    
    More than one dataset may be written, just list them. Each dataset
    consists of either:
    
    - a field interpolated on the slice (scalar, vector or tensor),
      followed by an optional name.
    - a mesh_fem and a field, followed by an optional name.
    
    Examples:
    
    - Slice.export_to_vtk('test.vtk', Usl, 'first_dataset', mf,
      U2, 'second_dataset')
    - Slice.export_to_vtk('test.vtk', 'ascii', mf,U2)
    - Slice.export_to_vtk('test.vtk', 'edges', 'ascii', Uslice)"""
    return self.get("export_to_vtk", filename, *args)


  def export_to_pov(self, filename):
    """Export a the triangles of the slice to POV-RAY."""
    return self.get("export_to_pov", filename)


  def export_to_dx(self, filename, *args):
    """Synopsis: Slice.export_to_dx(self, string filename, ...)

    Export a slice to OpenDX.
    
    Following the `filename`, you may use any of the following
    options:
    
    - if 'ascii' is not used, the file will contain binary data
      (non portable, but fast).
    - if 'edges' is used, the edges of the original mesh will be
      written instead of the slice content.
    - if 'append' is used, the opendx file will not be overwritten,
      and the new data will be added at the end of the file.
    
    More than one dataset may be written, just list them. Each dataset
    consists of either:
    
    - a field interpolated on the slice (scalar, vector or tensor),
      followed by an optional name.
    - a mesh_fem and a field, followed by an optional name."""
    return self.get("export_to_dx", filename, *args)


  def export_to_pos(self, filename, name=None, *args):
    """Synopsis: Slice.export_to_pos(self, string filename[, string name][[,MeshFem mf1], mat U1, string nameU1[[,MeshFem mf1], mat U2, string nameU2,...])

    Export a slice to Gmsh.
    
    More than one dataset may be written, just list them.
    Each dataset consists of either:
    
    - a field interpolated on the slice (scalar, vector or tensor).
    - a mesh_fem and a field."""
    return self.get("export_to_pos", filename, name, *args)


  def char(self):
    """Output a (unique) string representation of the Slice.
    
    This can be used to perform comparisons between two
    different Slice objects.
    This function is to be completed.
    """
    return self.get("char")


  def display(self):
    """displays a short summary for a Slice object."""
    return self.get("display")


  def set_pts(self, P):
    """Replace the points of the slice.
    
    The new points `P` are stored in the columns the matrix. Note that
    you can use the function to apply a deformation to a slice, or to
    change the dimension of the slice (the number of rows of `P` is not
    required to be equal to Slice.dim())."""
    return self.set("pts", P)


#
# GetFEM class Spmat definition.
#

class Spmat:
  """GetFEM Spmat object

  Create a new sparse matrix in getfem++ format. These sparse matrix can be stored as CSC (compressed column
  sparse), which is the format used by Matlab, or they can be stored as WSC
  (internal format to getfem). The CSC matrices are not writable (it would
  be very inefficient), but they are optimized for multiplication with
  vectors, and memory usage. The WSC are writable, they are very fast with
  respect to random read/write operation. However their memory overhead is
  higher than CSC matrices, and they are a little bit slower for
  matrix-vector multiplications.

  By default, all newly created matrices are build as WSC matrices. This can
  be changed later with ``Spmat.to_csc(...)``, or may be changed
  automatically by getfem (for example ``gf_linsolve()`` converts the
  matrices to CSC).

  The matrices may store REAL or COMPLEX values.
  """
  def __init__(self, *args):
    """General constructor for Spmat objects

  * ``SM = Spmat('empty', int m [, int n])``
    Create a new empty (i.e. full of zeros) sparse matrix, of dimensions
    `m x n`. If `n` is omitted, the matrix dimension is `m x m`.

  * ``SM = Spmat('copy', mat K [, list I [, list J]])``
    Duplicate a matrix `K` (which might be a SpMat). If index `I` and/or `J` are given, the matrix will
    be a submatrix of `K`. For example::
    
      
      
      m = Spmat('copy', Spmat('empty',50,50), range(40), [6, 7, 8, 3, 10])
    
    will return a 40x5 matrix.

  * ``SM = Spmat('identity', int n)``
    Create a `n x n` identity matrix.

  * ``SM = Spmat('mult', Spmat A, Spmat B)``
    Create a sparse matrix as the product of the sparse matrices `A` and
    `B`. It requires that `A` and `B` be both real or both complex, you
    may have to use ``Spmat.to_complex()``

  * ``SM = Spmat('add', Spmat A, Spmat B)``
    Create a sparse matrix as the sum of the sparse matrices `A` and `B`.
    Adding a real matrix with a complex matrix is possible.

  * ``SM = Spmat('diag', mat D [, ivec E [, int n [,int m]]])``
    Create a diagonal matrix. If `E` is given, `D` might be a matrix and
    each column of `E` will contain the sub-diagonal number that will be
    filled with the corresponding column of `D`.

  * ``SM = Spmat('load','hb'|'harwell-boeing'|'mm'|'matrix-market', string filename)``
    Read a sparse matrix from an Harwell-Boeing or a Matrix-Market file
    .

    """
    generic_constructor(self,'spmat',*args)
  def __del__(self):
    generic_destructor(self, destructible=True)
  def get(self, *args):
    return getfem('spmat_get',self.id, *args)
  def __repr__(self):
    getfem('spmat_get',self.id, 'display')
    return ''
  def set(self, *args):
    return getfem('spmat_set',self.id, *args)
  def __str__(self):
    return self.char()

  def __getitem__(self, key):
    return getfem('spmat_get',self.id, 'full',*key)
  def __setitem__(self, key, keyval):
    getfem('spmat_set', self.id, 'assign', key[0], key[1], keyval)
  def __neg__(self):
    m=Spmat('copy',self)
    m.scale(-1)
    return m
  def __add__(self, other):
    return Spmat('add',self,other)
  def __sub__(self, other):
    return Spmat('add',self,other.__neg__())
  def __mul__(self, other):
    """Multiplication of a Spmat with another Spmat or a vector or a scalar.

       The result is another Spmat object.
    """
    if isinstance(other,numbers.Number):
      m = Spmat('copy',self)
      m.set('scale',other)
    elif (isinstance(other,list) or isinstance(other, numpy.ndarray)):
      m = self.mult(other)
    else:
      m = Spmat('mult',self,other)
    return m
  def __rmul__(self, other):
    if isinstance(other,numbers.Number):
      m=Spmat('copy',self)
      m.set('scale',other)
    elif (isinstance(other,list) or isinstance(other, numpy.ndarray)):
      m=self.tmult(other)
    else:
      m=Spmat('mult',other,self)
    return m;
  

  def nnz(self):
    """Return the number of non-null values stored in the sparse matrix."""
    return self.get("nnz")


  def full(self, I=None, *args):
    """Synopsis: Sm = Spmat.full(self[, list I[, list J]])

    Return a full (sub-)matrix.
    
    The optional arguments `I` and `J`, are the sub-intervals for the
    rows and columns that are to be extracted."""
    return self.get("full", I, *args)


  def mult(self, V):
    """Product of the sparse matrix `M` with a vector `V`.
    
    For matrix-matrix multiplications, see Spmat('mult')."""
    return self.get("mult", V)


  def tmult(self, V):
    """Product of `M` transposed (conjugated if `M` is complex) with the
    vector `V`."""
    return self.get("tmult", V)


  def diag(self, E=None):
    """Return the diagonal of `M` as a vector.
    
    If `E` is used, return the sub-diagonals whose ranks are given in E."""
    return self.get("diag", E)


  def storage(self):
    """Return the storage type currently used for the matrix.
    
    The storage is returned as a string, either 'CSC' or 'WSC'."""
    return self.get("storage")


  def size(self):
    """Return a vector where `ni` and `nj` are the dimensions of the matrix."""
    return self.get("size")


  def is_complex(self):
    """Return 1 if the matrix contains complex values."""
    return self.get("is_complex")


  def csc_ind(self):
    """Return the two usual index arrays of CSC storage.
    
    If `M` is not stored as a CSC matrix, it is converted into CSC."""
    return self.get("csc_ind")


  def csc_val(self):
    """Return the array of values of all non-zero entries of `M`.
    
    If `M` is not stored as a CSC matrix, it is converted into CSC."""
    return self.get("csc_val")


  def dirichlet_nullspace(self, R):
    """Solve the dirichlet conditions `M.U=R`.
    
    A solution `U0` which has a minimum L2-norm is returned, with a
    sparse matrix `N` containing an orthogonal basis of the kernel of
    the (assembled) constraints matrix `M` (hence, the PDE linear system
    should be solved on this subspace): the initial problem
    
    `K.U = B` with constraints `M.U = R`
    
    is replaced by
    
    `(N'.K.N).UU = N'.B` with `U = N.UU + U0`"""
    return self.get("dirichlet_nullspace", R)


  def save(self, format, filename):
    """Export the sparse matrix.
    
    the format of the file may be 'hb' for Harwell-Boeing, or 'mm'
    for Matrix-Market."""
    return self.get("save", format, filename)


  def char(self):
    """Output a (unique) string representation of the Spmat.
    
    This can be used to perform comparisons between two
    different Spmat objects.
    This function is to be completed.
    """
    return self.get("char")


  def display(self):
    """displays a short summary for a Spmat object."""
    return self.get("display")


  def clear(self, I=None, *args):
    """Synopsis: Spmat.clear(self[, list I[, list J]])

    Erase the non-zero entries of the matrix.
    
    The optional arguments `I` and `J` may be specified to clear a
    sub-matrix instead of the entire matrix."""
    return self.set("clear", I, *args)


  def scale(self, v):
    """Multiplies the matrix by a scalar value `v`."""
    return self.set("scale", v)


  def transpose(self):
    """Transpose the matrix."""
    return self.set("transpose")


  def conjugate(self):
    """Conjugate each element of the matrix."""
    return self.set("conjugate")


  def transconj(self):
    """Transpose and conjugate the matrix."""
    return self.set("transconj")


  def to_csc(self):
    """Convert the matrix to CSC storage.
    
    CSC storage is recommended for matrix-vector multiplications."""
    return self.set("to_csc")


  def to_wsc(self):
    """Convert the matrix to WSC storage.
    
    Read and write operation are quite fast with WSC storage."""
    return self.set("to_wsc")


  def to_complex(self):
    """Store complex numbers."""
    return self.set("to_complex")


  def set_diag(self, D, E=None):
    """Change the diagonal (or sub-diagonals) of the matrix.
    
    If `E` is given, `D` might be a matrix and each column of `E` will
    contain the sub-diagonal number that will be filled with the
    corresponding column of `D`."""
    return self.set("diag", D, E)


  def assign(self, I, J, V):
    """Copy V into the sub-matrix 'M(I,J)'.
    
    `V` might be a sparse matrix or a full matrix."""
    return self.set("assign", I, J, V)


  def add(self, I, J, V):
    """Add `V` to the sub-matrix 'M(I,J)'.
    
    `V` might be a sparse matrix or a full matrix."""
    return self.set("add", I, J, V)

#
# asm module
#


def asm_mass_matrix(mim, mf1, mf2=None, *args):
  """Synopsis: M = asm_mass_matrix(MeshIm mim, MeshFem mf1[, MeshFem mf2[, boundary_num]])

  Assembly of a mass matrix.
  
  Return a SpMat object.
  """
  return getfem('asm', 'mass_matrix', mim, mf1, mf2, *args)


def asm_lsneuman_matrix(mim, mf1, mf2, ls):
  """Assembly of a level set Neuman  matrix.
  
  Return a SpMat object.
  """
  return getfem('asm', 'lsneuman_matrix', mim, mf1, mf2, ls)


def asm_nlsgrad_matrix(mim, mf1, mf2, ls):
  """Assembly of a nlsgrad matrix.
  
  Return a SpMat object.
  """
  return getfem('asm', 'nlsgrad_matrix', mim, mf1, mf2, ls)


def asm_stabilization_patch_matrix(mesh, mf, mim, ratio, h):
  """Assembly of stabilization patch matrix .
  
  Return a SpMat object.
  """
  return getfem('asm', 'stabilization_patch_matrix', mesh, mf, mim, ratio, h)


def asm_laplacian(mim, mf_u, mf_d, a):
  """Assembly of the matrix for the Laplacian problem.
  
  :math:`\\nabla\\cdot(a(x)\\nabla u)`  with `a` a scalar.
  
  Return a SpMat object.
  """
  return getfem('asm', 'laplacian', mim, mf_u, mf_d, a)


def asm_linear_elasticity(mim, mf_u, mf_d, lambda_d, mu_d):
  """Assembles of the matrix for the linear (isotropic) elasticity problem.
  
  :math:`\\nabla\\cdot(C(x):\\nabla u)`
  with :math:`C` defined via `lambda_d` and `mu_d`.
  
  Return a SpMat object.
  """
  return getfem('asm', 'linear_elasticity', mim, mf_u, mf_d, lambda_d, mu_d)


def asm_nonlinear_elasticity(mim, mf_u, U, law, mf_d, params, *args):
  """Synopsis: TRHS = 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[.
  
  Te parameters of the material law are described on the MeshFem `mf_d`.
  Te matrix `params` should have `nbdof(mf_d)` columns, each row
  crrespounds to a parameter.
  
  Te last argument selects what is to be built: either the tangent
  mtrix, or the right hand side. If the incompressibility is
  cnsidered, it should be followed by a MeshFem `mf_p`, for the
  pession.
  
  Rturn a SpMat object (tangent matrix), vec object (right hand
  sde), tuple of SpMat objects (incompressible tangent matrix), or
  tple of vec objects (incompressible right hand side).
  """
  return getfem('asm', 'nonlinear_elasticity', mim, mf_u, U, law, mf_d, params, *args)


def asm_stokes(mim, mf_u, mf_p, mf_d, nu):
  """Assembly of matrices for the Stokes problem.
  
  :math:`-\\nu(x)\\Delta u + \\nabla p = 0`
  :math:`\\nabla\\cdot u  = 0`
  with :math:`\\nu` (`nu`), the fluid's dynamic viscosity.
  
  On output, `K` is the usual linear elasticity stiffness matrix with
  :math:`\\lambda = 0` and
  :math:`2\\mu = \\nu`. `B` is a matrix
  corresponding to :math:`\\int p\\nabla\\cdot\\phi`.
  
  `K` and `B` are SpMat object's.
  """
  return getfem('asm', 'stokes', mim, mf_u, mf_p, mf_d, nu)


def asm_helmholtz(mim, mf_u, mf_d, k):
  """Assembly of the matrix for the Helmholtz problem.
  
  :math:`\\Delta u + k^2 u` = 0,  with `k` complex scalar.
  
  Return a SpMat object.
  """
  return getfem('asm', 'helmholtz', mim, mf_u, mf_d, k)


def asm_bilaplacian(mim, mf_u, mf_d, a):
  """Assembly of the matrix for the Bilaplacian problem.
  
  :math:`\\Delta(a(x)\\Delta u) = 0`   with `a` scalar.
  
  Return a SpMat object.
  """
  return getfem('asm', 'bilaplacian', mim, mf_u, mf_d, a)


def asm_bilaplacian_KL(mim, mf_u, mf_d, a, nu):
  """Assembly of the matrix for the Bilaplacian problem with Kirchoff-Love formulation.
  
  :math:`\\Delta(a(x)\\Delta u) = 0`   with `a` scalar.
  
  Return a SpMat object.
  """
  return getfem('asm', 'bilaplacian_KL', mim, mf_u, mf_d, a, nu)


def asm_volumic_source(mim, mf_u, mf_d, 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.
  """
  return getfem('asm', 'volumic_source', mim, mf_u, mf_d, fd)


def asm_boundary_source(bnum, mim, mf_u, mf_d, 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.
  """
  return getfem('asm', 'boundary_source', bnum, mim, mf_u, mf_d, G)


def asm_dirichlet(bnum, mim, mf_u, mf_d, H, R, threshold=None):
  """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:
  
  .. math::
  
    `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 Spmat.Dirichlet_nullspace()."""
  return getfem('asm', 'dirichlet', bnum, mim, mf_u, mf_d, H, R, threshold)


def asm_boundary_qu_term(boundary_num, mim, mf_u, mf_d, 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.
  """
  return getfem('asm', 'boundary_qu_term', boundary_num, mim, mf_u, mf_d, q)


def asm_volumic(CVLST=None, *args):
  """Synopsis: (...) = 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('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);"""
  return getfem('asm', 'volumic', CVLST, *args)


def asm_boundary(bnum, expr, mim=None, mf=None, data=None, *args):
  """Synopsis: (...) = asm_boundary(int bnum, string expr [, MeshIm mim, MeshFem mf, data...])

  Generic boundary assembly.
  
  See the help for gf_asm('volumic')."""
  return getfem('asm', 'boundary', bnum, expr, mim, mf, data, *args)


def asm_interpolation_matrix(mf, 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('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.
  """
  return getfem('asm', 'interpolation_matrix', mf, mfi)


def asm_extrapolation_matrix(mf, 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('extrapolate_on',mfe). Useful for repeated
  extrapolations.
  
  `Me` is a SpMat object.
  """
  return getfem('asm', 'extrapolation_matrix', mf, mfe)


def asm_integral_contact_Uzawa_projection(bnum, mim, mf_u, U, mf_lambda, vec_lambda, mf_obstacle, obstacle, r, *args):
  """Synopsis: B = asm_integral_contact_Uzawa_projection(int bnum, MeshIm mim, MeshFem mf_u, vec U, MeshFem mf_lambda, vec vec_lambda, MeshFem mf_obstacle, vec obstacle, scalar r [, {scalar coeff | MeshFem mf_coeff, vec coeff} [, int option[, scalar alpha, vec W]]])

  Specific assembly procedure for the use of an Uzawa algorithm to solve
    contact problems. Projects the term $-(\\lambda - r (u_N-g))_-$ on the
    finite element space of $\\lambda$.
  
  Return a vec object.
  """
  return getfem('asm', 'integral_contact_Uzawa_projection', bnum, mim, mf_u, U, mf_lambda, vec_lambda, mf_obstacle, obstacle, r, *args)


def asm_level_set_normal_source_term(bnum, mim, mf_u, mf_lambda, vec_lambda, mf_levelset, levelset):
  """Performs an assembly of the source term represented by `vec_lambda`
  on `mf_lambda` considered to be a component in the direction of the
  gradient of a levelset function (normal to the levelset) of a vector
  field defined on `mf_u` on the boundary `bnum`.
  
  Return a vec object.
  """
  return getfem('asm', 'level_set_normal_source_term', bnum, mim, mf_u, mf_lambda, vec_lambda, mf_levelset, levelset)

#
# compute module
#


def compute_L2_norm(MF, U, mim, CVids=None):
  """Compute the L2 norm of the (real or complex) field `U`.
  
  If `CVids` is given, the norm will be computed only on the listed
  convexes."""
  return getfem('compute', MF, U, 'L2_norm', mim, CVids)


def compute_L2_dist(MF, U, mim, mf2, U2, CVids=None):
  """Compute the L2 distance between `U` and `U2`.
  
  If `CVids` is given, the norm will be computed only on the listed
  convexes."""
  return getfem('compute', MF, U, 'L2_dist', mim, mf2, U2, CVids)


def compute_H1_semi_norm(MF, U, mim, CVids=None):
  """Compute the L2 norm of grad(`U`).
  
  If `CVids` is given, the norm will be computed only on the listed
  convexes."""
  return getfem('compute', MF, U, 'H1_semi_norm', mim, CVids)


def compute_H1_semi_dist(MF, U, mim, mf2, U2, CVids=None):
  """Compute the semi H1 distance between `U` and `U2`.
  
  If `CVids` is given, the norm will be computed only on the listed
  convexes."""
  return getfem('compute', MF, U, 'H1_semi_dist', mim, mf2, U2, CVids)


def compute_H1_norm(MF, U, mim, CVids=None):
  """Compute the H1 norm of `U`.
  
  If `CVids` is given, the norm will be computed only on the listed
  convexes."""
  return getfem('compute', MF, U, 'H1_norm', mim, CVids)


def compute_H2_semi_norm(MF, U, mim, CVids=None):
  """Compute the L2 norm of D^2(`U`).
  
  If `CVids` is given, the norm will be computed only on the listed
  convexes."""
  return getfem('compute', MF, U, 'H2_semi_norm', mim, CVids)


def compute_H2_norm(MF, U, mim, CVids=None):
  """Compute the H2 norm of `U`.
  
  If `CVids` is given, the norm will be computed only on the listed
  convexes."""
  return getfem('compute', MF, U, 'H2_norm', mim, CVids)


def compute_gradient(MF, U, mf_du):
  """Compute the gradient of the field `U` defined on MeshFem `mf_du`.
  
  The gradient is interpolated on the MeshFem `mf_du`, and returned in
  `DU`. For example, if `U` is defined on a P2 MeshFem, `DU` should be
  evaluated on a P1-discontinuous MeshFem. `mf` and `mf_du` should
  share the same mesh.
  
  `U` may have any number of dimensions (i.e. this function is not
  restricted to the gradient of scalar fields, but may also be used
  for tensor fields). However the last dimension of `U` has to be
  equal to the number of dof of `mf`. For example, if `U` is a
  [3x3xNmf] array (where Nmf is the number of dof of `mf`), `DU` will
  be a [Nx3x3[xQ]xNmf_du] array, where N is the dimension of the mesh,
  Nmf_du is the number of dof of `mf_du`, and the optional Q dimension
  is inserted if `Qdim_mf != Qdim_mf_du`, where Qdim_mf is the Qdim of
  `mf` and Qdim_mf_du is the Qdim of `mf_du`."""
  return getfem('compute', MF, U, 'gradient', mf_du)


def compute_hessian(MF, U, mf_h):
  """Compute the hessian of the field `U` defined on MeshFem `mf_h`.
  
  See also gf_compute('gradient', MeshFem mf_du)."""
  return getfem('compute', MF, U, 'hessian', mf_h)


def compute_eval_on_triangulated_surface(MF, U, Nrefine, CVLIST=None):
  """[OBSOLETE FUNCTION! will be removed in a future release]
  Utility function designed for 2D triangular meshes : returns a list
  of triangles coordinates with interpolated U values. This can be
  used for the accurate visualization of data defined on a
  discontinous high order element. On output, the six first rows of UP
  contains the triangle coordinates, and the others rows contain the
  interpolated values of U (one for each triangle vertex) CVLIST may
  indicate the list of convex number that should be consider, if not
  used then all the mesh convexes will be used. U should be a row
  vector.
  """
  return getfem('compute', MF, U, 'eval_on_triangulated_surface', Nrefine, CVLIST)


def compute_interpolate_on(MF, U, *args):
  """Synopsis: Ui = compute_interpolate_on(MeshFem MF, vec U, {MeshFem mfi | Slice sli | vec pts})

  Interpolate a field on another MeshFem or a Slice or a list of points.
  
  - Interpolation on another MeshFem `mfi`:
     `mfi` has to be Lagrangian. If `mf` and `mfi` share the same
     mesh object, the interpolation will be much faster.
  - Interpolation on a Slice `sli`:
     this is similar to interpolation on a refined P1-discontinuous
     mesh, but it is much faster. This can also be used with
     Slice('points') to obtain field values at a given set of
     points.
  - Interpolation on a set of points `pts`
  
  See also gf_asm('interpolation matrix')
  """
  return getfem('compute', MF, U, 'interpolate_on', *args)


def compute_extrapolate_on(MF, U, mfe):
  """Extrapolate a field on another MeshFem.
  
  If the mesh of `mfe` is stricly included in the mesh of `mf`, this
  function does stricly the same job as gf_compute('interpolate_on').
  However, if the mesh of `mfe` is not exactly included in `mf`
  (imagine interpolation between a curved refined mesh and a coarse
  mesh), then values which are outside `mf` will be
  extrapolated.
  
  See also gf_asm('extrapolation matrix')"""
  return getfem('compute', MF, U, 'extrapolate_on', mfe)


def compute_error_estimate(MF, U, mim):
  """Compute an a posteriori error estimate.
  
  Currently there is only one which is available: for each convex,
  the jump of the normal derivative is integrated on its faces."""
  return getfem('compute', MF, U, 'error_estimate', mim)


def compute_convect(MF, U, mf_v, V, dt, nt, option=None):
  """Compute a convection of `U` with regards to a steady state velocity
  field `V` with a Characteristic-Galerkin method. This
  method is restricted to pure Lagrange fems for U. `mf_v` should represent
  a continuous finite element method. `dt` is the integration time and `nt`
  is the number of integration step on the caracteristics. `option` is an
  option for the part of the boundary where there is a re-entrant convection.
  `option = 'extrapolation'` for an extrapolation on the nearest element
  or `option = 'unchanged'` for a constant value on that boundary.
  This method is rather dissipative, but stable.
  """
  return getfem('compute', MF, U, 'convect', mf_v, V, dt, nt, option)

#
# delete module
#


def delete(I, J=None, K=None, *args):
  """Synopsis: delete(I[, J, K,...])

  I should be a descriptor given by gf_mesh(),
  gf_mesh_im(), gf_slice() etc.
  
  Note that if another object uses I, then object I will be deleted only
  when both have been asked for deletion.
  
  Only objects listed in the output of gf_workspace('stats') can be
  deleted (for example gf_fem objects cannot be destroyed).
  
  You may also use gf_workspace('clear all') to erase everything at
  once.
  """
  return getfem('delete', I, J, K, *args)

#
# linsolve module
#


def linsolve_gmres(M, b, restart=None, *args):
  """Synopsis: X = linsolve_gmres(SpMat M, vec b[, int restart][, Mrecond P][,'noisy'][,'res', r][,'maxiter', n])

  Solve `M.X = b` with the generalized minimum residuals method.
  
  Optionally using `P` as preconditioner. The default value of the
  restart parameter is 50."""
  return getfem('linsolve', 'gmres', M, b, restart, *args)


def linsolve_cg(M, b, P=None, *args):
  """Synopsis: X = linsolve_cg(SpMat M, vec b [, Mrecond P][,'noisy'][,'res', r][,'maxiter', n])

  Solve `M.X = b` with the conjugated gradient method.
  
  Optionally using `P` as preconditioner."""
  return getfem('linsolve', 'cg', M, b, P, *args)


def linsolve_bicgstab(M, b, P=None, *args):
  """Synopsis: X = linsolve_bicgstab(SpMat M, vec b [, Mrecond P][,'noisy'][,'res', r][,'maxiter', n])

  Solve `M.X = b` with the bi-conjugated gradient stabilized method.
  
  Optionally using `P` as a preconditioner."""
  return getfem('linsolve', 'bicgstab', M, b, P, *args)


def linsolve_lu(M, b):
  """Alias for gf_linsolve('superlu',...)"""
  return getfem('linsolve', 'lu', M, b)


def linsolve_superlu(M, b):
  """Solve `M.U = b` apply the SuperLU solver (sparse LU factorization).
  
  The condition number estimate `cond` is returned with the solution `U`."""
  return getfem('linsolve', 'superlu', M, b)

#
# poly module
#


def poly_print(P):
  """Prints the content of P.
  """
  return getfem('poly', P, 'print')


def poly_product(P):
  """To be done ... !
  """
  return getfem('poly', P, 'product')

#
# undelete module
#


def undelete(I, J=None, K=None, *args):
  """Synopsis: undelete(I[, J, K,...])

  I should be a descriptor given by gf_mesh(), gf_mesh_im(),
  gf_slice() etc.
  """
  return getfem('undelete', I, J, K, *args)

#
# util module
#


def util_save_matrix(FMT, FILENAME, A):
  """Exports a sparse matrix into the file named FILENAME, using
  Harwell-Boeing (FMT='hb') or Matrix-Market (FMT='mm') formatting. """
  return getfem('util', 'save_matrix', FMT, FILENAME, A)


def util_load_matrix(FMT, FILENAME):
  """Imports a sparse matrix from a file."""
  return getfem('util', 'load_matrix', FMT, FILENAME)


def util_trace_level(level=None):
  """Set the verbosity of some getfem++ routines.
  
  Typically the messages printed by the model bricks, 0 means no
  trace message (default is 3). if no level is given,
  the current trace level is returned. """
  return getfem('util', 'trace_level', level)


def util_warning_level(level):
  """Filter the less important warnings displayed by getfem.
  
  0 means no warnings, default level is 3. if no level is given,
  the current warning level is returned. """
  return getfem('util', 'warning_level', level)


def memstats():
  print "*** Getfem view of the workspace:"
  getfem('workspace','stats')
  print "*** Python view of the workspace:"
  for id,c in obj_count.iteritems():
    if (c):
      name=str(factory(id).__class__)
      print "%s class %d, id %d : instances=%d" % (name,id.classid,id.objid,c)

def linsolve(what, *args):
  return getfem('linsolve', what, *args)
def compute(mf, U, what, *args):
  return getfem('compute', mf, U, what, *args)
def asm(what, *args):
  return getfem('asm', what, *args)
def util(what, *args):
  return getfem('util', what, *args)


def factory(id):
  t = ( ContStruct,
        CvStruct,
        Eltm,
        Fem,
        GeoTrans,
        GlobalFunction,
        Integ,
        LevelSet,
        MdBrick,
        MdState,
        Mesh,
        MeshFem,
        MeshIm,
        MeshLevelSet,
        MesherObject,
        Model,
        Precond,
        Slice,
        Spmat)[id.classid]
  return t(id)

register_python_factory(factory)
