diff --git a/phasefield/nphase_nestler.py b/phasefield/nphase_nestler.py
index 7104c1f0edd0065cc243ea33a746711a5b49bf97..c33419a1ea5ec4e89f5d5c59662c282b065c8f16 100644
--- a/phasefield/nphase_nestler.py
+++ b/phasefield/nphase_nestler.py
@@ -8,6 +8,10 @@ from pystencils import create_data_handling, Assignment, create_kernel
 from pystencils.fd import Diff, expand_diff_full, discretize_spatial
 from pystencils.fd.derivation import FiniteDifferenceStencilDerivation
 
+import pyximport
+pyximport.install(language_level=3)
+from lbmpy.phasefield.simplex_projection import simplex_projection_2d  # NOQA
+
 
 def forth_order_isotropic_discretize(field):
     second_neighbor_stencil = [(i, j)
@@ -33,13 +37,11 @@ def forth_order_isotropic_discretize(field):
     return substitutions
 
 
-def create_model(domain_size, num_phases, kappas, epsilon_dict, alpha=1, penalty_factor=0.01):
+def create_model(domain_size, num_phases, coeff_a, coeff_epsilon, gabd, alpha=1, penalty_factor=0.01,
+                 simplex_projection=False):
     def lapl(e):
         return sum(Diff(Diff(e, i), i) for i in range(dh.dim))
 
-    def f(c):
-        return c ** 2 * (1 - c) ** 2
-
     def interfacial_chemical_potential(c):
         result = []
         n = len(c)
@@ -48,11 +50,22 @@ def create_model(domain_size, num_phases, kappas, epsilon_dict, alpha=1, penalty
             for k in range(n):
                 if i == k:
                     continue
-                eps = epsilon_dict[(i, k)] if i < k else epsilon_dict[k, i]
+                eps = coeff_epsilon[(k, i)] if i < k else coeff_epsilon[(i, k)]
                 entry += alpha ** 2 * eps ** 2 * (c[k] * lapl(c[i]) - c[i] * lapl(c[k]))
             result.append(entry)
         return -sp.Matrix(result)
 
+    def bulk(c):
+        result = 0
+        for i in range(num_phases):
+            for j in range(i):
+                result += (c[i] ** 2 * c[j] ** 2) / (4 * coeff_a[i, j])
+        for i in range(num_phases):
+            for j in range(i):
+                for k in range(j):
+                    result += gabd * c[i] * c[j] * c[k]
+        return result
+
     # -------------- Data ------------------
     dh = create_data_handling(domain_size, periodicity=(True, True), default_ghost_layers=2)
 
@@ -78,8 +91,8 @@ def create_model(domain_size, num_phases, kappas, epsilon_dict, alpha=1, penalty
     # ------------- Compute kernels --------
     c_vec = c.center_vector
     f_penalty = penalty_factor * (1 - sum(c_vec[i] for i in range(num_phases))) ** 2
-    f_bulk = sum(kappa_i * f(c_i) for kappa_i, c_i in zip(kappas, c_vec)) + f_penalty
-
+    f_bulk = bulk(c_vec) + f_penalty
+    print(f_bulk)
     mu_eq = chemical_potentials_from_free_energy(f_bulk, order_parameters=c_vec)
     mu_eq += interfacial_chemical_potential(c_vec)
     mu_eq = [expand_diff_full(mu_i, functions=c) for mu_i in mu_eq]
@@ -101,6 +114,7 @@ def create_model(domain_size, num_phases, kappas, epsilon_dict, alpha=1, penalty
         ch_methods.append(ch_method)
         ch_update_rule = create_lb_update_rule(lb_method=ch_method,
                                                kernel_type='collide_only',
+                                               density_input=c(i),
                                                velocity_input=u.center_vector,
                                                compressible=True,
                                                optimization={"symbolic_field": pdf_field[i]})
@@ -133,7 +147,7 @@ def create_model(domain_size, num_phases, kappas, epsilon_dict, alpha=1, penalty
     for i in range(num_phases):
         cqc = ch_methods[i].conserved_quantity_computation
         output_assign = cqc.output_equations_from_pdfs(pdf_field[i].center_vector,
-                                                       {'density': c.center[i]})
+                                                       {'density': c(i)})
         getter_kernel = create_kernel(output_assign).compile()
         getter_kernels.append(getter_kernel)
 
@@ -205,29 +219,8 @@ def create_model(domain_size, num_phases, kappas, epsilon_dict, alpha=1, penalty
                 dh.run_kernel(ch_stream_kernels[i])
                 dh.swap(pdf_field[i].name, pdf_dst_field[i].name)
                 dh.run_kernel(getter_kernels[i])
+            if simplex_projection:
+                simplex_projection_2d(dh.cpu_arrays[c.name])
         return dh.cpu_arrays[c.name][1:-1, 1:-1, :]
 
     return dh, init, run
-
-
-if __name__ == '__main__':
-    from collections import defaultdict
-    num_phases = 3
-    kappas = [0.01] * 3
-    epsilon_dict = defaultdict(lambda: 0.1)
-    alpha = 1
-    dh, init, run = create_model([100, 100], num_phases, kappas,
-                                 epsilon_dict, alpha, penalty_factor=0.01)
-
-    c_arr = dh.cpu_arrays['c']
-    nx, ny = dh.shape
-
-    c_arr[:, :int(0.5 * nx), 0] = 1
-    c_arr[:, int(0.5 * nx):, 1] = 1
-
-    c_arr[int(0.4 * nx):int(0.6 * nx), int(0.4 * ny):int(0.6 * ny), 0] = 0
-    c_arr[int(0.4 * nx):int(0.6 * nx), int(0.4 * ny):int(0.6 * ny), 1] = 0
-    c_arr[int(0.4 * nx):int(0.6 * nx), int(0.4 * ny):int(0.6 * ny), 2] = 1
-    init()
-
-    res = run(1)
diff --git a/phasefield/simplex_projection.pyx b/phasefield/simplex_projection.pyx
new file mode 100644
index 0000000000000000000000000000000000000000..70b49b225c100c89c3407391f573772ef907c8aa
--- /dev/null
+++ b/phasefield/simplex_projection.pyx
@@ -0,0 +1,49 @@
+# Workaround for cython bug
+# see https://stackoverflow.com/questions/8024805/cython-compiled-c-extension-importerror-dynamic-module-does-not-define-init-fu
+WORKAROUND = "Something"
+
+import cython
+
+
+@cython.boundscheck(False)
+@cython.wraparound(False)
+@cython.cdivision(True)
+def simplex_projection_2d(object[double, ndim=3] c):
+    cdef int xs, ys, num_phases, x, y, a, b, local_phases
+    cdef unsigned int handled_mask = 0
+    cdef double threshold = 1e-18
+    cdef double phase_sum
+
+    xs, ys, num_phases = c.shape
+
+    for y in range(ys):
+        for x in range(xs):
+            local_phases = num_phases
+
+            ## Mark zero phases
+            for a in range(num_phases):
+                if  -threshold < c[x, y, a] < threshold:
+                    local_phases -= 1
+                    handled_mask |= (1 << a)
+                    c[x, y, a] = 0
+
+            # Distribute negative phases to others
+            a = 0
+            while a < num_phases:
+                if c[x, y, a] < 0.0:
+                    handled_mask |= (1 << a)
+                    local_phases -= 1
+                    for b in range(num_phases): # distribute to unhandled phases
+                        if handled_mask & (1 << b) == 0:
+                            c[x, y, b] += c[x, y, a] / local_phases
+                    c[x, y, a] = 0.0
+                    a = -1  # restart loop, since other phases might have become negative
+                a += 1
+
+            # Normalize phases
+            phase_sum = 0.0
+            for a in range(num_phases):
+                phase_sum += c[x, y, a]
+
+            for a in range(num_phases):
+                c[x, y, a] /= phase_sum