diff --git a/CMakeLists.txt b/CMakeLists.txt
index 2bb09325733d1568e797aad92a50357a16b6d676..2a88e8959205d0c03e0f6a3d2cd034c2eb7b8717 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -41,6 +41,7 @@ option(ENABLE_MPEG_ENCODE "Enable built-in MPEG encoder" ON)
 option(ENABLE_MPI "Enable MPI parallelization" OFF)
 option(ENABLE_MSVC_STATIC_RUNTIME "Use static Visual C++ runtime" OFF)
 option(ENABLE_NATIVE_FILE_CHOOSER "Enable native file chooser in GUI" ON)
+option(ENABLE_NUMPY "Enable Numpy function in solvers (requires SWIG)" ON)
 option(ENABLE_NETGEN "Enable Netgen mesh generator" ON)
 option(ENABLE_OCC "Enable Open CASCADE geometrical models" ON)
 option(ENABLE_OSMESA "Use OSMesa for offscreen rendering" OFF)
@@ -799,6 +800,26 @@ if(ENABLE_OSMESA)
   endif(OSMESA_LIB)
 endif(ENABLE_OSMESA)
 
+if(ENABLE_SWIG)
+  find_package(SWIG)
+  find_package(PythonLibs)
+  if(SWIG_FOUND AND PYTHONLIBS_FOUND)
+    message(STATUS "Found SWIG version " ${SWIG_VERSION})
+    string(SUBSTRING ${SWIG_VERSION} 0 1 SWIG_MAJOR_VERSION)
+    if(SWIG_MAJOR_VERSION EQUAL 1)
+      message("WARNING: Python bindings require SWIG >= 2: disabling Python")
+    else(SWIG_MAJOR_VERSION EQUAL 1)
+      set_config_option(HAVE_SWIG "Swig")
+      if(ENABLE_NUMPY)
+        find_path(NUMPY_INC "numpyconfig.h" PATH_SUFFIXES include/numpy)
+        if(NUMPY_INC)
+          set_config_option(HAVE_NUMPY "Numpy")
+        endif(NUMPY_INC)
+      endif(ENABLE_NUMPY)
+    endif(SWIG_MAJOR_VERSION EQUAL 1)
+  endif(SWIG_FOUND AND PYTHONLIBS_FOUND)
+endif(ENABLE_SWIG)
+
 check_function_exists(vsnprintf HAVE_VSNPRINTF)
 if(NOT HAVE_VSNPRINTF)
   set_config_option(HAVE_NO_VSNPRINTF "NoVsnprintf")
diff --git a/Common/GmshConfig.h.in b/Common/GmshConfig.h.in
index 30771075fba98347d1ae18c1e9db43bca4e53ec5..edc5de2f8e3e284bcd51651218259b640c39a3e5 100644
--- a/Common/GmshConfig.h.in
+++ b/Common/GmshConfig.h.in
@@ -38,6 +38,7 @@
 #cmakedefine HAVE_NETGEN
 #cmakedefine HAVE_NO_SOCKLEN_T
 #cmakedefine HAVE_NO_VSNPRINTF
+#cmakedefine HAVE_NUMPY
 #cmakedefine HAVE_OCC
 #cmakedefine HAVE_OPENGL
 #cmakedefine HAVE_OSMESA
diff --git a/Solver/functionNumpy.h b/Solver/functionNumpy.h
new file mode 100644
index 0000000000000000000000000000000000000000..bfce74bc37a441b628ac629bb25dec3f6e001f06
--- /dev/null
+++ b/Solver/functionNumpy.h
@@ -0,0 +1,80 @@
+#ifndef _FUNCTION_NUMPY_H_
+#define _FUNCTION_NUMPY_H_
+#include "GmshConfig.h"
+#ifdef HAVE_NUMPY
+#include "Python.h"
+#include "numpy/arrayobject.h"
+
+class functionNumpy : public function {
+  PyObject *_pycallback;
+  std::vector<fullMatrix<double> > args;
+public:
+  static PyObject *pyArrayFromFullMatrix(fullMatrix<double> &m) {
+    long int n[2] = {m.size1(), m.size2()};
+    return PyArray_New(&PyArray_Type, 2, n, NPY_DOUBLE, NULL, &m(0, 0), 0, NPY_FARRAY, NULL);
+  }
+  void call (dataCacheMap *m, fullMatrix<double> &res) 
+  {
+    PyObject *swigR;
+    PyObject *pyargs;
+    std::vector<PyObject*> swigA(args.size());
+    swigR = pyArrayFromFullMatrix(res);
+    for (int i = 0; i < args.size(); i++) {
+      swigA[i] = pyArrayFromFullMatrix(args[i]);
+    }
+    switch(args.size()) {
+      case 0 : pyargs = Py_BuildValue("(N)", swigR); break;
+      case 1 : pyargs = Py_BuildValue("(NN)", swigR, swigA[0]); break;
+      case 2 : pyargs = Py_BuildValue("(NNN)", swigR, swigA[0], swigA[1]); break;
+      case 3 : pyargs = Py_BuildValue("(NNNN)", swigR, swigA[0], swigA[1], swigA[2]); break;
+      case 4 : pyargs = Py_BuildValue("(NNNNN)", swigR, swigA[0], swigA[1], swigA[2], swigA[3]); break;
+      case 5 : pyargs = Py_BuildValue("(NNNNNN)", swigR, swigA[0], swigA[1], swigA[2], swigA[3], swigA[4]); break;
+      case 6 : pyargs = Py_BuildValue("(NNNNNNN)", swigR, swigA[0], swigA[1], swigA[2], swigA[3], swigA[4], swigA[5]); break;
+      case 7 : pyargs = Py_BuildValue("(NNNNNNNN)", swigR, swigA[0], swigA[1], swigA[2], swigA[3], swigA[4], swigA[5], swigA[6]); break;
+      case 8 : pyargs = Py_BuildValue("(NNNNNNNNN)", swigR, swigA[0], swigA[1], swigA[2], swigA[3], swigA[4], swigA[5], swigA[6], swigA[7]); break;
+      default:Msg::Error("python function not implemented for more than 8 arguments");
+    }
+    PyObject *result = PyEval_CallObject(_pycallback, pyargs);
+    if (result) {
+      Py_DECREF(result);
+    }
+    else {
+      PyErr_Print();
+      Msg::Fatal("An error occurs in the python function.");
+    }
+/*    for (int i = 0; i < args.size(); i++) {
+      Py_DECREF(swigA[i]);
+    }
+    Py_DECREF(swigR);*/
+  }
+  functionNumpy (int nbCol, PyObject *callback, std::vector<const function*> dependencies)
+    : function(nbCol), _pycallback(callback)
+  {
+    args.resize(dependencies.size());
+    for (int i = 0; i < dependencies.size(); i++) {
+      setArgument(args[i], dependencies[i]);
+    }
+    static bool _arrayImported = false;
+    if (! _arrayImported){
+      _import_array();
+      _arrayImported = true;
+    }
+  }
+  functionNumpy (int nbCol, PyObject *callback, std::vector<std::pair<const function*, int> > dependencies)
+    : function(nbCol), _pycallback(callback)
+  {
+    args.resize(dependencies.size());
+    for (int i = 0; i < dependencies.size(); i++) {
+      setArgument(args[i], dependencies[i].first, dependencies[i].second);
+    }
+    printf("import array !!!\n");
+    static bool _arrayImported = false;
+    if (! _arrayImported) {
+      printf("import array !!!\n");
+      _import_array();
+      _arrayImported = true;
+    }
+  }
+};
+#endif
+#endif
diff --git a/gmshpy/CMakeLists.txt b/gmshpy/CMakeLists.txt
index 9521b8628bbf86b9e1395741218e3c3a13aeb6e5..4933e7db41169735efc143d123f106ff5c1b71bf 100644
--- a/gmshpy/CMakeLists.txt
+++ b/gmshpy/CMakeLists.txt
@@ -56,37 +56,29 @@ MACRO(SWIG_GET_WRAPPER_DEPENDENCIES swigFile genWrapper language DEST_VARIABLE)
   ENDIF(NOT ${swig_getdeps_error} EQUAL 0)
 ENDMACRO(SWIG_GET_WRAPPER_DEPENDENCIES)
 
-if(ENABLE_SWIG)
-  find_package(SWIG)
-  if(SWIG_FOUND)
-    message(STATUS "Found SWIG version " ${SWIG_VERSION})
-    string(SUBSTRING ${SWIG_VERSION} 0 1 SWIG_MAJOR_VERSION)
-    if(SWIG_MAJOR_VERSION EQUAL 1)
-      message("WARNING: Python bindings require SWIG >= 2: disabling Python")
-    else(SWIG_MAJOR_VERSION EQUAL 1)
-      include(${SWIG_USE_FILE})
-      find_package(PythonLibs)
-      include_directories(${PYTHON_INCLUDE_DIR})
+if(HAVE_SWIG)
+  include(${SWIG_USE_FILE})
+  include_directories(${PYTHON_INCLUDE_DIR})
+  if(HAVE_NUMPY)
+    include_directories(${NUMPY_INC})
+    add_definitions(-DHAVE_NUMPY)
+  endif(HAVE_NUMPY)
 
-      foreach(module ${SWIG_MODULES})
-        set_source_files_properties(${module}.i PROPERTIES CPLUSPLUS ON)
+  foreach(module ${SWIG_MODULES})
+    set_source_files_properties(${module}.i PROPERTIES CPLUSPLUS ON)
 
-        # code backported from CMake git version, see CMake bug 4147
-        SWIG_GET_WRAPPER_DEPENDENCIES(${CMAKE_CURRENT_SOURCE_DIR}/\${module}.i ${CMAKE_CURRENT_BINARY_DIR}/${module}PYTHON_wrap.cxx python swig_extra_dependencies)
-        LIST(APPEND SWIG_MODULE_${module}_EXTRA_DEPS ${swig_extra_dependencies})
+    # code backported from CMake git version, see CMake bug 4147
+    SWIG_GET_WRAPPER_DEPENDENCIES(${CMAKE_CURRENT_SOURCE_DIR}/\${module}.i ${CMAKE_CURRENT_BINARY_DIR}/${module}PYTHON_wrap.cxx python swig_extra_dependencies)
+    LIST(APPEND SWIG_MODULE_${module}_EXTRA_DEPS ${swig_extra_dependencies})
 
-        swig_add_module(${module} python ${module}.i)
-        swig_link_libraries(${module} ${PYTHON_LIBRARIES} shared)
-        SET(GMSH_PYTHON_MODULES_INCLUDE_CODE 
-            "${GMSH_PYTHON_MODULES_INCLUDE_CODE}from ${module} import *\n")
-        list(APPEND GMSHPY_DEPENDS "_${module}")
-      endforeach(module)
-      add_custom_target("_gmshpy" DEPENDS ${GMSHPY_DEPENDS})
+    swig_add_module(${module} python ${module}.i)
+    swig_link_libraries(${module} ${PYTHON_LIBRARIES} shared)
+    SET(GMSH_PYTHON_MODULES_INCLUDE_CODE 
+        "${GMSH_PYTHON_MODULES_INCLUDE_CODE}from ${module} import *\n")
+    list(APPEND GMSHPY_DEPENDS "_${module}")
+  endforeach(module)
+  add_custom_target("_gmshpy" DEPENDS ${GMSHPY_DEPENDS})
 
-      configure_file(${CMAKE_CURRENT_SOURCE_DIR}/__init__.py.in 
-                     ${CMAKE_CURRENT_BINARY_DIR}/__init__.py)
-
-
-    endif(SWIG_MAJOR_VERSION EQUAL 1)
-  endif(SWIG_FOUND)
-endif(ENABLE_SWIG)
+  configure_file(${CMAKE_CURRENT_SOURCE_DIR}/__init__.py.in 
+                 ${CMAKE_CURRENT_BINARY_DIR}/__init__.py)
+endif(HAVE_SWIG)
diff --git a/gmshpy/gmshSolver.i b/gmshpy/gmshSolver.i
index 1d350c8b669e6cc209883ef4fe673200a248be8b..97832aa66a0c13a42f954b253acd2f401ca53efd 100644
--- a/gmshpy/gmshSolver.i
+++ b/gmshpy/gmshSolver.i
@@ -13,6 +13,7 @@
   #include "function.h"
   #include "functionDerivator.h"
   #include "functionPython.h"
+  #include "functionNumpy.h"
   #include "linearSystem.h"
   #include "linearSystemCSR.h"
   #include "linearSystemFull.h"
@@ -31,6 +32,7 @@ namespace std {
 %include "function.h"
 %include "functionDerivator.h"
 %include "functionPython.h"
+%include "functionNumpy.h"
 %include "linearSystem.h"
 %template(linearSystemDouble) linearSystem<double>;
 %template(linearSystemFullMatrixDouble) linearSystem<fullMatrix<double> >;