From ec0809400be1a23400bfedfa54e0a1271e8cd13d Mon Sep 17 00:00:00 2001
From: Jan Caron <j.caron@fz-juelich.de>
Date: Tue, 11 Mar 2014 10:01:45 +0100
Subject: [PATCH] First simple reconstruction approach documentation: minor
 changes and updates of docstrings

---
 pyramid/__init__.py                           |   2 +-
 pyramid/costfunction.py                       |  15 +-
 pyramid/datacollection.py                     |  31 ++--
 pyramid/forwardmodel.py                       |  31 +++-
 pyramid/kernel.py                             |  46 +++--
 pyramid/logfile.log                           |   0
 pyramid/optimizer.py                          |  15 +-
 pyramid/phasemap.py                           |  43 ++---
 pyramid/phasemapper.py                        |  52 +++---
 pyramid/projector.py                          |  75 ++++++--
 scripts/edinburgh_test.py                     |   2 +-
 scripts/images_poster.py                      | 112 +++++++-----
 scripts/logfile.log                           |   1 -
 .../ch5-4-comparison_of_methods_new.py        |   4 +-
 scripts/paper 1/logfile.log                   | 169 +++++++++--------
 scripts/simple_phasemapping.py                |   2 +-
 scripts/simple_reconstruction.py              | 171 ++++++++++++++++++
 scripts/test_projection.py                    |  68 +++++++
 18 files changed, 588 insertions(+), 251 deletions(-)
 create mode 100644 pyramid/logfile.log
 create mode 100644 scripts/simple_reconstruction.py
 create mode 100644 scripts/test_projection.py

diff --git a/pyramid/__init__.py b/pyramid/__init__.py
index 8d25565..2316e34 100644
--- a/pyramid/__init__.py
+++ b/pyramid/__init__.py
@@ -8,7 +8,7 @@ magcreator
 magdata
     Class for the storage of magnetization data.
 projector
-    Class for projections of given magnetization distribution.
+    Class for projecting given magnetization distributions.
 kernel
     Class for the kernel matrix representing one magnetized pixel.
 phasemapper
diff --git a/pyramid/costfunction.py b/pyramid/costfunction.py
index 6201f91..811a2a9 100644
--- a/pyramid/costfunction.py
+++ b/pyramid/costfunction.py
@@ -26,20 +26,29 @@ class Costfunction:
         y = self.y
         F = self.F
         Se_inv = self.Se_inv
-        return (F(x)-y).dot(Se_inv.dot(F(x)-y))
+#        print 'Costfunction - __call__ - input: ', len(x)
+        result = (F(x)-y).dot(Se_inv.dot(F(x)-y))
+#        print 'Costfunction - __call__ - output:', result
+        return result
 
     def jac(self, x):
         # TODO: Docstring!
         y = self.y
         F = self.F
         Se_inv = self.Se_inv
-        return F.jac_T_dot(x, (Se_inv.dot(F(x)-y)))
+#        print 'Costfunction - jac - input: ', len(x)
+        result = F.jac_T_dot(x, Se_inv.dot(F(x)-y))
+#        print 'Costfunction - jac - output:', len(result)
+        return result
 
     def hess_dot(self, x, vector):
         # TODO: Docstring!
         F = self.F
         Se_inv = self.Se_inv
-        return F.jac_T_dot(x, Se_inv.dot(F.jac_dot(x, vector)))
+#        print 'Costfunction - hess_dot - input: ', len(vector)
+        result = F.jac_T_dot(x, Se_inv.dot(F.jac_dot(x, vector)))
+#        print 'Costfunction - hess_dot - output:', len(result)
+        return result
         # TODO: Murks!
 
 
diff --git a/pyramid/datacollection.py b/pyramid/datacollection.py
index 54d0371..496173e 100644
--- a/pyramid/datacollection.py
+++ b/pyramid/datacollection.py
@@ -17,8 +17,8 @@ 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.
+    :class:`~.PhaseMap` objects and corresponding projectors stored as :class:`~.Projector`
+    objects. At creation, the grid spacing `a` and the dimension `dim_uv` 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.
 
@@ -26,7 +26,7 @@ class DataCollection(object):
     ----------
     a: float
         The grid spacing in nm.
-    dim: tuple (N=2)
+    dim_uv: tuple (N=2)
         Dimensions of the projected grid.
     phase_maps:
         A list of all stored :class:`~.PhaseMap` objects.
@@ -42,8 +42,8 @@ class DataCollection(object):
         return self._a
     
     @property
-    def dim(self):
-        return self._dim
+    def dim_uv(self):
+        return self._dim_uv
 
     @property
     def phase_vec(self):
@@ -57,25 +57,28 @@ class DataCollection(object):
     def projectors(self):
         return [d[1] for d in self.data]
 
-    def __init__(self, a, dim):
+    def __init__(self, a, dim_uv, b_0):
         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
-        assert isinstance(dim, tuple) and len(dim)==2, 'Dimension has to be a tuple of length 2!'
+        assert isinstance(dim_uv, tuple) and len(dim_uv)==2, \
+            'Dimension has to be a tuple of length 2!'
         assert np.all([])
-        self.dim = dim
+        self._dim_uv = dim_uv
+        self.b_0 = b_0
         self.data = []
+        # TODO: make it work
+#        self.log.info('Created:', str(self))
 
     def __repr__(self):
         self.log.info('Calling __repr__')
-        return '%s(a=%r, dim=%r)' % (self.__class__, self.a, self.dim)
+        return '%s(a=%r, dim_uv=%r)' % (self.__class__, self.a, self.dim_uv)
 
     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))
+        return 'DataCollection(%s, a=%s, dim_uv=%s, data_count=%s)' % \
+            (self.__class__, self.a, self.dim_uv, len(self.data))
 
     def append(self, (phase_map, projector)):
         '''Appends a data pair of phase map and projection infos to the data collection.`
@@ -94,6 +97,6 @@ class DataCollection(object):
         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!'
-        assert (projector.dim_v, projector.dim_u) == self.dim, 'Projector dimensions must match!'
+        assert phase_map.dim_uv == self.dim_uv, 'Added phasemap must have the same dimension!'
+        assert projector.dim_uv == self.dim_uv, 'Projector dimensions must match!'
         self.data.append((phase_map, projector))
diff --git a/pyramid/forwardmodel.py b/pyramid/forwardmodel.py
index 89d1d7a..c231829 100644
--- a/pyramid/forwardmodel.py
+++ b/pyramid/forwardmodel.py
@@ -17,7 +17,7 @@ class ForwardModel:
     @property
     def projectors(self):
         return self._projectors
-    
+
     @projectors.setter
     def projectors(self, projectors):
         assert np.all([isinstance(projector, Projector) for projector in projectors]), \
@@ -33,27 +33,42 @@ class ForwardModel:
         assert isinstance(kernel, Kernel), 'A Kernel object has to be provided!'
         self._kernel = kernel
 
-    def __init__(self,projectors, kernel):
+    def __init__(self, projectors, kernel, b_0):
         # TODO: Docstring!
         self.kernel = kernel
-        self.b_0 = kernel.b_0
+        self.b_0 = b_0
         self.a = kernel.a
-        self.dim = kernel.dim
+        self.dim_uv = kernel.dim_uv
         self.projectors = projectors
 
     def __call__(self, x):
         # TODO: Docstring!
+#        print 'FWD Model - __call__ -  input: ', len(x)
         result = [self.kernel.jac_dot(projector.jac_dot(x)) for projector in self.projectors]
-        return np.reshape(result, -1)
+        result = self.b_0 * np.reshape(result, -1)
+#        print 'FWD Model - __call__ -  output:', len(result)
+        return result
 
     # TODO: jac_dot ausschreiben!!!
 
     def jac_dot(self, x, vector):
         # TODO: Docstring! multiplication with the jacobi-matrix (may depend on x)
-        return self(vector)  # The jacobi-matrix does not depend on x in a linear problem
+#        print 'FWD Model - jac_dot - input: ', len(vector)
+        result = self(vector)
+#        print 'FWD Model - jac_dot - output:', len(result)
+        return result  # The jacobi-matrix does not depend on x in a linear problem
     
     def jac_T_dot(self, x, vector):
         # TODO: Docstring! multiplication with the jacobi-matrix (may depend on x)
         # The jacobi-matrix does not depend on x in a linear problem
-        result = [projector.jac_T_dot(self.kernel.jac_T_dot(x)) for projector in self.projectors]
-        return np.reshape(result, -1)
+#        print 'FWD Model - jac_T_dot - input: ', len(vector)
+        size_3d = self.projectors[0].size_3d
+        size_2d = np.prod(self.dim_uv)
+        result = np.zeros(3*size_3d)
+        for (i, projector) in enumerate(self.projectors):
+            result += projector.jac_T_dot(self.kernel.jac_T_dot(vector[i*size_2d:(i+1)*size_2d]))
+#        result = [projector.jac_T_dot(self.kernel.jac_T_dot(vector[i*size_2d:(i+1)*size_2d]))
+#                  for (i, projector) in enumerate(self.projectors)]
+        result = np.reshape(result, -1)
+#        print 'FWD Model - jac_T_dot - output:', len(result)
+        return result
diff --git a/pyramid/kernel.py b/pyramid/kernel.py
index b8653e3..0ce1963 100644
--- a/pyramid/kernel.py
+++ b/pyramid/kernel.py
@@ -51,14 +51,12 @@ class Kernel(object):
 
     Attributes
     ----------
-    dim : tuple (N=2)
+    dim_uv : tuple (N=2)
         Dimensions of the projected magnetization grid.
     a : float
         The grid spacing in nm.
     geometry : {'disc', 'slab'}, optional
         The elementary geometry of the single magnetized pixel.
-    b_0 : float, optional
-        The saturation magnetic induction. Default is 1.
     u : :class:`~numpy.ndarray` (N=3)
         The phase contribution of one pixel magnetized in u-direction.
     v : :class:`~numpy.ndarray` (N=3)
@@ -69,7 +67,8 @@ class Kernel(object):
         The real FFT of the phase contribution of one pixel magnetized in v-direction.
     dim_fft : tuple (N=2)
         Dimensions of the grid, which is used for the FFT. Calculated by adding the dimensions
-        `dim` of the magnetization grid and the dimensions of the kernel (given by ``2*dim-1``)
+        `dim_uv` of the magnetization grid and the dimensions of the kernel (given by
+        ``2*dim_uv-1``)
         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
@@ -77,24 +76,21 @@ class Kernel(object):
 
     '''# TODO: Can be used for several PhaseMappers via the fft arguments or via calling!
     
-    def __init__(self, a, dim, b_0=1, numcore=True, geometry='disc'):
+    def __init__(self, a, dim_uv, numcore=True, geometry='disc'):
         '''Constructor for a :class:`~.Kernel` object for representing a kernel matrix.
 
         Parameters
         ----------
         a : float
             The grid spacing in nm.
-        dim : tuple (N=2)
+        dim_uv : tuple (N=2)
             Dimensions of the projected magnetization grid.
-        b_0 : float, optional
-            The saturation magnetic induction. Default is 1.
         geometry : {'disc', 'slab'}, optional
             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):
             if geometry == 'disc':
@@ -108,23 +104,22 @@ class Kernel(object):
                 return 0.5 * (F_a(n-0.5, m-0.5) - F_a(n+0.5, m-0.5)
                             - F_a(n-0.5, m+0.5) + F_a(n+0.5, m+0.5))
         # Set basic properties:
-        self.dim = dim  # !!! size of the FOV, not the kernel (kernel is bigger)!
+        self.dim_uv = dim_uv  # !!! size of the FOV, not the kernel (kernel is bigger)!
         self.a = a
         self.numcore = numcore
         self.geometry = geometry
-        self.b_0 = b_0
         # Calculate kernel (single pixel phase):
-        coeff = -a**2 * b_0 / (2*PHI_0)
-        v_dim, u_dim = dim
+        coeff = -a**2 / (2*PHI_0)
+        v_dim, u_dim = dim_uv
         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)
         uu, vv = np.meshgrid(u, v)
         self.u = coeff * get_elementary_phase(geometry, uu, vv, a)
         self.v = coeff * get_elementary_phase(geometry, vv, uu, a)
         # Calculate Fourier trafo of kernel components:
-        dim_combined = 3*np.array(dim) - 1  # dim + (2*dim - 1) magnetisation + kernel
+        dim_combined = 3*np.array(dim_uv) - 1  # dim_uv + (2*dim_uv - 1) magnetisation + kernel
         self.dim_fft = 2 ** np.ceil(np.log2(dim_combined)).astype(int)  # next multiple of 2
-        self.slice_fft = (slice(dim[0]-1, 2*dim[0]-1), slice(dim[1]-1, 2*dim[1]-1))
+        self.slice_fft = (slice(dim_uv[0]-1, 2*dim_uv[0]-1), slice(dim_uv[1]-1, 2*dim_uv[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))
@@ -132,6 +127,7 @@ class Kernel(object):
     def __call__(self, x):
         '''Test'''
         self.log.info('Calling __call__')
+#        print 'Kernel - __call__:', len(x)
         if self.numcore:
             return self._multiply_jacobi_core(x)
         else:
@@ -140,12 +136,13 @@ class Kernel(object):
 
     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)
+        return '%s(a=%r, dim_uv=%r, numcore=%r, geometry=%r)' % \
+            (self.__class__, self.a, self.dim_uv, self.numcore, self.geometry)
 
     def jac_dot(self, vector):
         '''TEST'''# TODO: Docstring
         self.log.info('Calling jac_dot')
+#        print 'Kernel - jac_dot:', len(vector)
         if self.numcore:
             return self._multiply_jacobi_core(vector)
         else:
@@ -154,6 +151,7 @@ class Kernel(object):
     def jac_T_dot(self, vector):
         # TODO: Docstring
         self.log.info('Calling jac_dot_T')
+#        print 'Kernel - jac_T_dot:', len(vector)
         return self._multiply_jacobi_T(vector)
 
     def _multiply_jacobi(self, vector):
@@ -173,8 +171,8 @@ class Kernel(object):
 
         '''# TODO: move!
         self.log.info('Calling _multiply_jacobi')
-        v_dim, u_dim = self.dim
-        size = v_dim * u_dim
+        v_dim, u_dim = self.dim_uv
+        size = np.prod(self.dim_uv)
         assert len(vector) == 2*size, 'vector size not compatible!'
         result = np.zeros(size)
         for s in range(size):  # column-wise (two columns at a time, u- and v-component)
@@ -206,9 +204,9 @@ class Kernel(object):
 
         '''# 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!'
+        v_dim, u_dim = self.dim_uv
+        size = np.prod(self.dim_uv)
+        assert len(vector) == size, 'vector size not compatible! vector: {}, size: {}'.format(len(vector),size)
         result = np.zeros(2*size)
         for s in range(size):  # row-wise (two rows at a time, u- and v-component)
             i = s % u_dim
@@ -223,6 +221,6 @@ class Kernel(object):
 
     def _multiply_jacobi_core(self, vector):
         self.log.info('Calling _multiply_jacobi_core')
-        result = np.zeros(np.prod(self.dim))
-        core.multiply_jacobi_core(self.dim[0], self.dim[1], self.u, self.v, vector, result)
+        result = np.zeros(np.prod(self.dim_uv))
+        core.multiply_jacobi_core(self.dim_uv[0], self.dim_uv[1], self.u, self.v, vector, result)
         return result
diff --git a/pyramid/logfile.log b/pyramid/logfile.log
new file mode 100644
index 0000000..e69de29
diff --git a/pyramid/optimizer.py b/pyramid/optimizer.py
index ca22601..f45546e 100644
--- a/pyramid/optimizer.py
+++ b/pyramid/optimizer.py
@@ -34,21 +34,24 @@ from pyramid.magdata import MagData
 
 
 
-def optimize_cg(self, data_collection, first_guess):
+def optimize_cg(data_collection, first_guess):
     # TODO: where should data_collection and first_guess go? here or __init__?
-    data = data_collection
+    data = data_collection  # TODO: name the parameter 'data' directly...
     mag_0 = first_guess
     x_0 = first_guess.mag_vec
     y = data.phase_vec
-    kern = Kernel(data.dim, data.a, data.b_0)
-    F = ForwardModel(data, kern)
+    kern = Kernel(data.a, data.dim_uv)
+    F = ForwardModel(data.projectors, kern, data.b_0)
     C = Costfunction(y, F)
 
-    result = minimize(C, x_0, method='CG', jac=C.jac, hessp=C.hess_dot)
+    result = minimize(C, x_0, method='Newton-CG', jac=C.jac, hessp=C.hess_dot,
+                      options={'maxiter':200, 'disp':True})
 
     x_opt = result.x
 
-    mag_opt = MagData(mag_0.a, np.zeros((3,)+mag_0.dim)).mag_vec = x_opt
+    mag_opt = MagData(mag_0.a, np.zeros((3,)+mag_0.dim))
+    
+    mag_opt.mag_vec = x_opt
 
     return mag_opt
 
diff --git a/pyramid/phasemap.py b/pyramid/phasemap.py
index 293dd63..be2b294 100644
--- a/pyramid/phasemap.py
+++ b/pyramid/phasemap.py
@@ -38,7 +38,7 @@ class PhaseMap(object):
     ----------
     a: float
         The grid spacing in nm.
-    dim: tuple (N=2)
+    dim_uv: tuple (N=2)
         Dimensions of the grid.
     phase: :class:`~numpy.ndarray` (N=2)
         Matrix containing the phase shift.
@@ -107,8 +107,8 @@ class PhaseMap(object):
         self._a = a
     
     @property
-    def dim(self):
-        return self._dim
+    def dim_uv(self):
+        return self._dim_uv
 
     @property
     def phase(self):
@@ -119,7 +119,7 @@ class PhaseMap(object):
         assert isinstance(phase, np.ndarray), 'Phase has to be a numpy array!'
         assert len(phase.shape) == 2, 'Phase has to be 2-dimensional!'
         self._phase = phase
-        self._dim = phase.shape
+        self._dim_uv = phase.shape
 
     @property
     def phase_vec(self):
@@ -128,8 +128,8 @@ class PhaseMap(object):
     @phase_vec.setter
     def phase_vec(self, phase_vec):
         assert isinstance(phase_vec, np.ndarray), 'Vector has to be a numpy array!'
-        assert np.size(phase_vec) == np.prod(self.dim), 'Vector size has to match phase!'
-        self.phase = phase_vec.reshape(self.dim)
+        assert np.size(phase_vec) == np.prod(self.dim_uv), 'Vector size has to match phase!'
+        self.phase = phase_vec.reshape(self.dim_uv)
 
     @property
     def unit(self):
@@ -154,7 +154,7 @@ class PhaseMap(object):
 
     def __str__(self):
         self.log.info('Calling __str__')
-        return 'PhaseMap(a=%s, dim=%s)' % (self.a, self.dim)
+        return 'PhaseMap(a=%s, dim_uv=%s)' % (self.a, self.dim_uv)
 
     def __neg__(self):  # -self
         self.log.info('Calling __neg__')
@@ -167,7 +167,7 @@ class PhaseMap(object):
         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, \
+            assert other.phase.shape == self.dim_uv, \
                 'Added magnitude has to have the same dimensions!'
             return PhaseMap(self.a, self.phase+other.phase, self.unit)
         else:  # other is a Number
@@ -266,8 +266,8 @@ class PhaseMap(object):
         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])
-        phase_file.createDimension('u_dim', self.dim[1])
+        phase_file.createDimension('v_dim', self.dim_uv[0])
+        phase_file.createDimension('u_dim', self.dim_uv[1])
         phase = phase_file.createVariable('phase', 'f', ('v_dim', 'u_dim'))
         phase[:] = self.phase
         phase_file.close()
@@ -334,8 +334,8 @@ class PhaseMap(object):
         # Plot the phasemap:
         im = axis.pcolormesh(phase, cmap=cmap, vmin=-limit, vmax=limit, norm=norm)
         # Set the axes ticks and labels:
-        axis.set_xlim(0, self.dim[1])
-        axis.set_ylim(0, self.dim[0])
+        axis.set_xlim(0, self.dim_uv[1])
+        axis.set_ylim(0, self.dim_uv[0])
         axis.xaxis.set_major_locator(MaxNLocator(nbins=9, integer=True))
         axis.yaxis.set_major_locator(MaxNLocator(nbins=9, integer=True))
         axis.xaxis.set_major_formatter(FuncFormatter(lambda x, pos: '{:g}'.format(x*self.a)))
@@ -381,8 +381,8 @@ class PhaseMap(object):
         fig = plt.figure()
         axis = Axes3D(fig)
         # Plot surface and contours:
-        u = range(self.dim[1])
-        v = range(self.dim[0])
+        u = range(self.dim_uv[1])
+        v = range(self.dim_uv[0])
         uu, vv = np.meshgrid(u, v)
         axis.plot_surface(uu, vv, phase, rstride=4, cstride=4, alpha=0.7, cmap=cmap,
                         linewidth=0, antialiased=False)
@@ -458,8 +458,8 @@ class PhaseMap(object):
         axis.set_title(title, fontsize=18)
         axis.set_xlabel('x-axis [px]', fontsize=15)
         axis.set_ylabel('y-axis [px]', fontsize=15)
-        axis.set_xlim(0, self.dim[1])
-        axis.set_ylim(0, self.dim[0])
+        axis.set_xlim(0, self.dim_uv[1])
+        axis.set_ylim(0, self.dim_uv[0])
         axis.xaxis.set_major_locator(MaxNLocator(nbins=9, integer=True))
         axis.yaxis.set_major_locator(MaxNLocator(nbins=9, integer=True))
         # Show Plot:
@@ -467,9 +467,9 @@ class PhaseMap(object):
             plt.show()
         # Return plotting axis:
         return axis
-    
-    def display_combined(self, density=1, title='Combined Plot', interpolation='none',
-                         grad_encode='dark'):
+
+    def display_combined(self, title='Combined Plot', cmap='RdBu', limit=None, norm=None,
+                         density=1, interpolation='none', grad_encode='dark'):
         '''Display the phase map and the resulting color coded holography image in one plot.
     
         Parameters
@@ -499,7 +499,7 @@ class PhaseMap(object):
         # 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, show=False)
+        self.display_phase(cmap='RdBu', limit=limit, norm=norm, axis=phase_axis, show=False)
         plt.show()
         # Return the plotting axes:
         return phase_axis, holo_axis
@@ -537,6 +537,3 @@ class PhaseMap(object):
         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 772e6fa..4501e37 100644
--- a/pyramid/phasemapper.py
+++ b/pyramid/phasemapper.py
@@ -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_2d, b_0, geometry))
+        self.fwd_model = ForwardModel([projector], Kernel(a, projector.dim_uv, geometry), b_0)
 
     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_2d))
+        phase_map = PhaseMap(self.a, np.zeros(self.projector.dim_uv))
         phase_map.phase_vec = self.fwd_model(mag_data.mag_vec)
         return phase_map
 
@@ -94,8 +94,8 @@ 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_2d
-        u_mag, v_mag = self.projector(mag_data.mag_vec).reshape((2,)+self.projector.dim_2d)
+        v_dim, u_dim = self.projector.dim_uv
+        u_mag, v_mag = self.projector(mag_data.mag_vec).reshape((2,)+self.projector.dim_uv)
         # Create zero padded matrices:
         u_pad = u_dim/2 * self.padding
         v_pad = v_dim/2 * self.padding
@@ -183,7 +183,7 @@ class PMElectric(PhaseMapper):
         # Calculate mask:
         mask = np.sqrt(np.sum(np.array(mag_data.magnitude)**2, axis=0)) > self.threshold
         # Project and calculate phase:
-        projection = self.projector(mask.reshape(-1)).reshape(self.projector.dim)
+        projection = self.projector(mask.reshape(-1)).reshape(self.projector.dim_uv)
         phase = v_0 * Ce * projection * self.a*1E-9
         return PhaseMap(self.a, phase)
 
@@ -200,14 +200,15 @@ class PMConvolve(PhaseMapper):
         a : float
             The grid spacing in nm.
         projection : tuple (N=3) of :class:`~numpy.ndarray` (N=2)
-            The in-plane projection of the magnetization as a tuple, storing the `u`- and `v`-component
-            of the magnetization and the thickness projection for the resulting 2D-grid.
+            The in-plane projection of the magnetization as a tuple, storing the `u`- and
+            `v`-component of the magnetization and the thickness projection for the resulting
+            2D-grid.
         b_0 : float, optional
             The magnetic induction corresponding to a magnetization `M`\ :sub:`0` in T.
             The default is 1.
         kernel : :class:`~pyramid.kernel.Kernel`, optional
-            Specifies the kernel for the convolution with the magnetization data. If none is specified,
-            one will be created with `disc` as the default geometry.
+            Specifies the kernel for the convolution with the magnetization data. If none is
+            specified, one will be created with `disc` as the default geometry.
 
         Returns
         -------
@@ -218,13 +219,14 @@ class PMConvolve(PhaseMapper):
         assert isinstance(projector, Projector), 'Argument has to be a Projector object!'
         self.a = a
         self.projector = projector
+        self.b_0 = b_0
         self.threshold = threshold
-        self.kernel = Kernel(a, projector.dim_2d, b_0, geometry)
+        self.kernel = Kernel(a, projector.dim_uv, 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_2d)    
+        u_mag, v_mag = self.projector(mag_data.mag_vec).reshape((2,)+self.projector.dim_uv)    
         # Fourier transform the projected magnetisation:
         kernel = self.kernel
         u_mag_fft = np.fft.rfftn(u_mag, kernel.dim_fft)
@@ -233,7 +235,7 @@ class PMConvolve(PhaseMapper):
         u_phase = np.fft.irfftn(u_mag_fft * kernel.u_fft, kernel.dim_fft)[kernel.slice_fft].copy()
         v_phase = np.fft.irfftn(v_mag_fft * kernel.v_fft, kernel.dim_fft)[kernel.slice_fft].copy()
         # Return the result:
-        return PhaseMap(self.a, u_phase - v_phase)
+        return PhaseMap(self.a, self.b_0*(u_phase-v_phase))
 
 
 class PMReal(PhaseMapper):
@@ -267,30 +269,34 @@ class PMReal(PhaseMapper):
         assert isinstance(projector, Projector), 'Argument has to be a Projector object!'
         self.a = a
         self.projector = projector
+        self.b_0 = b_0
         self.threshold = threshold
-        self.kernel = Kernel(a, projector.dim_2d, b_0, geometry)
+        self.kernel = Kernel(a, projector.dim_uv, geometry)
         self.numcore = numcore
 
     def __call__(self, mag_data):
         # TODO: Docstring
         # Process input parameters: 
-        dim = self.projector.dim_2d
+        dim_uv = self.projector.dim_uv
         threshold = self.threshold
-        u_mag, v_mag = self.projector(mag_data.mag_vec).reshape((2,)+dim)
+        u_mag, v_mag = self.projector(mag_data.mag_vec).reshape((2,)+dim_uv)
         # Create kernel (lookup-tables for the phase of one pixel):
-        u_phi = self.kernel.u
-        v_phi = self.kernel.v
+        u_phi = self.b_0 * self.kernel.u
+        v_phi = self.b_0 * self.kernel.v
         # Calculation of the phase:
-        phase = np.zeros(dim)
+        phase = np.zeros(dim_uv)
         if self.numcore:
-            nc.phase_mag_real_core(dim[0], dim[1], v_phi, u_phi, v_mag, u_mag, phase, threshold)
+            nc.phase_mag_real_core(dim_uv[0], dim_uv[1], v_phi, u_phi,
+                                   v_mag, u_mag, phase, threshold)
         else:
-            for j in range(dim[0]):
-                for i in range(dim[1]):
-                    u_phase = u_phi[dim[0]-1-j:(2*dim[0]-1)-j, dim[1]-1-i:(2*dim[1]-1)-i]
+            for j in range(dim_uv[0]):
+                for i in range(dim_uv[1]):
+                    u_phase = u_phi[dim_uv[0]-1-j:(2*dim_uv[0]-1)-j,
+                                    dim_uv[1]-1-i:(2*dim_uv[1]-1)-i]
                     if abs(u_mag[j, i]) > threshold:
                         phase += u_mag[j, i] * u_phase
-                    v_phase = v_phi[dim[0]-1-j:(2*dim[0]-1)-j, dim[1]-1-i:(2*dim[1]-1)-i]
+                    v_phase = v_phi[dim_uv[0]-1-j:(2*dim_uv[0]-1)-j,
+                                    dim_uv[1]-1-i:(2*dim_uv[1]-1)-i]
                     if abs(v_mag[j, i]) > threshold:
                         phase -= v_mag[j, i] * v_phase
         # Return the phase:
diff --git a/pyramid/projector.py b/pyramid/projector.py
index 85e8641..99b3e31 100644
--- a/pyramid/projector.py
+++ b/pyramid/projector.py
@@ -30,7 +30,7 @@ class Projector(object):
 
     Attributes
     ----------
-    dim_2d : tuple (N=2)
+    dim_uv : tuple (N=2)
         Dimensions (v, u) of the projected grid.
     size_3d : int
         Number of voxels of the 3-dimensional grid.
@@ -48,26 +48,19 @@ class Projector(object):
     __metaclass__ = abc.ABCMeta
 
     @abc.abstractmethod
-    def __init__(self, (dim_v, dim_u), weight, coeff):
+    def __init__(self, dim_uv, weight, coeff):
         self.log = logging.getLogger(__name__)
         self.log.info('Calling __init__')
-        self.dim_2d = (dim_v, dim_u)
+        self.dim_uv = dim_uv
         self.weight = weight
         self.coeff = coeff
         self.size_2d, self.size_3d = weight.shape
         self.log.info('Created '+str(self))
 
     def __call__(self, vector):
-        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)
-        else:
-            raise AssertionError('Vector size has to be suited either for ' \
-                                 'vector- or scalar-field-projection!')
+        self.log.info('Calling as function')
+#        print 'Projector - __call__:', len(vector)
+        return self.jac_dot(vector)
 
     def _vector_field_projection(self, vector):
         self.log.info('Calling _vector_field_projection')
@@ -79,19 +72,42 @@ class Projector(object):
         if self.coeff[0][1] != 0:  # y to u
             result[:size_2d] += self.coeff[0][1] * self.weight.dot(vector[size_3d:2*size_3d])
         if self.coeff[0][2] != 0:  # z to u
-            result[:size_2d] += self.coeff[0][2] * self.weight.dot(vector[2*size_3d])
+            result[:size_2d] += self.coeff[0][2] * self.weight.dot(vector[2*size_3d:])
         if self.coeff[1][0] != 0:  # x to v
             result[size_2d:] += self.coeff[1][0] * self.weight.dot(vector[:size_3d])
         if self.coeff[1][1] != 0:  # y to v
             result[size_2d:] += self.coeff[1][1] * self.weight.dot(vector[size_3d:2*size_3d])
         if self.coeff[1][2] != 0:  # z to v
-            result[size_2d:] += self.coeff[1][2] * self.weight.dot(vector[2*size_3d])
+            result[size_2d:] += self.coeff[1][2] * self.weight.dot(vector[2*size_3d:])
+        return result
+
+    def _vector_field_projection_T(self, vector):
+        self.log.info('Calling _vector_field_projection_T')
+        size_2d, size_3d = self.size_2d, self.size_3d
+        result = np.zeros(3*size_3d)
+        # Go over all possible component projections (z, y, x) to (u, v):
+        if self.coeff[0][0] != 0:  # x to u
+            result[:size_3d] += self.coeff[0][0] * self.weight.T.dot(vector[:size_2d])
+        if self.coeff[0][1] != 0:  # y to u
+            result[:size_3d] += self.coeff[0][1] * self.weight.T.dot(vector[size_2d:])
+        if self.coeff[0][2] != 0:  # z to u
+            result[size_3d:2*size_3d] += self.coeff[0][2] * self.weight.T.dot(vector[:size_2d])
+        if self.coeff[1][0] != 0:  # x to v
+            result[size_3d:2*size_3d] += self.coeff[1][0] * self.weight.T.dot(vector[size_2d:])
+        if self.coeff[1][1] != 0:  # y to v
+            result[2*size_3d:] += self.coeff[1][1] * self.weight.T.dot(vector[:size_2d])
+        if self.coeff[1][2] != 0:  # z to v
+            result[2*size_3d:] += self.coeff[1][2] * self.weight.T.dot(vector[size_2d:])
         return result
 
     def _scalar_field_projection(self, vector):
         self.log.info('Calling _scalar_field_projection')
         return np.array(self.weight.dot(vector))
 
+    def _scalar_field_projection_T(self, vector):
+        self.log.info('Calling _scalar_field_projection_T')
+        return np.array(self.weight.T.dot(vector))
+
     def jac_dot(self, vector):
         '''Multiply a `vector` with the jacobi matrix of this :class:`~.Projector` object.
 
@@ -109,7 +125,30 @@ class Projector(object):
 
         '''
         self.log.info('Calling jac_dot')
-        return self(vector)
+#        print 'Projector - jac_dot:', len(vector)
+        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)
+        else:
+            raise AssertionError('Vector size has to be suited either for ' \
+                                 'vector- or scalar-field-projection!')
+
+    def jac_T_dot(self, vector):
+        # TODO: Docstring!
+        self.log.info('Calling jac_T_dot') 
+#        print 'Projector - jac_T_dot:', len(vector)        
+        if len(vector) == 2*self.size_2d:  # mode == 'vector'
+            self.log.info('mode == vector')
+            return self._vector_field_projection_T(vector)
+        elif len(vector) == self.size_2d:  # mode == 'scalar'
+            self.log.info('mode == scalar')
+            return self._scalar_field_projection_T(vector)
+        else:
+            raise AssertionError('Vector size has to be suited either for ' \
+                                 'vector- or scalar-field-projection!')
 
 
 
@@ -124,7 +163,7 @@ class YTiltProjector(Projector):
 #
 #    Attributes
 #    ----------
-#    dim_2d : tuple (N=2)
+#    dim_uv : tuple (N=2)
 #        Dimensions (v, u) of the projected grid.
 #    size_3d : int
 #        Number of voxels of the 3-dimensional grid.
@@ -239,7 +278,7 @@ class SimpleProjector(Projector):
 #
 #    Attributes
 #    ----------
-#    dim_2d : tuple (N=2)
+#    dim_uv : 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
diff --git a/scripts/edinburgh_test.py b/scripts/edinburgh_test.py
index f101582..27bf0cc 100644
--- a/scripts/edinburgh_test.py
+++ b/scripts/edinburgh_test.py
@@ -42,7 +42,7 @@ phasemapper = PMAdapterFM(mag_data.a, projector)
 
 phase_map = phasemapper(mag_data)
 
-phase_axis = phase_map.display_combined(density=20, interpolation='bilinear')[0]
+phase_axis = phase_map.display_combined(density=20, interpolation='bilinear', grad_encode='bright')[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)))
diff --git a/scripts/images_poster.py b/scripts/images_poster.py
index d008673..2135cbe 100644
--- a/scripts/images_poster.py
+++ b/scripts/images_poster.py
@@ -6,58 +6,86 @@ Created on Wed Feb 05 19:19:19 2014
 """
 
 import os
+
 from numpy import pi
+import numpy as np
 
 import pyramid.magcreator as mc
+import pyramid.analytic as an
 from pyramid.magdata import MagData
 from pyramid.phasemapper import PMConvolve
 from pyramid.projector import SimpleProjector
+from pyramid.phasemap import PhaseMap
 
 import matplotlib.pyplot as plt
 
+from time import clock
 
-
-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'))
+#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()
 
 
-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))
+a = 1.
+dim = (128, 128, 128)
+center = (dim[0]/2, dim[1]/2, dim[2]/2)
+radius = dim[1]/4  # in px
+mag_shape = mc.Shapes.sphere(dim, center, radius)
+mag_data = MagData(a, mc.create_mag_dist_homog(mag_shape, pi/4))
 phasemapper = PMConvolve(a, SimpleProjector(dim))
-phasemapper(mag_data_x).display_phase()
-phasemapper(mag_data_y).display_phase()
\ No newline at end of file
+start = clock()
+phase_map = phasemapper(mag_data)
+print 'TIME:', clock() - start
+phase_ana = an.phase_mag_sphere(dim, a, pi/4, center, radius)
+phase_diff = (phase_ana - phase_map).phase
+print 'RMS%:', np.sqrt(np.mean((phase_diff)**2))/phase_ana.phase.max()*100
+print 'max:', phase_ana.phase.max()
+print 'RMS:', np.sqrt(np.mean((phase_diff)**2))
+PhaseMap(a, phase_diff).display_phase()
+
+mag_data.scale_down(2)
+mag_data.quiver_plot()
+mag_data.quiver_plot3d()
+phase_map.display_phase()
+
diff --git a/scripts/logfile.log b/scripts/logfile.log
index 8354e33..e69de29 100644
--- a/scripts/logfile.log
+++ b/scripts/logfile.log
@@ -1 +0,0 @@
-2014-02-08 21:43:12: INFO     @ <root>:    Calling copy
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 735db86..e976c83 100644
--- a/scripts/paper 1/ch5-4-comparison_of_methods_new.py	
+++ b/scripts/paper 1/ch5-4-comparison_of_methods_new.py	
@@ -25,7 +25,7 @@ from pyramid.phasemapper import PMConvolve, PMFourier
 import shelve
 
 
-force_calculation = False
+force_calculation = True
 
 
 print '\nACCESS SHELVE'
@@ -133,6 +133,8 @@ else:
         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 'TIME:', data_disc_real_d[2, i]
+        print 'RMS%:', np.sqrt(np.mean(((phase_ana_disc-phase_num_disc).phase/phase_ana_disc.phase)**2))*100, '%'
 
         print '----CALCULATE RMS/DURATION HOMOG. MAGN. DISC'
         # Analytic solution:
diff --git a/scripts/paper 1/logfile.log b/scripts/paper 1/logfile.log
index e8f8d21..3bc36a6 100644
--- a/scripts/paper 1/logfile.log	
+++ b/scripts/paper 1/logfile.log	
@@ -1,85 +1,84 @@
-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))
+2014-02-18 09:30:30: INFO     @ <pyramid.projector>:    Calling __init__
+2014-02-18 09:30:30: INFO     @ <pyramid.projector>:    Calling __init__
+2014-02-18 09:30:30: INFO     @ <pyramid.projector>:    Created <pyramid.projector.SimpleProjector object at 0x0DC7ECD0>
+2014-02-18 09:30:30: INFO     @ <pyramid.projector>:    Created <pyramid.projector.SimpleProjector object at 0x0DC7ECD0>
+2014-02-18 09:30:30: INFO     @ <pyramid.phasemap>:    Calling __str__
+2014-02-18 09:30:30: INFO     @ <pyramid.phasemap>:    Created PhaseMap(a=1.0, dim_uv=(128, 128))
+2014-02-18 09:30:30: INFO     @ <pyramid.phasemap>:    Calling __str__
+2014-02-18 09:30:30: INFO     @ <pyramid.phasemap>:    Created PhaseMap(a=1.0, dim_uv=(128, 128))
+2014-02-18 09:30:30: INFO     @ <pyramid.projector>:    Calling as function
+2014-02-18 09:30:30: INFO     @ <pyramid.projector>:    mode == vector
+2014-02-18 09:30:30: INFO     @ <pyramid.projector>:    Calling _vector_field_projection
+2014-02-18 09:30:30: INFO     @ <pyramid.phasemap>:    Calling __str__
+2014-02-18 09:30:30: INFO     @ <pyramid.phasemap>:    Created PhaseMap(a=1.0, dim_uv=(128, 128))
+2014-02-18 09:30:30: INFO     @ <pyramid.phasemap>:    Calling __sub__
+2014-02-18 09:30:30: INFO     @ <pyramid.phasemap>:    Calling __neg__
+2014-02-18 09:30:30: INFO     @ <pyramid.phasemap>:    Calling __str__
+2014-02-18 09:30:30: INFO     @ <pyramid.phasemap>:    Created PhaseMap(a=1.0, dim_uv=(128, 128))
+2014-02-18 09:30:30: INFO     @ <pyramid.phasemap>:    Calling __add__
+2014-02-18 09:30:30: INFO     @ <pyramid.phasemap>:    Adding two PhaseMap objects
+2014-02-18 09:30:30: INFO     @ <pyramid.phasemap>:    Calling __str__
+2014-02-18 09:30:30: INFO     @ <pyramid.phasemap>:    Created PhaseMap(a=1.0, dim_uv=(128, 128))
+2014-02-18 09:30:30: INFO     @ <pyramid.phasemap>:    Calling display_phase
+2014-02-18 09:30:30: INFO     @ <pyramid.projector>:    Calling as function
+2014-02-18 09:30:30: INFO     @ <pyramid.projector>:    mode == vector
+2014-02-18 09:30:30: INFO     @ <pyramid.projector>:    Calling _vector_field_projection
+2014-02-18 09:30:30: INFO     @ <pyramid.phasemap>:    Calling __str__
+2014-02-18 09:30:30: INFO     @ <pyramid.phasemap>:    Created PhaseMap(a=1.0, dim_uv=(128, 128))
+2014-02-18 09:30:30: INFO     @ <pyramid.phasemap>:    Calling __sub__
+2014-02-18 09:30:30: INFO     @ <pyramid.phasemap>:    Calling __neg__
+2014-02-18 09:30:30: INFO     @ <pyramid.phasemap>:    Calling __str__
+2014-02-18 09:30:30: INFO     @ <pyramid.phasemap>:    Created PhaseMap(a=1.0, dim_uv=(128, 128))
+2014-02-18 09:30:30: INFO     @ <pyramid.phasemap>:    Calling __add__
+2014-02-18 09:30:30: INFO     @ <pyramid.phasemap>:    Adding two PhaseMap objects
+2014-02-18 09:30:30: INFO     @ <pyramid.phasemap>:    Calling __str__
+2014-02-18 09:30:30: INFO     @ <pyramid.phasemap>:    Created PhaseMap(a=1.0, dim_uv=(128, 128))
+2014-02-18 09:30:30: INFO     @ <pyramid.phasemap>:    Calling __isub__
+2014-02-18 09:30:30: INFO     @ <pyramid.phasemap>:    Calling __sub__
+2014-02-18 09:30:30: INFO     @ <pyramid.phasemap>:    Calling __add__
+2014-02-18 09:30:30: INFO     @ <pyramid.phasemap>:    Adding an offset
+2014-02-18 09:30:30: INFO     @ <pyramid.phasemap>:    Calling __str__
+2014-02-18 09:30:30: INFO     @ <pyramid.phasemap>:    Created PhaseMap(a=1.0, dim_uv=(128, 128))
+2014-02-18 09:30:30: INFO     @ <pyramid.phasemap>:    Calling display_phase
+2014-02-18 09:30:31: INFO     @ <pyramid.projector>:    Calling as function
+2014-02-18 09:30:31: INFO     @ <pyramid.projector>:    mode == vector
+2014-02-18 09:30:31: INFO     @ <pyramid.projector>:    Calling _vector_field_projection
+2014-02-18 09:30:31: INFO     @ <pyramid.phasemap>:    Calling __str__
+2014-02-18 09:30:31: INFO     @ <pyramid.phasemap>:    Created PhaseMap(a=1.0, dim_uv=(128, 128))
+2014-02-18 09:30:31: INFO     @ <pyramid.phasemap>:    Calling __sub__
+2014-02-18 09:30:31: INFO     @ <pyramid.phasemap>:    Calling __neg__
+2014-02-18 09:30:31: INFO     @ <pyramid.phasemap>:    Calling __str__
+2014-02-18 09:30:31: INFO     @ <pyramid.phasemap>:    Created PhaseMap(a=1.0, dim_uv=(128, 128))
+2014-02-18 09:30:31: INFO     @ <pyramid.phasemap>:    Calling __add__
+2014-02-18 09:30:31: INFO     @ <pyramid.phasemap>:    Adding two PhaseMap objects
+2014-02-18 09:30:31: INFO     @ <pyramid.phasemap>:    Calling __str__
+2014-02-18 09:30:31: INFO     @ <pyramid.phasemap>:    Created PhaseMap(a=1.0, dim_uv=(128, 128))
+2014-02-18 09:30:31: INFO     @ <pyramid.phasemap>:    Calling display_phase
+2014-02-18 09:30:31: INFO     @ <pyramid.projector>:    Calling as function
+2014-02-18 09:30:31: INFO     @ <pyramid.projector>:    mode == vector
+2014-02-18 09:30:31: INFO     @ <pyramid.projector>:    Calling _vector_field_projection
+2014-02-18 09:30:32: INFO     @ <pyramid.phasemap>:    Calling __str__
+2014-02-18 09:30:32: INFO     @ <pyramid.phasemap>:    Created PhaseMap(a=1.0, dim_uv=(128, 128))
+2014-02-18 09:30:32: INFO     @ <pyramid.phasemap>:    Calling __sub__
+2014-02-18 09:30:32: INFO     @ <pyramid.phasemap>:    Calling __neg__
+2014-02-18 09:30:32: INFO     @ <pyramid.phasemap>:    Calling __str__
+2014-02-18 09:30:32: INFO     @ <pyramid.phasemap>:    Created PhaseMap(a=1.0, dim_uv=(128, 128))
+2014-02-18 09:30:32: INFO     @ <pyramid.phasemap>:    Calling __add__
+2014-02-18 09:30:32: INFO     @ <pyramid.phasemap>:    Adding two PhaseMap objects
+2014-02-18 09:30:32: INFO     @ <pyramid.phasemap>:    Calling __str__
+2014-02-18 09:30:32: INFO     @ <pyramid.phasemap>:    Created PhaseMap(a=1.0, dim_uv=(128, 128))
+2014-02-18 09:30:32: INFO     @ <pyramid.phasemap>:    Calling __isub__
+2014-02-18 09:30:32: INFO     @ <pyramid.phasemap>:    Calling __sub__
+2014-02-18 09:30:32: INFO     @ <pyramid.phasemap>:    Calling __add__
+2014-02-18 09:30:32: INFO     @ <pyramid.phasemap>:    Adding an offset
+2014-02-18 09:30:32: INFO     @ <pyramid.phasemap>:    Calling __str__
+2014-02-18 09:30:32: INFO     @ <pyramid.phasemap>:    Created PhaseMap(a=1.0, dim_uv=(128, 128))
+2014-02-18 09:30:32: INFO     @ <pyramid.phasemap>:    Calling display_phase
+2014-02-18 09:30:33: INFO     @ <pyramid.projector>:    Calling __init__
+2014-02-18 09:30:33: INFO     @ <pyramid.projector>:    Calling __init__
+2014-02-18 09:30:33: INFO     @ <pyramid.projector>:    Created <pyramid.projector.SimpleProjector object at 0x0DC7EB70>
+2014-02-18 09:30:33: INFO     @ <pyramid.projector>:    Created <pyramid.projector.SimpleProjector object at 0x0DC7EB70>
+2014-02-18 09:30:33: INFO     @ <pyramid.phasemap>:    Calling __str__
+2014-02-18 09:30:33: INFO     @ <pyramid.phasemap>:    Created PhaseMap(a=1.0, dim_uv=(128, 128))
+2014-02-18 09:30:33: INFO     @ <pyramid.phasemap>:    Calling __str__
+2014-02-18 09:30:33: INFO     @ <pyramid.phasemap>:    Created PhaseMap(a=1.0, dim_uv=(128, 128))
diff --git a/scripts/simple_phasemapping.py b/scripts/simple_phasemapping.py
index 80c6737..c8d1715 100644
--- a/scripts/simple_phasemapping.py
+++ b/scripts/simple_phasemapping.py
@@ -15,7 +15,7 @@ from time import clock
 #import cProfile
 
 
-mag_data = MagData.load_from_netcdf4('../output/vtk data/rect_500x125x3.nc')
+mag_data = MagData.load_from_netcdf4('../output/vtk data/tube_90x30x30.nc')
 
 projector = SimpleProjector(mag_data.dim)
 
diff --git a/scripts/simple_reconstruction.py b/scripts/simple_reconstruction.py
new file mode 100644
index 0000000..d9a81a8
--- /dev/null
+++ b/scripts/simple_reconstruction.py
@@ -0,0 +1,171 @@
+# -*- coding: utf-8 -*-
+"""
+Created on Fri Feb 28 14:25:59 2014
+
+@author: Jan
+"""
+
+
+import numpy as np
+from numpy import pi
+
+from pyramid.magdata import MagData
+from pyramid.projector import YTiltProjector
+from pyramid.phasemapper import PMConvolve
+from pyramid.datacollection import DataCollection
+import pyramid.optimizer as opt
+
+from pyramid.kernel import Kernel
+from pyramid.forwardmodel import ForwardModel
+from pyramid.costfunction import Costfunction
+
+
+a = 1.
+b_0 = 1000.
+dim = (3, 3, 3)
+count = 1
+
+###################################################################################################
+print('--Generating input phase_maps')
+
+
+magnitude = np.zeros((3,)+dim)
+magnitude[:, int(dim[0]/2), int(dim[1]/2), int(dim[2]/2)] = 1.
+
+mag_data = MagData(a, magnitude)
+mag_data.quiver_plot3d()
+
+tilts = np.linspace(0, 2*pi, num=count, endpoint=False)
+projectors = [YTiltProjector(mag_data.dim, tilt) for tilt in tilts]
+phasemappers = [PMConvolve(mag_data.a, projector, b_0) for projector in projectors]
+phase_maps = [pm(mag_data) for pm in phasemappers]
+
+#[phase_map.display_phase(title=u'Tilt series $(\phi = {:2.1f} \pi)$'.format(tilts[i]/pi))
+#                         for i, phase_map in enumerate(phase_maps)]
+phase_maps[0].display_phase()
+
+###################################################################################################
+print('--Setting up data collection')
+
+dim_uv = dim[1:3]
+
+data_collection = DataCollection(a, dim_uv, b_0)
+
+[data_collection.append((phase_maps[i], projectors[i])) for i in range(count)]
+
+###################################################################################################
+print('--Test optimizer')
+
+first_guess = MagData(a, np.zeros((3,)+dim))
+
+first_guess.magnitude[1, int(dim[0]/2), int(dim[1]/2), int(dim[2]/2)] = 1
+#first_guess.magnitude[0, int(dim[0]/2), int(dim[1]/2), int(dim[2]/2)] = -1
+
+first_guess.quiver_plot3d()
+
+phase_guess = PMConvolve(first_guess.a, projectors[0], b_0)(first_guess)
+
+phase_guess.display_phase()
+
+#mag_opt = opt.optimize_cg(data_collection, first_guess)
+#
+#mag_opt.quiver_plot3d()
+#
+#phase_opt = PMConvolve(mag_opt.a, projectors[0], b_0)(mag_opt)
+#
+#phase_opt.display_phase()
+
+
+###################################################################################################
+print('--Further testing')
+
+data = data_collection
+mag_0 = first_guess
+x_0 = first_guess.mag_vec
+y = data.phase_vec
+kern = Kernel(data.a, data.dim_uv)
+F = ForwardModel(data.projectors, kern, data.b_0)
+C = Costfunction(y, F)
+
+size_3d = np.prod(dim)
+
+cost = C(first_guess.mag_vec)
+cost_grad = C.jac(first_guess.mag_vec)
+cost_grad_del_x = cost_grad.reshape((3, 3, 3, 3))[0, ...]
+cost_grad_del_y = cost_grad.reshape((3, 3, 3, 3))[1, ...]
+cost_grad_del_z = cost_grad.reshape((3, 3, 3, 3))[2, ...]
+
+
+
+
+x_t = np.asmatrix(mag_data.mag_vec).T
+y = np.asmatrix(y).T
+K = np.array([F.jac_dot(x_0, np.eye(81)[:, i]) for i in range(81)]).T
+K = np.asmatrix(K)
+lam = 10. ** -10
+KTK = K.T * K + lam * np.asmatrix(np.eye(81))
+print lam, 
+#print pylab.cond(KTK),
+x_f = KTK.I * K.T * y
+print (np.asarray(K * x_f - y) ** 2).sum(),
+print (np.asarray(K * x_t - y) ** 2).sum()
+print x_f
+x_rec = np.asarray(x_f).reshape(3,3,3,3)
+print x_rec[0, ...]
+#KTK = K.T * K
+#u,s,v = pylab.svd(KTK, full_matrices=1)
+#si = np.zeros_like(s)
+#
+#si[s>lam] = 1. / s[s>lam]
+#si=np.asmatrix(np.diag(si))
+#KTKI = np.asmatrix(v).T * si * np.asmatrix(u)
+#
+#
+#x_f = KTKI * K.T * y
+#print x_f
+#
+#
+
+
+###################################################################################################
+print('--Compliance test')
+
+
+# test F
+
+# test F.jac
+
+# test F.jac_dot
+
+#F_evaluate = F(mag_data.mag_vec)
+#F_jacobi = F.jac_dot(None, mag_data.mag_vec)
+#np.testing.assert_equal(F_evaluate, F_jacobi)
+#
+#F_reverse = F.jac_T_dot(None, F_jacobi)
+#np.testing.assert_equal(F_reverse, mag_data.mag_vec)
+
+
+
+from scipy.sparse.linalg import cg
+
+K = np.asmatrix([F.jac_dot(x_0, np.eye(81)[:, i]) for i in range(81)]).T
+lam = 10. ** -10
+KTK = K.T * K + lam * np.asmatrix(np.eye(81))
+
+A = KTK#np.array([F(np.eye(81)[:, i]) for i in range(81)])
+
+b = F.jac_T_dot(None, y)
+
+b_test = np.asarray((K.T * y).T)[0]
+
+x_f = cg(A, b_test)[0]
+
+mag_data_rec = MagData(a, np.zeros((3,)+dim))
+
+mag_data_rec.mag_vec = x_f
+
+mag_data_rec.quiver_plot3d()
+
+
+
+
diff --git a/scripts/test_projection.py b/scripts/test_projection.py
new file mode 100644
index 0000000..baaeb0a
--- /dev/null
+++ b/scripts/test_projection.py
@@ -0,0 +1,68 @@
+# -*- coding: utf-8 -*-
+"""
+Created on Fri Jan 17 14:06:01 2014
+
+@author: Jan
+"""
+
+import numpy as np
+from numpy import pi
+
+from pyramid.magdata import MagData
+from pyramid.projector import YTiltProjector
+from pyramid.phasemapper import PMConvolve
+
+from time import clock
+
+import matplotlib.pyplot as plt
+
+#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)
+
+
+PATH = '../output/vtk data/tube_90x30x50_sat_edge_equil.gmr'
+
+mag_data = MagData.load_from_netcdf4(PATH+'.nc')
+
+#for tilt in np.linspace(0, 2*pi, num=20, endpoint=False):
+#    projector = YTiltProjector(mag_data.dim, tilt)
+#    phasemapper = PMConvolve(mag_data.a, projector)
+#    phase_map = phasemapper(mag_data)
+#    (-phase_map).display_combined(title=u'Tilt series $(\phi = {:2.1f} \pi)$'.format(tilt/pi),
+#                                  limit=2., density=12, interpolation='bilinear', 
+#                                  grad_encode='bright')
+#    plt.savefig(PATH+'_tilt_{:3.2f}pi.png'.format(tilt/pi))
+
+
+mag_data.scale_down()
+
+mag_data.quiver_plot3d()
+
+#projectors = [YTiltProjector(mag_data.dim, i)
+#              for i in np.linspace(0, 2*pi, num=20, endpoint=False)]
+#
+#start = clock()
+#phasemapper = PMConvolve[PMConvolve(mag_data.a, projector) for projector in projectors]
+#print 'Overhead  :', clock()-start
+#
+#start = clock()
+#phase_maps = [pm(mag_data) for pm in phasemappers]
+#print 'Phasemapping:', clock()-start
+#
+#[phase_map.display_combined(density=12, interpolation='bilinear', grad_encode='bright')
+# for phase_map in phase_maps]
-- 
GitLab