diff --git a/hysop/backend/device/opencl/opencl_array.py b/hysop/backend/device/opencl/opencl_array.py
index bb50347f6afd089181302a745d8d9d25fbb6da5c..caae51deaece578600a1fb8d128fd1755024d499 100644
--- a/hysop/backend/device/opencl/opencl_array.py
+++ b/hysop/backend/device/opencl/opencl_array.py
@@ -39,9 +39,19 @@ class OpenClArray(Array):
         backend.check_queue(handle.queue)
         super(OpenClArray,self).__init__(handle=handle, backend=backend, **kargs)
     
-    def s(self, name, **kwds):
+    def as_symbolic_array(self, name, **kwds):
+        """
+        Return a symbolic array variable that contain a reference to this array.
+        """
         from hysop.symbolic.array import OpenClSymbolicArray
-        return OpenClSymbolicArray(array=self, name=name, **kwds)
+        return OpenClSymbolicArray(memory_object=self, name=name, **kwds)
+    
+    def as_symbolic_buffer(self, name, **kwds):
+        """
+        Return a symbolic buffer variable that contain a reference to this array.
+        """
+        from hysop.symbolic.array import OpenClSymbolicBuffer
+        return OpenClSymbolicBuffer(memory_object=self, name=name, **kwds)
 
     def get_ndim(self):
         return self._handle.ndim
diff --git a/hysop/backend/device/opencl/opencl_symbolic.py b/hysop/backend/device/opencl/opencl_symbolic.py
index 577847c1876e133c8c947b7b964ad7aec4d87075..394e748943f81ef4f759a0b0ff7e7a2e9b99650b 100644
--- a/hysop/backend/device/opencl/opencl_symbolic.py
+++ b/hysop/backend/device/opencl/opencl_symbolic.py
@@ -16,13 +16,16 @@ from hysop.tools.numpywrappers import npw
 from hysop.fields.continuous_field import Field
 from hysop.parameters.tensor_parameter import TensorParameter
 from hysop.operator.base.custom_symbolic_operator import ValidExpressions, \
-        SymbolicExpressionParser, CustomSymbolicOperatorBase
+                        SymbolicExpressionParser, CustomSymbolicOperatorBase
 from hysop.backend.device.opencl.opencl_operator import OpenClOperator
-from hysop.constants import ComputeGranularity, SpaceDiscretization, TranspositionState, DirectionLabels, SymbolicExpressionKind
+from hysop.constants import ComputeGranularity, SpaceDiscretization, TranspositionState, \
+                            DirectionLabels, SymbolicExpressionKind
 from hysop.numerics.interpolation.interpolation import Interpolation
 from hysop.numerics.odesolvers.runge_kutta import TimeIntegrator
 from hysop.topology.cartesian_descriptor import CartesianTopologyDescriptors
-from hysop.backend.device.opencl.autotunable_kernels.custom_symbolic import OpenClAutotunableCustomSymbolicKernel
+from hysop.backend.device.opencl.autotunable_kernels.custom_symbolic import \
+                                                OpenClAutotunableCustomSymbolicKernel
+from hysop.tools.sympy_utils import subscript, subscripts
 
 class OpenClSymbolic(OpenClOperator):
     """
@@ -30,7 +33,8 @@ class OpenClSymbolic(OpenClOperator):
     that require custom symbolic kernels.
     """
     __default_method    = CustomSymbolicOperatorBase._CustomSymbolicOperatorBase__default_method
-    __available_methods = CustomSymbolicOperatorBase._CustomSymbolicOperatorBase__available_methods
+    __available_methods = \
+            CustomSymbolicOperatorBase._CustomSymbolicOperatorBase__available_methods
     
     @classmethod
     def default_method(cls):
@@ -44,6 +48,7 @@ class OpenClSymbolic(OpenClOperator):
         am.update(cls.__available_methods)
         return am
 
+
     @debug
     def __init__(self, **kwds):
         """
@@ -71,7 +76,56 @@ class OpenClSymbolic(OpenClOperator):
         check_instance(name, str)
         check_instance(exprs, tuple, values=ValidExpressions, minsize=1)
         self.expressions[name] = exprs
+
+    def symbolic_buffers(self, *names, **kwds):
+        from hysop.symbolic.array import OpenClSymbolicBuffer
+        buffers = ()
+        if ('count' in kwds):
+            count = kwds.pop('count')
+            assert len(names)==1
+            snames      = tuple(names[0]+subscript(i)           for i in xrange(count))         
+            var_names   = tuple('{}{}'.format(names[0], i)      for i in xrange(count))         
+            latex_names = tuple('{}_{{{}}}'.format(names[0], i) for i in xrange(count))
+        else:
+            snames     = names
+            varnames   = names
+            latexnames = names
+        for (name, var_name, latex_name) in zip(snames, var_names, latex_names):
+            check_instance(name, (str,unicode))
+            buf = OpenClSymbolicBuffer(name=name, var_name=var_name, latex_name=latex_name,
+                                                                    memory_object=None, **kwds)
+            buffers += (buf,)
+        return buffers
+
+    def symbolic_arrays(self, *names, **kwds):
+        from hysop.symbolic.array import OpenClSymbolicArray
+        arrays = ()
+        if ('count' in kwds):
+            count = kwds.pop('count')
+            assert len(names)==1
+            snames      = tuple(names[0]+subscript(i)           for i in xrange(count))         
+            var_names   = tuple('{}{}'.format(names[0], i)      for i in xrange(count))         
+            latex_names = tuple('{}_{{{}}}'.format(names[0], i) for i in xrange(count))
+        else:
+            snames     = names
+            varnames   = names
+            latexnames = names
+        for (name, var_name, latex_name) in zip(snames, var_names, latex_names):
+            check_instance(name, (str,unicode))
+            arr = OpenClSymbolicArray(name=name, var_name=var_name, latex_name=latex_name,
+                                                                    memory_object=None, **kwds)
+            arrays += (arr,)
+        return arrays
         
+    def symbolic_tmp_scalars(self, *names, **kwds):
+        from hysop.symbolic.tmp import TmpScalar
+        scalars = ()
+        for name in names:
+            check_instance(name, str)
+            tmp = TmpScalar(name=name, **kwds)
+            scalars += (tmp,)
+        return scalars
+
     @debug
     def handle_method(self, method):
         """
@@ -133,7 +187,7 @@ class OpenClSymbolic(OpenClOperator):
             _cmp('output_fields', output_fields, expr_info.output_fields, exprs)
             _cmp('input_params',  input_params,  expr_info.input_params,  exprs)
             _cmp('output_params', output_params, expr_info.output_params, exprs)
-            assert (0 <= self.cr <= expr_info.max_granularity), cr
+            assert (0 <= self.cr <= expr_info.max_granularity), self.cr
             expr_info.compute_granularity  = self.cr
             expr_info.time_integrator      = self.time_integrator
             expr_info.interpolation        = self.interpolation
@@ -149,7 +203,7 @@ class OpenClSymbolic(OpenClOperator):
         for expr_info in self.expr_infos.values():
             expr_info.extract_field_requirements()
 
-            dim        = expr_info.domain.dim
+            dim        = expr_info.dim
             field_reqs = expr_info.field_requirements
             direction  = expr_info.direction
             has_direction = expr_info.has_direction
@@ -162,11 +216,15 @@ class OpenClSymbolic(OpenClOperator):
             
             min_ghosts_per_components = {}
 
-            for (fields, is_input, iter_requirements) in zip((self.input_fields, self.output_fields), (True, False),
-                    (requirements.iter_input_requirements, requirements.iter_output_requirements)):
+            for (fields, is_input, iter_requirements) in \
+                    zip((self.input_fields, self.output_fields), (True, False),
+                    (requirements.iter_input_requirements, 
+                        requirements.iter_output_requirements)):
                 if not fields:
                     continue
                 for (field, td, req) in iter_requirements():
+                    if (field not in expr_info.input_fields):
+                        continue
                     min_ghosts = npw.int_zeros(shape=(field.nb_components, field.dim))
                     if has_direction:
                         req.axes = axes
@@ -190,7 +248,8 @@ class OpenClSymbolic(OpenClOperator):
                             req.max_ghosts = npw.minimum(_max_ghosts, req.max_ghosts)
                             min_ghosts[index] = _min_ghosts.copy()
                         else:
-                            req.min_ghosts[dim-1-direction] = max(G, req.min_ghosts[dim-1-direction])
+                            req.min_ghosts[dim-1-direction] = \
+                                    max(G, req.min_ghosts[dim-1-direction])
                             min_ghosts[index][dim-1-direction] = G
                         assert req.min_ghosts[dim-1-direction] >= G
                         assert req.max_ghosts[dim-1-direction] >= G
@@ -200,7 +259,8 @@ class OpenClSymbolic(OpenClOperator):
 
             expr_info.min_ghosts = {k:npw.max(v, axis=0) for (k,v) in \
                                             min_ghosts_per_components.iteritems()}
-            expr_info.min_ghosts_per_components = {field:gpc[:,-1-direction] for (field,gpc) in min_ghosts_per_components.iteritems()}
+            expr_info.min_ghosts_per_components = {field:gpc[:,-1-direction] 
+                                for (field,gpc) in min_ghosts_per_components.iteritems()}
         return requirements
 
     @debug
@@ -231,7 +291,8 @@ class OpenClSymbolic(OpenClOperator):
                 build_opts=build_opts, autotuner_config=autotuner_config)
         
         for (name, expr_info) in self.expr_infos.iteritems():
-            kernel, args_dict, update_input_parameters = kernel_autotuner.autotune(expr_info=expr_info)
+            kernel, args_dict, update_input_parameters = \
+                    kernel_autotuner.autotune(expr_info=expr_info)
             kl = kernel.build_launcher(**args_dict)
             self.symbolic_kernels[name] = (kl, update_input_parameters)
 
diff --git a/hysop/backend/device/opencl/operator/poisson_rotational.py b/hysop/backend/device/opencl/operator/poisson_rotational.py
index f71551ff6a22538d94fce1252a78cf785a431b74..d5ee401c5ef81f0a4e6553a499d70de75a253d59 100644
--- a/hysop/backend/device/opencl/operator/poisson_rotational.py
+++ b/hysop/backend/device/opencl/operator/poisson_rotational.py
@@ -20,20 +20,20 @@ class OpenClPoissonRotational(PoissonRotationalOperatorBase, OpenClSymbolic):
     
     def initialize(self, **kwds):
         # request the projection kernel if required
-        if (projection != FieldProjection.NONE):
+        if (self.projection != FieldProjection.NONE):
             assert (self.dim == 3), self.dim
-            I    = local_indexes_symbols[:3]
-            K    = self.symbolic_buffers('Kx', 'Ky', 'Kz')
-            W    = self.symbolic_arrays('Wx', 'Wy', 'Wz')
-            divW = self.tmp_scalar('divW')
+            I     = local_indexes_symbols[:3]
+            K     = self.symbolic_buffers('K', count=3)
+            W     = self.symbolic_arrays('W', count=3)
+            divW, = self.symbolic_tmp_scalars('divW')
 
-            expr = Assignment(divW, sum(K[i][I[i]]*W[i]))
+            expr  = Assignment(divW, sum(K[i][I[i]]*W[i] for i in range(3)))
             exprs = (expr,)
             for i in xrange(3):
-                expr = Assignment(W[i], W[i] - K[i]*diwW)
+                expr   = Assignment(W[i], W[i] - K[i][I[i]]*divW)
                 exprs += (expr,)
-            
-            self.require_symbolic_kernel('solenoidal_reprojection_W', exprs)
+
+            self.require_symbolic_kernel('solenoidal_reprojection_W', *exprs)
             self.reprojection_buffers = (K,W)
 
 
@@ -91,7 +91,7 @@ class OpenClPoissonRotational(PoissonRotationalOperatorBase, OpenClSymbolic):
             K2d[start:end] = k2
             start = end
             if (self.projection != FieldProjection.NONE):
-                self.reprojection_buffers[0][i].bind_buffer(K1d[start:end])
+                self.reprojection_buffers[0][i].bind_memory_object(K1d[start:end])
         
         self.K1d      = K1d
         self.K2d      = K2d
@@ -120,16 +120,20 @@ class OpenClPoissonRotational(PoissonRotationalOperatorBase, OpenClSymbolic):
 
     @debug
     def setup(self, work):
+        fft_buffer, = work.get_buffer(self, 'R2C_C2R')
+        if (self.projection != FieldProjection.NONE):
+            N = npw.prod(sizes, dtype=npw.int64)
+            for i in xrange(3):
+                self.reprojection_buffers[1][i].bind_memory_object(fft_buffer[i*N:(i+1)*N])
         super(OpenClPoissonRotational, self).setup(work)
-        self._build_fft_plans(work)
+        self._build_fft_plans(fft_buffer)
         self._build_ghost_exchanger()
 
-    def _build_fft_plans(self, work):
+    def _build_fft_plans(self, fft_buffer):
         axes    = self.axes
         context = self.backend.cl_env.context
         queue   = self.backend.cl_env.default_queue
         
-        fft_buffer = work.get_buffer(self, 'R2C_C2R')[0]
         forward_plans, backward_plans = [],[]
         
         for (i,Wi) in enumerate(self.W_buffers):
diff --git a/hysop/backend/host/host_array.py b/hysop/backend/host/host_array.py
index c8f03287d93fc332a893a2902b46171ec0a013b9..d333f137e2faa29a00492a075669be080b19e17f 100644
--- a/hysop/backend/host/host_array.py
+++ b/hysop/backend/host/host_array.py
@@ -50,9 +50,19 @@ class HostArray(Array):
         # array interface
         self.__array_interface__ = handle.__array_interface__
 
-    def s(self, name, **kwds):
+    def as_symbolic_array(self, name, **kwds):
+        """
+        Return a symbolic array variable that contain a reference to this array.
+        """
         from hysop.symbolic.array import HostSymbolicArray
-        return HostSymbolicArray(array=self, name=name, **kwds)
+        return HostSymbolicArray(memory_object=self, name=name, **kwds)
+    
+    def as_symbolic_buffer(self, name, **kwds):
+        """
+        Return a symbolic buffer variable that contain a reference to this array.
+        """
+        from hysop.symbolic.array import HostSymbolicBuffer
+        return HostSymbolicBuffer(memory_object=self, name=name, **kwds)
    
     def get_ndim(self):
         return self.handle.ndim
diff --git a/hysop/core/arrays/array.py b/hysop/core/arrays/array.py
index 7795758896b4eea7332ea93a40b5208d1931c021..39912e4486072b744bb5423af042a147625a2cb7 100644
--- a/hysop/core/arrays/array.py
+++ b/hysop/core/arrays/array.py
@@ -136,12 +136,19 @@ class Array(object):
         return self.backend._call(f, *args, **kargs)
     
     @abstractmethod
-    def s(self, name, **kwds):
+    def as_symbolic_array(self, name, **kwds):
         """
         Return a symbolic array variable that contain a reference to this array.
         """
         pass
     
+    @abstractmethod
+    def as_symbolic_buffer(self, name, **kwds):
+        """
+        Return a symbolic buffer variable that contain a reference to this array.
+        """
+        pass
+    
     @abstractmethod
     @required_property
     def get_ndim(self):
diff --git a/hysop/operator/base/custom_symbolic_operator.py b/hysop/operator/base/custom_symbolic_operator.py
index 57b0c6e59929b8fa44be1fa5907509210afcad79..2afebee94d44885863220765bf5b99c89a1d12a8 100644
--- a/hysop/operator/base/custom_symbolic_operator.py
+++ b/hysop/operator/base/custom_symbolic_operator.py
@@ -17,11 +17,14 @@ from hysop.topology.cartesian_descriptor import CartesianTopologyDescriptors
 from hysop.symbolic import Dummy, space_symbols, dspace_symbols, time_symbol
 from hysop.symbolic.relational import Assignment
 from hysop.symbolic.misc import TimeIntegrate
+from hysop.symbolic.tmp import TmpScalar
+from hysop.symbolic.array import SymbolicArray, SymbolicBuffer
 from hysop.symbolic.field import AppliedSymbolicField, SymbolicDiscreteField
 from hysop.symbolic.parameter import SymbolicScalarParameter
 from hysop.symbolic.misc import ApplyStencil
 
-from hysop.constants import ComputeGranularity, SpaceDiscretization, TranspositionState, DirectionLabels, SymbolicExpressionKind
+from hysop.constants import ComputeGranularity, SpaceDiscretization, TranspositionState, \
+                            DirectionLabels, SymbolicExpressionKind
 from hysop.numerics.odesolvers.runge_kutta import TimeIntegrator, ExplicitRungeKutta, Euler, RK2, RK3, RK4
 from hysop.numerics.interpolation.interpolation import Interpolation
 from hysop.numerics.stencil.stencil_generator import StencilGenerator, CenteredStencilGenerator, MPQ
@@ -34,14 +37,30 @@ class ExprDiscretizationInfo(object):
         self.write_counter = {}
         self.parameters = {}
 
-    def read(self, field, index, count=1):
+    def read(self, obj, index, count=1):
         check_instance(count, int)
-        check_instance(field, DiscreteFieldView)
-        self.read_counter.setdefault(field.dfield, npw.int_zeros(shape=(field.nb_components,)))[index] += count
-    def write(self, field, index, count=1):
+        if isinstance(obj, DiscreteFieldView):
+            self.read_counter.setdefault(obj.dfield, 
+                        npw.int_zeros(shape=(obj.nb_components,)))[index] += count
+        elif isinstance(obj, (SymbolicArray, TmpScalar)):
+            self.read_counter.setdefault(obj, 0)
+            self.read_counter[obj] += 1
+        else:
+            msg='Unsupported type {}.'.format(type(obj))
+            raise TypeError(msg)
+
+    def write(self, obj, index=None, count=1):
         check_instance(count, int)
-        check_instance(field, DiscreteFieldView)
-        self.write_counter.setdefault(field.dfield, npw.int_zeros(shape=(field.nb_components,)))[index] += count
+        if isinstance(obj, DiscreteFieldView):
+            self.write_counter.setdefault(obj.dfield, 
+                        npw.int_zeros(shape=(obj.nb_components,)))[index] += count
+        elif isinstance(obj, (SymbolicArray, TmpScalar)):
+            self.write_counter.setdefault(obj, 0)
+            self.write_counter[obj] += 1
+        else:
+            msg='Unsupported type {}.'.format(type(obj))
+            raise TypeError(msg)
+
     def copy(self):
         obj = ExprDiscretizationInfo()
         for (field, counts) in self.read_counter.iteritems():
@@ -52,15 +71,25 @@ class ExprDiscretizationInfo(object):
             counter += counts
         obj.push_parameters(**self.parameters)
         return obj
+
     def update(self, other):
         check_instance(other, ExprDiscretizationInfo)
-        for (field, counts) in other.read_counter.iteritems():
-            counter = self.read_counter.setdefault(field, npw.int_zeros(shape=(field.nb_components,)))
-            counter += counts
-        for (field, counts) in other.write_counter.iteritems():
-            counter = self.write_counter.setdefault(field, npw.int_zeros(shape=(field.nb_components,)))
-            counter += counts
+        for (obj, counts) in other.read_counter.iteritems():
+            if isinstance(obj, AppliedSymbolicField):
+                counter = self.read_counter.setdefault(field, npw.int_zeros(shape=(field.nb_components,)))
+                counter += counts
+            else:
+                self.read_counter.setdefault(obj, 0)
+                self.read_counter[obj] += counts
+        for (obj, counts) in other.write_counter.iteritems():
+            if isinstance(obj, AppliedSymbolicField):
+                counter = self.write_counter.setdefault(obj, npw.int_zeros(shape=(field.nb_components,)))
+                counter += counts
+            else:
+                self.write_counter.setdefault(obj, 0)
+                self.write_counter[obj] += counts
         self.push_parameters(**other.parameters)
+
     def push_parameters(self, *param, **kwd_params):
         self.parameters.update(**kwd_params)
         for p in param:
@@ -97,10 +126,13 @@ class SymbolicExpressionInfo(object):
         
         # continuous part
         self.domain = None
+        self.input_arrays   = {}
+        self.output_arrays  = {}
+        self.input_buffers  = {}
         self.input_fields   = {}
         self.output_fields  = {}
-        self.input_params  = {}
-        self.output_params = {}
+        self.input_params   = {}
+        self.output_params  = {}
         self.direction = None
         self.has_direction = None
 
@@ -125,18 +157,18 @@ class SymbolicExpressionInfo(object):
         self.input_dfields  = None
         self.output_dfields = None
         self.inout_dfields = None
-        self.max_granularity = None
         self.discretization_info = None
         self.stencils = None
         self.tmp_vars = None
+        self._dim = None
 
     def _is_discretized(self):
         """Return true if the SymbolicExpressionInfo was discretized."""
         return (self.dexprs is not None)
     def _get_dim(self):
         """Shortcut to domain dimension."""
-        assert (self.domain is not None)
-        return self.domain.dim
+        assert (self._dim is not None)
+        return self._dim
     def _get_fields(self):
         """Return input and output fields."""
         fields = {k: v for (k,v) in self.input_fields.iteritems()}
@@ -147,6 +179,10 @@ class SymbolicExpressionInfo(object):
         fields = {k: v for (k,v) in self.input_params.iteritems()}
         fields.update(self.output_params)
         return fields
+
+    @property
+    def max_granularity(self):
+        return (self.dim - 1)
     
     dim        = property(_get_dim)
     fields     = property(_get_fields)
@@ -159,17 +195,41 @@ class SymbolicExpressionInfo(object):
     def check_field(self, field):
         """
         Check if given continuous field is compatible with previously
-        parsed fields.
+        parsed fields and arrays.
         """
         check_instance(field, Field)
         if (self.domain is None):
             self.domain = field.domain
-            self.max_granularity = self.dim - 1
-        else:
-            if (field.domain is not self.domain):
-                msg='Domain mismatch for field {}:\n{}\nReference domain was:\n{}.'
-                msg=msg.format(field.name, field.domain, self.domain)
+            if (self._dim is None):
+                self._dim = field.domain.dim
+            elif (self._dim != field.domain.dim):
+                msg='Dimension mismatch between field domain dimension and array dimension, '
+                msg+='got {} and {}.'.format(self._dim, field.domain.dim)
+                raise ValueError(msg)
+        elif (field.domain is not self.domain):
+            msg='Domain mismatch for field {}:\n{}\nReference domain was:\n{}.'
+            msg=msg.format(field.name, field.domain, self.domain)
+            raise ValueError(msg)
+
+    def check_array(self, array):
+        """
+        Check if given symbolic array is compatible with previously
+        parsed fields and arrays.
+        """
+        check_instance(array, SymbolicArray)
+        dim = array.dim
+        if (self.domain is not None):
+            if (self.domain.dim != dim):
+                msg='Dimension mismatch between field domain dimension and array dimension, '
+                msg+='got {} and {}.'.format(self.domain.dim, dim)
+                raise ValueError(msg)
+        elif (self._dim is not None):
+            if (self._dim != dim):
+                msg='Dimension mismatch between arrays, got {} and {}.'
+                msg=msg.format(self._dim, dim)
                 raise ValueError(msg)
+        else:
+            self._dim = dim
 
     def extract_field_requirements(self):
         field_requirements = SymbolicExpressionParser.extract_field_requirements(self)
@@ -180,12 +240,12 @@ class SymbolicExpressionInfo(object):
     def discretize_expressions(self, input_dfields, output_dfields):
         check_instance(input_dfields,  dict, keys=Field, values=DiscreteFieldView)
         check_instance(output_dfields, dict, keys=Field, values=DiscreteFieldView)
-        assert set(input_dfields.keys())  == set(self.input_fields.keys())
-        assert set(output_dfields.keys()) == set(self.output_fields.keys())
-        self.input_dfields  = input_dfields
-        self.output_dfields = output_dfields
+        assert len(set(self.input_fields.keys())  - set(input_dfields.keys())) == 0
+        assert len(set(self.output_fields.keys()) - set(output_dfields.keys())) == 0
+        self.input_dfields  = {k:v for (k,v) in input_dfields.iteritems()  if (k in self.input_fields)}
+        self.output_dfields = {k:v for (k,v) in output_dfields.iteritems() if (k in self.output_fields)}
         self.inout_dfields = {k:v for (k,v) in self.output_dfields.iteritems() 
-                if ((k in input_dfields) and (input_dfields[k].dfield is v.dfield))}
+                if ((k in self.input_dfields) and (self.input_dfields[k].dfield is v.dfield))}
         self.stencils = {}
         
         SymbolicExpressionParser.discretize_expressions(self)
@@ -215,7 +275,8 @@ class SymbolicExpressionInfo(object):
                     xd = space_symbols[direction]
                     if (xd != var):
                         msg='Expression already contained a derivative with respect to {} (direction {}).'
-                        msg+='\nFound a new derivative direction which is not compatible with the current one.'
+                        msg+='\nFound a new derivative direction which is not compatible with the current '
+                        msg+='one.'
                         msg+='\nCannot differentiate with respect to {}.'
                         msg=msg.format(xd, direction, var)
                         raise ValueError(msg)
@@ -238,8 +299,8 @@ class SymbolicExpressionInfo(object):
   '''.format(
     self.kind,
     '\n'+'\n'.join('    {}/ {}'.format(i,e) for i,e in enumerate(self.exprs)),
-    ', '.join('{}'.format(f.name) for f in self.input_fields.keys())      if self.input_fields      else 'none',
-    ', '.join('{}'.format(f.name) for f in self.output_fields.keys())     if self.output_fields     else 'none',
+    ', '.join('{}'.format(f.name) for f in self.input_fields.keys())    if self.input_fields      else 'none',
+    ', '.join('{}'.format(f.name) for f in self.output_fields.keys())   if self.output_fields     else 'none',
     ', '.join('{}'.format(p) for p in self.input_params.keys())  if self.input_params  else 'none',
     ', '.join('{}'.format(p) for p in self.output_params.keys()) if self.output_params else 'none',
     '\n'+'\n'.join('    {}: {}'.format(f.name, (d.short_description() if isinstance(d, TopologyView) 
@@ -249,8 +310,10 @@ class SymbolicExpressionInfo(object):
   min_ghosts_per_components:{}
   min_ghosts:{}
 '''.format(
-    '\n'+'\n'.join('    {}/ [{}]'.format(f.name,', '.join(str(x) for x in gpc)) for f,gpc in self.min_ghosts_per_components.iteritems()),
-    '\n'+'\n'.join('    {}/ [{}]'.format(f.name,', '.join(str(x) for x in g)) for f,g in self.min_ghosts.iteritems()))
+    '\n'+'\n'.join('    {}/ [{}]'.format(f.name,', '.join(str(x) for x in gpc)) 
+                                    for f,gpc in self.min_ghosts_per_components.iteritems()),
+    '\n'+'\n'.join('    {}/ [{}]'.format(f.name,', '.join(str(x) for x in g)) 
+                                                    for f,g in self.min_ghosts.iteritems()))
         if self.is_discretized:
             msg += '''
 
@@ -259,8 +322,10 @@ class SymbolicExpressionInfo(object):
   write_counter:  {}
 '''.format(
     '\n'+'\n'.join('    {}/ {}'.format(i,e) for i,e in enumerate(self.dexprs)),
-    ', '.join('{}{}'.format(f.name, self.discretization_info.read_counter[f.dfield])  for f in self.input_dfields.values())  if self.input_dfields  else 'none',
-    ', '.join('{}{}'.format(f.name, self.discretization_info.write_counter[f.dfield]) for f in self.output_dfields.values()) if self.output_dfields else 'none')
+    ', '.join('{}{}'.format(f.name, self.discretization_info.read_counter[f.dfield])
+                            for f in self.input_dfields.values())  if self.input_dfields  else 'none',
+    ', '.join('{}{}'.format(f.name, self.discretization_info.write_counter[f.dfield]) 
+                            for f in self.output_dfields.values()) if self.output_dfields else 'none')
         return msg
 
 
@@ -275,11 +340,15 @@ class SymbolicExpressionParser(object):
     def check_expressions(cls, exprs):
         kind = None
         fields = {}
+        arrays = {}
         for expr in exprs:
             check_instance(expr, ValidExpressions)
             lhs = expr.args[0]
-            field = lhs
-            if isinstance(lhs, AppliedSymbolicField):
+            field = None
+            array = None
+            if isinstance(lhs, TmpScalar):
+                continue
+            elif isinstance(lhs, (AppliedSymbolicField, SymbolicArray)):
                 if (kind is None):
                     kind = SymbolicExpressionKind.AFFECT
                 elif (kind is not SymbolicExpressionKind.AFFECT):
@@ -287,17 +356,24 @@ class SymbolicExpressionParser(object):
                     msg+=' an expression that is of kind {}.\n expr: {}'
                     msg=msg.format(kind, SymbolicExpressionKind.AFFECT, expr)
                     raise ValueError(msg)
+                if isinstance(lhs, AppliedSymbolicField):
+                    field = lhs
+                else:
+                    array = lhs
             elif isinstance(lhs, sm.Derivative):
-                field = lhs.args[0]
-                _vars = lhs.args[1:]
-                _t = time_symbol
+                lhs, _vars = lhs.args[0], lhs.args[1:]
+                _t    = time_symbol
                 unique_vars = set(_vars)
-                if not isinstance(field, AppliedSymbolicField):
+                if isinstance(lhs, AppliedSymbolicField):
+                    field = lhs
+                elif isinstance(lhs, SymbolicArray):
+                    array = lhs
+                else:
                     msg='Assignment LHS cannot be a derivative of a {}.'
                     msg=msg.format(type(field))
                     raise TypeError(msg)
                 if (_t not in unique_vars) or len(unique_vars)!=1:
-                    msg='Assignment LHS only be a derivative of time {}, got {}.'
+                    msg='Assignment LHS can only be a derivative of time {}, got {}.'
                     msg=msg.format(_t, ', '.join(str(x) for x in unique_vars))
                     raise TypeError(msg)
                 if (kind is None):
@@ -310,16 +386,31 @@ class SymbolicExpressionParser(object):
             else:
                 msg='Assignment LHS cannot be of type {}.'.format(type(lhs))
                 raise TypeError(msg)
+        
+            if (field is not None):
+                assert isinstance(field, AppliedSymbolicField)
+                index = field.index
+                field = field.field
+                key = (field, index)
+                if (key in fields):
+                    msg='Field {} was already written by expression\n'
+                    msg+='{}\ncannot write it again in expression\n'
+                    msg+='{}\nFATAL ERROR: Invalid expressions.'
+                    msg=msg.format(field.name, fields[key], expr)
+                    raise ValueError(msg)
+                fields[key] = expr
+            
+            if (array is not None):
+                assert isinstance(array, SymbolicArray)
+                key = array
+                if (key in arrays):
+                    msg='Zrray {} was already written by expression\n'
+                    msg+='{}\ncannot write it again in expression\n'
+                    msg+='{}\nFATAL ERROR: Invalid expressions.'
+                    msg=msg.format(array.name, arrays[key], expr)
+                    raise ValueError(msg)
+                arrays[key] = expr
 
-            assert isinstance(field, AppliedSymbolicField)
-            index = field.index
-            field = field.field
-            key = (field, index)
-            if (key in fields):
-                msg='Field {} was already written by expression\n  {}\ncannot write it again in expression\n  {}\nFATAL ERROR: Invalid expressions.'
-                msg=msg.format(field.name, fields[key], expr)
-                raise ValueError(msg)
-            fields[key] = expr
         return kind
 
     @classmethod
@@ -327,6 +418,16 @@ class SymbolicExpressionParser(object):
         info = SymbolicExpressionInfo(name, exprs, **kwds)
         for expr in exprs:
             cls.parse_one(variables, info, expr)
+        if (info._dim is None):
+            msg='\n\nFATAL ERROR: Neither SymbolicFields nor SymbolicArrays were present in parsed '
+            msg+='symbolic expressions.'
+            msg+='\nAt least one is needed to deduce the shape of the compute kernel.'
+            msg+='\n'
+            msg+='\nExpressions were:'
+            for (i,e) in enumerate(exprs):
+                msg+='\n  {:2>}/  {}'.format(i,e)
+            msg+='\n'
+            raise RuntimeError(msg)
         if (info.direction is None):
             info.direction = 0
         return info
@@ -343,12 +444,11 @@ class SymbolicExpressionParser(object):
     
     @classmethod
     def parse_assignment(cls, variables, info, lhs, rhs):
-        if isinstance(lhs, AppliedSymbolicField):
+        if isinstance(lhs, (AppliedSymbolicField, SymbolicArray, TmpScalar)):
             cls.write(variables, info, lhs)
             cls.parse_subexpr(variables, info, rhs)
         elif isinstance(lhs, sm.Derivative):
             f = lhs.args[0]
-            assert isinstance(f, AppliedSymbolicField), f
             cls.read(variables, info, f)
             cls.write(variables, info, f)
             cls.parse_subexpr(variables, info, rhs)
@@ -379,7 +479,16 @@ class SymbolicExpressionParser(object):
 
     @classmethod
     def write(cls, variables, info, var):
-        if isinstance(var, AppliedSymbolicField):
+        if isinstance(var, TmpScalar):
+            return
+        elif isinstance(var, SymbolicArray):
+            array = var
+            info.check_array(array)
+            if (array not in info.output_arrays):
+                info.output_arrays[array.name] = array
+            else:
+                assert info.output_arrays[array.name] is array
+        elif isinstance(var, AppliedSymbolicField):
             field = var.field
             info.check_field(field)
             if (field not in variables):
@@ -441,9 +550,12 @@ class SymbolicExpressionParser(object):
             lhs = expr.args[0]
             if isinstance(lhs, sm.Derivative):
                 lhs = lhs.args[0]
+            if not isinstance(lhs, AppliedSymbolicField):
+                continue
             field, index = lhs.field, lhs.index
             updated_fields[i] = (field, index, '{}_{}'.format(field.name, index))
-            min_ghosts_per_expr[i] = {'{}_{}'.format(k[0].name,k[1]):v.min_ghosts[-direction-1] for (k,v) in field_reqs.iteritems()}
+            min_ghosts_per_expr[i] = {'{}_{}'.format(k[0].name,k[1]):v.min_ghosts[-direction-1] 
+                                                                for (k,v) in field_reqs.iteritems()}
             for (field, reqs) in field_reqs.iteritems():
                 if field in field_requirements:
                     field_requirements[field].update_requirements(reqs)
@@ -474,29 +586,32 @@ class SymbolicExpressionParser(object):
             nsteps = info.time_integrator.stages
         else:
             nsteps = 1
+
+        info.nsteps = nsteps
+        info.nlhsfields = nlhsfields
         
-        G_f = expr_ghost_map[:,:nlhsfields]
-        min_ghosts_per_step = npw.int_zeros(shape=(nsteps, nlhsfields))
-        min_ghosts_per_step[0,:] = npw.max(G_f, axis=0)
-        for s in xrange(1, nsteps):
-            min_ghosts_per_step[s] = npw.max(G_f + min_ghosts_per_step[s-1][:,None], axis=0)
-        min_ghosts_lhs = min_ghosts_per_step[nsteps-1]
-        
-        if nsteps>1:
-            min_ghosts_rhs = npw.max(expr_ghost_map[:,nlhsfields:] + min_ghosts_per_step[nsteps-2][:,None], axis=0)
-        else:
-            min_ghosts_rhs = npw.max(expr_ghost_map[:,nlhsfields:], axis=0)
-        min_ghosts = min_ghosts_lhs.tolist() + min_ghosts_rhs.tolist()
+        if (nlhsfields > 0):
+            G_f = expr_ghost_map[:,:nlhsfields]
+            min_ghosts_per_step = npw.int_zeros(shape=(nsteps, nlhsfields))
+            min_ghosts_per_step[0,:] = npw.max(G_f, axis=0)
+            for s in xrange(1, nsteps):
+                min_ghosts_per_step[s] = npw.max(G_f + min_ghosts_per_step[s-1][:,None], axis=0)
+            min_ghosts_lhs = min_ghosts_per_step[nsteps-1]
+            
+            if nsteps>1:
+                min_ghosts_rhs = npw.max(expr_ghost_map[:,nlhsfields:] + \
+                                                min_ghosts_per_step[nsteps-2][:,None], axis=0)
+            else:
+                min_ghosts_rhs = npw.max(expr_ghost_map[:,nlhsfields:], axis=0)
+            min_ghosts = min_ghosts_lhs.tolist() + min_ghosts_rhs.tolist()
+            info.min_ghosts_per_integration_step = min_ghosts_per_step
+            info.min_ghosts_per_field_name = dict(zip(all_fields, min_ghosts))
+            info.expr_ghost_map = expr_ghost_map
         
         lhs_fields = { v:k for (k,v) in lhs_fields.iteritems() }
         lhs_fields = tuple(lhs_fields[i] for i in xrange(nlhsfields))
         all_fields = { v:k for (k,v) in all_fields.iteritems() }
         all_fields = tuple(all_fields[i] for i in xrange(nfields))
-        info.nsteps = nsteps
-        info.nlhsfields = nlhsfields
-        info.expr_ghost_map                  = expr_ghost_map
-        info.min_ghosts_per_integration_step = min_ghosts_per_step
-        info.min_ghosts_per_field_name = dict(zip(all_fields, min_ghosts))
         info.lhs_field_names = lhs_fields
         info.rhs_field_names = rhs_fields
         info.all_field_names = all_fields
@@ -529,7 +644,8 @@ class SymbolicExpressionParser(object):
             if (direction is not None):
                 xd = space_symbols[direction]
                 if (unique_dvars - set([xd])):
-                    msg='Expression already contained a derivative with respect to {} (direction {}, {}-axis).'
+                    msg='Expression already contained a derivative with respect to {} (direction {}, '
+                    msg+='{}-axis).'
                     msg+='\nFound a new derivative direction which is not compatible with the current one.'
                     msg+='\nCannot differentiate with respect to {}.'
                     msg=msg.format(xd, direction, DirectionLabels[direction],
@@ -612,9 +728,10 @@ class SymbolicExpressionParser(object):
     def discretize_assignment(cls, info, expr):
         lhs, rhs = expr.args
         rhs, di = cls.discretize_subexpr(info, rhs)
-        if isinstance(lhs, AppliedSymbolicField):
+        if isinstance(lhs, (AppliedSymbolicField, SymbolicArray, TmpScalar,)):
             func = expr.func
         elif isinstance(lhs, sm.Derivative):
+            assert isinstance(lhs.args[0], AppliedSymbolicField)
             assert lhs.args[1] == time_symbol
             assert len(lhs.args)==2
             lhs = lhs.args[0]
@@ -626,13 +743,16 @@ class SymbolicExpressionParser(object):
             msg='Invalid symbolic assignment lhs type {}.'
             msg=msg.format(type(lhs))
             raise NotImplementedError(msg)
+        
+        if isinstance(lhs, AppliedSymbolicField):
+            field, index, indexed_field  = lhs.field, lhs.index, lhs.indexed_field
+            dfield = info.output_dfields[field]
+            lhs = dfield.s[index]
+            check_instance(lhs, SymbolicDiscreteField)
+            cls.write_discrete(info, lhs, dfield, di)
+        else:
+            di.write(lhs)
 
-        field, index, indexed_field  = lhs.field, lhs.index, lhs.indexed_field
-        dfield = info.output_dfields[field]
-        lhs = dfield.s[index]
-        check_instance(lhs, SymbolicDiscreteField)
-
-        cls.write_discrete(info, lhs, dfield, di)
         new_expr = func(lhs, rhs)
         return new_expr, di
 
@@ -801,7 +921,8 @@ class CustomSymbolicOperatorBase(DirectionalOperatorBase):
         splitting_dim       = first_not_None(splitting_dim, expr_info.domain.dim)
 
         if (expr_info.direction != splitting_direction):
-            msg='Direction mismatch, expression has derivative in direction {} but direction {} has been specified.'
+            msg='Direction mismatch, expression has derivative in direction {} but direction {} '
+            msg+='has been specified.'
             msg=msg.format(expr_info.direction, direction)
             raise ValueError(msg)
         
@@ -846,7 +967,8 @@ class CustomSymbolicOperatorBase(DirectionalOperatorBase):
         
         min_ghosts_per_components = {}
 
-        for (fields, is_input, iter_requirements) in zip((self.input_fields, self.output_fields), (True, False),
+        for (fields, is_input, iter_requirements) in zip((self.input_fields, self.output_fields), 
+                (True, False),
                 (requirements.iter_input_requirements, requirements.iter_output_requirements)):
             if not fields:
                 continue
@@ -883,7 +1005,8 @@ class CustomSymbolicOperatorBase(DirectionalOperatorBase):
                     min_ghosts_per_components[field] = min_ghosts
         expr_info.min_ghosts = {k:npw.max(v, axis=0) for (k,v) in \
                                         min_ghosts_per_components.iteritems()}
-        expr_info.min_ghosts_per_components = {field:gpc[:,-1-direction] for (field,gpc) in min_ghosts_per_components.iteritems()}
+        expr_info.min_ghosts_per_components = {field:gpc[:,-1-direction] 
+                                for (field,gpc) in min_ghosts_per_components.iteritems()}
         
         return requirements
     
diff --git a/hysop/operator/base/poisson_rotational.py b/hysop/operator/base/poisson_rotational.py
index f6b44f1d1fa07059546026f684723f4869cab848..9ef41ddc90bf1200f7e4b271de0c6310374ed540 100644
--- a/hysop/operator/base/poisson_rotational.py
+++ b/hysop/operator/base/poisson_rotational.py
@@ -86,6 +86,7 @@ class PoissonRotationalOperatorBase(FftOperatorBase):
         self.W = vorticity
         self.U = velocity
         self.projection = projection
+        self.dim = velocity.dim
     
     @debug
     def discretize(self):
@@ -113,7 +114,6 @@ class PoissonRotationalOperatorBase(FftOperatorBase):
         self.W_buffers = W_buffers
         self.U_buffers = U_buffers
         
-        self.dim = dim
         self.dtype = dtype
         self.ctype = ctype
         self.axes  = axes
diff --git a/hysop/symbolic/array.py b/hysop/symbolic/array.py
index 5425522878cd79b2fd5e8f96a686ffaf3596a96a..7ce473f75db6ca9b01671a57049b2cd7acf7b75e 100644
--- a/hysop/symbolic/array.py
+++ b/hysop/symbolic/array.py
@@ -7,43 +7,90 @@ from hysop.backend.device.opencl import clArray
 from hysop.backend.device.opencl.opencl_array import OpenClArray
 from hysop.backend.host.host_array import HostArray
 
-class SymbolicArray(SymbolicScalar):
-    def __new__(cls, array, name, **kwds):
-        obj = super(SymbolicArray, cls).__new__(cls, name=name, **kwds)
-        obj._array = None
-        if (array is not None):
-            obj.bind_array(array)
+class SymbolicMemoryObject(SymbolicScalar):
+    def __new__(cls, memory_object, name, **kwds):
+        obj = super(SymbolicMemoryObject, cls).__new__(cls, name=name, **kwds)
+        obj._memory_object = None
+        if (memory_object is not None):
+            obj.bind_memory_object(memory_object)
         return obj
+
+    @property
+    def is_bound(self):
+        return (self._memory_object is not None)
     
     @property
-    def array(self):
-        if (self._array is None):
-            msg='Symbolic array {} has not been setup yet.'.format(self.name)
+    def memory_object(self):
+        if (self._memory_object is None):
+            msg='Symbolic memory_object {} has not been setup yet.'.format(self.name)
             raise RuntimeError(msg)
-        return self._array
+        return self._memory_object
     
     @abstractmethod
-    def bind_array(self, array):
-        if (self._array is not None):
-            msg='An array was already bind to SymbolicArray {}.'.format(self.name)
+    def bind_memory_object(self, memory_object):
+        if (self._memory_object is not None):
+            msg='An memory_object was already bind to SymbolicArray {}.'.format(self.name)
             raise RuntimeError(msg)
-        if isinstance(array, (OpenClArray, HostArray)):
-            array = array.handle
-        self._array = array
+        if isinstance(memory_object, (OpenClArray, HostArray)):
+            memory_object = memory_object.handle
+        self._memory_object = memory_object
+
+class IndexedBuffer(sm.Indexed):
+    """
+    Tag for indexed SymbolicBuffers.
+    """
+    pass
+
+class SymbolicArray(SymbolicMemoryObject):
+    """
+    An array is considered to be indexed by local indices in 
+    autogenerated vectorized code (in symbolic code generation
+    framework).
+    """
+    def __getitem__(self, key):
+        msg='Symbolic array {} cannot be indexed.'.format(self.name)
+        raise RuntimeError(msg)
+
+    @property
+    def array(self):
+        return self._memory_object
+
+    @property
+    def dim(self):
+        return 3
 
+class SymbolicBuffer(SymbolicMemoryObject):
+    """
+    A buffer will not be indexed by local indices by default.
+    The user has to index a SymbolicBuffer so that it can be 
+    used for code generation.
+    """
     def __getitem__(self, key):
         assert isinstance(key, (int, npw.integer, sm.Expr))
-        return sm.Indexed(self, key)
+        return IndexedBuffer(self, key)
+    
+    @property
+    def buffer(self):
+        return self._memory_object
+
+class SymbolicHostMemoryObject(object):
+    def bind_memory_object(self, memory_object):
+        check_instance(memory_object, (HostArray, npw.ndarray))
+        super(SymbolicHostMemoryObject, self).bind_memory_object(memory_object)
 
-class HostSymbolicArray(SymbolicArray):
-    def bind_array(self, array):
-        check_instance(array, (HostArray, npw.ndarray))
-        super(HostSymbolicArray, self).bind_array(array)
+class SymbolicDeviceMemoryObject(object):
+    def bind_memory_object(self, memory_object):
+        check_instance(memory_object, (OpenClArray, clArray.Array))
+        super(SymbolicDeviceMemoryObject, self).bind_memory_object(memory_object)
 
-class OpenClSymbolicArray(SymbolicArray):
-    def bind_array(self, array):
-        check_instance(array, (OpenClArray, clArray.Array))
-        super(OpenClSymbolicArray, self).bind_array(array)
+class HostSymbolicArray(SymbolicHostMemoryObject, SymbolicArray):
+    pass
+class OpenClSymbolicArray(SymbolicDeviceMemoryObject, SymbolicArray):
+    pass
+class HostSymbolicBuffer(SymbolicHostMemoryObject, SymbolicBuffer):
+    pass
+class OpenClSymbolicBuffer(SymbolicDeviceMemoryObject, SymbolicBuffer):
+    pass
     
 
 if __name__ == '__main__':
@@ -51,11 +98,27 @@ if __name__ == '__main__':
     from hysop.core.arrays.all import default_host_array_backend
     a = npw.ones(shape=(10,10), dtype=npw.int8)
     b = default_host_array_backend.zeros(shape=(10,), dtype=npw.uint16)
-    A = HostSymbolicArray(array=a, name='a')
-    B = b.s('b')
-    print 7*A + 9*B
-    assert A.array is a
-    assert B.array is b.handle
-
-    print A[5]
-    print A[B]
+    
+    A = HostSymbolicArray(a, name='a')
+    B = b.as_symbolic_array('b')
+    
+    C = HostSymbolicBuffer(a, name='c')
+    D = b.as_symbolic_buffer('d')
+
+    print 7*A + 9*B + 10*C - 4*D
+
+    assert A.array  is a
+    assert B.array  is b.handle
+    assert C.buffer is a
+    assert D.buffer is b.handle
+    
+    try:
+        A[5]
+        assert False
+    except RuntimeError as e:
+        pass 
+
+    print C[5]
+    print D[C]
+
+    print 
diff --git a/hysop/symbolic/tmp.py b/hysop/symbolic/tmp.py
new file mode 100644
index 0000000000000000000000000000000000000000..cf9e4aae54bb6fd0a62bce0faccea6e7f2702683
--- /dev/null
+++ b/hysop/symbolic/tmp.py
@@ -0,0 +1,5 @@
+
+from hysop.symbolic.base import SymbolicScalar
+class TmpScalar(SymbolicScalar):
+    """Tag for temporary scalar variables."""
+    pass
diff --git a/hysop/tools/types.py b/hysop/tools/types.py
index eb32a880eaafcf4049f9e44e98757313e4cb0edc..1ce7e9df84e9217fd6ac417b9cc72508198fb065 100644
--- a/hysop/tools/types.py
+++ b/hysop/tools/types.py
@@ -101,7 +101,8 @@ def check_instance(val, cls, allow_none=False, **kargs):
             maxval = kargs.pop('maxval', None)
             for v in val:
                 if not any((isinstance(v, val_cls) for val_cls in all_val_cls)):
-                    msg='Value contained in given {} is not an instance of {} but a value of type {}.'
+                    msg='Value contained in given {} is not an instance of {} but a '
+                    msg='value of type {}.'
                     msg=msg.format(type(val).__name__, all_val_cls, type(v))
                     print_offending_value(v, all_val_cls)
                     raise TypeError(msg)