diff --git a/.hgignore b/.hgignore
index a9ff8eb73973341b9b5be1c54ca39fe7a8f97483..5f7570492ed255fd62287fc2d9bf2abec379c3c8 100644
--- a/.hgignore
+++ b/.hgignore
@@ -8,7 +8,6 @@ syntax: glob
 *.so
 *.os
 *.c
-_*
 output*
 build*
 Pyramid.egg-info*
\ No newline at end of file
diff --git a/desktop.ini b/desktop.ini
index e3da4d705005ef1b5c7e9641c22981f1312e37d6..ed829e62137655210c6d17e08844b0ed9929acac 100644
--- a/desktop.ini
+++ b/desktop.ini
@@ -1,5 +1,5 @@
 [.ShellClassInfo]
-IconResource=C:\Users\Jan\Home\PhD Thesis\Pyramid\icon.ico,0
+IconResource=C:\Users\Jan\Home\PhD Thesis\Pyramid\docs\icon.ico,0
 [ViewState]
 Mode=
 Vid=
diff --git a/docs/Pyramid Logo.png b/docs/Pyramid Logo.png
new file mode 100644
index 0000000000000000000000000000000000000000..9d68d277a5b322c744a6fd941e1baf1d978759e4
Binary files /dev/null and b/docs/Pyramid Logo.png differ
diff --git a/docs/_static/sphinxdoc.css b/docs/_static/sphinxdoc.css
new file mode 100644
index 0000000000000000000000000000000000000000..d208cf7974e78e10ef9bf7d6c99c2a9b376ddf3e
--- /dev/null
+++ b/docs/_static/sphinxdoc.css
@@ -0,0 +1,354 @@
+/*
+ * sphinxdoc.css_t
+ * ~~~~~~~~~~~~~~~
+ *
+ * Sphinx stylesheet -- sphinxdoc theme.  Originally created by
+ * Armin Ronacher for Werkzeug.
+ *
+ * :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS.
+ * :license: BSD, see LICENSE for details.
+ *
+ */
+
+@import url("basic.css");
+
+/* -- page layout ----------------------------------------------------------- */
+
+body {
+    font-family: 'Lucida Grande', 'Lucida Sans Unicode', 'Geneva',
+                 'Verdana', sans-serif;
+    font-size: 14px;
+    letter-spacing: -0.01em;
+    line-height: 150%;
+    text-align: center;
+    background-color: #BFD1D4;
+    color: black;
+    padding: 0;
+    border: 1px solid #aaa;
+
+    margin: 0px 80px 0px 80px;
+    min-width: 740px;
+}
+
+div.document {
+    background-color: white;
+    text-align: left;
+    background-image: url(contents.png);
+    background-repeat: repeat-x;
+}
+
+div.bodywrapper {
+    margin: 0 240px 0 0;
+    border-right: 1px solid #ccc;
+}
+
+div.body {
+    margin: 0;
+    padding: 0.5em 20px 20px 20px;
+}
+
+div.related {
+    font-size: 1em;
+}
+
+div.related ul {
+    background-image: url(navigation.png);
+    height: 2em;
+    border-top: 1px solid #ddd;
+    border-bottom: 1px solid #ddd;
+}
+
+div.related ul li {
+    margin: 0;
+    padding: 0;
+    height: 2em;
+    float: left;
+}
+
+div.related ul li.right {
+    float: right;
+    margin-right: 5px;
+}
+
+div.related ul li a {
+    margin: 0;
+    padding: 0 5px 0 5px;
+    line-height: 1.75em;
+    color: #EE9816;
+}
+
+div.related ul li a:hover {
+    color: #3CA8E7;
+}
+
+div.sphinxsidebarwrapper {
+    padding: 0;
+}
+
+div.sphinxsidebar {
+    margin: 0;
+    padding: 0.5em 15px 15px 0;
+    width: 210px;
+    float: right;
+    font-size: 1em;
+    text-align: left;
+}
+
+div.sphinxsidebar h3, div.sphinxsidebar h4 {
+    margin: 1em 0 0.5em 0;
+    font-size: 1em;
+    padding: 0.1em 0 0.1em 0.5em;
+    color: white;
+    border: 1px solid #86989B;
+    background-color: #AFC1C4;
+}
+
+div.sphinxsidebar h3 a {
+    color: white;
+}
+
+div.sphinxsidebar ul {
+    padding-left: 1.5em;
+    margin-top: 7px;
+    padding: 0;
+    line-height: 130%;
+}
+
+div.sphinxsidebar ul ul {
+    margin-left: 20px;
+}
+
+div.footer {
+    background-color: #E3EFF1;
+    color: #86989B;
+    padding: 3px 8px 3px 0;
+    clear: both;
+    font-size: 0.8em;
+    text-align: right;
+}
+
+div.footer a {
+    color: #86989B;
+    text-decoration: underline;
+}
+
+/* -- body styles ----------------------------------------------------------- */
+
+p {    
+    margin: 0.8em 0 0.5em 0;
+}
+
+a {
+    color: #CA7900;
+    text-decoration: none;
+}
+
+a:hover {
+    color: #2491CF;
+}
+
+div.body a {
+    text-decoration: underline;
+}
+
+h1 {
+    margin: 0;
+    padding: 0.7em 0 0.3em 0;
+    font-size: 1.5em;
+    color: #11557C;
+	background-color: #ccd8ff;
+}
+
+h2 {
+    margin: 1.3em 0 0.2em 0;
+    font-size: 1.35em;
+    padding: 0;
+	background-color: #ccd8ff;
+}
+
+h3 {
+    margin: 1em 0 -0.3em 0;
+    font-size: 1.2em;
+	background-color: #ccd8ff;
+}
+
+h4 {
+	background-color: #ccd8ff
+}
+
+h5 {
+	background-color: #ccd8ff
+}
+
+div.body h1 a, div.body h2 a, div.body h3 a, div.body h4 a, div.body h5 a, div.body h6 a {
+    color: black!important;
+}
+
+h1 a.anchor, h2 a.anchor, h3 a.anchor, h4 a.anchor, h5 a.anchor, h6 a.anchor {
+    display: none;
+    margin: 0 0 0 0.3em;
+    padding: 0 0.2em 0 0.2em;
+    color: #aaa!important;
+}
+
+h1:hover a.anchor, h2:hover a.anchor, h3:hover a.anchor, h4:hover a.anchor,
+h5:hover a.anchor, h6:hover a.anchor {
+    display: inline;
+}
+
+h1 a.anchor:hover, h2 a.anchor:hover, h3 a.anchor:hover, h4 a.anchor:hover,
+h5 a.anchor:hover, h6 a.anchor:hover {
+    color: #777;
+    background-color: #eee;
+}
+
+a.headerlink {
+    color: #c60f0f!important;
+    font-size: 1em;
+    margin-left: 6px;
+    padding: 0 4px 0 4px;
+    text-decoration: none!important;
+}
+
+a.headerlink:hover {
+    background-color: #ccc;
+    color: white!important;
+}
+
+cite, code, tt {
+    font-family: 'Consolas', 'Deja Vu Sans Mono',
+                 'Bitstream Vera Sans Mono', monospace;
+    font-size: 1.17em;
+    letter-spacing: 0.01em;
+}
+
+tt {
+    background-color: #f2f2f2;
+    border-bottom: 1px solid #ddd;
+    color: #333;
+}
+
+tt.descname, tt.descclassname, tt.xref {
+    border: 0;
+}
+
+hr {
+    border: 1px solid #abc;
+    margin: 2em;
+}
+
+a tt {
+    border: 0;
+    color: #CA7900;
+}
+
+a tt:hover {
+    color: #2491CF;
+}
+
+th {
+    background-color: #fff3cc;
+}
+
+pre {
+    font-family: 'Consolas', 'Deja Vu Sans Mono',
+                 'Bitstream Vera Sans Mono', monospace;
+    font-size: 0.95em;
+    letter-spacing: 0.015em;
+    line-height: 120%;
+    padding: 0.5em;
+    border: 1px solid #ccc;
+    background-color: #f8f8f8;
+}
+
+pre a {
+    color: inherit;
+    text-decoration: underline;
+}
+
+td.linenos pre {
+    padding: 0.5em 0;
+}
+
+div.quotebar {
+    background-color: #f8f8f8;
+    max-width: 250px;
+    float: right;
+    padding: 2px 7px;
+    border: 1px solid #ccc;
+}
+
+div.topic {
+    background-color: #f8f8f8;
+}
+
+table {
+    border-collapse: collapse;
+    margin: 0 -0.5em 0 -0.5em;
+}
+
+table td, table th {
+    padding: 0.2em 0.5em 0.2em 0.5em;
+}
+
+div.admonition, div.warning {
+    font-size: 0.9em;
+    margin: 1em 0 1em 0;
+    border: 1px solid #86989B;
+    background-color: #f7f7f7;
+    padding: 0;
+}
+
+div.admonition p, div.warning p {
+    margin: 0.5em 1em 0.5em 1em;
+    padding: 0;
+}
+
+div.admonition pre, div.warning pre {
+    margin: 0.4em 1em 0.4em 1em;
+}
+
+div.admonition p.admonition-title,
+div.warning p.admonition-title {
+    margin: 0;
+    padding: 0.1em 0 0.1em 0.5em;
+    color: white;
+    border-bottom: 1px solid #86989B;
+    font-weight: bold;
+    background-color: #AFC1C4;
+}
+
+div.warning {
+    border: 1px solid #940000;
+}
+
+div.warning p.admonition-title {
+    background-color: #CF0000;
+    border-bottom-color: #940000;
+}
+
+div.admonition ul, div.admonition ol,
+div.warning ul, div.warning ol {
+    margin: 0.1em 0.5em 0.5em 3em;
+    padding: 0;
+}
+
+div.versioninfo {
+    margin: 1em 0 0 0;
+    border: 1px solid #ccc;
+    background-color: #DDEAF0;
+    padding: 8px;
+    line-height: 1.3em;
+    font-size: 0.9em;
+}
+
+.viewcode-back {
+    font-family: 'Lucida Grande', 'Lucida Sans Unicode', 'Geneva',
+                 'Verdana', sans-serif;
+}
+
+div.viewcode-block:target {
+    background-color: #f4debf;
+    border-top: 1px solid #ac9;
+    border-bottom: 1px solid #ac9;
+}
\ No newline at end of file
diff --git a/docs/conf.py b/docs/conf.py
index 259c0970cd0e2eb3617b88fb2c71f1e1ccfade8e..cf566933896ec3965fae8427376f9e83e72a170a 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -25,8 +25,10 @@ sys.path.insert(0, os.path.abspath('C:\Users\Jan\Home\PhD Thesis\Pyramid'))
 
 # Add any Sphinx extension module names here, as strings. They can be extensions
 # coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
-extensions = ['sphinx.ext.autodoc', 'sphinx.ext.viewcode', 'rst2pdf.pdfbuilder',
-              'numpydoc']
+extensions = ['sphinx.ext.autodoc', 'sphinx.ext.viewcode', 'sphinx.ext.autosummary',
+			  'rst2pdf.pdfbuilder', 'numpydoc']
+
+numpydoc_show_class_members = False
 
 # Add any paths that contain templates here, relative to this directory.
 templates_path = ['_templates']
@@ -92,7 +94,7 @@ pygments_style = 'sphinx'
 
 # The theme to use for HTML and HTML Help pages.  See the documentation for
 # a list of builtin themes.
-html_theme = 'default'
+html_theme = 'sphinxdoc'
 
 # Theme options are theme-specific and customize the look and feel of a theme
 # further.  For a list of options available for each theme, see the
@@ -111,12 +113,12 @@ html_theme = 'default'
 
 # The name of an image file (relative to this directory) to place at the top
 # of the sidebar.
-#html_logo = None
+html_logo = 'Pyramid Logo.png'
 
 # The name of an image file (within the static path) to use as favicon of the
 # docs.  This file should be a Windows icon file (.ico) being 16x16 or 32x32
 # pixels large.
-#html_favicon = None
+html_favicon = 'icon.ico'
 
 # Add any paths that contain custom static files (such as style sheets) here,
 # relative to this directory. They are copied after the builtin static files,
diff --git a/icon.ico b/docs/icon.ico
similarity index 100%
rename from icon.ico
rename to docs/icon.ico
diff --git a/docs/pyramid.numcore.rst b/docs/pyramid.numcore.rst
index 9d3a9c39bab16bb343a843246c3726977a079b81..4ad4c515f2c46870d53142b9d064a0467a3835e9 100644
--- a/docs/pyramid.numcore.rst
+++ b/docs/pyramid.numcore.rst
@@ -6,7 +6,6 @@ numcore Package
 
 .. automodule:: pyramid.numcore
     :members:
-    :undoc-members:
     :show-inheritance:
 	:special-members:
 
diff --git a/docs/pyramid.rst b/docs/pyramid.rst
index 3491e66ec3ab49baf2a06d77b1b654c0f9670ee2..8bd3b4c52bfc4d67c3eb53e14e9df3d08ac51b51 100644
--- a/docs/pyramid.rst
+++ b/docs/pyramid.rst
@@ -6,25 +6,38 @@ pyramid Package
 
 .. automodule:: pyramid.analytic
     :members:
-    :undoc-members:
     :show-inheritance:
 	:special-members:
 
-:mod:`holoimage` Module
------------------------
+:mod:`costfunction` Module
+--------------------------
+
+.. automodule:: pyramid.costfunction
+    :members:
+    :show-inheritance:
+	:special-members:
+
+:mod:`datacollection` Module
+----------------------------
 
-.. automodule:: pyramid.holoimage
+.. automodule:: pyramid.datacollection
+    :members:
+    :show-inheritance:
+	:special-members:
+
+:mod:`forwardmodel` Module
+--------------------------
+
+.. automodule:: pyramid.forwardmodel
     :members:
-    :undoc-members:
     :show-inheritance:
 	:special-members:
 
 :mod:`kernel` Module
------------------------
+--------------------
 
 .. automodule:: pyramid.kernel
     :members:
-    :undoc-members:
     :show-inheritance:
 	:special-members:
 
@@ -33,7 +46,6 @@ pyramid Package
 
 .. automodule:: pyramid.magcreator
     :members:
-    :undoc-members:
     :show-inheritance:
 	:special-members:
 
@@ -42,7 +54,14 @@ pyramid Package
 
 .. automodule:: pyramid.magdata
     :members:
-    :undoc-members:
+    :show-inheritance:
+	:special-members:
+
+:mod:`optimizer` Module
+-----------------------
+
+.. automodule:: pyramid.optimizer
+    :members:
     :show-inheritance:
 	:special-members:
 
@@ -51,7 +70,6 @@ pyramid Package
 
 .. automodule:: pyramid.phasemap
     :members:
-    :undoc-members:
     :show-inheritance:
 	:special-members:
 
@@ -60,7 +78,6 @@ pyramid Package
 
 .. automodule:: pyramid.phasemapper
     :members:
-    :undoc-members:
     :show-inheritance:
 	:special-members:
 
@@ -69,16 +86,6 @@ pyramid Package
 
 .. automodule:: pyramid.projector
     :members:
-    :undoc-members:
-    :show-inheritance:
-	:special-members:
-
-:mod:`reconstructor` Module
----------------------------
-
-.. automodule:: pyramid.reconstructor
-    :members:
-    :undoc-members:
     :show-inheritance:
 	:special-members:
 
diff --git a/logfile.log b/logfile.log
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/pyramid/__init__.py b/pyramid/__init__.py
index 109731534a012c2fa22dbc214f7909a8ebbd23a0..8d25565aa7341e668317b8fd813c6ca9765d8e3d 100644
--- a/pyramid/__init__.py
+++ b/pyramid/__init__.py
@@ -6,9 +6,9 @@ Modules
 magcreator
     Create simple magnetic distributions.
 magdata
-    Class for the storage of magnetizatin data.
+    Class for the storage of magnetization data.
 projector
-    Create projections of a given magnetization distribution.
+    Class for projections of given magnetization distribution.
 kernel
     Class for the kernel matrix representing one magnetized pixel.
 phasemapper
@@ -17,8 +17,14 @@ phasemap
     Class for the storage of phase data.
 analytic
     Create phase maps for magnetic distributions with analytic solutions.
-holoimage
-    Create holographic contour maps from a given phase map.
+datacollection
+    Class for collecting pairs of phase maps and corresponding projectors.
+forwardmodel
+    Class which represents a phase mapping strategy.
+costfunction
+    Class for the evaluation of the cost of a function.
+optimizer
+    Provides strategies for optimizing first guess magnetic distributions.
 reconstructor
     Reconstruct magnetic distributions from given phasemaps.
 
@@ -33,10 +39,8 @@ numcore
 import logging, logging.config
 import os
 
-LOGGING_CONF = os.path.join(os.path.dirname(__file__), 'logging.ini')
 
-logging.config.fileConfig(LOGGING_CONF)
+LOGGING_CONF = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'logging.ini')
 
 
-log = logging.getLogger(__name__)
-log.info('imported package, log:'+log.name)
\ No newline at end of file
+logging.config.fileConfig(LOGGING_CONF)
diff --git a/pyramid/analytic.py b/pyramid/analytic.py
index 5445990a923ede7dccd77d4d1232bd90aeff8c27..bf2ffccd69db5206304c463fd5da401519acecb2 100644
--- a/pyramid/analytic.py
+++ b/pyramid/analytic.py
@@ -11,6 +11,8 @@ calculated by the functions from the :mod:`~pyramid.phasemapper` module.
 import numpy as np
 from numpy import pi
 
+from pyramid.phasemap import PhaseMap
+
 
 PHI_0 = -2067.83  # magnetic flux in T*nm²
 
@@ -44,17 +46,17 @@ def phase_mag_slab(dim, a, phi, center, width, b_0=1):
     # Function for the phase:
     def phi_mag(x,  y):
         def F_0(x, y):
-            a = np.log(x**2 + y**2 + 1E-30)
-            b = np.arctan(x / (y+1E-30))
-            return x*a - 2*x + 2*y*b
+            A = np.log(x**2 + y**2 + 1E-30)
+            B = np.arctan(x / (y+1E-30))
+            return x*A - 2*x + 2*y*B
         return coeff * Lz * (- np.cos(phi) * (F_0(x-x0-Lx/2, y-y0-Ly/2)
-                                             - F_0(x-x0+Lx/2, y-y0-Ly/2)
-                                             - F_0(x-x0-Lx/2, y-y0+Ly/2)
-                                             + F_0(x-x0+Lx/2, y-y0+Ly/2))
+                                            - F_0(x-x0+Lx/2, y-y0-Ly/2)
+                                            - F_0(x-x0-Lx/2, y-y0+Ly/2)
+                                            + F_0(x-x0+Lx/2, y-y0+Ly/2))
                              + np.sin(phi) * (F_0(y-y0-Ly/2, x-x0-Lx/2)
-                                             - F_0(y-y0+Ly/2, x-x0-Lx/2)
-                                             - F_0(y-y0-Ly/2, x-x0+Lx/2)
-                                             + F_0(y-y0+Ly/2, x-x0+Lx/2)))
+                                            - F_0(y-y0+Ly/2, x-x0-Lx/2)
+                                            - F_0(y-y0-Ly/2, x-x0+Lx/2)
+                                            + F_0(y-y0+Ly/2, x-x0+Lx/2)))
     # Process input parameters:
     z_dim, y_dim, x_dim = dim
     y0 = a * (center[1] + 0.5)  # y0, x0 define the center of a pixel,
@@ -66,7 +68,7 @@ def phase_mag_slab(dim, a, phi, center, width, b_0=1):
     y = np.linspace(a/2, y_dim*a-a/2, num=y_dim)
     xx, yy = np.meshgrid(x, y)
     # Return phase:
-    return phi_mag(xx, yy)
+    return PhaseMap(a, phi_mag(xx, yy))
 
 
 def phase_mag_disc(dim, a, phi, center, radius, height, b_0=1):
@@ -115,7 +117,7 @@ def phase_mag_disc(dim, a, phi, center, radius, height, b_0=1):
     y = np.linspace(a/2, y_dim*a-a/2, num=y_dim)
     xx, yy = np.meshgrid(x, y)
     # Return phase:
-    return phi_mag(xx, yy)
+    return PhaseMap(a, phi_mag(xx, yy))
 
 
 def phase_mag_sphere(dim, a, phi, center, radius, b_0=1):
@@ -161,7 +163,7 @@ def phase_mag_sphere(dim, a, phi, center, radius, b_0=1):
     y = np.linspace(a / 2, y_dim * a - a / 2, num=y_dim)
     xx, yy = np.meshgrid(x, y)
     # Return phase:
-    return phi_mag(xx, yy)
+    return PhaseMap(a, phi_mag(xx, yy))
 
 
 def phase_mag_vortex(dim, a, center, radius, height, b_0=1):
@@ -206,4 +208,4 @@ def phase_mag_vortex(dim, a, center, radius, height, b_0=1):
     y = np.linspace(a/2, y_dim*a-a/2, num=y_dim)
     xx, yy = np.meshgrid(x, y)
     # Return phase:
-    return phi_mag(xx, yy)
+    return PhaseMap(a, phi_mag(xx, yy))
diff --git a/pyramid/costfunction.py b/pyramid/costfunction.py
index 3a5ac71ccbb5847c156094a2589bba203f45d491..6201f91519b23f5d0514c65383891aa41f7a055b 100644
--- a/pyramid/costfunction.py
+++ b/pyramid/costfunction.py
@@ -14,12 +14,14 @@ class Costfunction:
     # TODO: Docstring!
     
     def __init__(self, y, F):
+        '''TEST DOCSTRING FOR INIT'''
         # TODO: Docstring!
         self.y = y  # TODO: get y from phasemaps!
         self.F = F  # Forward Model
         self.Se_inv = np.eye(len(y))
 
     def __call__(self, x):
+        '''TEST DOCSTRING FOR CALL'''
         # TODO: Docstring!
         y = self.y
         F = self.F
diff --git a/pyramid/datacollection.py b/pyramid/datacollection.py
index 43320b029c8811a94596cc9e88639af7b058fdf0..54d03710c8cd15678e414daa51f0c31742badd59 100644
--- a/pyramid/datacollection.py
+++ b/pyramid/datacollection.py
@@ -1,7 +1,10 @@
 # -*- coding: utf-8 -*-
-"""Class for the collection of phase maps and additional data."""
+"""This module provides the :class:`~.DataCollection` class for the collection of phase maps
+and additional data like corresponding projectors."""
 
 
+import logging
+
 import numpy as np
 from numbers import Number
 
@@ -11,6 +14,29 @@ from pyramid.projector import Projector
 
 class DataCollection(object):
 
+    '''Class for collecting phase maps and corresponding projectors.
+
+    Represents a collection of (e.g. experimentally derived) phase maps, stored as
+    :class:´~.PhaseMap´ objects and corresponding projectors stored as :class:`~.Projector`
+    objects. At creation, the grid spacing `a` and the dimension `dim` of the projected grid.
+    Data can be added via the :func:`~.append` method, where a :class:`~.PhaseMap` and a
+    :class:`~.Projector` have to be given as tuple argument.
+
+    Attributes
+    ----------
+    a: float
+        The grid spacing in nm.
+    dim: tuple (N=2)
+        Dimensions of the projected grid.
+    phase_maps:
+        A list of all stored :class:`~.PhaseMap` objects.
+    projectors:
+        A list of all stored :class:`~.Projector` objects.
+    phase_vec: :class:`~numpy.ndarray` (N=1)
+        The concatenaded, vectorized phase of all ;class:`~.PhaseMap` objects.
+
+    '''
+
     @property
     def a(self):
         return self._a
@@ -32,7 +58,8 @@ class DataCollection(object):
         return [d[1] for d in self.data]
 
     def __init__(self, a, dim):
-        # TODO: Docstring!
+        self.log = logging.getLogger(__name__)
+        self.log.info('Creating '+str(self))
         assert isinstance(a, Number), 'Grid spacing has to be a number!'
         assert a >= 0, 'Grid spacing has to be a positive number!'
         self._a = a
@@ -41,8 +68,30 @@ class DataCollection(object):
         self.dim = dim
         self.data = []
 
+    def __repr__(self):
+        self.log.info('Calling __repr__')
+        return '%s(a=%r, dim=%r)' % (self.__class__, self.a, self.dim)
+
+    def __str__(self):
+        self.log.info('Calling __str__')
+        return 'DataCollection(a=%s, dim=%s, data_count=%s)' % \
+            (self.__class__, self.a, self.dim, len(self.phase_maps))
+
     def append(self, (phase_map, projector)):
-        # TODO: Docstring!
+        '''Appends a data pair of phase map and projection infos to the data collection.`
+
+        Parameters
+        ----------
+        (phase_map, projector): tuple (N=2)
+            tuple which contains a :class:`~.PhaseMap` object and a :class:`~.Projector` object,
+            which should be added to the data collection.
+
+        Returns
+        -------
+        None
+
+        '''
+        self.log.info('Calling append')
         assert isinstance(phase_map, PhaseMap) and isinstance(projector, Projector),  \
             'Argument has to be a tuple of a PhaseMap and a Projector object!'
         assert phase_map.dim == self.dim, 'Added phasemap must have the same dimension!'
diff --git a/pyramid/kernel.py b/pyramid/kernel.py
index 2f1a0735f2108b2ad37246af68def8d908388a90..b8653e36c52921f926ce28095260640f4c230988 100644
--- a/pyramid/kernel.py
+++ b/pyramid/kernel.py
@@ -1,30 +1,35 @@
 # -*- coding: utf-8 -*-
-"""Class for the calculation and storage of kernel.
+"""This module provides the :class:`~.Kernel` class, representing the phase contribution of one
+single magnetized pixel."""
 
-This module provides the :class:`~.Kernel` class whose instances can be used to calculate and
-store the kernel matrix representing the phase of a single pixel for the convolution used in the
-phase calculation. The phasemap of a single pixel for two orthogonal directions (`u` and `v`) are
-stored seperately as 2-dimensional matrices. The Jacobi matrix of the phasemapping just depends
-on the kernel and can be calculated via the :func:`~.get_jacobi` function. Storing the Jacobi
-matrix uses much memory, thus it is also possible to directly get the multiplication of a given
-vector with the (transposed) Jacobi matrix without explicit calculation of the latter.
-It is possible to load data from and save them to NetCDF4 files. See :class:`~.Kernel` for further
-information.
-
-"""
 
+import logging
 
 import numpy as np
 
-import pyramid.numcore as nc
+import pyramid.numcore.kernel_core as core
 
 
 PHI_0 = -2067.83    # magnetic flux in T*nm²
 # TODO: sign?
 
 
-class Kernel:
+class Kernel(object):
+
     '''Class for calculating kernel matrices for the phase calculation.
+    
+    
+    
+    This module provides the :class:`~.Kernel` class whose instances can be used to calculate and
+    store the kernel matrix representing the phase of a single pixel for the convolution used in the
+    phase calculation. The phasemap of a single pixel for two orthogonal directions (`u` and `v`) are
+    stored seperately as 2-dimensional matrices. The Jacobi matrix of the phasemapping just depends
+    on the kernel and can be calculated via the :func:`~.get_jacobi` function. Storing the Jacobi
+    matrix uses much memory, thus it is also possible to directly get the multiplication of a given
+    vector with the (transposed) Jacobi matrix without explicit calculation of the latter.
+    It is possible to load data from and save them to NetCDF4 files. See :class:`~.Kernel` for further
+    information.
+    
 
     Represents the phase of a single magnetized pixel for two orthogonal directions (`u` and `v`),
     which can be accessed via the corresponding attributes. The default elementary geometry is
@@ -32,6 +37,18 @@ class Kernel:
     magnetized pixel. During the construction, a few attributes are calculated that are used in
     the convolution during phase calculation.
 
+
+    An instance `kernel` of the :class:`~.Kernel` class is callable via:
+    
+    .. :function:: kernel(vector)
+        
+        do stuff
+        
+        :param str sender: do other stuff
+        :return: nix
+
+    with `vector` being a :class:`~numpy.ndarray` (N=1).
+
     Attributes
     ----------
     dim : tuple (N=2)
@@ -56,7 +73,7 @@ class Kernel:
         and increasing to the next multiple of 2 (for faster FFT).
     slice_fft : tuple (N=2) of :class:`slice`
         A tuple of :class:`slice` objects to extract the original field of view from the increased
-        size (size_fft) of the grid for the FFT-convolution.
+        size (`size_fft`) of the grid for the FFT-convolution.
 
     '''# TODO: Can be used for several PhaseMappers via the fft arguments or via calling!
     
@@ -75,6 +92,8 @@ class Kernel:
             The elementary geometry of the single magnetized pixel.
 
         ''' # TODO: Docstring
+        self.log = logging.getLogger(__name__)
+        self.log.info('Calling __init__')
         # TODO: Check if b_0 has an influence or is forgotten
         # Function for the phase of an elementary geometry:
         def get_elementary_phase(geometry, n, m, a):
@@ -95,7 +114,7 @@ class Kernel:
         self.geometry = geometry
         self.b_0 = b_0
         # Calculate kernel (single pixel phase):
-        coeff = -a**2 / (2*PHI_0)
+        coeff = -a**2 * b_0 / (2*PHI_0)
         v_dim, u_dim = dim
         u = np.linspace(-(u_dim-1), u_dim-1, num=2*u_dim-1)
         v = np.linspace(-(v_dim-1), v_dim-1, num=2*v_dim-1)
@@ -108,22 +127,33 @@ class Kernel:
         self.slice_fft = (slice(dim[0]-1, 2*dim[0]-1), slice(dim[1]-1, 2*dim[1]-1))
         self.u_fft = np.fft.rfftn(self.u, self.dim_fft)
         self.v_fft = np.fft.rfftn(self.v, self.dim_fft)
+        self.log.info('Created '+str(self))
 
     def __call__(self, x):
+        '''Test'''
+        self.log.info('Calling __call__')
         if self.numcore:
             return self._multiply_jacobi_core(x)
         else:
             return self._multiply_jacobi(x)
         # TODO: Bei __init__ variable auf die entsprechende Funktion setzen.
 
+    def __repr__(self):
+        self.log.info('Calling __repr__')
+        return '%s(a=%r, dim=%r, b_0=%r, numcore=%r, geometry=%r)' % \
+            (self.__class__, self.a, self.dim, self.b_0, self.numcore, self.geometry)
 
-    def jac_dot(self, vector): 
+    def jac_dot(self, vector):
+        '''TEST'''# TODO: Docstring
+        self.log.info('Calling jac_dot')
         if self.numcore:
             return self._multiply_jacobi_core(vector)
         else:
             return self._multiply_jacobi(vector)
 
     def jac_T_dot(self, vector):
+        # TODO: Docstring
+        self.log.info('Calling jac_dot_T')
         return self._multiply_jacobi_T(vector)
 
     def _multiply_jacobi(self, vector):
@@ -141,7 +171,8 @@ class Kernel:
         result : :class:`~numpy.ndarray` (N=1)
             Product of the Jacobi matrix (which is not explicitely calculated) with the vector.
 
-        '''
+        '''# TODO: move!
+        self.log.info('Calling _multiply_jacobi')
         v_dim, u_dim = self.dim
         size = v_dim * u_dim
         assert len(vector) == 2*size, 'vector size not compatible!'
@@ -173,7 +204,8 @@ class Kernel:
             Product of the transposed Jacobi matrix (which is not explicitely calculated) with
             the vector.
 
-        '''
+        '''# TODO: move!
+        self.log.info('Calling _multiply_jacobi_T')
         v_dim, u_dim = self.dim
         size = v_dim * u_dim
         assert len(vector) == size, 'vector size not compatible!'
@@ -190,7 +222,7 @@ class Kernel:
         return result
 
     def _multiply_jacobi_core(self, vector):
-        # TODO: Docstring!
+        self.log.info('Calling _multiply_jacobi_core')
         result = np.zeros(np.prod(self.dim))
-        nc.multiply_jacobi_core(self.dim[0], self.dim[1], self.u, self.v, vector, result)
+        core.multiply_jacobi_core(self.dim[0], self.dim[1], self.u, self.v, vector, result)
         return result
diff --git a/pyramid/logging.ini b/pyramid/logging.ini
index 0803943502b3aeaab94b50e11cd8d72e5748b84e..266c37587b5288c8d796dfc92c4025f405264fba 100644
--- a/pyramid/logging.ini
+++ b/pyramid/logging.ini
@@ -9,7 +9,7 @@ class=logging.Formatter
 
 [formatter_file]
 format=%(asctime)s: %(levelname)-8s @ <%(name)s>:    %(message)s
-datefmt=%Y-%m-%d H:%M:%S
+datefmt=%Y-%m-%d %H:%M:%S
 class=logging.Formatter
 
 [handlers]
@@ -25,7 +25,7 @@ args=tuple()
 class=logging.FileHandler
 level=INFO
 formatter=file
-args=('../output/logfile.log', 'w')
+args=('logfile.log', 'w')
 
 [loggers]
 keys=root
diff --git a/pyramid/magdata.py b/pyramid/magdata.py
index 30cc4ac2a30fc8e3c2e5ac5ad1516cf89b1283d6..0dc7044b92183182a680aeb5c9d6ce32852c8163 100644
--- a/pyramid/magdata.py
+++ b/pyramid/magdata.py
@@ -1,12 +1,13 @@
 # -*- coding: utf-8 -*-
-"""Class for the storage of magnetizatin data."""
+"""This module provides the :class:`~.MagData` class for storing of magnetization data."""
 
 
+import logging
 import numpy as np
+from scipy.ndimage.interpolation import zoom
 
 import matplotlib.pyplot as plt
 from matplotlib.ticker import MaxNLocator
-
 from mayavi import mlab
 
 from numbers import Number
@@ -20,30 +21,28 @@ class MagData(object):
 
     Represents 3-dimensional magnetic distributions with 3 components which are stored as a
     2-dimensional numpy array in `magnitude`, but which can also be accessed as a vector via
-    `mag_vec`. :class:`~.MagData` objects support arithmetic operators (``+``, ``-``, ``*``, ``/``)
-    and their augmented counterparts (``+=``, ``-=``, ``*=``, ``/=``), with numbers and other
-    :class:`~.MagData` objects, if their dimensions and grid spacings match. It is possible to load
-    data from NetCDF4 or LLG (.txt) files or to save the data in these formats. Plotting methods 
-    are also provided.
+    `mag_vec`. :class:`~.MagData` objects support negation, arithmetic operators 
+    (``+``, ``-``, ``*``) and their augmented counterparts (``+=``, ``-=``, ``*=``), with numbers
+    and other :class:`~.MagData` objects, if their dimensions and grid spacings match. It is
+    possible to load data from NetCDF4 or LLG (.txt) files or to save the data in these formats.
+    Plotting methods are also provided.
 
     Attributes
     ----------
-    a : float
+    a: float
         The grid spacing in nm.
-    dim : tuple (N=3)
+    dim: tuple (N=3)
         Dimensions (z, y, x) of the grid.
-    magnitude : :class:`~numpy.ndarray` (N=4)
+    magnitude: :class:`~numpy.ndarray` (N=4)
         The `x`-, `y`- and `z`-component of the magnetization vector for every 3D-gridpoint
         as a 4-dimensional numpy array (first dimension has to be 3, because of the 3 components).
     mag_vec: :class:`~numpy.ndarray` (N=1)
         Vector containing the magnetic distribution.
 
     '''
-
-    # TODO: Implement: __str__ or __repr__
-
-    # TODO: Implement: logging
-
+    
+    log = logging.getLogger()
+    
     @property
     def a(self):
         return self._a
@@ -81,57 +80,94 @@ class MagData(object):
         self.magnitude = mag_vec.reshape((3,)+self.dim)
 
     def __init__(self, a, magnitude):
+        self.log = logging.getLogger(__name__)
+        self.log.info('Calling __init__')
         self.a = a
-        self.magnitude = magnitude
+        self.magnitude = magnitude        
+        self.log.info('Created '+str(self))
+
+    def __getstate__(self):
+        d = dict(self.__dict__)
+        del d['log']
+        return d
+
+    def __setstate__(self, d):
+        self.__dict__.update(d)
+        self.log = logging.getLogger(__name__)
+
+    def __repr__(self):
+        self.log.info('Calling __repr__')
+        return '%s(a=%r, magnitude=%r)' % (self.__class__, self.a, self.magnitude)
+
+    def __str__(self):
+        self.log.info('Calling __str__')
+        return 'MagData(a=%s, dim=%s)' % (self.a, self.dim)
 
     def __neg__(self):  # -self
+        self.log.info('Calling __neg__')
         return MagData(self.a, -self.magnitude)
         
     def __add__(self, other):  # self + other
+        self.log.info('Calling __add__')
         assert isinstance(other, (MagData, Number)), \
             'Only MagData objects and scalar numbers (as offsets) can be added/subtracted!'
         if isinstance(other, MagData):
+            self.log.info('Adding two MagData objects')
             assert other.a == self.a, 'Added phase has to have the same grid spacing!'
             assert other.magnitude.shape == (3,)+self.dim, \
                 'Added magnitude has to have the same dimensions!'
             return MagData(self.a, self.magnitude+other.magnitude)
         else:  # other is a Number
+            self.log.info('Adding an offset')
             return MagData(self.a, self.magnitude+other)
 
     def __sub__(self, other):  # self - other
+        self.log.info('Calling __sub__')
         return self.__add__(-other)
 
     def __mul__(self, other):  # self * other
+        self.log.info('Calling __mul__')
         assert isinstance(other, Number), 'MagData objects can only be multiplied by numbers!'
         return MagData(self.a, other*self.magnitude)
 
-    def __div__(self, other):  # self / other 
-        assert other != 0, 'Division by zero!'
-        return self.__mul__(1./other)
-        # TODO: Does not work, but why?
-
     def __radd__(self, other):  # other + self
+        self.log.info('Calling __radd__')
         return self.__add__(other)
 
     def __rsub__(self, other):  # other - self
+        self.log.info('Calling __rsub__')
         return -self.__sub__(other)
 
     def __rmul__(self, other):  # other * self
+        self.log.info('Calling __rmul__')
         return self.__mul__(other)
     
     def __iadd__(self, other):  # self += other
+        self.log.info('Calling __iadd__')
         return self.__add__(other)
 
     def __isub__(self, other):  # self -= other
+        self.log.info('Calling __isub__')
         return self.__sub__(other)
 
     def __imul__(self, other):  # self *= other
+        self.log.info('Calling __imul__')
         return self.__mul__(other)
-
-    def __idiv__(self, other):  # self /= other
-        return self.__div__(other)
     
     def copy(self):
+        '''Returns a copy of the :class:`~.MagData` object
+
+        Parameters
+        ----------
+        None
+
+        Returns
+        -------
+        mag_data: :class:`~.MagData`
+            A copy of the :class:`~.MagData`.
+
+        '''
+        self.log.info('Calling copy7')
         return MagData(self.a, self.magnitude.copy())
 
     def scale_down(self, n=1):
@@ -152,12 +188,32 @@ class MagData(object):
         Only possible, if each axis length is a power of 2!
 
         '''
+        self.log.info('Calling scale_down')
         assert n > 0 and isinstance(n, (int, long)), 'n must be a positive integer!'
         assert np.all([d % 2**n == 0 for d in self.dim]), 'Dimensions must a multiples of 2!'
+        self.a = self.a * 2**n
         for t in range(n):
             # Create coarser grid for the magnetization:
             self.magnitude = self.magnitude.reshape(
                 3, self.dim[0]/2, 2, self.dim[1]/2, 2, self.dim[2]/2, 2).mean(axis=(6, 4, 2))
+            
+
+    def scale_up(self, n=1, order=0):
+        # TODO: Docstring!
+        self.log.info('Calling scale_up')
+        assert n > 0 and isinstance(n, (int, long)), 'n must be a positive integer!'
+        assert 5 > order >= 0 and isinstance(order, (int, long)), \
+            'order must be a positive integer between 0 and 5!'
+        self.a = self.a / 2**n
+        self.magnitude = np.array((zoom(self.magnitude[0], zoom=2**n, order=order),
+                                   zoom(self.magnitude[1], zoom=2**n, order=order),
+                                   zoom(self.magnitude[2], zoom=2**n, order=order)))
+
+    def pad(self, x_pad, y_pad, z_pad):
+        # TODO: Docstring!
+        self.magnitude = np.pad(self.magnitude,
+                                ((0, 0), (z_pad, z_pad), (y_pad, y_pad), (x_pad, x_pad)),
+                                mode='constant', constant_values=0)
 
     def save_to_llg(self, filename='..\output\magdata_output.txt'):
         '''Save magnetization data in a file with LLG-format.
@@ -173,6 +229,7 @@ class MagData(object):
         None
 
         '''
+        self.log.info('Calling save_to_llg')
         a = self.a * 1.0E-9 / 1.0E-2  # from nm to cm
         # Create 3D meshgrid and reshape it and the magnetization into a list where x varies first:
         zz, yy, xx = np.mgrid[a/2:(self.dim[0]*a-a/2):self.dim[0]*1j,
@@ -202,6 +259,7 @@ class MagData(object):
             A :class:`~.MagData` object containing the loaded data.
 
         '''
+        cls.log.info('Calling load_from_llg')
         SCALE = 1.0E-9 / 1.0E-2  # From cm to nm
         data = np.genfromtxt(filename, skip_header=2)
         dim = tuple(np.genfromtxt(filename, dtype=int, skip_header=1, skip_footer=len(data[:, 0])))
@@ -223,6 +281,7 @@ class MagData(object):
         None
 
         '''
+        self.log.info('Calling save_to_netcdf4')
         mag_file = netCDF4.Dataset(filename, 'w', format='NETCDF4')
         mag_file.a = self.a
         mag_file.createDimension('comp', 3)  # Number of components
@@ -248,6 +307,7 @@ class MagData(object):
             A :class:`~.MagData` object containing the loaded data.
 
         '''
+        cls.log.info('Calling copy')
         mag_file = netCDF4.Dataset(filename, 'r', format='NETCDF4')
         a = mag_file.a
         magnitude =  mag_file.variables['magnitude'][...]
@@ -279,24 +339,31 @@ class MagData(object):
             The axis on which the graph is plotted.
 
         '''
+        self.log.info('Calling quiver_plot')
         assert proj_axis == 'z' or proj_axis == 'y' or proj_axis == 'x', \
             'Axis has to be x, y or z (as string).'
         if proj_axis == 'z':  # Slice of the xy-plane with z = ax_slice
+            self.log.info('proj_axis == z')
             if ax_slice is None:
+                self.log.info('ax_slice is None')
                 ax_slice = int(self.dim[0]/2)
             mag_slice_u = self.magnitude[0][ax_slice, ...]  # x-component
             mag_slice_v = self.magnitude[1][ax_slice, ...]  # y-component
             u_label = 'x [px]'
             v_label = 'y [px]'
         elif proj_axis == 'y':  # Slice of the xz-plane with y = ax_slice
+            self.log.info('proj_axis == y')
             if ax_slice is None:
+                self.log.info('ax_slice is None')
                 ax_slice = int(self.dim[1]/2)
             mag_slice_u = self.magnitude[0][:, ax_slice, :]  # x-component
             mag_slice_v = self.magnitude[2][:, ax_slice, :]  # z-component
             u_label = 'x [px]'
             v_label = 'z [px]'
         elif proj_axis == 'x':  # Slice of the yz-plane with x = ax_slice
+            self.log.info('proj_axis == x')
             if ax_slice is None:
+                self.log.info('ax_slice is None')
                 ax_slice = int(self.dim[2]/2)
             mag_slice_u = self.magnitude[1][..., ax_slice]  # y-component
             mag_slice_v = self.magnitude[2][..., ax_slice]  # z-component
@@ -304,6 +371,7 @@ class MagData(object):
             v_label = 'z [px]'
         # If no axis is specified, a new figure is created:
         if axis is None:
+            self.log.info('axis is None')
             fig = plt.figure(figsize=(8.5, 7))
             axis = fig.add_subplot(1, 1, 1, aspect='equal')
         axis.quiver(mag_slice_u, mag_slice_v, pivot='middle', angles='xy', scale_units='xy',
@@ -331,6 +399,7 @@ class MagData(object):
         None
 
         '''
+        self.log.info('Calling quiver_plot3D')
         a = self.a
         dim = self.dim
         # Create points and vector components as lists:
@@ -345,7 +414,7 @@ class MagData(object):
         z_mag = np.reshape(self.magnitude[2], (-1))
         # Plot them as vectors:
         mlab.figure()
-        plot = mlab.quiver3d(xx, yy, zz, x_mag, y_mag, z_mag, mode='arrow')#, scale_factor=5.0)
+        plot = mlab.quiver3d(xx, yy, zz, x_mag, y_mag, z_mag, mode='arrow')
         mlab.outline(plot)
         mlab.axes(plot)
         mlab.colorbar()
diff --git a/pyramid/numcore/__init__.py b/pyramid/numcore/__init__.py
index df89b8e95b165b037eba1bbe18824f3a3d219f9e..fd8ed341b1fb38e8aa62c63d1398301b0745be86 100644
--- a/pyramid/numcore/__init__.py
+++ b/pyramid/numcore/__init__.py
@@ -11,5 +11,3 @@ Notes
 Packages are written in `pyx`-format for the use with :mod:`~cython`.
 
 """
-
-from phase_mag_real import *
diff --git a/pyramid/optimizer.py b/pyramid/optimizer.py
index b2d0aff814ca6d7807dc9822fe6df3cc67c0ae2d..ca226018246a2f56eb2f7459c4e0c63cda1d17ed 100644
--- a/pyramid/optimizer.py
+++ b/pyramid/optimizer.py
@@ -56,85 +56,85 @@ def optimize_cg(self, data_collection, first_guess):
 
 # TODO: Implement the following:
 
-# -*- coding: utf-8 -*-
-"""Reconstruct magnetic distributions from given phasemaps.
-
-This module reconstructs 3-dimensional magnetic distributions (as :class:`~pyramid.magdata.MagData`
-objects) from a given set of phase maps (represented by :class:`~pyramid.phasemap.PhaseMap`
-objects) by using several model based reconstruction algorithms which use the forward model
-provided by :mod:`~pyramid.projector` and :mod:`~pyramid.phasemapper` and a priori knowledge of
-the distribution.
-So far, only a simple least square algorithm for known pixel locations for 2-dimensional problems
-is implemented (:func:`~.reconstruct_simple_leastsq`), but more complex solutions are planned.
-
-"""
-
-
-
-import numpy as np
-
-from scipy.optimize import leastsq
-
-import pyramid.projector as pj
-import pyramid.phasemapper as pm
-from pyramid.magdata import MagData
-from pyramid.projector import Projection
-from pyramid.kernel import Kernel
-
-
-def reconstruct_simple_leastsq(phase_map, mask, b_0=1):
-    '''Reconstruct a magnetic distribution for a 2-D problem with known pixel locations.
-
-    Parameters
-    ----------
-        phase_map : :class:`~pyramid.phasemap.PhaseMap`
-            A :class:`~pyramid.phasemap.PhaseMap` object, representing the phase from which to
-            reconstruct the magnetic distribution.
-        mask : :class:`~numpy.ndarray` (N=3)
-            A boolean matrix (or a matrix consisting of ones and zeros), representing the
-            positions of the magnetized voxels in 3 dimensions.
-        b_0 : float, optional
-            The magnetic induction corresponding to a magnetization `M`\ :sub:`0` in T.
-            The default is 1.
-    Returns
-    -------
-        mag_data : :class:`~pyramid.magdata.MagData`
-            The reconstructed magnetic distribution as a
-            :class:`~pyramid.magdata.MagData` object.
-
-    Notes
-    -----
-    Only works for a single phase_map, if the positions of the magnetized voxels are known and
-    for slice thickness of 1 (constraint for the `z`-dimension).
-
-    '''
-    # Read in parameters:
-    y_m = phase_map.phase.reshape(-1)  # Measured phase map as a vector
-    a = phase_map.a  # Grid spacing
-    dim = mask.shape  # Dimensions of the mag. distr.
-    count = mask.sum()  # Number of pixels with magnetization
-    lam = 1e-6  # Regularisation parameter
-    # Create empty MagData object for the reconstruction:
-    mag_data_rec = MagData(a, (np.zeros(dim), np.zeros(dim), np.zeros(dim)))
-
-    # Function that returns the phase map for a magnetic configuration x:
-    def F(x):
-        mag_data_rec.set_vector(mask, x)
-        phase = pm.phase_mag_real(a, pj.simple_axis_projection(mag_data_rec), b_0)
-        return phase.reshape(-1)
-
-    # Cost function which should be minimized:
-    def J(x_i):
-        y_i = F(x_i)
-        term1 = (y_i - y_m)
-        term2 = lam * x_i
-        return np.concatenate([term1, term2])
-
-    # Reconstruct the magnetization components:
-    x_rec, _ = leastsq(J, np.zeros(3*count))
-    mag_data_rec.set_vector(mask, x_rec)
-    return mag_data_rec
-
-def reconstruct_test():
-    product = (kernel.multiply_jacobi_T(projection.multiply_jacobi_T(x))
-             * kernel.multiply_jacobi(projection.multiply_jacobi(x)))
\ No newline at end of file
+## -*- coding: utf-8 -*-
+#"""Reconstruct magnetic distributions from given phasemaps.
+#
+#This module reconstructs 3-dimensional magnetic distributions (as :class:`~pyramid.magdata.MagData`
+#objects) from a given set of phase maps (represented by :class:`~pyramid.phasemap.PhaseMap`
+#objects) by using several model based reconstruction algorithms which use the forward model
+#provided by :mod:`~pyramid.projector` and :mod:`~pyramid.phasemapper` and a priori knowledge of
+#the distribution.
+#So far, only a simple least square algorithm for known pixel locations for 2-dimensional problems
+#is implemented (:func:`~.reconstruct_simple_leastsq`), but more complex solutions are planned.
+#
+#"""
+#
+#
+#
+#import numpy as np
+#
+#from scipy.optimize import leastsq
+#
+#import pyramid.projector as pj
+#import pyramid.phasemapper as pm
+#from pyramid.magdata import MagData
+#from pyramid.projector import Projection
+#from pyramid.kernel import Kernel
+#
+#
+#def reconstruct_simple_leastsq(phase_map, mask, b_0=1):
+#    '''Reconstruct a magnetic distribution for a 2-D problem with known pixel locations.
+#
+#    Parameters
+#    ----------
+#        phase_map : :class:`~pyramid.phasemap.PhaseMap`
+#            A :class:`~pyramid.phasemap.PhaseMap` object, representing the phase from which to
+#            reconstruct the magnetic distribution.
+#        mask : :class:`~numpy.ndarray` (N=3)
+#            A boolean matrix (or a matrix consisting of ones and zeros), representing the
+#            positions of the magnetized voxels in 3 dimensions.
+#        b_0 : float, optional
+#            The magnetic induction corresponding to a magnetization `M`\ :sub:`0` in T.
+#            The default is 1.
+#    Returns
+#    -------
+#        mag_data : :class:`~pyramid.magdata.MagData`
+#            The reconstructed magnetic distribution as a
+#            :class:`~pyramid.magdata.MagData` object.
+#
+#    Notes
+#    -----
+#    Only works for a single phase_map, if the positions of the magnetized voxels are known and
+#    for slice thickness of 1 (constraint for the `z`-dimension).
+#
+#    '''
+#    # Read in parameters:
+#    y_m = phase_map.phase.reshape(-1)  # Measured phase map as a vector
+#    a = phase_map.a  # Grid spacing
+#    dim = mask.shape  # Dimensions of the mag. distr.
+#    count = mask.sum()  # Number of pixels with magnetization
+#    lam = 1e-6  # Regularisation parameter
+#    # Create empty MagData object for the reconstruction:
+#    mag_data_rec = MagData(a, (np.zeros(dim), np.zeros(dim), np.zeros(dim)))
+#
+#    # Function that returns the phase map for a magnetic configuration x:
+#    def F(x):
+#        mag_data_rec.set_vector(mask, x)
+#        phase = pm.phase_mag_real(a, pj.simple_axis_projection(mag_data_rec), b_0)
+#        return phase.reshape(-1)
+#
+#    # Cost function which should be minimized:
+#    def J(x_i):
+#        y_i = F(x_i)
+#        term1 = (y_i - y_m)
+#        term2 = lam * x_i
+#        return np.concatenate([term1, term2])
+#
+#    # Reconstruct the magnetization components:
+#    x_rec, _ = leastsq(J, np.zeros(3*count))
+#    mag_data_rec.set_vector(mask, x_rec)
+#    return mag_data_rec
+#
+#def reconstruct_test():
+#    product = (kernel.multiply_jacobi_T(projection.multiply_jacobi_T(x))
+#             * kernel.multiply_jacobi(projection.multiply_jacobi(x)))
\ No newline at end of file
diff --git a/pyramid/phasemap.py b/pyramid/phasemap.py
index 6964ded5353fd3c567b3838b0ba12f3f4c7339a3..293dd6359cbf3ac19052248bb8a74335964eda77 100644
--- a/pyramid/phasemap.py
+++ b/pyramid/phasemap.py
@@ -1,7 +1,9 @@
 # -*- coding: utf-8 -*-
-"""Class for the storage of phase data."""
+"""This module provides the :class:`~.PhaseMap` class for storing phase map data."""
 
 
+import logging
+
 import numpy as np
 from numpy import pi
 
@@ -22,8 +24,8 @@ class PhaseMap(object):
 
     Represents 2-dimensional phase maps. The phase information itself is stored as a 2-dimensional
     matrix in `phase`, but can also be accessed as a vector via `phase_vec`. :class:`~.PhaseMap`
-    objects support arithmetic operators (``+``, ``-``, ``*``, ``/``) and their augmented 
-    counterparts (``+=``, ``-=``, ``*=``, ``/=``), with numbers and other :class:`~.PhaseMap`
+    objects support negation, arithmetic operators (``+``, ``-``, ``*``) and their augmented 
+    counterparts (``+=``, ``-=``, ``*=``), with numbers and other :class:`~.PhaseMap`
     objects, if their dimensions and grid spacings match. It is possible to load data from NetCDF4
     or textfiles or to save the data in these formats. Methods for plotting the phase or a
     corresponding holographic contour map are provided. Holographic contour maps are created by
@@ -34,44 +36,65 @@ class PhaseMap(object):
 
     Attributes
     ----------
-    a : float
+    a: float
         The grid spacing in nm.
-    dim : tuple (N=2)
+    dim: tuple (N=2)
         Dimensions of the grid.
-    phase : :class:`~numpy.ndarray` (N=2)
+    phase: :class:`~numpy.ndarray` (N=2)
         Matrix containing the phase shift.
     phase_vec: :class:`~numpy.ndarray` (N=2)
         Vector containing the phase shift.
-    unit : {'rad', 'mrad', 'µrad'}, optional
-        Set the unit of the phase map. This is important for the :func:`~.display` function,
+    unit: {'rad', 'mrad'}, optional
+        Set the unit of the phase map. This is important for the :func:`display` function,
         because the phase is scaled accordingly. Does not change the phase itself, which is
         always in `rad`.
 
     '''
 
-    UNITDICT = {'rad': 1E0,
-                'mrad': 1E3,
-                'µrad': 1E6}
-
-    CDICT = {'red':   [(0.00, 1.0, 0.0),
-                       (0.25, 1.0, 1.0),
-                       (0.50, 1.0, 1.0),
-                       (0.75, 0.0, 0.0),
-                       (1.00, 0.0, 1.0)],
-
-             'green': [(0.00, 0.0, 0.0),
-                       (0.25, 0.0, 0.0),
-                       (0.50, 1.0, 1.0),
-                       (0.75, 1.0, 1.0),
-                       (1.00, 0.0, 1.0)],
-
-             'blue':  [(0.00, 1.0, 1.0),
-                       (0.25, 0.0, 0.0),
-                       (0.50, 0.0, 0.0),
-                       (0.75, 0.0, 0.0),
-                       (1.00, 1.0, 1.0)]}
+    log = logging.getLogger(__name__)
+
+    UNITDICT = {u'rad': 1E0,
+                u'mrad': 1E3,
+                u'µrad': 1E6}
+
+    CDICT =     {'red':   [(0.00, 1.0, 0.0),
+                           (0.25, 1.0, 1.0),
+                           (0.50, 1.0, 1.0),
+                           (0.75, 0.0, 0.0),
+                           (1.00, 0.0, 1.0)],
+
+                 'green': [(0.00, 0.0, 0.0),
+                           (0.25, 0.0, 0.0),
+                           (0.50, 1.0, 1.0),
+                           (0.75, 1.0, 1.0),
+                           (1.00, 0.0, 1.0)],
+
+                 'blue':  [(0.00, 1.0, 1.0),
+                           (0.25, 0.0, 0.0),
+                           (0.50, 0.0, 0.0),
+                           (0.75, 0.0, 0.0),
+                           (1.00, 1.0, 1.0)]}
+
+    CDICT_INV = {'red':   [(0.00, 0.0, 1.0),
+                           (0.25, 0.0, 0.0),
+                           (0.50, 0.0, 0.0),
+                           (0.75, 1.0, 1.0),
+                           (1.00, 1.0, 0.0)],
+
+                 'green': [(0.00, 1.0, 1.0),
+                           (0.25, 1.0, 1.0),
+                           (0.50, 0.0, 0.0),
+                           (0.75, 0.0, 0.0),
+                           (1.00, 1.0, 0.0)],
+
+                 'blue':  [(0.00, 0.0, 0.0),
+                           (0.25, 1.0, 1.0),
+                           (0.50, 1.0, 1.0),
+                           (0.75, 1.0, 1.0),
+                           (1.00, 0.0, 0.0)]}
     
     HOLO_CMAP = mpl.colors.LinearSegmentedColormap('my_colormap', CDICT, 256)
+    HOLO_CMAP_INV = mpl.colors.LinearSegmentedColormap('my_colormap', CDICT_INV, 256)
     
     @property
     def a(self):
@@ -121,52 +144,69 @@ class PhaseMap(object):
         self.a = a
         self.phase = phase
         self.unit = unit
+        self.log = logging.getLogger(__name__)
+        self.log.info('Created '+str(self))
+
+    def __repr__(self):
+        self.log.info('Calling __repr__')
+        return '%s(a=%r, phase=%r, unit=&r)' % \
+            (self.__class__, self.a, self.phase, self.unit)
+
+    def __str__(self):
+        self.log.info('Calling __str__')
+        return 'PhaseMap(a=%s, dim=%s)' % (self.a, self.dim)
 
     def __neg__(self):  # -self
+        self.log.info('Calling __neg__')
         return PhaseMap(self.a, -self.phase, self.unit)
         
     def __add__(self, other):  # self + other
+        self.log.info('Calling __add__')
         assert isinstance(other, (PhaseMap, Number)), \
             'Only PhaseMap objects and scalar numbers (as offsets) can be added/subtracted!'
         if isinstance(other, PhaseMap):
+            self.log.info('Adding two PhaseMap objects')
             assert other.a == self.a, 'Added phase has to have the same grid spacing!'
             assert other.phase.shape == self.dim, \
                 'Added magnitude has to have the same dimensions!'
             return PhaseMap(self.a, self.phase+other.phase, self.unit)
         else:  # other is a Number
+            self.log.info('Adding an offset')
             return PhaseMap(self.a, self.phase+other, self.unit)
 
     def __sub__(self, other):  # self - other
+        self.log.info('Calling __sub__')
         return self.__add__(-other)
 
     def __mul__(self, other):  # self * other
+        self.log.info('Calling __mul__')
         assert isinstance(other, Number), 'PhaseMap objects can only be multiplied by numbers!'
         return PhaseMap(self.a, other*self.phase, self.unit)
 
-    def __div__(self, other):  # self / other
-        return self.__mul__(1.0/other)
-
     def __radd__(self, other):  # other + self
+        self.log.info('Calling __radd__')
         return self.__add__(other)
 
     def __rsub__(self, other):  # other - self
+        self.log.info('Calling __rsub__')
         return -self.__sub__(other)
 
     def __rmul__(self, other):  # other * self
+        self.log.info('Calling __rmul__')
         return self.__mul__(other)
     
     def __iadd__(self, other):  # self += other
+        self.log.info('Calling __iadd__')
         return self.__add__(other)
 
     def __isub__(self, other):  # self -= other
+        self.log.info('Calling __isub__')
         return self.__sub__(other)
 
     def __imul__(self, other):  # self *= other
+        self.log.info('Calling __imul__')
         return self.__mul__(other)
 
-    def __idiv__(self, other):  # self /= other
-        return self.__div__(other)
-
     def save_to_txt(self, filename='..\output\phasemap_output.txt'):
         '''Save :class:`~.PhaseMap` data in a file with txt-format.
 
@@ -181,6 +221,7 @@ class PhaseMap(object):
         None
 
         '''
+        self.log.info('Calling save_to_txt')
         with open(filename, 'w') as phase_file:
             phase_file.write('{}\n'.format(filename.replace('.txt', '')))
             phase_file.write('grid spacing = {} nm\n'.format(self.a))
@@ -201,6 +242,7 @@ class PhaseMap(object):
             A :class:`~.PhaseMap` object containing the loaded data.
 
         '''
+        cls.log.info('Calling load_from_txt')
         with open(filename, 'r') as phase_file:
             phase_file.readline()  # Headerline is not used
             a = float(phase_file.readline()[15:-4])
@@ -221,6 +263,7 @@ class PhaseMap(object):
         None
 
         '''
+        self.log.info('Calling save_to_netcdf4')
         phase_file = netCDF4.Dataset(filename, 'w', format='NETCDF4')
         phase_file.a = self.a
         phase_file.createDimension('v_dim', self.dim[0])
@@ -244,13 +287,15 @@ class PhaseMap(object):
             A :class:`~.PhaseMap` object containing the loaded data.
 
         '''
+        cls.log.info('Calling load_from_netcdf4')
         phase_file = netCDF4.Dataset(filename, 'r', format='NETCDF4')
         a = phase_file.a
         phase = phase_file.variables['phase'][:]
         phase_file.close()
         return PhaseMap(a, phase)
 
-    def display_phase(self, title='Phase Map', cmap='RdBu', limit=None, norm=None, axis=None):
+    def display_phase(self, title='Phase Map', cmap='RdBu',
+                      limit=None, norm=None, axis=None, show=True):
         '''Display the phasemap as a colormesh.
 
         Parameters
@@ -268,6 +313,8 @@ class PhaseMap(object):
             If not specified, :class:`~matplotlib.colors.Normalize` is automatically used.
         axis : :class:`~matplotlib.axes.AxesSubplot`, optional
             Axis on which the graph is plotted. Creates a new figure if none is specified.
+        show : bool, optional
+            A switch which determines if the plot is shown at the end of plotting.
 
         Returns
         -------
@@ -275,6 +322,7 @@ class PhaseMap(object):
             The axis on which the graph is plotted.
 
         '''
+        self.log.info('Calling display_phase')
         # Take units into consideration:
         phase = self.phase * self.UNITDICT[self.unit]
         if limit is None:
@@ -302,9 +350,10 @@ class PhaseMap(object):
         cbar_ax = fig.add_axes([0.82, 0.15, 0.02, 0.7])
         cbar = fig.colorbar(im, cax=cbar_ax)
         cbar.ax.tick_params(labelsize=14)
-        cbar.set_label('phase shift [{}]'.format(self.unit), fontsize=15)
+        cbar.set_label(u'phase shift [{}]'.format(self.unit), fontsize=15)
         # Show plot:
-        plt.show()
+        if show:
+            plt.show()
         # Return plotting axis:
         return axis
 
@@ -325,6 +374,7 @@ class PhaseMap(object):
             The axis on which the graph is plotted.
 
         '''
+        self.log.info('Calling display_phase3d')
         # Take units into consideration:
         phase = self.phase * self.UNITDICT[self.unit]
         # Create figure and axis:
@@ -347,7 +397,7 @@ class PhaseMap(object):
         return axis
     
     def display_holo(self, density=1, title='Holographic Contour Map',
-                     axis=None, interpolation='none'):
+                     axis=None, grad_encode='dark', interpolation='none', show=True):
         '''Display the color coded holography image.
     
         Parameters
@@ -360,13 +410,16 @@ class PhaseMap(object):
             Axis on which the graph is plotted. Creates a new figure if none is specified.
         interpolation : {'none, 'bilinear', 'cubic', 'nearest'}, optional
             Defines the interpolation method. No interpolation is used in the default case.
+        show: bool, optional
+            A switch which determines if the plot is shown at the end of plotting.
     
         Returns
         -------
         axis: :class:`~matplotlib.axes.AxesSubplot`
             The axis on which the graph is plotted.
     
-        '''
+        '''# TODO: Docstring saturation!
+        self.log.info('Calling display_holo')
         # Calculate the holography image intensity:
         img_holo = (1 + np.cos(density * self.phase)) / 2
         # Calculate the phase gradients, expressed by magnitude and angle:
@@ -374,11 +427,24 @@ class PhaseMap(object):
         phase_angle = (1 - np.arctan2(phase_grad_y, phase_grad_x)/pi) / 2
         phase_magnitude = np.hypot(phase_grad_x, phase_grad_y)
         if phase_magnitude.max() != 0:
-            phase_magnitude = np.sin(phase_magnitude/phase_magnitude.max() * pi / 2)
+            saturation = np.sin(phase_magnitude/phase_magnitude.max() * pi / 2)
+            phase_saturation = np.dstack((saturation,)*4)
         # Color code the angle and create the holography image:
-        rgba = self.HOLO_CMAP(phase_angle)
-        rgb = (255.999 * img_holo.T * phase_magnitude.T * rgba[:, :, :3].T).T.astype(np.uint8)
-        holo_image = Image.fromarray(rgb) 
+        if grad_encode == 'dark':
+            rgba = self.HOLO_CMAP(phase_angle)
+            rgb = (255.999 * img_holo.T * saturation.T * rgba[:, :, :3].T).T.astype(np.uint8)
+        elif grad_encode == 'bright':
+            rgba = self.HOLO_CMAP(phase_angle)+(1-phase_saturation)*self.HOLO_CMAP_INV(phase_angle)
+            rgb = (255.999 * img_holo.T * rgba[:, :, :3].T).T.astype(np.uint8)
+        elif grad_encode == 'color':
+            rgba = self.HOLO_CMAP(phase_angle)
+            rgb = (255.999 * img_holo.T * rgba[:, :, :3].T).T.astype(np.uint8)
+        elif grad_encode == 'none':
+            rgba = self.HOLO_CMAP(phase_angle)+self.HOLO_CMAP_INV(phase_angle)
+            rgb = (255.999 * img_holo.T * rgba[:, :, :3].T).T.astype(np.uint8)
+        else:
+            raise AssertionError('Gradient encoding not recognized!') 
+        holo_image = Image.fromarray(rgb)
         # If no axis is specified, a new figure is created:
         if axis is None:
             fig = plt.figure()
@@ -397,11 +463,13 @@ class PhaseMap(object):
         axis.xaxis.set_major_locator(MaxNLocator(nbins=9, integer=True))
         axis.yaxis.set_major_locator(MaxNLocator(nbins=9, integer=True))
         # Show Plot:
-        plt.show()
+        if show:
+            plt.show()
         # Return plotting axis:
         return axis
     
-    def display_combined(self, density=1, title='Combined Plot', interpolation='none'):
+    def display_combined(self, density=1, title='Combined Plot', interpolation='none',
+                         grad_encode='dark'):
         '''Display the phase map and the resulting color coded holography image in one plot.
     
         Parameters
@@ -419,21 +487,25 @@ class PhaseMap(object):
         phase_axis, holo_axis: :class:`~matplotlib.axes.AxesSubplot`
             The axes on which the graphs are plotted.
     
-        '''
+        '''# TODO: Docstring grad_encode!
+        self.log.info('Calling display_combined')
         # Create combined plot and set title:
         fig = plt.figure(figsize=(16, 7))
         fig.suptitle(title, fontsize=20)
         # Plot holography image:
         holo_axis = fig.add_subplot(1, 2, 1, aspect='equal')
-        self.display_holo(density=density, axis=holo_axis, interpolation=interpolation)
+        self.display_holo(density=density, axis=holo_axis, interpolation=interpolation,
+                          show=False, grad_encode=grad_encode)
         # Plot phase map:
         phase_axis = fig.add_subplot(1, 2, 2, aspect='equal')
         fig.subplots_adjust(right=0.85)
-        self.display_phase(axis=phase_axis)
+        self.display_phase(axis=phase_axis, show=False)
+        plt.show()
         # Return the plotting axes:
         return phase_axis, holo_axis
 
-    def make_color_wheel(self):
+    @classmethod
+    def make_color_wheel(cls):
         '''Display a color wheel to illustrate the color coding of the gradient direction.
     
         Parameters
@@ -445,6 +517,7 @@ class PhaseMap(object):
         None
     
         '''
+        cls.log.info('Calling make_color_wheel')
         x = np.linspace(-256, 256, num=512)
         y = np.linspace(-256, 256, num=512)
         xx, yy = np.meshgrid(x, y)
@@ -454,7 +527,7 @@ class PhaseMap(object):
         color_wheel_magnitude *= 0 * (r > 256) + 1 * (r <= 256)
         color_wheel_angle = (1 - np.arctan2(xx, -yy)/pi) / 2
         # Color code the angle and create the holography image:
-        rgba = self.HOLO_CMAP(color_wheel_angle)
+        rgba = cls.HOLO_CMAP(color_wheel_angle)
         rgb = (255.999 * color_wheel_magnitude.T * rgba[:, :, :3].T).T.astype(np.uint8)
         color_wheel = Image.fromarray(rgb)
         # Plot the color wheel:
@@ -463,3 +536,7 @@ class PhaseMap(object):
         axis.imshow(color_wheel, origin='lower')
         axis.xaxis.set_major_locator(NullLocator())
         axis.yaxis.set_major_locator(NullLocator())
+        plt.show()
+
+
+PhaseMap.make_color_wheel()
diff --git a/pyramid/phasemapper.py b/pyramid/phasemapper.py
index e6421d279f8b0299c46c7db831aee666ee62d56d..772e6faae8f1356f1321f18808ee0fcca58cd52c 100644
--- a/pyramid/phasemapper.py
+++ b/pyramid/phasemapper.py
@@ -14,7 +14,7 @@ from numpy import pi
 
 import abc
 
-import pyramid.numcore as nc
+import pyramid.numcore.kernel_core as nc
 from pyramid.kernel import Kernel
 from pyramid.projector import Projector
 from pyramid.magdata import MagData
@@ -46,13 +46,13 @@ class PMAdapterFM(PhaseMapper):
         assert isinstance(projector, Projector), 'Argument has to be a Projector object!'
         self.a = a
         self.projector = projector
-        self.fwd_model = ForwardModel([projector], Kernel(a, projector.dim, b_0, geometry))
+        self.fwd_model = ForwardModel([projector], Kernel(a, projector.dim_2d, b_0, geometry))
 
     def __call__(self, mag_data):
         assert isinstance(mag_data, MagData), 'Only MagData objects can be mapped!'
         assert  mag_data.a == self.a, 'Grid spacing has to match!'
         # TODO: test if mag_data fits in all aspects
-        phase_map = PhaseMap(self.a, np.zeros(self.projector.dim))
+        phase_map = PhaseMap(self.a, np.zeros(self.projector.dim_2d))
         phase_map.phase_vec = self.fwd_model(mag_data.mag_vec)
         return phase_map
 
@@ -94,11 +94,12 @@ class PMFourier(PhaseMapper):
         assert isinstance(mag_data, MagData), 'Only MagData objects can be mapped!'
         assert  mag_data.a == self.a, 'Grid spacing has to match!'
         # TODO: test if mag_data fits in all aspects (especially with projector)
-        v_dim, u_dim = self.projector.dim
-        u_mag, v_mag = self.projector(mag_data.mag_vec).reshape((2,)+self.projector.dim)
+        v_dim, u_dim = self.projector.dim_2d
+        u_mag, v_mag = self.projector(mag_data.mag_vec).reshape((2,)+self.projector.dim_2d)
         # Create zero padded matrices:
         u_pad = u_dim/2 * self.padding
         v_pad = v_dim/2 * self.padding
+        # TODO: use mag_data.padding or np.pad(...)
         u_mag_big = np.zeros(((1 + self.padding) * v_dim, (1 + self.padding) * u_dim))
         v_mag_big = np.zeros(((1 + self.padding) * v_dim, (1 + self.padding) * u_dim))
         u_mag_big[v_pad:v_pad+v_dim, u_pad:u_pad+u_dim] = u_mag
@@ -218,12 +219,12 @@ class PMConvolve(PhaseMapper):
         self.a = a
         self.projector = projector
         self.threshold = threshold
-        self.kernel = Kernel(a, projector.dim, b_0, geometry)
+        self.kernel = Kernel(a, projector.dim_2d, b_0, geometry)
 
     def __call__(self, mag_data):
         # Docstring!
         # Process input parameters:
-        u_mag, v_mag = self.projector(mag_data.mag_vec).reshape((2,)+self.projector.dim)    
+        u_mag, v_mag = self.projector(mag_data.mag_vec).reshape((2,)+self.projector.dim_2d)    
         # Fourier transform the projected magnetisation:
         kernel = self.kernel
         u_mag_fft = np.fft.rfftn(u_mag, kernel.dim_fft)
@@ -267,15 +268,14 @@ class PMReal(PhaseMapper):
         self.a = a
         self.projector = projector
         self.threshold = threshold
-        self.kernel = Kernel(a, projector.dim, b_0, geometry)
+        self.kernel = Kernel(a, projector.dim_2d, b_0, geometry)
         self.numcore = numcore
 
     def __call__(self, mag_data):
         # TODO: Docstring
         # Process input parameters: 
-        dim = self.projector.dim
+        dim = self.projector.dim_2d
         threshold = self.threshold
-        v_dim, u_dim = self.projector.dim
         u_mag, v_mag = self.projector(mag_data.mag_vec).reshape((2,)+dim)
         # Create kernel (lookup-tables for the phase of one pixel):
         u_phi = self.kernel.u
diff --git a/pyramid/projector.py b/pyramid/projector.py
index 28538574af512f14876a13ca175238b3274a0744..85e86415f3f102859b3bcfc2dce931b301799060 100644
--- a/pyramid/projector.py
+++ b/pyramid/projector.py
@@ -1,13 +1,9 @@
 # -*- coding: utf-8 -*-
-"""Create projections of a given magnetization distribution.
+"""This module provides the abstract base class :class:`~.Projector` and concrete subclasses for
+projections of vector and scalar fields."""
 
-This module creates 2-dimensional projections from 3-dimensional magnetic distributions, which
-are stored in :class:`~pyramid.magdata.MagData` objects. Either simple projections along the
-major axes are possible (:func:`~.simple_axis_projection`), or projections with a tilt around
-the y-axis. The thickness profile is also calculated and can be used for electric phase maps.
-
-"""
 
+import logging
 
 import numpy as np
 from numpy import pi
@@ -16,59 +12,68 @@ import abc
 
 import itertools
 
-import scipy.sparse as sp
-from scipy.sparse import coo_matrix, csr_matrix, csr_matrix
-
-from pyramid.magdata import MagData
-
-
-
-
-
-
+from scipy.sparse import coo_matrix, csr_matrix
 
 
 class Projector(object):
 
-    '''
+    '''Abstract base class representing a projection function.
+    
+    The :class:`~.Projector` class represents a projection function for a 3-dimensional
+    vector- or scalar field onto a 2-dimensional grid. :class:`~.Projector` is an abstract base
+    class and provides a unified interface which should be subclassed with a custom
+    :func:`__init__` function, which should call the parent :func:`__init__` method. Concrete
+    subclasses can be called as a function and take a `vector` as argument which contains the
+    3-dimensional field. The output is the projected field, given as a `vector`. Depending on the
+    length of the input and the given dimensions `dim` at construction time, vector or scalar
+    projection is choosen intelligently.
 
     Attributes
     ----------
-    
+    dim_2d : tuple (N=2)
+        Dimensions (v, u) of the projected grid.
+    size_3d : int
+        Number of voxels of the 3-dimensional grid.
+    size_2d : int
+        Number of pixels of the 2-dimensional projected grid.
+    weight : :class:`~scipy.sparse.csr_matrix` (N=2)
+        The weight matrix containing the weighting coefficients describing the influence of all
+        3-dimensional voxels on the 2-dimensional pixels of the projection.
+    coeff : list (N=2)
+        List containing the six weighting coefficients describing the influence of the 3 components
+        of a 3-dimensional vector field on the 2 projected components.
 
-    
-    ''' # TODO: Docstring!
+    '''
 
     __metaclass__ = abc.ABCMeta
 
     @abc.abstractmethod
     def __init__(self, (dim_v, dim_u), weight, coeff):
-        #TODO: Docstring!
-        self.dim = (dim_v, dim_u)  # TODO: are they even used?
+        self.log = logging.getLogger(__name__)
+        self.log.info('Calling __init__')
+        self.dim_2d = (dim_v, dim_u)
         self.weight = weight
         self.coeff = coeff
         self.size_2d, self.size_3d = weight.shape
+        self.log.info('Created '+str(self))
 
     def __call__(self, vector):
-        # TODO: Docstring!
-        assert any([len(vector) == i*self.size_3d for i in (1, 3)]), \
-            'Vector size has to be suited either for vector- or scalar-field-projection!'
+        self.log.info('Calling as function')         
         if len(vector) == 3*self.size_3d:  # mode == 'vector'
+            self.log.info('mode == vector')
             return self._vector_field_projection(vector)
         elif len(vector) == self.size_3d:  # mode == 'scalar'
+            self.log.info('mode == scalar')
             return self._scalar_field_projection(vector)
-        # TODO: Raise Assertion Error
+        else:
+            raise AssertionError('Vector size has to be suited either for ' \
+                                 'vector- or scalar-field-projection!')
 
     def _vector_field_projection(self, vector):
-        # TODO: Docstring!
+        self.log.info('Calling _vector_field_projection')
         size_2d, size_3d = self.size_2d, self.size_3d
         result = np.zeros(2*size_2d)
-#        for j in range(2):
-#            for i in range(3):
-#                if coefficient[j, i] != 0:
-#                    result[j*self.size_2d:(j+1)*self.size_2d] += self.coeff[j, i] * self.weight.dot(vector[j*length:(j+1)*length])
-        # x_vec, y_vec, z_vec = vector[:length], vector[length:2*length], vector[2*length]
-        # TODO: Which solution?
+        # Go over all possible component projections (z, y, x) to (u, v):
         if self.coeff[0][0] != 0:  # x to u
             result[:size_2d] += self.coeff[0][0] * self.weight.dot(vector[:size_3d])
         if self.coeff[0][1] != 0:  # y to u
@@ -84,30 +89,87 @@ class Projector(object):
         return result
 
     def _scalar_field_projection(self, vector):
-        # TODO: Docstring!
-        # TODO: Implement smarter weight-multiplication!
+        self.log.info('Calling _scalar_field_projection')
         return np.array(self.weight.dot(vector))
 
     def jac_dot(self, vector):
-        return self._vector_field_projection(vector)
+        '''Multiply a `vector` with the jacobi matrix of this :class:`~.Projector` object.
+
+        Parameters
+        ----------
+        vector : :class:`~numpy.ndarray` (N=1)
+            Vector containing the field which should be projected. Must have the same or 3 times
+            the size of `size_3d` of the projector for  scalar and vector projection, respectively.
+
+        Returns
+        -------
+        proj_vector : :class:`~numpy.ndarray` (N=1)
+            Vector containing the projected field of the 2-dimensional grid. The length is
+            always`size_2d`.
 
+        '''
+        self.log.info('Calling jac_dot')
+        return self(vector)
 
 
 
 class YTiltProjector(Projector):
 
+#    '''Class representing a projection where the projection axis is tilted around the y-axis.
+#    
+#    The :class:`~.YTiltProjector` class is a concrete subclass of the :class:`~.Projector` class
+#    and overwrites the :func:`__init__` constructor which accepts `dim` and `tilt` as arguments.
+#    The dimensions of the 3-dimensional grid are given by `dim`, the tilting angle of the ample
+#    around the y-axis is given by `tilt`.
+#
+#    Attributes
+#    ----------
+#    dim_2d : tuple (N=2)
+#        Dimensions (v, u) of the projected grid.
+#    size_3d : int
+#        Number of voxels of the 3-dimensional grid.
+#    size_2d : int
+#        Number of pixels of the 2-dimensional projected grid.
+#    weight : :class:`~scipy.sparse.csr_matrix` (N=2)
+#        The weight matrix containing the weighting coefficients describing the influence of all
+#        3-dimensional voxels on the 2-dimensional pixels of the projection.
+#    coeff : list (N=2)
+#        List containing the six weighting coefficients describing the influence of the 3 components
+#        of a 3-dimensional vector field on the 2 projected components.
+#    '''
+#
+#    '''
+#    weight : :class:`~scipy.sparse.csr_matrix` (N=2)
+#        The weight matrix containing the weighting coefficients which determine the influence of
+#        all 3-dimensional voxels to the 2-dimensional pixels of the projection.
+#    coeff : `list`t (N=2)
+#        List containing the six weighting coefficients describing the influence of the 3 components
+#        of a 3-dimensional vector fields on the 2 components of the projected field. Only used for
+#        vector field projection.
+#
+#    Notes
+#    -----
+#    An instance `projector` of the :class:`~.YSimpleProjector` class is callable via:
+#    
+#    :func:`projector(vector)`
+#    
+#    with `vector` being a :class:`~numpy.ndarray` (N=1).
+#    '''
+
     def __init__(self, dim, tilt):
-        # TODO: Docstring!
-        # TODO: Implement!
+
         def get_position(p, m, b, size):
+            self.log.info('Calling get_position')
             y, x = np.array(p)[:, 0]+0.5, np.array(p)[:, 1]+0.5
             return (y-m*x-b)/np.sqrt(m**2+1) + size/2.
     
         def get_impact(pos, r, size):
+            self.log.info('Calling get_impact')
             return [x for x in np.arange(np.floor(pos-r), np.floor(pos+r)+1, dtype=int)
                     if 0 <= x < size]
     
         def get_weight(delta, rho):  # use circles to represent the voxels
+            self.log.info('Calling get_weight')
             lo, up = delta-rho, delta+rho
             # Upper boundary:
             if up >= 1:
@@ -121,21 +183,21 @@ class YTiltProjector(Projector):
                 w_lo = (lo*np.sqrt(1-lo**2) + np.arctan(lo/np.sqrt(1-lo**2))) / pi
             return w_up - w_lo
 
+        self.log = logging.getLogger(__name__)
+        self.log.info('Calling __init__')
+        self.tilt = tilt
         # Set starting variables:
         # length along projection (proj, z), rotation (rot, y) and perpendicular (perp, x) axis:
         dim_proj, dim_rot, dim_perp = dim
         size_2d = dim_rot * dim_perp
         size_3d = dim_proj * dim_rot * dim_perp
-        
         # Creating coordinate list of all voxels:
         voxels = list(itertools.product(range(dim_proj), range(dim_perp)))
-    
         # Calculate positions along the projected pixel coordinate system:
         center = (dim_proj/2., dim_perp/2.)
         m = np.where(tilt<=pi, -1/np.tan(tilt+1E-30), 1/np.tan(tilt+1E-30))
         b = center[0] - m * center[1]
         positions = get_position(voxels, m, b, dim_perp)
-        
         # Calculate weight-matrix:
         r = 1/np.sqrt(np.pi)  # radius of the voxel circle
         rho = 0.5 / r
@@ -151,57 +213,80 @@ class YTiltProjector(Projector):
                 col.append(voxel[0]*size_2d + voxel[1])
                 row.append(impact)
                 data.append(get_weight(delta, rho))
-        # all other slices:
+        # All other slices:
         columns = col
         rows = row
         for i in np.arange(1, dim_rot):  # TODO: more efficient, please!
             columns = np.hstack((np.array(columns), np.array(col)+i*dim_perp))
             rows = np.hstack((np.array(rows), np.array(row)+i*dim_perp))
-
+        # Calculate weight matrix and coefficients for jacobi matrix:
         weight = csr_matrix(coo_matrix((np.tile(data, dim_rot), (rows, columns)),
-                                               shape = (size_2d, size_3d)))
+                                                shape = (size_2d, size_3d)))
         dim_v, dim_u = dim_rot, dim_perp
         coeff = [[np.cos(tilt), 0, np.sin(tilt)], [0, 1, 0]]
         super(YTiltProjector, self).__init__((dim_v, dim_u), weight, coeff)
+        self.log.info('Created '+str(self))
 
 
 class SimpleProjector(Projector):
 
-    # TODO: Docstring!
+#    '''Class representing a projection along one of the major axes (x, y, z).
+#    
+#    The :class:`~.SimpleProjector` class is a concrete subclass of the :class:`~.Projector` class
+#    and overwrites the :func:`__init__` constructor which accepts `dim` and `axis` as arguments.
+#    The dimensions of the 3-dimensional grid are given by `dim`, the major axis along which to
+#    project is given by `axis` and can be `'x'`, `'y'` or `'z'` (default).
+#
+#    Attributes
+#    ----------
+#    dim_2d : tuple (N=2)
+#        Dimensions (v, u) of the projected grid.
+#    weight : :class:`~scipy.sparse.csr_matrix` (N=2)
+#        The weight matrix containing the weighting coefficients which determine the influence of
+#        all 3-dimensional voxels to the 2-dimensional pixels of the projection.
+#    coeff : list (N=2)
+#        List containing the six weighting coefficients describing the influence of the 3 components
+#        of a 3-dimensional vector fields on the 2 components of the projected field. Only used for
+#        vector field projection.
+#    size_3d : int
+#        Number of voxels of the 3-dimensional grid.
+#    size_2d : int
+#        Number of pixels of the 2-dimensional projected grid.
+#
+#    Notes
+#    -----
+#    An instance `projector` of the :class:`~.SimpleProjector` class is callable via:
+#    
+#    :func:`projector(vector)`
+#
+#    with `vector` being a :class:`~numpy.ndarray` (N=1).
+#
+#    '''
+
+    AXIS_DICT = {'z': (0, 1, 2), 'y': (1, 0, 2), 'x': (1, 2, 0)}
 
     def __init__(self, dim, axis='z'):
-        # TODO: Docstring!
+        self.log = logging.getLogger(__name__)
+        self.log.info('Calling __init__')
+        proj, v, u = self.AXIS_DICT[axis]
+        dim_proj, dim_v, dim_u = dim[proj], dim[v], dim[u]
+        dim_z, dim_y, dim_x = dim
+        size_2d = dim_u * dim_v
+        size_3d = np.prod(dim)
+        data = np.repeat(1, size_3d)
+        indptr = np.arange(0, size_3d+1, dim_proj)
         if axis == 'z':
-            dim_z, dim_y, dim_x = dim   # TODO: in functions
-            dim_proj, dim_v, dim_u = dim
-            size_2d = dim_u * dim_v
-            size_3d = dim_x * dim_y * dim_z
-            data = np.repeat(1, size_3d)
-            indptr = np.arange(0, size_3d+1, dim_proj)
+            coeff = [[1, 0, 0], [0, 1, 0]]
             indices = np.array([np.arange(row, size_3d, size_2d) 
                                 for row in range(size_2d)]).reshape(-1)
-            weight = csr_matrix((data, indices, indptr), shape = (size_2d, size_3d))
-            coeff = [[1, 0, 0], [0, 1, 0]]
         elif axis == 'y':
-            dim_z, dim_y, dim_x = dim
-            dim_v, dim_proj, dim_u = dim
-            size_2d = dim_u * dim_v
-            size_3d = dim_x * dim_y * dim_z
-            data = np.repeat(1, size_3d)
-            indptr = np.arange(0, size_3d+1, dim_proj)
+            coeff = [[1, 0, 0], [0, 0, 1]]
             indices = np.array([np.arange(row%dim_x, dim_x*dim_y, dim_x)+int(row/dim_x)*dim_x*dim_y
                                 for row in range(size_2d)]).reshape(-1)
-            weight = csr_matrix((data, indices, indptr), shape = (size_2d, size_3d))
-            coeff = [[1, 0, 0], [0, 0, 1]]
         elif axis == 'x':
-            dim_z, dim_y, dim_x = dim
-            dim_v, dim_u, dim_proj = dim
-            size_2d = dim_u * dim_v
-            size_3d = dim_x * dim_y * dim_z
-            data = np.repeat(1, size_3d)
-            indptr = np.arange(0, size_3d+1, dim_proj)
+            coeff = [[0, 1, 0], [0, 0, 1]]
             indices = np.array([np.arange(dim_proj) + row*dim_proj
                                 for row in range(size_2d)]).reshape(-1)
-            weight = csr_matrix((data, indices, indptr), shape = (size_2d, size_3d))
-            coeff = [[0, 1, 0], [0, 0, 1]]  
+        weight = csr_matrix((data, indices, indptr), shape = (size_2d, size_3d))
         super(SimpleProjector, self).__init__((dim_v, dim_u), weight, coeff)
+        self.log.info('Created '+str(self))
diff --git a/regrid/array.cpp b/regrid/array.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..23d46f36ef2d50e8f4d3111684f9943b18716ea9
--- /dev/null
+++ b/regrid/array.cpp
@@ -0,0 +1,46 @@
+#define NO_IMPORT_ARRAY
+
+#include "gloripex.hpp"
+#include "array.hpp"
+
+namespace gloripex {
+    using namespace boost::python;
+    /// Converts a numpy array to an Array instance if possible. Uses
+    /// constructor of Array class, but needs to manually generate a boost
+    /// object from raw pointer..
+    template <class T>
+    struct ArrayConverter {
+        ArrayConverter() {
+            converter::registry::push_back(&convertible, &construct, type_id<T>());
+        }
+
+        static void* convertible(PyObject* obj_ptr) {
+           return is_object_convertible_to_array<T>(obj_ptr) ? obj_ptr : 0;
+        }
+
+      /// See here for an explanation
+      /// http://mail.python.org/pipermail/cplusplus-sig/2008-October/013895.html
+        static void construct(PyObject* obj_ptr,
+                              converter::rvalue_from_python_stage1_data* data)
+        {
+            object obj(handle<>(borrowed(obj_ptr)));
+            data->convertible = (reinterpret_cast<converter::rvalue_from_python_storage<T>*> (data))->storage.bytes;
+            new (data->convertible) T(obj);
+        }
+    };
+
+  // Add converters as necessary
+  ArrayConverter<Array<cub_t, 1> > array_cub_t_1_converter;
+  ArrayConverter<Array<cub_t, 2> > array_cub_t_2_converter;
+  ArrayConverter<Array<cub_t, 3> > array_cub_t_3_converter;
+
+  ArrayConverter<Array<float, 1> > array_float_1_converter;
+  ArrayConverter<Array<float, 2> > array_float_2_converter;
+  ArrayConverter<Array<float, 3> > array_float_3_converter;
+
+  ArrayConverter<Array<double, 1> > array_double_1_converter;
+  ArrayConverter<Array<double, 2> > array_double_2_converter;
+  ArrayConverter<Array<double, 3> > array_double_3_converter;
+
+  ArrayConverter<Array<size_t, 1> > array_sizet_1_converter;
+}
diff --git a/regrid/array.hpp b/regrid/array.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..6b0b2685a7e8af0e447dc73d2781928bde520dd0
--- /dev/null
+++ b/regrid/array.hpp
@@ -0,0 +1,162 @@
+//
+// Copyright 2013 by Forschungszentrum Juelich GmbH
+//
+
+#ifndef GLORIPEX_ARRAY_HPP
+#define GLORIPEX_ARRAY_HPP
+
+#include "numpy.hpp"
+
+namespace gloripex {
+
+#pragma GCC diagnostic ignored "-Wold-style-cast"
+    /// Determines whether a python object is a numpy array fitting to the Array
+    /// type supplied by T.
+    ///
+    /// Example:
+    /// if (is_object_convertible_to_array<Array<double, 3> >(obj_ptr)) { ... }
+    template<typename T>
+    bool is_object_convertible_to_array(PyObject* obj_ptr) {
+        return (PyArray_Check(obj_ptr) &&
+                PyArray_TYPE(obj_ptr) == numpy::getTypeID(typename T::value_type()) &&
+                PyArray_NDIM(obj_ptr) == T::ndim());
+    }
+#pragma GCC diagnostic warning "-Wold-style-cast"
+
+    /// \brief A fast array class suited to our needs. Based on the Blitz++
+    /// concept without the fancy stuff.
+    template<typename T, int ndimm>
+    struct Array {
+        // some typedefs for making this STL compatible
+        typedef Array<T, ndimm> type;
+        typedef T value_type;
+        typedef T* iterator;
+        typedef const T* const_iterator;
+        typedef T& reference;
+        typedef const T& const_reference;
+        typedef size_t size_type;
+
+        /// Function that provides a neat wrapper around numpy arrays. No copying is
+        /// performed. User needs to supply dimensionality and type, but it is
+        /// checked during runtime, if it fits!
+        ///
+        /// object is const, but this class does not really care about this...
+        /// Instantiate a const Array if object should really be const.
+        Array(const python::object& object) :
+            object_(object),
+            data_(static_cast<T*>(numpy::getArrayData(this->object_)))
+        {
+            this->initialise();
+        }
+
+        /// This function creates a numpy array. It may be accessed later on
+        /// with the object member function, e.g. for returning it to python.
+        Array(const std::vector<npy_intp>& dims) :
+            object_(numpy::createFromScratch<T>(dims)),
+            data_(static_cast<T*>(numpy::getArrayData(this->object_)))
+        {
+            this->initialise();
+        }
+
+        Array(const Array<T, ndimm>& other) :
+            object_(other.object_),
+            data_(static_cast<T*>(numpy::getArrayData(this->object_)))
+        {
+            this->initialise();
+        }
+
+        /// 1D access
+        inline const T& operator() (size_type idx0) const {
+            static_assert(ndimm == 1, "dimensionality does not fit function call");
+            return this->data()[idx0 * this->stride(0)];
+        }
+        /// 1D access
+        inline T& operator() (size_type idx0) {
+            static_assert(ndimm == 1, "dimensionality does not fit function call");
+            return this->data()[idx0 * this->stride(0)];
+        }
+        /// 2D access
+        inline const T& operator() (size_type idx0, size_type idx1) const {
+            static_assert(ndimm == 2, "dimensionality does not fit function call");
+            return this->data()[idx0 * this->stride(0) + idx1 * this->stride(1)];
+        }
+        /// 2D access
+        inline T& operator() (size_type idx0, size_type idx1) {
+            static_assert(ndimm == 2, "dimensionality does not fit function call");
+            return this->data()[idx0 * this->stride(0) + idx1 * this->stride(1)];
+        }
+        /// 3D access
+        inline const T& operator() (size_type idx0, size_type idx1, size_type idx2) const {
+            static_assert(ndimm == 3, "dimensionality does not fit function call");
+            return this->data()[idx0 * this->stride(0) + idx1 * this->stride(1) +
+                                idx2 * this->stride(2)];
+        }
+        /// 3D access
+        inline T& operator() (size_type idx0, size_type idx1, size_type idx2) {
+            static_assert(ndimm == 3, "dimensionality does not fit function call");
+            return this->data()[idx0 * this->stride(0) + idx1 * this->stride(1) +
+                                idx2 * this->stride(2)];
+        }
+
+        inline iterator begin() { return this->data(); }
+        inline const_iterator begin() const { return this->data(); }
+        inline iterator end() { return this->data() + this->size(); }
+        inline const_iterator end()  const { return this->data() + this->size(); }
+
+        /// returns the number of dimensions.
+        static inline int ndim() { return ndimm; }
+
+        /// returns the total size of the array
+        size_type size() const {
+            size_type result = shape(0);
+            for (int i = 1; i < this->ndim(); ++ i) {
+                result *= this->shape(i);
+            }
+            return result;
+        }
+        /// This function explores the shape of the array.
+        inline size_type shape(size_type dim) const {
+            assert(0 <= dim && dim < ndimm);
+            return static_cast<size_type>(numpy::getArrayDims(this->object_)[dim]);
+        }
+        /// This function explores the strides of the array.
+        inline size_type stride(size_type dim) const { return this->stride_[dim]; }
+        /// Returns pointer to underlying data.
+        inline T* data() const { return this->data_; }
+
+        /// Returns the wrapped object.
+        inline python::object object() const { return this->object_; }
+
+        template<typename T2, int ndim2>
+        friend std::ostream& operator<<(std::ostream& os, const Array<T2, ndim2>& a);
+
+    private:
+
+        void initialise() {
+            assert(is_object_convertible_to_array<type>(this->object_.ptr()));
+
+            for (int i = 0; i < ndimm; ++ i) {
+                this->stride_[i] = numpy::getArrayStrides(this->object_)[i] / sizeof(T);
+            }
+        }
+
+    protected:
+        /// Reference to python array object
+        python::object object_;
+        /// Holds the a pointer to the memory of the array (regardless of who manages it).
+        T* data_;
+        /// \brief Stores the stride of the array (e.g., 20(=4*5) and 5 for a
+        /// 3x4x5 array).
+        size_type stride_[ndimm];
+    };
+
+    // ****************************************************************************
+
+    template<typename T2, int ndim2>
+    std::ostream& operator<<(std::ostream& os, const Array<T2, ndim2>& a) {
+        os << python::extract<std::string>(a.object_.attr("__str__")())();
+        return os;
+    }
+}
+
+#endif
diff --git a/regrid/gloripex.hpp b/regrid/gloripex.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..511b96f3838555a63f6c983f02fa272af885bfbb
--- /dev/null
+++ b/regrid/gloripex.hpp
@@ -0,0 +1,95 @@
+//
+// Copyright 2013 by Forschungszentrum Juelich GmbH
+//
+#ifndef GLORIPEX_HPP
+#define GLORIPEX_HPP
+
+// this removes strange linkage issues with extensions covering multiple files
+#define PY_ARRAY_UNIQUE_SYMBOL GLORIPEX_PY_ARRAY
+
+#include <iostream>
+#include <iomanip>
+#include <sstream>
+#include <vector>
+#include <complex>
+#include <boost/python/detail/wrap_python.hpp>
+#include <boost/python.hpp>
+#include <numpy/arrayobject.h>
+
+#ifdef _OPENMP
+#include <omp.h>
+#endif
+
+
+namespace std {
+    /// Conveniencev  vvc ostream operator for std::vector.
+    template<typename T>
+    inline std::ostream& operator<<(std::ostream& os, const std::vector<T>& vec) {
+        os << "[";
+        for (typename std::vector<T>::size_type i = 0; i < vec.size(); ++ i) {
+            os << (i == 0 ? "" : ", ") << vec[i];
+        }
+        os << "]";
+        return os;
+    }
+
+    /// Convenience ostream operator for std::vector<std::string>.
+    template<>
+    inline std::ostream& operator<<(std::ostream& os, const std::vector<std::string>& vec) {
+        os << "[";
+        for (std::vector<std::string>::size_type i = 0; i < vec.size(); ++ i) {
+            os << (i == 0 ? "'" : ", '") << vec[i] << "'";
+        }
+        os << "]";
+        return os;
+    }
+}
+
+
+namespace gloripex {
+    namespace python = boost::python;
+
+    typedef std::complex<float> complex64;
+    typedef std::complex<double> complex128;
+    typedef uint16_t cub_t;
+
+    /// Simple struct for error handling.
+    ///
+    /// This should be the base struct of all gloripy Exceptions. It is
+    /// translated to a python runtime error.
+    struct Exception : std::exception {
+        std::string msg_;
+        Exception(std::string msg)  : msg_(msg) {}
+        virtual ~Exception() throw() {}
+        virtual char const* what() const throw() { return msg_.c_str(); }
+    };
+
+    /// An assert that throws an exception instead of aborting the program.
+#ifndef NDEBUG
+#define gassert(cond, msg)                              \
+    if (!(cond)) {                                      \
+        std::ostringstream message;                     \
+        message << __FILE__ << ":"                      \
+                << std::setw(4) << __LINE__ << ": "     \
+                << msg << std::endl;                    \
+        throw Exception(message.str());                 \
+    }
+#else
+#define gassert(cond, msg) (void) (0)
+#endif
+
+    /// This functions takes a datum and returns a string representation.
+    template<typename T>
+    inline std::string toString(const T& object) {
+        std::stringstream result;
+        result << object;
+        return result.str();
+    }
+
+    /// Allows printing of all boost::python wrapped python objects.
+    inline std::ostream& operator<<(std::ostream& os, const python::object& object) {
+        os << python::extract<std::string>(object.attr("__str__")())();
+        return os;
+    }
+}
+#endif
diff --git a/regrid/numpy.hpp b/regrid/numpy.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..568b6302d8d2ffcb0482ce1f3aaefcba193c9857
--- /dev/null
+++ b/regrid/numpy.hpp
@@ -0,0 +1,93 @@
+//
+// Copyright 2013 by Forschungszentrum Juelich GmbH
+//
+
+#ifndef GLORIPEX_NUMPY
+#define GLORIPEX_NUMPY
+
+
+namespace gloripex {
+    namespace numpy {
+      typedef python::numeric::array ndarray;
+
+        inline int getTypeID(float) { return NPY_FLOAT; }
+        inline int getTypeID(double) { return NPY_DOUBLE; }
+        inline int getTypeID(long double) { return NPY_LONGDOUBLE; }
+        inline int getTypeID(signed char) { return NPY_BYTE; }
+        inline int getTypeID(unsigned char) { return NPY_UBYTE; }
+        inline int getTypeID(int) { return NPY_INT; }
+        inline int getTypeID(unsigned int) { return NPY_UINT; }
+        inline int getTypeID(short) { return NPY_SHORT; }
+        inline int getTypeID(unsigned short) { return NPY_USHORT; }
+        inline int getTypeID(unsigned long) { return NPY_ULONG; }
+        inline int getTypeID(long) { return NPY_LONG; }
+
+
+        inline int getArrayType(const python::object &x) {
+            return reinterpret_cast<PyArrayObject*>(x.ptr())->descr->type_num;
+        }
+
+        inline npy_intp* getArrayDims(const python::object &x) {
+            return reinterpret_cast<PyArrayObject*>(x.ptr())->dimensions;
+        }
+
+        inline npy_intp* getArrayStrides(const python::object &x) {
+            return reinterpret_cast<PyArrayObject*>(x.ptr())->strides;
+        }
+
+        inline int getArrayNDims(const python::object &x) {
+            return reinterpret_cast<PyArrayObject*>(x.ptr())->nd;
+        }
+
+        inline void* getArrayData(const python::object &x) {
+            return reinterpret_cast<PyArrayObject*>(x.ptr())->data;
+        }
+
+        inline PyArray_Descr* getArrayDescription(const python::object &x) {
+            return reinterpret_cast<PyArrayObject*>(x.ptr())->descr;
+        }
+
+        inline int getArrayItemsize(const python::object &x) {
+            return reinterpret_cast<PyArrayObject*>(x.ptr())->descr->elsize;
+        }
+
+        template<typename T>
+        inline T* getArrayDataAs(const python::object &x) {
+            return reinterpret_cast<T*>(getArrayData(x));
+        }
+
+#pragma GCC diagnostic ignored "-Wold-style-cast"
+        inline bool isArray(const python::object &x) {
+            return PyArray_Check(x.ptr());
+        }
+
+        /// Creates an empty python array.
+        template<typename T>
+        inline ndarray createFromScratch(const std::vector<npy_intp>& dims) {
+            PyObject* ptr = PyArray_SimpleNew(
+                    static_cast<int>(dims.size()),
+                    const_cast<npy_intp*>(&dims[0]),
+                    getTypeID(T()));
+            python::handle<> hndl(ptr);
+            return ndarray(hndl);
+        }
+
+        /// Creates a python array from existing memory. As the lifetime of the
+        /// python object cannot be controlled, it is rather dangerous to delete
+        /// the memory. Use with utmost care.
+        template<typename T>
+        inline ndarray createFromData(
+                const std::vector<npy_intp>& dims, T* data) {
+            PyObject* ptr = PyArray_SimpleNewFromData(
+                    static_cast<int>(dims.size()),
+                    const_cast<npy_intp*>(&dims[0]),
+                    getTypeID(T()),
+                    data);
+            python::handle<> hndl(ptr);
+            return ndarray(hndl);
+        }
+#pragma GCC diagnostic warning "-Wold-style-cast"
+    }
+}
+
+#endif
diff --git a/regrid/regrid.cc b/regrid/regrid.cc
new file mode 100644
index 0000000000000000000000000000000000000000..45f044938b5675d63c718c8d3763116fc3f84ecb
--- /dev/null
+++ b/regrid/regrid.cc
@@ -0,0 +1,94 @@
+
+// this removes strange linkage issues with extensions covering multiple files
+#define PY_ARRAY_UNIQUE_SYMBOL GLORIPEX_PY_ARRAY
+#include <iostream>
+#include <iomanip>
+#include <sstream>
+#include <vector>
+#include <complex>
+#include <boost/python/detail/wrap_python.hpp>
+#include <boost/python.hpp>
+#include <numpy/arrayobject.h>
+
+namespace python = boost::python;
+
+#include "numpy.hpp"
+#include "array.hpp"
+
+#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
+
+#include <CGAL/Delaunay_triangulation_2.h>
+#include <CGAL/Delaunay_triangulation_3.h>
+
+#include <CGAL/Triangulation_vertex_base_with_info_3.h>
+#include <CGAL/Triangulation_vertex_base_with_info_2.h>
+
+#include <CGAL/natural_neighbor_coordinates_2.h>
+#include <CGAL/natural_neighbor_coordinates_3.h>
+
+struct Interpolate {
+
+  typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel;
+  typedef Kernel::FT CoordType;
+  typedef Kernel::Point_3 Point;
+  typedef CGAL::Triangulation_vertex_base_with_info_3<unsigned, Kernel> Vb;
+  typedef CGAL::Triangulation_data_structure_3<Vb> Tds;
+  typedef CGAL::Delaunay_triangulation_3<Kernel, Tds> DelaunayTriangulation;
+  typedef DelaunayTriangulation::Vertex_handle VertexHandle;
+
+  DelaunayTriangulation T_;
+  const gloripex::Array<double, 2> data_;
+
+  Interpolate(const gloripex::Array<double, 2>& data) :
+    data_(data)
+  {
+    const auto size = data_.shape(0);
+    for (size_t i = 0; i < size; ++ i) {
+      this->T_.insert(Point(data_(i, 0), data_(i, 1), data_(i, 2)))->info() = i;
+    }
+  }
+
+  // *****************************************************************************
+
+  void interpolate(const gloripex::Array<double, 2>& coord2) const
+  {
+    gloripex::Array<double, 2>& coord = const_cast<gloripex::Array<double, 2>&>(coord2);
+    // coordinate computation
+    const auto size = coord.shape(0);
+
+    for (size_t i = 0; i < size; ++ i) {
+      Point p(coord(i, 0), coord(i, 1), coord(i, 2));
+      std::vector<std::pair<VertexHandle, CoordType> > vertices;
+      CoordType norm;
+
+      CGAL::laplace_natural_neighbor_coordinates_3(this->T_, p, std::back_inserter(vertices), norm);
+
+      if (! vertices.empty()) {
+        for (int j = 3; j < data_.shape(1); ++ j) {
+          coord(i, j) = 0;
+        }
+        for (const auto& vertex : vertices) {
+          double weight = vertex.second / norm;
+          for (int j = 3; j < data_.shape(1); ++ j) {
+            coord(i, j) += weight * data_((vertex.first)->info(), j);
+          }
+
+        }
+      } else {
+        for (int j = 3; j < data_.shape(1); ++ j) {
+          coord(i, j) = std::numeric_limits<double>::quiet_NaN();
+        }
+      }
+    }
+  }
+};
+
+BOOST_PYTHON_MODULE(regrid)
+{
+  python::numeric::array::set_module_and_type("numpy", "ndarray");
+  import_array();
+
+  python::class_<Interpolate>("regrid", python::init<const gloripex::Array<double, 2>&>())
+    .def("__call__", &Interpolate::interpolate);
+}
+
diff --git a/regrid/regrid.o b/regrid/regrid.o
new file mode 100644
index 0000000000000000000000000000000000000000..d7cfe16e98b29c5539685fabfb573cff83ca4536
Binary files /dev/null and b/regrid/regrid.o differ
diff --git a/regrid/test.py b/regrid/test.py
new file mode 100644
index 0000000000000000000000000000000000000000..108f0ae5ee3365e56630e1a63521b3256a2edb80
--- /dev/null
+++ b/regrid/test.py
@@ -0,0 +1,39 @@
+from regrid import regrid
+from pylab import *
+
+
+# semi irregular grid:
+data = zeros((10**3,6))
+o = mgrid[0:10, 0:10, 0:10]
+for i in range(3):
+    data[:, i] = o[i].reshape(-1)
+data += rand(1000,6)
+data -= 0.5
+
+
+# dummy data
+data[:, 3] = sin(data[:, 0] * pi / 2.) + cos(data[:, 1] * pi / 4.) + data[:, 2]
+data[:, 4] = data[:, 0] + data[:, 1] + data[:, 2]
+data[:, 5] = 0
+
+# initialize regridding
+functor = regrid(data)
+
+# regular grid
+n = 50
+p = mgrid[0:n, 0:n, 0:n] / 5.
+data2 = zeros((n ** 3, 6))
+for i in range(3):
+    data2[:, i] = p[i].reshape(-1)
+
+# perform regridding
+functor(data2)
+
+# visualize some portion
+data2 = ma.masked_where(isnan(data2), data2)
+print data2.shape, data2[:, 3:].shape
+pcolor(data2[:, 3].reshape(n, n, n)[:, :, 5])
+colorbar()
+show()
+
+
diff --git a/scripts/compare methods/logfile.log b/scripts/compare methods/logfile.log
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/scripts/create distributions/create_logo.py b/scripts/create distributions/create_logo.py
index fe6cde5f940dadc1f24e5ed954c4a6684a23ec64..a1561fe03e0f0490ca500dbd2b9f9be1c7c06406 100644
--- a/scripts/create distributions/create_logo.py	
+++ b/scripts/create distributions/create_logo.py	
@@ -11,11 +11,9 @@ import numpy as np
 from numpy import pi
 
 import pyramid.magcreator as mc
-import pyramid.projector as pj
-import pyramid.phasemapper as pm
-import pyramid.holoimage as hi
+from pyramid.phasemapper import PMAdapterFM
 from pyramid.magdata import MagData
-from pyramid.phasemap import PhaseMap
+from pyramid.projector import SimpleProjector
 
 
 def create_logo():
@@ -43,9 +41,9 @@ def create_logo():
     # Create magnetic data, project it, get the phase map and display the holography image:
     mag_data = MagData(a, mc.create_mag_dist_homog(mag_shape, phi))
     mag_data.quiver_plot()
-    projection = pj.simple_axis_projection(mag_data)
-    phase_map = PhaseMap(a, pm.phase_mag(a, projection))
-    hi.display(hi.holo_image(phase_map, density), 'PYRAMID - LOGO', interpolation='bilinear')
+    projector = SimpleProjector(dim)
+    phase_map = PMAdapterFM(a, projector)(mag_data)
+    phase_map.display_holo(density, 'PYRAMID - LOGO', interpolation='bilinear', grad_encode='none')
 
 
 if __name__ == "__main__":
diff --git a/scripts/create distributions/logfile.log b/scripts/create distributions/logfile.log
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/scripts/edinburgh_test.py b/scripts/edinburgh_test.py
new file mode 100644
index 0000000000000000000000000000000000000000..f1015829c609e5b87ce4e7ef2486afced4d4193b
--- /dev/null
+++ b/scripts/edinburgh_test.py
@@ -0,0 +1,50 @@
+# -*- coding: utf-8 -*-
+"""
+Created on Tue Jan 28 15:15:08 2014
+
+@author: Jan
+"""
+
+
+import numpy as np
+from pyramid.magdata import MagData
+from pyramid.projector import SimpleProjector
+from pyramid.phasemapper import PMAdapterFM
+from matplotlib.ticker import FuncFormatter
+
+data = np.loadtxt('../output/data from Edinburgh/long_grain_remapped_0p0035.txt', delimiter=',')
+
+a = 1000 * (data[1, 2] - data[0, 2])
+
+dim = len(np.unique(data[:, 2])), len(np.unique(data[:, 1])), len(np.unique(data[:, 0]))
+
+mag_vec = np.concatenate([data[:, 3], data[:, 4], data[:, 5]])
+
+x_mag = np.reshape(data[:, 3], dim, order='F')
+y_mag = np.reshape(data[:, 4], dim, order='F')
+z_mag = np.reshape(data[:, 5], dim, order='F')
+
+magnitude = np.array((x_mag, y_mag, z_mag))
+
+mag_data = MagData(a, magnitude)
+
+mag_data.pad(30, 20, 0)
+
+mag_data.scale_up()
+
+mag_data.quiver_plot()
+
+#mag_data.quiver_plot3d()
+
+projector = SimpleProjector(mag_data.dim)
+
+phasemapper = PMAdapterFM(mag_data.a, projector)
+
+phase_map = phasemapper(mag_data)
+
+phase_axis = phase_map.display_combined(density=20, interpolation='bilinear')[0]
+
+phase_axis.xaxis.set_major_formatter(FuncFormatter(lambda x, pos: '{:3.0f}'.format(x*mag_data.a)))
+phase_axis.yaxis.set_major_formatter(FuncFormatter(lambda x, pos: '{:3.0f}'.format(x*mag_data.a)))
+
+#phase_map.display_phase3d()
diff --git a/scripts/images_poster.py b/scripts/images_poster.py
new file mode 100644
index 0000000000000000000000000000000000000000..d008673c3fbac97d0825aee76aef952574a34c7c
--- /dev/null
+++ b/scripts/images_poster.py
@@ -0,0 +1,63 @@
+# -*- coding: utf-8 -*-
+"""
+Created on Wed Feb 05 19:19:19 2014
+
+@author: Jan
+"""
+
+import os
+from numpy import pi
+
+import pyramid.magcreator as mc
+from pyramid.magdata import MagData
+from pyramid.phasemapper import PMConvolve
+from pyramid.projector import SimpleProjector
+
+import matplotlib.pyplot as plt
+
+
+
+directory = '../output/poster'
+if not os.path.exists(directory):
+    os.makedirs(directory)
+# Input parameters:
+a = 10.0  # nm
+dim = (64, 128, 128)
+# Slab:f
+center = (32, 32, 32)  # in px (z, y, x), index starts with 0!
+width = (322, 48, 48)  # in px (z, y, x)
+mag_shape_slab = mc.Shapes.slab(dim, center, width)
+# Disc:
+center = (32, 32, 96)  # in px (z, y, x), index starts with 0!
+radius = 24  # in px
+height = 24  # in px
+mag_shape_disc = mc.Shapes.disc(dim, center, radius, height)
+# Sphere:
+center = (32, 96, 64)  # in px (z, y, x), index starts with 0!
+radius = 24  # in px
+mag_shape_sphere = mc.Shapes.sphere(dim, center, radius)
+# Create empty MagData object and add magnetized objects:
+mag_data = MagData(a, mc.create_mag_dist_homog(mag_shape_slab, pi/6))
+mag_data += MagData(a, mc.create_mag_dist_vortex(mag_shape_disc, (32, 96)))
+mag_data += MagData(a, mc.create_mag_dist_homog(mag_shape_sphere, -pi/4))
+# Plot the magnetic distribution, phase map and holographic contour map:
+mag_data_coarse = mag_data.copy()
+mag_data_coarse.scale_down(2)
+mag_data_coarse.quiver_plot()
+plt.savefig(os.path.join(directory, 'mag.png'))
+mag_data_coarse.quiver_plot3d()
+projector = SimpleProjector(dim)
+phase_map = PMConvolve(a, projector, b_0=0.1)(mag_data)
+phase_map.display_phase()
+plt.savefig(os.path.join(directory, 'phase.png'))
+phase_map.display_holo(density=4, interpolation='bilinear')
+plt.savefig(os.path.join(directory, 'holo.png'))
+
+
+dim = (1, 9, 9)
+mag_shape = mc.Shapes.pixel(dim, (int(dim[0]/2), int(dim[1]/2), int(dim[2]/2)))
+mag_data_x = MagData(a, mc.create_mag_dist_homog(mag_shape, 0))
+mag_data_y = MagData(a, mc.create_mag_dist_homog(mag_shape, pi/2))
+phasemapper = PMConvolve(a, SimpleProjector(dim))
+phasemapper(mag_data_x).display_phase()
+phasemapper(mag_data_y).display_phase()
\ No newline at end of file
diff --git a/scripts/logfile.log b/scripts/logfile.log
new file mode 100644
index 0000000000000000000000000000000000000000..8354e3313761d33ac8792c274fddf51547e46c67
--- /dev/null
+++ b/scripts/logfile.log
@@ -0,0 +1 @@
+2014-02-08 21:43:12: INFO     @ <root>:    Calling copy
diff --git a/scripts/paper 1/ch5-0-evaluation_and_comparison.py b/scripts/paper 1/ch5-0-evaluation_and_comparison.py
index bdae2361b751c18660361391eae14d978f1a4d0d..00463cc8dbc9f2044b1b16ac5f728161739277e4 100644
--- a/scripts/paper 1/ch5-0-evaluation_and_comparison.py	
+++ b/scripts/paper 1/ch5-0-evaluation_and_comparison.py	
@@ -6,9 +6,6 @@ Created on Fri Jul 26 14:37:20 2013
 """
 
 
-import sys
-import traceback
-import pdb
 import os
 
 import numpy as np
@@ -24,99 +21,90 @@ import matplotlib.pyplot as plt
 from matplotlib.ticker import FixedFormatter, IndexLocator
 
 
-def run():
-
-    print '\nACCESS SHELVE'
-    # Create / Open databank:
-    directory = '../../output/paper 1'
-    if not os.path.exists(directory):
-        os.makedirs(directory)
-    data_shelve = shelve.open(directory + '/paper_1_shelve')
-
-    ###############################################################################################
-    print 'CH5-0 KERNELS'
-    
-    x = np.linspace(-5, 5, 1000)
-    
-    y_r = x/np.abs(x)**3
-    y_k = x/np.abs(x)**2
-    fig = plt.figure()
-    axis = fig.add_subplot(1, 1, 1, aspect='equal')
-    axis.plot(x,y_r, 'r', label=r'$r/|r|^3$')
-    axis.plot(x,y_k, 'b', label=r'$k/|k|^2$')
-    axis.set_xlim(-5, 5)
-    axis.set_ylim(-5, 5)
-    axis.axvline(0, linewidth=2, color='k')
-    axis.axhline(0, linewidth=2, color='k')
-    axis.legend()
-
-    ###############################################################################################
-    print 'CH5-0 MAGNETIC DISTRIBUTIONS'
-
-    key = 'ch5-0-magnetic_distributions'
-    if key in data_shelve:
-        print '--LOAD MAGNETIC DISTRIBUTIONS'
-        (mag_data_disc, mag_data_vort) = data_shelve[key]
-    else:
-        print '--CREATE MAGNETIC DISTRIBUTIONS'
-        # Input parameters:
-        a = 1.0  # in nm
-        phi = pi/2
-        dim = (16, 128, 128)  # in px (z, y, x)
-        # Create magnetic shape:
-        center = (dim[0]/2-0.5, dim[1]/2.-0.5, dim[2]/2.-0.5)  # in px (z, y, x) index starts at 0!
-        radius = dim[1]/4  # in px
-        height = dim[0]/2  # in px
-        mag_shape = mc.Shapes.disc(dim, center, radius, height)
-        print '--CREATE MAGN. DISTR. OF HOMOG. MAG. DISC'
-        mag_data_disc = MagData(a, mc.create_mag_dist_homog(mag_shape, phi))
-        mag_data_disc.scale_down(2)
-        print '--CREATE MAGN. DISTR. OF VORTEX STATE DISC'
-        mag_data_vort = MagData(a, mc.create_mag_dist_vortex(mag_shape, center))
-        mag_data_vort.scale_down(2)
-        # Mayavi-Plots:
-        mag_data_disc.quiver_plot3d()
-        mag_data_vort.quiver_plot3d()
-        print '--SHELVE MAGNETIC DISTRIBUTIONS'
-        data_shelve[key] = (mag_data_disc, mag_data_vort)
-
-    print '--PLOT/SAVE MAGNETIC DISTRIBUTIONS'
-    fig, axes = plt.subplots(1, 2, figsize=(16, 7))
-    fig.suptitle('Magnetic Distributions', fontsize=20)
-    # Plot MagData (Disc):
-    mag_data_disc.quiver_plot('Homog. magn. disc', axis=axes[0])
-    axes[0].set_aspect('equal')
-    axes[0].xaxis.set_major_locator(IndexLocator(base=4, offset=-0.5))
-    axes[0].yaxis.set_major_locator(IndexLocator(base=4, offset=-0.5))
-    axes[0].xaxis.set_major_formatter(FixedFormatter([16*i for i in range(10)]))
-    axes[0].yaxis.set_major_formatter(FixedFormatter([16*i for i in range(10)]))
-    axes[0].set_xlabel('x [nm]', fontsize=15)
-    axes[0].set_ylabel('x [ym]', fontsize=15)
-    # Plot MagData (Disc):
-    mag_data_vort.quiver_plot('Vortex state disc', axis=axes[1])
-    axes[1].set_aspect('equal')
-    axes[1].xaxis.set_major_locator(IndexLocator(base=4, offset=-0.5))
-    axes[1].yaxis.set_major_locator(IndexLocator(base=4, offset=-0.5))
-    axes[1].xaxis.set_major_formatter(FixedFormatter([16*i for i in range(10)]))
-    axes[1].yaxis.set_major_formatter(FixedFormatter([16*i for i in range(10)]))
-    axes[1].set_xlabel('x [nm]', fontsize=15)
-    axes[1].set_ylabel('x [ym]', fontsize=15)
-    # Save Plots:
-    plt.figtext(0.15, 0.15, 'a)', fontsize=30)
-    plt.figtext(0.57, 0.15, 'b)', fontsize=30)
-    plt.savefig(directory + '/ch5-0-magnetic_distributions.png', bbox_inches='tight')
-
-    ###############################################################################################
-    print 'CLOSING SHELVE\n'
-    # Close shelve:
-    data_shelve.close()
-
-    ###############################################################################################
-
-if __name__ == "__main__":
-    try:
-        run()
-    except:
-        type, value, tb = sys.exc_info()
-        traceback.print_exc()
-        pdb.post_mortem(tb)
+force_calculation = False
+
+
+print '\nACCESS SHELVE'
+# Create / Open databank:
+directory = '../../output/paper 1'
+if not os.path.exists(directory):
+    os.makedirs(directory)
+data_shelve = shelve.open(directory + '/paper_1_shelve')
+
+###############################################################################################
+print 'CH5-0 KERNELS'
+
+x = np.linspace(-5, 5, 1000)
+
+y_r = x/np.abs(x)**3
+y_k = x/np.abs(x)**2
+fig = plt.figure()
+axis = fig.add_subplot(1, 1, 1, aspect='equal')
+axis.plot(x,y_r, 'r', label=r'$r/|r|^3$')
+axis.plot(x,y_k, 'b', label=r'$k/|k|^2$')
+axis.set_xlim(-5, 5)
+axis.set_ylim(-5, 5)
+axis.axvline(0, linewidth=2, color='k')
+axis.axhline(0, linewidth=2, color='k')
+axis.legend()
+
+###############################################################################################
+print 'CH5-0 MAGNETIC DISTRIBUTIONS'
+
+key = 'ch5-0-magnetic_distributions'
+if key in data_shelve and not force_calculation:
+    print '--LOAD MAGNETIC DISTRIBUTIONS'
+    (mag_data_disc, mag_data_vort) = data_shelve[key]
+else:
+    print '--CREATE MAGNETIC DISTRIBUTIONS'
+    # Input parameters:
+    a = 1.0  # in nm
+    phi = pi/2
+    dim = (16, 128, 128)  # in px (z, y, x)
+    # Create magnetic shape:
+    center = (dim[0]/2-0.5, dim[1]/2.-0.5, dim[2]/2.-0.5)  # in px (z, y, x) index starts at 0!
+    radius = dim[1]/4  # in px
+    height = dim[0]/2  # in px
+    mag_shape = mc.Shapes.disc(dim, center, radius, height)
+    print '--CREATE MAGN. DISTR. OF HOMOG. MAG. DISC'
+    mag_data_disc = MagData(a, mc.create_mag_dist_homog(mag_shape, phi))
+    mag_data_disc.scale_down(2)
+    print '--CREATE MAGN. DISTR. OF VORTEX STATE DISC'
+    mag_data_vort = MagData(a, mc.create_mag_dist_vortex(mag_shape, center))
+    mag_data_vort.scale_down(2)
+    # Mayavi-Plots:
+    mag_data_disc.quiver_plot3d()
+    mag_data_vort.quiver_plot3d()
+    print '--SHELVE MAGNETIC DISTRIBUTIONS'
+    data_shelve[key] = (mag_data_disc, mag_data_vort)
+
+print '--PLOT/SAVE MAGNETIC DISTRIBUTIONS'
+fig, axes = plt.subplots(1, 2, figsize=(16, 7))
+fig.suptitle('Magnetic Distributions', fontsize=20)
+# Plot MagData (Disc):
+mag_data_disc.quiver_plot('Homog. magn. disc', axis=axes[0])
+axes[0].set_aspect('equal')
+axes[0].xaxis.set_major_locator(IndexLocator(base=4, offset=-0.5))
+axes[0].yaxis.set_major_locator(IndexLocator(base=4, offset=-0.5))
+axes[0].xaxis.set_major_formatter(FixedFormatter([16*i for i in range(10)]))
+axes[0].yaxis.set_major_formatter(FixedFormatter([16*i for i in range(10)]))
+axes[0].set_xlabel('x [nm]', fontsize=15)
+axes[0].set_ylabel('x [nm]', fontsize=15)
+# Plot MagData (Disc):
+mag_data_vort.quiver_plot('Vortex state disc', axis=axes[1])
+axes[1].set_aspect('equal')
+axes[1].xaxis.set_major_locator(IndexLocator(base=4, offset=-0.5))
+axes[1].yaxis.set_major_locator(IndexLocator(base=4, offset=-0.5))
+axes[1].xaxis.set_major_formatter(FixedFormatter([16*i for i in range(10)]))
+axes[1].yaxis.set_major_formatter(FixedFormatter([16*i for i in range(10)]))
+axes[1].set_xlabel('x [nm]', fontsize=15)
+axes[1].set_ylabel('x [nm]', fontsize=15)
+# Save Plots:
+plt.figtext(0.15, 0.15, 'a)', fontsize=30)
+plt.figtext(0.57, 0.15, 'b)', fontsize=30)
+plt.savefig(directory + '/ch5-0-magnetic_distributions.png', bbox_inches='tight')
+
+###############################################################################################
+print 'CLOSING SHELVE\n'
+# Close shelve:
+data_shelve.close()
diff --git a/scripts/paper 1/ch5-1-evaluation_real_space.py b/scripts/paper 1/ch5-1-evaluation_real_space.py
index babbdcbac83173d0d34f09b82c35f37221461444..d3a618a0e06080eca94806c733a8617440cd4548 100644
--- a/scripts/paper 1/ch5-1-evaluation_real_space.py	
+++ b/scripts/paper 1/ch5-1-evaluation_real_space.py	
@@ -6,9 +6,6 @@ Created on Fri Jul 26 14:37:30 2013
 """
 
 
-import pdb
-import traceback
-import sys
 import os
 
 import numpy as np
@@ -17,10 +14,9 @@ from numpy import pi
 import shelve
 
 import pyramid.magcreator as mc
-import pyramid.projector as pj
-import pyramid.phasemapper as pm
-import pyramid.holoimage as hi
 import pyramid.analytic as an
+from pyramid.projector import SimpleProjector
+from pyramid.phasemapper import PMConvolve
 from pyramid.magdata import MagData
 from pyramid.phasemap import PhaseMap
 
@@ -31,346 +27,332 @@ from matplotlib.cm import RdBu
 from matplotlib.patches import Rectangle
 
 
+force_calculation = False
 PHI_0 = -2067.83  # magnetic flux in T*nm²
 
 
-def run():
-
-    print '\nACCESS SHELVE'
-    # Create / Open databank:
-    directory = '../../output/paper 1'
-    if not os.path.exists(directory):
-        os.makedirs(directory)
-    data_shelve = shelve.open(directory + '/paper_1_shelve')
-
-    ###############################################################################################
-    print 'CH5-1 ANALYTIC SOLUTIONS'
-
-    # Input parameters:
-    a = 0.125  # in nm
-    phi = pi/2
-    dim = (128, 1024, 1024)  # in px (z, y, x)
-    density = 100
-    # Create magnetic shape:
-    center = (dim[0]/2-0.5, dim[1]/2.-0.5, dim[2]/2.-0.5)  # in px (z, y, x) index starts with 0!
-    radius = dim[1]/4  # in px
-    height = dim[0]/2  # in px
-    print '--CALCULATE ANALYTIC SOLUTIONS'
-    # Get analytic solution:
-    phase_ana_disc = an.phase_mag_disc(dim, a, phi, center, radius, height)
-    phase_ana_vort = an.phase_mag_vortex(dim, a, center, radius, height)
-    phase_map_ana_disc = PhaseMap(a, phase_ana_disc)
-    phase_map_ana_vort = PhaseMap(a, phase_ana_vort)
-    print '--PLOT/SAVE ANALYTIC SOLUTIONS'
-    hi.display_combined(phase_map_ana_disc, density,
-                        'Analytic solution: hom. magn. disc', 'bilinear')
-    axis = plt.gcf().add_subplot(1, 2, 2, aspect='equal')
-    axis.axhline(y=512, linewidth=3, linestyle='--', color='r')
-    plt.figtext(0.15, 0.2, 'a)', fontsize=30, color='w')
-    plt.figtext(0.52, 0.2, 'b)', fontsize=30)
-    plt.savefig(directory + '/ch5-1-analytic_solution_disc.png', bbox_inches='tight')
-    hi.display_combined(phase_map_ana_vort, density,
-                        'Analytic solution: vortex state', 'bilinear')
-    axis = plt.gcf().add_subplot(1, 2, 2, aspect='equal')
-    axis.axhline(y=512, linewidth=3, linestyle='--', color='r')
-    plt.figtext(0.15, 0.2, 'c)', fontsize=30, color='w')
-    plt.figtext(0.52, 0.2, 'd)', fontsize=30)
-    plt.savefig(directory + '/ch5-1-analytic_solution_vort.png', bbox_inches='tight')
-    # Get colorwheel:
-    hi.make_color_wheel()
-    plt.figtext(0.15, 0.14, 'e)', fontsize=30, color='w')
-    plt.savefig(directory + '/ch5-1-colorwheel.png', bbox_inches='tight')
-
-    ###############################################################################################
-    print 'CH5-1 PHASE SLICES REAL SPACE'
-
-    # Input parameters:
-    a = 0.25  # in nm
-    phi = pi/2
-    density = 100
-    dim = (64, 512, 512)  # in px (z, y, x)
-    # Create magnetic shape:
-    center = (dim[0]/2-0.5, dim[1]/2.-0.5, dim[2]/2.-0.5)  # in px (z, y, x) index starts with 0!
-    radius = dim[1]/4  # in px
-    height = dim[0]/2  # in px
-
-    key = 'ch5-1-phase_slices_real'
-    if key in data_shelve:
-        print '--LOAD MAGNETIC DISTRIBUTION'
-        (x_d, y_d, dy_d, x_v, y_v, dy_v) = data_shelve[key]
-    else:
-        print '--CREATE MAGNETIC DISTRIBUTION'
-        mag_shape = mc.Shapes.disc(dim, center, radius, height)
-
-        print '--CREATE PHASE SLICES HOMOG. MAGN. DISC'
-        # Arrays for plotting:
-        x_d = []
-        y_d = []
-        dy_d = []
-        # Analytic solution:
-        L = dim[1] * a  # in px/nm
-        Lz = 0.5 * dim[0] * a  # in px/nm
-        R = 0.25 * L  # in px/nm
-        x0 = L / 2  # in px/nm
-
-        def F_disc(x):
-            coeff = - pi * Lz / (2*PHI_0) * 1E3  # in mrad -> *1000
-            result = coeff * (- (x - x0) * np.sin(phi))
-            result *= np.where(np.abs(x - x0) <= R, 1, (R / (x - x0)) ** 2)
-            return result
-
-        x_d.append(np.linspace(0, L, 5000))
-        y_d.append(F_disc(x_d[0]))
-        dy_d.append(np.zeros_like(x_d[0]))
-        # Create MagData (Disc):
-        mag_data_disc = MagData(a, mc.create_mag_dist_homog(mag_shape, phi))
-        for i in range(5):
-            mag_data_disc.scale_down()
-            print '----a =', mag_data_disc.a, 'nm', 'dim =', mag_data_disc.dim
-            projection = pj.simple_axis_projection(mag_data_disc)
-            phase_map = PhaseMap(mag_data_disc.a, pm.phase_mag(mag_data_disc.a, projection))
-            hi.display_combined(phase_map, density, 'Disc, a = {} nm'.format(mag_data_disc.a))
-            x_d.append(np.linspace(mag_data_disc.a * 0.5,
-                                   mag_data_disc.a * (mag_data_disc.dim[1]-0.5),
-                                   mag_data_disc.dim[1]))
-            slice_pos = int(mag_data_disc.dim[1]/2)
-            y_d.append(phase_map.phase[slice_pos, :]*1E3)  # *1E3: rad to mrad
-            dy_d.append(phase_map.phase[slice_pos, :]*1E3 - F_disc(x_d[-1]))  # *1E3: rad to mrad
-
-        print '--CREATE PHASE SLICES VORTEX STATE DISC'
-        x_v = []
-        y_v = []
-        dy_v = []
-        # Analytic solution:
-        L = dim[1] * a  # in px/nm
-        Lz = 0.5 * dim[0] * a  # in px/nm
-        R = 0.25 * L  # in px/nm
-        x0 = L / 2  # in px/nm
-
-        def F_vort(x):
-            coeff = pi*Lz/PHI_0 * 1E3  # in mrad -> *1000
-            result = coeff * np.where(np.abs(x - x0) <= R, (np.abs(x-x0)-R), 0)
-            return result
-
-        x_v.append(np.linspace(0, L, 5001))
-        y_v.append(F_vort(x_v[0]))
-        dy_v.append(np.zeros_like(x_v[0]))
-        # Create MagData (Vortex):
-        mag_data_vort = MagData(a, mc.create_mag_dist_vortex(mag_shape))
-        for i in range(5):
-            mag_data_vort.scale_down()
-            print '----a =', mag_data_vort.a, 'nm', 'dim =', mag_data_vort.dim
-            projection = pj.simple_axis_projection(mag_data_vort)
-            phase_map = PhaseMap(mag_data_vort.a, pm.phase_mag(mag_data_vort.a, projection))
-            hi.display_combined(phase_map, density, 'Disc, a = {} nm'.format(mag_data_vort.a))
-            x_v.append(np.linspace(mag_data_vort.a * 0.5,
-                                   mag_data_vort.a * (mag_data_vort.dim[1]-0.5),
-                                   mag_data_vort.dim[1]))
-            slice_pos = int(mag_data_vort.dim[1]/2)
-            y_v.append(phase_map.phase[slice_pos, :]*1E3)  # *1E3: rad to mrad
-            dy_v.append(phase_map.phase[slice_pos, :]*1E3 - F_vort(x_v[-1]))  # *1E3: rad to mrad
-
-        # Shelve x, y and dy:
-        print '--SAVE PHASE SLICES'
-        data_shelve[key] = (x_d, y_d, dy_d, x_v, y_v, dy_v)
-
-    # Create figure:
-    fig, axes = plt.subplots(1, 2, figsize=(16, 7))
-    fig.suptitle('Central phase slices', fontsize=20)
-
-    print '--PLOT/SAVE PHASE SLICES HOMOG. MAGN. DISC'
-    # Plot phase slices:
-    axes[0].plot(x_d[0], y_d[0], '-k', linewidth=1.5, label='analytic')
-    axes[0].plot(x_d[1], y_d[1], '-r', linewidth=1.5, label='0.5 nm')
-    axes[0].plot(x_d[2], y_d[2], '-m', linewidth=1.5, label='1 nm')
-    axes[0].plot(x_d[3], y_d[3], '-y', linewidth=1.5, label='2 nm')
-    axes[0].plot(x_d[4], y_d[4], '-g', linewidth=1.5, label='4 nm')
-    axes[0].plot(x_d[5], y_d[5], '-c', linewidth=1.5, label='8 nm')
-    axes[0].tick_params(axis='both', which='major', labelsize=14)
-    axes[0].set_title('Homog. magn. disc', fontsize=18)
-    axes[0].set_xlabel('x [nm]', fontsize=15)
-    axes[0].set_ylabel('phase [mrad]', fontsize=15)
-    axes[0].set_xlim(0, 128)
-    axes[0].set_ylim(-220, 220)
-    # Plot Zoombox and Arrow:
-    zoom = (23.5, 160, 15, 40)
-    rect = Rectangle((zoom[0], zoom[1]), zoom[2], zoom[3], fc='w', ec='k')
-    axes[0].add_patch(rect)
-    axes[0].arrow(zoom[0]+zoom[2], zoom[1]+zoom[3]/2, 36, 0, length_includes_head=True,
-              head_width=10, head_length=4, fc='k', ec='k')
-    # Plot zoom inset:
-    ins_axis_d = plt.axes([0.33, 0.57, 0.14, 0.3])
-    ins_axis_d.plot(x_d[0], y_d[0], '-k', linewidth=1.5, label='analytic')
-    ins_axis_d.plot(x_d[1], y_d[1], '-r', linewidth=1.5, label='0.5 nm')
-    ins_axis_d.plot(x_d[2], y_d[2], '-m', linewidth=1.5, label='1 nm')
-    ins_axis_d.plot(x_d[3], y_d[3], '-y', linewidth=1.5, label='2 nm')
-    ins_axis_d.plot(x_d[4], y_d[4], '-g', linewidth=1.5, label='4 nm')
-    ins_axis_d.plot(x_d[5], y_d[5], '-c', linewidth=1.5, label='8 nm')
-    ins_axis_d.tick_params(axis='both', which='major', labelsize=14)
-    ins_axis_d.set_xlim(zoom[0], zoom[0]+zoom[2])
-    ins_axis_d.set_ylim(zoom[1], zoom[1]+zoom[3])
-    ins_axis_d.xaxis.set_major_locator(MaxNLocator(nbins=4, integer=True))
-    ins_axis_d.yaxis.set_major_locator(MaxNLocator(nbins=3))
-
-    print '--PLOT/SAVE PHASE SLICES VORTEX STATE DISC'
-    # Plot phase slices:
-    axes[1].plot(x_v[0], y_v[0], '-k', linewidth=1.5, label='analytic')
-    axes[1].plot(x_v[1], y_v[1], '-r', linewidth=1.5, label='0.5 nm')
-    axes[1].plot(x_v[2], y_v[2], '-m', linewidth=1.5, label='1 nm')
-    axes[1].plot(x_v[3], y_v[3], '-y', linewidth=1.5, label='2 nm')
-    axes[1].plot(x_v[4], y_v[4], '-g', linewidth=1.5, label='4 nm')
-    axes[1].plot(x_v[5], y_v[5], '-c', linewidth=1.5, label='8 nm')
-    axes[1].tick_params(axis='both', which='major', labelsize=14)
-    axes[1].set_title('Vortex state disc', fontsize=18)
-    axes[1].set_xlabel('x [nm]', fontsize=15)
-    axes[1].set_ylabel('phase [mrad]', fontsize=15)
-    axes[1].set_xlim(0, 128)
-    axes[1].yaxis.set_major_locator(MaxNLocator(nbins=6))
-    axes[1].legend()
-    # Plot Zoombox and Arrow:
-    zoom = (59, 340, 10, 55)
-    rect = Rectangle((zoom[0], zoom[1]), zoom[2], zoom[3], fc='w', ec='k')
-    axes[1].add_patch(rect)
-    axes[1].arrow(zoom[0]+zoom[2]/2, zoom[1], 0, -193, length_includes_head=True,
-              head_width=2, head_length=20, fc='k', ec='k')
-    # Plot zoom inset:
-    ins_axis_v = plt.axes([0.695, 0.15, 0.075, 0.3])
-    ins_axis_v.plot(x_v[0], y_v[0], '-k', linewidth=1.5, label='analytic')
-    ins_axis_v.plot(x_v[1], y_v[1], '-r', linewidth=1.5, label='0.5 nm')
-    ins_axis_v.plot(x_v[2], y_v[2], '-m', linewidth=1.5, label='1 nm')
-    ins_axis_v.plot(x_v[3], y_v[3], '-y', linewidth=1.5, label='2 nm')
-    ins_axis_v.plot(x_v[4], y_v[4], '-g', linewidth=1.5, label='4 nm')
-    ins_axis_v.plot(x_v[5], y_v[5], '-c', linewidth=1.5, label='8 nm')
-    ins_axis_v.tick_params(axis='both', which='major', labelsize=14)
-    ins_axis_v.set_xlim(zoom[0], zoom[0]+zoom[2])
-    ins_axis_v.set_ylim(zoom[1], zoom[1]+zoom[3])
-    ins_axis_v.xaxis.set_major_locator(MaxNLocator(nbins=4, integer=True))
-    ins_axis_v.yaxis.set_major_locator(MaxNLocator(nbins=4))
-
-    plt.show()
-    plt.figtext(0.15, 0.13, 'a)', fontsize=30)
-    plt.figtext(0.57, 0.13, 'b)', fontsize=30)
-    plt.savefig(directory + '/ch5-1-phase_slice_comparison.png', bbox_inches='tight')
-
-    # Create figure:
-    fig, axes = plt.subplots(1, 2, figsize=(16, 7))
-    fig.suptitle('Central phase slice errors', fontsize=20)
-
-    print '--PLOT/SAVE PHASE SLICE ERRORS HOMOG. MAGN. DISC'
-    # Plot phase slices:
-    axes[0].plot(x_d[0], dy_d[0], '-k', linewidth=1.5, label='analytic')
-    axes[0].plot(x_d[1], dy_d[1], '-r', linewidth=1.5, label='0.5 nm')
-    axes[0].plot(x_d[2], dy_d[2], '-m', linewidth=1.5, label='1 nm')
-    axes[0].plot(x_d[3], dy_d[3], '-y', linewidth=1.5, label='2 nm')
-    axes[0].plot(x_d[4], dy_d[4], '-g', linewidth=1.5, label='4 nm')
-    axes[0].plot(x_d[5], dy_d[5], '-c', linewidth=1.5, label='8 nm')
-    axes[0].tick_params(axis='both', which='major', labelsize=14)
-    axes[0].set_title('Homog. magn. disc', fontsize=18)
-    axes[0].set_xlabel('x [nm]', fontsize=15)
-    axes[0].set_ylabel('phase [mrad]', fontsize=15)
-    axes[0].set_xlim(0, 128)
-
-    print '--PLOT/SAVE PHASE SLICE ERRORS VORTEX STATE DISC'
-    # Plot phase slices:
-    axes[1].plot(x_v[0], dy_v[0], '-k', linewidth=1.5, label='analytic')
-    axes[1].plot(x_v[1], dy_v[1], '-r', linewidth=1.5, label='0.5 nm')
-    axes[1].plot(x_v[2], dy_v[2], '-m', linewidth=1.5, label='1 nm')
-    axes[1].plot(x_v[3], dy_v[3], '-y', linewidth=1.5, label='2 nm')
-    axes[1].plot(x_v[4], dy_v[4], '-g', linewidth=1.5, label='4 nm')
-    axes[1].plot(x_v[5], dy_v[5], '-c', linewidth=1.5, label='8 nm')
-    axes[1].tick_params(axis='both', which='major', labelsize=14)
-    axes[1].set_title('Vortex state disc', fontsize=18)
-    axes[1].set_xlabel('x [nm]', fontsize=15)
-    axes[1].set_ylabel('phase [mrad]', fontsize=15)
-    axes[1].set_xlim(0, 128)
-    axes[1].legend(loc=4)
-
-    plt.show()
-    plt.figtext(0.15, 0.13, 'a)', fontsize=30)
-    plt.figtext(0.57, 0.13, 'b)', fontsize=30)
-    plt.savefig(directory + '/ch5-1-phase_slice_errors.png', bbox_inches='tight')
-
-    ###############################################################################################
-    print 'CH5-1 PHASE DIFFERENCES REAL SPACE'
-
-    # Input parameters:
-    a = 1.0  # in nm
-    phi = pi/2
-    dim = (16, 128, 128)  # in px (z, y, x)
-    center = (dim[0]/2-0.5, dim[1]/2.-0.5, dim[2]/2.-0.5)  # in px (z, y, x) index starts with 0!
-    radius = dim[1]/4  # in px
-    height = dim[0]/2  # in px
-
-    key = 'ch5-1-phase_diff_mag_dist'
-    if key in data_shelve:
-        print '--LOAD MAGNETIC DISTRIBUTIONS'
-        (mag_data_disc, mag_data_vort) = data_shelve[key]
-    else:
-        print '--CREATE MAGNETIC DISTRIBUTIONS'
-        # Create magnetic shape (4 times the size):
-        a_big = a / 2
-        dim_big = (dim[0]*2, dim[1]*2, dim[2]*2)
-        center_big = (dim_big[0]/2-0.5, dim_big[1]/2.-0.5, dim_big[2]/2.-0.5)
-        radius_big = dim_big[1]/4  # in px
-        height_big = dim_big[0]/2  # in px
-        mag_shape = mc.Shapes.disc(dim_big, center_big, radius_big, height_big)
-        # Create MagData (4 times the size):
-        mag_data_disc = MagData(a_big, mc.create_mag_dist_homog(mag_shape, phi))
-        mag_data_vort = MagData(a_big, mc.create_mag_dist_vortex(mag_shape, center_big))
-        # Scale mag_data, grid spacing and dimensions:
-        mag_data_disc.scale_down()
-        mag_data_vort.scale_down()
-        print '--SAVE MAGNETIC DISTRIBUTIONS'
-        # Shelve magnetic distributions:
-        data_shelve[key] = (mag_data_disc, mag_data_vort)
-
-    print '--CALCULATE PHASE DIFFERENCES'
-    # Create projections along z-axis:
-    projection_disc = pj.simple_axis_projection(mag_data_disc)
-    projection_vort = pj.simple_axis_projection(mag_data_vort)
-    # Get analytic solutions:
-    phase_ana_disc = an.phase_mag_disc(dim, a, phi, center, radius, height)
-    phase_ana_vort = an.phase_mag_vortex(dim, a, center, radius, height)
-    # Create norm for the plots:
-    bounds = np.array([-3, -0.5, -0.25, -0.1, 0, 0.1, 0.25, 0.5, 3])
-    norm = BoundaryNorm(bounds, RdBu.N)
-    # Calculations (Disc):
-    phase_num_disc = pm.phase_mag(a, projection_disc)
-    phase_diff_disc = PhaseMap(a, (phase_num_disc-phase_ana_disc), 'mrad')
-    RMS_disc = np.sqrt(np.mean(phase_diff_disc.phase**2))
-    # Calculations (Vortex):
-    phase_num_vort = pm.phase_mag(a, projection_vort)
-    phase_diff_vort = PhaseMap(a, (phase_num_vort-phase_ana_vort), 'mrad')
-    RMS_vort = np.sqrt(np.mean(phase_diff_vort.phase**2))
-
-    print '--PLOT/SAVE PHASE DIFFERENCES'
-    fig, axes = plt.subplots(1, 2, figsize=(16, 7))
-    fig.suptitle('Difference of the real space approach from the analytical solution', fontsize=20)
-    # Plot MagData (Disc):
-    phase_diff_disc.display('Homog. magn. disc, RMS = {:3.2f} mrad'.format(RMS_disc),
-                            limit=np.max(bounds), norm=norm, axis=axes[0])
-    axes[0].set_aspect('equal')
-    # Plot MagData (Disc):
-    phase_diff_vort.display('Vortex state disc, RMS = {:3.2f} mrad'.format(RMS_vort),
-                            limit=np.max(bounds), norm=norm, axis=axes[1])
-    axes[1].set_aspect('equal')
-    # Save Plots:
-    plt.figtext(0.15, 0.2, 'a)', fontsize=30)
-    plt.figtext(0.52, 0.2, 'b)', fontsize=30)
-    plt.savefig(directory + '/ch5-1-phase_differences.png', bbox_inches='tight')
-
-    ###############################################################################################
-    print 'CLOSING SHELVE\n'
-    # Close shelve:
-    data_shelve.close()
-
-    ###############################################################################################
-
-
-if __name__ == "__main__":
-    try:
-        run()
-    except:
-        type, value, tb = sys.exc_info()
-        traceback.print_exc()
-        pdb.post_mortem(tb)
+print '\nACCESS SHELVE'
+# Create / Open databank:
+directory = '../../output/paper 1'
+if not os.path.exists(directory):
+    os.makedirs(directory)
+data_shelve = shelve.open(directory + '/paper_1_shelve')
+
+###############################################################################################
+print 'CH5-1 ANALYTIC SOLUTIONS'
+
+# Input parameters:
+a = 0.125  # in nm
+phi = pi/2
+dim = (128, 1024, 1024)  # in px (z, y, x)
+density = 100
+# Create magnetic shape:
+center = (dim[0]/2-0.5, dim[1]/2.-0.5, dim[2]/2.-0.5)  # in px (z, y, x) index starts with 0!
+radius = dim[1]/4  # in px
+height = dim[0]/2  # in px
+print '--CALCULATE ANALYTIC SOLUTIONS'
+# Get analytic solution:
+phase_map_ana_disc = an.phase_mag_disc(dim, a, phi, center, radius, height)
+phase_map_ana_vort = an.phase_mag_vortex(dim, a, center, radius, height)
+print '--PLOT/SAVE ANALYTIC SOLUTIONS'
+phase_map_ana_disc.display_combined(density, 'Analytic solution: hom. magn. disc', 'bilinear')
+axis = plt.gcf().add_subplot(1, 2, 2, aspect='equal')
+axis.axhline(y=512, linewidth=3, linestyle='--', color='r')
+plt.figtext(0.15, 0.2, 'a)', fontsize=30, color='w')
+#plt.figtext(0.52, 0.2, 'b)', fontsize=30)
+plt.savefig(directory + '/ch5-1-analytic_solution_disc.png', bbox_inches='tight')
+phase_map_ana_vort.display_combined(density, 'Analytic solution: vortex state', 'bilinear')
+axis = plt.gcf().add_subplot(1, 2, 2, aspect='equal')
+axis.axhline(y=512, linewidth=3, linestyle='--', color='r')
+plt.figtext(0.15, 0.2, 'c)', fontsize=30, color='w')
+plt.figtext(0.52, 0.2, 'd)', fontsize=30)
+plt.savefig(directory + '/ch5-1-analytic_solution_vort.png', bbox_inches='tight')
+# Get colorwheel:
+PhaseMap.make_color_wheel()
+plt.figtext(0.15, 0.14, 'e)', fontsize=30, color='w')
+plt.savefig(directory + '/ch5-1-colorwheel.png', bbox_inches='tight')
+
+###############################################################################################
+print 'CH5-1 PHASE SLICES REAL SPACE'
+
+# Input parameters:
+a = 0.5  # in nm
+phi = pi/2
+density = 100
+dim = (32, 256, 256)  # in px (z, y, x)
+# Create magnetic shape:
+center = (dim[0]/2-0.5, dim[1]/2.-0.5, dim[2]/2.-0.5)  # in px (z, y, x) index starts with 0!
+radius = dim[1]/4  # in px
+height = dim[0]/2  # in px
+
+key = 'ch5-1-phase_slices_real'
+if key in data_shelve and not force_calculation:
+    print '--LOAD MAGNETIC DISTRIBUTION'
+    (x_d, y_d, dy_d, x_v, y_v, dy_v) = data_shelve[key]
+else:
+    print '--CREATE MAGNETIC DISTRIBUTION'
+    mag_shape = mc.Shapes.disc(dim, center, radius, height)
+
+    print '--CREATE PHASE SLICES HOMOG. MAGN. DISC'
+    # Arrays for plotting:
+    x_d = []
+    y_d = []
+    dy_d = []
+    # Analytic solution:
+    L = dim[1] * a  # in px/nm
+    Lz = 0.5 * dim[0] * a  # in px/nm
+    R = 0.25 * L  # in px/nm
+    x0 = L / 2  # in px/nm
+
+    def F_disc(x):
+        coeff = - pi * Lz / (2*PHI_0) * 1E3  # in mrad -> *1000
+        result = coeff * (- (x - x0) * np.sin(phi))
+        result *= np.where(np.abs(x - x0) <= R, 1, (R / (x - x0)) ** 2)
+        return result
+
+    x_d.append(np.linspace(0, L, 5000))
+    y_d.append(F_disc(x_d[0]))
+    dy_d.append(np.zeros_like(x_d[0]))
+    # Create MagData (Disc):
+    mag_data_disc = MagData(a, mc.create_mag_dist_homog(mag_shape, phi))
+    for i in range(5):
+        print '----a =', mag_data_disc.a, 'nm', 'dim =', mag_data_disc.dim
+        projector = SimpleProjector(mag_data_disc.dim)
+        phase_map = PMConvolve(mag_data_disc.a, projector)(mag_data_disc)
+        phase_map.display_combined(density, 'Disc, a = {} nm'.format(mag_data_disc.a))
+        x_d.append(np.linspace(mag_data_disc.a * 0.5,
+                               mag_data_disc.a * (mag_data_disc.dim[1]-0.5),
+                               mag_data_disc.dim[1]))
+        slice_pos = int(mag_data_disc.dim[1]/2)
+        y_d.append(phase_map.phase[slice_pos, :]*1E3)  # *1E3: rad to mrad
+        dy_d.append(phase_map.phase[slice_pos, :]*1E3 - F_disc(x_d[-1]))  # *1E3: rad to mrad
+        if i < 4: mag_data_disc.scale_down()
+
+    print '--CREATE PHASE SLICES VORTEX STATE DISC'
+    x_v = []
+    y_v = []
+    dy_v = []
+    # Analytic solution:
+    L = dim[1] * a  # in px/nm
+    Lz = 0.5 * dim[0] * a  # in px/nm
+    R = 0.25 * L  # in px/nm
+    x0 = L / 2  # in px/nm
+
+    def F_vort(x):
+        coeff = pi*Lz/PHI_0 * 1E3  # in mrad -> *1000
+        result = coeff * np.where(np.abs(x - x0) <= R, (np.abs(x-x0)-R), 0)
+        return result
+
+    x_v.append(np.linspace(0, L, 5001))
+    y_v.append(F_vort(x_v[0]))
+    dy_v.append(np.zeros_like(x_v[0]))
+    # Create MagData (Vortex):
+    mag_data_vort = MagData(a, mc.create_mag_dist_vortex(mag_shape))
+    for i in range(5):
+        print '----a =', mag_data_vort.a, 'nm', 'dim =', mag_data_vort.dim
+        projector = SimpleProjector(mag_data_vort.dim) 
+        phase_map = PMConvolve(mag_data_vort.a, projector)(mag_data_vort)
+        phase_map.display_combined(density, 'Disc, a = {} nm'.format(mag_data_vort.a))
+        x_v.append(np.linspace(mag_data_vort.a * 0.5,
+                               mag_data_vort.a * (mag_data_vort.dim[1]-0.5),
+                               mag_data_vort.dim[1]))
+        slice_pos = int(mag_data_vort.dim[1]/2)
+        y_v.append(phase_map.phase[slice_pos, :]*1E3)  # *1E3: rad to mrad
+        dy_v.append(phase_map.phase[slice_pos, :]*1E3 - F_vort(x_v[-1]))  # *1E3: rad to mrad
+        if i < 4: mag_data_vort.scale_down()
+
+    # Shelve x, y and dy:
+    print '--SAVE PHASE SLICES'
+    data_shelve[key] = (x_d, y_d, dy_d, x_v, y_v, dy_v)
+
+# Create figure:
+fig, axes = plt.subplots(1, 2, figsize=(16, 7))
+fig.suptitle('Central phase slices', fontsize=20)
+
+print '--PLOT/SAVE PHASE SLICES HOMOG. MAGN. DISC'
+# Plot phase slices:
+axes[0].plot(x_d[0], y_d[0], '-k', linewidth=1.5, label='analytic')
+axes[0].plot(x_d[1], y_d[1], '-r', linewidth=1.5, label='0.5 nm')
+axes[0].plot(x_d[2], y_d[2], '-m', linewidth=1.5, label='1 nm')
+axes[0].plot(x_d[3], y_d[3], '-y', linewidth=1.5, label='2 nm')
+axes[0].plot(x_d[4], y_d[4], '-g', linewidth=1.5, label='4 nm')
+axes[0].plot(x_d[5], y_d[5], '-c', linewidth=1.5, label='8 nm')
+axes[0].tick_params(axis='both', which='major', labelsize=14)
+axes[0].set_title('Homog. magn. disc', fontsize=18)
+axes[0].set_xlabel('x [nm]', fontsize=15)
+axes[0].set_ylabel('phase [mrad]', fontsize=15)
+axes[0].set_xlim(0, 128)
+axes[0].set_ylim(-220, 220)
+# Plot Zoombox and Arrow:
+zoom = (23.5, 160, 15, 40)
+rect = Rectangle((zoom[0], zoom[1]), zoom[2], zoom[3], fc='w', ec='k')
+axes[0].add_patch(rect)
+axes[0].arrow(zoom[0]+zoom[2], zoom[1]+zoom[3]/2, 36, 0, length_includes_head=True,
+          head_width=10, head_length=4, fc='k', ec='k')
+# Plot zoom inset:
+ins_axis_d = plt.axes([0.33, 0.57, 0.14, 0.3])
+ins_axis_d.plot(x_d[0], y_d[0], '-k', linewidth=1.5, label='analytic')
+ins_axis_d.plot(x_d[1], y_d[1], '-r', linewidth=1.5, label='0.5 nm')
+ins_axis_d.plot(x_d[2], y_d[2], '-m', linewidth=1.5, label='1 nm')
+ins_axis_d.plot(x_d[3], y_d[3], '-y', linewidth=1.5, label='2 nm')
+ins_axis_d.plot(x_d[4], y_d[4], '-g', linewidth=1.5, label='4 nm')
+ins_axis_d.plot(x_d[5], y_d[5], '-c', linewidth=1.5, label='8 nm')
+ins_axis_d.tick_params(axis='both', which='major', labelsize=14)
+ins_axis_d.set_xlim(zoom[0], zoom[0]+zoom[2])
+ins_axis_d.set_ylim(zoom[1], zoom[1]+zoom[3])
+ins_axis_d.xaxis.set_major_locator(MaxNLocator(nbins=4, integer=True))
+ins_axis_d.yaxis.set_major_locator(MaxNLocator(nbins=3))
+
+print '--PLOT/SAVE PHASE SLICES VORTEX STATE DISC'
+# Plot phase slices:
+axes[1].plot(x_v[0], y_v[0], '-k', linewidth=1.5, label='analytic')
+axes[1].plot(x_v[1], y_v[1], '-r', linewidth=1.5, label='0.5 nm')
+axes[1].plot(x_v[2], y_v[2], '-m', linewidth=1.5, label='1 nm')
+axes[1].plot(x_v[3], y_v[3], '-y', linewidth=1.5, label='2 nm')
+axes[1].plot(x_v[4], y_v[4], '-g', linewidth=1.5, label='4 nm')
+axes[1].plot(x_v[5], y_v[5], '-c', linewidth=1.5, label='8 nm')
+axes[1].tick_params(axis='both', which='major', labelsize=14)
+axes[1].set_title('Vortex state disc', fontsize=18)
+axes[1].set_xlabel('x [nm]', fontsize=15)
+axes[1].set_ylabel('phase [mrad]', fontsize=15)
+axes[1].set_xlim(0, 128)
+axes[1].yaxis.set_major_locator(MaxNLocator(nbins=6))
+axes[1].legend()
+# Plot Zoombox and Arrow:
+zoom = (59, 340, 10, 55)
+rect = Rectangle((zoom[0], zoom[1]), zoom[2], zoom[3], fc='w', ec='k')
+axes[1].add_patch(rect)
+axes[1].arrow(zoom[0]+zoom[2]/2, zoom[1], 0, -193, length_includes_head=True,
+          head_width=2, head_length=20, fc='k', ec='k')
+# Plot zoom inset:
+ins_axis_v = plt.axes([0.695, 0.15, 0.075, 0.3])
+ins_axis_v.plot(x_v[0], y_v[0], '-k', linewidth=1.5, label='analytic')
+ins_axis_v.plot(x_v[1], y_v[1], '-r', linewidth=1.5, label='0.5 nm')
+ins_axis_v.plot(x_v[2], y_v[2], '-m', linewidth=1.5, label='1 nm')
+ins_axis_v.plot(x_v[3], y_v[3], '-y', linewidth=1.5, label='2 nm')
+ins_axis_v.plot(x_v[4], y_v[4], '-g', linewidth=1.5, label='4 nm')
+ins_axis_v.plot(x_v[5], y_v[5], '-c', linewidth=1.5, label='8 nm')
+ins_axis_v.tick_params(axis='both', which='major', labelsize=14)
+ins_axis_v.set_xlim(zoom[0], zoom[0]+zoom[2])
+ins_axis_v.set_ylim(zoom[1], zoom[1]+zoom[3])
+ins_axis_v.xaxis.set_major_locator(MaxNLocator(nbins=4, integer=True))
+ins_axis_v.yaxis.set_major_locator(MaxNLocator(nbins=4))
+
+plt.show()
+#plt.figtext(0.15, 0.13, 'a)', fontsize=30)
+#plt.figtext(0.57, 0.13, 'b)', fontsize=30)
+plt.savefig(directory + '/ch5-1-phase_slice_comparison.png', bbox_inches='tight')
+
+# Create figure:
+fig, axes = plt.subplots(1, 2, figsize=(16, 7))
+fig.suptitle('Central phase slice errors', fontsize=20)
+
+print '--PLOT/SAVE PHASE SLICE ERRORS HOMOG. MAGN. DISC'
+# Plot phase slices:
+axes[0].plot(x_d[0], dy_d[0], '-k', linewidth=1.5, label='analytic')
+axes[0].plot(x_d[1], dy_d[1], '-r', linewidth=1.5, label='0.5 nm')
+axes[0].plot(x_d[2], dy_d[2], '-m', linewidth=1.5, label='1 nm')
+axes[0].plot(x_d[3], dy_d[3], '-y', linewidth=1.5, label='2 nm')
+axes[0].plot(x_d[4], dy_d[4], '-g', linewidth=1.5, label='4 nm')
+axes[0].plot(x_d[5], dy_d[5], '-c', linewidth=1.5, label='8 nm')
+axes[0].tick_params(axis='both', which='major', labelsize=14)
+axes[0].set_title('Homog. magn. disc', fontsize=18)
+axes[0].set_xlabel('x [nm]', fontsize=15)
+axes[0].set_ylabel('phase [mrad]', fontsize=15)
+axes[0].set_xlim(0, 128)
+
+print '--PLOT/SAVE PHASE SLICE ERRORS VORTEX STATE DISC'
+# Plot phase slices:
+axes[1].plot(x_v[0], dy_v[0], '-k', linewidth=1.5, label='analytic')
+axes[1].plot(x_v[1], dy_v[1], '-r', linewidth=1.5, label='0.5 nm')
+axes[1].plot(x_v[2], dy_v[2], '-m', linewidth=1.5, label='1 nm')
+axes[1].plot(x_v[3], dy_v[3], '-y', linewidth=1.5, label='2 nm')
+axes[1].plot(x_v[4], dy_v[4], '-g', linewidth=1.5, label='4 nm')
+axes[1].plot(x_v[5], dy_v[5], '-c', linewidth=1.5, label='8 nm')
+axes[1].tick_params(axis='both', which='major', labelsize=14)
+axes[1].set_title('Vortex state disc', fontsize=18)
+axes[1].set_xlabel('x [nm]', fontsize=15)
+axes[1].set_ylabel('phase [mrad]', fontsize=15)
+axes[1].set_xlim(0, 128)
+axes[1].legend(loc=4)
+
+plt.show()
+#plt.figtext(0.15, 0.13, 'a)', fontsize=30)
+#plt.figtext(0.57, 0.13, 'b)', fontsize=30)
+plt.savefig(directory + '/ch5-1-phase_slice_errors.png', bbox_inches='tight')
+
+###############################################################################################
+print 'CH5-1 PHASE DIFFERENCES REAL SPACE'
+
+# Input parameters:
+a = 1.0  # in nm
+phi = pi/2
+dim = (16, 128, 128)  # in px (z, y, x)
+center = (dim[0]/2-0.5, dim[1]/2.-0.5, dim[2]/2.-0.5)  # in px (z, y, x) index starts with 0!
+radius = dim[1]/4  # in px
+height = dim[0]/2  # in px
+
+key = 'ch5-1-phase_diff_mag_dist'
+if key in data_shelve and not force_calculation:
+    print '--LOAD MAGNETIC DISTRIBUTIONS'
+    (mag_data_disc, mag_data_vort) = data_shelve[key]
+else:
+    print '--CREATE MAGNETIC DISTRIBUTIONS'
+    # Create magnetic shape (4 times the size):
+    a_big = a / 2
+    dim_big = (dim[0]*2, dim[1]*2, dim[2]*2)
+    center_big = (dim_big[0]/2-0.5, dim_big[1]/2.-0.5, dim_big[2]/2.-0.5)
+    radius_big = dim_big[1]/4  # in px
+    height_big = dim_big[0]/2  # in px
+    mag_shape = mc.Shapes.disc(dim_big, center_big, radius_big, height_big)
+    # Create MagData (4 times the size):
+    mag_data_disc = MagData(a_big, mc.create_mag_dist_homog(mag_shape, phi))
+    mag_data_vort = MagData(a_big, mc.create_mag_dist_vortex(mag_shape, center_big))
+    # Scale mag_data, grid spacing and dimensions:
+    mag_data_disc.scale_down()
+    mag_data_vort.scale_down()
+    print '--SAVE MAGNETIC DISTRIBUTIONS'
+    # Shelve magnetic distributions:
+    data_shelve[key] = (mag_data_disc, mag_data_vort)
+
+print '--CALCULATE PHASE DIFFERENCES'
+# Create projector along z-axis and phasemapper:
+projector = SimpleProjector(dim)
+phasemapper = PMConvolve(a, projector)
+# Get analytic solutions:
+phase_map_ana_disc = an.phase_mag_disc(dim, a, phi, center, radius, height)
+phase_map_ana_vort = an.phase_mag_vortex(dim, a, center, radius, height)
+# Create norm for the plots:
+bounds = np.array([-3, -0.5, -0.25, -0.1, 0, 0.1, 0.25, 0.5, 3])
+norm = BoundaryNorm(bounds, RdBu.N)
+# Calculations (Disc):
+phase_map_num_disc = phasemapper(mag_data_disc)
+phase_map_num_disc.unit = 'mrad'
+phase_diff_disc = phase_map_num_disc - phase_map_ana_disc
+RMS_disc = np.sqrt(np.mean(phase_diff_disc.phase**2))
+# Calculations (Vortex):
+phase_map_num_vort = phasemapper(mag_data_vort)
+phase_map_num_vort.unit = 'mrad'
+phase_diff_vort = phase_map_num_vort - phase_map_ana_vort
+RMS_vort = np.sqrt(np.mean(phase_diff_vort.phase**2))
+
+print '--PLOT/SAVE PHASE DIFFERENCES'
+fig, axes = plt.subplots(1, 2, figsize=(16, 7))
+fig.suptitle('Difference of the real space approach from the analytical solution', fontsize=20)
+# Plot MagData (Disc):
+phase_diff_disc.display_phase(u'Homog. magn. disc, RMS = {:3.2f} µrad'.format(RMS_disc*1000),
+                              limit=np.max(bounds), norm=norm, axis=axes[0])
+axes[0].set_aspect('equal')
+# Plot MagData (Disc):
+phase_diff_vort.display_phase(u'Vortex state disc, RMS = {:3.2f} µrad'.format(RMS_vort*1000),
+                              limit=np.max(bounds), norm=norm, axis=axes[1])
+axes[1].set_aspect('equal')
+# Save Plots:
+plt.figtext(0.15, 0.2, 'a)', fontsize=30)
+plt.figtext(0.52, 0.2, 'b)', fontsize=30)
+plt.savefig(directory + '/ch5-1-phase_differences.png', bbox_inches='tight')
+
+###############################################################################################
+print 'CLOSING SHELVE\n'
+# Close shelve:
+data_shelve.close()
diff --git a/scripts/paper 1/ch5-2-evaluation_fourier_space.py b/scripts/paper 1/ch5-2-evaluation_fourier_space.py
index 4a1ef4596f874aaf1cb39fb8d9be64a597f09651..53838f275a742c47ece125d2907c7e3266a95022 100644
--- a/scripts/paper 1/ch5-2-evaluation_fourier_space.py	
+++ b/scripts/paper 1/ch5-2-evaluation_fourier_space.py	
@@ -7,9 +7,6 @@ Created on Fri Jul 26 14:37:30 2013
 
 
 import time
-import pdb
-import traceback
-import sys
 import os
 
 import numpy as np
@@ -18,12 +15,10 @@ from numpy import pi
 import shelve
 
 import pyramid.magcreator as mc
-import pyramid.projector as pj
-import pyramid.phasemapper as pm
 import pyramid.analytic as an
-import pyramid.holoimage as hi
 from pyramid.magdata import MagData
-from pyramid.phasemap import PhaseMap
+from pyramid.projector import SimpleProjector
+from pyramid.phasemapper import PMFourier
 
 import matplotlib.pyplot as plt
 from matplotlib.colors import BoundaryNorm
@@ -31,157 +26,151 @@ from matplotlib.ticker import MaxNLocator
 from matplotlib.cm import RdBu
 
 
+force_calculation = False
 PHI_0 = -2067.83  # magnetic flux in T*nm²
 
 
-def run():
-
-    print '\nACCESS SHELVE'
-    # Create / Open databank:
-    directory = '../../output/paper 1'
-    if not os.path.exists(directory):
-        os.makedirs(directory)
-    data_shelve = shelve.open(directory + '/paper_1_shelve')
-
-    ###############################################################################################
-    print 'CH5-1 PHASE SLICES FOURIER SPACE'
-
-    # Input parameters:
-    a = 0.25  # in nm
-    phi = pi/2
-    density = 100
-    dim = (64, 512, 512)  # in px (z, y, x)
-    # Create magnetic shape:
-    center = (dim[0]/2-0.5, dim[1]/2.-0.5, dim[2]/2.-0.5)  # in px (z, y, x) index starts with 0!
-    radius = dim[1]/4  # in px
-    height = dim[0]/2  # in px
-
-    key = 'ch5-2-phase_slices_fourier'
-    if key in data_shelve:
-        print '--LOAD MAGNETIC DISTRIBUTION'
-        (x_d, y_d0, y_d10, dy_d0, dy_d10, x_v, y_v0, y_v10, dy_v0, dy_v10) = data_shelve[key]
-    else:
-        print '--CREATE MAGNETIC DISTRIBUTION'
-        mag_shape = mc.Shapes.disc(dim, center, radius, height)
-
-        print '--CREATE PHASE SLICES HOMOG. MAGN. DISC'
-        # Arrays for plotting:
-        x_d = []
-        y_d0 = []
-        y_d10 = []
-        dy_d0 = []
-        dy_d10 = []
-        # Analytic solution:
-        L = dim[1] * a  # in px/nm
-        Lz = 0.5 * dim[0] * a  # in px/nm
-        R = 0.25 * L  # in px/nm
-        x0 = L / 2  # in px/nm
-
-        def F_disc(x):
-            coeff = - pi * Lz / (2*PHI_0) * 1E3  # in mrad -> *1000
-            result = coeff * (- (x - x0) * np.sin(phi))
-            result *= np.where(np.abs(x - x0) <= R, 1, (R / (x - x0)) ** 2)
-            return result
-
-        x_d.append(np.linspace(0, L, 5000))
-        y_d0.append(F_disc(x_d[0]))
-        y_d10.append(F_disc(x_d[0]))
-        dy_d0.append(np.zeros_like(x_d[0]))
-        dy_d10.append(np.zeros_like(x_d[0]))
-        # Create MagData (Disc):
-        mag_data_disc = MagData(a, mc.create_mag_dist_homog(mag_shape, phi))
-        for i in range(5):
-            mag_data_disc.scale_down()
-            print '----a =', mag_data_disc.a, 'nm', 'dim =', mag_data_disc.dim
-            projection = pj.simple_axis_projection(mag_data_disc)
-            phase_map0 = PhaseMap(mag_data_disc.a,
-                                  pm.phase_mag_fourier(mag_data_disc.a, projection,
-                                                       padding=0), 'mrad')
-            phase_map10 = PhaseMap(mag_data_disc.a,
-                                   pm.phase_mag_fourier(mag_data_disc.a, projection,
-                                                        padding=10), 'mrad')
-            hi.display_combined(phase_map0, density,
-                                'Disc, a = {} nm'.format(mag_data_disc.a))
-            hi.display_combined(phase_map10, density,
-                                'Disc, a = {} nm'.format(mag_data_disc.a))
-            x_d.append(np.linspace(mag_data_disc.a * 0.5,
-                                   mag_data_disc.a * (mag_data_disc.dim[1]-0.5),
-                                   mag_data_disc.dim[1]))
-            slice_pos = int(mag_data_disc.dim[1]/2)
-            y_d0.append(phase_map0.phase[slice_pos, :]*1E3)  # *1E3: rad to mrad
-            y_d10.append(phase_map10.phase[slice_pos, :]*1E3)  # *1E3: rad to mrad
-            dy_d0.append(phase_map0.phase[slice_pos, :]*1E3 - F_disc(x_d[-1]))  # *1E3: in mrad
-            dy_d10.append(phase_map10.phase[slice_pos, :]*1E3 - F_disc(x_d[-1]))  # *1E3: in mrad
-
-        print '--CREATE PHASE SLICES VORTEX STATE DISC'
-        x_v = []
-        y_v0 = []
-        y_v10 = []
-        dy_v0 = []
-        dy_v10 = []
-        # Analytic solution:
-        L = dim[1] * a  # in px/nm
-        Lz = 0.5 * dim[0] * a  # in px/nm
-        R = 0.25 * L  # in px/nm
-        x0 = L / 2  # in px/nm
-
-        def F_vort(x):
-            coeff = pi*Lz/PHI_0 * 1E3  # in mrad -> *1000
-            result = coeff * np.where(np.abs(x - x0) <= R, (np.abs(x-x0)-R), 0)
-            return result
-
-        x_v.append(np.linspace(0, L, 5000))
-        y_v0.append(F_vort(x_v[0]))
-        y_v10.append(F_vort(x_v[0]))
-        dy_v0.append(np.zeros_like(x_v[0]))
-        dy_v10.append(np.zeros_like(x_v[0]))
-        # Create MagData (Vortex):
-        mag_data_vort = MagData(a, mc.create_mag_dist_vortex(mag_shape))
-        for i in range(5):
-            mag_data_vort.scale_down()
-            print '----a =', mag_data_vort.a, 'nm', 'dim =', mag_data_vort.dim
-            projection = pj.simple_axis_projection(mag_data_vort)
-            phase_map0 = PhaseMap(mag_data_vort.a,
-                                  pm.phase_mag_fourier(mag_data_vort.a, projection,
-                                                       padding=0), 'mrad')
-            phase_map10 = PhaseMap(mag_data_vort.a,
-                                   pm.phase_mag_fourier(mag_data_vort.a, projection,
-                                                        padding=10), 'mrad')
-            hi.display_combined(phase_map0, density,
-                                'Disc, a = {} nm'.format(mag_data_vort.a))
-            hi.display_combined(phase_map10, density,
-                                'Disc, a = {} nm'.format(mag_data_vort.a))
-            x_v.append(np.linspace(mag_data_vort.a * 0.5,
-                                   mag_data_vort.a * (mag_data_vort.dim[1]-0.5),
-                                   mag_data_vort.dim[1]))
-            slice_pos = int(mag_data_vort.dim[1]/2)
-            y_v0.append(phase_map0.phase[slice_pos, :]*1E3)  # *1E3: rad to mrad
-            y_v10.append(phase_map10.phase[slice_pos, :]*1E3)  # *1E3: rad to mrad
-            dy_v0.append(phase_map0.phase[slice_pos, :]*1E3 - F_vort(x_v[-1]))  # *1E3: in mrad
-            dy_v10.append(phase_map10.phase[slice_pos, :]*1E3 - F_vort(x_v[-1]))  # *1E3: in mrad
-
-        # Shelve x, y and dy:
-        print '--SAVE PHASE SLICES'
-        data_shelve[key] = (x_d, y_d0, y_d10, dy_d0, dy_d10, x_v, y_v0, y_v10, dy_v0, dy_v10)
-
-    # Create figure:
-    fig, axes = plt.subplots(1, 2, figsize=(16, 7))
-    fig.suptitle('Central phase slices (padding = 0)', fontsize=20)
-
-    print '--PLOT/SAVE PHASE SLICES HOMOG. MAGN. DISC PADDING = 0'
-    # Plot phase slices:
-    axes[0].plot(x_d[0], y_d0[0], '-k', linewidth=1.5, label='analytic')
-    axes[0].plot(x_d[1], y_d0[1], '-r', linewidth=1.5, label='0.5 nm')
-    axes[0].plot(x_d[2], y_d0[2], '-m', linewidth=1.5, label='1 nm')
-    axes[0].plot(x_d[3], y_d0[3], '-y', linewidth=1.5, label='2 nm')
-    axes[0].plot(x_d[4], y_d0[4], '-g', linewidth=1.5, label='4 nm')
-    axes[0].plot(x_d[5], y_d0[5], '-c', linewidth=1.5, label='8 nm')
-    axes[0].tick_params(axis='both', which='major', labelsize=14)
-    axes[0].set_title('Homog. magn. disc', fontsize=18)
-    axes[0].set_xlabel('x [nm]', fontsize=15)
-    axes[0].set_ylabel('phase [mrad]', fontsize=15)
-    axes[0].set_xlim(0, 128)
-    axes[0].set_ylim(-220, 220)
+print '\nACCESS SHELVE'
+# Create / Open databank:
+directory = '../../output/paper 1'
+if not os.path.exists(directory):
+    os.makedirs(directory)
+data_shelve = shelve.open(directory + '/paper_1_shelve')
+
+###############################################################################################
+print 'CH5-1 PHASE SLICES FOURIER SPACE'
+
+# Input parameters:
+a = 0.5  # in nm
+phi = pi/2
+density = 100
+dim = (32, 256, 256)  # in px (z, y, x)
+# Create magnetic shape:
+center = (dim[0]/2-0.5, dim[1]/2.-0.5, dim[2]/2.-0.5)  # in px (z, y, x) index starts with 0!
+radius = dim[1]/4  # in px
+height = dim[0]/2  # in px
+
+key = 'ch5-2-phase_slices_fourier'
+if key in data_shelve and not force_calculation:
+    print '--LOAD MAGNETIC DISTRIBUTION'
+    (x_d, y_d0, y_d10, dy_d0, dy_d10, x_v, y_v0, y_v10, dy_v0, dy_v10) = data_shelve[key]
+else:
+    print '--CREATE MAGNETIC DISTRIBUTION'
+    mag_shape = mc.Shapes.disc(dim, center, radius, height)
+
+    print '--CREATE PHASE SLICES HOMOG. MAGN. DISC'
+    # Arrays for plotting:
+    x_d = []
+    y_d0 = []
+    y_d10 = []
+    dy_d0 = []
+    dy_d10 = []
+    # Analytic solution:
+    L = dim[1] * a  # in px/nm
+    Lz = 0.5 * dim[0] * a  # in px/nm
+    R = 0.25 * L  # in px/nm
+    x0 = L / 2  # in px/nm
+
+    def F_disc(x):
+        coeff = - pi * Lz / (2*PHI_0) * 1E3  # in mrad -> *1000
+        result = coeff * (- (x - x0) * np.sin(phi))
+        result *= np.where(np.abs(x - x0) <= R, 1, (R / (x - x0)) ** 2)
+        return result
+
+    x_d.append(np.linspace(0, L, 5000))
+    y_d0.append(F_disc(x_d[0]))
+    y_d10.append(F_disc(x_d[0]))
+    dy_d0.append(np.zeros_like(x_d[0]))
+    dy_d10.append(np.zeros_like(x_d[0]))
+    # Create MagData (Disc):
+    mag_data_disc = MagData(a, mc.create_mag_dist_homog(mag_shape, phi))
+    for i in range(5):
+        print '----a =', mag_data_disc.a, 'nm', 'dim =', mag_data_disc.dim
+        projector = SimpleProjector(mag_data_disc.dim)
+        phase_map0 = PMFourier(mag_data_disc.a, projector, padding=0)(mag_data_disc)
+        phase_map10 = PMFourier(mag_data_disc.a, projector, padding=10)(mag_data_disc)
+        phase_map0.unit = 'mrad'
+        phase_map10.unit = 'mrad'
+        phase_map0.display_combined(density, 'Disc, a = {} nm'.format(mag_data_disc.a))
+        phase_map10.display_combined(density, 'Disc, a = {} nm'.format(mag_data_disc.a))
+        x_d.append(np.linspace(mag_data_disc.a * 0.5,
+                               mag_data_disc.a * (mag_data_disc.dim[1]-0.5),
+                               mag_data_disc.dim[1]))
+        slice_pos = int(mag_data_disc.dim[1]/2)
+        y_d0.append(phase_map0.phase[slice_pos, :]*1E3)  # *1E3: rad to mrad
+        y_d10.append(phase_map10.phase[slice_pos, :]*1E3)  # *1E3: rad to mrad
+        dy_d0.append(phase_map0.phase[slice_pos, :]*1E3 - F_disc(x_d[-1]))  # *1E3: in mrad
+        dy_d10.append(phase_map10.phase[slice_pos, :]*1E3 - F_disc(x_d[-1]))  # *1E3: in mrad
+        if i < 4: mag_data_disc.scale_down()
+
+    print '--CREATE PHASE SLICES VORTEX STATE DISC'
+    x_v = []
+    y_v0 = []
+    y_v10 = []
+    dy_v0 = []
+    dy_v10 = []
+    # Analytic solution:
+    L = dim[1] * a  # in px/nm
+    Lz = 0.5 * dim[0] * a  # in px/nm
+    R = 0.25 * L  # in px/nm
+    x0 = L / 2  # in px/nm
+
+    def F_vort(x):
+        coeff = pi*Lz/PHI_0 * 1E3  # in mrad -> *1000
+        result = coeff * np.where(np.abs(x - x0) <= R, (np.abs(x-x0)-R), 0)
+        return result
+
+    x_v.append(np.linspace(0, L, 5000))
+    y_v0.append(F_vort(x_v[0]))
+    y_v10.append(F_vort(x_v[0]))
+    dy_v0.append(np.zeros_like(x_v[0]))
+    dy_v10.append(np.zeros_like(x_v[0]))
+    # Create MagData (Vortex):
+    mag_data_vort = MagData(a, mc.create_mag_dist_vortex(mag_shape))
+    for i in range(5):
+        print '----a =', mag_data_vort.a, 'nm', 'dim =', mag_data_vort.dim
+        projector = SimpleProjector(mag_data_vort.dim)
+        phase_map0 = PMFourier(mag_data_vort.a, projector, padding=0)(mag_data_vort)
+        phase_map10 = PMFourier(mag_data_vort.a, projector, padding=10)(mag_data_vort)
+        phase_map0.unit = 'mrad'
+        phase_map10.unit = 'mrad'
+        print np.mean(phase_map0.phase)
+        phase_map0 -= phase_map0.phase[0, 0]
+        phase_map10 -= phase_map10.phase[0, 0]
+        phase_map0.display_combined(density, 'Vortex, a = {} nm'.format(mag_data_vort.a))
+        phase_map10.display_combined(density, 'Vortex, a = {} nm'.format(mag_data_vort.a))
+        x_v.append(np.linspace(mag_data_vort.a * 0.5,
+                               mag_data_vort.a * (mag_data_vort.dim[1]-0.5),
+                               mag_data_vort.dim[1]))
+        slice_pos = int(mag_data_vort.dim[1]/2)
+        y_v0.append(phase_map0.phase[slice_pos, :]*1E3)  # *1E3: rad to mrad
+        y_v10.append(phase_map10.phase[slice_pos, :]*1E3)  # *1E3: rad to mrad
+        dy_v0.append(phase_map0.phase[slice_pos, :]*1E3 - F_vort(x_v[-1]))  # *1E3: in mrad
+        dy_v10.append(phase_map10.phase[slice_pos, :]*1E3 - F_vort(x_v[-1]))  # *1E3: in mrad
+        if i < 4: mag_data_vort.scale_down()
+
+    # Shelve x, y and dy:
+    print '--SAVE PHASE SLICES'
+    data_shelve[key] = (x_d, y_d0, y_d10, dy_d0, dy_d10, x_v, y_v0, y_v10, dy_v0, dy_v10)
+
+# Create figure:
+fig, axes = plt.subplots(1, 2, figsize=(16, 7))
+fig.suptitle('Central phase slices (padding = 0)', fontsize=20)
+
+print '--PLOT/SAVE PHASE SLICES HOMOG. MAGN. DISC PADDING = 0'
+# Plot phase slices:
+axes[0].plot(x_d[0], y_d0[0], '-k', linewidth=1.5, label='analytic')
+axes[0].plot(x_d[1], y_d0[1], '-r', linewidth=1.5, label='0.5 nm')
+axes[0].plot(x_d[2], y_d0[2], '-m', linewidth=1.5, label='1 nm')
+axes[0].plot(x_d[3], y_d0[3], '-y', linewidth=1.5, label='2 nm')
+axes[0].plot(x_d[4], y_d0[4], '-g', linewidth=1.5, label='4 nm')
+axes[0].plot(x_d[5], y_d0[5], '-c', linewidth=1.5, label='8 nm')
+axes[0].tick_params(axis='both', which='major', labelsize=14)
+axes[0].set_title('Homog. magn. disc', fontsize=18)
+axes[0].set_xlabel('x [nm]', fontsize=15)
+axes[0].set_ylabel('phase [mrad]', fontsize=15)
+axes[0].set_xlim(0, 128)
+axes[0].set_ylim(-220, 220)
 #    # Plot Zoombox and Arrow:
 #    zoom = (23.5, 160, 15, 40)
 #    rect = Rectangle((zoom[0], zoom[1]), zoom[2], zoom[3], fc='w', ec='k')
@@ -202,21 +191,21 @@ def run():
 #    ins_axis_d.xaxis.set_major_locator(MaxNLocator(nbins=4, integer= True))
 #    ins_axis_d.yaxis.set_major_locator(MaxNLocator(nbins=3))
 
-    print '--PLOT/SAVE PHASE SLICES VORTEX STATE DISC PADDING = 0'
-    # Plot phase slices:
-    axes[1].plot(x_v[0], y_v0[0], '-k', linewidth=1.5, label='analytic')
-    axes[1].plot(x_v[1], y_v0[1], '-r', linewidth=1.5, label='0.5 nm')
-    axes[1].plot(x_v[2], y_v0[2], '-m', linewidth=1.5, label='1 nm')
-    axes[1].plot(x_v[3], y_v0[3], '-y', linewidth=1.5, label='2 nm')
-    axes[1].plot(x_v[4], y_v0[4], '-g', linewidth=1.5, label='4 nm')
-    axes[1].plot(x_v[5], y_v0[5], '-c', linewidth=1.5, label='8 nm')
-    axes[1].tick_params(axis='both', which='major', labelsize=14)
-    axes[1].set_title('Vortex state disc', fontsize=18)
-    axes[1].set_xlabel('x [nm]', fontsize=15)
-    axes[1].set_ylabel('phase [mrad]', fontsize=15)
-    axes[1].set_xlim(0, 128)
-    axes[1].yaxis.set_major_locator(MaxNLocator(nbins=6))
-    axes[1].legend()
+print '--PLOT/SAVE PHASE SLICES VORTEX STATE DISC PADDING = 0'
+# Plot phase slices:
+axes[1].plot(x_v[0], y_v0[0], '-k', linewidth=1.5, label='analytic')
+axes[1].plot(x_v[1], y_v0[1], '-r', linewidth=1.5, label='0.5 nm')
+axes[1].plot(x_v[2], y_v0[2], '-m', linewidth=1.5, label='1 nm')
+axes[1].plot(x_v[3], y_v0[3], '-y', linewidth=1.5, label='2 nm')
+axes[1].plot(x_v[4], y_v0[4], '-g', linewidth=1.5, label='4 nm')
+axes[1].plot(x_v[5], y_v0[5], '-c', linewidth=1.5, label='8 nm')
+axes[1].tick_params(axis='both', which='major', labelsize=14)
+axes[1].set_title('Vortex state disc', fontsize=18)
+axes[1].set_xlabel('x [nm]', fontsize=15)
+axes[1].set_ylabel('phase [mrad]', fontsize=15)
+axes[1].set_xlim(0, 128)
+axes[1].yaxis.set_major_locator(MaxNLocator(nbins=6))
+axes[1].legend()
 #    # Plot Zoombox and Arrow:
 #    zoom = (59, 340, 10, 55)
 #    rect = Rectangle((zoom[0], zoom[1]), zoom[2], zoom[3], fc='w', ec='k')
@@ -237,29 +226,29 @@ def run():
 #    ins_axis_v.xaxis.set_major_locator(MaxNLocator(nbins=4, integer= True))
 #    ins_axis_v.yaxis.set_major_locator(MaxNLocator(nbins=4))
 
-    plt.show()
-    plt.figtext(0.15, 0.13, 'a)', fontsize=30)
-    plt.figtext(0.57, 0.13, 'b)', fontsize=30)
-    plt.savefig(directory + '/ch5-1-phase_slice_padding_0.png', bbox_inches='tight')
-
-    # Create figure:
-    fig, axes = plt.subplots(1, 2, figsize=(16, 7))
-    fig.suptitle('Central phase slices (padding = 10)', fontsize=20)
-
-    print '--PLOT/SAVE PHASE SLICES HOMOG. MAGN. DISC PADDING = 10'
-    # Plot phase slices:
-    axes[0].plot(x_d[0], y_d10[0], '-k', linewidth=1.5, label='analytic')
-    axes[0].plot(x_d[1], y_d10[1], '-r', linewidth=1.5, label='0.5 nm')
-    axes[0].plot(x_d[2], y_d10[2], '-m', linewidth=1.5, label='1 nm')
-    axes[0].plot(x_d[3], y_d10[3], '-y', linewidth=1.5, label='2 nm')
-    axes[0].plot(x_d[4], y_d10[4], '-g', linewidth=1.5, label='4 nm')
-    axes[0].plot(x_d[5], y_d10[5], '-c', linewidth=1.5, label='8 nm')
-    axes[0].tick_params(axis='both', which='major', labelsize=14)
-    axes[0].set_title('Homog. magn. disc', fontsize=18)
-    axes[0].set_xlabel('x [nm]', fontsize=15)
-    axes[0].set_ylabel('phase [mrad]', fontsize=15)
-    axes[0].set_xlim(0, 128)
-    axes[0].set_ylim(-220, 220)
+plt.show()
+plt.figtext(0.15, 0.13, 'a)', fontsize=30)
+plt.figtext(0.57, 0.13, 'b)', fontsize=30)
+plt.savefig(directory + '/ch5-1-phase_slice_padding_0.png', bbox_inches='tight')
+
+# Create figure:
+fig, axes = plt.subplots(1, 2, figsize=(16, 7))
+fig.suptitle('Central phase slices (padding = 10)', fontsize=20)
+
+print '--PLOT/SAVE PHASE SLICES HOMOG. MAGN. DISC PADDING = 10'
+# Plot phase slices:
+axes[0].plot(x_d[0], y_d10[0], '-k', linewidth=1.5, label='analytic')
+axes[0].plot(x_d[1], y_d10[1], '-r', linewidth=1.5, label='0.5 nm')
+axes[0].plot(x_d[2], y_d10[2], '-m', linewidth=1.5, label='1 nm')
+axes[0].plot(x_d[3], y_d10[3], '-y', linewidth=1.5, label='2 nm')
+axes[0].plot(x_d[4], y_d10[4], '-g', linewidth=1.5, label='4 nm')
+axes[0].plot(x_d[5], y_d10[5], '-c', linewidth=1.5, label='8 nm')
+axes[0].tick_params(axis='both', which='major', labelsize=14)
+axes[0].set_title('Homog. magn. disc', fontsize=18)
+axes[0].set_xlabel('x [nm]', fontsize=15)
+axes[0].set_ylabel('phase [mrad]', fontsize=15)
+axes[0].set_xlim(0, 128)
+axes[0].set_ylim(-220, 220)
 #    # Plot Zoombox and Arrow:
 #    zoom = (23.5, 160, 15, 40)
 #    rect = Rectangle((zoom[0], zoom[1]), zoom[2], zoom[3], fc='w', ec='k')
@@ -280,21 +269,21 @@ def run():
 #    ins_axis_d.xaxis.set_major_locator(MaxNLocator(nbins=4, integer= True))
 #    ins_axis_d.yaxis.set_major_locator(MaxNLocator(nbins=3))
 
-    print '--PLOT/SAVE PHASE SLICES VORTEX STATE DISC PADDING = 10'
-    # Plot phase slices:
-    axes[1].plot(x_v[0], y_v10[0], '-k', linewidth=1.5, label='analytic')
-    axes[1].plot(x_v[1], y_v10[1], '-r', linewidth=1.5, label='0.5 nm')
-    axes[1].plot(x_v[2], y_v10[2], '-m', linewidth=1.5, label='1 nm')
-    axes[1].plot(x_v[3], y_v10[3], '-y', linewidth=1.5, label='2 nm')
-    axes[1].plot(x_v[4], y_v10[4], '-g', linewidth=1.5, label='4 nm')
-    axes[1].plot(x_v[5], y_v10[5], '-c', linewidth=1.5, label='8 nm')
-    axes[1].tick_params(axis='both', which='major', labelsize=14)
-    axes[1].set_title('Vortex state disc', fontsize=18)
-    axes[1].set_xlabel('x [nm]', fontsize=15)
-    axes[1].set_ylabel('phase [mrad]', fontsize=15)
-    axes[1].set_xlim(0, 128)
-    axes[1].yaxis.set_major_locator(MaxNLocator(nbins=6))
-    axes[1].legend()
+print '--PLOT/SAVE PHASE SLICES VORTEX STATE DISC PADDING = 10'
+# Plot phase slices:
+axes[1].plot(x_v[0], y_v10[0], '-k', linewidth=1.5, label='analytic')
+axes[1].plot(x_v[1], y_v10[1], '-r', linewidth=1.5, label='0.5 nm')
+axes[1].plot(x_v[2], y_v10[2], '-m', linewidth=1.5, label='1 nm')
+axes[1].plot(x_v[3], y_v10[3], '-y', linewidth=1.5, label='2 nm')
+axes[1].plot(x_v[4], y_v10[4], '-g', linewidth=1.5, label='4 nm')
+axes[1].plot(x_v[5], y_v10[5], '-c', linewidth=1.5, label='8 nm')
+axes[1].tick_params(axis='both', which='major', labelsize=14)
+axes[1].set_title('Vortex state disc', fontsize=18)
+axes[1].set_xlabel('x [nm]', fontsize=15)
+axes[1].set_ylabel('phase [mrad]', fontsize=15)
+axes[1].set_xlim(0, 128)
+axes[1].yaxis.set_major_locator(MaxNLocator(nbins=6))
+axes[1].legend()
 #    # Plot Zoombox and Arrow:
 #    zoom = (59, 340, 10, 55)
 #    rect = Rectangle((zoom[0], zoom[1]), zoom[2], zoom[3], fc='w', ec='k')
@@ -315,349 +304,357 @@ def run():
 #    ins_axis_v.xaxis.set_major_locator(MaxNLocator(nbins=4, integer= True))
 #    ins_axis_v.yaxis.set_major_locator(MaxNLocator(nbins=4))
 
-    plt.show()
-    plt.figtext(0.15, 0.13, 'c)', fontsize=30)
-    plt.figtext(0.57, 0.13, 'd)', fontsize=30)
-    plt.savefig(directory + '/ch5-1-phase_slice_padding_10.png', bbox_inches='tight')
-
-    # Create figure:
-    fig, axes = plt.subplots(1, 2, figsize=(16, 7))
-    fig.suptitle('Central phase slice errors (padding = 0)', fontsize=20)
-
-    print '--PLOT/SAVE PHASE SLICE ERRORS HOMOG. MAGN. DISC PADDING = 0'
-    # Plot phase slices:
-    axes[0].plot(x_d[0], dy_d0[0], '-k', linewidth=1.5, label='analytic')
-    axes[0].plot(x_d[1], dy_d0[1], '-r', linewidth=1.5, label='0.5 nm')
-    axes[0].plot(x_d[2], dy_d0[2], '-m', linewidth=1.5, label='1 nm')
-    axes[0].plot(x_d[3], dy_d0[3], '-y', linewidth=1.5, label='2 nm')
-    axes[0].plot(x_d[4], dy_d0[4], '-g', linewidth=1.5, label='4 nm')
-    axes[0].plot(x_d[5], dy_d0[5], '-c', linewidth=1.5, label='8 nm')
-    axes[0].tick_params(axis='both', which='major', labelsize=14)
-    axes[0].set_title('Homog. magn. disc', fontsize=18)
-    axes[0].set_xlabel('x [nm]', fontsize=15)
-    axes[0].set_ylabel('phase [mrad]', fontsize=15)
-    axes[0].set_xlim(0, 128)
-
-    print '--PLOT/SAVE PHASE SLICE ERRORS VORTEX STATE DISC PADDING = 0'
-    # Plot phase slices:
-    axes[1].plot(x_v[0], dy_v0[0], '-k', linewidth=1.5, label='analytic')
-    axes[1].plot(x_v[1], dy_v0[1], '-r', linewidth=1.5, label='0.5 nm')
-    axes[1].plot(x_v[2], dy_v0[2], '-m', linewidth=1.5, label='1 nm')
-    axes[1].plot(x_v[3], dy_v0[3], '-y', linewidth=1.5, label='2 nm')
-    axes[1].plot(x_v[4], dy_v0[4], '-g', linewidth=1.5, label='4 nm')
-    axes[1].plot(x_v[5], dy_v0[5], '-c', linewidth=1.5, label='8 nm')
-    axes[1].tick_params(axis='both', which='major', labelsize=14)
-    axes[1].set_title('Vortex state disc', fontsize=18)
-    axes[1].set_xlabel('x [nm]', fontsize=15)
-    axes[1].set_ylabel('phase [mrad]', fontsize=15)
-    axes[1].set_xlim(0, 128)
-    axes[1].legend(loc=4)
-
-    plt.show()
-    plt.figtext(0.15, 0.13, 'c)', fontsize=30)
-    plt.figtext(0.57, 0.13, 'd)', fontsize=30)
-    plt.savefig(directory + '/ch5-1-phase_slice_errors_padding_0.png', bbox_inches='tight')
-
-    # Create figure:
-    fig, axes = plt.subplots(1, 2, figsize=(16, 7))
-    fig.suptitle('Central phase slice errors (padding = 10)', fontsize=20)
-
-    print '--PLOT/SAVE PHASE SLICE ERRORS HOMOG. MAGN. DISC PADDING = 10'
-    # Plot phase slices:
-    axes[0].plot(x_d[0], dy_d10[0], '-k', linewidth=1.5, label='analytic')
-    axes[0].plot(x_d[1], dy_d10[1], '-r', linewidth=1.5, label='0.5 nm')
-    axes[0].plot(x_d[2], dy_d10[2], '-m', linewidth=1.5, label='1 nm')
-    axes[0].plot(x_d[3], dy_d10[3], '-y', linewidth=1.5, label='2 nm')
-    axes[0].plot(x_d[4], dy_d10[4], '-g', linewidth=1.5, label='4 nm')
-    axes[0].plot(x_d[5], dy_d10[5], '-c', linewidth=1.5, label='8 nm')
-    axes[0].tick_params(axis='both', which='major', labelsize=14)
-    axes[0].set_title('Homog. magn. disc', fontsize=18)
-    axes[0].set_xlabel('x [nm]', fontsize=15)
-    axes[0].set_ylabel('phase [mrad]', fontsize=15)
-    axes[0].set_xlim(0, 128)
-
-    print '--PLOT/SAVE PHASE SLICE ERRORS VORTEX STATE DISC PADDING = 10'
-    # Plot phase slices:
-    axes[1].plot(x_v[0], dy_v10[0], '-k', linewidth=1.5, label='analytic')
-    axes[1].plot(x_v[1], dy_v10[1], '-r', linewidth=1.5, label='0.5 nm')
-    axes[1].plot(x_v[2], dy_v10[2], '-m', linewidth=1.5, label='1 nm')
-    axes[1].plot(x_v[3], dy_v10[3], '-y', linewidth=1.5, label='2 nm')
-    axes[1].plot(x_v[4], dy_v10[4], '-g', linewidth=1.5, label='4 nm')
-    axes[1].plot(x_v[5], dy_v10[5], '-c', linewidth=1.5, label='8 nm')
-    axes[1].tick_params(axis='both', which='major', labelsize=14)
-    axes[1].set_title('Vortex state disc', fontsize=18)
-    axes[1].set_xlabel('x [nm]', fontsize=15)
-    axes[1].set_ylabel('phase [mrad]', fontsize=15)
-    axes[1].set_xlim(0, 128)
-    axes[1].legend(loc=4)
-
-    plt.show()
-    plt.figtext(0.15, 0.13, 'c)', fontsize=30)
-    plt.figtext(0.57, 0.13, 'd)', fontsize=30)
-    plt.savefig(directory + '/ch5-1-phase_slice_errors_padding_10.png', bbox_inches='tight')
-
-    ###############################################################################################
-    print 'CH5-2 PHASE DIFFERENCES FOURIER SPACE'
-
-    # Input parameters:
-    a = 1.0  # in nm
-    phi = pi/2
-    dim = (16, 128, 128)  # in px (z, y, x)
-    center = (dim[0]/2-0.5, dim[1]/2.-0.5, dim[2]/2.-0.5)  # in px (z, y, x) index starts with 0!
-    radius = dim[1]/4  # in px
-    height = dim[0]/2  # in px
-
-    key = 'ch5-1-phase_diff_mag_dist'
-    if key in data_shelve:
-        print '--LOAD MAGNETIC DISTRIBUTIONS'
-        (mag_data_disc, mag_data_vort) = data_shelve[key]
+plt.show()
+plt.figtext(0.15, 0.13, 'c)', fontsize=30)
+plt.figtext(0.57, 0.13, 'd)', fontsize=30)
+plt.savefig(directory + '/ch5-1-phase_slice_padding_10.png', bbox_inches='tight')
+
+# Create figure:
+fig, axes = plt.subplots(1, 2, figsize=(16, 7))
+fig.suptitle('Central phase slice errors (padding = 0)', fontsize=20)
+
+print '--PLOT/SAVE PHASE SLICE ERRORS HOMOG. MAGN. DISC PADDING = 0'
+# Plot phase slices:
+axes[0].plot(x_d[0], dy_d0[0], '-k', linewidth=1.5, label='analytic')
+axes[0].plot(x_d[1], dy_d0[1], '-r', linewidth=1.5, label='0.5 nm')
+axes[0].plot(x_d[2], dy_d0[2], '-m', linewidth=1.5, label='1 nm')
+axes[0].plot(x_d[3], dy_d0[3], '-y', linewidth=1.5, label='2 nm')
+axes[0].plot(x_d[4], dy_d0[4], '-g', linewidth=1.5, label='4 nm')
+axes[0].plot(x_d[5], dy_d0[5], '-c', linewidth=1.5, label='8 nm')
+axes[0].tick_params(axis='both', which='major', labelsize=14)
+axes[0].set_title('Homog. magn. disc', fontsize=18)
+axes[0].set_xlabel('x [nm]', fontsize=15)
+axes[0].set_ylabel('phase [mrad]', fontsize=15)
+axes[0].set_xlim(0, 128)
+
+print '--PLOT/SAVE PHASE SLICE ERRORS VORTEX STATE DISC PADDING = 0'
+# Plot phase slices:
+axes[1].plot(x_v[0], dy_v0[0], '-k', linewidth=1.5, label='analytic')
+axes[1].plot(x_v[1], dy_v0[1], '-r', linewidth=1.5, label='0.5 nm')
+axes[1].plot(x_v[2], dy_v0[2], '-m', linewidth=1.5, label='1 nm')
+axes[1].plot(x_v[3], dy_v0[3], '-y', linewidth=1.5, label='2 nm')
+axes[1].plot(x_v[4], dy_v0[4], '-g', linewidth=1.5, label='4 nm')
+axes[1].plot(x_v[5], dy_v0[5], '-c', linewidth=1.5, label='8 nm')
+axes[1].tick_params(axis='both', which='major', labelsize=14)
+axes[1].set_title('Vortex state disc', fontsize=18)
+axes[1].set_xlabel('x [nm]', fontsize=15)
+axes[1].set_ylabel('phase [mrad]', fontsize=15)
+axes[1].set_xlim(0, 128)
+axes[1].legend(loc=4)
+
+plt.show()
+plt.figtext(0.15, 0.13, 'c)', fontsize=30)
+plt.figtext(0.57, 0.13, 'd)', fontsize=30)
+plt.savefig(directory + '/ch5-1-phase_slice_errors_padding_0.png', bbox_inches='tight')
+
+# Create figure:
+fig, axes = plt.subplots(1, 2, figsize=(16, 7))
+fig.suptitle('Central phase slice errors (padding = 10)', fontsize=20)
+
+print '--PLOT/SAVE PHASE SLICE ERRORS HOMOG. MAGN. DISC PADDING = 10'
+# Plot phase slices:
+axes[0].plot(x_d[0], dy_d10[0], '-k', linewidth=1.5, label='analytic')
+axes[0].plot(x_d[1], dy_d10[1], '-r', linewidth=1.5, label='0.5 nm')
+axes[0].plot(x_d[2], dy_d10[2], '-m', linewidth=1.5, label='1 nm')
+axes[0].plot(x_d[3], dy_d10[3], '-y', linewidth=1.5, label='2 nm')
+axes[0].plot(x_d[4], dy_d10[4], '-g', linewidth=1.5, label='4 nm')
+axes[0].plot(x_d[5], dy_d10[5], '-c', linewidth=1.5, label='8 nm')
+axes[0].tick_params(axis='both', which='major', labelsize=14)
+axes[0].set_title('Homog. magn. disc', fontsize=18)
+axes[0].set_xlabel('x [nm]', fontsize=15)
+axes[0].set_ylabel('phase [mrad]', fontsize=15)
+axes[0].set_xlim(0, 128)
+
+print '--PLOT/SAVE PHASE SLICE ERRORS VORTEX STATE DISC PADDING = 10'
+# Plot phase slices:
+axes[1].plot(x_v[0], dy_v10[0], '-k', linewidth=1.5, label='analytic')
+axes[1].plot(x_v[1], dy_v10[1], '-r', linewidth=1.5, label='0.5 nm')
+axes[1].plot(x_v[2], dy_v10[2], '-m', linewidth=1.5, label='1 nm')
+axes[1].plot(x_v[3], dy_v10[3], '-y', linewidth=1.5, label='2 nm')
+axes[1].plot(x_v[4], dy_v10[4], '-g', linewidth=1.5, label='4 nm')
+axes[1].plot(x_v[5], dy_v10[5], '-c', linewidth=1.5, label='8 nm')
+axes[1].tick_params(axis='both', which='major', labelsize=14)
+axes[1].set_title('Vortex state disc', fontsize=18)
+axes[1].set_xlabel('x [nm]', fontsize=15)
+axes[1].set_ylabel('phase [mrad]', fontsize=15)
+axes[1].set_xlim(0, 128)
+axes[1].legend(loc=4)
+
+plt.show()
+plt.figtext(0.15, 0.13, 'c)', fontsize=30)
+plt.figtext(0.57, 0.13, 'd)', fontsize=30)
+plt.savefig(directory + '/ch5-1-phase_slice_errors_padding_10.png', bbox_inches='tight')
+
+###############################################################################################
+print 'CH5-2 PHASE DIFFERENCES FOURIER SPACE'
+
+# Input parameters:
+a = 1.0  # in nm
+phi = pi/2
+dim = (16, 128, 128)  # in px (z, y, x)
+center = (dim[0]/2-0.5, dim[1]/2.-0.5, dim[2]/2.-0.5)  # in px (z, y, x) index starts with 0!
+radius = dim[1]/4  # in px
+height = dim[0]/2  # in px
+
+key = 'ch5-1-phase_diff_mag_dist'
+if key in data_shelve and not force_calculation:
+    print '--LOAD MAGNETIC DISTRIBUTIONS'
+    (mag_data_disc, mag_data_vort) = data_shelve[key]
+else:
+    print '--CREATE MAGNETIC DISTRIBUTIONS'
+    # Create magnetic shape (4 times the size):
+    a_big = a / 2
+    dim_big = (dim[0]*2, dim[1]*2, dim[2]*2)
+    center_big = (dim_big[0]/2-0.5, dim_big[1]/2.-0.5, dim_big[2]/2.-0.5)
+    radius_big = dim_big[1]/4  # in px
+    height_big = dim_big[0]/2  # in px
+    mag_shape = mc.Shapes.disc(dim_big, center_big, radius_big, height_big)
+    # Create MagData (4 times the size):
+    mag_data_disc = MagData(a_big, mc.create_mag_dist_homog(mag_shape, phi))
+    mag_data_vort = MagData(a_big, mc.create_mag_dist_vortex(mag_shape, center_big))
+    # Scale mag_data, grid spacing and dimensions:
+    mag_data_disc.scale_down()
+    mag_data_vort.scale_down()
+    print '--SAVE MAGNETIC DISTRIBUTIONS'
+    # Shelve magnetic distributions:
+    data_shelve[key] = (mag_data_disc, mag_data_vort)
+
+print '--PLOT/SAVE PHASE DIFFERENCES'
+# Create projections along z-axis:
+projector = SimpleProjector(dim)
+# Get analytic solutions:
+phase_map_ana_disc = an.phase_mag_disc(dim, a, phi, center, radius, height)
+phase_map_ana_vort = an.phase_mag_vortex(dim, a, center, radius, height)
+
+# Create phasemapper:
+phasemapper = PMFourier(a, projector, padding=0)
+# Create figure:
+fig, axes = plt.subplots(1, 2, figsize=(16, 7))
+fig.suptitle('Difference of the Fourier space approach from the analytical solution', fontsize=20)
+# Create norm for the plots:
+bounds = np.array([-100, -50, -25, -5, 0, 5, 25, 50, 100])
+norm = BoundaryNorm(bounds, RdBu.N)
+# Disc:
+phase_map_num_disc = phasemapper(mag_data_disc)
+phase_map_num_disc.unit = 'mrad'
+phase_diff_disc = phase_map_num_disc - phase_map_ana_disc
+RMS_disc = np.sqrt(np.mean(phase_diff_disc.phase**2))
+phase_diff_disc.display_phase('Homog. magn. disc, RMS = {:3.2f} mrad'.format(RMS_disc),
+                              axis=axes[0], limit=np.max(bounds), norm=norm)
+axes[0].set_aspect('equal')
+
+# Create norm for the plots:
+bounds = np.array([-3, -0.5, -0.25, -0.1, 0, 0.1, 0.25, 0.5, 3])
+norm = BoundaryNorm(bounds, RdBu.N)
+# Vortex:
+phase_map_num_vort = phasemapper(mag_data_vort)
+phase_map_num_vort.unit = 'mrad'
+phase_diff_vort = phase_map_num_vort - phase_map_ana_vort
+phase_diff_vort -= np.mean(phase_diff_vort.phase)
+RMS_vort = np.sqrt(np.mean(phase_diff_vort.phase**2))
+phase_diff_vort.display_phase(u'Vortex state disc, RMS = {:3.2f} µrad'.format(RMS_vort*1000),
+                              axis=axes[1], limit=np.max(bounds), norm=norm)
+axes[1].set_aspect('equal')
+
+plt.show()
+plt.figtext(0.15, 0.2, 'a)', fontsize=30)
+plt.figtext(0.52, 0.2, 'b)', fontsize=30)
+plt.savefig(directory + '/ch5-2-fourier_phase_differe_no_padding.png', bbox_inches='tight')
+
+# Create phasemapper:
+phasemapper = PMFourier(a, projector, padding=10)
+# Create figure:
+fig, axes = plt.subplots(1, 2, figsize=(16, 7))
+fig.suptitle('Difference of the Fourier space approach from the analytical solution', fontsize=20)
+# Create norm for the plots:
+bounds = np.array([-3, -0.5, -0.25, -0.1, 0, 0.1, 0.25, 0.5, 3])
+norm = BoundaryNorm(bounds, RdBu.N)
+# Disc:
+phase_map_num_disc = phasemapper(mag_data_disc)
+phase_map_num_disc.unit = 'mrad'
+phase_diff_disc = phase_map_num_disc - phase_map_ana_disc
+RMS_disc = np.sqrt(np.mean(phase_diff_disc.phase**2))
+phase_diff_disc.display_phase(u'Homog. magn. disc, RMS = {:3.2f} µrad'.format(RMS_disc*1000),
+                              axis=axes[0], limit=np.max(bounds), norm=norm)
+axes[0].set_aspect('equal')
+
+# Create norm for the plots:
+bounds = np.array([-3, -0.5, -0.25, -0.1, 0, 0.1, 0.25, 0.5, 3])
+norm = BoundaryNorm(bounds, RdBu.N)
+# Vortex:
+phase_map_num_vort = phasemapper(mag_data_vort)
+phase_map_num_vort.unit = 'mrad'
+phase_diff_vort = phase_map_num_vort - phase_map_ana_vort
+phase_diff_vort -= np.mean(phase_diff_vort.phase)
+RMS_vort = np.sqrt(np.mean(phase_diff_vort.phase**2))
+phase_diff_vort.display_phase(u'Vortex state disc, RMS = {:3.2f} µrad'.format(RMS_vort*1000),
+                              axis=axes[1], limit=np.max(bounds), norm=norm)
+axes[1].set_aspect('equal')
+
+plt.show()
+plt.figtext(0.15, 0.2, 'c)', fontsize=30)
+plt.figtext(0.52, 0.2, 'd)', fontsize=30)
+plt.savefig(directory + '/ch5-2-fourier_phase_differe_padding_10.png', bbox_inches='tight')
+
+###############################################################################################
+print 'CH5-2 FOURIER PADDING VARIATION'
+
+# Input parameters:
+a = 1.0  # in nm
+phi = pi/2
+dim = (16, 128, 128)  # in px (z, y, x)
+center = (dim[0]/2-0.5, dim[1]/2.-0.5, dim[2]/2.-0.5)  # in px (z, y, x) index starts with 0!
+radius = dim[1]/4  # in px
+height = dim[0]/2  # in px
+
+key = 'ch5-2-fourier_padding_mag_dist'
+if key in data_shelve and not force_calculation:
+    print '--LOAD MAGNETIC DISTRIBUTIONS'
+    (mag_data_disc, mag_data_vort) = data_shelve[key]
+else:
+    print '--CREATE MAGNETIC DISTRIBUTIONS'
+    # Create magnetic shape (4 times the size):
+    a_big = a / 2
+    dim_big = (dim[0]*2, dim[1]*2, dim[2]*2)
+    center_big = (dim_big[0]/2-0.5, dim_big[1]/2.-0.5, dim_big[2]/2.-0.5)
+    radius_big = dim_big[1]/4  # in px
+    height_big = dim_big[0]/2  # in px
+    mag_shape = mc.Shapes.disc(dim_big, center_big, radius_big, height_big)
+    # Create MagData (4 times the size):
+    mag_data_disc = MagData(a_big, mc.create_mag_dist_homog(mag_shape, phi))
+    mag_data_vort = MagData(a_big, mc.create_mag_dist_vortex(mag_shape, center_big))
+    # Scale mag_data, grid spacing and dimensions:
+    mag_data_disc.scale_down()
+    mag_data_vort.scale_down()
+    print '--SAVE MAGNETIC DISTRIBUTIONS'
+    # Shelve magnetic distributions:
+    data_shelve[key] = (mag_data_disc, mag_data_vort)
+
+# Create projections along z-axis:
+projector = SimpleProjector(dim)
+# Get analytic solutions:
+phase_ana_disc = an.phase_mag_disc(dim, a, phi, center, radius, height)
+phase_ana_vort = an.phase_mag_vortex(dim, a, center, radius, height)
+
+# List of applied paddings:
+padding_list = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]
+
+print '--LOAD/CREATE PADDING SERIES OF HOMOG. MAGN. DISC'
+data_disc = np.zeros((3, len(padding_list)))
+data_disc[0, :] = padding_list
+for (i, padding) in enumerate(padding_list):
+    key = ', '.join(['Padding->RMS|duration', 'Fourier', 'padding={}'.format(padding_list[i]),
+                    'a={}'.format(a), 'dim={}'.format(dim), 'phi={}'.format(phi), 'disc'])
+    if key in data_shelve and not force_calculation:
+        data_disc[:, i] = data_shelve[key]
     else:
-        print '--CREATE MAGNETIC DISTRIBUTIONS'
-        # Create magnetic shape (4 times the size):
-        a_big = a / 2
-        dim_big = (dim[0]*2, dim[1]*2, dim[2]*2)
-        center_big = (dim_big[0]/2-0.5, dim_big[1]/2.-0.5, dim_big[2]/2.-0.5)
-        radius_big = dim_big[1]/4  # in px
-        height_big = dim_big[0]/2  # in px
-        mag_shape = mc.Shapes.disc(dim_big, center_big, radius_big, height_big)
-        # Create MagData (4 times the size):
-        mag_data_disc = MagData(a_big, mc.create_mag_dist_homog(mag_shape, phi))
-        mag_data_vort = MagData(a_big, mc.create_mag_dist_vortex(mag_shape, center_big))
-        # Scale mag_data, grid spacing and dimensions:
-        mag_data_disc.scale_down()
-        mag_data_vort.scale_down()
-        print '--SAVE MAGNETIC DISTRIBUTIONS'
-        # Shelve magnetic distributions:
-        data_shelve[key] = (mag_data_disc, mag_data_vort)
-
-    print '--PLOT/SAVE PHASE DIFFERENCES'
-    # Create projections along z-axis:
-    projection_disc = pj.simple_axis_projection(mag_data_disc)
-    projection_vort = pj.simple_axis_projection(mag_data_vort)
-    # Get analytic solutions:
-    phase_ana_disc = an.phase_mag_disc(dim, a, phi, center, radius, height)
-    phase_ana_vort = an.phase_mag_vortex(dim, a, center, radius, height)
-
-    # Create figure:
-    fig, axes = plt.subplots(1, 2, figsize=(16, 7))
-    fig.suptitle('Difference of the real space approach from the analytical solution', fontsize=20)
-    # Create norm for the plots:
-    bounds = np.array([-100, -50, -25, -5, 0, 5, 25, 50, 100])
-    norm = BoundaryNorm(bounds, RdBu.N)
-    # Disc:
-    phase_num_disc = pm.phase_mag_fourier(a, projection_disc, padding=0)
-    phase_diff_disc = PhaseMap(a, (phase_num_disc-phase_ana_disc), 'mrad')
-    RMS_disc = np.sqrt(np.mean(phase_diff_disc.phase**2))
-    phase_diff_disc.display('Homog. magn. disc, RMS = {:3.2f} mrad'.format(RMS_disc),
-                            axis=axes[0], limit=np.max(bounds), norm=norm)
-    axes[0].set_aspect('equal')
-    # Vortex:
-    phase_num_vort = pm.phase_mag_fourier(a, projection_vort, padding=0)
-    phase_diff_vort = PhaseMap(a, (phase_num_vort-phase_ana_vort), 'mrad')
-    RMS_vort = np.sqrt(np.mean(phase_diff_vort.phase**2))
-    phase_diff_vort.display('Vortex state disc, RMS = {:3.2f} mrad'.format(RMS_vort),
-                            axis=axes[1], limit=np.max(bounds), norm=norm)
-    axes[1].set_aspect('equal')
-
-    plt.show()
-    plt.figtext(0.15, 0.2, 'a)', fontsize=30)
-    plt.figtext(0.52, 0.2, 'b)', fontsize=30)
-    plt.savefig(directory + '/ch5-2-fourier_phase_differe_no_padding.png', bbox_inches='tight')
-
-    # Create figure:
-    fig, axes = plt.subplots(1, 2, figsize=(16, 7))
-    fig.suptitle('Difference of the real space approach from the analytical solution', fontsize=20)
-    # Create norm for the plots:
-    bounds = np.array([-3, -0.5, -0.25, -0.1, 0, 0.1, 0.25, 0.5, 3])
-    norm = BoundaryNorm(bounds, RdBu.N)
-    # Disc:
-    phase_num_disc = pm.phase_mag_fourier(a, projection_disc, padding=10)
-    phase_diff_disc = PhaseMap(a, (phase_num_disc-phase_ana_disc), 'mrad')
-    RMS_disc = np.sqrt(np.mean(phase_diff_disc.phase**2))
-    phase_diff_disc.display('Homog. magn. disc, RMS = {:3.2f} mrad'.format(RMS_disc),
-                            axis=axes[0], limit=np.max(bounds), norm=norm)
-    axes[0].set_aspect('equal')
-    # Vortex:
-    phase_num_vort = pm.phase_mag_fourier(a, projection_vort, padding=10)
-    phase_diff_vort = PhaseMap(a, (phase_num_vort-phase_ana_vort), 'mrad')
-    RMS_vort = np.sqrt(np.mean(phase_diff_vort.phase**2))
-    phase_diff_vort.display('Vortex state disc, RMS = {:3.2f} mrad'.format(RMS_vort),
-                            axis=axes[1], limit=np.max(bounds), norm=norm)
-    axes[1].set_aspect('equal')
-
-    plt.show()
-    plt.figtext(0.15, 0.2, 'c)', fontsize=30)
-    plt.figtext(0.52, 0.2, 'd)', fontsize=30)
-    plt.savefig(directory + '/ch5-2-fourier_phase_differe_padding_10.png', bbox_inches='tight')
-
-    ###############################################################################################
-    print 'CH5-2 FOURIER PADDING VARIATION'
-
-    # Input parameters:
-    a = 1.0  # in nm
-    phi = pi/2
-    dim = (16, 128, 128)  # in px (z, y, x)
-    center = (dim[0]/2-0.5, dim[1]/2.-0.5, dim[2]/2.-0.5)  # in px (z, y, x) index starts with 0!
-    radius = dim[1]/4  # in px
-    height = dim[0]/2  # in px
-
-    key = 'ch5-2-fourier_padding_mag_dist'
-    if key in data_shelve:
-        print '--LOAD MAGNETIC DISTRIBUTIONS'
-        (mag_data_disc, mag_data_vort) = data_shelve[key]
+        print '----calculate and save padding =', padding_list[i]
+        phasemapper = PMFourier(a, projector, padding=padding_list[i])
+        start_time = time.time()
+        phase_num_disc = phasemapper(mag_data_disc)
+        data_disc[2, i] = time.time() - start_time
+        phase_map_diff = phase_num_disc - phase_ana_disc
+        phase_map_diff.unit = 'mrad'
+        phase_map_diff.display_phase()
+        data_disc[1, i] = np.sqrt(np.mean(phase_map_diff.phase**2))*1E3  # *1E3: rad to mraddd
+        data_shelve[key] = data_disc[:, i]
+
+print '--PLOT/SAVE PADDING SERIES OF HOMOG. MAGN. DISC'
+# Create figure:
+fig, axes = plt.subplots(1, 2, figsize=(16, 7))
+fig.suptitle('Variation of the padding (homog. magn. disc)', fontsize=20)
+# Plot RMS against padding:
+axes[0].axhline(y=0.18, linestyle='--', color='g', label='RMS [mrad] (real space)')
+axes[0].plot(data_disc[0], data_disc[1], 'go-', label='RMS [mrad] (Fourier space)')
+axes[0].set_xlabel('padding', fontsize=15)
+axes[0].set_ylabel('RMS [mrad]', fontsize=15)
+axes[0].set_xlim(-0.5, 16.5)
+axes[0].set_ylim(-5, 45)
+axes[0].xaxis.set_major_locator(MaxNLocator(nbins=10, integer=True))
+axes[0].tick_params(axis='both', which='major', labelsize=14)
+axes[0].legend()
+# Plot zoom inset:
+ins_axis_d = plt.axes([0.2, 0.35, 0.25, 0.4])
+ins_axis_d.axhline(y=0.18, linestyle='--', color='g')
+ins_axis_d.plot(data_disc[0], data_disc[1], 'go-')
+ins_axis_d.set_yscale('log')
+ins_axis_d.set_xlim(5.5, 16.5)
+ins_axis_d.set_ylim(0.1, 1.1)
+ins_axis_d.tick_params(axis='both', which='major', labelsize=14)
+# Plot duration against padding:
+axes[1].plot(data_disc[0], data_disc[2], 'bo-')
+axes[1].set_xlabel('padding', fontsize=15)
+axes[1].set_ylabel('duration [s]', fontsize=15)
+axes[1].set_xlim(-0.5, 16.5)
+axes[1].set_ylim(-0.05, 1.5)
+axes[1].xaxis.set_major_locator(MaxNLocator(nbins=10, integer=True))
+axes[1].yaxis.set_major_locator(MaxNLocator(nbins=10))
+axes[1].tick_params(axis='both', which='major', labelsize=14)
+
+plt.show()
+plt.figtext(0.15, 0.13, 'a)', fontsize=30)
+plt.figtext(0.57, 0.17, 'b)', fontsize=30)
+plt.savefig(directory + '/ch5-2-disc_padding_variation.png', bbox_inches='tight')
+
+print '--LOAD/CREATE PADDING SERIES OF VORTEX STATE DISC'
+data_vort = np.zeros((3, len(padding_list)))
+data_vort[0, :] = padding_list
+for (i, padding) in enumerate(padding_list):
+    key = ', '.join(['Padding->RMS|duration', 'Fourier', 'padding={}'.format(padding_list[i]),
+                    'a={}'.format(a), 'dim={}'.format(dim), 'phi={}'.format(phi), 'vort'])
+    if key in data_shelve and not force_calculation:
+        data_vort[:, i] = data_shelve[key]
     else:
-        print '--CREATE MAGNETIC DISTRIBUTIONS'
-        # Create magnetic shape (4 times the size):
-        a_big = a / 2
-        dim_big = (dim[0]*2, dim[1]*2, dim[2]*2)
-        center_big = (dim_big[0]/2-0.5, dim_big[1]/2.-0.5, dim_big[2]/2.-0.5)
-        radius_big = dim_big[1]/4  # in px
-        height_big = dim_big[0]/2  # in px
-        mag_shape = mc.Shapes.disc(dim_big, center_big, radius_big, height_big)
-        # Create MagData (4 times the size):
-        mag_data_disc = MagData(a_big, mc.create_mag_dist_homog(mag_shape, phi))
-        mag_data_vort = MagData(a_big, mc.create_mag_dist_vortex(mag_shape, center_big))
-        # Scale mag_data, grid spacing and dimensions:
-        mag_data_disc.scale_down()
-        mag_data_vort.scale_down()
-        print '--SAVE MAGNETIC DISTRIBUTIONS'
-        # Shelve magnetic distributions:
-        data_shelve[key] = (mag_data_disc, mag_data_vort)
-
-    # Create projections along z-axis:
-    projection_disc = pj.simple_axis_projection(mag_data_disc)
-    projection_vort = pj.simple_axis_projection(mag_data_vort)
-    # Get analytic solutions:
-    phase_ana_disc = an.phase_mag_disc(dim, a, phi, center, radius, height)
-    phase_ana_vort = an.phase_mag_vortex(dim, a, center, radius, height)
-
-    # List of applied paddings:
-    padding_list = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]
-
-    print '--LOAD/CREATE PADDING SERIES OF HOMOG. MAGN. DISC'
-    data_disc = np.zeros((3, len(padding_list)))
-    data_disc[0, :] = padding_list
-    for (i, padding) in enumerate(padding_list):
-        key = ', '.join(['Padding->RMS|duration', 'Fourier', 'padding={}'.format(padding_list[i]),
-                        'a={}'.format(a), 'dim={}'.format(dim), 'phi={}'.format(phi), 'disc'])
-        if key in data_shelve:
-            data_disc[:, i] = data_shelve[key]
-        else:
-            print '----calculate and save padding =', padding_list[i]
-            start_time = time.time()
-            phase_num_disc = pm.phase_mag_fourier(a, projection_disc, padding=padding_list[i])
-            data_disc[2, i] = time.time() - start_time
-            phase_diff = (phase_num_disc-phase_ana_disc)
-            phase_map_diff = PhaseMap(a, phase_diff, 'mrad')
-            phase_map_diff.display()
-            data_disc[1, i] = np.sqrt(np.mean(phase_map_diff.phase**2))*1E3  # *1E3: rad to mraddd
-            data_shelve[key] = data_disc[:, i]
-
-    print '--PLOT/SAVE PADDING SERIES OF HOMOG. MAGN. DISC'
-    # Create figure:
-    fig, axes = plt.subplots(1, 2, figsize=(16, 7))
-    fig.suptitle('Variation of the padding (homog. magn. disc)', fontsize=20)
-    # Plot RMS against padding:
-    axes[0].axhline(y=0.18, linestyle='--', color='g', label='RMS [mrad] (real space)')
-    axes[0].plot(data_disc[0], data_disc[1], 'go-', label='RMS [mrad] (Fourier space)')
-    axes[0].set_xlabel('padding', fontsize=15)
-    axes[0].set_ylabel('RMS [mrad]', fontsize=15)
-    axes[0].set_xlim(-0.5, 16.5)
-    axes[0].set_ylim(-5, 45)
-    axes[0].xaxis.set_major_locator(MaxNLocator(nbins=10, integer=True))
-    axes[0].tick_params(axis='both', which='major', labelsize=14)
-    axes[0].legend()
-    # Plot zoom inset:
-    ins_axis_d = plt.axes([0.2, 0.35, 0.25, 0.4])
-    ins_axis_d.axhline(y=0.18, linestyle='--', color='g')
-    ins_axis_d.plot(data_disc[0], data_disc[1], 'go-')
-    ins_axis_d.set_yscale('log')
-    ins_axis_d.set_xlim(5.5, 16.5)
-    ins_axis_d.set_ylim(0.1, 1.1)
-    ins_axis_d.tick_params(axis='both', which='major', labelsize=14)
-    # Plot duration against padding:
-    axes[1].plot(data_disc[0], data_disc[2], 'bo-')
-    axes[1].set_xlabel('padding', fontsize=15)
-    axes[1].set_ylabel('duration [s]', fontsize=15)
-    axes[1].set_xlim(-0.5, 16.5)
-    axes[1].set_ylim(-0.05, 3)
-    axes[1].xaxis.set_major_locator(MaxNLocator(nbins=10, integer=True))
-    axes[1].yaxis.set_major_locator(MaxNLocator(nbins=10))
-    axes[1].tick_params(axis='both', which='major', labelsize=14)
-
-    plt.show()
-    plt.figtext(0.15, 0.13, 'a)', fontsize=30)
-    plt.figtext(0.57, 0.17, 'b)', fontsize=30)
-    plt.savefig(directory + '/ch5-2-disc_padding_variation.png', bbox_inches='tight')
-
-    print '--LOAD/CREATE PADDING SERIES OF VORTEX STATE DISC'
-    data_vort = np.zeros((3, len(padding_list)))
-    data_vort[0, :] = padding_list
-    for (i, padding) in enumerate(padding_list):
-        key = ', '.join(['Padding->RMS|duration', 'Fourier', 'padding={}'.format(padding_list[i]),
-                        'a={}'.format(a), 'dim={}'.format(dim), 'phi={}'.format(phi), 'vort'])
-        if key in data_shelve:
-            data_vort[:, i] = data_shelve[key]
-        else:
-            print '----calculate and save padding =', padding_list[i]
-            start_time = time.time()
-            phase_num_vort = pm.phase_mag_fourier(a, projection_vort, padding=padding_list[i])
-            data_vort[2, i] = time.time() - start_time
-            phase_diff = (phase_num_vort-phase_ana_vort)
-            phase_map_diff = PhaseMap(a, phase_diff, 'mrad')
-            phase_map_diff.display()
-            data_vort[1, i] = np.sqrt(np.mean(phase_map_diff.phase**2))*1E3  # *1E3: rad to mrad
-            data_shelve[key] = data_vort[:, i]
-
-    print '--PLOT/SAVE PADDING SERIES OF VORTEX STATE DISC'
-    # Create figure:
-    fig, axes = plt.subplots(1, 2, figsize=(16, 7))
-    fig.suptitle('Variation of the padding (Vortex state disc)', fontsize=20)
-    # Plot RMS against padding:
-    axes[0].axhline(y=0.22, linestyle='--', color='g', label='RMS [mrad] (real space)')
-    axes[0].plot(data_vort[0], data_vort[1], 'go-', label='RMS [mrad] (Fourier space)')
-    axes[0].set_xlabel('padding', fontsize=15)
-    axes[0].set_ylabel('RMS [mrad]', fontsize=15)
-    axes[0].set_xlim(-0.5, 16.5)
-    axes[0].set_ylim(-5, 45)
-    axes[0].tick_params(axis='both', which='major', labelsize=14)
-    axes[0].xaxis.set_major_locator(MaxNLocator(nbins=10, integer=True))
-    axes[0].legend()
-    # Plot zoom inset:
-    ins_axis_v = plt.axes([0.2, 0.35, 0.25, 0.4])
-    ins_axis_v.axhline(y=0.22, linestyle='--', color='g')
-    ins_axis_v.plot(data_vort[0], data_vort[1], 'go-')
-    ins_axis_v.set_yscale('log')
-    ins_axis_v.set_xlim(5.5, 16.5)
-    ins_axis_v.set_ylim(0.1, 1.1)
-    ins_axis_v.tick_params(axis='both', which='major', labelsize=14)
-    # Plot duration against padding:
-    axes[1].plot(data_vort[0], data_vort[2], 'bo-')
-    axes[1].set_xlabel('padding', fontsize=15)
-    axes[1].set_ylabel('duration [s]', fontsize=15)
-    axes[1].set_xlim(-0.5, 16.5)
-    axes[1].set_ylim(-0.05, 3)
-    axes[1].xaxis.set_major_locator(MaxNLocator(nbins=10, integer=True))
-    axes[1].yaxis.set_major_locator(MaxNLocator(nbins=10))
-    axes[1].tick_params(axis='both', which='major', labelsize=14)
-
-    plt.show()
-    plt.figtext(0.15, 0.13, 'c)', fontsize=30)
-    plt.figtext(0.57, 0.17, 'd)', fontsize=30)
-    plt.savefig(directory + '/ch5-2-vortex_padding_variation.png', bbox_inches='tight')
-
-    ###############################################################################################
-    print 'CLOSING SHELVE\n'
-    # Close shelve:
-    data_shelve.close()
-
-    ###############################################################################################
-
-
-if __name__ == "__main__":
-    try:
-        run()
-    except:
-        type, value, tb = sys.exc_info()
-        traceback.print_exc()
-        pdb.post_mortem(tb)
+        print '----calculate and save padding =', padding_list[i]
+        phasemapper = PMFourier(a, projector, padding=padding_list[i])
+        start_time = time.time()
+        phase_num_vort = phasemapper(mag_data_vort)
+        data_vort[2, i] = time.time() - start_time
+        phase_map_diff = phase_num_vort - phase_ana_vort
+        phase_map_diff -= np.mean(phase_map_diff.phase)
+        phase_map_diff.unit = 'mrad'
+        phase_map_diff.display_phase()
+        data_vort[1, i] = np.sqrt(np.mean(phase_map_diff.phase**2))*1E3  # *1E3: rad to mrad
+        data_shelve[key] = data_vort[:, i]
+
+print '--PLOT/SAVE PADDING SERIES OF VORTEX STATE DISC'
+# Create figure:
+fig, axes = plt.subplots(1, 2, figsize=(16, 7))
+fig.suptitle('Variation of the padding (Vortex state disc)', fontsize=20)
+# Plot RMS against padding:
+axes[0].axhline(y=0.22, linestyle='--', color='g', label='RMS [mrad] (real space)')
+axes[0].plot(data_vort[0], data_vort[1], 'go-', label='RMS [mrad] (Fourier space)')
+axes[0].set_xlabel('padding', fontsize=15)
+axes[0].set_ylabel('RMS [mrad]', fontsize=15)
+axes[0].set_xlim(-0.5, 16.5)
+axes[0].set_ylim(-5, 45)
+axes[0].tick_params(axis='both', which='major', labelsize=14)
+axes[0].xaxis.set_major_locator(MaxNLocator(nbins=10, integer=True))
+axes[0].legend()
+# Plot zoom inset:
+ins_axis_v = plt.axes([0.2, 0.35, 0.25, 0.4])
+ins_axis_v.axhline(y=0.22, linestyle='--', color='g')
+ins_axis_v.plot(data_vort[0], data_vort[1], 'go-')
+ins_axis_v.set_yscale('log')
+ins_axis_v.set_xlim(5.5, 16.5)
+ins_axis_v.set_ylim(0.1, 1.1)
+ins_axis_v.tick_params(axis='both', which='major', labelsize=14)
+# Plot duration against padding:
+axes[1].plot(data_vort[0], data_vort[2], 'bo-')
+axes[1].set_xlabel('padding', fontsize=15)
+axes[1].set_ylabel('duration [s]', fontsize=15)
+axes[1].set_xlim(-0.5, 16.5)
+axes[1].set_ylim(-0.05, 1.5)
+axes[1].xaxis.set_major_locator(MaxNLocator(nbins=10, integer=True))
+axes[1].yaxis.set_major_locator(MaxNLocator(nbins=10))
+axes[1].tick_params(axis='both', which='major', labelsize=14)
+
+plt.show()
+plt.figtext(0.15, 0.13, 'c)', fontsize=30)
+plt.figtext(0.57, 0.17, 'd)', fontsize=30)
+plt.savefig(directory + '/ch5-2-vortex_padding_variation.png', bbox_inches='tight')
+
+###############################################################################################
+print 'CLOSING SHELVE\n'
+# Close shelve:
+data_shelve.close()
diff --git a/scripts/paper 1/ch5-3-comparison_of_methods.py b/scripts/paper 1/ch5-3-comparison_of_methods.py
index 6d230f049699fe388d30d5c117f6512aa225f03e..c0c64b4c74136f4439ae31a2ae3a8bad2a51ec20 100644
--- a/scripts/paper 1/ch5-3-comparison_of_methods.py	
+++ b/scripts/paper 1/ch5-3-comparison_of_methods.py	
@@ -8,9 +8,6 @@ Created on Fri Jul 26 14:37:30 2013
 
 
 import time
-import pdb
-import traceback
-import sys
 import os
 
 import numpy as np
@@ -27,248 +24,235 @@ from pyramid.magdata import MagData
 import shelve
 
 
-def run():
+print '\nACCESS SHELVE'
+# Create / Open databank:
+directory = '../../output/paper 1'
+if not os.path.exists(directory):
+    os.makedirs(directory)
+data_shelve = shelve.open(directory + '/paper_1_shelve')
 
-    print '\nACCESS SHELVE'
-    # Create / Open databank:
-    directory = '../../output/paper 1'
-    if not os.path.exists(directory):
-        os.makedirs(directory)
-    data_shelve = shelve.open(directory + '/paper_1_shelve')
+###############################################################################################
+print 'CH5-3 METHOD COMPARISON'
 
-    ###############################################################################################
-    print 'CH5-3 METHOD COMPARISON'
+key = 'ch5-3-method_comparison'
+if key in data_shelve:
+    print '--LOAD METHOD DATA'
+    (data_disc_fourier0, data_vort_fourier0,
+     data_disc_fourier1, data_vort_fourier1,
+     data_disc_fourier10, data_vort_fourier10,
+     data_disc_real_s, data_vort_real_s,
+     data_disc_real_d, data_vort_real_d) = data_shelve[key]
+else:
+    # Input parameters:
+    steps = 6
+    a = 0.25  # in nm
+    phi = pi/2
+    dim = (64, 512, 512)  # in px (z, y, x)
+    center = (dim[0]/2-0.5, dim[1]/2.-0.5, dim[2]/2.-0.5)  # in px (z, y, x) index starts at 0!
+    radius = dim[1]/4  # in px
+    height = dim[0]/2  # in px
 
-    key = 'ch5-3-method_comparison'
-    if key in data_shelve:
-        print '--LOAD METHOD DATA'
-        (data_disc_fourier0, data_vort_fourier0,
-         data_disc_fourier1, data_vort_fourier1,
-         data_disc_fourier10, data_vort_fourier10,
-         data_disc_real_s, data_vort_real_s,
-         data_disc_real_d, data_vort_real_d) = data_shelve[key]
-    else:
-        # Input parameters:
-        steps = 6
-        a = 0.25  # in nm
-        phi = pi/2
-        dim = (64, 512, 512)  # in px (z, y, x)
-        center = (dim[0]/2-0.5, dim[1]/2.-0.5, dim[2]/2.-0.5)  # in px (z, y, x) index starts at 0!
-        radius = dim[1]/4  # in px
-        height = dim[0]/2  # in px
-
-        print '--CREATE MAGNETIC SHAPE'
-        mag_shape = mc.Shapes.disc(dim, center, radius, height)
-        # Create MagData (4 times the size):
-        print '--CREATE MAG. DIST. HOMOG. MAGN. DISC'
-        mag_data_disc = MagData(a, mc.create_mag_dist_homog(mag_shape, phi))
-        print '--CREATE MAG. DIST. VORTEX STATE DISC'
-        mag_data_vort = MagData(a, mc.create_mag_dist_vortex(mag_shape, center))
-
-        # Create Data Arrays:
-        a_list = [a*2**i for i in np.linspace(1, steps, steps)]
-        data_disc_fourier0 = np.vstack((a_list, np.zeros((2, steps))))
-        data_vort_fourier0 = np.vstack((a_list, np.zeros((2, steps))))
-        data_disc_fourier1 = np.vstack((a_list, np.zeros((2, steps))))
-        data_vort_fourier1 = np.vstack((a_list, np.zeros((2, steps))))
-        data_disc_fourier10 = np.vstack((a_list, np.zeros((2, steps))))
-        data_vort_fourier10 = np.vstack((a_list, np.zeros((2, steps))))
-        data_disc_real_s = np.vstack((a_list, np.zeros((2, steps))))
-        data_vort_real_s = np.vstack((a_list, np.zeros((2, steps))))
-        data_disc_real_d = np.vstack((a_list, np.zeros((2, steps))))
-        data_vort_real_d = np.vstack((a_list, np.zeros((2, steps))))
+    print '--CREATE MAGNETIC SHAPE'
+    mag_shape = mc.Shapes.disc(dim, center, radius, height)
+    # Create MagData (4 times the size):
+    print '--CREATE MAG. DIST. HOMOG. MAGN. DISC'
+    mag_data_disc = MagData(a, mc.create_mag_dist_homog(mag_shape, phi))
+    print '--CREATE MAG. DIST. VORTEX STATE DISC'
+    mag_data_vort = MagData(a, mc.create_mag_dist_vortex(mag_shape, center))
 
-        for i in range(steps):
-            # Scale mag_data, grid spacing and dimensions:
-            mag_data_disc.scale_down()
-            mag_data_vort.scale_down()
-            dim = mag_data_disc.dim
-            a = mag_data_disc.a
-            center = (dim[0]/2-0.5, dim[1]/2.-0.5, dim[2]/2.-0.5)  # in px, index starts at 0!
-            radius = dim[1]/4  # in px
-            height = dim[0]/2  # in px
+    # Create Data Arrays:
+    a_list = [a*2**i for i in np.linspace(1, steps, steps)]
+    data_disc_fourier0 = np.vstack((a_list, np.zeros((2, steps))))
+    data_vort_fourier0 = np.vstack((a_list, np.zeros((2, steps))))
+    data_disc_fourier1 = np.vstack((a_list, np.zeros((2, steps))))
+    data_vort_fourier1 = np.vstack((a_list, np.zeros((2, steps))))
+    data_disc_fourier10 = np.vstack((a_list, np.zeros((2, steps))))
+    data_vort_fourier10 = np.vstack((a_list, np.zeros((2, steps))))
+    data_disc_real_s = np.vstack((a_list, np.zeros((2, steps))))
+    data_vort_real_s = np.vstack((a_list, np.zeros((2, steps))))
+    data_disc_real_d = np.vstack((a_list, np.zeros((2, steps))))
+    data_vort_real_d = np.vstack((a_list, np.zeros((2, steps))))
 
-            print '--a =', a, 'nm', 'dim =', dim
-
-            print '----CALCULATE RMS/DURATION HOMOG. MAGN. DISC'
-            # Create projections along z-axis:
-            projection_disc = pj.simple_axis_projection(mag_data_disc)
-            # Analytic solution:
-            phase_ana_disc = an.phase_mag_disc(dim, a, phi, center, radius, height)
-            # Fourier unpadded:
-            padding = 0
-            start_time = time.clock()
-            phase_num_disc = pm.phase_mag_fourier(a, projection_disc, padding=padding)
-            data_disc_fourier0[2, i] = time.clock() - start_time
-            print '------time (disc, fourier0) =', data_disc_fourier0[2, i]
-            phase_diff_disc = (phase_ana_disc-phase_num_disc) * 1E3  # in mrad -> *1000
-            data_disc_fourier0[1, i] = np.sqrt(np.mean(phase_diff_disc**2))
-            # Fourier padding 1:
-            padding = 1
-            start_time = time.clock()
-            phase_num_disc = pm.phase_mag_fourier(a, projection_disc, padding=padding)
-            data_disc_fourier1[2, i] = time.clock() - start_time
-            print '------time (disc, fourier1) =', data_disc_fourier1[2, i]
-            phase_diff_disc = (phase_ana_disc-phase_num_disc) * 1E3  # in mrad -> *1000
-            data_disc_fourier1[1, i] = np.sqrt(np.mean(phase_diff_disc**2))
-            # Fourier padding 10:
-            padding = 10
-            start_time = time.clock()
-            phase_num_disc = pm.phase_mag_fourier(a, projection_disc, padding=padding)
-            data_disc_fourier10[2, i] = time.clock() - start_time
-            print '------time (disc, fourier10) =', data_disc_fourier10[2, i]
-            phase_diff_disc = (phase_ana_disc-phase_num_disc) * 1E3  # in mrad -> *1000
-            data_disc_fourier10[1, i] = np.sqrt(np.mean(phase_diff_disc**2))
-            # Real space slab:
-            start_time = time.clock()
-            phase_num_disc = pm.phase_mag_real(a, projection_disc, geometry='slab')
-            data_disc_real_s[2, i] = time.clock() - start_time
-            print '------time (disc, real slab) =', data_disc_real_s[2, i]
-            phase_diff_disc = (phase_ana_disc-phase_num_disc) * 1E3  # in mrad -> *1000
-            data_disc_real_s[1, i] = np.sqrt(np.mean(phase_diff_disc**2))
-            # Real space disc:
-            start_time = time.clock()
-            phase_num_disc = pm.phase_mag_real(a, projection_disc, geometry='disc')
-            data_disc_real_d[2, i] = time.clock() - start_time
-            print '------time (disc, real disc) =', data_disc_real_d[2, i]
-            phase_diff_disc = (phase_ana_disc-phase_num_disc) * 1E3  # in mrad -> *1000
-            data_disc_real_d[1, i] = np.sqrt(np.mean(phase_diff_disc**2))
-
-            print '----CALCULATE RMS/DURATION VORTEX STATE DISC'
-            # Create projections along z-axis:
-            projection_vort = pj.simple_axis_projection(mag_data_vort)
-            # Analytic solution:
-            phase_ana_vort = an.phase_mag_vortex(dim, a, center, radius, height)
-            # Fourier unpadded:
-            padding = 0
-            start_time = time.clock()
-            phase_num_vort = pm.phase_mag_fourier(a, projection_vort, padding=padding)
-            data_vort_fourier0[2, i] = time.clock() - start_time
-            print '------time (vortex, fourier0) =', data_vort_fourier0[2, i]
-            phase_diff_vort = (phase_ana_vort-phase_num_vort) * 1E3  # in mrad -> *1000
-            data_vort_fourier0[1, i] = np.sqrt(np.mean(phase_diff_vort**2))
-            # Fourier padding 1:
-            padding = 1
-            start_time = time.clock()
-            phase_num_vort = pm.phase_mag_fourier(a, projection_vort, padding=padding)
-            data_vort_fourier1[2, i] = time.clock() - start_time
-            print '------time (vortex, fourier1) =', data_vort_fourier1[2, i]
-            phase_diff_vort = (phase_ana_vort-phase_num_vort) * 1E3  # in mrad -> *1000
-            data_vort_fourier1[1, i] = np.sqrt(np.mean(phase_diff_vort**2))
-            # Fourier padding 10:
-            padding = 10
-            start_time = time.clock()
-            phase_num_vort = pm.phase_mag_fourier(a, projection_vort, padding=padding)
-            data_vort_fourier10[2, i] = time.clock() - start_time
-            print '------time (vortex, fourier10) =', data_vort_fourier10[2, i]
-            phase_diff_vort = (phase_ana_vort-phase_num_vort) * 1E3  # in mrad -> *1000
-            data_vort_fourier10[1, i] = np.sqrt(np.mean(phase_diff_vort**2))
-            # Real space slab:
-            start_time = time.clock()
-            phase_num_vort = pm.phase_mag_real(a, projection_vort, geometry='slab')
-            data_vort_real_s[2, i] = time.clock() - start_time
-            print '------time (vortex, real slab) =', data_vort_real_s[2, i]
-            phase_diff_vort = (phase_ana_vort-phase_num_vort) * 1E3  # in mrad -> *1000
-            data_vort_real_s[1, i] = np.sqrt(np.mean(phase_diff_vort**2))
-            # Real space disc:
-            start_time = time.clock()
-            phase_num_vort = pm.phase_mag_real(a, projection_vort, geometry='disc')
-            data_vort_real_d[2, i] = time.clock() - start_time
-            print '------time (vortex, real disc) =', data_vort_real_d[2, i]
-            phase_diff_vort = (phase_ana_vort-phase_num_vort) * 1E3  # in mrad -> *1000
-            data_vort_real_d[1, i] = np.sqrt(np.mean(phase_diff_vort**2))
+    for i in range(steps):
+        # Scale mag_data, grid spacing and dimensions:
+        mag_data_disc.scale_down()
+        mag_data_vort.scale_down()
+        dim = mag_data_disc.dim
+        a = mag_data_disc.a
+        center = (dim[0]/2-0.5, dim[1]/2.-0.5, dim[2]/2.-0.5)  # in px, index starts at 0!
+        radius = dim[1]/4  # in px
+        height = dim[0]/2  # in px
 
-        print '--SHELVE METHOD DATA'
-        data_shelve[key] = (data_disc_fourier0, data_vort_fourier0,
-                            data_disc_fourier1, data_vort_fourier1,
-                            data_disc_fourier10, data_vort_fourier10,
-                            data_disc_real_s, data_vort_real_s,
-                            data_disc_real_d, data_vort_real_d)
+        print '--a =', a, 'nm', 'dim =', dim
 
-    print '--PLOT/SAVE METHOD DATA'
+        print '----CALCULATE RMS/DURATION HOMOG. MAGN. DISC'
+        # Create projections along z-axis:
+        projection_disc = pj.simple_axis_projection(mag_data_disc)
+        # Analytic solution:
+        phase_ana_disc = an.phase_mag_disc(dim, a, phi, center, radius, height)
+        # Fourier unpadded:
+        padding = 0
+        start_time = time.clock()
+        phase_num_disc = pm.phase_mag_fourier(a, projection_disc, padding=padding)
+        data_disc_fourier0[2, i] = time.clock() - start_time
+        print '------time (disc, fourier0) =', data_disc_fourier0[2, i]
+        phase_diff_disc = (phase_ana_disc-phase_num_disc) * 1E3  # in mrad -> *1000
+        data_disc_fourier0[1, i] = np.sqrt(np.mean(phase_diff_disc**2))
+        # Fourier padding 1:
+        padding = 1
+        start_time = time.clock()
+        phase_num_disc = pm.phase_mag_fourier(a, projection_disc, padding=padding)
+        data_disc_fourier1[2, i] = time.clock() - start_time
+        print '------time (disc, fourier1) =', data_disc_fourier1[2, i]
+        phase_diff_disc = (phase_ana_disc-phase_num_disc) * 1E3  # in mrad -> *1000
+        data_disc_fourier1[1, i] = np.sqrt(np.mean(phase_diff_disc**2))
+        # Fourier padding 10:
+        padding = 10
+        start_time = time.clock()
+        phase_num_disc = pm.phase_mag_fourier(a, projection_disc, padding=padding)
+        data_disc_fourier10[2, i] = time.clock() - start_time
+        print '------time (disc, fourier10) =', data_disc_fourier10[2, i]
+        phase_diff_disc = (phase_ana_disc-phase_num_disc) * 1E3  # in mrad -> *1000
+        data_disc_fourier10[1, i] = np.sqrt(np.mean(phase_diff_disc**2))
+        # Real space slab:
+        start_time = time.clock()
+        phase_num_disc = pm.phase_mag_real(a, projection_disc, geometry='slab')
+        data_disc_real_s[2, i] = time.clock() - start_time
+        print '------time (disc, real slab) =', data_disc_real_s[2, i]
+        phase_diff_disc = (phase_ana_disc-phase_num_disc) * 1E3  # in mrad -> *1000
+        data_disc_real_s[1, i] = np.sqrt(np.mean(phase_diff_disc**2))
+        # Real space disc:
+        start_time = time.clock()
+        phase_num_disc = pm.phase_mag_real(a, projection_disc, geometry='disc')
+        data_disc_real_d[2, i] = time.clock() - start_time
+        print '------time (disc, real disc) =', data_disc_real_d[2, i]
+        phase_diff_disc = (phase_ana_disc-phase_num_disc) * 1E3  # in mrad -> *1000
+        data_disc_real_d[1, i] = np.sqrt(np.mean(phase_diff_disc**2))
 
-    # Plot using shared rows and colums:
-    fig, axes = plt.subplots(2, 2, sharex='col', sharey='row', figsize=(12, 8))
-    fig.tight_layout(rect=(0.05, 0.05, 0.95, 0.95))
-    fig.suptitle('Method Comparison', fontsize=20)
+        print '----CALCULATE RMS/DURATION VORTEX STATE DISC'
+        # Create projections along z-axis:
+        projection_vort = pj.simple_axis_projection(mag_data_vort)
+        # Analytic solution:
+        phase_ana_vort = an.phase_mag_vortex(dim, a, center, radius, height)
+        # Fourier unpadded:
+        padding = 0
+        start_time = time.clock()
+        phase_num_vort = pm.phase_mag_fourier(a, projection_vort, padding=padding)
+        data_vort_fourier0[2, i] = time.clock() - start_time
+        print '------time (vortex, fourier0) =', data_vort_fourier0[2, i]
+        phase_diff_vort = (phase_ana_vort-phase_num_vort) * 1E3  # in mrad -> *1000
+        data_vort_fourier0[1, i] = np.sqrt(np.mean(phase_diff_vort**2))
+        # Fourier padding 1:
+        padding = 1
+        start_time = time.clock()
+        phase_num_vort = pm.phase_mag_fourier(a, projection_vort, padding=padding)
+        data_vort_fourier1[2, i] = time.clock() - start_time
+        print '------time (vortex, fourier1) =', data_vort_fourier1[2, i]
+        phase_diff_vort = (phase_ana_vort-phase_num_vort) * 1E3  # in mrad -> *1000
+        data_vort_fourier1[1, i] = np.sqrt(np.mean(phase_diff_vort**2))
+        # Fourier padding 10:
+        padding = 10
+        start_time = time.clock()
+        phase_num_vort = pm.phase_mag_fourier(a, projection_vort, padding=padding)
+        data_vort_fourier10[2, i] = time.clock() - start_time
+        print '------time (vortex, fourier10) =', data_vort_fourier10[2, i]
+        phase_diff_vort = (phase_ana_vort-phase_num_vort) * 1E3  # in mrad -> *1000
+        data_vort_fourier10[1, i] = np.sqrt(np.mean(phase_diff_vort**2))
+        # Real space slab:
+        start_time = time.clock()
+        phase_num_vort = pm.phase_mag_real(a, projection_vort, geometry='slab')
+        data_vort_real_s[2, i] = time.clock() - start_time
+        print '------time (vortex, real slab) =', data_vort_real_s[2, i]
+        phase_diff_vort = (phase_ana_vort-phase_num_vort) * 1E3  # in mrad -> *1000
+        data_vort_real_s[1, i] = np.sqrt(np.mean(phase_diff_vort**2))
+        # Real space disc:
+        start_time = time.clock()
+        phase_num_vort = pm.phase_mag_real(a, projection_vort, geometry='disc')
+        data_vort_real_d[2, i] = time.clock() - start_time
+        print '------time (vortex, real disc) =', data_vort_real_d[2, i]
+        phase_diff_vort = (phase_ana_vort-phase_num_vort) * 1E3  # in mrad -> *1000
+        data_vort_real_d[1, i] = np.sqrt(np.mean(phase_diff_vort**2))
 
-    # Plot duration against a (disc) [top/left]:
-    axes[1, 0].set_yscale('log')
-    axes[1, 0].plot(data_disc_fourier0[0], data_disc_fourier0[1], ':bs')
-    axes[1, 0].plot(data_disc_fourier1[0], data_disc_fourier1[1], ':bo')
-    axes[1, 0].plot(data_disc_fourier10[0], data_disc_fourier10[1], ':b^')
-    axes[1, 0].plot(data_disc_real_s[0], data_disc_real_s[1], '--rs')
-    axes[1, 0].plot(data_disc_real_d[0], data_disc_real_d[1], '--ro')
-    axes[1, 0].set_xlabel('a [nm]', fontsize=15)
-    axes[1, 0].set_ylabel('RMS [mrad]', fontsize=15)
-    axes[1, 0].set_xlim(-0.5, 16.5)
-    axes[1, 0].tick_params(axis='both', which='major', labelsize=14)
-    axes[1, 0].xaxis.set_major_locator(IndexLocator(base=4, offset=-0.5))
+    print '--SHELVE METHOD DATA'
+    data_shelve[key] = (data_disc_fourier0, data_vort_fourier0,
+                        data_disc_fourier1, data_vort_fourier1,
+                        data_disc_fourier10, data_vort_fourier10,
+                        data_disc_real_s, data_vort_real_s,
+                        data_disc_real_d, data_vort_real_d)
 
-    # Plot RMS against a (disc) [bottom/left]:
-    plt.tick_params(axis='both', which='major', labelsize=14)
-    axes[0, 0].set_yscale('log')
-    axes[0, 0].plot(data_disc_fourier0[0], data_disc_fourier0[2], ':bs')
-    axes[0, 0].plot(data_disc_fourier1[0], data_disc_fourier1[2], ':bo')
-    axes[0, 0].plot(data_disc_fourier10[0], data_disc_fourier10[2], ':b^')
-    axes[0, 0].plot(data_disc_real_s[0], data_disc_real_s[2], '--rs')
-    axes[0, 0].plot(data_disc_real_d[0], data_disc_real_d[2], '--ro')
-    axes[0, 0].set_title('Homog. magn. disc', fontsize=18)
-    axes[0, 0].set_ylabel('duration [s]', fontsize=15)
-    axes[0, 0].set_xlim(-0.5, 16.5)
-    axes[0, 0].tick_params(axis='both', which='major', labelsize=14)
-    axes[0, 0].xaxis.set_major_locator(IndexLocator(base=4, offset=-0.5))
+print '--PLOT/SAVE METHOD DATA'
 
-    # Plot duration against a (vortex) [top/right]:
-    axes[1, 1].set_yscale('log')
-    axes[1, 1].plot(data_vort_fourier0[0], data_vort_fourier0[1], ':bs')
-    axes[1, 1].plot(data_vort_fourier1[0], data_vort_fourier1[1], ':bo')
-    axes[1, 1].plot(data_vort_fourier10[0], data_vort_fourier10[1], ':b^')
-    axes[1, 1].plot(data_vort_real_s[0], data_vort_real_s[1], '--rs')
-    axes[1, 1].plot(data_vort_real_d[0], data_vort_real_d[1], '--ro')
-    axes[1, 1].set_xlabel('a [nm]', fontsize=15)
-    axes[1, 1].set_xlim(-0.5, 16.5)
-    axes[1, 1].tick_params(axis='both', which='major', labelsize=14)
-    axes[1, 1].xaxis.set_major_locator(IndexLocator(base=4, offset=-0.5))
+# Plot using shared rows and colums:
+fig, axes = plt.subplots(2, 2, sharex='col', sharey='row', figsize=(12, 8))
+fig.tight_layout(rect=(0.05, 0.05, 0.95, 0.95))
+fig.suptitle('Method Comparison', fontsize=20)
 
-    # Plot RMS against a (vortex) [bottom/right]:
-    axes[0, 1].set_yscale('log')
-    axes[0, 1].plot(data_vort_fourier0[0], data_vort_fourier0[2], ':bs',
-                    label='Fourier padding=0')
-    axes[0, 1].plot(data_vort_fourier1[0], data_vort_fourier1[2], ':bo',
-                    label='Fourier padding=1')
-    axes[0, 1].plot(data_vort_fourier10[0], data_vort_fourier10[2], ':b^',
-                    label='Fourier padding=10')
-    axes[0, 1].plot(data_vort_real_s[0], data_vort_real_s[2], '--rs',
-                    label='Real space (slab)')
-    axes[0, 1].plot(data_vort_real_d[0], data_vort_real_d[2], '--ro',
-                    label='Real space (disc)')
-    axes[0, 1].set_title('Vortex state disc', fontsize=18)
-    axes[0, 1].set_xlim(-0.5, 16.5)
-    axes[0, 1].tick_params(axis='both', which='major', labelsize=14)
-    axes[0, 1].xaxis.set_major_locator(IndexLocator(base=4, offset=-0.5))
-    axes[0, 1].legend(loc=1)
+# Plot duration against a (disc) [top/left]:
+axes[1, 0].set_yscale('log')
+axes[1, 0].plot(data_disc_fourier0[0], data_disc_fourier0[1], ':bs')
+axes[1, 0].plot(data_disc_fourier1[0], data_disc_fourier1[1], ':bo')
+axes[1, 0].plot(data_disc_fourier10[0], data_disc_fourier10[1], ':b^')
+axes[1, 0].plot(data_disc_real_s[0], data_disc_real_s[1], '--rs')
+axes[1, 0].plot(data_disc_real_d[0], data_disc_real_d[1], '--ro')
+axes[1, 0].set_xlabel('a [nm]', fontsize=15)
+axes[1, 0].set_ylabel('RMS [mrad]', fontsize=15)
+axes[1, 0].set_xlim(-0.5, 16.5)
+axes[1, 0].tick_params(axis='both', which='major', labelsize=14)
+axes[1, 0].xaxis.set_major_locator(IndexLocator(base=4, offset=-0.5))
 
-    # Save figure as .png:
-    plt.show()
-    plt.figtext(0.45, 0.85, 'a)', fontsize=30)
-    plt.figtext(0.57, 0.85, 'b)', fontsize=30)
-    plt.figtext(0.45, 0.15, 'c)', fontsize=30)
-    plt.figtext(0.57, 0.15, 'd)', fontsize=30)
-    plt.savefig(directory + '/ch5-3-method comparison.png', bbox_inches='tight')
+# Plot RMS against a (disc) [bottom/left]:
+plt.tick_params(axis='both', which='major', labelsize=14)
+axes[0, 0].set_yscale('log')
+axes[0, 0].plot(data_disc_fourier0[0], data_disc_fourier0[2], ':bs')
+axes[0, 0].plot(data_disc_fourier1[0], data_disc_fourier1[2], ':bo')
+axes[0, 0].plot(data_disc_fourier10[0], data_disc_fourier10[2], ':b^')
+axes[0, 0].plot(data_disc_real_s[0], data_disc_real_s[2], '--rs')
+axes[0, 0].plot(data_disc_real_d[0], data_disc_real_d[2], '--ro')
+axes[0, 0].set_title('Homog. magn. disc', fontsize=18)
+axes[0, 0].set_ylabel('duration [s]', fontsize=15)
+axes[0, 0].set_xlim(-0.5, 16.5)
+axes[0, 0].tick_params(axis='both', which='major', labelsize=14)
+axes[0, 0].xaxis.set_major_locator(IndexLocator(base=4, offset=-0.5))
 
-    ###############################################################################################
-    print 'CLOSING SHELVE\n'
-    # Close shelve:
-    data_shelve.close()
+# Plot duration against a (vortex) [top/right]:
+axes[1, 1].set_yscale('log')
+axes[1, 1].plot(data_vort_fourier0[0], data_vort_fourier0[1], ':bs')
+axes[1, 1].plot(data_vort_fourier1[0], data_vort_fourier1[1], ':bo')
+axes[1, 1].plot(data_vort_fourier10[0], data_vort_fourier10[1], ':b^')
+axes[1, 1].plot(data_vort_real_s[0], data_vort_real_s[1], '--rs')
+axes[1, 1].plot(data_vort_real_d[0], data_vort_real_d[1], '--ro')
+axes[1, 1].set_xlabel('a [nm]', fontsize=15)
+axes[1, 1].set_xlim(-0.5, 16.5)
+axes[1, 1].tick_params(axis='both', which='major', labelsize=14)
+axes[1, 1].xaxis.set_major_locator(IndexLocator(base=4, offset=-0.5))
 
-    ###############################################################################################
+# Plot RMS against a (vortex) [bottom/right]:
+axes[0, 1].set_yscale('log')
+axes[0, 1].plot(data_vort_fourier0[0], data_vort_fourier0[2], ':bs',
+                label='Fourier padding=0')
+axes[0, 1].plot(data_vort_fourier1[0], data_vort_fourier1[2], ':bo',
+                label='Fourier padding=1')
+axes[0, 1].plot(data_vort_fourier10[0], data_vort_fourier10[2], ':b^',
+                label='Fourier padding=10')
+axes[0, 1].plot(data_vort_real_s[0], data_vort_real_s[2], '--rs',
+                label='Real space (slab)')
+axes[0, 1].plot(data_vort_real_d[0], data_vort_real_d[2], '--ro',
+                label='Real space (disc)')
+axes[0, 1].set_title('Vortex state disc', fontsize=18)
+axes[0, 1].set_xlim(-0.5, 16.5)
+axes[0, 1].tick_params(axis='both', which='major', labelsize=14)
+axes[0, 1].xaxis.set_major_locator(IndexLocator(base=4, offset=-0.5))
+axes[0, 1].legend(loc=1)
 
+# Save figure as .png:
+plt.show()
+plt.figtext(0.45, 0.85, 'a)', fontsize=30)
+plt.figtext(0.57, 0.85, 'b)', fontsize=30)
+plt.figtext(0.45, 0.15, 'c)', fontsize=30)
+plt.figtext(0.57, 0.15, 'd)', fontsize=30)
+plt.savefig(directory + '/ch5-3-method comparison.png', bbox_inches='tight')
 
-if __name__ == "__main__":
-    try:
-        run()
-    except:
-        type, value, tb = sys.exc_info()
-        traceback.print_exc()
-        pdb.post_mortem(tb)
+###############################################################################################
+print 'CLOSING SHELVE\n'
+# Close shelve:
+data_shelve.close()
diff --git a/scripts/paper 1/ch5-4-comparison_of_methods_new.py b/scripts/paper 1/ch5-4-comparison_of_methods_new.py
index 6be62fcf7f172aaf5c53b626f1bdc66ec6a69775..735db864308c704bf4fc85b4470e68c493ce2a74 100644
--- a/scripts/paper 1/ch5-4-comparison_of_methods_new.py	
+++ b/scripts/paper 1/ch5-4-comparison_of_methods_new.py	
@@ -8,9 +8,6 @@ Created on Fri Jul 26 14:37:30 2013
 
 
 import time
-import pdb
-import traceback
-import sys
 import os
 
 import numpy as np
@@ -20,284 +17,272 @@ import matplotlib.pyplot as plt
 from matplotlib.ticker import NullLocator, LogLocator, LogFormatter
 
 import pyramid.magcreator as mc
-import pyramid.projector as pj
-import pyramid.phasemapper as pm
 import pyramid.analytic as an
 from pyramid.magdata import MagData
-from pyramid.kernel import Kernel
+from pyramid.projector import SimpleProjector
+from pyramid.phasemapper import PMConvolve, PMFourier
+
 import shelve
 
 
-def run():
+force_calculation = False
 
-    print '\nACCESS SHELVE'
-    # Create / Open databank:
-    directory = '../../output/paper 1'
-    if not os.path.exists(directory):
-        os.makedirs(directory)
-    data_shelve = shelve.open(directory + '/paper_1_shelve')
 
-    ###############################################################################################
-    print 'CH5-4 METHOD COMPARISON'
+print '\nACCESS SHELVE'
+# Create / Open databank:
+directory = '../../output/paper 1'
+if not os.path.exists(directory):
+    os.makedirs(directory)
+data_shelve = shelve.open(directory + '/paper_1_shelve')
 
-    key = 'ch5-4-method_comparison_new'
-    if key in data_shelve:
-        print '--LOAD METHOD DATA'
-        (data_disc_fourier0, data_vort_fourier0,
-         data_disc_fourier3, data_vort_fourier3,
-         data_disc_fourier10, data_vort_fourier10,
-         data_disc_real_s, data_vort_real_s,
-         data_disc_real_d, data_vort_real_d) = data_shelve[key]
-    else:
-        # Input parameters:
-        steps = 5
-        a = 0.25  # in nm
-        phi = pi/2
-        dim = (64, 512, 512)  # in px (z, y, x)
-        center = (dim[0]/2-0.5, dim[1]/2.-0.5, dim[2]/2.-0.5)  # in px (z, y, x) index starts at 0!
-        radius = dim[1]/4  # in px
-        height = dim[0]/2  # in px
+###############################################################################################
+print 'CH5-4 METHOD COMPARISON'
 
-        print '--CREATE MAGNETIC SHAPE'
-        mag_shape = mc.Shapes.disc(dim, center, radius, height)
-        # Create MagData (4 times the size):
-        print '--CREATE MAG. DIST. HOMOG. MAGN. DISC'
-        mag_data_disc = MagData(a, mc.create_mag_dist_homog(mag_shape, phi))
-        print '--CREATE MAG. DIST. VORTEX STATE DISC'
-        mag_data_vort = MagData(a, mc.create_mag_dist_vortex(mag_shape, center))
+key = 'ch5-4-method_comparison_new'
+if key in data_shelve and not force_calculation:
+    print '--LOAD METHOD DATA'
+    (data_disc_fourier0, data_vort_fourier0,
+     data_disc_fourier3, data_vort_fourier3,
+     data_disc_fourier10, data_vort_fourier10,
+     data_disc_real_s, data_vort_real_s,
+     data_disc_real_d, data_vort_real_d) = data_shelve[key]
+else:
+    # Input parameters:
+    steps = 4
+    a = 0.5  # in nm
+    phi = pi/2
+    dim = (32, 256, 256)  # in px (z, y, x)
+    center = (dim[0]/2-0.5, dim[1]/2.-0.5, dim[2]/2.-0.5)  # in px (z, y, x) index starts at 0!
+    radius = dim[1]/4  # in px
+    height = dim[0]/2  # in px
 
-        # Create Data Arrays:
-        dim_list = [dim[2]/2**i for i in np.linspace(1, steps, steps)]
-        data_disc_fourier0 = np.vstack((dim_list, np.zeros((2, steps))))
-        data_vort_fourier0 = np.vstack((dim_list, np.zeros((2, steps))))
-        data_disc_fourier3 = np.vstack((dim_list, np.zeros((2, steps))))
-        data_vort_fourier3 = np.vstack((dim_list, np.zeros((2, steps))))
-        data_disc_fourier10 = np.vstack((dim_list, np.zeros((2, steps))))
-        data_vort_fourier10 = np.vstack((dim_list, np.zeros((2, steps))))
-        data_disc_real_s = np.vstack((dim_list, np.zeros((2, steps))))
-        data_vort_real_s = np.vstack((dim_list, np.zeros((2, steps))))
-        data_disc_real_d = np.vstack((dim_list, np.zeros((2, steps))))
-        data_vort_real_d = np.vstack((dim_list, np.zeros((2, steps))))
+    print '--CREATE MAGNETIC SHAPE'
+    mag_shape = mc.Shapes.disc(dim, center, radius, height)
+    # Create MagData (4 times the size):
+    print '--CREATE MAG. DIST. HOMOG. MAGN. DISC'
+    mag_data_disc = MagData(a, mc.create_mag_dist_homog(mag_shape, phi))
+    print '--CREATE MAG. DIST. VORTEX STATE DISC'
+    mag_data_vort = MagData(a, mc.create_mag_dist_vortex(mag_shape, center))
 
-        for i in range(steps):
-            # Scale mag_data, grid spacing and dimensions:
-            mag_data_disc.scale_down()
-            mag_data_vort.scale_down()
-            dim = mag_data_disc.dim
-            a = mag_data_disc.a
-            center = (dim[0]/2-0.5, dim[1]/2.-0.5, dim[2]/2.-0.5)  # in px, index starts at 0!
-            radius = dim[1]/4  # in px
-            height = dim[0]/2  # in px
+    # Create Data Arrays:
+    dim_list = [dim[2]/2**i for i in range(steps)]
+    data_disc_fourier0 = np.vstack((dim_list, np.zeros((2, steps))))
+    data_vort_fourier0 = np.vstack((dim_list, np.zeros((2, steps))))
+    data_disc_fourier3 = np.vstack((dim_list, np.zeros((2, steps))))
+    data_vort_fourier3 = np.vstack((dim_list, np.zeros((2, steps))))
+    data_disc_fourier10 = np.vstack((dim_list, np.zeros((2, steps))))
+    data_vort_fourier10 = np.vstack((dim_list, np.zeros((2, steps))))
+    data_disc_real_s = np.vstack((dim_list, np.zeros((2, steps))))
+    data_vort_real_s = np.vstack((dim_list, np.zeros((2, steps))))
+    data_disc_real_d = np.vstack((dim_list, np.zeros((2, steps))))
+    data_vort_real_d = np.vstack((dim_list, np.zeros((2, steps))))
 
-            print '--a =', a, 'nm', 'dim =', dim
+    for i in range(steps):
+        # Scale mag_data, grid spacing and dimensions:
+        dim = mag_data_disc.dim
+        a = mag_data_disc.a
+        center = (dim[0]/2-0.5, dim[1]/2.-0.5, dim[2]/2.-0.5)  # in px, index starts at 0!
+        radius = dim[1]/4  # in px
+        height = dim[0]/2  # in px
 
-            print '----CALCULATE RMS/DURATION HOMOG. MAGN. DISC'
-            # Create projections along z-axis:
-            projection_disc = pj.simple_axis_projection(mag_data_disc)
-            # Analytic solution:
-            phase_ana_disc = an.phase_mag_disc(dim, a, phi, center, radius, height)
-            # Fourier unpadded:
-            padding = 0
-            start_time = time.clock()
-            phase_num_disc = pm.phase_mag_fourier(a, projection_disc, padding=padding)
-            data_disc_fourier0[2, i] = time.clock() - start_time
-            print '------time (disc, fourier0) =', data_disc_fourier0[2, i]
-            phase_diff_disc = (phase_ana_disc-phase_num_disc) * 1E3  # in mrad -> *1000
-            data_disc_fourier0[1, i] = np.sqrt(np.mean(phase_diff_disc**2))
-            # Fourier padding 3:
-            padding = 3
-            start_time = time.clock()
-            phase_num_disc = pm.phase_mag_fourier(a, projection_disc, padding=padding)
-            data_disc_fourier3[2, i] = time.clock() - start_time
-            print '------time (disc, fourier3) =', data_disc_fourier3[2, i]
-            phase_diff_disc = (phase_ana_disc-phase_num_disc) * 1E3  # in mrad -> *1000
-            data_disc_fourier3[1, i] = np.sqrt(np.mean(phase_diff_disc**2))
-            # Fourier padding 10:
-            padding = 10
-            start_time = time.clock()
-            phase_num_disc = pm.phase_mag_fourier(a, projection_disc, padding=padding)
-            data_disc_fourier10[2, i] = time.clock() - start_time
-            print '------time (disc, fourier10) =', data_disc_fourier10[2, i]
-            phase_diff_disc = (phase_ana_disc-phase_num_disc) * 1E3  # in mrad -> *1000
-            data_disc_fourier10[1, i] = np.sqrt(np.mean(phase_diff_disc**2))
-            # Real space slab:
-            kernel = Kernel((dim[1], dim[2]), a, geometry='slab')
-            start_time = time.clock()
-            phase_num_disc = pm.phase_mag(a, projection_disc, kernel=kernel)
-            data_disc_real_s[2, i] = time.clock() - start_time
-            print '------time (disc, real slab) =', data_disc_real_s[2, i]
-            phase_diff_disc = (phase_ana_disc-phase_num_disc) * 1E3  # in mrad -> *1000
-            data_disc_real_s[1, i] = np.sqrt(np.mean(phase_diff_disc**2))
-            # Real space disc:
-            kernel = Kernel((dim[1], dim[2]), a, geometry='slab')
-            start_time = time.clock()
-            phase_num_disc = pm.phase_mag(a, projection_disc, kernel=kernel)
-            data_disc_real_d[2, i] = time.clock() - start_time
-            print '------time (disc, real disc) =', data_disc_real_d[2, i]
-            phase_diff_disc = (phase_ana_disc-phase_num_disc) * 1E3  # in mrad -> *1000
-            data_disc_real_d[1, i] = np.sqrt(np.mean(phase_diff_disc**2))
+        print '--a =', a, 'nm', 'dim =', dim
+        
+        # Create projector along z-axis and phasemapper:
+        projector = SimpleProjector(dim)
+        pm_fourier0 = PMFourier(a, projector, padding=0)
+        pm_fourier3 = PMFourier(a, projector, padding=3)
+        pm_fourier10 = PMFourier(a, projector, padding=10)
+        pm_slab = PMConvolve(a, projector, geometry='slab')
+        pm_disc = PMConvolve(a, projector, geometry='disc')
 
-            print '----CALCULATE RMS/DURATION HOMOG. MAGN. DISC'
-            # Create projections along z-axis:
-            projection_vort = pj.simple_axis_projection(mag_data_vort)
-            # Analytic solution:
-            phase_ana_vort = an.phase_mag_vortex(dim, a, center, radius, height)
-            # Fourier unpadded:
-            padding = 0
-            start_time = time.clock()
-            phase_num_vort = pm.phase_mag_fourier(a, projection_vort, padding=padding)
-            data_vort_fourier0[2, i] = time.clock() - start_time
-            print '------time (vortex, fourier0) =', data_vort_fourier0[2, i]
-            phase_diff_vort = (phase_ana_vort-phase_num_vort) * 1E3  # in mrad -> *1000
-            data_vort_fourier0[1, i] = np.sqrt(np.mean(phase_diff_vort**2))
-            # Fourier padding 3:
-            padding = 3
-            start_time = time.clock()
-            phase_num_vort = pm.phase_mag_fourier(a, projection_vort, padding=padding)
-            data_vort_fourier3[2, i] = time.clock() - start_time
-            print '------time (vortex, fourier3) =', data_vort_fourier3[2, i]
-            phase_diff_vort = (phase_ana_vort-phase_num_vort) * 1E3  # in mrad -> *1000
-            data_vort_fourier3[1, i] = np.sqrt(np.mean(phase_diff_vort**2))
-            # Fourier padding 10:
-            padding = 10
-            start_time = time.clock()
-            phase_num_vort = pm.phase_mag_fourier(a, projection_vort, padding=padding)
-            data_vort_fourier10[2, i] = time.clock() - start_time
-            print '------time (vortex, fourier10) =', data_vort_fourier10[2, i]
-            phase_diff_vort = (phase_ana_vort-phase_num_vort) * 1E3  # in mrad -> *1000
-            data_vort_fourier10[1, i] = np.sqrt(np.mean(phase_diff_vort**2))
-            # Real space slab:
-            kernel = Kernel((dim[1], dim[2]), a, geometry='slab')
-            start_time = time.clock()
-            phase_num_vort = pm.phase_mag(a, projection_vort, kernel=kernel)
-            data_vort_real_s[2, i] = time.clock() - start_time
-            print '------time (vortex, real slab) =', data_vort_real_s[2, i]
-            phase_diff_vort = (phase_ana_vort-phase_num_vort) * 1E3  # in mrad -> *1000
-            data_vort_real_s[1, i] = np.sqrt(np.mean(phase_diff_vort**2))
-            # Real space disc:
-            kernel = Kernel((dim[1], dim[2]), a, geometry='disc')
-            start_time = time.clock()
-            phase_num_vort = pm.phase_mag(a, projection_vort, kernel=kernel)
-            data_vort_real_d[2, i] = time.clock() - start_time
-            print '------time (vortex, real disc) =', data_vort_real_d[2, i]
-            phase_diff_vort = (phase_ana_vort-phase_num_vort) * 1E3  # in mrad -> *1000
-            data_vort_real_d[1, i] = np.sqrt(np.mean(phase_diff_vort**2))
+        print '----CALCULATE RMS/DURATION HOMOG. MAGN. DISC'
+        # Analytic solution:
+        phase_ana_disc = an.phase_mag_disc(dim, a, phi, center, radius, height)
+        # Fourier unpadded:
+        start_time = time.clock()
+        phase_num_disc = pm_fourier0(mag_data_disc)
+        data_disc_fourier0[2, i] = time.clock() - start_time
+        print '------time (disc, fourier0) =', data_disc_fourier0[2, i]
+        phase_diff_disc = (phase_ana_disc-phase_num_disc) * 1E3  # in mrad -> *1000
+        data_disc_fourier0[1, i] = np.sqrt(np.mean(phase_diff_disc.phase**2))
+        # Fourier padding 3:
+        start_time = time.clock()
+        phase_num_disc = pm_fourier3(mag_data_disc)
+        data_disc_fourier3[2, i] = time.clock() - start_time
+        print '------time (disc, fourier3) =', data_disc_fourier3[2, i]
+        phase_diff_disc = (phase_ana_disc-phase_num_disc) * 1E3  # in mrad -> *1000
+        data_disc_fourier3[1, i] = np.sqrt(np.mean(phase_diff_disc.phase**2))
+        # Fourier padding 10:
+        start_time = time.clock()
+        phase_num_disc = pm_fourier10(mag_data_disc)
+        data_disc_fourier10[2, i] = time.clock() - start_time
+        print '------time (disc, fourier10) =', data_disc_fourier10[2, i]
+        phase_diff_disc = (phase_ana_disc-phase_num_disc) * 1E3  # in mrad -> *1000
+        data_disc_fourier10[1, i] = np.sqrt(np.mean(phase_diff_disc.phase**2))
+        # Real space slab:
+        start_time = time.clock()
+        phase_num_disc = pm_slab(mag_data_disc)
+        data_disc_real_s[2, i] = time.clock() - start_time
+        print '------time (disc, real slab) =', data_disc_real_s[2, i]
+        phase_diff_disc = (phase_ana_disc-phase_num_disc) * 1E3  # in mrad -> *1000
+        data_disc_real_s[1, i] = np.sqrt(np.mean(phase_diff_disc.phase**2))
+        # Real space disc:
+        start_time = time.clock()
+        phase_num_disc = pm_disc(mag_data_disc)
+        data_disc_real_d[2, i] = time.clock() - start_time
+        print '------time (disc, real disc) =', data_disc_real_d[2, i]
+        phase_diff_disc = (phase_ana_disc-phase_num_disc) * 1E3  # in mrad -> *1000
+        data_disc_real_d[1, i] = np.sqrt(np.mean(phase_diff_disc.phase**2))
 
-        print '--SHELVE METHOD DATA'
-        data_shelve[key] = (data_disc_fourier0, data_vort_fourier0,
-                            data_disc_fourier3, data_vort_fourier3,
-                            data_disc_fourier10, data_vort_fourier10,
-                            data_disc_real_s, data_vort_real_s,
-                            data_disc_real_d, data_vort_real_d)
+        print '----CALCULATE RMS/DURATION HOMOG. MAGN. DISC'
+        # Analytic solution:
+        phase_ana_vort = an.phase_mag_vortex(dim, a, center, radius, height)
+        # Fourier unpadded:
+        start_time = time.clock()
+        phase_num_vort = pm_fourier0(mag_data_vort)
+        data_vort_fourier0[2, i] = time.clock() - start_time
+        print '------time (vortex, fourier0) =', data_vort_fourier0[2, i]
+        phase_diff_vort = (phase_ana_vort-phase_num_vort) * 1E3  # in mrad -> *1000
+        data_vort_fourier0[1, i] = np.sqrt(np.mean(phase_diff_vort.phase**2))
+        # Fourier padding 3:
+        start_time = time.clock()
+        phase_num_vort = pm_fourier3(mag_data_vort)
+        data_vort_fourier3[2, i] = time.clock() - start_time
+        print '------time (vortex, fourier3) =', data_vort_fourier3[2, i]
+        phase_diff_vort = (phase_ana_vort-phase_num_vort) * 1E3  # in mrad -> *1000
+        data_vort_fourier3[1, i] = np.sqrt(np.mean(phase_diff_vort.phase**2))
+        # Fourier padding 10:
+        start_time = time.clock()
+        phase_num_vort = pm_fourier10(mag_data_vort)
+        data_vort_fourier10[2, i] = time.clock() - start_time
+        print '------time (vortex, fourier10) =', data_vort_fourier10[2, i]
+        phase_diff_vort = (phase_ana_vort-phase_num_vort) * 1E3  # in mrad -> *1000
+        data_vort_fourier10[1, i] = np.sqrt(np.mean(phase_diff_vort.phase**2))
+        # Real space slab:
+        start_time = time.clock()
+        phase_num_vort = pm_slab(mag_data_vort)
+        data_vort_real_s[2, i] = time.clock() - start_time
+        print '------time (vortex, real slab) =', data_vort_real_s[2, i]
+        phase_diff_vort = (phase_ana_vort-phase_num_vort) * 1E3  # in mrad -> *1000
+        data_vort_real_s[1, i] = np.sqrt(np.mean(phase_diff_vort.phase**2))
+        # Real space disc:
+        start_time = time.clock()
+        phase_num_vort = pm_disc(mag_data_vort)
+        data_vort_real_d[2, i] = time.clock() - start_time
+        print '------time (vortex, real disc) =', data_vort_real_d[2, i]
+        phase_diff_vort = (phase_ana_vort-phase_num_vort) * 1E3  # in mrad -> *1000
+        data_vort_real_d[1, i] = np.sqrt(np.mean(phase_diff_vort.phase**2))
 
-    print '--PLOT/SAVE METHOD DATA'
+        # Scale down for next iteration:
+        mag_data_disc.scale_down()
+        mag_data_vort.scale_down()
 
-    # Plot using shared rows and colums:
-    fig, axes = plt.subplots(2, 2, sharex='col', sharey='row', figsize=(12, 8))
-    fig.tight_layout(rect=(0.05, 0.05, 0.95, 0.95))
-    fig.suptitle('Method Comparison', fontsize=20)
+    print '--SHELVE METHOD DATA'
+    data_shelve[key] = (data_disc_fourier0, data_vort_fourier0,
+                        data_disc_fourier3, data_vort_fourier3,
+                        data_disc_fourier10, data_vort_fourier10,
+                        data_disc_real_s, data_vort_real_s,
+                        data_disc_real_d, data_vort_real_d)
 
-    # Plot duration against a (disc) [top/left]:
-    axes[1, 0].set_xscale('log')
-    axes[1, 0].set_yscale('log')
-    axes[1, 0].plot(data_disc_fourier0[0], data_disc_fourier0[1], ':bs')
-    axes[1, 0].plot(data_disc_fourier3[0], data_disc_fourier3[1], ':bo')
-    axes[1, 0].plot(data_disc_fourier10[0], data_disc_fourier10[1], ':b^')
-    axes[1, 0].plot(data_disc_real_s[0], data_disc_real_s[1], '--rs')
-    axes[1, 0].plot(data_disc_real_d[0], data_disc_real_d[1], '--ro')
-    axes[1, 0].set_xlabel('grid size [px]', fontsize=15)
-    axes[1, 0].set_ylabel('RMS [mrad]', fontsize=15)
-    axes[1, 0].set_xlim(12, 350)
-    axes[1, 0].tick_params(axis='both', which='major', labelsize=14)
-    axes[1, 0].xaxis.set_major_locator(LogLocator(base=2))
-    axes[1, 0].xaxis.set_major_formatter(LogFormatter(base=2))
-    axes[1, 0].xaxis.set_minor_locator(NullLocator())
-    axes[1, 0].grid()
+print '--PLOT/SAVE METHOD DATA'
 
-    # Plot RMS against a (disc) [bottom/left]:
-    plt.tick_params(axis='both', which='major', labelsize=14)
-    axes[0, 0].set_xscale('log')
-    axes[0, 0].set_yscale('log')
-    axes[0, 0].plot(data_disc_fourier0[0], data_disc_fourier0[2], ':bs')
-    axes[0, 0].plot(data_disc_fourier3[0], data_disc_fourier3[2], ':bo')
-    axes[0, 0].plot(data_disc_fourier10[0], data_disc_fourier10[2], ':b^')
-    axes[0, 0].plot(data_disc_real_s[0], data_disc_real_s[2], '--rs')
-    axes[0, 0].plot(data_disc_real_d[0], data_disc_real_d[2], '--ro')
-    axes[0, 0].set_title('Homog. magn. disc', fontsize=18)
-    axes[0, 0].set_ylabel('duration [s]', fontsize=15)
-    axes[0, 0].set_xlim(12, 350)
-    axes[0, 0].tick_params(axis='both', which='major', labelsize=14)
-    axes[0, 0].xaxis.set_major_locator(LogLocator(base=2))
-    axes[0, 0].xaxis.set_major_formatter(LogFormatter(base=2))
-    axes[0, 0].xaxis.set_minor_locator(NullLocator())
-    axes[0, 0].grid()
+# Plot using shared rows and colums:
+fig, axes = plt.subplots(2, 2, sharex='col', sharey='row', figsize=(12, 8))
+fig.tight_layout(rect=(0.05, 0.05, 0.95, 0.95))
+fig.suptitle('Method Comparison', fontsize=20)
 
-    # Plot duration against a (vortex) [top/right]:
-    axes[1, 1].set_xscale('log')
-    axes[1, 1].set_yscale('log')
-    axes[1, 1].plot(data_vort_fourier0[0], data_vort_fourier0[1], ':bs',
-                    label='Fourier padding=0')
-    axes[1, 1].plot(data_vort_fourier3[0], data_vort_fourier3[1], ':bo',
-                    label='Fourier padding=3')
-    axes[1, 1].plot(data_vort_fourier10[0], data_vort_fourier10[1], ':b^',
-                    label='Fourier padding=10')
-    axes[1, 1].plot(data_vort_real_s[0], data_vort_real_s[1], '--rs',
-                    label='Real space (slab)')
-    axes[1, 1].plot(data_vort_real_d[0], data_vort_real_d[1], '--ro',
-                    label='Real space (disc)')
-    axes[1, 1].set_xlabel('grid size [px]', fontsize=15)
-    axes[1, 1].set_xlim(12, 350)
-    axes[1, 1].tick_params(axis='both', which='major', labelsize=14)
-    axes[1, 1].xaxis.set_major_locator(LogLocator(base=2))
-    axes[1, 1].xaxis.set_major_formatter(LogFormatter(base=2))
-    axes[1, 1].xaxis.set_minor_locator(NullLocator())
-    axes[1, 1].grid()
+# Plot duration against a (disc) [top/left]:
+axes[1, 0].set_xscale('log')
+axes[1, 0].set_yscale('log')
+axes[1, 0].plot(data_disc_fourier0[0], data_disc_fourier0[1], ':bs')
+axes[1, 0].plot(data_disc_fourier3[0], data_disc_fourier3[1], ':bo')
+axes[1, 0].plot(data_disc_fourier10[0], data_disc_fourier10[1], ':b^')
+axes[1, 0].plot(data_disc_real_s[0], data_disc_real_s[1], '--rs')
+axes[1, 0].plot(data_disc_real_d[0], data_disc_real_d[1], '--ro')
+axes[1, 0].set_xlabel('grid size [px]', fontsize=15)
+axes[1, 0].set_ylabel('RMS [mrad]', fontsize=15)
+axes[1, 0].set_xlim(25, 350)
+axes[1, 0].tick_params(axis='both', which='major', labelsize=14)
+axes[1, 0].xaxis.set_major_locator(LogLocator(base=2))
+axes[1, 0].xaxis.set_major_formatter(LogFormatter(base=2))
+axes[1, 0].xaxis.set_minor_locator(NullLocator())
+axes[1, 0].grid()
 
-    # Plot RMS against a (vortex) [bottom/right]:
-    axes[0, 1].set_xscale('log')
-    axes[0, 1].set_yscale('log')
-    axes[0, 1].plot(data_vort_fourier0[0], data_vort_fourier0[2], ':bs',
-                    label='Fourier padding=0')
-    axes[0, 1].plot(data_vort_fourier3[0], data_vort_fourier3[2], ':bo',
-                    label='Fourier padding=3')
-    axes[0, 1].plot(data_vort_fourier10[0], data_vort_fourier10[2], ':b^',
-                    label='Fourier padding=10')
-    axes[0, 1].plot(data_vort_real_s[0], data_vort_real_s[2], '--rs',
-                    label='Real space (slab)')
-    axes[0, 1].plot(data_vort_real_d[0], data_vort_real_d[2], '--ro',
-                    label='Real space (disc)')
-    axes[0, 1].set_title('Vortex state disc', fontsize=18)
-    axes[0, 1].set_xlim(12, 350)
-    axes[0, 1].tick_params(axis='both', which='major', labelsize=14)
-    axes[0, 1].xaxis.set_major_locator(LogLocator(base=2))
-    axes[0, 1].xaxis.set_major_formatter(LogFormatter(base=2))
-    axes[0, 1].xaxis.set_minor_locator(NullLocator())
-    axes[0, 1].grid()
+# Plot RMS against a (disc) [bottom/left]:
+plt.tick_params(axis='both', which='major', labelsize=14)
+axes[0, 0].set_xscale('log')
+axes[0, 0].set_yscale('log')
+axes[0, 0].plot(data_disc_fourier0[0], data_disc_fourier0[2], ':bs')
+axes[0, 0].plot(data_disc_fourier3[0], data_disc_fourier3[2], ':bo')
+axes[0, 0].plot(data_disc_fourier10[0], data_disc_fourier10[2], ':b^')
+axes[0, 0].plot(data_disc_real_s[0], data_disc_real_s[2], '--rs')
+axes[0, 0].plot(data_disc_real_d[0], data_disc_real_d[2], '--ro')
+axes[0, 0].set_title('Homog. magn. disc', fontsize=18)
+axes[0, 0].set_ylabel('duration [s]', fontsize=15)
+axes[0, 0].set_xlim(25, 350)
+axes[0, 0].tick_params(axis='both', which='major', labelsize=14)
+axes[0, 0].xaxis.set_major_locator(LogLocator(base=2))
+axes[0, 0].xaxis.set_major_formatter(LogFormatter(base=2))
+axes[0, 0].xaxis.set_minor_locator(NullLocator())
+axes[0, 0].grid()
 
-    # Add legend:
-    axes[1, 1].legend(bbox_to_anchor=(0, 0, 0.955, 0.615), bbox_transform=fig.transFigure,
-                      prop={'size':12})
+# Plot duration against a (vortex) [top/right]:
+axes[1, 1].set_xscale('log')
+axes[1, 1].set_yscale('log')
+axes[1, 1].plot(data_vort_fourier0[0], data_vort_fourier0[1], ':bs',
+                label='Fourier padding=0')
+axes[1, 1].plot(data_vort_fourier3[0], data_vort_fourier3[1], ':bo',
+                label='Fourier padding=3')
+axes[1, 1].plot(data_vort_fourier10[0], data_vort_fourier10[1], ':b^',
+                label='Fourier padding=10')
+axes[1, 1].plot(data_vort_real_s[0], data_vort_real_s[1], '--rs',
+                label='Real space (slab)')
+axes[1, 1].plot(data_vort_real_d[0], data_vort_real_d[1], '--ro',
+                label='Real space (disc)')
+axes[1, 1].set_xlabel('grid size [px]', fontsize=15)
+axes[1, 1].set_xlim(25, 350)
+axes[1, 1].tick_params(axis='both', which='major', labelsize=14)
+axes[1, 1].xaxis.set_major_locator(LogLocator(base=2))
+axes[1, 1].xaxis.set_major_formatter(LogFormatter(base=2))
+axes[1, 1].xaxis.set_minor_locator(NullLocator())
+axes[1, 1].grid()
 
-    # Save figure as .png:
-    plt.show()
-    plt.figtext(0.12, 0.85, 'a)', fontsize=30)
-    plt.figtext(0.57, 0.85, 'b)', fontsize=30)
-    plt.figtext(0.12, 0.15, 'c)', fontsize=30)
-    plt.figtext(0.57, 0.15, 'd)', fontsize=30)
-    plt.savefig(directory + '/ch5-3-method comparison.png', bbox_inches='tight')
+# Plot RMS against a (vortex) [bottom/right]:
+axes[0, 1].set_xscale('log')
+axes[0, 1].set_yscale('log')
+axes[0, 1].plot(data_vort_fourier0[0], data_vort_fourier0[2], ':bs',
+                label='Fourier padding=0')
+axes[0, 1].plot(data_vort_fourier3[0], data_vort_fourier3[2], ':bo',
+                label='Fourier padding=3')
+axes[0, 1].plot(data_vort_fourier10[0], data_vort_fourier10[2], ':b^',
+                label='Fourier padding=10')
+axes[0, 1].plot(data_vort_real_s[0], data_vort_real_s[2], '--rs',
+                label='Real space (slab)')
+axes[0, 1].plot(data_vort_real_d[0], data_vort_real_d[2], '--ro',
+                label='Real space (disc)')
+axes[0, 1].set_title('Vortex state disc', fontsize=18)
+axes[0, 1].set_xlim(25, 350)
+axes[0, 1].tick_params(axis='both', which='major', labelsize=14)
+axes[0, 1].xaxis.set_major_locator(LogLocator(base=2))
+axes[0, 1].xaxis.set_major_formatter(LogFormatter(base=2))
+axes[0, 1].xaxis.set_minor_locator(NullLocator())
+axes[0, 1].grid()
 
-    ###############################################################################################
-    print 'CLOSING SHELVE\n'
-    # Close shelve:
-    data_shelve.close()
+# Add legend:
+axes[1, 1].legend(bbox_to_anchor=(0, 0, 0.955, 0.615), bbox_transform=fig.transFigure,
+                  prop={'size':12})
 
-    ###############################################################################################
+# Save figure as .png:
+plt.show()
+plt.figtext(0.12, 0.85, 'a)', fontsize=30)
+plt.figtext(0.57, 0.85, 'b)', fontsize=30)
+plt.figtext(0.12, 0.15, 'c)', fontsize=30)
+plt.figtext(0.57, 0.15, 'd)', fontsize=30)
+plt.savefig(directory + '/ch5-3-method comparison.png', bbox_inches='tight')
 
+###############################################################################################
+print 'CLOSING SHELVE\n'
+# Close shelve:
+data_shelve.close()
 
-if __name__ == "__main__":
-    try:
-        run()
-    except:
-        type, value, tb = sys.exc_info()
-        traceback.print_exc()
-        pdb.post_mortem(tb)
+###############################################################################################
diff --git a/scripts/paper 1/logfile.log b/scripts/paper 1/logfile.log
new file mode 100644
index 0000000000000000000000000000000000000000..e8f8d219b3f7e2003db1b0eb3aacc4de9518df38
--- /dev/null
+++ b/scripts/paper 1/logfile.log	
@@ -0,0 +1,85 @@
+2014-02-08 20:46:32: INFO     @ <pyramid.phasemap>:    Calling make_color_wheel
+2014-02-08 20:46:43: INFO     @ <pyramid.projector>:    Calling __init__
+2014-02-08 20:46:43: INFO     @ <pyramid.projector>:    Calling __init__
+2014-02-08 20:46:43: INFO     @ <pyramid.projector>:    Created <pyramid.projector.SimpleProjector object at 0x0A8519F0>
+2014-02-08 20:46:43: INFO     @ <pyramid.projector>:    Created <pyramid.projector.SimpleProjector object at 0x0A8519F0>
+2014-02-08 20:46:43: INFO     @ <pyramid.phasemap>:    Calling __str__
+2014-02-08 20:46:43: INFO     @ <pyramid.phasemap>:    Created PhaseMap(a=1.0, dim=(128, 128))
+2014-02-08 20:46:43: INFO     @ <pyramid.phasemap>:    Calling __str__
+2014-02-08 20:46:43: INFO     @ <pyramid.phasemap>:    Created PhaseMap(a=1.0, dim=(128, 128))
+2014-02-08 20:46:43: INFO     @ <pyramid.projector>:    Calling as function
+2014-02-08 20:46:43: INFO     @ <pyramid.projector>:    mode == vector
+2014-02-08 20:46:43: INFO     @ <pyramid.projector>:    Calling _vector_field_projection
+2014-02-08 20:46:43: INFO     @ <pyramid.phasemap>:    Calling __str__
+2014-02-08 20:46:43: INFO     @ <pyramid.phasemap>:    Created PhaseMap(a=1.0, dim=(128, 128))
+2014-02-08 20:46:43: INFO     @ <pyramid.phasemap>:    Calling __sub__
+2014-02-08 20:46:43: INFO     @ <pyramid.phasemap>:    Calling __neg__
+2014-02-08 20:46:43: INFO     @ <pyramid.phasemap>:    Calling __str__
+2014-02-08 20:46:43: INFO     @ <pyramid.phasemap>:    Created PhaseMap(a=1.0, dim=(128, 128))
+2014-02-08 20:46:43: INFO     @ <pyramid.phasemap>:    Calling __add__
+2014-02-08 20:46:43: INFO     @ <pyramid.phasemap>:    Adding two PhaseMap objects
+2014-02-08 20:46:43: INFO     @ <pyramid.phasemap>:    Calling __str__
+2014-02-08 20:46:43: INFO     @ <pyramid.phasemap>:    Created PhaseMap(a=1.0, dim=(128, 128))
+2014-02-08 20:46:43: INFO     @ <pyramid.phasemap>:    Calling display_phase
+2014-02-08 20:46:43: INFO     @ <pyramid.projector>:    Calling as function
+2014-02-08 20:46:43: INFO     @ <pyramid.projector>:    mode == vector
+2014-02-08 20:46:43: INFO     @ <pyramid.projector>:    Calling _vector_field_projection
+2014-02-08 20:46:43: INFO     @ <pyramid.phasemap>:    Calling __str__
+2014-02-08 20:46:43: INFO     @ <pyramid.phasemap>:    Created PhaseMap(a=1.0, dim=(128, 128))
+2014-02-08 20:46:43: INFO     @ <pyramid.phasemap>:    Calling __sub__
+2014-02-08 20:46:43: INFO     @ <pyramid.phasemap>:    Calling __neg__
+2014-02-08 20:46:43: INFO     @ <pyramid.phasemap>:    Calling __str__
+2014-02-08 20:46:43: INFO     @ <pyramid.phasemap>:    Created PhaseMap(a=1.0, dim=(128, 128))
+2014-02-08 20:46:43: INFO     @ <pyramid.phasemap>:    Calling __add__
+2014-02-08 20:46:43: INFO     @ <pyramid.phasemap>:    Adding two PhaseMap objects
+2014-02-08 20:46:43: INFO     @ <pyramid.phasemap>:    Calling __str__
+2014-02-08 20:46:43: INFO     @ <pyramid.phasemap>:    Created PhaseMap(a=1.0, dim=(128, 128))
+2014-02-08 20:46:43: INFO     @ <pyramid.phasemap>:    Calling __isub__
+2014-02-08 20:46:43: INFO     @ <pyramid.phasemap>:    Calling __sub__
+2014-02-08 20:46:43: INFO     @ <pyramid.phasemap>:    Calling __add__
+2014-02-08 20:46:43: INFO     @ <pyramid.phasemap>:    Adding an offset
+2014-02-08 20:46:43: INFO     @ <pyramid.phasemap>:    Calling __str__
+2014-02-08 20:46:43: INFO     @ <pyramid.phasemap>:    Created PhaseMap(a=1.0, dim=(128, 128))
+2014-02-08 20:46:43: INFO     @ <pyramid.phasemap>:    Calling display_phase
+2014-02-08 20:46:44: INFO     @ <pyramid.projector>:    Calling as function
+2014-02-08 20:46:44: INFO     @ <pyramid.projector>:    mode == vector
+2014-02-08 20:46:44: INFO     @ <pyramid.projector>:    Calling _vector_field_projection
+2014-02-08 20:46:44: INFO     @ <pyramid.phasemap>:    Calling __str__
+2014-02-08 20:46:44: INFO     @ <pyramid.phasemap>:    Created PhaseMap(a=1.0, dim=(128, 128))
+2014-02-08 20:46:44: INFO     @ <pyramid.phasemap>:    Calling __sub__
+2014-02-08 20:46:44: INFO     @ <pyramid.phasemap>:    Calling __neg__
+2014-02-08 20:46:44: INFO     @ <pyramid.phasemap>:    Calling __str__
+2014-02-08 20:46:44: INFO     @ <pyramid.phasemap>:    Created PhaseMap(a=1.0, dim=(128, 128))
+2014-02-08 20:46:44: INFO     @ <pyramid.phasemap>:    Calling __add__
+2014-02-08 20:46:44: INFO     @ <pyramid.phasemap>:    Adding two PhaseMap objects
+2014-02-08 20:46:44: INFO     @ <pyramid.phasemap>:    Calling __str__
+2014-02-08 20:46:44: INFO     @ <pyramid.phasemap>:    Created PhaseMap(a=1.0, dim=(128, 128))
+2014-02-08 20:46:44: INFO     @ <pyramid.phasemap>:    Calling display_phase
+2014-02-08 20:46:45: INFO     @ <pyramid.projector>:    Calling as function
+2014-02-08 20:46:45: INFO     @ <pyramid.projector>:    mode == vector
+2014-02-08 20:46:45: INFO     @ <pyramid.projector>:    Calling _vector_field_projection
+2014-02-08 20:46:45: INFO     @ <pyramid.phasemap>:    Calling __str__
+2014-02-08 20:46:45: INFO     @ <pyramid.phasemap>:    Created PhaseMap(a=1.0, dim=(128, 128))
+2014-02-08 20:46:45: INFO     @ <pyramid.phasemap>:    Calling __sub__
+2014-02-08 20:46:45: INFO     @ <pyramid.phasemap>:    Calling __neg__
+2014-02-08 20:46:45: INFO     @ <pyramid.phasemap>:    Calling __str__
+2014-02-08 20:46:45: INFO     @ <pyramid.phasemap>:    Created PhaseMap(a=1.0, dim=(128, 128))
+2014-02-08 20:46:45: INFO     @ <pyramid.phasemap>:    Calling __add__
+2014-02-08 20:46:45: INFO     @ <pyramid.phasemap>:    Adding two PhaseMap objects
+2014-02-08 20:46:45: INFO     @ <pyramid.phasemap>:    Calling __str__
+2014-02-08 20:46:45: INFO     @ <pyramid.phasemap>:    Created PhaseMap(a=1.0, dim=(128, 128))
+2014-02-08 20:46:45: INFO     @ <pyramid.phasemap>:    Calling __isub__
+2014-02-08 20:46:45: INFO     @ <pyramid.phasemap>:    Calling __sub__
+2014-02-08 20:46:45: INFO     @ <pyramid.phasemap>:    Calling __add__
+2014-02-08 20:46:45: INFO     @ <pyramid.phasemap>:    Adding an offset
+2014-02-08 20:46:45: INFO     @ <pyramid.phasemap>:    Calling __str__
+2014-02-08 20:46:45: INFO     @ <pyramid.phasemap>:    Created PhaseMap(a=1.0, dim=(128, 128))
+2014-02-08 20:46:45: INFO     @ <pyramid.phasemap>:    Calling display_phase
+2014-02-08 20:46:47: INFO     @ <pyramid.projector>:    Calling __init__
+2014-02-08 20:46:47: INFO     @ <pyramid.projector>:    Calling __init__
+2014-02-08 20:46:47: INFO     @ <pyramid.projector>:    Created <pyramid.projector.SimpleProjector object at 0x0B117190>
+2014-02-08 20:46:47: INFO     @ <pyramid.projector>:    Created <pyramid.projector.SimpleProjector object at 0x0B117190>
+2014-02-08 20:46:47: INFO     @ <pyramid.phasemap>:    Calling __str__
+2014-02-08 20:46:47: INFO     @ <pyramid.phasemap>:    Created PhaseMap(a=1.0, dim=(128, 128))
+2014-02-08 20:46:47: INFO     @ <pyramid.phasemap>:    Calling __str__
+2014-02-08 20:46:47: INFO     @ <pyramid.phasemap>:    Created PhaseMap(a=1.0, dim=(128, 128))
diff --git a/scripts/simple_phasemapping.py b/scripts/simple_phasemapping.py
new file mode 100644
index 0000000000000000000000000000000000000000..80c67372b54518a2ed487f9da4689f3238b79254
--- /dev/null
+++ b/scripts/simple_phasemapping.py
@@ -0,0 +1,63 @@
+# -*- coding: utf-8 -*-
+"""
+Created on Fri Jan 17 14:06:01 2014
+
+@author: Jan
+"""
+
+
+from pyramid.magdata import MagData
+from pyramid.projector import SimpleProjector
+from pyramid.phasemapper import PMAdapterFM, PMConvolve, PMFourier, PMReal
+
+from time import clock
+
+#import cProfile
+
+
+mag_data = MagData.load_from_netcdf4('../output/vtk data/rect_500x125x3.nc')
+
+projector = SimpleProjector(mag_data.dim)
+
+start = clock()
+pm_adapter = PMAdapterFM(mag_data.a, projector)
+pm_convolve = PMConvolve(mag_data.a, projector)
+pm_fourier = PMFourier(mag_data.a, projector, padding=3)
+pm_real = PMReal(mag_data.a, projector)
+print 'Overhead  :', clock()-start
+
+#cProfile.run('phasemapper(mag_data)')#, filename='../output/profile.profile')
+
+start = clock()
+pm_adapter(mag_data)
+print 'Adapter FM:', clock()-start
+start = clock()
+pm_convolve(mag_data)
+print 'Convolve  :', clock()-start
+start = clock()
+pm_fourier(mag_data)
+print 'Fourier   :', clock()-start
+start = clock()
+pm_real(mag_data)
+print 'Real      :', clock()-start
+
+phase_map = pm_convolve(mag_data)
+
+(-phase_map).display_combined(density=16)
+
+
+
+
+
+##from xml.etree import ElementTree
+#from cProfile import Profile
+##xml_content = '<a>\n' + '\t<b/><c><d>text</d></c>\n' * 100 + '</a>'
+#profiler = Profile()
+##profiler.runctx("ElementTree.fromstring(xml_content)", locals(), globals())
+#profiler.run('phasemapper(mag_data)')
+#
+#import pyprof2calltree
+#from pyprof2calltree import convert, visualize
+#
+#pyprof2calltree.visualize(profiler.getstats())                            # run kcachegrind
+#pyprof2calltree.convert(profiler.getstats(), 'profiling_results.kgrind')  # save for later
\ No newline at end of file
diff --git a/scripts/vtk-interpolation.py b/scripts/vtk-interpolation.py
deleted file mode 100644
index 24bbaa6a9878175724132426f324a89c655a896b..0000000000000000000000000000000000000000
--- a/scripts/vtk-interpolation.py
+++ /dev/null
@@ -1,61 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
-Created on Tue Jan 14 10:06:42 2014
-
-@author: Jan
-"""
-
-import vtk
-
-reader = vtk.vtkDataSetReader()
-
-reader.SetFileName('test.vtk')
-
-reader.ReadAllScalarsOn()
-
-reader.Update()
-
-output = reader.GetOutput()
-scalar_range = output.GetScalarRange()
- 
-# Create the mapper that corresponds the objects of the vtk file into graphics elements
-mapper = vtk.vtkDataSetMapper()
-mapper.SetInput(output)
-mapper.SetScalarRange(scalar_range)
- 
-# Create the Actor
-actor = vtk.vtkActor()
-actor.SetMapper(mapper)
- 
-# Create the Renderer
-renderer = vtk.vtkRenderer()
-renderer.AddActor(actor)
-renderer.SetBackground(1, 1, 1) # Set background to white
- 
-# Create the RendererWindow
-renderer_window = vtk.vtkRenderWindow()
-renderer_window.AddRenderer(renderer)
- 
-# Create the RendererWindowInteractor and display the vtk_file
-interactor = vtk.vtkRenderWindowInteractor()
-interactor.SetRenderWindow(renderer_window)
-interactor.Initialize()
-interactor.Start()
-
-
-
-
-
-print reader.GetHeader()
-
-print 'Points:', output.GetNumberOfPoints()
-print 'Cells: ', output.GetNumberOfCells()
-#print 'Polys: ', output.GetNumberOfPolys()
-#print 'Lines: ', output.GetNumberOfLines()
-#print 'Strips:', output.GetNumberOfStrips()
-#print 'Piece: ', output.GetNumberOfPiece()
-#print 'Verts: ', output.GetNumberOfVerts()
-
-points = output.GetPoints()
-
-print output.GetPoint(0)
diff --git a/scripts/vtk_conversion.py b/scripts/vtk_conversion.py
new file mode 100644
index 0000000000000000000000000000000000000000..bbbb5067be95355684bddf1a69647b5e84b257a2
--- /dev/null
+++ b/scripts/vtk_conversion.py
@@ -0,0 +1,159 @@
+# -*- coding: utf-8 -*-
+"""
+Created on Fri Jan 24 11:17:11 2014
+
+@author: Jan
+"""
+
+
+import numpy as np
+import vtk
+import logging
+import os
+import sys
+import pickle
+from tqdm import tqdm
+from pyramid.magdata import MagData
+import matplotlib.pyplot as plt
+from pylab import griddata
+from pyramid.projector import SimpleProjector
+from pyramid.phasemapper import PMAdapterFM
+
+###################################################################################################
+PATH = '../output/vtk data/tube_90x30x50_sat_edge_equil.gmr'
+b_0 = 1.54
+gain = 12
+force_calculation = False
+###################################################################################################
+
+logging.basicConfig(level=logging.INFO, format='%(levelname)s: %(message)s', stream=sys.stdout)
+log = logging.getLogger(__name__)
+
+if force_calculation or not os.path.exists(PATH+'.pickle'):
+    log.info('Reading data from vtk-file')
+    # Setting up reader:
+    reader = vtk.vtkDataSetReader()
+    reader.SetFileName(PATH+'.vtk')
+    reader.ReadAllScalarsOn()
+    reader.ReadAllVectorsOn()
+    reader.Update()
+    # Getting output:
+    output = reader.GetOutput()
+    # Reading points and vectors:
+    size = output.GetNumberOfPoints()
+    vtk_points = output.GetPoints().GetData()
+    vtk_vectors = output.GetPointData().GetVectors()
+    # Converting points to numpy array:
+    point_array = np.zeros(vtk_points.GetSize())
+    vtk_points.ExportToVoidPointer(point_array)
+    point_array = np.reshape(point_array, (-1, 3))
+    # Converting vectors to numpy array:
+    vector_array = np.zeros(vtk_points.GetSize())
+    vtk_vectors.ExportToVoidPointer(vector_array)
+    vector_array = np.reshape(vector_array, (-1, 3))
+    # Combining data:
+    data = np.hstack((point_array, vector_array))
+    log.info('Data reading complete!')
+    log.info('Pickling data!')
+    with open(PATH+'.pickle', 'w') as pf:
+        pickle.dump(data, pf)
+    log.info('Pickling complete!')
+else:
+    log.info('Loading pickled data!')
+    with open(PATH+'.pickle') as pf:
+        data = pickle.load(pf)
+    log.info('Loading complete!')
+# Scatter plot of all x-y-coordinates
+axis = plt.figure().add_subplot(1, 1, 1)
+axis.scatter(data[:, 0], data[:, 1])
+plt.show()
+
+if force_calculation or not os.path.exists(PATH+'.nc'):
+    log.info('Arranging data in z-slices!')
+    # Find unique z-slices:
+    zs =  np.unique(data[:, 2])
+    # Determine the grid spacing:
+    a = zs[1] - zs[0]
+    # Determine the size of object:
+    x_min, x_max = data[:, 0].min(), data[:, 0].max()
+    y_min, y_max = data[:, 1].min(), data[:, 1].max()
+    z_min, z_max = data[:, 2].min(), data[:, 2].max()
+    x_diff, y_diff, z_diff = np.ptp(data[:, 0]), np.ptp(data[:, 1]), np.ptp(data[:, 2])
+    x_cent, y_cent, z_cent = x_min+x_diff/2., y_min+y_diff/2., z_min+z_diff/2.
+    # Create regular grid
+    xs = np.arange(x_cent-x_diff, x_cent+x_diff, a)    #linspace(-8.5*2, 8.5*2, 256)
+    ys = np.arange(y_cent-y_diff, y_cent+y_diff, a)    #linspace(-9.5*2, 9.5*2, 256)
+    o, p = np.meshgrid(xs, ys)
+    # Create empty magnitude:
+    magnitude = np.zeros((3, len(zs), len(ys), len(xs)))
+    
+    # WITH MASKING OF THE CENTER (SYMMETRIC):
+    iz_x = np.concatenate([np.linspace(-4.95, -4.95, 50),
+                           np.linspace(-4.95, 0, 50),
+                           np.linspace(0, 4.95, 50),
+                           np.linspace(4.95, 4.95, 50),
+                           np.linspace(-4.95, 0, 50),
+                           np.linspace(0, 4.95, 50),])
+    iz_y = np.concatenate([np.linspace(-2.88, 2.88, 50),
+                           np.linspace(2.88, 5.7, 50),
+                           np.linspace(5.7, 2.88, 50),
+                           np.linspace(2.88, -2.88, 50),
+                           np.linspace(-2.88, -5.7, 50),
+                           np.linspace(-5.7, -2.88, 50), ])
+    for i, z in tqdm(enumerate(zs), total=len(zs)):
+        subdata = data[data[:, 2] == z, :]
+        for j in range(3):  # For all 3 components!
+            gridded_subdata = griddata(np.concatenate([subdata[:, 0], iz_x]),
+                                       np.concatenate([subdata[:, 1], iz_y]), 
+                                       np.concatenate([subdata[:, 3 + j], np.zeros(len(iz_x))]),
+                                       o, p)
+            magnitude[j, i, :, :] = gridded_subdata.filled(fill_value=0)
+
+#    # WITH MASKING OF THE CENTER (ASYMMETRIC):
+#    iz_x = np.concatenate([np.linspace(-5.88, -5.88, 50),
+#                           np.linspace(-5.88, 0, 50),
+#                            np.linspace(0, 5.88, 50),
+#                            np.linspace(5.88, 5.88, 50),
+#                            np.linspace(5.88, 0, 50),
+#                            np.linspace(0, -5.88, 50),])
+#    iz_y = np.concatenate([np.linspace(-2.10, 4.50, 50),
+#                           np.linspace(4.50, 7.90, 50),
+#                            np.linspace(7.90, 4.50, 50),
+#                            np.linspace(4.50, -2.10, 50),
+#                            np.linspace(-2.10, -5.50, 50),
+#                            np.linspace(-5.50, -2.10, 50), ])
+#    for i, z in tqdm(enumerate(zs), total=len(zs)):
+#        subdata = data[data[:, 2] == z, :]
+#        for j in range(3):  # For all 3 components!
+#            gridded_subdata = griddata(np.concatenate([subdata[:, 0], iz_x]),
+#                                       np.concatenate([subdata[:, 1], iz_y]), 
+#                                       np.concatenate([subdata[:, 3 + j], np.zeros(len(iz_x))]),
+#                                       o, p)
+#            magnitude[j, i, :, :] = gridded_subdata.filled(fill_value=0)
+    
+#    # WITHOUT MASKING OF THE CENTER:
+#    for i, z in tqdm(enumerate(zs), total=len(zs)):
+#        subdata = data[data[:, 2] == z, :]
+#        for j in range(3):  # For all 3 components!
+#            gridded_subdata = griddata(subdata[:, 0], subdata[:, 1], subdata[:, 3 + j], o, p)
+#            magnitude[j, i, :, :] = gridded_subdata.filled(fill_value=0)
+
+    # Creating MagData object:
+    mag_data = MagData(0.2*10, magnitude)
+    mag_data.save_to_netcdf4(PATH+'.nc')
+    log.info('MagData created!')
+else:
+    log.info('Loading MagData!')
+    mag_data = MagData.load_from_netcdf4(PATH+'.nc')
+    log.info('Loading complete!')
+mag_data.quiver_plot()
+
+projector = SimpleProjector(mag_data.dim)
+phasemapper = PMAdapterFM(mag_data.a, projector)
+phase_map = phasemapper(mag_data)
+(-phase_map).display_combined(title=r'Combined Plot (B$_0$={} T, Cos x {})'.format(b_0, gain),
+                              density=gain)
+plt.savefig(PATH+'_{}T_cosx{}.png'.format(b_0, gain))
+(-phase_map).display_combined(title=r'Combined Plot (B$_0$={} T, Cos x {})'.format(b_0, gain),
+                              density=gain, interpolation='bilinear')
+plt.savefig(PATH+'_{}T_cosx{}_smooth.png'.format(b_0, gain))
diff --git a/scripts/vtk_interpolation.py b/scripts/vtk_interpolation.py
new file mode 100644
index 0000000000000000000000000000000000000000..3fea0932818f62bbbece6b4fb96151dfe1b6e860
--- /dev/null
+++ b/scripts/vtk_interpolation.py
@@ -0,0 +1,73 @@
+# -*- coding: utf-8 -*-
+"""
+Created on Fri Jan 17 13:09:08 2014
+
+@author: Jan
+"""
+
+from pylab import *
+import pickle
+from tqdm import tqdm
+from pyramid.magdata import MagData
+
+with open("vtk_to_numpy.pickle") as pf:
+    data = pickle.load(pf)
+zs =  unique(data[:,2])
+
+axis = plt.figure().add_subplot(1, 1, 1)
+axis.scatter(data[:, 0], data[:, 1])
+plt.show()
+
+# # regular grid
+xs = linspace(-8.5*2, 8.5*2, 256)
+ys = linspace(-9.5*2, 9.5*2, 256)
+
+o, p = meshgrid(xs, ys)
+
+newdata = zeros((len(xs), len(ys), len(zs), data.shape[1] - 3))
+
+
+## WITH MASKING OF THE CENTER:
+#
+#iz_x = concatenate([linspace(-4.95, -4.95, 50),
+#                    linspace(-4.95, 0, 50),
+#                    linspace(0, 4.95, 50),
+#                    linspace(4.95, 4.95, 50),
+#                    linspace(-4.95, 0, 50),
+#                    linspace(0, 4.95, 50),])
+#iz_y = concatenate([linspace(-2.88,  2.88, 50),
+#                    linspace(2.88,  5.7, 50),
+#                    linspace(5.7,  2.88, 50),
+#                    linspace(2.88, -2.88, 50),
+#                    linspace(-2.88,  -5.7, 50),
+#                    linspace(-5.7,  -2.88, 50), ])
+#
+#
+#for i, z in tqdm(enumerate(zs), total=len(zs)):
+#    subdata = data[data[:, 2] == z, :]
+#
+#    for j in range(newdata.shape[-1]):
+#        gridded_subdata = griddata(concatenate([subdata[:, 0], iz_x]),
+#        concatenate([subdata[:, 1], iz_y]), concatenate([subdata[:, 3 + j],
+#        zeros(len(iz_x))]), o, p)
+#        newdata[:, :, i, j] = gridded_subdata.filled(fill_value=0)
+
+
+# WITHOUT MASKING OF THE CENTER:
+
+
+for i, z in tqdm(enumerate(zs), total=len(zs)):
+    subdata = data[data[:, 2] == z, :]
+
+    for j in range(3):  # For all 3 components!
+        gridded_subdata = griddata(subdata[:, 0], subdata[:, 1], subdata[:, 3 + j], o, p)
+        newdata[:, :, i, j] = gridded_subdata.filled(fill_value=0)
+
+
+magnitude = newdata.swapaxes(0,3).swapaxes(1,2).swapaxes(2,3)
+
+mag_data = MagData(1., magnitude)
+
+mag_data.quiver_plot()
+
+mag_data.save_to_netcdf4('vtk_mag_data.nc')
diff --git a/scripts/vtk_to_numpy.py b/scripts/vtk_to_numpy.py
new file mode 100644
index 0000000000000000000000000000000000000000..0e88286be7740c90bcfff944ce843058647fd6b0
--- /dev/null
+++ b/scripts/vtk_to_numpy.py
@@ -0,0 +1,74 @@
+# -*- coding: utf-8 -*-
+"""
+Created on Tue Jan 14 10:06:42 2014
+
+@author: Jan
+"""
+
+
+import numpy as np
+import vtk
+#import netCDF4
+import logging
+import sys
+
+import pickle
+
+logging.basicConfig(level=logging.INFO, format='%(levelname)s: %(message)s', stream=sys.stdout)
+log = logging.getLogger(__name__)
+
+reader = vtk.vtkDataSetReader()
+reader.SetFileName('irect_500x125x3.vtk')
+reader.ReadAllScalarsOn()
+reader.ReadAllVectorsOn()
+reader.Update()
+
+output = reader.GetOutput()
+size = output.GetNumberOfPoints()
+
+vtk_points = output.GetPoints().GetData()
+vtk_vectors = output.GetPointData().GetVectors()
+
+point_array = np.zeros(vtk_points.GetSize())
+vtk_points.ExportToVoidPointer(point_array)
+point_array = np.reshape(point_array, (-1, 3))
+
+vector_array = np.zeros(vtk_points.GetSize())
+vtk_vectors.ExportToVoidPointer(vector_array)
+vector_array = np.reshape(vector_array, (-1, 3))
+
+data = np.hstack((point_array, vector_array))
+
+log.info('Data reading complete!')
+
+#magfile = netCDF4.Dataset('tube_90x30x30.nc', 'w', format='NETCDF3_64BIT')
+#magfile.createDimension('comp', 6)  # Number of components
+#magfile.createDimension('size', size)
+#
+#x = magfile.createVariable('x', 'f8', ('size'))
+#y = magfile.createVariable('y', 'f8', ('size'))
+#z = magfile.createVariable('z', 'f8', ('size'))
+#x_mag = magfile.createVariable('x_mag', 'f8', ('size'))
+#y_mag = magfile.createVariable('y_mag', 'f8', ('size'))
+#z_mag = magfile.createVariable('z_mag', 'f8', ('size'))
+#
+#log.info('Start saving data separately!')
+#x = data[:, 0]
+#y = data[:, 1]
+#z = data[:, 2]
+#x_mag = data[:, 3]
+#y_mag = data[:, 4]
+#z_mag = data[:, 5]
+#log.info('Separate saving complete!')
+#
+#log.info('Try saving the whole array!')
+#filedata = magfile.createVariable('data', 'f8', ('size', 'comp'))
+#filedata[:, :] = data
+#log.info('Saving complete!')
+#
+#magfile.close()
+
+log.info('Pickling data!')
+with open('vtk_to_numpy.pickle', 'w') as pf:
+    pickle.dump(data, pf)
+log.info('Pickling complete!')
diff --git a/setup.py b/setup.py
index 9d9a4eacea61b3ba19b275ce7926d0805790c8a5..42a2f1533583357e894421329f96539c3cc402c6 100644
--- a/setup.py
+++ b/setup.py
@@ -67,7 +67,7 @@ setup(
 
       ext_package = 'pyramid/numcore',
       ext_modules = [
-          Extension('phase_mag_real', ['pyramid/numcore/phase_mag_real.pyx'],
+          Extension('kernel_core', ['pyramid/numcore/kernel_core.pyx'],
                     include_dirs = [numpy.get_include(), numpy.get_numarray_include()],
                     extra_compile_args=['-march=native', '-mtune=native']
                     )
diff --git a/tests/test_costfunction.py b/tests/test_costfunction.py
new file mode 100644
index 0000000000000000000000000000000000000000..0d06db5a44c2d20495f245c33734ea03ed755e20
--- /dev/null
+++ b/tests/test_costfunction.py
@@ -0,0 +1,7 @@
+# -*- coding: utf-8 -*-
+"""
+Created on Mon Jan 20 20:01:25 2014
+
+@author: Jan
+"""
+
diff --git a/tests/test_datacollection.py b/tests/test_datacollection.py
new file mode 100644
index 0000000000000000000000000000000000000000..ebe232287a5eb502750dbd04f7b8931cea061c49
--- /dev/null
+++ b/tests/test_datacollection.py
@@ -0,0 +1,7 @@
+# -*- coding: utf-8 -*-
+"""
+Created on Mon Jan 20 19:58:01 2014
+
+@author: Jan
+"""
+
diff --git a/tests/test_forwardmodel.py b/tests/test_forwardmodel.py
new file mode 100644
index 0000000000000000000000000000000000000000..5bd1ef1c2e5abd3ffa129b8c99a8d2ed1ad25a3b
--- /dev/null
+++ b/tests/test_forwardmodel.py
@@ -0,0 +1,7 @@
+# -*- coding: utf-8 -*-
+"""
+Created on Mon Jan 20 20:01:13 2014
+
+@author: Jan
+"""
+
diff --git a/tests/test_holoimage.py b/tests/test_holoimage.py
deleted file mode 100644
index 2680ef1ca999fa733876863edd6ec654904127b2..0000000000000000000000000000000000000000
--- a/tests/test_holoimage.py
+++ /dev/null
@@ -1,44 +0,0 @@
-# -*- coding: utf-8 -*-
-"""Testcase for the holoimage module."""
-
-
-import os
-import unittest
-import numpy as np
-from numpy import pi
-
-from pyramid.phasemap import PhaseMap
-import pyramid.holoimage as hi
-
-
-class TestCaseHoloImage(unittest.TestCase):
-
-    def setUp(self):
-        self.path = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'test_holoimage')
-        phase = np.zeros((4, 4))
-        phase[1:-1, 1:-1] = pi/4
-        self.phase_map = PhaseMap(10.0, phase)
-
-    def tearDown(self):
-        self.path = None
-        self.phase_map = None
-
-    def test_holo_image(self):
-        img = hi.holo_image(self.phase_map)
-        arr = np.array(img.getdata(), np.uint8).reshape(img.size[1], img.size[0], 3)
-        holo_img_r, holo_img_g, holo_img_b = arr[..., 0], arr[..., 1], arr[..., 2]
-        ref_holo_img_r = np.loadtxt(os.path.join(self.path, 'ref_holo_img_r.txt'))
-        ref_holo_img_g = np.loadtxt(os.path.join(self.path, 'ref_holo_img_g.txt'))
-        ref_holo_img_b = np.loadtxt(os.path.join(self.path, 'ref_holo_img_b.txt'))
-        hi.display(img)
-        np.testing.assert_equal(holo_img_r, ref_holo_img_r,
-                                'Unexpected behavior in holo_image() (r-component)!')
-        np.testing.assert_equal(holo_img_g, ref_holo_img_g,
-                                'Unexpected behavior in holo_image() (g-component)!')
-        np.testing.assert_equal(holo_img_b, ref_holo_img_b,
-                                'Unexpected behavior in holo_image() (b-component)!')
-
-
-if __name__ == '__main__':
-    suite = unittest.TestLoader().loadTestsFromTestCase(TestCaseHoloImage)
-    unittest.TextTestRunner(verbosity=2).run(suite)
diff --git a/tests/test_holoimage/ref_holo_img_b.txt b/tests/test_holoimage/ref_holo_img_b.txt
deleted file mode 100644
index fe1fcf2e95f700820ecec28f6f0a4995868f096b..0000000000000000000000000000000000000000
--- a/tests/test_holoimage/ref_holo_img_b.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00
-0.000000000000000000e+00 0.000000000000000000e+00 9.700000000000000000e+01 2.550000000000000000e+02
-0.000000000000000000e+00 0.000000000000000000e+00 1.000000000000000000e+02 2.550000000000000000e+02
-0.000000000000000000e+00 3.000000000000000000e+00 3.000000000000000000e+00 0.000000000000000000e+00
diff --git a/tests/test_holoimage/ref_holo_img_g.txt b/tests/test_holoimage/ref_holo_img_g.txt
deleted file mode 100644
index a4a674dfa22150e448ee4b39702d3fc8ee85cdcc..0000000000000000000000000000000000000000
--- a/tests/test_holoimage/ref_holo_img_g.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-0.000000000000000000e+00 1.000000000000000000e+00 1.000000000000000000e+00 0.000000000000000000e+00
-2.550000000000000000e+02 9.900000000000000000e+01 0.000000000000000000e+00 0.000000000000000000e+00
-2.550000000000000000e+02 1.950000000000000000e+02 9.500000000000000000e+01 0.000000000000000000e+00
-0.000000000000000000e+00 2.520000000000000000e+02 2.520000000000000000e+02 0.000000000000000000e+00
diff --git a/tests/test_holoimage/ref_holo_img_r.txt b/tests/test_holoimage/ref_holo_img_r.txt
deleted file mode 100644
index 7373e5e22f2ec6849bdad2beb44f6847cf8988d2..0000000000000000000000000000000000000000
--- a/tests/test_holoimage/ref_holo_img_r.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-0.000000000000000000e+00 2.550000000000000000e+02 2.550000000000000000e+02 0.000000000000000000e+00
-2.530000000000000000e+02 1.950000000000000000e+02 9.800000000000000000e+01 0.000000000000000000e+00
-2.530000000000000000e+02 9.500000000000000000e+01 0.000000000000000000e+00 0.000000000000000000e+00
-0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00
diff --git a/tests/test_kernel.py b/tests/test_kernel.py
new file mode 100644
index 0000000000000000000000000000000000000000..b4fa9e47e440c1c220f9ea0fa8aff9f473ecb26c
--- /dev/null
+++ b/tests/test_kernel.py
@@ -0,0 +1,7 @@
+# -*- coding: utf-8 -*-
+"""
+Created on Mon Jan 20 20:00:50 2014
+
+@author: Jan
+"""
+
diff --git a/tests/test_reconstructor.py b/tests/test_optimize.py
similarity index 100%
rename from tests/test_reconstructor.py
rename to tests/test_optimize.py