diff --git a/Docs/manual.pdf b/Docs/manual.pdf
new file mode 100644
index 0000000000000000000000000000000000000000..3f58dc12655ad1aa90334c96014e7db543a26632
Binary files /dev/null and b/Docs/manual.pdf differ
diff --git a/Docs/manual.tex b/Docs/manual.tex
new file mode 100644
index 0000000000000000000000000000000000000000..4e12e287fdd7506169d853a48256db7966869320
--- /dev/null
+++ b/Docs/manual.tex
@@ -0,0 +1,77 @@
+\documentclass[a4paper,10pt]{article}
+\usepackage{ucs,amsmath,a4wide,natbib, amssymb}
+\usepackage[utf8x]{inputenc}
+\usepackage{fancyhdr}
+\usepackage{lastpage}
+\fancyhead[C]{}
+\fancyhead[R]{\texttt{\thepage/\pageref{LastPage}}}
+\fancyfoot[L]{}
+\fancyfoot[C]{}
+\fancyfoot[R]{\texttt{file main.tex -- \isodayandtime}}
+\usepackage{multirow}
+\setlength{\parskip}{12pt}
+\usepackage{graphicx}
+\graphicspath{{./images/}}
+\usepackage{pdfsync}
+ \usepackage{cancel}
+\usepackage{xcolor}
+\usepackage[left=3cm,right=3cm,top=2.5cm,bottom=2.5cm]{geometry}
+\overfullrule 5pt 
+\usepackage[left=3cm,right=3cm,top=2.5cm,bottom=2.5cm]{geometry}
+\overfullrule 5pt %Pour d\'esigner les listes couples d'un *full carre noir la ou l on sort
+
+\usepackage[pdftex]{hyperref}
+\hypersetup{
+  pdftitle={ParMeS User Guide},
+  pdfauthor={ParMeS Devel},
+  pdfcreator={ParMeS},
+  pdfkeywords={particular methods, GPU, MPI},
+%  pdfsubject={}
+% pagebackref=false,
+%colorlinks=false,citecolor=red,
+%linkcolor=blue,
+%plainpages=false,
+%breaklinks=true,
+% pdfpagelabels=true
+}
+
+\usepackage{mathtools}
+
+\DeclarePairedDelimiter\abs{\lvert}{\rvert}%
+\DeclarePairedDelimiter\norm{\lVert}{\rVert}%
+% Swap the definition of \abs* and \norm*, so that \abs
+% and \norm resizes the size of the brackets, and the 
+% starred version does not.
+\makeatletter
+\let\oldabs\abs
+\def\abs{\@ifstar{\oldabs}{\oldabs*}}
+%
+\let\oldnorm\norm
+\def\norm{\@ifstar{\oldnorm}{\oldnorm*}}
+\makeatother
+
+\title{ParMeS User Guide}
+\author{ParMeS Development team}
+
+\begin{document}
+\maketitle
+
+
+\part{Introduction}
+\part{Operators}
+\section{About operators}
+\section{Computational operators}
+\input{velocity_correction}
+\section{Monitors}
+\input{monitors}
+\section{Redistribute operators}
+
+\end{document}
+
+%%% Local Variables: 
+%%% mode: latex
+%%% TeX-master: t
+%%% End: 
+
+
+
diff --git a/Docs/monitors.tex b/Docs/monitors.tex
new file mode 100644
index 0000000000000000000000000000000000000000..c3edc57dea6c0bed57955628342cedb04a4c51d9
--- /dev/null
+++ b/Docs/monitors.tex
@@ -0,0 +1,41 @@
+
+\subsection{Introduction}
+\subsection{Printer}
+\subsection{DragAndLift}
+\subsection{Reprojection$\_$criterion}
+Purpose : compute a projection criterion, depending on the current vorticity value on the grid.
+
+IN : vorticity field, reproj$\_$cst\\
+OUT : reprojRate, projCriterion
+with\\
+ reprojRate : how often (in terms of iterations) this criteria must be taken into account \\
+ and checkCriterion : true if reprojRate must be checked and updated (if necessary).
+
+\begin{itemize}
+\item Case 1: checkCriterion == True.\\
+If checkCriterion is true, the operator computes a criterion projection every reprojRate iteration.
+If this criterion is greater than reproj$\_$cst (user defined constant), then reprojRate is set to 1. 
+reprojRate is reset to defaultRate (user-defined) at the beginning of every apply.
+\item Case 2 : checkCriterion == False.\\
+The operator will do nothing but give the (user-defined) value for reprojRate.
+\end{itemize}
+
+If io$\_$params is set, then a file is appended with some diagnostics values (see below) each reprojRate iterations.\\
+
+$\Omega$ being the whole domain, $\omega$ the vorticity field, let us denote : 
+\begin{eqnarray}
+d1 &=& \max_{\Omega}\abs{\sum_j \frac{\partial \omega_j}{\partial x_j}}\\
+d2 &=& \max_{\Omega}\abs{\frac{\partial \omega_i}{\partial x_j}} \ \  \forall i,j \in [0,2]
+\end{eqnarray}
+
+And so, diagnostics = simulation.time, projCriterion, d1, d2, counter \\
+
+counter being the number of projection done since the beginning of the simulation.
+
+
+\subsection{Energy$\_$enstrophy}
+%%% Local Variables: 
+%%% mode: latex
+%%% TeX-master: "manual"
+%%% End: 
+
diff --git a/Docs/velocity_correction.pdf b/Docs/velocity_correction.pdf
deleted file mode 100644
index 832eb6c5416b2f09a32efef01b8ab5b90d6800cb..0000000000000000000000000000000000000000
Binary files a/Docs/velocity_correction.pdf and /dev/null differ
diff --git a/Docs/velocity_correction.tex b/Docs/velocity_correction.tex
index 229f69ed7d3613013722b82a55affa2d57918f0f..a19616e22cb6100a0db8835836d5f5c8b5d733a7 100644
--- a/Docs/velocity_correction.tex
+++ b/Docs/velocity_correction.tex
@@ -1,43 +1,4 @@
-\documentclass[a4paper,10pt]{article}
-\usepackage[utf8x]{inputenc}
-\usepackage{amsmath}
-% \usepackage{showkeys} % affiche les labels et references
-\usepackage[T1]{fontenc}
-\usepackage{multirow}
-\usepackage{amsthm,amssymb}
-\setlength{\parskip}{12pt} %taille du saut entre deux paragraphes
-\usepackage{graphicx}
-\graphicspath{{./images/}}
-\usepackage{pdfsync} % permet de cliquer sur le pdf pour avoir l endroit ou il y a le code latex
- \usepackage{cancel}
-\usepackage{xcolor}
-\usepackage[left=3cm,right=3cm,top=2.5cm,bottom=2.5cm]{geometry}
-\overfullrule 5pt %Pour d\'esigner les listes couples d'un *full carre noir la ou l on sort
-
-\usepackage[pdftex]{hyperref}
-\hypersetup{
-  pdftitle={Flow past 3D sphere},
-  pdfauthor={Mimeau Chloe},
-  pdfcreator={PARMES},
-  pdfkeywords={sphere, potential flow, velocity correction, flow rate},
-  pdfsubject={Flow past 3D sphere}
-% pagebackref=false,
-%colorlinks=false,citecolor=red,
-%linkcolor=blue,
-%plainpages=false,
-%breaklinks=true,
-% pdfpagelabels=true
-}
-
-
-\theoremstyle{plain}
-\newtheorem{Theoreme}{Th\'eor\`eme}[section]
-%opening
-\title{Correction de vitesse pour la modélisation d'un écoulement incompressible dans une boîte}
-\author{}
-\date{}
-
-\begin{document}
+\subsection{Correction de vitesse pour la modélisation d'un écoulement incompressible dans une boîte}
 
 \maketitle
 Lors de la résolution de l'équation de Poisson $\Delta \mathbf{u} = - \nabla \boldsymbol{\omega} $, le mode 0 des transformées de Fourier rapides de la vitesse est imposé à 0, ce qui entraîne une modification des valeurs moyennes des composantes de la vitesse et donc des composantes de la vitesse elles-mêmes lorsque la transformée de Fourier inverse est appliquée. Une correction de la vitesse est donc nécessaire après la résolution de l'équation de Poisson, à chaque itération.
@@ -219,5 +180,8 @@ u_z &= -u_{\infty} \dfrac{3R^3 xz}{2 r^5}
 % \begin{equation}
 % \underbrace{\iint\limits_S  u_x \ dydz}_{\text{débit souhaité}} = \iint\limits_S \ \dfrac{-u_{\infty} x}{r} \left ( 1 - \dfrac{R^3}{r^3} \right )  \ dydz = -u_{\infty} x_0 \iint\limits_S \ \dfrac{1}{r} \left ( 1 - \dfrac{R^3}{r^3} \right )  \ dydz 
 % \end{equation}
+%%% Local Variables: 
+%%% mode: latex
+%%% TeX-master: "manual"
+%%% End: 
 
-\end{document}
diff --git a/Examples/NSDebug.py b/Examples/NSDebug.py
index 1217d0ab50b5615923667e5b0e31cbd26271197c..bbc6095af0bc65910349bd5e384927ecee78689d 100755
--- a/Examples/NSDebug.py
+++ b/Examples/NSDebug.py
@@ -11,7 +11,6 @@ import parmepy as pp
 from parmepy.f2py import fftw2py
 import numpy as np
 from parmepy.fields.continuous import Field
-from parmepy.variables.variables import Variables
 from parmepy.mpi.topology import Cartesian
 from parmepy.domain.obstacle.sphere import Sphere
 from parmepy.operator.advection import Advection
@@ -22,19 +21,17 @@ from parmepy.operator.diffusion import Diffusion
 from parmepy.operator.penalization import Penalization
 from parmepy.operator.differential import Curl
 from parmepy.operator.redistribute import Redistribute
-from parmepy.operator.monitors.printer import Printer
-from parmepy.operator.monitors.energy_enstrophy import Energy_enstrophy
-from parmepy.operator.monitors.compute_forces import Forces
+from parmepy.operator.monitors import Printer, Energy_enstrophy, DragAndLift,\
+    Reprojection_criterion
 from parmepy.problem.simulation import Simulation
 from parmepy.constants import VTK, HDF5
 from parmepy.domain.obstacle.planes import PlaneBoundaries
 from dataNS_bb import dim, nb, NBGHOSTS, ADVECTION_METHOD, VISCOSITY, \
     OUTPUT_FREQ, FILENAME, PROJ, LCFL, CFL, CURL_METHOD, \
     TIMESTEP_METHOD, OBST_Ox, OBST_Oy, OBST_Oz, RADIUS
-from parmepy.operator.monitors.compute_forces import DragAndLift
 from parmepy.domain.obstacle.controlBox import ControlBox
-
-
+import parmepy.tools.numpywrappers as npw
+import parmepy.tools.io_utils as io
 ## ----------- A 3d problem -----------
 print " ========= Start Navier-Stokes 3D (Flow past bluff bodies) ========="
 
@@ -44,8 +41,8 @@ cos = np.cos
 sin = np.sin
 
 ## Domain
-boxlength = [2.0 * pi, pi, pi]
-boxorigin = [0., 0., 0.]
+boxlength = npw.realarray([2.0 * pi, pi, pi])
+boxorigin = npw.realarray([0., 0., 0.])
 box = pp.Box(dim, length=boxlength, origin=boxorigin)
 
 ## Global resolution
@@ -105,76 +102,79 @@ op['stretching'] = Stretching(velo, vorti,
 
 op['diffusion'] = Diffusion(vorti, resolution=nbElem, viscosity=VISCOSITY)
 
-op['poisson'] = Poisson(velo, vorti, resolutions={velo: nbElem, vorti: nbElem},
-                        projection=PROJ)
+op['poisson'] = Poisson(velo, vorti, resolutions={velo: nbElem, vorti: nbElem})
 
 op['curl'] = Curl(velo, vorti, resolutions={velo: nbElem, vorti: nbElem},
                   method=CURL_METHOD)
 
 ## Discretisation of computational operators
-for ope in op:
+for ope in op.values():
     ope.discretize()
 
 # Get fft topology and use it for penalization and correction operators
 opfft = op['poisson']
 topofft = opfft.discreteFields[opfft.vorticity].topology
+topocurl = op['curl'].discreteFields[op['curl'].invar].topology
 
-op['penal'] = Penalization(velo, [sphere, bc], coeff=[1e8], topo=topofft,
-                           resolutions={velo: nbElem})
+op['penalization'] = Penalization(velo, [sphere, bc], coeff=[1e8],
+                                  topo=topofft, resolutions={velo: nbElem})
 
-op['correc'] = VelocityCorrection(velo, vorti,
-                                  resolutions={velo: nbElem, vorti: nbElem},
-                                  uinf=uinf, topo=topofft)
+ref_rate = uinf * box.length[1] * box.length[2]
+op['correction'] = VelocityCorrection(velo, vorti,
+                                      resolutions={velo: nbElem,
+                                                   vorti: nbElem},
+                                      req_flowrate=ref_rate, topo=topofft)
 
-op['penal'].discretize()
-op['correc'].discretize()
+op['penalization'].discretize()
+op['correction'].discretize()
 
 ## === Bridges between the different topologies ===
 distr = {}
+
+distr['fft2curl'] = Redistribute([velo], op['penalization'], op['curl'])
+distr['curl2fft'] = Redistribute([vorti], op['curl'], op['poisson'])
+
 # 1 - Curl_fft to stretching (velocity only)
 distr['Curl2Str'] = Redistribute([velo], op['curl'], op['stretching'])
 # 2 - Advection to stretching (vorticity only)
 distr['Advec2Str_v'] = Redistribute([velo], op['advection'], op['stretching'])
 distr['Advec2Str_w'] = Redistribute([vorti], op['advection'], op['stretching'])
 # 3 - Stretching to Diffusion
-distr['stretch2diff'] = Redistribute([vorti], op['stretching'], op['diffusion'])
-# + - Brigdes required if Curl op. is solved using a FD method
-distrPoissCurl = Redistribute([vorti, velo], poisson, curl)
-distrCurlAdv = Redistribute([vorti, velo], curl, advec)
+distr['Str2diff'] = Redistribute([vorti], op['stretching'], op['diffusion'])
+distr['Curl2Advec'] = Redistribute([vorti], op['curl'], op['advection'])
 
-distrAdvStr_velo.discretize()
-distrAdvStr_vorti.discretize()
-distrStrDiff.discretize()
-distrCurlStr_velo.discretize()
-distrCurlAdv.discretize()
-
-## === Fields initialization ===
-velo.initialize(topo=topofft)
+for ope in distr.values():
+    ope.discretize()
 
-ind = sphere.discretize(topofft)
-vdfft = velo.discreteFields[topofft].data
+# === Simulation setup ===
+simu = Simulation(tinit=0.0, tend=0.2, timeStep=0.005, iterMax=1000000)
 
 ## === Monitoring operators ===
+monitors = {}
+# Save velo and vorti values on topofft
+monitors['printerFFT'] = Printer(variables=[velo, vorti], topo=topofft,
+                                 formattype=HDF5)
+
+monitors['printerCurl'] = Printer(variables=[velo, vorti], topo=topocurl,
+                                  formattype=HDF5, prefix='curl_io_vorti')
+# Compute and save enstrophy/Energy, on topofft
+io_default = {}
+monitors['energy'] = Energy_enstrophy(velo, vorti, topo=topofft, io_params={},
+                                      viscosity=VISCOSITY, isNormalized=False)
+# Setup for reprojection
+reprojection_constant = 0.04
+reprojection_rate = 1
+monitors["reprojection"] = Reprojection_criterion(vorti, reprojection_constant,
+                                                  reprojection_rate, topofft,
+                                                  io_params={})
+
+# Add reprojection for poisson operator
+op["poisson"].activateProjection(monitors["reprojection"])
 
-outputdir = 'res_' + str(topofft.size) + 'procs'
-pref = outputdir + '/vwfft'
-
-printerFFT = Printer(variables=[velo, vorti],
-                     topo=topofft,
-                     frequency=1,
-                     prefix=pref,
-                     formattype=HDF5)
-
-printerFFT.setUp()
-
-prefE = outputdir + '/ener'
-energy = Energy_enstrophy(velo, vorti,
-                          topo=topofft,
-                          viscosity=VISCOSITY,
-                          isNormalized=False,
-                          frequency=1,
-                          prefix=prefE)
+ind = sphere.discretize(topofft)
+vdfft = velo.discreteFields[topofft].data
 
+# Compute and save drag and lift on topofft
 # 3D Control box
 ref_step = topofft.mesh.space_step
 cbpos = boxorigin + boxlength + 10 * ref_step
@@ -183,93 +183,118 @@ cb = ControlBox(box, cbpos, cblength)
 nu = 0.1
 coeffForce = 1.
 # Monitor for forces
-forces = DragAndLift(velo, vorti, nu, coeffForce, topofft, cb,
-                     obstacle=[sphere],
-                     filename=outputdir + 'forces.dat')
-
-## Simulation with fixed time step
-simu = Simulation(tinit=0.0,
-                  tend=5., timeStep=0.005,
-                  iterMax=1000000)
-
-
-curl.setUp()
-advec.setUp()
-stretch.setUp()
-diffusion.setUp()
-poisson.setUp()
-correction.setUp()
-penal.setUp()
-distrAdvStr_velo.setUp()
-distrAdvStr_vorti.setUp()
-distrStrDiff.setUp()
-distrCurlStr_velo.setUp()
-distrCurlAdv.setUp()
-
-energy.setUp()
-
-
-## Initialization of velocity on topofft
-def run():
-    penal.apply(simu)
-    ## end of time loop ##
-
-    ## from parmepy.mpi import MPI
-    ## print "Start computation ..."
-    ## time = MPI.Wtime()
-    if topofft.rank == 0:
-        print "start curl"
-    curl.apply(simu)
-
-    #printerFFT.apply(simu)
-    # From topo fft to topo advec
-    if topofft.rank == 0:
-        print "start d0"
-    distrCurlAdv.apply(simu)
-    if topofft.rank == 0:
-        print "start advec"
-    advec.apply(simu)
-
-    # From topo adv to topo stretch
-    if topofft.rank == 0:
-        print "start d1"
-    distrAdvStr_velo.apply(simu)
-    if topofft.rank == 0:
-        print "start d1"
-    distrAdvStr_vorti.apply(simu)
-    if topofft.rank == 0:
-        print "start stret"
-    stretch.apply(simu)
-
-    if topofft.rank == 0:
-        print "start d2"
-    distrStrDiff.apply(simu)
-    if topofft.rank == 0:
-        print "start diff"
-    diffusion.apply(simu)
-    if topofft.rank == 0:
-        print "start poiss"
-    poisson.apply(simu)
-    if topofft.rank == 0:
-        print "start correc"
-    correction.apply(simu)
-    if topofft.rank == 0:
-        print "start penal"
-    penal.apply(simu)
-    energy.apply(simu)
-    if topofft.rank == 0:
-        print "start printer"
-    printerFFT.apply(simu)
-
-
-#while not simu.isOver:
-for i in xrange(200):
+monitors['forces'] = DragAndLift(velo, vorti, nu, coeffForce, topofft, cb,
+                                 obstacles=[sphere], io_params={})
+
+# === Setup for all declared operators ===
+for ope in op.values():
+    ope.setUp()
+for ope in distr.values():
+    ope.setUp()
+# Set up for monitors
+for monit in monitors.values():
+    monit.setUp()
+
+allops = dict(op.items() + distr.items() + monitors.items())
+
+
+## === Fields initialization ===
+# Initialisation, mode 1:
+# - compute velocity on topofft
+# - penalize
+# - compute vorticity with curl
+def initFields_mode1():
+    # The velocity is initialized on the fftw topology
+    # penalized and distributed on curl topo
+    velo.initialize(topo=topofft)
+    op['penalization'].apply(simu)
+    distr['fft2curl'].apply(simu)
+    # Vorticity is initialized after penalization of velocity
+    op['curl'].apply(simu)
+    # Distribute vorticity on topofft
+    distr['curl2fft'].apply(simu)
+    # From this point both velocity and vorticity are initialized
+    # on topofft and on topocurl
+
+## Call initialization
+initFields_mode1()
+
+##### Check initialize process results #####
+norm_vel_fft = velo.norm(topofft)
+norm_vel_curl = velo.norm(topocurl)
+norm_vort_fft = vorti.norm(topofft)
+norm_vort_curl = vorti.norm(topocurl)
+
+print norm_vort_curl, norm_vort_fft
+print norm_vel_curl, norm_vel_fft
+assert np.allclose(norm_vort_curl, norm_vort_fft)
+assert np.allclose(norm_vel_curl, norm_vel_fft)
+
+## Print initial state
+for mon in monitors.values():
+    mon.apply(simu)
+
+
+## Note Franck : tests init ok, same values on both topologies, for v and w.
+
+# === Definition of the 'one-step' sequence of operators ===
+#
+#  1 - w = curl(v), topocurl
+#  2 - w = advection(v,w), topo-advec
+#  3 - w = stretching(v,w), topostr
+#  4 - w = diffusion(w), topofft
+#  5 - v = poisson(w), topofft
+#  6 - v = correction(v, w), topofft
+#  7 - v = penalization(v), topofft
+#
+fullseq = ['curl', 'printerCurl', 'advection', 'stretching', 'diffusion',
+           'reprojection', 'poisson', 'correction', 'energy', 'forces',
+           'printerFFT']
+
+
+def run(sequence):
+    for name in sequence:
+        assert allops.keys().count(name) > 0 or distr.keys().count(name) > 0\
+            or monitors.keys().count(name) > 0
+        allops[name].apply(simu)
+
+seq = fullseq
+simu.initialize()
+while not simu.isOver:
     simu.printState()
-    run()
+    run(seq)
     simu.advance()
 
 
 ## print 'total time (rank):', MPI.Wtime() - time, '(', topo.rank, ')'
 
+
+print 'aaaa', velo.norm(topofft)
+op['correction'].apply(simu)
+print 'iiii', velo.norm(topofft)
+
+sref = op['correction'].discreteOperator.surfRef
+
+flowrate = velo.integrateOnSurface(sref, topofft)
+print flowrate
+assert (flowrate - ref_rate) < 1e-10
+
+flowratey = velo.integrateOnSurface(sref, topofft, component=1)
+print flowratey
+flowratez = velo.integrateOnSurface(sref, topofft, component=2)
+print flowratez
+
+
+# === Finalize for all declared operators ===
+
+# Note FP : bug in fft finalize. To be checked ...
+# --> clean_fftw must be called only once
+#for ope in op.values():
+#    ope.finalize()
 ## Clean memory buffers
 fftw2py.clean_fftw_solver(box.dimension)
+for ope in distr.values():
+    ope.finalize()
+for monit in monitors.values():
+    monit.finalize()
+
diff --git a/HySoP/hysop/__init__.py.in b/HySoP/hysop/__init__.py.in
index f680e04c9d5e08c39b522340178e6727917cf288..7d7e223902ffec4e7a71b69c633e3ea8c8a99258 100755
--- a/HySoP/hysop/__init__.py.in
+++ b/HySoP/hysop/__init__.py.in
@@ -15,13 +15,13 @@ __FFTW_ENABLED__ = "@WITH_FFTW@" is "ON"
 __SCALES_ENABLED__ = "@WITH_SCALES@" is "ON"
 __VERBOSE__ = "@DEBUG@" in ["1", "3"]
 __DEBUG__ = "@DEBUG@" in ["2", "3"]
-__PROFILE__= "@PROFILE@" in ["0", "1"]
-__OPTIMIZE__= "@OPTIM@" is "ON"
+__PROFILE__ = "@PROFILE@" in ["0", "1"]
+__OPTIMIZE__ = "@OPTIM@" is "ON"
 # MPI
 if __MPI_ENABLED__:
     #import parmepy.mpi as mpi
     #    from mpi import main_rank
-    import mpi
+    import parmepy.mpi
     if(mpi.main_rank == 0):
         print "Starting @PACKAGE_NAME@ version " + str(__version__) + ".\n"
 else:
@@ -30,13 +30,20 @@ else:
 version = "1.0.0"
 
 ## Box-type physical domain
-import domain.box
-Box = domain.box.Box
+import parmepy.domain.box
+Box = parmepy.domain.box.Box
 
 ## Fields
-import fields.continuous
-Field = fields.continuous.Field
+import parmepy.fields.continuous
+Field = parmepy.fields.continuous.Field
 
+## Variable parameters
+import parmepy.variable_parameter
+VariableParameter = parmepy.variable_parameter.VariableParameter
+
+## Simulation parameters
+import parmepy.problem.simulation
+Simulation = parmepy.problem.simulation.Simulation
 
 # ## ## Problem
 # import problem.problem
diff --git a/HySoP/hysop/domain/obstacle/planes.py b/HySoP/hysop/domain/obstacle/planes.py
index 6791bb23ff5d245e64fe7ca0a1756096ebf9a609..961ce968bb862d673929490262b6a37e6daf6fa6 100644
--- a/HySoP/hysop/domain/obstacle/planes.py
+++ b/HySoP/hysop/domain/obstacle/planes.py
@@ -115,6 +115,7 @@ class SubSpace(HalfSpace):
         self.dist = dist
         self.origin = npw.realarray(point)
         self.max = self.origin + npw.realarray(lengths)
+        self.lengths = npw.realarray(lengths)
         ndir = np.where(self.normal != 0)[0][0]
         if normal[ndir] > 0:
             self.max[ndir] = self.origin[ndir]
diff --git a/HySoP/hysop/domain/tests/test_obstacle.py b/HySoP/hysop/domain/tests/test_obstacle.py
index c40c2a37eaa1850ed85ac7e7633bac52e8ac9953..f7810b7ff11a0b5459aef5814d12111f459dec4d 100644
--- a/HySoP/hysop/domain/tests/test_obstacle.py
+++ b/HySoP/hysop/domain/tests/test_obstacle.py
@@ -33,7 +33,7 @@ dvol = np.prod(h3d)
 ds = np.prod(h2d)
 import math
 pi = math.pi
-tol = 1e-3
+tol = 1e-6
 lengths = np.asarray([20 * h3d[0], 22 * h3d[1], 31 * h3d[2]])
 rlengths = lengths + h3d
 rlengths2d = lengths[:2] + h2d
diff --git a/HySoP/hysop/fields/continuous.py b/HySoP/hysop/fields/continuous.py
index a60a3d6611f784786e4ef5d9fbc93065a3811dc5..1e5007e8a6fd06a35c36794ef18c44a348ff55fd 100644
--- a/HySoP/hysop/fields/continuous.py
+++ b/HySoP/hysop/fields/continuous.py
@@ -6,6 +6,8 @@ Continuous variable description.
 from parmepy.constants import debug
 from parmepy.fields.discrete import DiscreteField
 from parmepy.mpi import main_rank
+import parmepy.tools.numpywrappers as npw
+import numpy as np
 
 
 class Field(object):
@@ -256,3 +258,36 @@ class Field(object):
 
     def finalize(self):
         pass
+
+    def integrate(self, box, topo, useSlice=True,
+                  component=0, root=0, mpiall=True):
+        """
+        integrate the field on a control box, on the current processus
+        @param box : a parmepy.domain.obstacles.controlBox.ControlBox
+        @param topo : discretization used for integration
+        @param useSlice : true if integrate with slices else integrate with
+        boolean numpy array
+        @param component : component number of the field to integrate
+        @param root : root process for mpi reduce
+        @param mpiall : true for allreduce, else reduce on root
+        """
+        return self.discreteFields[topo].integrate(box, useSlice, component,
+                                                   root, mpiall)
+
+    def integrateOnSurface(self, surf, topo, useSlice=True, component=0,
+                           root=0, mpiall=True):
+        """
+        integrate the field on a surface, on the current processus
+        @param surf : a parmepy.domain.obstacles.controlBox.planes.SubPlane
+        @param topo : discretization used for integration
+        @param useSlice : true if integrate with slices else integrate with
+        boolean numpy array
+        @param component : component number of the field to integrate
+        @param root : root process for mpi reduce
+        @param mpiall : true for allreduce, else reduce on root
+        Warning : surf slices or cond must have been computed for integration
+        purpose, that is last point in each dir must not be included.
+        """
+        return self.discreteFields[topo].integrateOnSurface(surf, useSlice,
+                                                            component, root,
+                                                            mpiall)
diff --git a/HySoP/hysop/fields/discrete.py b/HySoP/hysop/fields/discrete.py
index 60704c3ef653b582905006540d813a7f77429249..cdf9abfa679d1ef49a17acc7460ec9332dd12a1b 100644
--- a/HySoP/hysop/fields/discrete.py
+++ b/HySoP/hysop/fields/discrete.py
@@ -15,7 +15,8 @@ from parmepy.numerics.updateGhosts import UpdateGhosts
 
 
 class DiscreteField(object):
-    """Interface for discrete fields (scalar or vector).
+    """
+    Interface for discrete fields (scalar or vector).
 
     A discrete field represents the data layout on each mpi process for
     a given global resolution.
@@ -187,10 +188,10 @@ class DiscreteField(object):
             # No formula, set all components to zero"
             for d in xrange(self.nbComponents):
                 self.data[d][...] = 0.0
-        if not all([(s == self.resolution).all()
-                    for s in [dat.shape for dat in self.data]]):
-            print "WARNING: The shape of " + self.name + " has changed during"\
-                " field initialisation."
+        assert all([(s == self.resolution).all()
+                    for s in [dat.shape for dat in self.data]]),\
+            "WARNING: The shape of " + self.name + " has changed during"\
+            " field initialisation."
 
     def norm(self):
         """
@@ -209,9 +210,6 @@ class DiscreteField(object):
         self.topology.comm.Allreduce(result, gResult)
         return gResult ** (1. / 2)
 
-    def get_data_method(self):
-        pass
-
     @debug
     @timed_function
     def dump(self, filename, mode=None):
@@ -253,3 +251,79 @@ class DiscreteField(object):
         """ set all components to zero"""
         for dim in xrange(self.nbComponents):
             self.data[dim][...] = 0.0
+
+    def integrate_on_proc(self, box, useSlice=True, component=0):
+        """
+        integrate the field on a control box, on the current processus
+        @param box : a parmepy.domain.obstacles.controlBox.ControlBox
+        @param useSlice : true if integrate with slices else integrate with
+        boolean numpy array
+        @param component : component number of the field to integrate
+        """
+        if useSlice:
+            cond = box.slices[self.topology]
+        else:
+            iC = self.topology.mesh.iCompute
+            cond = box.ind[self.topology][0][iC]
+        dvol = npw.prod(self.topology.mesh.space_step)
+        result = npw.sum(self.data[component][cond])
+        result *= dvol
+        return result
+
+    def integrate(self, box, useSlice=True, component=0,
+                  root=0, mpiall=True):
+        """
+        integrate the field on a control box, on the current processus
+        @param box : a parmepy.domain.obstacles.controlBox.ControlBox
+        @param useSlice : true if integrate with slices else integrate with
+        boolean numpy array
+        @param component : component number of the field to integrate
+        @param root : root process for mpi reduce
+        @param mpiall : true for allreduce, else reduce on root
+        """
+        res = self.integrate_on_proc(box, useSlice, component)
+        if mpiall:
+            return self.topology.comm.allreduce(res)
+        else:
+            return self.topology.comm.reduce(res, root=root)
+
+    def integrateOnSurface(self, surf, useSlice=True, component=0,
+                           root=0, mpiall=True):
+        """
+        integrate the field on a surface, on the current processus
+        @param surf : a parmepy.domain.obstacles.controlBox.planes.SubPlane
+        @param useSlice : true if integrate with slices else integrate with
+        boolean numpy array
+        @param component : component number of the field to integrate
+        @param root : root process for mpi reduce
+        @param mpiall : true for allreduce, else reduce on root
+        Warning : surf slices or cond must have been computed for integration
+        purpose, that is last point in each dir must not be included.
+        """
+        res = self.integrateOnSurf_proc(surf, useSlice, component)
+        if mpiall:
+            return self.topology.comm.allreduce(res)
+        else:
+            return self.topology.comm.reduce(res, root=root)
+
+    def integrateOnSurf_proc(self, surf, useSlice=True, component=0):
+        """
+        integrate the field on a surface, on the current processus
+        @param surf : a parmepy.domain.obstacles.controlBox.planes.Plane
+         or SubPlane
+        @param useSlice : true if integrate with slices else integrate with
+        boolean numpy array
+        @param component : component number of the field to integrate
+        Warning : surf slices or cond must have been computed for integration
+        purpose, that is last point in each dir must not be included.
+        """
+        if useSlice:
+            cond = surf.slices[self.topology]
+        else:
+            iC = self.topology.mesh.iCompute
+            cond = surf.ind[self.topology][0][iC]
+        dirs = np.where(surf.normal == 0)[0]
+        dS = npw.prod(self.topology.mesh.space_step[dirs])
+        result = npw.sum(self.data[component][cond])
+        result *= dS
+        return result
diff --git a/HySoP/hysop/fields/tests/test_field.py b/HySoP/hysop/fields/tests/test_field.py
index 631a81994415a5c59be108bbd276ae6c654a5e5c..020e8df0fd6ed393d8eae24d1f8ce805cadd6ff8 100644
--- a/HySoP/hysop/fields/tests/test_field.py
+++ b/HySoP/hysop/fields/tests/test_field.py
@@ -4,6 +4,7 @@ Testing parmepy.field.continuous.Field
 from parmepy.fields.continuous import Field
 from parmepy.domain.box import Box
 from parmepy.mpi.topology import Cartesian
+from parmepy.domain.obstacle.planes import SubPlane
 import sys
 import numpy as np
 
@@ -63,3 +64,22 @@ def test_discretization():
                     cvf.discreteFields[topo].data[1].shape).all()
     assert np.equal(cvf.discreteFields[topo].resolution,
                     cvf.discreteFields[topo].data[2].shape).all()
+
+
+def test_integrate_onSurf():
+    dom = Box()
+    myf = Field(dom, isVector=True)
+    resolTopo = [33, 33, 17]
+    topo = Cartesian(dom, 3, resolTopo)
+    fdiscr = myf.discretize(topo)
+    fdiscr[0][...] = 1.0
+    normal = [1, 0, 0]
+    hh = topo.mesh.space_step
+    surf = SubPlane(dom, normal=normal, point=dom.origin,
+                    lengths=dom.length - hh,
+                    epsilon=topo.mesh.space_step[0]/2.)
+
+    surf.discretize(topo)
+    res = myf.integrateOnSurface(surf, topo)
+    sref = dom.length[1] * dom.length[2]
+    assert(abs(res - sref) < 1e-6)
diff --git a/HySoP/hysop/gpu/QtRendering.py b/HySoP/hysop/gpu/QtRendering.py
index 81d7a02a05aa17a6fabbd3a37f44b011fd29e1b8..4a3ccfdbc702a636be66c2305e35ce1d66882843 100644
--- a/HySoP/hysop/gpu/QtRendering.py
+++ b/HySoP/hysop/gpu/QtRendering.py
@@ -14,6 +14,7 @@ from parmepy.gpu import cl
 from parmepy.gpu.gpu_discrete import GPUDiscreteField
 from parmepy.gpu.gpu_kernel import KernelLauncher
 from parmepy.tools.timers import timed_function
+from parmepy.mpi import main_rank
 
 
 class QtOpenGLRendering(Monitoring):
@@ -164,7 +165,8 @@ class QtOpenGLRendering(Monitoring):
         """
         t = simulation.time
         dt = simulation.timeStep
-        simulation.printState()
+        if main_rank == 0:
+            simulation.printState()
         # OpenCL update
         self.numMethod(self.gpu_field.gpu_data[self.component],
                        self.color)
diff --git a/HySoP/hysop/gpu/tests/test_advection_nullVelocity.py b/HySoP/hysop/gpu/tests/test_advection_nullVelocity.py
index 1613faaf644845446e0bcf79fd54837bd6854f48..7dabdfc4e430fda423ab6b5d25703ac5714807bb 100644
--- a/HySoP/hysop/gpu/tests/test_advection_nullVelocity.py
+++ b/HySoP/hysop/gpu/tests/test_advection_nullVelocity.py
@@ -44,7 +44,7 @@ def assertion_2D(scal, velo, advec):
     scal_d.toDevice()
     velo_d.toDevice()
 
-    advec.apply(Simulation(0., 0.01, 1))
+    advec.apply(Simulation(0., 1., 0.01))
 
     scal_d.toHost()
 
@@ -69,8 +69,8 @@ def assertion_2D_withPython(scal, velo, advec, advec_py):
     scal_d.toDevice()
     velo_d.toDevice()
 
-    advec_py.apply(Simulation(0., 0.01, 1))
-    advec.apply(Simulation(0., 0.01, 1))
+    advec_py.apply(Simulation(0., 1., 0.01))
+    advec.apply(Simulation(0., 1., 0.01))
 
     py_res = scal_d.data[0].copy()
     scal_d.toHost()
@@ -99,7 +99,7 @@ def assertion_3D(scal, velo, advec):
     scal_d.toDevice()
     velo_d.toDevice()
 
-    advec.apply(Simulation(0., 0.01, 1))
+    advec.apply(Simulation(0., 1., 0.01))
 
     scal_d.toHost()
 
@@ -126,8 +126,8 @@ def assertion_3D_withPython(scal, velo, advec, advec_py):
     scal_d.toDevice()
     velo_d.toDevice()
 
-    advec_py.apply(Simulation(0., 0.01, 1))
-    advec.apply(Simulation(0., 0.01, 1))
+    advec_py.apply(Simulation(0., 1., 0.01))
+    advec.apply(Simulation(0., 1., 0.01))
 
     py_res = scal_d.data[0].copy()
     scal_d.toHost()
@@ -954,8 +954,8 @@ def test_rectangular_domain2D():
     scal_d.toDevice()
     velo_d.toDevice()
 
-    advec.apply(Simulation(0., 0.01, 1))
-    advec_py.apply(Simulation(0., 0.01, 1))
+    advec.apply(Simulation(0., 1., 0.01))
+    advec_py.apply(Simulation(0., 1., 0.01))
     scal_py_res = scal_d.data[0].copy()
 
     scal_d.toHost()
@@ -1008,8 +1008,8 @@ def test_rectangular_domain3D():
     scal_d.toDevice()
     velo_d.toDevice()
 
-    advec.apply(Simulation(0., 0.01, 1))
-    advec_py.apply(Simulation(0., 0.01, 1))
+    advec.apply(Simulation(0., 1., 0.01))
+    advec_py.apply(Simulation(0., 1., 0.01))
     scal_py_res = scal_d.data[0].copy()
 
     scal_d.toHost()
@@ -1063,8 +1063,8 @@ def test_2D_vector():
     scal_d.toDevice()
     velo_d.toDevice()
 
-    advec.apply(Simulation(0., 0.01, 1))
-    advec_py.apply(Simulation(0., 0.01, 1))
+    advec.apply(Simulation(0., 1., 0.01))
+    advec_py.apply(Simulation(0., 1., 0.01))
     scal_py_res_X = scal_d.data[0].copy()
     scal_py_res_Y = scal_d.data[1].copy()
 
@@ -1126,8 +1126,8 @@ def test_3D_vector():
     scal_d.toDevice()
     velo_d.toDevice()
 
-    advec.apply(Simulation(0., 0.01, 1))
-    advec_py.apply(Simulation(0., 0.01, 1))
+    advec.apply(Simulation(0., 1., 0.01))
+    advec_py.apply(Simulation(0., 1., 0.01))
     scal_py_res_X = scal_d.data[0].copy()
     scal_py_res_Y = scal_d.data[1].copy()
     scal_py_res_Z = scal_d.data[2].copy()
diff --git a/HySoP/hysop/gpu/tests/test_advection_randomVelocity.py b/HySoP/hysop/gpu/tests/test_advection_randomVelocity.py
index 7e1d32982cc5872a3235fa2eda0820a4c6b9095f..e2165bfb0a40e38488bd8ea276203d24d8c9d578 100644
--- a/HySoP/hysop/gpu/tests/test_advection_randomVelocity.py
+++ b/HySoP/hysop/gpu/tests/test_advection_randomVelocity.py
@@ -2,7 +2,6 @@
 @file parmepy.gpu.tests.test_advection_randomVelocity
 Testing advection kernels with a random velocity field.
 """
-import parmepy
 from parmepy.domain.box import Box
 from parmepy.fields.continuous import Field
 from parmepy.operator.advection import Advection
@@ -49,8 +48,8 @@ def assertion_2D_withPython(scal, velo, advec, advec_py):
     scal_d.toDevice()
     velo_d.toDevice()
 
-    advec_py.apply(Simulation(0., 0.001, 1))
-    advec.apply(Simulation(0., 0.001, 1))
+    advec_py.apply(Simulation(0., 1., 0.001))
+    advec.apply(Simulation(0., 1., 0.001))
 
     py_res = scal_d.data[0].copy()
     scal_d.toHost()
@@ -82,8 +81,8 @@ def assertion_3D_withPython(scal, velo, advec, advec_py):
     scal_d.toDevice()
     velo_d.toDevice()
 
-    advec_py.apply(Simulation(0., 0.1, 1))
-    advec.apply(Simulation(0., 0.1, 1))
+    advec_py.apply(Simulation(0., 1., 0.1))
+    advec.apply(Simulation(0., 1., 0.1))
 
     py_res = scal_d.data[0].copy()
     scal_d.toHost()
@@ -834,8 +833,8 @@ def test_rectangular_domain2D():
     scal_d.toDevice()
     velo_d.toDevice()
 
-    advec_py.apply(Simulation(0., 0.1, 1))
-    advec.apply(Simulation(0., 0.1, 1))
+    advec_py.apply(Simulation(0., 1., 0.1))
+    advec.apply(Simulation(0., 1., 0.1))
 
     py_res = scal_d.data[0].copy()
     scal_d.toHost()
@@ -889,8 +888,8 @@ def test_rectangular_domain3D():
     scal_d.toDevice()
     velo_d.toDevice()
 
-    advec_py.apply(Simulation(0., 0.01, 1))
-    advec.apply(Simulation(0., 0.01, 1))
+    advec_py.apply(Simulation(0., 1., 0.01))
+    advec.apply(Simulation(0., 1., 0.01))
 
     py_res = scal_d.data[0].copy()
     scal_d.toHost()
@@ -945,8 +944,8 @@ def test_vector_2D():
     velo_d.toDevice()
 
     print np.max(scal_d.data[0] - scal_d.data[1])
-    advec_py.apply(Simulation(0., 0.01, 1))
-    advec.apply(Simulation(0., 0.01, 1))
+    advec_py.apply(Simulation(0., 1., 0.01))
+    advec.apply(Simulation(0., 1., 0.01))
 
     py_res_X = scal_d.data[0].copy()
     py_res_Y = scal_d.data[1].copy()
@@ -1006,8 +1005,8 @@ def test_vector_3D():
     scal_d.toDevice()
     velo_d.toDevice()
 
-    advec_py.apply(Simulation(0., 0.01, 1))
-    advec.apply(Simulation(0., 0.01, 1))
+    advec_py.apply(Simulation(0., 1., 0.01))
+    advec.apply(Simulation(0., 1., 0.01))
 
     py_res_X = scal_d.data[0].copy()
     py_res_Y = scal_d.data[1].copy()
@@ -1018,4 +1017,3 @@ def test_vector_3D():
     assert np.allclose(py_res_Y, scal_d.data[1], rtol=5e-02, atol=5e-05)
     assert np.allclose(py_res_Z, scal_d.data[2], rtol=5e-02, atol=5e-05)
     advec.finalize()
-
diff --git a/HySoP/hysop/gpu/tests/test_opencl_environment.py b/HySoP/hysop/gpu/tests/test_opencl_environment.py
index 1643ba3bda76d3a22382621053606afb50f2ca0a..46931e9af3231460586d6c9a87e2987fd1eff1b7 100644
--- a/HySoP/hysop/gpu/tests/test_opencl_environment.py
+++ b/HySoP/hysop/gpu/tests/test_opencl_environment.py
@@ -1,6 +1,5 @@
 from parmepy.constants import np
-from parmepy.gpu.tools import get_opencl_environment, \
-    get_opengl_shared_environment
+from parmepy.gpu.tools import get_opencl_environment
 FLOAT_GPU = np.float32
 
 
diff --git a/HySoP/hysop/gpu/tests/test_transposition.py b/HySoP/hysop/gpu/tests/test_transposition.py
index 28873c2d34f584ac9193999e467d989569b5c4a3..fd245a3a5d973b7a64ffde136a22b2e6cd85bfe3 100644
--- a/HySoP/hysop/gpu/tests/test_transposition.py
+++ b/HySoP/hysop/gpu/tests/test_transposition.py
@@ -256,7 +256,8 @@ def test_transposition_xz3D():
     src_transpose_xz = 'kernels/transpose_xz_noVec.cl'
     build_options = ""
     build_options += " -D NB_I=32 -D NB_II=32 -D NB_III=32"
-    build_options += " -D TILE_DIM_XZ=16 -D BLOCK_ROWS_XZ=4 -D BLOCK_DEPH_XZ=4 -D PADDING_XZ=1"
+    build_options += " -D TILE_DIM_XZ=16 -D BLOCK_ROWS_XZ=4"
+    build_options += " -D BLOCK_DEPH_XZ=4 -D PADDING_XZ=1"
     gwi = (int(resolution[0]),
            int(resolution[1] / 4),
            int(resolution[2] / 4))
@@ -302,7 +303,6 @@ def test_transposition_xz3D():
 
 def test_transposition_xz3D_rect():
     resolution = (32, 32, 64)
-    resolutionT = (64, 32, 32)
     cl_env = get_opencl_environment(0, 0, 'gpu', PARMES_REAL)
     vec = 1
     src_transpose_xz = 'kernels/transpose_xz_noVec.cl'
@@ -310,7 +310,8 @@ def test_transposition_xz3D_rect():
     # Settings are taken from destination layout as current layout.
     # gwi is computed form input layout (appears as transposed layout)
     build_options += " -D NB_I=64 -D NB_II=32 -D NB_III=32"
-    build_options += " -D TILE_DIM_XZ=16 -D BLOCK_ROWS_XZ=4 -D BLOCK_DEPH_XZ=4 -D PADDING_XZ=1"
+    build_options += " -D TILE_DIM_XZ=16 -D BLOCK_ROWS_XZ=4"
+    build_options += " -D BLOCK_DEPH_XZ=4 -D PADDING_XZ=1"
     gwi = (int(resolution[0]),
            int(resolution[1] / 4),
            int(resolution[2] / 4))
@@ -321,7 +322,8 @@ def test_transposition_xz3D_rect():
 
     build_options = ""
     build_options += " -D NB_I=32 -D NB_II=32 -D NB_III=64"
-    build_options += " -D TILE_DIM_XZ=16 -D BLOCK_ROWS_XZ=4 -D BLOCK_DEPH_XZ=4 -D PADDING_XZ=1"
+    build_options += " -D TILE_DIM_XZ=16 -D BLOCK_ROWS_XZ=4"
+    build_options += " -D BLOCK_DEPH_XZ=4 -D PADDING_XZ=1"
     gwi = (int(resolution[2]),
            int(resolution[1] / 4),
            int(resolution[0] / 4))
@@ -373,7 +375,8 @@ def test_transposition_xz3Dslice():
     src_transpose_xz = 'kernels/transpose_xz_slice_noVec.cl'
     build_options = ""
     build_options += " -D NB_I=32 -D NB_II=32 -D NB_III=32"
-    build_options += " -D TILE_DIM_XZ=16 -D BLOCK_ROWS_XZ=1 -D BLOCK_DEPH_XZ=4 -D PADDING_XZ=1"
+    build_options += " -D TILE_DIM_XZ=16 -D BLOCK_ROWS_XZ=1"
+    build_options += " -D BLOCK_DEPH_XZ=4 -D PADDING_XZ=1"
     gwi = (int(resolution[0]),
            int(resolution[1]),
            int(resolution[2] / 4))
@@ -419,7 +422,6 @@ def test_transposition_xz3Dslice():
 
 def test_transposition_xz3Dslice_rect():
     resolution = (32, 32, 64)
-    resolutionT = (64, 32, 32)
     cl_env = get_opencl_environment(0, 0, 'gpu', PARMES_REAL)
     vec = 1
     src_transpose_xz = 'kernels/transpose_xz_slice_noVec.cl'
@@ -427,7 +429,8 @@ def test_transposition_xz3Dslice_rect():
     # Settings are taken from destination layout as current layout.
     # gwi is computed form input layout (appears as transposed layout)
     build_options += " -D NB_I=64 -D NB_II=32 -D NB_III=32"
-    build_options += " -D TILE_DIM_XZ=16 -D BLOCK_ROWS_XZ=1 -D BLOCK_DEPH_XZ=4 -D PADDING_XZ=1"
+    build_options += " -D TILE_DIM_XZ=16 -D BLOCK_ROWS_XZ=1"
+    build_options += " -D BLOCK_DEPH_XZ=4 -D PADDING_XZ=1"
     gwi = (int(resolution[0]),
            int(resolution[1]),
            int(resolution[2] / 4))
@@ -438,7 +441,8 @@ def test_transposition_xz3Dslice_rect():
 
     build_options = ""
     build_options += " -D NB_I=32 -D NB_II=32 -D NB_III=64"
-    build_options += " -D TILE_DIM_XZ=16 -D BLOCK_ROWS_XZ=1 -D BLOCK_DEPH_XZ=4 -D PADDING_XZ=1"
+    build_options += " -D TILE_DIM_XZ=16 -D BLOCK_ROWS_XZ=1"
+    build_options += " -D BLOCK_DEPH_XZ=4 -D PADDING_XZ=1"
     gwi = (int(resolution[2]),
            int(resolution[1]),
            int(resolution[0] / 4))
diff --git a/HySoP/hysop/gpu/tools.py b/HySoP/hysop/gpu/tools.py
index b33a41a7385c9203c333183cd1f007890e23db17..e6ec65a2942f622f38c485f4f63d8df35d002e6c 100644
--- a/HySoP/hysop/gpu/tools.py
+++ b/HySoP/hysop/gpu/tools.py
@@ -72,7 +72,6 @@ class OpenCLEnvironment(object):
         self.kernels_config = kernel_cfg
         self._locMem_Buffers = {}
 
-
     def modify(self, platform_id, device_id, device_type,
                precision, gl_sharing=False):
         """
diff --git a/HySoP/hysop/mpi/topology.py b/HySoP/hysop/mpi/topology.py
index 3f8fc6b37d953c4b366687fe9d1af4582e8ac471..4ddc7e3f62b03ffd3ed97be6511ca7f06a909b40 100644
--- a/HySoP/hysop/mpi/topology.py
+++ b/HySoP/hysop/mpi/topology.py
@@ -75,7 +75,7 @@ class Cartesian(object):
         # to 0 if shape[:] = 1
         ## (Source) Communicator used to build the topology
         if comm is None:
-             from parmepy.mpi.main_var import main_comm as comm
+            from parmepy.mpi.main_var import main_comm as comm
         self._comm_origin = comm
         ## number of process in comm_origin
         self._origin_size = self._comm_origin.Get_size()
@@ -215,10 +215,6 @@ class Cartesian(object):
         newId = self.domain.register(self)
         self.isNew = True
         if newId >= 0:
-            s = "A similar topology already exist in the domain's list."
-            s += "You'd rather destroy this one and use topo of id"
-            s += str(newId)
-            print s
             self.isNew = False
 
     def getParent(self):
@@ -227,12 +223,6 @@ class Cartesian(object):
         """
         return self._comm_origin
 
-    def setParent(self, comm):
-        """
-        returns the communicator used to build this topology
-        """
-        self._comm_origin = comm
-
     @debug
     def setUp(self):
         """Topology set up.
@@ -697,8 +687,6 @@ class Bridge(object):
         return s
 
 
-
-
 class Bridge_intercomm(object):
     """
     This bridge is defined as the Bridge class.
diff --git a/HySoP/hysop/numerics/differential_operations.py b/HySoP/hysop/numerics/differential_operations.py
index 9773a8e19a7439f434a1bcfaef3a6ac645925154..1575827da586daae58298878362d80a76d17871c 100755
--- a/HySoP/hysop/numerics/differential_operations.py
+++ b/HySoP/hysop/numerics/differential_operations.py
@@ -6,7 +6,7 @@ Library of functions used to perform classical vector calculus
 """
 from parmepy.constants import debug, XDIR, YDIR, ZDIR
 from abc import ABCMeta, abstractmethod
-from parmepy.numerics.finite_differences import FD_C_4, FD2_C_2, FD_C_2
+from parmepy.numerics.finite_differences import FD_C_4, FD2_C_2
 import numpy as np
 
 
@@ -326,107 +326,6 @@ class Laplacian(DifferentialOperation):
         return result
 
 
-class DivStressTensor3D(DifferentialOperation):
-    """
-    Computes the 3D stress tensor T defined by 
-    \f$ T=div(\nabla.(U) + \nabla^{T}.(U)) \f$,
-    \f$U\f$ being a velocity vector field.
-
-    Methods :
-    1 - FD_C_4 (default) : 4th order, centered finite differences, with
-    local workspace and based on fd.compute_and_add.
-    init : func = GradS(topo, method)
-    call : result = func(var, result)
-
-    var stands for the vector field U.
-    result must be a vector field (same number of components as var),
-    each component with the same size as var[i].
-    work must be a three component vector field
-    each component with the same size as var[i].
-
-    """
-    def __init__(self, topo, method=FD_C_2):
-        if method is FD_C_4:
-            raise ValueError("4th order scheme Not yet implemented")
-        else :
-            # - 2nd ordered FD
-            # - with work
-            # - fd.compute_and_add method
-
-            # connect call function
-            self.fcall = self.FDCentral2
-            self.fd_scheme = FD_C_2((topo.mesh.space_step))
-
-    @staticmethod
-    def getWorkLengths(nb_components=None, domain_dim=None, fd_method=None):
-        return 0
-
-    def __call__(self, var, result, ind):
-        assert result[0].shape == var[0].shape
-        return self.fcall(var, result, ind)
-
-    def FDCentral2(self, var, result, ind):
-        """
-        """
-        # compute indices according to "ind" list
-        self._indices = ind
-        self.fd_scheme.computeIndices(self._indices)
-        self.fd_scheme.computeIndices_crossed(self._indices)
-
-        # 1st component of the stress tensor
-        # ----- 2 * d2ux/dx2
-        self.fd_scheme.compute_2nd_deriv(var[XDIR], XDIR, result[XDIR])
-        result[XDIR][...] *= 2.
-        # ----- += d2ux/dy2
-        self.fd_scheme.compute_and_add_2nd_deriv(var[XDIR], YDIR, 
-                                                 result[XDIR])
-        # ----- += d2ux/dz2
-        self.fd_scheme.compute_and_add_2nd_deriv(var[XDIR], ZDIR, 
-                                                 result[XDIR])
-        # ----- += d2uy/dxdy
-        self.fd_scheme.compute_and_add_2nd_crossed_deriv(var[YDIR], XDIR,
-                                                         YDIR, result[XDIR])
-        # ----- += d2uz/dxdz
-        self.fd_scheme.compute_and_add_2nd_crossed_deriv(var[ZDIR], XDIR, 
-                                                         ZDIR, result[XDIR])
-
-        # 2nd component of the stress tensor
-        # ----- 2 * d2uy/dy2
-        self.fd_scheme.compute_2nd_deriv(var[YDIR], YDIR, result[YDIR])
-        result[YDIR][...] *= 2.
-        # ----- += d2uy/dx2
-        self.fd_scheme.compute_and_add_2nd_deriv(var[YDIR], XDIR, 
-                                                 result[YDIR])
-        # ----- += d2uy/dz2
-        self.fd_scheme.compute_and_add_2nd_deriv(var[YDIR], ZDIR, 
-                                                 result[YDIR])
-        # ----- += d2ux/dydx
-        self.fd_scheme.compute_and_add_2nd_crossed_deriv(var[XDIR], YDIR,
-                                                         XDIR, result[YDIR])
-        # ----- += d2uz/dydz
-        self.fd_scheme.compute_and_add_2nd_crossed_deriv(var[ZDIR], YDIR, 
-                                                         ZDIR, result[YDIR])
-
-        # 3rd component of the stress tensor
-        # ----- 2 * d2uz/dz2
-        self.fd_scheme.compute_2nd_deriv(var[ZDIR], ZDIR, result[ZDIR])
-        result[ZDIR][...] *= 2.
-        # ----- += d2uz/dx2
-        self.fd_scheme.compute_and_add_2nd_deriv(var[ZDIR], XDIR, 
-                                                 result[ZDIR])
-        # ----- += d2uz/dy2
-        self.fd_scheme.compute_and_add_2nd_deriv(var[ZDIR], YDIR, 
-                                                 result[ZDIR])
-        # ----- += d2ux/dzdx
-        self.fd_scheme.compute_and_add_2nd_crossed_deriv(var[XDIR], ZDIR,
-                                                         XDIR, result[ZDIR])
-        # ----- += d2uy/dzdy
-        self.fd_scheme.compute_and_add_2nd_crossed_deriv(var[YDIR], ZDIR, 
-                                                         YDIR, result[ZDIR])
-
-        return result
-
-
 class GradS(DifferentialOperation):
     """
     Computes \f$ \nabla\rho \f$, \f$ \rho\f$ a scalar field
diff --git a/HySoP/hysop/numerics/finite_differences.py b/HySoP/hysop/numerics/finite_differences.py
index a260da267294f76d43900c6e447169cf78737993..bc05d712a6ce3ab699c29d48e5ed014bb1a53007 100644
--- a/HySoP/hysop/numerics/finite_differences.py
+++ b/HySoP/hysop/numerics/finite_differences.py
@@ -19,14 +19,14 @@ class FiniteDifference(object):
     and initialize it with a step from domain discretisation description
 
     \code
-    >>> step = topo.mesh_space_step
-    >>> scheme = FD_C_4(step)
+    >> step = topo.mesh_space_step
+    >> scheme = FD_C_4(step)
     \endcode
 
     - Compute scheme indices, based on topology grid points :
 
     \code
-    >>> scheme.computeIndices(topo.mesh.iCompute)
+    >> scheme.computeIndices(topo.mesh.iCompute)
     \endcode
 
     2 - Computation
@@ -36,14 +36,14 @@ class FiniteDifference(object):
     \f$ result = \frac{\partial tab}{\partial dir}\f$ :
 
     \code
-    >>> scheme.compute(tab, dir, result)
+    >> scheme.compute(tab, dir, result)
     \endcode
 
     or :
     \f$ result = result + \frac{\partial tab}{\partial dir}\f$
 
     \code
-    >>> scheme.compute_and_add(tab, dir, result)
+    >> scheme.compute_and_add(tab, dir, result)
     \endcode
 
     Notes FP :
@@ -270,4 +270,3 @@ class FD_C_4(FiniteDifference):
                                                       tab[self._m1[cdir]]) +
                                                      tab[self._m2[cdir]] -
                                                      tab[self._a2[cdir]])
-
diff --git a/HySoP/hysop/numerics/tests/test_diffOp.py b/HySoP/hysop/numerics/tests/test_diffOp.py
index ecfa4000777dfd0375c6158ed31bcbc83500c6cb..c1b5b768c4e50d8745df5166dc539b1e5469b67b 100755
--- a/HySoP/hysop/numerics/tests/test_diffOp.py
+++ b/HySoP/hysop/numerics/tests/test_diffOp.py
@@ -4,7 +4,6 @@ import numpy as np
 from parmepy.fields.continuous import Field
 from parmepy.mpi.topology import Cartesian
 import parmepy.numerics.differential_operations as diffop
-from parmepy.numerics.updateGhosts import UpdateGhosts
 import parmepy.tools.numpywrappers as npw
 import math as m
 pi = m.pi
@@ -61,11 +60,10 @@ velo = Field(domain=box, formula=computeVel,
              name='Velocity', isVector=True)
 vorti = Field(domain=box, formula=computeVort,
               name='Vorticity', isVector=True)
-vorti.setTopoInit(topo)
 velo.discretize(topo)
 vorti.discretize(topo)
-velo.initialize()
-vorti.initialize()
+velo.initialize(topo=topo)
+vorti.initialize(topo=topo)
 wd = vorti.discreteFields[topo]
 vd = velo.discreteFields[topo]
 ind = topo.mesh.iCompute
@@ -88,13 +86,13 @@ def testDivWV():
     ref = Field(domain=box, formula=analyticalDivWV,
                 name='Analytical', isVector=True)
     ref.discretize(topo)
-    ref.initialize()
+    ref.initialize(topo=topo)
     refd = ref.discreteFields[topo]
     memshape = vd.data[0].shape
     # Div operator
-    lwork = diffop.DivV.getWorkLengths()
+    lwork = diffop.DivWV.getWorkLengths()
     work = [npw.zeros(memshape) for i in xrange(lwork)]
-    divOp = diffop.DivV(topo, work)
+    divOp = diffop.DivWV(topo, work)
     result = [npw.zeros(memshape) for i in xrange(3)]
     result = divOp(vd.data, wd.data, result)
 
@@ -110,7 +108,7 @@ def testGradVxW():
     ref = Field(domain=box, formula=analyticalGradVxW,
                 name='Analytical', isVector=True)
     ref.discretize(topo)
-    ref.initialize()
+    ref.initialize(topo=topo)
     refd = ref.discreteFields[topo]
     memshape = vd.data[0].shape
     lwork = diffop.GradVxW.getWorkLengths()
@@ -125,39 +123,3 @@ def testGradVxW():
     errX = (Lx / (nb - 1)) ** 4
     for i in xrange(3):
         assert np.allclose(refd[i][ind], result[i][ind], rtol=errX)
-
-
-def testDivStressTensor():
-    # Topologies
-#    topo1G = Cartesian(box, box.dimension, nbElem,
-#                       ghosts=[2, 2, 2])
-    topoNoG = Cartesian(box, box.dimension, nbElem)
-    ind = topo.mesh.iCompute
-    # Reference field
-    ref = Field(domain=box, formula=analyticalDivStressTensor,
-                name='Analytical', isVector=True)
-    ref.discretize(topoNoG)
-    ref.initialize()
-    refd = ref.discreteFields[topoNoG]
-    memshape = vd.data[0].shape
-
-    # prepare ghost points synchro for velocity
-    synchronize = UpdateGhosts(topo, velo.nbComponents)
-    synchronize(vd.data)
-
-    divTOp = diffop.DivStressTensor3D(topo)
-    result = [npw.zeros(memshape) for i in xrange(3)]
-    result = divTOp(vd.data, result, ind)
-
-    # Numerical VS analytical
-    Lx = box.length[0]
-    errX = (Lx / (nb - 1)) ** 2
-
-    for i in xrange(3):
-        assert np.allclose(refd[i], result[i][ind], rtol=errX)
-
-if __name__ == "__main__":
-    testDivWV()
-    testGradVxW()
-    testCurl()
-    testDivStressTensor()
diff --git a/HySoP/hysop/operator/__init__.py b/HySoP/hysop/operator/__init__.py
index 09b8f2632344d26a2e52c155fcee2aab99c523e0..8cebe57a80a8ba046ec546043d544d3a651adec8 100644
--- a/HySoP/hysop/operator/__init__.py
+++ b/HySoP/hysop/operator/__init__.py
@@ -24,3 +24,4 @@
 #  - method["Support"] = GPU, CPU
 #  - method["Formulation"] = Conservative, GradUW (may depends on the operator)
 #  - ...
+
diff --git a/HySoP/hysop/operator/adapt_timestep.py b/HySoP/hysop/operator/adapt_timestep.py
index 6cb98714501470e5c259ae10efb572e2b79a48cb..70662d439d2d4f9830c97a33ff96ac5dd463d4ac 100755
--- a/HySoP/hysop/operator/adapt_timestep.py
+++ b/HySoP/hysop/operator/adapt_timestep.py
@@ -6,26 +6,27 @@ Definition of the adaptative time step according to the flow fields.
 
 """
 from parmepy.constants import debug
-from parmepy.methods_keys import TimeIntegrator, SpaceDiscretisation, dtAdvecCrit
+from parmepy.methods_keys import TimeIntegrator, SpaceDiscretisation,\
+    dtAdvecCrit
 from parmepy.numerics.integrators.runge_kutta3 import RK3
 from parmepy.numerics.finite_differences import FD_C_4
 from parmepy.operator.discrete.adapt_timestep import AdaptTimeStep_D
 from parmepy.operator.continuous import Operator
+from parmepy.variable_parameter import VariableParameter
 import numpy as np
 
 
 class AdaptTimeStep(Operator):
     """
-    The adaptative Time Step is computed according to the following expression :
+    The adaptative Time Step is computed according
+    to the following expression :
     dt_adapt = min (dt_advection, dt_stretching, dt_cfl)
     """
 
     @debug
-    def __init__(self, velocity, vorticity, resolutions,
-                 dt_adapt=None,
-                 method=None,
-                 topo=None, ghosts=None, prefix='./dt.dat',
-                 task_id=None, comm=None, **other_config):
+    def __init__(self, velocity, vorticity, resolutions, dt_adapt,
+                 method=None, topo=None, ghosts=None, filename='./dt.dat',
+                 task_id=None, comm=None, time_range=None):
         """
         Create a timeStep-evaluation operator from given
         velocity and vorticity variables.
@@ -46,6 +47,11 @@ class AdaptTimeStep(Operator):
         @param topo : a predefined topology to discretize velocity/vorticity
         @param ghosts : number of ghosts points. Default depends on the method.
         Automatically computed if not set.
+        @param time_range : [start, end] use to define a 'window' in which
+        the current operator is applied. Outside start-end, this operator
+        has no effect. Start/end are iteration numbers.
+        Default = [2, endofsimu]
+
         """
         if method is None:
             method = {TimeIntegrator: RK3,
@@ -53,7 +59,6 @@ class AdaptTimeStep(Operator):
                       dtAdvecCrit: 'vort'}
         Operator.__init__(self, [velocity, vorticity], method, topo=topo,
                           ghosts=ghosts, task_id=task_id, comm=comm)
-        self.config = other_config
         ## velocity variable (vector)
         self.velocity = velocity
         ## vorticity variable (vector)
@@ -62,9 +67,12 @@ class AdaptTimeStep(Operator):
         self.resolutions = resolutions
         ## adaptative time step variable ("variable" object)
         self.dt_adapt = dt_adapt
+        assert isinstance(self.dt_adapt, VariableParameter)
+        # Check if 'dt' key is present in dt_adapt dict
+        assert 'dt' in self.dt_adapt.data
         ## Numerical methods for time and space discretization
         self.method = method
-        self.prefix = prefix
+        self.filename = filename
         assert SpaceDiscretisation in self.method.keys()
         assert TimeIntegrator in self.method.keys()
         if not dtAdvecCrit in self.method.keys():
@@ -72,6 +80,7 @@ class AdaptTimeStep(Operator):
 
         self.input = [self.velocity, self.vorticity]
         self.output = [self.vorticity]
+        self.time_range = time_range
 
     def discretize(self):
         if self.method[SpaceDiscretisation] is FD_C_4:
@@ -105,9 +114,8 @@ class AdaptTimeStep(Operator):
         self.discreteOperator =\
             AdaptTimeStep_D(self.discreteFields[self.velocity],
                             self.discreteFields[self.vorticity],
-                            self.dt_adapt,
-                            method=self.method, prefix=self.prefix,
-                            **self.config)
+                            self.dt_adapt, method=self.method,
+                            filename=self.filename, time_range=self.time_range)
 
         self.discreteOperator.setUp()
         self._isUpToDate = True
diff --git a/HySoP/hysop/operator/analytic.py b/HySoP/hysop/operator/analytic.py
index a71394ea924b92e70d5e6eb87abf07f6855dc502..78a176c42ea9eae4db6cfe8b2c958b1df0aaf8fb 100644
--- a/HySoP/hysop/operator/analytic.py
+++ b/HySoP/hysop/operator/analytic.py
@@ -77,13 +77,6 @@ class Analytic(Operator):
         for v in self.variables:
             v.initialize(simulation.time)
 
-    @debug
-    def finalize(self):
-        """
-        Memory cleaning.
-        """
-        pass
-
     def __str__(self):
         s = super(Analytic, self).__str__()
         if self.discreteOperator is None:
diff --git a/HySoP/hysop/operator/continuous.py b/HySoP/hysop/operator/continuous.py
index 641629c7f91cb6209b2cf73663df083204937c0d..7a8c0b5467c3196806704620259d0d0544d1e7f9 100644
--- a/HySoP/hysop/operator/continuous.py
+++ b/HySoP/hysop/operator/continuous.py
@@ -99,6 +99,8 @@ class Operator(object):
         self.timer = Timer(self)
         ## Redistribute operator list that we must wait for.
         self.requirements = []
+        ## time monitoring
+        self.time_info = None
 
     @staticmethod
     def getWorkLengths():
@@ -133,7 +135,7 @@ class Operator(object):
     @abstractmethod
     def setUp(self):
         """
-        Last step of initializaton. After this, the operator must be
+        Last step of initialization. After this, the operator must be
         ready for apply call.
 
         Main step : setup for discrete operators.
@@ -144,8 +146,9 @@ class Operator(object):
         """
         Memory cleaning.
         """
-        self.discreteOperator.finalize()
-        self.timer = self.timer + self.discreteOperator.timer
+        if self.discreteOperator is not None:
+            self.discreteOperator.finalize()
+            self.timer = self.timer + self.discreteOperator.timer
 
     @debug
     def apply(self, simulation=None):
@@ -169,6 +172,7 @@ class Operator(object):
             shortName = str(self.__class__).rpartition('.')[-1][0:-2]
             s = '[' + str(main_rank) + '] ' + shortName
             s += " : operator not discretized --> no computation, time = 0."
+            print s
 
     def isUp(self):
         """
diff --git a/HySoP/hysop/operator/discrete/adapt_timestep.py b/HySoP/hysop/operator/discrete/adapt_timestep.py
index e49dfe8355838653e9c81d05379d938ea340e874..c36d5d26606fd541ab36f1617b96adbd7bd66344 100755
--- a/HySoP/hysop/operator/discrete/adapt_timestep.py
+++ b/HySoP/hysop/operator/discrete/adapt_timestep.py
@@ -6,8 +6,9 @@ Evaluation of the adaptative time step according to the flow fields.
 """
 
 from parmepy.constants import debug
-from parmepy.methods_keys import TimeIntegrator, SpaceDiscretisation, dtAdvecCrit
-from parmepy.numerics.finite_differences import FD_C_4, FD_C_2
+from parmepy.methods_keys import TimeIntegrator, SpaceDiscretisation,\
+    dtAdvecCrit
+from parmepy.numerics.finite_differences import FD_C_4
 from parmepy.operator.discrete.discrete import DiscreteOperator
 from parmepy.numerics.integrators.euler import Euler
 from parmepy.numerics.integrators.runge_kutta2 import RK2
@@ -17,40 +18,48 @@ from parmepy.tools.timers import timed_function
 from parmepy.numerics.differential_operations import GradV
 import parmepy.tools.numpywrappers as npw
 from parmepy.numerics.updateGhosts import UpdateGhosts
-from parmepy.mpi import main_rank
 from parmepy.mpi import MPI
 from parmepy.constants import np, PARMES_MPI_REAL
+import scitools.filetable as ft
 import math
+import os
 ceil = math.ceil
 
 
 class AdaptTimeStep_D(DiscreteOperator):
     """
-    The adaptative Time Step is computed according to the following expression :
+    The adaptative Time Step is computed according
+    to the following expression :
     dt_adapt = min (dt_advection, dt_stretching, dt_cfl)
     """
 
     @debug
-    def __init__(self, velocity, vorticity,
-                 dt_adapt=None,
-                 method={TimeIntegrator: RK3, SpaceDiscretisation: FD_C_4,
-                 dtAdvecCrit: 'vort'},
-                 lcfl=0.125, cfl=0.5, prefix='./dt.dat'):
+    def __init__(self, velocity, vorticity, dt_adapt, method=None,
+                 lcfl=0.125, cfl=0.5, filename='./dt.dat', time_range=None):
         """
         @param velocity : discrete field
         @param vorticity : discrete field
-        @param dt_adapt : adaptative timestep variable
+        @param dt_adapt : adaptative timestep
+        (a parmepy.variable_parameter.VariableParameter)
         @param method : numerical method for space/time discretizations
-        @param lcfl : the lagrangian CFL coefficient used for advection stability
+        @param lcfl : the lagrangian CFL coefficient used
+        for advection stability
         @param cfl : the CFL coefficient.
+        @param filename : output file name
+        @param time_range : [start, end] use to define a 'window' in which
+        the current operator is applied. Outside start-end, this operator
+        has no effect. Start/end are iteration numbers.
+        Default = [2, endofsimu]
         """
         ## velocity discrete field
         self.velocity = velocity
         ## vorticity discrete field
         self.vorticity = vorticity
-        ## adaptative time step variable ("variable" object)
+        ## adaptative time step variable
         self.dt_adapt = dt_adapt
-
+        if method is None:
+            method = {TimeIntegrator: RK3, SpaceDiscretisation: FD_C_4,
+                      dtAdvecCrit: 'vort'}
         DiscreteOperator.__init__(self, [self.velocity, self.vorticity],
                                   method=method)
 
@@ -76,10 +85,17 @@ class AdaptTimeStep_D(DiscreteOperator):
 
         # Definition of criterion for dt_advec computation
         self.dtAdvecCrit = self.method[dtAdvecCrit]
-
-        self.prefix = prefix
-        if (main_rank == 0):
-            self.f = open(self.prefix, 'w')
+        ## Output file name
+        self.filename = filename
+        ## Time range
+        if time_range is None:
+            time_range = [2, np.infty]
+        self.time_range = time_range
+
+        # local buffer :
+        # [time, dt, d1, d2, d3, d4, d5]
+        # for d1...d5 see computation details in apply.
+        self.diagnostics = npw.zeros((7))
 
     def setUp(self):
 
@@ -87,26 +103,32 @@ class AdaptTimeStep_D(DiscreteOperator):
         self._synchronize = UpdateGhosts(self.velocity.topology,
                                          self.velocity.nbComponents)
 
+        if self.velocity.topology.rank == 0:
+            # Create output dir if required
+            d = os.path.dirname(self.filename)
+            if not os.path.exists(d):
+                os.makedirs(d)
+            self._file = open(self.filename, 'w')
         # gradU function
         self._function = GradV(self.velocity.topology,
                                method=self.method[SpaceDiscretisation])
         memshape = self.velocity.data[0].shape
         worklength = self.velocity.nbComponents ** 2
-        # gradU result array
-        self.grad = [npw.zeros(memshape)
-                     for i in xrange(worklength)]
+        # gradU result array.
+        self.grad = [npw.zeros(memshape) for i in xrange(worklength)]
 
         self._isUpToDate = True
 
     @timed_function
-    def apply(self, simulation):
+    def apply(self, simulation=None):
         if simulation is None:
             raise ValueError("Missing simulation value for computation.")
         # current time
         time = simulation.time
         iteration = simulation.currentIteration
-
-        if iteration >= 2:
+        Nmax = min(simulation.iterMax, self.time_range[1])
+        self.diagnostics[0] = time
+        if iteration >= self.time_range[0] and iteration <= Nmax:
             # Calling for requirements completion
             DiscreteOperator.apply(self, simulation)
 
@@ -114,25 +136,30 @@ class AdaptTimeStep_D(DiscreteOperator):
             self._synchronize(self.velocity.data)
             # gradU computation
             self.grad = self._function(self.velocity.data, self.grad)
-
-            diagnostics = npw.zeros((5))
+            self.diagnostics[2:] = 0.0
             nbComponents = self.velocity.nbComponents
             for direc in xrange(nbComponents):
-                # maxima of partial derivatives of velocity : needed for advection stability condition (1st option)
-                diagnostics[0] = max(diagnostics[0],
-                                    np.max(abs(self.grad[(nbComponents + 1) * direc])))
-
-                # maxima of partial derivatives of velocity: needed for stretching stability condition
-                diagnostics[1] = max(diagnostics[1],
-                                    np.max(sum([abs(self.grad[i])
-                                            for i in xrange(nbComponents * direc,
-                                                            nbComponents * (direc +1 ))])))
+                # maxima of partial derivatives of velocity :
+                # needed for advection stability condition (1st option)
+                tmp = np.max(abs(self.grad[(nbComponents + 1) * direc]))
+                self.diagnostics[2] = max(self.diagnostics[2], tmp)
+
+                # maxima of partial derivatives of velocity:
+                # needed for stretching stability condition
+                tmp = np.max(sum([abs(self.grad[i])
+                                  for i in xrange(nbComponents * direc,
+                                                  nbComponents * (direc + 1))
+                                  ]))
+                self.diagnostics[3] = max(self.diagnostics[3], tmp)
+
                 # maxima of velocity : needed for CFL based time step
-                diagnostics[2] = max(diagnostics[2],
-                                    np.max(abs(self.velocity.data[direc])))
-                # maxima of vorticity : needed for advection stability condition (2nd option)
-                diagnostics[3] = max(diagnostics[3],
-                                    np.max(abs(self.vorticity.data[direc])))
+                tmp = np.max(abs(self.velocity.data[direc]))
+                self.diagnostics[4] = max(self.diagnostics[4], tmp)
+
+                # maxima of vorticity :
+                # needed for advection stability condition (2nd option)
+                tmp = np.max(abs(self.vorticity.data[direc]))
+                self.diagnostics[5] = max(self.diagnostics[5], tmp)
 
             # 1/2(gradU + gradU^T) computation
             self.grad[1] += self.grad[3]
@@ -144,26 +171,28 @@ class AdaptTimeStep_D(DiscreteOperator):
             self.grad[3][...] = self.grad[1][...]
             self.grad[6][...] = self.grad[2][...]
             self.grad[7][...] = self.grad[5][...]
+            # maxima of deformation tensor:
+            # needed for advection stability condition (3rd option)
             for direc in xrange(nbComponents):
-                # maxima of deformation tensor: needed for advection stability condition (3rd option)
-                diagnostics[4] = max(diagnostics[4],
-                                    np.max(sum([abs(self.grad[i])
-                                            for i in xrange(nbComponents * direc,
-                                                            nbComponents * (direc +1 ))])))
+                tmp = np.max(sum([abs(self.grad[i])
+                                  for i in xrange(nbComponents * direc,
+                                                  nbComponents * (direc + 1))
+                                  ]))
+                self.diagnostics[6] = max(self.diagnostics[6], tmp)
 
             # definition of dt_advection
             if self.dtAdvecCrit == 'gradU':
             # => based on gradU
-                dt_advec = self.lcfl / diagnostics[0]
+                dt_advec = self.lcfl / self.diagnostics[2]
             elif self.dtAdvecCrit == 'deform':
             # => based on the deformations
-                dt_advec = self.lcfl / diagnostics[4]
+                dt_advec = self.lcfl / self.diagnostics[6]
             else:
             # => based on the vorticity
-                dt_advec = self.lcfl / diagnostics[3]
+                dt_advec = self.lcfl / self.diagnostics[5]
 
             # definition of dt_stretching
-            dt_stretch = self.coef_stretch / diagnostics[1]
+            dt_stretch = self.coef_stretch / self.diagnostics[3]
 
             # round dt_advec
 #            pow_adv = 0
@@ -183,24 +212,24 @@ class AdaptTimeStep_D(DiscreteOperator):
 
             # redefine timestep
             if self.cfl is None:
-                self.dt_adapt.data[0] = min(dt_advec, dt_stretch)
-            else :
+                self.dt_adapt['dt'] = min(dt_advec, dt_stretch)
+            else:
                 # definition of dt_cfl
-                dt_cfl = (self.cfl * self.velocity.topology.mesh.space_step[0]) / (diagnostics[2])
-                self.dt_adapt.data[0] = min(dt_advec, dt_stretch, dt_cfl)
+                h = self.velocity.topology.mesh.space_step[0]
+                dt_cfl = (self.cfl * h) / (self.diagnostics[4])
+                self.dt_adapt['dt'] = min(dt_advec, dt_stretch, dt_cfl)
 
-            self.dt_adapt.data[0] = \
+            self.dt_adapt['dt'] = \
                 self.velocity.topology.comm.allreduce(self.dt_adapt.data[0],
-                                                    PARMES_MPI_REAL, op=MPI.MIN)
-
-
-            if ((main_rank == 0)):
-                self.f = open(self.prefix, 'a')
-                self.f.write("%s   %s   %s   %s   %s   %s   %s\n" % (time,
-                                                                    self.dt_adapt.data[0],
-                                                                    diagnostics[0],
-                                                                    diagnostics[1],
-                                                                    diagnostics[2],
-                                                                    diagnostics[3],
-                                                                    diagnostics[4]))
-                self.f.close()
+                                                      PARMES_MPI_REAL,
+                                                      op=MPI.MIN)
+            self.diagnostics[1] = self.dt_adapt['dt']
+            if self.velocity.topology.rank == 0:
+                self.writeToFile()
+            # Update simulation time step with the new dt
+            simulation.updateTimeStep(self.dt_adapt['dt'])
+
+    def writeToFile(self):
+        self._file = open(self.filename, 'a')
+        ft.write(self._file, self.diagnostics)
+        self._file.close()
diff --git a/HySoP/hysop/operator/discrete/discrete.py b/HySoP/hysop/operator/discrete/discrete.py
index 02d54ba6f81f7f6098385ce2e374c150110707b2..a752db902e728422419f6ccb33f1cb1fe4b6e96b 100644
--- a/HySoP/hysop/operator/discrete/discrete.py
+++ b/HySoP/hysop/operator/discrete/discrete.py
@@ -101,6 +101,7 @@ class DiscreteOperator(object):
         return self._isUpToDate
 
     @debug
+    @abstractmethod
     def apply(self, simulation=None):
         """
         Apply this operator to its variables.
diff --git a/HySoP/hysop/operator/discrete/poisson_fft.py b/HySoP/hysop/operator/discrete/poisson_fft.py
index ab2df6eebf2efc6bdaa004da09cd512e10de0f7c..9e24ff4f38e846060aa2f2ad2fe38388e50b26c8 100644
--- a/HySoP/hysop/operator/discrete/poisson_fft.py
+++ b/HySoP/hysop/operator/discrete/poisson_fft.py
@@ -5,10 +5,8 @@ Discrete operator for Poisson problem (fftw based)
 """
 import parmepy.tools.numpywrappers as npw
 from parmepy.f2py import fftw2py
-from discrete import DiscreteOperator
+from parmepy.operator.discrete.discrete import DiscreteOperator
 from parmepy.constants import debug, prof
-from parmepy.tools.timers import timed_function
-from parmepy.variables.variables import Variables
 from parmepy.mpi import MPI
 
 
@@ -19,111 +17,157 @@ class PoissonFFT(DiscreteOperator):
     """
 
     @debug
-    def __init__(self, velocity, vorticity, method=None, projection=None,
-                 multires=False, filterSize=None):
+    def __init__(self, velocity, vorticity, projection=None,
+                 multires=False, filterSize=None, correction=None):
         """
         Constructor.
         @param[out] velocity : discretisation of the solution field
         @param[in] vorticity : discretisation of the RHS (mind the minus rhs!)
+        @param projection :
+        @param[in] multires : true if velo/vorticity do not have the same
+        resolution
+        @param filterSize :
+        @param correction : operator used to shift velocity according
+        to a given input (fixed) flowrate.
+        See parmepy.operator.velocity_correction.
+        Default = None.
         """
         ## Solution field
         self.velocity = velocity
         ## RHS field
         self.vorticity = vorticity
         ## Solenoidal projection of vorticity ?
-        if (isinstance(projection, Variables)):
-            self.projection = projection.data
-        else:
-            self.projection = projection
-        ## Multiresolution ?
-        self.multires = multires
+        self.projection = projection
         ## Filter size array = domainLength/(CoarseRes-1)
         self.filterSize = filterSize
         # Base class initialisation
-        DiscreteOperator.__init__(self, [velocity, vorticity], method)
+        DiscreteOperator.__init__(self, [velocity, vorticity])
 
         # If 2D problem, vorticity must be a scalar
-        if self.velocity.dimension == 2:
+        self.dim = self.velocity.domain.dimension
+        if self.dim == 2:
             assert self.vorticity.nbComponents == 1
-            ## fftw solver case (2 or 3D)
-            self.case = '2D'
-        elif self.velocity.dimension == 3:
-            self.case = '3D'
-        else:
+
+        if self.dim != 2 and self.dim != 3:
             raise AttributeError("Wrong problem dimension: only 2D \
                                         and 3D cases are implemented.")
 
         self.input = [self.vorticity]
         self.output = [self.velocity]
-        # If there is a projection, vorticity is also an output
-        if self.projection is not None and self.projection[0]:
-            self.output.append(self.vorticity)
+        ## Multiresolution ?
+        self.multires = multires
 
-    @debug
-    @prof
-    def apply(self, simulation):
-        # Calling for requirements completion
-        DiscreteOperator.apply(self, simulation)
-        ctime = MPI.Wtime()
+        # connexion to the required apply function
+        # (to avoid 'if' calls during apply)
+        if self.dim == 2:
+            self._solve = self._solve2D
+        elif self.dim == 3:
+            # If there is a projection, vorticity is also an output
+            if self.projection is not None:
+                self.output.append(self.vorticity)
+                if self.multires:
+                    self._solve = self._solve3D_proj_multires
+                else:
+                    self._solve = self._solve3D_proj
+            else:
+                if self.multires:
+                    self._solve = self._solve3D_multires
+                else:
+                    self._solve = self._solve3D
+
+        # Operator to shift velocity according to an input required flowrate
+        if correction is not None:
+            self.correctionOp = correction
+            self.solve = self._solve_and_correct
+        else:
+            self.solve = self._solve
+
+    def _solve2D(self, simu=None):
+        """
+        Solve 2D poisson problem
+        """
+        self.velocity.data[0], self.velocity.data[1] =\
+            fftw2py.solve_poisson_2d(self.vorticity.data,
+                                     self.velocity.data[0],
+                                     self.velocity.data[1])
+
+    def _project(self):
+        """
+        apply projection onto vorticity
+        """
+        ghosts_w = self.vorticity.topology.ghosts
+        self.vorticity.data[0], self.vorticity.data[1], \
+            self.vorticity.data[2] = \
+               fftw2py.projection_om_3d(self.vorticity.data[0],
+                                        self.vorticity.data[1],
+                                        self.vorticity.data[2], ghosts_w)
 
-        ite = simulation.currentIteration
+    def _solve3D_multires(self, simu=None):
+        """
+        3D, multiresolution
+        """
+        # Projects vorticity values from fine to coarse grid
+        # in frequencies space by nullifying the smallest modes
+        vortFilter = npw.copy(self.vorticity.data)
+        vortFilter[0], vortFilter[1], vortFilter[2] = \
+           fftw2py.multires_om_3d(self.filterSize[0], self.filterSize[1],
+                                  self.filterSize[2], self.vorticity.data[0],
+                                  self.vorticity.data[1],
+                                  self.vorticity.data[2])
+
+        # Solves Poisson equation using filter vorticity
         ghosts_v = self.velocity.topology.ghosts
         ghosts_w = self.vorticity.topology.ghosts
-        if self.case is '2D':
-            self.velocity.data[0], self.velocity.data[1] =\
-                fftw2py.solve_poisson_2d(self.vorticity.data,
-                                         self.velocity.data[0],
-                                         self.velocity.data[1])
-
-        elif self.case is '3D':
-            #=== SOLENOIDAL PROJECTION OF VORTICITY FIELD ===
-            if (self.projection is not None and self.projection[0] \
-                and ite % self.projection[1] == 0):
-                self.vorticity.data[0], self.vorticity.data[1], \
-                    self.vorticity.data[2] = \
-                    fftw2py.projection_om_3d(self.vorticity.data[0],
-                                             self.vorticity.data[1],
-                                             self.vorticity.data[2],
-                                             ghosts_w)
-
-            if (self.multires):
-                # Projects vorticity values from fine to coarse grid
-                # in frequencies space by nullifying the smallest modes
-                vortFilter = npw.copy(self.vorticity.data)
-                vortFilter[0], vortFilter[1], \
-                    vortFilter[2] = \
-                    fftw2py.multires_om_3d(self.filterSize[0],
-                                           self.filterSize[1],
-                                           self.filterSize[2],
-                                           self.vorticity.data[0],
-                                           self.vorticity.data[1],
-                                           self.vorticity.data[2])
-
-                # Solves Poisson equation using filter vorticity
-                self.velocity.data[0], self.velocity.data[1], \
-                    self.velocity.data[2] = \
-                    fftw2py.solve_poisson_3d(vortFilter[0],
-                                             vortFilter[1],
-                                             vortFilter[2],
-                                             self.velocity.data[0],
-                                             self.velocity.data[1],
-                                             self.velocity.data[2],
-                                             ghosts_w, ghosts_v)
+        self.velocity.data[0], self.velocity.data[1], self.velocity.data[2] = \
+            fftw2py.solve_poisson_3d(vortFilter[0], vortFilter[1],
+                                     vortFilter[2], self.velocity.data[0],
+                                     self.velocity.data[1],
+                                     self.velocity.data[2], ghosts_w, ghosts_v)
 
-            else:
-                # Solves Poisson equation using usual vorticity
-                self.velocity.data[0], self.velocity.data[1], \
-                    self.velocity.data[2] = \
-                    fftw2py.solve_poisson_3d(self.vorticity.data[0],
-                                             self.vorticity.data[1],
-                                             self.vorticity.data[2],
-                                             self.velocity.data[0],
-                                             self.velocity.data[1],
-                                             self.velocity.data[2],
-                                             ghosts_w, ghosts_v)
+    def _solve3D_proj_multires(self, simu):
+        """
+        3D, multiresolution, with projection
+        """
+        ite = simu.currentIteration
+        if self.projection.doProjection(ite):
+            self._project()
+        self._solve3D_multires()
 
-        else:
-            raise ValueError("invalid problem dimension")
+    def _solve3D_proj(self, simu):
+        """
+        3D, with projection
+        """
+        ite = simu.currentIteration
+        if self.projection.doProjection(ite):
+            self._project()
+        self._solve3D()
+
+    def _solve3D(self,simu=None):
+        """
+        Basic solve
+        """
+        # Solves Poisson equation using usual vorticity
+        ghosts_v = self.velocity.topology.ghosts
+        ghosts_w = self.vorticity.topology.ghosts
+        self.velocity.data[0], self.velocity.data[1], self.velocity.data[2] =\
+            fftw2py.solve_poisson_3d(self.vorticity.data[0],
+                                     self.vorticity.data[1],
+                                     self.vorticity.data[2],
+                                     self.velocity.data[0],
+                                     self.velocity.data[1],
+                                     self.velocity.data[2], ghosts_w, ghosts_v)
+
+    def _solve_and_correct(self, simu):
+        self._solve(simu.currentIteration)
+        self.correctionOp.apply(simu)
+
+    @debug
+    @prof
+    def apply(self, simulation=None):
+        # Calling for requirements completion
+        DiscreteOperator.apply(self, simulation)
+        ctime = MPI.Wtime()
+        self.solve(simulation)
         self._apply_timer.append_time(MPI.Wtime() - ctime)
 
     def finalize(self):
diff --git a/HySoP/hysop/operator/discrete/velocity_correction.py b/HySoP/hysop/operator/discrete/velocity_correction.py
index f36f88ad470c7eb2afa5449169c1fd95aabba301..e574cf49dfa514389511d628d9b380db5b728cd5 100755
--- a/HySoP/hysop/operator/discrete/velocity_correction.py
+++ b/HySoP/hysop/operator/discrete/velocity_correction.py
@@ -15,116 +15,128 @@ from parmepy.mpi import MPI
 
 class VelocityCorrection_D(DiscreteOperator):
     """
-    The velocity field is corrected after solving the 
-    Poisson equation. For more details about calculations, 
-    see the "velocity_correction.pdf" explanations document 
+    The velocity field is corrected after solving the
+    Poisson equation. For more details about calculations,
+    see the "velocity_correction.pdf" explanations document
     in ParmeDoc directory.
     """
 
     @debug
-    def __init__(self, velocity, vorticity, uinf):
+    def __init__(self, velocity, vorticity, req_flowrate, cb=None):
         """
-        @param velocity : discrete field
+        @param[in, out] velocity field to be corrected
+        @param[in] vorticity field used to compute correction
+        @param[in] req_flowrate : required value for the flowrate
+        @param[in] surf : surface (parmepy.domain.obstacle.planes.SubPlane)
+        used to compute reference flow rates. Default = surface at x_origin,
+        normal to x-dir.
         """
         ## velocity discrete field
         self.velocity = velocity
         ## vorticity discrete field
         self.vorticity = vorticity
-        ## free stream velocity
-        self.uinf = uinf
-
+        ## domain dimension
+        self.dim = self.velocity.domain.dimension
         # If 2D problem, vorticity must be a scalar
-        if self.velocity.dimension == 2:
+        if self.dim == 2:
             assert self.vorticity.nbComponents == 1
-            self.case = '2D'
-        elif self.velocity.dimension == 3:
-            self.case = '3D'
-        else:
-            raise AttributeError("Wrong problem dimension: only 2D \
-                                        and 3D cases are implemented.")
+        assert (self.dim == 2 or self.dim == 3),\
+            "Wrong problem dimension: only 2D and 3D cases are implemented."
 
         DiscreteOperator.__init__(self, [self.velocity, self.vorticity])
 
         self.input = [self.velocity, self.vorticity]
         self.output = [self.velocity]
+        ## Velocity from topology will be used as reference
+        self.topo = self.velocity.topology
+        hh = self.topo.mesh.space_step
+        self.cb = cb
+        self.cb.discretize(self.topo)
+        self.surfRef = cb.lowerS[XDIR]
+        normal = self.surfRef.normal
+        dirs = np.where(normal == 0)[0]
+        self.ds = np.prod(self.surfRef.lengths[dirs] + hh[dirs])
+        ## Expected value for the flow rate through self.surfRef
+        ## warning : divided with area of input surf.
+        self.req_flowrate = req_flowrate / self.ds
+        ## The correction that must be applied on each
+        ## component of the velocity.
+        self.velocity_shift = npw.zeros(self.dim)
+        nbf = self.velocity.nbComponents + self.vorticity.nbComponents
+        # temp buffer, used to save flow rates and mean
+        # values of vorticity
+        self.rates = npw.zeros(nbf)
 
     def setUp(self):
-        spaceStep = self.velocity.topology.mesh.space_step
-        lengths = self.velocity.topology.domain.length
-        self.coeff_mean = np.prod(spaceStep) / np.prod(lengths)
-        self.x0_coord = self.velocity.topology.domain.origin[XDIR]
-        self.x_coord = self.velocity.topology.mesh.coords[XDIR]
-        if self.case is '2D':
-            self.surf = lengths[YDIR]
-            self.dvol = spaceStep[YDIR]
-        elif self.case is '3D':
-            self.surf = lengths[YDIR] * lengths[ZDIR]
-            self.dvol = spaceStep[YDIR] * spaceStep[ZDIR]
-        else:
-            raise ValueError("invalid problem dimension")
-        self.comput_flowrates = npw.zeros((3))
-
+        spaceStep = self.topo.mesh.space_step
+        lengths = self.topo.domain.length
+        self.coeff_mean = npw.prod(spaceStep) / npw.prod(lengths)
+        x0 = self.topo.domain.origin[XDIR]
+        self.x_coord = self.topo.mesh.coords[XDIR] - x0
         self._isUpToDate = True
 
-    @timed_function
-    def apply(self, simulation):
-        ## Calling for requirements completion
-        DiscreteOperator.apply(self, simulation)
-        ctime = MPI.Wtime()
-
-        ## Computation of the flowrates evaluated from 
+    def computeCorrection(self):
+        """
+        Compute the required correction for the current state
+        but do not apply it onto velocity.
+        """
+        ## Computation of the flowrates evaluated from
         ## current (ie non corrected) velocity
-        local_comput_flowrates = npw.zeros((3))
+        ## local flow reduced only on proc 0
+        nbf = self.velocity.nbComponents + self.vorticity.nbComponents
+        localrates = npw.zeros((nbf))
         for i in xrange(self.velocity.nbComponents):
-            local_comput_flowrates[i] = np.sum(self.velocity[i][...])
-
-        recvbuff = npw.zeros((3))
-        self.velocity.topology.topo.Allreduce(local_comput_flowrates, 
-                                              recvbuff)
+            localrates[i] = self.velocity.integrateOnSurf_proc(self.surfRef,
+                                                               component=i)
+        start = self.velocity.nbComponents
+        ## Integrate vorticity over the whole domain
+        for i in xrange(self.vorticity.nbComponents):
+            localrates[start + i] = \
+                self.vorticity.integrate_on_proc(self.cb, component=i)
+
+        # MPI reduction for rates
+        # rates = [flowrate[X], flowrate[Y], flowrate[Z],
+        #          vort_mean[X], ..., vort_mean[Z]]
+        # or (in 2D) = [flowrate[X], flowrate[Y], vort_mean]
+        self.velocity.topology.comm.Allreduce(localrates, self.rates)
+
+        # Set velocity_shift == [Vx_shift, vort_mean[Y], vort_mean[Z]]
+        # or (in 2D) velocity_shift == [Vx_shift, vort_mean]
+        # Velocity shift for main dir component
+        self.velocity_shift[XDIR] = self.req_flowrate\
+            - self.rates[XDIR] / self.ds
+        # Shifts in other directions depend on x coord
+        # and will be computed during apply.
 
-        for i in xrange(self.velocity.nbComponents):
-            self.comput_flowrates[i] = recvbuff[i] * self.dvol
-
-        ## Correction of the X-velocity component
-        self.velocity[XDIR][...] += self.uinf - \
-                                    self.comput_flowrates[XDIR] / self.surf
-
-        ## Correction of the other velocity components
-        if self.case is '2D':
-            # Computation of vorticity mean (in space)
-            local_vort_mean = np.sum(self.vorticity[0][...])
-            recvbuff = 0.0
-            self.velocity.topology.topo.Allreduce(local_vort_mean,
-                                                  recvbuff)
-            vort_mean = recvbuff * self.coeff_mean
+    @timed_function
+    def apply(self, simulation=None):
+        # Calling for requirements completion
+        DiscreteOperator.apply(self, simulation)
+        ctime = MPI.Wtime()
 
+        # Computation of the required velocity shift
+        # for the current state
+        self.computeCorrection()
+        iCompute = self.topo.mesh.iCompute
+
+        # Apply shift to velocity
+        self.velocity[XDIR][iCompute] += self.velocity_shift[XDIR]
+        start = self.velocity.nbComponents
+        # reminder : self.rates =[vx_shift, flowrates[Y], flowrate[Z],
+        #                         vort_mean[X], vort_mean[Y], vort_mean[Z]]
+        # or (in 2D) [vx_shift, flowrates[Y], vort_mean]
+        vort_mean = self.rates[start:]
+        if self.dim == 2:
             # Correction of the Y-velocity component
-            self.velocity[YDIR][...] += vort_mean * \
-                                        (self.x_coord - self.x0_coord) - \
-                                        self.comput_flowrates[YDIR] \
-                                        / self.surf
-
-        elif self.case is '3D':
-            # Computation of Y and Z-vorticity means (in space)
-            local_vort_Y_mean = np.sum(self.vorticity[YDIR][...])
-            local_vort_Z_mean = np.sum(self.vorticity[ZDIR][...])
-
-            sendbuff = npw.zeros((2))
-            recvbuff = npw.zeros((2))
-            sendbuff[:] = [local_vort_Y_mean, local_vort_Z_mean]
-            self.velocity.topology.topo.Allreduce(sendbuff, recvbuff)
-            vort_mean = recvbuff * self.coeff_mean
+            self.velocity[YDIR][...] += vort_mean[XDIR] * self.x_coord \
+                - self.rates[YDIR] / self.ds
 
+        elif self.dim == 3:
             # Correction of the Y and Z-velocity components
-            self.velocity[YDIR][...] += vort_mean[1] * \
-                                        (self.x_coord - self.x0_coord) - \
-                                        self.comput_flowrates[YDIR] \
-                                        / self.surf
-            self.velocity[ZDIR][...] += vort_mean[0] * \
-                                        (self.x_coord - self.x0_coord) - \
-                                        self.comput_flowrates[ZDIR] \
-                                        / self.surf
-
-        else:
-            raise ValueError("invalid problem dimension")
+            self.velocity[YDIR][...] += vort_mean[ZDIR] * self.x_coord - \
+                self.rates[YDIR] / self.ds
+            self.velocity[ZDIR][...] += -vort_mean[YDIR] * self.x_coord - \
+                self.rates[ZDIR] / self.ds
+
         self._apply_timer.append_time(MPI.Wtime() - ctime)
+
diff --git a/HySoP/hysop/operator/energy_enstrophy.py b/HySoP/hysop/operator/energy_enstrophy.py
index cb68191782c23e9402079176812c2e7d4e4018b1..33644d0df331de7af3a880e5cb8aef46480d891b 100644
--- a/HySoP/hysop/operator/energy_enstrophy.py
+++ b/HySoP/hysop/operator/energy_enstrophy.py
@@ -8,8 +8,6 @@ from parmepy.constants import debug, XDIR
 from parmepy.operator.monitors.monitoring import Monitoring
 from parmepy.tools.timers import timed_function
 import parmepy.tools.numpywrappers as npw
-import scitools.filetable as ft
-import os
 
 
 class Energy_enstrophy(Monitoring):
@@ -25,8 +23,8 @@ class Energy_enstrophy(Monitoring):
     """
 
     def __init__(self, velocity, vorticity,
-                 viscosity, isNormalized, topo, frequency, prefix=None,
-                 filename=None, safeOutput=True, task_id=None):
+                 viscosity, isNormalized, topo,
+                 io_params=None, task_id=None):
         """
         Constructor.
         @param velocity field
@@ -35,16 +33,20 @@ class Energy_enstrophy(Monitoring):
         @param isNormalized : boolean indicating whether the enstrophy
         and energy values have to be normalized by the domain lengths.
         @param topo : the topology on which we want to monitor the fields
-        @param frequency : output file producing frequency.
-        @param filename : output file name. Default is None ==> no output.
-        Full or relative path.
-        @param safeOutput : boolean defining how often output file is written:
-        True --> open/close file everytime data are written
-        False --> open at init and close during finalize (cost less but if simu
-        crashes, data are lost.)
+        @param io_params : parameters (dict) to set file output.
+        If  None, no output. Set io_params = {} if you want output,
+        with default parameters values. Default file name = 'energy_enstrophy'
+        See parmepy.tools.io_utils.Writer for details
         """
-        Monitoring.__init__(self, [velocity, vorticity], topo, frequency,
-                            task_id=task_id)
+        if io_params is not None:
+            if not "filename" in io_params:
+                io_params["filename"] = "energy_enstrophy"
+            # Set output buffer shape
+            io_params["writebuffshape"] = (1, 3)
+
+            io_params["writebuffshape"] = (1, 3)
+        Monitoring.__init__(self, [velocity, vorticity], topo,
+                            io_params, task_id=task_id)
         ## velocity field
         self.velocity = velocity
         ## vorticity field
@@ -63,70 +65,28 @@ class Energy_enstrophy(Monitoring):
         # Note FP : for multiresolution case, it would probably be
         # better to use two different operators for energy and enstrophy.
 
-        # Output file
-        if filename is None:
-            self._writeOuput = False
-            self.filename = None
-        else:
-            self._writeOuput = True
-            self.filename = filename
-            if (self._topo.rank == 0):
-                # Create output dir if required
-                d = os.path.dirname(self.filename)
-                if not os.path.exists(d):
-                    os.makedirs(d)
-            self.safeOutput = safeOutput
-            if self.safeOutput:
-                self._writeFile = self._fullwrite
-            else:
-                self._writeFile = self._partialwrite
-
-            self._file = open(self.filename, 'w')
-
-    def _fullwrite(self, data):
-        self._file = open(self.filename, 'a')
-        self._file.write("%s      %s      %s \n" % (data[0, 0],
-                                                    data[0, 1],
-                                                    data[0, 2]))
-        self._file.close()
-
-    def _partialwrite(self, data):
-#        ft.write(self._file, data)
-        self._file.write("%s      %s      %s \n" % (data[0, 0],
-                                                    data[0, 1],
-                                                    data[0, 2]))
-
     def setUp(self):
-        Monitoring.setUp(self)
-        # Get discrete fields for velocity and vorticity.
-        # Note FP : two options to get the discrete fields:
-        # - 'field.discretization(topo)' that just try
-        # to get the discrete field and return an error
-        # if it does not exist.
-        # - 'field.discretizet(topo) try to get the discrete field and create
-        # a new discretization if it does not exist.
-        # Current choice : no creation.
-        self.discreteFields[self.velocity] = \
-            self.velocity.discretization(self._topo)
-        self.discreteFields[self.vorticity] =\
-            self.vorticity.discretization(self._topo)
-
-        self._isUpToDate = True
-
-        spaceStep = self._topo.mesh.space_step
-        length = self._topo.domain.length
-        if self.isNormalized :
-            self.coeffEnstrophy = (np.prod(spaceStep) /
-                                   np.prod(length))
-        else:
-            self.coeffEnstrophy = np.prod(spaceStep)
-        self.coeffEnergy = 0.5 * self.coeffEnstrophy
+        if not self._isUpToDate:
+            self.discreteFields[self.velocity] = \
+                self.velocity.discretization(self._topo)
+            self.discreteFields[self.vorticity] =\
+                self.vorticity.discretization(self._topo)
+
+            spaceStep = self._topo.mesh.space_step
+            length = self._topo.domain.length
+            if self.isNormalized:
+                self.coeffEnstrophy = (np.prod(spaceStep) /
+                                       np.prod(length))
+            else:
+                self.coeffEnstrophy = np.prod(spaceStep)
+            self.coeffEnergy = 0.5 * self.coeffEnstrophy
 
-        # A work vector for local computations
-        # Warning : we assume one topo for all variables
-        self.ind = self._topo.mesh.iCompute
-        shape = self.discreteFields[self.velocity].data[0][self.ind].shape
-        self._work = npw.zeros(shape)
+            # A work vector for local computations
+            # Warning : we assume one topo for all variables
+            self.ind = self._topo.mesh.iCompute
+            shape = self.discreteFields[self.velocity].data[0][self.ind].shape
+            self._work = npw.zeros(shape)
+            self._isUpToDate = True
 
     @debug
     @timed_function
@@ -139,8 +99,6 @@ class Energy_enstrophy(Monitoring):
             raise ValueError("Missing simulation value for computation.")
 
         #time = MPI.Wtime()
-        t = simulation.time
-        ite = simulation.currentIteration
 
         # --- Kinetic energy computation ---
         vd = self.discreteFields[self.velocity]
@@ -167,6 +125,12 @@ class Energy_enstrophy(Monitoring):
         recvbuff = npw.zeros((2))
         sendbuff[:] = [local_energy, local_enstrophy]
         self._topo.comm.Allreduce(sendbuff, recvbuff)
+        # the other way :
+        #energy = self._topovel.topo.allreduce(local_energy, PARMES_MPI_REAL,
+        #                                     op=MPI.SUM)
+        #enstrophy = self._topovel.topo.allreduce(local_enstrophy,
+        #                                        PARMES_MPI_REAL,
+        #                                        op=MPI.SUM)
 
         # Update global values
         energy = recvbuff[0] * self.coeffEnergy
@@ -179,14 +143,9 @@ class Energy_enstrophy(Monitoring):
         ## self._buffer_1 = energy
 
         # Print results, if required
-        if self._writeOuput and self._topo.rank == 0 \
-            and (ite % self.freq) == 0:
-            dataout = npw.zeros((1, 3))
-            dataout[0, 0] = simulation.time
-            dataout[0, 1] = energy
-            dataout[0, 2] = enstrophy
-            self._writeFile(dataout)
-
-    def finalize(self):
-        if not self.safeOutput:
-            self._file.close()
+        ite = simulation.currentIteration
+        if self._writer is not None and self._writer.doWrite(ite):
+            self._writer.buffer[0, 0] = simulation.time
+            self._writer.buffer[0, 1] = energy
+            self._writer.buffer[0, 2] = enstrophy
+            self._writer.write()
diff --git a/HySoP/hysop/operator/monitors/__init__.py b/HySoP/hysop/operator/monitors/__init__.py
index 905c2429f51593c82146ad38a9e3824e9c53003a..5728a8fe9c9feff86bc390bdcd5eac0b1daacb57 100644
--- a/HySoP/hysop/operator/monitors/__init__.py
+++ b/HySoP/hysop/operator/monitors/__init__.py
@@ -1,3 +1,19 @@
 ## @package parmepy.operator.monitors
 # Parmes tools for data and fields monitoring.
 #
+# import and alias so that monitors are
+# available with
+# from parmepy.operators.monitors import Printer, ...
+import printer
+Printer = printer.Printer
+import compute_forces
+DragAndLift = compute_forces.DragAndLift
+import reprojection_criterion
+Reprojection_criterion = reprojection_criterion.Reprojection_criterion
+import energy_enstrophy as energy_enstrophy
+Energy_enstrophy = energy_enstrophy.Energy_enstrophy
+
+# Set list for 'import *'
+__all__ = ['DragAndLift', 'Energy_enstrophy',
+           'Reprojection_criterion', 'Printer']
+
diff --git a/HySoP/hysop/operator/monitors/compute_forces.py b/HySoP/hysop/operator/monitors/compute_forces.py
index 038600f8c245b0b7222bc9145be824f3b8549b2e..00b0c59f3a25d26b8d3d50c593c24c1fe7940cab 100644
--- a/HySoP/hysop/operator/monitors/compute_forces.py
+++ b/HySoP/hysop/operator/monitors/compute_forces.py
@@ -3,18 +3,12 @@
 @file compute_forces.py
 Compute forces
 """
-from parmepy.constants import debug, np, ORDER, \
-    PARMES_INTEGER, PI, XDIR, YDIR, ZDIR, PARMES_MPI_REAL
+from parmepy.constants import np, XDIR, YDIR, ZDIR
 from parmepy.numerics.updateGhosts import UpdateGhosts
-from parmepy.numerics.differential_operations import Laplacian,\
-    DivStressTensor3D
+from parmepy.numerics.differential_operations import Laplacian
 from parmepy.numerics.finite_differences import FD_C_2
 from parmepy.operator.monitors.monitoring import Monitoring
-from parmepy.mpi import MPI
-from parmepy.tools.timers import timed_function
 import parmepy.tools.numpywrappers as npw
-import scitools.filetable as ft
-import os
 
 
 class DragAndLift(Monitoring):
@@ -25,8 +19,8 @@ class DragAndLift(Monitoring):
     Integral inside the obstacle is not taken into account.
     """
     def __init__(self, velocity, vorticity, nu, coefForce, topo,
-                 volumeOfControl, obstacles=None, frequency=1,
-                 filename=None, safeOutput=True, task_id=None):
+                 volumeOfControl, obstacles=None, io_params=None,
+                 task_id=None):
         """
         @param velocity field
         @param vorticity field
@@ -36,12 +30,19 @@ class DragAndLift(Monitoring):
         (parmepy.domain.obstacle.controlBox.ControlBox object)
         @param obstacles a list of parmepy.domain.obstacles inside
         the box
-        @param frequency : output rate
-        @param filename output file name. Default is None ==> no output.
-        Full or relative path.
+        @param io_params : parameters (dict) to set file output.
+        If  None, no output. Set io_params = {} if you want output,
+        with default parameters values. Default file name = 'drag_and_lift'
+        See parmepy.tools.io_utils.Writer for details
         """
-        Monitoring.__init__(self, [velocity, vorticity], topo, frequency,
-                            task_id=task_id)
+        if io_params is not None:
+            if not "filename" in io_params:
+                io_params["filename"] = "drag_and_lift"
+            # Set output buffer shape
+            io_params["writebuffshape"] = (1, 4)
+
+        Monitoring.__init__(self, [velocity, vorticity], topo,
+                            io_params, task_id=task_id)
         self.velocity = velocity
         self.vorticity = vorticity
         self._voc = volumeOfControl
@@ -85,40 +86,6 @@ class DragAndLift(Monitoring):
         # Normalizing coefficient for forces
         # (based on the physics of the flow)
         self.coefForce = coefForce
-        # Output file
-        if filename is None:
-            self._writeOuput = False
-            self.filename = None
-        else:
-            self._writeOuput = True
-            self.filename = filename
-            if (self.topo.rank == 0):
-                # Create output dir if required
-                d = os.path.dirname(self.filename)
-                if not os.path.exists(d):
-                    os.makedirs(d)
-            ## Defines how often
-            ## output file is written :
-            ## True --> open/close file everytime
-            ## data are written.
-            ## False --> open at init and close
-            ## during finalize. Cost less but if simu
-            ## crashes, data are lost.
-            self.safeOutput = safeOutput
-            if self.safeOutput:
-                self._writeFile = self._fullwrite
-            else:
-                self._writeFile = self._partialwrite
-
-            self._file = open(self.filename, 'w')
-
-    def _fullwrite(self, data):
-        self._file = open(self.filename, 'a')
-        ft.write(self._file, data)
-        self._file.close()
-
-    def _partialwrite(self, data):
-        ft.write(self._file, data)
 
     def _mpi_allsum(self):
         """
@@ -135,22 +102,24 @@ class DragAndLift(Monitoring):
         """
         self.force = self.topo.comm.reduce(self.force, root=root)
 
-    def discretize(self):
+    def setUp(self):
         """
         """
-        for v in self.variables:
-            # the discrete fields
-            self.discreteFields[v] = v.discretize(self.topo)
-        self.vd = self.discreteFields[self.velocity]
-        self.wd = self.discreteFields[self.vorticity]
-        self._voc.discretize(self.topo)
-        for obs in self.obstacles:
-            obs.discretize(self.topo)
-        # prepare ghost points synchro for velocity and vorticity used
-        # in fd schemes
-        self._synchronize = UpdateGhosts(self.topo,
-                                         self.vd.nbComponents
-                                         + self.wd.nbComponents)
+        if not self._isUpToDate:
+            for v in self.variables:
+                # the discrete fields
+                self.discreteFields[v] = v.discretize(self.topo)
+            self.vd = self.discreteFields[self.velocity]
+            self.wd = self.discreteFields[self.vorticity]
+            self._voc.discretize(self.topo)
+            for obs in self.obstacles:
+                obs.discretize(self.topo)
+            # prepare ghost points synchro for velocity and vorticity used
+            # in fd schemes
+            self._synchronize = UpdateGhosts(self.topo,
+                                             self.vd.nbComponents
+                                             + self.wd.nbComponents)
+            self._isUpToDate = True
 
     def apply(self, simulation=None):
         """
@@ -190,11 +159,10 @@ class DragAndLift(Monitoring):
         self.force *= self.coefForce
 
         # Print results, if required
-        if self._writeOuput and self.topo.rank == 0 and (ite % self.freq) == 0:
-            dataout = npw.zeros((1, 4))
-            dataout[0, 0] = simulation.time
-            dataout[0, 1:] = self.force
-            self._writeFile(dataout)
+        if self._writer is not None and self._writer.doWrite(ite):
+            self._writer.buffer[0, 0] = simulation.time
+            self._writer.buffer[0, 1:] = self.force
+            self._writer.write()
 
         return self.force
 
@@ -317,502 +285,3 @@ class DragAndLift(Monitoring):
 
         res *= self._dvol
         return res
-
-    def finalize(self):
-        if not self.safeOutput:
-            self._file.close()
-
-class Forces(Monitoring):
-    """
-    Compute the forces according the Noca s formula
-    """
-
-    def __init__(self, velocity, vorticity, topo,
-                 obstacle, boxMin= None, boxMax=None, Reynolds=None,
-                 uinf=1.0, method=FD_C_2, frequency=None, prefix=None):
-        """
-        Constructor.
-        @param velocity : Continuous velocity field
-        @param vorticity : Continuous vorticity field
-        @param obstacle :  obstacle upon which the forces are exerced
-        @param topo :  the topology on which we want to monitor the fields
-        @param boxMin : Global minimum coordinates of the control volume
-        @param boxMax : Global maximum coordinates of the control volume
-        @param Reynolds : Reynolds number value
-        @param method : numerical method for Differential operators discretizations
-        @param frequency : output file producing frequency.
-        @param prefix : file name prefix, contains relative path.
-        """
-        Monitoring.__init__(self, [velocity, vorticity], topo, frequency)
-        if prefix is None:
-            self.prefix = './res/Noca_sphere.dat'
-        else:
-            self.prefix = prefix
-        self.velocity = velocity
-        self.vorticity = vorticity
-        self.obstacle = obstacle
-        self.boxMin = boxMin
-        self.boxMax = boxMax
-        if not (boxMin < boxMax):
-            raise ValueError("Error, boxMin has to be lower than " +
-                             "boxMax to define control Noca box")
-        self.Re = Reynolds
-        self.method = method
-        self.prefix = prefix
-        self.input = [velocity, vorticity]
-        self.output = []
-        self.topo = self._predefinedTopo
-
-        # Compute coef used to determine drag coefficient :
-        # cD = coef.Fx = 2.Fx/rho.uinf**2.D
-        self.bufferForce = 0.
-        rho = 1.0
-        self.coef = 2. / (rho * uinf ** 2 * PI * self.obstacle.radius ** 2)
-
-    def setUp(self):
-        Monitoring.setUp(self)
-
-        # Variables Discretization
-        for v in self.variables:
-            self.discreteFields[v] = v.discretize(self.topo)
-        self.velo = self.discreteFields[self.velocity]
-        self.vort = self.discreteFields[self.vorticity]
-
-        # Control box definition
-        self.isForceComputationNeeded = True
-        self.compute_control_box(self.obstacle)
-
-        # prepare ghost points synchro for velocity
-        self._synchronize = UpdateGhosts(self.topo,
-                                         self.velocity.nbComponents)
-
-        # Function for the computation of div(T) where
-        # T is the stress tensor: T = Nabla(U) + Nabla(U)t
-        self.divT = DivStressTensor3D(self.topo, method=self.method)
-        self.fd_scheme = FD_C_2(self.topo.mesh.space_step)
-
-        self._isUpToDate = True
-
-        if (self.topo.comm.Get_rank() == 0):
-            self.f = open(self.prefix, 'w')
-
-    def compute_control_box(self, obst) :
-        """
-        Compute indicator functions for the control box
-        (including the obstacle)
-
-        @param obstacle :  obstacle upon which the forces are exerced
-
-        """
-        # The control box definition is based on velocity topology
-        self.dim = obst.dimension
-        self.ghosts = self.velo.topology.ghosts
-        self.res = self.velo.topology.mesh.resolution - 2 * self.ghosts
-        self.step = self.velo.topology.mesh.space_step
-        self.coords = self.velo.topology.mesh.coords
-        self.coord_start = self.velo.topology.mesh.origin + \
-                        (self.ghosts * self.step)
-        self.coord_end = self.velo.topology.mesh.end - \
-                        (self.ghosts * self.step)
-        local_start = self.velo.topology.mesh.local_start
-        local_end = self.velo.topology.mesh.local_end
-
-        # normal vectors definitions
-        self.normal = npw.zeros([self.dim * 2, self.dim])
-        self.x_minus = 0
-        self.x_plus = 1
-        self.y_minus = 2
-        self.y_plus = 3
-        self.z_minus = 4
-        self.z_plus = 5
-        self.normal[self.x_minus][0] = - 1.0
-        self.normal[self.x_plus][0] = 1.0
-        self.normal[self.y_minus][1] = - 1.0
-        self.normal[self.y_plus][1] = 1.0
-        self.normal[self.z_minus][2] = - 1.0
-        self.normal[self.z_plus][2] = 1.0
-
-        # local indices and coordinates of the control box boundaries
-        ind_boundaries = np.zeros([self.dim, 2], dtype=PARMES_INTEGER, order=ORDER)
-#        coord_boundaries = npw.zeros([self.dim, 2])
-
-        distMin = self.boxMin - self.coord_start
-        distMax = self.boxMax - self.coord_end
-
-        for i in xrange(self.dim):
-            if (distMin[i]>=0. and distMax[i]<=0.):
-            # the control volume is included inside the local domain
-                ind_boundaries[i][0] = local_start[i] + distMin[i] // self.step[i] # interpolation to lower grid point
-                ind_boundaries[i][1] = local_end[i] + distMax[i] // self.step[i] # interpolation to higher grid point
-#                coord_boundaries[i][0] = self.coord_start[i] + distMin[i] // self.step[i] * self.step[i]
-#                coord_boundaries[i][1] = self.coord_end[i] + distMax[i] // self.step[i] * self.step[i]
-
-            elif (distMin[i]>=0. and self.boxMin[i]<= self.coord_end[i] and distMax[i]>0.):
-            # only min corner of control volume is included inside the local domain
-                ind_boundaries[i][0] = local_start[i] + distMin[i] // self.step[i]
-                ind_boundaries[i][1] = local_end[i]
-#                coord_boundaries[i][0] = self.coord_start[i] + distMin[i] // self.step[i] * self.step[i]
-#                coord_boundaries[i][1] = self.coord_end[i]
-
-            elif (distMin[i]<0. and self.boxMax[i]>= self.coord_start[i] and distMax[i]<=0.) :
-            # only max corner of control volume is included inside the local domain
-                ind_boundaries[i][0] = local_start[i]
-                ind_boundaries[i][1] = local_end[i] + distMax[i] // self.step[i]
-#                coord_boundaries[i][0] = self.coord_start[i]
-#                coord_boundaries[i][1] = self.coord_end[i] + distMax[i] // self.step[i] * self.step[i]
-
-            elif (distMin[i]<=0. and distMax[i]>=0.):
-            # the local domain is included inside the control volume
-                ind_boundaries[i][0] = local_start[i]
-                ind_boundaries[i][1] = local_end[i]
-#                coord_boundaries[i][0] = self.coord_start[i]
-#                coord_boundaries[i][1] = self.coord_end[i]
-            else:
-            # there is no part of the volume control inside the local domain
-                self.isForceComputationNeeded = False
-
-#        print 'coord_start, coord_end', self.topo.comm.Get_rank(), self.coord_start, self.coord_end
-#        print 'distMin, distMax, step, res', self.topo.comm.Get_rank(), distMin, distMax, self.step, self.res
-#        print 'ind_bound_ChiX-', self.topo.comm.Get_rank(), ind_boundaries[0][0], coord_boundaries[0][0], self.coords[0][ind_boundaries[0][0], :, :]
-#        print 'ind_bound_ChiX+', self.topo.comm.Get_rank(), ind_boundaries[0][1], coord_boundaries[0][1], self.coords[0][ind_boundaries[0][1], :, :]
-#        print 'ind_bound_ChiY-', self.topo.comm.Get_rank(), ind_boundaries[1][0], coord_boundaries[1][0], self.coords[1][:, ind_boundaries[1][0], :]
-#        print 'ind_bound_ChiY+', self.topo.comm.Get_rank(), ind_boundaries[1][1], coord_boundaries[1][1], self.coords[1][:, ind_boundaries[1][1], :]
-#        print 'ind_bound_ChiZ-', self.topo.comm.Get_rank(), ind_boundaries[2][0], coord_boundaries[2][0], self.coords[2][:, :, ind_boundaries[2][0]]
-#        print 'ind_bound_ChiZ+', self.topo.comm.Get_rank(), ind_boundaries[2][1], coord_boundaries[2][1], self.coords[2][:, :, ind_boundaries[2][1]]
-
-        # definition of the indicator functions of box boundaries
-        self.chi_x_minus = [slice(ind_boundaries[0][0], ind_boundaries[0][0] +1),
-                            slice(ind_boundaries[1][0], ind_boundaries[1][1] +1),
-                            slice(ind_boundaries[2][0], ind_boundaries[2][1] +1)]
-
-        self.chi_x_plus = [slice(ind_boundaries[0][1], ind_boundaries[0][1] +1 ),
-                           slice(ind_boundaries[1][0], ind_boundaries[1][1] +1),
-                           slice(ind_boundaries[2][0], ind_boundaries[2][1] +1)]
-
-        self.chi_y_minus = [slice(ind_boundaries[0][0], ind_boundaries[0][1] +1),
-                            slice(ind_boundaries[1][0], ind_boundaries[1][0] +1),
-                            slice(ind_boundaries[2][0], ind_boundaries[2][1] +1)]
-
-        self.chi_y_plus = [slice(ind_boundaries[0][0], ind_boundaries[0][1] +1),
-                           slice(ind_boundaries[1][0], ind_boundaries[1][0] +1),
-                           slice(ind_boundaries[2][0], ind_boundaries[2][1] +1)]
-
-        self.chi_z_minus = [slice(ind_boundaries[0][0], ind_boundaries[0][1] +1),
-                            slice(ind_boundaries[1][0], ind_boundaries[1][1] +1),
-                            slice(ind_boundaries[2][0], ind_boundaries[2][0] +1)]
-
-        self.chi_z_plus = [slice(ind_boundaries[0][0], ind_boundaries[0][1] +1),
-                           slice(ind_boundaries[1][0], ind_boundaries[1][1] +1),
-                           slice(ind_boundaries[2][1], ind_boundaries[2][1] +1)]
-
-        # definition of the indicator function of the whole box (includind the obstacle)
-        # TODO : defining this indicator function without includind the obstacle
-        self.chi_box = []
-        for d in xrange(self.dim):
-            self.chi_box.append(slice(ind_boundaries[d][0], ind_boundaries[d][1]))
-
-    @debug
-    @timed_function
-    def apply(self, simulation):
-        """
-        Computation of the drag according to the "impulsion" formula presented by
-        Noca et. al in Journal of Fluids and Structures, 1999.
-        Integrals on the obstacle are neglected.
-        \f$ F=-\frac{1}{N-1}\frac{d}{dt}\int_{V}\mathbf{x}\wedge\mathbf{\omega}\, dV
-                +\int_{S}\mathbf{n}\cdot\gamma\, dS \f$
-        """
-        t = simulation.time
-        dt = simulation.timeStep
-        ite = simulation.currentIteration
-
-        velo = self.velo.data
-        vort = self.vort.data
-
-        # Synchronize ghost points of velocity
-        self._synchronize(velo)
-
-        if not self.isForceComputationNeeded:
-            pass
-        else :
-            localForce = npw.zeros(self.dim)
-            force = npw.zeros(self.dim)
-
-            # Surfaces normal to X axis
-            # n=(-1, 0, 0)
-            dsurf = self.step[YDIR] * self.step[ZDIR]
-            localForce = self.integrateOnSurface(localForce, velo, vort, self.chi_x_minus,
-                                                 self.normal[self.x_minus][:],
-                                                 dsurf, direc=XDIR)
-            # n=(1, 0, 0)
-            localForce = self.integrateOnSurface(localForce, velo, vort, self.chi_x_plus,
-                                                 self.normal[self.x_plus][:],
-                                                 dsurf, direc=XDIR)
-            # Surfaces normal to Y axis
-            dsurf = self.step[XDIR] * self.step[ZDIR]
-            # n=(0,-1, 0)
-            localForce = self.integrateOnSurface(localForce, velo, vort, self.chi_y_minus,
-                                                 self.normal[self.y_minus][:],
-                                                 dsurf, direc=YDIR)
-            # n=(0, 1, 0)
-            localForce = self.integrateOnSurface(localForce, velo, vort, self.chi_y_plus,
-                                                 self.normal[self.y_plus][:],
-                                                 dsurf, direc=YDIR)
-            # Surfaces normal to Z axis
-            dsurf = self.step[XDIR] * self.step[YDIR]
-            # n=(0, 0,-1)
-            localForce = self.integrateOnSurface(localForce, velo, vort, self.chi_z_minus,
-                                                 self.normal[self.z_minus][:],
-                                                 dsurf, direc=ZDIR)
-            # n=(0, 0, 1)
-            localForce = self.integrateOnSurface(localForce, velo, vort, self.chi_z_plus,
-                                                 self.normal[self.z_plus][:],
-                                                 dsurf, direc=ZDIR)
-            # Integration over the volume
-            localForce = self.integrateOnBox(localForce, vort, self.chi_box, dt)
-
-            # Reduction operation
-            if self.topo.comm.Get_rank() == 0:
-                comm = self.topo.comm
-                comm.Reduce([localForce, PARMES_MPI_REAL],
-                            [force, PARMES_MPI_REAL],
-                            op=MPI.SUM, root=0)
-                force = force * self.coef
-                # Print drag, lift and side force coefficients in output file
-                if ((ite % self.freq == 0) and (t > dt)):
-                    self.f = open(self.prefix, 'a')
-                    self.f.write("%s   %s   %s   %s\n" % (t,
-                                                          force[XDIR],
-                                                          force[YDIR],
-                                                          force[ZDIR]))
-                    self.f.close()
-
-    def integrateOnBox(self, force, vort, chi, dt):
-    ## WARNING : this routine is available inly if velo and vort
-    ## topologies have the same global mesh resolution !!!
-        """
-        Returns \f$-\frac{1}{2}\frac{d}{dt}
-        \int_{V}\mathbf{x}\wedge\mathbf{\omega}\, dV \f$
-        """
-        dvol = self.step[XDIR] * self.step[YDIR] * self.step[ZDIR]
-        fact = - dvol / ((self.dim - 1) * dt)
-        intbox = npw.zeros(self.dim)
-        work = [npw.zeros_like(vort[0]) for i in xrange(self.dim)]
-
-        # (coord X vorticity)
-        coords = np.asarray(self.coords)
-        work[XDIR][...] = self.coords[YDIR] * vort[ZDIR][...] - \
-                          self.coords[ZDIR] * vort[YDIR][...]
-        work[YDIR][...] = self.coords[ZDIR] * vort[XDIR][...] - \
-                          self.coords[XDIR] * vort[ZDIR][...]
-        work[ZDIR][...] = self.coords[XDIR] * vort[YDIR][...] - \
-                          self.coords[YDIR] * vort[XDIR][...]
-        for i in xrange(self.dim):
-            intbox[i] = np.sum(work[i][chi])
-        force += fact * (intbox - self.bufferForce) # 1st order time integration
-        self.bufferForce = intbox # Save for next time step ...
-
-        return force
-
-
-    def integrateOnSurface(self, force, velo, vort, chi, NormalVec, dsurf, direc):
-    ## WARNING : this routine is available inly if velo and vort
-    ## topologies have the same global mesh resolution !!!
-        """
-        Compute integrals on surface normal to "direc" axis to calculate forces
-        acting on the body. See (2.1) of Noca 1999 or (52) of Plouhmans 2002.
-        Returns \f$ \int_{S}\mathbf{n}\cdot\gamma\, dS \f$, where
-        \f$ \mathbf{n}\cdot\gamma = [(\frac{1}{2} (\mathbf{u}\cdot\mathbf{u})\mathbf{n} -
-        (\mathbf{n}\cdot\mathbf{u})\mathbf{u}) -
-        \frac{1}{N-1}(\mathbf{n}\cdot\mathbf{u})(\mathbf{x}\wedge\mathbf{\omega}) +
-        \frac{1}{N-1}(\mathbf{n}\cdot\mathbf{\omega})(\mathbf{x}\wedge\mathbf{u})] +
-        [\frac{1}{N-1}\mathbf{x}\wedge(\mathbf{n}\wedge\nabla\cdot T)] +
-        [\frac{1}{N-1}\mathbf{n}\cdot T] \f$
-        In the following, the computation of surface integrals is split in three parts :
-        force = [int_part 1] + [int_part 2] + [int_part 3]
-        """
-        fact = 1. / (self.dim - 1)
-        work = [npw.zeros_like(velo[0]) for i in xrange(self.dim)]
-        divT = [npw.zeros_like(velo[0]) for i in xrange(self.dim)]
-        # Divergence of stress tensor T, computed with 2nd order FD
-        divT = self.divT(velo, divT, chi)
-        # Functions to compute part 2 and part 3 of the surface integral, with:
-        # part 2 = 1/(dim-1)(X^(n^Div(T))
-        # part 3 = (1/Re) * n.T
-        if direc==XDIR:
-            self.X_n_DivT = self.part2_Xdir
-            self.n_T = self.part3_Xdir
-        elif direc==YDIR:
-            self.X_n_DivT = self.part2_Ydir
-            self.n_T = self.part3_Ydir
-        else:
-            assert direc==ZDIR
-            self.X_n_DivT = self.part2_Zdir
-            self.n_T = self.part3_Zdir
-
-        # ====================== part 1 =======================
-        # part 1 = 1/2(velocity.velocity)n -
-        # (n.velocity)velocity -
-        # 1/(dim-1)(n.velocity)(coord X vorticity) +
-        # 1/(dim-1)(n.vorticity)(coord X velocity)
-
-        # 1/2(velocity.velocity)n
-        u_u = np.sum(velo[i][chi] * velo[i][chi] for i in xrange(self.dim))
-        force[direc] += 0.5 * np.sum(u_u[...] * NormalVec[direc])
-        # -(n.velocity)velocity
-        n_u = velo[direc][chi] * NormalVec[direc]
-        for i in xrange(self.dim):
-            work[i][chi] = n_u[...] * velo[i][chi]
-        for i in xrange(self.dim):
-            force[i] -= np.sum(work[i][chi])
-
-        # -1/(dim-1)(n.velocity)(coord X vorticity)
-        work[XDIR][...] = self.coords[XDIR] * vort[ZDIR][...] - \
-                          self.coords[ZDIR] * vort[YDIR][...]
-        work[YDIR][...] = self.coords[ZDIR] * vort[XDIR][...] - \
-                          self.coords[XDIR] * vort[ZDIR][...]
-        work[ZDIR][...] = self.coords[XDIR] * vort[YDIR][...] - \
-                          self.coords[YDIR] * vort[XDIR][...]
-        for i in xrange(self.dim):
-            work[i][chi] *= n_u[...]
-        for i in xrange(self.dim):
-            force[i] -= fact * np.sum(work[i][chi])
-
-        # 1/(dim-1)(n.vorticity)(coord X velocity)
-        n_w = vort[direc][chi] * NormalVec[direc]
-        work[XDIR][...] = self.coords[XDIR] * velo[ZDIR][...] - \
-                          self.coords[ZDIR] * velo[YDIR][...]
-        work[YDIR][...] = self.coords[ZDIR] * velo[XDIR][...] - \
-                          self.coords[XDIR] * velo[ZDIR][...]
-        work[ZDIR][...] = self.coords[XDIR] * velo[YDIR][...] - \
-                          self.coords[YDIR] * velo[XDIR][...]
-        for i in xrange(self.dim):
-            work[i][chi] *= n_w[...]
-        for i in xrange(self.dim):
-            force[i] += fact * np.sum(work[i][chi])
-
-        # ====================== part 2 =======================
-        # part 2 = 1/(dim-1)(X^(n^Div(T))
-        work = self.X_n_DivT(chi, divT, work)
-
-        if NormalVec[direc] == 1:
-            for i in xrange(self.dim):
-                force[i] += (fact / self.Re) * np.sum(work[i][chi])
-        else:
-            assert NormalVec[direc] == -1
-            for i in xrange(self.dim):
-                force[i] += (fact / self.Re) * np.sum(-work[i][chi])
-
-        # ====================== part 3 =======================
-        # part 3 = (1/Re) * n.T
-        work = self.n_T(velo, work, chi)
-
-        if NormalVec[direc] == 1:
-            for i in xrange(self.dim):
-                force[i] += (1.0 / self.Re) * np.sum(work[i][chi])
-        else:
-            assert NormalVec[direc] == -1
-            for i in xrange(self.dim):
-                force[i] += (1.0 / self.Re) * np.sum(-work[i][chi])
-
-        force *= dsurf
-
-        return force
-
-    # Functions to compute part 2 of a surface integral
-    def part2_Xdir(self, chi, divT, work):
-        # X^(n^Div(T)) computation for normalVec = (1,0,0)
-        work[XDIR][...] = self.coords[YDIR] * divT[YDIR][...] + \
-                          self.coords[ZDIR] * divT[ZDIR][...]
-        work[YDIR][...] = - self.coords[XDIR] * divT[YDIR][...]
-        work[ZDIR][...] = - self.coords[XDIR] * divT[ZDIR][...]
-
-        return work
-
-    def part2_Ydir(self, chi, divT, work):
-        # X^(n^Div(T)) computation for normalVec = (0,1,0)
-        work[XDIR][...] = - self.coords[YDIR] * divT[XDIR][...]
-        work[YDIR][...] = self.coords[XDIR] * divT[XDIR][...] + \
-                          self.coords[ZDIR] * divT[ZDIR][...]
-        work[ZDIR][...] = - self.coords[YDIR] * divT[ZDIR][...]
-
-        return work
-
-    def part2_Zdir(self, chi, divT, work):
-        # X^(n^Div(T)) computation for normalVec = (0,0,1)
-        work[XDIR][...] = - self.coords[ZDIR] * divT[XDIR][...]
-        work[YDIR][...] = - self.coords[ZDIR] * divT[YDIR][...]
-        work[ZDIR][...] = self.coords[XDIR] * divT[XDIR][...] + \
-                          self.coords[YDIR] * divT[YDIR][...]
-
-        return work
-
-    # Functions to compute part 3 of a surface integral
-    def part3_Xdir(self, velo, work, chi):
-        # n.T[XDIR] = 2 * dux/dx[i,j,k]
-        # n.T[YDIR] = duy/dx[i,j,k] + dux/dy[i,j,k]
-        # n.T[ZDIR] = duz/dx[i,j,k] + dux/dz[i,j,k]
-
-        self.fd_scheme.computeIndices(chi)
-        workJacobian = npw.zeros_like(velo[0])
-
-        # n.T computation for normalVec = (1,0,0)
-        self.fd_scheme.compute_1st_deriv(velo[XDIR], XDIR, workJacobian)
-        work[XDIR][chi] = 2 * workJacobian[chi]
-
-        self.fd_scheme.compute_1st_deriv(velo[YDIR], XDIR, workJacobian)
-        self.fd_scheme.compute_and_add_1st_deriv(velo[XDIR], YDIR, workJacobian)
-        work[YDIR][chi] = workJacobian[chi]
-
-        self.fd_scheme.compute_1st_deriv(velo[ZDIR], XDIR, workJacobian)
-        self.fd_scheme.compute_and_add_1st_deriv(velo[XDIR], ZDIR, workJacobian)
-        work[ZDIR][chi] = workJacobian[chi]
-
-        return work
-
-    def part3_Ydir(self, velo, work, chi):
-        # n.T[XDIR] = dux/dy[i,j,k] + duy/dx[i,j,k]
-        # n.T[YDIR] = 2.0 * duy/dy[i,j,k]
-        # n.T[ZDIR] = duz/dy[i,j,k] + duy/dz[i,j,k]
-
-        self.fd_scheme.computeIndices(chi)
-        workJacobian = npw.zeros_like(velo[0])
-
-        # n.T computation for normalVec = (0,1,0)
-        self.fd_scheme.compute_1st_deriv(velo[XDIR], YDIR, workJacobian)
-        self.fd_scheme.compute_and_add_1st_deriv(velo[YDIR], XDIR, workJacobian)
-        work[XDIR][chi] = workJacobian[chi]
-
-        self.fd_scheme.compute_1st_deriv(velo[YDIR], YDIR, workJacobian)
-        work[YDIR][chi] = 2.* workJacobian[chi]
-
-        self.fd_scheme.compute_1st_deriv(velo[ZDIR], YDIR, workJacobian)
-        self.fd_scheme.compute_and_add_1st_deriv(velo[YDIR], ZDIR, workJacobian)
-        work[ZDIR][chi] = workJacobian[chi]
-
-        return work
-
-    def part3_Zdir(self, velo, work, chi):
-        # n.T[XDIR] = dux/dz[i,j,k] + duz/dx[i,j,k]
-        # n.T[YDIR] = duy/dz[i,j,k] + duz/dy[i,j,k]
-        # n.T[ZDIR] = 2.0 * duz/dz[i,j,k]
-
-        self.fd_scheme.computeIndices(chi)
-        workJacobian = npw.zeros_like(velo[0])
-
-        # n.T computation for normalVec = (0,0,1)
-        self.fd_scheme.compute_1st_deriv(velo[XDIR], ZDIR, workJacobian)
-        self.fd_scheme.compute_and_add_1st_deriv(velo[ZDIR], XDIR, workJacobian)
-        work[XDIR][chi] = workJacobian[chi]
-
-        self.fd_scheme.compute_1st_deriv(velo[YDIR], ZDIR, workJacobian)
-        self.fd_scheme.compute_and_add_1st_deriv(velo[ZDIR], YDIR, workJacobian)
-        work[YDIR][chi] = workJacobian[chi]
-
-        self.fd_scheme.compute_1st_deriv(velo[ZDIR], ZDIR, workJacobian)
-        work[ZDIR][chi] = 2.* workJacobian[chi]
-
-        return work
-
-    def __str__(self):
-        s = "Compute_forces. "
-        return s
diff --git a/HySoP/hysop/operator/monitors/monitoring.py b/HySoP/hysop/operator/monitors/monitoring.py
index c8703fbb466a5a3635e5e3f45a7e8bd8af29b12f..c96932fddfab2a3195bf21e01e8c99500adcccf6 100644
--- a/HySoP/hysop/operator/monitors/monitoring.py
+++ b/HySoP/hysop/operator/monitors/monitoring.py
@@ -5,6 +5,7 @@ Global interface for monitors.
 from abc import ABCMeta, abstractmethod
 from parmepy.operator.continuous import Operator
 from parmepy.tools.timers import Timer
+import parmepy.tools.io_utils as io
 
 
 class Monitoring(Operator):
@@ -13,27 +14,45 @@ class Monitoring(Operator):
     __metaclass__ = ABCMeta
 
     @abstractmethod
-    def __init__(self, variables, topo, frequency, task_id=None):
+    def __init__(self, variables, topo, io_params=None, task_id=None):
         """ Constructor
         @param variables : list of fields to monitor.
         @param topo : topo on which fields are to be monitored
-        @param frequency : output rate.
-        @param name : Monitor name.
+        @param filename output file name. Default is None ==> no output.
+        Full or relative path.
+        @param io_params : parameters (dict) to set file output.
+        If  None, no output. Set io_params = {} if you want output,
+        with default parameters values.
+        See parmepy.tools.io_utils.Writer for details
         """
         Operator.__init__(self, variables, topo=topo, task_id=task_id)
-        ## Monitor frequency
-        self.freq = frequency
         ## Object to store computational times of lower level functions
         self.timer = Timer(self)
         self.requirements = []
+        self._isUpToDate = False
+        # Output file.
+        if io_params is None:
+            self._writer = None
+        else:
+            self._writer = io.Writer(io_params, topo.comm)
 
     def setUp(self):
-        pass
+        """
+        Class-method required
+        to fit with operator base-class interface.
+        """
+        self._isUpToDate = True
 
     def finalize(self):
-        pass
+        if self._writer is not None:
+            self._writer.finalize()
 
     def discretize(self):
+        """
+        Does nothing.
+        No discretization in monitors, but class-method required
+        to fit with operator base-class interface.
+        """
         pass
 
     def addRedistributeRequirement(self, red):
diff --git a/HySoP/hysop/operator/monitors/printer.py b/HySoP/hysop/operator/monitors/printer.py
index 7d9bbc0e7141ae270e23a98b8fc62ceaa9151f64..35022c94cf2fb84b1ca67a125f54ef3bd2782e5a 100644
--- a/HySoP/hysop/operator/monitors/printer.py
+++ b/HySoP/hysop/operator/monitors/printer.py
@@ -1,12 +1,14 @@
 """
 @file printer.py
 
-Classes for handling ouputs.
+File output for field(s) value on a grid.
 """
 from parmepy.constants import np, S_DIR, debug, VTK, HDF5, DATA
 from parmepy.operator.monitors.monitoring import Monitoring
 import parmepy.tools.numpywrappers as npw
+import parmepy.tools.io_utils as io
 import os
+
 try:
     import evtk.hl as evtk
 except ImportError as evtk_error:
@@ -20,29 +22,23 @@ from parmepy.tools.timers import timed_function
 
 class Printer(Monitoring):
     """
-    Basic printer.
-
-    Performs outputs in VTK images.
+    Print field(s) values on a given topo, in HDF5 or VTK format.
     """
-    def __init__(self, variables, topo, frequency=0,
-                 prefix=None, formattype=None, task_id=None):
+    def __init__(self, variables, topo, prefix=None,
+                 frequency=1, formattype=None, task_id=None):
         """
-        Create a results printer for given fields, filename
+        Create a results printer for given fields, prefix
         prefix (relative path) and an output frequency.
 
-        @param fields : list of variables to export.
+        @param variables : list of variables to export.
         @param frequency : output rate (output every freq iteration)
-        @param prefix : output file name prefix.
-        @param ext : output file extension, default=.vtk.
+        @param prefix output file name. Default is None ==> no output.
+        Full or relative path.
+        @param formattype : output file format, default=vtk.
         """
-        Monitoring.__init__(self, variables, topo, frequency,
-                            task_id=task_id)
-        ## output file name prefix
-        if prefix is None:
-            self.prefix = './out_'
-        else:
-            self.prefix = prefix
-
+        Monitoring.__init__(self, variables, topo, task_id=task_id)
+        assert frequency > 0
+        self.frequency = frequency
         ## Default output type
         if formattype is None:
             self.formattype = VTK
@@ -61,41 +57,44 @@ class Printer(Monitoring):
 
         self.input = self.variables
         self.output = []
-        ## Method to collect data in case of distributed data
-        self.get_data_method = None
-        if self.freq > 0:
-            ## Printer core method
-            self.step = self._printStep
+        # If no prefix is given, set it to
+        # the concatenation of variables'names.
+        if prefix is None:
+            prefix = io.io.defaultPath()
+            name = ''
+            for var in self.input:
+                name += var.name
+                name += '_'
+            prefix = os.path.join(prefix, name)
         else:
-            self.step = self._passStep
-        # Internal counter
-        self._call_number = 0
+            if not os.path.isabs(prefix):
+                prefix = os.path.join(io.io.defaultPath(), prefix)
         ## shortcut to topo name
         self.topo = self._predefinedTopo
+        io.io.checkDir(prefix, 0, self.topo.comm)
+        self.prefix = prefix
         self._xmf_data_files = []
-
-
-    def setUp(self):
-        """
-        Print initial state
-        """
-        # Create output dir if required
-        if self.topo.rank == 0:
-            d = os.path.dirname(self.prefix)
-            if not os.path.exists(d):
-                os.makedirs(d)
-        # Force synchro to be sure that all output dirs
-        # have been created.
-        self.topo.comm.barrier()
         if self.formattype == VTK:
+            # filename = prefix_rk_N, rk = current process rank,
+            # N = counter value
             self._get_filename = lambda i: self.prefix + \
-                "{0}_iter_{1:03d}".format(self.topo.rank, i)
+                "_{0}_{1:05d}".format(self.topo.rank, i)
+            self.step = self._step_VTK
         elif self.formattype == HDF5:
+            # filename = prefix_N, N = counter value
             self._get_filename = lambda i: self.prefix + \
-                "{0}procs_iter_{1:03d}".format(self.topo.size, i) + '.h5'
+                "_{0:05d}".format(i) + '.h5'
+            self.step = self._step_HDF5
         elif self.formattype == DATA:
             self._get_filename = lambda i: self.prefix + \
-                "{0}_iter_{1:03d}.dat".format(self.topo.rank, i)
+                "_{0}_{1:05d}.dat".format(self.topo.rank, i)
+            self.step = self._step_DATA
+        self._isUpToDate = True
+        # count the number of calls
+        self._count = 0
+        ## Rank of 'leader' mpi process for output
+        ## Forced to 0. \todo : add a param for this?
+        self.io_rank = 0
 
     @debug
     @timed_function
@@ -103,21 +102,29 @@ class Printer(Monitoring):
         if simulation is None:
             raise ValueError("Missing simulation value for monitoring.")
 
-        self._call_number += 1
-        if self.freq > 0 and (simulation.currentIteration % self.freq) == 0:
+        if simulation.currentIteration % self.frequency == 0:
+            # Transfer from GPU to CPU if required
+            for f in self.variables:
+                df = f.discreteFields[self.topo]
+                try:
+                    if not df.isBatch:
+                    # To host only if data fit in the device memory
+                        df.toHost()
+                        df.wait()
+                except AttributeError:
+                    pass
             self.step(simulation)
+            self._count += 1
 
     def finalize(self):
-        if self.freq == -1:
-            self._printStep(self._call_number)
-        if self.formattype == HDF5 and self.topo.rank == 0:
+        if self.formattype == HDF5 and self.topo.rank == self.io_rank:
             # Write the xmf file driving all h5 files.
             # Writing only one file
             # We have a temporal list of Grid => a single xmf file
             # Manual writing of the xmf file because "XDMF library very
             # difficult to compile and to use"
             #  [Advanced HDF5 & XDMF - Groupe Calcul]
-            f = open(self.prefix + str(self.topo.size) + 'procs.xmf', 'w')
+            f = open(self.prefix + '.xmf', 'w')
             f.write("<?xml version=\"1.0\" ?>\n")
             f.write("<!DOCTYPE Xdmf SYSTEM \"Xdmf.dtd\">\n")
             f.write("<Xdmf Version=\"2.0\">\n")
@@ -151,151 +158,119 @@ class Printer(Monitoring):
                     res[name] = npw.realarray(df.data[d])
         return res
 
-    def set_get_data_method(self, method):
-        """Set data collect method."""
-        if callable(method):
-            self.get_data_method = method
-        else:
-            raise ValueError("Cannot set non callable method to get data " +
-                             "to print. Given method : " + str(method))
-
-    def _passStep(self, simu=None):
-        """A code method that do nothing."""
-        pass
-
-    def _printStep(self, simu=None):
+    def _step_VTK(self, simu):
         """
-        Try to write data into VTK files.
-        If fails, turn to classical ascii output.
-        @param iter : current iteration number
         """
-        ite = simu.currentIteration
-        t = ite * simu.timeStep
-        # Transfer from GPU to CPU if required
-        for f in self.variables:
-            df = f.discreteFields[self.topo]
-            try:
-                if not df.isBatch:
-                    # To host only if data fit in the device memory
-                    df.toHost()
-                    df.wait()
-            except AttributeError:
-                pass
+        orig = [0.] * 3
+        dim = self.topo.mesh.dim
+        orig[:dim] = [self.topo.mesh.origin[i] for i in xrange(dim)]
+        #orig = tuple(orig)
+        #ind = self.topo.mesh.local_start
+        ## orig = tuple([self.topo.mesh.coords[i].flatten()[ind[i]]
+        ##               for i in xrange(self.topo.mesh.dim)])
+        spacing = [0] * 3
+        spacing[:dim] = [self.topo.mesh.space_step[i] for i in xrange(dim)]
+        evtk.imageToVTK(self._get_filename(self._count),
+                        origin=orig, spacing=spacing,
+                        pointData=self._build_vtk_dict())
 
-        ## VTK output \todo: Need fix in 2D, getting an IOError.
-        if self.formattype == VTK:
-            orig = [0.] * 3
-            dim = self.topo.mesh.dim
-            orig[:dim] = [self.topo.mesh.origin[i] for i in xrange(dim)]
-            #orig = tuple(orig)
-            coords = self.topo.mesh.coords
-            #ind = self.topo.mesh.local_start
-            ## orig = tuple([self.topo.mesh.coords[i].flatten()[ind[i]]
-            ##               for i in xrange(self.topo.mesh.dim)])
-            spacing = [0] * 3
-            spacing[:dim] = [self.topo.mesh.space_step[i] for i in xrange(dim)]
-            evtk.imageToVTK(self._get_filename(ite),
-                            origin=orig, spacing=spacing,
-                            pointData=self._build_vtk_dict())
-
-        elif self.formattype == HDF5:
-            filename = self._get_filename(ite)
-            # Write the h5 file
-            # (force np.float64, ParaView seems to not be able to read float32)
-            # Writing compressed hdf5 files (gzip compression seems the best)
-            # In parallel, one file is written, thus filename no longe contains
-            # mpi rank.
-            # TODO: Why gzip compression not working in parallel ??
-            # Remark: h5py must be build with --mpi option
-            if self.topo.size == 1:
-                f = h5py.File(filename, "w")
-                compression = 'gzip'
-            else:
-                f = h5py.File(filename, 'w',
-                              driver='mpio', comm=self.topo.comm)
-                compression = None
+    def _step_HDF5(self, simu):
+        t = simu.time
+        filename = self._get_filename(self._count)
+        # Write the h5 file
+        # (force np.float64, ParaView seems to not be able to read float32)
+        # Writing compressed hdf5 files (gzip compression seems the best)
+        # In parallel, one file is written, thus filename no longe contains
+        # mpi rank.
+        # TODO: Why gzip compression not working in parallel ??
+        # Remark: h5py must be build with --mpi option
+        if self.topo.size == 1:
+            f = h5py.File(filename, "w")
+            compression = 'gzip'
+        else:
+            f = h5py.File(filename, 'w', driver='mpio', comm=self.topo.comm)
+            compression = None
+        g_start = self.topo.mesh.global_start
+        g_end = self.topo.mesh.global_end + 1
+        sl = [slice(g_start[i], g_end[i])
+              for i in xrange(self.domain.dimension)]
+        sl.reverse()
+        sl = tuple(sl)
+        datasetNames = []
+        for field in self.variables:
+            df = field.discreteFields[self.topo]
+            for d in xrange(df.nbComponents):
+                # creating datasets for the vector field
+                currentName = df.name + S_DIR[d]
+                datasetNames.append(currentName)
+                res = list(self.topo.globalMeshResolution - 1)
+                res.reverse()
+                ds = f.create_dataset(currentName,
+                                      res,
+                                      dtype=np.float64,
+                                      compression=compression)
+                # In parallel, each proc must write in the proper part
+                # Of the dataset (of site global resolution)
+                ds[sl] = npw.realarray(df.data[d][self.topo.mesh.iCompute].T)
+        self._xmf_data_files.append((datasetNames, self._count, t))
 
-            g_start = self.topo.mesh.global_start
-            g_end = self.topo.mesh.global_end + 1
-            sl = [slice(g_start[i], g_end[i])
-                  for i in xrange(self.domain.dimension)]
-            sl.reverse()
-            sl = tuple(sl)
-            datasetNames = []
-            for field in self.variables:
-                df = field.discreteFields[self.topo]
-                for d in xrange(df.nbComponents):
-                    # creating datasets for the vector field
-                    currentName = df.name + S_DIR[d]
-                    datasetNames.append(currentName)
-                    res = list(self.topo.globalMeshResolution - 1)
-                    res.reverse()
-                    ds = f.create_dataset(currentName,
-                                          res,
-                                          dtype=np.float64,
-                                          compression=compression)
-                    # In parallel, each proc must write in the proper part
-                    # Of the dataset (of site global resolution)
-                    ds[sl] = \
-                        npw.realarray(df.data[d][self.topo.mesh.iCompute].T)
-            self._xmf_data_files.append((datasetNames, ite, t))
+        f.close()
 
-            f.close()
-        elif self.formattype == DATA:
-            f = open(self._get_filename(ite), 'w')
-            shape = self.topo.mesh.resolution
-            coords = self.topo.mesh.coords
-            pbDimension = self.domain.dimension
-            if pbDimension == 2:
-                if len(shape) == 2:
-                    for i in xrange(shape[0] - 1):
-                        for j in xrange(shape[1] - 1):
-                            f.write("{0:8.12} {1:8.12} ".format(
-                                    coords[0][i, 0], coords[1][0, j]))
-                            for field in self.variables:
-                                df = field.discreteFields[self.topo]
-                                if field.isVector:
-                                    f.write("{0:8.12} {1:8.12} ".format(
-                                            df[0][i, j],
-                                            df[1][i, j]))
-                                else:
-                                    f.write("{0:8.12} ".format(
-                                            df[0][i, j]))
-                            f.write("\n")
-            elif pbDimension == 3:
+    def _step_DATA(self, simu):
+        f = open(self._get_filename(self._count), 'w')
+        shape = self.topo.mesh.resolution
+        coords = self.topo.mesh.coords
+        pbDimension = self.domain.dimension
+        if pbDimension == 2:
+            if len(shape) == 2:
                 for i in xrange(shape[0] - 1):
                     for j in xrange(shape[1] - 1):
-                        for k in xrange(shape[2] - 1):
-                            f.write(
-                                "{0:8.12} {1:8.12} {2:8.12} ".format(
-                                    coords[0][i, 0, 0],
-                                    coords[1][0, j, 0],
-                                    coords[2][0, 0, k]))
-                            for field in self.variables:
-                                df = field.discreteFields[self.topo]
-                                if field.isVector:
-                                    f.write(
-                                        "{0:8.12} {1:8.12} " +
-                                        "{2:8.12} ".format(
-                                            df[0][i, j, k],
-                                            df[1][i, j, k],
-                                            df[2][i, j, k]))
-                                else:
-                                    f.write("{0:8.12} ".format(
-                                            df[0][i, j, k]))
-                            f.write("\n")
-            else:
-                for i in xrange(shape[0] - 1):
-                    f.write("{0:8.12} ".format(coords[0][i]))
-                    for field in self.variables:
-                        df = field.discreteFields[self.topo]
-                        if field.isVector:
-                            f.write(
-                                "{0:8.12} ".format(df[0][i]))
-                        else:
-                            f.write("{0:8.12} ".format(df[i]))
-                            f.write("\n")
-            f.close()
+                        f.write("{0:8.12} {1:8.12} ".format(
+                                coords[0][i, 0], coords[1][0, j]))
+                        for field in self.variables:
+                            df = field.discreteFields[self.topo]
+                            if field.isVector:
+                                f.write("{0:8.12} {1:8.12} ".format(
+                                        df[0][i, j],
+                                        df[1][i, j]))
+                            else:
+                                f.write("{0:8.12} ".format(
+                                        df[0][i, j]))
+                        f.write("\n")
+        elif pbDimension == 3:
+            for i in xrange(shape[0] - 1):
+                for j in xrange(shape[1] - 1):
+                    for k in xrange(shape[2] - 1):
+                        f.write(
+                            "{0:8.12} {1:8.12} {2:8.12} ".format(
+                                coords[0][i, 0, 0],
+                                coords[1][0, j, 0],
+                                coords[2][0, 0, k]))
+                        for field in self.variables:
+                            df = field.discreteFields[self.topo]
+                            if field.isVector:
+                                f.write(
+                                    "{0:8.12} {1:8.12} " +
+                                    "{2:8.12} ".format(
+                                        df[0][i, j, k],
+                                        df[1][i, j, k],
+                                        df[2][i, j, k]))
+                            else:
+                                f.write("{0:8.12} ".format(
+                                        df[0][i, j, k]))
+                        f.write("\n")
+        else:
+            for i in xrange(shape[0] - 1):
+                f.write("{0:8.12} ".format(coords[0][i]))
+                for field in self.variables:
+                    df = field.discreteFields[self.topo]
+                    if field.isVector:
+                        f.write(
+                            "{0:8.12} ".format(df[0][i]))
+                    else:
+                        f.write("{0:8.12} ".format(df[i]))
+                        f.write("\n")
+        f.close()
 
 
 def _listFormat(l):
@@ -332,7 +307,7 @@ def _TemporalGridXMF(topo, datasetNames, ite, t, filename):
     g += "     " + _listFormat(ori) + "\n"
     g += "     </DataItem>\n"
     g += "     <DataItem Dimensions=\"" + str(topo.mesh.dim) + " \""
-    g += " NumberType=\"Float\" Precision=\"4\" Format=\"XML\">\n"
+    g += " NumberType=\"Float\" Precision=\"8\" Format=\"XML\">\n"
     step = list(topo.mesh.space_step)
     step.reverse()
     g += "     " + _listFormat(step) + "\n"
diff --git a/HySoP/hysop/operator/poisson.py b/HySoP/hysop/operator/poisson.py
index 768d56466b919de611923599d182111de0c2c7d8..a9c7a454f8eb8709a0ee6b28dbf8c8ca433118de 100644
--- a/HySoP/hysop/operator/poisson.py
+++ b/HySoP/hysop/operator/poisson.py
@@ -7,9 +7,10 @@ Poisson problem.
 from parmepy.operator.continuous import Operator
 from parmepy.f2py import fftw2py
 from parmepy.operator.discrete.poisson_fft import PoissonFFT
-from parmepy.variables.variables import Variables
 from parmepy.constants import debug
 import numpy as np
+from parmepy.mpi.main_var import main_size
+from parmepy.operator.velocity_correction import VelocityCorrection
 
 
 class Poisson(Operator):
@@ -26,14 +27,19 @@ class Poisson(Operator):
 
     @debug
     def __init__(self, velocity, vorticity, resolutions, ghosts=None,
-                 method=None, topo=None, task_id=None, comm=None,
-                 **other_config):
+                 method=None, flowrate=None, topo=None,
+                 task_id=None, comm=None):
         """
         Constructor for the Poisson problem.
 
         @param[out] velocity : solution field
         @param[in] vorticity : rhs field
         @param[in] resolutions :  list of resolutions (one per variable)
+        @param[in] ghosts : ghost layer (optional), default=[0, 0, ...]
+        @param[in] method : numerical method (default = fft)
+        @param[in] flowrate : a flow rate value (through input surf,
+        normal to xdir) used to compute a correction of the solution field.
+        Default = 0 (no correction). See parmepy.operator.velocity_correction.
         """
         ## solution of the problem
         self.velocity = velocity
@@ -45,7 +51,6 @@ class Poisson(Operator):
 
         Operator.__init__(self, [velocity, vorticity], method, ghosts=ghosts,
                           topo=topo, task_id=task_id, comm=comm)
-        self.config = other_config
         if method is None:
             self.method = 'fftw'
         if self.method is 'fftw':
@@ -53,25 +58,20 @@ class Poisson(Operator):
             assert self.resolution == self.resolutions[self.vorticity],\
                 'Poisson error : for fftw, all variables must have\
                 the same global resolution.'
+        else:
+            raise AttributeError("Method not yet implemented.")
         self.input = [self.vorticity]
         self.output = [self.velocity]
-
-        # If there is a projection, vorticity is also an output
-        try:
-            if (isinstance(other_config['projection'], Variables)):
-                proj = other_config['projection'].data
-            else:
-                proj = other_config['projection']
-        except KeyError:
-            proj = None
-        if proj is not None and proj[0]:
-            self.output.append(self.vorticity)
+        if flowrate is not None:
+            self.withCorrection = True
+            self._flowrate = flowrate
+        else:
+            self.withCorrection = False
+        self.correction = None
+        self.projection = None
 
     def discretize(self):
         # Poisson solver based on fftw
-        if self.method is not 'fftw':
-            print self.method
-            raise AttributeError("Method not yet implemented.")
         if self.ghosts is not None:
             raise AttributeError("Ghosts points not yet\
             implemented for poisson operator.")
@@ -88,13 +88,13 @@ class Poisson(Operator):
             self.resolution, self.domain.length, comm=comm.py2f())
 
         if self._predefinedTopo is not None:
-            main_size = self._predefinedTopo.size
+            commsize = self._predefinedTopo.size
         elif self._comm is not None:
-            main_size = self._comm.Get_size()
+            commsize = self._comm.Get_size()
         else:
-            from parmepy.mpi.main_var import main_size
+            commsize = main_size
         topodims = np.ones((self.domain.dimension))
-        topodims[-1] = main_size
+        topodims[-1] = commsize
         #variables discretization
         if self._predefinedTopo is not None:
             topo = self._predefinedTopo
@@ -113,15 +113,32 @@ class Poisson(Operator):
                     ghosts=self.ghosts,
                     comm=self._comm)
                 self.discreteFields[v] = v.discretize(topo)
+        # Build and discretize correction operator, if necessary
+        if self.withCorrection:
+            self.correction = VelocityCorrection(self.velocity, self.vorticity,
+                                                 resolutions=self.resolutions,
+                                                 flowrate=self._flowrate,
+                                                 topo=self.velocity.topology)
+            self.correction.discretize()
 
     @debug
     def setUp(self):
         """
         """
         # Build and setup for the discrete operator
+        if self.withCorrection:
+            self.correction.setUp()
+            cd = self.correction.discreteOperator
+        else:
+            cd = None
         self.discreteOperator = PoissonFFT(self.discreteFields[self.velocity],
                                            self.discreteFields[self.vorticity],
-                                           method=self.method,
-                                           **self.config)
+                                           correction=cd,
+                                           projection=self.projection)
         self.discreteOperator.setUp()
         self._isUpToDate = True
+
+    def activateProjection(self, projection):
+        # If there is a projection, vorticity is also an output
+        self.output.append(self.vorticity)
+        self.projection = projection
diff --git a/HySoP/hysop/operator/redistribute.py b/HySoP/hysop/operator/redistribute.py
index d1f2a8c731cf3e6acf65ea530d8be93b697b0433..d805e01eaae9915a081a0d6ac59ca2a91fbf35d6 100644
--- a/HySoP/hysop/operator/redistribute.py
+++ b/HySoP/hysop/operator/redistribute.py
@@ -23,6 +23,7 @@ from parmepy import __VERBOSE__
 from parmepy.constants import debug, PARMES_MPI_REAL, ORDERMPI, np, S_DIR
 from parmepy.operator.continuous import Operator
 from parmepy.mpi.topology import Bridge
+from parmepy.mpi import main_rank, main_comm
 from parmepy.methods_keys import Support
 
 
@@ -365,9 +366,6 @@ class Redistribute(Operator):
                     return res
         return res
 
-    def finalize(self):
-        pass
-
     def addRedistributeRequirement(self, red):
         raise ValueError(
             "Cannot add a requirement to a Redistribute operator.")
diff --git a/HySoP/hysop/operator/redistribute_intercomm.py b/HySoP/hysop/operator/redistribute_intercomm.py
index 9b68569a044772aa8ec494acd30906b7bb1c76a9..959e4d1506b54427ec257275290691e356984892 100644
--- a/HySoP/hysop/operator/redistribute_intercomm.py
+++ b/HySoP/hysop/operator/redistribute_intercomm.py
@@ -346,5 +346,3 @@ class RedistributeIntercomm(Operator):
                     return res
         return res
 
-    def finalize(self):
-        pass
diff --git a/HySoP/hysop/operator/reprojection.py b/HySoP/hysop/operator/reprojection.py
index eb3c89f9531af0aa06bdaa73c81e3f4e3d91d89a..a35bb739cf41f004624744fa136b1c80891d6a7e 100644
--- a/HySoP/hysop/operator/reprojection.py
+++ b/HySoP/hysop/operator/reprojection.py
@@ -4,10 +4,10 @@
 Compute reprojection criterion and divergence maximum
 """
 import numpy as np
-from parmepy.constants import np, debug, PARMES_REAL, PARMES_MPI_REAL
+from parmepy.constants import debug, PARMES_MPI_REAL
 from parmepy.methods_keys import SpaceDiscretisation
 from parmepy.operator.monitors.monitoring import Monitoring
-from parmepy.numerics.finite_differences import FD_C_4, FD_C_2
+from parmepy.numerics.finite_differences import FD_C_4
 from parmepy.numerics.differential_operations import GradV
 import parmepy.tools.numpywrappers as npw
 from parmepy.numerics.updateGhosts import UpdateGhosts
@@ -21,150 +21,162 @@ class Reprojection_criterion(Monitoring):
     See the related PDF called "vorticity_solenoidal_projection.pdf"
     in ParmesDoc for more details.
     """
-    def __init__(self, vorticity,
-                 need_reproj,
-                 reproj_cst,
-                 topo, frequency,
-                 method={SpaceDiscretisation: FD_C_4},
-                 prefix=None, task_id=None):
+    def __init__(self, vorticity, reproj_cst, reprojRate,
+                 topo, checkCriterion=False, io_params=None,
+                 method=None, task_id=None):
         """
         Constructor.
         @param vorticity field
         @param method : finite difference scheme
         @param topo : the topology on which we want to monitor the fields
-        @param frequency : output file producing frequency.
         @param prefix : output file name.
+        @param checkCriterion :  set behavior of this operator :
+        if True, compute some criterion and force frequency
+        to 1 if reprojection is needed.
+        else (false) performs reprojection every reprojRate iterations.
+        @param reprojRate : set rate of execution of the reprojection
+        @param io_params : parameters (dict) to set file output.
+        If  None, no output. Set io_params = {} if you want output,
+        with default parameters values. Default file name = 'reproj'
+        See parmepy.tools.io_utils.Writer for details
         """
-        Monitoring.__init__(self, [vorticity], topo, frequency,
+        if io_params is not None:
+            if not "filename" in io_params:
+                io_params["filename"] = "reproj"
+            # Set output buffer shape
+            io_params["writebuffshape"] = (1, 5)
+
+        Monitoring.__init__(self, [vorticity], topo, io_params,
                             task_id=task_id)
-        if prefix is None:
-            self.prefix = './res/reproj_crit.dat'
-        else:
-            self.prefix = prefix
-        ## vorticity field
-        self.vorticity = vorticity
-        ## Numerical methods for space discretization
-        assert SpaceDiscretisation in method.keys()
-        self.method = method[SpaceDiscretisation]
-
-        self.input = [vorticity]
-        self.output = []
         # alias for local topo
         self._topo = self._predefinedTopo
         # \todo : rewrite for multiresolution case.
         # Note FP : for multiresolution case, it would probably be
         # better to use two different operators for energy and enstrophy.
-
-        # Boolean : is the reprojection of vorticity needed for
-        # current timestep ?
-        self.need_reproj = need_reproj
-
+        ## Frequency for reprojection
+        self.reprojRate = reprojRate
+        ## The initial value will be used as default during
+        # simulation
+        self.default_rate = reprojRate
+        ## Set behavior of this operator :
+        ## if True, compute some criterion and force frequency
+        ## to 1 if reprojection is needed.
+        ## else (false) performs reprojection every frequency iterations.
+        self.checkCriterion = checkCriterion
         # constant defining the reprojection criterion :
-        # if the latter is greater than this constant, then a reprojection is needed
+        # if the latter is greater than this constant, then a reprojection
+        # is needed
         self.reproj_cst = reproj_cst
-        self.default_reproj_frequency =  need_reproj.data[1]
         self.proj_counter = 0
+        ## local buffer
+        ## diag = [time, projCriterion, d1, d2, proj_counter]
+        ## See apply for details about d1, d2.
+        self.diagnostics = npw.zeros(5)
+        # Connect writer buffer to diagnostics, if required
+        if self._writer is not None:
+            self._writer.buffer = self.diagnostics.reshape(1,5)
+
+        if self.checkCriterion:
+            ## vorticity field
+            self.vorticity = vorticity
+            if method is None:
+                method = {SpaceDiscretisation: FD_C_4}
+            ## Numerical methods for space discretization
+            assert SpaceDiscretisation in method.keys()
+            self.method = method[SpaceDiscretisation]
+
+            self.input = [vorticity]
+        else:
+            self.input = []
+            
+        self.output = []
+
 
     def setUp(self):
-        Monitoring.setUp(self)
-        # Get discrete fields for vorticity.
-        # Note FP : two options to get the discrete fields:
-        # - 'field.discretization(topo)' that just try
-        # to get the discrete field and return an error
-        # if it does not exist.
-        # - 'field.discretizet(topo) try to get the discrete field and create
-        # a new discretization if it does not exist.
-        # Current choice : no creation.
-        self.discreteFields[self.vorticity] =\
-            self.vorticity.discretization(self._topo)
-
-        # prepare ghost points synchro for vorticity
-        self._synchronize = UpdateGhosts(self._topo,
-                                         self.vorticity.nbComponents)
-
-        # grad function
-        self._function = GradV(self._topo,
-                               method=self.method)
-
-        self.vort_d = self.discreteFields[self.vorticity]
-
-        memshape = self.vort_d.data[0].shape
-        worklength = self.vort_d.nbComponents ** 2
-        # gradient result array
-        self.grad = [npw.zeros(memshape)
-                     for i in xrange(worklength)]
+        if not self._isUpToDate and self.checkCriterion:
+            # Get discrete fields for vorticity.
+            # Note FP : two options to get the discrete fields:
+            # - 'field.discretization(topo)' that just try
+            # to get the discrete field and return an error
+            # if it does not exist.
+            # - 'field.discretizet(topo)
+            # try to get the discrete field and create
+            # a new discretization if it does not exist.
+            # Current choice : no creation.
+            self.discreteFields[self.vorticity] =\
+                self.vorticity.discretization(self._topo)
+
+            # prepare ghost points synchro for vorticity
+            self._synchronize = UpdateGhosts(self._topo,
+                                             self.vorticity.nbComponents)
+
+            # grad function
+            self._function = GradV(self._topo, method=self.method)
+
+            self.vort_d = self.discreteFields[self.vorticity]
+
+            memshape = self.vort_d.data[0].shape
+            worklength = self.vort_d.nbComponents ** 2
+            # gradient result array
+            self.grad = [npw.zeros(memshape) for i in xrange(worklength)]
 
         self._isUpToDate = True
 
-        # Open file for output
-        if (self._topo.rank == 0):
-            import os
-            path = os.path.dirname(self.prefix)
-            if not os.path.exists(path):
-                os.mkdir(path)
-
-            self.f = open(self.prefix, 'w')
-
     @debug
     @timed_function
     def apply(self, simulation=None):
         """
         Computes and prints reprojection criterion and divergence maximum
         """
-        t = simulation.time
+        self.diagnostics[0] = simulation.time
         ite = simulation.currentIteration
 
-        self.need_reproj.data[1] = self.default_reproj_frequency
-
-        # Synchronize ghost points of vorticity
-        self._synchronize(self.vort_d.data)
-        # gradU computation
-        self.grad = self._function(self.vort_d.data, self.grad)
-
-        diagnostics = npw.zeros((2))
-        nbComponents = self.vorticity.nbComponents
+        # Reset reprojection frequency to default
+        self.reprojRate = self.default_rate
+
+        # If required, computation of a criterion
+        # and reset frequency
+        if self.checkCriterion:
+            # Synchronize ghost points of vorticity
+            self._synchronize(self.vort_d.data)
+            # gradU computation
+            self.grad = self._function(self.vort_d.data, self.grad)
+            nbComponents = self.vorticity.nbComponents
+            # maxima of vorticity divergence (abs)
+            self.diagnostics[2] = \
+                np.max(abs(sum([(self.grad[(nbComponents + 1) * i])
+                               for i in xrange(nbComponents)])))
+
+            # maxima of partial derivatives of vorticity
+            for grad_n in self.grad:
+                self.diagnostics[3] = max(self.diagnostics[3],
+                                          np.max(abs(grad_n)))
+
+            # computation of the reprojection criterion and reduction
+            # among all proc.
+            projCriterion = self.diagnostics[2] / self.diagnostics[3]
+            projCriterion = \
+                self._topo.comm.allreduce(projCriterion, PARMES_MPI_REAL,
+                                          op=MPI.MAX)
+            self.diagnostics[1] = projCriterion
 
-        # maxima of vorticity divergence (abs)
-        diagnostics[0] = np.max(abs(sum([(self.grad[(nbComponents + 1) * i])
-                                    for i in xrange(nbComponents)])))
+            # is reprojection of vorticity needed for the future time step ?
+            if (projCriterion > self.reproj_cst):
+                self.reprojRate = 1
 
-        # maxima of partial derivatives of vorticity
-        for direc1 in xrange(nbComponents):
-            for direc2 in xrange(nbComponents):
-                diagnostics[1] = max(diagnostics[1],
-                                     np.max(abs(self.grad[nbComponents * \
-                                                          direc1 + direc2])))
+        # Note FP : is counter really useful? Maybe it should be increased
+        # by the operator that use projection (poisson)?
+        if (ite % self.reprojRate == 0):
+            self.proj_counter += 1
+        self.diagnostics[4] = self.proj_counter
 
-        # computation of the reprojection criterion and reduction among all proc.
-        projCriterion = diagnostics[0] / diagnostics[1]
-        projCriterion = \
-            self._topo.comm.allreduce(projCriterion,
-                                      PARMES_MPI_REAL,
-                                      op=MPI.MAX)
+        # Print results, if required
+        # Remark : writer buffer is (pointer) connected to diagnostics
+        if self._writer is not None and self._writer.doWrite(ite):
+            self._writer.write()
 
-        if self.need_reproj.data[0]:
-            # is reprojection of vorticity needed for the future time step ?
-            if ((projCriterion > self.reproj_cst) and (self.need_reproj.data[2])):
-                self.need_reproj.data[1] = 1
-
-            if (ite % self.need_reproj.data[1] == 0):
-                self.proj_counter += 1
-
-        # printer
-        if ((self._topo.comm.Get_rank() == 0) and (ite % self.freq == 0)):
-            self.f = open(self.prefix, 'a')
-            self.f.write("%s   %s   %s   %s    %s\n" % (t, projCriterion,
-                                                        diagnostics[0],
-                                                        diagnostics[1],
-                                                        self.proj_counter))
-            self.f.close()
-
-
-    def __str__(self):
-        s = "Reprojection_criterion. "
-        return s
-
-if __name__ == "__main__":
-    print __doc__
-    print "- Provided class : Reprojection_criterion"
-    print Reprojection_criterion.__doc__
+    def doProjection(self, ite):
+        """
+        True if projection must be done
+        """
+        return ite % self.reprojRate == 0
diff --git a/HySoP/hysop/operator/tests/test_Stretching.py b/HySoP/hysop/operator/tests/test_Stretching.py
index 5af3da16e2d0b21d711ce940d88ca53abfa6abd6..1be61b32017611c2081f13a6eca6ee71e3f668b4 100755
--- a/HySoP/hysop/operator/tests/test_Stretching.py
+++ b/HySoP/hysop/operator/tests/test_Stretching.py
@@ -84,5 +84,5 @@ def test_Stretching():
     velo.initialize()
     vorti.initialize()
     stretch.setUp()
-    simulation = Simulation(0, timeStep, 20)
+    simulation = Simulation(0, 20, timeStep)
     stretch.apply(simulation)
diff --git a/HySoP/hysop/operator/tests/test_advec_scales.py b/HySoP/hysop/operator/tests/test_advec_scales.py
index 87087a47206d9c31ea029d26f690b481a4743e2c..3001b05297a0d7b75dad5280b761f1847f54504c 100755
--- a/HySoP/hysop/operator/tests/test_advec_scales.py
+++ b/HySoP/hysop/operator/tests/test_advec_scales.py
@@ -48,8 +48,8 @@ def test_nullVelocity_m4():
         dtype=PARMES_REAL, order=ORDER)
     scal_ref_d.data[0][...] = scal_d.data[0][...]
 
-    advec.apply(Simulation(0., 0.1, 1))
-    advec_py.apply(Simulation(0., 0.1, 1))
+    advec.apply(Simulation(0., 1., 0.1))
+    advec_py.apply(Simulation(0., 1, 0.1))
 
     assert np.allclose(scal_ref_d.data[0], scal_d.data[0])
 
@@ -97,8 +97,8 @@ def test_nullVelocity_vec_m4():
     scal_ref_d.data[1][...] = scal_d.data[1][...]
     scal_ref_d.data[2][...] = scal_d.data[2][...]
 
-    advec.apply(Simulation(0., 0.1, 1))
-    advec_py.apply(Simulation(0., 0.1, 1))
+    advec.apply(Simulation(0., 1., 0.1))
+    advec_py.apply(Simulation(0., 1., 0.1))
 
     assert np.allclose(scal_ref_d.data[0], scal_d.data[0])
     assert np.allclose(scal_ref_d.data[1], scal_d.data[1])
@@ -125,7 +125,7 @@ def test_nullVelocity_m6():
                                      dtype=PARMES_REAL, order=ORDER)
     scal_init = npw.copy(scal_d.data[0])
 
-    advec.apply(Simulation(0., 0.1, 1))
+    advec.apply(Simulation(0., 1., 0.1))
 
     assert np.allclose(scal_init, scal_d.data[0])
 
@@ -159,7 +159,7 @@ def test_nullVelocity_vec_m6():
     scal_init1 = npw.copy(scal_d.data[1])
     scal_init2 = npw.copy(scal_d.data[2])
 
-    advec.apply(Simulation(0., 0.1, 1))
+    advec.apply(Simulation(0., 1., 0.1))
 
     assert np.allclose(scal_init0, scal_d.data[0])
     assert np.allclose(scal_init1, scal_d.data[1])
@@ -201,8 +201,8 @@ def test_nullVelocity_m8():
         dtype=PARMES_REAL, order=ORDER)
     scal_ref_d.data[0][...] = scal_d.data[0]
 
-    advec.apply(Simulation(0., 0.1, 1))
-    advec_py.apply(Simulation(0., 0.1, 1))
+    advec.apply(Simulation(0., 1., 0.1))
+    advec_py.apply(Simulation(0., 1., 0.1))
 
     assert np.allclose(scal_ref_d.data[0], scal_d.data[0])
 
@@ -250,8 +250,8 @@ def test_nullVelocity_vec_m8():
     scal_ref_d.data[1][...] = scal_d.data[1][...]
     scal_ref_d.data[2][...] = scal_d.data[2][...]
 
-    advec.apply(Simulation(0., 0.075, 1))
-    advec_py.apply(Simulation(0., 0.075, 1))
+    advec.apply(Simulation(0., 1., 0.075))
+    advec_py.apply(Simulation(0., 1., 0.075))
 
     assert np.allclose(scal_ref_d.data[0], scal_d.data[0])
     assert np.allclose(scal_ref_d.data[1], scal_d.data[1])
@@ -301,8 +301,8 @@ def _randomVelocity_m4():
         np.random.random(scal_d.data[0].shape),
         dtype=PARMES_REAL, order=ORDER) / (2. * scal_d.resolution[1])
 
-    advec.apply(Simulation(0., 0.1, 1))
-    advec_py.apply(Simulation(0., 0.1, 1))
+    advec.apply(Simulation(0., 1., 0.1,))
+    advec_py.apply(Simulation(0., 1., 0.1))
 
     assert np.allclose(scal_ref_d.data[0], scal_d.data[0])
 
@@ -358,8 +358,8 @@ def _randomVelocity_vec_m4():
         np.random.random(scal_d.data[2].shape),
         dtype=PARMES_REAL, order=ORDER) / (2. * scal_d.resolution[1])
 
-    advec.apply(Simulation(0., 0.1, 1))
-    advec_py.apply(Simulation(0., 0.1, 1))
+    advec.apply(Simulation(0., 1., 0.1))
+    advec_py.apply(Simulation(0., 1., 0.1))
 
     assert np.allclose(scal_ref_d.data[0], scal_d.data[0])
     assert np.allclose(scal_ref_d.data[1], scal_d.data[1])
@@ -409,8 +409,8 @@ def test_randomVelocity_m6():
         np.random.random(scal_d.data[0].shape),
         dtype=PARMES_REAL, order=ORDER) / (2. * scal_d.resolution[1])
 
-    advec.apply(Simulation(0., 0.1, 1))
-    advec_py.apply(Simulation(0., 0.1, 1))
+    advec.apply(Simulation(0., 1., 0.1))
+    advec_py.apply(Simulation(0., 1., 0.1))
 
     assert np.allclose(scal_ref_d.data[0], scal_d.data[0])
 
@@ -466,8 +466,8 @@ def test_randomVelocity_vec_m6():
         np.random.random(scal_d.data[2].shape),
         dtype=PARMES_REAL, order=ORDER) / (2. * scal_d.resolution[1])
 
-    advec.apply(Simulation(0., 0.1, 1))
-    advec_py.apply(Simulation(0., 0.1, 1))
+    advec.apply(Simulation(0., 1., 0.1))
+    advec_py.apply(Simulation(0., 1., 0.1))
 
     assert np.allclose(scal_ref_d.data[0], scal_d.data[0])
     assert np.allclose(scal_ref_d.data[1], scal_d.data[1])
@@ -517,8 +517,8 @@ def test_randomVelocity_m8():
         np.random.random(scal_d.data[0].shape),
         dtype=PARMES_REAL, order=ORDER) / (2. * scal_d.resolution[1])
 
-    advec.apply(Simulation(0., 0.1, 1))
-    advec_py.apply(Simulation(0., 0.1, 1))
+    advec.apply(Simulation(0., 1., 0.1))
+    advec_py.apply(Simulation(0., 1., 0.1))
 
     assert np.allclose(scal_ref_d.data[0], scal_d.data[0], atol=1e-07)
 
@@ -574,8 +574,8 @@ def test_randomVelocity_vec_m8():
         np.random.random(scal_d.data[2].shape),
         dtype=PARMES_REAL, order=ORDER) / (2. * scal_d.resolution[1])
 
-    advec.apply(Simulation(0., 0.01, 1))
-    advec_py.apply(Simulation(0., 0.01, 1))
+    advec.apply(Simulation(0., 1., 0.01))
+    advec_py.apply(Simulation(0., 1., 0.01))
 
     assert np.allclose(scal_ref_d.data[0], scal_d.data[0], atol=1e-07)
     assert np.allclose(scal_ref_d.data[1], scal_d.data[1], atol=1e-07)
diff --git a/HySoP/hysop/operator/tests/test_analytic.py b/HySoP/hysop/operator/tests/test_analytic.py
index b71cacc92009eab9468959d900690b4c59d4ef96..2d6240b713302099b197ad6d311b8127d0dc78c1 100644
--- a/HySoP/hysop/operator/tests/test_analytic.py
+++ b/HySoP/hysop/operator/tests/test_analytic.py
@@ -70,7 +70,7 @@ res2D = [33, 33]
 L2D = [1., 1.]
 origin2D = [0., 0.]
 nbc = 4
-simu = Simulation(10., 0.1, 1)
+simu = Simulation(0., 1., 0.1)
 
 ## I - Tests with direct calls of field.initialize
 
diff --git a/HySoP/hysop/operator/tests/test_particle_advection.py b/HySoP/hysop/operator/tests/test_particle_advection.py
index 2de9116329aea1305bfedeb6c3d870e218b99b00..d4b604ca883d2a780b69691f4388f6c692ebe019 100644
--- a/HySoP/hysop/operator/tests/test_particle_advection.py
+++ b/HySoP/hysop/operator/tests/test_particle_advection.py
@@ -70,7 +70,7 @@ def assertion(scal, advec):
                                      dtype=PARMES_REAL, order=ORDER)
     scal_init = npw.copy(scal_d.data[0])
 
-    advec.apply(Simulation(0., 0.01, 1))
+    advec.apply(Simulation(0., 1., 0.01))
     return np.allclose(scal_init, scal_d.data[0])
 
 
@@ -86,7 +86,7 @@ def assertion_vector2D(scal, advec):
     scal1_init = npw.copy(scal_d.data[0])
     scal2_init = npw.copy(scal_d.data[1])
 
-    advec.apply(Simulation(0., 0.01, 1))
+    advec.apply(Simulation(0., 1., 0.01))
     return np.allclose(scal1_init, scal_d.data[0]) and \
         np.allclose(scal2_init, scal_d.data[1])
 
@@ -106,7 +106,7 @@ def assertion_vector3D(scal, advec):
     scal2_init = npw.copy(scal_d.data[1])
     scal3_init = npw.copy(scal_d.data[2])
 
-    advec.apply(Simulation(0., 0.01, 1))
+    advec.apply(Simulation(0., 1., 0.01))
     return np.allclose(scal1_init, scal_d.data[0]) and \
         np.allclose(scal2_init, scal_d.data[1]) and \
         np.allclose(scal3_init, scal_d.data[2])
@@ -125,7 +125,7 @@ def assertion_list(scal, advec):
     scal1_init = npw.copy(scal1_d.data[0])
     scal2_init = npw.copy(scal2_d.data[0])
 
-    advec.apply(Simulation(0., 0.01, 1))
+    advec.apply(Simulation(0., 1., 0.01))
     print scal1_init, scal1_d.data[0]
     print scal2_init, scal2_d.data[0]
     return np.allclose(scal1_init, scal1_d.data[0]) and \
diff --git a/HySoP/hysop/operator/tests/test_velocity_correction.py b/HySoP/hysop/operator/tests/test_velocity_correction.py
new file mode 100755
index 0000000000000000000000000000000000000000..06c2ff23d91ae497816d208ae9a53d6264b16ca7
--- /dev/null
+++ b/HySoP/hysop/operator/tests/test_velocity_correction.py
@@ -0,0 +1,148 @@
+# -*- coding: utf-8 -*-
+
+import parmepy as pp
+from parmepy.operator.velocity_correction import VelocityCorrection
+from parmepy.problem.simulation import Simulation
+import numpy as np
+from parmepy.mpi.topology import Cartesian
+import math
+pi = math.pi
+sin = np.sin
+cos = np.cos
+import parmepy.tools.numpywrappers as npw
+
+## Physical Domain description
+print " ========= Start Navier-Stokes 3D (Flow past bluff bodies) ========="
+
+## pi constant
+pi = np.pi
+cos = np.cos
+sin = np.sin
+# Upstream flow velocity
+uinf = 1.0
+tol = 1e-12
+
+
+## Function to compute TG velocity
+def computeVel(res, x, y, z, t):
+    res[0][...] = sin(x) * cos(y) * cos(z)
+    res[1][...] = - cos(x) * sin(y) * cos(z)
+    res[2][...] = 0.
+    return res
+
+
+## Function to compute reference vorticity
+def computeVort(res, x, y, z, t):
+    res[0][...] = - cos(x) * sin(y) * sin(z)
+    res[1][...] = - sin(x) * cos(y) * sin(z)
+    res[2][...] = 2. * sin(x) * sin(y) * cos(z)
+    return res
+
+
+## Function to compute TG velocity
+def computeVel2D(res, x, y, t):
+    res[0][...] = sin(x) * cos(y)
+    res[1][...] = - cos(x) * sin(y)
+    return res
+
+
+## Function to compute reference vorticity
+def computeVort2D(res, x, y, t):
+    res[0][...] = - cos(x) * sin(y)
+    return res
+
+
+def test_velocity_correction_3D():
+    dim = 3
+    ## Domain
+    boxlength = npw.realarray([2.0 * pi, pi, pi])
+    boxorigin = npw.realarray([0., 0., 0.])
+    box = pp.Box(dim, length=boxlength, origin=boxorigin)
+
+    ## Global resolution
+    nbElem = [33, 33, 33]
+
+    ## Vector Fields
+    velo = pp.Field(domain=box, formula=computeVel,
+                    name='Velocity', isVector=True)
+    vorti = pp.Field(domain=box, formula=computeVort,
+                     name='Vorticity', isVector=True)
+
+    ## Usual Cartesian topology definition
+    NBGHOSTS = 2
+    ghosts = np.ones((box.dimension)) * NBGHOSTS
+    topo = Cartesian(box, box.dimension, nbElem,
+                     ghosts=ghosts)
+
+    op = {}
+    ref_rate = uinf * box.length[1] * box.length[2]
+    op['correction'] = VelocityCorrection(velo, vorti,
+                                          resolutions={velo: nbElem,
+                                                       vorti: nbElem},
+                                          req_flowrate=ref_rate, topo=topo)
+    op['correction'].discretize()
+    op['correction'].setUp()
+    # === Simulation setup ===
+    simu = Simulation(tinit=0.0, tend=5., timeStep=0.005, iterMax=1000000)
+    # init fields
+    velo.initialize(topo=topo)
+    vorti.initialize(topo=topo)
+
+    # Apply correction
+    op['correction'].apply(simu)
+    # check new flowrate values
+    sref = op['correction'].discreteOperator.surfRef
+    flowrate = velo.integrateOnSurface(sref, topo)
+    print flowrate
+    assert (flowrate - ref_rate) < tol
+    for i in xrange(1, dim):
+        flowrate2 = velo.integrateOnSurface(sref, topo, component=i)
+        assert flowrate2 < tol
+
+
+def test_velocity_correction_2D():
+    dim = 2
+    ## Domain
+    boxlength = npw.realarray([2.0 * pi, pi])
+    boxorigin = npw.realarray([0., 0.])
+    box = pp.Box(dim, length=boxlength, origin=boxorigin)
+
+    ## Global resolution
+    nbElem = [33, 33]
+
+    ## Vector Fields
+    velo = pp.Field(domain=box, formula=computeVel2D,
+                    name='Velocity', isVector=True)
+    vorti = pp.Field(domain=box, formula=computeVort2D,
+                     name='Vorticity', isVector=False)
+
+    ## Usual Cartesian topology definition
+    NBGHOSTS = 2
+    ghosts = np.ones((box.dimension)) * NBGHOSTS
+    topo = Cartesian(box, box.dimension, nbElem,
+                     ghosts=ghosts)
+
+    op = {}
+    ref_rate = uinf * box.length[1]
+    op['correction'] = VelocityCorrection(velo, vorti,
+                                          resolutions={velo: nbElem,
+                                                       vorti: nbElem},
+                                          req_flowrate=ref_rate, topo=topo)
+    op['correction'].discretize()
+    op['correction'].setUp()
+    # === Simulation setup ===
+    simu = Simulation(tinit=0.0, tend=5., timeStep=0.005, iterMax=1000000)
+    # init fields
+    velo.initialize(topo=topo)
+    vorti.initialize(topo=topo)
+
+    # Apply correction
+    op['correction'].apply(simu)
+    # check new flowrate values
+    sref = op['correction'].discreteOperator.surfRef
+    flowrate = velo.integrateOnSurface(sref, topo)
+    print flowrate
+    assert (flowrate - ref_rate) < tol
+    for i in xrange(1, dim):
+        flowrate2 = velo.integrateOnSurface(sref, topo, component=i)
+        assert flowrate2 < tol
diff --git a/HySoP/hysop/operator/velocity_correction.py b/HySoP/hysop/operator/velocity_correction.py
index 72de985cc96d0aa4d0bc7a884edd098f1c62a8aa..0735875e5bbfdcb848ce44e7abffbb283f324530 100755
--- a/HySoP/hysop/operator/velocity_correction.py
+++ b/HySoP/hysop/operator/velocity_correction.py
@@ -2,13 +2,13 @@
 """
 @file operator/velocity_correction.py
 
-Correction of the velocity field according to the desired flowrate.
+Operator to shift velocity to fit with a required input flowrate.
 
 """
 from parmepy.constants import debug
 from parmepy.operator.discrete.velocity_correction import VelocityCorrection_D
 from parmepy.operator.continuous import Operator
-import numpy as np
+from parmepy.domain.obstacle.controlBox import ControlBox
 
 
 class VelocityCorrection(Operator):
@@ -20,20 +20,24 @@ class VelocityCorrection(Operator):
     """
 
     @debug
-    def __init__(self, velocity, vorticity, resolutions,
-                 topo=None, task_id=None, comm=None, **other_config):
+    def __init__(self, velocity, vorticity, resolutions, req_flowrate,
+                 surf=None, topo=None, comm=None, task_id=None):
         """
         Corrects the values of the velocity field after
         solving Poisson equation in order to prescribe proper
         mean flow and ensure the desired inlet flowrate.
 
-        @param velocity field
-        @param resolutions : grid resolution of velocity
-        @param topo : a predefined topology to discretize velocity
+        @param[in, out] velocity field to be corrected
+        @param[in] vorticity field used to compute correction
+        @param resolutions : grid resolutions of velocity and vorticity
+        @param[in] req_flowrate : required value for the flowrate
+        @param[in] surf : surface (parmepy.domain.obstacle.planes.SubPlane)
+        used to compute reference flow rates. Default = surface at x_origin,
+        normal to x-dir.
+        @param topo : a predefined topology to discretize velocity/vorticity
         """
         Operator.__init__(self, [velocity, vorticity], topo=topo,
                           task_id=task_id, comm=comm)
-        self.config = other_config
         ## velocity variable (vector)
         self.velocity = velocity
         ## velocity variable
@@ -43,6 +47,13 @@ class VelocityCorrection(Operator):
 
         self.input = [self.velocity, self.vorticity]
         self.output = [self.velocity]
+        ## A 'reference' surface on which flow rates will be computed
+        ## (usually, surface normal to the flow at origin)
+        self.surfRef = surf
+        ## Expected value for the flow rate through self.surfRef
+        self.req_flowrate = req_flowrate
+        dom = self.velocity.domain
+        self.cb = ControlBox(dom, dom.origin, dom.length)
 
     def discretize(self):
         if self._predefinedTopo is not None:
@@ -62,7 +73,20 @@ class VelocityCorrection(Operator):
         self.discreteOperator =\
             VelocityCorrection_D(self.discreteFields[self.velocity],
                                  self.discreteFields[self.vorticity],
-                                 **self.config)
+                                 self.req_flowrate, self.cb)
 
         self.discreteOperator.setUp()
         self._isUpToDate = True
+
+    def apply(self, simulation=None):
+        """
+        Compute correction and add it to current velocoty
+        """
+        self.discreteOperator.apply(simulation)
+
+    def computeCorrection(self):
+        """
+        Compute the required correction for the current state
+        but do not apply it onto velocity.
+        """
+        self.discreteOperator.computeCorrection()
diff --git a/HySoP/hysop/problem/problem.py b/HySoP/hysop/problem/problem.py
index 37227c62914bdc5349843e5238928b83af4f01d3..5483c7dd1b3e21a3f63c2cf598fea72ddfce7e37 100644
--- a/HySoP/hysop/problem/problem.py
+++ b/HySoP/hysop/problem/problem.py
@@ -181,7 +181,8 @@ class Problem(object):
         if main_rank == 0:
             print "\n\n Start solving ..."
         while not self.simulation.isOver:
-            self.simulation.printState()
+            if main_rank == 0:
+                self.simulation.printState()
 
             for op in self.operators:
                 if __VERBOSE__:
diff --git a/HySoP/hysop/problem/problem_tasks.py b/HySoP/hysop/problem/problem_tasks.py
index 9749aa4e178c610078e60e3d7a1e0edc46310943..3ec307560d1e3f284811ba7e49b6d017f4a579ab 100644
--- a/HySoP/hysop/problem/problem_tasks.py
+++ b/HySoP/hysop/problem/problem_tasks.py
@@ -178,7 +178,8 @@ class ProblemTasks(Problem):
         if self._main_rank == 0:
             print "\n\n Start solving ..."
         while not self.simulation.isOver:
-            self.simulation.printState()
+            if self._main_rank == 0:
+                self.simulation.printState()
             for op in self.operators:
                 op.apply(self.simulation)
             testdump = \
diff --git a/HySoP/hysop/problem/simulation.py b/HySoP/hysop/problem/simulation.py
index df6b3850fc7f318318216277ca2812e49b625dc8..fb16b807648bede2ff8fdd1171c8c090dfa6cbe0 100644
--- a/HySoP/hysop/problem/simulation.py
+++ b/HySoP/hysop/problem/simulation.py
@@ -3,8 +3,6 @@
 
 Description of the simulation parameters (time, iteration ...)
 """
-from parmepy.mpi import main_rank
-from parmepy.variables.variables import Variables
 
 
 class Simulation(object):
@@ -29,10 +27,13 @@ class Simulation(object):
         @param bridgeOp : Redistribute operator
         @param computeTimeStepOp : Operator which evaluates
         the adaptative time step according to the flow fields
+
+        Notation:
+        iteration number 'currentIteration'
+        between tk and tkp1 = tk + timeStep
         """
         ## Simulation final time
         self.end = tend
-        print 'final time:', tend, self.end, iterMax
         ## Starting time
         self.start = tinit
         ## Simulation current time
@@ -41,25 +42,21 @@ class Simulation(object):
         self.isOver = False
         ## Iteration counter
         self.currentIteration = 0
-        ## Simulation time step variable
-        if (isinstance(timeStep, Variables)):
-            ## Set isAdaptative to True
-            self.isAdaptative = True
-            ## Simulation time step variable
-            self.timeStep_variable = timeStep
-            ## Simulation time step adaptative value
-            self.timeStep = timeStep.data[0]
-            ## Save the initial timestep value
-            self.timeStepInit = timeStep.data[0]
-        else:
-            ## Set isAdaptative to False
-            self.isAdaptative = False
-            ## Simulation time step fixed value
-            self.timeStep = timeStep
-
+        ## Simulation time step
+        self.timeStep = timeStep
+        ## Starting time for the current iteration
+        self.tk = tinit
+        ## tk + dt
+        self.tkp1 = tinit + self.timeStep
         ## Maximum number of iterations
         self.iterMax = iterMax
         self._lastStep = False
+        print self.start, self.timeStep, self.end
+        print self.start + self.timeStep
+        assert self.end > self.start, \
+            'Final time must be greater than initial time'
+        assert (self.start + self.timeStep) <= self.end,\
+            'start + step is bigger than end.'
 
     def init(self):
         self.currentIteration = 1
@@ -71,6 +68,8 @@ class Simulation(object):
         Compute a timestep for the incoming iteration (from a vairable and
         to reach the end of simulation)
         """
+        # Increment iteration counter
+        self.currentIteration += 1
         if self._lastStep:
             # The timestep was adjusted to reach end in the previous call
             # So now the simulation is over
@@ -78,42 +77,33 @@ class Simulation(object):
         else:
             if self.currentIteration < self.iterMax:
                 # Advance time for the iteration just ended
-                self.time += self.timeStep
-                self.currentIteration += 1
-
-                # Prepare the timestep for the following itertation
-                if self.isAdaptative and self.currentIteration >= 2:
-                    self.timeStep = self.timeStep_variable.data[0]
+                self.tk = self.tkp1
+                self.tkp1 = self.tk + self.timeStep
 
-                # Axdjust last timestep to reach self.end
-                if self.end - self.time < self.timeStep:
-                    self.timeStep = self.end - self.time
+                # Adjust last timestep to reach self.end
+                if self.tkp1 > self.end:
+                    self.timeStep = self.end - self.tk
+                    self.tkp1 = self.end
                     self._lastStep = True
             else:
                 # iteration number is reached
                 self.isOver = True
-            # Time is close enough to the end to consider that the simulation
-            # is over.
-            if abs(self.time - self.end) < 1e-10:
-                self.isOver = True
 
-    def printState(self):
+        self.time = self.tkp1
+
+    def updateTimeStep(self, newDt):
         """
-        print current state
+        Update current time step.
+        This function is usually called from Adapt_timestep operator.
         """
-        if main_rank == 0:
-            print "=== Iteration : {0:3d}, start from t ={1:6.3f} \
-to t ={2:6.3f} ===".format(
-                self.currentIteration, self.time, self.time + self.timeStep)
+        self.timeStep = newDt
 
-    def reset(self):
+    def printState(self):
         """
-        set initial time to current and reset iteration counter.
-        Used to initialize simulation after a restart.
+        print current state
         """
-        self.start = self.time
-        self.isOver = False
-        self.currentIteration = 1
+        msg = "== Iteration : {0:3d}, from t = {1:6.5} to t = {2:6.5f} =="
+        print msg.format(self.currentIteration, self.tk, self.time)
 
     def __str__(self):
         s = "Simulation parameters : "
@@ -123,3 +113,8 @@ to t ={2:6.3f} ===".format(
         s += str(self.currentIteration) + ', max number of iterations : '
         s += str(self.iterMax)
         return s
+
+    def initialize(self):
+        self.time = self.tkp1
+        self.isOver = False
+        self.currentIteration = 0
diff --git a/HySoP/hysop/tools/io_utils.py b/HySoP/hysop/tools/io_utils.py
new file mode 100644
index 0000000000000000000000000000000000000000..1cced51835f5256a3f195bac2f4e7bab0017e891
--- /dev/null
+++ b/HySoP/hysop/tools/io_utils.py
@@ -0,0 +1,181 @@
+"""
+@file io_utils.py
+Tools related to i/o in parmes.
+"""
+import os
+import scitools.filetable as ft
+import parmepy.tools.numpywrappers as npw
+import inspect
+import parmepy.mpi as mpi
+
+
+class io(object):
+    """
+    Static class with utilities for file i/o
+    """
+    @staticmethod
+    def defaultPath():
+        """
+        Get the default path for io.
+        Used name if set. If not, get basename of the
+        top exec. file.
+        Example : if you run python MyExe.py for your parmes simulation,
+        results will be saved in ./MyExe/p1/, ./MyExe/p4/
+        the number after 'p' being the number of mpi processus
+        set for the simulation.
+        """
+        # Memo for getouterframe usage:
+        #    frame, filename, line_number, function_name, lines, index =\
+        # inspect.getouterframes(inspect.currentframe())[-1]
+        a = inspect.getouterframes(inspect.currentframe())[-1]
+        return os.path.join(a[1].split('.')[0], 'p' + str(mpi.main_size))
+
+    @staticmethod
+    def checkDir(filename, io_rank=0, comm=None):
+        """
+        Check if the directory of 'filename' exists.
+        Creates it if not.
+        @param filename : file name with full or relative path
+        @param io_rank : processus rank that does the check.
+        @param comm : the mpi communicator that does the check
+        """
+        # Create output dir if required
+        if comm is None:
+            comm = mpi.main_comm
+        if comm.Get_rank() == io_rank:
+            d = os.path.dirname(filename)
+            if not os.path.exists(d):
+                os.makedirs(d)
+
+
+class Writer(object):
+    """
+    @param params : dictionnary to set parameters
+    for output file (name, path, ...)
+    available keys are :
+    - filename : file name with full or relative path.
+    Default = data.out, in filepath.
+    If filename contains absolute path, filepath is ignored.
+    - filepath : path to the i/o file.
+    Default =  parmepy.tools.io_utils.io.defaultPath.
+    - frequency : how often output file is written. Default = 1
+    (i.e. every iteration). N means writes every N iteration and
+    0 means write only after last iteration.
+    - io_rank : mpi process rank (in comm) that performs writting. Default = 0
+    - writebuffshape : shape (numpy array) of the output buffer,
+     written in filename. Default = 1.
+    - safeOutput : boolean. Default = True.
+    True --> open/close file everytime data are written.
+    False --> open at init and close during finalize. Cost less but if simu
+    crashes, data are lost.
+    @param comm : mpi communicator that handles this
+    writer. Default = parmepy.mpi.main_comm.
+
+    Usage :
+    \code
+    >>> import parmepy.tools.io_utils as io
+    >>> defaultPath = io.io.defaultPath()
+    >>> params = {"filename": defaultPath + 'r.dat', "writebuffshape": (1, 2)}
+    >>> wr = Writer(params)
+    >>> ite = 3 # current iteration number
+    >>> if wr.doWrite(ite):
+    ...    wr.buffer[...] = 3.
+    ...    wr.write()
+    >>> wr.finalize()
+
+    \endcode
+    result : buffer is written into r.dat.
+    """
+    def __init__(self, params, comm=None):
+        """
+        """
+        # Directory for output
+        if "filepath" in params:
+            filepath = params["filepath"]
+        else:
+            filepath = io.defaultPath()
+        # file name
+        if "filename" in params:
+            filename = params["filename"]
+        else:
+            filename = 'data.out'
+        ## Absolute path + name for i/o file
+        ## Note that if filename contains absolute path
+        ## filepath is ignored
+        self.filename = os.path.join(filepath, filename)
+
+        ## How often i/o must occur
+        if "frequency" in params:
+            self.frequency = params["frequency"]
+        else:
+            self.frequency = 1
+        ## Rank of the mpi process that performs i/o (if any)
+        if "io_rank" in params:
+            self.io_rank = params["io_rank"]
+        else:
+            self.io_rank = 0
+
+        if comm is None:
+            comm = mpi.main_comm
+        ## A reference communicator, just to identify a
+        ## process rank for io.
+        self.comm = comm
+
+        # check if output dir exists, create it if not.
+        io.checkDir(self.filename, self.io_rank, self.comm)
+
+        ## Shape of the output buffer (must be a 2D numpy array)
+        if "writebuffshape" in params:
+            self.buffshape = params["writebuffshape"]
+        else:
+            self.buffshape = (1, 1)
+        assert len(self.buffshape) == 2,\
+            '2D shape required : set writebuffshape: (x,y)'
+        ## The buffer (numpy array) that will be printed to a file
+        self.buffer = npw.zeros(self.buffshape)
+
+        ## Defines how often
+        ## output file is written :
+        ## True --> open/close file everytime
+        ## data are written.
+        ## False --> open at init and close
+        ## during finalize. Cost less but if simu
+        ## crashes, data are lost.
+        if "safeOutput" in params:
+            self.safeOutput = params["safeOutput"]
+        else:
+            self.safeOutput = True
+
+        if self.safeOutput:
+            self.write = self._fullwrite
+        else:
+            self.write = self._partialwrite
+        # Force synchro to be sure that all output dirs
+        # have been created.
+        self.comm.barrier()
+        if self.comm.Get_rank() == self.io_rank:
+            self._file = open(self.filename, 'w')
+
+    def doWrite(self, ite):
+        """
+        True if output is required
+        for iteration ite
+        @param ite : current iteration number
+        """
+        rank = self.comm.Get_rank()
+        return rank == self.io_rank and (ite % self.frequency) == 0
+
+    def _fullwrite(self):
+        if self.comm.Get_rank() == self.io_rank:
+            self._file = open(self.filename, 'a')
+            ft.write(self._file, self.buffer)
+            self._file.close()
+
+    def _partialwrite(self):
+        if self.comm.Get_rank() == self.io_rank:
+            ft.write(self._file, self.buffer)
+
+    def finalize(self):
+        if self.comm.Get_rank() == self.io_rank:
+            if not self._file.closed:
+                self._file.close()
diff --git a/HySoP/hysop/tools/numpywrappers.py b/HySoP/hysop/tools/numpywrappers.py
index 11d8011ba74ed46a2fea3d0465e6739b7d8ccca2..333d6527dcca5e41ad1c6889b80f56c3488c7adc 100644
--- a/HySoP/hysop/tools/numpywrappers.py
+++ b/HySoP/hysop/tools/numpywrappers.py
@@ -6,6 +6,7 @@ Tools to build numpy arrays based on parmepy setup (float type ...)
 """
 from parmepy.constants import PARMES_REAL, ORDER, PARMES_INTEGER, PARMES_INDEX
 import numpy as np
+import scitools.filetable as ft
 
 
 def zeros(shape, dtype=PARMES_REAL):
@@ -100,3 +101,11 @@ def prod(tab, dtype=PARMES_REAL):
     """
     return np.prod(tab, dtype=dtype)
 
+
+def writeToFile(fname, data, mode='a'):
+    """
+    write data (numpy array) to file fname
+    """
+    fout = open(fname, mode)
+    ft.write(fout, data)
+    fout.close()
diff --git a/HySoP/hysop/variable_parameter.py b/HySoP/hysop/variable_parameter.py
new file mode 100644
index 0000000000000000000000000000000000000000..3cd0bea10fb771cc6585d87807265dbff3dcce84
--- /dev/null
+++ b/HySoP/hysop/variable_parameter.py
@@ -0,0 +1,75 @@
+#
+# Definition of the adaptative time step (for example) on the 3D domain:
+# \code
+# dt_adapt = Variable(dom3D, name="adaptative_timestep, data=[0.1]")
+# ...
+# \endcode
+#
+#
+"""
+@file variables/variables.py
+
+Tools to define parameters that do not depend on space but may
+be used as input-output parameter during simulation.
+
+Example : the time step.
+
+\code
+data = {'timestep': 0.1 }
+dt = VariableParameter(data)
+
+## An operator that can change dt
+op = Adaptative_timestep(..., dt)
+simu = Simulation(..., dt, ...)
+
+op.apply(simu) ===> change simu.time_step
+
+\endcode
+
+"""
+
+
+class VariableParameter(object):
+    """
+    Class to embed a user-defined parameter (a dictionnary indeed).
+
+    VariableParameter has a member data which is mutable.
+    """
+
+    def __init__(self, data=None, name=None):
+        """
+        Creates a dictionnary with data
+        @param data: the data used as parameter
+        @param name : optional name, used if data is not a dict.
+
+        If data is a dictionnary, self.data = data, that's it.
+        Else data will be added into self.data dict, with name as a key.
+        """
+        ## name of the variable
+        self.name = name
+        ## data values
+        if isinstance(data, dict):
+            self.data = data
+        else:
+            if name is None:
+                msg = "Name arg is required when data is not a dict."
+                raise AttributeError(msg)
+            self.data = {name: data}
+
+    def __getitem__(self, key):
+        """ Access to the content of the data[key]
+        @param key : requested key.
+        @return component 'key' of the dict
+        """
+        return self.data[key]
+
+    def __setitem__(self, key, value):
+        """
+        Set the data[key] = value
+        """
+        self.data[key] = value
+
+    def __str__(self):
+        s = "Variable parameter, which contains: "
+        s += str(self.data)
+        return s
diff --git a/HySoP/hysop/variables/__init__.py b/HySoP/hysop/variables/__init__.py
deleted file mode 100644
index c876f935ed708d186e1e8652c1583183e777da0c..0000000000000000000000000000000000000000
--- a/HySoP/hysop/variables/__init__.py
+++ /dev/null
@@ -1,27 +0,0 @@
-## @package parmepy.variables
-# Tools to build and use numpy arrays of 0_d_variables : all the types are allowed
-# to define a variable (real, integer, boolean ...)
-#
-# To define a variable, one must provide :
-# - the domain on which it is defined
-# and optionnaly:
-# - a user defined initialization of the numpy array containing the 0_d_subvariables
-# - a name
-#
-# First of all, one must have defined a domain :
-# \code
-# from parmepy.domain.box import Box
-# from parmepy.fields.continuous import Field
-#
-# # First, the domain : 3D and 2D boxes
-# dom3D = Box()
-# dom2D = Box(dimension=2, length=[1.0, 1.0], origin=[0., 0.])
-#\endcode
-#
-# Definition of the adaptative time step (for example) on the 3D domain:
-# \code
-# dt_adapt = Variable(dom3D, name="adaptative_timestep, data=[0.1]")
-# ...
-# \endcode
-#
-#
diff --git a/HySoP/hysop/variables/variables.py b/HySoP/hysop/variables/variables.py
deleted file mode 100644
index 5163d63e746cf10b1ddb7f51a0dd3e5b78456497..0000000000000000000000000000000000000000
--- a/HySoP/hysop/variables/variables.py
+++ /dev/null
@@ -1,47 +0,0 @@
-"""
-@file variables/variables.py
-
-0_d_Variables description.
-"""
-from parmepy.constants import debug
-#from parmepy.fields.vector import VectorField
-from parmepy.mpi import main_rank
-from parmepy.constants import np
-
-
-class Variables(object):
-    """
-    0_d variable defined on a physical domain.
-    """
-
-    @debug
-    def __new__(cls, *args, **kw):
-        return object.__new__(cls, *args, **kw)
-
-    @debug
-    def __init__(self, domain, name=None, data=None):
-        """
-        Create a scalar of vector field which dimension is determined
-        by its domain of definition.
-
-        @param domain : physical domain where this field is defined.
-        @param name : name of the variable.
-        @param data : list of data subvalues of the variable.
-
-        """
-        ## Physical domain of definition of the variable.
-        self.domain = domain
-        ## name of the variable
-        if(name is not None):
-            self.name = name
-        else:
-            self.name = 'unamed'
-        ## data values
-        self.data = np.asarray(data)
-
-    def __str__(self):
-        """ Variable info display """
-
-        s = '[' + str(main_rank) + '] " ' + self.name + ' ", '
-        s += ' 0D variable with ' + str(len(self.data)) + 'sub_values '
-        return s
diff --git a/HySoP/setup.py.in b/HySoP/setup.py.in
index eef3c0bc9bea2c24d2afd24ec7e2822029e87a13..3c75c97226a0edb1984fd3a8d8261a6be509fcda 100644
--- a/HySoP/setup.py.in
+++ b/HySoP/setup.py.in
@@ -16,7 +16,6 @@ packages = ['parmepy',
             'parmepy.domain',
             'parmepy.domain.obstacle',
             'parmepy.fields',
-            'parmepy.variables',
             'parmepy.operator',
             'parmepy.operator.discrete',
             'parmepy.operator.monitors',
diff --git a/HySoP/src/CMakeLists.txt b/HySoP/src/CMakeLists.txt
index 88df76a15bd81f3bab2bd5004b17e1dbcaab1dd1..c03b48f1d21157d920cf0b3356bb1ad10bee29a4 100644
--- a/HySoP/src/CMakeLists.txt
+++ b/HySoP/src/CMakeLists.txt
@@ -23,15 +23,18 @@ if(WITH_FFTW)
     )
 endif()
 
+#set(SCALES_DIR scalesReduced)
+set(SCALES_DIR scalesInterface)
+
 # --- scales ---
 if(WITH_SCALES)
   set(${PARMES_LIBRARY_NAME}_SRCDIRS
     ${${PARMES_LIBRARY_NAME}_SRCDIRS}
-    scalesInterface/
-    scalesInterface/layout
-    scalesInterface/particles
-    scalesInterface/particles/advec_line
-    scalesInterface/output
+    ${SCALES_DIR}/
+    ${SCALES_DIR}/layout
+    ${SCALES_DIR}/particles
+    ${SCALES_DIR}/particles/advec_line
+    ${SCALES_DIR}/output
     )
 endif()