From ecfe52f674c98004bc5c752355bddbe320a3d6dc Mon Sep 17 00:00:00 2001 From: "Joern Ungermann (IEK-7 FZ-Juelich)" <j.ungermann@fz-juelich.de> Date: Thu, 30 Oct 2014 00:37:09 +0100 Subject: [PATCH] fixed some bugs, got reconstruction to work. --- pyramid/costfunction.py | 7 +++++-- pyramid/dataset.py | 2 +- pyramid/forwardmodel.py | 4 +++- pyramid/kernel.py | 35 +++++++++++++++++++++++++++++++++++ pyramid/magdata.py | 15 ++++++++++----- pyramid/phasemap.py | 1 + pyramid/phasemapper.py | 12 +++++++----- pyramid/reconstruction.py | 33 ++++++++++++++++++++++++++++----- pyramid/regularisator.py | 36 +++++++++++------------------------- 9 files changed, 101 insertions(+), 44 deletions(-) diff --git a/pyramid/costfunction.py b/pyramid/costfunction.py index ad7c226..50df34d 100644 --- a/pyramid/costfunction.py +++ b/pyramid/costfunction.py @@ -53,8 +53,9 @@ class Costfunction(object): # Extract important information: self.y = data_set.phase_vec self.Se_inv = data_set.Se_inv - self.n = data_set.n * 3 + self.n = data_set.m self.m = len(self.y) + self.chisq, self.chisq_a, self.chisq_m = None, None, None self.LOG.debug('Created '+str(self)) def __repr__(self): @@ -73,7 +74,9 @@ class Costfunction(object): def __call__(self, x): self.LOG.debug('Calling __call__') delta_y = self.fwd_model(x) - self.y - self.chisq = delta_y.dot(self.Se_inv.dot(delta_y)) + self.regularisator(x) + self.chisq_m = delta_y.dot(self.Se_inv.dot(delta_y)) + self.chisq_a = self.regularisator(x) + self.chisq = self.chisq_m + self.chisq_a return self.chisq def jac(self, x): diff --git a/pyramid/dataset.py b/pyramid/dataset.py index fd5fb49..914d306 100644 --- a/pyramid/dataset.py +++ b/pyramid/dataset.py @@ -88,7 +88,7 @@ class DataSet(object): 'Dimension has to be a tuple of length 3!' if mask is not None: assert mask.shape == dim, 'Mask dimensions must match!' - self.m = 3 * np.sum(self.mask) + self.m = 3 * np.sum(mask) else: self.m = 3 * np.prod(dim) self.a = a diff --git a/pyramid/forwardmodel.py b/pyramid/forwardmodel.py index c48a7f7..758a692 100644 --- a/pyramid/forwardmodel.py +++ b/pyramid/forwardmodel.py @@ -59,6 +59,7 @@ class ForwardModel(object): def __call__(self, x): self.LOG.debug('Calling __call__') + self.mag_data.magnitude[:] = 0 self.mag_data.set_vector(x, self.data_set.mask) # TODO: Multiprocessing result = np.zeros(self.n) @@ -89,6 +90,7 @@ class ForwardModel(object): ''' self.LOG.debug('Calling jac_dot') + self.mag_data.magnitude[:] = 0 self.mag_data.set_vector(vector, self.data_set.mask) result = np.zeros(self.n) hp = self.hook_points @@ -119,7 +121,7 @@ class ForwardModel(object): ''' self.LOG.debug('Calling jac_T_dot') - result = np.zeros(self.m) + result = np.zeros(3*np.prod(self.data_set.dim)) hp = self.hook_points for i, projector in enumerate(self.data_set.projectors): vec = vector[hp[i]:hp[i+1]] diff --git a/pyramid/kernel.py b/pyramid/kernel.py index be8502d..0c48d21 100644 --- a/pyramid/kernel.py +++ b/pyramid/kernel.py @@ -105,3 +105,38 @@ class Kernel(object): self.LOG.debug('Calling __str__') return 'Kernel(a=%s, dim_uv=%s, numcore=%s, geometry=%s)' % \ (self.a, self.dim_uv, self.numcore, self.geometry) + + def _multiply_jacobi(self, vector): + self.LOG.debug('Calling _multiply_jacobi') + v_dim, u_dim = self.dim_uv + assert len(vector) == 2 * self.size, \ + 'vector size not compatible! vector: {}, size: {}'.format(len(vector), self.size) + result = np.zeros(self.size) + # Iterate over all contributing pixels (numbered consecutively) + for s in range(self.size): # column-wise (two columns at a time, u- and v-component) + i = s % u_dim # u-coordinate of current contributing pixel + j = int(s/u_dim) # v-coordinate of current ccontributing pixel + u_min = (u_dim-1) - i # u_dim-1: center of the kernel + u_max = (2*u_dim-1) - i # = u_min + u_dim + v_min = (v_dim-1) - j # v_dim-1: center of the kernel + v_max = (2*v_dim-1) - j # = v_min + v_dim + result += vector[s] * self.u[v_min:v_max, u_min:u_max].reshape(-1) # u + result -= vector[s+self.size] * self.v[v_min:v_max, u_min:u_max].reshape(-1) # v + return result + + def _multiply_jacobi_T(self, vector): + self.LOG.debug('Calling _multiply_jacobi_T') + v_dim, u_dim = self.dim_uv + result = np.zeros(2*self.size) + # Iterate over all contributing pixels (numbered consecutively): + for s in range(self.size): # row-wise (two rows at a time, u- and v-component) + i = s % u_dim # u-coordinate of current contributing pixel + j = int(s/u_dim) # v-coordinate of current contributing pixel + u_min = (u_dim-1) - i # u_dim-1: center of the kernel + u_max = (2*u_dim-1) - i # = u_min + u_dim + v_min = (v_dim-1) - j # v_dim-1: center of the kernel + v_max = (2*v_dim-1) - j # = v_min + v_dim + result[s] = np.sum(vector*self.u[v_min:v_max, u_min:u_max].reshape(-1)) # u + result[s+self.size] = np.sum(vector*-self.v[v_min:v_max, u_min:u_max].reshape(-1)) # v + return result +# diff --git a/pyramid/magdata.py b/pyramid/magdata.py index 5989153..fc6f4d4 100644 --- a/pyramid/magdata.py +++ b/pyramid/magdata.py @@ -83,7 +83,8 @@ class MagData(object): @mag_vec.setter def mag_vec(self, mag_vec): assert isinstance(mag_vec, np.ndarray), 'Vector has to be a numpy array!' - assert np.size(mag_vec) == 3*np.prod(self.dim), 'Vector has to match magnitude dimensions!' + assert np.size(mag_vec) == 3*np.prod(self.dim), \ + 'Vector has to match magnitude dimensions! {} {}'.format(mag_vec.shape, 3*np.prod(self.dim)) self.magnitude = mag_vec.reshape((3,)+self.dim) def __init__(self, a, magnitude): @@ -281,9 +282,13 @@ class MagData(object): Order is: first all `x`-, then all `y`-, then all `z`-components. ''' - return np.reshape([self.magnitude[2][mask], + if mask is not None: + return np.reshape([self.magnitude[0][mask], self.magnitude[1][mask], - self.magnitude[0][mask]], -1) + self.magnitude[2][mask]], -1) + else: + return self.mag_vec + def set_vector(self, vector, mask=None): '''Set the magnetic components of the masked pixels to the values specified by `vector`. @@ -304,9 +309,9 @@ class MagData(object): assert np.size(vector) % 3 == 0, 'Vector has to contain all 3 components for every pixel!' count = np.size(vector)/3 if mask is not None: - self.magnitude[2][mask] = vector[:count] # x-component + self.magnitude[0][mask] = vector[:count] # x-component self.magnitude[1][mask] = vector[count:2*count] # y-component - self.magnitude[0][mask] = vector[2*count:] # z-component + self.magnitude[2][mask] = vector[2*count:] # z-component else: self.mag_vec = vector diff --git a/pyramid/phasemap.py b/pyramid/phasemap.py index af1e708..f5a3a4a 100644 --- a/pyramid/phasemap.py +++ b/pyramid/phasemap.py @@ -293,6 +293,7 @@ class PhaseMap(object): phase_file = netCDF4.Dataset(filename, 'r', format='NETCDF4') a = phase_file.a phase = phase_file.variables['phase'][:] + #phase = phase[28:36, 28:36] phase_file.close() return PhaseMap(a, phase) diff --git a/pyramid/phasemapper.py b/pyramid/phasemapper.py index 1d4205a..343a876 100644 --- a/pyramid/phasemapper.py +++ b/pyramid/phasemapper.py @@ -138,7 +138,9 @@ class PhaseMapperRDFC(PhaseMapper): assert len(vector) == self.m, \ 'vector size not compatible! vector: {}, size: {}'.format(len(vector), self.m) u_mag, v_mag = np.reshape(vector, (2,)+self.kernel.dim_uv) - return self._convolve(u_mag, v_mag) + result = self._convolve(u_mag, v_mag).reshape(-1) + return result + #return self.kernel._multiply_jacobi(vector) def jac_T_dot(self, vector): '''Calculate the product of the transposed Jacobi matrix with a given `vector`. @@ -161,10 +163,10 @@ class PhaseMapperRDFC(PhaseMapper): 'vector size not compatible! vector: {}, size: {}'.format(len(vector), self.n) # TODO: directly? ask Jörn again! result = np.zeros(self.m) + v_dim, u_dim = self.kernel.dim_uv nc.jac_T_dot_real_convolve(self.kernel.dim_uv[0], self.kernel.dim_uv[1], self.kernel.u, self.kernel.v, vector, result) - return result - + return self.kernel._multiply_jacobi_T(vector) class PhaseMapperRDRC(PhaseMapper): @@ -317,8 +319,8 @@ class PhaseMapperRDRC(PhaseMapper): u_max = (2*u_dim-1) - i # = u_min + u_dim v_min = (v_dim-1) - j # v_dim-1: center of the kernel v_max = (2*v_dim-1) - j # = v_min + v_dim - result[s] = np.sum(vector*self.u[v_min:v_max, u_min:u_max].reshape(-1)) - result[s+self.n] = np.sum(vector*-self.v[v_min:v_max, u_min:u_max].reshape(-1)) + result[s] = np.sum(vector*self.kernel.u[v_min:v_max, u_min:u_max].reshape(-1)) + result[s+self.n] = np.sum(vector*-self.kernel.v[v_min:v_max, u_min:u_max].reshape(-1)) return result diff --git a/pyramid/reconstruction.py b/pyramid/reconstruction.py index 1eff2ea..d8d6640 100644 --- a/pyramid/reconstruction.py +++ b/pyramid/reconstruction.py @@ -119,11 +119,11 @@ def optimize_linear(data, regularisator=None, maxiter=1000, verbosity=0): fwd_model = ForwardModel(data) cost = Costfunction(data, regularisator) print cost(np.zeros(cost.n)) - x_opt = jutil.cg.conj_grad_minimize(cost) + x_opt = jutil.cg.conj_grad_minimize(cost, max_iter=20) print cost(x_opt) # Create and return fitting MagData object: mag_opt = MagData(data.a, np.zeros((3,)+data.dim)) - mag_opt.mag_vec = x_opt + mag_opt.set_vector(x_opt, data.mask) return mag_opt @@ -152,15 +152,38 @@ def optimize_nonlin(data, first_guess=None, regularisator=None): LOG.debug('Calling optimize_cg') if first_guess is None: first_guess = MagData(data.a, np.zeros((3,)+data.dim)) - x_0 = first_guess.mag_vec + x_0 = first_guess.get_vector(data.mask) fwd_model = ForwardModel(data) cost = Costfunction(data, regularisator) + +# proj = fwd_model.data_set.projectors[0] +# proj_jac1 = np.array([proj.jac_dot(np.eye(proj.m, 1, -i).squeeze()) for i in range(proj.m)]) +# proj_jac2 = np.array([proj.jac_T_dot(np.eye(proj.n, 1, -i).squeeze()) for i in range(proj.n)]) +# print jac1, jac2.T, abs(jac1-jac2.T).sum() +# print jac1.shape, jac2.shape + +# pm = fwd_model.phase_mappers[proj.dim_uv] +# pm_jac1 = np.array([pm.jac_dot(np.eye(pm.m)[:, i]) for i in range(pm.m)]) +# pm_jac2 = np.array([pm.jac_T_dot(np.eye(pm.n)[:, i]) for i in range(pm.n)]) +# print jac1, jac2.T, abs(jac1-jac2.T).sum() +# print jac1.shape, jac2.shape + + + # jac1 = np.array([fwd_model.jac_dot(x_0, np.eye(fwd_model.m)[:, i]) for i in range(fwd_model.m)]) + # jac2 = np.array([fwd_model.jac_T_dot(x_0, np.eye(fwd_model.n)[:, i]) for i in range(fwd_model.n)]) + # print proj_jac1.dot(pm_jac1) + # print (pm_jac2.dot(proj_jac2)).T + # print jac1 +# print jac2.T +# print abs(jac1-jac2.T).sum() +# print jac1.shape, jac2.shape + assert len(x_0) == cost.n, (len(x_0), cost.m, cost.n) - result = jutil.minimizer.minimize(cost, x_0, options={"conv_rel":1e-20}, tol={"max_iteration":1}) + result = jutil.minimizer.minimize(cost, x_0, options={"conv_rel":1e-2}, tol={"max_iteration":4}) x_opt = result.x print cost(x_opt) mag_opt = MagData(data.a, np.zeros((3,)+data.dim)) - mag_opt.mag_vec = x_opt + mag_opt.set_vector(x_opt, data.mask) return mag_opt diff --git a/pyramid/regularisator.py b/pyramid/regularisator.py index bd06648..5f4c2cf 100644 --- a/pyramid/regularisator.py +++ b/pyramid/regularisator.py @@ -110,28 +110,14 @@ class ZeroOrderRegularisator(Regularisator): self.LOG.debug('Created '+str(self)) -#class FirstOrderRegularisator(Regularisator): -# # TODO: Docstring! -# -# def __init__(self, fwd_model, lam, x_a=None): -# size_3d = fwd_model.size_3d -# dim = fwd_model.dim -# converter = IndexConverter(dim) -# row = [] -# col = [] -# data = [] -# -# for i in range(size_3d): -# neighbours = converter.find_neighbour_ind(i) -# -# Sa_inv = csr_matrix(coo_matrix(data, (rows, columns)), shape=(3*size_3d, 3*size_3d)) -# -# term2 = [] -# for i in range(3): -# component = mag_data[i, ...] -# for j in range(3): -# if component.shape[j] > 1: -# term2.append(np.diff(component, axis=j).reshape(-1)) -# -# super(FirstOrderRegularisator, self).__init__(Sa_inv, x_a) -# self.LOG.debug('Created '+str(self)) +class FirstOrderRegularisator(Regularisator): + # TODO: Docstring! + + def __init__(self, mask, lam, x_a=None): + import jutil + D0 = jutil.diff.get_diff_operator(mask, 0, 3) + D1 = jutil.diff.get_diff_operator(mask, 1, 3) + D = jutil.operator.VStack([D0, D1]) + norm = jutil.norms.WeightedL2Square(D) + super(FirstOrderRegularisator, self).__init__(norm, lam) + self.LOG.debug('Created '+str(self)) -- GitLab