diff --git a/pystencils/backends/cbackend.py b/pystencils/backends/cbackend.py
index bb25a6a4ca9e119886d3b553ab937b188bad1173..94f3477290ecf79fcd8a095389a752d1505d67e2 100644
--- a/pystencils/backends/cbackend.py
+++ b/pystencils/backends/cbackend.py
@@ -6,7 +6,6 @@ import numpy as np
 import sympy as sp
 from sympy.core import S
 from sympy.logic.boolalg import BooleanFalse, BooleanTrue
-from sympy.printing.ccode import C89CodePrinter
 
 from pystencils.astnodes import KernelFunction, Node
 from pystencils.cpu.vectorization import vec_all, vec_any
@@ -330,10 +329,6 @@ class CustomSympyPrinter(CCodePrinter):
     def __init__(self):
         super(CustomSympyPrinter, self).__init__()
         self._float_type = create_type("float32")
-        if 'Min' in self.known_functions:
-            del self.known_functions['Min']
-        if 'Max' in self.known_functions:
-            del self.known_functions['Max']
 
     def _print_Pow(self, expr):
         """Don't use std::pow function, for small integer exponents, write as multiplication"""
@@ -402,6 +397,8 @@ class CustomSympyPrinter(CCodePrinter):
             return f"({self._print(1 / sp.sqrt(expr.args[0]))})"
         elif isinstance(expr, sp.Abs):
             return f"abs({self._print(expr.args[0])})"
+        elif isinstance(expr, sp.Max):
+            return self._print(expr)
         elif isinstance(expr, sp.Mod):
             if expr.args[0].is_integer and expr.args[1].is_integer:
                 return f"({self._print(expr.args[0])} % {self._print(expr.args[1])})"
@@ -476,8 +473,25 @@ class CustomSympyPrinter(CCodePrinter):
     def _print_ConditionalFieldAccess(self, node):
         return self._print(sp.Piecewise((node.outofbounds_value, node.outofbounds_condition), (node.access, True)))
 
-    _print_Max = C89CodePrinter._print_Max
-    _print_Min = C89CodePrinter._print_Min
+    def _print_Max(self, expr):
+        def inner_print_max(args):
+            if len(args) == 1:
+                return self._print(args[0])
+            half = len(args) // 2
+            a = inner_print_max(args[:half])
+            b = inner_print_max(args[half:])
+            return f"(({a} > {b}) ? {a} : {b})"
+        return inner_print_max(expr.args)
+
+    def _print_Min(self, expr):
+        def inner_print_min(args):
+            if len(args) == 1:
+                return self._print(args[0])
+            half = len(args) // 2
+            a = inner_print_min(args[:half])
+            b = inner_print_min(args[half:])
+            return f"(({a} < {b}) ? {a} : {b})"
+        return inner_print_min(expr.args)
 
     def _print_re(self, expr):
         return f"real({self._print(expr.args[0])})"
@@ -575,6 +589,9 @@ class VectorizedCustomSympyPrinter(CustomSympyPrinter):
             result = self.instruction_set['&'].format(result, item)
         return result
 
+    def _print_Max(self, expr):
+        return "test"
+
     def _print_Or(self, expr):
         result = self._scalarFallback('_print_Or', expr)
         if result:
diff --git a/pystencils/fd/finitevolumes.py b/pystencils/fd/finitevolumes.py
index c72ec8d90bf1f6afd1c0ec6df654e740911f577b..d2ddc3c79ebb9ad0bb846d71c19170272b69724d 100644
--- a/pystencils/fd/finitevolumes.py
+++ b/pystencils/fd/finitevolumes.py
@@ -78,6 +78,9 @@ class FVM1stOrder:
         fluxes = [sp.Matrix(fluxes.tolist()[i]) if flux_field.index_dimensions > 1 else fluxes.tolist()[i] 
                   for i in range(self.dim)]
 
+        A0 = sum([sp.Matrix(ps.stencil.direction_string_to_offset(d)).norm()
+                  for d in flux_field.staggered_stencil]) / self.dim
+
         discrete_fluxes = []
         for neighbor in flux_field.staggered_stencil:
             neighbor = ps.stencil.direction_string_to_offset(neighbor)
@@ -85,14 +88,14 @@ class FVM1stOrder:
             for i in range(1, self.dim):
                 directional_flux += fluxes[i] * int(neighbor[i])
             discrete_flux = discretize(directional_flux, neighbor)
-            discrete_fluxes.append(discrete_flux)
+            discrete_fluxes.append(discrete_flux / sp.Matrix(neighbor).norm())
 
         if flux_field.index_dimensions > 1:
-            return [ps.Assignment(lhs, rhs)
+            return [ps.Assignment(lhs, rhs / A0)
                     for i, d in enumerate(flux_field.staggered_stencil) if discrete_fluxes[i]
                     for lhs, rhs in zip(flux_field.staggered_vector_access(d), sp.simplify(discrete_fluxes[i]))]
         else:
-            return [ps.Assignment(flux_field.staggered_access(d), sp.simplify(discrete_fluxes[i]))
+            return [ps.Assignment(flux_field.staggered_access(d), sp.simplify(discrete_fluxes[i]) / A0)
                     for i, d in enumerate(flux_field.staggered_stencil)]
 
     def discrete_source(self):
@@ -184,14 +187,9 @@ class FVM1stOrder:
 
         neighbors = flux_field.staggered_stencil + [ps.stencil.inverse_direction_string(d)
                                                     for d in flux_field.staggered_stencil]
-        divergence = flux_field.staggered_vector_access(neighbors[0]) / \
-            sp.Matrix(ps.stencil.direction_string_to_offset(neighbors[0])).norm()
+        divergence = flux_field.staggered_vector_access(neighbors[0])
         for d in neighbors[1:]:
-            divergence += flux_field.staggered_vector_access(d) / \
-                sp.Matrix(ps.stencil.direction_string_to_offset(d)).norm()
-        A0 = sum([sp.Matrix(ps.stencil.direction_string_to_offset(d)).norm()
-                  for d in flux_field.staggered_stencil]) / self.dim
-        divergence /= A0
+            divergence += flux_field.staggered_vector_access(d)
 
         source = self.discrete_source()
         source = {s.lhs: s.rhs for s in source}
@@ -204,7 +202,8 @@ def VOF(j: ps.field.Field, v: ps.field.Field, ρ: ps.field.Field):
     """Volume-of-fluid discretization of advection
 
     Args:
-        j: the staggeredfield to write the fluxes to
+        j: the staggered field to write the fluxes to. Should have a D2Q9/D3Q27 stencil. Other stencils work too, but
+           incur a small error (D2Q5/D3Q7: v^2, D3Q19: v^3).
         v: the flow velocity field
         ρ: the quantity to advect
     """
@@ -229,7 +228,8 @@ def VOF(j: ps.field.Field, v: ps.field.Field, ρ: ps.field.Field):
         overlap1 = [1 - sp.Abs(v1[i]) for i in range(len(v1))]
         overlap2 = [v1[i] for i in range(len(v1))]
         overlap = sp.Mul(*[(overlap1[i] if c[i] == 0 else overlap2[i]) for i in range(len(v1))])
-        fluxes[d].append(ρ.neighbor_vector(c) * overlap * sp.Piecewise((1, cond), (0, True)))
+        sign = (c == 1).sum() % 2 * 2 - 1
+        fluxes[d].append(sign * ρ.neighbor_vector(c) * overlap * sp.Piecewise((1, cond), (0, True)))
 
     for i, ff in enumerate(fluxes):
         fluxes[i] = ff[0]
diff --git a/pystencils_tests/test_Min_Max.py b/pystencils_tests/test_Min_Max.py
new file mode 100644
index 0000000000000000000000000000000000000000..18cd2d99d10ec0b03a38630d07679f3191281493
--- /dev/null
+++ b/pystencils_tests/test_Min_Max.py
@@ -0,0 +1,70 @@
+import sympy
+import numpy
+import pystencils
+from pystencils.datahandling import create_data_handling
+
+
+def test_max():
+    dh = create_data_handling(domain_size=(10, 10), periodicity=True)
+
+    x = dh.add_array('x', values_per_cell=1)
+    dh.fill("x", 0.0, ghost_layers=True)
+    y = dh.add_array('y', values_per_cell=1)
+    dh.fill("y", 1.0, ghost_layers=True)
+    z = dh.add_array('z', values_per_cell=1)
+    dh.fill("z", 2.0, ghost_layers=True)
+
+    # test sp.Max with one argument
+    assignment_1 = pystencils.Assignment(x.center, sympy.Max(y.center + 3.3))
+    ast_1 = pystencils.create_kernel(assignment_1)
+    kernel_1 = ast_1.compile()
+
+    # test sp.Max with two arguments
+    assignment_2 = pystencils.Assignment(x.center, sympy.Max(0.5, y.center - 1.5))
+    ast_2 = pystencils.create_kernel(assignment_2)
+    kernel_2 = ast_2.compile()
+
+    # test sp.Max with many arguments
+    assignment_3 = pystencils.Assignment(x.center, sympy.Max(z.center, 4.5, y.center - 1.5, y.center + z.center))
+    ast_3 = pystencils.create_kernel(assignment_3)
+    kernel_3 = ast_3.compile()
+
+    dh.run_kernel(kernel_1)
+    assert numpy.all(dh.cpu_arrays["x"] == 4.3)
+    dh.run_kernel(kernel_2)
+    assert numpy.all(dh.cpu_arrays["x"] == 0.5)
+    dh.run_kernel(kernel_3)
+    assert numpy.all(dh.cpu_arrays["x"] == 4.5)
+
+
+def test_min():
+    dh = create_data_handling(domain_size=(10, 10), periodicity=True)
+
+    x = dh.add_array('x', values_per_cell=1)
+    dh.fill("x", 0.0, ghost_layers=True)
+    y = dh.add_array('y', values_per_cell=1)
+    dh.fill("y", 1.0, ghost_layers=True)
+    z = dh.add_array('z', values_per_cell=1)
+    dh.fill("z", 2.0, ghost_layers=True)
+
+    # test sp.Min with one argument
+    assignment_1 = pystencils.Assignment(x.center, sympy.Min(y.center + 3.3))
+    ast_1 = pystencils.create_kernel(assignment_1)
+    kernel_1 = ast_1.compile()
+
+    # test sp.Min with two arguments
+    assignment_2 = pystencils.Assignment(x.center, sympy.Min(0.5, y.center - 1.5))
+    ast_2 = pystencils.create_kernel(assignment_2)
+    kernel_2 = ast_2.compile()
+
+    # test sp.Min with many arguments
+    assignment_3 = pystencils.Assignment(x.center, sympy.Min(z.center, 4.5, y.center - 1.5, y.center + z.center))
+    ast_3 = pystencils.create_kernel(assignment_3)
+    kernel_3 = ast_3.compile()
+
+    dh.run_kernel(kernel_1)
+    assert numpy.all(dh.cpu_arrays["x"] == 4.3)
+    dh.run_kernel(kernel_2)
+    assert numpy.all(dh.cpu_arrays["x"] == - 0.5)
+    dh.run_kernel(kernel_3)
+    assert numpy.all(dh.cpu_arrays["x"] == - 0.5)
diff --git a/pystencils_tests/test_fvm.py b/pystencils_tests/test_fvm.py
index c973448e580eb300f729cf4b550a6ca11ab36c2b..c289ac54e7492cef31d74867847e2aefb2663d67 100644
--- a/pystencils_tests/test_fvm.py
+++ b/pystencils_tests/test_fvm.py
@@ -3,28 +3,24 @@ import pystencils as ps
 import numpy as np
 import pytest
 from itertools import product
+from scipy.optimize import curve_fit
 
 
-@pytest.mark.parametrize("dim", [2, 3])
-def test_advection_diffusion(dim: int):
+def advection_diffusion(dim: int):
     # parameters
     if dim == 2:
-        domain_size = (32, 32)
-        flux_neighbors = 4
+        L = (32, 32)
     elif dim == 3:
-        domain_size = (16, 16, 16)
-        flux_neighbors = 13
+        L = (16, 16, 16)
 
-    dh = ps.create_data_handling(
-        domain_size=domain_size, periodicity=True, default_target='cpu')
+    dh = ps.create_data_handling(domain_size=L, periodicity=True, default_target='cpu')
 
     n_field = dh.add_array('n', values_per_cell=1)
-    j_field = dh.add_array('j', values_per_cell=flux_neighbors,
-                           field_type=ps.FieldType.STAGGERED_FLUX)
+    j_field = dh.add_array('j', values_per_cell=3 ** dim // 2, field_type=ps.FieldType.STAGGERED_FLUX)
     velocity_field = dh.add_array('v', values_per_cell=dim)
 
     D = 0.0666
-    time = 200
+    time = 100
 
     def grad(f):
         return sp.Matrix([ps.fd.diff(f, i) for i in range(dim)])
@@ -42,28 +38,27 @@ def test_advection_diffusion(dim: int):
 
     flux_kernel = ps.create_staggered_kernel(flux).compile()
 
-    pde_kernel = ps.create_kernel(
-        fvm_eq.discrete_continuity(j_field)).compile()
+    pde_kernel = ps.create_kernel(fvm_eq.discrete_continuity(j_field)).compile()
 
     sync_conc = dh.synchronization_function([n_field.name])
 
     # analytical density calculation
-    def density(pos: np.ndarray, time: int):
-        return (4 * np.pi * D * time)**(-1.5) * \
-            np.exp(-np.sum(np.square(pos), axis=dim) / (4 * D * time))
+    def density(pos: np.ndarray, time: int, D: float):
+        return (4 * np.pi * D * time)**(-dim / 2) * \
+            np.exp(-np.sum(np.square(pos), axis=-1) / (4 * D * time))
 
-    pos = np.zeros((*domain_size, dim))
-    xpos = np.arange(-domain_size[0] // 2, domain_size[0] // 2)
-    ypos = np.arange(-domain_size[1] // 2, domain_size[1] // 2)
+    pos = np.zeros((*L, dim))
+    xpos = np.arange(-L[0] // 2, L[0] // 2)
+    ypos = np.arange(-L[1] // 2, L[1] // 2)
 
     if dim == 2:
         pos[..., 1], pos[..., 0] = np.meshgrid(xpos, ypos)
     elif dim == 3:
-        zpos = np.arange(-domain_size[2] // 2, domain_size[2] // 2)
+        zpos = np.arange(-L[2] // 2, L[2] // 2)
         pos[..., 2], pos[..., 1], pos[..., 0] = np.meshgrid(xpos, ypos, zpos)
+    pos += 0.5
 
     def run(velocity: np.ndarray, time: int):
-        print(f"{velocity}, {time}")
         dh.fill(n_field.name, np.nan, ghost_layers=True, inner_ghost_layers=True)
         dh.fill(j_field.name, np.nan, ghost_layers=True, inner_ghost_layers=True)
 
@@ -71,8 +66,12 @@ def test_advection_diffusion(dim: int):
         for i in range(dim):
             dh.fill(velocity_field.name, velocity[i], i, ghost_layers=True, inner_ghost_layers=True)
         dh.fill(n_field.name, 0)
-        dh.fill(n_field.name, 1, slice_obj=ps.make_slice[[
-                dom // 2 for dom in domain_size]])
+        if dim == 2:
+            start = ps.make_slice[L[0] // 2 - 1:L[0] // 2 + 1, L[1] // 2 - 1:L[1] // 2 + 1]
+        else:
+            start = ps.make_slice[L[0] // 2 - 1:L[0] // 2 + 1, L[1] // 2 - 1:L[1] // 2 + 1,
+                                  L[2] // 2 - 1:L[2] // 2 + 1]
+        dh.fill(n_field.name, 2**-dim, slice_obj=start)
 
         sync_conc()
         for i in range(time):
@@ -80,16 +79,152 @@ def test_advection_diffusion(dim: int):
             dh.run_kernel(pde_kernel)
             sync_conc()
 
-        calc_density = density(pos - velocity * time, time)
-
-        np.testing.assert_allclose(dh.gather_array(
-            n_field.name), calc_density, atol=1e-2, rtol=0)
-
-    for vel in product([0, -0.08, 0.08], repeat=dim):
-        run(np.array(vel), time)
+        sim_density = dh.gather_array(n_field.name)
+        
+        # check that mass was conserved
+        assert np.isclose(sim_density.sum(), 1)
+        assert np.all(sim_density > 0)
+        
+        # check that the maximum is in the right place
+        peak = np.unravel_index(np.argmax(sim_density, axis=None), sim_density.shape)
+        assert np.allclose(peak, np.array(L) // 2 - 0.5 + velocity * time, atol=0.5)
+        
+        # check the concentration profile
+        if np.linalg.norm(velocity) == 0:
+            calc_density = density(pos - velocity * time, time, D)
+            target = [time, D]
+        
+            popt, _ = curve_fit(lambda x, t, D: density(x - velocity * time, t, D),
+                                pos.reshape(-1, dim),
+                                sim_density.reshape(-1),
+                                p0=target)
+        
+            assert np.isclose(popt[0], time, rtol=0.1)
+            assert np.isclose(popt[1], D, rtol=0.1)
+            assert np.allclose(calc_density, sim_density, atol=1e-4)
+
+    return lambda v: run(np.array(v), time)
+
+
+advection_diffusion.runners = {}
+
+
+@pytest.mark.parametrize("velocity", list(product([0, -0.047, 0.041], [0, -0.031, 0.023])))
+def test_advection_diffusion_2d(velocity):
+    if 2 not in advection_diffusion.runners:
+        advection_diffusion.runners[2] = advection_diffusion(2)
+    advection_diffusion.runners[2](velocity)
+
+
+@pytest.mark.parametrize("velocity", list(product([0, -0.047, 0.041], [0, -0.031, 0.023], [0, -0.017, 0.011])))
+def test_advection_diffusion_3d(velocity):
+    if 3 not in advection_diffusion.runners:
+        advection_diffusion.runners[3] = advection_diffusion(3)
+    advection_diffusion.runners[3](velocity)
+
+
+def VOF2(j: ps.field.Field, v: ps.field.Field, ρ: ps.field.Field, simplify=True):
+    """Volume-of-fluid discretization of advection
+
+    Args:
+        j: the staggered field to write the fluxes to. Should have a D2Q9/D3Q27 stencil. Other stencils work too, but
+           incur a small error (D2Q5/D3Q7: v^2, D3Q19: v^3).
+        v: the flow velocity field
+        ρ: the quantity to advect
+        simplify: whether to simplify the generated expressions (slow, but makes them much more readable and faster)
+    """
+    dim = j.spatial_dimensions
+    assert ps.FieldType.is_staggered(j)
+    
+    def assume_velocity(e):
+        if not simplify:
+            return e
+        repl = {}
+        for c in e.atoms(sp.StrictGreaterThan, sp.GreaterThan):
+            if isinstance(c.lhs, ps.field.Field.Access) and c.lhs.field == v and isinstance(c.rhs, sp.Number):
+                if c.rhs <= -1:
+                    repl[c] = True
+                elif c.rhs >= 1:
+                    repl[c] = False
+        for c in e.atoms(sp.StrictLessThan, sp.LessThan):
+            if isinstance(c.lhs, ps.field.Field.Access) and c.lhs.field == v and isinstance(c.rhs, sp.Number):
+                if c.rhs >= 1:
+                    repl[c] = True
+                elif c.rhs <= -1:
+                    repl[c] = False
+        for c in e.atoms(sp.Equality):
+            if isinstance(c.lhs, ps.field.Field.Access) and c.lhs.field == v and isinstance(c.rhs, sp.Number):
+                if c.rhs <= -1 or c.rhs >= 1:
+                    repl[c] = False
+        return e.subs(repl)
+    
+    class AABB:
+        def __init__(self, corner0, corner1):
+            self.dim = len(corner0)
+            self.minCorner = sp.zeros(self.dim, 1)
+            self.maxCorner = sp.zeros(self.dim, 1)
+            for i in range(self.dim):
+                self.minCorner[i] = sp.Piecewise((corner0[i], corner0[i] < corner1[i]), (corner1[i], True))
+                self.maxCorner[i] = sp.Piecewise((corner1[i], corner0[i] < corner1[i]), (corner0[i], True))
+
+        def intersect(self, other):
+            minCorner = [sp.Max(self.minCorner[d], other.minCorner[d]) for d in range(self.dim)]
+            maxCorner = [sp.Max(minCorner[d], sp.Min(self.maxCorner[d], other.maxCorner[d]))
+                         for d in range(self.dim)]
+            return AABB(minCorner, maxCorner)
+
+        @property
+        def volume(self):
+            v = sp.prod([self.maxCorner[d] - self.minCorner[d] for d in range(self.dim)])
+            if simplify:
+                return sp.simplify(assume_velocity(v.rewrite(sp.Piecewise)))
+            else:
+                return v
+    
+    fluxes = []
+    cell = AABB([-0.5] * dim, [0.5] * dim)
+    cell_s = AABB(sp.Matrix([-0.5] * dim) + v.center_vector, sp.Matrix([0.5] * dim) + v.center_vector)
+    for d, neighbor in enumerate(j.staggered_stencil):
+        c = sp.Matrix(ps.stencil.direction_string_to_offset(neighbor)[:dim])
+        cell_n = AABB(sp.Matrix([-0.5] * dim) + c, sp.Matrix([0.5] * dim) + c)
+        cell_ns = AABB(sp.Matrix([-0.5] * dim) + c + v.neighbor_vector(neighbor),
+                       sp.Matrix([0.5] * dim) + c + v.neighbor_vector(neighbor))
+        fluxes.append(assume_velocity(ρ.center_vector * cell_s.intersect(cell_n).volume
+                                      - ρ.neighbor_vector(neighbor) * cell_ns.intersect(cell).volume))
+    
+    assignments = []
+    for i, d in enumerate(j.staggered_stencil):
+        for lhs, rhs in zip(j.staggered_vector_access(d).values(), fluxes[i].values()):
+            assignments.append(ps.Assignment(lhs, rhs))
+    return assignments
 
 
-def test_ek():
+@pytest.mark.parametrize("dim", [2, 3])
+def test_advection(dim):
+    L = (8,) * dim
+    dh = ps.create_data_handling(L, periodicity=True, default_target='cpu')
+    c = dh.add_array('c', values_per_cell=1)
+    j = dh.add_array('j', values_per_cell=3 ** dh.dim // 2, field_type=ps.FieldType.STAGGERED_FLUX)
+    u = dh.add_array('u', values_per_cell=dh.dim)
+    
+    dh.cpu_arrays[c.name][:] = (np.random.random([l + 2 for l in L]))
+    dh.cpu_arrays[u.name][:] = (np.random.random([l + 2 for l in L] + [dim]) - 0.5) / 5
+    
+    vof1 = ps.create_kernel(ps.fd.VOF(j, u, c)).compile()
+    dh.fill(j.name, np.nan, ghost_layers=True)
+    dh.run_kernel(vof1)
+    j1 = dh.gather_array(j.name).copy()
+    
+    vof2 = ps.create_kernel(VOF2(j, u, c, simplify=False)).compile()
+    dh.fill(j.name, np.nan, ghost_layers=True)
+    dh.run_kernel(vof2)
+    j2 = dh.gather_array(j.name)
+    
+    assert np.allclose(j1, j2)
+
+
+@pytest.mark.parametrize("stencil", ["D2Q5", "D2Q9"])
+def test_ek(stencil):
 
     # parameters
 
@@ -101,8 +236,7 @@ def test_ek():
 
     dh = ps.create_data_handling(L, periodicity=True, default_target='cpu')
     c = dh.add_array('c', values_per_cell=1)
-    v = dh.add_array('v', values_per_cell=dh.dim)
-    j = dh.add_array('j', values_per_cell=dh.dim * 2, field_type=ps.FieldType.STAGGERED_FLUX)
+    j = dh.add_array('j', values_per_cell=int(stencil[-1]) // 2, field_type=ps.FieldType.STAGGERED_FLUX)
     Phi = dh.add_array('Φ', values_per_cell=1)
 
     # perform automatic discretization
@@ -114,27 +248,28 @@ def test_ek():
 
     disc = ps.fd.FVM1stOrder(c, flux_eq)
     flux_assignments = disc.discrete_flux(j)
-    advection_assignments = ps.fd.VOF(j, v, c)
     continuity_assignments = disc.discrete_continuity(j)
 
     # manual discretization
 
     x_staggered = - c[-1, 0] + c[0, 0] + z * (c[-1, 0] + c[0, 0]) / 2 * (Phi[-1, 0] - Phi[0, 0])
     y_staggered = - c[0, -1] + c[0, 0] + z * (c[0, -1] + c[0, 0]) / 2 * (Phi[0, -1] - Phi[0, 0])
-    xy_staggered = - c[-1, -1] + c[0, 0] + z * (c[-1, -1] + c[0, 0]) / 2 * (Phi[-1, -1] - Phi[0, 0])
-    xY_staggered = - c[-1, 1] + c[0, 0] + z * (c[-1, 1] + c[0, 0]) / 2 * (Phi[-1, 1] - Phi[0, 0])
+    xy_staggered = (- c[-1, -1] + c[0, 0]) / sp.sqrt(2) + \
+        z * (c[-1, -1] + c[0, 0]) / 2 * (Phi[-1, -1] - Phi[0, 0]) / sp.sqrt(2)
+    xY_staggered = (- c[-1, 1] + c[0, 0]) / sp.sqrt(2) + \
+        z * (c[-1, 1] + c[0, 0]) / 2 * (Phi[-1, 1] - Phi[0, 0]) / sp.sqrt(2)
+    A0 = (1 + sp.sqrt(2) if j.index_shape[0] == 4 else 1)
 
     jj = j.staggered_access
-    divergence = -1 / (1 + sp.sqrt(2) if j.index_shape[0] == 4 else 1) * \
-        sum([jj(d) / sp.Matrix(ps.stencil.direction_string_to_offset(d)).norm() for d in j.staggered_stencil
-            + [ps.stencil.inverse_direction_string(d) for d in j.staggered_stencil]])
+    divergence = -1 * sum([jj(d) for d in j.staggered_stencil
+                          + [ps.stencil.inverse_direction_string(d) for d in j.staggered_stencil]])
 
     update = [ps.Assignment(c.center, c.center + divergence)]
-    flux = [ps.Assignment(j.staggered_access("W"), D * x_staggered),
-            ps.Assignment(j.staggered_access("S"), D * y_staggered)]
+    flux = [ps.Assignment(j.staggered_access("W"), D * x_staggered / A0),
+            ps.Assignment(j.staggered_access("S"), D * y_staggered / A0)]
     if j.index_shape[0] == 4:
-        flux += [ps.Assignment(j.staggered_access("SW"), D * xy_staggered),
-                 ps.Assignment(j.staggered_access("NW"), D * xY_staggered)]
+        flux += [ps.Assignment(j.staggered_access("SW"), D * xy_staggered / A0),
+                 ps.Assignment(j.staggered_access("NW"), D * xY_staggered / A0)]
 
     # compare