← Back to team overview

dolfin team mailing list archive

[Fwd: [Branch ~dolfin-core/dolfin/main] Rev 4352: Work on Expression in PyDOLFIN]

 

This change appears to have broken compiled expressions.

Garth

-------- Original Message --------
Subject: [Branch ~dolfin-core/dolfin/main] Rev 4352: Work on
Expression in	PyDOLFIN
Date: Mon, 30 Nov 2009 08:11:09 -0000
From: noreply@xxxxxxxxxxxxx
Reply-To: noreply@xxxxxxxxxxxxx
To: Garth Wells <gnw20@xxxxxxxxx>

------------------------------------------------------------
revno: 4352
committer: Johan Hake <johan.hake@xxxxxxxxx>
branch nick: dolfin
timestamp: Sun 2009-11-29 23:59:29 -0800
message:
  Work on Expression in PyDOLFIN
    - Simplify expression.py
      * I have split the logic in create_expression_class into on for
        python Expressions and one for compiled ones
      * Removed the possibilty of creating compiled classes that is
        not instantiated. (never used?)
    - Fixes in some typemaps
      * director typemaps for std::vector<double> &values now works
      * I have turned off director for eval(values,x). Could not get it
to work
        It now works through eval(values,data) in python
      * Got argout typemap for std::vector<double> & values to work.

  Bottom line we are up to par in features wrt Expression in PyDOLFIN
    - Plotting works
    - Subclassing in Python works for both eval and eval_data
    - CompiledExpressions work:
      * MultiLine expressions need to set its value shape if it is
        different from 0

  TODO:
    - Cleanup in the SWIG interface files and docstrings in expression.py
    - get_row, and set_row in GenericMatrix does not work as intended.
      Needed to sacrify this one...
modified:
  demo/pde/poisson/python/demo.py
  dolfin/function/Expression.cpp
  dolfin/function/Expression.h
  dolfin/swig/function_post.i
  dolfin/swig/function_pre.i
  dolfin/swig/std_vector_typemaps.i
  site-packages/dolfin/expression.py


--
lp:dolfin
https://code.launchpad.net/~dolfin-core/dolfin/main

Your team DOLFIN Core Team is subscribed to branch lp:dolfin.
To unsubscribe from this branch go to
https://code.launchpad.net/~dolfin-core/dolfin/main/+edit-subscription.



=== modified file 'demo/pde/poisson/python/demo.py'
--- demo/pde/poisson/python/demo.py	2009-11-29 21:17:18 +0000
+++ demo/pde/poisson/python/demo.py	2009-11-30 07:59:29 +0000
@@ -13,7 +13,7 @@
 """
 
 __author__ = "Anders Logg (logg@xxxxxxxxx)"
-__date__ = "2007-08-16 -- 2009-11-24"
+__date__ = "2007-08-16 -- 2009-11-29"
 __copyright__ = "Copyright (C) 2007-2009 Anders Logg"
 __license__  = "GNU LGPL Version 2.1"
 
@@ -25,7 +25,7 @@
 
 class Source(Expression):
     def eval(self, values, x):
-        values[0] = 4.0*DOLFIN_PI*DOLFIN_PI*DOLFIN_PI*DOLFIN_PI*sin(DOLFIN_PI*x[0])*sin(DOLFIN_PI*x[1])
+        values[0] = 10*exp(-((x[0] - 0.5)**2 + (x[1] - 0.5)**2) / 0.02)
 
 # Define Dirichlet boundary (x = 0 or x = 1)
 def boundary(x):
@@ -38,8 +38,8 @@
 # Define variational problem
 v = TestFunction(V)
 u = TrialFunction(V)
-#f = Expression("10*exp(-(pow(x[0] - 0.5, 2) + pow(x[1] - 0.5, 2)) / 0.02)")
-f = Source(V)
+f = Expression("10*exp(-(pow(x[0] - 0.5, 2) + pow(x[1] - 0.5, 2)) / 0.02)")
+#f = Source()
 g = Expression("sin(5*x[0])")
 a = inner(grad(v), grad(u))*dx
 L = v*f*dx - v*g*ds
@@ -53,4 +53,4 @@
 file << u
 
 # Plot solution
-#plot(u, interactive=True)
+plot(u, interactive=True)

=== modified file 'dolfin/function/Expression.cpp'
--- dolfin/function/Expression.cpp	2009-11-29 12:18:27 +0000
+++ dolfin/function/Expression.cpp	2009-11-30 07:59:29 +0000
@@ -2,7 +2,7 @@
 // Licensed under the GNU LGPL Version 2.1.
 //
 // First added:  2009-09-28
-// Last changed: 2009-10-11
+// Last changed: 2009-11-29
 //
 // Modified by Johan Hake, 2009.
 
@@ -114,8 +114,8 @@
 //-----------------------------------------------------------------------------
 void Expression::eval(std::vector<double>& values, const std::vector<double>& x) const
 {
-  eval(&values[0], x);
-  //error("Missing eval() for Expression (must be overloaded).");
+  //eval(&values[0], x);
+  error("Missing eval() for Expression (must be overloaded).");
 }
 //-----------------------------------------------------------------------------
 

=== modified file 'dolfin/function/Expression.h'
--- dolfin/function/Expression.h	2009-11-29 21:17:18 +0000
+++ dolfin/function/Expression.h	2009-11-30 07:59:29 +0000
@@ -2,7 +2,7 @@
 // Licensed under the GNU LGPL Version 2.1.
 //
 // First added:  2009-09-28
-// Last changed: 2009-10-11
+// Last changed: 2009-11-29
 
 #ifndef __EXPRESSION_H
 #define __EXPRESSION_H
@@ -75,13 +75,6 @@
     /// Evaluate expression, must be overloaded by user (simple version)
     virtual void eval(std::vector<double>& values, const std::vector<double>& x) const;
 
-    // Tempory fix while figuring out SWIG
-    virtual void eval(double* values, const std::vector<double>& x) const
-    {
-      cout << "In eval " << endl;
-      error("Missing eval() for Expression (must be overloaded).");
-    }
-
   protected:
 
     // Value shape

=== modified file 'dolfin/swig/function_post.i'
--- dolfin/swig/function_post.i	2009-11-16 15:13:08 +0000
+++ dolfin/swig/function_post.i	2009-11-30 07:59:29 +0000
@@ -25,16 +25,16 @@
 //-----------------------------------------------------------------------------
 // Extend the Data class with an accessor function for the x coordinates
 //-----------------------------------------------------------------------------
-//%extend dolfin::Data {
-//  PyObject* x_() {
-//    npy_intp adims[1];
-//    adims[0] = self->cell().dim();
-//    PyArrayObject* array = reinterpret_cast<PyArrayObject*>(PyArray_SimpleNewFromData(1, adims, NPY_DOUBLE, (char *)(self->x)));
-//    if ( array == NULL ) return NULL;
-//    PyArray_INCREF(array);
-//    return reinterpret_cast<PyObject*>(array);
-//  }
-//}
+%extend dolfin::Data {
+  PyObject* x_() {
+    npy_intp adims[1];
+    adims[0] = self->cell().dim();
+    PyArrayObject* array = reinterpret_cast<PyArrayObject*>(PyArray_SimpleNewFromData(1, adims, NPY_DOUBLE, reinterpret_cast<char *>( &(const_cast<std::vector<double>& >(self->x))[0] )));
+    if ( array == NULL ) return NULL;
+    PyArray_INCREF(array);
+    return reinterpret_cast<PyObject*>(array);
+  }
+}
 
 //-----------------------------------------------------------------------------
 // Clear director typemaps
@@ -42,3 +42,4 @@
 %clear const double* x;
 %clear double* y;
 %clear const std::vector<double>& x;
+%clear std::vector<double>& values;

=== modified file 'dolfin/swig/function_pre.i'
--- dolfin/swig/function_pre.i	2009-11-29 21:17:18 +0000
+++ dolfin/swig/function_pre.i	2009-11-30 07:59:29 +0000
@@ -9,7 +9,7 @@
 // Modified by Kent-Andre Mardal, 2009
 // 
 // First added:  2007-08-16
-// Last changed: 2009-10-07
+// Last changed: 2009-11-29
 
 // ===========================================================================
 // SWIG directives for the DOLFIN function kernel module (pre)
@@ -60,8 +60,7 @@
 //-----------------------------------------------------------------------------
 %ignore dolfin::Data::x;
 %rename (x) dolfin::Data::x_();
-%ignore dolfin::Expression::eval(std::vector<double>& values, const std::vector<double>& x) const;
-//%ignore dolfin::Expression::eval(double* values, const std::vector<double>& x) const;
+//%ignore dolfin::Expression::eval(std::vector<double>& values, const std::vector<double>& x) const;
 
 //-----------------------------------------------------------------------------
 // Modifying the interface of Constant
@@ -118,19 +117,18 @@
 %feature("novaluewrapper") std::vector<double>; 
 
 //-----------------------------------------------------------------------------
-// Instantiate a dummy std::vector<dolfin::uint> so value wrapper is not used
+// Instantiate a dummy std::vector<dolfin::double> so value wrapper is not used
 //-----------------------------------------------------------------------------
 %template () std::vector<double>; 
 
 //-----------------------------------------------------------------------------
-// Typemap for std::vector<dolfin::uint> values
+// Typemap for std::vector<dolfin::double> values (used in Constant constructor)
 //-----------------------------------------------------------------------------
-//%typecheck(SWIG_TYPECHECK_DOUBLE_ARRAY) std::vector<double> values
-//{
-//  $1 = PyList_Check($input) ? 1 : 0;
-//}
+%typecheck(SWIG_TYPECHECK_DOUBLE_ARRAY) std::vector<double> values
+{
+  $1 = PyList_Check($input) ? 1 : 0;
+}
 
-/*
 %typemap (in) std::vector<double> values
 {
   if (PyList_Check($input))
@@ -153,7 +151,7 @@
     SWIG_exception(SWIG_TypeError, "expected list of floats");
   }
 }
-*/
+
 //-----------------------------------------------------------------------------
 // Add director classes
 //-----------------------------------------------------------------------------
@@ -163,28 +161,14 @@
 %feature("nodirector") dolfin::Expression::gather;
 %feature("nodirector") dolfin::Expression::value_dimension;
 %feature("nodirector") dolfin::Expression::value_rank;
+%feature("nodirector") dolfin::Expression::eval(std::vector<double>& values, const  std::vector<double>& x) const;
 
 //-----------------------------------------------------------------------------
 // Director typemap for values in Expression
 //-----------------------------------------------------------------------------
-%typemap(directorin) double* values 
-{
-  {
-    // Compute size of value (number of entries in tensor value)
-    dolfin::uint size = 1;
-    for (dolfin::uint i = 0; i < this->value_rank(); i++)
-      size *= this->value_dimension(i);
-
-    npy_intp dims[1] = {size};
-    $input = PyArray_SimpleNewFromData(1, dims, NPY_DOUBLE, 
-                                       reinterpret_cast<char*>($1_name));
-  }
-}
-
 %typemap(directorin) std::vector<double>& values 
 {
   {
-    std::cout << "In typemap " << std::endl;
     // Compute size of x
     npy_intp dims[1] = {$1_name.size()};
     $input = PyArray_SimpleNewFromData(1, dims, NPY_DOUBLE, 
@@ -195,18 +179,11 @@
 //-----------------------------------------------------------------------------
 // Director typemap for coordinates in Expression
 //-----------------------------------------------------------------------------
-//%typemap(directorin) const double* x {
-//  {
-//    // Compute size of x
-//    npy_intp dims[1] = {this->geometric_dimension()};
-//    $input = PyArray_SimpleNewFromData(1, dims, NPY_DOUBLE, reinterpret_cast<char *>(const_cast<double*>($1_name)));
-//  }
-//}
-
 // FIXME: Is there a better way to map a std::vector to a numpy array?
 %typemap(directorin) const std::vector<double>& x 
 {
   {
+    std::cout << "In typemap & x" << std::endl;
     // Compute size of x
     npy_intp dims[1] = {$1_name.size()};
     $input = PyArray_SimpleNewFromData(1, dims, NPY_DOUBLE, 
@@ -214,3 +191,43 @@
   }
 }
 
+////-----------------------------------------------------------------------------
+//// In typemaps for std::vector<double> _array
+////-----------------------------------------------------------------------------
+//%typemap(in) std::vector<double> & _array (std::vector<double> vec_tmp)
+//{
+//  // Check arguments
+//  if (!PyArray_Check($input)){
+//    PyErr_SetString(PyExc_TypeError, "numpy array of 'double' expected. Make sure that the numpy array use dtype='d'.");
+//    return NULL;
+//  }
+//  
+//  PyArrayObject *xa = reinterpret_cast<PyArrayObject*>(input);
+//  if (!PyArray_TYPE(xa) == NPY_DOUBLE ){
+//    PyErr_SetString(PyExc_TypeError, "numpy array of 'double' expected. Make sure that the numpy array use dtype='d'.");
+//    return NULL;
+//  }
+//  
+//  // Get size and reserve the tmp vector
+//  npy_int size = PyArray_Size(xa);
+//  vec_tmp.reserve(size);
+//  
+//  // Get the data
+//  double * data = static_cast<double*>(PyArray_DATA(xa));
+//  for (int i=0, i<size; i++)
+//    vec_tmp[i] = data[i];
+//
+//  // Provide the out argument
+//  $1 = &vec_tmp;
+//}
+//
+//%typecheck(SWIG_TYPECHECK_DOUBLE_ARRAY) std::vector<double> & values
+//{
+//    $1 = PyArray_Check($input) ? 1 : 0;
+//}
+//
+//%typecheck(SWIG_TYPECHECK_DOUBLE_ARRAY) const std::vector<double> & x
+//{
+//    $1 = PyArray_Check($input) ? 1 : 0;
+//}
+//

=== modified file 'dolfin/swig/std_vector_typemaps.i'
--- dolfin/swig/std_vector_typemaps.i	2009-11-29 21:17:18 +0000
+++ dolfin/swig/std_vector_typemaps.i	2009-11-30 07:59:29 +0000
@@ -3,7 +3,7 @@
 // Licensed under the GNU LGPL Version 2.1.
 //
 // First added:  2009-08-31
-// Last changed: 2009-09-29
+// Last changed: 2009-11-29
 
 //=============================================================================
 // In this file we declare what types that should be able to be passed using a
@@ -132,6 +132,7 @@
 //-----------------------------------------------------------------------------
 %typemap (in,numinputs=0) std::vector<TYPE>& ARG_NAME (std::vector<TYPE> vec_temp)
 {
+  // ARGOUT ARG_NAME
   $1 = &vec_temp;
 }
 
@@ -184,8 +185,11 @@
 IN_TYPEMAPS_STD_VECTOR_OF_POINTERS(FunctionSpace)
 
 ARGOUT_TYPEMAP_STD_VECTOR_OF_PRIMITIVES(dolfin::uint, INT32, cells, NPY_INT)
-ARGOUT_TYPEMAP_STD_VECTOR_OF_PRIMITIVES(dolfin::uint, INT32, columns, NPY_INT)
-ARGOUT_TYPEMAP_STD_VECTOR_OF_PRIMITIVES(double, DOUBLE, values, NPY_DOUBLE)
+// FIXME: We cannot have argout typemaps for columns and values
+// FIXME: They work for get_row, but they interfere with eval interface.
+// FIXME: They should also _not_ kick in for const std::vector<TYPE>, but they do
+//ARGOUT_TYPEMAP_STD_VECTOR_OF_PRIMITIVES(dolfin::uint, INT32, columns, NPY_INT)
+//ARGOUT_TYPEMAP_STD_VECTOR_OF_PRIMITIVES(double, DOUBLE, values, NPY_DOUBLE)
 
 //-----------------------------------------------------------------------------
 // NumPy to const std::vector<double>& typemap.
@@ -194,28 +198,6 @@
     $1 = PyArray_Check($input) ? 1 : 0;
 }
 
-%typemap(in) std::vector<double>& x (std::vector<double> temp)
-{
-  {
-    if (PyArray_Check($input)) 
-    {
-      PyArrayObject *xa = reinterpret_cast<PyArrayObject*>($input);
-      if ( PyArray_TYPE(xa) == NPY_DOUBLE )
-      {
-        const unsigned int size = PyArray_DIM(xa, 0);
-        temp.resize(size);
-        double* array = static_cast<double*>(PyArray_DATA(xa));
-        std::copy(array, array + size, temp.begin());
-        $1 = &temp;
-      }
-     else
-       SWIG_exception(SWIG_TypeError, "NumPy array expected");
-    }
-    else
-      SWIG_exception(SWIG_TypeError, "NumPy array expected");
-  }
-}
-
 %typemap(in) const std::vector<double>& x (std::vector<double> temp)
 {
   {
@@ -237,19 +219,64 @@
       SWIG_exception(SWIG_TypeError, "NumPy array expected");
   }
 }
-//-----------------------------------------------------------------------------
-// const std::vector<double>& to NumPy typemap.
-//-----------------------------------------------------------------------------
-%typemap(argout) const std::vector<double>& x
-{
-  // Do nothing
-}
-//-----------------------------------------------------------------------------
-// std::vector<double>& to NumPy typemap.
-//-----------------------------------------------------------------------------
-%typemap(argout) std::vector<double>& x
-{
-  SWIG_exception(SWIG_TypeError, "std::vector<double> to NumPy (argout) not implemented");
-}
-//-----------------------------------------------------------------------------
-
+
+//-----------------------------------------------------------------------------
+// std::vector<double>& to NumPy typemap.
+//-----------------------------------------------------------------------------
+%typemap(in) std::vector<double>& values (std::vector<double> temp, PyArrayObject *out_array = 0)
+{
+  if (!PyArray_Check($input))
+    SWIG_exception(SWIG_TypeError, "numpy array of 'double' expected. Make sure that the numpy array use dtype='d'.");
+  out_array = reinterpret_cast<PyArrayObject*>($input);
+  if ( !PyArray_TYPE(out_array) == NPY_DOUBLE )
+    SWIG_exception(SWIG_TypeError, "numpy array of 'double' expected. Make sure that the numpy array use dtype='d'.");
+  
+  // Use the size of the incomming array to pass a correct sized vector to the function
+  const unsigned int size = PyArray_DIM(out_array, 0);
+  temp.resize(size);
+  $1 = &temp;
+}
+
+%typemap(argout) std::vector<double>& values
+{
+  // Get the pointer to the data in the passed NumPy array
+  double* array = static_cast<double*>(PyArray_DATA(out_array$argnum));
+  
+  // Copy the content from the temp array to the NumPy array
+  std::copy(temp$argnum.begin(), temp$argnum.end(), array);
+  
+  // Tell the function to return 'None', which means not return value
+  $result = Py_None;
+  
+}
+
+//-----------------------------------------------------------------------------
+// std::vector<double>& to NumPy typemap.
+//-----------------------------------------------------------------------------
+%typemap(in) std::vector<double>& vertex_values (std::vector<double> temp, PyArrayObject *out_array = 0, dolfin::uint init_size = 0)
+{
+  if (!PyArray_Check($input))
+    SWIG_exception(SWIG_TypeError, "numpy array of 'double' expected. Make sure that the numpy array use dtype='d'.");
+  out_array = reinterpret_cast<PyArrayObject*>($input);
+  if ( !PyArray_TYPE(out_array) == NPY_DOUBLE )
+    SWIG_exception(SWIG_TypeError, "numpy array of 'double' expected. Make sure that the numpy array use dtype='d'.");
+  
+  // Use the size of the incomming array to pass a correct sized vector to the function
+  const unsigned int size = PyArray_DIM(out_array, 0);
+  init_size = size;
+  temp.resize(size);
+  $1 = &temp;
+}
+
+%typemap(argout) std::vector<double>& vertex_values
+{
+  // Get the pointer to the data in the passed NumPy array
+  double* array = static_cast<double*>(PyArray_DATA(out_array$argnum));
+  
+  // Copy the content from the temp array to the NumPy array
+  std::copy(temp$argnum.begin(), temp$argnum.end(), array);
+
+  // Tell the function to return 'None', which means not return value
+  $result = Py_None;
+  
+}

=== modified file 'site-packages/dolfin/expression.py'
--- site-packages/dolfin/expression.py	2009-11-28 21:18:15 +0000
+++ site-packages/dolfin/expression.py	2009-11-30 07:59:29 +0000
@@ -42,7 +42,6 @@
 __license__  = "GNU LGPL Version 2.1"
 
 # Modified by Anders Logg, 2008-2009.
-# Modified by Garth N. Wells, 2009.
 
 __all__ = ["Expression", "Expressions"]
 
@@ -64,96 +63,93 @@
 from compile_expressions import compile_expressions
 from functionspace import *
 
-def create_expression_class(name,
-                            cpp_base,
-                            user_bases = None,
-                            user_dict = None,
-                            dim_needs_to_be_passed = False):
+def create_compiled_expression_class(cpp_base):
+    # Check the cpp_base
+    assert(isinstance(cpp_base, (types.ClassType, type)))
+
+    def __init__(self, cpparg, defaults=None, element=None, degree=None):
+        """ Initialize the Expression """
+        # Initialize the cpp base class first and extract value_shape
+        cpp_base.__init__(self)
+        value_shape = tuple(self.value_dimension(i) \
+                                  for i in range(self.value_rank()))
+
+        # Store the dim 
+        if len(value_shape) == 0:
+            self._dim = 0
+        elif len(value_shape) == 1:
+            self._dim = value_shape[0]
+        else:
+            self._dim = value_shape
+
+        # Select an appropriate element if not specified
+        if element is None:
+            element = _auto_select_element_from_shape(value_shape, degree)
+        else:
+            # Check that we have an element
+            if not isinstance(element, ufl.FiniteElementBase):
+                raise TypeError, "The 'element' argument must be a UFL finite element."
+            
+            # Check same value shape of compiled expression and passed element
+            if not element.value_shape() == value_shape:
+                raise ValueError, "The value shape of the passed 'element', is not equal to the value shape of the compiled expression."
+
+        # Initialize UFL base class
+        self._ufl_element = element
+        ufl.Function.__init__(self, self._ufl_element)
+
+    # Create and return the class
+    return type("CompiledExpression", (Expression, ufl.Function, cpp_base), {"__init__":__init__})
+
+def create_python_derived_expression_class(name, user_bases, user_dict):
     """Return Expression class
 
     This function is used to create all the dynamically created Expression
     classes. It takes a name, and a compiled cpp.Expression and returns
-    a dolfin.Expression class. In addition to cpp.Expression and dolfin.Expression
-    it also inherits from ufl.Function.
+    a class that inherits the compiled class together with dolfin.Expression
+    and ufl.Function.
 
     @param name:
         The name of the class
-    @param cpp_base:
-        The cpp.Expression base class which the created
-        Expression class shall inherit.
     @param user_bases:
-        Optional user defined bases
+        User defined bases
     @param user_dict:
-        Optional dict with user specified function or attributes
-    @param dim_needs_to_be_passed:
-        Optional if a simple expression using cpparg is created with no
-        information about geometric dimensions
+        Dict with user specified function or attributes
     """
 
-    # Check the name
+    # Check args
     assert(isinstance(name, str))
-    assert(name != "Expression"), "Cannot create a sub class of Expression with the same name as Expression"
-
-    assert(isinstance(cpp_base, (types.ClassType, type)))
+    assert(isinstance(user_bases, list))
+    assert(isinstance(user_dict, dict))
 
     # Define the bases
-    user_bases = user_bases or []
     assert(all([isinstance(t, (types.ClassType, type)) for t in user_bases]))
-    bases = tuple([Expression, ufl.Function, cpp_base] + user_bases)
-
-    # Define the dictionary of the class
-    dict_ = user_dict or {}
-    assert isinstance(dict_, dict)
-
+    bases = tuple([Expression, ufl.Function, cpp.Expression] + user_bases)
+    
     # If a user init is not provided create a dummy one
-    if "__init__" not in dict_:
+    if "__init__" not in user_dict:
         def user_init(self, *arg, **kwargs): pass
     else:
-        user_init = dict_.pop("__init__")
-
-    # If a user init is not provided create a dummy one
-    if "dim" not in dict_:
-        def user_dim(self): return 1
-    else:
-        user_dim = dict_.pop("dim")
+        user_init = user_dict.pop("__init__")
 
     def __init__(self, *args, **kwargs):
-        # This is called if no user defined init function is provided
 
         # Get element and degree
-        element = kwargs.pop("element", None)
-        degree = kwargs.pop("degree", None)
+        element = kwargs.get("element", None)
+        degree = kwargs.get("degree", None)
 
         # Select an appropriate element if not specified
-        if element is None and len(args) > 0:
-            element = _auto_select_element_from_cpparg(args[0], degree)
-        elif element is None:
-            element = _auto_select_element_from_dim(user_dim(self), degree)
-
-        # Check that we have have an element
-        if not isinstance(element, ufl.FiniteElementBase):
+        if element is None:
+            element = _auto_select_element_from_dim(self.dim(), degree)
+        elif not isinstance(element, ufl.FiniteElementBase):
             raise TypeError, "The 'element' argument must be a UFL finite element."
-
+            
         # Initialize UFL base class
         self._ufl_element = element
         ufl.Function.__init__(self, self._ufl_element)
 
         # Initialize cpp_base class
-
-        # First check if we are instantiating a user-defined Python class
-        if "eval" in dict_ or "eval_data" in dict_:
-            assert cpp_base == cpp.Expression
-            cpp_base.__init__(self, list(self._ufl_element.value_shape()))
-        else:
-            cpp_base.__init__(self)
-
-        # Check that the value_shape of the ufl.FiniteElement corresponds with the
-        # created cpp.Expression
-        shape = self._ufl_element.value_shape()
-        if not (self.value_rank() == len(shape) and
-           all(dim == self.value_dimension(i) for i, dim in enumerate(shape))):
-            exp_shape = tuple(self.value_dimension(i) for i in xrange(self.value_rank()))
-            raise ValueError, "value_shape of passed element does not match value_shape of the Expression: %s != %s"%(str(shape), str(exp_shape))
+        cpp.Expression.__init__(self, list(self._ufl_element.value_shape()))
 
         # Calling the user defined_init
         user_init(self, *args, **kwargs)
@@ -165,6 +161,7 @@
         __init__.__doc__ = """ Initialize the Expression"""
 
     # NOTE: Do not prevent the user to overload attributes "reserved" by PyDOLFIN
+    # NOTE: Why not?
 
     ## Collect reserved attributes from both cpp.Function and ufl.Function
     #reserved_attr = dir(ufl.Function)
@@ -180,22 +177,22 @@
     #    if attr in dict_:
     #        raise TypeError, "The Function attribute '%s' is reserved by PyDOLFIN."%attr
 
-    # Fill the dict_ with constructed function
-    dict_["__init__"]  = __init__
+    # Add __init__ to the user_dict
+    user_dict["__init__"]  = __init__
 
     # Create the class and return it
-    return type(name, bases, dict_)
+    return type(name, bases, user_dict)
 
 class ExpressionMetaClass(type):
-
+    """ Meta Class for Expression"""
     def __new__(cls, name, bases, dict_):
-        """ Return a new Expression class """
+        """ Returns a new Expression class """
 
         assert(isinstance(name, str)), "Expecting a 'str'"
         assert(isinstance(bases, tuple)), "Expecting a 'tuple'"
         assert(isinstance(dict_, dict)), "Expecting a 'dict'"
 
-        # First check if we are creating the Function class
+        # First check if we are creating the Expression class
         if name == "Expression":
             # Assert that the class is _not_ a subclass of Expression,
             # i.e., a user have tried to:
@@ -209,7 +206,9 @@
             # this module
             return type.__new__(cls, name, bases, dict_)
 
-        # If subclassing Expression directly (used in specialfunctions.py)
+        # If creating a fullfledged derived expression class, i.e, inheriting
+        # dolfin.Expression, ufl.Function and cpp.Expression (or a subclass)
+        # then just return the new class.
         if len(bases) >= 3 and bases[0] == Expression and \
                bases[1] == ufl.Function and issubclass(bases[2], cpp.Expression):
             # Return the instantiated class
@@ -221,59 +220,28 @@
         # remove Expression, to be added later
         user_bases.remove(Expression)
 
-        # Check the cppcode and eval attributes
-        if 'cpparg' in dict_  and ('eval' in dict_ or 'eval_data' in dict_) :
-            raise TypeError, "Cannot create class with both 'eval'/'eval_data' and 'cpparg' attributes defined."
-
-        # If the Expression class is a user defined python class, case 4. from docstring
-        if 'eval' in dict_ or 'eval_data' in dict_:
-            # Get name of eval function
-            eval_name = 'eval' if 'eval' in dict_ else 'eval_data'
-
-            user_eval = dict_[eval_name]
-
-            # Check type and number of arguments of user_eval function
-            if not isinstance(user_eval, types.FunctionType):
-                raise TypeError, "'%s' attribute must be a 'function'"%eval_name
-            if not user_eval.func_code.co_argcount == 3:
-                raise TypeError, "The overloaded '%s' function must use three arguments"%eval_name
-
-            return create_expression_class(name, cpp.Expression, user_bases, dict_)
-
-        # If cpparg is provided, case 5. from docstring
-        if 'cpparg' in dict_:
-
-            # Check the handed attributes and return an args tuple
-            cpparg   = dict_.pop('cpparg')
-            defaults = dict_.pop("defaults",None)
-
-            # Check that the user has not provide any other attributes
-            # than the allowed ones.
-            if len(dict_) > 1:
-                dict_.pop('__module__')
-                raise TypeError, "Not allowed to provide user defined attributes to a sub class of Expression when the compiled function interface is used. Found: %s"%\
-                      (", ".join(["'%s'"%key for key in dict_.iterkeys()]))
-
-            # Check arguments
-            _check_cpparg(cpparg)
-            _check_defaults(defaults)
-
-            # Compile the cppargs
-            cpp_base = compile_expressions([cpparg], [defaults])[0]
-
-            # Add back the cpparg as an attribute
-            cpp_base.cpparg = cpparg
-
-            # If defaults where handed add it back too
-            if defaults is not None:
-                cpp_base.defaults = defaults
-
-            # Create the Expression class and return it
-            return create_expression_class(name, cpp_base, user_bases,
-                                           dim_needs_to_be_passed = not _is_complex_expression(cpparg))
-
-        # If we have reached this stage raise error
-        raise TypeError, "Error in subclassing Expression. For correct usage see 4. and 5. in Expression docstring."
+        # Check the user has provided either an eval or eval_data method
+        if not ('eval' in dict_ or 'eval_data' in dict_):
+            raise TypeError, "expected an overload 'eval' or 'eval_data' method"
+        
+        # Get name of eval function
+        eval_name = 'eval' if 'eval' in dict_ else 'eval_data'
+
+        user_eval = dict_[eval_name]
+
+        # Check type and number of arguments of user_eval function
+        if not isinstance(user_eval, types.FunctionType):
+            raise TypeError, "'%s' attribute must be a 'function'"%eval_name
+        if not user_eval.func_code.co_argcount == 3:
+            raise TypeError, "The overloaded '%s' function must use three arguments"%eval_name
+        # A nice hack to get around some SWIG director problems
+        # In short: eval_data works but not eval...
+        if eval_name == 'eval':
+            def eval_data(self, values, data):
+                user_eval(self, values, data.x())
+            dict_['eval_data'] = eval_data
+        
+        return create_python_derived_expression_class(name, user_bases, dict_)
 
 #--- The user interface ---
 
@@ -324,7 +292,6 @@
         return ufl.Function.__call__(self,*args)
 
     # Some help variables
-    #dim = self.geometric_dimension()
     value_size = ufl.common.product(self.ufl_element().value_shape())
 
     # If values (return argument) is passed, check the type and length
@@ -349,19 +316,14 @@
             raise TypeError, "expected a scalar or an iterable as coordinate argument"
         # Check for scalar x
         if isinstance(x[0], (int, float)):
-            #if not dim == 1:
-            #    raise TypeError, "expected a coordinate argument of length %d"%dim
             x = numpy.fromiter(x, 'd')
         else:
             x = x[0]
-            #if len(x) != dim:
-            #    raise TypeError, "expected an iterable of length %d as coordinate argument"%dim
             if isinstance(x, (list, tuple)):
                 x = numpy.fromiter(x, 'd')
 
     # If several x arguments have been provided
     else:
-        #if len(x) != dim or not all(isinstance(v,(int,float)) for v in x):
         if not all(isinstance(v,(int,float)) for v in x):
             raise TypeError, "expected different number of scalar arguments for the coordinates"
         x = numpy.fromiter(x,'d')
@@ -550,8 +512,8 @@
           Optional quadrature degree element.
         """
 
-        # If the __new__ function is called because we are instantiating a sub
-        # class of Expression, then use the object's __new__ function instead
+        # If the __new__ function is called because we are instantiating a python sub
+        # class of Expression, then just return a new instant of the passed class
         if cls.__name__ != "Expression":
             return object.__new__(cls)
 
@@ -562,85 +524,111 @@
         # Compile module and get the cpp.Expression class
         cpp_base = compile_expressions([cpparg], [defaults])[0]
 
-        # Store arguments for later use
+        # Store compile arguments for later use
         cpp_base.cpparg = cpparg
         cpp_base.defaults = defaults
-        cpp_base.element = element
-        cpp_base.degree = degree
-        return object.__new__(create_expression_class("CompiledExpression", cpp_base))
-
+
+        return object.__new__(create_compiled_expression_class(cpp_base))
+
+    # This method is only included so a user can check what arguments
+    # one should use in IPython using tab completion
+    def __init__(self, cpparg=None, defaults=None, element=None, degree=None):pass
+
+    # Reuse the docstring from __new__
+    __init__.__doc__ = __new__.__doc__
+        
     def ufl_element(self):
         " Return the ufl FiniteElement."
         return self._ufl_element
 
     def __str__(self):
+        "x.__str__() <==> print(x)"
         # FIXME: We might change this using rank and dimension instead
         return "<Expression on a %s>" % str(self._ufl_element)
 
     def __repr__(self):
+        "x.__repr__() <==> repr(x)"
         return ufl.Function.__repr__(self)
 
+    # Default value of dim
+    _dim = 0
+    
+    def dim(self):
+        """ Returns the dimension of the value"""
+        return self._dim
+
+    __call__ = expression__call__
+
 def Expressions(*args, **kwargs):
     """ Batch-processed user-defined JIT-compiled expressions
     -------------------------------------------------------
 
     By specifying several cppargs one may compile more than one expression
-    at a time. These may either be instantiated using a single FunctionSpace
-    common for all expressions, using the optional kwarg 'V', or with
-    a separate FunctionSpace for each cpparg:
+    at a time:
 
     >>> f0, f1 = Expressions('sin(x[0]) + cos(x[1])', 'exp(x[1])', degree=3)
-    >>> f0, f1 = Expressions('sin(x[0]) + cos(x[1])', 'exp(x[1])', element=element)
-
-    Here cppcode is a code snippet, which should be a string of C++
+
+    >>> f0, f1, f2 = Expressions((('A*sin(x[0])', 'B*cos(x[1])')
+                                 ('0','1')), {'A':2.0,'B':3.0},
+                                 code,
+                                 (('cos(x[0])','sin(x[1])'),
+                                 ('sin(x[0])','cos(x[1])')), element=element)
+
+    Here code is a C++ code snippet, which should be a string of C++
     code that implements a class that inherits from dolfin::Expression,
     see user case 3. in Expression docstring
 
     Batch-processing of JIT-compiled expressions may significantly speed up
     JIT-compilation at run-time.
-
-"""
+    """
 
     # Get the element/degree from kwarg
+    if len(kwargs) > 1:
+        raise TypeError, "Can only define one kwarg and that can only be 'degree' or 'element'."
     degree  = kwargs.pop("degree", None)
     element = kwargs.pop("element", None)
-    if len(kwargs) > 1:
-        raise TypeError, "Can only define one kwarg and that can only be 'degree' or 'element'."
 
     # Iterate over the *args and collect input to compile_expressions
     cppargs = []; defaults = []; i = 0;
-    while i < len(args):
+    while i < nargs:
+
+        # Check type of cppargs
         if not isinstance(args[i],(tuple, list, str)):
             raise TypeError, "Expected either a 'list', 'tuple' or 'str' for argument %d"%i
+        
         cppargs.append(args[i])
-        defaults.append(None)
         i += 1
 
+        # If we have more args and the next is a dict
+        if i < nargs and isinstance(args[i], dict):
+            # Append the dict to defaults
+            _check_defaults(args[i])
+            defaults.append(args[i])
+            i += 1
+        else:
+            # If not append None
+            defaults.append(None)
+
     # Compile the cpp.Expressions
     cpp_bases = compile_expressions(cppargs, defaults)
 
     # Instantiate the return arguments
     return_expressions = []
-    for i, cpp_base in enumerate(cpp_bases):
-        return_expressions.append(create_expression_class("CompiledExpression", cpp_base)
-                                 (cppargs[i], element=element, degree=degree))
+
+    for cpp_base in cpp_bases:
+        # If we only want the cpp.Expression
+        return_expressions.append(create_compiled_expression_class(cpp_base)(\
+            degree=degree,
+            element=element))
 
     # Return the instantiated Expressions
     return tuple(return_expressions)
 
-# Assign doc string
-expression__call__.__doc__
-
-# Assign __call__ method
-Expression.__call__ = types.MethodType(expression__call__, None, Expression)
-
 #--- Utility functions ---
 
 def _check_cpparg(cpparg):
     "Check that cpparg makes sense"
 
-    if cpparg is None: return
-
     # Check that we get a string expression or nested expression
     if not isinstance(cpparg, (str, tuple, list)):
         raise TypeError, "Please provide a 'str', 'tuple' or 'list' for the 'cpparg' argument."
@@ -665,14 +653,6 @@
     "Check if cpparg is a complex expression"
     return isinstance(cpparg, str) and "class" in cpparg and "Expression" in cpparg
 
-def _auto_select_element_from_cpparg(cpparg, degree=None):
-    "Automatically select an appropriate element from cpparg."
-
-    # Use numpy to get the shape
-    shape = numpy.shape(cpparg)
-
-    return _auto_select_element_from_shape(shape, degree)
-
 def _auto_select_element_from_dim(dim, degree=None):
     "Automatically select an appropriate element from dim."
 
@@ -708,3 +688,12 @@
     cpp.info("Automatic selection of expression element: " + str(element))
 
     return element
+
+def _check_name_and_base(name, cpp_base):
+    # Check the name
+    assert(isinstance(name, str))
+    assert(name != "Expression"), "Cannot create a sub class of Expression with the same name as Expression"
+
+    assert(isinstance(cpp_base, (types.ClassType, type)))
+
+    



Follow ups