diff --git a/python/dune/codegen/options.py b/python/dune/codegen/options.py
index eb9d73aef388124ab61ad75faa0aa15f1252d3fb..9a29c5701523c62d7e68ea4c2b9faaa403966caa 100644
--- a/python/dune/codegen/options.py
+++ b/python/dune/codegen/options.py
@@ -3,132 +3,58 @@
 from argparse import ArgumentParser
 from os.path import abspath
 from pytools import ImmutableRecord, memoize
+import cerberus
+import yaml
+import pkg_resources
+from six.moves import configparser
+from six import StringIO
 from contextlib import contextmanager
 
-from dune.testtools.parametertree.parser import parse_ini_file
 
+class CodegenOptionsValidator(cerberus.Validator):
+    # A validator that accepts the helpstr field in the scheme
+    def _validate_helpstr(self, helpstr, field, value):
+        """ Describe the option
 
-class CodegenOption(ImmutableRecord):
-    """ Data structure representing a single formcompiler option """
-    def __init__(self,
-                 default=None,
-                 helpstr="Undocumented feature!",
-                 process=lambda x: x,
-                 _type=type(None),
-                 ):
-        _type = type(default)
-        if issubclass(_type, type(None)):
-            _type = str
-        ImmutableRecord.__init__(self,
-                                 helpstr=helpstr,
-                                 default=default,
-                                 type=_type,
-                                 )
+        The rule's arguments are validated against this schema:
+        {'type': 'string'}
+        """
+        return True
+
+
+def _load_scheme(form=False):
+    resource_package = __name__
+    if form:
+        resource_path = 'options_form.yaml'
+    else:
+        resource_path = 'options_global.yaml'
+    yaml_stream = pkg_resources.resource_string(resource_package, resource_path)
+    try:
+        scheme = yaml.safe_load(yaml_stream)
+    except Exception as e:
+        raise e
+    return scheme
 
 
 class CodegenGlobalOptionsArray(ImmutableRecord):
     """ A collection of form compiler arguments """
     def __init__(self, **kwargs):
-        opts = {k: v.default for k, v in CodegenGlobalOptionsArray.__dict__.items() if isinstance(v, CodegenOption)}
+        # Set the default values from the yaml scheme as defaults
+        scheme = _load_scheme()
+        opts = {k: v['default'] for k, v in scheme.items()}
         opts.update(**kwargs)
         ImmutableRecord.__init__(self, **opts)
 
-    # Arguments that are to be set from the outside
-    uflfile = CodegenOption(helpstr="the UFL file to compile")
-    debug_cache_with_stack = CodegenOption(default=False, helpstr="Store stack along with cache objects. Makes debugging caching issues easier.")
-    driver_file = CodegenOption(helpstr="The filename for the generated driver header")
-    explicit_time_stepping = CodegenOption(default=False, helpstr="use explicit time stepping")
-    time_stepping_order = CodegenOption(default=1, helpstr="Order of the time stepping method")
-    exact_solution_expression = CodegenOption(helpstr="name of the exact solution expression in the ufl file")
-    compare_l2errorsquared = CodegenOption(helpstr="maximal allowed l2 error squared of difference between numerical solution and interpolation of exact solution (NOTE: requires --exact-solution-expression)")
-    grid_info = CodegenOption(default=None, helpstr="Path to file with information about facedir and facemod variations. This can be used to limit the generation of skeleton kernels.")
-    l2error_tree_path = CodegenOption(default=None, helpstr="Tree pathes that should be considered for l2 error calculation. Default None means we take all of them into account.")
-    ini_file = CodegenOption(helpstr="An inifile to use. A generated driver will be hard-coded to it, a [formcompiler] section will be used as default values to form compiler arguments (use snake case)")
-    opcounter = CodegenOption(default=False, helpstr="Count operations. Note: In this case only operator applications are generated since solving and operator counting does not work. You probably want to set instrumentation level>0.")
-    performance_measuring = CodegenOption(default=False, helpstr="Generate opcounter codepath, but only measure times!")
-    instrumentation_level = CodegenOption(default=0, helpstr="Control time/opcounter measurements. 0-do nothing, 1-measure program as a whole, 2-operator applications, 3-measure kernel (eg. alpha-volume, ...), 4-parts of kernel (eg. stage 1-3 of SF)")
-    project_basedir = CodegenOption(helpstr="The base (build) directory of the dune-codegen project")
-    architecture = CodegenOption(default="haswell", helpstr="The architecture to optimize for. Possible values: haswell|knl|skylake")
-    yaspgrid_offset = CodegenOption(default=False, helpstr="Set to true if you want a yasp grid where the lower left corner is not in the origin.")
-    grid_unstructured = CodegenOption(default=False, helpstr="Set to true if you want to use an unstructured grid.")
-    grid_consistent = CodegenOption(default=False, helpstr="The used grid is already consistent.")
-    precision_bits = CodegenOption(default=64, helpstr="The number of bits for the floating point type")
-    overlapping = CodegenOption(default=False, helpstr="Use an overlapping solver and constraints. You still need to make sure to construct a grid with overlap! The parallel option will be set automatically.")
-    operators = CodegenOption(default="r", helpstr="A comma separated list of operators, each name will be interpreted as a subsection name within the formcompiler section")
-    target_name = CodegenOption(default=None, helpstr="The target name from CMake")
-    operator_to_build = CodegenOption(default=None, helpstr="The operators from the list that is about to be build now. CMake sets this one!!!")
-    debug_interpolate_input = CodegenOption(default=False, helpstr="Should the input for printresidual and printmatix be interpolated (instead of random input).")
-    use_likwid = CodegenOption(default=False, helpstr="Use likwid instead of own performance measurements.")
-    use_sde = CodegenOption(default=False, helpstr="Use sde instead of own performance measurements.")
-    autotune_google_benchmark = CodegenOption(default=False, helpstr="Use google-benchmark library for autotuning (when autotuning is activated).")
-    with_mpi = CodegenOption(default=True, helpstr="The module was configured with mpi")
-    permuting_horizontal_add = CodegenOption(default=True, helpstr="Whether SIMD horizontal_add should use a permuting implementation.")
-
-    # Arguments that are mainly to be set by logic depending on other options
-    max_vector_width = CodegenOption(default=256, helpstr=None)
-    parallel = CodegenOption(default=False, helpstr="Mark that this program should be run in parallel. If set to true the c++ code will check that there are more than 1 MPI-ranks involved and the error computation will use communication.")
-
 
 class CodegenFormOptionsArray(ImmutableRecord):
     """ A collection of form-specific form compiler arguments """
     def __init__(self, **kwargs):
-        opts = {k: v.default for k, v in CodegenFormOptionsArray.__dict__.items() if isinstance(v, CodegenOption)}
+        # Set the default values from the yaml scheme as defaults
+        scheme = _load_scheme(form=True)
+        opts = {k: v['default'] for k, v in scheme.items()}
         opts.update(**kwargs)
         ImmutableRecord.__init__(self, **opts)
 
-    # Form specific options
-    form = CodegenOption(default=None, helpstr="The name of the UFL object representing the form in the UFL file")
-    filename = CodegenOption(default=None, helpstr="The filename to use for this LocalOperator")
-    classname = CodegenOption(default=None, helpstr="The name of the C++ class to generate")
-    numerical_jacobian = CodegenOption(default=False, helpstr="use numerical jacobians (only makes sense, if uflpdelab for some reason fails to generate analytic jacobians)")
-    matrix_free = CodegenOption(default=False, helpstr="Generate jacobian_apply_* methods for matrix free solvers")
-    print_transformations = CodegenOption(default=False, helpstr="print out dot files after ufl tree transformations")
-    print_transformations_dir = CodegenOption(default=".", helpstr="place where to put dot files (can be omitted)")
-    quadrature_order = CodegenOption(_type=int, helpstr="Quadrature order used for all integrals.")
-    diagonal_transformation_matrix = CodegenOption(default=False, helpstr="set option if the jacobian of the transformation is diagonal (axiparallel grids)")
-    constant_transformation_matrix = CodegenOption(default=False, helpstr="set option if the jacobian of the transformation is constant on a cell")
-    fastdg = CodegenOption(default=False, helpstr="Use FastDGGridOperator from PDELab.")
-    sumfact = CodegenOption(default=False, helpstr="Use sumfactorization")
-    sumfact_regular_jacobians = CodegenOption(default=False, helpstr="Generate non sum-factorized jacobians (only useful if sumfact is set)")
-    sumfact_on_boundary = CodegenOption(default=True, helpstr="Whether boundary integrals should be vectorized. It might not be worth the hassle...")
-    sumfact_optimize_loop_order = CodegenOption(default=False, helpstr="Optimize order of loops in sumf factorization function using autotuning.")
-    sumfact_performance_transformations = CodegenOption(default=False, helpstr="Apply sum factorization specific performance transformations.")
-    sumfact_performance_transformations_testrun = CodegenOption(default=0, helpstr="If larger than zero determines test case to run.")
-    vectorization_quadloop = CodegenOption(default=False, helpstr="whether to generate code with explicit vectorization")
-    vectorization_strategy = CodegenOption(default="none", helpstr="The identifier of the vectorization cost model. Possible values: none|explicit|model|target|autotune")
-    vectorization_not_fully_vectorized_error = CodegenOption(default=False, helpstr="throw an error if nonquadloop vectorization did not fully vectorize")
-    vectorization_horizontal = CodegenOption(default=None, helpstr="an explicit value for horizontal vectorization read by the 'explicit' strategy")
-    vectorization_vertical = CodegenOption(default=None, helpstr="an explicit value for vertical vectorization read by the 'explicit' strategy")
-    vectorization_padding = CodegenOption(default=None, helpstr="an explicit value for the allowed padding in vectorization")
-    vectorization_allow_quadrature_changes = CodegenOption(default=False, helpstr="whether the vectorization strategy is allowed to alter quadrature point numbers")
-    vectorization_list_index = CodegenOption(default=None, helpstr="Which vectorization to pick from a list (only valid with vectorization_strategy=fromlist).")
-    vectorization_jacobians = CodegenOption(default=True, helpstr="Whether to attempt to vectorize jacobians (takes time, often not needed)")
-    vectorization_target = CodegenOption(_type=float, helpstr="The cost function target for the 'target' cost model. Only needed to verify the cost model itself, do not use light-heartedly!!!")
-    simplify = CodegenOption(default=False, helpstr="Whether to simplify expressions using sympy")
-    generate_jacobians = CodegenOption(default=True, helpstr="Whether jacobian_* methods should be generated. This is set to false automatically, when numerical_jacobian is set to true.")
-    generate_jacobian_apply = CodegenOption(default=False, helpstr="Wether jacobian_allpy_* methods should be generated.")
-    generate_residuals = CodegenOption(default=True, helpstr="Whether alpha_* methods should be generated.")
-    unroll_dimension_loops = CodegenOption(default=False, helpstr="whether loops over the geometric dimension should be unrolled")
-    blockstructured = CodegenOption(default=False, helpstr="Use block structure")
-    number_of_blocks = CodegenOption(default=1, helpstr="Number of sub blocks in one direction")
-    vectorization_blockstructured = CodegenOption(default=False, helpstr="Vectorize block structuring")
-    vectorization_blockstructured_tail = CodegenOption(default=True, helpstr="Try to fully vectorize block structuring even when 'nunmber_of_blocks' is not divisible by vector length")
-    vectorization_blockstructured_tail_ordering = CodegenOption(default='consecutive', helpstr="Ordering of the tail w.r.t the vectorized loop. Possible values: consecutive|blocked")
-    adjoint = CodegenOption(default=False, helpstr="Generate adjoint operator")
-    control = CodegenOption(default=False, helpstr="Generate operator of derivative w.r.t. the control variable")
-    objective_function = CodegenOption(default=None, helpstr="Name of form representing the objective function in UFL file")
-    control_variable = CodegenOption(default=None, helpstr="Name of control variable in UFL file")
-    block_preconditioner_diagonal = CodegenOption(default=False, helpstr="Whether this operator should implement the diagonal part of a block preconditioner")
-    block_preconditioner_offdiagonal = CodegenOption(default=False, helpstr="Whether this operator should implement the off-diagonal part of a block preconditioner")
-    block_preconditioner_pointdiagonal = CodegenOption(default=False, helpstr="Whether this operator should implement the point diagonal part of a block preconditioner")
-    geometry_mixins = CodegenOption(default="generic", helpstr="A comma separated list of mixin identifiers to use for geometries. Currently implemented mixins: generic, axiparallel, equidistant, sumfact_multilinear, sumfact_axiparallel, sumfact_equidistant")
-    quadrature_mixins = CodegenOption(default="generic", helpstr="A comma separated list of mixin identifiers to use for quadrature. Currently implemented: generic, sumfact")
-    basis_mixins = CodegenOption(default="generic", helpstr="A comma separated list of mixin identifiers to use for basis function evaluation. Currently implemented: generic, sumfact")
-    accumulation_mixins = CodegenOption(default="generic", helpstr="A comma separated list of mixin identifiers to use for accumulation. Currently implemented: generic, sumfact, control, blockstructured")
-    enable_volume = CodegenOption(default=True, helpstr="Whether to assemble volume integrals")
-    enable_skeleton = CodegenOption(default=True, helpstr="Whether to assemble skeleton integrals")
-    enable_boundary = CodegenOption(default=True, helpstr="Whether to assemble boundary integrals")
-
 
 # Until more sophisticated logic is needed, we keep the actual option data in this module
 _global_options = CodegenGlobalOptionsArray()
@@ -136,17 +62,17 @@ _form_options = {}
 
 
 def show_options():
-    def subopt(arr):
-        for k, v in arr.__dict__.items():
-            if isinstance(v, CodegenOption) and v.helpstr is not None:
-                print("{}\n    {}".format(k, v.helpstr))
+    def print_options(form=False):
+        scheme = _load_scheme(form=form)
+        for k, v in scheme.items():
+            print("{}\n    {}".format(k, v['helpstr']))
 
     print("This is a summary of options available for the code generation process:\n")
     print("The following options can be given in the [formcompiler] section:")
-    subopt(CodegenGlobalOptionsArray)
+    print_options(form=False)
 
     print("\nThefollowing options can be given in a form-specific subsection of [formcompiler]:")
-    subopt(CodegenFormOptionsArray)
+    print_options(form=True)
 
 
 def initialize_options():
@@ -155,6 +81,38 @@ def initialize_options():
     _global_options = update_options_from_commandline(_global_options)
     _global_options = update_options_from_inifile(_global_options)
 
+    # Validate global options
+    scheme_global = _load_scheme()
+    validator_global = CodegenOptionsValidator(scheme_global, require_all=True)
+    if not validator_global.validate(_global_options.__dict__):
+        raise RuntimeError("Global options validation failed: {}".format(validator_global.errors))
+
+    # Validate form options
+    scheme_form = _load_scheme(form=True)
+    validator_form = CodegenOptionsValidator(scheme_form, require_all=True)
+    for form in [i.strip() for i in _global_options.operators.split(",")]:
+        if not validator_form.validate(_form_options[form].__dict__):
+            raise RuntimeError("Form options validation failed: {}".format(validator_form.errors))
+
+
+def _scheme_type_to_type(scheme_type):
+    assert isinstance(scheme_type, str)
+    if scheme_type == 'string':
+        return str
+    if scheme_type == 'boolean':
+        return bool
+    if scheme_type == 'integer':
+        return int
+    if scheme_type == 'float':
+        return float
+
+
+def _transform_type(scheme_type, a):
+    if scheme_type == 'boolean':
+        return bool(int(a))
+    else:
+        return _scheme_type_to_type(scheme_type)(a)
+
 
 def update_options_from_commandline(opt):
     """ Return an options array object with updated values from the commandline """
@@ -163,10 +121,15 @@ def update_options_from_commandline(opt):
                             epilog="Please report bugs to dominic.kempf@iwr.uni-heidelberg.de",
                             )
     parser.add_argument('--version', action='version', version='%(prog)s 0.1')
-    for k, v in type(opt).__dict__.items():
-        if isinstance(v, CodegenOption) and v.helpstr is not None:
+
+    # Load global options scheme
+    scheme = _load_scheme()
+
+    # Add all options that have a helpstr to the command line parser
+    for k, v in scheme.items():
+        if v['helpstr'] is not None:
             cmdopt = "--{}".format(k.replace('_', '-'))
-            parser.add_argument(cmdopt, help=v.helpstr, type=v.type)
+            parser.add_argument(cmdopt, help=v['helpstr'], type=_scheme_type_to_type(v['type']))
     parsedargs = {k: v for k, v in vars(parser.parse_args()).items() if v is not None}
     return opt.copy(**parsedargs)
 
@@ -174,20 +137,38 @@ def update_options_from_commandline(opt):
 def update_options_from_inifile(opt):
     """ Return an options array object with updated values from an inifile """
     if opt.ini_file:
-        def parse_ini(section, opttype):
-            def _fix_types(k, v):
-                if hasattr(opttype, k) and getattr(opttype, k).type is bool:
-                    return bool(eval(v))
-                if hasattr(opttype, k):
-                    return getattr(opttype, k).type(v)
-                return v
-            ini = parse_ini_file(opt.ini_file).get(section, {})
-            return {k: _fix_types(k, v) for k, v in ini.items()}
-
-        opt = opt.copy(**parse_ini("formcompiler", CodegenGlobalOptionsArray))
-        # Also parse form-specific options
+        config = configparser.ConfigParser()
+
+        # Read ini file
+        try:
+            config.read(opt.ini_file)
+        except configparser.MissingSectionHeaderError:
+            # Config parser doesn't like ini files where without section. For
+            # this case we introduce a [root] section on top.
+            ini_str = '[root]\n' + open(opt.ini_file, 'r').read()
+            ini_fp = StringIO(ini_str)
+            config = configparser.RawConfigParser()
+            config.readfp(ini_fp)
+
+        # Parse global options
+        scheme = _load_scheme()
+        options = dict(config.items('formcompiler'))
+        for k, v in options.items():
+            assert k in scheme
+            options[k] = _transform_type(scheme[k]['type'], v)
+        opt = opt.copy(**options)
+
+        # Parse form options
+        scheme = _load_scheme(form=True)
         for form in [i.strip() for i in opt.operators.split(",")]:
-            _form_options[form] = CodegenFormOptionsArray(**parse_ini("formcompiler.{}".format(form), CodegenFormOptionsArray))
+            section = 'formcompiler.{}'.format(form)
+            options = {}
+            if config.has_section(section):
+                options = dict(config.items('formcompiler.{}'.format(form)))
+                for k, v in options.items():
+                    assert k in scheme
+                    options[k] = _transform_type(scheme[k]['type'], v)
+            _form_options[form] = CodegenFormOptionsArray(**options)
 
     return opt
 
diff --git a/python/dune/codegen/options_form.yaml b/python/dune/codegen/options_form.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..97c0a733a327718009d25eaa32486747d21cfaa4
--- /dev/null
+++ b/python/dune/codegen/options_form.yaml
@@ -0,0 +1,215 @@
+accumulation_mixins:
+    type: string
+    default: "generic"
+    helpstr: "A comma separated list of mixin identifiers to use for accumulation. Currently implemented: generic, sumfact, control, blockstructured"
+adjoint:
+    type: boolean
+    default: False
+    helpstr: "Generate adjoint operator"
+basis_mixins:
+    type: string
+    default: "generic"
+    helpstr: "A comma separated list of mixin identifiers to use for basis function evaluation. Currently implemented: generic, sumfact"
+block_preconditioner_diagonal:
+    type: boolean
+    default: False
+    helpstr: "Whether this operator should implement the diagonal part of a block preconditioner"
+block_preconditioner_offdiagonal:
+    type: boolean
+    default: False
+    helpstr: "Whether this operator should implement the off-diagonal part of a block preconditioner"
+block_preconditioner_pointdiagonal:
+    type: boolean
+    default: False
+    helpstr: "Whether this operator should implement the point diagonal part of a block preconditioner"
+blockstructured:
+    type: boolean
+    default: False
+    helpstr: "Use block structure"
+classname:
+    type: string
+    default:
+    nullable: True
+    helpstr: "The name of the C++ class to generate"
+constant_transformation_matrix:
+    type: boolean
+    default: False
+    helpstr: "set option if the jacobian of the transformation is constant on a cell"
+control:
+    type: boolean
+    default: False
+    helpstr: "Generate operator of derivative w.r.t. the control variable"
+control_variable:
+    type: string
+    default:
+    nullable: True
+    helpstr: "Name of control variable in UFL file"
+diagonal_transformation_matrix:
+    type: boolean
+    default: False
+    helpstr: "set option if the jacobian of the transformation is diagonal (axiparallel grids)"
+enable_boundary:
+    type: boolean
+    default: True
+    helpstr: "Whether to assemble boundary integrals"
+enable_skeleton:
+    type: boolean
+    default: True
+    helpstr: "Whether to assemble skeleton integrals"
+enable_volume:
+    type: boolean
+    default: True
+    helpstr: "Whether to assemble volume integrals"
+fastdg:
+    type: boolean
+    default: False
+    helpstr: "Use FastDGGridOperator from PDELab."
+filename:
+    type: string
+    default:
+    nullable: True
+    helpstr: "The filename to use for this LocalOperator"
+form:
+    type: string
+    default:
+    nullable: True
+    helpstr: "The name of the UFL object representing the form in the UFL file"
+generate_jacobian_apply:
+    type: boolean
+    default: False
+    helpstr: "Wether jacobian_allpy_* methods should be generated."
+generate_jacobians:
+    type: boolean
+    default: True
+    helpstr: "Whether jacobian_* methods should be generated. This is set to false automatically, when numerical_jacobian is set to true."
+generate_residuals:
+    type: boolean
+    default: True
+    helpstr: "Whether alpha_* methods should be generated."
+geometry_mixins:
+    type: string
+    default: "generic"
+    helpstr: "A comma separated list of mixin identifiers to use for geometries. Currently implemented mixins: generic, axiparallel, equidistant, sumfact_multilinear, sumfact_axiparallel, sumfact_equidistant"
+matrix_free:
+    type: boolean
+    default: False
+    helpstr: "Generate jacobian_apply_* methods for matrix free solvers"
+number_of_blocks:
+    type: integer
+    default: 1
+    helpstr: "Number of sub blocks in one direction"
+numerical_jacobian:
+    type: boolean
+    default: False
+    helpstr: "use numerical jacobians (only makes sense, if uflpdelab for some reason fails to generate analytic jacobians)"
+objective_function:
+    type: string
+    default:
+    nullable: True
+    helpstr: "Name of form representing the objective function in UFL file"
+print_transformations:
+    type: boolean
+    default: False
+    helpstr: "print out dot files after ufl tree transformations"
+print_transformations_dir:
+    type: string
+    default: "."
+    helpstr: "place where to put dot files (can be omitted)"
+quadrature_mixins:
+    type: string
+    default: "generic"
+    helpstr: "A comma separated list of mixin identifiers to use for quadrature. Currently implemented: generic, sumfact"
+quadrature_order:
+    type: string
+    default:
+    nullable: True
+    helpstr: "Quadrature order used for all integrals."
+simplify:
+    type: boolean
+    default: False
+    helpstr: "Whether to simplify expressions using sympy"
+sumfact:
+    type: boolean
+    default: False
+    helpstr: "Use sumfactorization"
+sumfact_on_boundary:
+    type: boolean
+    default: True
+    helpstr: "Whether boundary integrals should be vectorized. It might not be worth the hassle..."
+sumfact_optimize_loop_order:
+    type: boolean
+    default: False
+    helpstr: "Optimize order of loops in sumf factorization function using autotuning."
+sumfact_performance_transformations:
+    type: boolean
+    default: False
+    helpstr: "Apply sum factorization specific performance transformations."
+sumfact_performance_transformations_testrun:
+    type: integer
+    default: 0
+    helpstr: "If larger than zero determines test case to run."
+sumfact_regular_jacobians:
+    type: boolean
+    default: False
+    helpstr: "Generate non sum-factorized jacobians (only useful if sumfact is set)"
+unroll_dimension_loops:
+    type: boolean
+    default: False
+    helpstr: "whether loops over the geometric dimension should be unrolled"
+vectorization_allow_quadrature_changes:
+    type: boolean
+    default: False
+    helpstr: "whether the vectorization strategy is allowed to alter quadrature point numbers"
+vectorization_blockstructured:
+    type: boolean
+    default: False
+    helpstr: "Vectorize block structuring"
+vectorization_blockstructured_tail:
+    type: boolean
+    default: True
+    helpstr: "Try to fully vectorize block structuring even when 'nunmber_of_blocks' is not divisible by vector length"
+vectorization_blockstructured_tail_ordering:
+    type: string
+    default: "consecutive"
+    helpstr: "Ordering of the tail w.r.t the vectorized loop. Possible values: consecutive|blocked"
+vectorization_horizontal:
+    type: string
+    default:
+    nullable: True
+    helpstr: "an explicit value for horizontal vectorization read by the 'explicit' strategy"
+vectorization_jacobians:
+    type: boolean
+    default: True
+    helpstr: "Whether to attempt to vectorize jacobians (takes time, often not needed)"
+vectorization_list_index:
+    type: string
+    default:
+    nullable: True
+    helpstr: "Which vectorization to pick from a list (only valid with vectorization_strategy=fromlist)."
+vectorization_not_fully_vectorized_error:
+    type: boolean
+    default: False
+    helpstr: "throw an error if nonquadloop vectorization did not fully vectorize"
+vectorization_padding:
+    type: string
+    default:
+    nullable: True
+    helpstr: "an explicit value for the allowed padding in vectorization"
+vectorization_quadloop:
+    type: boolean
+    default: False
+    helpstr: "whether to generate code with explicit vectorization"
+vectorization_strategy:
+    type: string
+    default: "none"
+    helpstr: "The identifier of the vectorization cost model. Possible values: none|explicit|model|target|autotune"
+vectorization_target:
+    type: float
+    default:
+    nullable: True
+    helpstr: "The cost function target for the 'target' cost model. Only needed to verify the cost model itself, do not use light-heartedly!!!"
+vectorization_vertical:
+    type: string
+    default:
+    nullable: True
+    helpstr: "an explicit value for vertical vectorization read by the 'explicit' strategy"
\ No newline at end of file
diff --git a/python/dune/codegen/options_global.yaml b/python/dune/codegen/options_global.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..4db7aa253ae8e58810a25da9904622ca2f671cf9
--- /dev/null
+++ b/python/dune/codegen/options_global.yaml
@@ -0,0 +1,136 @@
+architecture:
+    type: string
+    default: "haswell"
+    helpstr: "The architecture to optimize for. Possible values: haswell|knl|skylake"
+autotune_google_benchmark:
+    type: boolean
+    default: False
+    helpstr: "Use google-benchmark library for autotuning (when autotuning is activated)."
+compare_l2errorsquared:
+    type: string
+    default:
+    nullable: True
+    helpstr: "maximal allowed l2 error squared of difference between numerical solution and interpolation of exact solution (NOTE: requires --exact-solution-expression)"
+debug_cache_with_stack:
+    type: boolean
+    default: False
+    helpstr: "Store stack along with cache objects. Makes debugging caching issues easier."
+debug_interpolate_input:
+    type: boolean
+    default: False
+    helpstr: "Should the input for printresidual and printmatix be interpolated (instead of random input)."
+driver_file:
+    type: string
+    default:
+    nullable: True
+    helpstr: "The filename for the generated driver header"
+exact_solution_expression:
+    type: string
+    default:
+    nullable: True
+    helpstr: "name of the exact solution expression in the ufl file"
+explicit_time_stepping:
+    type: boolean
+    default: False
+    helpstr: "use explicit time stepping"
+grid_consistent:
+    type: boolean
+    default: False
+    helpstr: "The used grid is already consistent"
+grid_info:
+    type: string
+    default:
+    nullable: True
+    helpstr: "Path to file with information about facedir and facemod variations. This can be used to limit the generation of skeleton kernels."
+grid_unstructured:
+    type: boolean
+    default: False
+    helpstr: "Set to true if you want to use an unstructured grid."
+ini_file:
+    type: string
+    default:
+    nullable: True
+    helpstr: "An inifile to use. A generated driver will be hard-coded to it, a [formcompiler] section will be used as default values to form compiler arguments (use snake case)"
+instrumentation_level:
+    type: integer
+    default: 0
+    helpstr: "Control time/opcounter measurements. 0-do nothing, 1-measure program as a whole, 2-operator applications, 3-measure kernel (eg. alpha-volume, ...), 4-parts of kernel (eg. stage 1-3 of SF)"
+l2error_tree_path:
+    type: string
+    default:
+    nullable: True
+    helpstr: "Tree pathes that should be considered for l2 error calculation. Default None means we take all of them into account."
+opcounter:
+    type: boolean
+    default: False
+    helpstr: "Count operations. Note: In this case only operator applications are generated since solving and operator counting does not work. You probably want to set instrumentation level>0."
+operator_to_build:
+    type: string
+    default:
+    nullable: True
+    helpstr: "The operators from the list that is about to be build now. CMake sets this one!!!"
+operators:
+    type: string
+    default: "r"
+    helpstr: "A comma separated list of operators, each name will be interpreted as a subsection name within the formcompiler section"
+overlapping:
+    type: boolean
+    default: False
+    helpstr: "Use an overlapping solver and constraints. You still need to make sure to construct a grid with overlap! The parallel option will be set automatically."
+performance_measuring:
+    type: boolean
+    default: False
+    helpstr: "Generate opcounter codepath, but only measure times!"
+permuting_horizontal_add:
+    type: boolean
+    default: True
+    helpstr: "Whether SIMD horizontal_add should use a permuting implementation."
+precision_bits:
+    type: integer
+    default: 64
+    helpstr: "The number of bits for the floating point type"
+project_basedir:
+    type: string
+    default:
+    nullable: True
+    helpstr: "The base (build) directory of the dune-codegen project"
+target_name:
+    type: string
+    default:
+    nullable: True
+    helpstr: "The target name from CMake"
+time_stepping_order:
+    type: integer
+    default: 1
+    helpstr: "Order of the time stepping method"
+uflfile:
+    type: string
+    default:
+    nullable: True
+    helpstr: "the UFL file to compile"
+use_likwid:
+    type: boolean
+    default: False
+    helpstr: "Use likwid instead of own performance measurements."
+use_sde:
+    type: boolean
+    default: False
+    helpstr: "Use sde instead of own performance measurements."
+with_mpi:
+    type: boolean
+    default: True
+    helpstr: "The module was configured with mpi"
+yaspgrid_offset:
+    type: boolean
+    default: False
+    helpstr: "Set to true if you want a yasp grid where the lower left corner is not in the origin."
+
+# Arguments that are mainly to be set by logic depending on other options
+max_vector_width:
+    type: integer
+    default: 256
+    helpstr: None
+parallel:
+    type: boolean
+    default: False
+    helpstr: "Mark that this program should be run in parallel. If set to true the c++ code will check that there are more than 1 MPI-ranks involved and the error computation will use communication."
diff --git a/python/setup.py b/python/setup.py
index 713ffbab9d5761f775764a67c2807a017a817da4..35c300e82115cf08d1cfb753e9ed66662427c5e4 100644
--- a/python/setup.py
+++ b/python/setup.py
@@ -42,7 +42,7 @@ setup(name='dune.codegen',
                 'dune.codegen.ufl',
                 'dune.codegen.ufl.transformations',
                 ],
-      install_requires=['dune.testtools', 'sympy', 'frozendict', 'pytest', 'pytest-pep8', 'filelock'],
+      install_requires=['sympy', 'frozendict', 'pytest', 'pytest-pep8', 'filelock', 'cerberus', 'pyaml'],
       cmdclass={'test': PyTest},
       entry_points = {
         "console_scripts": [
diff --git a/test/nonlinear/diffusivewave.mini b/test/nonlinear/diffusivewave.mini
index e02ec95646d5838b95d3be5793adeebc4e060a72..f7c67fe5dd4b2fb7bf9d39b68cd9e8f9f5e93816 100644
--- a/test/nonlinear/diffusivewave.mini
+++ b/test/nonlinear/diffusivewave.mini
@@ -21,7 +21,7 @@ geometry_mixins = equidistant, sumfact_equidistant | expand sf
 sumfact = 0, 1 | expand sf
 fastdg = 0, 0 | expand sf
 
-[formcompiler.operator]
+[formcompiler.poisson]
 geometry_mixins = equidistant, sumfact_equidistant | expand sf
 sumfact = 0, 1 | expand sf
 fastdg = 0, 0 | expand sf
diff --git a/test/poisson/opcount_poisson_dg_symdiff.mini b/test/poisson/opcount_poisson_dg_symdiff.mini
index 186c4344f9fed7512cde913433145259a76bf7b5..90df6bdc2889d13e7fa849face5df6fc7e5daf2d 100644
--- a/test/poisson/opcount_poisson_dg_symdiff.mini
+++ b/test/poisson/opcount_poisson_dg_symdiff.mini
@@ -10,4 +10,6 @@ extension = vtu
 [formcompiler]
 opcounter = 1
 instrumentation_level = 3
+
+[formcompiler.r]
 geometry_mixins = equidistant