{ "cells": [ { "cell_type": "code", "execution_count": null, "id": "77b4a5bc", "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": "13ead338", "metadata": {}, "source": [ "(model)=\n", "\n", "# The model object\n", "\n", "In this chapter we will get familiar with the flatspin model object, which implements the [theoretical model](theory).\n", "We will cover how to create a model object, setting parameters, and different model attributes.\n", "\n", "This guide is written as a [Jupyter notebook](https://jupyter.org/), which can be downloaded by clicking the download link from the top of the page." ] }, { "cell_type": "markdown", "id": "d1dcda4d", "metadata": {}, "source": [ "The main object in flatspin is the *model* ({mod}`flatspin.model`). Each model class defines a spin ice *geometry*, which specifies the positions and angles of the spins. The {class}`SquareSpinIceClosed ` class, for instance, creates a square spin ice geometry (with \"closed\" edges):" ] }, { "cell_type": "code", "execution_count": null, "id": "04de4dc1", "metadata": {}, "outputs": [], "source": [ "from flatspin.model import SquareSpinIceClosed\n", "\n", "model = SquareSpinIceClosed()\n", "model.plot();" ] }, { "cell_type": "markdown", "id": "c4ca4035", "metadata": {}, "source": [ "flatspin comes with model classes for some common geometries, shown in the gallery below:" ] }, { "cell_type": "code", "execution_count": null, "id": "49567372", "metadata": { "tags": [ "hide-input" ] }, "outputs": [], "source": [ "import flatspin.model\n", "\n", "class_names = ['SquareSpinIceClosed', 'SquareSpinIceOpen',\n", " 'KagomeSpinIce', 'KagomeSpinIceRotated',\n", " 'PinwheelSpinIceDiamond', 'PinwheelSpinIceLuckyKnot',\n", " ]\n", "\n", "n_cols = 3\n", "n_rows = int(np.ceil(len(class_names) / n_cols))\n", "plt.figure(figsize=(2*n_cols, 2*n_rows))\n", "for i, name in enumerate(class_names):\n", " cls = getattr(flatspin.model, name)\n", " plt.subplot(n_rows, n_cols, i+1)\n", " plt.title(name)\n", " model = cls()\n", " model.plot()\n", " plt.axis(False)\n", "plt.tight_layout(w_pad=8)" ] }, { "cell_type": "markdown", "id": "121fcac9", "metadata": {}, "source": [ "If you would like to add your own geometries, see [](extending).\n", "\n", "(model-params)=\n", "## Model parameters\n", "\n", "Properties of the model can be changed through *parameters*, which are passed as keyword arguments to the model class. Note that the model *only* accepts keyword arguments (and no positional arguments).\n", "\n", "For example, we may change the `size` parameter to create a larger spin ice:" ] }, { "cell_type": "code", "execution_count": null, "id": "31507075", "metadata": {}, "outputs": [], "source": [ "model = SquareSpinIceClosed(size=(10,5))\n", "print(f\"10x5 square ASI has\", model.spin_count, \"spins\")\n", "model.plot();" ] }, { "cell_type": "markdown", "id": "c53e2218", "metadata": {}, "source": [ "Note that `size` is geometry-specific: for {class}`SquareSpinIceClosed `, the size specifies the number of columns (rows) of horizontal (vertical) magnets.\n", "For {class}`KagomeSpinIce `, the size denotes the number of hexagonal units:" ] }, { "cell_type": "code", "execution_count": null, "id": "6f7053e7", "metadata": {}, "outputs": [], "source": [ "from flatspin.model import KagomeSpinIce\n", "model = KagomeSpinIce(size=(10,5))\n", "print(f\"10x5 kagome ASI has\", model.spin_count, \"spins\")\n", "model.plot();" ] }, { "cell_type": "markdown", "id": "950b4d1b", "metadata": {}, "source": [ "Other important parameters include `alpha` (the coupling strength), `hc` (the coercive field), `disorder` (random variations in the coercive fields) and `temperature` (absolute temperature in Kelvin). For a list of available parameters, see {class}`SpinIce `." ] }, { "cell_type": "markdown", "id": "9922bb9a", "metadata": {}, "source": [ "(model-spin)=\n", "## Dealing with spins\n", "\n", "The state of all the spins is stored in the `spin` array. Spin values are either `1` or `-1`, and are all initialized to `1` at model instantiation." ] }, { "cell_type": "code", "execution_count": null, "id": "b7d30e39", "metadata": {}, "outputs": [], "source": [ "model = SquareSpinIceClosed()\n", "model.spin" ] }, { "cell_type": "markdown", "id": "11b60bf6", "metadata": {}, "source": [ "You may access elements of this array directly to read or modify the state of spins.\n", "Alternatively, use {func}`flip() ` to flip a single spin, {func}`set_spin() ` to set the state of all spins, or {func}`polarize() ` to reset all spins to `1` or `-1`." ] }, { "cell_type": "code", "execution_count": null, "id": "63fcebee", "metadata": {}, "outputs": [], "source": [ "model.spin[0] = -1\n", "model.spin[-1] = -1\n", "model.flip(4)\n", "model.plot();" ] }, { "cell_type": "markdown", "id": "b7b3c964", "metadata": {}, "source": [ "The `spin` array has a flat index, where spins are ordered sequentially. Sometimes it can be easier to work in a different coordinate system, which is where spin labels come in. The left plot below shows the index of each spin. The right plot shows the corresponding labels, for {class}`SquareSpinIceClosed `, which uses a `(row, col)` labeling scheme." ] }, { "cell_type": "code", "execution_count": null, "id": "fd073f0a", "metadata": { "tags": [ "hide-input" ] }, "outputs": [], "source": [ "plt.figure(figsize=(8,4))\n", "plt.subplot(121)\n", "plt.title(\"Spin indices\")\n", "model.plot()\n", "for i in model.indices():\n", " plt.text(model.pos[i,0], model.pos[i,1], str(i), ha='center', va='center')\n", "\n", "plt.subplot(122)\n", "plt.title(\"Spin labels\")\n", "model.plot()\n", "for i, l in enumerate(model.labels):\n", " plt.text(model.pos[i,0], model.pos[i,1], tuple(l), ha='center', va='center')" ] }, { "cell_type": "markdown", "id": "ad6d7a85", "metadata": {}, "source": [ "You can use the `L` object to look up the spin index of a label, or a label range:" ] }, { "cell_type": "code", "execution_count": null, "id": "40ef4dca", "metadata": {}, "outputs": [], "source": [ "L = model.L\n", "print(\"(4,2):\", L[4,2])\n", "print(\"Row 3:\", L[3])\n", "print(\"Column 4:\", L[:,4])\n", "print(\"Rows 1-3:\", L[1:3])\n", "print(\"Odd rows:\", L[1::2])" ] }, { "cell_type": "markdown", "id": "239b8665", "metadata": {}, "source": [ "(model-geometry)=\n", "## Geometry\n", "\n", "Spin ice geometry is defined by the positions and angles of all the spins, and are stored in the `pos` and `angle` attributes. Positions are in reduced units, defined by `alpha` (see [](theory)). The angles are in radians and define the rotation for the spins *assuming a positive spin value of `1`*.\n", "\n", "Please note that these attributes are considered **read-only** and cannot be changed after model initialization." ] }, { "cell_type": "code", "execution_count": null, "id": "6c4418d0", "metadata": {}, "outputs": [], "source": [ "print(f\"Spin 0 has position {model.pos[0]} and angle {np.rad2deg(model.angle[0])}\")\n", "print(f\"Spin 4 has position {model.pos[4]} and angle {np.rad2deg(model.angle[4])}\")" ] }, { "cell_type": "markdown", "id": "b144f6f0", "metadata": {}, "source": [ "As an alternative to tuning the coupling strength `alpha`, the distance between spins may be adjusted by the `lattice_spacing` parameter. This affects the positions of the spins directly, as opposed to indirectly through `alpha` (see [](theory))." ] }, { "cell_type": "code", "execution_count": null, "id": "fd2dfcd1", "metadata": {}, "outputs": [], "source": [ "model2 = SquareSpinIceClosed(lattice_spacing=10)\n", "# Notice change in x/y labels when we plot()\n", "model2.plot();" ] }, { "cell_type": "markdown", "id": "d512da8b", "metadata": {}, "source": [ "(model-vectors)=\n", "## Magnetization vectors\n", "\n", "As mentioned above, `angle` is independent of the current spin state. To obtain the magnetization direction, use {attr}`vectors `." ] }, { "cell_type": "code", "execution_count": null, "id": "755759a2", "metadata": {}, "outputs": [], "source": [ "print(f\"Spin 0 has magnetization {model.vectors[0]}\")\n", "print(f\"Spin 1 has magnetization {model.vectors[1]}\")\n", "print(f\"Spin 4 has magnetization {model.vectors[4]}\")" ] }, { "cell_type": "markdown", "id": "9a99ca32", "metadata": {}, "source": [ "(model-hc)=\n", "## Coercive fields and disorder\n", "\n", "The coercive field defines the critical field strength required to flip a spin (see also [](switching)). \n", "The coercive fields for all spins are stored in the `threshold` array of the model object.\n", "By default, the coercive fields are uniformly set to the parameter `hc`.\n", "We can introduce small variations in the coercive fields by setting the `disorder` parameter, in which case the thresholds are sampled from a normal distribution with mean `hc` and standard deviation `disorder * hc`.\n", "\n", "Below we plot a histogram of the coercive fields with 1% and 5% disorder." ] }, { "cell_type": "code", "execution_count": null, "id": "8bfc4036", "metadata": {}, "outputs": [], "source": [ "model1 = SquareSpinIceClosed(size=(25,25), hc=0.1, disorder=0.01)\n", "model5 = SquareSpinIceClosed(size=(25,25), hc=0.1, disorder=0.05)\n", "bins = np.linspace(0.08, 0.12, 21) - 0.001\n", "plt.hist(model1.threshold, bins=bins, label='1% disorder', alpha=0.5)\n", "plt.hist(model5.threshold, bins=bins, label='5% disorder', alpha=0.5)\n", "plt.legend()\n", "plt.xlabel(\"hc\");" ] }, { "cell_type": "markdown", "id": "de273308", "metadata": {}, "source": [ "## GPU acceleration\n", "\n", "flatspin provides GPU acceleration to speed up calculations on the GPU, but note that this must be explicitly enabled by setting the parameter `use_opencl=True`. It is primarily the calculations of the magnetic fields that benefit from running on the GPU." ] } ], "metadata": { "jupytext": { "formats": "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, 35, 39, 44, 48, 69, 80, 84, 89, 94, 98, 105, 108, 113, 118, 122, 137, 141, 148, 157, 160, 164, 168, 175, 179, 191, 199 ] }, "nbformat": 4, "nbformat_minor": 5 }