{ "cells": [ { "cell_type": "code", "execution_count": null, "id": "fe30fb3b", "metadata": { "tags": [ "remove-input" ] }, "outputs": [], "source": [ "%config InlineBackend.figure_formats = ['svg']\n", "\n", "import numpy as np\n", "from numpy.linalg import norm\n", "import matplotlib.pyplot as plt\n", "plt.rcParams['animation.frame_format'] = \"svg\"" ] }, { "cell_type": "markdown", "id": "fdbac80a", "metadata": {}, "source": [ "# Switching\n", "\n", "flatspin uses a generalized Stoner-Wohlfarth (GSW) switching model to describe the angle-dependent switching threshold (coercive field) of a spin.\n", "\n", "A *switching astroid* is a polar plot of the coercive field at different angles, with $h_{\\perp}$ on the horizontal axis (hard axis) and $h_{\\parallel}$ on the vertical axis (easy axis) (see [](fields)).\n", "\n", "The coercive field is described by the GSW equation (see [](theory)):\n", "\n", "$$\n", "\\left(\\frac{h_{\\parallel}}{b h_k}\\right)^{2/\\gamma} + \\left(\\frac{h_{\\perp}}{c h_k}\\right)^{2/\\beta} = 1\n", "$$\n", "\n", "The parameters $b$, $c$, $\\beta$ and $\\gamma$ adjust the shape of the switching astroid: $b$ and $c$ define the height and width, respectively, while $\\beta$ and $\\gamma$ adjust the curvature of the astroid at the easy and hard axis, respectively.\n", "$h_k$ scales the coercive fields and corresponds to the switching threshold at $h_\\parallel=0$, i.e., when the field is aligned with the hard axis.\n", "In the flatspin model, $h_k$ corresponds to the `hc` parameter.\n", "\n", "Tuning the parameters of the GSW equation allows the model to capture the switching characteristics of magnets with different shapes.\n", "For example:\n", "* **Elliptical magnets** have a symmetric astroid, described by the regular Stoner-Wohlfarth model: $b=c=1$ and $\\beta=\\gamma=3$.\n", "* **Rectangular magnets** have an asymmetric switching astroid: they switch more easily along the parallel axis: $b < c$.\n", "\n", "Below we plot the GSW astroid for a few different parameters:" ] }, { "cell_type": "code", "execution_count": null, "id": "0551180d", "metadata": { "tags": [ "hide-input" ] }, "outputs": [], "source": [ "def GSW(h_par, h_perp, b=1, c=1, beta=3, gamma=3):\n", " \"\"\" Generalized Stoner-Wohlfarth astroid \"\"\"\n", " sw = b*(1 - ((h_perp/c)**2)**(1/beta))**(gamma/2)\n", " sw[h_par<0] *= -1\n", " return sw\n", "\n", "def plot_GSW(b=1, c=1, beta=3, gamma=3, ax=None, angle_range=(0, 2*np.pi), **kwargs):\n", " thetas = np.linspace(angle_range[0], angle_range[1], 3601)\n", "\n", " h_perp = c * np.cos(thetas)\n", " h_par = b * np.sin(thetas)\n", " \n", " kwargs.setdefault(\"label\", rf\"$b={b:g}, c={c:g}, \\beta={beta:g}, \\gamma={gamma:g}$\")\n", "\n", " if ax is None:\n", " ax = plt.gca()\n", " return ax.plot(h_perp, GSW(h_par, h_perp, b, c, beta, gamma), **kwargs)" ] }, { "cell_type": "code", "execution_count": null, "id": "79ddce95", "metadata": {}, "outputs": [], "source": [ "plot_GSW(label=\"Stoner-Wohlfarth\")\n", "plot_GSW(b=0.5)\n", "plot_GSW(b=0.5, beta=1.5)\n", "plt.xlabel('$h_\\perp / h_k$')\n", "plt.ylabel('$h_\\parallel / h_k$')\n", "plt.axis('square')\n", "plt.legend(loc='upper left', bbox_to_anchor=(1.0, 1.0));" ] }, { "cell_type": "markdown", "id": "16213084", "metadata": {}, "source": [ "## Switching a spin\n", "\n", "A spin may flip if the total magnetic field acting on the spin:\n", "\n", "1. is outside of the switching astroid (left hand side of the GSW equation is greater than 1)\n", "2. is oriented in the opposite direction of the spin magnetization ($h_\\parallel < 0$)\n", "\n", "To illustrate the switching model, let us consider a single vertical spin:" ] }, { "cell_type": "code", "execution_count": null, "id": "ba2355c1", "metadata": {}, "outputs": [], "source": [ "from flatspin.model import IsingSpinIce\n", "\n", "model = IsingSpinIce(size=(1,1))\n", "model.plot();" ] }, { "cell_type": "markdown", "id": "35df419e", "metadata": {}, "source": [ "Next, let us set up a cycling external field at some angle to the spin.\n", "The animation below shows the switching astroid for the spin (left plot) with the corresponding magnetic field superimposed (arrow inside the astroid).\n", "The top right column shows the state of the spin, and the bottom right column shows the external field.\n", "\n", "Notice how switching only occurs when the field crosses the *negative side* of the astroid ($h_\\parallel < 0$), because of switching condition (2).\n", "After switching, the external field is aligned with the magnetization of the spin, and the field arrow jumps to the positive side of the astroid ($h_\\parallel > 0).\n", "\n", "Because only the negative side of the astroid is relevant for switching, the positive side of the astroid is marked with a dashed line in the astroid plots below." ] }, { "cell_type": "code", "execution_count": null, "id": "a0d240f7", "metadata": { "tags": [ "hide-input" ] }, "outputs": [], "source": [ "from matplotlib.animation import FuncAnimation\n", "from IPython.display import HTML\n", "from flatspin.encoder import Triangle\n", "from flatspin.plotting import plot_vectors, vector_colors\n", "\n", "def animate_switching(model, H=0.15, phi=-100):\n", " # Reset system back to the polarized state\n", " model.polarize()\n", " hk = model.threshold.reshape((-1,1))\n", "\n", " # Set up figure and axes\n", " fig = plt.figure(facecolor='white')\n", " ax_astroid = plt.subplot2grid((2,3), (0,0), rowspan=2, colspan=2)\n", " ax_spin = plt.subplot2grid((2,3), (0,2))\n", " ax_h_ext = plt.subplot2grid((2,3), (1,2))\n", "\n", " # Set up external field (triangle wave)\n", " enc = Triangle(timesteps=64, H=H, phi=phi)\n", " h_ext = enc([1])\n", "\n", " # Plot astroid with field vector\n", " plt.sca(ax_astroid)\n", " line, = plot_GSW(*model.sw_params, angle_range=(np.pi, 2*np.pi))\n", " plot_GSW(*model.sw_params, angle_range=(0, np.pi), ls='dashed', color=line.get_color())\n", " origin = np.tile([0, 0], (model.spin_count, 1))\n", " plot_vectors(origin, origin, C=origin[:,0],\n", " clim=(-.5,.5), cmap='bwr_r', scale=1, width=.05, pivot='tail', mask_zero=False)\n", " plt.xlabel('$h_\\perp / h_k$')\n", " plt.ylabel('$h_\\parallel / h_k$')\n", "\n", " # spin axis\n", " plt.sca(ax_spin)\n", " plt.axis('off')\n", " plt.title('spin')\n", "\n", " # h_ext axis\n", " plt.sca(ax_h_ext)\n", " plt.axis('off')\n", " plt.title('h_ext')\n", "\n", " def do_cycle():\n", " for h in h_ext:\n", " model.set_h_ext(h)\n", " model.relax()\n", " h_tot = model.total_fields()\n", " yield model.total_fields()\n", "\n", " def do_plot(h_tot):\n", " h_tot /= hk\n", " h_tot = np.column_stack([h_tot[:,1], h_tot[:,0]])\n", " plot_vectors(origin, h_tot, C=np.sign(h_tot[:,1]), ax=ax_astroid, replace=True)\n", "\n", " model.plot(ax=ax_spin, replace=True)\n", "\n", " h_ext = model.h_ext / hk\n", " plot_vectors(model.pos, h_ext, ax=ax_h_ext, replace=True, scale=.5, width=.1)\n", "\n", " anim = FuncAnimation(fig, do_plot, init_func=lambda: None, frames=do_cycle(), interval=200, blit=False)\n", " plt.close() # Only show the animation\n", " #anim.save(\"astroid.gif\")\n", " return HTML(anim.to_jshtml())" ] }, { "cell_type": "code", "execution_count": null, "id": "8cfef3f9", "metadata": {}, "outputs": [], "source": [ "animate_switching(model)" ] }, { "cell_type": "markdown", "id": "4cbe867e", "metadata": {}, "source": [ "We may change the astroid shape of the spins in the model by setting the parameters `sw_b`, `sw_c`, `sw_beta` and `sw_gamma`.\n", "Below we change switching parameters to describe an elliptical magnet, and repeat the switching animation.\n", "Notice how elliptical magnets are much harder to switch when the field is aligned to the easy axis." ] }, { "cell_type": "code", "execution_count": null, "id": "e4612485", "metadata": {}, "outputs": [], "source": [ "model = IsingSpinIce(size=(1,1), sw_b=1, sw_c=1, sw_beta=3, sw_gamma=3)\n", "animate_switching(model)" ] }, { "cell_type": "markdown", "id": "9f68afc5", "metadata": {}, "source": [ "## Switching many spins\n", "\n", "Finally, we illustrate the switching process for a system of coupled spins in a square spin ice.\n", "Inside the astroid, there is one arrow for each spin.\n", "There are two main groups of arrows, since spins have two orientations (horizontal and vertical).\n", "Notice how, within a group, the arrows do not overlap perfectly.\n", "This is because of the dipolar fields from neighboring magnets." ] }, { "cell_type": "code", "execution_count": null, "id": "71c01bc1", "metadata": {}, "outputs": [], "source": [ "from flatspin.model import SquareSpinIceClosed\n", "model = SquareSpinIceClosed()\n", "animate_switching(model)" ] }, { "cell_type": "markdown", "id": "97d3779e", "metadata": {}, "source": [ "The switching process of many spin systems is discussed further in [](dynamics)." ] } ], "metadata": { "jupytext": { "formats": "ipynb,md:myst", "text_representation": { "extension": ".md", "format_name": "myst", "format_version": 0.13, "jupytext_version": "1.11.5" } }, "kernelspec": { "display_name": "Python 3", "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.8.10" }, "source_map": [ 15, 24, 49, 71, 79, 90, 95, 106, 172, 174, 180, 183, 193, 197 ] }, "nbformat": 4, "nbformat_minor": 5 }