diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000000000000000000000000000000000000..ac6e7e293f675117f535fe87cbb70707fcfbfe22
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "externals/km3net-dataformat"]
+	path = externals/km3net-dataformat
+	url = git@git.km3net.de:common/km3net-dataformat.git
diff --git a/Dockerfile b/Dockerfile
index e3792bdfd213432560028727341581b9bfe366a6..d434257f37bb2bb4452bceb447c0a67d9245d7b8 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,27 +1,9 @@
-FROM debian:stretch
+FROM docker.km3net.de/base/centos7-bundle:2021.03.01
 
-RUN apt-get update -qq && \
-    apt-get upgrade -qq -y
-RUN apt-get install -qq -y gfortran make cmake libbz2-dev wget g++ git && \
-    apt-get install -qq -y python3-dev python3-pip python3-tk python3-lxml python3-six
+RUN  yum install -y -e 0 devtoolset-10
 
-
-RUN  cd /opt && \
-     mkdir -p cmake-3.18 && wget -qO- "https://cmake.org/files/v3.18/cmake-3.18.2-Linux-x86_64.tar.gz" | tar --strip-components=1 -xz -C cmake-3.18
-
-RUN  cd /opt && \
-     wget https://root.cern.ch/download/root_v6.20.04.source.tar.gz && \
-     tar xvzf root_v6.20.04.source.tar.gz
-
-RUN  export PATH=/opt/cmake-3.18/bin:$PATH && \
-     cd /opt/root-6.20.04 && \
-     mkdir -p obj && \
-     cd obj && \
-     cmake -DCMAKE_INSTALL_PREFIX=/usr/local -Dpyroot=OFF -Dpyroot_experimental=OFF -Dx11=OFF -Dxft=OFF ..  && \
-     make -j4; make install && \
-     rm -rf /opt/root-6.20.04*
-
-RUN  cd /opt && \
+RUN  source /opt/rh/devtoolset-10/enable && \
+     cd /opt && \
      wget http://www.hepforge.org/archive/roottuple/RootTuple-1.0.0.tar.gz && \
      tar -xzvf RootTuple-1.0.0.tar.gz && \
      cd RootTuple-1.0.0 && \
@@ -31,7 +13,8 @@ RUN  cd /opt && \
      cmake -DCMAKE_INSTALL_PREFIX=/usr/local .. && \
      make; make install
 
-RUN cd /opt && \
+RUN  source /opt/rh/devtoolset-10/enable && \
+    cd /opt && \
     wget https://gibuu.hepforge.org/downloads?f=buuinput2021.tar.gz && \
     tar xvzf downloads?f=buuinput2021.tar.gz && \
     wget https://gibuu.hepforge.org/downloads?f=release2021.tar.gz && \
@@ -43,5 +26,15 @@ RUN cd /opt && \
     make -j withROOT=1 && \
     rm -rf /opt/*.tar.gz
 
+ADD . /km3buu
+
+RUN cd /km3buu && \
+    pip3 install setuptools-scm && \
+    pip3 install pytest-runner && \
+    pip3 install -e .
+
+RUN cd /km3buu/externals/km3net-dataformat/ && \
+    make
+ENV KM3NET_LIB=/km3buu/externals/km3net-dataformat/lib    
 ENV CONTAINER_GIBUU_EXEC=/opt/release2021/objects/GiBUU.x 
 ENV LD_LIBRARY_PATH="/usr/local/lib:${LD_LIBRARY_PATH}"
diff --git a/config/MediaComposition.xml b/config/MediaComposition.xml
new file mode 100644
index 0000000000000000000000000000000000000000..11bc934fd242298e4d66dcd974d16b9af744e874
--- /dev/null
+++ b/config/MediaComposition.xml
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+
+<media_comp>
+
+<!--
+Definition of the interaction media composition
+
+-->
+
+<!--
+  // media composition: SeaWater, Rock, Mantle, Core
+-->
+
+  <param_set media="SeaWater" density="1.03975">
+     <param name="O">    0.8584        </param>
+     <param name="H">    0.1082        </param>
+     <param name="Cl">   1.94E-2       </param>
+     <param name="Na">   1.08E-2       </param>
+     <param name="Mg">   0.1292E-2     </param>
+     <param name="S">    0.091E-2      </param>
+     <param name="Ca">   0.04E-2       </param>
+     <param name="K">    0.04E-2       </param>
+     <param name="Br">   0.0067E-2     </param>
+     <param name="C">    0.0028E-2     </param>
+  </param_set>
+
+
+  <param_set media="Rock" density="2.65">
+     <param name="O">    0.463	  </param>
+     <param name="Si">   0.282	  </param>
+     <param name="Al">   0.0823	  </param>
+     <param name="Fe">   0.0563	  </param>
+     <param name="Ca">   0.0415	  </param>
+     <param name="Na">   0.0236	  </param>
+     <param name="Mg">   0.0233	  </param>
+     <param name="K">    0.0209	  </param>
+     <param name="Ti">   0.0057	  </param>
+     <param name="H">    0.0014	  </param>
+  </param_set>
+
+
+  <param_set media="Mantle">
+     <param name="O">    0.4522        </param>
+     <param name="Mg">   0.2283        </param>
+     <param name="Si">   0.2149        </param>
+     <param name="Fe">   0.0597        </param>
+     <param name="Al">   0.0225        </param>
+     <param name="Ca">   0.0224        </param>
+  </param_set>
+
+
+  <param_set media="Core">
+     <param name="Fe">    0.9        </param>
+     <param name="Ni">    0.1        </param>
+  </param_set>
+
+</media_comp>
+
diff --git a/externals/km3net-dataformat b/externals/km3net-dataformat
new file mode 160000
index 0000000000000000000000000000000000000000..59d2e2bc4de69fb5497cdf09a0146d0090913933
--- /dev/null
+++ b/externals/km3net-dataformat
@@ -0,0 +1 @@
+Subproject commit 59d2e2bc4de69fb5497cdf09a0146d0090913933
diff --git a/km3buu/config.py b/km3buu/config.py
index 083f953659c876350f4fdc1a803a21ee6b74c939..25279ce20f4210c4563af4ffda9475decbd41c10 100644
--- a/km3buu/config.py
+++ b/km3buu/config.py
@@ -159,5 +159,10 @@ def read_media_compositions(filename):
 
 def read_default_media_compositions():
     cfg = Config()
-    fpath = join(cfg.gseagen_path, "dat", GSEAGEN_MEDIA_COMPOSITION_FILE)
+    try:
+        fpath = join(cfg.gseagen_path, "dat", GSEAGEN_MEDIA_COMPOSITION_FILE)
+    except:
+        fpath = abspath(
+            join(dirname(__file__), "../config/",
+                 GSEAGEN_MEDIA_COMPOSITION_FILE))
     return read_media_compositions(fpath)
diff --git a/km3buu/ctrl.py b/km3buu/ctrl.py
index d696530dec1c1f3c5c18be24d1c0fa55c9c94af3..d0dfe4b1b00e49bd29bfd7940480c5e5a14030dd 100644
--- a/km3buu/ctrl.py
+++ b/km3buu/ctrl.py
@@ -13,7 +13,9 @@ __email__ = "jschumann@km3net.de"
 __status__ = "Development"
 
 from shutil import copy
+import subprocess
 from spython.main import Client
+import os
 from os.path import join, abspath, basename, isdir, isfile
 from tempfile import NamedTemporaryFile, TemporaryDirectory
 from thepipe.logger import get_logger
@@ -21,15 +23,10 @@ from thepipe.logger import get_logger
 from . import IMAGE_NAME
 from .config import Config
 from .jobcard import Jobcard, read_jobcard
-from .environment import is_singularity_version_greater, MIN_SINGULARITY_VERSION
+from .environment import check_singularity_version
 
 log = get_logger(basename(__file__))
 
-if not is_singularity_version_greater(
-        MIN_SINGULARITY_VERSION):  # pragma: no cover
-    log.error("Singularity version lower than %s" % MIN_SINGULARITY_VERSION)
-    raise OSError("Singularity version below %s" % MIN_SINGULARITY_VERSION)
-
 GIBUU_SHELL = """
 #!/bin/bash
 
@@ -47,7 +44,7 @@ $CONTAINER_GIBUU_EXEC < {1};
 """
 
 
-def run_jobcard(jobcard, outdir):
+def run_jobcard(jobcard, outdir, container=False):
     """
     Method for run
 
@@ -58,6 +55,8 @@ def run_jobcard(jobcard, outdir):
         of a jobcard object or a path to a jobcard
     outdir: str 
         The path to the directory the output should be written to.
+    container: boolean
+        Call GiBUU inside container environment
     """
     input_dir = TemporaryDirectory()
     outdir = abspath(outdir)
@@ -80,23 +79,31 @@ def run_jobcard(jobcard, outdir):
         jobcard["neutrino_induced"]["FileNameflux"] = tmp_fluxfile
     with open(jobcard_fpath, "w") as f:
         f.write(str(jobcard))
-    log.info("Create temporary file for associated runscript")
-    script_fpath = join(input_dir.name, "run.sh")
-    with open(script_fpath, "w") as f:
-        ctnt = GIBUU_SHELL.format(outdir, jobcard_fpath)
-        f.write(ctnt)
-    output = Client.execute(
-        Config().gibuu_image_path,
-        ["/bin/sh", script_fpath],
-        bind=[outdir, input_dir.name],
-        return_result=True,
-    )
     with open(join(outdir, jobcard.filename), "w") as f:
         f.write(str(jobcard))
-    msg = output["message"]
-    if isinstance(msg, str):
-        log.info("GiBUU output:\n %s" % msg)
+    if container:
+        check_singularity_version()
+        log.info("Create temporary file for associated runscript")
+        script_fpath = join(input_dir.name, "run.sh")
+        with open(script_fpath, "w") as f:
+            ctnt = GIBUU_SHELL.format(outdir, jobcard_fpath)
+            f.write(ctnt)
+        output = Client.execute(
+            Config().gibuu_image_path,
+            ["/bin/sh", script_fpath],
+            bind=[outdir, input_dir.name],
+            return_result=True,
+        )
+        msg = output["message"]
+        if isinstance(msg, str):
+            log.info("GiBUU output:\n %s" % msg)
+        else:
+            log.info("GiBUU output:\n %s" % msg[0])
+            log.error("GiBUU stacktrace:\n%s" % msg[1])
+        return output["return_code"]
     else:
-        log.info("GiBUU output:\n %s" % msg[0])
-        log.error("GiBUU stacktrace:\n%s" % msg[1])
-    return output["return_code"]
+        p = subprocess.Popen(
+            "%s < %s" % (os.environ["CONTAINER_GIBUU_EXEC"], jobcard_fpath),
+            shell=True,
+            cwd=outdir)
+        return p.wait()
diff --git a/km3buu/environment.py b/km3buu/environment.py
index 8a4c3f03f4b9b05b6263086e16d244a657719cdc..5bed27339de93906a8eadce3912a8a3a39dfa780 100644
--- a/km3buu/environment.py
+++ b/km3buu/environment.py
@@ -26,6 +26,13 @@ log = get_logger(basename(__file__))
 MIN_SINGULARITY_VERSION = "3.3"
 
 
+def check_singularity_version():  # pragma: no cover
+    if not is_singularity_version_greater(MIN_SINGULARITY_VERSION):
+        log.error("Singularity version lower than %s" %
+                  MIN_SINGULARITY_VERSION)
+        raise OSError("Singularity version below %s" % MIN_SINGULARITY_VERSION)
+
+
 def is_singularity_version_greater(min_version):  # pragma: no cover
     singularity_version = LooseVersion(get_singularity_version().split()[-1])
     retval = singularity_version > LooseVersion(MIN_SINGULARITY_VERSION)
diff --git a/km3buu/jobcard.py b/km3buu/jobcard.py
index 3db1c675329b6df9adecda4003bc7a6ada2c48b8..14013d9eac9933658691b5d8a92b275078d82d58 100644
--- a/km3buu/jobcard.py
+++ b/km3buu/jobcard.py
@@ -89,6 +89,11 @@ def read_jobcard(filepath):
     return Jobcard(f90nml.read(filepath), filename=basename(filepath))
 
 
+def write_jobcard(jobcard, filepath):
+    with open(filepath, 'w') as nml_file:
+        f90nml.write(jobcard, nml_file)
+
+
 def generate_neutrino_jobcard(events,
                               process,
                               flavour,
diff --git a/km3buu/tests/test_ctrl.py b/km3buu/tests/test_ctrl.py
index 6d310997f9ed47d15bc61544adde20dc6a1e0700..34d4faa8e300471b005b04c82637d8099384ca06 100644
--- a/km3buu/tests/test_ctrl.py
+++ b/km3buu/tests/test_ctrl.py
@@ -35,7 +35,7 @@ class TestCTRLbyJobcardFile(unittest.TestCase):
             writer.writerows(zip(ene, np.power(ene, -1)))
         jc = read_jobcard(self.filename)
         jc["neutrino_induced"]["FileNameFlux"] = self.flux_file.name
-        self.retval = run_jobcard(jc, self.output_dir.name)
+        self.retval = run_jobcard(jc, self.output_dir.name, container=True)
         log = get_logger("ctrl.py")
         log.setLevel("INFO")
 
@@ -78,7 +78,9 @@ class TestCTRLbyJobcardObject(unittest.TestCase):
         self.test_jobcard["neutrinoAnalysis"]["outputEvents"] = True
         self.test_jobcard["pythia"]["PARP(91)"] = 0.44
         self.output_dir = TemporaryDirectory()
-        self.retval = run_jobcard(self.test_jobcard, self.output_dir.name)
+        self.retval = run_jobcard(self.test_jobcard,
+                                  self.output_dir.name,
+                                  container=True)
         # raise Exception(self.test_jobcard)
 
     def test_output(self):
diff --git a/notebooks/create_jobcard.py b/notebooks/create_jobcard.py
new file mode 100644
index 0000000000000000000000000000000000000000..e1445718fee00ebaf18ae1482aa3c57f96286c27
--- /dev/null
+++ b/notebooks/create_jobcard.py
@@ -0,0 +1,16 @@
+#!/usr/bin/python3
+
+from km3buu.jobcard import generate_neutrino_jobcard
+from km3buu.jobcard import write_jobcard
+from km3buu.jobcard import XSECTIONMODE_LOOKUP, PROCESS_LOOKUP, FLAVOR_LOOKUP
+
+events = 1000
+energy_min = 0.1
+energy_max = 50
+interaction = "cc"
+flavor = "electron"
+target_z = 8
+target_a = 16
+fluxfile = None
+jc = generate_neutrino_jobcard(events, interaction, flavor, (energy_min,energy_max), (target_z,target_a),fluxfile=fluxfile)
+write_jobcard(jc,"./job.job")