diff --git a/hysop/constants.py b/hysop/constants.py
index 7ccba265279bc7af6811ae875b33c589ba2c39b6..ca123a9eb14a81c0fc0bbf038ce658c169c938f6 100644
--- a/hysop/constants.py
+++ b/hysop/constants.py
@@ -147,6 +147,27 @@ BoundaryCondition = EnumFactory.create('BoundaryCondition',
           'NEUMANN', 'DIRICHLET' ])
 """Boundary conditions enum"""
 
+def boundary2str(b):
+    """Helper function to convert a BoundaryCondition to a short string."""
+    sstr = {
+        BoundaryCondition.NONE:                  'NONE',
+        BoundaryCondition.MIXED:                 'MIXED',
+        BoundaryCondition.PERIODIC:              'PER',
+        BoundaryCondition.HOMOGENEOUS_NEUMANN:   'HNEU',
+        BoundaryCondition.HOMOGENEOUS_DIRICHLET: 'HDIR',
+        BoundaryCondition.NEUMANN:               'NEU',
+        BoundaryCondition.DIRICHLET:             'DIR',
+    }
+    if b in sstr:
+        return sstr[b]
+    else:
+        return str(b)
+    
+def format_boundaries(lboundaries, rboundaries):
+    """Helper function format boundary conditions."""
+    return ','.join(('{}/{}'.format(boundary2str(lb), boundary2str(rb))
+                      for (lb,rb) in zip(lboundaries, rboundaries)))
+
 DomainExtension = EnumFactory.create('DomainExtension',
         ['PERIODIC', 'EVEN', 'ODD'])
 
diff --git a/hysop/constants.py.in b/hysop/constants.py.in
index 1149c4c46fd35e0da863e052473e272f2d109baa..35d1b4745174086d0fc3170849287f5e70e78700 100644
--- a/hysop/constants.py.in
+++ b/hysop/constants.py.in
@@ -146,6 +146,27 @@ BoundaryCondition = EnumFactory.create('BoundaryCondition',
           'HOMOGENEOUS_NEUMANN', 'HOMOGENEOUS_DIRICHLET', 
           'NEUMANN', 'DIRICHLET' ])
 """Boundary conditions enum"""
+        
+def boundary2str(b):
+    """Helper function to convert a BoundaryCondition to a short string."""
+    sstr = {
+        BoundaryCondition.NONE:                  'NONE',
+        BoundaryCondition.MIXED:                 'MIXED',
+        BoundaryCondition.PERIODIC:              'PER',
+        BoundaryCondition.HOMOGENEOUS_NEUMANN:   'HNEU',
+        BoundaryCondition.HOMOGENEOUS_DIRICHLET: 'HDIR',
+        BoundaryCondition.NEUMANN:               'NEU',
+        BoundaryCondition.DIRICHLET:             'DIR',
+    }
+    if b in sstr:
+        return sstr[b]
+    else:
+        return str(b)
+    
+def format_boundaries(lboundaries, rboundaries):
+    """Helper function format boundary conditions."""
+    return ','.join(('{}/{}'.format(boundary2str(lb), boundary2str(rb))
+                      for (lb,rb) in zip(lboundaries, rboundaries)))
 
 DomainExtension = EnumFactory.create('DomainExtension',
         ['PERIODIC', 'EVEN', 'ODD'])
diff --git a/hysop/fields/continuous_field.py b/hysop/fields/continuous_field.py
index e5e0c82e1d60f5b79bd44bb941a6027716127599..7ba53d130a0d917d8df4089d99293af3b5ff8414 100644
--- a/hysop/fields/continuous_field.py
+++ b/hysop/fields/continuous_field.py
@@ -244,7 +244,9 @@ class FieldContainerI(TaggedObject):
         pass
     
     @classmethod
-    def from_sympy_expressions(cls, name, exprs, space_symbols, pretty_name=None, dtype=None, **kwds):
+    def from_sympy_expressions(cls, name, exprs, space_symbols, 
+                                    scalar_name_prefix=None, scalar_pretty_name_prefix=None,
+                                    pretty_name=None,  **kwds):
         """
         Create a field wich has the same shape as exprs, with optional names.
         Expressions should be of kind sympy.Expr and are converted to FieldExpression: this
@@ -256,33 +258,66 @@ class FieldContainerI(TaggedObject):
         if isinstance(exprs, sm.Expr):
             raise NotImplementedError('Call self.from_sympy_expression instead.')
         check_instance(exprs, npw.ndarray, values=sm.Expr)
+        check_instance(name, str)
+        check_instance(pretty_name, (str, unicode), allow_none=True)
+        check_instance(scalar_name_prefix, str, allow_none=True)
+        check_instance(scalar_pretty_name_prefix, (str, unicode), allow_none=True)
+        if isinstance(pretty_name, unicode):
+            pretty_name = pretty_name.encode('utf-8')
+        if isinstance(scalar_pretty_name_prefix, unicode):
+            scalar_pretty_name_prefix = scalar_pretty_name_prefix.encode('utf-8')
+
         fields = npw.empty(shape=exprs.shape, dtype=object)
         fields[...] = None
-        for idx in npw.nditer(*exprs.shape):
-            _name        = name
-            _pretty_name = pretty_name
+        for idx in npw.ndindex(*exprs.shape):
+            if (scalar_name_prefix is not None):
+                sname = TensorField.default_name_formatter(scalar_name_prefix, idx)
+                if (scalar_pretty_name_prefix is not None):
+                    spname = TensorField.default_pretty_name_formatter(scalar_pretty_name_prefix, idx)
+                else:
+                    spname = TensorField.default_pretty_name_formatter(scalar_name_prefix, idx)
+            else:
+                # names will be autogenerated from sympy expression
+                sname  = None
+                spname = None
+
             fields[idx] = cls.from_sympy_expression(expr=exprs[idx], space_symbols=space_symbols,
-                            name=_name, pretty_name=_pname, dtype=dtype, **kwds)
+                            name=sname, pretty_name=spname, **kwds)
         return TensorField.from_field_array(name=name, pretty_name=pretty_name,
                                             fields=fields)
 
     @classmethod
     def from_sympy_expression(cls, expr, space_symbols, **kwds):
         from hysop.symbolic.field import FieldExpressionBuilder
+        from hysop.tools.field_utils import print_all_names
         assert 'lboundaries' not in kwds
         assert 'rboundaries' not in kwds
         assert 'domain' not in kwds
+
+        # determine names if not given
+        if ('name' not in kwds) or (kwds['name'] is None):
+            (name, pretty_name, var_name, latex_name) = print_all_names(expr)
+            kwds['name'] = name
+            kwds['pretty_name'] = pretty_name
+            kwds['var_name'] = var_name
+            kwds['latex_name'] = latex_name
+
+        # determine domain and boundary conditions
         fe = FieldExpressionBuilder.to_field_expression(
                 expr=expr, space_symbols=space_symbols, strict=True)
         kwds['domain']      = fe.domain
         kwds['lboundaries'] = fe.lboundaries
         kwds['rboundaries'] = fe.rboundaries
-        kwds['name'] = first_not_None(kwds.get('name', None), 'lol')
-        kwds['pretty_name'] = first_not_None(kwds.get('pretty_name', None), 'lol')
+
+        # deduce data type from field expression if not specified
+        kwds['dtype'] = first_not_None(kwds.get('dtype', None), fe.dtype)
+
+        # finally return create and return the ScalarField
         return ScalarField(**kwds)
         
 
     def gradient(self, name=None, pretty_name=None, 
+                       scalar_name_prefix=None, scalar_pretty_name_prefix=None,
                        directions=None, axis=-1, 
                        space_symbols=None,
                        dtype=None, **kwds):
@@ -290,11 +325,12 @@ class FieldContainerI(TaggedObject):
         Create a field capable of storing the gradient of self, 
         possibly altered.
         """
-        dim    = self.dim
-        ndim   = self.ndim
+        dim    = self.dim  # dimension of the domain
+        ndim   = self.ndim # number of dimension of the np.ndarray
+        frame = self.domain.frame
 
         directions = to_tuple(first_not_None(directions, range(dim)))
-        space_symbols = to_tuple(first_not_None(space_symbols, self.domain.frame.coords))
+        space_symbols = to_tuple(first_not_None(space_symbols, frame.coords))
         check_instance(directions, tuple, minval=0, maxval=self.dim-1, minsize=1, unique=True) 
         check_instance(axis, int, minval=-ndim, maxval=ndim-1)
         check_instance(space_symbols, tuple, values=SpaceSymbol, size=dim, unique=True)
@@ -306,50 +342,115 @@ class FieldContainerI(TaggedObject):
         else:
             shape = (ndirs,)
 
+        name = first_not_None(name, 'grad_{}'.format(self.name))
+        pretty_name = first_not_None(pretty_name, '{}{}'.format(nabla.encode('utf8'),
+                                     self.pretty_name))
+
         if shape==(1,):
-            expr = sm.Derivative(self.symbol, space_symbols[directions[0]])
+            expr = self.symbol(frame.time, *space_symbols).diff(space_symbols[directions[0]])
             return self.from_sympy_expression(expr=expr, space_symbols=space_symbols,
                                               name=name, pretty_name=pretty_name,
                                               dtype=dtype, **kwds)
         else:
             exprs = npw.empty(shape=shape, dtype=object)
-            for idx in npw.nditer(*shape):
+            for idx in npw.ndindex(*shape):
                 i = idx[:axis+1] + idx[axis+2:]
                 d = directions[idx[axis+1]]
-                exprs[idx] = sm.Derivative(self[i].symbol, space_symbols[d])
+                exprs[idx] = self[i].symbol(frame.time, *space_symbols).diff(space_symbols[d])
             return self.from_sympy_expressions(exprs=exprs, space_symbols=space_symbols,
                                                name=name, pretty_name=pretty_name,
+                                               scalar_name_prefix=scalar_name_prefix,
+                                               scalar_pretty_name_prefix=scalar_pretty_name_prefix,
                                                dtype=dtype, **kwds)
-    
-        #if shape==(1,):
-            #name  = first_not_None(name, '{d}{}_dx{}'.format(
-                                        #F.name, directions[0], d='d'))
-            #pname = first_not_None(pretty_name, u'{d}{}/{d}{x}{}'.format(
-                        #F.pretty_name.decode('utf-8'), 
-                        #subscript(directions[0]), d=partial, x=xsymbol))
-            #return self.field_like(name=name, pretty_name=pretty_name)
-        #else:
-            #name           = first_not_None(name, 'grad_{}'.format(self.name))
-            #pretty_name    = first_not_None(pretty_name, '{}{}'.format(nabla.encode('utf8'), 
-                                            #self.pretty_name))
-            #def make_field(idx, **fkwds): 
-                #i = idx[:axis+1] + idx[axis+2:]
-                #d = directions[idx[axis+1]]
-                
-                #if (ndim==0):
-                    #Fi = self
-                #else:
-                    #Fi = self[i]
 
-                #fkwds['dtype']       = first_not_None(dtype, Fi.dtype)
-                #fkwds['name']        = '{d}{}_{d}x{}'.format(Fi.name, d, d='d')
-                #fkwds['pretty_name'] = u'{d}{}/{d}{x}{}'.format(Fi.pretty_name.decode('utf-8'), 
-                                        #subscript(d), d=partial, x=xsymbol)
+    def laplacian(self, name=None, pretty_name=None, 
+                  scalar_name_prefix=None, scalar_pretty_name_prefix=None,
+                  dtype=None, **kwds):
+        from hysop.symbolic.field import laplacian
+        frame = self.domain.frame
+        exprs = laplacian(self.symbol(*frame.vars), frame)
+
+        name = first_not_None(name, 'laplacian_{}'.format(self.name))
+        pretty_name = first_not_None(pretty_name, u'\u0394{}'.format(
+                                     self.pretty_name.decode('utf-8')))
+        
+        if (exprs.size == 1):
+            expr = npw.asscalar(exprs)
+            return self.from_sympy_expression(expr=expr, space_symbols=frame.coords,
+                                              name=name, pretty_name=pretty_name,
+                                              dtype=dtype, **kwds)
+        else:
+            return self.from_sympy_expressions(exprs=exprs, space_symbols=frame.coords,
+                                               name=name, pretty_name=pretty_name,
+                                               scalar_name_prefix=scalar_name_prefix,
+                                               scalar_pretty_name_prefix=scalar_pretty_name_prefix,
+                                               dtype=dtype, **kwds)
 
-                #return Fi.field_like(**fkwds)
 
-            #return TensorField(name=name, pretty_name=pretty_name, domain=domain, shape=shape,
-                                #make_field=make_field, **kwds)
+    def div(self, name=None, pretty_name=None, 
+                  scalar_name_prefix=None, scalar_pretty_name_prefix=None,
+                  axis=-1, dtype=None, **kwds):
+        """
+        Create a field capable of storing the divergence of self, 
+        on chosen axis.
+        """
+        from hysop.symbolic.field import div
+        frame = self.domain.frame
+        exprs = npw.asarray(div(self.symbol(*frame.vars), frame))
+
+        name = first_not_None(name, 'div_{}'.format(self.name))
+        pretty_name = first_not_None(pretty_name, u'{}\u22c5{}'.format(nabla,
+                                     self.pretty_name.decode('utf-8')))
+        
+        if exprs.size in (0,1):
+            expr = npw.asscalar(exprs)
+            return self.from_sympy_expression(expr=expr, space_symbols=frame.coords,
+                                              name=name, pretty_name=pretty_name,
+                                              dtype=dtype, **kwds)
+        else:
+            return self.from_sympy_expressions(exprs=exprs, space_symbols=frame.coords,
+                                               name=name, pretty_name=pretty_name,
+                                               scalar_name_prefix=scalar_name_prefix,
+                                               scalar_pretty_name_prefix=scalar_pretty_name_prefix,
+                                               dtype=dtype, **kwds)
+
+    def curl(self, name=None, pretty_name=None, 
+                   scalar_name_prefix=None, scalar_pretty_name_prefix=None,
+                   dtype=None, **kwds):
+        """
+        Create a field capable of storing the curl of self, 
+
+        Only 2D and 3D fields are supported as the curl brings 
+        a 1-vector to a 2-vector (ie. a vector to a pseudoscalar 
+        in 2D and vector to a pseudovector in 3D). 
+
+        In 1D the curl is 0, and in 4D the curl would be a 6D 'field'.
+        """
+        from hysop.symbolic.field import curl
+        msg='Can only take curl for a 2D or 3D vector field.'
+        assert (self.dim in (2,3)) and (self.nb_components == self.dim), msg
+        frame = self.domain.frame
+        exprs = curl(self.symbol(*frame.vars), frame)
+
+        name = first_not_None(name, 'curl_{}'.format(self.name))
+        pretty_name = first_not_None(pretty_name, u'{}\u2227{}'.format(nabla,
+                                     self.pretty_name.decode('utf-8')))
+
+        if (self.dim==2):
+            return self.from_sympy_expression(expr=exprs, space_symbols=frame.coords,
+                                              name=name, pretty_name=pretty_name,
+                                              dtype=dtype, **kwds)
+        else:
+            return self.from_sympy_expressions(exprs=exprs, space_symbols=frame.coords,
+                                               name=name, pretty_name=pretty_name,
+                                               scalar_name_prefix=scalar_name_prefix,
+                                               scalar_pretty_name_prefix=scalar_pretty_name_prefix,
+                                               dtype=dtype, **kwds)
+
+    def rot(self, *args, **kwds):
+        """See curl."""
+        return self.curl(*args, **kwds)
+
     
     def get_attributes(self, *attrs):
         """
@@ -459,6 +560,7 @@ class ScalarField(NamedScalarContainerI, FieldContainerI):
 
     @debug
     def __new__(cls, domain, name, pretty_name=None,
+                var_name=None, latex_name=None,
                 initial_values=0, dtype=HYSOP_REAL,
                 lboundaries=None, rboundaries=None,
                 is_tmp=False, **kwds):
@@ -474,6 +576,12 @@ class ScalarField(NamedScalarContainerI, FieldContainerI):
         pretty_name: string or unicode, optional.
             A pretty name used for display whenever possible.
             Defaults to name.
+        var_name: string, optional.
+            A variable name used for code generation.
+            This will be passed to the symbolic representation of this field.
+        latex_name: string, optional.
+            A variable name used for latex generation.
+            This will be passed to the symbolic representation of this field.
         dtype: npw.dtype, optional, defaults to HYSOP_REAL
             Underlying data type of this field
         initial_values: numeric value, or tuple of numeric values, optional
@@ -510,8 +618,11 @@ class ScalarField(NamedScalarContainerI, FieldContainerI):
         periodicity: numpy.ndarray of bool
             Numpy array mask, True is axis is periodic, else False.
         """
-        check_instance(is_tmp, bool)
         check_instance(name, str)
+        check_instance(pretty_name, (str, unicode), allow_none=True)
+        check_instance(latex_name, str, allow_none=True)
+        check_instance(var_name, str, allow_none=True)
+        check_instance(is_tmp, bool)
 
         # Data type of the field
         if (dtype==npw.bool) or (dtype==bool):
@@ -569,7 +680,9 @@ class ScalarField(NamedScalarContainerI, FieldContainerI):
     
         # Symbolic representation of this field
         from hysop.symbolic.field import SymbolicField
-        obj._symbol = SymbolicField(field=obj)
+        obj._symbol = SymbolicField(field=obj, 
+                                    var_name=var_name, 
+                                    latex_name=latex_name)
 
         # Dictionnary of all the discretizations of this field.
         # keys are hysop.topology.topology.Topology,
@@ -649,31 +762,32 @@ class ScalarField(NamedScalarContainerI, FieldContainerI):
         return s
     
     def format_boundaries(self):
-        return ','.join(('{}/{}'.format(
-                          str(lb).replace('HOMOGENEOUS_','')[:3],
-                          str(rb).replace('HOMOGENEOUS_','')[:3]) 
-                          for (lb,rb) in zip(*self.boundaries)))
+        from hysop.constants import format_boundaries as fb
+        return fb(*self.boundaries)
 
     def long_description(self):
         """Long description of this field."""
         s = textwrap.dedent(
-        '''{}
+        '''
+        {}
           *name:           {}
-          *pname:          {}
+          *pretty_name:    {}
+          *var_name:       {}
+          *latex_name:     {}
           *dim:            {}
           *dtype:          {}
-          *symbolic repr.: {}
           *left  boundary: {}
           *right boundary: {}
           *initial values: {}
           *topology tags:  [{}]
         ''').format(self.full_tag,
-                self.name, self.pretty_name, self.dim,
-                self.dtype, self.symbol,
-                self.lboundaries.tolist(), self.rboundaries.tolist(),
+                self.name, self.pretty_name, 
+                self.symbol._var_name, self.symbol._latex_name,
+                self.dim, self.dtype,
+                self.lboundaries.tolist(), self.rboundaries.tolist(), 
                 self.initial_values,
                 ','.join([k.full_tag for k in self.discrete_fields.keys()]))
-        return s
+        return s[1:]
                 
     
     @debug
@@ -1004,7 +1118,7 @@ class TensorField(NamedTensorContainerI, FieldContainerI):
         '''
             {}
               *name:           {}
-              *pname:          {}
+              *pretty_name:    {}
               *dim:            {}
               *shape:          {}
               *nb_components:  {}
diff --git a/hysop/fields/default_fields.py b/hysop/fields/default_fields.py
index a9ae41167e84ad4e64234892bc9f61ae9fa8da33..462f00248b05fe55d319dc255483b57cecbaf537 100644
--- a/hysop/fields/default_fields.py
+++ b/hysop/fields/default_fields.py
@@ -53,7 +53,9 @@ def VorticityField(velocity, name=None, pretty_name=None, **kwds):
     assert velocity.nb_components == domain.dim, 'Invalid velocity Field.'
     name        = first_not_None(name, 'W')
     pretty_name = first_not_None(pretty_name, greak[24])
-    return velocity.curl(name=name, pretty_name=pretty_name, **kwds)
+    return velocity.curl(name=name, pretty_name=pretty_name, 
+            scalar_name_prefix=name, scalar_pretty_name_prefix=pretty_name,
+            **kwds)
 
 
 def DensityField(domain, name=None, pretty_name=None, **kwds):
diff --git a/hysop/fields/tests/test_fields.py b/hysop/fields/tests/test_fields.py
index b14a279eaede44f90a6c9f0466031960d4adf817..0284189b9f7ccb3e6b214ef1d06f6646d9d2e055 100644
--- a/hysop/fields/tests/test_fields.py
+++ b/hysop/fields/tests/test_fields.py
@@ -339,26 +339,38 @@ def domain_boundary_iterator(dim):
 
 
 def test_boundaries():
-    for dim in (1,2):
+    """This test checks that all boundaries are compatible for velocity and vorticity."""
+    for dim in (1,2,): #3,):
         i=0
         for (lbd, rbd) in domain_boundary_iterator(dim): 
             domain = Box(dim=dim, lboundaries=lbd, 
                                   rboundaries=rbd)
             V = VelocityField(domain)
-            print V.gradient()
-            W = VorticityField(V)
             S = ScalarField(name='S0', domain=domain)
+            divV  = V.div()
+            gradV = V.gradient()
+            lapV  = V.laplacian()
             print
             print 'DOMAIN BOUNDARIES:'
             print ' *boundaries=[{}]'.format(domain.format_boundaries())
+            print 'SCALAR BOUNDARIES:'
+            print ' *{} boundaries=[{}]'.format(S.pretty_name, S.format_boundaries())
             print 'VELOCITY BOUNDARIES:'
             for Vi in V.fields:
-                print ' *{} boundaries=[{}]'.format(Vi.name, Vi.format_boundaries())
-            print 'VORTICITY BOUNDARIES:'
-            for Wi in W.fields:
-                print ' *{} boundaries=[{}]'.format(Wi.name, Wi.format_boundaries())
-            print 'SCALAR BOUNDARIES:'
-            print ' *{} boundaries=[{}]'.format(S.name, S.format_boundaries())
+                print ' *{} boundaries=[{}]'.format(Vi.pretty_name, Vi.format_boundaries())
+            print '{} BOUNDARIES:'.format(divV.pretty_name)
+            print ' *{} boundaries=[{}]'.format(divV.pretty_name, divV.format_boundaries())
+            print '{} BOUNDARIES:'.format(gradV.pretty_name)
+            for gVi in gradV.fields:
+                print ' *{} boundaries=[{}]'.format(gVi.pretty_name, gVi.format_boundaries())
+            print '{} BOUNDARIES:'.format(lapV.pretty_name)
+            for lVi in lapV.fields:
+                print ' *{} boundaries=[{}]'.format(lVi.pretty_name, lVi.format_boundaries())
+            if (dim>1):
+                rotV = V.curl()
+                print '{} (VORTICITY) BOUNDARIES:'.format(rotV.pretty_name)
+                for Wi in rotV.fields:
+                    print ' *{} boundaries=[{}]'.format(Wi.pretty_name, Wi.format_boundaries())
     
 
 
diff --git a/hysop/symbolic/field.py b/hysop/symbolic/field.py
index d4d2215eccf447961802d985e6877f418decb731..5475b1ee36d80bdc391dbb1b8bd66a41a81c52d3 100644
--- a/hysop/symbolic/field.py
+++ b/hysop/symbolic/field.py
@@ -1,8 +1,11 @@
 from abc import abstractmethod
 from hysop.deps import sm
+from hysop.constants import BoundaryCondition
+
 from hysop.tools.numpywrappers import npw
 from hysop.tools.types import check_instance, first_not_None
 from hysop.tools.sympy_utils import get_derivative_variables
+from hysop.tools.numerics import find_common_dtype
         
 from hysop.fields.continuous_field import Field, TensorField
 from hysop.fields.discrete_field import DiscreteField, DiscreteTensorField
@@ -10,7 +13,6 @@ from hysop.symbolic import Symbol
 from hysop.symbolic.base import TensorBase, SymbolicTensor
 from hysop.symbolic.func import UndefinedFunction, AppliedSymbolicFunction, FunctionBase, \
                                 SymbolicFunctionTensor
-from hysop.constants import BoundaryCondition
 from hysop.domain.domain import Domain
 
 class FieldExpressionI(object):
@@ -26,20 +28,23 @@ class FieldExpressionI(object):
     def domain(self):
         pass
     
+    @abstractmethod
+    def dtype(self):
+        pass
+    
     @property
     def boundaries(self):
         return (self.lboundaries, self.rboundaries)
     
     def format_boundaries(self):
-        return ','.join(('{}/{}'.format(
-                          str(lb).replace('HOMOGENEOUS_','')[:3],
-                          str(rb).replace('HOMOGENEOUS_','')[:3]) 
-                          for (lb,rb) in zip(*self.boundaries)))
+        from hysop.constants import format_boundaries as fb
+        return fb(*self.boundaries)
    
 
 class FieldExpression(FieldExpressionI):
     def __init__(self, *args, **kwds):
         self._domain      = kwds.pop('domain', None)
+        self._dtype       = kwds.pop('dtype', None)
         self._lboundaries = kwds.pop('lboundaries', None)
         self._rboundaries = kwds.pop('rboundaries', None)
         super(FieldExpression, self).__init__(*args, **kwds)
@@ -74,6 +79,16 @@ class FieldExpression(FieldExpressionI):
         check_instance(dom, Domain)
         self._domain = dom 
 
+    @property
+    def dtype(self):
+        assert (self._dtype is not None)
+        return self._dtype
+    @dtype.setter
+    def dtype(self, dt):
+        assert (self._dtype is None)
+        check_instance(dt, npw.dtype)
+        self._dtype = dt 
+
 
 class FieldExpressionBuilder(object):
     class BoundaryIncompatibilityError(ValueError):
@@ -112,7 +127,8 @@ class FieldExpressionBuilder(object):
                     pass
                 e = _to_field_expression_impl(expr.args[0])
                 if cls.is_field_expr(e):
-                    lb, rb, domain = e.lboundaries.copy(), e.rboundaries.copy(), e.domain
+                    dtype, domain = e.dtype, e.domain
+                    lb, rb = e.lboundaries.copy(), e.rboundaries.copy(), 
                     assert len(space_symbols)==lb.size==rb.size
                     for xi in get_derivative_variables(expr):
                         assert xi in space_symbols, xi
@@ -121,6 +137,7 @@ class FieldExpressionBuilder(object):
                         rb[i] = cls.update_boundaries(rb[i], +1)
                     expr = DerivativeFieldExpr(e, *expr.args[1:])
                     expr.domain = domain
+                    expr.dtype  = dtype
                     expr.lboundaries = lb
                     expr.rboundaries = rb
                     return expr
@@ -129,10 +146,10 @@ class FieldExpressionBuilder(object):
             else:
                 func = expr.func
                 args = tuple(_to_field_expression_impl(a) for a in expr.args)
-                field_expression_args = filter(lambda x: cls.is_field_expr(x), args)
+                field_expression_args = tuple(filter(lambda x: cls.is_field_expr(x), args))
                 if field_expression_args:
                     try:
-                        return FieldExpression.make_expr(func, args)
+                        return cls.make_expr(func, *args)
                     except cls.BoundaryIncompatibilityError:
                         msg='\nError during the handling of expression {}.'.format(expr)
                         msg+='\nSome boundaries were not compatible:'
@@ -144,32 +161,34 @@ class FieldExpressionBuilder(object):
         fexpr = _to_field_expression_impl(expr)
         if strict and (not cls.is_field_expr(fexpr)):
             msg='\nError during the handling of expression {}.'.format(expr)
-            msg+='Could not determine boundaries because no FieldExpression '
+            msg+='\nCould not determine boundaries because no FieldExpression '
             msg+='was present in expression.'
             raise cls.InvalidExpression(msg)
         return fexpr
 
     @classmethod
-    def mk_expr(cls, func, *args):
+    def make_expr(cls, func, *args):
         check_instance(func, type)
-        field_expression_args = filter(lambda x: cls.is_field_expr(x), args)
-        if field_expression_args:
-            msg='No FieldExpression arguments.'
+        field_expression_args = tuple(filter(lambda x: cls.is_field_expr(x), args))
+        if not field_expression_args:
+            msg='No FieldExpression arguments present in args.'
             raise ValueError(msg)
         if not cls.check_boundary_compatibility(*field_expression_args):
             raise cls.BoundaryIncompatibilityError
+        fea0 = field_expression_args[0]
         new_func = type(func.__name__+'FieldExpr', (FieldExpression, func), {})
         new_expr = new_func(*args)
-        new_expr.domain      = args[0].domain
-        new_expr.lboundaries = args[0].lboundaries.copy()
-        new_expr.rboundaries = args[0].rboundaries.copy()
+        new_expr.dtype       = npw.dtype(find_common_dtype(*tuple(a.dtype for a in field_expression_args)))
+        new_expr.domain      = fea0.domain
+        new_expr.lboundaries = fea0.lboundaries.copy()
+        new_expr.rboundaries = fea0.rboundaries.copy()
         return new_expr
         
 
     @classmethod
-    def check_boundary_compatibility(arg0, *args):
+    def check_boundary_compatibility(cls, arg0, *args):
         check_instance(args, tuple, values=FieldExpressionI)
-        lb, rb = arg0.lboundaries, arg0.rboundaries
+        domain, lb, rb = arg0.domain, arg0.lboundaries, arg0.rboundaries
         if args:
             match  = all((domain == a.domain)   for a in args)
             match &= all(all(lb==a.lboundaries) for a in args)
@@ -180,7 +199,7 @@ class FieldExpressionBuilder(object):
 
         
 
-class FieldBase(FieldExpressionI, FunctionBase):
+class FieldBase(FunctionBase):
     def __new__(cls, field, idx=None, name=None, pretty_name=None, **kwds):
         check_instance(field, (Field, DiscreteField))
         assert (field.nb_components == 1) or (idx is not None), (field.nb_components, idx)
@@ -199,18 +218,6 @@ class FieldBase(FieldExpressionI, FunctionBase):
         hc += (self._field, self._index,)
         return hc
     
-    @property
-    def lboundaries(self):
-        return self._field.lboundaries
-    
-    @property
-    def rboundaries(self):
-        return self._field.rboundaries
-
-    @property
-    def domain(self):
-        return self._field.domain
-
     @property
     def field(self):
         """Get associated field."""
@@ -277,7 +284,7 @@ class SymbolicField(FieldBase, UndefinedFunction):
         return not (self==other)
 
 
-class AppliedSymbolicField(AppliedSymbolicFunction):
+class AppliedSymbolicField(FieldExpressionI, AppliedSymbolicFunction):
     """Applied scalar fields, hold a reference to a continuous field."""
     def __new__(cls, *args, **kwds):
         args = args if args else cls.field.domain.frame.vars
@@ -302,6 +309,23 @@ class AppliedSymbolicField(AppliedSymbolicFunction):
     def indexed_field(self):
         """Get a unique identifier for an indexed field component."""
         return (self.field, self.index)
+    
+    @property
+    def lboundaries(self):
+        return self.field.lboundaries
+    
+    @property
+    def rboundaries(self):
+        return self.field.rboundaries
+
+    @property
+    def domain(self):
+        return self.field.domain
+    
+    @property
+    def dtype(self):
+        return self.field.dtype
+
 
 class SymbolicFieldTensor(SymbolicFunctionTensor):
     """Symbolic tensor symbol."""
@@ -358,17 +382,20 @@ def grad(F, frame, axis=-1):
     return gradF.view(TensorBase)
 
 def div(F, frame, axis=-1):
-    assert isinstance(F, npw.ndarray)
-    assert F.shape[axis] == frame.dim
-    shape = F.shape
-    ndim  = F.ndim
-    axis = (axis+ndim)%ndim
-    
-    divF = npw.empty_like(F)
-    for idx in npw.ndindex(*shape):
-        divF[idx] = diff(F[idx], frame.coords[idx[axis]])
-    divF = divF.sum(axis=axis)
-    return divF.view(TensorBase)
+    if isinstance(F, npw.ndarray):
+        assert F.shape[axis] == frame.dim
+        shape = F.shape
+        ndim  = F.ndim
+        axis = (axis+ndim)%ndim
+        
+        divF = npw.empty_like(F)
+        for idx in npw.ndindex(*shape):
+            divF[idx] = diff(F[idx], frame.coords[idx[axis]])
+        divF = divF.sum(axis=axis)
+        return divF.view(TensorBase)
+    else:
+        assert frame.dim==1
+        return F.diff(frame.coords[0])
 
 def rot(F, frame):
     assert (frame.dim in (2,3))
diff --git a/hysop/symbolic/frame.py b/hysop/symbolic/frame.py
index a8743ce3889e78f663d9b665f2a17062d061f255..888e9303d2e541fe360960a92ac8c78009b03d43 100644
--- a/hysop/symbolic/frame.py
+++ b/hysop/symbolic/frame.py
@@ -31,6 +31,7 @@ class SymbolicFrame(object):
         """Get the time variable for conveniance."""
         return time_symbol
     
+    
     @property
     def dtime(self):
         """Get the infinitesimal time variable for conveniance."""
diff --git a/hysop/tools/field_utils.py b/hysop/tools/field_utils.py
index fe09283d7f5fa74f3768708149bca7057451507a..72004242c7d8e4ab5fb05ce49168583c75b206a2 100644
--- a/hysop/tools/field_utils.py
+++ b/hysop/tools/field_utils.py
@@ -1,6 +1,146 @@
 from hysop.tools.types import first_not_None, to_tuple
 from hysop.tools.sympy_utils import nabla, partial, subscript, subscripts, \
-                                    exponent, exponents, xsymbol
+                                    exponent, exponents, xsymbol, get_derivative_variables
+
+from sympy.printing.str import StrPrinter, StrReprPrinter
+from sympy.printing.ccode import C99CodePrinter
+from sympy.printing.latex import LatexPrinter
+
+class BasePrinter(object):
+    def print_Derivative(self, expr):
+        (bvar, pvar, vvar, lvar) = print_all_names(expr.args[0])
+        pvar = pvar.decode('utf-8')
+        all_xvars = get_derivative_variables(expr)
+        xvars   = tuple(set(all_xvars))
+        varpows = tuple(all_xvars.count(x) for x in xvars) 
+        bxvars  = tuple(print_name(x) for x in xvars)
+        pxvars  = tuple(print_pretty_name(x).decode('utf-8') for x in xvars)
+        vxvars  = tuple(print_var_name(x) for x in xvars)
+        lxvars  = tuple(print_latex_name(x) for x in xvars)
+        return DifferentialStringFormatter.format_pd(bvar, pvar, vvar, lvar,
+                                                     bxvars, pxvars, vxvars, lxvars,
+                                                     varpows=varpows)
+        
+    def _print(self, expr, **kwds):
+        try:
+            return super(BasePrinter, self)._print(expr, **kwds)
+        except:
+            print
+            msg='FATAL ERROR: {} failed to print expression {}.'
+            msg=msg.format(type(self).__name__, expr)
+            print msg
+            print
+            raise
+   
+
+class NamePrinter(BasePrinter, StrReprPrinter):
+    def _print(self, expr, **kwds):
+        if hasattr(expr, 'name'):
+            return expr.name
+        elif hasattr(expr, '_name'):
+            return expr._name
+        return super(NamePrinter, self)._print(expr, **kwds)
+    def _print_Derivative(self, expr):
+        return super(NamePrinter, self).print_Derivative(expr)[0]
+    def _print_Add(self, expr):
+        return super(NamePrinter, self)._print_Add(expr).replace(' ', '')
+    def _print_Mul(self, expr):
+        return super(NamePrinter, self)._print_Mul(expr).replace(' ', '')
+    def emptyPrinter(self, expr):
+        msg='\n{} does not implement _print_{}(self, expr).'
+        msg+='\nExpression is {}.'.format(expr)
+        msg+='\nExpression type MRO is:'
+        msg+='\n  *'+'\n  *'.join(t.__name__ for t in type(expr).__mro__)
+        msg=msg.format(self.__class__.__name__, expr.__class__.__name__)
+        raise NotImplementedError(msg)
+
+
+class PrettyNamePrinter(BasePrinter, StrPrinter):
+    def _print(self, expr, **kwds):
+        if hasattr(expr, 'pretty_name'):
+            return expr.pretty_name
+        elif hasattr(expr, '_pretty_name'):
+            return expr._pretty_name
+        return super(PrettyNamePrinter, self)._print(expr, **kwds)
+    def _print_Derivative(self, expr):
+        return super(PrettyNamePrinter, self).print_Derivative(expr)[1]
+    def emptyPrinter(self, expr):
+        msg='\n{} does not implement _print_{}(self, expr).'
+        msg+='\nExpression is {}.'.format(expr)
+        msg+='\nExpression type MRO is:'
+        msg+='\n  *'+'\n  *'.join(t.__name__ for t in type(expr).__mro__)
+        msg=msg.format(self.__class__.__name__, expr.__class__.__name__)
+        raise NotImplementedError(msg)
+
+
+class VarNamePrinter(BasePrinter, C99CodePrinter):
+    def _print(self, expr, **kwds):
+        if hasattr(expr, 'var_name'):
+            return expr.var_name
+        elif hasattr(expr, '_var_name'):
+            return expr._var_name
+        return super(VarNamePrinter, self)._print(expr, **kwds).replace(' ', '')
+    def _print_Derivative(self, expr):
+        return super(VarNamePrinter, self).print_Derivative(expr)[2]
+    def _print_Add(self, expr):
+        s = super(VarNamePrinter, self)._print_Add(expr)
+        s = s.replace(' + ', '_plus_').replace(' - ', '_minus_')
+        s = s.replace('+', 'plus_').replace('-', 'minus_')
+        return s
+    def _print_Mul(self, expr):
+        s = super(VarNamePrinter, self)._print_Mul(expr)
+        s = s.replace(' * ', '_times_')
+        return s
+    def emptyPrinter(self, expr):
+        msg='\n{} does not implement _print_{}(self, expr).'
+        msg+='\nExpression is {}.'.format(expr)
+        msg+='\nExpression type MRO is:'
+        msg+='\n  *'+'\n  *'.join(t.__name__ for t in type(expr).__mro__)
+        msg=msg.format(self.__class__.__name__, expr.__class__.__name__)
+        raise NotImplementedError(msg)
+
+
+class LatexNamePrinter(BasePrinter, LatexPrinter):
+    def _print(self, expr, **kwds):
+        if hasattr(expr, 'latex_name'):
+            return expr.latex_name
+        elif hasattr(expr, '_latex_name'):
+            return expr._latex_name
+        return super(LatexNamePrinter, self)._print(expr, **kwds)
+    def _print_Derivative(self, expr):
+        return super(LatexNamePrinter, self).print_Derivative(expr)[3]
+    def emptyPrinter(self, expr):
+        msg='\n{} does not implement _print_{}(self, expr).'
+        msg+='\nExpression is {}.'.format(expr)
+        msg+='\nExpression type MRO is:'
+        msg+='\n  *'+'\n  *'.join(t.__name__ for t in type(expr).__mro__)
+        msg=msg.format(self.__class__.__name__, expr.__class__.__name__)
+        raise NotImplementedError(msg)
+
+pbn = NamePrinter()
+ppn = PrettyNamePrinter()
+#pvn = VarNamePrinter()
+pln = LatexNamePrinter()
+
+def print_name(expr):
+    return pbn.doprint(expr)
+
+def print_pretty_name(expr):
+    return ppn.doprint(expr)
+
+def print_var_name(expr):
+    return VarNamePrinter().doprint(expr)
+
+def print_latex_name(expr):
+    return pln.doprint(expr)
+
+def print_all_names(expr):
+    name = print_name(expr)
+    pretty_name = print_pretty_name(expr)
+    var_name = print_var_name(expr)
+    latex_name = print_latex_name(expr)
+    return (name, pretty_name, var_name, latex_name)
+
 
 def to_str(*args):
     if len(args)==1:
@@ -181,6 +321,7 @@ class DifferentialStringFormatter(object):
                        varpows=1, var_components=None, xvars_components=None,
                        bdivide_fn=bdivide_fn, pdivide_fn=pdivide_fn, vdivide_fn=vdivide_fn, ldivide_fn=ldivide_fn, 
                        fsc=True, **kwds):
+
         for k in ('dpow', 'components', 'bvars', 'pvars', 'vvars', 'lvars', 'varpow'):
             assert k not in kwds, 'Cannot specify reserved keyword {}.'.format(k)
 
@@ -278,5 +419,5 @@ if __name__ == '__main__':
     _printDifferentialStringFormatter.format_pd(bvar, pvar, vvar, lvar, 
                                               bxvars, pxvars, vxvars, lxvars,
                                               varpows=varpows, xvars_components=xvars_components,
-                                              var_components=var_components), multiline=True)
+                                              var_components=var_components, multiline=True)
 
diff --git a/hysop/tools/sympy_utils.py b/hysop/tools/sympy_utils.py
index 91c59e3e124cfac7d60825306e6f0a17d08f23dd..d54ede72fb4754042ff79ebbe46a096aa8eac5a9 100644
--- a/hysop/tools/sympy_utils.py
+++ b/hysop/tools/sympy_utils.py
@@ -237,7 +237,6 @@ def tensor_xreplace(tensor,vars):
                 T[idx] = vars[symbol.name]
     return T
 
-
 def non_eval_xreplace(expr, rule):
     """
     Duplicate of sympy's xreplace but with non-evaluate statement included.