diff --git a/src/pystencils_autodiff/walberla.py b/src/pystencils_autodiff/walberla.py
new file mode 100644
index 0000000000000000000000000000000000000000..9d272eaf9e7df12a1b4a16d9a8bd734b5bd45d68
--- /dev/null
+++ b/src/pystencils_autodiff/walberla.py
@@ -0,0 +1,183 @@
+#
+# Copyright © 2020 Stephan Seitz <stephan.seitz@fau.de>
+#
+# Distributed under terms of the GPLv3 license.
+
+"""
+
+"""
+
+
+from os.path import dirname, join
+
+import jinja2
+
+from pystencils.data_types import TypedSymbol
+from pystencils_autodiff._file_io import read_template_from_file
+from pystencils_autodiff.framework_integration.astnodes import JinjaCppFile
+
+
+class WalberlaModule(JinjaCppFile):
+    TEMPLATE = read_template_from_file(join(dirname(__file__), 'walberla_main.tmpl.cpp'))
+
+    def __init__(self, main):
+        ast_dict = {'main': main}
+        JinjaCppFile.__init__(self, ast_dict)
+
+
+class WalberlaMain(JinjaCppFile):
+
+    TEMPLATE = jinja2.Template("""
+int main( int argc, char ** argv )
+{
+   using namespace walberla;
+   Environment {{ walberl_env }}( argc, argv );
+
+   {{ body | indent(3) }}
+
+   return EXIT_SUCCESS;
+}
+    """)
+
+    headers = ['"core/Environment.h"',
+               '<cstdlib>',
+               '"UserDefinitions.h"']
+
+    def __init__(self, body, walberl_env="walberlaEnv"):
+
+        ast_dict = {
+            'body': body,
+            'walberl_env': TypedSymbol(walberl_env, "Environment")
+        }
+
+        super().__init__(ast_dict)
+
+    @property
+    def symbols_defined(self):
+        return {self.ast_dict.walberl_env}
+
+
+class BlockForrestCreation(JinjaCppFile):
+    TEMPLATE = jinja2.Template("""auto {{ blocks }} = walberla_user::createBlockForrest(walberlaEnv);""")
+    def __init__(self, block_forrest_name):
+
+        ast_dict = {
+            'blocks': TypedSymbol(block_forrest_name, "auto")
+        }
+
+        super().__init__(ast_dict)
+
+    @property
+    def symbols_defined(self):
+        return {self.ast_dict.blocks}
+
+
+class UniformBlockForrestFromConfig(BlockForrestCreation):
+    TEMPLATE = jinja2.Template(
+        """auto {{ blocks }} = blockforest::createUniformBlockGridFromConfig( walberlaEnv.config() );""")
+    headers = ['"blockforest/Initialization.h"']
+
+    def __init__(self):
+        super().__init__('blocks')
+
+    @property
+    def config_required(self):
+        return {"DomainSetup": {"blocks": [1, 1, 1], "cellsPerBlock": [100, 100, 100]}}
+
+    @property
+    def blocks(self):
+        return self.ast_dict.blocks
+
+
+class DefinitionsHeader(JinjaCppFile):
+    TEMPLATE = read_template_from_file(join(dirname(__file__), 'walberla_user_defintions.tmpl.hpp'))
+
+    def __init__(self, walberla_module):
+        self.main_module = walberla_module
+        super().__init__({})
+
+    @property
+    def config_required(self):
+        return {"DomainSetup": {"blocks": [1, 1, 1], "cellsPerBlock": [100, 100, 100]}}
+
+
+class Using(JinjaCppFile):
+    TEMPLATE = jinja2.Template("using {{ new_type }} = {{ definition }};\n")
+
+    def __init__(self, new_type, definition):
+        ast_dict = {
+            'new_type': new_type,
+            'definition': definition,
+        }
+        super().__init__(ast_dict)
+
+    @property
+    def symbols_defined(self):
+        return {self.ast_dict.new_type}
+
+
+class GetParameter(JinjaCppFile):
+
+    TEMPLATE = jinja2.Template(
+        'walberlaEnv.config()->getOneBlock("{{ block }}").getParameter<{{ key.dtype }}>("{{ key }}"{% if default %}, {{ default }}{% endif %})'  # noqa
+        )
+
+    def __init__(self, block: str, key, default_value=None):
+        ast_dict = {
+            'key': key,
+            'block': block,
+            'default': default_value
+        }
+        super().__init__(ast_dict)
+
+    @property
+    def config_required(self):
+        return {self.ast_dict.block: {self.ast_dict.symbol: self.ast_dict.default_value}}
+
+    def __sympy__(self):
+        return TypedSymbol(self.ast_dict.key.name + "Config", str(self.ast_dict.key.dtype))
+
+
+class FieldAllocation(JinjaCppFile):
+    """
+    .. code:: cpp
+
+        BlockDataID addToStorage(const shared_ptr < BlockStorage_T > & blocks,
+                                  const std:: string & identifier,
+                                  const typename GhostLayerField_T:: value_type & initValue = typename GhostLayerField_T: : value_type(),
+                                  const Layout layout=zyxf,
+                                  const uint_t nrOfGhostLayers=uint_t(1),
+                                  const bool alwaysInitialize=false,
+                                  const std:: function < void (GhostLayerField_T * field, IBlock * const block ) > & initFunction =
+                                     std: : function < void (GhostLayerField_T * field, IBlock * const block ) > (),
+                                  const Set < SUID > & requiredSelectors = Set < SUID > : : emptySet(),
+                                  const Set < SUID > & incompatibleSelectors = Set < SUID > : : emptySet() )
+
+    """  # noqa
+
+    TEMPLATE = jinja2.Template("""BlockDataID {{ field_name }}_data = field::addToStorage<{{ field_type }}>( {{ block_forrest }},
+                              {{ field_name }}
+     {%- if init_value %}      , {{ init_value }} {% endif %}
+     {%- if layout_str %}      , {{ layout_str }} {% endif %}
+     {%- if num_ghost_layers %}, {{ num_ghost_layers }} {% endif %}
+     {%- if always_initialize %}, {{ always_initialize }} {% endif %})
+        """)  # noqa
+
+    def __init__(self, block_forrest, field):
+        self._symbol = TypedSymbol(field.name + '_data', 'BlockDataID')
+        ast_dict = {
+            'block_forrest': block_forrest,
+            'field_name': field.name,
+            'field_type': f'GhostLayerField< {field.dtype}, {field.index_shape[0] if field.index_shape else 1} >'
+        }
+        super().__init__(ast_dict)
+
+    headers = ['"fields/GhostLayerField.h"']
+
+    @property
+    def symbol(self):
+        return self._symbol
+
+    @property
+    def symbols_defined(self):
+        return {self.symbol}
diff --git a/src/pystencils_autodiff/walberla_main.tmpl.cpp b/src/pystencils_autodiff/walberla_main.tmpl.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..83968b619b3c20fcb40e794c4cc0d54c709f4b89
--- /dev/null
+++ b/src/pystencils_autodiff/walberla_main.tmpl.cpp
@@ -0,0 +1,13 @@
+/* 
+ * Automatically generated waLBerla main
+ *
+ */
+
+{% for header in headers -%}
+#include {{ header }}
+{% endfor %}
+{% for global in globals -%}
+{{ global }}
+{% endfor %}
+
+{{ main }}
diff --git a/src/pystencils_autodiff/walberla_user_defintions.tmpl.hpp b/src/pystencils_autodiff/walberla_user_defintions.tmpl.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..dc6d4e5d2f623b60b92a86fb8df4682198152e12
--- /dev/null
+++ b/src/pystencils_autodiff/walberla_user_defintions.tmpl.hpp
@@ -0,0 +1,28 @@
+/*
+ * walberla_user_defintions.tmpl.hpp
+ * Copyright (C) 2020 Stephan Seitz <stephan.seitz@fau.de>
+ *
+ * Distributed under terms of the GPLv3 license.
+ */
+
+#pragma once
+
+#include "lbm/communication/PdfFieldPackInfo.h"
+#include "lbm/field/AddToStorage.h"
+#include "lbm/field/PdfField.h"
+#include "lbm/gui/Connection.h"
+#include "lbm/vtk/VTKOutput.h"
+
+namespace walberla_user {
+using namespace walberla;
+using LatticeModel_T = lbm::LbCodeGenerationExample_LatticeModel;
+using Stencil_T = LatticeModel_T::Stencil;
+using CommunicationStencil_T = LatticeModel_T::CommunicationStencil_T;
+using lPdfField_T = bm::PdfField<LatticeModel_T>;
+using flag_t = walberla::uint8_t;
+using FlagField_T FlagField<flag_t>;
+
+using PdfField_T = lbm::PdfField<LatticeModel_T>;
+typedef VectorField_T = GhostLayerField<real_t, LatticeModel_T::Stencil::D>;
+typedef ScalarField_T GhostLayerField<real_t, 1>;
+} // namespace walberla_user
diff --git a/tests/test_walberla.py b/tests/test_walberla.py
new file mode 100644
index 0000000000000000000000000000000000000000..9147f41495050b4844108e0cab40dea32fd5679b
--- /dev/null
+++ b/tests/test_walberla.py
@@ -0,0 +1,45 @@
+#
+# Copyright © 2020 Stephan Seitz <stephan.seitz@fau.de>
+#
+# Distributed under terms of the GPLv3 license.
+
+"""
+
+"""
+import numpy as np
+import sympy as sp
+
+import pystencils
+from pystencils.astnodes import Block, EmptyLine, SympyAssignment
+from pystencils.data_types import TypedSymbol
+from pystencils_autodiff._file_io import write_file
+from pystencils_autodiff.walberla import (
+    DefinitionsHeader, FieldAllocation, GetParameter, UniformBlockForrestFromConfig,
+    WalberlaMain, WalberlaModule)
+
+
+def test_walberla():
+    x, y = pystencils.fields('x, y:  float32[3d]')
+    foo_symbol = TypedSymbol('foo', np.bool)
+    number_symbol = TypedSymbol('number', np.float32)
+    crazy_plus_one = TypedSymbol('crazy', np.float32)
+
+    block_forrest = UniformBlockForrestFromConfig()
+
+    block = Block([
+        block_forrest,
+        SympyAssignment(foo_symbol, GetParameter('parameters', foo_symbol)),
+        SympyAssignment(number_symbol, GetParameter('parameters', number_symbol, 1.2)),
+        SympyAssignment(crazy_plus_one, number_symbol + 1),
+        EmptyLine(),
+        FieldAllocation(block_forrest.blocks, x)
+    ])
+
+    module = WalberlaModule(WalberlaMain(block))
+    code = str(module)
+    print(code)
+
+    write_file('/localhome/seitz_local/projects/walberla/apps/autogen/main.cpp', code)
+
+    definitions = DefinitionsHeader(module)
+    write_file('/localhome/seitz_local/projects/walberla/apps/autogen/UserDefinitions.h', str(definitions))