diff --git a/hysop/backend/host/python/operator/penalization.py b/hysop/backend/host/python/operator/penalization.py
index 238b8dad33a617e40e918d7af607935c20839a09..fddd21532dec3e3dd81a05ad11092098efe7e6ac 100644
--- a/hysop/backend/host/python/operator/penalization.py
+++ b/hysop/backend/host/python/operator/penalization.py
@@ -244,3 +244,186 @@ class PythonPenalizeVorticity(HostOperator):
         # Y direction
         self.tmp = self.stencil[1](a=self.tmp_v[0], out=self.tmp, axis=0)
         self.W[0][...] += -self.tmp
+
+
+class PythonPenalizeVelocity(HostOperator):
+    """
+
+    """
+    __default_method = {
+        SpaceDiscretization: SpaceDiscretization.FDC4
+    }
+
+    __available_methods = {
+        SpaceDiscretization: (InstanceOf(SpaceDiscretization), InstanceOf(int))
+    }
+
+    @classmethod
+    def default_method(cls):
+        dm = super(PythonPenalizeVelocity, cls).default_method()
+        dm.update(cls.__default_method)
+        return dm
+
+    @classmethod
+    def available_methods(cls):
+        am = super(PythonPenalizeVelocity, cls).available_methods()
+        am.update(cls.__available_methods)
+        return am
+
+    @debug
+    def __init__(self, obstacles, variables,
+                 velocity,
+                 dt, coeff=None, ubar=None, formulation=None, **kwds):
+        check_instance(velocity, Field)
+        check_instance(variables, dict, keys=Field,
+                       values=CartesianTopologyDescriptors)
+        check_instance(dt, ScalarParameter)
+        check_instance(coeff, (ScalarParameter, float, type(lambda x: x)), allow_none=True)
+        check_instance(ubar, TensorParameter, allow_none=True)
+        check_instance(formulation, PenalizationFormulation, allow_none=True)
+        check_instance(obstacles, (tuple, dict), values=Field,
+                       keys=(ScalarParameter, float, type(lambda x: x)), check_kwds=False)
+
+        input_fields = {velocity: variables[velocity], }
+        output_fields = {velocity: variables[velocity]}
+        input_params = {dt.name: dt}
+
+        if isinstance(coeff, ScalarParameter):
+            self.coeff = lambda o: coeff()*o
+        elif isinstance(coeff, type(lambda x: x)):
+            self.coeff = coeff
+        elif not coeff is None:
+            c = ScalarParameter("penal_coeff", initial_value=coeff)
+            self.coeff = lambda o: c()*o
+
+        if isinstance(obstacles, dict):
+            obs = {}
+            for c, o in obstacles.iteritems():
+                if isinstance(c, ScalarParameter):
+                    obs[lambda x: c()*x] = o
+                elif isinstance(c, type(lambda x: x)):
+                    obs[c] = o
+                elif not c is None:
+                    _ = ScalarParameter("penal_coeff", initial_value=c)
+                    obs[lambda x: _()*x] = o
+        else:
+            obs = {}
+            for o in obstacles:
+                obs[self.coeff] = o
+        for o in obs.values():
+            assert o.nb_components == 1
+            input_fields[o] = variables[o]
+        self._ubar = ubar
+        if ubar is None:
+            self._ubar = TensorParameter(
+                name="ubar", shape=(velocity.dim,),
+                quiet=True, dtype=velocity.dtype,
+                initial_value=(0.,)*velocity.dim)
+        if formulation is None or formulation is PenalizationFormulation.IMPLICIT:
+            self._compute_penalization = self._compute_penalization_implicit
+        else:
+            self._compute_penalization = self._compute_penalization_exact
+
+        self.velocity = velocity
+        self.obstacles = obs
+        self.dt = dt
+        super(PythonPenalizeVelocity, self).__init__(
+            input_fields=input_fields, output_fields=output_fields,
+            input_params=input_params, **kwds)
+
+    @debug
+    def handle_method(self, method):
+        super(PythonPenalizeVelocity, self).handle_method(method)
+        self.space_discretization = method.pop(SpaceDiscretization)
+        csg = CenteredStencilGenerator()
+        csg.configure(dtype=MPQ, dim=1)
+        try:
+            self.order = int(str(self.space_discretization)[3:])
+        except:
+            self.order = self.space_discretization
+        self.stencil = tuple(csg.generate_exact_stencil(
+            derivative=1,
+            order=self.order) for _ in range(3))
+
+    @debug
+    def get_field_requirements(self):
+        requirements = super(PythonPenalizeVelocity,
+                             self).get_field_requirements()
+        stencil = self.stencil[0]
+        G = max(max(a, b) for a, b in zip(stencil.L, stencil.R))
+        for is_input, (field, td, req) in requirements.iter_requirements():
+            min_ghosts = (max(g, G) for g in req.min_ghosts.copy())
+            req.min_ghosts = min_ghosts
+            req.axes = (tuple(range(field.dim)), )
+        return requirements
+
+    @debug
+    def discretize(self):
+        if self.discretized:
+            return
+        super(PythonPenalizeVelocity, self).discretize()
+        dim = self.velocity.dim
+        self.dvelocity = self.input_discrete_tensor_fields[self.velocity]
+
+        dv = self.dvelocity
+        stencil = self.stencil[0]
+        G = max(max(a, b) for a, b in zip(stencil.L, stencil.R))
+        view = dv.local_slices(ghosts=(G, )*dim)
+        V = tuple(Vi[view] for Vi in dv.buffers)
+        self.V = V
+        self.dobstacles = {}
+        for c, o in self.obstacles.iteritems():
+            o_df = self.input_discrete_fields[o]
+            self.dobstacles[c] = o_df.data[0][o_df.local_slices(
+                ghosts=(G, )*dim)]
+
+        for s, dx in zip(self.stencil, dv.space_step):
+            s.replace_symbols({s.dx: dx})
+
+        self.v_ghost_exchanger = dv.build_ghost_exchanger()
+
+    @debug
+    def get_work_properties(self):
+        requests = super(PythonPenalizeVelocity, self).get_work_properties()
+        buffers = MemoryRequest.empty_like(
+            a=self.V[0], nb_components=4, backend=self.dvelocity.backend)
+        requests.push_mem_request('Wtmp', buffers)
+        return requests
+
+    def setup(self, work):
+        super(PythonPenalizeVelocity, self).setup(work=work)
+        Wtmp = work.get_buffer(self, 'Wtmp', handle=True)
+        self.tmp_v = Wtmp[0:3]
+        self.tmp = Wtmp[-1]
+
+    @classmethod
+    def supported_dimensions(cls):
+        return (3, 2)
+
+    @classmethod
+    def supports_mpi(cls):
+        return True
+
+    def _compute_penalization_implicit(self):
+        dt = self.dt()
+        self.tmp[...] = 0.
+        for c, o in self.dobstacles.iteritems():
+            self.tmp[...] += (-dt) * c(o) / (1.0 + dt * c(o))
+
+    def _compute_penalization_exact(self):
+        dt = self.dt()
+        self.tmp[...] = 1.
+        for c, o in self.dobstacles.iteritems():
+            self.tmp[...] *= np.exp(-dt*c(o))
+        self.tmp[...] -= 1.
+
+    @op_apply
+    def apply(self, **kwds):
+        super(PythonPenalizeVelocity, self).apply(**kwds)
+        self.v_ghost_exchanger()
+
+        # Penalize velocity
+        self._compute_penalization()
+        for ubar, v, tmp in zip(self._ubar(), self.V, self.tmp_v):
+            tmp[...] = (v - ubar) * self.tmp
+        self.v_ghost_exchanger()
diff --git a/hysop/operator/penalization.py b/hysop/operator/penalization.py
index 94d750e7392f588948447ad1f053fdb54d3541c4..e9304b830198a9eefbc6a073a9beb22684a17e90 100644
--- a/hysop/operator/penalization.py
+++ b/hysop/operator/penalization.py
@@ -15,7 +15,7 @@ from hysop.topology.cartesian_descriptor import CartesianTopologyDescriptors
 from hysop.parameters.scalar_parameter import ScalarParameter
 from hysop.parameters.tensor_parameter import TensorParameter
 from hysop.core.graph.computational_node_frontend import ComputationalGraphNodeFrontend
-from hysop.backend.host.python.operator.penalization import PythonPenalizeVorticity
+from hysop.backend.host.python.operator.penalization import PythonPenalizeVorticity, PythonPenalizeVelocity
 
 
 class PenalizeVorticity(ComputationalGraphNodeFrontend):
@@ -113,3 +113,91 @@ class PenalizeVorticity(ComputationalGraphNodeFrontend):
             variables=variables,
             implementation=implementation,
             **kwds)
+
+
+class PenalizeVelocity(ComputationalGraphNodeFrontend):
+    """
+    Solve
+    \f{eqnarray*}
+    \frac{\partial w}{\partial t} &=& \lambda\chi_s\nabla\times(v_D - v)
+    \f}
+    using penalization.
+    """
+    __implementations = {
+        Implementation.PYTHON: PythonPenalizeVelocity
+    }
+
+    @classmethod
+    def implementations(cls):
+        return cls.__implementations
+
+    @classmethod
+    def default_implementation(cls):
+        return Implementation.PYTHON
+
+    @debug
+    def __init__(self, obstacles, variables,
+                 velocity,
+                 dt, coeff=None, ubar=None, formulation=None,
+                 implementation=None, **kwds):
+        """
+        Parameters
+        ----------
+        obstacles : dict or list of :class:`~hysop.Field`
+            sets of geometries on which penalization must be applied
+        velocity: field
+            input velocity
+        coeff : ScalarParameter, optional
+            penalization factor (\f\lambda\f) applied to all geometries.
+        ubar : TensorParameter, optional
+            Solid velocity (default to 0)
+        formulation: PenalizationFormulation
+            Solving penalization either with IMPLICIT scheme or EXACT solution
+        variables: dict
+            dictionary of fields as keys and topologies as values.
+        dt: ScalarParameter
+            Timestep parameter that will be used for time integration.
+        implementation: Implementation, optional, defaults to None
+            target implementation, should be contained in available_implementations().
+            If None, implementation will be set to default_implementation().
+        kwds:
+            Keywords arguments that will be passed towards implementation
+            poisson operator __init__.
+
+        Set::
+
+        obstacles = {coeff1: obs1, coeff2: obs2, ...}
+        coeff = None
+
+        to apply a different coefficient on each subset.
+        Set::
+
+        obstacles = [obs1, obs2, ...]
+        coeff = some_value
+
+        Warning : coeff as a function is not yet implemented!!
+        """
+        if not isinstance(obstacles, dict):
+            obstacles = to_list(obstacles)
+            assert len(set(obstacles)) == len(obstacles)
+            obstacles = tuple(obstacles)
+
+        check_instance(velocity, Field)
+        check_instance(variables, dict, keys=Field,
+                       values=CartesianTopologyDescriptors)
+        check_instance(dt, ScalarParameter)
+        check_instance(coeff, (ScalarParameter, float, type(lambda x: x)), allow_none=True)
+        check_instance(formulation, PenalizationFormulation, allow_none=True)
+        check_instance(ubar, TensorParameter, allow_none=True)
+        check_instance(obstacles, (tuple, dict), values=Field,
+                       keys=(ScalarParameter, float, type(lambda x: x)), check_kwds=False)
+        super(PenalizeVelocity, self).__init__(
+            velocity=velocity,
+            coeff=coeff,
+            ubar=ubar,
+            obstacles=obstacles,
+            dt=dt,
+            formulation=formulation,
+            variables=variables,
+            implementation=implementation,
+            **kwds)
diff --git a/hysop/operators.py b/hysop/operators.py
index cc7a742dfdad40a815bca512dfd87b50075d31b2..526f0b2a2610dd1a9000e736406168a2d321877b 100644
--- a/hysop/operators.py
+++ b/hysop/operators.py
@@ -9,7 +9,7 @@ from hysop.operator.poisson import Poisson
 from hysop.operator.poisson_curl import PoissonCurl
 from hysop.operator.diffusion import Diffusion  # FFTW diffusion
 from hysop.operator.advection import Advection  # Scales fortran advection
-from hysop.operator.penalization import PenalizeVorticity
+from hysop.operator.penalization import PenalizeVorticity, PenalizeVelocity
 from hysop.operator.flowrate_correction import FlowRateCorrection
 from hysop.operator.vorticity_absorption import VorticityAbsorption
 from hysop.operator.transpose import Transpose