From 0bfdb8964ac1529c8cb4bbf18f0974b5a0ec3daa Mon Sep 17 00:00:00 2001 From: Jan Caron <j.caron@fz-juelich.de> Date: Wed, 15 May 2013 09:50:45 +0200 Subject: [PATCH] Middle Stage of converting the program structure (not working correctly9 For Pushing Purposes --- pyramid/dataloader.py | 45 ---- pyramid/holoimage.py | 198 +++++++++--------- pyramid/magcreator.py | 94 ++++----- pyramid/magdata.py | 128 ++++++++++-- pyramid/numcore/setup.py | 30 --- pyramid/phasemap.py | 288 ++++++++------------------ pyramid/phasemapper.py | 177 ++++++++++++++++ pyramid/projector.py | 17 ++ pyramid/reconstructor.py | 7 + scripts/create_random_distribution.py | 26 ++- 10 files changed, 564 insertions(+), 446 deletions(-) delete mode 100644 pyramid/dataloader.py delete mode 100644 pyramid/numcore/setup.py create mode 100644 pyramid/phasemapper.py create mode 100644 pyramid/projector.py create mode 100644 pyramid/reconstructor.py diff --git a/pyramid/dataloader.py b/pyramid/dataloader.py deleted file mode 100644 index 5900c56..0000000 --- a/pyramid/dataloader.py +++ /dev/null @@ -1,45 +0,0 @@ -# -*- coding: utf-8 -*- -"""Load magnetization data from LLG files.""" - - -import numpy as np - - -class MagDataLLG: - - '''An object storing magnetization data loaded from a LLG-file.''' - - def __init__(self, filename): - '''Load magnetization in LLG-file format. - Arguments: - filename - the name of the file where the data are stored - Returns: - None - - ''' - scale = 1.0E-9 / 1.0E-2 #from cm to nm - data = np.genfromtxt(filename, skip_header=2) - x_dim, y_dim, z_dim = np.genfromtxt(filename, dtype=int, - skip_header=1, - skip_footer=len(data[:, 0])) - res = (data[1, 0] - data[0, 0]) / scale - x_len, y_len, z_len = [data[-1, i]/scale+res/2 for i in range(3)] - x_mag, y_mag, z_mag = [data[:, i].reshape(z_dim, y_dim, x_dim) - for i in range(3,6)] - #Reshape in Python and Igor is different, - #Python fills rows first, Igor columns! - self.filename = filename - self.res = res - self.dim = (z_dim, y_dim, x_dim) - self.length = (z_len, y_len, x_len) - self.magnitude = (z_mag, y_mag, x_mag) - - def __str__(self): - '''Return the filename of the loaded file. - Arguments: - None - Returns: - the name of the loaded file as a string - - ''' - return self.filename \ No newline at end of file diff --git a/pyramid/holoimage.py b/pyramid/holoimage.py index 756bd29..a419b18 100644 --- a/pyramid/holoimage.py +++ b/pyramid/holoimage.py @@ -9,111 +9,117 @@ from numpy import pi from PIL import Image -CDICT = {'red': [(0.00, 1.0, 0.0), - (0.25, 1.0, 1.0), - (0.50, 1.0, 1.0), - (0.75, 0.0, 0.0), - (1.00, 0.0, 1.0)], - - 'green': [(0.00, 0.0, 0.0), - (0.25, 0.0, 0.0), - (0.50, 1.0, 1.0), - (0.75, 1.0, 1.0), - (1.00, 0.0, 1.0)], - - 'blue': [(0.00, 1.0, 1.0), - (0.25, 0.0, 0.0), - (0.50, 0.0, 0.0), - (0.75, 0.0, 0.0), - (1.00, 1.0, 1.0)]} - -HOLO_CMAP = mpl.colors.LinearSegmentedColormap('my_colormap', CDICT, 256) - - -def holo_image(phase, res, density): - '''Returns a holography image with color-encoded gradient direction. - Arguments: - phase - the phasemap that should be displayed - res - the resolution of the phasemap - density - the factor for determining the number of contour lines - Returns: - Image - - ''' - img_holo = (1 + np.cos(density * phase * pi/2)) /2 +class HoloImage: - phase_grad_y, phase_grad_x = np.gradient(phase, res, res) + '''An object storing magnetization data.''' - phase_angle = (1 - np.arctan2(phase_grad_y, phase_grad_x)/pi) / 2 - - # TODO: Delete -# import pdb; pdb.set_trace() + + CDICT = {'red': [(0.00, 1.0, 0.0), + (0.25, 1.0, 1.0), + (0.50, 1.0, 1.0), + (0.75, 0.0, 0.0), + (1.00, 0.0, 1.0)], - phase_magnitude = np.hypot(phase_grad_x, phase_grad_y) - phase_magnitude /= phase_magnitude.max() - phase_magnitude = np.sin(phase_magnitude * pi / 2) + 'green': [(0.00, 0.0, 0.0), + (0.25, 0.0, 0.0), + (0.50, 1.0, 1.0), + (0.75, 1.0, 1.0), + (1.00, 0.0, 1.0)], - cmap = HOLO_CMAP - rgba_img = cmap(phase_angle) - rgb_img = np.delete(rgba_img, 3, 2) - red, green, blue = rgb_img[:, :, 0], rgb_img[:, :, 1], rgb_img[:, :, 2] - red *= 255.999 * img_holo * phase_magnitude - green *= 255.999 * img_holo * phase_magnitude - blue *= 255.999 * img_holo * phase_magnitude - rgb = np.dstack((red, green, blue)).astype(np.uint8) - # TODO: Which one? - rgb = (255.999 * img_holo.T * phase_magnitude.T - * rgba_img[:, :, :3].T).T.astype(np.uint8) - img = Image.fromarray(rgb) + 'blue': [(0.00, 1.0, 1.0), + (0.25, 0.0, 0.0), + (0.50, 0.0, 0.0), + (0.75, 0.0, 0.0), + (1.00, 1.0, 1.0)]} + + HOLO_CMAP = mpl.colors.LinearSegmentedColormap('my_colormap', CDICT, 256) - return img - -def make_color_wheel(): - '''Display a color wheel for the gradient direction. - Arguments: - None - Returns: - None + def __init__(self, phase, res, density): + '''Returns a holography image with color-encoded gradient direction. + Arguments: + phase - the phasemap that should be displayed + res - the resolution of the phasemap + density - the factor for determining the number of contour lines + Returns: + Image + + ''' + img_holo = (1 + np.cos(density * phase * pi/2)) /2 - ''' - x = np.linspace(-256, 256, num=512) - y = np.linspace(-256, 256, num=512) - xx, yy = np.meshgrid(x, y) - color_wheel_angle = (1 - np.arctan2(xx, -yy)/pi) / 2 + phase_grad_y, phase_grad_x = np.gradient(phase, res, res) + + phase_angle = (1 - np.arctan2(phase_grad_y, phase_grad_x)/pi) / 2 + + # TODO: Delete + # import pdb; pdb.set_trace() + + phase_magnitude = np.hypot(phase_grad_x, phase_grad_y) + phase_magnitude /= phase_magnitude.max() + phase_magnitude = np.sin(phase_magnitude * pi / 2) + + cmap = HoloImage.HOLO_CMAP + rgba_img = cmap(phase_angle) + rgb_img = np.delete(rgba_img, 3, 2) + red, green, blue = rgb_img[:, :, 0], rgb_img[:, :, 1], rgb_img[:, :, 2] + red *= 255.999 * img_holo * phase_magnitude + green *= 255.999 * img_holo * phase_magnitude + blue *= 255.999 * img_holo * phase_magnitude + rgb = np.dstack((red, green, blue)).astype(np.uint8) + # TODO: Which one? + rgb = (255.999 * img_holo.T * phase_magnitude.T + * rgba_img[:, :, :3].T).T.astype(np.uint8) + img = Image.fromarray(rgb) + + self.image = img - r = np.sqrt(xx ** 2 + yy ** 2) - color_wheel_magnitude = (1 - np.cos(r * pi/360)) / 2 - color_wheel_magnitude *= 0 * (r > 256) + 1 * (r <= 256) - - cmap = HOLO_CMAP - rgba_img = cmap(color_wheel_angle) - rgb_img = np.delete(rgba_img, 3, 2) - red, green, blue = rgb_img[:, :, 0], rgb_img[:, :, 1], rgb_img[:, :, 2] - red *= 255.999 * color_wheel_magnitude - green *= 255.999 * color_wheel_magnitude - blue *= 255.999 * color_wheel_magnitude - #rgb = np.dstack((red, green, blue)).astype(np.uint8) - # TODO Evtl. einfacher: - rgb = (255.999 * color_wheel_magnitude.T * rgba_img[:, :, :3].T).T.astype(np.uint8) - color_wheel = Image.fromarray(rgb) - - fig = plt.figure() - ax = fig.add_subplot(111, aspect='equal') - ax.imshow(color_wheel) - ax.set_title('Color Wheel') - ax.set_xlabel('x-axis') - ax.set_ylabel('y-axis') - -def display_holo(holo, title, axis=None): - # TODO: Docstring - if axis == None: + @classmethod + def make_color_wheel(self): + '''Display a color wheel for the gradient direction. + Arguments: + None + Returns: + None + + ''' + x = np.linspace(-256, 256, num=512) + y = np.linspace(-256, 256, num=512) + xx, yy = np.meshgrid(x, y) + color_wheel_angle = (1 - np.arctan2(xx, -yy)/pi) / 2 + + r = np.sqrt(xx ** 2 + yy ** 2) + color_wheel_magnitude = (1 - np.cos(r * pi/360)) / 2 + color_wheel_magnitude *= 0 * (r > 256) + 1 * (r <= 256) + + cmap = HoloImage.HOLO_CMAP + rgba_img = cmap(color_wheel_angle) + rgb_img = np.delete(rgba_img, 3, 2) + red, green, blue = rgb_img[:, :, 0], rgb_img[:, :, 1], rgb_img[:, :, 2] + red *= 255.999 * color_wheel_magnitude + green *= 255.999 * color_wheel_magnitude + blue *= 255.999 * color_wheel_magnitude + #rgb = np.dstack((red, green, blue)).astype(np.uint8) + # TODO Evtl. einfacher: + rgb = (255.999 * color_wheel_magnitude.T * rgba_img[:, :, :3].T).T.astype(np.uint8) + color_wheel = Image.fromarray(rgb) + fig = plt.figure() - axis = fig.add_subplot(1,1,1, aspect='equal') + ax = fig.add_subplot(111, aspect='equal') + ax.imshow(color_wheel) + ax.set_title('Color Wheel') + ax.set_xlabel('x-axis') + ax.set_ylabel('y-axis') - axis.imshow(holo) - axis.set_title(title) - axis.set_xlabel('x-axis') - axis.set_ylabel('y-axis') \ No newline at end of file + def display_holo(holo, title, axis=None): + # TODO: Docstring + if axis == None: + fig = plt.figure() + axis = fig.add_subplot(1,1,1, aspect='equal') + + axis.imshow(holo) + + axis.set_title(title) + axis.set_xlabel('x-axis') + axis.set_ylabel('y-axis') \ No newline at end of file diff --git a/pyramid/magcreator.py b/pyramid/magcreator.py index a497325..7ad98ef 100644 --- a/pyramid/magcreator.py +++ b/pyramid/magcreator.py @@ -1,11 +1,12 @@ # -*- coding: utf-8 -*- """Create simple LLG Files which describe magnetization in 2D (z-Dim=1).""" + import numpy as np -import matplotlib.pyplot as plt +from magdata import MagData -def slab(dim, center, width): +def shape_slab(dim, center, width): '''Get the magnetic shape of a slab. Arguments: dim - the dimensions of the grid, shape(y, x) @@ -15,13 +16,14 @@ def slab(dim, center, width): the magnetic shape as a 2D-boolean-array. ''' - mag_shape = np.array([[abs(x - center[1]) <= width[1] / 2 - and abs(y - center[0]) <= width[0] / 2 - for x in range(dim[1])] for y in range(dim[0])]) + mag_shape = np.array([[[abs(x - center[2]) <= width[2] / 2 + and abs(y - center[1]) <= width[1] / 2 + and abs(z - center[0]) <= width[0] / 2 + for x in range(dim[2])] for y in range(dim[1])] for z in range(dim[0])]) return mag_shape -def disc(dim, center, radius): +def shape_disc(dim, center, radius, height): '''Get the magnetic shape of a disc. Arguments: dim - the dimensions of the grid, shape(y, x) @@ -30,13 +32,14 @@ def disc(dim, center, radius): Returns: the magnetic shape as a 2D-boolean-array. - ''' - mag_shape = np.array([[(np.hypot(x-center[1], y-center[0]) <= radius) - for x in range(dim[1])] for y in range(dim[0])]) + '''# TODO: up till now only in z-direction + mag_shape = np.array([[[np.hypot(x - center[2], y - center[1]) <= radius + and abs(z - center[0]) <= height / 2 + for x in range(dim[2])] for y in range(dim[1])] for z in range(dim[0])]) return mag_shape -def filament(dim, pos, x_or_y): +def shape_filament(dim, pos, x_or_y): '''Get the magnetic shape of a single filament in x or y direction. Arguments: dim - the dimensions of the grid, shape(y, x) @@ -46,16 +49,16 @@ def filament(dim, pos, x_or_y): Returns: the magnetic shape as a 2D-boolean-array. - ''' + '''# TODO: up till now no z-direction mag_shape = np.zeros(dim) if x_or_y == 'y': - mag_shape[:, pos] = 1 + mag_shape[:, :, pos] = 1 else: - mag_shape[pos, :] = 1 + mag_shape[:, pos, :] = 1 return mag_shape -def alternating_filaments(dim, spacing, x_or_y): +def shape_alternating_filaments(dim, spacing, x_or_y): '''Get the magnetic shape of alternating filaments in x or y direction. Arguments: dim - the dimensions of the grid, shape(y, x) @@ -68,16 +71,15 @@ def alternating_filaments(dim, spacing, x_or_y): ''' mag_shape = np.zeros(dim) if x_or_y == 'y': - # TODO: List comprehension: for i in range(0, dim[1], spacing): - mag_shape[:, i] = 1 - 2 * (int(i / spacing) % 2) # 1 or -1 + mag_shape[:, :, i] = 1 - 2 * (int(i / spacing) % 2) # 1 or -1 else: for i in range(0, dim[0], spacing): - mag_shape[i, :] = 1 - 2 * (int(i / spacing) % 2) # 1 or -1 + mag_shape[:, i, :] = 1 - 2 * (int(i / spacing) % 2) # 1 or -1 return mag_shape -def single_pixel(dim, pixel): +def shape_single_pixel(dim, pixel): '''Get the magnetic shape of a single magnetized pixel. Arguments: dim - the dimensions of the grid, shape(y, x) @@ -87,11 +89,11 @@ def single_pixel(dim, pixel): ''' mag_shape = np.zeros(dim) - mag_shape[pixel[0], pixel[1]] = 1 + mag_shape[pixel] = 1 return mag_shape -def create_hom_mag(dim, res, beta, mag_shape, filename='output.txt', plot_mag_distr=False): +def hom_mag(dim, res, mag_shape, beta, magnitude=1): '''Create homog. magnetization data, saved in a file with LLG-format. Arguments: dim - the dimensions of the grid, shape(y, x) @@ -104,33 +106,27 @@ def create_hom_mag(dim, res, beta, mag_shape, filename='output.txt', plot_mag_di Returns: the the magnetic distribution as a 2D-boolean-array. - ''' - res *= 1.0E-9 / 1.0E-2 # from nm to cm - - x = np.linspace(res / 2, dim[1] * res - res / 2, num=dim[1]) - y = np.linspace(res / 2, dim[0] * res - res / 2, num=dim[0]) - xx, yy = np.meshgrid(x, y) - - x_mag = np.array(np.ones(dim)) * np.cos(beta) * mag_shape - y_mag = np.array(np.ones(dim)) * np.sin(beta) * mag_shape - z_mag = np.array(np.zeros(dim)) - - if (plot_mag_distr): - fig = plt.figure() - fig.add_subplot(111, aspect='equal') - plt.quiver(x_mag, y_mag, pivot='middle', angles='xy', scale_units='xy', - scale=1, headwidth=6, headlength=7) - - xx = np.reshape(xx,(-1)) - yy = np.reshape(yy,(-1)) - zz = np.array(np.ones(dim[0] * dim[1]) * res / 2) - x_mag = np.reshape(x_mag,(-1)) - y_mag = np.reshape(y_mag,(-1)) - z_mag = np.array(np.zeros(dim[0] * dim[1])) + ''' # TODO: renew Docstring + z_mag = np.array(np.zeros(dim)) + y_mag = np.array(np.ones(dim)) * np.sin(beta) * mag_shape * magnitude + x_mag = np.array(np.ones(dim)) * np.cos(beta) * mag_shape * magnitude + return z_mag, y_mag, x_mag - data = np.array([xx, yy, zz, x_mag, y_mag, z_mag]).T - with open(filename,'w') as mag_file: - mag_file.write('LLGFileCreator2D: %s\n' % filename.replace('.txt', '')) - mag_file.write(' %d %d %d\n' % (dim[1], dim[0], 1)) - mag_file.writelines('\n'.join(' '.join('{:7.6e}'.format(cell) - for cell in row) for row in data) ) \ No newline at end of file + +def create_mag_dist(dim, res, mag_shape_list, beta_list, magnitude_list=None): + # TODO: Docstring: can take just one or a list of objects! OR JUST A LIST!!! + # If no relative magnitude is specified, 1 is assumed for every homog. object: + if magnitude_list is None: + magnitude_list = np.ones(np.size(beta_list)) + # For every shape of a homogeneous object a relative magnitude and angle have to be set: + assert (np.shape(mag_shape_list)[0],) == np.shape(beta_list) == np.shape(magnitude_list), \ + 'Lists have not the same length!' + x_mag = np.zeros(dim) + y_mag = np.zeros(dim) + z_mag = np.zeros(dim) + for i in range(np.size(beta_list)): + pixel_mag = hom_mag(dim, res, mag_shape_list[i], beta_list[i], magnitude_list[i]) + z_mag += pixel_mag[0] + y_mag += pixel_mag[1] + x_mag += pixel_mag[2] + return MagData(res, z_mag, y_mag, x_mag) \ No newline at end of file diff --git a/pyramid/magdata.py b/pyramid/magdata.py index 3d91b8d..04b883d 100644 --- a/pyramid/magdata.py +++ b/pyramid/magdata.py @@ -3,52 +3,136 @@ import numpy as np +import matplotlib.pyplot as plt +from mpl_toolkits.mplot3d import Axes3D +from matplotlib.patches import FancyArrowPatch +from mpl_toolkits.mplot3d import proj3d class MagData: - '''An object storing magnetization data loaded from a LLG-file.''' + '''An object storing magnetization data.''' - def __init__(self, x_mag, y_mag, z_mag, res): # TODO: electrostatic component! + + def __init__(self, res, z_mag, y_mag, x_mag): # TODO: electrostatic component! '''Load magnetization in LLG-file format. Arguments: filename - the name of the file where the data are stored Returns: None - ''' + '''# TODO: Docstring assert np.shape(x_mag) == np.shape(y_mag) == np.shape(z_mag), 'Dimensions do not match!' - self.res = res self.dim = np.shape(x_mag) + self.magnitude = (z_mag, y_mag, x_mag) - - - + @classmethod + def load_from_llg(self, filename): + # TODO: Docstring scale = 1.0E-9 / 1.0E-2 #from cm to nm data = np.genfromtxt(filename, skip_header=2) x_dim, y_dim, z_dim = np.genfromtxt(filename, dtype=int, skip_header=1, skip_footer=len(data[:, 0])) res = (data[1, 0] - data[0, 0]) / scale - x_len, y_len, z_len = [data[-1, i]/scale+res/2 for i in range(3)] x_mag, y_mag, z_mag = [data[:, i].reshape(z_dim, y_dim, x_dim) for i in range(3,6)] - #Reshape in Python and Igor is different, - #Python fills rows first, Igor columns! - self.filename = filename - self.res = res - self.dim = (z_dim, y_dim, x_dim) - self.length = (z_len, y_len, x_len) - self.magnitude = (z_mag, y_mag, x_mag) - - def __str__(self): - '''Return the filename of the loaded file. + #Reshape in Python and Igor is different, Python fills rows first, Igor columns! + return MagData(res, z_mag, y_mag, x_mag) + + + def save_to_llg(self, filename='output.txt'): + '''Create homog. magnetization data, saved in a file with LLG-format. Arguments: - None + dim - the dimensions of the grid, shape(y, x) + res - the resolution of the grid + (real space distance between two points) + beta - the angle of the magnetization + filename - the name of the file in which to save the data + mag_shape - an array of shape dim, representing the shape of the magnetic object, + a few are supplied in this module Returns: - the name of the loaded file as a string + the the magnetic distribution as a 2D-boolean-array. - ''' - return self.filename \ No newline at end of file + ''' # TODO: Renew Docstring + dim = self.dim + res = self.res * 1.0E-9 / 1.0E-2 # from nm to cm + + zz, yy, xx = np.mgrid[res/2 : (dim[0]*res-res/2) : dim[0]*1j, + res/2 : (dim[1]*res-res/2) : dim[1]*1j, + res/2 : (dim[2]*res-res/2) : dim[2]*1j] + + xx = np.reshape(xx,(-1)) + yy = np.reshape(yy,(-1)) + zz = np.reshape(zz,(-1)) + x_mag = np.reshape(self.magnitude[2], (-1)) + y_mag = np.reshape(self.magnitude[1], (-1)) + z_mag = np.reshape(self.magnitude[0], (-1)) + + data = np.array([xx, yy, zz, x_mag, y_mag, z_mag]).T + with open(filename,'w') as mag_file: + mag_file.write('LLGFileCreator2D: %s\n' % filename.replace('.txt', '')) + mag_file.write(' %d %d %d\n' % (dim[2], dim[1], dim[0])) + mag_file.writelines('\n'.join(' '.join('{:7.6e}'.format(cell) + for cell in row) for row in data) ) + + + def quiver_plot(self, axis='z', ax_slice=0): + # TODO: Docstring + assert axis == 'z' or axis == 'y' or axis == 'x', 'Axis has to be x, y or z (as string).' + if axis == 'z': + mag_slice_1 = self.magnitude[2][ax_slice,...] + mag_slice_2 = self.magnitude[1][ax_slice,...] + elif axis == 'y': + mag_slice_1 = self.magnitude[2][:,ax_slice,:] + mag_slice_2 = self.magnitude[0][:,ax_slice,:] + elif axis == 'x': + mag_slice_1 = self.magnitude[1][...,ax_slice] + mag_slice_2 = self.magnitude[0][...,ax_slice] + + fig = plt.figure() + fig.add_subplot(111, aspect='equal') + plt.quiver(mag_slice_1, mag_slice_2, pivot='middle', angles='xy', scale_units='xy', + scale=1, headwidth=6, headlength=7) + + + def quiver_plot_3D(self): + # TODO: Docstring + res = self.res + dim = self.dim + fig = plt.figure() + ax = fig.add_subplot(111, projection='3d') + ax.set_aspect("equal") + + class Arrow3D(FancyArrowPatch): + def __init__(self, xs, ys, zs, *args, **kwargs): + FancyArrowPatch.__init__(self, (0,0), (0,0), *args, **kwargs) + self._verts3d = xs, ys, zs + def draw(self, renderer): + xs3d, ys3d, zs3d = self._verts3d + xs, ys, zs = proj3d.proj_transform(xs3d, ys3d, zs3d, renderer.M) + self.set_positions((xs[0],ys[0]),(xs[1],ys[1])) + FancyArrowPatch.draw(self, renderer) + + zz, yy, xx = np.mgrid[res/2 : (dim[0]*res-res/2) : dim[0]*1j, + res/2 : (dim[1]*res-res/2) : dim[1]*1j, + res/2 : (dim[2]*res-res/2) : dim[2]*1j] + xx = np.reshape(xx, (-1)) + yy = np.reshape(yy, (-1)) + zz = np.reshape(zz, (-1)) + x_mag = np.reshape(self.magnitude[2], (-1)) + y_mag = np.reshape(self.magnitude[1], (-1)) + z_mag = np.reshape(self.magnitude[0], (-1)) + + for i in range(np.size(xx)): + xs = [xx[i] - x_mag[i]*res/2, xx[i] + x_mag[i]*res/2] + ys = [yy[i] - y_mag[i]*res/2, yy[i] + y_mag[i]*res/2] + zs = [zz[i] - z_mag[i]*res/2, zz[i] + z_mag[i]*res/2] + a = Arrow3D(xs, ys, zs, mutation_scale=10, lw=1, arrowstyle="-|>", color="k") + ax.add_artist(a) + ax.set_xlim3d(0, xx[-1]+res/2) + ax.set_ylim3d(0, yy[-1]+res/2) + ax.set_zlim3d(0, zz[-1]+res/2) + plt.show() \ No newline at end of file diff --git a/pyramid/numcore/setup.py b/pyramid/numcore/setup.py deleted file mode 100644 index b31924c..0000000 --- a/pyramid/numcore/setup.py +++ /dev/null @@ -1,30 +0,0 @@ -""" -Created on Fri May 03 10:27:04 2013 - -@author: Jan -""" - -#call with: python setup.py build_ext --inplace --compiler=mingw32 - -import glob -import numpy -from distutils.core import setup -from distutils.extension import Extension -from Cython.Build import cythonize -from Cython.Distutils import build_ext - -#setup( -# cmdclass = {'build_ext': build_ext}, -# ext_modules = [Extension("multiply", -# sources=["multiply.pyx", "c_multiply.c"], -# include_dirs=[numpy.get_include()])], -#) - -setup( - name = 'Pyramex', - version = '0.1', - description = 'Pyramid Cython Extensions', - author = 'Jan Caron', - author_email = 'j.caron@fz-juelich.de', - ext_modules = cythonize(glob.glob('*.pyx')) -) diff --git a/pyramid/phasemap.py b/pyramid/phasemap.py index 60c639d..84e4efc 100644 --- a/pyramid/phasemap.py +++ b/pyramid/phasemap.py @@ -1,209 +1,105 @@ # -*- coding: utf-8 -*- -"""Create and display a phase map from magnetization data.""" +""" +Created on Mon May 13 16:00:57 2013 +@author: Jan +""" -import numpy as np -import matplotlib.pyplot as plt -from numpy import pi - - -PHI_0 = 2067.83 # magnetic flux in T*nm² -H_BAR = 6.626E-34 # TODO: unit -M_E = 9.109E-31 # TODO: unit -Q_E = 1.602E-19 # TODO: unit -C = 2.998E8 # TODO: unit - - -def fourier_space(mag_data, b_0=1, padding=0): - '''Calculate phasemap from magnetization data (fourier approach). - Arguments: - mag_data - MagDataLLG object (from magneticimaging.dataloader) storing - the filename, coordinates and magnetization in x, y and z - b_0 - magnetic induction corresponding to a magnetization Mo in T - (default: 1) - padding - factor for zero padding, the default is 0 (no padding), for - a factor of n the number of pixels is increase by (1+n)**2, - padded zeros are cropped at the end - v_0 - average potential of the sample in V (default: 0) - v_acc - acceleration voltage of the microscop in V (default: 30000) - Returns: - the phasemap as a 2 dimensional array - - ''' - res = mag_data.res - z_dim, y_dim, x_dim = mag_data.dim - z_mag, y_mag, x_mag = mag_data.magnitude +class PhaseMap: - # TODO: interpolation (redefine xDim,yDim,zDim) thickness ramp + '''An object storing magnetization data.''' - x_pad = x_dim/2 * padding - y_pad = y_dim/2 * padding - x_mag_big = np.zeros(((1 + padding) * y_dim, (1 + padding) * x_dim)) - y_mag_big = np.zeros(((1 + padding) * y_dim, (1 + padding) * x_dim)) - # TODO: padding so that x_dim and y_dim = 2^n - x_mag_big[y_pad : y_pad + y_dim, x_pad : x_pad + x_dim] = x_mag - y_mag_big[y_pad : y_pad + y_dim, x_pad : x_pad + x_dim] = y_mag - x_mag_fft = np.fft.fftshift(np.fft.rfft2(x_mag_big), axes=0) - y_mag_fft = np.fft.fftshift(np.fft.rfft2(y_mag_big), axes=0) - nyq = 1 / res # nyquist frequency - x = np.linspace( 0, nyq/2, x_mag_fft.shape[1]) - y = np.linspace( -nyq/2, nyq/2, x_mag_fft.shape[0]+1)[:-1] - xx, yy = np.meshgrid(x, y) - - phase_fft = (1j * res * b_0) / (2 * PHI_0) * ((x_mag_fft * yy - y_mag_fft * xx) - / (xx ** 2 + yy ** 2 + 1e-18)) - phase_big = np.fft.irfft2(np.fft.ifftshift(phase_fft, axes=0)) - - phase = phase_big[y_pad : y_pad + y_dim, x_pad : x_pad + x_dim] - - # TODO: Electrostatic Component - - return phase - - -def phi_pixel(method, n, m, res, b_0): # TODO: rename - if method == 'slab': - def F_h(n, m): - a = np.log(res**2 * (n**2 + m**2)) - b = np.arctan(n / m) - return n*a - 2*n + 2*m*b - coeff = -b_0 * res**2 / ( 2 * PHI_0 ) - return coeff * 0.5 * ( F_h(n-0.5, m-0.5) - F_h(n+0.5, m-0.5) - -F_h(n-0.5, m+0.5) + F_h(n+0.5, m+0.5) ) - elif method == 'disc': - coeff = - b_0 * res**2 / ( 2 * PHI_0 ) - in_or_out = np.logical_not(np.logical_and(n == 0, m == 0)) - return coeff * m / (n**2 + m**2 + 1E-30) * in_or_out - - -def real_space(mag_data, method, b_0=1, jacobi=None): - '''Calculate phasemap from magnetization data (real space approach). - Arguments: - mag_data - MagDataLLG object (from magneticimaging.dataloader) storing the filename, - coordinates and magnetization in x, y and z - Returns: - the phasemap as a 2 dimensional array + def __init__(self, phase): # TODO: more arguments? + '''Load magnetization in LLG-file format. + Arguments: + filename - the name of the file where the data are stored + Returns: + None - ''' - # TODO: Expand docstring! - - res = mag_data.res - z_dim, y_dim, x_dim = mag_data.dim - z_mag, y_mag, x_mag = mag_data.magnitude - - # TODO: proper projection algorithm - x_mag, y_mag, z_mag = x_mag.mean(0), y_mag.mean(0), z_mag.mean(0) - - beta = np.arctan2(y_mag, x_mag) + '''# TODO: Docstring + self.phase = phase + + + def load_from_file(self, filename): # TODO: Implement + pass +# # TODO: Docstring +# scale = 1.0E-9 / 1.0E-2 #from cm to nm +# data = np.genfromtxt(filename, skip_header=2) +# x_dim, y_dim, z_dim = np.genfromtxt(filename, dtype=int, +# skip_header=1, +# skip_footer=len(data[:, 0])) +# res = (data[1, 0] - data[0, 0]) / scale +# x_mag, y_mag, z_mag = [data[:, i].reshape(z_dim, y_dim, x_dim) +# for i in range(3,6)] +# #Reshape in Python and Igor is different, Python fills rows first, Igor columns! +# return MagData(res, z_mag, y_mag, x_mag) - mag = np.hypot(x_mag, y_mag) - - '''CREATE COORDINATE GRIDS''' - x = np.linspace(0,(x_dim-1),num=x_dim) - y = np.linspace(0,(y_dim-1),num=y_dim) - xx, yy = np.meshgrid(x,y) - - x_big = np.linspace(-(x_dim-1), x_dim-1, num=2*x_dim-1) - y_big = np.linspace(-(y_dim-1), y_dim-1, num=2*y_dim-1) - xx_big, yy_big = np.meshgrid(x_big, y_big) - - phi_cos = phi_pixel(method, xx_big, yy_big, res, b_0) - phi_sin = phi_pixel(method, yy_big, xx_big, res, b_0) - - def phi_mag(i, j): # TODO: rename - return (np.cos(beta[j,i])*phi_cos[y_dim-1-j:(2*y_dim-1)-j, x_dim-1-i:(2*x_dim-1)-i] - -np.sin(beta[j,i])*phi_sin[y_dim-1-j:(2*y_dim-1)-j, x_dim-1-i:(2*x_dim-1)-i]) - - def phi_mag_deriv(i, j): # TODO: rename - return -(np.sin(beta[j,i])*phi_cos[y_dim-1-j:(2*y_dim-1)-j, x_dim-1-i:(2*x_dim-1)-i] - +np.cos(beta[j,i])*phi_sin[y_dim-1-j:(2*y_dim-1)-j, x_dim-1-i:(2*x_dim-1)-i]) - - def phi_mag_fd(i, j, h): # TODO: rename - return ((np.cos(beta[j,i]+h) - np.cos(beta[j,i])) / h - * phi_cos[y_dim-1-j:(2*y_dim-1)-j, x_dim-1-i:(2*x_dim-1)-i] - -(np.sin(beta[j,i]+h) - np.sin(beta[j,i])) / h - * phi_sin[y_dim-1-j:(2*y_dim-1)-j, x_dim-1-i:(2*x_dim-1)-i]) - - '''CALCULATE THE PHASE''' - phase = np.zeros((y_dim, x_dim)) - - # TODO: only iterate over pixels that have a magn. > threshold (first >0) - if jacobi is not None: - jacobi_fd = jacobi.copy() - h = 0.0001 - - for j in range(y_dim): - for i in range(x_dim): - #if (mag[j,i] != 0 ):#or jacobi is not None): # TODO: same result with or without? - phi_mag_cache = phi_mag(i, j) - phase += mag[j,i] * phi_mag_cache - if jacobi is not None: - jacobi[:,i+x_dim*j] = phi_mag_cache.reshape(-1) - jacobi[:,x_dim*y_dim+i+x_dim*j] = (mag[j,i]*phi_mag_deriv(i,j)).reshape(-1) - - jacobi_fd[:,i+x_dim*j] = phi_mag_cache.reshape(-1) - jacobi_fd[:,x_dim*y_dim+i+x_dim*j] = (mag[j,i]*phi_mag_fd(i,j,h)).reshape(-1) - - - - if jacobi is not None: - jacobi_diff = jacobi_fd - jacobi - assert (np.abs(jacobi_diff) < 1.0E-8).all(), 'jacobi matrix is not the same' - - return phase - -def phase_elec(mag_data, b_0=1, v_0=0, v_acc=30000): - # TODO: Docstring + def save_to_file(self, filename='output.txt'): # TODO: Implement + pass +# '''Create homog. magnetization data, saved in a file with LLG-format. +# Arguments: +# dim - the dimensions of the grid, shape(y, x) +# res - the resolution of the grid +# (real space distance between two points) +# beta - the angle of the magnetization +# filename - the name of the file in which to save the data +# mag_shape - an array of shape dim, representing the shape of the magnetic object, +# a few are supplied in this module +# Returns: +# the the magnetic distribution as a 2D-boolean-array. +# +# ''' # TODO: Renew Docstring +# dim = self.dim +# res = self.res * 1.0E-9 / 1.0E-2 # from nm to cm +# +# zz, yy, xx = np.mgrid[res/2 : (dim[0]*res-res/2) : dim[0]*1j, +# res/2 : (dim[1]*res-res/2) : dim[1]*1j, +# res/2 : (dim[2]*res-res/2) : dim[2]*1j] +# +# xx = np.reshape(xx,(-1)) +# yy = np.reshape(yy,(-1)) +# zz = np.reshape(zz,(-1)) +# x_mag = np.reshape(self.magnitude[2], (-1)) +# y_mag = np.reshape(self.magnitude[1], (-1)) +# z_mag = np.reshape(self.magnitude[0], (-1)) +# +# data = np.array([xx, yy, zz, x_mag, y_mag, z_mag]).T +# with open(filename,'w') as mag_file: +# mag_file.write('LLGFileCreator2D: %s\n' % filename.replace('.txt', '')) +# mag_file.write(' %d %d %d\n' % (dim[2], dim[1], dim[0])) +# mag_file.writelines('\n'.join(' '.join('{:7.6e}'.format(cell) +# for cell in row) for row in data) ) - # TODO: Delete -# import pdb; pdb.set_trace() - - res = mag_data.res - z_dim, y_dim, x_dim = mag_data.dim - z_mag, y_mag, x_mag = mag_data.magnitude - - phase = np.logical_or(x_mag, y_mag, z_mag) - - lam = H_BAR / np.sqrt(2 * M_E * v_acc * (1 + Q_E*v_acc / (2*M_E*C**2))) - - Ce = (2*pi*Q_E/lam * (Q_E*v_acc + M_E*C**2) / - (Q_E*v_acc * (Q_E*v_acc + 2*M_E*C**2))) - - phase *= res * v_0 * Ce - - return phase - - -def display_phase(phase, res, title, axis=None): - '''Display the phasemap as a colormesh. - Arguments: - phase - the phasemap that should be displayed - res - the resolution of the phasemap - title - the title of the plot - Returns: - None + def display_phase(self, res, title, axis=None): + '''Display the phasemap as a colormesh. + Arguments: + phase - the phasemap that should be displayed + res - the resolution of the phasemap + title - the title of the plot + Returns: + None + + ''' + if axis == None: + fig = plt.figure() + axis = fig.add_subplot(1,1,1, aspect='equal') - ''' - if axis == None: - fig = plt.figure() - axis = fig.add_subplot(1,1,1, aspect='equal') + im = plt.pcolormesh(phase, cmap='gray') - im = plt.pcolormesh(phase, cmap='gray') - - ticks = axis.get_xticks()*res - axis.set_xticklabels(ticks) - ticks = axis.get_yticks()*res - axis.set_yticklabels(ticks) - - axis.set_title(title) - axis.set_xlabel('x-axis [nm]') - axis.set_ylabel('y-axis [nm]') - - fig = plt.gcf() - fig.subplots_adjust(right=0.85) - cbar_ax = fig.add_axes([0.9, 0.15, 0.02, 0.7]) - fig.colorbar(im, cax=cbar_ax) + ticks = axis.get_xticks()*res + axis.set_xticklabels(ticks) + ticks = axis.get_yticks()*res + axis.set_yticklabels(ticks) - plt.show() \ No newline at end of file + axis.set_title(title) + axis.set_xlabel('x-axis [nm]') + axis.set_ylabel('y-axis [nm]') + + fig = plt.gcf() + fig.subplots_adjust(right=0.85) + cbar_ax = fig.add_axes([0.9, 0.15, 0.02, 0.7]) + fig.colorbar(im, cax=cbar_ax) + + plt.show() \ No newline at end of file diff --git a/pyramid/phasemapper.py b/pyramid/phasemapper.py new file mode 100644 index 0000000..53f7888 --- /dev/null +++ b/pyramid/phasemapper.py @@ -0,0 +1,177 @@ +# -*- coding: utf-8 -*- +"""Create and display a phase map from magnetization data.""" + + +import numpy as np +import matplotlib.pyplot as plt +import pyramid.projector as pj +from numpy import pi +from phasemap import PhaseMap + + +PHI_0 = 2067.83 # magnetic flux in T*nm² +H_BAR = 6.626E-34 # TODO: unit +M_E = 9.109E-31 # TODO: unit +Q_E = 1.602E-19 # TODO: unit +C = 2.998E8 # TODO: unit + + +def fourier_space(mag_data, b_0=1, padding=0): + '''Calculate phasemap from magnetization data (fourier approach). + Arguments: + mag_data - MagDataLLG object (from magneticimaging.dataloader) storing + the filename, coordinates and magnetization in x, y and z + b_0 - magnetic induction corresponding to a magnetization Mo in T + (default: 1) + padding - factor for zero padding, the default is 0 (no padding), for + a factor of n the number of pixels is increase by (1+n)**2, + padded zeros are cropped at the end + v_0 - average potential of the sample in V (default: 0) + v_acc - acceleration voltage of the microscop in V (default: 30000) + Returns: + the phasemap as a 2 dimensional array + + ''' + res = mag_data.res + z_dim, y_dim, x_dim = mag_data.dim + z_mag, y_mag, x_mag = pj.simple_axis_projection(mag_data)#mag_data.magnitude + + # TODO: interpolation (redefine xDim,yDim,zDim) thickness ramp + + x_pad = x_dim/2 * padding + y_pad = y_dim/2 * padding + x_mag_big = np.zeros(((1 + padding) * y_dim, (1 + padding) * x_dim)) + y_mag_big = np.zeros(((1 + padding) * y_dim, (1 + padding) * x_dim)) + # TODO: padding so that x_dim and y_dim = 2^n + x_mag_big[y_pad : y_pad + y_dim, x_pad : x_pad + x_dim] = x_mag + y_mag_big[y_pad : y_pad + y_dim, x_pad : x_pad + x_dim] = y_mag + + x_mag_fft = np.fft.fftshift(np.fft.rfft2(x_mag_big), axes=0) + y_mag_fft = np.fft.fftshift(np.fft.rfft2(y_mag_big), axes=0) + nyq = 1 / res # nyquist frequency + x = np.linspace( 0, nyq/2, x_mag_fft.shape[1]) + y = np.linspace( -nyq/2, nyq/2, x_mag_fft.shape[0]+1)[:-1] + xx, yy = np.meshgrid(x, y) + + phase_fft = (1j * res * b_0) / (2 * PHI_0) * ((x_mag_fft * yy - y_mag_fft * xx) + / (xx ** 2 + yy ** 2 + 1e-18)) + phase_big = np.fft.irfft2(np.fft.ifftshift(phase_fft, axes=0)) + + phase = phase_big[y_pad : y_pad + y_dim, x_pad : x_pad + x_dim] + + # TODO: Electrostatic Component + + return PhaseMap(phase) + + +def phi_pixel(method, n, m, res, b_0): # TODO: rename + if method == 'slab': + def F_h(n, m): + a = np.log(res**2 * (n**2 + m**2)) + b = np.arctan(n / m) + return n*a - 2*n + 2*m*b + coeff = -b_0 * res**2 / ( 2 * PHI_0 ) + return coeff * 0.5 * ( F_h(n-0.5, m-0.5) - F_h(n+0.5, m-0.5) + -F_h(n-0.5, m+0.5) + F_h(n+0.5, m+0.5) ) + elif method == 'disc': + coeff = - b_0 * res**2 / ( 2 * PHI_0 ) + in_or_out = np.logical_not(np.logical_and(n == 0, m == 0)) + return coeff * m / (n**2 + m**2 + 1E-30) * in_or_out + + +def real_space(mag_data, method, b_0=1, jacobi=None): + '''Calculate phasemap from magnetization data (real space approach). + Arguments: + mag_data - MagDataLLG object (from magneticimaging.dataloader) storing the filename, + coordinates and magnetization in x, y and z + Returns: + the phasemap as a 2 dimensional array + + ''' + # TODO: Expand docstring! + + res = mag_data.res + z_dim, y_dim, x_dim = mag_data.dim + z_mag, y_mag, x_mag = mag_data.magnitude + + z_mag, y_mag, x_mag = pj.simple_axis_projection(mag_data) + + beta = np.arctan2(y_mag, x_mag) + + mag = np.hypot(x_mag, y_mag) + + '''CREATE COORDINATE GRIDS''' + x = np.linspace(0,(x_dim-1),num=x_dim) + y = np.linspace(0,(y_dim-1),num=y_dim) + xx, yy = np.meshgrid(x,y) + + x_big = np.linspace(-(x_dim-1), x_dim-1, num=2*x_dim-1) + y_big = np.linspace(-(y_dim-1), y_dim-1, num=2*y_dim-1) + xx_big, yy_big = np.meshgrid(x_big, y_big) + + phi_cos = phi_pixel(method, xx_big, yy_big, res, b_0) + phi_sin = phi_pixel(method, yy_big, xx_big, res, b_0) + + def phi_mag(i, j): # TODO: rename + return (np.cos(beta[j,i])*phi_cos[y_dim-1-j:(2*y_dim-1)-j, x_dim-1-i:(2*x_dim-1)-i] + -np.sin(beta[j,i])*phi_sin[y_dim-1-j:(2*y_dim-1)-j, x_dim-1-i:(2*x_dim-1)-i]) + + def phi_mag_deriv(i, j): # TODO: rename + return -(np.sin(beta[j,i])*phi_cos[y_dim-1-j:(2*y_dim-1)-j, x_dim-1-i:(2*x_dim-1)-i] + +np.cos(beta[j,i])*phi_sin[y_dim-1-j:(2*y_dim-1)-j, x_dim-1-i:(2*x_dim-1)-i]) + + def phi_mag_fd(i, j, h): # TODO: rename + return ((np.cos(beta[j,i]+h) - np.cos(beta[j,i])) / h + * phi_cos[y_dim-1-j:(2*y_dim-1)-j, x_dim-1-i:(2*x_dim-1)-i] + -(np.sin(beta[j,i]+h) - np.sin(beta[j,i])) / h + * phi_sin[y_dim-1-j:(2*y_dim-1)-j, x_dim-1-i:(2*x_dim-1)-i]) + + '''CALCULATE THE PHASE''' + phase = np.zeros((y_dim, x_dim)) + + # TODO: only iterate over pixels that have a magn. > threshold (first >0) + if jacobi is not None: + jacobi_fd = jacobi.copy() + h = 0.0001 + + for j in range(y_dim): + for i in range(x_dim): + #if (mag[j,i] != 0 ):#or jacobi is not None): # TODO: same result with or without? + phi_mag_cache = phi_mag(i, j) + phase += mag[j,i] * phi_mag_cache + if jacobi is not None: + jacobi[:,i+x_dim*j] = phi_mag_cache.reshape(-1) + jacobi[:,x_dim*y_dim+i+x_dim*j] = (mag[j,i]*phi_mag_deriv(i,j)).reshape(-1) + + jacobi_fd[:,i+x_dim*j] = phi_mag_cache.reshape(-1) + jacobi_fd[:,x_dim*y_dim+i+x_dim*j] = (mag[j,i]*phi_mag_fd(i,j,h)).reshape(-1) + + + + if jacobi is not None: + jacobi_diff = jacobi_fd - jacobi + assert (np.abs(jacobi_diff) < 1.0E-8).all(), 'jacobi matrix is not the same' + + return phase + + +def phase_elec(mag_data, b_0=1, v_0=0, v_acc=30000): + # TODO: Docstring + + # TODO: Delete +# import pdb; pdb.set_trace() + + res = mag_data.res + z_dim, y_dim, x_dim = mag_data.dim + z_mag, y_mag, x_mag = mag_data.magnitude + + phase = np.logical_or(x_mag, y_mag, z_mag) + + lam = H_BAR / np.sqrt(2 * M_E * v_acc * (1 + Q_E*v_acc / (2*M_E*C**2))) + + Ce = (2*pi*Q_E/lam * (Q_E*v_acc + M_E*C**2) / + (Q_E*v_acc * (Q_E*v_acc + 2*M_E*C**2))) + + phase *= res * v_0 * Ce + + return phase \ No newline at end of file diff --git a/pyramid/projector.py b/pyramid/projector.py new file mode 100644 index 0000000..c101733 --- /dev/null +++ b/pyramid/projector.py @@ -0,0 +1,17 @@ +# -*- coding: utf-8 -*- +""" +Created on Tue May 14 14:44:36 2013 + +@author: Jan +"""# TODO: Docstring + +from magdata import MagData + +def simple_axis_projection(mag_data, axis=0): + # TODO: assert isinstance(mag_data, MagData), 'Object is no instance of MagData!' + return (mag_data.magnitude[0].mean(axis), # x_mag + mag_data.magnitude[1].mean(axis), # y_mag + mag_data.magnitude[2].mean(axis)) # z_mag + + +# TODO: proper projection algorithm with two angles and such! \ No newline at end of file diff --git a/pyramid/reconstructor.py b/pyramid/reconstructor.py new file mode 100644 index 0000000..0e3835a --- /dev/null +++ b/pyramid/reconstructor.py @@ -0,0 +1,7 @@ +# -*- coding: utf-8 -*- +""" +Created on Tue May 14 15:19:33 2013 + +@author: Jan +""" + diff --git a/scripts/create_random_distribution.py b/scripts/create_random_distribution.py index 1ac5c6b..fb7cd80 100644 --- a/scripts/create_random_distribution.py +++ b/scripts/create_random_distribution.py @@ -5,30 +5,40 @@ Created on Mon May 13 13:05:40 2013 @author: Jan """ -import random +import random as rnd import numpy as np -import matplotlib.pyplot as plt import pyramid.magcreator as mc -import time import pdb, traceback, sys from numpy import pi -def phase_from_mag(): +def create_random_distribution(): count = 10 - dim = (128, 128) + dim = (1, 128, 128) + res = 10 # in nm - random.seed(42) + rnd.seed(42) + + mag_shape_list = np.zeros((count, dim[0], dim[1], dim[2])) + beta_list = np.zeros(count) + magnitude_list = np.zeros(count) for i in range(count): + pixel = (rnd.randrange(dim[0]), rnd.randrange(dim[1]), rnd.randrange(dim[2])) + mag_shape_list[i,...] = mc.shape_single_pixel(dim, pixel) + beta_list[i] = 2*pi*rnd.random() + magnitude_list[i] = 1#rnd.random() - x = random.rand + mag_data = mc.create_mag_dist(dim, res, mag_shape_list, beta_list, magnitude_list) + mag_data.quiver_plot() + #mag_data.quiver_plot_3D() + mag_data.save_to_llg('../output/mag_dist_random_pixel.txt') if __name__ == "__main__": try: - phase_from_mag() + create_random_distribution() except: type, value, tb = sys.exc_info() traceback.print_exc() -- GitLab