diff --git a/docs/_static/custom.css b/docs/_static/custom.css index 7e5ad264..85cecc03 100644 --- a/docs/_static/custom.css +++ b/docs/_static/custom.css @@ -5,4 +5,14 @@ html[data-theme="dark"] .navbar-brand img { .headerlink { display: none; +} + +.side-by-side-images { + display: flex; + gap: 5%; +} + +.side-by-side-images img { + display: block; + width: 100%; } \ No newline at end of file diff --git a/docs/images/magnet_cylinder.png b/docs/images/magnet_cylinder.png new file mode 100644 index 00000000..e9b6f7c3 Binary files /dev/null and b/docs/images/magnet_cylinder.png differ diff --git a/docs/images/magnet_full.png b/docs/images/magnet_full.png new file mode 100644 index 00000000..d7e3cbbf Binary files /dev/null and b/docs/images/magnet_full.png differ diff --git a/docs/images/magnet_remove_line.png b/docs/images/magnet_remove_line.png new file mode 100644 index 00000000..a5aaa7b8 Binary files /dev/null and b/docs/images/magnet_remove_line.png differ diff --git a/docs/images/magnet_sawtooth.png b/docs/images/magnet_sawtooth.png new file mode 100644 index 00000000..74d082ef Binary files /dev/null and b/docs/images/magnet_sawtooth.png differ diff --git a/docs/images/magnet_sphere.png b/docs/images/magnet_sphere.png new file mode 100644 index 00000000..306a39d3 Binary files /dev/null and b/docs/images/magnet_sphere.png differ diff --git a/docs/tutorial.rst b/docs/tutorial.rst index c304982e..1816f328 100644 --- a/docs/tutorial.rst +++ b/docs/tutorial.rst @@ -11,6 +11,7 @@ started! :maxdepth: 1 tutorial/magnetization + tutorial/geometry tutorial/shapes tutorial/regions tutorial/stdp4 diff --git a/docs/tutorial/geometry.rst b/docs/tutorial/geometry.rst new file mode 100644 index 00000000..4f512f5f --- /dev/null +++ b/docs/tutorial/geometry.rst @@ -0,0 +1,145 @@ +:nosearch: + +Geometry +======== + +This tutorial will teach you how to set your geometry for your magnets. The ``geometry`` parameter can accept numpy arrays and functions. + +.. code-block:: python + + import numpy as np + from mumaxplus import Ferromagnet, Grid, World + import mumaxplus.util.shape as shape + import matplotlib.pyplot as plt + +We will first define the constants of our world and grid. The grid is comprised of 128 x 64 x 1 cells of each 1 x 1 x 1 nm³. + +.. code-block:: python + + nx, ny, nz = 128, 64, 1 + cx, cy, cz = 1e-9, 1e-9, 1e-9 + center = cx*(nx-1)/2, cy*(ny-1)/2, cz*(nz-1)/2 + +Now we create a function to visualise the geometry. In the final images empty space will be shown as white while the magnetic material will be gray. + +.. code-block:: python + + def show_2D_geom(magnet): + geom = magnet.geometry[0,...] + im_extent = (-0.5*cx * 1e9, (nx*cx - 0.5*cx) * 1e9, -0.5*cy * 1e9, (ny*cy - 0.5*cy) * 1e9) + plt.imshow(geom, cmap="Greys", origin="lower", extent=im_extent, vmin=0, vmax=2) + plt.xlabel("x (nm)") + plt.ylabel("y (nm)") + plt.show() + +1. Numpy arrays +--------------- +Here we will be looking at setting the geometry with a numpy array. The array should have the same dimensions as our grid and should contain booleans. + +1.1 The full grid +^^^^^^^^^^^^^^^^^ +If we want our magnet to be the entire grid we do not have to specify a geometry. + +.. code-block:: python + + world = World(cellsize=(cx, cy, cz)) + grid = Grid((nx, ny, nz)) + + magnet = Ferromagnet(world=world, grid=grid) + + show_2D_geom(magnet) + +.. image:: ../images/magnet_full.png + :align: center + :width: 600px + +1.2 Eliminating pixels +^^^^^^^^^^^^^^^^^^^^^^ +If we want to remove some pixels from the magnet we can create an array as big as our grid and set some values to 0 (or ``False``). Note that the array should have a shape of (nz, ny, nx). +Let's now remove a row of cells at the center of the magnet. + +.. code-block:: python + + world = World(cellsize=(cx, cy, cz)) + grid = Grid((nx, ny, nz)) + + geom_array = np.ones(shape=(nz,ny,nx)) + geom_array[:,ny//2,:] = np.zeros(shape=(nz,nx)) + + magnet = Ferromagnet(world=world, grid=grid, geometry=geom_array) + + show_2D_geom(magnet) + +.. image:: ../images/magnet_remove_line.png + :align: center + :width: 600px + +2. Functions +------------ +We can also create our own functions to form geometries. The input of every function should be (x,y,z) where x, y and z are real space coordinates. The output of the function should be a boolean. + +2.1 Circle +^^^^^^^^^^ +Here we create a circle with a radius of 20nm at the center of the grid. + +.. code-block:: python + + world = World(cellsize=(cx, cy, cz)) + grid = Grid((nx, ny, nz)) + + geomfunc = lambda x, y, z: (x - center[0])**2 + (y - center[1])**2 < (20e-9)**2 + + magnet = Ferromagnet(world=world, grid=grid, geometry=geomfunc) + + show_2D_geom(magnet) + +.. image:: ../images/magnet_cylinder.png + :align: center + :width: 600px + +2.2 Sawtooth +^^^^^^^^^^^^ +Here we will cut a sawtooth pattern out of a magnet. + +.. code-block:: python + + world = World(cellsize=(cx, cy, cz)) + grid = Grid((nx, ny, nz)) + + p = 25e-9 + a = 20e-9 + + def saw(x,y,z): + func = a*(x/p - np.floor(0.5 + x/p)) + a/2-cy + return y > func + + magnet = Ferromagnet(world=world, grid=grid, geometry=saw) + + show_2D_geom(magnet) + +.. image:: ../images/magnet_sawtooth.png + :align: center + :width: 600px + +3. Shapes +--------- +Let's end this tutoial by using the ``Shape`` class to generate a geometry. For more information on different shapes and shape manipulations see :doc:`Shapes `. + +3.1 Sphere +^^^^^^^^^^ +Here we create a spherical magnet with a diameter of 60nm. + +.. code-block:: python + + world = World(cellsize=(cx, cy, cz)) + grid = Grid((nx, ny, nz)) + + circ = shape.Sphere(diam=20e-9) + circ.translate(*center) + magnet = Ferromagnet(world=world, grid=grid, geometry=circ) + + show_2D_geom(magnet) + +.. image:: ../images/magnet_sphere.png + :align: center + :width: 600px diff --git a/docs/tutorial/plot_field.rst b/docs/tutorial/plot_field.rst index a518fdff..2f5a9e14 100644 --- a/docs/tutorial/plot_field.rst +++ b/docs/tutorial/plot_field.rst @@ -88,11 +88,13 @@ Or look along a different out-of-plane axis. plot_field(mag, out_of_plane_axis="x") plot_field(mag, out_of_plane_axis="y") -.. image:: ../images/plot_field/plot_field_OoP_x.png - :width: 45% +.. container:: side-by-side-images -.. image:: ../images/plot_field/plot_field_OoP_y.png - :width: 45% + .. image:: ../images/plot_field/plot_field_OoP_x.png + :width: 100% + + .. image:: ../images/plot_field/plot_field_OoP_y.png + :width: 100% A few things to note: diff --git a/docs/tutorial/regions.rst b/docs/tutorial/regions.rst index 937430fa..0fd73f69 100644 --- a/docs/tutorial/regions.rst +++ b/docs/tutorial/regions.rst @@ -81,11 +81,13 @@ Now one can set parameter values in each region seperately. plot_field(magnet.magnetization, arrow_size=1) -.. image:: ../images/regions_1.png - :width: 45% +.. container:: side-by-side-images -.. image:: ../images/regions_2.png - :width: 45% + .. image:: ../images/regions_1.png + :width: 100% + + .. image:: ../images/regions_2.png + :width: 100% Likewise, the antiferromagnetic nearest-neighbour exchange constant, ``afmex_nn``, can be set in the same way. \ No newline at end of file diff --git a/examples/geometry.ipynb b/examples/geometry.ipynb new file mode 100644 index 00000000..54b2e29d --- /dev/null +++ b/examples/geometry.ipynb @@ -0,0 +1,241 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "87d10106", + "metadata": {}, + "source": [ + "# Geometry\n", + "This notebook will teach you how to set your geometry for your magnets. The `geometry` parameter can accept numpy arrays and functions." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1fbda135", + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "from mumaxplus import Ferromagnet, Grid, World\n", + "import mumaxplus.util.shape as shape\n", + "import matplotlib.pyplot as plt" + ] + }, + { + "cell_type": "markdown", + "id": "6ae2a331", + "metadata": {}, + "source": [ + "We will first define the constants of our world and grid. The grid is comprised of 128 x 64 x 1 cells of each 1 x 1 x 1 nm³." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bbf906e6", + "metadata": {}, + "outputs": [], + "source": [ + "nx, ny, nz = 128, 64, 1\n", + "cx, cy, cz = 1e-9, 1e-9, 1e-9\n", + "center = cx*(nx-1)/2, cy*(ny-1)/2, cz*(nz-1)/2" + ] + }, + { + "cell_type": "markdown", + "id": "94e1c830", + "metadata": {}, + "source": [ + "Now we create a function to visualise the geometry. In the final images empty space will be shown as white while the magnetic material will be gray." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cd1e5e70", + "metadata": {}, + "outputs": [], + "source": [ + "def show_2D_geom(magnet):\n", + " geom = magnet.geometry[0,...]\n", + " im_extent = (-0.5*cx * 1e9, (nx*cx - 0.5*cx) * 1e9, -0.5*cy * 1e9, (ny*cy - 0.5*cy) * 1e9)\n", + " plt.imshow(geom, cmap=\"Greys\", origin=\"lower\", extent=im_extent, vmin=0, vmax=2)\n", + " plt.xlabel(\"x (nm)\")\n", + " plt.ylabel(\"y (nm)\")\n", + " plt.show()" + ] + }, + { + "cell_type": "markdown", + "id": "943bd466", + "metadata": {}, + "source": [ + "## 1. Numpy arrays\n", + "Here we will be looking at setting the geometry with a numpy array. The array should have the same dimensions as our grid and should contain booleans.\n", + "\n", + "### 1.1 The full grid\n", + "If we want our magnet to be the entire grid we do not have to specify a geometry." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3a5da627", + "metadata": {}, + "outputs": [], + "source": [ + "world = World(cellsize=(cx, cy, cz))\n", + "grid = Grid((nx, ny, nz))\n", + "\n", + "magnet = Ferromagnet(world=world, grid=grid)\n", + "\n", + "show_2D_geom(magnet)" + ] + }, + { + "cell_type": "markdown", + "id": "d9c758c4", + "metadata": {}, + "source": [ + "### 1.2 Eliminating pixels\n", + "If we want to remove some pixels from the magnet we can create an array as big as our grid and set some values to 0 (or `False`). Note that the array should have a shape of (nz, ny, nx).\n", + "Let's now remove a row of cells at the center of the magnet." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "554ba29a", + "metadata": {}, + "outputs": [], + "source": [ + "world = World(cellsize=(cx, cy, cz))\n", + "grid = Grid((nx, ny, nz))\n", + "\n", + "geom_array = np.ones(shape=(nz,ny,nx))\n", + "geom_array[:,ny//2,:] = 0\n", + "\n", + "magnet = Ferromagnet(world=world, grid=grid, geometry=geom_array)\n", + "\n", + "show_2D_geom(magnet)" + ] + }, + { + "cell_type": "markdown", + "id": "bc83a787", + "metadata": {}, + "source": [ + "## 2. Functions" + ] + }, + { + "cell_type": "markdown", + "id": "83936698", + "metadata": {}, + "source": [ + "We can also create our own functions to form geometries. The input of every function should be (x,y,z) where x, y and z are real space coordinates. The output of the function should be a boolean.\n", + "\n", + "### 2.1 Circle\n", + "Here we create a circle with a radius of 20nm at the center of the grid." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7a3450bd", + "metadata": {}, + "outputs": [], + "source": [ + "world = World(cellsize=(cx, cy, cz))\n", + "grid = Grid((nx, ny, nz))\n", + "\n", + "geomfunc = lambda x, y, z: (x - center[0])**2 + (y - center[1])**2 < (20e-9)**2\n", + "\n", + "magnet = Ferromagnet(world=world, grid=grid, geometry=geomfunc)\n", + "\n", + "show_2D_geom(magnet)" + ] + }, + { + "cell_type": "markdown", + "id": "ef62e6aa", + "metadata": {}, + "source": [ + "### 2.2 Sawtooth\n", + "Here we will cut a sawtooth pattern out of a magnet." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6fe431da", + "metadata": {}, + "outputs": [], + "source": [ + "world = World(cellsize=(cx, cy, cz))\n", + "grid = Grid((nx, ny, nz))\n", + "\n", + "p = 25e-9\n", + "a = 20e-9\n", + "\n", + "def saw(x,y,z):\n", + " func = a*(x/p - np.floor(0.5 + x/p)) + a/2-cy\n", + " return y > func\n", + "\n", + "magnet = Ferromagnet(world=world, grid=grid, geometry=saw)\n", + "\n", + "show_2D_geom(magnet)" + ] + }, + { + "cell_type": "markdown", + "id": "798c55fe", + "metadata": {}, + "source": [ + "## 3. Shapes\n", + "Let's end this tutoial by using the `Shape` class to generate a geometry. For more information on different shapes and shape manipulations see `shape.ipynb`.\n", + "### 3.1 Sphere\n", + "Here we create a circular magnet with a diameter of 60nm." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "49c0f54e", + "metadata": {}, + "outputs": [], + "source": [ + "world = World(cellsize=(cx, cy, cz))\n", + "grid = Grid((nx, ny, nz))\n", + "\n", + "circ = shape.Circle(diam=60e-9)\n", + "circ.translate(*center)\n", + "magnet = Ferromagnet(world=world, grid=grid, geometry=circ)\n", + "\n", + "show_2D_geom(magnet)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "mumaxplus", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.13.13" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +}