#!/usr/bin/env python
# -*- coding: iso-8859-1 -*-
#
# Python GetFEM interface
#
# Copyright (C) 2004-2022 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

getfem_python_par=False


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

from numpy import *

try:
  from ._getfem import *
except ImportError:
  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:
        # getfem("undelete",self.id)
    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 (self.id in obj_count):
      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 of solution branches of models (for more details about
  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 parameterization is done via a vector datum, `dataname_init`
    and `dataname_final` should store two given values of this datum
    determining the parameterization, and `dataname_current` serves for actual
    values of this datum. `sc_fac` is a scale factor involved in the weighted
    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';
    - 'h_init', scalar HIN
       initial step size (the default value is 1e-2);
    - 'h_max', scalar HMAX
       maximum step size (the default value is 1e-1);
    - 'h_min', scalar HMIN
       minimum 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);
    - 'max_iter', int MIT
       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 4);
    - 'max_res', scalar RES
       target residual value of a new point on the solution curve (the
       default value is 1e-6);
    - 'max_diff', scalar DIFF
       determines a convergence criterion for two consecutive points (the
       default value is 1e-6);
    - 'min_cos', scalar MCOS
       minimal value of the cosine of the angle between tangents to the
       solution curve at an old point and a new one (the default value is
       0.9);
    - 'max_res_solve', scalar RES_SOLVE
       target residual value for the linear systems to be solved (the
       default value is 1e-8);
    - 'singularities', int SING
       activates tools for detection and treatment of singular points (1 for
       limit points, 2 for bifurcation points and points requiring special
       branching techniques);
    - 'non-smooth'
       determines that some special methods for non-smooth problems can be
       used;
    - 'delta_max', scalar DMAX
       maximum size of division for evaluating the test function on the
       convex combination of two augmented Jacobians that belong to different
       smooth pieces (the default value is 0.005);
    - 'delta_min', scalar DMIN
       minimum size of division for evaluating the test function on the
       convex combination (the default value is 0.00012);
    - 'thr_var', scalar TVAR
       threshold variation for refining the division (the default value is
       0.02);
    - 'nb_dir', int NDIR
       total number of the linear combinations of one couple of reference
       vectors when searching for new tangent predictions during location of
       new one-sided branches (the default value is 40);
    - 'nb_span', int NSPAN
       total number of the couples of the reference vectors forming the
       linear combinations (the default value is 1);
    - 'noisy' or 'very_noisy'
       determines how detailed information has to be displayed during the
       continuation 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_step_size(self):
    """Return an initial step size for continuation."""
    return self.get("init_step_size")


  def min_step_size(self):
    """Return the minimum step size for continuation."""
    return self.get("min_step_size")


  def max_step_size(self):
    """Return the maximum step size for continuation."""
    return self.get("max_step_size")


  def step_size_decrement(self):
    """Return the decrement ratio of the step size for continuation."""
    return self.get("step_size_decrement")


  def step_size_increment(self):
    """Return the increment ratio of the step size for continuation."""
    return self.get("step_size_increment")


  def compute_tangent(self, solution, parameter, tangent_sol, tangent_par):
    """Compute and return an updated tangent."""
    return self.get("compute_tangent", solution, parameter, tangent_sol, tangent_par)


  def init_Moore_Penrose_continuation(self, solution, parameter, init_dir):
    """Initialise the Moore-Penrose continuation: Return a unit tangent to
    the solution curve at the point given by `solution` and `parameter`,
    and an initial step size for the continuation. Orientation of the
    computed tangent with respect to the parameter is determined by the
    sign of `init_dir`."""
    return self.get("init_Moore_Penrose_continuation", solution, parameter, init_dir)


  def Moore_Penrose_continuation(self, solution, parameter, tangent_sol, tangent_par, h):
    """Compute one step of the Moore-Penrose continuation: Take the point
    given by `solution` and `parameter`, the tangent given by `tangent_sol`
    and `tangent_par`, and the step size `h`. Return a new point on the
    solution curve, the corresponding tangent, a step size for the next
    step and optionally the current step size. If the returned step
    size equals zero, the continuation has failed. Optionally, return
    the type of any detected singular point.
    NOTE: The new point need not to be saved in the model in the end!"""
    return self.get("Moore_Penrose_continuation", solution, parameter, tangent_sol, tangent_par, h)


  def non_smooth_bifurcation_test(self, solution1, parameter1, tangent_sol1, tangent_par1, solution2, parameter2, tangent_sol2, tangent_par2):
    """Test for a non-smooth bifurcation point between the point given by
    `solution1` and `parameter1` with the tangent given by `tangent_sol1`
    and `tangent_par1` and the point given by `solution2` and `parameter2`
    with the tangent given by `tangent_sol2` and `tangent_par2`."""
    return self.get("non_smooth_bifurcation_test", solution1, parameter1, tangent_sol1, tangent_par1, solution2, parameter2, tangent_sol2, tangent_par2)


  def bifurcation_test_function(self):
    """Return the last value of the bifurcation test function and eventually
    the whole calculated graph when passing between different sub-domains
    of differentiability."""
    return self.get("bifurcation_test_function")


  def sing_data(self):
    """Return a singular point (`X`, `gamma`) stored in the ContStruct object and a
    couple of arrays (`T_X`, `T_gamma`) of tangents to all located solution
    branches that emanate from there."""
    return self.get("sing_data")


  def char(self):
    """Output a (unique) string representation of the ContStruct.
    
    This can be used for performing 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_source, MeshIm mim_target, [ivec blocked_dofs[, bool caching]])``
    Build a special Fem which is interpolated from another MeshFem.
    
    Using this special finite element, it is possible to interpolate a given
    MeshFem `mf_source` on another mesh, given the integration method `mim_target`
    that will be used on this mesh.
    
    Note that this finite element may be quite slow or consume much
    memory depending if caching is used or not. By default `caching` is
    True

  * ``F = Fem('projected_fem', MeshFem mf_source, MeshIm mim_target, int rg_source, int rg_target[, ivec blocked_dofs[, bool caching]])``
    Build a special Fem which is interpolated from another MeshFem.
    
    Using this special finite element, it is possible to interpolate a given
    MeshFem `mf_source` on another mesh, given the integration method `mim_target`
    that will be used on this mesh.
    
    Note that this finite element may be quite slow or consume much
    memory depending if caching is used or not. By default `caching` is
    True

  * ``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(n) :
      incomplete Q2 elements with 8 and 20 dof (serendipity Quad 8 and
      Hexa 20 elements).
    - 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 index_of_global_dof(self, cv):
    """Return the index of global dof for special fems such as interpolated fem.
    """
    return self.get("index_of_global_dof", 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`.
    This function could be improved by using the derivation of the generic
    assembly language ... to be done. 

  * ``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 (with the syntax of the high
    generic assembly language). 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` function.
    
    If `nls` is 0, the method return the vector of dof for the primary
    level-set function. 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 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('pyramidal', vec X[, vec Y[, vec Z,..]])``
    Build quickly a regular mesh of pyramids, 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-dimensional parallelepiped 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[, int degree])``
    Extrude a prismatic Mesh `M` from a Mesh `m`.
    
    In the additional dimension there are `nl` layers of elements
    distributed from ``0`` to ``1``.
    If the optional parameter `degree` is provided with a value greater
    than the default value of ``1``, a non-linear transformation of
    corresponding degree is considered in the extrusion direction.

  * ``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`
    - 'gmsh_with_lower_dim_elt' for a mesh created with `Gmsh` and including elements of lower dimension than the mesh
    - 'gid' for a mesh created with `GiD`
    - 'cdb' for a mesh created with `ANSYS`
    - '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 experimental mesher of Getfem on the geometry
    represented by `mo`. please control the conformity of the produced mesh.
    You can help 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 can be run again since 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
    deactivated using `gf_util('trace level', 2)`. More information
    can be obtained by `gf_util('trace level', 4)`. See ``MesherObject``
    to manipulate geometric primitives in order to describe the geometry.
    

    """
    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):
    """Return 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):
    """Return 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):
    """Return 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):
    """Return 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`.
    
    Return `Pts` and `IDx`.
    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]
    
    Return E and C.
    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):
    """Return point #id which are not linked to a convex."""
    return self.get("orphaned_pid")


  def cvid_from_pid(self, PIDs, share=False):
    """Return 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, dim=None, *args):
    """Synopsis: CVFIDs = Mesh.outer_faces(self[, dim][, CVIDs])

    Return the set of faces not shared by two elements.
    
    The output `CVFIDs` is a two-rows matrix, the first row lists
    convex #ids, and the second one lists face numbers (local number
    in the convex). If `dim` is provided, the function is forced to
    detect faces of elements that have dimension `dim`, e.g. `dim`=2 will
    detect edges of surface elements, even if these belong to a 3D mesh.
    If `CVIDs` is not given, all convexes are considered, and the
    function 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", dim, *args)


  def inner_faces(self, CVIDs=None):
    """Return the set of faces shared at least by two elements in CVIDs.
    Each face is represented only once and is arbitrarily chosen
    between the two neighbor elements. """
    return self.get("inner_faces", CVIDs)


  def all_faces(self, CVIDs=None):
    """Return the set of faces of the in CVIDs (in all the mesh if CVIDs is
    omitted). Note that the face shared by two neighbor elements will be
    represented twice. """
    return self.get("all_faces", CVIDs)


  def outer_faces_with_direction(self, v, angle, dim=None, *args):
    """Synopsis: CVFIDs = Mesh.outer_faces_with_direction(self, vec v, scalar angle[, dim][, CVIDs])

    Return the set of faces not shared by two convexes and with a mean outward vector lying within an angle `angle` (in radians) from vector `v`.
    
    The output `CVFIDs` is a two-rows matrix, the first row lists convex
    #ids, and the second one lists face numbers (local number in the
    convex). The argument `dim` works as in outer_faces().
    If `CVIDs` is given, it returns portion of the boundary of
    the convex set defined by the #ids listed in `CVIDs`."""
    return self.get("outer_faces_with_direction", v, angle, dim, *args)


  def outer_faces_in_box(self, pmin, pmax, dim=None, *args):
    """Synopsis: CVFIDs = Mesh.outer_faces_in_box(self, vec pmin, vec pmax[, dim][, CVIDs])

    Return the set of faces not shared by two convexes and lying within the box defined by the corner points `pmin` and `pmax`.
    
    The output `CVFIDs` is a two-rows matrix, the first row lists convex
    #ids, and the second one lists face numbers (local number in the
    convex). The argument `dim` works as in outer_faces().
    If `CVIDs` is given, it returns portion of the boundary of
    the convex set defined by the #ids listed in `CVIDs`."""
    return self.get("outer_faces_in_box", pmin, pmax, dim, *args)


  def outer_faces_in_ball(self, center, radius, dim=None, *args):
    """Synopsis: CVFIDs = Mesh.outer_faces_in_ball(self, vec center, scalar radius[, dim][, CVIDs])

    Return the set of faces not shared by two convexes and lying within the ball of corresponding `center` and `radius`.
    
    The output `CVFIDs` is a two-rows matrix, the first row lists convex
    #ids, and the second one lists face numbers (local number in the
    convex). The argument `dim` works as in outer_faces().
    If `CVIDs` is given, it returns portion of the boundary of
    the convex set defined by the #ids listed in `CVIDs`."""
    return self.get("outer_faces_in_ball", center, radius, dim, *args)


  def adjacent_face(self, cvid, fid):
    """Return convex face of the neighbor element if it exists.
    If the convex have more than one neighbor
    relatively to the face ``f`` (think to bar elements in 3D for instance),
    return the first face found. """
    return self.get("adjacent_face", cvid, fid)


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

    Return a list of convex 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):
    """Return the normal vector 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):
    """Return matrix of (at face centers) the normal vectors 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 convexes_in_box(self, pmin, pmax):
    """Return the set of convexes lying entirely within the box defined by the corner points `pmin` and `pmax`.
    
    The output `CVIDs` is a two-rows matrix, the first row lists convex
    #ids, and the second one lists face numbers (local number in the
    convex). If `CVIDs` is given, it returns portion of the boundary of
    the convex set defined by the #ids listed in `CVIDs`."""
    return self.get("convexes_in_box", pmin, pmax)


  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_vtu(self, filename, *args):
    """Synopsis: Mesh.export_to_vtu(self, string filename, ... [,'ascii'][,'quality'])

    Exports a mesh to a VTK(XML) file .
    
    If 'quality' is specified, an estimation of the quality of each
    convex will be written to the file.
    
    See also MeshFem.export_to_vtu(), Slice.export_to_vtu()."""
    return self.get("export_to_vtu", 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 set of convexes or/and convex
    faces provided in the matrix `CVFIDs`.
    
    The first row of `CVFIDs` contains 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 extend_region(self, rnum, CVFIDs):
    """Extends the region identified by the region number `rnum` to include
    the set of convexes or/and convex faces provided in the matrix
    `CVFIDs`, see also ``Mesh.(set region)``."""
    return self.set("extend_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_subtract(self, r1, r2):
    """Replace the region number `r1` with its difference with region
    number `r2`."""
    return self.set("region_subtract", 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, tol=None):
    """Merge with the Mesh `m2`.
    
    Overlapping points, within a tolerance radius `tol`, will not be
    duplicated. If `m2` is a MeshFem object, its linked mesh will be used."""
    return self.set("merge", m2, tol)


  def optimize_structure(self, with_renumbering=None):
    """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", with_renumbering)


  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(Mesh m[, int Qdim1=1[, int Qdim2=1, ...]])``
    Build a new MeshFem object.
    
    The `Qdim` parameters specifies the dimension of the field represented
    by the finite element method. Qdim1 = 1 for a scalar field,
    Qdim1 = n for a vector field off size n, Qdim1=m, Qdim2=n for
    a matrix field of size mxn ...
    Returns the handle of the created object. 

  * ``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 spans two (or more) MeshFem's.
    
    All MeshFem must share the same mesh.
    
    After that, you should not modify the FEM of `mf1`, `mf2` etc.

  * ``MF = MeshFem('product', MeshFem mf1, MeshFem mf2)``
    Create a MeshFem that spans all the product of a selection of shape
    functions of `mf1` by all shape functions of `mf2`.
    Designed for Xfem enrichment.
    
    `mf1` and `mf2` must share the same mesh.
    
    After that, you should not modify the FEM of `mf1`, `mf2`.

  * ``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`.

    """
    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 an 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 reduce_vector(self, V):
    """Multiply the provided vector V with the extension matrix of the MeshFem."""
    return self.get("reduce_vector", V)


  def extend_vector(self, V):
    """Multiply the provided vector V with the reduction matrix of the MeshFem."""
    return self.get("extend_vector", V)


  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 correspondence 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 neighboring 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 optionally 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_vtu(self, filename, *args):
    """Synopsis: MeshFem.export_to_vtu(self,string filename, ... ['ascii'], U, 'name'...)

    Export a MeshFem and some fields to a vtu file.
    
    The FEM and geometric transformations will be mapped to order 1
    or 2 isoparametric Pk (or Qk) FEMs (as VTK(XML) 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_vtu()."""
    return self.get("export_to_vtu", 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
    an 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 (getfem_python_par):
      rk = mpi.COMM_WORLD.rank
      nbp = mpi.COMM_WORLD.size
    else:
      rk = 0
      nbp = 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())
      P   = P[:,Ind]
      nbd = P.shape[1]
    vars = ('x','y','z','u','v','w')
    nbvars = min(P.shape[0],len(vars))
    for i in range(0,nbvars):
      gl[vars[i]] = P[i,0]
      lo[vars[i]] = P[i,0]
    ccode = compile(expression, '<string>', 'eval');
    r = numpy.array(eval(ccode,gl,lo))
    Z = numpy.zeros(r.shape + (nbd,), r.dtype)
    nbd_p = int(nbd/nbp)
    nbd_end = nbd_p*(rk+1)
    if (rk == nbp-1):
      nbd_end = nbd
    for j in range(nbd_p*rk,nbd_end):
      for i in range(0,nbvars):
        gl[vars[i]] = P[i,j]
        lo[vars[i]] = P[i,j]
      Z[...,j] = eval(ccode,gl,lo)
    if (nbp > 1):
      W = numpy.zeros(r.shape + (nbd,), r.dtype)
      mpi.COMM_WORLD.Allreduce(Z, W, op=mpi.SUM)
      Z = W
    return Z
  

  def set_fem(self, f, CVids=None):
    """Set the Finite Element Method.
    
    Assign an 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, *args):
    """Synopsis: MeshFem.set_classical_fem(self, int k[[, 'complete'], ivec CVids])

    Assign a classical (Lagrange polynomial) fem of order `k` to the MeshFem.
    The option 'complete' requests complete Langrange polynomial elements,
    even if the element geometric transformation is an incomplete one
    (e.g. 8-node quadrilateral or 20-node hexahedral).
    
    Uses FEM_PK for simplexes, FEM_QK for parallelepipeds etc."""
    return self.set("classical_fem", k, *args)


  def set_classical_discontinuous_fem(self, k, *args):
    """Synopsis: MeshFem.set_classical_discontinuous_fem(self, int k[[, 'complete'], @tscalar alpha[, ivec CVIDX]])

    Assigns a classical (Lagrange polynomial) discontinuous fem of order k.
    
    Similar to MeshFem.set_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.
    The option 'complete' requests complete Langrange polynomial elements,
    even if the element geometric transformation is an incomplete one
    (e.g. 8-node quadrilateral or 20-node hexahedral)."""
    return self.set("classical_discontinuous_fem", k, *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 freedom 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)


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


  def set_enriched_dofs(self, DOFs):
    """For a MeshFem product object only. Set te enriched dofs and adapt the MeshFem product.
    """
    return self.set("set_enriched_dofs", DOFs)


#
# GetFEM class MeshIm definition.
#

class MeshIm:
  """GetFEM MeshIm object

  This object represents an integration method defined on a whole mesh (an 
  potentially 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
    implicitly 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'.
    
    it can be completed by a string defining the boolean operation
    to define the integration domain when there is more than one levelset.
    
    the syntax is very simple, for example if there are 3 different
    levelset,
     
     "a*b*c" is the intersection of the domains defined by each
     levelset (this is the default behaviour if this function is not
     called).
    
     "a+b+c" is the union of their domains.
    
     "c-(a+b)" is the domain of the third levelset minus the union of
     the domains of the two others.
     
     "!a" is the complementary of the domain of a (i.e. it is the
     domain where a(x)>0)
    
     The first levelset is always referred to with "a", the second
     with "b", and so on.
    
    for intance INSIDE(a*b*c)
    
    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 do not have
    their corresponding 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 optionally 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 MeshImData definition.
#

class MeshImData:
  """GetFEM MeshImData object

  This object represents data defined on a mesh_im object.

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

  * ``MIMD = MeshImData(MeshIm mim, int region, ivec size)``
    Build a new MeshImd object linked to a MeshIm object. If `region` is
    provided, considered integration points are filtered in this region.
    `size` is a vector of integers that specifies the dimensions of the
    stored data per integration point. If not given, the scalar stored
    data are considered.
    

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

  def region(self):
    """Output the region that the MeshImd is restricted to.
    """
    return self.get("region")


  def nbpts(self):
    """Output the number of integration points (filtered in the considered region).
    """
    return self.get("nbpts")


  def nb_tensor_elements(self):
    """Output the size of the stored data (per integration point).
    """
    return self.get("nb_tensor_elements")


  def tensor_size(self):
    """Output the dimensions of the stored data (per integration point).
    """
    return self.get("tensor_size")


  def display(self):
    """displays a short summary for a MeshImd 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 set_region(self, rnum):
    """Set the considered region to `rnum`.
    """
    return self.set("region", rnum)


  def set_tensor_size(self):
    """Set the size of the data per integration point.
    """
    return self.set("tensor_size")


#
# 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
  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.

  """
  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 get_time_step(self):
    """Gives the value of the time step."""
    return self.get("get_time_step")


  def get_time(self):
    """Give the value of the data `t` corresponding to the current time.
    """
    return self.get("get_time")


  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 variable_list(self):
    """print to the output the list of variables and constants of the model."""
    return self.get("variable_list")


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


  def list_residuals(self):
    """print to the output the residuals corresponding to all terms
    included in the model."""
    return self.get("list_residuals")


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


  def interpolation(self, expr, *args):
    """Synopsis: V = Model.interpolation(self, string expr, {MeshFem mf | MeshImd mimd | vec pts,  Mesh m}[, int region[, int extrapolation[, int rg_source]]])

    Interpolate a certain expression with respect to the mesh_fem `mf`
    or the mesh_im_data `mimd` or the set of points `pts` on mesh `m`.
    The expression has to be valid according to the high-level generic
    assembly language possibly including references to the variables
    and data of the model.
    
    The options `extrapolation` and `rg_source` are specific to
    interpolations with respect to a set of points `pts`. """
    return self.get("interpolation", expr, *args)


  def local_projection(self, mim, expr, mf, region=None):
    """Make an elementwise L2 projection of an expression with respect
    to the mesh_fem `mf`. This mesh_fem has to be
    a discontinuous one.
    The expression has to be valid according to the high-level generic
    assembly language possibly including references to the variables
    and data of the model. """
    return self.get("local_projection", mim, expr, mf, region)


  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', 'build_rhs_with_internal',
    'build_matrix_condensed', 'build_all_condensed'.
    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'.
    
      Return the number of iterations, if an 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 then 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, 0 is an acceptable value) around
    the current position.
    Each dof of the random position is chosen in the range
    [current-scale, current+scale].
    """
    return self.get("test_tangent_matrix", EPS, *args)


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

    Test the consistency of a part of the tangent matrix in some
    random positions and random directions
    (useful to test newly created bricks).
    The increment is only made on variable `varname2` and tested on the
    part of the residual corresponding to `varname1`. This means that
    only the term (`varname1`, `varname2`) of the tangent matrix is tested.
    `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, 0 is an acceptable value)
    around the current position.
    Each dof of the random position is chosen in the range
    [current-scale, current+scale].
    """
    return self.get("test_tangent_matrix_term", varname1, varname2, EPS, *args)


  def Neumann_term(self, varname, region):
    """Gives the assembly string corresponding to the Neumann term of
    the fem variable `varname` on `region`. It is deduced from the
    assembly string declared by the model bricks.
    `region` should be the index of a boundary region
    on the mesh where `varname` is defined. Care to call this function
    only after all the volumic bricks have been declared.
    Complains, if a brick
    omit to declare an assembly string. """
    return self.get("Neumann_term", varname, region)


  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).
    Parametrized by Lame coefficients.
    """
    return self.get("compute_isotropic_linearized_Von_Mises_or_Tresca", varname, dataname_lambda, dataname_mu, mf_vm, version)


  def compute_isotropic_linearized_Von_Mises_pstrain(self, varname, data_E, data_nu, mf_vm):
    """Compute the Von-Mises stress  of a displacement field for isotropic
    linearized elasticity in 3D or in 2D with plane strain assumption.
    Parametrized by Young modulus and Poisson ratio.
    """
    return self.get("compute_isotropic_linearized_Von_Mises_pstrain", varname, data_E, data_nu, mf_vm)


  def compute_isotropic_linearized_Von_Mises_pstress(self, varname, data_E, data_nu, mf_vm):
    """Compute the Von-Mises stress  of a displacement field for isotropic
    linearized elasticity in 3D or in 2D with plane stress assumption.
    Parametrized by Young modulus and Poisson ratio.
    """
    return self.get("compute_isotropic_linearized_Von_Mises_pstress", varname, data_E, data_nu, mf_vm)


  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', 'neo Hookean' 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_finite_strain_elasticity_Von_Mises(self, lawname, varname, params, mf_vm, region=None):
    """Compute on `mf_vm` the Von-Mises stress of a field `varname`
    for nonlinear elasticity in 3D. `lawname` is the constitutive law which
    should be a valid name. `params` are the parameters law. It could be
    a short vector of constant values or may depend on data or variables
    of the model.
    Uses the high-level generic assembly.
    """
    return self.get("compute_finite_strain_elasticity_Von_Mises", lawname, varname, params, mf_vm, region)


  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', 'neo Hookean' 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 elastoplasticity_next_iter(self, mim, varname, previous_dep_name, projname, datalambda, datamu, datathreshold, datasigma):
    """Used with the old (obsolete) elastoplasticity brick to pass from an
    iteration to the next one.
    Compute and save the stress constraints sigma for the next iterations.
    'mim' is the integration method to use for the computation.
    'varname' is the main variable of the problem.
    'previous_dep_name' represents the displacement at the previous time step.
    '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 contain the new stress constraints values."""
    return self.get("elastoplasticity_next_iter", mim, varname, previous_dep_name, projname, datalambda, datamu, datathreshold, datasigma)


  def small_strain_elastoplasticity_next_iter(self, mim, lawname, unknowns_type, varnames=None, *args):
    """Synopsis: Model.small_strain_elastoplasticity_next_iter(self, MeshIm mim,  string lawname, string unknowns_type [, string varnames, ...] [, string params, ...] [, string theta = '1' [, string dt = 'timestep']] [, int region = -1])

    Function that allows to pass from a time step to another for the
    small strain plastic brick. The parameters have to be exactly the
    same than the one of `add_small_strain_elastoplasticity_brick`,
    so see the documentation of this function for the explanations.
    Basically, this brick computes the plastic strain
    and the plastic multiplier and stores them for the next step.
    Additionaly, it copies the computed displacement to the data
    that stores the displacement of the previous time step (typically
    'u' to 'Previous_u'). It has to be called before any use of
    `compute_small_strain_elastoplasticity_Von_Mises`.
    """
    return self.get("small_strain_elastoplasticity_next_iter", mim, lawname, unknowns_type, varnames, *args)


  def small_strain_elastoplasticity_Von_Mises(self, mim, mf_vm, lawname, unknowns_type, varnames=None, *args):
    """Synopsis: V = Model.small_strain_elastoplasticity_Von_Mises(self, MeshIm mim, MeshFem mf_vm, string lawname, string unknowns_type [, string varnames, ...] [, string params, ...] [, string theta = '1' [, string dt = 'timestep']] [, int region])

    This function computes the Von Mises stress field with respect to
    a small strain elastoplasticity term, approximated on `mf_vm`,
    and stores the result into `VM`.  All other parameters have to be
    exactly the same as for `add_small_strain_elastoplasticity_brick`.
    Remember that `small_strain_elastoplasticity_next_iter` has to be called
    before any call of this function.
    """
    return self.get("small_strain_elastoplasticity_Von_Mises", mim, mf_vm, lawname, unknowns_type, varnames, *args)


  def compute_elastoplasticity_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_elastoplasticity_Von_Mises_or_Tresca", datasigma, mf_vm, version)


  def compute_plastic_part(self, mim, mf_pl, varname, previous_dep_name, 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, previous_dep_name, projname, datalambda, datamu, datathreshold, datasigma)


  def finite_strain_elastoplasticity_next_iter(self, mim, lawname, unknowns_type, varnames=None, *args):
    """Synopsis: Model.finite_strain_elastoplasticity_next_iter(self, MeshIm mim, string lawname, string unknowns_type, [, string varnames, ...] [, string params, ...] [, int region = -1])

    Function that allows to pass from a time step to another for the
    finite strain plastic brick. The parameters have to be exactly the
    same than the one of `add_finite_strain_elastoplasticity_brick`,
    so see the documentation of this function for the explanations.
    Basically, this brick computes the plastic strain
    and the plastic multiplier and stores them for the next step.
    For the Simo-Miehe law which is currently the only one implemented,
    this function updates the state variables defined in the last two
    entries of `varnames`, and resets the plastic multiplier field given
    as the second entry of `varnames`.
    """
    return self.get("finite_strain_elastoplasticity_next_iter", mim, lawname, unknowns_type, varnames, *args)


  def compute_finite_strain_elastoplasticity_Von_Mises(self, mim, mf_vm, lawname, unknowns_type, varnames=None, *args):
    """Synopsis: V = Model.compute_finite_strain_elastoplasticity_Von_Mises(self, MeshIm mim, MeshFem mf_vm, string lawname, string unknowns_type, [, string varnames, ...] [, string params, ...] [, int region = -1])

    Compute on `mf_vm` the Von-Mises or the Tresca stress of a field for plasticity and return it into the vector V.
    The first input parameters ar as in the function 'finite strain elastoplasticity next iter'.
    """
    return self.get("compute_finite_strain_elastoplasticity_Von_Mises", mim, mf_vm, lawname, unknowns_type, varnames, *args)


  def sliding_data_group_name_of_large_sliding_contact_brick(self, indbrick):
    """Gives the name of the group of variables corresponding to the
    sliding data for an existing large sliding contact brick."""
    return self.get("sliding_data_group_name_of_large_sliding_contact_brick", indbrick)


  def displacement_group_name_of_large_sliding_contact_brick(self, indbrick):
    """Gives the name of the group of variables corresponding to the
    sliding data for an existing large sliding contact brick."""
    return self.get("displacement_group_name_of_large_sliding_contact_brick", indbrick)


  def transformation_name_of_large_sliding_contact_brick(self, indbrick):
    """Gives the name of the group of variables corresponding to the
    sliding data for an existing large sliding contact brick."""
    return self.get("transformation_name_of_large_sliding_contact_brick", indbrick)


  def sliding_data_group_name_of_Nitsche_large_sliding_contact_brick(self, indbrick):
    """Gives the name of the group of variables corresponding to the
    sliding data for an existing large sliding contact brick."""
    return self.get("sliding_data_group_name_of_Nitsche_large_sliding_contact_brick", indbrick)


  def displacement_group_name_of_Nitsche_large_sliding_contact_brick(self, indbrick):
    """Gives the name of the group of variables corresponding to the
    sliding data for an existing large sliding contact brick."""
    return self.get("displacement_group_name_of_Nitsche_large_sliding_contact_brick", indbrick)


  def transformation_name_of_Nitsche_large_sliding_contact_brick(self, indbrick):
    """Gives the name of the group of variables corresponding to the
    sliding data for an existing large sliding contact brick."""
    return self.get("transformation_name_of_Nitsche_large_sliding_contact_brick", indbrick)


  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):
    """Add a variable to the model linked to a MeshFem. `name` is the variable
    name. """
    return self.set("add_fem_variable", name, mf)


  def add_filtered_fem_variable(self, name, mf, region):
    """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. """
    return self.set("add_filtered_fem_variable", name, mf, region)


  def add_im_variable(self, name, mimd):
    """Add a variable to the model linked to a MeshImd. `name` is the variable
    name. """
    return self.set("add_im_variable", name, mimd)


  def add_internal_im_variable(self, name, mimd):
    """Add a variable to the model, which is linked to a MeshImd and will be
    condensed out during the assemblage of the tangent matrix. `name` is
    the variable name. """
    return self.set("add_internal_im_variable", name, mimd)


  def add_variable(self, name, sizes):
    """Add a variable to the model of constant sizes. `sizes` is either a
    integer (for a scalar or vector variable) or a vector of dimensions
    for a tensor variable. `name` is the variable name. """
    return self.set("add_variable", name, sizes)


  def delete_variable(self, name):
    """Delete a variable or a data from the model."""
    return self.set("delete_variable", name)


  def resize_variable(self, name, sizes):
    """Resize a  constant size variable of the model.  `sizes` is either a
    integer (for a scalar or vector variable) or a vector of dimensions
    for a tensor variable. `name` is the variable name. """
    return self.set("resize_variable", name, sizes)


  def add_multiplier(self, name, mf, primalname, mim=None, region=None):
    """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 independent constraints on the primal variable.
    Optimized for boundary multipliers. """
    return self.set("add_multiplier", name, mf, primalname, mim, region)


  def add_im_data(self, name, mimd):
    """Add a data set to the model linked to a MeshImd. `name` is the data
    name. """
    return self.set("add_im_data", name, mimd)


  def add_fem_data(self, name, mf, sizes=None):
    """Add a data to the model linked to a MeshFem. `name` is the data name,
    `sizes` an optional parameter which is either an 
    integer  or a vector of suplementary dimensions with respect to `mf`. """
    return self.set("add_fem_data", name, mf, sizes)


  def add_initialized_fem_data(self, name, mf, V, sizes=None):
    """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. `sizes` an optional parameter which is either an 
    integer or a vector of suplementary dimensions with respect to `mf`."""
    return self.set("add_initialized_fem_data", name, mf, V, sizes)


  def add_data(self, name, size):
    """Add a fixed size data to the model.  `sizes` is either a
    integer (for a scalar or vector data) or a vector of dimensions
    for a tensor data. `name` is the data name. """
    return self.set("add_data", name, size)


  def add_macro(self, name, expr):
    """Define a new macro for the high generic assembly language.
    The name include the parameters. For instance name='sp(a,b)', expr='a.b'
    is a valid definition. Macro without parameter can also be defined.
    For instance name='x1', expr='X[1]' is valid. The form name='grad(u)',
    expr='Grad_u' is also allowed but in that case, the parameter 'u' will
    only be allowed to be a variable name when using the macro. Note that
    macros can be directly defined inside the assembly strings with the
    keyword 'Def'.
    """
    return self.set("add_macro", name, expr)


  def del_macro(self, name):
    """Delete a previously defined macro for the high generic assembly language.
    """
    return self.set("del_macro", name)


  def add_initialized_data(self, name, V, sizes=None):
    """Add an initialized fixed size data to the model. `sizes` an
    optional parameter which is either an 
    integer  or a vector dimensions that describes the format of the
    data. By default, the data is considered to b a vector field.
    `name` is the data name and `V` is the value of the data."""
    return self.set("add_initialized_data", name, V, sizes)


  def set_variable(self, name, V):
    """Set the value of a variable or data. `name` is the data name."""
    return self.set("variable", name, V)


  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 delete_brick(self, ind_brick):
    """Delete a variable or a data from the model."""
    return self.set("delete_brick", ind_brick)


  def define_variable_group(self, name, varname=None, *args):
    """Synopsis: Model.define_variable_group(self, string name[, string varname, ...])

    Defines a group of variables for the interpolation (mainly for the
    raytracing interpolation transformation."""
    return self.set("define_variable_group", name, varname, *args)


  def add_elementary_rotated_RT0_projection(self, transname):
    """Add the elementary transformation corresponding to the projection
    on rotated RT0 element for two-dimensional elements to the model.
    The name is the name given to the elementary transformation. """
    return self.set("add_elementary_rotated_RT0_projection", transname)


  def add_elementary_P0_projection(self, transname):
    """Add the elementary transformation corresponding to the projection
    P0 element.
    The name is the name given to the elementary transformation. """
    return self.set("add_elementary_P0_projection", transname)


  def add_HHO_reconstructed_gradient(self, transname):
    """Add to the model the elementary transformation corresponding to the
    reconstruction of a gradient for HHO methods.
    The name is the name given to the elementary transformation. """
    return self.set("add_HHO_reconstructed_gradient", transname)


  def add_HHO_reconstructed_symmetrized_gradient(self, transname):
    """Add to the model the elementary transformation corresponding to the
    reconstruction of a symmetrized gradient for HHO methods.
    The name is the name given to the elementary transformation. """
    return self.set("add_HHO_reconstructed_symmetrized_gradient", transname)


  def add_HHO_reconstructed_value(self, transname):
    """Add to the model the elementary transformation corresponding to the
    reconstruction of the variable for HHO methods.
    The name is the name given to the elementary transformation. """
    return self.set("add_HHO_reconstructed_value", transname)


  def add_HHO_reconstructed_symmetrized_value(self, transname):
    """Add to the model the elementary transformation corresponding to the
    reconstruction of the variable for HHO methods using a symmetrized
    gradient.
    The name is the name given to the elementary transformation. """
    return self.set("add_HHO_reconstructed_symmetrized_value", transname)


  def add_HHO_stabilization(self, transname):
    """Add to the model the elementary transformation corresponding to the
    HHO stabilization operator.
    The name is the name given to the elementary transformation. """
    return self.set("add_HHO_stabilization", transname)


  def add_HHO_symmetrized_stabilization(self, transname):
    """Add to the model the elementary transformation corresponding to the
    HHO stabilization operator using a symmetrized gradient.
    The name is the name given to the elementary transformation. """
    return self.set("add_HHO_symmetrized_stabilization", transname)


  def add_interpolate_transformation_from_expression(self, transname, source_mesh, target_mesh, expr):
    """Add a transformation to the model from mesh `source_mesh` to mesh
    `target_mesh` given by the expression `expr` which corresponds to a
    high-level generic assembly expression which may contains some
    variable of the model. CAUTION: the derivative of the
    transformation with used variable is taken into account in the
    computation of the tangen system. However, order two derivative is not
    implemented, so such tranformation is not allowed in the definition
    of a potential. """
    return self.set("add_interpolate_transformation_from_expression", transname, source_mesh, target_mesh, expr)


  def add_element_extrapolation_transformation(self, transname, source_mesh, elt_corr):
    """Add a special interpolation transformation which represents the identity
    transformation but allows to evaluate the expression on another element
    than the current element by polynomial extrapolation. It is used for
    stabilization term in fictitious domain applications. the array elt_cor
    should be a two entry array whose first line contains the elements
    concerned by the transformation and the second line the respective
    elements on which the extrapolation has to be made. If an element
    is not listed in elt_cor the evaluation is just made on the current
    element. """
    return self.set("add_element_extrapolation_transformation", transname, source_mesh, elt_corr)


  def add_standard_secondary_domain(self, name, mim, region = -1):
    """Add a secondary domain to the model which can be used in a weak-form language expression for integration on the product of two domains. `name` is the name
    of the secondary domain, `mim` is an integration method on this domain
    and `region` the region on which the integration is to be performed. """
    return self.set("add_standard_secondary_domain", name, mim, region )


  def set_element_extrapolation_correspondence(self, transname, elt_corr):
    """Change the correspondence map of an element extrapolation interpolate
    transformation. """
    return self.set("set_element_extrapolation_correspondence", transname, elt_corr)


  def add_raytracing_transformation(self, transname, release_distance):
    """Add a raytracing interpolate transformation called `transname` to a model
    to be used by the generic assembly bricks.
    CAUTION: For the moment, the derivative of the
    transformation is not taken into account in the model solve. """
    return self.set("add_raytracing_transformation", transname, release_distance)


  def add_master_contact_boundary_to_raytracing_transformation(self, transname, m, dispname, region):
    """Add a master contact boundary with corresponding displacement variable
    `dispname` on a specific boundary `region` to an existing raytracing
    interpolate transformation called `transname`. """
    return self.set("add_master_contact_boundary_to_raytracing_transformation", transname, m, dispname, region)


  def add_slave_contact_boundary_to_raytracing_transformation(self, transname, m, dispname, region):
    """Add a slave contact boundary with corresponding displacement variable
    `dispname` on a specific boundary `region` to an existing raytracing
    interpolate transformation called `transname`. """
    return self.set("add_slave_contact_boundary_to_raytracing_transformation", transname, m, dispname, region)


  def add_rigid_obstacle_to_raytracing_transformation(self, transname, expr, N):
    """Add a rigid obstacle whose geometry corresponds to the zero level-set
    of the high-level generic assembly expression `expr`
    to an existing raytracing interpolate transformation called `transname`.
    """
    return self.set("add_rigid_obstacle_to_raytracing_transformation", transname, expr, N)


  def add_projection_transformation(self, transname, release_distance):
    """Add a projection interpolate transformation called `transname` to a model
    to be used by the generic assembly bricks.
    CAUTION: For the moment, the derivative of the
    transformation is not taken into account in the model solve. """
    return self.set("add_projection_transformation", transname, release_distance)


  def add_master_contact_boundary_to_projection_transformation(self, transname, m, dispname, region):
    """Add a master contact boundary with corresponding displacement variable
    `dispname` on a specific boundary `region` to an existing projection
    interpolate transformation called `transname`. """
    return self.set("add_master_contact_boundary_to_projection_transformation", transname, m, dispname, region)


  def add_slave_contact_boundary_to_projection_transformation(self, transname, m, dispname, region):
    """Add a slave contact boundary with corresponding displacement variable
    `dispname` on a specific boundary `region` to an existing projection
    interpolate transformation called `transname`. """
    return self.set("add_slave_contact_boundary_to_projection_transformation", transname, m, dispname, region)


  def add_rigid_obstacle_to_projection_transformation(self, transname, expr, N):
    """Add a rigid obstacle whose geometry corresponds to the zero level-set
    of the high-level generic assembly expression `expr`
    to an existing projection interpolate transformation called `transname`.
    """
    return self.set("add_rigid_obstacle_to_projection_transformation", transname, expr, N)


  def add_linear_term(self, mim, expression, region=None, *args):
    """Synopsis: ind = Model.add_linear_term(self, MeshIm mim, string expression[, int region[, int is_symmetric[, int is_coercive]]])

    Adds a matrix term given by the assembly string `expr` which will
    be assembled in region `region` and with the integration method `mim`.
    Only the matrix term will be taken into account, assuming that it is
    linear.
    The advantage of declaring a term linear instead of nonlinear is that
    it will be assembled only once and no assembly is necessary for the
    residual.
    Take care that if the expression contains some variables and if the
    expression is a potential or of first order (i.e. describe the weak
    form, not the derivative of the weak form), the expression will be
    derivated with respect to all variables.
    You can specify if the term is symmetric, coercive or not.
    If you are not sure, the better is to declare the term not symmetric
    and not coercive. But some solvers (conjugate gradient for instance)
    are not allowed for non-coercive problems.
    `brickname` is an optional name for the brick."""
    return self.set("add_linear_term", mim, expression, region, *args)


  def add_linear_twodomain_term(self, mim, expression, region, secondary_domain, is_symmetric=None, *args):
    """Synopsis: ind = Model.add_linear_twodomain_term(self, MeshIm mim, string expression, int region, string secondary_domain[, int is_symmetric[, int is_coercive]])

    Adds a linear term given by a weak form language expression like
    Model.add_linear_term() but for an integration on a direct
    product of two domains, a first specfied by ``mim`` and ``region``
    and a second one by ``secondary_domain`` which has to be declared
    first into the model."""
    return self.set("add_linear_twodomain_term", mim, expression, region, secondary_domain, is_symmetric, *args)


  def add_linear_generic_assembly_brick(self, mim, expression, region=None, *args):
    """Synopsis: ind = Model.add_linear_generic_assembly_brick(self, MeshIm mim, string expression[, int region[, int is_symmetric[, int is_coercive]]])

    Deprecated. Use Model.add_linear_term() instead."""
    return self.set("add_linear_generic_assembly_brick", mim, expression, region, *args)


  def add_nonlinear_term(self, mim, expression, region=None, *args):
    """Synopsis: ind = Model.add_nonlinear_term(self, MeshIm mim, string expression[, int region[, int is_symmetric[, int is_coercive]]])

    Adds a nonlinear term given by the assembly string `expr` which will
    be assembled in region `region` and with the integration method `mim`.
    The expression can describe a potential or a weak form. Second order
    terms (i.e. containing second order test functions, Test2) are not
    allowed.
    You can specify if the term is symmetric, coercive or not.
    If you are not sure, the better is to declare the term not symmetric
    and not coercive. But some solvers (conjugate gradient for instance)
    are not allowed for non-coercive problems.
    `brickname` is an optional name for the brick."""
    return self.set("add_nonlinear_term", mim, expression, region, *args)


  def add_nonlinear_twodomain_term(self, mim, expression, region, secondary_domain, is_symmetric=None, *args):
    """Synopsis: ind = Model.add_nonlinear_twodomain_term(self, MeshIm mim, string expression, int region, string secondary_domain[, int is_symmetric[, int is_coercive]])

    Adds a nonlinear term given by a weak form language expression like
    Model.add_nonlinear_term() but for an integration on a direct
    product of two domains, a first specfied by ``mim`` and ``region``
    and a second one by ``secondary_domain`` which has to be declared
    first into the model."""
    return self.set("add_nonlinear_twodomain_term", mim, expression, region, secondary_domain, is_symmetric, *args)


  def add_nonlinear_generic_assembly_brick(self, mim, expression, region=None, *args):
    """Synopsis: ind = Model.add_nonlinear_generic_assembly_brick(self, MeshIm mim, string expression[, int region[, int is_symmetric[, int is_coercive]]])

    Deprecated. Use Model.add_nonlinear_term() instead."""
    return self.set("add_nonlinear_generic_assembly_brick", mim, expression, region, *args)


  def add_source_term(self, mim, expression, region=None):
    """Adds a source term given by the assembly string `expr` which will
    be assembled in region `region` and with the integration method `mim`.
    Only the residual term will be taken into account.
    Take care that if the expression contains some variables and if the
    expression is a potential, the expression will be
    derivated with respect to all variables.
    `brickname` is an optional name for the brick."""
    return self.set("add_source_term", mim, expression, region)


  def add_twodomain_source_term(self, mim, expression, region, secondary_domain):
    """Adds a source term given by a weak form language expression like
    Model.add_source_term() but for an integration on a direct
    product of two domains, a first specfied by ``mim`` and ``region``
    and a second one by ``secondary_domain`` which has to be declared
    first into the model."""
    return self.set("add_twodomain_source_term", mim, expression, region, secondary_domain)


  def add_source_term_generic_assembly_brick(self, mim, expression, region=None):
    """Deprecated. Use Model.add_source_term() instead."""
    return self.set("add_source_term_generic_assembly_brick", mim, expression, region)


  def add_assembly_assignment(self, dataname, expression, region=None, *args):
    """Synopsis: Model.add_assembly_assignment(self, string dataname, string expression[, int region[, int order[, int before]]])

    Adds expression `expr` to be evaluated at assembly time and being
    assigned to the data `dataname` which has to be of im_data type.
    This allows for instance to store a sub-expression of an assembly
    computation to be used on an other assembly. It can be used for instance
    to store the plastic strain in plasticity models.
    `order` represents the order of assembly where this assignement has to be
    done (potential(0), weak form(1) or tangent system(2) or at each
    order(-1)). The default value is 1.
    If before = 1, the the assignement is perfromed before the computation
    of the other assembly terms, such that the data can be used in the
    remaining of the assembly as an intermediary result (be careful that it is
    still considered as a data, no derivation of the expression is performed
    for the tangent system). 	 
    If before = 0 (default), the assignement is done after the assembly terms.
    """
    return self.set("add_assembly_assignment", dataname, expression, region, *args)


  def clear_assembly_assignment(self):
    """Delete all added assembly assignments
    """
    return self.set("clear_assembly_assignment")


  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. Note that
    for the real
    version which uses the high-level generic assembly language, `dataname`
    can be any regular expression of the high-level generic assembly
    language (like "1", "sin(X(1))" or "Norm(u)" for instance) even
    depending on model variables. 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, dataexpr, region=None, *args):
    """Synopsis: ind = Model.add_source_term_brick(self, MeshIm mim, string varname, string dataexpr[, int region[, string directdataname]])

    Add a source term to the model relatively to the variable `varname`.
    The source term is
    represented by `dataexpr` which could be any regular expression of the
    high-level generic assembly language (except for the complex version
    where it has to be a declared data of the model).
    `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. Note that when region is a
    boundary, this brick allows to prescribe a nonzero Neumann boundary
    condition. Return the brick index in the model."""
    return self.set("add_source_term_brick", mim, varname, dataexpr, 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 `dataepxpr` which could be any regular
    expression of the high-level generic assembly language (except
    for the complex version where it has to be a declared data of
    the model). 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_simplification(self, varname, region, dataname=None):
    """Adds a (simple) Dirichlet condition on the variable `varname` and
    the mesh region `region`. The Dirichlet condition is prescribed by
    a simple post-treatment of the final linear system (tangent system
    for nonlinear problems) consisting of modifying the lines corresponding
    to the degree of freedom of the variable on `region` (0 outside the
    diagonal, 1 on the diagonal of the matrix and the expected value on
    the right hand side).
    The symmetry of the linear system is kept if all other bricks are
    symmetric.
    This brick is to be reserved for simple Dirichlet conditions (only dof
    declared on the corresponding boundary are prescribed). The application
    of this brick on reduced dof may be problematic. Intrinsic vectorial
    finite element method are not supported. 
    `dataname` is the optional right hand side of  the Dirichlet condition.
    It could be constant (but in that case, it can only be applied to
    Lagrange f.e.m.) or (important) described on the same finite
    element method as `varname`.
    Returns the brick index in the model. """
    return self.set("add_Dirichlet_condition_with_simplification", varname, region, dataname)


  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_Nitsche_method(self, mim, varname, Neumannterm, datagamma0, region, theta=None, *args):
    """Synopsis: ind = Model.add_Dirichlet_condition_with_Nitsche_method(self, MeshIm mim, string varname, string Neumannterm, string datagamma0, int region[, scalar theta][, string dataname])

    Add a Dirichlet condition on the variable `varname` and the mesh
    region `region`. This region should be a boundary. `Neumannterm`
    is the expression of the Neumann term (obtained by the Green formula)
    described as an expression of the high-level
    generic assembly language. This term can be obtained by 
    Model.Neumann_term(varname, region) once all volumic bricks have
    been added to the model. The Dirichlet
    condition is prescribed with Nitsche's method. `datag` is the optional
    right hand side of the Dirichlet condition. `datagamma0` is the
    Nitsche's method parameter. `theta` is a scalar value which can be
    positive or negative. `theta = 1` corresponds to the standard symmetric
    method which is conditionally coercive for  `gamma0` small.
    `theta = -1` corresponds to the skew-symmetric method which is
    inconditionally coercive. `theta = 0` (default) is the simplest method
    for which the second derivative of the Neumann term is not necessary
    even for nonlinear problems. Return the brick index in the model."""
    return self.set("add_Dirichlet_condition_with_Nitsche_method", mim, varname, Neumannterm, datagamma0, region, theta, *args)


  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_normal_Dirichlet_condition_with_Nitsche_method(self, mim, varname, Neumannterm, gamma0name, region, theta=None, *args):
    """Synopsis: ind = Model.add_normal_Dirichlet_condition_with_Nitsche_method(self, MeshIm mim, string varname, string Neumannterm, string gamma0name, int region[, scalar theta][, string dataname])

    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. `Neumannterm`
    is the expression of the Neumann term (obtained by the Green formula)
    described as an expression of the high-level
    generic assembly language. This term can be obtained by 
    Model.Neumann_term(varname, region) once all volumic bricks have
    been added to the model. The Dirichlet
    condition is prescribed with Nitsche's method. `dataname` is the optional
    right hand side of the Dirichlet condition. It could be constant or
    described on a fem. `gamma0name` is the
    Nitsche's method parameter. `theta` is a scalar value which can be
    positive or negative. `theta = 1` corresponds to the standard symmetric
    method which is conditionally coercive for  `gamma0` small.
    `theta = -1` corresponds to the skew-symmetric method which is
    inconditionally coercive. `theta = 0` is the simplest method
    for which the second derivative of the Neumann term is not necessary
    even for nonlinear problems. 
    Returns the brick index in the model.
    (This brick is not fully tested)"""
    return self.set("add_normal_Dirichlet_condition_with_Nitsche_method", mim, varname, Neumannterm, gamma0name, region, theta, *args)


  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_generalized_Dirichlet_condition_with_Nitsche_method(self, mim, varname, Neumannterm, gamma0name, region, theta=None):
    """Add a Dirichlet condition on the variable `varname` and the mesh
    region `region`.
    This version is for vector field. It prescribes a condition
    @f$ Hu = r @f$ where `H` is a matrix field.
    CAUTION : the matrix H should have all eigenvalues equal to 1 or 0.
    The region should be a boundary.   `Neumannterm`
    is the expression of the Neumann term (obtained by the Green formula)
    described as an expression of the high-level
    generic assembly language. This term can be obtained by 
    Model.Neumann_term(varname, region) once all volumic bricks have
    been added to the model.  The Dirichlet
    condition is prescribed with Nitsche's method. `dataname` is the optional
    right hand side of the Dirichlet condition. It could be constant or
    described on a fem. `gamma0name` is the
    Nitsche's method parameter. `theta` is a scalar value which can be
    positive or negative. `theta = 1` corresponds to the standard symmetric
    method which is conditionally coercive for  `gamma0` small.
    `theta = -1` corresponds to the skew-symmetric method which is
    inconditionally coercive. `theta = 0` is the simplest method
    for which the second derivative of the Neumann term is not necessary
    even for nonlinear problems. `Hname` is the data
    corresponding to the matrix field `H`. It has to be a constant matrix
    or described on a scalar fem. Returns the brick index in the model.
    (This brick is not fully tested)"""
    return self.set("add_generalized_Dirichlet_condition_with_Nitsche_method", mim, varname, Neumannterm, gamma0name, region, theta)


  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, dataexpr, region=None):
    """Add a Helmholtz term to the model relatively to the variable `varname`.
    `dataexpr` is 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, dataexpr, region)


  def add_Fourier_Robin_brick(self, mim, varname, dataexpr, 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`. `dataexpr` is the parameter :math:`q` of
    the Fourier-Robin condition.  It can be an arbitrary valid expression
    of the high-level generic assembly language (except for the complex version
    for which it should be a data of the model). `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, dataexpr, region)


  def add_constraint_with_multipliers(self, varname, multname, B, *args):
    """Synopsis: ind = Model.add_constraint_with_multipliers(self, string varname, string multname, Spmat B, {vec L | string dataname})

    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 with the methods Model.set_private_matrix()
    and Model.set_private_rhs(). If `dataname` is specified instead of `L`,
    the vector `L` is defined in the model as data with the given name.
    Return the brick index in the model."""
    return self.set("add_constraint_with_multipliers", varname, multname, B, *args)


  def add_constraint_with_penalization(self, varname, coeff, B, *args):
    """Synopsis: ind = Model.add_constraint_with_penalization(self, string varname, scalar coeff, Spmat B, {vec L | string dataname})

    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 plain row, otherwise the whole
    tangent matrix will be plain. It is possible to change the constraint
    at any time with the methods Model.set_private_matrix()
    and Model.set_private_rhs(). The method
    Model.change_penalization_coeff() can be used.
    If `dataname` is specified instead of `L`, the vector `L` is defined
    in the model as data with the given name.
    Return the brick
    index in the model."""
    return self.set("add_constraint_with_penalization", varname, coeff, B, *args)


  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(). If `dataname` is specified instead of
    `L`, the vector `L` is defined in the model as data with the given name.
    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_isotropic_linearized_elasticity_pstrain_brick(self, mim, varname, data_E, data_nu, region=None):
    """Add an isotropic linearized elasticity term to the model relatively to
    the variable `varname`. `data_E` and `data_nu` should
    contain the Young modulus and Poisson ratio, respectively.
    `region` is an optional mesh region on which the term is added.
    If it is not specified, it is added
    on the whole mesh.
    On two-dimensional meshes, the term will correpsond to a plain strain
    approximation. On three-dimensional meshes, it will correspond to the
    standard model. 
    Return the brick index in the model."""
    return self.set("add_isotropic_linearized_elasticity_pstrain_brick", mim, varname, data_E, data_nu, region)


  def add_isotropic_linearized_elasticity_pstress_brick(self, mim, varname, data_E, data_nu, region=None):
    """Add an isotropic linearized elasticity term to the model relatively to
    the variable `varname`. `data_E` and `data_nu` should
    contain the Young modulus and Poisson ratio, respectively.
    `region` is an optional mesh region on which the term is added.
    If it is not specified, it is added
    on the whole mesh.
    On two-dimensional meshes, the term will correpsond to a plain stress
    approximation. On three-dimensional meshes, it will correspond to the
    standard model. 
    Return the brick index in the model."""
    return self.set("add_isotropic_linearized_elasticity_pstress_brick", mim, varname, data_E, data_nu, 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 dataexpr_coeff]])

    Add a 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. `dataexpr_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` (deprecated brick, use add_finite_strain_elaticity
    instead). `lawname` is the constitutive law which
    could be 'SaintVenant Kirchhoff', 'Mooney Rivlin', 'neo Hookean',
    'Ciarlet Geymonat' or 'generalized Blatz Ko'.
    'Mooney Rivlin' and 'neo Hookean' law names can be preceded with the word
    'compressible' or 'incompressible' to force using the corresponding version.
    The compressible version of these laws requires one additional material
    coefficient. By default, the incompressible version of 'Mooney Rivlin' law
    and the compressible one of the 'neo Hookean' law are considered. In
    general, 'neo Hookean' is a special case of the 'Mooney Rivlin' law that
    requires one coefficient less.
    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.
    This brick use the low-level generic assembly.
    Returns the brick index in the model."""
    return self.set("add_nonlinear_elasticity_brick", mim, varname, constitutive_law, dataname, region)


  def add_finite_strain_elasticity_brick(self, mim, constitutive_law, varname, params, 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', 'Neo Hookean',
    'Ciarlet Geymonat' or 'Generalized Blatz Ko'.
    'Mooney Rivlin' and 'Neo Hookean' law names have to be preceeded with
    the word 'Compressible' or 'Incompressible' to force using the
    corresponding version.
    The compressible version of these laws requires one additional material
    coefficient.
    
    IMPORTANT : if the variable is defined on a 2D mesh, the plane strain
    approximation is automatically used.
    `params` 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.
    This brick use the high-level generic assembly.
    Returns the brick index in the model."""
    return self.set("add_finite_strain_elasticity_brick", mim, constitutive_law, varname, params, region)


  def add_small_strain_elastoplasticity_brick(self, mim, lawname, unknowns_type, varnames=None, *args):
    """Synopsis: ind = Model.add_small_strain_elastoplasticity_brick(self, MeshIm mim,  string lawname, string unknowns_type [, string varnames, ...] [, string params, ...] [, string theta = '1' [, string dt = 'timestep']] [, int region = -1])

    Adds a small strain plasticity term to the model `M`. This is the
    main GetFEM brick for small strain plasticity. `lawname` is the name
    of an implemented plastic law, `unknowns_type` indicates the choice
    between a discretization where the plastic multiplier is an unknown of
    the problem or (return mapping approach) just a data of the model
    stored for the next iteration. Remember that in both cases, a multiplier
    is stored anyway. `varnames` is a set of variable and data names with
    length which may depend on the plastic law (at least the displacement,
    the plastic multiplier and the plastic strain). `params` is a list of
    expressions for the parameters (at least elastic coefficients and the
    yield stress). These expressions can be some data names (or even
    variable names) of the model but can also be any scalar valid expression
    of the high level assembly language (such as '1/2', '2+sin(X[0])',
    '1+Norm(v)' ...). The last two parameters optionally provided in
    `params` are the `theta` parameter of the `theta`-scheme (generalized
    trapezoidal rule) used for the plastic strain integration and the
    time-step`dt`. The default value for `theta` if omitted is 1, which
    corresponds to the classical Backward Euler scheme which is first order
    consistent. `theta=1/2` corresponds to the Crank-Nicolson scheme
    (trapezoidal rule) which is second order consistent. Any value
    between 1/2 and 1 should be a valid value. The default value of `dt` is
    'timestep' which simply indicates the time step defined in the model
    (by md.set_time_step(dt)). Alternatively it can be any expression
    (data name, constant value ...). The time step can be altered from one
    iteration to the next one. `region` is a mesh region.
    
    The available plasticity laws are:
    
    - 'Prandtl Reuss' (or 'isotropic perfect plasticity').
      Isotropic elasto-plasticity with no hardening. The variables are the
      displacement, the plastic multiplier and the plastic strain.
      The displacement should be a variable and have a corresponding data
      having the same name preceded by 'Previous\\_' corresponding to the
      displacement at the previous time step (typically 'u' and 'Previous_u').
      The plastic multiplier should also have two versions (typically 'xi'
      and 'Previous_xi') the first one being defined as data if
      `unknowns_type ` is 'DISPLACEMENT_ONLY' or the integer value 0, or as
      a variable if `unknowns_type` is DISPLACEMENT_AND_PLASTIC_MULTIPLIER
      or the integer value 1.
      The plastic strain should represent a n x n data tensor field stored
      on mesh_fem or (preferably) on an im_data (corresponding to `mim`).
      The data are the first Lame coefficient, the second one (shear modulus)
      and the uniaxial yield stress. A typical call is
      Model.add_small_strain_elastoplasticity_brick(mim, 'Prandtl Reuss', 0, 'u', 'xi', 'Previous_Ep', 'lambda', 'mu', 'sigma_y', '1', 'timestep');
      IMPORTANT: Note that this law implements
      the 3D expressions. If it is used in 2D, the expressions are just
      transposed to the 2D. For the plane strain approximation, see below.
    - "plane strain Prandtl Reuss"
      (or "plane strain isotropic perfect plasticity")
      The same law as the previous one but adapted to the plane strain
      approximation. Can only be used in 2D.
    - "Prandtl Reuss linear hardening"
      (or "isotropic plasticity linear hardening").
      Isotropic elasto-plasticity with linear isotropic and kinematic
      hardening. An additional variable compared to "Prandtl Reuss" law:
      the accumulated plastic strain. Similarly to the plastic strain, it
      is only stored at the end of the time step, so a simple data is
      required (preferably on an im_data).
      Two additional parameters: the kinematic hardening modulus and the
      isotropic one. 3D expressions only. A typical call is
      Model.add_small_strain_elastoplasticity_brick(mim, 'Prandtl Reuss linear hardening', 0, 'u', 'xi', 'Previous_Ep', 'Previous_alpha', 'lambda', 'mu', 'sigma_y', 'H_k', H_i', '1', 'timestep');
    - "plane strain Prandtl Reuss linear hardening"
      (or "plane strain isotropic plasticity linear hardening").
      The same law as the previous one but adapted to the plane strain
      approximation. Can only be used in 2D.
    
    See GetFEM user documentation for further explanations on the
    discretization of the plastic flow and on the implemented plastic laws.
    See also GetFEM user documentation on time integration strategy
    (integration of transient problems).
    
    IMPORTANT : remember that `small_strain_elastoplasticity_next_iter` has
    to be called at the end of each time step, before the next one
    (and before any post-treatment : this sets the value of the plastic
    strain and plastic multiplier)."""
    return self.set("add_small_strain_elastoplasticity_brick", mim, lawname, unknowns_type, varnames, *args)


  def add_elastoplasticity_brick(self, mim, projname, varname, previous_dep_name, datalambda, datamu, datathreshold, datasigma, region=None):
    """Old (obsolete) brick which do not use the high level generic
    assembly. 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 used: only the Von Mises projection is
    available with 'VM' or 'Von Mises'.
    `datasigma` is the variable representing the constraints on the material.
    `previous_dep_name` represents the displacement at the previous time step.
    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 variables 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, previous_dep_name, datalambda, datamu, datathreshold, datasigma, region)


  def add_finite_strain_elastoplasticity_brick(self, mim, lawname, unknowns_type, varnames=None, *args):
    """Synopsis: ind = Model.add_finite_strain_elastoplasticity_brick(self, MeshIm mim , string lawname, string unknowns_type [, string varnames, ...] [, string params, ...] [, int region = -1])

    Add a finite strain elastoplasticity brick to the model.
    For the moment there is only one supported law defined through 
    `lawname` as "Simo_Miehe".
    This law supports to possibilities of unknown variables to solve for
    defined by means of `unknowns_type` set to either
    'DISPLACEMENT_AND_PLASTIC_MULTIPLIER' (integer value 1) or
    'DISPLACEMENT_AND_PLASTIC_MULTIPLIER_AND_PRESSURE' (integer value 3).
    The  "Simo_Miehe" law expects as `varnames` a set of the
    following names that have to be defined as variables in the model:
    
    - the displacement variable which has to be defined as an unknown,
    - the plastic multiplier which has also defined as an unknown,
    - optionally the pressure variable for a mixed displacement-pressure
      formulation for 'DISPLACEMENT_AND_PLASTIC_MULTIPLIER_AND_PRESSURE'
      as `unknowns_type`,
    - the name of a (scalar) fem_data or im_data field that holds the
      plastic strain at the previous time step, and
    - the name of a fem_data or im_data field that holds all
      non-repeated components of the inverse of the plastic right
      Cauchy-Green tensor at the previous time step
      (it has to be a 4 element vector for plane strain 2D problems
      and a 6 element vector for 3D problems).
    
    The  "Simo_Miehe" law also expects as `params` a set of the
    following three parameters:
    
    - an expression for the initial bulk modulus K,
    - an expression for the initial shear modulus G,
    - the name of a user predefined function that decribes
      the yield limit as a function of the hardening variable
      (both the yield limit and the hardening variable values are
      assumed to be Frobenius norms of appropriate stress and strain
      tensors, respectively).
    
    As usual, `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_finite_strain_elastoplasticity_brick", mim, lawname, unknowns_type, varnames, *args)


  def add_nonlinear_incompressibility_brick(self, mim, varname, multname_pressure, region=None):
    """Add a 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_finite_strain_incompressibility_brick(self, mim, varname, multname_pressure, region=None):
    """Add a finite strain 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.
    This brick is equivalent to the ``nonlinear incompressibility brick`` but
    uses the high-level generic assembly adding the term
    ``p*(1-Det(Id(meshdim)+Grad_u))`` if ``p`` is the multiplier and
    ``u`` the variable which represent the displacement."""
    return self.set("add_finite_strain_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
    on the variable `varname` and the mesh region `region`.
    `dataname_M` represents the bending moment tensor and  `dataname_divM`
    its divergence.
    Return 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).
    The general form is
    :math:`\\int \\partial_n u(x)v(x) = \\int r(x)v(x) \\forall v`
    where :math:`r(x)` is
    the right hand side for the Dirichlet condition (0 for
    homogeneous conditions) and :math:`v` is in a space of multipliers
    defined 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 an optional parameter which represents
    the right hand side of the Dirichlet condition.
    If `R_must_be_derivated` is set to `true` then the normal
    derivative of `dataname` is considered.
    Return 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).
    The general form is
    :math:`\\int \\partial_n u(x)v(x) = \\int r(x)v(x) \\forall v`
    where :math:`r(x)` is
    the right hand side for the Dirichlet condition (0 for
    homogeneous conditions).
    The penalization coefficient
    is initially `coeff` and will be added to the data of the model.
    It can be changed with the command Model.change_penalization_coeff().
    `dataname` is an optional parameter which represents
    the right hand side of the Dirichlet condition.
    If `R_must_be_derivated` is set to `true` then the normal
    derivative of `dataname` is considered.
    Return 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_Mindlin_Reissner_plate_brick(self, mim, mim_reduced, varname_u3, varname_theta, param_E, param_nu, param_epsilon, param_kappa, variant=None, *args):
    """Synopsis: ind = Model.add_Mindlin_Reissner_plate_brick(self, MeshIm mim, MeshIm mim_reduced, string varname_u3, string varname_theta , string param_E, string param_nu, string param_epsilon, string param_kappa [,int variant [, int region]])

    Add a term corresponding to the classical Reissner-Mindlin plate
    model for which `varname_u3` is the transverse displacement,
    `varname_theta` the rotation of
    fibers normal to the midplane, 'param_E' the Young Modulus,
    `param_nu` the poisson ratio,
    `param_epsilon` the plate thickness,
    `param_kappa` the shear correction factor. Note that since this brick
    uses the high level generic assembly language, the parameter can
    be regular expression of this language.
    There are three variants.
    `variant = 0` corresponds to the an
    unreduced formulation and in that case only the integration
    method `mim` is used. Practically this variant is not usable since
    it is subject to a strong locking phenomenon.
    `variant = 1` corresponds to a reduced integration where `mim` is
    used for the rotation term and `mim_reduced` for the transverse
    shear term. `variant = 2` (default) corresponds to the projection onto
    a rotated RT0 element of the transverse shear term. For the moment, this
    is adapted to quadrilateral only (because it is not sufficient to
    remove the locking phenomenon on triangle elements). Note also that if
    you use high order elements, the projection on RT0 will reduce the order
    of the approximation.
    Returns the brick index in the model.
    """
    return self.set("add_Mindlin_Reissner_plate_brick", mim, mim_reduced, varname_u3, varname_theta, param_E, param_nu, param_epsilon, param_kappa, variant, *args)


  def add_enriched_Mindlin_Reissner_plate_brick(self, mim, mim_reduced1, mim_reduced2, varname_ua, varname_theta, varname_u3, varname_theta3, param_E, param_nu, param_epsilon, variant=None, *args):
    """Synopsis: ind = Model.add_enriched_Mindlin_Reissner_plate_brick(self, MeshIm mim, MeshIm mim_reduced1, MeshIm mim_reduced2, string varname_ua, string varname_theta,string varname_u3, string varname_theta3 , string param_E, string param_nu, string param_epsilon [,int variant [, int region]])

    Add a term corresponding to the enriched Reissner-Mindlin plate
    model for which `varname_ua` is the membrane displacements,
    `varname_u3` is the transverse displacement,
    `varname_theta` the rotation of
    fibers normal to the midplane, 
    `varname_theta3` the pinching,     
    'param_E' the Young Modulus,
    `param_nu` the poisson ratio,
    `param_epsilon` the plate thickness. Note that since this brick
    uses the high level generic assembly language, the parameter can
    be regular expression of this language.
    There are four variants.
    `variant = 0` corresponds to the an
    unreduced formulation and in that case only the integration
    method `mim` is used. Practically this variant is not usable since
    it is subject to a strong locking phenomenon.
    `variant = 1` corresponds to a reduced integration where `mim` is
    used for the rotation term and `mim_reduced1` for the transverse
    shear term and `mim_reduced2` for the pinching term.
    `variant = 2` (default) corresponds to the projection onto
    a rotated RT0 element of the transverse shear term and a reduced integration for the pinching term.
    For the moment, this is adapted to quadrilateral only (because it is not sufficient to
    remove the locking phenomenon on triangle elements). Note also that if
    you use high order elements, the projection on RT0 will reduce the order
    of the approximation.
    `variant = 3` corresponds to the projection onto
    a rotated RT0 element of the transverse shear term and the projection onto P0 element of the pinching term.
    For the moment, this is adapted to quadrilateral only (because it is not sufficient to
    remove the locking phenomenon on triangle elements). Note also that if
    you use high order elements, the projection on RT0 will reduce the order
    of the approximation.   
    Returns the brick index in the model.
      """
    return self.set("add_enriched_Mindlin_Reissner_plate_brick", mim, mim_reduced1, mim_reduced2, varname_ua, varname_theta, varname_u3, varname_theta3, param_E, param_nu, param_epsilon, variant, *args)


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

    Add mass term to the model relatively to the variable `varname`.
    If specified, the data `dataexpr_rho` is 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, dataexpr_rho, *args)


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

    Add lumped mass for first order term to the model relatively to the variable `varname`.
    If specified, the data `dataexpr_rho` is 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_lumped_mass_for_first_order_brick", mim, varname, dataexpr_rho, *args)


  def shift_variables_for_time_integration(self):
    """Function used to shift the variables of a model to the data
    corresponding of ther value on the previous time step for time
    integration schemes. For each variable for which a time integration
    scheme has been declared, the scheme is called to perform the shift.
    This function has to be called between two time steps. """
    return self.set("shift_variables_for_time_integration")


  def perform_init_time_derivative(self, ddt):
    """By calling this function, indicates that the next solve will compute
    the solution for a (very) small time step `ddt` in order to initalize
    the data corresponding to the derivatives needed by time integration
    schemes (mainly the initial time derivative for order one in time
    problems  and the second order time derivative for second order in time
    problems). The next solve will not change the value of the variables. """
    return self.set("perform_init_time_derivative", ddt)


  def set_time_step(self, dt):
    """Set the value of the time step to `dt`. This value can be change
    from a step to another for all one-step schemes (i.e. for the moment
    to all proposed time integration schemes). """
    return self.set("set_time_step", dt)


  def set_time(self, t):
    """Set the value of the data `t` corresponding to the current time to `t`.
    """
    return self.set("set_time", t)


  def add_theta_method_for_first_order(self, varname, theta):
    """Attach a theta method for the time discretization of the variable
    `varname`. Valid only if there is at most first order time derivative
    of the variable. """
    return self.set("add_theta_method_for_first_order", varname, theta)


  def add_theta_method_for_second_order(self, varname, theta):
    """Attach a theta method for the time discretization of the variable
    `varname`. Valid only if there is at most second order time derivative
    of the variable. """
    return self.set("add_theta_method_for_second_order", varname, theta)


  def add_Newmark_scheme(self, varname, beta, gamma):
    """Attach a theta method for the time discretization of the variable
    `varname`. Valid only if there is at most second order time derivative
    of the variable. """
    return self.set("add_Newmark_scheme", varname, beta, gamma)


  def add_Houbolt_scheme(self, varname):
    """Attach a Houbolt method for the time discretization of the variable
    `varname`. Valid only if there is at most second order time derivative
    of the variable  """
    return self.set("add_Houbolt_scheme", varname)


  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 (and its attached multipliers).
    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 (and its attached multipliers)."""
    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[, string dataname_gamma, string dataname_wt]]])

    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 add_basic_contact_brick_two_deformable_bodies(self, varname_u1, varname_u2, multname_n, dataname_r, BN1, BN2, dataname_gap=None, *args):
    """Synopsis: ind = Model.add_basic_contact_brick_two_deformable_bodies(self, string varname_u1, string varname_u2, string multname_n, string dataname_r, Spmat BN1, Spmat BN2[, string dataname_gap[, string dataname_alpha[, int augmented_version]]])

    Add a frictionless contact condition to the model between two deformable
     bodies. If U1, U2 are the vector
     of degrees of freedom on which the unilateral constraint is applied,
     the matrices `BN1` and `BN2` have to be such that this condition
     is defined by
     $B_{N1} U_1 B_{N2} U_2 + \\le gap$. The constraint is prescribed thank
     to a multiplier
     `multname_n` whose dimension should be equal to the number of lines of
     `BN`. 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 `aug_version` indicates
     the augmentation strategy : 1 for the non-symmetric Alart-Curnier
     augmented Lagrangian, 2 for the symmetric one, 3 for the unsymmetric
     method with augmented multiplier. """
    return self.set("add_basic_contact_brick_two_deformable_bodies", varname_u1, varname_u2, multname_n, dataname_r, BN1, BN2, dataname_gap, *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, Neumannterm, dataname_obstacle, gamma0name, region, theta=None, *args):
    """Synopsis: ind = Model.add_Nitsche_contact_with_rigid_obstacle_brick(self, MeshIm mim, string varname, string Neumannterm, string dataname_obstacle, string gamma0name,  int region[, scalar theta[, string dataname_friction_coeff[, string dataname_alpha, string dataname_wt]]])

    Adds a contact condition with or without Coulomb friction on the variable
    `varname` and the mesh boundary `region`. The contact condition
    is prescribed with Nitsche's method. The rigid obstacle should
    be described with the data `dataname_obstacle` being a signed distance to
    the obstacle (interpolated on a finite element method).
    `gamma0name` is the Nitsche's method parameter.
    `theta` is a scalar value which can be
    positive or negative. `theta = 1` corresponds to the standard symmetric
    method which is conditionally coercive for  `gamma0` small.
    `theta = -1` corresponds to the skew-symmetric method which is
    inconditionally coercive. `theta = 0` is the simplest method
    for which the second derivative of the Neumann term is not necessary.
    The optional parameter `dataname_friction_coeff` is the friction
    coefficient which could be constant or defined on a finite element
    method.
    CAUTION: This brick has to be added in the model after all the bricks
    corresponding to partial differential terms having a Neumann term.
    Moreover, This brick can only be applied to bricks declaring their
    Neumann terms. Returns the brick index in the model.
    """
    return self.set("add_Nitsche_contact_with_rigid_obstacle_brick", mim, varname, Neumannterm, dataname_obstacle, gamma0name, region, theta, *args)


  def add_Nitsche_midpoint_contact_with_rigid_obstacle_brick(self, mim, varname, Neumannterm, Neumannterm_wt, dataname_obstacle, gamma0name, region, theta, dataname_friction_coeff, dataname_alpha, dataname_wt):
    """EXPERIMENTAL BRICK: for midpoint scheme only !!
    Adds a contact condition with or without Coulomb friction on the variable
    `varname` and the mesh boundary `region`. The contact condition
    is prescribed with Nitsche's method. The rigid obstacle should
    be described with the data `dataname_obstacle` being a signed distance to
    the obstacle (interpolated on a finite element method).
    `gamma0name` is the Nitsche's method parameter.
    `theta` is a scalar value which can be
    positive or negative. `theta = 1` corresponds to the standard symmetric
    method which is conditionally coercive for  `gamma0` small.
    `theta = -1` corresponds to the skew-symmetric method which is
    inconditionally coercive. `theta = 0` is the simplest method
    for which the second derivative of the Neumann term is not necessary.
    The optional parameter `dataname_friction_coeff` is the friction
    coefficient which could be constant or defined on a finite element
    method.
    Returns the brick index in the model.
    
    """
    return self.set("add_Nitsche_midpoint_contact_with_rigid_obstacle_brick", mim, varname, Neumannterm, Neumannterm_wt, dataname_obstacle, gamma0name, region, theta, dataname_friction_coeff, dataname_alpha, dataname_wt)


  def add_Nitsche_fictitious_domain_contact_brick(self, mim, varname1, varname2, dataname_d1, dataname_d2, gamma0name, theta=None, *args):
    """Synopsis: ind = Model.add_Nitsche_fictitious_domain_contact_brick(self, MeshIm mim, string varname1, string varname2, string dataname_d1, string dataname_d2, string gamma0name [, scalar theta[, string dataname_friction_coeff[, string dataname_alpha, string dataname_wt1,string dataname_wt2]]])

    Adds a contact condition with or without Coulomb friction between
    two bodies in a fictitious domain. The contact condition is applied on 
    the variable `varname_u1` corresponds with the first and slave body 
    with Nitsche's method and on the variable `varname_u2` corresponds 
    with the second and master body with Nitsche's method. 
    The contact condition is evaluated on the fictitious slave boundary.
    The first body should be described by the level-set `dataname_d1` 
    and the second body should be described by the level-set `dataname_d2`.
    `gamma0name` is the Nitsche's method parameter. 
    `theta` is a scalar value which can be positive or negative. 
    `theta = 1` corresponds to the standard symmetric method which is
    conditionally coercive for  `gamma0` small.
    `theta = -1` corresponds to the skew-symmetric method which is inconditionally coercive.
    `theta = 0` is the simplest method for which the second derivative of
    the Neumann term is not necessary. The optional parameter `dataname_friction_coeff`
    is the friction coefficient which could be constant or defined on a finite element method. 
    CAUTION: This brick has to be added in the model after all the bricks
    corresponding to partial differential terms having a Neumann term.
    Moreover, This brick can only be applied to bricks declaring their
    Neumann terms. Returns the brick index in the model. 
    """
    return self.set("add_Nitsche_fictitious_domain_contact_brick", mim, varname1, varname2, dataname_d1, dataname_d2, gamma0name, theta, *args)


  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_raytracing(self, dataname_r, release_distance, dataname_fr=None, *args):
    """Synopsis: ind = Model.add_integral_large_sliding_contact_brick_raytracing(self, string dataname_r, scalar release_distance, [, string dataname_fr[, string dataname_alpha[, int version]]])

    Adds a large sliding contact with friction brick to the model.
    This brick is able to deal with self-contact, contact between
    several deformable bodies and contact with rigid obstacles.
    It uses the high-level generic assembly. It adds to the model
    a raytracing_interpolate_transformation object.
    For each slave boundary a multiplier variable should be defined.
    The release distance should be determined with care
    (generally a few times a mean element size, and less than the
    thickness of the body). Initially, the brick is added with no contact
    boundaries. The contact boundaries and rigid bodies are added with
    special functions. `version` is 0 (the default value) for the
    non-symmetric version and 1 for the more symmetric one
    (not fully symmetric even without friction). """
    return self.set("add_integral_large_sliding_contact_brick_raytracing", dataname_r, release_distance, dataname_fr, *args)


  def add_rigid_obstacle_to_large_sliding_contact_brick(self, indbrick, expr, N):
    """Adds a rigid obstacle to an existing large sliding contact
    with friction brick. `expr` is an expression using the high-level
    generic assembly language (where `x` is the current point n the mesh)
    which should be a signed distance to the obstacle.
    `N` is the mesh dimension. """
    return self.set("add_rigid_obstacle_to_large_sliding_contact_brick", indbrick, expr, N)


  def add_master_contact_boundary_to_large_sliding_contact_brick(self, indbrick, mim, region, dispname, wname=None):
    """Adds a master contact boundary to an existing large sliding contact
    with friction brick. """
    return self.set("add_master_contact_boundary_to_large_sliding_contact_brick", indbrick, mim, region, dispname, wname)


  def add_slave_contact_boundary_to_large_sliding_contact_brick(self, indbrick, mim, region, dispname, lambdaname, wname=None):
    """Adds a slave contact boundary to an existing large sliding contact
    with friction brick. """
    return self.set("add_slave_contact_boundary_to_large_sliding_contact_brick", indbrick, mim, region, dispname, lambdaname, wname)


  def add_master_slave_contact_boundary_to_large_sliding_contact_brick(self, indbrick, mim, region, dispname, lambdaname, wname=None):
    """Adds a contact boundary to an existing large sliding contact
    with friction brick which is both master and slave
    (allowing the self-contact). """
    return self.set("add_master_slave_contact_boundary_to_large_sliding_contact_brick", indbrick, mim, region, dispname, lambdaname, wname)


  def add_Nitsche_large_sliding_contact_brick_raytracing(self, unbiased_version, dataname_r, release_distance, dataname_fr=None, *args):
    """Synopsis: ind = Model.add_Nitsche_large_sliding_contact_brick_raytracing(self, bool unbiased_version, string dataname_r, scalar release_distance[, string dataname_fr[, string dataname_alpha[, int version]]])

    Adds a large sliding contact with friction brick to the model based on the Nitsche's method.
    This brick is able to deal with self-contact, contact between
    several deformable bodies and contact with rigid obstacles.
    It uses the high-level generic assembly. It adds to the model
    a raytracing_interpolate_transformation object. "unbiased_version" refers to the version of Nische's method to be used.
    (unbiased or biased one).
    For each slave boundary a  material law should be defined as a function of the dispacement variable on this boundary.
    The release distance should be determined with care
    (generally a few times a mean element size, and less than the
    thickness of the body). Initially, the brick is added with no contact
    boundaries. The contact boundaries and rigid bodies are added with
    special functions. `version` is 0 (the default value) for the
    non-symmetric version and 1 for the more symmetric one
    (not fully symmetric even without friction). """
    return self.set("add_Nitsche_large_sliding_contact_brick_raytracing", unbiased_version, dataname_r, release_distance, dataname_fr, *args)


  def add_rigid_obstacle_to_Nitsche_large_sliding_contact_brick(self, indbrick, expr, N):
    """Adds a rigid obstacle to an existing large sliding contact
    with friction brick. `expr` is an expression using the high-level
    generic assembly language (where `x` is the current point n the mesh)
    which should be a signed distance to the obstacle.
    `N` is the mesh dimension. """
    return self.set("add_rigid_obstacle_to_Nitsche_large_sliding_contact_brick", indbrick, expr, N)


  def add_master_contact_boundary_to_biased_Nitsche_large_sliding_contact_brick(self, indbrick, mim, region, dispname, wname=None):
    """Adds a master contact boundary to an existing biased Nitsche's large sliding contact
    with friction brick. """
    return self.set("add_master_contact_boundary_to_biased_Nitsche_large_sliding_contact_brick", indbrick, mim, region, dispname, wname)


  def add_slave_contact_boundary_to_biased_Nitsche_large_sliding_contact_brick(self, indbrick, mim, region, dispname, lambdaname, wname=None):
    """Adds a slave contact boundary to an existing biased Nitsche's large sliding contact
    with friction brick. """
    return self.set("add_slave_contact_boundary_to_biased_Nitsche_large_sliding_contact_brick", indbrick, mim, region, dispname, lambdaname, wname)


  def add_contact_boundary_to_unbiased_Nitsche_large_sliding_contact_brick(self, indbrick, mim, region, dispname, lambdaname, wname=None):
    """Adds a contact boundary to an existing unbiased Nitschelarge sliding contact
    with friction brick which is both master and slave. """
    return self.set("add_contact_boundary_to_unbiased_Nitsche_large_sliding_contact_brick", indbrick, mim, region, dispname, lambdaname, wname)


#
# 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)``
    Preconditioner 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_vtu(self, filename, *args):
    """Synopsis: Slice.export_to_vtu(self, string filename, ...)

    Export a slice to VTK(XML).
    
    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_vtu('test.vtu', Usl, 'first_dataset', mf,
      U2, 'second_dataset')
    - Slice.export_to_vtu('test.vtu', 'ascii', mf,U2)
    - Slice.export_to_vtu('test.vtu', 'edges', 'ascii', Uslice)"""
    return self.get("export_to_vtu", 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 determinant(self):
    """returns the matrix determinant calculated using MUMPS."""
    return self.get("determinant")


  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_generic(mim, order, expression, region, model=None, *args):
  """Synopsis: (...) = asm_generic(MeshIm mim, int order, string expression, int region, [Model model, ['Secondary_domain', 'name',]] [string varname, int is_variable[, {MeshFem mf, MeshImd mimd}], value], ['select_output', 'varname1'[, 'varname2]], ...)

  High-level generic assembly procedure for volumic or boundary assembly.
  
  Performs the generic assembly of `expression` with the integration
  method `mim` on the mesh region of index `region` (-1 means all
  elements of the mesh). The same mesh should be shared by
  the integration method and all the finite element methods or
  mesh_im_data corresponding to the variables.
  
  `order` indicates either that the (scalar) potential
  (order = 0) or the (vector) residual (order = 1) or the
  tangent (matrix) (order = 2) is to be computed.
  
  `model` is an optional parameter allowing to take into account
  all variables and data of a model. Note that all enabled variables
  of the model will occupy space in the returned vector/matrix
  corresponding to their degrees of freedom in the global system, even
  if they are not present in `expression`.
  
  The variables and constants (data) are listed after the region number
  (or optionally the model).
  For each variable/constant, a name must be given first (as it is
  referred in the assembly string), then an integer equal to 1 or 0
  is expected respectively for declaring a variable or a constant,
  then the finite element method if it is a fem variable/constant or
  the mesh_im_data if it is data defined on integration points, and
  the vector representing the value of the variable/constant.
  It is possible to give an arbitrary number of variable/constant.
  The difference between a variable and a constant is that test
  functions are only available for variables, not for constants.
  
  `select_output` is an optional parameter which allows to reduce the
  output vector (for `order` equal to 1) or the matrix (for `order`
  equal to 2) to the degrees of freedom of the specified variables.
  One variable has to be specified for a vector output and two for a
  matrix output.
  
  Note that if several variables are given, the assembly of the
  tangent matrix/residual vector will be done considering the order
  in the call of the function (the degrees of freedom of the first
  variable, then of the second one, and so on). If a model is provided,
  all degrees of freedom of the model will be counted first, even if
  some of the model variables do not appear in `expression`.
  
  For example, the L2 norm of a vector field "u" can be computed with::
  
    gf_compute('L2 norm') or with the square root of:
  
    gf_asm('generic', mim, 0, 'u.u', -1, 'u', 1, mf, U);
  
  The nonhomogeneous Laplacian stiffness matrix of a scalar field can be evaluated with::
  
    gf_asm('laplacian', mim, mf, mf_data, A) or equivalently with:
  
    gf_asm('generic', mim, 2, 'A*Grad_Test2_u.Grad_Test_u', -1, 'u', 1, mf, U, 'A', 0, mf_data, A);
  
    """
  return getfem('asm', 'generic', mim, order, expression, region, model, *args)


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

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


def asm_laplacian(mim, mf_u, mf_d, a, region=None):
  """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, region)


def asm_linear_elasticity(mim, mf_u, mf_d, lambda_d, mu_d, region=None):
  """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, region)


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':
    This law has three parameters, called C1, C2 and D1.
    Can be preceded with the words 'compressible' or 'incompressible' to force
    a specific version. By default, the incompressible version is considered
    which requires only the first two material coefficients.
  - 'neo Hookean':
    A special case of the 'Mooney Rivlin' law that requires one material
    coefficient less (C2 = 0). By default, its compressible version is used.
  - 'Ciarlet Geymonat':
    This law has 3 parameters, called lambda, mu and gamma, with
    gamma chosen such that gamma is in ]-lambda/2-mu, -mu[.
  
  The parameters of the material law are described on the MeshFem `mf_d`.
  The matrix `params` should have `nbdof(mf_d)` columns, each row
  correspounds to a parameter.
  
  The last argument selects what is to be built: either the tangent
  matrix, or the right hand side. If the incompressibility is
  considered, it should be followed by a MeshFem `mf_p`, for the
  pression.
  
  Return a SpMat object (tangent matrix), vec object (right hand
  side), tuple of SpMat objects (incompressible tangent matrix), or
  tuple of vec objects (incompressible right hand side).
  """
  return getfem('asm', 'nonlinear_elasticity', mim, mf_u, U, law, mf_d, params, *args)


def asm_helmholtz(mim, mf_u, mf_d, k, region=None):
  """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, region)


def asm_bilaplacian(mim, mf_u, mf_d, a, region=None):
  """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, region)


def asm_bilaplacian_KL(mim, mf_u, mf_d, a, nu, region=None):
  """Assembly of the matrix for the Bilaplacian problem with Kirchhoff-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, region)


def asm_volumic_source(mim, mf_u, mf_d, fd, region=None):
  """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, region)


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_define_function(name, nb_args, expression, expression_derivative_t=None, *args):
  """Synopsis: asm_define_function(string name, int nb_args, string expression[, string expression_derivative_t[, string expression_derivative_u]])

  Define a new function `name` which can be used in high level
  generic assembly. The function can have one or two parameters.
  In `expression` all available predefined function or operation
  of the generic assembly can be used. However, no reference to
  some variables or data can be specified. The argument of the
  function is `t` for a one parameter function and `t` and `u`
  for a two parameter function. For instance 'sin(pi*t)+2*t*t'
  is a valid expression for a one parameter function and
  'sin(max(t,u)*pi)' is a valid expression for a two parameters
  function. `expression_derivative_t` and `expression_derivative_u`
  are optional expressions for the derivatives with respect
  to `t` and `u`. If they are not furnished, a symbolic derivation
  is used. """
  return getfem('asm', 'define_function', name, nb_args, expression, expression_derivative_t, *args)


def asm_undefine_function(name):
  """Cancel the definition of a previously defined function `name`
  for the high level generic assembly.  """
  return getfem('asm', 'undefine_function', name)


def asm_define_linear_hardening_function(name, sigma_y0, H, *args):
  """Synopsis: asm_define_linear_hardening_function(string name, scalar sigma_y0, scalar H, ... [string 'Frobenius'])

  Define a new linear hardening function under the name `name`, with
  initial yield stress `sigma_y0` and hardening modulus H.
  If an extra string argument with the value 'Frobenius' is provided,
  the hardening function is expressed in terms of Frobenius norms of its
  input strain and output stress, instead of their Von-Mises equivalents. """
  return getfem('asm', 'define_linear_hardening_function', name, sigma_y0, H, *args)


def asm_define_Ramberg_Osgood_hardening_function(name, sigma_ref, *args):
  """Synopsis: asm_define_Ramberg_Osgood_hardening_function(string name, scalar sigma_ref, {scalar eps_ref | scalar E, scalar alpha}, scalar n[, string 'Frobenius'])

  Define a new Ramberg Osgood hardening function under the name `name`,
  with initial yield stress `sigma_y0` and hardening modulus H.
  If an extra string argument with the value 'Frobenius' is provided,
  the hardening function is expressed in terms of Frobenius norms of its
  input strain and output stress, instead of their Von-Mises equivalents. """
  return getfem('asm', 'define_Ramberg_Osgood_hardening_function', name, sigma_ref, *args)


def asm_expression_analysis(expression, *args):
  """Synopsis: asm_expression_analysis(string expression [, {Mesh mesh | MeshIm mim}] [, der_order] [, Model model] [, string varname, int is_variable[, {MeshFem mf | MeshImd mimd}], ...])

  Analyse a high-level generic assembly expression and print
  information about the provided expression."""
  return getfem('asm', 'expression_analysis', expression, *args)


def asm_volumic(CVLST=None, *args):
  """Synopsis: (...) = asm_volumic(,CVLST], expr [, mesh_ims, mesh_fems, data...])

  Low-level 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 the square root of:
  
    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, mf_data, 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,mf_data,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...])

  Low-level 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, *args):
  """Synopsis: Mi = asm_interpolation_matrix(MeshFem mf, {MeshFem mfi | vec pts})

  Build the interpolation matrix from a MeshFem onto another MeshFem or a set of points.
  
  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, *args)


def asm_extrapolation_matrix(mf, *args):
  """Synopsis: Me = asm_extrapolation_matrix(MeshFem mf,  {MeshFem mfe | vec pts})

  Build the extrapolation matrix from a MeshFem onto another MeshFem or a set of points.
  
  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, *args)


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)


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


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


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)

#
# 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
  elements."""
  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
  elements."""
  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
  elements."""
  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
  elements."""
  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
  elements."""
  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
  elements."""
  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
  elements."""
  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_error_estimate_nitsche(MF, U, mim, GAMMAC, GAMMAN, lambda_, mu_, gamma0, f_coeff, vertical_force):
  """Compute an a posteriori error estimate in the case of Nitsche method.
  
  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_nitsche', mim, GAMMAC, GAMMAN, lambda_, mu_, gamma0, f_coeff, vertical_force)


def compute_convect(MF, U, mf_v, V, dt, nt, option=None, *args):
  """Synopsis: compute_convect(MeshFem MF, vec U, MeshFem mf_v, vec V, scalar dt, int nt[, string option[, vec per_min, vec per_max]])

  Compute a convection of `U` with regards to a steady state velocity
  field `V` with a Characteristic-Galerkin method. The result is returned
  in-place in `U`.
  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,
  `option = 'unchanged'` for a constant value on that boundary or
  `option = 'periodicity'` for a peridiodic boundary. For this latter option
  the two vectors per_min, per_max has to be given and represent the limits
  of the periodic domain (on components where per_max[k] < per_min[k]
  no operation is done).
  This method is rather dissipative, but stable.
  """
  return getfem('compute', MF, U, 'convect', mf_v, V, dt, nt, option, *args)

#
# 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)


def linsolve_mumps(M, b):
  """Solve `M.U = b` using the MUMPS solver."""
  return getfem('linsolve', 'mumps', 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')

#
# 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.items():
    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,
        Mesh,
        MeshFem,
        MeshIm,
        MeshImData,
        MeshLevelSet,
        MesherObject,
        Model,
        Precond,
        Slice,
        Spmat)[id.classid]
  return t(id)

register_python_factory(factory)
