From a088c4f51d7b1ce969813c74220b09dfd3e9ddb6 Mon Sep 17 00:00:00 2001
From: Jan Caron <j.caron@fz-juelich.de>
Date: Tue, 11 Mar 2014 17:14:25 +0100
Subject: [PATCH] Fixed problems with the transposed operations of the forward
 model which did not represent the correct matrizes (hopefully, now they do).

>>> PACKAGE
forwardmodel, kernel, phasemapper:
        b_0 is now again inherent part of the kernel.
projector:
        Corrected .jac_T_dot, now delivers product for the correct matrix.
>>> SCRIPTS
simple_reconstruction:
        Does simple compliance tests for 1 and 2 projections and tests a simple
        solver via scipy.sparse.linalg.cg for the reconstruction.
---
 pyramid/forwardmodel.py          |   5 +-
 pyramid/kernel.py                |   4 +-
 pyramid/phasemapper.py           |  12 +-
 pyramid/projector.py             |  22 +--
 scripts/simple_reconstruction.py | 323 +++++++++++++++++++++++--------
 5 files changed, 264 insertions(+), 102 deletions(-)

diff --git a/pyramid/forwardmodel.py b/pyramid/forwardmodel.py
index c231829..44694cc 100644
--- a/pyramid/forwardmodel.py
+++ b/pyramid/forwardmodel.py
@@ -33,10 +33,9 @@ class ForwardModel:
         assert isinstance(kernel, Kernel), 'A Kernel object has to be provided!'
         self._kernel = kernel
 
-    def __init__(self, projectors, kernel, b_0):
+    def __init__(self, projectors, kernel):
         # TODO: Docstring!
         self.kernel = kernel
-        self.b_0 = b_0
         self.a = kernel.a
         self.dim_uv = kernel.dim_uv
         self.projectors = projectors
@@ -45,7 +44,7 @@ class ForwardModel:
         # TODO: Docstring!
 #        print 'FWD Model - __call__ -  input: ', len(x)
         result = [self.kernel.jac_dot(projector.jac_dot(x)) for projector in self.projectors]
-        result = self.b_0 * np.reshape(result, -1)
+        result = np.reshape(result, -1)
 #        print 'FWD Model - __call__ -  output:', len(result)
         return result
 
diff --git a/pyramid/kernel.py b/pyramid/kernel.py
index 0ce1963..00752a9 100644
--- a/pyramid/kernel.py
+++ b/pyramid/kernel.py
@@ -76,7 +76,7 @@ class Kernel(object):
 
     '''# TODO: Can be used for several PhaseMappers via the fft arguments or via calling!
     
-    def __init__(self, a, dim_uv, numcore=True, geometry='disc'):
+    def __init__(self, a, dim_uv, b_0=1., numcore=True, geometry='disc'):
         '''Constructor for a :class:`~.Kernel` object for representing a kernel matrix.
 
         Parameters
@@ -109,7 +109,7 @@ class Kernel(object):
         self.numcore = numcore
         self.geometry = geometry
         # Calculate kernel (single pixel phase):
-        coeff = -a**2 / (2*PHI_0)
+        coeff = -b_0 * 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)
diff --git a/pyramid/phasemapper.py b/pyramid/phasemapper.py
index 4501e37..7dd5de8 100644
--- a/pyramid/phasemapper.py
+++ b/pyramid/phasemapper.py
@@ -46,7 +46,7 @@ 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_uv, geometry), b_0)
+        self.fwd_model = ForwardModel([projector], Kernel(a, projector.dim_uv, b_0, geometry))
 
     def __call__(self, mag_data):
         assert isinstance(mag_data, MagData), 'Only MagData objects can be mapped!'
@@ -221,7 +221,7 @@ class PMConvolve(PhaseMapper):
         self.projector = projector
         self.b_0 = b_0
         self.threshold = threshold
-        self.kernel = Kernel(a, projector.dim_uv, geometry)
+        self.kernel = Kernel(a, projector.dim_uv, b_0, geometry)
 
     def __call__(self, mag_data):
         # Docstring!
@@ -235,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, self.b_0*(u_phase-v_phase))
+        return PhaseMap(self.a, u_phase-v_phase)
 
 
 class PMReal(PhaseMapper):
@@ -271,7 +271,7 @@ class PMReal(PhaseMapper):
         self.projector = projector
         self.b_0 = b_0
         self.threshold = threshold
-        self.kernel = Kernel(a, projector.dim_uv, geometry)
+        self.kernel = Kernel(a, projector.dim_uv, b_0, geometry)
         self.numcore = numcore
 
     def __call__(self, mag_data):
@@ -281,8 +281,8 @@ class PMReal(PhaseMapper):
         threshold = self.threshold
         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.b_0 * self.kernel.u
-        v_phi = self.b_0 * self.kernel.v
+        u_phi = self.kernel.u
+        v_phi = self.kernel.v
         # Calculation of the phase:
         phase = np.zeros(dim_uv)
         if self.numcore:
diff --git a/pyramid/projector.py b/pyramid/projector.py
index 99b3e31..fd57f77 100644
--- a/pyramid/projector.py
+++ b/pyramid/projector.py
@@ -85,18 +85,18 @@ class Projector(object):
         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
+        # Go over all possible component projections (u, v) to (z, y, x):
+        if self.coeff[0][0] != 0:  # u to x
             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
+        if self.coeff[0][1] != 0:  # u to y
+            result[size_3d:2*size_3d] += self.coeff[0][1] * self.weight.T.dot(vector[:size_2d])
+        if self.coeff[0][2] != 0:  # u to z
+            result[2*size_3d:] += self.coeff[0][2] * self.weight.T.dot(vector[:size_2d])
+        if self.coeff[1][0] != 0:  # v to x
+            result[:size_3d] += self.coeff[1][0] * self.weight.T.dot(vector[size_2d:])
+        if self.coeff[1][1] != 0:  # v to y
+            result[size_3d:2*size_3d] += self.coeff[1][1] * self.weight.T.dot(vector[size_2d:])
+        if self.coeff[1][2] != 0:  # v to z
             result[2*size_3d:] += self.coeff[1][2] * self.weight.T.dot(vector[size_2d:])
         return result
 
diff --git a/scripts/simple_reconstruction.py b/scripts/simple_reconstruction.py
index d9a81a8..f487272 100644
--- a/scripts/simple_reconstruction.py
+++ b/scripts/simple_reconstruction.py
@@ -13,25 +13,167 @@ 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
 
+from scipy.sparse.linalg import cg
+
+
+###################################################################################################
+print('--Compliance test for one projection')
 
 a = 1.
 b_0 = 1000.
-dim = (3, 3, 3)
+dim = (2, 2, 2)
 count = 1
 
+magnitude = np.zeros((3,)+dim)
+magnitude[:, int(dim[0]/2), int(dim[1]/2), int(dim[2]/2)] = 1.
+
+mag_data = MagData(a, magnitude)
+
+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]
+
+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)]
+
+data = data_collection
+y = data.phase_vec
+kern = Kernel(data.a, data.dim_uv, data.b_0)
+F = ForwardModel(data.projectors, kern)
+C = Costfunction(y, F)
+
+size_2d = np.prod(dim[1]*dim[2])
+size_3d = np.prod(dim)
+
+P = np.array([data.projectors[0](np.eye(3*size_3d)[:, i]) for i in range(3*size_3d)]).T
+K = np.array([kern(np.eye(2*size_2d)[:, i]) for i in range(2*size_2d)]).T
+F_mult = K.dot(P)
+F_direct = np.array([F(np.eye(3*size_3d)[:, i]) for i in range(3*size_3d)]).T
+np.testing.assert_almost_equal(F_direct, F_mult)
+
+P_jac = np.array([data.projectors[0].jac_dot(np.eye(3*size_3d)[:, i]) for i in range(3*size_3d)]).T
+K_jac = np.array([kern.jac_dot(np.eye(2*size_2d)[:, i]) for i in range(2*size_2d)]).T
+F_jac_mult = K.dot(P)
+F_jac_direct = np.array([F.jac_dot(None, np.eye(3*size_3d)[:, i]) for i in range(3*size_3d)]).T
+np.testing.assert_almost_equal(F_jac_direct, F_jac_mult)
+np.testing.assert_almost_equal(F_direct, F_jac_direct)
+
+P_t = np.array([data.projectors[0].jac_T_dot(np.eye(2*size_2d)[:, i]) for i in range(2*size_2d)]).T
+K_t = np.array([kern.jac_T_dot(np.eye(size_2d)[:, i]) for i in range(size_2d)]).T
+F_t_mult = P_t.dot(K_t)
+F_t_direct = np.array([F.jac_T_dot(None, np.eye(size_2d)[:, i]) for i in range(size_2d)]).T
+
+P_t_ref = P.T
+K_t_ref = K.T
+F_t_ref = F_mult.T
+np.testing.assert_almost_equal(P_t, P_t_ref)
+np.testing.assert_almost_equal(K_t, K_t_ref)
+np.testing.assert_almost_equal(F_t_mult, F_t_ref)
+np.testing.assert_almost_equal(F_t_direct, F_t_ref)
+
 ###################################################################################################
-print('--Generating input phase_maps')
+print('--Compliance test for two projections')
 
+a = 1.
+b_0 = 1000.
+dim = (2, 2, 2)
+count = 2
 
 magnitude = np.zeros((3,)+dim)
 magnitude[:, int(dim[0]/2), int(dim[1]/2), int(dim[2]/2)] = 1.
 
+mag_data = MagData(a, magnitude)
+
+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]
+
+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)]
+
+data = data_collection
+y = data.phase_vec
+kern = Kernel(data.a, data.dim_uv, data.b_0)
+F = ForwardModel(data.projectors, kern)
+C = Costfunction(y, F)
+
+size_2d = np.prod(dim[1]*dim[2])
+size_3d = np.prod(dim)
+
+P0 = np.array([data.projectors[0](np.eye(3*size_3d)[:, i]) for i in range(3*size_3d)]).T
+P1 = np.array([data.projectors[1](np.eye(3*size_3d)[:, i]) for i in range(3*size_3d)]).T
+P = np.vstack((P0, P1))
+K = np.array([kern(np.eye(2*size_2d)[:, i]) for i in range(2*size_2d)]).T
+F_mult0 = K.dot(P0)
+F_mult1 = K.dot(P1)
+F_mult = np.vstack((F_mult0, F_mult1))
+F_direct = np.array([F(np.eye(3*size_3d)[:, i]) for i in range(3*size_3d)]).T
+np.testing.assert_almost_equal(F_direct, F_mult)
+
+P_jac0 = np.array([data.projectors[0].jac_dot(np.eye(3*size_3d)[:, i]) for i in range(3*size_3d)]).T
+P_jac1 = np.array([data.projectors[1].jac_dot(np.eye(3*size_3d)[:, i]) for i in range(3*size_3d)]).T
+P = np.vstack((P0, P1))
+K_jac = np.array([kern.jac_dot(np.eye(2*size_2d)[:, i]) for i in range(2*size_2d)]).T
+F_jac_mult0 = K.dot(P_jac0)
+F_jac_mult1 = K.dot(P_jac1)
+F_jac_mult = np.vstack((F_jac_mult0, F_jac_mult1))
+F_jac_direct = np.array([F.jac_dot(None, np.eye(3*size_3d)[:, i]) for i in range(3*size_3d)]).T
+np.testing.assert_almost_equal(F_jac_direct, F_jac_mult)
+np.testing.assert_almost_equal(F_direct, F_jac_direct)
+
+P_t0 = np.array([data.projectors[0].jac_T_dot(np.eye(2*size_2d)[:, i]) for i in range(2*size_2d)]).T
+P_t1 = np.array([data.projectors[1].jac_T_dot(np.eye(2*size_2d)[:, i]) for i in range(2*size_2d)]).T
+P_t = np.hstack((P_t0, P_t1))
+K_t = np.array([kern.jac_T_dot(np.eye(size_2d)[:, i]) for i in range(size_2d)]).T
+F_t_mult0 = P_t0.dot(K_t)
+F_t_mult1 = P_t1.dot(K_t)
+F_t_mult = np.hstack((F_t_mult0, F_t_mult1))
+F_t_direct = np.array([F.jac_T_dot(None, np.eye(count*size_2d)[:, i]) for i in range(count*size_2d)]).T
+
+P_t_ref = P.T
+K_t_ref = K.T
+F_t_ref = F_mult.T
+np.testing.assert_almost_equal(P_t, P_t_ref)
+np.testing.assert_almost_equal(K_t, K_t_ref)
+np.testing.assert_almost_equal(F_t_mult, F_t_ref)
+np.testing.assert_almost_equal(F_t_direct, F_t_ref)
+
+
+
+
+
+
+
+
+###################################################################################################
+print('--STARTING RECONSTRUCTION')
+
+
+
+###################################################################################################
+print('--Generating input phase_maps')
+
+a = 1.
+b_0 = 1000.
+dim = (9, 9, 9)
+count = 8
+
+magnitude = np.zeros((3,)+dim)
+magnitude[0, int(dim[0]/2), int(dim[1]/2), int(dim[2]/2)] = 1.
+
 mag_data = MagData(a, magnitude)
 mag_data.quiver_plot3d()
 
@@ -40,32 +182,67 @@ 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()
+[phase_map.display_phase(title=u'Tilt series $(\phi = {:2.1f} \pi)$'.format(tilts[i]/pi))
+                         for i, phase_map in enumerate(phase_maps)]
 
 ###################################################################################################
 print('--Setting up data collection')
 
 dim_uv = dim[1:3]
 
+size_2d = np.prod(dim_uv)
+size_3d = np.prod(dim)
+
+
 data_collection = DataCollection(a, dim_uv, b_0)
 
 [data_collection.append((phase_maps[i], projectors[i])) for i in range(count)]
 
+data = data_collection
+y = data.phase_vec
+kern = Kernel(data.a, data.dim_uv, data.b_0)
+F = ForwardModel(data.projectors, kern)
+C = Costfunction(y, F)
+
 ###################################################################################################
-print('--Test optimizer')
+print('--Test simple solver')
 
-first_guess = MagData(a, np.zeros((3,)+dim))
+M = np.asmatrix([F.jac_dot(None, np.eye(3*size_3d)[:, i]) for i in range(3*size_3d)]).T
+lam = 1*10. ** -10
+MTM = M.T * M + lam * np.asmatrix(np.eye(3*size_3d))
 
-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
+A = MTM#np.array([F(np.eye(81)[:, i]) for i in range(81)])
+
+b = F.jac_T_dot(None, y)
+
+b_test = np.asarray((M.T.dot(y)).T)[0]
+
+x_f = cg(A, b)[0]
+
+mag_data_rec = MagData(a, np.zeros((3,)+dim))
+
+mag_data_rec.mag_vec = x_f
+
+mag_data_rec.quiver_plot3d()
+
+phase_maps_rec = [pm(mag_data_rec) for pm in phasemappers]
+[phase_map.display_phase(title=u'Tilt series (rec.) $(\phi = {:2.1f} \pi)$'.format(tilts[i]/pi))
+                         for i, phase_map in enumerate(phase_maps_rec)]
 
-first_guess.quiver_plot3d()
 
-phase_guess = PMConvolve(first_guess.a, projectors[0], b_0)(first_guess)
 
-phase_guess.display_phase()
+
+#
+#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)
 #
@@ -76,42 +253,42 @@ phase_guess.display_phase()
 #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, ...]
+####################################################################################################
+#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)
@@ -123,48 +300,34 @@ print x_rec[0, ...]
 #
 #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()
+#K = np.asmatrix([F.jac_dot(None, np.eye(24)[:, i]) for i in range(24)]).T
+#lam = 10. ** -10
+#KTK = K.T * K + lam * np.asmatrix(np.eye(24))
+#
+#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.dot(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()
 
 
 
-- 
GitLab